123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594 |
- #include "Arduino.h"
- #include "ATSHA204.h"
-
- /* Local data and function prototypes */
-
- static uint8_t device_pin;
- #ifdef ARDUINO_ARCH_AVR
- static volatile uint8_t *device_port_DDR, *device_port_OUT, *device_port_IN;
- #endif
- static void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc);
- static uint8_t sha204c_check_crc(uint8_t *response);
- static void swi_set_signal_pin(uint8_t is_high);
- static uint8_t swi_receive_bytes(uint8_t count, uint8_t *buffer);
- static uint8_t swi_send_bytes(uint8_t count, uint8_t *buffer);
- static uint8_t swi_send_byte(uint8_t value);
- static uint8_t sha204p_receive_response(uint8_t size, uint8_t *response);
- static uint8_t sha204c_resync(uint8_t size, uint8_t *response);
- static 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);
-
- /* SWI bit bang functions */
-
- static void swi_set_signal_pin(uint8_t is_high)
- {
- SHA204_SET_OUTPUT();
-
- if (is_high) {
- SHA204_POUT_HIGH();
- } else {
- SHA204_POUT_LOW();
- }
- }
-
- static uint8_t 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.
- SHA204_POUT_HIGH();
- SHA204_SET_OUTPUT();
-
-
- // 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]) {
- SHA204_POUT_LOW(); //*device_port_OUT &= ~device_pin;
- delayMicroseconds(BIT_DELAY); //BIT_DELAY_1;
- SHA204_POUT_HIGH(); //*device_port_OUT |= device_pin;
- delayMicroseconds(7*BIT_DELAY); //BIT_DELAY_7;
- } else {
- // Send a zero bit.
- SHA204_POUT_LOW(); //*device_port_OUT &= ~device_pin;
- delayMicroseconds(BIT_DELAY); //BIT_DELAY_1;
- SHA204_POUT_HIGH(); //*device_port_OUT |= device_pin;
- delayMicroseconds(BIT_DELAY); //BIT_DELAY_1;
- SHA204_POUT_LOW(); //*device_port_OUT &= ~device_pin;
- delayMicroseconds(BIT_DELAY); //BIT_DELAY_1;
- SHA204_POUT_HIGH(); //*device_port_OUT |= device_pin;
- delayMicroseconds(5*BIT_DELAY); //BIT_DELAY_5;
- }
- }
- }
- interrupts(); //swi_enable_interrupts();
- return SWI_FUNCTION_RETCODE_SUCCESS;
- }
-
- static uint8_t swi_send_byte(uint8_t value)
- {
- return swi_send_bytes(1, &value);
- }
-
- static uint8_t 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.
- SHA204_SET_INPUT();
-
- // 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 (SHA204_PIN_READ() == 0) {
- break;
- }
- }
-
- if (timeout_count == 0) {
- status = SWI_FUNCTION_RETCODE_TIMEOUT;
- break;
- }
-
- do {
- // Wait for rising edge.
- if (SHA204_PIN_READ() != 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 (SHA204_PIN_READ() == 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 (SHA204_PIN_READ() != 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 */
-
- static uint8_t sha204p_receive_response(uint8_t size, uint8_t *response)
- {
- 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) {
- uint8_t count_byte;
- 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;
- }
- }
-
- /* Communication functions */
-
- static uint8_t sha204c_resync(uint8_t size, uint8_t *response)
- {
- // Try to re-synchronize without sending a Wake token
- // (step 1 of the re-synchronization process).
- delay(SHA204_SYNC_TIMEOUT);
- uint8_t ret_code = sha204p_receive_response(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).
- atsha204_sleep();
- ret_code = atsha204_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);
- }
-
- static 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 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 = swi_send_byte(SHA204_SWI_FLAG_CMD);
- if (ret_code != SWI_FUNCTION_RETCODE_SUCCESS) {
- ret_code = SHA204_COMM_FAIL;
- } else {
- ret_code = swi_send_bytes(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;
- }
-
- /* CRC Calculator and Checker */
-
- static void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc)
- {
- uint8_t counter;
- uint16_t crc_register = 0;
- 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;
- }
- }
- }
- crc[0] = (uint8_t) (crc_register & 0x00FF);
- crc[1] = (uint8_t) (crc_register >> 8);
- }
-
- static uint8_t 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;
- }
-
- /* Public functions */
-
- void atsha204_init(uint8_t pin)
- {
- #if defined(ARDUINO_ARCH_AVR)
- 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);
- #else
- device_pin = pin;
- #endif
- }
-
- void atsha204_idle(void)
- {
- swi_send_byte(SHA204_SWI_FLAG_IDLE);
- }
-
- void atsha204_sleep(void)
- {
- swi_send_byte(SHA204_SWI_FLAG_SLEEP);
- }
-
- uint8_t atsha204_wakeup(uint8_t *response)
- {
- swi_set_signal_pin(0);
- delayMicroseconds(10*SHA204_WAKEUP_PULSE_WIDTH);
- swi_set_signal_pin(1);
- delay(SHA204_WAKEUP_DELAY);
-
- uint8_t 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 atsha204_execute(uint8_t op_code, uint8_t param1, uint16_t param2,
- uint8_t datalen1, uint8_t *data1, 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;
- (void)tx_size;
-
- // Supply delays and response size.
- switch (op_code) {
- 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_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_RANDOM:
- poll_delay = RANDOM_DELAY;
- poll_timeout = RANDOM_EXEC_MAX - RANDOM_DELAY;
- response_size = RANDOM_RSP_SIZE;
- break;
-
- case SHA204_SHA:
- poll_delay = SHA_DELAY;
- poll_timeout = SHA_EXEC_MAX - SHA_DELAY;
- response_size = param1 == SHA_INIT
- ? SHA_RSP_SIZE_SHORT : SHA_RSP_SIZE_LONG;
- 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 + 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;
- }
-
- 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 atsha204_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 = atsha204_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03);
- if (!returnCode) {
- 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 = atsha204_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 = atsha204_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;
- }
-
- uint8_t atsha204_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address)
- {
- uint8_t rx_size;
-
- address >>= 2;
-
- 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);
- }
|