aboutsummaryrefslogblamecommitdiff
path: root/tamper.c
blob: 2893a6cf1cb36c59ac962da33c4ea740bef125b8 (plain) (tree)
1
2

                                                














































































































                                                                          

                                                            
             

                                                       





                                    


                                                                     
               

                                                   










































































































                                                                  
/* Copyright (c) 2016, NORDUnet A/S. */
/* See LICENSE.txt for licensing information. */

#include <inttypes.h>
#include <avr/io.h> /* -D__AVR_ATtiny828__ will include <avr/iotn828.h> */

/* Mapping of pins to names. */
#define AVR_LED1 PORTA0
#define AVR_LED2 PORTA3
#define AVR_LED3 PORTA2
#define AVR_LED4 PORTA1
#define AVR_PANIC PORTA4

#define MKM_AVR_CS_N PORTA5
#define MKM_CONTROL_AVR_ENA PORTA6
#define MKM_CONTROL_FPGA_DIS PORTA7

#define MKM_AVR_MOSI PORTD0
#define MKM_AVR_MISO PORTD1
#define MKM_AVR_SCK PORTD3


/* Input pins. */
#define AVR_PANIC_PIN PINA      /* Panic button. */
#define AVR_PANIC_BIT PINA4     /* 0 = panic. */

/* Output ports. */
#define AVR_LED_PORT PORTA
#define AVR_LED_BLUE_BIT PORTA0
#define AVR_LED_RED_BIT PORTA3
#define AVR_LED_YELLOW_BIT PORTA2
#define AVR_LED_GREEN_BIT PORTA1

#define MKM_CS_PORT PORTA       /* MKM chip select. */
#define MKM_CS_BIT MKM_AVR_CS_N /* 0 -> selected. */

#define MKM_CONTROL_AVR_PORT PORTA              /* AVR in control. */
#define MKM_CONTROL_AVR_BIT MKM_CONTROL_AVR_ENA /* 0 -> in control. */

#define MKM_CONTROL_FPGA_PORT PORTA /* FPGA in control. */
#define MKM_CONTROL_FPGA_BIT MKM_CONTROL_FPGA_DIS /* 0 -> in control. */

/* SPI. */
#define MKM_AVR_MOSI_PORT PORTD
#define MKM_AVR_MOSI_BIT MKM_AVR_MOSI /* PD0, Master Out Slave In. */
#define MKM_AVR_MISO_PORT PORTD
#define MKM_AVR_MISO_BIT PORTD1 /* PD1, Master In Slave Out. */
#define MKM_AVR_SCK_PORT PORTD
#define MKM_AVR_SCK_BIT PORTD3  /* PD3, SPI clock. */

/*******/
/* MKM */
static inline void
mkm_chip_select(int select_flag)
{
  if (select_flag)
    MKM_CS_PORT &= ~_BV(MKM_CS_BIT); /* CS low. */
  else
    MKM_CS_PORT |= _BV(MKM_CS_BIT); /* CS high. */
}

static inline void
mkm_grab()
{
  MKM_CONTROL_FPGA_PORT |= _BV(MKM_CONTROL_FPGA_BIT);
  MKM_CONTROL_AVR_PORT &= ~_BV(MKM_CONTROL_AVR_BIT);
}

static inline void
mkm_release()
{
  MKM_CONTROL_AVR_PORT |= _BV(MKM_CONTROL_AVR_BIT);
  MKM_CONTROL_FPGA_PORT &= ~_BV(MKM_CONTROL_FPGA_BIT);
}

/*******/
/* SPI */
#define SPI_SS DDRC0            /* SPI slave select. */

static inline void
spi_setup(int on_flag)
{
  if (on_flag)
    {
      /* Disable SPI power reduction. */
      PRR &= ~_BV(PRSPI);

      /* Set MOSI and SCK to output. */
      DDRD = _BV(MKM_AVR_MOSI_BIT) | _BV(MKM_AVR_SCK_BIT);

      /* Make sure SPI slave select (SS) is configured as output before
         enabling SPI master mode!. */
      DDRC |= _BV(SPI_SS);

      /* Enable SPI in master mode, clock rate f/16. */
      SPCR = _BV(SPE) | _BV(MSTR) | _BV(SPR0);
    }
  else
    {
      SPCR &= ~_BV(SPE);
      PRR |= _BV(PRSPI);
    }
}

/* SPI commands for MKM (23K640). */
#define SPI_READ 0x03
#define SPI_WRITE 0x02
#define SPI_RDSR 0x05           /* Read status register. */
#define SPI_WRSR 0x01           /* Write status register. */

static inline void
spi_write(uint8_t val)
{
  /* Move the value to be sent to the SPI slave into the SPI
     register. This starts the SPI clock. */
  SPDR = val;

  /* Wait for the byte to be shifted into the slave. */
  loop_until_bit_is_set(SPSR, SPIF);
}

static inline uint8_t
spi_read()
{
  /* Start clocking the SPI slave by moving a dummy byte (0) into the
     SPI register and wait for the byte from the slave to be shifted
     in. */
  spi_write(0);

  /* Read the SPI register and return the value. */
  return SPDR;
}

static inline uint8_t
spi_read_status()
{
  spi_write(SPI_RDSR);
  return SPDR;
}

static inline void
spi_set_operation_byte()
{
  spi_write(SPI_WRSR);
  spi_write(0x00);
}

static inline void
spi_set_operation_page()
{
  spi_write(SPI_WRSR);
  spi_write(0x80);
}

static inline void
spi_set_operation_seq()
{
  spi_write(SPI_WRSR);
  spi_write(0x40);
}

static void
spi_write_byte(uint16_t addr, uint8_t data)
{
  mkm_chip_select(1);
  spi_write(SPI_WRITE);
  spi_write(addr & 0xff00);
  spi_write(addr & 0x00ff);
  spi_write(data);
  mkm_chip_select(0);
}

static uint8_t
spi_read_byte(uint16_t addr)
{
  mkm_chip_select(1);
  spi_write(SPI_READ);
  spi_write(addr & 0xff00);
  spi_write(addr & 0x00ff);
  uint8_t data = spi_read();
  mkm_chip_select(0);
  return data;
}

static inline int
panic_p()
{
  return !bit_is_set(AVR_PANIC_PIN, AVR_PANIC_BIT);
}


static inline void
init_ports()
{
  /* Configure all PORTA pins except the tamper detection pin to
     outputs. */
  DDRA = 0xff & ~_BV(AVR_PANIC_BIT);
}

int
main()
{
  init_ports();

  int i, j = 0, wait;
  uint8_t mkm_val = 0;
  while (1)
    {
      if (panic_p())
        {
          spi_setup(1);
          mkm_grab();

          spi_write_byte(0, spi_read_byte(0) + 1);
          mkm_val = spi_read_byte(0);
          AVR_LED_PORT = (AVR_LED_PORT & 0xf0) | (mkm_val & 0x0f);

          wait = 32000;
        }
      else
        {
          mkm_release();
          spi_setup(0);

          if ((j++ & 1) == 0)
            AVR_LED_PORT = (AVR_LED_PORT & 0xf0) | 0xa;
          else
            AVR_LED_PORT = (AVR_LED_PORT & 0xf0) | 0x5;

          wait = 16000;
        }

      for (i = 0; i < wait; i++);
    }

  return 0;
}