1 /**
2 * @file atecc608a-tnglora-se-hal.c
3 *
4 * @brief Secure Element hardware abstraction layer implementation
5 *
6 * @remark Current implementation only supports LoRaWAN 1.0.x version
7 *
8 * @copyright Copyright (c) 2020 The Things Industries B.V.
9 *
10 * Revised BSD License
11 * Copyright The Things Industries B.V 2020. All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 * * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * * Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * * Neither the name of the Things Industries B.V nor the
21 * names of its contributors may be used to endorse or promote products
22 * derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE THINGS INDUSTRIES B.V BE LIABLE FOR ANY
28 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include <string.h>
37 #include <stdio.h>
38
39 #include "atca_hal.h"
40 #include "atca_device.h"
41 #include "atca_execution.h"
42 #include "atca_status.h"
43 #include "i2c-board.h"
44 #include "delay.h"
45
46 #include "radio.h"
47
48 #include "atecc608a-tnglora-se-hal.h"
49
ATECC608ASeHalGetRandomNumber(void)50 uint32_t ATECC608ASeHalGetRandomNumber( void )
51 {
52 return Radio.Random( );
53 }
54
55 /** @brief This function delays for a number of microseconds.
56 *
57 * @param[in] delay number of 0.001 milliseconds to delay
58 */
atca_delay_us(uint32_t delay)59 void atca_delay_us(uint32_t delay)
60 {
61 // use ASF supplied delay
62 DelayMs(delay / 1000);
63 }
64
65 /** @brief This function delays for a number of tens of microseconds.
66 *
67 * @param[in] delay number of 0.01 milliseconds to delay
68 */
atca_delay_10us(uint32_t delay)69 void atca_delay_10us(uint32_t delay)
70 {
71 // use ASF supplied delay
72 DelayMs(delay / 100);
73 }
74
75 /** @brief This function delays for a number of milliseconds.
76 *
77 * You can override this function if you like to do
78 * something else in your system while delaying.
79 * @param[in] delay number of milliseconds to delay
80 */
atca_delay_ms(uint32_t delay)81 void atca_delay_ms(uint32_t delay)
82 {
83 // use ASF supplied delay
84 DelayMs(delay);
85 }
86
87 /** @brief discover i2c buses available for this hardware
88 * this maintains a list of logical to physical bus mappings freeing the application
89 * of the a-priori knowledge
90 * @param[in] i2c_buses - an array of logical bus numbers
91 * @param[in] max_buses - maximum number of buses the app wants to attempt to discover
92 * @return ATCA_SUCCESS
93 */
94
hal_i2c_discover_buses(int i2c_buses[],int max_buses)95 ATCA_STATUS hal_i2c_discover_buses(int i2c_buses[], int max_buses)
96 {
97 return ATCA_SUCCESS;
98 }
99
100 /** @brief discover any CryptoAuth devices on a given logical bus number
101 * @param[in] bus_num logical bus number on which to look for CryptoAuth devices
102 * @param[out] cfg pointer to head of an array of interface config structures which get filled in by this method
103 * @param[out] found number of devices found on this bus
104 * @return ATCA_SUCCESS
105 */
106
hal_i2c_discover_devices(int bus_num,ATCAIfaceCfg cfg[],int * found)107 ATCA_STATUS hal_i2c_discover_devices(int bus_num, ATCAIfaceCfg cfg[], int *found)
108 {
109 return ATCA_SUCCESS;
110 }
111
112 /** @brief
113 - this HAL implementation assumes you've included the ASF SERCOM I2C libraries in your project, otherwise,
114 the HAL layer will not compile because the ASF I2C drivers are a dependency *
115 */
116
117 /** @brief hal_i2c_init manages requests to initialize a physical interface. it manages use counts so when an interface
118 * has released the physical layer, it will disable the interface for some other use.
119 * You can have multiple ATCAIFace instances using the same bus, and you can have multiple ATCAIFace instances on
120 * multiple i2c buses, so hal_i2c_init manages these things and ATCAIFace is abstracted from the physical details.
121 */
122
123 /** @brief initialize an I2C interface using given config
124 * @param[in] hal - opaque ptr to HAL data
125 * @param[in] cfg - interface configuration
126 * @return ATCA_SUCCESS on success, otherwise an error code.
127 */
hal_i2c_init(void * hal,ATCAIfaceCfg * cfg)128 ATCA_STATUS hal_i2c_init(void *hal, ATCAIfaceCfg *cfg)
129 {
130 return ATCA_SUCCESS;
131 }
132
133 /** @brief HAL implementation of I2C post init
134 * @param[in] iface instance
135 * @return ATCA_SUCCESS
136 */
hal_i2c_post_init(ATCAIface iface)137 ATCA_STATUS hal_i2c_post_init(ATCAIface iface)
138 {
139 return ATCA_SUCCESS;
140 }
141
142 /** @brief HAL implementation of I2C send over ASF
143 * @param[in] iface instance
144 * @param[in] txdata pointer to space to bytes to send
145 * @param[in] txlength number of bytes to send
146 * @return ATCA_SUCCESS on success, otherwise an error code.
147 */
148
hal_i2c_send(ATCAIface iface,uint8_t * txdata,int txlength)149 ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength)
150 {
151
152 txdata[0] = 0x3;
153 txlength++;
154 if (I2cMcuWriteBuffer((I2c_t *)NULL, iface->mIfaceCFG->atcai2c.slave_address, txdata, (size_t)txlength) == 1)
155 {
156 return ATCA_SUCCESS;
157 }
158 else
159 {
160 return ATCA_TX_FAIL;
161 }
162 }
163
164 /** @brief HAL implementation of I2C receive function for ASF I2C
165 * @param[in] iface Device to interact with.
166 * @param[out] rxdata Data received will be returned here.
167 * @param[inout] rxlength As input, the size of the rxdata buffer.
168 * As output, the number of bytes received.
169 * @return ATCA_SUCCESS on success, otherwise an error code.
170 */
hal_i2c_receive(ATCAIface iface,uint8_t * rxdata,uint16_t * rxlength)171 ATCA_STATUS hal_i2c_receive(ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength)
172 {
173 // read procedure is:
174 // 1. read 1 byte, this will be the length of the package
175 // 2. read the rest of the package
176
177 uint8_t lengthPackage[1] = {0};
178 int r = -1;
179 int retries = iface->mIfaceCFG->rx_retries;
180 while (--retries > 0 && r != 1)
181 {
182 r = I2cMcuReadBuffer((I2c_t *)NULL, iface->mIfaceCFG->atcai2c.slave_address, lengthPackage, 1);
183 }
184
185 if (r != 1)
186 {
187 return ATCA_RX_TIMEOUT;
188 }
189
190 uint8_t bytesToRead = lengthPackage[0] - 1;
191
192 if (bytesToRead > *rxlength)
193 {
194 printf("hal_i2c_receive buffer too small, requested %u, but have %u", bytesToRead, *rxlength);
195 return ATCA_SMALL_BUFFER;
196 }
197
198 memset(rxdata, 0, *rxlength);
199 rxdata[0] = lengthPackage[0];
200
201 r = -1;
202 retries = iface->mIfaceCFG->rx_retries;
203 while (--retries > 0 && r != 1)
204 {
205 r = I2cMcuReadBuffer((I2c_t *)NULL, iface->mIfaceCFG->atcai2c.slave_address, rxdata + 1, bytesToRead);
206 }
207
208 if (r != 1)
209 {
210 return ATCA_RX_TIMEOUT;
211 }
212
213 *rxlength = lengthPackage[0];
214
215 return ATCA_SUCCESS;
216 }
217
218 /** @brief method to change the bus speec of I2C
219 * @param[in] iface interface on which to change bus speed
220 * @param[in] speed baud rate (typically 100000 or 400000)
221 */
222
change_i2c_speed(ATCAIface iface,uint32_t speed)223 void change_i2c_speed(ATCAIface iface, uint32_t speed)
224 {
225 return;
226 }
227
228 /** @brief wake up CryptoAuth device using I2C bus
229 * @param[in] iface interface to logical device to wakeup
230 * @return ATCA_SUCCESS on success, otherwise an error code.
231 */
232
hal_i2c_wake(ATCAIface iface)233 ATCA_STATUS hal_i2c_wake(ATCAIface iface)
234 {
235 // 2. Send NULL buffer to address 0x0 (NACK)
236 uint8_t emptybuff[1] = {0};
237 int r = I2cMcuWriteBuffer((I2c_t *)NULL, 0x00, emptybuff, (size_t)0);
238
239 // 3. Wait for wake_delay
240 atca_delay_us(iface->mIfaceCFG->wake_delay);
241
242 uint8_t rx_buffer[4] = {0};
243
244 // 4. Read from normal slave_address
245 r = -1;
246 int retries = iface->mIfaceCFG->rx_retries;
247 while (--retries > 0 && r != 1)
248 {
249 r = I2cMcuReadBuffer((I2c_t *)NULL, iface->mIfaceCFG->atcai2c.slave_address, rx_buffer, 4);
250 }
251
252 // 5. Set frequency back to requested one
253 const uint8_t expected_response[4] = {0x04, 0x11, 0x33, 0x43};
254 uint8_t selftest_fail_resp[4] = {0x04, 0x07, 0xC4, 0x40};
255
256 if (memcmp(rx_buffer, expected_response, 4) == 0)
257 {
258 return ATCA_SUCCESS;
259 }
260 if (memcmp(rx_buffer, selftest_fail_resp, 4) == 0)
261 {
262 return ATCA_STATUS_SELFTEST_ERROR;
263 }
264 return ATCA_WAKE_FAILED;
265 }
266
267 /** @brief idle CryptoAuth device using I2C bus
268 * @param[in] iface interface to logical device to idle
269 * @return ATCA_SUCCESS on success, otherwise an error code.
270 */
271
hal_i2c_idle(ATCAIface iface)272 ATCA_STATUS hal_i2c_idle(ATCAIface iface)
273 {
274 uint8_t buffer[1] = { 0x2 }; // idle word address value
275 I2cMcuWriteBuffer((I2c_t*)NULL, iface->mIfaceCFG->atcai2c.slave_address, buffer, (size_t)1);
276 return ATCA_SUCCESS;
277 }
278
279 /** @brief sleep CryptoAuth device using I2C bus
280 * @param[in] iface interface to logical device to sleep
281 * @return ATCA_SUCCESS on success, otherwise an error code.
282 */
283
hal_i2c_sleep(ATCAIface iface)284 ATCA_STATUS hal_i2c_sleep(ATCAIface iface)
285 {
286 uint8_t buffer[1] = { 0x1 }; // sleep word address value
287 I2cMcuWriteBuffer((I2c_t*)NULL, iface->mIfaceCFG->atcai2c.slave_address, buffer, (size_t)1);
288 return ATCA_SUCCESS;
289 }
290
291 /** @brief manages reference count on given bus and releases resource if no more refences exist
292 * @param[in] hal_data - opaque pointer to hal data structure - known only to the HAL implementation
293 * return ATCA_SUCCESS
294 */
295
hal_i2c_release(void * hal_data)296 ATCA_STATUS hal_i2c_release(void *hal_data)
297 {
298 return ATCA_SUCCESS;
299 }
300