summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/rp2/CMakeLists.txt41
-rw-r--r--ports/rp2/btstack_inc/btstack_config.h9
-rw-r--r--ports/rp2/cyw43_configport.h10
-rw-r--r--ports/rp2/main.c2
-rw-r--r--ports/rp2/mpbthciport.c26
-rw-r--r--ports/rp2/mpbthciport.h2
-rw-r--r--ports/rp2/mpbtstackport.c157
-rw-r--r--ports/rp2/mpconfigport.h6
-rw-r--r--ports/rp2/mpnetworkport.c2
9 files changed, 238 insertions, 17 deletions
diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt
index 72f44b19e..4334a0aba 100644
--- a/ports/rp2/CMakeLists.txt
+++ b/ports/rp2/CMakeLists.txt
@@ -18,6 +18,8 @@ endif()
set(PICO_TINYUSB_PATH ${MICROPY_DIR}/lib/tinyusb)
# Use the local lwip instead of the one in pico-sdk
set(PICO_LWIP_PATH ${MICROPY_DIR}/lib/lwip)
+# Use the local btstack instead of the one in pico-sdk
+set(PICO_BTSTACK_PATH ${MICROPY_DIR}/lib/btstack)
# Set the location of this port's directory.
set(MICROPY_PORT_DIR ${CMAKE_CURRENT_LIST_DIR})
@@ -217,11 +219,40 @@ if(MICROPY_PY_BLUETOOTH)
MICROPY_PY_BLUETOOTH=1
MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS=1
MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE=1
- MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING=1
- MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS=1
)
endif()
+if (MICROPY_PY_BLUETOOTH_CYW43)
+ target_compile_definitions(${MICROPY_TARGET} PRIVATE
+ CYW43_ENABLE_BLUETOOTH=1
+ MICROPY_PY_BLUETOOTH_CYW43=1
+ )
+
+ if (MICROPY_BLUETOOTH_BTSTACK)
+ target_link_libraries(${MICROPY_TARGET}
+ pico_btstack_hci_transport_cyw43
+ )
+ endif()
+endif()
+
+if (MICROPY_BLUETOOTH_BTSTACK)
+ string(CONCAT GIT_SUBMODULES "${GIT_SUBMODULES} " lib/btstack)
+
+ list(APPEND MICROPY_SOURCE_PORT mpbtstackport.c)
+
+ include(${MICROPY_DIR}/extmod/btstack/btstack.cmake)
+ target_link_libraries(${MICROPY_TARGET} micropy_extmod_btstack)
+
+ target_compile_definitions(${MICROPY_TARGET} PRIVATE
+ MICROPY_BLUETOOTH_BTSTACK=1
+ MICROPY_BLUETOOTH_BTSTACK_CONFIG_FILE=\"btstack_inc/btstack_config.h\"
+ )
+
+ # For modbluetooth_btstack.c includes
+ get_target_property(BTSTACK_INCLUDE micropy_extmod_btstack INTERFACE_INCLUDE_DIRECTORIES)
+ list(APPEND MICROPY_INC_CORE ${BTSTACK_INCLUDE})
+endif()
+
if(MICROPY_BLUETOOTH_NIMBLE)
string(CONCAT GIT_SUBMODULES "${GIT_SUBMODULES} " lib/mynewt-nimble)
if(NOT (${ECHO_SUBMODULES}) AND NOT EXISTS ${MICROPY_DIR}/lib/mynewt-nimble/nimble/host/include/host/ble_hs.h)
@@ -232,6 +263,8 @@ if(MICROPY_BLUETOOTH_NIMBLE)
target_compile_definitions(${MICROPY_TARGET} PRIVATE
MICROPY_BLUETOOTH_NIMBLE=1
MICROPY_BLUETOOTH_NIMBLE_BINDINGS_ONLY=0
+ MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING=1
+ MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS=1
)
target_compile_options(${MICROPY_TARGET} PRIVATE
# TODO: This flag is currently needed to make nimble build.
@@ -272,6 +305,10 @@ if (MICROPY_PY_NETWORK_CYW43)
cyw43_driver_picow
cmsis_core
)
+ target_include_directories(${MICROPY_TARGET} PRIVATE
+ ${MICROPY_DIR}/lib/cyw43-driver/
+ )
+
endif()
if (MICROPY_PY_NETWORK_NINAW10)
diff --git a/ports/rp2/btstack_inc/btstack_config.h b/ports/rp2/btstack_inc/btstack_config.h
new file mode 100644
index 000000000..ec7cd7fb7
--- /dev/null
+++ b/ports/rp2/btstack_inc/btstack_config.h
@@ -0,0 +1,9 @@
+#ifndef MICROPY_INCLUDED_BTSTACK_BTSTACK_CONFIG_H
+#define MICROPY_INCLUDED_BTSTACK_BTSTACK_CONFIG_H
+
+#define HCI_OUTGOING_PRE_BUFFER_SIZE 4
+#define HCI_ACL_CHUNK_SIZE_ALIGNMENT 4
+
+#include "btstack_config_common.h"
+
+#endif
diff --git a/ports/rp2/cyw43_configport.h b/ports/rp2/cyw43_configport.h
index 08cded6f1..0c4a03210 100644
--- a/ports/rp2/cyw43_configport.h
+++ b/ports/rp2/cyw43_configport.h
@@ -33,7 +33,6 @@
#include "extmod/modnetwork.h"
#include "pendsv.h"
-#define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "w43439A0_7_95_49_00_combined.h"
#define CYW43_WIFI_NVRAM_INCLUDE_FILE "wifi_nvram_43439.h"
#define CYW43_IOCTL_TIMEOUT_US (1000000)
#define CYW43_SLEEP_MAX (10)
@@ -91,6 +90,15 @@
#define cyw43_schedule_internal_poll_dispatch(func) pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, func)
+// Bluetooth uses the C heap to load its firmware (provided by pico-sdk).
+// Space is reserved for this, see MICROPY_C_HEAP_SIZE.
+#ifndef cyw43_malloc
+#define cyw43_malloc malloc
+#endif
+#ifndef cyw43_free
+#define cyw43_free free
+#endif
+
void cyw43_post_poll_hook(void);
extern volatile int cyw43_has_pending;
diff --git a/ports/rp2/main.c b/ports/rp2/main.c
index c5118857a..ff0384b95 100644
--- a/ports/rp2/main.c
+++ b/ports/rp2/main.c
@@ -122,7 +122,7 @@ int main(int argc, char **argv) {
#endif
#endif
- #if MICROPY_PY_NETWORK_CYW43
+ #if MICROPY_PY_NETWORK_CYW43 || MICROPY_PY_BLUETOOTH_CYW43
{
cyw43_init(&cyw43_state);
cyw43_irq_init();
diff --git a/ports/rp2/mpbthciport.c b/ports/rp2/mpbthciport.c
index 8840fe52f..ac05e4607 100644
--- a/ports/rp2/mpbthciport.c
+++ b/ports/rp2/mpbthciport.c
@@ -50,11 +50,6 @@ void mp_bluetooth_hci_init(void) {
events_task_is_scheduled = false;
}
-STATIC void mp_bluetooth_hci_start_polling(void) {
- events_task_is_scheduled = false;
- mp_bluetooth_hci_poll_now();
-}
-
static int64_t mp_bluetooth_hci_timer_callback(alarm_id_t id, void *user_data) {
poll_timer_id = 0;
mp_bluetooth_hci_poll_now();
@@ -70,7 +65,7 @@ void mp_bluetooth_hci_poll_in_ms(uint32_t ms) {
STATIC mp_obj_t run_events_scheduled_task(mp_obj_t none_in) {
(void)none_in;
events_task_is_scheduled = false;
- // This will process all buffered HCI UART data, and run any callouts or events.
+ // This will process all HCI data, and run any callouts or events.
mp_bluetooth_hci_poll();
return mp_const_none;
}
@@ -88,8 +83,15 @@ void mp_bluetooth_hci_poll_now(void) {
}
}
+#if defined(MICROPY_HW_BLE_UART_ID)
+
mp_obj_t mp_bthci_uart;
+STATIC void mp_bluetooth_hci_start_polling(void) {
+ events_task_is_scheduled = false;
+ mp_bluetooth_hci_poll_now();
+}
+
int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) {
debug_printf("mp_bluetooth_hci_uart_init\n");
@@ -121,11 +123,6 @@ int mp_bluetooth_hci_uart_deinit(void) {
return 0;
}
-int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate) {
- debug_printf("mp_bluetooth_hci_uart_set_baudrate(%lu)\n", baudrate);
- return 0;
-}
-
int mp_bluetooth_hci_uart_any(void) {
int errcode = 0;
const mp_stream_p_t *proto = (mp_stream_p_t *)MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, protocol);
@@ -171,6 +168,13 @@ int mp_bluetooth_hci_uart_readchar(void) {
}
}
+int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate) {
+ debug_printf("mp_bluetooth_hci_uart_set_baudrate(%lu)\n", baudrate);
+ return 0;
+}
+
+#endif // defined(MICROPY_HW_BLE_UART_ID)
+
// Default (weak) implementation of the HCI controller interface.
// A driver (e.g. cywbt43.c) can override these for controller-specific
// functionality (i.e. power management).
diff --git a/ports/rp2/mpbthciport.h b/ports/rp2/mpbthciport.h
index ac5263aa1..fdf46c506 100644
--- a/ports/rp2/mpbthciport.h
+++ b/ports/rp2/mpbthciport.h
@@ -34,7 +34,7 @@ void mp_bluetooth_hci_poll_now(void);
void mp_bluetooth_hci_poll_in_ms(uint32_t ms);
// Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c).
-// Request new data from the uart and pass to the stack, and run pending events/callouts.
+// 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);
diff --git a/ports/rp2/mpbtstackport.c b/ports/rp2/mpbtstackport.c
new file mode 100644
index 000000000..4d907be76
--- /dev/null
+++ b/ports/rp2/mpbtstackport.c
@@ -0,0 +1,157 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020-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.
+ */
+
+#include "py/runtime.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+
+#define DEBUG_printf(...)
+#define BTSTACK_ENABLE_HCI_DUMP (0)
+
+#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK
+
+#include "lib/btstack/src/btstack.h"
+#include "lib/btstack/platform/embedded/hci_dump_embedded_stdout.h"
+#include "extmod/mpbthci.h"
+#include "extmod/btstack/modbluetooth_btstack.h"
+#include "mpbthciport.h"
+#include "pico/btstack_hci_transport_cyw43.h"
+
+void mp_bluetooth_hci_poll_in_ms(uint32_t ms);
+
+static btstack_linked_list_t mp_btstack_runloop_timers;
+
+static void mp_btstack_runloop_init(void) {
+ mp_btstack_runloop_timers = NULL;
+}
+
+static void mp_btstack_runloop_set_timer(btstack_timer_source_t *tim, uint32_t timeout_ms) {
+ DEBUG_printf("mp_btstack_runloop_set_timer %lu\n", timeout_ms);
+ tim->timeout = mp_hal_ticks_ms() + timeout_ms + 1;
+}
+
+static void mp_btstack_runloop_add_timer(btstack_timer_source_t *tim) {
+ DEBUG_printf("mp_btstack_runloop_add_timer %lu\n", tim->timeout);
+ btstack_linked_item_t **node = &mp_btstack_runloop_timers;
+ for (; *node; node = &(*node)->next) {
+ btstack_timer_source_t *node_tim = (btstack_timer_source_t *)*node;
+ if (node_tim == tim) {
+ // Timer is already in the list, don't add it.
+ return;
+ }
+ int32_t delta = btstack_time_delta(tim->timeout, node_tim->timeout);
+ if (delta < 0) {
+ // Found sorted location in list.
+ break;
+ }
+ }
+
+ // Insert timer into list in sorted location.
+ tim->item.next = *node;
+ *node = &tim->item;
+
+ // Reschedule the HCI poll if this timer is at the head of the list.
+ if (mp_btstack_runloop_timers == &tim->item) {
+ int32_t delta_ms = btstack_time_delta(tim->timeout, mp_hal_ticks_ms());
+ mp_bluetooth_hci_poll_in_ms(delta_ms);
+ }
+}
+
+static bool mp_btstack_runloop_remove_timer(btstack_timer_source_t *tim) {
+ return btstack_linked_list_remove(&mp_btstack_runloop_timers, (btstack_linked_item_t *)tim);
+}
+
+static uint32_t mp_btstack_runloop_get_time_ms(void) {
+ return mp_hal_ticks_ms();
+}
+
+static const btstack_run_loop_t mp_btstack_runloop_rp2 = {
+ &mp_btstack_runloop_init,
+ &btstack_run_loop_base_add_data_source,
+ &btstack_run_loop_base_remove_data_source,
+ &btstack_run_loop_base_enable_data_source_callbacks,
+ &btstack_run_loop_base_disable_data_source_callbacks,
+ &mp_btstack_runloop_set_timer,
+ &mp_btstack_runloop_add_timer,
+ &mp_btstack_runloop_remove_timer,
+ NULL, // execute
+ NULL, // dump_timer
+ &mp_btstack_runloop_get_time_ms,
+ &mp_bluetooth_hci_poll_now, // poll_data_sources_from_irq
+ NULL, // execute_on_main_thread
+ NULL, // trigger_exit
+};
+
+void mp_bluetooth_hci_poll(void) {
+ if (mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_OFF) {
+ return;
+ }
+
+ // Process BT data.
+ if (mp_bluetooth_btstack_state != MP_BLUETOOTH_BTSTACK_STATE_HALTING) {
+ btstack_run_loop_base_poll_data_sources();
+ }
+
+ // Process any BTstack timers.
+ while (mp_btstack_runloop_timers != NULL) {
+ btstack_timer_source_t *tim = (btstack_timer_source_t *)mp_btstack_runloop_timers;
+ int32_t delta_ms = btstack_time_delta(tim->timeout, mp_hal_ticks_ms());
+ if (delta_ms > 0) {
+ // Timer has not expired yet, reschedule HCI poll for this timer.
+ mp_bluetooth_hci_poll_in_ms(delta_ms);
+ break;
+ }
+ btstack_linked_list_pop(&mp_btstack_runloop_timers);
+ tim->process(tim);
+ }
+}
+
+void mp_bluetooth_btstack_port_init(void) {
+ btstack_run_loop_init(&mp_btstack_runloop_rp2);
+
+ #if BTSTACK_ENABLE_HCI_DUMP
+ hci_dump_init(hci_dump_embedded_stdout_get_instance());
+ #endif
+
+ const hci_transport_t *transport = hci_transport_cyw43_instance();
+ hci_init(transport, NULL);
+}
+
+void mp_bluetooth_btstack_port_deinit(void) {
+ hci_power_control(HCI_POWER_OFF);
+ // We really need hci to be closed or else we might get a BT interrupt going off and
+ // this will cause a crash when calling btstack_run_loop_poll_data_sources_from_irq after the btstack run loop has been deleted
+ if (mp_bluetooth_btstack_state != MP_BLUETOOTH_BTSTACK_STATE_OFF) {
+ hci_transport_cyw43_instance()->close();
+ }
+ hci_close();
+}
+
+void mp_bluetooth_btstack_port_start(void) {
+ hci_power_control(HCI_POWER_ON);
+}
+
+#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK
diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index 28b06fa3a..df4483166 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -282,3 +282,9 @@ typedef intptr_t mp_off_t;
extern uint32_t rosc_random_u32(void);
extern void lwip_lock_acquire(void);
extern void lwip_lock_release(void);
+
+#if MICROPY_PY_BLUETOOTH_CYW43
+// Bluetooth code only runs in the scheduler, no locking/mutex required.
+#define MICROPY_PY_BLUETOOTH_ENTER uint32_t atomic_state = 0;
+#define MICROPY_PY_BLUETOOTH_EXIT (void)atomic_state;
+#endif
diff --git a/ports/rp2/mpnetworkport.c b/ports/rp2/mpnetworkport.c
index d8e33e229..dac04760b 100644
--- a/ports/rp2/mpnetworkport.c
+++ b/ports/rp2/mpnetworkport.c
@@ -62,7 +62,7 @@ static void gpio_irq_handler(void) {
}
void cyw43_irq_init(void) {
- gpio_add_raw_irq_handler_with_order_priority(IO_IRQ_BANK0, gpio_irq_handler, CYW43_SHARED_IRQ_HANDLER_PRIORITY);
+ gpio_add_raw_irq_handler_with_order_priority(CYW43_PIN_WL_HOST_WAKE, gpio_irq_handler, CYW43_SHARED_IRQ_HANDLER_PRIORITY);
irq_set_enabled(IO_IRQ_BANK0, true);
NVIC_SetPriority(PendSV_IRQn, PICO_LOWEST_IRQ_PRIORITY);
}