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