/** * \brief This function runs a SHA204 Wakeup / Sleep test. * * This test wakes up the device, reads its Wakeup response, * and sends a Sleep command. It then sends a command and * expects a response timeout to verify that the device has * gone to sleep. * * \param test current test case */ static void test_sha204_wakeup(const struct test_case *test) { uint8_t sha204_status = SHA204_SUCCESS; // Catch watchdog timeout in case no Security Xplained board is connected. if ((reset_cause_get_causes() & CHIP_RESET_CAUSE_WDT) != CHIP_RESET_CAUSE_WDT) { reset_cause_clear_causes(CHIP_RESET_CAUSE_POR | CHIP_RESET_CAUSE_EXTRST | CHIP_RESET_CAUSE_BOD_CPU | CHIP_RESET_CAUSE_OCD | CHIP_RESET_CAUSE_SOFT | CHIP_RESET_CAUSE_SPIKE); } else { wdt_disable(); reset_cause_clear_causes(CHIP_RESET_CAUSE_WDT); test_assert_false(test, sha204_status == SHA204_SUCCESS, "No Device."); return; } /* Start watchdog timer. */ wdt_set_timeout_period(WDT_TIMEOUT_PERIOD_250CLK); // 250 ms wdt_enable(); uint8_t response[DEVREV_RSP_SIZE]; success = false; sha204_status = sha204c_wakeup(response); // The TWI_M driver is not hanging. We can disable the watchdog now. wdt_disable(); test_assert_true(test, sha204_status == SHA204_SUCCESS, "Sending Wakeup token failed."); sha204_status = sha204p_sleep(); test_assert_true(test, sha204_status == SHA204_SUCCESS, "Sending Sleep command failed."); // Make sure the device is asleep. The code below works only for TWI, not for SWI, // because there is no acknowledging of a TWI address for SWI. uint8_t command[DEVREV_COUNT] = {DEVREV_COUNT, SHA204_DEVREV, 0, 0, 0, 0x03, 0x5d}; sha204_status = sha204p_send_command(sizeof(command), command); test_assert_false(test, sha204_status == SHA204_SUCCESS, "Device is not asleep."); success = true; }
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; }