Skip to content

Commit 4eb1c7d

Browse files
Support Bluetooth under FreeRTOS (#3095)
Integrate the BTStack run loop into the new LWIP work thread for CYW43 processing. Remove the async_context and use alarms and FreeRTOS primitves to do the work. FreeRTOS binary semaphores are a better way of not wasting time or burning CPU when waiting for the BTStack run loop to complete.
1 parent 19a8853 commit 4eb1c7d

File tree

4 files changed

+173
-0
lines changed

4 files changed

+173
-0
lines changed

cores/rp2040/cyw43_wrappers.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,19 @@ extern "C" void init_cyw43_wifi() {
159159
}
160160

161161
extern "C" void __lockBluetooth() {
162+
#ifdef __FREERTOS
163+
cyw43_thread_enter();
164+
#else
162165
async_context_acquire_lock_blocking(cyw43_arch_async_context());
166+
#endif
163167
}
164168

165169
extern "C" void __unlockBluetooth() {
170+
#ifdef __FREERTOS
171+
cyw43_thread_exit();
172+
#else
166173
async_context_release_lock(cyw43_arch_async_context());
174+
#endif
167175
}
168176

169177
extern "C" void __pinMode(pin_size_t pin, PinMode mode);

cores/rp2040/lwip_wrap.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <sys/lock.h>
3232
#include "_xoshiro.h"
3333
#include "lwip_wrap.h"
34+
#include <pico/btstack_run_loop_async_context.h>
3435

3536
//auto_init_recursive_mutex(__lwipMutex); // Only for case with no Ethernet or PicoW, but still doing LWIP (PPP?)
3637
recursive_mutex_t __lwipMutex;
@@ -900,6 +901,11 @@ extern "C" {
900901
__real_cyw43_arch_gpio_put(wl_gpio, value);
901902
}
902903

904+
extern const btstack_run_loop_t *__real_btstack_run_loop_async_context_get_instance(async_context_t *async_context);
905+
const btstack_run_loop_t *__wrap_btstack_run_loop_async_context_get_instance(async_context_t *async_context) {
906+
return __real_btstack_run_loop_async_context_get_instance(async_context);
907+
}
908+
903909

904910
#endif
905911

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// Hacked by EFP3 to with FreeRTOS native, no async context.
2+
3+
#ifdef __FREERTOS
4+
/*
5+
Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
6+
7+
SPDX-License-Identifier: BSD-3-Clause
8+
*/
9+
#include <Arduino.h>
10+
#include <lwip_wrap.h>
11+
#include "FreeRTOS.h"
12+
#include "semphr.h"
13+
14+
#include "pico/btstack_run_loop_async_context.h"
15+
#include "hardware/sync.h"
16+
17+
static void btstack_work_pending(async_context_t *context, async_when_pending_worker_t *worker);
18+
static SemaphoreHandle_t _run_loop_exit_binary;
19+
20+
static void do_btstack_work_pending(void *data) {
21+
btstack_work_pending(NULL, NULL);
22+
}
23+
24+
static void btstack_run_loop_freertos_native_init(void) {
25+
_run_loop_exit_binary = xSemaphoreCreateBinary();
26+
btstack_run_loop_base_init();
27+
}
28+
29+
static void btstack_run_loop_freertos_native_add_data_source(btstack_data_source_t * data_source) {
30+
cyw43_thread_enter();
31+
btstack_run_loop_base_add_data_source(data_source);
32+
cyw43_thread_exit();
33+
}
34+
35+
static bool btstack_run_loop_freertos_native_remove_data_source(btstack_data_source_t * data_source) {
36+
cyw43_thread_enter();
37+
bool rc = btstack_run_loop_base_remove_data_source(data_source);
38+
cyw43_thread_exit();
39+
return rc;
40+
}
41+
42+
static void btstack_run_loop_freertos_native_enable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callbacks) {
43+
cyw43_thread_enter();
44+
btstack_run_loop_base_enable_data_source_callbacks(data_source, callbacks);
45+
cyw43_thread_exit();
46+
}
47+
48+
static void btstack_run_loop_freertos_native_disable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callbacks) {
49+
cyw43_thread_enter();
50+
btstack_run_loop_base_disable_data_source_callbacks(data_source, callbacks);
51+
cyw43_thread_exit();
52+
}
53+
54+
static void btstack_run_loop_freertos_native_set_timer(btstack_timer_source_t *ts, uint32_t timeout_in_ms) {
55+
cyw43_thread_enter();
56+
ts->timeout = to_ms_since_boot(get_absolute_time()) + timeout_in_ms + 1;
57+
lwip_callback(do_btstack_work_pending, NULL);
58+
cyw43_thread_exit();
59+
}
60+
61+
static void btstack_run_loop_freertos_native_add_timer(btstack_timer_source_t *timer) {
62+
cyw43_thread_enter();
63+
btstack_run_loop_base_add_timer(timer);
64+
lwip_callback(do_btstack_work_pending, NULL);
65+
cyw43_thread_exit();
66+
}
67+
68+
static bool btstack_run_loop_freertos_native_remove_timer(btstack_timer_source_t *timer) {
69+
cyw43_thread_enter();
70+
bool rc = btstack_run_loop_base_remove_timer(timer);
71+
cyw43_thread_exit();
72+
return rc;
73+
}
74+
75+
static void btstack_run_loop_freertos_native_dump_timer(void) {
76+
cyw43_thread_enter();
77+
btstack_run_loop_base_dump_timer();
78+
cyw43_thread_exit();
79+
}
80+
81+
static uint32_t btstack_run_loop_freertos_native_get_time_ms(void) {
82+
return to_ms_since_boot(get_absolute_time());
83+
}
84+
85+
static void btstack_run_loop_freertos_native_execute(void) {
86+
// Try and take a binary semaphore that only the done-loop will give
87+
xSemaphoreTake(_run_loop_exit_binary, portMAX_DELAY);
88+
}
89+
90+
static void btstack_run_loop_async_context_trigger_exit(void) {
91+
xSemaphoreGive(_run_loop_exit_binary);
92+
}
93+
94+
static void btstack_run_loop_freertos_native_execute_on_main_thread(btstack_context_callback_registration_t *callback_registration) {
95+
cyw43_thread_enter();
96+
btstack_run_loop_base_add_callback(callback_registration);
97+
lwip_callback(do_btstack_work_pending, NULL);
98+
cyw43_thread_exit();
99+
}
100+
101+
static void btstack_run_loop_freertos_native_poll_data_sources_from_irq(void) {
102+
lwip_callback(do_btstack_work_pending, NULL);
103+
}
104+
105+
static const btstack_run_loop_t btstack_run_loop_freertos_native = {
106+
&btstack_run_loop_freertos_native_init,
107+
&btstack_run_loop_freertos_native_add_data_source,
108+
&btstack_run_loop_freertos_native_remove_data_source,
109+
&btstack_run_loop_freertos_native_enable_data_source_callbacks,
110+
&btstack_run_loop_freertos_native_disable_data_source_callbacks,
111+
&btstack_run_loop_freertos_native_set_timer,
112+
&btstack_run_loop_freertos_native_add_timer,
113+
&btstack_run_loop_freertos_native_remove_timer,
114+
&btstack_run_loop_freertos_native_execute,
115+
&btstack_run_loop_freertos_native_dump_timer,
116+
&btstack_run_loop_freertos_native_get_time_ms,
117+
&btstack_run_loop_freertos_native_poll_data_sources_from_irq,
118+
&btstack_run_loop_freertos_native_execute_on_main_thread,
119+
&btstack_run_loop_async_context_trigger_exit,
120+
};
121+
122+
static alarm_id_t _timeout = -1;
123+
static int64_t cb_btstack_timeout_worker(alarm_id_t id, void *user_data) {
124+
static __callback_req _timeoutIRQBuffer;
125+
// This will be in IRQ context, so do a lwip callback. Only one at a time can be outstanding so this single struct is good enough
126+
_timeout = -1;
127+
lwip_callback(do_btstack_work_pending, NULL, &_timeoutIRQBuffer);
128+
return 0; // Don't reschedule
129+
}
130+
131+
static void btstack_work_pending(__unused async_context_t *context, __unused async_when_pending_worker_t *worker) {
132+
// poll data sources
133+
btstack_run_loop_base_poll_data_sources();
134+
135+
// execute callbacks
136+
btstack_run_loop_base_execute_callbacks();
137+
138+
uint32_t now = to_ms_since_boot(get_absolute_time());
139+
140+
// process timers
141+
btstack_run_loop_base_process_timers(now);
142+
now = to_ms_since_boot(get_absolute_time());
143+
int ms = btstack_run_loop_base_get_time_until_timeout(now);
144+
if (ms == -1) {
145+
if (_timeout != -1) {
146+
cancel_alarm(_timeout);
147+
_timeout = -1;
148+
}
149+
} else {
150+
_timeout = add_alarm_in_ms(ms, cb_btstack_timeout_worker, NULL, true);
151+
}
152+
}
153+
154+
// The only exported function here...
155+
extern "C" const btstack_run_loop_t *__wrap_btstack_run_loop_async_context_get_instance(async_context_t *freertos_native) {
156+
return &btstack_run_loop_freertos_native;
157+
}
158+
#endif

lib/core_wrap.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,4 @@
9393
-Wl,--wrap=cyw43_arch_wifi_connect_bssid_timeout_ms
9494
-Wl,--wrap=cyw43_arch_wifi_connect_timeout_ms
9595
-Wl,--wrap=cyw43_arch_gpio_put
96+
-Wl,--wrap=btstack_run_loop_async_context_get_instance

0 commit comments

Comments
 (0)