1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2019 Damien P. George
7  * Copyright (c) 2020 Jim Mussared
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to deal
11  * in the Software without restriction, including without limitation the rights
12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25  * THE SOFTWARE.
26  */
27 
28 #include <stdio.h>
29 #include <string.h>
30 
31 #include "py/mperrno.h"
32 #include "py/mphal.h"
33 #include "py/runtime.h"
34 #include "extmod/modbluetooth.h"
35 #include "mpbthciport.h"
36 #include "rtc.h"
37 #include "rfcore.h"
38 
39 #if defined(STM32WB)
40 
41 #include "stm32wbxx_ll_ipcc.h"
42 
43 #if MICROPY_PY_BLUETOOTH
44 
45 #if MICROPY_BLUETOOTH_NIMBLE
46 // For mp_bluetooth_nimble_hci_uart_wfi
47 #include "nimble/nimble_npl.h"
48 #else
49 #error "STM32WB must use NimBLE."
50 #endif
51 
52 #if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
53 #error "STM32WB must use synchronous BLE events."
54 #endif
55 
56 #endif
57 
58 #define DEBUG_printf(...) // printf("rfcore: " __VA_ARGS__)
59 
60 // Define to 1 to print traces of HCI packets
61 #define HCI_TRACE (0)
62 
63 #define IPCC_CH_BLE         (LL_IPCC_CHANNEL_1) // BLE HCI command and response
64 #define IPCC_CH_SYS         (LL_IPCC_CHANNEL_2) // system HCI command and response
65 #define IPCC_CH_MM          (LL_IPCC_CHANNEL_4) // release buffer
66 #define IPCC_CH_HCI_ACL     (LL_IPCC_CHANNEL_6) // HCI ACL outgoing data
67 
68 #define OGF_CTLR_BASEBAND        (0x03)
69 #define OCF_CB_RESET             (0x03)
70 #define OCF_CB_SET_EVENT_MASK2   (0x63)
71 
72 #define OGF_VENDOR                        (0x3f)
73 #define OCF_WRITE_CONFIG                  (0x0c)
74 #define OCF_SET_TX_POWER                  (0x0f)
75 #define OCF_BLE_INIT                      (0x66)
76 #define OCF_C2_FLASH_ERASE_ACTIVITY       (0x69)
77 #define OCF_C2_SET_FLASH_ACTIVITY_CONTROL (0x73)
78 
79 #define HCI_OPCODE(ogf, ocf) ((ogf) << 10 | (ocf))
80 
81 #define HCI_KIND_BT_CMD (0x01) // <kind=1>...?
82 #define HCI_KIND_BT_ACL (0x02) // <kind=2><?><?><len LSB><len MSB>
83 #define HCI_KIND_BT_EVENT (0x04) // <kind=4><op><len><data...>
84 #define HCI_KIND_VENDOR_RESPONSE (0x11)
85 #define HCI_KIND_VENDOR_EVENT (0x12)
86 
87 #define HCI_EVENT_COMMAND_COMPLETE            (0x0E) // <num packets><opcode 16><status><data...>
88 #define HCI_EVENT_COMMAND_STATUS              (0x0F) // <status><num_packets><opcode 16>
89 #define HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS (0x13) // <num>(<handle 16><completed 16>)*
90 
91 #define SYS_ACK_TIMEOUT_MS (250)
92 #define BLE_ACK_TIMEOUT_MS (250)
93 
94 // AN5185
95 #define MAGIC_FUS_ACTIVE 0xA94656B9
96 // AN5289
97 #define MAGIC_IPCC_MEM_INCORRECT 0x3DE96F61
98 
99 volatile bool hci_acl_cmd_pending = false;
100 
101 typedef struct _tl_list_node_t {
102     volatile struct _tl_list_node_t *next;
103     volatile struct _tl_list_node_t *prev;
104     uint8_t body[0];
105 } tl_list_node_t;
106 
107 typedef struct _parse_hci_info_t {
108     int (*cb_fun)(void *, const uint8_t *, size_t);
109     void *cb_env;
110     bool was_hci_reset_evt;
111 } parse_hci_info_t;
112 
113 // Version
114 // [0:3]   = Build - 0: Untracked - 15:Released - x: Tracked version
115 // [4:7]   = branch - 0: Mass Market - x: ...
116 // [8:15]  = Subversion
117 // [16:23] = Version minor
118 // [24:31] = Version major
119 
120 // Memory Size
121 // [0:7]   = Flash (Number of 4k sectors)
122 // [8:15]  = Reserved (Shall be set to 0 - may be used as flash extension)
123 // [16:23] = SRAM2b (Number of 1k sectors)
124 // [24:31] = SRAM2a (Number of 1k sectors)
125 
126 typedef union __attribute__((packed)) _ipcc_device_info_table_t {
127     struct {
128         uint32_t table_state;
129         uint8_t reserved0;
130         uint8_t last_fus_state;
131         uint8_t last_ws_state;
132         uint8_t ws_type;
133         uint32_t safeboot_version;
134         uint32_t fus_version;
135         uint32_t fus_memorysize;
136         uint32_t ws_version;
137         uint32_t ws_memorysize;
138         uint32_t ws_ble_info;
139         uint32_t ws_thread_info;
140         uint32_t reserved1;
141         uint64_t uid64;
142         uint16_t device_id;
143         uint16_t pad;
144     } fus;
145     struct {
146         uint32_t safeboot_version;
147         uint32_t fus_version;
148         uint32_t fus_memorysize;
149         uint32_t fus_info;
150         uint32_t fw_version;
151         uint32_t fw_memorysize;
152         uint32_t fw_infostack;
153         uint32_t fw_reserved;
154     } ws;
155 } ipcc_device_info_table_t;
156 
157 typedef struct __attribute__((packed)) _ipcc_ble_table_t {
158     uint8_t *pcmd_buffer;
159     uint8_t *pcs_buffer;
160     tl_list_node_t *pevt_queue;
161     uint8_t *phci_acl_data_buffer;
162 } ipcc_ble_table_t;
163 
164 // msg
165 // [0:7]  = cmd/evt
166 // [8:31] = Reserved
167 typedef struct __attribute__((packed)) _ipcc_sys_table_t {
168     uint8_t *pcmd_buffer;
169     tl_list_node_t *sys_queue;
170 } ipcc_sys_table_t;
171 
172 typedef struct __attribute__((packed)) _ipcc_mem_manager_table_t {
173     uint8_t *spare_ble_buffer;
174     uint8_t *spare_sys_buffer;
175     uint8_t *blepool;
176     uint32_t blepoolsize;
177     tl_list_node_t *pevt_free_buffer_queue;
178     uint8_t *traces_evt_pool;
179     uint32_t tracespoolsize;
180 } ipcc_mem_manager_table_t;
181 
182 typedef struct __attribute__((packed)) _ipcc_ref_table_t {
183     ipcc_device_info_table_t *p_device_info_table;
184     ipcc_ble_table_t *p_ble_table;
185     void *p_thread_table;
186     ipcc_sys_table_t *p_sys_table;
187     ipcc_mem_manager_table_t *p_mem_manager_table;
188     void *p_traces_table;
189     void *p_mac_802_15_4_table;
190     void *p_zigbee_table;
191     void *p_lld_tests_table;
192     void *p_lld_ble_table;
193 } ipcc_ref_table_t;
194 
195 // The stm32wb55xg.ld script puts .bss.ipcc_mem_* into SRAM2A and .bss_ipcc_membuf_* into SRAM2B.
196 // It also leaves 64 bytes at the start of SRAM2A for the ref table.
197 
198 STATIC ipcc_device_info_table_t ipcc_mem_dev_info_tab; // mem1
199 STATIC ipcc_ble_table_t ipcc_mem_ble_tab; // mem1
200 STATIC ipcc_sys_table_t ipcc_mem_sys_tab; // mem1
201 STATIC ipcc_mem_manager_table_t ipcc_mem_memmgr_tab; // mem1
202 
203 STATIC uint8_t ipcc_membuf_sys_cmd_buf[272];  // mem2
204 STATIC tl_list_node_t ipcc_mem_sys_queue; // mem1
205 
206 STATIC tl_list_node_t ipcc_mem_memmgr_free_buf_queue; // mem1
207 STATIC uint8_t ipcc_membuf_memmgr_ble_spare_evt_buf[272]; // mem2
208 STATIC uint8_t ipcc_membuf_memmgr_sys_spare_evt_buf[272]; // mem2
209 STATIC uint8_t ipcc_membuf_memmgr_evt_pool[6 * 272];  // mem2
210 
211 STATIC uint8_t ipcc_membuf_ble_cmd_buf[272]; // mem2
212 STATIC uint8_t ipcc_membuf_ble_cs_buf[272]; // mem2
213 STATIC tl_list_node_t ipcc_mem_ble_evt_queue; // mem1
214 STATIC uint8_t ipcc_membuf_ble_hci_acl_data_buf[272]; // mem2
215 
216 /******************************************************************************/
217 // Transport layer linked list
218 
tl_list_init(volatile tl_list_node_t * n)219 STATIC void tl_list_init(volatile tl_list_node_t *n) {
220     n->next = n;
221     n->prev = n;
222 }
223 
tl_list_unlink(volatile tl_list_node_t * n)224 STATIC volatile tl_list_node_t *tl_list_unlink(volatile tl_list_node_t *n) {
225     volatile tl_list_node_t *next = n->next;
226     volatile tl_list_node_t *prev = n->prev;
227     prev->next = next;
228     next->prev = prev;
229     return next;
230 }
231 
tl_list_append(volatile tl_list_node_t * head,volatile tl_list_node_t * n)232 STATIC void tl_list_append(volatile tl_list_node_t *head, volatile tl_list_node_t *n) {
233     n->next = head;
234     n->prev = head->prev;
235     head->prev->next = n;
236     head->prev = n;
237 }
238 
239 /******************************************************************************/
240 // IPCC interface
241 
get_buffer_table(void)242 STATIC volatile ipcc_ref_table_t *get_buffer_table(void) {
243     // The IPCCDBA option bytes must not be changed without
244     // making a corresponding change to the linker script.
245     return (volatile ipcc_ref_table_t *)(SRAM2A_BASE + LL_FLASH_GetIPCCBufferAddr() * 4);
246 }
247 
ipcc_init(uint32_t irq_pri)248 void ipcc_init(uint32_t irq_pri) {
249     DEBUG_printf("ipcc_init\n");
250 
251     // Setup buffer table pointers
252     volatile ipcc_ref_table_t *tab = get_buffer_table();
253     tab->p_device_info_table = &ipcc_mem_dev_info_tab;
254     tab->p_ble_table = &ipcc_mem_ble_tab;
255     tab->p_sys_table = &ipcc_mem_sys_tab;
256     tab->p_mem_manager_table = &ipcc_mem_memmgr_tab;
257 
258     // Start IPCC peripheral
259     __HAL_RCC_IPCC_CLK_ENABLE();
260 
261     // Enable receive IRQ on the BLE channel.
262     LL_C1_IPCC_EnableIT_RXO(IPCC);
263     LL_C1_IPCC_DisableReceiveChannel(IPCC, LL_IPCC_CHANNEL_1 | LL_IPCC_CHANNEL_2 | LL_IPCC_CHANNEL_3 | LL_IPCC_CHANNEL_4 | LL_IPCC_CHANNEL_5 | LL_IPCC_CHANNEL_6);
264     LL_C1_IPCC_EnableReceiveChannel(IPCC, IPCC_CH_BLE);
265     NVIC_SetPriority(IPCC_C1_RX_IRQn, irq_pri);
266     HAL_NVIC_EnableIRQ(IPCC_C1_RX_IRQn);
267 
268     // Device info table will be populated by FUS/WS on CPU2 boot.
269 
270     // Populate system table
271     tl_list_init(&ipcc_mem_sys_queue);
272     ipcc_mem_sys_tab.pcmd_buffer = ipcc_membuf_sys_cmd_buf;
273     ipcc_mem_sys_tab.sys_queue = &ipcc_mem_sys_queue;
274 
275     // Populate memory manager table
276     tl_list_init(&ipcc_mem_memmgr_free_buf_queue);
277     ipcc_mem_memmgr_tab.spare_ble_buffer = ipcc_membuf_memmgr_ble_spare_evt_buf;
278     ipcc_mem_memmgr_tab.spare_sys_buffer = ipcc_membuf_memmgr_sys_spare_evt_buf;
279     ipcc_mem_memmgr_tab.blepool = ipcc_membuf_memmgr_evt_pool;
280     ipcc_mem_memmgr_tab.blepoolsize = sizeof(ipcc_membuf_memmgr_evt_pool);
281     ipcc_mem_memmgr_tab.pevt_free_buffer_queue = &ipcc_mem_memmgr_free_buf_queue;
282     ipcc_mem_memmgr_tab.traces_evt_pool = NULL;
283     ipcc_mem_memmgr_tab.tracespoolsize = 0;
284 
285     // Populate BLE table
286     tl_list_init(&ipcc_mem_ble_evt_queue);
287     ipcc_mem_ble_tab.pcmd_buffer = ipcc_membuf_ble_cmd_buf;
288     ipcc_mem_ble_tab.pcs_buffer = ipcc_membuf_ble_cs_buf;
289     ipcc_mem_ble_tab.pevt_queue = &ipcc_mem_ble_evt_queue;
290     ipcc_mem_ble_tab.phci_acl_data_buffer = ipcc_membuf_ble_hci_acl_data_buf;
291 }
292 
293 /******************************************************************************/
294 // Transport layer HCI interface
295 
296 // The WS firmware doesn't support OCF_CB_SET_EVENT_MASK2, and fails with:
297 //  v1.8.0.0.4 (and below): HCI_EVENT_COMMAND_COMPLETE with a non-zero status
298 //  v1.9.0.0.4 (and above): HCI_EVENT_COMMAND_STATUS with a non-zero status
299 // In either case we detect the failure response and inject this response
300 // instead (which is HCI_EVENT_COMMAND_COMPLETE for OCF_CB_SET_EVENT_MASK2
301 // with status=0).
302 STATIC const uint8_t set_event_event_mask2_fix_payload[] = { 0x04, 0x0e, 0x04, 0x01, 0x63, 0x0c, 0x00 };
303 
tl_parse_hci_msg(const uint8_t * buf,parse_hci_info_t * parse)304 STATIC size_t tl_parse_hci_msg(const uint8_t *buf, parse_hci_info_t *parse) {
305     const char *info;
306     #if HCI_TRACE
307     int applied_set_event_event_mask2_fix = 0;
308     #endif
309     size_t len;
310     switch (buf[0]) {
311         case HCI_KIND_BT_ACL: {
312             info = "HCI_ACL";
313 
314             len = 5 + buf[3] + (buf[4] << 8);
315             if (parse != NULL) {
316                 parse->cb_fun(parse->cb_env, buf, len);
317             }
318             break;
319         }
320         case HCI_KIND_BT_EVENT: {
321             info = "HCI_EVT";
322 
323             // Acknowledgment of a pending ACL request, allow another one to be sent.
324             if (buf[1] == HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS) {
325                 hci_acl_cmd_pending = false;
326             }
327 
328             len = 3 + buf[2];
329             if (parse != NULL) {
330 
331                 if (buf[1] == HCI_EVENT_COMMAND_COMPLETE && len == 7) {
332                     uint16_t opcode = (buf[5] << 8) | buf[4];
333                     uint8_t status = buf[6];
334 
335                     if (opcode == HCI_OPCODE(OGF_CTLR_BASEBAND, OCF_CB_SET_EVENT_MASK2) && status != 0) {
336                         // For WS firmware v1.8.0.0.4 and below. Reply with the "everything OK" payload.
337                         parse->cb_fun(parse->cb_env, set_event_event_mask2_fix_payload, sizeof(set_event_event_mask2_fix_payload));
338                         #if HCI_TRACE
339                         applied_set_event_event_mask2_fix = 18;
340                         #endif
341                         break; // Don't send the original payload.
342                     }
343 
344                     if (opcode == HCI_OPCODE(OGF_CTLR_BASEBAND, OCF_CB_RESET) && status == 0) {
345                         // Controller acknowledged reset command.
346                         // This will trigger setting the MAC address.
347                         parse->was_hci_reset_evt = true;
348                     }
349                 }
350 
351                 if (buf[1] == HCI_EVENT_COMMAND_STATUS && len == 7) {
352                     uint16_t opcode = (buf[6] << 8) | buf[5];
353                     uint8_t status = buf[3];
354 
355                     if (opcode == HCI_OPCODE(OGF_CTLR_BASEBAND, OCF_CB_SET_EVENT_MASK2) && status != 0) {
356                         // For WS firmware v1.9.0.0.4 and higher. Reply with the "everything OK" payload.
357                         parse->cb_fun(parse->cb_env, set_event_event_mask2_fix_payload, sizeof(set_event_event_mask2_fix_payload));
358                         #if HCI_TRACE
359                         applied_set_event_event_mask2_fix = 19;
360                         #endif
361                         break;  // Don't send the original payload.
362                     }
363                 }
364 
365                 parse->cb_fun(parse->cb_env, buf, len);
366             }
367             break;
368         }
369         case HCI_KIND_VENDOR_RESPONSE: {
370             // assert(buf[1] == 0x0e);
371             info = "VEND_RESP";
372             len = 3 + buf[2]; // ???
373             // uint16_t cmd = buf[4] | buf[5] << 8;
374             // uint8_t status = buf[6];
375             break;
376         }
377         case HCI_KIND_VENDOR_EVENT: {
378             // assert(buf[1] == 0xff);
379             info = "VEND_EVT";
380             len = 3 + buf[2]; // ???
381             // uint16_t evt = buf[3] | buf[4] << 8;
382             break;
383         }
384         default:
385             info = "HCI_UNKNOWN";
386             len = 0;
387             break;
388     }
389 
390     #if HCI_TRACE
391     printf("[% 8d] <%s(%02x", mp_hal_ticks_ms(), info, buf[0]);
392     for (int i = 1; i < len; ++i) {
393         printf(":%02x", buf[i]);
394     }
395     printf(")");
396     if (parse && parse->was_hci_reset_evt) {
397         printf(" (reset)");
398     }
399     if (applied_set_event_event_mask2_fix) {
400         printf(" (mask2 fix %d)", applied_set_event_event_mask2_fix);
401     }
402     printf("\n");
403 
404     #else
405     (void)info;
406     #endif
407 
408     return len;
409 }
410 
tl_process_msg(volatile tl_list_node_t * head,unsigned int ch,parse_hci_info_t * parse)411 STATIC void tl_process_msg(volatile tl_list_node_t *head, unsigned int ch, parse_hci_info_t *parse) {
412     volatile tl_list_node_t *cur = head->next;
413     bool added_to_free_queue = false;
414     while (cur != head) {
415         tl_parse_hci_msg((uint8_t *)cur->body, parse);
416 
417         volatile tl_list_node_t *next = tl_list_unlink(cur);
418 
419         // If this node is allocated from the memmgr event pool, then place it into the free buffer.
420         if ((uint8_t *)cur >= ipcc_membuf_memmgr_evt_pool && (uint8_t *)cur < ipcc_membuf_memmgr_evt_pool + sizeof(ipcc_membuf_memmgr_evt_pool)) {
421             // Wait for C2 to indicate that it has finished using the free buffer,
422             // so that we can link the newly-freed memory in to this buffer.
423             // If waiting is needed then it is typically between 5 and 20 microseconds.
424             while (LL_C1_IPCC_IsActiveFlag_CHx(IPCC, IPCC_CH_MM)) {
425             }
426 
427             // Place memory back in free pool.
428             tl_list_append(&ipcc_mem_memmgr_free_buf_queue, cur);
429             added_to_free_queue = true;
430         }
431 
432         cur = next;
433     }
434 
435     if (added_to_free_queue) {
436         // Notify change in free pool.
437         LL_C1_IPCC_SetFlag_CHx(IPCC, IPCC_CH_MM);
438     }
439 }
440 
441 // Only call this when IRQs are disabled on this channel.
tl_check_msg(volatile tl_list_node_t * head,unsigned int ch,parse_hci_info_t * parse)442 STATIC void tl_check_msg(volatile tl_list_node_t *head, unsigned int ch, parse_hci_info_t *parse) {
443     if (LL_C2_IPCC_IsActiveFlag_CHx(IPCC, ch)) {
444         // Process new data.
445         tl_process_msg(head, ch, parse);
446 
447         // Clear receive channel (allows RF core to send more data to us).
448         LL_C1_IPCC_ClearFlag_CHx(IPCC, ch);
449 
450         if (ch == IPCC_CH_BLE) {
451             // Renable IRQs for BLE now that we've cleared the flag.
452             LL_C1_IPCC_EnableReceiveChannel(IPCC, IPCC_CH_BLE);
453         }
454     }
455 }
456 
tl_hci_cmd(uint8_t * cmd,unsigned int ch,uint8_t hdr,uint16_t opcode,const uint8_t * buf,size_t len)457 STATIC void tl_hci_cmd(uint8_t *cmd, unsigned int ch, uint8_t hdr, uint16_t opcode, const uint8_t *buf, size_t len) {
458     tl_list_node_t *n = (tl_list_node_t *)cmd;
459     n->next = NULL;
460     n->prev = NULL;
461     cmd[8] = hdr;
462     cmd[9] = opcode;
463     cmd[10] = opcode >> 8;
464     cmd[11] = len;
465     memcpy(&cmd[12], buf, len);
466 
467     #if HCI_TRACE
468     printf("[% 8d] >HCI(", mp_hal_ticks_ms());
469     for (int i = 0; i < len + 4; ++i) {
470         printf(":%02x", cmd[i + 8]);
471     }
472     printf(")\n");
473     #endif
474 
475     // Indicate that this channel is ready.
476     LL_C1_IPCC_SetFlag_CHx(IPCC, ch);
477 }
478 
tl_sys_wait_ack(const uint8_t * buf,mp_int_t timeout_ms)479 STATIC ssize_t tl_sys_wait_ack(const uint8_t *buf, mp_int_t timeout_ms) {
480     uint32_t t0 = mp_hal_ticks_ms();
481 
482     timeout_ms = MAX(SYS_ACK_TIMEOUT_MS, timeout_ms);
483 
484     // C2 will clear this bit to acknowledge the request.
485     while (LL_C1_IPCC_IsActiveFlag_CHx(IPCC, IPCC_CH_SYS)) {
486         if (mp_hal_ticks_ms() - t0 > timeout_ms) {
487             printf("tl_sys_wait_ack: timeout\n");
488             return -MP_ETIMEDOUT;
489         }
490     }
491 
492     // C1-to-C2 bit cleared, so process the response (just get the length, do
493     // not parse any further).
494     return (ssize_t)tl_parse_hci_msg(buf, NULL);
495 }
496 
tl_sys_hci_cmd_resp(uint16_t opcode,const uint8_t * buf,size_t len,mp_int_t timeout_ms)497 STATIC ssize_t tl_sys_hci_cmd_resp(uint16_t opcode, const uint8_t *buf, size_t len, mp_int_t timeout_ms) {
498     tl_hci_cmd(ipcc_membuf_sys_cmd_buf, IPCC_CH_SYS, 0x10, opcode, buf, len);
499     return tl_sys_wait_ack(ipcc_membuf_sys_cmd_buf, timeout_ms);
500 }
501 
tl_ble_wait_resp(void)502 STATIC int tl_ble_wait_resp(void) {
503     uint32_t t0 = mp_hal_ticks_ms();
504     while (!LL_C2_IPCC_IsActiveFlag_CHx(IPCC, IPCC_CH_BLE)) {
505         if (mp_hal_ticks_ms() - t0 > BLE_ACK_TIMEOUT_MS) {
506             printf("tl_ble_wait_resp: timeout\n");
507             return -MP_ETIMEDOUT;
508         }
509     }
510 
511     // C2 set IPCC flag -- process the data, clear the flag, and re-enable IRQs.
512     tl_check_msg(&ipcc_mem_ble_evt_queue, IPCC_CH_BLE, NULL);
513     return 0;
514 }
515 
516 // Synchronously send a BLE command.
tl_ble_hci_cmd_resp(uint16_t opcode,const uint8_t * buf,size_t len)517 STATIC void tl_ble_hci_cmd_resp(uint16_t opcode, const uint8_t *buf, size_t len) {
518     // Poll for completion rather than wait for IRQ->scheduler.
519     LL_C1_IPCC_DisableReceiveChannel(IPCC, IPCC_CH_BLE);
520     tl_hci_cmd(ipcc_membuf_ble_cmd_buf, IPCC_CH_BLE, HCI_KIND_BT_CMD, opcode, buf, len);
521     tl_ble_wait_resp();
522 }
523 
524 /******************************************************************************/
525 // RF core interface
526 
rfcore_init(void)527 void rfcore_init(void) {
528     DEBUG_printf("rfcore_init\n");
529 
530     // Ensure LSE is running
531     rtc_init_finalise();
532 
533     // Select LSE as RF wakeup source
534     RCC->CSR = (RCC->CSR & ~RCC_CSR_RFWKPSEL) | 1 << RCC_CSR_RFWKPSEL_Pos;
535 
536     // Initialise IPCC and shared memory structures
537     ipcc_init(IRQ_PRI_SDIO);
538 
539     // Boot the second core
540     __SEV();
541     __WFE();
542     PWR->CR4 |= PWR_CR4_C2BOOT;
543 }
544 
545 static const struct {
546     uint8_t *pBleBufferAddress;     // unused
547     uint32_t BleBufferSize;         // unused
548     uint16_t NumAttrRecord;
549     uint16_t NumAttrServ;
550     uint16_t AttrValueArrSize;
551     uint8_t NumOfLinks;
552     uint8_t ExtendedPacketLengthEnable;
553     uint8_t PrWriteListSize;
554     uint8_t MblockCount;
555     uint16_t AttMtu;
556     uint16_t SlaveSca;
557     uint8_t MasterSca;
558     uint8_t LsSource;
559     uint32_t MaxConnEventLength;
560     uint16_t HsStartupTime;
561     uint8_t ViterbiEnable;
562     uint8_t LlOnly;
563     uint8_t HwVersion;
564 } ble_init_params = {
565     0, // pBleBufferAddress
566     0, // BleBufferSize
567     MICROPY_HW_RFCORE_BLE_NUM_GATT_ATTRIBUTES,
568     MICROPY_HW_RFCORE_BLE_NUM_GATT_SERVICES,
569     MICROPY_HW_RFCORE_BLE_ATT_VALUE_ARRAY_SIZE,
570     MICROPY_HW_RFCORE_BLE_NUM_LINK,
571     MICROPY_HW_RFCORE_BLE_DATA_LENGTH_EXTENSION,
572     MICROPY_HW_RFCORE_BLE_PREPARE_WRITE_LIST_SIZE,
573     MICROPY_HW_RFCORE_BLE_MBLOCK_COUNT,
574     MICROPY_HW_RFCORE_BLE_MAX_ATT_MTU,
575     MICROPY_HW_RFCORE_BLE_SLAVE_SCA,
576     MICROPY_HW_RFCORE_BLE_MASTER_SCA,
577     MICROPY_HW_RFCORE_BLE_LSE_SOURCE,
578     MICROPY_HW_RFCORE_BLE_MAX_CONN_EVENT_LENGTH,
579     MICROPY_HW_RFCORE_BLE_HSE_STARTUP_TIME,
580     MICROPY_HW_RFCORE_BLE_VITERBI_MODE,
581     MICROPY_HW_RFCORE_BLE_LL_ONLY,
582     0, // HwVersion
583 };
584 
rfcore_ble_init(void)585 void rfcore_ble_init(void) {
586     DEBUG_printf("rfcore_ble_init\n");
587 
588     // Clear any outstanding messages from ipcc_init.
589     tl_check_msg(&ipcc_mem_sys_queue, IPCC_CH_SYS, NULL);
590 
591     // Configure and reset the BLE controller.
592     tl_sys_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_BLE_INIT), (const uint8_t *)&ble_init_params, sizeof(ble_init_params), 0);
593     tl_ble_hci_cmd_resp(HCI_OPCODE(0x03, 0x0003), NULL, 0);
594 
595     // Enable PES rather than SEM7 to moderate flash access between the cores.
596     uint8_t buf = 0; // FLASH_ACTIVITY_CONTROL_PES
597     tl_sys_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_C2_SET_FLASH_ACTIVITY_CONTROL), &buf, 1, 0);
598 }
599 
rfcore_ble_hci_cmd(size_t len,const uint8_t * src)600 void rfcore_ble_hci_cmd(size_t len, const uint8_t *src) {
601     DEBUG_printf("rfcore_ble_hci_cmd\n");
602 
603     #if HCI_TRACE
604     printf("[% 8d] >HCI_CMD(%02x", mp_hal_ticks_ms(), src[0]);
605     for (int i = 1; i < len; ++i) {
606         printf(":%02x", src[i]);
607     }
608     printf(")\n");
609     #endif
610 
611     tl_list_node_t *n;
612     uint32_t ch;
613     if (src[0] == HCI_KIND_BT_CMD) {
614         // The STM32WB has a problem when address resolution is enabled: under certain
615         // conditions the MCU can get into a state where it draws an additional 10mA
616         // or so and eventually ends up with a broken BLE RX path in the silicon.  A
617         // simple way to reproduce this is to enable address resolution (which is the
618         // default for NimBLE) and start the device advertising.  If there is enough
619         // BLE activity in the vicinity then the device will at some point enter the
620         // bad state and, if left long enough, will have permanent BLE RX damage.
621         //
622         // STMicroelectronics are aware of this issue.  The only known workaround at
623         // this stage is to not enable address resolution.  We do that here by
624         // intercepting any command that enables address resolution and convert it
625         // into a command that disables address resolution.
626         //
627         // OGF=0x08 OCF=0x002d HCI_LE_Set_Address_Resolution_Enable
628         if (len == 5 && memcmp(src + 1, "\x2d\x20\x01\x01", 4) == 0) {
629             src = (const uint8_t *)"\x01\x2d\x20\x01\x00";
630         }
631 
632         n = (tl_list_node_t *)&ipcc_membuf_ble_cmd_buf[0];
633         ch = IPCC_CH_BLE;
634     } else if (src[0] == HCI_KIND_BT_ACL) {
635         n = (tl_list_node_t *)&ipcc_membuf_ble_hci_acl_data_buf[0];
636         ch = IPCC_CH_HCI_ACL;
637 
638         // Give the previous ACL command up to 100ms to complete.
639         mp_uint_t timeout_start_ticks_ms = mp_hal_ticks_ms();
640         while (hci_acl_cmd_pending) {
641             if (mp_hal_ticks_ms() - timeout_start_ticks_ms > 100) {
642                 break;
643             }
644             #if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE
645             mp_bluetooth_nimble_hci_uart_wfi();
646             #endif
647         }
648 
649         // Prevent sending another command until this one returns with HCI_EVENT_COMMAND_{COMPLETE,STATUS}.
650         hci_acl_cmd_pending = true;
651     } else {
652         printf("** UNEXPECTED HCI HDR: 0x%02x **\n", src[0]);
653         return;
654     }
655 
656     n->next = NULL;
657     n->prev = NULL;
658     memcpy(n->body, src, len);
659 
660     // IPCC indicate.
661     LL_C1_IPCC_SetFlag_CHx(IPCC, ch);
662 }
663 
rfcore_ble_check_msg(int (* cb)(void *,const uint8_t *,size_t),void * env)664 void rfcore_ble_check_msg(int (*cb)(void *, const uint8_t *, size_t), void *env) {
665     parse_hci_info_t parse = { cb, env, false };
666     tl_check_msg(&ipcc_mem_ble_evt_queue, IPCC_CH_BLE, &parse);
667 
668     // Intercept HCI_Reset events and reconfigure the controller following the reset
669     if (parse.was_hci_reset_evt) {
670         uint8_t buf[8];
671         buf[0] = 0; // config offset
672         buf[1] = 6; // config length
673         mp_hal_get_mac(MP_HAL_MAC_BDADDR, &buf[2]);
674         #define SWAP_UINT8(a, b) { uint8_t temp = a; a = b; b = temp; \
675 }
676         SWAP_UINT8(buf[2], buf[7]);
677         SWAP_UINT8(buf[3], buf[6]);
678         SWAP_UINT8(buf[4], buf[5]);
679         tl_ble_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_WRITE_CONFIG), buf, 8); // set BDADDR
680     }
681 }
682 
683 // "level" is 0x00-0x1f, ranging from -40 dBm to +6 dBm (not linear).
rfcore_ble_set_txpower(uint8_t level)684 void rfcore_ble_set_txpower(uint8_t level) {
685     uint8_t buf[2] = { 0x00, level };
686     tl_ble_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_SET_TX_POWER), buf, 2);
687 }
688 
rfcore_start_flash_erase(void)689 void rfcore_start_flash_erase(void) {
690     uint8_t buf = 1; // ERASE_ACTIVITY_ON
691     tl_sys_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_C2_FLASH_ERASE_ACTIVITY), &buf, 1, 0);
692 }
693 
rfcore_end_flash_erase(void)694 void rfcore_end_flash_erase(void) {
695     uint8_t buf = 0; // ERASE_ACTIVITY_OFF
696     tl_sys_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_C2_FLASH_ERASE_ACTIVITY), &buf, 1, 0);
697 }
698 
699 /******************************************************************************/
700 // IPCC IRQ Handlers
701 
IPCC_C1_TX_IRQHandler(void)702 void IPCC_C1_TX_IRQHandler(void) {
703     IRQ_ENTER(IPCC_C1_TX_IRQn);
704     IRQ_EXIT(IPCC_C1_TX_IRQn);
705 }
706 
IPCC_C1_RX_IRQHandler(void)707 void IPCC_C1_RX_IRQHandler(void) {
708     IRQ_ENTER(IPCC_C1_RX_IRQn);
709 
710     DEBUG_printf("IPCC_C1_RX_IRQHandler\n");
711 
712     if (LL_C2_IPCC_IsActiveFlag_CHx(IPCC, IPCC_CH_BLE)) {
713         // Disable this IRQ until the incoming data is processed (in tl_check_msg).
714         LL_C1_IPCC_DisableReceiveChannel(IPCC, IPCC_CH_BLE);
715 
716         #if MICROPY_PY_BLUETOOTH
717         // Queue up the scheduler to process UART data and run events.
718         mp_bluetooth_hci_poll_now();
719         #endif
720     }
721 
722     IRQ_EXIT(IPCC_C1_RX_IRQn);
723 }
724 
725 /******************************************************************************/
726 // MicroPython bindings
727 
rfcore_status(void)728 STATIC mp_obj_t rfcore_status(void) {
729     return mp_obj_new_int_from_uint(ipcc_mem_dev_info_tab.fus.table_state);
730 }
731 MP_DEFINE_CONST_FUN_OBJ_0(rfcore_status_obj, rfcore_status);
732 
get_version_tuple(uint32_t data)733 STATIC mp_obj_t get_version_tuple(uint32_t data) {
734     mp_obj_t items[] = {
735         MP_OBJ_NEW_SMALL_INT(data >> 24), MP_OBJ_NEW_SMALL_INT(data >> 16 & 0xFF), MP_OBJ_NEW_SMALL_INT(data >> 8 & 0xFF), MP_OBJ_NEW_SMALL_INT(data >> 4 & 0xF), MP_OBJ_NEW_SMALL_INT(data & 0xF)
736     };
737     return mp_obj_new_tuple(5, items);
738 }
739 
rfcore_fw_version(mp_obj_t fw_id_in)740 STATIC mp_obj_t rfcore_fw_version(mp_obj_t fw_id_in) {
741     if (ipcc_mem_dev_info_tab.fus.table_state == MAGIC_IPCC_MEM_INCORRECT) {
742         mp_raise_OSError(MP_EINVAL);
743     }
744     mp_int_t fw_id = mp_obj_get_int(fw_id_in);
745     bool fus_active = ipcc_mem_dev_info_tab.fus.table_state == MAGIC_FUS_ACTIVE;
746     uint32_t v;
747     if (fw_id == 0) {
748         // FUS
749         v = fus_active ? ipcc_mem_dev_info_tab.fus.fus_version : ipcc_mem_dev_info_tab.ws.fus_version;
750     } else {
751         // WS
752         v = fus_active ? ipcc_mem_dev_info_tab.fus.ws_version : ipcc_mem_dev_info_tab.ws.fw_version;
753     }
754     return get_version_tuple(v);
755 }
756 MP_DEFINE_CONST_FUN_OBJ_1(rfcore_fw_version_obj, rfcore_fw_version);
757 
rfcore_sys_hci(size_t n_args,const mp_obj_t * args)758 STATIC mp_obj_t rfcore_sys_hci(size_t n_args, const mp_obj_t *args) {
759     if (ipcc_mem_dev_info_tab.fus.table_state == MAGIC_IPCC_MEM_INCORRECT) {
760         mp_raise_OSError(MP_EINVAL);
761     }
762     mp_int_t ogf = mp_obj_get_int(args[0]);
763     mp_int_t ocf = mp_obj_get_int(args[1]);
764     mp_buffer_info_t bufinfo = {0};
765     mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
766     mp_int_t timeout_ms = 0;
767     if (n_args >= 4) {
768         timeout_ms = mp_obj_get_int(args[3]);
769     }
770     ssize_t len = tl_sys_hci_cmd_resp(HCI_OPCODE(ogf, ocf), bufinfo.buf, bufinfo.len, timeout_ms);
771     if (len < 0) {
772         mp_raise_OSError(-len);
773     }
774     return mp_obj_new_bytes(ipcc_membuf_sys_cmd_buf, len);
775 }
776 MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rfcore_sys_hci_obj, 3, 4, rfcore_sys_hci);
777 
778 #endif // defined(STM32WB)
779