diff --git a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino index feb6dd6..a6420d1 100644 --- a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino +++ b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino @@ -1,7 +1,7 @@ // Default sensor sketch for MySensor Micro module // Act as a temperature / humidity sensor by default. // -// If A1 is held low while powering on, it will clear eeprom (and thereby the stored nodeid) +// If A0 is held low while powering on, it will enter testmode, which verifies all on-board peripherals // // Battery voltage is repported as child sensorId 199, as well as battery percentage @@ -10,7 +10,10 @@ #include #include #include +#include #include +#include +#include // Define a static node address, remove if you want auto address assignment //#define NODE_ADDRESS 3 @@ -21,8 +24,13 @@ #define CHILD_ID_BATT 199 //Pin definitions -#define RESET_CFG_PIN A1 +#define TEST_PIN A0 #define LED_PIN A2 +#define ATSHA204_PIN 17 // A3 + +const int sha204Pin = ATSHA204_PIN; +atsha204Class sha204(sha204Pin); + #define MEASURE_INTERVAL 60000 @@ -30,6 +38,8 @@ #define FORCE_TRANSMIT_INTERVAL 30 SI7021 humiditySensor; +SPIFlash flash(8, 0x1F65); + MySensor gw; // Sensor messages @@ -51,12 +61,14 @@ void setup() { pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); - // First check if we should boot into clear eeprom mode - pinMode(RESET_CFG_PIN, INPUT); - digitalWrite(RESET_CFG_PIN, HIGH); // Enable pullup - if (!digitalRead(RESET_CFG_PIN)) resetEEP(); - digitalWrite(RESET_CFG_PIN, LOW); + Serial.begin(115200); + // First check if we should boot into test mode + + pinMode(TEST_PIN,INPUT); + digitalWrite(TEST_PIN, HIGH); // Enable pullup + if (!digitalRead(TEST_PIN)) testMode(); + digitalWrite(TEST_PIN,LOW); digitalWrite(LED_PIN, HIGH); #ifdef NODE_ADDRESS @@ -75,7 +87,7 @@ void setup() { gw.present(CHILD_ID_HUM,S_HUM); gw.present(CHILD_ID_BATT, S_POWER); - switchClock(1< SI7021 : ")); + delay(100); + + if (humiditySensor.begin()) + { + Serial.println(F("ok!")); + tests ++; + } + else + { + Serial.println(F("failed!")); + } + delay(100); + + Serial.print(F("-> Flash : ")); +delay(100); + if (flash.initialize()) + { + Serial.println(F("ok!")); + tests ++; + } + else + { + Serial.println(F("failed!")); + } +delay(100); + + Serial.println(F("-> SHA204 : ")); + ret_code = sha204.sha204c_wakeup(rx_buffer); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Failed to wake device. Response: ")); Serial.println(ret_code, HEX); + } + + if (ret_code == SHA204_SUCCESS) + { + ret_code = sha204.getSerialNumber(rx_buffer); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Failed to obtain device serial number. Response: ")); Serial.println(ret_code, HEX); + } + else + { + Serial.print(F("Device serial: ")); + for (int i=0; i<9; i++) + { + if (rx_buffer[i] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[i], HEX); + } + Serial.println(); + tests ++; + } + + } + + + Serial.println(F("Test finished")); + + if (tests == 3) + { + Serial.println(F("Selftest ok!")); + while (1) // Blink OK pattern! + { + digitalWrite(LED_PIN, HIGH); + delay(800); + digitalWrite(LED_PIN, LOW); + delay(200); + } + } + else + { + Serial.println(F("----> Selftest failed!")); + while (1) // Blink FAILED pattern! Rappidly blinking.. + { + digitalWrite(LED_PIN, HIGH); + delay(100); + digitalWrite(LED_PIN, LOW); + delay(100); + } + } +} diff --git a/libraries/SPIFlash/SPIFlash.cpp b/libraries/SPIFlash/SPIFlash.cpp index 03d6a1a..bad4cdf 100644 --- a/libraries/SPIFlash/SPIFlash.cpp +++ b/libraries/SPIFlash/SPIFlash.cpp @@ -6,6 +6,9 @@ * Minimal modifications should allow chips that have different page size but modifications * DEPENDS ON: Arduino SPI library * + * Updated Jan. 5, 2015, TomWS1, modified writeBytes to allow blocks > 256 bytes and handle page misalignment. + * Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above) + * * This file is free software; you can redistribute it and/or modify * it under the terms of either the GNU General Public License version 2 * or the GNU Lesser General Public License version 2.1, both as @@ -32,15 +35,22 @@ SPIFlash::SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID) { /// Select the flash chip void SPIFlash::select() { - noInterrupts(); //save current SPI settings +#ifndef SPI_HAS_TRANSACTION + _SREG = SREG; + noInterrupts(); +#endif _SPCR = SPCR; _SPSR = SPSR; - //set FLASH chip SPI settings + +#ifdef SPI_HAS_TRANSACTION + SPI.beginTransaction(_settings); +#else + // set FLASH SPI settings SPI.setDataMode(SPI_MODE0); SPI.setBitOrder(MSBFIRST); - SPI.setClockDivider(SPI_CLOCK_DIV4); //decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present - SPI.begin(); + SPI.setClockDivider(SPI_CLOCK_DIV4); // decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present +#endif digitalWrite(_slaveSelectPin, LOW); } @@ -48,9 +58,13 @@ void SPIFlash::select() { void SPIFlash::unselect() { digitalWrite(_slaveSelectPin, HIGH); //restore SPI settings to what they were before talking to the FLASH chip +#ifdef SPI_HAS_TRANSACTION + SPI.endTransaction(); +#else + SREG = _SREG; // restore interrupts IFF they were enabled +#endif SPCR = _SPCR; SPSR = _SPSR; - interrupts(); } /// setup SPI, read device ID etc... @@ -58,7 +72,10 @@ boolean SPIFlash::initialize() { _SPCR = SPCR; _SPSR = SPSR; + digitalWrite(_slaveSelectPin, HIGH); pinMode(_slaveSelectPin, OUTPUT); + SPI.begin(); + _settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); unselect(); wakeup(); @@ -185,22 +202,33 @@ void SPIFlash::writeByte(long addr, uint8_t byt) { unselect(); } -/// write 1-256 bytes to flash memory +/// write multiple bytes to flash memory (up to 64K) /// WARNING: you can only write to previously erased memory locations (see datasheet) /// use the block erase commands to first clear memory (write 0xFFs) -/// WARNING: if you write beyond a page boundary (or more than 256bytes), -/// the bytes will wrap around and start overwriting at the beginning of that same page -/// see datasheet for more details +/// This version handles both page alignment and data blocks larger than 256 bytes. +/// void SPIFlash::writeBytes(long addr, const void* buf, uint16_t len) { - command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program - SPI.transfer(addr >> 16); - SPI.transfer(addr >> 8); - SPI.transfer(addr); - for (uint16_t i = 0; i < len; i++) - SPI.transfer(((byte*) buf)[i]); - unselect(); + uint16_t n; + uint16_t maxBytes = 256-(addr%256); // force the first set of bytes to stay within the first page + uint16_t offset = 0; + while (len>0) + { + n = (len<=maxBytes) ? len : maxBytes; + command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + for (uint16_t i = 0; i < n; i++) + SPI.transfer(((byte*) buf)[offset + i]); + unselect(); + addr+=n; // adjust the addresses and remaining bytes by what we've just transferred. + offset +=n; + len -= n; + maxBytes = 256; // now we can do up to 256 bytes per loop + } } + /// erase entire flash memory array /// may take several seconds depending on size, but is non blocking /// so you may wait for this to complete using busy() or continue doing diff --git a/libraries/SPIFlash/SPIFlash.h b/libraries/SPIFlash/SPIFlash.h index f0c071a..8f530b7 100644 --- a/libraries/SPIFlash/SPIFlash.h +++ b/libraries/SPIFlash/SPIFlash.h @@ -1,11 +1,13 @@ /* * Copyright (c) 2013 by Felix Rusu * SPI Flash memory library for arduino/moteino. - * This works with 256byte/page SPI flash memory - * For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes) + * This works with 256uint8_t/page SPI flash memory + * For instance a 4MBit (512Kuint8_t) flash chip will have 2048 pages: 256*2048 = 524288 uint8_ts (512Kuint8_ts) * Minimal modifications should allow chips that have different page size but modifications * DEPENDS ON: Arduino SPI library * + * Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above) + * * This file is free software; you can redistribute it and/or modify * it under the terms of either the GNU General Public License version 2 * or the GNU Lesser General Public License version 2.1, both as @@ -56,34 +58,34 @@ // but no actual need to wait for completion (instead need to check the status register BUSY bit) #define SPIFLASH_STATUSREAD 0x05 // read status register #define SPIFLASH_STATUSWRITE 0x01 // write status register -#define SPIFLASH_ARRAYREAD 0x0B // read array (fast, need to add 1 dummy byte after 3 address bytes) +#define SPIFLASH_ARRAYREAD 0x0B // read array (fast, need to add 1 dummy uint8_t after 3 address uint8_ts) #define SPIFLASH_ARRAYREADLOWFREQ 0x03 // read array (low frequency) #define SPIFLASH_SLEEP 0xB9 // deep power down #define SPIFLASH_WAKE 0xAB // deep power wake up -#define SPIFLASH_BYTEPAGEPROGRAM 0x02 // write (1 to 256bytes) -#define SPIFLASH_IDREAD 0x9F // read JEDEC manufacturer and device ID (2 bytes, specific bytes for each manufacturer and device) +#define SPIFLASH_BYTEPAGEPROGRAM 0x02 // write (1 to 256uint8_ts) +#define SPIFLASH_IDREAD 0x9F // read JEDEC manufacturer and device ID (2 uint8_ts, specific uint8_ts for each manufacturer and device) // Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf) // Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf) #define SPIFLASH_MACREAD 0x4B // read unique ID number (MAC) class SPIFlash { public: - static byte UNIQUEID[8]; - SPIFlash(byte slaveSelectPin, uint16_t jedecID=0); + static uint8_t UNIQUEID[8]; + SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID=0); boolean initialize(); - void command(byte cmd, boolean isWrite=false); - byte readStatus(); - byte readByte(long addr); + void command(uint8_t cmd, boolean isWrite=false); + uint8_t readStatus(); + uint8_t readByte(long addr); void readBytes(long addr, void* buf, word len); - void writeByte(long addr, byte byt); + void writeByte(long addr, uint8_t byt); void writeBytes(long addr, const void* buf, uint16_t len); boolean busy(); void chipErase(); void blockErase4K(long address); void blockErase32K(long address); word readDeviceId(); - byte* readUniqueId(); + uint8_t* readUniqueId(); void sleep(); void wakeup(); @@ -91,10 +93,16 @@ public: protected: void select(); void unselect(); - byte _slaveSelectPin; + uint8_t _slaveSelectPin; uint16_t _jedecID; - byte _SPCR; - byte _SPSR; + uint8_t _SPCR; + uint8_t _SPSR; + uint8_t _SREG; + +#ifdef SPI_HAS_TRANSACTION + SPISettings _settings; +#endif + }; #endif \ No newline at end of file diff --git a/libraries/sha204/sha204_lib_return_codes.h b/libraries/sha204/sha204_lib_return_codes.h new file mode 100644 index 0000000..db61120 --- /dev/null +++ b/libraries/sha204/sha204_lib_return_codes.h @@ -0,0 +1,48 @@ +// ---------------------------------------------------------------------------- +// ATMEL Microcontroller Software Support - Colorado Springs, CO - +// ---------------------------------------------------------------------------- +// DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE +// DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// ---------------------------------------------------------------------------- + +/** \file + * \brief SHA204 Library Return Code Definitions + * \author Atmel Crypto Products + * \date September 27, 2010 + */ + +#ifndef SHA204_LIB_RETURN_CODES_H +# define SHA204_LIB_RETURN_CODES_H + +#include // data type definitions + +/** \todo Use same values for same meanings for SHA204 and AES132. + * */ + +#define SHA204_SUCCESS ((uint8_t) 0x00) //!< Function succeeded. +#define SHA204_PARSE_ERROR ((uint8_t) 0xD2) //!< response status byte indicates parsing error +#define SHA204_CMD_FAIL ((uint8_t) 0xD3) //!< response status byte indicates command execution error +#define SHA204_STATUS_CRC ((uint8_t) 0xD4) //!< response status byte indicates CRC error +#define SHA204_STATUS_UNKNOWN ((uint8_t) 0xD5) //!< response status byte is unknown +#define SHA204_FUNC_FAIL ((uint8_t) 0xE0) //!< Function could not execute due to incorrect condition / state. +#define SHA204_GEN_FAIL ((uint8_t) 0xE1) //!< unspecified error +#define SHA204_BAD_PARAM ((uint8_t) 0xE2) //!< bad argument (out of range, null pointer, etc.) +#define SHA204_INVALID_ID ((uint8_t) 0xE3) //!< invalid device id, id not set +#define SHA204_INVALID_SIZE ((uint8_t) 0xE4) //!< Count value is out of range or greater than buffer size. +#define SHA204_BAD_CRC ((uint8_t) 0xE5) //!< incorrect CRC received +#define SHA204_RX_FAIL ((uint8_t) 0xE6) //!< Timed out while waiting for response. Number of bytes received is > 0. +#define SHA204_RX_NO_RESPONSE ((uint8_t) 0xE7) //!< Not an error while the Command layer is polling for a command response. +#define SHA204_RESYNC_WITH_WAKEUP ((uint8_t) 0xE8) //!< re-synchronization succeeded, but only after generating a Wake-up + +#define SHA204_COMM_FAIL ((uint8_t) 0xF0) //!< Communication with device failed. Same as in hardware dependent modules. +#define SHA204_TIMEOUT ((uint8_t) 0xF1) //!< Timed out while waiting for response. Number of bytes received is 0. + +#endif diff --git a/libraries/sha204/sha204_library.cpp b/libraries/sha204/sha204_library.cpp new file mode 100644 index 0000000..8e43890 --- /dev/null +++ b/libraries/sha204/sha204_library.cpp @@ -0,0 +1,819 @@ +#include "Arduino.h" +#include "sha204_library.h" +#include "sha204_lib_return_codes.h" + + +// atsha204Class Constructor +// Feed this function the Arduino-ized pin number you want to assign to the ATSHA204's SDA pin +// This will find the DDRX, PORTX, and PINX registrs it'll need to point to to control that pin +// As well as the bit value for each of those registers +atsha204Class::atsha204Class(uint8_t pin) +{ + device_pin = digitalPinToBitMask(pin); // Find the bit value of the pin + uint8_t port = digitalPinToPort(pin); // temoporarily used to get the next three registers + + // Point to data direction register port of pin + device_port_DDR = portModeRegister(port); + // Point to output register of pin + device_port_OUT = portOutputRegister(port); + // Point to input register of pin + device_port_IN = portInputRegister(port); +} + +/* Puts a the ATSHA204's unique, 4-byte serial number in the response array + returns an SHA204 Return code */ +uint8_t atsha204Class::getSerialNumber(uint8_t * response) +{ + uint8_t readCommand[READ_COUNT]; + uint8_t readResponse[READ_4_RSP_SIZE]; + + /* read from bytes 0->3 of config zone */ + uint8_t returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03); + if (!returnCode) // should return 0 if successful + { + for (int i=0; i<4; i++) // store bytes 0-3 into respones array + response[i] = readResponse[SHA204_BUFFER_POS_DATA+i]; + + /* read from bytes 8->11 of config zone */ + returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN47); + + for (int i=4; i<8; i++) // store bytes 4-7 of SN into response array + response[i] = readResponse[SHA204_BUFFER_POS_DATA+(i-4)]; + + if (!returnCode) + { /* Finally if last two reads were successful, read byte 8 of the SN */ + returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN8); + response[8] = readResponse[SHA204_BUFFER_POS_DATA]; // Byte 8 of SN should always be 0xEE + } + } + + return returnCode; +} + +/* Calculates CRC16 value of provided data (and optionally including provided existing CRC16 data) + returns the calculated CRC16 value */ +uint16_t atsha204Class::calculateAndUpdateCrc(uint8_t length, uint8_t *data, uint16_t current_crc) +{ + uint8_t counter; + uint16_t crc_register = current_crc; + uint16_t polynom = 0x8005; + uint8_t shift_register; + uint8_t data_bit, crc_bit; + + for (counter = 0; counter < length; counter++) + { + for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) + { + data_bit = (data[counter] & shift_register) ? 1 : 0; + crc_bit = crc_register >> 15; + + // Shift CRC to the left by 1. + crc_register <<= 1; + + if ((data_bit ^ crc_bit) != 0) + crc_register ^= polynom; + } + } + return crc_register; +} + +/* SWI bit bang functions */ + +void atsha204Class::swi_set_signal_pin(uint8_t is_high) +{ + *device_port_DDR |= device_pin; + + if (is_high) + *device_port_OUT |= device_pin; + else + *device_port_OUT &= ~device_pin; +} + +uint8_t atsha204Class::swi_send_bytes(uint8_t count, uint8_t *buffer) +{ + uint8_t i, bit_mask; + + // Disable interrupts while sending. + noInterrupts(); //swi_disable_interrupts(); + + // Set signal pin as output. + *device_port_OUT |= device_pin; + *device_port_DDR |= device_pin; + + // Wait turn around time. + delayMicroseconds(RX_TX_DELAY); //RX_TX_DELAY; + + for (i = 0; i < count; i++) + { + for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) + { + if (bit_mask & buffer[i]) + { + *device_port_OUT &= ~device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT |= device_pin; + delayMicroseconds(7*BIT_DELAY); //BIT_DELAY_7; + } + else + { + // Send a zero bit. + *device_port_OUT &= ~device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT |= device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT &= ~device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT |= device_pin; + delayMicroseconds(5*BIT_DELAY); //BIT_DELAY_5; + } + } + } + interrupts(); //swi_enable_interrupts(); + return SWI_FUNCTION_RETCODE_SUCCESS; +} + +uint8_t atsha204Class::swi_send_byte(uint8_t value) +{ + return swi_send_bytes(1, &value); +} + +uint8_t atsha204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer) +{ + uint8_t status = SWI_FUNCTION_RETCODE_SUCCESS; + uint8_t i; + uint8_t bit_mask; + uint8_t pulse_count; + uint8_t timeout_count; + + // Disable interrupts while receiving. + noInterrupts(); //swi_disable_interrupts(); + + // Configure signal pin as input. + *device_port_DDR &= ~device_pin; + + // Receive bits and store in buffer. + for (i = 0; i < count; i++) + { + for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) + { + pulse_count = 0; + + // Make sure that the variable below is big enough. + // Change it to uint16_t if 255 is too small, but be aware that + // the loop resolution decreases on an 8-bit controller in that case. + timeout_count = START_PULSE_TIME_OUT; + + // Detect start bit. + while (--timeout_count > 0) + { + // Wait for falling edge. + if ((*device_port_IN & device_pin) == 0) + break; + } + + if (timeout_count == 0) + { + status = SWI_FUNCTION_RETCODE_TIMEOUT; + break; + } + + do + { + // Wait for rising edge. + if ((*device_port_IN & device_pin) != 0) + { + // For an Atmel microcontroller this might be faster than "pulse_count++". + pulse_count = 1; + break; + } + } while (--timeout_count > 0); + + if (pulse_count == 0) + { + status = SWI_FUNCTION_RETCODE_TIMEOUT; + break; + } + + // Trying to measure the time of start bit and calculating the timeout + // for zero bit detection is not accurate enough for an 8 MHz 8-bit CPU. + // So let's just wait the maximum time for the falling edge of a zero bit + // to arrive after we have detected the rising edge of the start bit. + timeout_count = ZERO_PULSE_TIME_OUT; + + // Detect possible edge indicating zero bit. + do + { + if ((*device_port_IN & device_pin) == 0) + { + // For an Atmel microcontroller this might be faster than "pulse_count++". + pulse_count = 2; + break; + } + } while (--timeout_count > 0); + + // Wait for rising edge of zero pulse before returning. Otherwise we might interpret + // its rising edge as the next start pulse. + if (pulse_count == 2) + { + do + { + if ((*device_port_IN & device_pin) != 0) + break; + } while (timeout_count-- > 0); + } + + // Update byte at current buffer index. + else + buffer[i] |= bit_mask; // received "one" bit + } + + if (status != SWI_FUNCTION_RETCODE_SUCCESS) + break; + } + interrupts(); //swi_enable_interrupts(); + + if (status == SWI_FUNCTION_RETCODE_TIMEOUT) + { + if (i > 0) + // Indicate that we timed out after having received at least one byte. + status = SWI_FUNCTION_RETCODE_RX_FAIL; + } + return status; +} + +/* Physical functions */ + +uint8_t atsha204Class::sha204p_wakeup() +{ + swi_set_signal_pin(0); + delayMicroseconds(10*SHA204_WAKEUP_PULSE_WIDTH); + swi_set_signal_pin(1); + delay(SHA204_WAKEUP_DELAY); + + return SHA204_SUCCESS; +} + +uint8_t atsha204Class::sha204p_sleep() +{ + return swi_send_byte(SHA204_SWI_FLAG_SLEEP); +} + +uint8_t atsha204Class::sha204p_resync(uint8_t size, uint8_t *response) +{ + delay(SHA204_SYNC_TIMEOUT); + return sha204p_receive_response(size, response); +} + +uint8_t atsha204Class::sha204p_receive_response(uint8_t size, uint8_t *response) +{ + uint8_t count_byte; + uint8_t i; + uint8_t ret_code; + + for (i = 0; i < size; i++) + response[i] = 0; + + (void) swi_send_byte(SHA204_SWI_FLAG_TX); + + ret_code = swi_receive_bytes(size, response); + if (ret_code == SWI_FUNCTION_RETCODE_SUCCESS || ret_code == SWI_FUNCTION_RETCODE_RX_FAIL) + { + count_byte = response[SHA204_BUFFER_POS_COUNT]; + if ((count_byte < SHA204_RSP_SIZE_MIN) || (count_byte > size)) + return SHA204_INVALID_SIZE; + + return SHA204_SUCCESS; + } + + // Translate error so that the Communication layer + // can distinguish between a real error or the + // device being busy executing a command. + if (ret_code == SWI_FUNCTION_RETCODE_TIMEOUT) + return SHA204_RX_NO_RESPONSE; + else + return SHA204_RX_FAIL; +} + +uint8_t atsha204Class::sha204p_send_command(uint8_t count, uint8_t * command) +{ + uint8_t ret_code = swi_send_byte(SHA204_SWI_FLAG_CMD); + if (ret_code != SWI_FUNCTION_RETCODE_SUCCESS) + return SHA204_COMM_FAIL; + + return swi_send_bytes(count, command); +} + +/* Communication functions */ + +uint8_t atsha204Class::sha204c_wakeup(uint8_t *response) +{ + uint8_t ret_code = sha204p_wakeup(); + if (ret_code != SHA204_SUCCESS) + return ret_code; + + ret_code = sha204p_receive_response(SHA204_RSP_SIZE_MIN, response); + if (ret_code != SHA204_SUCCESS) + return ret_code; + + // Verify status response. + if (response[SHA204_BUFFER_POS_COUNT] != SHA204_RSP_SIZE_MIN) + ret_code = SHA204_INVALID_SIZE; + else if (response[SHA204_BUFFER_POS_STATUS] != SHA204_STATUS_BYTE_WAKEUP) + ret_code = SHA204_COMM_FAIL; + else + { + if ((response[SHA204_RSP_SIZE_MIN - SHA204_CRC_SIZE] != 0x33) + || (response[SHA204_RSP_SIZE_MIN + 1 - SHA204_CRC_SIZE] != 0x43)) + ret_code = SHA204_BAD_CRC; + } + if (ret_code != SHA204_SUCCESS) + delay(SHA204_COMMAND_EXEC_MAX); + + return ret_code; +} + +uint8_t atsha204Class::sha204c_resync(uint8_t size, uint8_t *response) +{ + // Try to re-synchronize without sending a Wake token + // (step 1 of the re-synchronization process). + uint8_t ret_code = sha204p_resync(size, response); + if (ret_code == SHA204_SUCCESS) + return ret_code; + + // We lost communication. Send a Wake pulse and try + // to receive a response (steps 2 and 3 of the + // re-synchronization process). + (void) sha204p_sleep(); + ret_code = sha204c_wakeup(response); + + // Translate a return value of success into one + // that indicates that the device had to be woken up + // and might have lost its TempKey. + return (ret_code == SHA204_SUCCESS ? SHA204_RESYNC_WITH_WAKEUP : ret_code); +} + +uint8_t atsha204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout) +{ + uint8_t ret_code = SHA204_FUNC_FAIL; + uint8_t ret_code_resync; + uint8_t n_retries_send; + uint8_t n_retries_receive; + uint8_t i; + uint8_t status_byte; + uint8_t count = tx_buffer[SHA204_BUFFER_POS_COUNT]; + uint8_t count_minus_crc = count - SHA204_CRC_SIZE; + uint16_t execution_timeout_us = (uint16_t) (execution_timeout * 1000) + SHA204_RESPONSE_TIMEOUT; + volatile uint16_t timeout_countdown; + + // Append CRC. + sha204c_calculate_crc(count_minus_crc, tx_buffer, tx_buffer + count_minus_crc); + + // Retry loop for sending a command and receiving a response. + n_retries_send = SHA204_RETRY_COUNT + 1; + + while ((n_retries_send-- > 0) && (ret_code != SHA204_SUCCESS)) + { + // Send command. + ret_code = sha204p_send_command(count, tx_buffer); + if (ret_code != SHA204_SUCCESS) + { + if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) + return ret_code; // The device seems to be dead in the water. + else + continue; + } + + // Wait minimum command execution time and then start polling for a response. + delay(execution_delay); + + // Retry loop for receiving a response. + n_retries_receive = SHA204_RETRY_COUNT + 1; + while (n_retries_receive-- > 0) + { + // Reset response buffer. + for (i = 0; i < rx_size; i++) + rx_buffer[i] = 0; + + // Poll for response. + timeout_countdown = execution_timeout_us; + do + { + ret_code = sha204p_receive_response(rx_size, rx_buffer); + timeout_countdown -= SHA204_RESPONSE_TIMEOUT; + } + while ((timeout_countdown > SHA204_RESPONSE_TIMEOUT) && (ret_code == SHA204_RX_NO_RESPONSE)); + + if (ret_code == SHA204_RX_NO_RESPONSE) + { + // We did not receive a response. Re-synchronize and send command again. + if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) + // The device seems to be dead in the water. + return ret_code; + else + break; + } + + // Check whether we received a valid response. + if (ret_code == SHA204_INVALID_SIZE) + { + // We see 0xFF for the count when communication got out of sync. + ret_code_resync = sha204c_resync(rx_size, rx_buffer); + if (ret_code_resync == SHA204_SUCCESS) + // We did not have to wake up the device. Try receiving response again. + continue; + if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) + // We could re-synchronize, but only after waking up the device. + // Re-send command. + break; + else + // We failed to re-synchronize. + return ret_code; + } + + // We received a response of valid size. + // Check the consistency of the response. + ret_code = sha204c_check_crc(rx_buffer); + if (ret_code == SHA204_SUCCESS) + { + // Received valid response. + if (rx_buffer[SHA204_BUFFER_POS_COUNT] > SHA204_RSP_SIZE_MIN) + // Received non-status response. We are done. + return ret_code; + + // Received status response. + status_byte = rx_buffer[SHA204_BUFFER_POS_STATUS]; + + // Translate the three possible device status error codes + // into library return codes. + if (status_byte == SHA204_STATUS_BYTE_PARSE) + return SHA204_PARSE_ERROR; + if (status_byte == SHA204_STATUS_BYTE_EXEC) + return SHA204_CMD_FAIL; + if (status_byte == SHA204_STATUS_BYTE_COMM) + { + // In case of the device status byte indicating a communication + // error this function exits the retry loop for receiving a response + // and enters the overall retry loop + // (send command / receive response). + ret_code = SHA204_STATUS_CRC; + break; + } + + // Received status response from CheckMAC, DeriveKey, GenDig, + // Lock, Nonce, Pause, UpdateExtra, or Write command. + return ret_code; + } + + else + { + // Received response with incorrect CRC. + ret_code_resync = sha204c_resync(rx_size, rx_buffer); + if (ret_code_resync == SHA204_SUCCESS) + // We did not have to wake up the device. Try receiving response again. + continue; + if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) + // We could re-synchronize, but only after waking up the device. + // Re-send command. + break; + else + // We failed to re-synchronize. + return ret_code; + } // block end of check response consistency + + } // block end of receive retry loop + + } // block end of send and receive retry loop + + return ret_code; +} + + +/* Marshaling functions */ + +uint8_t atsha204Class::sha204m_random(uint8_t * tx_buffer, uint8_t * rx_buffer, uint8_t mode) +{ + if (!tx_buffer || !rx_buffer || (mode > RANDOM_NO_SEED_UPDATE)) + return SHA204_BAD_PARAM; + + tx_buffer[SHA204_COUNT_IDX] = RANDOM_COUNT; + tx_buffer[SHA204_OPCODE_IDX] = SHA204_RANDOM; + tx_buffer[RANDOM_MODE_IDX] = mode & RANDOM_SEED_UPDATE; + + tx_buffer[RANDOM_PARAM2_IDX] = + tx_buffer[RANDOM_PARAM2_IDX + 1] = 0; + + return sha204c_send_and_receive(&tx_buffer[0], RANDOM_RSP_SIZE, &rx_buffer[0], RANDOM_DELAY, RANDOM_EXEC_MAX - RANDOM_DELAY); +} + +uint8_t atsha204Class::sha204m_dev_rev(uint8_t *tx_buffer, uint8_t *rx_buffer) +{ + if (!tx_buffer || !rx_buffer) + return SHA204_BAD_PARAM; + + tx_buffer[SHA204_COUNT_IDX] = DEVREV_COUNT; + tx_buffer[SHA204_OPCODE_IDX] = SHA204_DEVREV; + + // Parameters are 0. + tx_buffer[DEVREV_PARAM1_IDX] = + tx_buffer[DEVREV_PARAM2_IDX] = + tx_buffer[DEVREV_PARAM2_IDX + 1] = 0; + + return sha204c_send_and_receive(&tx_buffer[0], DEVREV_RSP_SIZE, &rx_buffer[0], + DEVREV_DELAY, DEVREV_EXEC_MAX - DEVREV_DELAY); +} + +uint8_t atsha204Class::sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address) +{ + uint8_t rx_size; + + if (!tx_buffer || !rx_buffer || ((zone & ~READ_ZONE_MASK) != 0) + || ((zone & READ_ZONE_MODE_32_BYTES) && (zone == SHA204_ZONE_OTP))) + return SHA204_BAD_PARAM; + + address >>= 2; + if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_CONFIG) + { + if (address > SHA204_ADDRESS_MASK_CONFIG) + return SHA204_BAD_PARAM; + } + else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_OTP) + { + if (address > SHA204_ADDRESS_MASK_OTP) + return SHA204_BAD_PARAM; + } + else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_DATA) + { + if (address > SHA204_ADDRESS_MASK) + return SHA204_BAD_PARAM; + } + + tx_buffer[SHA204_COUNT_IDX] = READ_COUNT; + tx_buffer[SHA204_OPCODE_IDX] = SHA204_READ; + tx_buffer[READ_ZONE_IDX] = zone; + tx_buffer[READ_ADDR_IDX] = (uint8_t) (address & SHA204_ADDRESS_MASK); + tx_buffer[READ_ADDR_IDX + 1] = 0; + + rx_size = (zone & SHA204_ZONE_COUNT_FLAG) ? READ_32_RSP_SIZE : READ_4_RSP_SIZE; + + return sha204c_send_and_receive(&tx_buffer[0], rx_size, &rx_buffer[0], READ_DELAY, READ_EXEC_MAX - READ_DELAY); +} + +uint8_t atsha204Class::sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2, + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer) +{ + uint8_t poll_delay, poll_timeout, response_size; + uint8_t *p_buffer; + uint8_t len; + + uint8_t ret_code = sha204m_check_parameters(op_code, param1, param2, + datalen1, data1, datalen2, data2, datalen3, data3, + tx_size, tx_buffer, rx_size, rx_buffer); + if (ret_code != SHA204_SUCCESS) + return ret_code; + + // Supply delays and response size. + switch (op_code) + { + case SHA204_CHECKMAC: + poll_delay = CHECKMAC_DELAY; + poll_timeout = CHECKMAC_EXEC_MAX - CHECKMAC_DELAY; + response_size = CHECKMAC_RSP_SIZE; + break; + + case SHA204_DERIVE_KEY: + poll_delay = DERIVE_KEY_DELAY; + poll_timeout = DERIVE_KEY_EXEC_MAX - DERIVE_KEY_DELAY; + response_size = DERIVE_KEY_RSP_SIZE; + break; + + case SHA204_DEVREV: + poll_delay = DEVREV_DELAY; + poll_timeout = DEVREV_EXEC_MAX - DEVREV_DELAY; + response_size = DEVREV_RSP_SIZE; + break; + + case SHA204_GENDIG: + poll_delay = GENDIG_DELAY; + poll_timeout = GENDIG_EXEC_MAX - GENDIG_DELAY; + response_size = GENDIG_RSP_SIZE; + break; + + case SHA204_HMAC: + poll_delay = HMAC_DELAY; + poll_timeout = HMAC_EXEC_MAX - HMAC_DELAY; + response_size = HMAC_RSP_SIZE; + break; + + case SHA204_LOCK: + poll_delay = LOCK_DELAY; + poll_timeout = LOCK_EXEC_MAX - LOCK_DELAY; + response_size = LOCK_RSP_SIZE; + break; + + case SHA204_MAC: + poll_delay = MAC_DELAY; + poll_timeout = MAC_EXEC_MAX - MAC_DELAY; + response_size = MAC_RSP_SIZE; + break; + + case SHA204_NONCE: + poll_delay = NONCE_DELAY; + poll_timeout = NONCE_EXEC_MAX - NONCE_DELAY; + response_size = param1 == NONCE_MODE_PASSTHROUGH + ? NONCE_RSP_SIZE_SHORT : NONCE_RSP_SIZE_LONG; + break; + + case SHA204_PAUSE: + poll_delay = PAUSE_DELAY; + poll_timeout = PAUSE_EXEC_MAX - PAUSE_DELAY; + response_size = PAUSE_RSP_SIZE; + break; + + case SHA204_RANDOM: + poll_delay = RANDOM_DELAY; + poll_timeout = RANDOM_EXEC_MAX - RANDOM_DELAY; + response_size = RANDOM_RSP_SIZE; + break; + + case SHA204_READ: + poll_delay = READ_DELAY; + poll_timeout = READ_EXEC_MAX - READ_DELAY; + response_size = (param1 & SHA204_ZONE_COUNT_FLAG) + ? READ_32_RSP_SIZE : READ_4_RSP_SIZE; + break; + + case SHA204_UPDATE_EXTRA: + poll_delay = UPDATE_DELAY; + poll_timeout = UPDATE_EXEC_MAX - UPDATE_DELAY; + response_size = UPDATE_RSP_SIZE; + break; + + case SHA204_WRITE: + poll_delay = WRITE_DELAY; + poll_timeout = WRITE_EXEC_MAX - WRITE_DELAY; + response_size = WRITE_RSP_SIZE; + break; + + default: + poll_delay = 0; + poll_timeout = SHA204_COMMAND_EXEC_MAX; + response_size = rx_size; + } + + // Assemble command. + len = datalen1 + datalen2 + datalen3 + SHA204_CMD_SIZE_MIN; + p_buffer = tx_buffer; + *p_buffer++ = len; + *p_buffer++ = op_code; + *p_buffer++ = param1; + *p_buffer++ = param2 & 0xFF; + *p_buffer++ = param2 >> 8; + + if (datalen1 > 0) { + memcpy(p_buffer, data1, datalen1); + p_buffer += datalen1; + } + if (datalen2 > 0) { + memcpy(p_buffer, data2, datalen2); + p_buffer += datalen2; + } + if (datalen3 > 0) { + memcpy(p_buffer, data3, datalen3); + p_buffer += datalen3; + } + + sha204c_calculate_crc(len - SHA204_CRC_SIZE, tx_buffer, p_buffer); + + // Send command and receive response. + return sha204c_send_and_receive(&tx_buffer[0], response_size, + &rx_buffer[0], poll_delay, poll_timeout); +} + +uint8_t atsha204Class::sha204m_check_parameters(uint8_t op_code, uint8_t param1, uint16_t param2, + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer) +{ +#ifdef SHA204_CHECK_PARAMETERS + + uint8_t len = datalen1 + datalen2 + datalen3 + SHA204_CMD_SIZE_MIN; + if (!tx_buffer || tx_size < len || rx_size < SHA204_RSP_SIZE_MIN || !rx_buffer) + return SHA204_BAD_PARAM; + + if ((datalen1 > 0 && !data1) || (datalen2 > 0 && !data2) || (datalen3 > 0 && !data3)) + return SHA204_BAD_PARAM; + + // Check parameters depending on op-code. + switch (op_code) + { + case SHA204_CHECKMAC: + if ( + // no null pointers allowed + !data1 || !data2 + // No reserved bits should be set. + || (param1 | CHECKMAC_MODE_MASK) != CHECKMAC_MODE_MASK + // key_id > 15 not allowed + || param2 > SHA204_KEY_ID_MAX + ) + return SHA204_BAD_PARAM; + break; + + case SHA204_DERIVE_KEY: + if (param2 > SHA204_KEY_ID_MAX) + return SHA204_BAD_PARAM; + break; + + case SHA204_DEVREV: + break; + + case SHA204_GENDIG: + if ((param1 != GENDIG_ZONE_OTP) && (param1 != GENDIG_ZONE_DATA)) + return SHA204_BAD_PARAM; + break; + + case SHA204_HMAC: + if ((param1 & ~HMAC_MODE_MASK) != 0) + return SHA204_BAD_PARAM; + break; + + case SHA204_LOCK: + if (((param1 & ~LOCK_ZONE_MASK) != 0) + || ((param1 & LOCK_ZONE_NO_CRC) && (param2 != 0))) + return SHA204_BAD_PARAM; + break; + + case SHA204_MAC: + if (((param1 & ~MAC_MODE_MASK) != 0) + || (((param1 & MAC_MODE_BLOCK2_TEMPKEY) == 0) && !data1)) + return SHA204_BAD_PARAM; + break; + + case SHA204_NONCE: + if ( !data1 + || (param1 > NONCE_MODE_PASSTHROUGH) + || (param1 == NONCE_MODE_INVALID) + ) + return SHA204_BAD_PARAM; + break; + + case SHA204_PAUSE: + break; + + case SHA204_RANDOM: + if (param1 > RANDOM_NO_SEED_UPDATE) + return SHA204_BAD_PARAM; + break; + + case SHA204_READ: + if (((param1 & ~READ_ZONE_MASK) != 0) + || ((param1 & READ_ZONE_MODE_32_BYTES) && (param1 == SHA204_ZONE_OTP))) + return SHA204_BAD_PARAM; + break; + + case SHA204_TEMPSENSE: + break; + + case SHA204_UPDATE_EXTRA: + if (param1 > UPDATE_CONFIG_BYTE_86) + return SHA204_BAD_PARAM; + break; + + case SHA204_WRITE: + if (!data1 || ((param1 & ~WRITE_ZONE_MASK) != 0)) + return SHA204_BAD_PARAM; + break; + + default: + // unknown op-code + return SHA204_BAD_PARAM; + } + + return SHA204_SUCCESS; + +#else + return SHA204_SUCCESS; +#endif +} + +/* CRC Calculator and Checker */ + +void atsha204Class::sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc) +{ + uint16_t crc_register = 0; + + crc_register = calculateAndUpdateCrc(length, data, crc_register); + crc[0] = (uint8_t) (crc_register & 0x00FF); + crc[1] = (uint8_t) (crc_register >> 8); +} + +uint8_t atsha204Class::sha204c_check_crc(uint8_t *response) +{ + uint8_t crc[SHA204_CRC_SIZE]; + uint8_t count = response[SHA204_BUFFER_POS_COUNT]; + + count -= SHA204_CRC_SIZE; + sha204c_calculate_crc(count, response, crc); + + return (crc[0] == response[count] && crc[1] == response[count + 1]) + ? SHA204_SUCCESS : SHA204_BAD_CRC; +} diff --git a/libraries/sha204/sha204_library.h b/libraries/sha204/sha204_library.h new file mode 100644 index 0000000..3e2c9f0 --- /dev/null +++ b/libraries/sha204/sha204_library.h @@ -0,0 +1,321 @@ +#include "Arduino.h" + +#ifndef sha204_library_H +#define sha204_library_H + +/* bitbang_config.h */ + +#define PORT_ACCESS_TIME (630) //! time it takes to toggle the pin at CPU clock of 16 MHz (ns) +#define START_PULSE_WIDTH (4340) //! width of start pulse (ns) +#define BIT_DELAY (4) //! delay macro for width of one pulse (start pulse or zero pulse, in ns) +#define RX_TX_DELAY (15) //! turn around time when switching from receive to transmit +#define START_PULSE_TIME_OUT (255) //! This value is decremented while waiting for the falling edge of a start pulse. +#define ZERO_PULSE_TIME_OUT (26) //! This value is decremented while waiting for the falling edge of a zero pulse. + +/* swi_phys.h */ + +#define SWI_FUNCTION_RETCODE_SUCCESS ((uint8_t) 0x00) //!< Communication with device succeeded. +#define SWI_FUNCTION_RETCODE_TIMEOUT ((uint8_t) 0xF1) //!< Communication timed out. +#define SWI_FUNCTION_RETCODE_RX_FAIL ((uint8_t) 0xF9) //!< Communication failed after at least one byte was received. + +/* sha204_physical.h */ + +#define SHA204_RSP_SIZE_MIN ((uint8_t) 4) //!< minimum number of bytes in response +#define SHA204_RSP_SIZE_MAX ((uint8_t) 35) //!< maximum size of response packet +#define SHA204_BUFFER_POS_COUNT (0) //!< buffer index of count byte in command or response +#define SHA204_BUFFER_POS_DATA (1) //!< buffer index of data in response +#define SHA204_WAKEUP_PULSE_WIDTH (uint8_t) (6.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5) //! width of Wakeup pulse in 10 us units +#define SHA204_WAKEUP_DELAY (uint8_t) (3.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5) //! delay between Wakeup pulse and communication in ms + +/* sha204_swi.c */ +#define SHA204_SWI_FLAG_CMD ((uint8_t) 0x77) //!< flag preceding a command +#define SHA204_SWI_FLAG_TX ((uint8_t) 0x88) //!< flag requesting a response +#define SHA204_SWI_FLAG_IDLE ((uint8_t) 0xBB) //!< flag requesting to go into Idle mode +#define SHA204_SWI_FLAG_SLEEP ((uint8_t) 0xCC) //!< flag requesting to go into Sleep mode + +/* sha204_comm_marshaling.h */ +// command op-code definitions +#define SHA204_CHECKMAC ((uint8_t) 0x28) //!< CheckMac command op-code +#define SHA204_DERIVE_KEY ((uint8_t) 0x1C) //!< DeriveKey command op-code +#define SHA204_DEVREV ((uint8_t) 0x30) //!< DevRev command op-code +#define SHA204_GENDIG ((uint8_t) 0x15) //!< GenDig command op-code +#define SHA204_HMAC ((uint8_t) 0x11) //!< HMAC command op-code +#define SHA204_LOCK ((uint8_t) 0x17) //!< Lock command op-code +#define SHA204_MAC ((uint8_t) 0x08) //!< MAC command op-code +#define SHA204_NONCE ((uint8_t) 0x16) //!< Nonce command op-code +#define SHA204_PAUSE ((uint8_t) 0x01) //!< Pause command op-code +#define SHA204_RANDOM ((uint8_t) 0x1B) //!< Random command op-code +#define SHA204_READ ((uint8_t) 0x02) //!< Read command op-code +#define SHA204_UPDATE_EXTRA ((uint8_t) 0x20) //!< UpdateExtra command op-code +#define SHA204_WRITE ((uint8_t) 0x12) //!< Write command op-code + +// packet size definitions +#define SHA204_RSP_SIZE_VAL ((uint8_t) 7) //!< size of response packet containing four bytes of data + +// parameter range definitions +#define SHA204_KEY_ID_MAX ((uint8_t) 15) //!< maximum value for key id +#define SHA204_OTP_BLOCK_MAX ((uint8_t) 1) //!< maximum value for OTP block + +// definitions for command packet indexes common to all commands +#define SHA204_COUNT_IDX ( 0) //!< command packet index for count +#define SHA204_OPCODE_IDX ( 1) //!< command packet index for op-code +#define SHA204_PARAM1_IDX ( 2) //!< command packet index for first parameter +#define SHA204_PARAM2_IDX ( 3) //!< command packet index for second parameter +#define SHA204_DATA_IDX ( 5) //!< command packet index for second parameter + +// zone definitions +#define SHA204_ZONE_CONFIG ((uint8_t) 0x00) //!< Configuration zone +#define SHA204_ZONE_OTP ((uint8_t) 0x01) //!< OTP (One Time Programming) zone +#define SHA204_ZONE_DATA ((uint8_t) 0x02) //!< Data zone +#define SHA204_ZONE_MASK ((uint8_t) 0x03) //!< Zone mask +#define SHA204_ZONE_COUNT_FLAG ((uint8_t) 0x80) //!< Zone bit 7 set: Access 32 bytes, otherwise 4 bytes. +#define SHA204_ZONE_ACCESS_4 ((uint8_t) 4) //!< Read or write 4 bytes. +#define SHA204_ZONE_ACCESS_32 ((uint8_t) 32) //!< Read or write 32 bytes. +#define SHA204_ADDRESS_MASK_CONFIG ( 0x001F) //!< Address bits 5 to 7 are 0 for Configuration zone. +#define SHA204_ADDRESS_MASK_OTP ( 0x000F) //!< Address bits 4 to 7 are 0 for OTP zone. +#define SHA204_ADDRESS_MASK ( 0x007F) //!< Address bit 7 to 15 are always 0. + +// CheckMAC command definitions +#define CHECKMAC_MODE_IDX SHA204_PARAM1_IDX //!< CheckMAC command index for mode +#define CHECKMAC_KEYID_IDX SHA204_PARAM2_IDX //!< CheckMAC command index for key identifier +#define CHECKMAC_CLIENT_CHALLENGE_IDX SHA204_DATA_IDX //!< CheckMAC command index for client challenge +#define CHECKMAC_CLIENT_RESPONSE_IDX (37) //!< CheckMAC command index for client response +#define CHECKMAC_DATA_IDX (69) //!< CheckMAC command index for other data +#define CHECKMAC_COUNT (84) //!< CheckMAC command packet size +#define CHECKMAC_MODE_MASK ((uint8_t) 0x27) //!< CheckMAC mode bits 3, 4, 6, and 7 are 0. +#define CHECKMAC_CLIENT_CHALLENGE_SIZE (32) //!< CheckMAC size of client challenge +#define CHECKMAC_CLIENT_RESPONSE_SIZE (32) //!< CheckMAC size of client response +#define CHECKMAC_OTHER_DATA_SIZE (13) //!< CheckMAC size of "other data" + +// DeriveKey command definitions +#define DERIVE_KEY_RANDOM_IDX SHA204_PARAM1_IDX //!< DeriveKey command index for random bit +#define DERIVE_KEY_TARGETKEY_IDX SHA204_PARAM2_IDX //!< DeriveKey command index for target slot +#define DERIVE_KEY_MAC_IDX SHA204_DATA_IDX //!< DeriveKey command index for optional MAC +#define DERIVE_KEY_COUNT_SMALL SHA204_CMD_SIZE_MIN //!< DeriveKey command packet size without MAC +#define DERIVE_KEY_COUNT_LARGE (39) //!< DeriveKey command packet size with MAC +#define DERIVE_KEY_RANDOM_FLAG ((uint8_t) 4) //!< DeriveKey 1. parameter +#define DERIVE_KEY_MAC_SIZE (32) //!< DeriveKey MAC size + +// DevRev command definitions +#define DEVREV_PARAM1_IDX SHA204_PARAM1_IDX //!< DevRev command index for 1. parameter (ignored) +#define DEVREV_PARAM2_IDX SHA204_PARAM2_IDX //!< DevRev command index for 2. parameter (ignored) +#define DEVREV_COUNT SHA204_CMD_SIZE_MIN //!< DevRev command packet size + +// GenDig command definitions +#define GENDIG_ZONE_IDX SHA204_PARAM1_IDX //!< GenDig command index for zone +#define GENDIG_KEYID_IDX SHA204_PARAM2_IDX //!< GenDig command index for key id +#define GENDIG_DATA_IDX SHA204_DATA_IDX //!< GenDig command index for optional data +#define GENDIG_COUNT SHA204_CMD_SIZE_MIN //!< GenDig command packet size without "other data" +#define GENDIG_COUNT_DATA (11) //!< GenDig command packet size with "other data" +#define GENDIG_OTHER_DATA_SIZE (4) //!< GenDig size of "other data" +#define GENDIG_ZONE_CONFIG ((uint8_t) 0) //!< GenDig zone id config +#define GENDIG_ZONE_OTP ((uint8_t) 1) //!< GenDig zone id OTP +#define GENDIG_ZONE_DATA ((uint8_t) 2) //!< GenDig zone id data + +// HMAC command definitions +#define HMAC_MODE_IDX SHA204_PARAM1_IDX //!< HMAC command index for mode +#define HMAC_KEYID_IDX SHA204_PARAM2_IDX //!< HMAC command index for key id +#define HMAC_COUNT SHA204_CMD_SIZE_MIN //!< HMAC command packet size +#define HMAC_MODE_MASK ((uint8_t) 0x74) //!< HMAC mode bits 0, 1, 3, and 7 are 0. + +// Lock command definitions +#define LOCK_ZONE_IDX SHA204_PARAM1_IDX //!< Lock command index for zone +#define LOCK_SUMMARY_IDX SHA204_PARAM2_IDX //!< Lock command index for summary +#define LOCK_COUNT SHA204_CMD_SIZE_MIN //!< Lock command packet size +#define LOCK_ZONE_NO_CONFIG ((uint8_t) 0x01) //!< Lock zone is OTP or Data +#define LOCK_ZONE_NO_CRC ((uint8_t) 0x80) //!< Lock command: Ignore summary. +#define LOCK_ZONE_MASK (0x81) //!< Lock parameter 1 bits 2 to 6 are 0. + +// Mac command definitions +#define MAC_MODE_IDX SHA204_PARAM1_IDX //!< MAC command index for mode +#define MAC_KEYID_IDX SHA204_PARAM2_IDX //!< MAC command index for key id +#define MAC_CHALLENGE_IDX SHA204_DATA_IDX //!< MAC command index for optional challenge +#define MAC_COUNT_SHORT SHA204_CMD_SIZE_MIN //!< MAC command packet size without challenge +#define MAC_COUNT_LONG (39) //!< MAC command packet size with challenge +#define MAC_MODE_BLOCK2_TEMPKEY ((uint8_t) 0x01) //!< MAC mode bit 0: second SHA block from TempKey +#define MAC_MODE_BLOCK1_TEMPKEY ((uint8_t) 0x02) //!< MAC mode bit 1: first SHA block from TempKey +#define MAC_MODE_SOURCE_FLAG_MATCH ((uint8_t) 0x04) //!< MAC mode bit 2: match TempKey.SourceFlag +#define MAC_MODE_PASSTHROUGH ((uint8_t) 0x07) //!< MAC mode bit 0-2: pass-through mode +#define MAC_MODE_INCLUDE_OTP_88 ((uint8_t) 0x10) //!< MAC mode bit 4: include first 88 OTP bits +#define MAC_MODE_INCLUDE_OTP_64 ((uint8_t) 0x20) //!< MAC mode bit 5: include first 64 OTP bits +#define MAC_MODE_INCLUDE_SN ((uint8_t) 0x40) //!< MAC mode bit 6: include serial number +#define MAC_CHALLENGE_SIZE (32) //!< MAC size of challenge +#define MAC_MODE_MASK ((uint8_t) 0x77) //!< MAC mode bits 3 and 7 are 0. + +// Nonce command definitions +#define NONCE_MODE_IDX SHA204_PARAM1_IDX //!< Nonce command index for mode +#define NONCE_PARAM2_IDX SHA204_PARAM2_IDX //!< Nonce command index for 2. parameter +#define NONCE_INPUT_IDX SHA204_DATA_IDX //!< Nonce command index for input data +#define NONCE_COUNT_SHORT (27) //!< Nonce command packet size for 20 bytes of data +#define NONCE_COUNT_LONG (39) //!< Nonce command packet size for 32 bytes of data +#define NONCE_MODE_MASK ((uint8_t) 3) //!< Nonce mode bits 2 to 7 are 0. +#define NONCE_MODE_SEED_UPDATE ((uint8_t) 0x00) //!< Nonce mode: update seed +#define NONCE_MODE_NO_SEED_UPDATE ((uint8_t) 0x01) //!< Nonce mode: do not update seed +#define NONCE_MODE_INVALID ((uint8_t) 0x02) //!< Nonce mode 2 is invalid. +#define NONCE_MODE_PASSTHROUGH ((uint8_t) 0x03) //!< Nonce mode: pass-through +#define NONCE_NUMIN_SIZE (20) //!< Nonce data length +#define NONCE_NUMIN_SIZE_PASSTHROUGH (32) //!< Nonce data length in pass-through mode (mode = 3) + +// Pause command definitions +#define PAUSE_SELECT_IDX SHA204_PARAM1_IDX //!< Pause command index for Selector +#define PAUSE_PARAM2_IDX SHA204_PARAM2_IDX //!< Pause command index for 2. parameter +#define PAUSE_COUNT SHA204_CMD_SIZE_MIN //!< Pause command packet size + +// Random command definitions +#define RANDOM_MODE_IDX SHA204_PARAM1_IDX //!< Random command index for mode +#define RANDOM_PARAM2_IDX SHA204_PARAM2_IDX //!< Random command index for 2. parameter +#define RANDOM_COUNT SHA204_CMD_SIZE_MIN //!< Random command packet size +#define RANDOM_SEED_UPDATE ((uint8_t) 0x00) //!< Random mode for automatic seed update +#define RANDOM_NO_SEED_UPDATE ((uint8_t) 0x01) //!< Random mode for no seed update + +// Read command definitions +#define READ_ZONE_IDX SHA204_PARAM1_IDX //!< Read command index for zone +#define READ_ADDR_IDX SHA204_PARAM2_IDX //!< Read command index for address +#define READ_COUNT SHA204_CMD_SIZE_MIN //!< Read command packet size +#define READ_ZONE_MASK ((uint8_t) 0x83) //!< Read zone bits 2 to 6 are 0. +#define READ_ZONE_MODE_32_BYTES ((uint8_t) 0x80) //!< Read mode: 32 bytes + +// UpdateExtra command definitions +#define UPDATE_MODE_IDX SHA204_PARAM1_IDX //!< UpdateExtra command index for mode +#define UPDATE_VALUE_IDX SHA204_PARAM2_IDX //!< UpdateExtra command index for new value +#define UPDATE_COUNT SHA204_CMD_SIZE_MIN //!< UpdateExtra command packet size +#define UPDATE_CONFIG_BYTE_86 ((uint8_t) 0x01) //!< UpdateExtra mode: update Config byte 86 + +// Write command definitions +#define WRITE_ZONE_IDX SHA204_PARAM1_IDX //!< Write command index for zone +#define WRITE_ADDR_IDX SHA204_PARAM2_IDX //!< Write command index for address +#define WRITE_VALUE_IDX SHA204_DATA_IDX //!< Write command index for data +#define WRITE_MAC_VS_IDX ( 9) //!< Write command index for MAC following short data +#define WRITE_MAC_VL_IDX (37) //!< Write command index for MAC following long data +#define WRITE_COUNT_SHORT (11) //!< Write command packet size with short data and no MAC +#define WRITE_COUNT_LONG (39) //!< Write command packet size with long data and no MAC +#define WRITE_COUNT_SHORT_MAC (43) //!< Write command packet size with short data and MAC +#define WRITE_COUNT_LONG_MAC (71) //!< Write command packet size with long data and MAC +#define WRITE_MAC_SIZE (32) //!< Write MAC size +#define WRITE_ZONE_MASK ((uint8_t) 0xC3) //!< Write zone bits 2 to 5 are 0. +#define WRITE_ZONE_WITH_MAC ((uint8_t) 0x40) //!< Write zone bit 6: write encrypted with MAC + +// Response size definitions +#define CHECKMAC_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of DeriveKey command +#define DERIVE_KEY_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of DeriveKey command +#define DEVREV_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of DevRev command returns 4 bytes +#define GENDIG_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of GenDig command +#define HMAC_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of HMAC command +#define LOCK_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Lock command +#define MAC_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of MAC command +#define NONCE_RSP_SIZE_SHORT SHA204_RSP_SIZE_MIN //!< response size of Nonce command with mode[0:1] = 3 +#define NONCE_RSP_SIZE_LONG SHA204_RSP_SIZE_MAX //!< response size of Nonce command +#define PAUSE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Pause command +#define RANDOM_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of Random command +#define READ_4_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of Read command when reading 4 bytes +#define READ_32_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of Read command when reading 32 bytes +#define TEMP_SENSE_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of TempSense command returns 4 bytes +#define UPDATE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of UpdateExtra command +#define WRITE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Write command + +// command timing definitions for minimum execution times (ms) +#define CHECKMAC_DELAY ((uint8_t) (12.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define DERIVE_KEY_DELAY ((uint8_t) (14.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define DEVREV_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define GENDIG_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define HMAC_DELAY ((uint8_t) (27.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define LOCK_DELAY ((uint8_t) ( 5.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define MAC_DELAY ((uint8_t) (12.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define NONCE_DELAY ((uint8_t) (22.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define PAUSE_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define RANDOM_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define READ_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define TEMP_SENSE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define UPDATE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define WRITE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) + +// command timing definitions for maximum execution times (ms) +#define CHECKMAC_EXEC_MAX ((uint8_t) (38.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define DERIVE_KEY_EXEC_MAX ((uint8_t) (62.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define DEVREV_EXEC_MAX ((uint8_t) ( 2.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define GENDIG_EXEC_MAX ((uint8_t) (43.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define HMAC_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define LOCK_EXEC_MAX ((uint8_t) (24.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define MAC_EXEC_MAX ((uint8_t) (35.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define NONCE_EXEC_MAX ((uint8_t) (60.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define PAUSE_EXEC_MAX ((uint8_t) ( 2.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define RANDOM_EXEC_MAX ((uint8_t) (50.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define READ_EXEC_MAX ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define TEMP_SENSE_EXEC_MAX ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define UPDATE_EXEC_MAX ((uint8_t) ( 6.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define WRITE_EXEC_MAX ((uint8_t) (42.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) + +/* from sha204_config.h */ + +#define CPU_CLOCK_DEVIATION_POSITIVE (1.01) +#define CPU_CLOCK_DEVIATION_NEGATIVE (0.99) +#define SHA204_RETRY_COUNT (1) +#define SWI_RECEIVE_TIME_OUT ((uint16_t) 163) //! #START_PULSE_TIME_OUT in us instead of loop counts +#define SWI_US_PER_BYTE ((uint16_t) 313) //! It takes 312.5 us to send a byte (9 single-wire bits / 230400 Baud * 8 flag bits). +#define SHA204_SYNC_TIMEOUT ((uint8_t) 85)//! delay before sending a transmit flag in the synchronization routine +#define SHA204_RESPONSE_TIMEOUT ((uint16_t) SWI_RECEIVE_TIME_OUT + SWI_US_PER_BYTE) //! SWI response timeout is the sum of receive timeout and the time it takes to send the TX flag. + +/* from sha204_comm.h */ + +#define SHA204_COMMAND_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) //! maximum command delay +#define SHA204_CMD_SIZE_MIN ((uint8_t) 7) //! minimum number of bytes in command (from count byte to second CRC byte) +#define SHA204_CMD_SIZE_MAX ((uint8_t) 84) //! maximum size of command packet (CheckMac) +#define SHA204_CRC_SIZE ((uint8_t) 2) //! number of CRC bytes +#define SHA204_BUFFER_POS_STATUS (1) //! buffer index of status byte in status response +#define SHA204_BUFFER_POS_DATA (1) //! buffer index of first data byte in data response +#define SHA204_STATUS_BYTE_WAKEUP ((uint8_t) 0x11) //! command parse error +#define SHA204_STATUS_BYTE_PARSE ((uint8_t) 0x03) //! command parse error +#define SHA204_STATUS_BYTE_EXEC ((uint8_t) 0x0F) //! command execution error +#define SHA204_STATUS_BYTE_COMM ((uint8_t) 0xFF) //! communication error + +/* EEPROM Addresses */ +/* Configuration Zone */ +#define ADDRESS_SN03 0 // SN[0:3] are bytes 0->3 of configuration zone +#define ADDRESS_RevNum 4 // bytes 4->7 of config zone are RevNum +#define ADDRESS_SN47 8 // SN[4:7] are bytes 8->11 of config zone +#define ADDRESS_SN8 12 // SN[8] is byte 12 of config zone, should be 0xEE +#define ADDRESS_I2CEN 14 // I2C Enable, bit 0 represents I2C enable status +#define ADDRESS_I2CADD 16 // Defines I2C address of SHA204 +#define ADDRESS_OTPMODE 18 // Sets the One-time-programmable mode +#define ADDRESS_SELECTOR 19 // Controls writability of Selector + + +class atsha204Class +{ +private: + uint8_t device_pin; + volatile uint8_t *device_port_DDR, *device_port_OUT, *device_port_IN; + void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc); + uint8_t sha204c_check_crc(uint8_t *response); + void swi_set_signal_pin(uint8_t is_high); + uint8_t swi_receive_bytes(uint8_t count, uint8_t *buffer); + uint8_t swi_send_bytes(uint8_t count, uint8_t *buffer); + uint8_t swi_send_byte(uint8_t value); + uint8_t sha204p_receive_response(uint8_t size, uint8_t *response); + uint8_t sha204p_wakeup(); + uint8_t sha204p_send_command(uint8_t count, uint8_t * command); + uint8_t sha204p_sleep(); + uint8_t sha204p_resync(uint8_t size, uint8_t *response); + + +public: + atsha204Class(uint8_t pin); // Constructor + uint8_t sha204c_wakeup(uint8_t *response); + uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout); + uint8_t sha204c_resync(uint8_t size, uint8_t *response); + uint8_t sha204m_random(uint8_t * tx_buffer, uint8_t * rx_buffer, uint8_t mode); + uint8_t sha204m_dev_rev(uint8_t *tx_buffer, uint8_t *rx_buffer); + uint8_t sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address); + uint8_t sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2, + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); + uint8_t sha204m_check_parameters(uint8_t op_code, uint8_t param1, uint16_t param2, + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); + + uint8_t getSerialNumber(uint8_t *response); + uint16_t calculateAndUpdateCrc(uint8_t length, uint8_t *data, uint16_t current_crc); + +}; + +#endif