rp2: Add Bluetooth support via cyw43.
Using BTstack with CYW43 for Pico W. Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
parent
35182a8688
commit
888a15cda3
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue