stm32/rfcore: Add Python API for basic rfcore operations.
The new functions provide FUS/WS status, version and SYS HCI commands: - stm.rfcore_status() - stm.rfcore_fw_version(fw_id) - stm.rfcore_sys_hci(ogf, ocf, cmd)
This commit is contained in:
parent
9855b9cd82
commit
7c76a2dfcf
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue