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:
Jim Mussared 2020-10-01 14:47:00 +10:00 committed by Damien George
parent 9855b9cd82
commit 7c76a2dfcf
3 changed files with 96 additions and 18 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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