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