diff options
-rw-r--r-- | ports/stm32/modstm.c | 7 | ||||
-rw-r--r-- | ports/stm32/rfcore.c | 103 | ||||
-rw-r--r-- | ports/stm32/rfcore.h | 4 |
3 files changed, 96 insertions, 18 deletions
diff --git a/ports/stm32/modstm.c b/ports/stm32/modstm.c index 418b8bde2..3f4f33979 100644 --- a/ports/stm32/modstm.c +++ b/ports/stm32/modstm.c @@ -30,6 +30,7 @@ #include "py/obj.h" #include "py/objint.h" #include "extmod/machine_mem.h" +#include "rfcore.h" #include "portmodules.h" #if MICROPY_PY_STM @@ -44,6 +45,12 @@ STATIC const mp_rom_map_elem_t stm_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) }, #include "genhdr/modstm_const.h" + + #if defined(STM32WB) + { MP_ROM_QSTR(MP_QSTR_rfcore_status), MP_ROM_PTR(&rfcore_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_rfcore_fw_version), MP_ROM_PTR(&rfcore_fw_version_obj) }, + { MP_ROM_QSTR(MP_QSTR_rfcore_sys_hci), MP_ROM_PTR(&rfcore_sys_hci_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(stm_module_globals, stm_module_globals_table); diff --git a/ports/stm32/rfcore.c b/ports/stm32/rfcore.c index dc23bbe0b..436042cc2 100644 --- a/ports/stm32/rfcore.c +++ b/ports/stm32/rfcore.c @@ -30,6 +30,7 @@ #include "py/mperrno.h" #include "py/mphal.h" +#include "py/runtime.h" #include "rtc.h" #include "rfcore.h" @@ -66,9 +67,16 @@ #define HCI_EVENT_COMMAND_COMPLETE (0x0E) // <num packets><opcode 16><status><data...> -#define SYS_ACK_TIMEOUT_MS (250) +// There can be quite long delays during firmware update. +#define SYS_ACK_TIMEOUT_MS (1000) + #define BLE_ACK_TIMEOUT_MS (250) +// AN5185 +#define MAGIC_FUS_ACTIVE 0xA94656B9 +// AN5289 +#define MAGIC_IPCC_MEM_INCORRECT 0x3DE96F61 + typedef struct _tl_list_node_t { volatile struct _tl_list_node_t *next; volatile struct _tl_list_node_t *prev; @@ -267,10 +275,10 @@ void ipcc_init(uint32_t irq_pri) { /******************************************************************************/ // Transport layer HCI interface -STATIC void tl_parse_hci_msg(const uint8_t *buf, parse_hci_info_t *parse) { +STATIC size_t tl_parse_hci_msg(const uint8_t *buf, parse_hci_info_t *parse) { const char *info; - size_t len = 0; bool applied_set_event_event_mask2_fix = false; + size_t len; switch (buf[0]) { case HCI_KIND_BT_ACL: { info = "HCI_ACL"; @@ -334,6 +342,7 @@ STATIC void tl_parse_hci_msg(const uint8_t *buf, parse_hci_info_t *parse) { } default: info = "HCI_UNKNOWN"; + len = 0; break; } @@ -354,6 +363,8 @@ STATIC void tl_parse_hci_msg(const uint8_t *buf, parse_hci_info_t *parse) { #else (void)info; #endif + + return len; } STATIC void tl_process_msg(volatile tl_list_node_t *head, unsigned int ch, parse_hci_info_t *parse) { @@ -397,7 +408,7 @@ STATIC void tl_check_msg_ble(volatile tl_list_node_t *head, parse_hci_info_t *pa } } -STATIC void tl_hci_cmd(uint8_t *cmd, unsigned int ch, uint8_t hdr, uint16_t opcode, size_t len, const uint8_t *buf) { +STATIC void tl_hci_cmd(uint8_t *cmd, unsigned int ch, uint8_t hdr, uint16_t opcode, const uint8_t *buf, size_t len) { tl_list_node_t *n = (tl_list_node_t *)cmd; n->next = n; n->prev = n; @@ -407,11 +418,19 @@ STATIC void tl_hci_cmd(uint8_t *cmd, unsigned int ch, uint8_t hdr, uint16_t opco cmd[11] = len; memcpy(&cmd[12], buf, len); + #if HCI_TRACE + printf("[% 8d] >HCI(", mp_hal_ticks_ms()); + for (int i = 0; i < len + 4; ++i) { + printf(":%02x", cmd[i + 8]); + } + printf(")\n"); + #endif + // Indicate that this channel is ready. LL_C1_IPCC_SetFlag_CHx(IPCC, ch); } -STATIC int tl_sys_wait_ack(const uint8_t *buf) { +STATIC ssize_t tl_sys_wait_ack(const uint8_t *buf) { uint32_t t0 = mp_hal_ticks_ms(); // C2 will clear this bit to acknowledge the request. @@ -422,14 +441,14 @@ STATIC int tl_sys_wait_ack(const uint8_t *buf) { } } - // C1-to-C2 bit cleared, so process (but ignore) the response. - tl_parse_hci_msg(buf, NULL); - return 0; + // C1-to-C2 bit cleared, so process the response (just get the length, do + // not parse any further). + return (ssize_t)tl_parse_hci_msg(buf, NULL); } -STATIC void tl_sys_hci_cmd_resp(uint16_t opcode, size_t len, const uint8_t *buf) { - tl_hci_cmd(ipcc_membuf_sys_cmd_buf, IPCC_CH_SYS, 0x10, opcode, len, buf); - tl_sys_wait_ack(ipcc_membuf_sys_cmd_buf); +STATIC ssize_t tl_sys_hci_cmd_resp(uint16_t opcode, const uint8_t *buf, size_t len) { + tl_hci_cmd(ipcc_membuf_sys_cmd_buf, IPCC_CH_SYS, 0x10, opcode, buf, len); + return tl_sys_wait_ack(ipcc_membuf_sys_cmd_buf); } STATIC int tl_ble_wait_resp(void) { @@ -447,10 +466,9 @@ STATIC int tl_ble_wait_resp(void) { } // Synchronously send a BLE command. -STATIC void tl_ble_hci_cmd_resp(uint16_t opcode, size_t len, const uint8_t *buf) { - tl_hci_cmd(ipcc_membuf_ble_cmd_buf, IPCC_CH_BLE, HCI_KIND_BT_CMD, opcode, len, buf); +STATIC void tl_ble_hci_cmd_resp(uint16_t opcode, const uint8_t *buf, size_t len) { + tl_hci_cmd(ipcc_membuf_ble_cmd_buf, IPCC_CH_BLE, HCI_KIND_BT_CMD, opcode, buf, len); tl_ble_wait_resp(); - } /******************************************************************************/ @@ -522,8 +540,8 @@ void rfcore_ble_init(void) { tl_check_msg_ble(&ipcc_mem_ble_evt_queue, NULL); // Configure and reset the BLE controller - tl_sys_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_BLE_INIT), sizeof(ble_init_params), (const uint8_t *)&ble_init_params); - tl_ble_hci_cmd_resp(HCI_OPCODE(0x03, 0x0003), 0, NULL); + tl_sys_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_BLE_INIT), (const uint8_t *)&ble_init_params, sizeof(ble_init_params)); + tl_ble_hci_cmd_resp(HCI_OPCODE(0x03, 0x0003), NULL, 0); } void rfcore_ble_hci_cmd(size_t len, const uint8_t *src) { @@ -573,14 +591,14 @@ void rfcore_ble_check_msg(int (*cb)(void *, const uint8_t *, size_t), void *env) SWAP_UINT8(buf[2], buf[7]); SWAP_UINT8(buf[3], buf[6]); SWAP_UINT8(buf[4], buf[5]); - tl_ble_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_WRITE_CONFIG), 8, buf); // set BDADDR + tl_ble_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_WRITE_CONFIG), buf, 8); // set BDADDR } } // "level" is 0x00-0x1f, ranging from -40 dBm to +6 dBm (not linear). void rfcore_ble_set_txpower(uint8_t level) { uint8_t buf[2] = { 0x00, level }; - tl_ble_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_SET_TX_POWER), 2, buf); + tl_ble_hci_cmd_resp(HCI_OPCODE(OGF_VENDOR, OCF_SET_TX_POWER), buf, 2); } // IPCC IRQ Handlers @@ -605,4 +623,53 @@ void IPCC_C1_RX_IRQHandler(void) { IRQ_EXIT(IPCC_C1_RX_IRQn); } +/******************************************************************************/ +// MicroPython bindings + +STATIC mp_obj_t rfcore_status(void) { + return mp_obj_new_int_from_uint(ipcc_mem_dev_info_tab.fus.table_state); +} +MP_DEFINE_CONST_FUN_OBJ_0(rfcore_status_obj, rfcore_status); + +STATIC mp_obj_t get_version_tuple(uint32_t data) { + mp_obj_t items[] = { + 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) + }; + return mp_obj_new_tuple(5, items); +} + +STATIC mp_obj_t rfcore_fw_version(mp_obj_t fw_id_in) { + if (ipcc_mem_dev_info_tab.fus.table_state == MAGIC_IPCC_MEM_INCORRECT) { + mp_raise_OSError(MP_EINVAL); + } + mp_int_t fw_id = mp_obj_get_int(fw_id_in); + bool fus_active = ipcc_mem_dev_info_tab.fus.table_state == MAGIC_FUS_ACTIVE; + uint32_t v; + if (fw_id == 0) { + // FUS + v = fus_active ? ipcc_mem_dev_info_tab.fus.fus_version : ipcc_mem_dev_info_tab.ws.fus_version; + } else { + // WS + v = fus_active ? ipcc_mem_dev_info_tab.fus.ws_version : ipcc_mem_dev_info_tab.ws.fw_version; + } + return get_version_tuple(v); +} +MP_DEFINE_CONST_FUN_OBJ_1(rfcore_fw_version_obj, rfcore_fw_version); + +STATIC mp_obj_t rfcore_sys_hci(mp_obj_t ogf_in, mp_obj_t ocf_in, mp_obj_t cmd_in) { + if (ipcc_mem_dev_info_tab.fus.table_state == MAGIC_IPCC_MEM_INCORRECT) { + mp_raise_OSError(MP_EINVAL); + } + mp_int_t ogf = mp_obj_get_int(ogf_in); + mp_int_t ocf = mp_obj_get_int(ocf_in); + mp_buffer_info_t bufinfo = {0}; + mp_get_buffer_raise(cmd_in, &bufinfo, MP_BUFFER_READ); + ssize_t len = tl_sys_hci_cmd_resp(HCI_OPCODE(ogf, ocf), bufinfo.buf, bufinfo.len); + if (len < 0) { + mp_raise_OSError(-len); + } + return mp_obj_new_bytes(ipcc_membuf_sys_cmd_buf, len); +} +MP_DEFINE_CONST_FUN_OBJ_3(rfcore_sys_hci_obj, rfcore_sys_hci); + #endif // defined(STM32WB) diff --git a/ports/stm32/rfcore.h b/ports/stm32/rfcore.h index fbe111e1e..39f6220a3 100644 --- a/ports/stm32/rfcore.h +++ b/ports/stm32/rfcore.h @@ -35,4 +35,8 @@ void rfcore_ble_hci_cmd(size_t len, const uint8_t *src); void rfcore_ble_check_msg(int (*cb)(void *, const uint8_t *, size_t), void *env); void rfcore_ble_set_txpower(uint8_t level); +MP_DECLARE_CONST_FUN_OBJ_0(rfcore_status_obj); +MP_DECLARE_CONST_FUN_OBJ_1(rfcore_fw_version_obj); +MP_DECLARE_CONST_FUN_OBJ_3(rfcore_sys_hci_obj); + #endif // MICROPY_INCLUDED_STM32_RFCORE_H |