1 // Copyright (c) 2010, Atmel Corporation. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are met: 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above copyright 9 // notice, this list of conditions and the following disclaimer in the 10 // documentation and/or other materials provided with the distribution. 11 // * Neither the name of Atmel nor the 12 // names of its contributors may be used to endorse or promote products 13 // derived from this software without specific prior written permission. 14 // 15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 19 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 26 #include <stdint.h> 27 #include "SHA_Comm.h" 28 #include "SHA_CommInterface.h" 29 #include "SHA_TimeUtils.h" 30 #include "SHA_Status.h" 31 32 33 /** \brief Calculates CRC 34 * 35 * \param[in] data pointer to data for which CRC should be calculated 36 * \param[in] count number of bytes in buffer 37 * \return 38 */ 39 uint16_t SHAC_CalculateCrc(uint8_t *data, uint8_t count) { 40 uint8_t counter; 41 uint16_t crc = 0x0000; 42 uint16_t poly = 0x8005; 43 uint16_t i; 44 uint8_t nbit, cbit; 45 46 for (counter = 0; counter < count; counter++) { 47 for (i = 0x1; i < 0x100; i <<= 1) { 48 nbit = (data[counter] & (uint8_t) i) ? 1 : 0; 49 cbit = (0x8000 & crc) ? 1 : 0; 50 crc <<= 1; 51 if (nbit ^ cbit) 52 crc ^= poly; 53 } 54 } 55 #ifdef BIGENDIAN 56 crc = (crc << 8) | (crc >> 8); // flip byte order 57 #endif 58 59 return crc; 60 } 61 62 63 uint8_t SHAC_Wakeup() { 64 return(SHAP_WakeDevice()); 65 } 66 67 68 /** \brief Runs a communication sequence: Append CRC to tx buffer, send command, delay, receive and verify response. 69 * 70 * The first byte in tx buffer must be its byte count. 71 * If CRC or count of the response is incorrect, or a command byte got "nacked" (TWI), 72 * this function requests to re-send the response. 73 * If the response contains an error status, this function resends the command. 74 * 75 * \param[in] params pointer to parameter structure 76 * \return status of the operation 77 */ 78 int8_t SHAC_SendAndReceive(SHA_CommParameters *params) { 79 uint8_t rxSize = params->rxSize; 80 uint8_t *rxBuffer = params->rxBuffer; 81 uint8_t *txBuffer = params->txBuffer; 82 uint8_t count; 83 uint8_t countMinusCrc; 84 int8_t status; 85 uint8_t nRetries; 86 uint8_t i; 87 uint8_t statusByte; 88 89 if (!params) 90 return SHA_BAD_PARAM; 91 if (!params->txBuffer) 92 return SHA_BAD_PARAM; 93 94 count = txBuffer[SHA_BUFFER_POS_COUNT]; 95 countMinusCrc = count - 2; 96 if (count < SHA_COMMAND_SIZE_MIN || rxSize < SHA_RESPONSE_SIZE_MIN || !rxBuffer) 97 return SHA_BAD_PARAM; 98 99 // Append CRC and send command. 100 *((uint16_t *) (txBuffer + countMinusCrc)) = SHAC_CalculateCrc(txBuffer, countMinusCrc); 101 status = SHAP_SendCommand(count, txBuffer); 102 103 if (status != SHA_SUCCESS) { 104 // Re-send command. 105 status = SHAP_SendCommand(count, txBuffer); 106 if (status != SHA_SUCCESS) { 107 // We lost communication. Wait until device goes to sleep. 108 //SHAP_Delay(WATCHDOG_TIMEOUT * 1000000); 109 return status; 110 } 111 } 112 113 // Wait for device to finish command execution. 114 SHAP_Delay(params->executionDelay); 115 116 // Receive response. 117 nRetries = SHA_RETRY_COUNT; 118 do { 119 // Reset response buffer. 120 for (i = 0; i < rxSize; i++) 121 rxBuffer[i] = 0; 122 123 status = SHAP_ReceiveResponse(rxSize, rxBuffer); 124 if (status != SHA_SUCCESS && !rxBuffer[SHA_BUFFER_POS_COUNT]) { 125 // We lost communication. Wait until device goes to sleep. 126 //SHAP_Delay(WATCHDOG_TIMEOUT * 1000000); 127 return status; 128 } 129 130 // Check whether we received a status packet instead of a full response. 131 if (rxSize != SHA_RESPONSE_SIZE_MIN && rxBuffer[SHA_BUFFER_POS_COUNT] == SHA_RESPONSE_SIZE_MIN) { 132 statusByte = rxBuffer[SHA_BUFFER_POS_STATUS]; 133 if (statusByte == SHA_STATUS_BYTE_PARSE) 134 return SHA_PARSE_ERROR; 135 if (statusByte == SHA_STATUS_BYTE_EXEC) 136 return SHA_CMD_FAIL; 137 if (statusByte != SHA_STATUS_BYTE_COMM) 138 return SHA_STATUS_UNKNOWN; 139 140 // Communication error. Request device to re-transmit response. 141 continue; 142 } 143 144 // Received response. Verify count and CRC. 145 if (rxBuffer[SHA_BUFFER_POS_COUNT] != rxSize) { 146 status = SHA_BAD_SIZE; 147 continue; 148 } 149 countMinusCrc = rxSize - 2; 150 status = (*((uint16_t *) (rxBuffer + countMinusCrc)) == SHAC_CalculateCrc(rxBuffer, countMinusCrc)) 151 ? SHA_SUCCESS : SHA_BAD_CRC; 152 } while (nRetries-- && status != SHA_SUCCESS); 153 154 return status; 155 } 156