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