xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/drivers/nrf52/src/ble_hw.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include <stdint.h>
21 #include <assert.h>
22 #include <string.h>
23 #include "syscfg/syscfg.h"
24 #include "os/os.h"
25 #include "ble/xcvr.h"
26 #include "nimble/ble.h"
27 #include "nimble/nimble_opt.h"
28 #include "nrfx.h"
29 #include "controller/ble_hw.h"
30 #if MYNEWT
31 #include "mcu/cmsis_nvic.h"
32 #else
33 #include "core_cm4.h"
34 #include <nimble/nimble_npl_os.h>
35 #endif
36 #include "os/os_trace_api.h"
37 
38 /* Total number of resolving list elements */
39 #define BLE_HW_RESOLV_LIST_SIZE     (16)
40 
41 /* We use this to keep track of which entries are set to valid addresses */
42 static uint8_t g_ble_hw_whitelist_mask;
43 
44 /* Random number generator isr callback */
45 ble_rng_isr_cb_t g_ble_rng_isr_cb;
46 
47 /* If LL privacy is enabled, allocate memory for AAR */
48 #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
49 
50 /* The NRF51 supports up to 16 IRK entries */
51 #if (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE) < 16)
52 #define NRF_IRK_LIST_ENTRIES    (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE))
53 #else
54 #define NRF_IRK_LIST_ENTRIES    (16)
55 #endif
56 
57 /* NOTE: each entry is 16 bytes long. */
58 uint32_t g_nrf_irk_list[NRF_IRK_LIST_ENTRIES * 4];
59 
60 /* Current number of IRK entries */
61 uint8_t g_nrf_num_irks;
62 
63 #endif
64 
65 /* Returns public device address or -1 if not present */
66 int
ble_hw_get_public_addr(ble_addr_t * addr)67 ble_hw_get_public_addr(ble_addr_t *addr)
68 {
69     int rc;
70     uint32_t addr_high;
71     uint32_t addr_low;
72 
73     /* Does FICR have a public address */
74     rc = -1;
75     if ((NRF_FICR->DEVICEADDRTYPE & 1) == 0) {
76         addr_low = NRF_FICR->DEVICEADDR[0];
77         addr_high = NRF_FICR->DEVICEADDR[1];
78         rc = 0;
79     } else {
80         /* See if programmed in UICR. Upper 16 bits must all be zero */
81         addr_high = NRF_UICR->CUSTOMER[1];
82         if (addr_high < 65536) {
83             addr_low = NRF_UICR->CUSTOMER[0];
84             rc = 0;
85         }
86     }
87 
88     if (!rc) {
89         /* Copy into device address. We can do this because we know platform */
90         memcpy(addr->val, &addr_low, 4);
91         memcpy(&addr->val[4], &addr_high, 2);
92         addr->type = BLE_ADDR_PUBLIC;
93     }
94 
95     return rc;
96 }
97 
98 /* Returns random static address or -1 if not present */
99 int
ble_hw_get_static_addr(ble_addr_t * addr)100 ble_hw_get_static_addr(ble_addr_t *addr)
101 {
102     int rc;
103 
104     if ((NRF_FICR->DEVICEADDRTYPE & 1) == 1) {
105         memcpy(addr->val, (void *)&NRF_FICR->DEVICEADDR[0], 4);
106         memcpy(&addr->val[4], (void *)&NRF_FICR->DEVICEADDR[1], 2);
107         addr->val[5] |= 0xc0;
108         addr->type = BLE_ADDR_RANDOM;
109         rc = 0;
110     } else {
111         rc = -1;
112     }
113 
114     return rc;
115 }
116 
117 /**
118  * Clear the whitelist
119  *
120  * @return int
121  */
122 void
ble_hw_whitelist_clear(void)123 ble_hw_whitelist_clear(void)
124 {
125     NRF_RADIO->DACNF = 0;
126     g_ble_hw_whitelist_mask = 0;
127 }
128 
129 /**
130  * Add a device to the hw whitelist
131  *
132  * @param addr
133  * @param addr_type
134  *
135  * @return int 0: success, BLE error code otherwise
136  */
137 int
ble_hw_whitelist_add(uint8_t * addr,uint8_t addr_type)138 ble_hw_whitelist_add(uint8_t *addr, uint8_t addr_type)
139 {
140     int i;
141     uint32_t mask;
142 
143     /* Find first ununsed device address match element */
144     mask = 0x01;
145     for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
146         if ((mask & g_ble_hw_whitelist_mask) == 0) {
147             NRF_RADIO->DAB[i] = get_le32(addr);
148             NRF_RADIO->DAP[i] = get_le16(addr + 4);
149             if (addr_type == BLE_ADDR_RANDOM) {
150                 NRF_RADIO->DACNF |= (mask << 8);
151             }
152             g_ble_hw_whitelist_mask |= mask;
153             return BLE_ERR_SUCCESS;
154         }
155         mask <<= 1;
156     }
157 
158     return BLE_ERR_MEM_CAPACITY;
159 }
160 
161 /**
162  * Remove a device from the hw whitelist
163  *
164  * @param addr
165  * @param addr_type
166  *
167  */
168 void
ble_hw_whitelist_rmv(uint8_t * addr,uint8_t addr_type)169 ble_hw_whitelist_rmv(uint8_t *addr, uint8_t addr_type)
170 {
171     int i;
172     uint8_t cfg_addr;
173     uint16_t dap;
174     uint16_t txadd;
175     uint32_t dab;
176     uint32_t mask;
177 
178     /* Find first ununsed device address match element */
179     dab = get_le32(addr);
180     dap = get_le16(addr + 4);
181     txadd = NRF_RADIO->DACNF >> 8;
182     mask = 0x01;
183     for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
184         if (mask & g_ble_hw_whitelist_mask) {
185             if ((dab == NRF_RADIO->DAB[i]) && (dap == NRF_RADIO->DAP[i])) {
186                 cfg_addr = txadd & mask;
187                 if (addr_type == BLE_ADDR_RANDOM) {
188                     if (cfg_addr != 0) {
189                         break;
190                     }
191                 } else {
192                     if (cfg_addr == 0) {
193                         break;
194                     }
195                 }
196             }
197         }
198         mask <<= 1;
199     }
200 
201     if (i < BLE_HW_WHITE_LIST_SIZE) {
202         g_ble_hw_whitelist_mask &= ~mask;
203         NRF_RADIO->DACNF &= ~mask;
204     }
205 }
206 
207 /**
208  * Returns the size of the whitelist in HW
209  *
210  * @return int Number of devices allowed in whitelist
211  */
212 uint8_t
ble_hw_whitelist_size(void)213 ble_hw_whitelist_size(void)
214 {
215     return BLE_HW_WHITE_LIST_SIZE;
216 }
217 
218 /**
219  * Enable the whitelisted devices
220  */
221 void
ble_hw_whitelist_enable(void)222 ble_hw_whitelist_enable(void)
223 {
224     /* Enable the configured device addresses */
225     NRF_RADIO->DACNF |= g_ble_hw_whitelist_mask;
226 }
227 
228 /**
229  * Disables the whitelisted devices
230  */
231 void
ble_hw_whitelist_disable(void)232 ble_hw_whitelist_disable(void)
233 {
234     /* Disable all whitelist devices */
235     NRF_RADIO->DACNF &= 0x0000ff00;
236 }
237 
238 /**
239  * Boolean function which returns true ('1') if there is a match on the
240  * whitelist.
241  *
242  * @return int
243  */
244 int
ble_hw_whitelist_match(void)245 ble_hw_whitelist_match(void)
246 {
247     return (int)NRF_RADIO->EVENTS_DEVMATCH;
248 }
249 
250 /* Encrypt data */
251 int
ble_hw_encrypt_block(struct ble_encryption_block * ecb)252 ble_hw_encrypt_block(struct ble_encryption_block *ecb)
253 {
254     int rc;
255     uint32_t end;
256     uint32_t err;
257 
258     /* Stop ECB */
259     NRF_ECB->TASKS_STOPECB = 1;
260     /* XXX: does task stop clear these counters? Anyway to do this quicker? */
261     NRF_ECB->EVENTS_ENDECB = 0;
262     NRF_ECB->EVENTS_ERRORECB = 0;
263     NRF_ECB->ECBDATAPTR = (uint32_t)ecb;
264 
265     /* Start ECB */
266     NRF_ECB->TASKS_STARTECB = 1;
267 
268     /* Wait till error or done */
269     rc = 0;
270     while (1) {
271         end = NRF_ECB->EVENTS_ENDECB;
272         err = NRF_ECB->EVENTS_ERRORECB;
273         if (end || err) {
274             if (err) {
275                 rc = -1;
276             }
277             break;
278         }
279     }
280 
281     return rc;
282 }
283 
284 /**
285  * Random number generator ISR.
286  */
287 static void
ble_rng_isr(void)288 ble_rng_isr(void)
289 {
290     uint8_t rnum;
291 
292     os_trace_isr_enter();
293 
294     /* No callback? Clear and disable interrupts */
295     if (g_ble_rng_isr_cb == NULL) {
296         NRF_RNG->INTENCLR = 1;
297         NRF_RNG->EVENTS_VALRDY = 0;
298         (void)NRF_RNG->SHORTS;
299         os_trace_isr_exit();
300         return;
301     }
302 
303     /* If there is a value ready grab it */
304     if (NRF_RNG->EVENTS_VALRDY) {
305         NRF_RNG->EVENTS_VALRDY = 0;
306         rnum = (uint8_t)NRF_RNG->VALUE;
307         (*g_ble_rng_isr_cb)(rnum);
308     }
309 
310     os_trace_isr_exit();
311 }
312 
313 /**
314  * Initialize the random number generator
315  *
316  * @param cb
317  * @param bias
318  *
319  * @return int
320  */
321 int
ble_hw_rng_init(ble_rng_isr_cb_t cb,int bias)322 ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
323 {
324     /* Set bias */
325     if (bias) {
326         NRF_RNG->CONFIG = 1;
327     } else {
328         NRF_RNG->CONFIG = 0;
329     }
330 
331     /* If we were passed a function pointer we need to enable the interrupt */
332     if (cb != NULL) {
333         NVIC_SetPriority(RNG_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
334 #if MYNEWT
335         NVIC_SetVector(RNG_IRQn, (uint32_t)ble_rng_isr);
336 #else
337         ble_npl_hw_set_isr(RNG_IRQn, ble_rng_isr);
338 #endif
339         NVIC_EnableIRQ(RNG_IRQn);
340         g_ble_rng_isr_cb = cb;
341     }
342 
343     return 0;
344 }
345 
346 /**
347  * Start the random number generator
348  *
349  * @return int
350  */
351 int
ble_hw_rng_start(void)352 ble_hw_rng_start(void)
353 {
354     os_sr_t sr;
355 
356     /* No need for interrupt if there is no callback */
357     OS_ENTER_CRITICAL(sr);
358     NRF_RNG->EVENTS_VALRDY = 0;
359     if (g_ble_rng_isr_cb) {
360         NRF_RNG->INTENSET = 1;
361     }
362     NRF_RNG->TASKS_START = 1;
363     OS_EXIT_CRITICAL(sr);
364 
365     return 0;
366 }
367 
368 /**
369  * Stop the random generator
370  *
371  * @return int
372  */
373 int
ble_hw_rng_stop(void)374 ble_hw_rng_stop(void)
375 {
376     os_sr_t sr;
377 
378     /* No need for interrupt if there is no callback */
379     OS_ENTER_CRITICAL(sr);
380     NRF_RNG->INTENCLR = 1;
381     NRF_RNG->TASKS_STOP = 1;
382     NRF_RNG->EVENTS_VALRDY = 0;
383     OS_EXIT_CRITICAL(sr);
384 
385     return 0;
386 }
387 
388 /**
389  * Read the random number generator.
390  *
391  * @return uint8_t
392  */
393 uint8_t
ble_hw_rng_read(void)394 ble_hw_rng_read(void)
395 {
396     uint8_t rnum;
397 
398     /* Wait for a sample */
399     while (NRF_RNG->EVENTS_VALRDY == 0) {
400     }
401 
402     NRF_RNG->EVENTS_VALRDY = 0;
403     rnum = (uint8_t)NRF_RNG->VALUE;
404 
405     return rnum;
406 }
407 
408 #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY))
409 /**
410  * Clear the resolving list
411  *
412  * @return int
413  */
414 void
ble_hw_resolv_list_clear(void)415 ble_hw_resolv_list_clear(void)
416 {
417     g_nrf_num_irks = 0;
418 }
419 
420 /**
421  * Add a device to the hw resolving list
422  *
423  * @param irk   Pointer to IRK to add
424  *
425  * @return int 0: success, BLE error code otherwise
426  */
427 int
ble_hw_resolv_list_add(uint8_t * irk)428 ble_hw_resolv_list_add(uint8_t *irk)
429 {
430     uint32_t *nrf_entry;
431 
432     /* Find first ununsed device address match element */
433     if (g_nrf_num_irks == NRF_IRK_LIST_ENTRIES) {
434         return BLE_ERR_MEM_CAPACITY;
435     }
436 
437     /* Copy into irk list */
438     nrf_entry = &g_nrf_irk_list[4 * g_nrf_num_irks];
439     memcpy(nrf_entry, irk, 16);
440 
441     /* Add to total */
442     ++g_nrf_num_irks;
443     return BLE_ERR_SUCCESS;
444 }
445 
446 /**
447  * Remove a device from the hw resolving list
448  *
449  * @param index Index of IRK to remove
450  */
451 void
ble_hw_resolv_list_rmv(int index)452 ble_hw_resolv_list_rmv(int index)
453 {
454     uint32_t *irk_entry;
455 
456     if (index < g_nrf_num_irks) {
457         --g_nrf_num_irks;
458         irk_entry = &g_nrf_irk_list[index];
459         if (g_nrf_num_irks > index) {
460             memmove(irk_entry, irk_entry + 4, g_nrf_num_irks - index);
461         }
462     }
463 }
464 
465 /**
466  * Returns the size of the resolving list. NOTE: this returns the maximum
467  * allowable entries in the HW. Configuration options may limit this.
468  *
469  * @return int Number of devices allowed in resolving list
470  */
471 uint8_t
ble_hw_resolv_list_size(void)472 ble_hw_resolv_list_size(void)
473 {
474     return BLE_HW_RESOLV_LIST_SIZE;
475 }
476 
477 /**
478  * Called to determine if the address received was resolved.
479  *
480  * @return int  Negative values indicate unresolved address; positive values
481  *              indicate index in resolving list of resolved address.
482  */
483 int
ble_hw_resolv_list_match(void)484 ble_hw_resolv_list_match(void)
485 {
486     uint32_t index;
487 
488     if (NRF_AAR->EVENTS_END) {
489         if (NRF_AAR->EVENTS_RESOLVED) {
490             index = NRF_AAR->STATUS;
491             return (int)index;
492         }
493     }
494 
495     return -1;
496 }
497 #endif
498