#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 // For AVR ARCH, 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 // For others it will only store the pin number which is used in subsequent functions atsha204Class::atsha204Class(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 } /* 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) { SHA204_SET_OUTPUT(); if (is_high) { SHA204_POUT_HIGH(); } else { SHA204_POUT_LOW(); } } 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. 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(); delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; SHA204_POUT_HIGH(); delayMicroseconds(7*BIT_DELAY); //BIT_DELAY_7; } else { // Send a zero bit. SHA204_POUT_LOW(); delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; SHA204_POUT_HIGH(); delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; SHA204_POUT_LOW(); delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; SHA204_POUT_HIGH(); 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 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 */ 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 (void)rx_size; (void)tx_size; (void)tx_buffer; (void)rx_buffer; (void)param1; (void)param2; (void)data1; (void)data2; (void)data3; (void)datalen1; (void)datalen2; (void)datalen3; (void)op_code; 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; }