diff --git a/extmod/nimble/logcfg/logcfg.h b/extmod/nimble/logcfg/logcfg.h index e9023dae65b5..398f7862356c 100644 --- a/extmod/nimble/logcfg/logcfg.h +++ b/extmod/nimble/logcfg/logcfg.h @@ -9,7 +9,9 @@ #include "modlog/modlog.h" #include "log_common/log_common.h" -#define MICROPY_PY_BLUETOOTH_DIAGNOSTIC_LOGGING (1) +#ifndef MICROPY_PY_BLUETOOTH_DIAGNOSTIC_LOGGING +#define MICROPY_PY_BLUETOOTH_DIAGNOSTIC_LOGGING (0) +#endif #if MICROPY_PY_BLUETOOTH_DIAGNOSTIC_LOGGING #define DFLT_LOG_DEBUG(...) MODLOG_DEBUG(4, __VA_ARGS__) diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c index c053ac56cf2b..9527d74800b3 100644 --- a/extmod/nimble/modbluetooth_nimble.c +++ b/extmod/nimble/modbluetooth_nimble.c @@ -519,24 +519,30 @@ STATIC int central_gap_event_cb(struct ble_gap_event *event, void *arg) { // On ports such as ESP32 where we only implement the bindings, then // the port must provide these functions. -// But for STM32 / Unix-H4, we provide a default implementation of the +// For STM32 / Unix-H4, we provide a default implementation of the // port-specific functionality. // TODO: In the future if a port ever needs to customise these functions // then investigate using MP_WEAK or splitting them out to another .c file. +#if !MICROPY_BLUETOOTH_NIMBLE_CONTROLLER #include "transport/uart/ble_hci_uart.h" +#endif void mp_bluetooth_nimble_port_hci_init(void) { DEBUG_printf("mp_bluetooth_nimble_port_hci_init (nimble default)\n"); + #if MYNEWT_VAL(BLE_HCI_TRANSPORT_UART) // This calls mp_bluetooth_hci_uart_init (via ble_hci_uart_init --> hal_uart_config --> mp_bluetooth_hci_uart_init). ble_hci_uart_init(); + #endif mp_bluetooth_hci_controller_init(); } void mp_bluetooth_nimble_port_hci_deinit(void) { DEBUG_printf("mp_bluetooth_nimble_port_hci_deinit (nimble default)\n"); mp_bluetooth_hci_controller_deinit(); + #if MYNEWT_VAL(BLE_HCI_TRANSPORT_UART) mp_bluetooth_hci_uart_deinit(); + #endif } void mp_bluetooth_nimble_port_start(void) { @@ -611,10 +617,6 @@ int mp_bluetooth_init(void) { MP_STATE_PORT(bluetooth_nimble_memory) = NULL; #endif - // Allow port (ESP32) to override NimBLE's HCI init. - // Otherwise default implementation above calls ble_hci_uart_init(). - mp_bluetooth_nimble_port_hci_init(); - // Static initialization is complete, can start processing events. mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_WAITING_FOR_SYNC; @@ -622,6 +624,10 @@ int mp_bluetooth_init(void) { DEBUG_printf("mp_bluetooth_init: nimble_port_init\n"); nimble_port_init(); + // Allow port (ESP32) to override NimBLE's HCI init. + // Otherwise default implementation above calls ble_hci_uart_init(). + mp_bluetooth_nimble_port_hci_init(); + // Make sure that the HCI UART and event handling task is running. mp_bluetooth_nimble_port_start(); diff --git a/extmod/nimble/nimble.mk b/extmod/nimble/nimble.mk index fc1709f0e50a..385ee21b7533 100644 --- a/extmod/nimble/nimble.mk +++ b/extmod/nimble/nimble.mk @@ -86,7 +86,6 @@ SRC_THIRDPARTY_C += $(addprefix $(NIMBLE_LIB_DIR)/, \ ble_uuid.c \ ) \ nimble/host/util/src/addr.c \ - nimble/transport/uart/src/ble_hci_uart.c \ $(addprefix porting/nimble/src/, \ endian.c \ mem.c \ @@ -100,7 +99,6 @@ SRC_THIRDPARTY_C += $(addprefix $(NIMBLE_LIB_DIR)/, \ SRC_THIRDPARTY_C += $(addprefix $(NIMBLE_EXTMOD_DIR)/, \ nimble/nimble_npl_os.c \ - hal/hal_uart.c \ ) INC += -I$(TOP)/$(NIMBLE_EXTMOD_DIR) @@ -112,11 +110,58 @@ INC += -I$(TOP)/$(NIMBLE_LIB_DIR)/nimble/host/services/gatt/include INC += -I$(TOP)/$(NIMBLE_LIB_DIR)/nimble/host/store/ram/include INC += -I$(TOP)/$(NIMBLE_LIB_DIR)/nimble/host/util/include INC += -I$(TOP)/$(NIMBLE_LIB_DIR)/nimble/include -INC += -I$(TOP)/$(NIMBLE_LIB_DIR)/nimble/transport/uart/include INC += -I$(TOP)/$(NIMBLE_LIB_DIR)/porting/nimble/include $(BUILD)/$(NIMBLE_LIB_DIR)/%.o: CFLAGS += -Wno-maybe-uninitialized -Wno-pointer-arith -Wno-unused-but-set-variable -Wno-format -Wno-sign-compare -Wno-old-style-declaration endif +ifeq ($(MICROPY_BLUETOOTH_NIMBLE_CONTROLLER),1) + +# Include controller layer to run entire stack on-chip +CFLAGS_EXTMOD += -DMICROPY_BLUETOOTH_NIMBLE_CONTROLLER=1 + +INC += -I$(TOP)/$(NIMBLE_LIB_DIR)/nimble/controller/include + +SRC_THIRDPARTY_C += $(addprefix $(NIMBLE_LIB_DIR)/, \ + $(addprefix nimble/controller/src/, \ + ble_ll.c \ + ble_ll_adv.c \ + ble_ll_conn.c \ + ble_ll_conn_hci.c \ + ble_ll_ctrl.c \ + ble_ll_dtm.c \ + ble_ll_hci.c \ + ble_ll_hci_ev.c \ + ble_ll_iso.c \ + ble_ll_rand.c \ + ble_ll_resolv.c \ + ble_ll_rfmgmt.c \ + ble_ll_scan.c \ + ble_ll_sched.c \ + ble_ll_supp_cmd.c \ + ble_ll_sync.c \ + ble_ll_trace.c \ + ble_ll_utils.c \ + ble_ll_whitelist.c \ + ) \ +) + +SRC_THIRDPARTY_C += $(addprefix $(NIMBLE_LIB_DIR)/, \ + $(addprefix porting/nimble/src/, \ + hal_timer.c \ + os_cputime.c \ + os_cputime_pwr2.c \ + ) \ +) + +SRC_THIRDPARTY_C += $(NIMBLE_LIB_DIR)/nimble/transport/ram/src/ble_hci_ram.c +INC += -I$(TOP)/$(NIMBLE_LIB_DIR)/nimble/transport/ram/include + +else # !MICROPY_BLUETOOTH_NIMBLE_CONTROLLER +# External controller being used +SRC_THIRDPARTY_C += $(NIMBLE_LIB_DIR)/nimble/transport/uart/src/ble_hci_uart.c +INC += -I$(TOP)/$(NIMBLE_LIB_DIR)/nimble/transport/uart/include + +endif endif diff --git a/extmod/nimble/nimble/nimble_npl_os.c b/extmod/nimble/nimble/nimble_npl_os.c index 21bdd535fe17..093476690b96 100644 --- a/extmod/nimble/nimble/nimble_npl_os.c +++ b/extmod/nimble/nimble/nimble_npl_os.c @@ -30,6 +30,8 @@ #include "nimble/ble.h" #include "nimble/nimble_npl.h" #include "extmod/nimble/hal/hal_uart.h" +#include "os/os_cputime.h" +#include "hal/hal_timer.h" #include "extmod/modbluetooth.h" #include "extmod/nimble/modbluetooth_nimble.h" @@ -44,7 +46,7 @@ #define DEBUG_TIME_printf(...) // printf(__VA_ARGS__) #define DEBUG_CRIT_printf(...) // printf(__VA_ARGS__) -bool ble_npl_os_started(void) { + MP_WEAK bool ble_npl_os_started(void) { DEBUG_OS_printf("ble_npl_os_started\n"); return true; } @@ -175,6 +177,24 @@ int nimble_sprintf(char *str, const char *fmt, ...) { return 0; } +// Function to implement `strncat()` function in C +char* strncat(char* destination, const char* source, size_t num) +{ + // make `ptr` point to the end of the destination string + char* ptr = destination + strlen(destination); + + // Appends characters of the source to the destination string + while (*source != '\0' && num--) { + *ptr++ = *source++; + } + + // null terminate destination string + *ptr = '\0'; + + // destination string is returned by standard `strncat()` + return destination; +} + /******************************************************************************/ // EVENTQ @@ -278,6 +298,61 @@ void ble_npl_eventq_put(struct ble_npl_eventq *evq, struct ble_npl_event *ev) { mp_bluetooth_hci_poll_now(); } +struct ble_npl_event *ble_npl_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo) { + if (tmo != BLE_NPL_TIME_FOREVER && tmo != 0) { + tmo += mp_hal_ticks_ms(); + } + + struct ble_npl_event *ev = NULL; + os_sr_t sr; + do { + ev = evq->head; + if (ev) { + OS_ENTER_CRITICAL(sr); + // Remove this event from the queue. + evq->head = ev->next; + if (ev->next) { + ev->next->prev = NULL; + ev->next = NULL; + } + ev->prev = NULL; + + ev->pending = false; + + // Stop searching and execute this event. + OS_EXIT_CRITICAL(sr); + break; + } + } while (tmo != 0 && (tmo == BLE_NPL_TIME_FOREVER || tmo < mp_hal_ticks_ms())); + + return ev; +} + +void ble_npl_event_run(struct ble_npl_event *ev) { + // Run the event handler. + DEBUG_EVENT_printf("ble_npl_event_run(%p)\n", ev); + ev->fn(ev); +} + +inline bool ble_npl_event_is_queued(struct ble_npl_event *ev) { + return ev->pending; +} + +void ble_npl_eventq_run(struct ble_npl_eventq *evq) { + printf("ble_npl_eventq_run\n"); + assert(0); +} + +void ble_npl_eventq_remove(struct ble_npl_eventq *evq, struct ble_npl_event *ev) { + DEBUG_EVENT_printf("ble_npl_eventq_remove(%p, %p (%p, %p))\n", evq, ev, ev->prev, ev->next); + os_sr_t sr; + OS_ENTER_CRITICAL(sr); + // Set the previous events next to this events next, so removing it from the chain + ev->prev->next = ev->next; + OS_EXIT_CRITICAL(sr); +} + + void ble_npl_event_init(struct ble_npl_event *ev, ble_npl_event_fn *fn, void *arg) { DEBUG_EVENT_printf("ble_npl_event_init(%p, %p, %p)\n", ev, fn, arg); ev->fn = fn; @@ -473,7 +548,7 @@ void ble_npl_callout_set_arg(struct ble_npl_callout *c, void *arg) { } /******************************************************************************/ -// TIME +// TIME (ticks in ms) uint32_t ble_npl_time_get(void) { DEBUG_TIME_printf("ble_npl_time_get -> %u\n", (uint)mp_hal_ticks_ms()); diff --git a/extmod/nimble/nimble/nimble_npl_os.h b/extmod/nimble/nimble/nimble_npl_os.h index 3205baa032da..924b1f88b834 100644 --- a/extmod/nimble/nimble/nimble_npl_os.h +++ b/extmod/nimble/nimble/nimble_npl_os.h @@ -88,7 +88,9 @@ struct ble_npl_sem { // --- Called by the MicroPython port ----------------------------------------- void mp_bluetooth_nimble_os_eventq_run_all(void); +void mp_bluetooth_nimble_eventq_run_all(struct ble_npl_eventq *eventq); void mp_bluetooth_nimble_os_callout_process(void); +void mp_bluetooth_nimble_os_cputime_timer_poll(void); // --- Must be provided by the MicroPython port ------------------------------- diff --git a/extmod/nimble/syscfg/syscfg.h b/extmod/nimble/syscfg/syscfg.h index f26f8db9ec37..2318ee73fce7 100644 --- a/extmod/nimble/syscfg/syscfg.h +++ b/extmod/nimble/syscfg/syscfg.h @@ -18,8 +18,13 @@ int nimble_sprintf(char *str, const char *fmt, ...); #define sprintf(str, fmt, ...) nimble_sprintf(str, fmt, __VA_ARGS__) #define MYNEWT_VAL(x) MYNEWT_VAL_ ## x +#define MYNEWT_VAL_CHOICE(_name, _val) MYNEWT_VAL_ ## _name ## __ ## _val +#if MICROPY_PY_BLUETOOTH_DIAGNOSTIC_LOGGING +#define MYNEWT_VAL_LOG_LEVEL (0) +#else #define MYNEWT_VAL_LOG_LEVEL (255) +#endif /*** compiler/arm-none-eabi-m4 */ #define MYNEWT_VAL_HARDFLOAT (1) @@ -30,8 +35,13 @@ int nimble_sprintf(char *str, const char *fmt, ...); #define MYNEWT_VAL_MSYS_1_BLOCK_SIZE (292) #define MYNEWT_VAL_MSYS_2_BLOCK_COUNT (0) #define MYNEWT_VAL_MSYS_2_BLOCK_SIZE (0) +#if MICROPY_BLUETOOTH_NIMBLE_CONTROLLER +#define MYNEWT_VAL_OS_CPUTIME_FREQ (32768) +#define MYNEWT_VAL_OS_CPUTIME_TIMER_NUM (5) +#else #define MYNEWT_VAL_OS_CPUTIME_FREQ (1000000) #define MYNEWT_VAL_OS_CPUTIME_TIMER_NUM (0) +#endif #define MYNEWT_VAL_OS_CTX_SW_STACK_CHECK (0) #define MYNEWT_VAL_OS_CTX_SW_STACK_GUARD (4) #define MYNEWT_VAL_OS_MAIN_STACK_SIZE (1024) @@ -40,6 +50,7 @@ int nimble_sprintf(char *str, const char *fmt, ...); #define MYNEWT_VAL_OS_MEMPOOL_POISON (0) /*** nimble */ +#define MYNEWT_VAL_BLE_VERSION (52) #define MYNEWT_VAL_BLE_EXT_ADV (0) #define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) #define MYNEWT_VAL_BLE_MAX_CONNECTIONS (4) @@ -147,19 +158,143 @@ int nimble_sprintf(char *str, const char *fmt, ...); #define MYNEWT_VAL_BLE_SVC_GAP_PPCP_SUPERVISION_TMO (0) /* Overridden by targets/porting-nimble (defined by nimble/transport) */ -#define MYNEWT_VAL_BLE_HCI_TRANSPORT_NIMBLE_BUILTIN (0) + +#if MICROPY_BLUETOOTH_NIMBLE_CONTROLLER + +#define NIMBLE_CFG_CONTROLLER (1) +#define MYNEWT_VAL_TIMER_5 (1) +#define MYNEWT_VAL_MCU_HFCLK_SOURCE_HFXO (1) + +#ifndef MYNEWT_VAL_MCU_LFCLK_SOURCE__LFRC +#define MYNEWT_VAL_MCU_LFCLK_SOURCE__LFRC (0) +#endif +#ifndef MYNEWT_VAL_MCU_LFCLK_SOURCE__LFSYNTH +#define MYNEWT_VAL_MCU_LFCLK_SOURCE__LFSYNTH (0) +#endif +#ifndef MYNEWT_VAL_MCU_LFCLK_SOURCE__LFXO +#define MYNEWT_VAL_MCU_LFCLK_SOURCE__LFXO (1) +#endif +#ifndef MYNEWT_VAL_MCU_LFCLK_SOURCE +#define MYNEWT_VAL_MCU_LFCLK_SOURCE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_HFCLK_SOURCE__HFINT +#define MYNEWT_VAL_MCU_HFCLK_SOURCE__HFINT (0) +#endif +#ifndef MYNEWT_VAL_MCU_HFCLK_SOURCE__HFXO +#define MYNEWT_VAL_MCU_HFCLK_SOURCE__HFXO (0) +#endif +#ifndef MYNEWT_VAL_MCU_HFCLK_SOURCE +#define MYNEWT_VAL_MCU_HFCLK_SOURCE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_TARGET__nRF52810 +#define MYNEWT_VAL_MCU_TARGET__nRF52810 (0) +#endif +#ifndef MYNEWT_VAL_MCU_TARGET__nRF52811 +#define MYNEWT_VAL_MCU_TARGET__nRF52811 (0) +#endif +#ifndef MYNEWT_VAL_MCU_TARGET__nRF52832 +#define MYNEWT_VAL_MCU_TARGET__nRF52832 (0) +#endif +#ifndef MYNEWT_VAL_MCU_TARGET__nRF52840 +#define MYNEWT_VAL_MCU_TARGET__nRF52840 (1) +#endif +#ifndef MYNEWT_VAL_MCU_TARGET +#define MYNEWT_VAL_MCU_TARGET (1) +#endif +#ifndef MYNEWT_VAL_OS_TICKS_PER_SEC +#define MYNEWT_VAL_OS_TICKS_PER_SEC (128) +#endif + +#define MYNEWT_VAL_BLE_HCI_TRANSPORT (1) #define MYNEWT_VAL_BLE_HCI_TRANSPORT_RAM (0) #define MYNEWT_VAL_BLE_HCI_TRANSPORT_SOCKET (0) -#define MYNEWT_VAL_BLE_HCI_TRANSPORT_UART (1) +#define MYNEWT_VAL_BLE_HCI_TRANSPORT_UART (0) -/*** nimble/transport/uart */ -#define MYNEWT_VAL_BLE_ACL_BUF_COUNT (12) +/*** nimble/controller */ +#define MYNEWT_VAL_BLE_CONTROLLER (1) +#define MYNEWT_VAL_BLE_HW_WHITELIST_ENABLE (1) +#define MYNEWT_VAL_BLE_LL_SYSVIEW (0) +#define MYNEWT_VAL_BLE_LL_PRIO (0) +#define MYNEWT_VAL_BLE_LL_SCA (MYNEWT_VAL_BLE_LL_OUR_SCA) +#define MYNEWT_VAL_BLE_LL_TX_PWR_DBM (0) +#define MYNEWT_VAL_BLE_LL_NUM_COMP_PKT_ITVL_MS (2000) +#define MYNEWT_VAL_BLE_LL_MFRG_ID (0xFFFF) +#define MYNEWT_VAL_BLE_LL_NUM_SCAN_DUP_ADVS (8) +#define MYNEWT_VAL_BLE_LL_NUM_SCAN_RSP_ADVS (8) +#define MYNEWT_VAL_BLE_LL_WHITELIST_SIZE (8) +#define MYNEWT_VAL_BLE_LL_RESOLV_LIST_SIZE (4) +#define MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE (251) +#define MYNEWT_VAL_BLE_LL_SUPP_MAX_RX_BYTES (MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE) +#define MYNEWT_VAL_BLE_LL_SUPP_MAX_TX_BYTES (MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE) +#define MYNEWT_VAL_BLE_LL_CONN_INIT_MAX_TX_BYTES (27) +#define MYNEWT_VAL_BLE_LL_CONN_INIT_SLOTS (4) +#define MYNEWT_VAL_BLE_LL_CONN_INIT_MIN_WIN_OFFSET (0) +#define MYNEWT_VAL_BLE_LL_STRICT_CONN_SCHEDULING (0) +#define MYNEWT_VAL_BLE_LL_ADD_STRICT_SCHED_PERIODS (0) +#define MYNEWT_VAL_BLE_LL_USECS_PER_PERIOD (3250) +#define MYNEWT_VAL_BLE_LL_RNG_BUFSIZE (32) +#define MYNEWT_VAL_BLE_LL_RFMGMT_ENABLE_TIME (MYNEWT_VAL_BLE_XTAL_SETTLE_TIME) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION (1) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_CONN_PARAM_REQ (1) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG (1) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_PING (MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_DATA_LEN_EXT (1) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PRIVACY (1) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CSA2 (0) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_2M_PHY (0) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CODED_PHY (0) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_EXT_ADV (MYNEWT_VAL_BLE_EXT_ADV) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV (MYNEWT_VAL_BLE_PERIODIC_ADV) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_CNT (MYNEWT_VAL_BLE_MAX_PERIODIC_SYNCS) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_LIST_CNT (MYNEWT_VAL_BLE_MAX_PERIODIC_SYNCS) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER (MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL (0) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_SCA_UPDATE (0) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_ISO (MYNEWT_VAL_BLE_ISO) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_ISO_TEST (MYNEWT_VAL_BLE_ISO_TEST) +#define MYNEWT_VAL_BLE_LL_EXT_ADV_AUX_PTR_CNT (0) +#define MYNEWT_VAL_BLE_PUBLIC_DEV_ADDR ((uint8_t[6]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) +#define MYNEWT_VAL_BLE_LL_DTM (BLE_LL_DIRECT_TEST_MODE) +#define MYNEWT_VAL_BLE_LL_DTM_EXTENSIONS (0) +#define MYNEWT_VAL_BLE_LL_VND_EVENT_ON_ASSERT (0) +#define MYNEWT_VAL_BLE_LL_SYSINIT_STAGE (250) +#define MYNEWT_VAL_BLE_LL_DEBUG_GPIO_HCI_CMD (-1) +#define MYNEWT_VAL_BLE_LL_DEBUG_GPIO_HCI_EV (-1) +#define MYNEWT_VAL_BLE_LL_DEBUG_GPIO_SCHED_RUN (-1) +#define MYNEWT_VAL_BLE_LL_DEBUG_GPIO_SCHED_ITEM_CB (-1) +#define MYNEWT_VAL_BLE_LL_SCHED_AUX_MAFS_DELAY (0) +#define MYNEWT_VAL_BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY (0) +#define MYNEWT_VAL_BLE_LL_SCHED_SCAN_AUX_PDU_LEN (41) +#define MYNEWT_VAL_BLE_LL_SCHED_SCAN_SYNC_PDU_LEN (32) +#define MYNEWT_VAL_BLE_LL_DIRECT_TEST_MODE (0) +#define MYNEWT_VAL_BLE_XTAL_SETTLE_TIME (0) +#define MYNEWT_VAL_BLE_LL_OUR_SCA (60) +#define MYNEWT_VAL_BLE_DEVICE (1) +#define MYNEWT_VAL_BLE_LP_CLOCK (1) +#define MYNEWT_VAL_BLE_NUM_COMP_PKT_RATE ((2 * OS_TICKS_PER_SEC)) +#define MYNEWT_VAL_BLE_LL_MASTER_SCA (4) + +/*** nimble/transport/ram */ +#define MYNEWT_VAL_BLE_ACL_BUF_COUNT (4) #define MYNEWT_VAL_BLE_ACL_BUF_SIZE (255) -#define MYNEWT_VAL_BLE_HCI_ACL_OUT_COUNT (12) +#if MYNEWT_VAL_BLE_EXT_ADV +#define MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE (257) +#else #define MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE (70) -#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT (8) +#endif +#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT (2) #define MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT (8) + +#else // ! MICROPY_BLUETOOTH_NIMBLE_CONTROLLER + +#define MYNEWT_VAL_BLE_HCI_TRANSPORT_NIMBLE_BUILTIN (0) +#define MYNEWT_VAL_BLE_HCI_TRANSPORT_RAM (0) +#define MYNEWT_VAL_BLE_HCI_TRANSPORT_SOCKET (0) +#define MYNEWT_VAL_BLE_HCI_TRANSPORT_UART (1) + /* Overridden by targets/porting-nimble (defined by nimble/transport/uart) */ #define MYNEWT_VAL_BLE_HCI_UART_BAUD (MICROPY_HW_BLE_UART_BAUDRATE) #define MYNEWT_VAL_BLE_HCI_UART_DATA_BITS (8) @@ -168,6 +303,16 @@ int nimble_sprintf(char *str, const char *fmt, ...); #define MYNEWT_VAL_BLE_HCI_UART_PORT (MICROPY_HW_BLE_UART_ID) #define MYNEWT_VAL_BLE_HCI_UART_STOP_BITS (1) +/*** nimble/transport/uart */ +#define MYNEWT_VAL_BLE_ACL_BUF_COUNT (12) +#define MYNEWT_VAL_BLE_ACL_BUF_SIZE (255) +#define MYNEWT_VAL_BLE_HCI_ACL_OUT_COUNT (12) +#define MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE (70) +#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT (8) +#define MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT (8) + +#endif + /* Required for code that uses BLE_HS_LOG */ #define MYNEWT_VAL_NEWT_FEATURE_LOGCFG (1) diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 7150aa6399b0..806835c8b24e 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -22,6 +22,11 @@ SD_LOWER = $(shell echo $(SD) | tr '[:upper:]' '[:lower:]') include boards/$(BOARD)/mpconfigboard.mk ifeq ($(SD), ) + # Use modbluetooth & nimble by default unless SD is manually specified. + MICROPY_PY_BLUETOOTH ?= 1 + MICROPY_BLUETOOTH_NIMBLE ?= 1 + MICROPY_BLUETOOTH_NIMBLE_CONTROLLER ?= 1 + # If the build directory is not given, make it reflect the board name. BUILD ?= build-$(BOARD) include ../../py/mkenv.mk @@ -59,7 +64,6 @@ MICROPY_ROM_TEXT_COMPRESSION ?= 1 endif FROZEN_MANIFEST ?= modules/manifest.py - # include py core make definitions include ../../py/py.mk include ../../extmod/extmod.mk @@ -235,12 +239,41 @@ SRC_C += \ drivers/bluetooth/ble_uart.c \ $(wildcard $(BOARD_DIR)/*.c) \ + + +ifeq ($(MICROPY_PY_BLUETOOTH),1) + +ifneq ($(SD), ) +$(error "MICROPY_PY_BLUETOOTH cannot be used at same time as SD") +endif + +# NRF chips support directly running the entire stack, so enable the controller. +MICROPY_BLUETOOTH_NIMBLE_CONTROLLER=1 + +ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1) + +GIT_SUBMODULES += lib/mynewt-nimble + +SRC_C += \ + mpnimbleport.c \ + mpbthciport.c + +INC += -I$(TOP)/$(NIMBLE_LIB_DIR)/nimble/drivers/nrf52/include +SRC_LIB_C += $(addprefix $(NIMBLE_LIB_DIR)/, \ + $(addprefix nimble/drivers/nrf52/src/, \ + ble_hw.c \ + ble_phy_trace.c \ + ble_phy.c \ + ) \ +) +endif +endif + ifeq ($(MCU_SUB_VARIANT), nrf52840) INC += -I./drivers/usb INC += -I../../lib/tinyusb/src - # If SoftDevice is selected. ifneq ($(SD), ) # For external tinyusb drivers to enable SoftDevice mode. @@ -273,6 +306,14 @@ DRIVERS_SRC_C += $(addprefix modules/,\ os/microbitfs.c \ board/modboard.c \ board/led.c \ + music/modmusic.c \ + music/musictunes.c \ + nrf/modnrf.c \ + nrf/flashbdev.c \ + ) + +ifneq ($(SD), ) +DRIVERS_SRC_C += $(addprefix modules/,\ ubluepy/modubluepy.c \ ubluepy/ubluepy_peripheral.c \ ubluepy/ubluepy_service.c \ @@ -283,12 +324,9 @@ DRIVERS_SRC_C += $(addprefix modules/,\ ubluepy/ubluepy_descriptor.c \ ubluepy/ubluepy_scanner.c \ ubluepy/ubluepy_scan_entry.c \ - music/modmusic.c \ - music/musictunes.c \ ble/modble.c \ - nrf/modnrf.c \ - nrf/flashbdev.c \ ) +endif # Custom micropython startup file with smaller interrupt vector table # than the file provided in nrfx. @@ -306,6 +344,7 @@ OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SYSTEM_C_SRC:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_LIB_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_SHARED_C:.c=.o)) +#OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) OBJ += $(GEN_PINS_SRC:.c=.o) $(BUILD)/$(OOFATFS_DIR)/ff.o: COPT += -Os @@ -446,8 +485,12 @@ nrfutil_dfu_sd: $(BUILD)/$(OUTPUT_FILENAME).hex $(Q)nrfutil pkg generate --hw-version 52 --sd-req 0x00 --sd-id 0x00 --softdevice $(BUILD)/stripped_sd.hex $(BUILD)/stripped_sd.zip $(Q)nrfutil dfu usb-serial -pkg $(BUILD)/stripped_sd.zip -p $(NRFUTIL_PORT) -t 0 -nrfutil_dfu_deploy: $(BUILD)/$(OUTPUT_FILENAME).hex +$(BUILD)/$(OUTPUT_FILENAME)_dfu.zip: $(BUILD)/$(OUTPUT_FILENAME).hex $(Q)nrfutil pkg generate --hw-version 52 --sd-req $(NRFUTIL_SD_REQ) --application-version 1 --application $(BUILD)/$(OUTPUT_FILENAME).hex $(BUILD)/$(OUTPUT_FILENAME)_dfu.zip + +nrfutil_pkg: $(BUILD)/$(OUTPUT_FILENAME)_dfu.zip + +nrfutil_dfu_deploy: nrfutil_pkg $(Q)nrfutil dfu usb-serial -pkg $(BUILD)/$(OUTPUT_FILENAME)_dfu.zip -p $(NRFUTIL_PORT) -t 0 deploy: nrfutil_dfu_deploy diff --git a/ports/nrf/boards/NRF52840_MDK_USB_DONGLE/mpconfigboard.mk b/ports/nrf/boards/NRF52840_MDK_USB_DONGLE/mpconfigboard.mk index 3a26a92b7dc1..6172b0b9f4e0 100644 --- a/ports/nrf/boards/NRF52840_MDK_USB_DONGLE/mpconfigboard.mk +++ b/ports/nrf/boards/NRF52840_MDK_USB_DONGLE/mpconfigboard.mk @@ -1,7 +1,6 @@ MCU_SERIES = m4 MCU_VARIANT = nrf52 MCU_SUB_VARIANT = nrf52840 -SOFTDEV_VERSION = 6.1.1 DFU ?= 1 diff --git a/ports/nrf/drivers/rng.c b/ports/nrf/drivers/rng.c index 2737c74c4bfc..18b38d973b03 100644 --- a/ports/nrf/drivers/rng.c +++ b/ports/nrf/drivers/rng.c @@ -31,6 +31,7 @@ #include "nrf_rng.h" #include "drivers/rng.h" +#include "py/runtime.h" #if BLUETOOTH_SD #include "nrf_soc.h" @@ -38,8 +39,35 @@ #define BLUETOOTH_STACK_ENABLED() (ble_drv_stack_enabled()) #endif + +#if MICROPY_PY_BLUETOOTH +#include "controller/ble_ll.h" +#include "extmod/modbluetooth.h" +#include "mpnimbleport.h" + +// Will be set by ble_npl_hw_set_isr() during init +func nrf_ble_isr_rng = NULL; + +void RNG_IRQHandler(void) +{ + /*** nimble/drivers/nrf52/src/ble_hw.c */ + if (nrf_ble_isr_rng != NULL) { + nrf_ble_isr_rng(); + } +} +#endif + static inline uint32_t generate_hw_random(void) { uint32_t retval = 0; + + #if MICROPY_PY_BLUETOOTH + if (!mp_bluetooth_is_active()) { + // This is safe to re-init if we can't be sure it's already done. + ble_ll_rand_init(); + } + ble_ll_rand_data_get((uint8_t *)&retval, 4); + + #else uint8_t * p_retval = (uint8_t *)&retval; nrf_rng_event_clear(NRF_RNG, NRF_RNG_EVENT_VALRDY); @@ -55,7 +83,7 @@ static inline uint32_t generate_hw_random(void) { } nrf_rng_task_trigger(NRF_RNG, NRF_RNG_TASK_STOP); - + #endif return retval; } diff --git a/ports/nrf/drivers/ticker.c b/ports/nrf/drivers/ticker.c index c2fa31e7c207..e1dc68111e87 100644 --- a/ports/nrf/drivers/ticker.c +++ b/ports/nrf/drivers/ticker.c @@ -26,7 +26,7 @@ #include "py/mphal.h" -#if MICROPY_PY_MACHINE_SOFT_PWM +#if MICROPY_PY_TICKER #include "ticker.h" #include "nrfx_glue.h" @@ -166,4 +166,4 @@ void SlowTicker_IRQHandler(void) } } -#endif // MICROPY_PY_MACHINE_SOFT_PWM +#endif // MICROPY_PY_TICKER diff --git a/ports/nrf/main.c b/ports/nrf/main.c index 0e5a26c487e4..1687eb135609 100644 --- a/ports/nrf/main.c +++ b/ports/nrf/main.c @@ -55,6 +55,10 @@ #include "rtcounter.h" #include "mphalport.h" +#if MICROPY_PY_BLUETOOTH +#include "extmod/modbluetooth.h" +#endif + #if MICROPY_PY_MACHINE_HW_PWM #include "pwm.h" #endif @@ -68,8 +72,11 @@ #include "ble_uart.h" #endif -#if MICROPY_PY_MACHINE_SOFT_PWM +#if MICROPY_PY_TICKER #include "ticker.h" +#endif + +#if MICROPY_PY_MACHINE_SOFT_PWM #include "softpwm.h" #endif @@ -242,8 +249,11 @@ int main(int argc, char **argv) { ble_uart_init0(); #endif - #if MICROPY_PY_MACHINE_SOFT_PWM + #if MICROPY_PY_TICKER ticker_init0(); + #endif + + #if MICROPY_PY_MACHINE_SOFT_PWM softpwm_init0(); #endif @@ -254,8 +264,11 @@ int main(int argc, char **argv) { board_modules_init0(); #endif - #if MICROPY_PY_MACHINE_SOFT_PWM + #if MICROPY_PY_TICKER ticker_start(); + #endif + + #if MICROPY_PY_MACHINE_SOFT_PWM pwm_start(); #endif @@ -290,6 +303,10 @@ int main(int argc, char **argv) { pwm_deinit_all(); #endif + #if MICROPY_PY_BLUETOOTH + mp_bluetooth_deinit(); + #endif + mp_deinit(); printf("MPY: soft reboot\n"); diff --git a/ports/nrf/modules/machine/rtcounter.c b/ports/nrf/modules/machine/rtcounter.c index d52ca3e9a336..7707eca8ee49 100644 --- a/ports/nrf/modules/machine/rtcounter.c +++ b/ports/nrf/modules/machine/rtcounter.c @@ -56,9 +56,13 @@ typedef struct _machine_rtc_obj_t { } machine_rtc_obj_t; STATIC const nrfx_rtc_t machine_rtc_instances[] = { +#if NRFX_RTC0_ENABLED NRFX_RTC_INSTANCE(0), +#endif +#if NRFX_RTC1_ENABLED NRFX_RTC_INSTANCE(1), -#if defined(NRF52_SERIES) +#endif +#if defined(NRFX_RTC2_ENABLED) NRFX_RTC_INSTANCE(2), #endif }; diff --git a/ports/nrf/modules/machine/timer.c b/ports/nrf/modules/machine/timer.c index db9f04c2fa7f..ba0d7eafbd84 100644 --- a/ports/nrf/modules/machine/timer.c +++ b/ports/nrf/modules/machine/timer.c @@ -53,7 +53,7 @@ STATIC mp_obj_t machine_timer_callbacks[] = { STATIC const machine_timer_obj_t machine_timer_obj[] = { {{&machine_timer_type}, NRFX_TIMER_INSTANCE(0)}, -#if MICROPY_PY_MACHINE_SOFT_PWM +#if MICROPY_PY_TICKER { }, #else {{&machine_timer_type}, NRFX_TIMER_INSTANCE(1)}, @@ -118,7 +118,7 @@ STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, } #endif -#if MICROPY_PY_MACHINE_SOFT_PWM +#if MICROPY_PY_TICKER if (timer_id == 1) { mp_raise_ValueError(MP_ERROR_TEXT("Timer reserved by ticker driver")); } diff --git a/ports/nrf/mpbthciport.c b/ports/nrf/mpbthciport.c new file mode 100644 index 000000000000..df35d064a26a --- /dev/null +++ b/ports/nrf/mpbthciport.c @@ -0,0 +1,81 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Jim Mussared + * Copyright (c) 2020 Damien P. George + * Copyright (c) 2022 Andrew Leech + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" + +#if MICROPY_PY_BLUETOOTH + +#define DEBUG_printf(...) // mp_printf(&mp_plat_print, "mpbthciport.c: " __VA_ARGS__) + +#include "mpbthciport.h" +#include "drivers/ticker.h" + +#define BLUETOOTH_TICKER_SLOT 0 + +// // Prevent double-enqueuing of the scheduled task. +STATIC volatile bool events_task_is_scheduled = false; + +void mp_bluetooth_hci_init(void) { + /* Start regular background task to handle events */ + events_task_is_scheduled = false; + set_ticker_callback(BLUETOOTH_TICKER_SLOT, mp_bluetooth_hci_poll_now, 0); +} + +void mp_bluetooth_hci_deinit(void) { + clear_ticker_callback(BLUETOOTH_TICKER_SLOT); + events_task_is_scheduled = false; +} + +// For synchronous mode, we run all BLE stack code inside a scheduled task. +// This task is scheduled periodically via a timer. +STATIC mp_obj_t run_events_scheduled_task(mp_obj_t none_in) { + (void)none_in; + events_task_is_scheduled = false; + mp_bluetooth_hci_poll(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(run_events_scheduled_task_obj, run_events_scheduled_task); + + +// Called periodically (ticker) to request that processing happens in the scheduler. +int32_t mp_bluetooth_hci_poll_now(void) { + // Return interval (128ms in 16us ticks) until next callback run + uint32_t next_tick = 128000 / 16; + if (!events_task_is_scheduled) { + events_task_is_scheduled = mp_sched_schedule(MP_OBJ_FROM_PTR(&run_events_scheduled_task_obj), mp_const_none); + if (!events_task_is_scheduled) { + // The schedule queue is full, set callback to try again soon (5ms). + next_tick = 5000 / 16; + } + } + return next_tick; +} + +#endif // MICROPY_PY_BLUETOOTH diff --git a/ports/nrf/mpbthciport.h b/ports/nrf/mpbthciport.h new file mode 100644 index 000000000000..21bc395d4626 --- /dev/null +++ b/ports/nrf/mpbthciport.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_NRF_MPBTHCIPORT_H +#define MICROPY_INCLUDED_NRF_MPBTHCIPORT_H + +// Initialise the HCI subsystem (should be called once, early on). +void mp_bluetooth_hci_init(void); +void mp_bluetooth_hci_deinit(void); + +// Poll the HCI now. +int32_t mp_bluetooth_hci_poll_now(void); + +// Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c). +// Request new HCI data and pass to the stack, and run pending events/callouts. +// This is a low-level function and should not be called directly, use +// mp_bluetooth_hci_poll_now/mp_bluetooth_hci_poll_in_ms instead. +void mp_bluetooth_hci_poll(void); + +#endif // MICROPY_INCLUDED_RP2_MPBTHCIPORT_H diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index f3c08059a06e..015a2bc14d14 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -178,6 +178,9 @@ #define MICROPY_PY_MACHINE_BOOTLOADER (1) #define MICROPY_PY_MACHINE_PULSE (0) #define MICROPY_PY_MACHINE_SOFTI2C (MICROPY_PY_MACHINE_I2C) +#ifndef MICROPY_ENABLE_SCHEDULER +#define MICROPY_ENABLE_SCHEDULER (1) +#endif #ifndef MICROPY_HW_LED_COUNT #define MICROPY_HW_LED_COUNT (0) @@ -240,6 +243,16 @@ #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) #define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0) +#define MICROPY_PY_TICKER (MICROPY_PY_MACHINE_SOFT_PWM || MICROPY_PY_BLUETOOTH) + +#ifndef MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#define MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE (1) +#endif + +#ifndef MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS +#define MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS (MICROPY_BLUETOOTH_NIMBLE) +#endif + // if sdk is in use, import configuration and enable some core features #if BLUETOOTH_SD #include "bluetooth_conf.h" @@ -348,6 +361,30 @@ long unsigned int rng_generate_random_word(void); #ifndef MP_NEED_LOG2 #define MP_NEED_LOG2 (1) + +// We have inlined IRQ functions for efficiency (they are generally +// 1 machine instruction). +// +// Note on IRQ state: you should not need to know the specific +// value of the state variable, but rather just pass the return +// value from disable_irq back to enable_irq. If you really need +// to know the machine-specific values, see irq.h. + +#include + +static inline void enable_irq(mp_uint_t state) { + __set_PRIMASK(state); +} + +static inline mp_uint_t disable_irq(void) { + mp_uint_t state = __get_PRIMASK(); + __disable_irq(); + return state; +} + +#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq() +#define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state) + #endif #ifndef MICROPY_BOARD_STARTUP diff --git a/ports/nrf/mphalport.c b/ports/nrf/mphalport.c index c964a26c2e37..709265436d51 100644 --- a/ports/nrf/mphalport.c +++ b/ports/nrf/mphalport.c @@ -220,16 +220,19 @@ void mp_hal_stdout_tx_str(const char *str) { void mp_hal_delay_us(mp_uint_t us) { uint32_t now; if (us == 0) { + MICROPY_EVENT_POLL_HOOK return; } now = mp_hal_ticks_us(); while (mp_hal_ticks_us() - now < us) { + MICROPY_EVENT_POLL_HOOK } } void mp_hal_delay_ms(mp_uint_t ms) { uint32_t now; if (ms == 0) { + MICROPY_EVENT_POLL_HOOK return; } now = mp_hal_ticks_ms(); diff --git a/ports/nrf/mpnimbleport.c b/ports/nrf/mpnimbleport.c new file mode 100644 index 000000000000..559519e7284e --- /dev/null +++ b/ports/nrf/mpnimbleport.c @@ -0,0 +1,155 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Jim Mussared + * Copyright (c) 2020 Damien P. George + * Copyright (c) 2022 Andrew Leech + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "led.h" + +#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE + +#define DEBUG_printf(...) // mp_printf(&mp_plat_print, "mpnimbleport.c: " __VA_ARGS__) + +#include "mpbthciport.h" +#include "drivers/rng.h" +#include "nimble/nimble_npl.h" +#include "controller/ble_ll.h" +#include "controller/ble_ll_hci.h" +#include "nimble/controller/src/ble_ll_conn_priv.h" +#include "controller/ble_phy.h" +#include "nimble/ble_hci_trans.h" + +#include "extmod/nimble/modbluetooth_nimble.h" + +void mp_bluetooth_hci_controller_init(void) { + DEBUG_printf("mp_bluetooth_hci_controller_init\n"); + + // Init ble phy + // ref: nimble/controller/src/ble_ll.c:ble_ll_task() + ble_phy_init(); + + // Set output power to 1mW (0 dBm) + ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM)); + + // Register callback for transport + ble_hci_trans_cfg_ll(ble_ll_hci_cmd_rx, NULL, ble_ll_hci_acl_rx, NULL); + + // Tell the host that we are ready to receive packets + ble_ll_hci_send_noop(); +} + +void mp_bluetooth_hci_controller_deinit(void) { + mp_bluetooth_hci_deinit(); +} + +// The global BLE controller LL data object +extern struct ble_ll_obj g_ble_ll_data; + +static void run_controller_events() { + struct ble_npl_event *ev = ble_npl_eventq_get(&g_ble_ll_data.ll_evq, 0); + if (ev != NULL) { + ble_npl_event_run(ev); + } +} + +// Get any pending data from the UART and send it to NimBLE's HCI buffers. +// Any further processing by NimBLE will be run via its event queue. +void mp_bluetooth_hci_poll(void) { + if (mp_bluetooth_nimble_ble_state >= MP_BLUETOOTH_NIMBLE_BLE_STATE_WAITING_FOR_SYNC) { + // DEBUG_printf("mp_bluetooth_hci_poll_uart %d\n", mp_bluetooth_nimble_ble_state); + + // Handle any controller events first + run_controller_events(); + + // Run any timers. + mp_bluetooth_nimble_os_callout_process(); + + // Run any remaining events. + mp_bluetooth_nimble_os_eventq_run_all(); + } +} + +// --- Port-specific helpers for the generic NimBLE bindings. ----------------- + +void mp_bluetooth_nimble_hci_uart_wfi(void) { + #if defined(__WFI) + __WFI(); + #endif + + run_controller_events(); +} + +long jrand48(unsigned short xsubi[3]) { + ble_ll_rand_data_get((uint8_t *)xsubi, 4); + return *((long *)xsubi); +} + + +// The interrupt table (VTOR) on nrf port is not in sram so NVIC_SetVector() doesn't work. +// Capture the required interrupt handler callbacks used in the nimble controller here to run in +// the statically defined interrupt handler functions. + +// ref: ports/nrf/drivers/rng.c +extern func nrf_ble_isr_rng; + +static func nrf_ble_isr_phy = NULL; +static func nrf_ble_isr_rtc0 = NULL; + +void RADIO_IRQHandler(void) { + if (nrf_ble_isr_phy != NULL) { + nrf_ble_isr_phy(); + } +} + +void RTC0_IRQHandler(void) { + if (nrf_ble_isr_rtc0 != NULL) { + nrf_ble_isr_rtc0(); + } +} + +void ble_npl_hw_set_isr(int irq_num, func irq_isr) { + switch (irq_num) { + case RNG_IRQn: + nrf_ble_isr_rng = irq_isr; + break; + + case RADIO_IRQn: + nrf_ble_isr_phy = irq_isr; + break; + + case RTC0_IRQn: + nrf_ble_isr_rtc0 = irq_isr; + break; + + default: + // Unknown ISR + assert(0); + } +} + +#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE diff --git a/ports/nrf/mpnimbleport.h b/ports/nrf/mpnimbleport.h new file mode 100644 index 000000000000..187fc0850fc0 --- /dev/null +++ b/ports/nrf/mpnimbleport.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Andrew Leech + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_NRF_NIMBLE_PORT_H +#define MICROPY_INCLUDED_NRF_NIMBLE_PORT_H + +typedef void (*func)(void); + +// #define OS_CPUTIME_FREQ_PWR2 + +/*** src/micropython/lib/mynewt-nimble/nimble/drivers/nrf52/syscfg.yml */ +#define MYNEWT_VAL_BLE_PHY_SYSVIEW (0) +#define MYNEWT_VAL_BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN (0) +#define MYNEWT_VAL_BLE_PHY_DBG_TIME_TXRXEN_READY_PIN (-1) +#define MYNEWT_VAL_BLE_PHY_DBG_TIME_ADDRESS_END_PIN (-1) +#define MYNEWT_VAL_BLE_PHY_DBG_TIME_WFR_PIN (-1) +#define MYNEWT_VAL_BLE_PHY_NRF52840_ERRATA_164 (0) +#define MYNEWT_VAL_BLE_PHY_NRF52840_ERRATA_191 (1) + +#endif // MICROPY_INCLUDED_NRF_NIMBLE_PORT_H diff --git a/ports/nrf/nrfx_config.h b/ports/nrf/nrfx_config.h index c38af62145f4..8270dc42019a 100644 --- a/ports/nrf/nrfx_config.h +++ b/ports/nrf/nrfx_config.h @@ -134,18 +134,21 @@ #define NRFX_SPIM_MISO_PULL_CFG 1 #define NRFX_RTC_ENABLED (MICROPY_PY_MACHINE_RTCOUNTER) +#if !MICROPY_BLUETOOTH_NIMBLE_CONTROLLER #define NRFX_RTC0_ENABLED 1 +#else +#define NRFX_RTC0_ENABLED 0 +#endif #define NRFX_RTC1_ENABLED 1 #define NRFX_RTC2_ENABLED (!NRF51) && (!NRF9160_XXAA) #define NRFX_TIMER_ENABLED (MICROPY_PY_MACHINE_TIMER_NRF) #define NRFX_TIMER0_ENABLED 1 -#define NRFX_TIMER1_ENABLED (!MICROPY_PY_MACHINE_SOFT_PWM) +#define NRFX_TIMER1_ENABLED (!MICROPY_PY_TICKER) #define NRFX_TIMER2_ENABLED 1 #define NRFX_TIMER3_ENABLED (!NRF51) && (!NRF9160_XXAA) #define NRFX_TIMER4_ENABLED (!NRF51) && (!NRF9160_XXAA) - #define NRFX_PWM_ENABLED (!NRF51) && MICROPY_PY_MACHINE_HW_PWM #define NRFX_PWM0_ENABLED 1 #define NRFX_PWM1_ENABLED 1