Add new async_context abstraction and refactor cyw43_arch to use it (#1177)
* Extract all poll/threadsafe_background/freertos from cyw43_arch into new abstraction async_context: * provides support for asynchronous events (timers/IRQ notifications) to be handled in a safe context. * now guarantees all callbacks happen on a single core. * is reusable by multiple different libraries (stdio_usb can now be ported to this but hasn't been yet). * supports multiple independent instances (independent instances will not block each other). * cyw43_arch libraries cleaned up to use the new abstraction. Note each distinct cyw43_arch type is now a very thin layer that creates the right type of context and adds cyw43_driver and lwip support as appropriate. Additionally, * Add new pico_time and hardware_alarm APIs * Add from_us_since_boot() * Add alarm_pool_create_with_unused_hardware_alarm() * Add alarm_pool_add_alarm_at_force_in_context() * Add hardware_alarm_claim_unused() * Add hardware_alarm_force_irq() * Added panic_compact() and some minor comment cleanup; moved FIRST_USER_IRQ define to platform_defs.h
This commit is contained in:
@ -1,7 +1,5 @@
|
||||
if (PICO_CYW43_SUPPORTED) # set by BOARD=pico-w
|
||||
if (TARGET cyw43_driver_picow)
|
||||
message("Enabling build support for Pico W wireless.")
|
||||
|
||||
pico_add_impl_library(pico_cyw43_arch)
|
||||
target_sources(pico_cyw43_arch INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/cyw43_arch.c
|
||||
@ -15,45 +13,70 @@ if (PICO_CYW43_SUPPORTED) # set by BOARD=pico-w
|
||||
|
||||
target_link_libraries(pico_cyw43_arch INTERFACE
|
||||
pico_unique_id
|
||||
cyw43_driver_picow)
|
||||
cyw43_driver_picow # driver for pico w
|
||||
pico_cyw43_driver # integration with async_context
|
||||
)
|
||||
|
||||
if (NOT TARGET pico_lwip)
|
||||
message(WARNING "lwIP is not available; Full Pico W wireless support will be unavailable too")
|
||||
message(WARNING "lwIP is not available; Full Pico W wireless support will be unavailable")
|
||||
else()
|
||||
add_library(pico_cyw43_arch_lwip_poll INTERFACE)
|
||||
target_link_libraries(pico_cyw43_arch_lwip_poll INTERFACE
|
||||
message("Pico W wireless build support available.")
|
||||
add_library(pico_cyw43_arch_poll INTERFACE)
|
||||
target_link_libraries(pico_cyw43_arch_poll INTERFACE
|
||||
pico_cyw43_arch
|
||||
pico_lwip
|
||||
pico_lwip_nosys)
|
||||
target_compile_definitions(pico_cyw43_arch_lwip_poll INTERFACE
|
||||
CYW43_LWIP=1
|
||||
pico_async_context_poll)
|
||||
target_compile_definitions(pico_cyw43_arch_poll INTERFACE
|
||||
PICO_CYW43_ARCH_POLL=1
|
||||
)
|
||||
|
||||
add_library(pico_cyw43_arch_lwip_threadsafe_background INTERFACE)
|
||||
target_link_libraries(pico_cyw43_arch_lwip_threadsafe_background INTERFACE
|
||||
add_library(pico_cyw43_arch_lwip_poll INTERFACE)
|
||||
target_link_libraries(pico_cyw43_arch_lwip_poll INTERFACE
|
||||
pico_lwip_nosys
|
||||
pico_cyw43_arch_poll)
|
||||
target_compile_definitions(pico_cyw43_arch_lwip_poll INTERFACE
|
||||
CYW43_LWIP=1
|
||||
)
|
||||
|
||||
add_library(pico_cyw43_arch_threadsafe_background INTERFACE)
|
||||
target_link_libraries(pico_cyw43_arch_threadsafe_background INTERFACE
|
||||
pico_cyw43_arch
|
||||
pico_lwip
|
||||
pico_lwip_nosys)
|
||||
pico_async_context_threadsafe_background)
|
||||
target_compile_definitions(pico_cyw43_arch_threadsafe_background INTERFACE
|
||||
PICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1
|
||||
)
|
||||
add_library(pico_cyw43_arch_lwip_threadsafe_background INTERFACE)
|
||||
|
||||
target_link_libraries(pico_cyw43_arch_lwip_threadsafe_background INTERFACE
|
||||
pico_lwip_nosys
|
||||
pico_cyw43_arch_threadsafe_background)
|
||||
target_compile_definitions(pico_cyw43_arch_lwip_threadsafe_background INTERFACE
|
||||
CYW43_LWIP=1
|
||||
PICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1
|
||||
)
|
||||
|
||||
add_library(pico_cyw43_arch_sys_freertos INTERFACE)
|
||||
target_link_libraries(pico_cyw43_arch_sys_freertos INTERFACE
|
||||
pico_cyw43_arch
|
||||
pico_async_context_freertos)
|
||||
target_compile_definitions(pico_cyw43_arch_sys_freertos INTERFACE
|
||||
PICO_CYW43_ARCH_FREERTOS=1
|
||||
)
|
||||
|
||||
add_library(pico_cyw43_arch_lwip_sys_freertos INTERFACE)
|
||||
target_link_libraries(pico_cyw43_arch_lwip_sys_freertos INTERFACE
|
||||
pico_cyw43_arch
|
||||
pico_lwip
|
||||
pico_lwip_contrib_freertos)
|
||||
pico_lwip_freertos
|
||||
pico_cyw43_arch_sys_freertos)
|
||||
target_compile_definitions(pico_cyw43_arch_lwip_sys_freertos INTERFACE
|
||||
CYW43_LWIP=1
|
||||
LWIP_PROVIDE_ERRNO=1
|
||||
PICO_CYW43_ARCH_FREERTOS=1
|
||||
# now the default
|
||||
#PICO_LWIP_CUSTOM_LOCK_TCPIP_CORE=1 # we want to override the lwip locking mechanism to use our mutex
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(pico_cyw43_arch_none INTERFACE)
|
||||
target_link_libraries(pico_cyw43_arch_none INTERFACE pico_cyw43_arch)
|
||||
target_link_libraries(pico_cyw43_arch_none INTERFACE
|
||||
pico_cyw43_arch
|
||||
pico_async_context_threadsafe_background)
|
||||
target_compile_definitions(pico_cyw43_arch_none INTERFACE
|
||||
CYW43_LWIP=0
|
||||
PICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 # none still uses threadsafe_background to make gpio use easy
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "cyw43_ll.h"
|
||||
#include "cyw43_stats.h"
|
||||
|
||||
#if CYW43_ARCH_DEBUG_ENABLED
|
||||
#if PICO_CYW43_ARCH_DEBUG_ENABLED
|
||||
#define CYW43_ARCH_DEBUG(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define CYW43_ARCH_DEBUG(...) ((void)0)
|
||||
@ -22,6 +22,12 @@
|
||||
|
||||
static uint32_t country_code = PICO_CYW43_ARCH_DEFAULT_COUNTRY_CODE;
|
||||
|
||||
static async_context_t *async_context;
|
||||
|
||||
void cyw43_arch_set_async_context(async_context_t *context) {
|
||||
async_context = context;
|
||||
}
|
||||
|
||||
void cyw43_arch_enable_sta_mode() {
|
||||
assert(cyw43_is_initialized(&cyw43_state));
|
||||
cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_STA, true, cyw43_arch_get_country_code());
|
||||
@ -39,9 +45,9 @@ void cyw43_arch_enable_ap_mode(const char *ssid, const char *password, uint32_t
|
||||
cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_AP, true, cyw43_arch_get_country_code());
|
||||
}
|
||||
|
||||
#if CYW43_ARCH_DEBUG_ENABLED
|
||||
#if PICO_CYW43_ARCH_DEBUG_ENABLED
|
||||
// Return a string for the wireless state
|
||||
static const char* status_name(int status)
|
||||
const char* cyw43_tcpip_link_status_name(int status)
|
||||
{
|
||||
switch (status) {
|
||||
case CYW43_LINK_DOWN:
|
||||
@ -79,14 +85,14 @@ int cyw43_arch_wifi_connect_until(const char *ssid, const char *pw, uint32_t aut
|
||||
int new_status = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA);
|
||||
if (new_status != status) {
|
||||
status = new_status;
|
||||
CYW43_ARCH_DEBUG("connect status: %s\n", status_name(status));
|
||||
CYW43_ARCH_DEBUG("connect status: %s\n", cyw43_tcpip_link_status_name(status));
|
||||
}
|
||||
// in case polling is required
|
||||
cyw43_arch_poll();
|
||||
best_effort_wfe_or_timeout(until);
|
||||
if (time_reached(until)) {
|
||||
return PICO_ERROR_TIMEOUT;
|
||||
}
|
||||
// Do polling
|
||||
cyw43_arch_poll();
|
||||
cyw43_arch_wait_for_work_until(until);
|
||||
}
|
||||
return status == CYW43_LINK_UP ? 0 : status;
|
||||
}
|
||||
@ -143,3 +149,64 @@ bool cyw43_arch_gpio_get(uint wl_gpio) {
|
||||
cyw43_gpio_get(&cyw43_state, (int)wl_gpio, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
async_context_t *cyw43_arch_async_context(void) {
|
||||
return async_context;
|
||||
}
|
||||
|
||||
void cyw43_arch_poll(void)
|
||||
{
|
||||
async_context_poll(async_context);
|
||||
}
|
||||
|
||||
void cyw43_arch_wait_for_work_until(absolute_time_t until) {
|
||||
async_context_wait_for_work_until(async_context, until);
|
||||
}
|
||||
|
||||
// Prevent background processing in pensv and access by the other core
|
||||
// These methods are called in pensv context and on either core
|
||||
// They can be called recursively
|
||||
void cyw43_thread_enter(void) {
|
||||
async_context_acquire_lock_blocking(async_context);
|
||||
}
|
||||
|
||||
void cyw43_thread_exit(void) {
|
||||
async_context_release_lock(async_context);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void cyw43_thread_lock_check(void) {
|
||||
async_context_lock_check(async_context);
|
||||
}
|
||||
#endif
|
||||
|
||||
void cyw43_await_background_or_timeout_us(uint32_t timeout_us) {
|
||||
async_context_wait_for_work_until(async_context, make_timeout_time_us(timeout_us));
|
||||
}
|
||||
|
||||
void cyw43_delay_ms(uint32_t ms) {
|
||||
async_context_wait_until(async_context, make_timeout_time_ms(ms));
|
||||
}
|
||||
|
||||
void cyw43_delay_us(uint32_t us) {
|
||||
async_context_wait_until(async_context, make_timeout_time_us(us));
|
||||
}
|
||||
|
||||
#if !CYW43_LWIP
|
||||
static void no_lwip_fail() {
|
||||
panic("cyw43 has no ethernet interface");
|
||||
}
|
||||
void __attribute__((weak)) cyw43_cb_tcpip_init(cyw43_t *self, int itf) {
|
||||
}
|
||||
void __attribute__((weak)) cyw43_cb_tcpip_deinit(cyw43_t *self, int itf) {
|
||||
}
|
||||
void __attribute__((weak)) cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) {
|
||||
no_lwip_fail();
|
||||
}
|
||||
void __attribute__((weak)) cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
|
||||
no_lwip_fail();
|
||||
}
|
||||
void __attribute__((weak)) cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf) {
|
||||
no_lwip_fail();
|
||||
}
|
||||
#endif
|
||||
|
@ -4,250 +4,71 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#if PICO_CYW43_ARCH_FREERTOS
|
||||
|
||||
#include "pico/cyw43_arch.h"
|
||||
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "hardware/sync.h"
|
||||
|
||||
#include "cyw43_stats.h"
|
||||
#include "pico/cyw43_driver.h"
|
||||
#include "pico/async_context_freertos.h"
|
||||
|
||||
#if CYW43_LWIP
|
||||
#include "pico/lwip_freertos.h"
|
||||
#include <lwip/tcpip.h>
|
||||
#endif
|
||||
|
||||
#if PICO_CYW43_ARCH_FREERTOS
|
||||
|
||||
// FreeRTOS includes
|
||||
#include "FreeRTOS.h"
|
||||
#include "timers.h"
|
||||
#include "semphr.h"
|
||||
|
||||
#if NO_SYS
|
||||
#error example_cyw43_arch_frertos_sys requires NO_SYS=0
|
||||
#error example_cyw43_arch_freetos_sys requires NO_SYS=0
|
||||
#endif
|
||||
|
||||
#ifndef CYW43_TASK_PRIORITY
|
||||
#define CYW43_TASK_PRIORITY ( tskIDLE_PRIORITY + 4)
|
||||
static async_context_freertos_t cyw43_async_context_freertos;
|
||||
|
||||
async_context_t *cyw43_arch_init_default_async_context(void) {
|
||||
async_context_freertos_config_t config = async_context_freertos_default_config();
|
||||
#ifdef CYW43_TASK_PRIORITY
|
||||
config.task_priority = CYW43_TASK_PRIORITY;
|
||||
#endif
|
||||
|
||||
#ifndef CYW43_SLEEP_CHECK_MS
|
||||
#define CYW43_SLEEP_CHECK_MS 50 // How often to run lwip callback
|
||||
#ifdef CYW43_TASK_STACK_SIZE
|
||||
config.task_stack_size = CYW43_TASK_STACK_SIZE;
|
||||
#endif
|
||||
|
||||
#define CYW43_GPIO_IRQ_HANDLER_PRIORITY 0x40
|
||||
|
||||
static void signal_cyw43_task(void);
|
||||
|
||||
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||
static SemaphoreHandle_t cyw43_mutex;
|
||||
#endif
|
||||
static TimerHandle_t timer_handle;
|
||||
static TaskHandle_t cyw43_task_handle;
|
||||
static volatile bool cyw43_task_should_exit;
|
||||
static SemaphoreHandle_t cyw43_worker_ran_sem;
|
||||
static uint8_t cyw43_core_num;
|
||||
|
||||
// Called in low priority pendsv interrupt only to do lwip processing and check cyw43 sleep
|
||||
static void periodic_worker(__unused TimerHandle_t handle)
|
||||
{
|
||||
#if CYW43_USE_STATS
|
||||
static uint32_t counter;
|
||||
if (counter++ % (30000 / LWIP_SYS_CHECK_MS) == 0) {
|
||||
cyw43_dump_stats();
|
||||
}
|
||||
#endif
|
||||
|
||||
CYW43_STAT_INC(LWIP_RUN_COUNT);
|
||||
if (cyw43_poll) {
|
||||
if (cyw43_sleep > 0) {
|
||||
if (--cyw43_sleep == 0) {
|
||||
signal_cyw43_task();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cyw43_await_background_or_timeout_us(uint32_t timeout_us) {
|
||||
// if we are called from within an IRQ, then don't wait (we are only ever called in a polling loop)
|
||||
assert(!portCHECK_IF_IN_ISR());
|
||||
xSemaphoreTake(cyw43_worker_ran_sem, pdMS_TO_TICKS(timeout_us / 1000));
|
||||
}
|
||||
|
||||
// GPIO interrupt handler to tell us there's cyw43 has work to do
|
||||
static void gpio_irq_handler(void)
|
||||
{
|
||||
uint32_t events = gpio_get_irq_event_mask(CYW43_PIN_WL_HOST_WAKE);
|
||||
if (events & GPIO_IRQ_LEVEL_HIGH) {
|
||||
// As we use a high level interrupt, it will go off forever until it's serviced
|
||||
// So disable the interrupt until this is done. It's re-enabled again by CYW43_POST_POLL_HOOK
|
||||
// which is called at the end of cyw43_poll_func
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
|
||||
signal_cyw43_task();
|
||||
CYW43_STAT_INC(IRQ_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
// Low priority interrupt handler to perform background processing
|
||||
static void cyw43_task(__unused void *param) {
|
||||
do {
|
||||
ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
|
||||
if (cyw43_task_should_exit) break;
|
||||
cyw43_thread_enter();
|
||||
if (cyw43_poll) cyw43_poll();
|
||||
cyw43_thread_exit();
|
||||
xSemaphoreGive(cyw43_worker_ran_sem);
|
||||
__sev(); // it is possible regular code is waiting on a WFE on the other core
|
||||
} while (true);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void tcpip_init_done(void *param) {
|
||||
xSemaphoreGive((SemaphoreHandle_t)param);
|
||||
if (async_context_freertos_init(&cyw43_async_context_freertos, &config))
|
||||
return &cyw43_async_context_freertos.core;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int cyw43_arch_init(void) {
|
||||
cyw43_core_num = get_core_num();
|
||||
#if configUSE_CORE_AFFINITY && configNUM_CORES > 1
|
||||
TaskHandle_t task_handle = xTaskGetCurrentTaskHandle();
|
||||
UBaseType_t affinity = vTaskCoreAffinityGet(task_handle);
|
||||
// we must bind the main task to one core during init
|
||||
vTaskCoreAffinitySet(task_handle, 1 << portGET_CORE_ID());
|
||||
#endif
|
||||
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||
cyw43_mutex = xSemaphoreCreateRecursiveMutex();
|
||||
#endif
|
||||
cyw43_init(&cyw43_state);
|
||||
cyw43_worker_ran_sem = xSemaphoreCreateBinary();
|
||||
|
||||
#if CYW43_LWIP
|
||||
SemaphoreHandle_t init_sem = xSemaphoreCreateBinary();
|
||||
tcpip_init(tcpip_init_done, init_sem);
|
||||
xSemaphoreTake(init_sem, portMAX_DELAY);
|
||||
#endif
|
||||
|
||||
timer_handle = xTimerCreate( "cyw43_sleep_timer", // Just a text name, not used by the kernel.
|
||||
pdMS_TO_TICKS(CYW43_SLEEP_CHECK_MS),
|
||||
pdTRUE, // The timers will auto-reload themselves when they expire.
|
||||
NULL,
|
||||
periodic_worker);
|
||||
|
||||
if (!timer_handle) {
|
||||
return PICO_ERROR_GENERIC;
|
||||
async_context_t *context = cyw43_arch_async_context();
|
||||
if (!context) {
|
||||
context = cyw43_arch_init_default_async_context();
|
||||
if (!context) return PICO_ERROR_GENERIC;
|
||||
cyw43_arch_set_async_context(context);
|
||||
}
|
||||
|
||||
gpio_add_raw_irq_handler_with_order_priority(CYW43_PIN_WL_HOST_WAKE, gpio_irq_handler, CYW43_GPIO_IRQ_HANDLER_PRIORITY);
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
|
||||
irq_set_enabled(IO_IRQ_BANK0, true);
|
||||
|
||||
cyw43_task_should_exit = false;
|
||||
xTaskCreate(cyw43_task, "CYW43 Worker", configMINIMAL_STACK_SIZE, NULL, CYW43_TASK_PRIORITY, &cyw43_task_handle);
|
||||
#if configUSE_CORE_AFFINITY && configNUM_CORES > 1
|
||||
// the cyw43 task mus tbe on the same core so it can restore IRQs
|
||||
vTaskCoreAffinitySet(cyw43_task_handle, 1 << portGET_CORE_ID());
|
||||
bool ok = cyw43_driver_init(context);
|
||||
#if CYW43_LWIP
|
||||
ok &= lwip_freertos_init(context);
|
||||
#endif
|
||||
|
||||
#if configUSE_CORE_AFFINITY && configNUM_CORES > 1
|
||||
vTaskCoreAffinitySet(task_handle, affinity);
|
||||
#endif
|
||||
|
||||
return PICO_OK;
|
||||
if (!ok) {
|
||||
cyw43_arch_deinit();
|
||||
return PICO_ERROR_GENERIC;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void cyw43_arch_deinit(void) {
|
||||
assert(cyw43_core_num == get_core_num());
|
||||
if (timer_handle) {
|
||||
xTimerDelete(timer_handle, 0);
|
||||
timer_handle = 0;
|
||||
}
|
||||
if (cyw43_task_handle) {
|
||||
cyw43_task_should_exit = true;
|
||||
signal_cyw43_task();
|
||||
}
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
|
||||
gpio_remove_raw_irq_handler(CYW43_PIN_WL_HOST_WAKE, gpio_irq_handler);
|
||||
cyw43_deinit(&cyw43_state);
|
||||
}
|
||||
|
||||
void cyw43_post_poll_hook(void) {
|
||||
assert(cyw43_core_num == get_core_num());
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
|
||||
}
|
||||
|
||||
// This is called in the gpio and low_prio_irq interrupts and on either core
|
||||
static void signal_cyw43_task(void) {
|
||||
if (cyw43_task_handle) {
|
||||
if (portCHECK_IF_IN_ISR()) {
|
||||
vTaskNotifyGiveFromISR(cyw43_task_handle, NULL);
|
||||
} else {
|
||||
xTaskNotifyGive(cyw43_task_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cyw43_schedule_internal_poll_dispatch(void (*func)(void)) {
|
||||
assert(func == cyw43_poll);
|
||||
signal_cyw43_task();
|
||||
}
|
||||
|
||||
static int nesting;
|
||||
// Prevent background processing in pensv and access by the other core
|
||||
// These methods are called in pensv context and on either core
|
||||
// They can be called recursively
|
||||
void cyw43_thread_enter(void) {
|
||||
// Lock the other core and stop low_prio_irq running
|
||||
assert(!portCHECK_IF_IN_ISR());
|
||||
#if LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||
// we must share their mutex otherwise we can get deadlocks with two different recursive mutexes
|
||||
LOCK_TCPIP_CORE();
|
||||
#else
|
||||
xSemaphoreTakeRecursive(cyw43_mutex, portMAX_DELAY);
|
||||
async_context_t *context = cyw43_arch_async_context();
|
||||
// there is a bit of a circular dependency here between lwIP and cyw43_driver. We
|
||||
// shut down cyw43_driver first as it has IRQs calling back into lwIP. Also lwIP itself
|
||||
// does not actually get shut down.
|
||||
// todo add a "pause" method to async_context if we need to provide some atomicity (we
|
||||
// don't want to take the lock as these methods may invoke execute_sync()
|
||||
cyw43_driver_deinit(context);
|
||||
#if CYW43_LWIP
|
||||
lwip_freertos_deinit(context);
|
||||
#endif
|
||||
nesting++;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void cyw43_thread_lock_check(void) {
|
||||
// Lock the other core and stop low_prio_irq running
|
||||
#if LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||
assert(xSemaphoreGetMutexHolder(lock_tcpip_core.mut) == xTaskGetCurrentTaskHandle());
|
||||
#else
|
||||
assert(xSemaphoreGetMutexHolder(cyw43_mutex) == xTaskGetCurrentTaskHandle());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// Re-enable background processing
|
||||
void cyw43_thread_exit(void) {
|
||||
// Run low_prio_irq if needed
|
||||
--nesting;
|
||||
#if LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||
// we must share their mutex otherwise we can get deadlocks with two different recursive mutexes
|
||||
UNLOCK_TCPIP_CORE();
|
||||
#else
|
||||
xSemaphoreGiveRecursive(cyw43_mutex);
|
||||
#endif
|
||||
|
||||
if (!nesting && cyw43_task_handle != xTaskGetCurrentTaskHandle())
|
||||
signal_cyw43_task();
|
||||
}
|
||||
|
||||
void cyw43_delay_ms(uint32_t ms) {
|
||||
assert(!portCHECK_IF_IN_ISR());
|
||||
vTaskDelay(pdMS_TO_TICKS(ms));
|
||||
}
|
||||
|
||||
void cyw43_delay_us(uint32_t us) {
|
||||
if (us >= 1000) {
|
||||
cyw43_delay_ms(us / 1000);
|
||||
} else {
|
||||
vTaskDelay(1);
|
||||
// if it is our context, then we de-init it.
|
||||
if (context == &cyw43_async_context_freertos.core) {
|
||||
async_context_deinit(context);
|
||||
cyw43_arch_set_async_context(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void cyw43_arch_poll() {
|
||||
}
|
||||
|
||||
#endif
|
@ -4,110 +4,62 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "pico/sem.h"
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include "cyw43_stats.h"
|
||||
#include "pico/cyw43_driver.h"
|
||||
|
||||
#if PICO_CYW43_ARCH_POLL
|
||||
#include <lwip/init.h>
|
||||
#include "lwip/timeouts.h"
|
||||
#include "pico/async_context_poll.h"
|
||||
#if CYW43_LWIP
|
||||
#include "pico/lwip_nosys.h"
|
||||
#endif
|
||||
|
||||
#if CYW43_LWIP && !NO_SYS
|
||||
#error PICO_CYW43_ARCH_POLL requires lwIP NO_SYS=1
|
||||
#endif
|
||||
|
||||
#define CYW43_GPIO_IRQ_HANDLER_PRIORITY 0x40
|
||||
static async_context_poll_t cyw43_async_context_poll;
|
||||
|
||||
#ifndef NDEBUG
|
||||
uint8_t cyw43_core_num;
|
||||
#endif
|
||||
|
||||
bool cyw43_poll_required;
|
||||
|
||||
// GPIO interrupt handler to tell us there's cyw43 has work to do
|
||||
static void gpio_irq_handler(void)
|
||||
{
|
||||
uint32_t events = gpio_get_irq_event_mask(CYW43_PIN_WL_HOST_WAKE);
|
||||
if (events & GPIO_IRQ_LEVEL_HIGH) {
|
||||
// As we use a high level interrupt, it will go off forever until it's serviced
|
||||
// So disable the interrupt until this is done. It's re-enabled again by CYW43_POST_POLL_HOOK
|
||||
// which is called at the end of cyw43_poll_func
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
|
||||
// also clear the force bit which we use to programmatically cause this handler to fire (on the right core)
|
||||
io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ?
|
||||
&iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
|
||||
hw_clear_bits(&irq_ctrl_base->intf[CYW43_PIN_WL_HOST_WAKE/8], GPIO_IRQ_LEVEL_HIGH << (4 * (CYW43_PIN_WL_HOST_WAKE & 7)));
|
||||
cyw43_schedule_internal_poll_dispatch(cyw43_poll);
|
||||
CYW43_STAT_INC(IRQ_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
void cyw43_post_poll_hook(void) {
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
|
||||
async_context_t *cyw43_arch_init_default_async_context(void) {
|
||||
if (async_context_poll_init_with_defaults(&cyw43_async_context_poll))
|
||||
return &cyw43_async_context_poll.core;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int cyw43_arch_init(void) {
|
||||
#ifndef NDEBUG
|
||||
cyw43_core_num = (uint8_t)get_core_num();
|
||||
#endif
|
||||
cyw43_init(&cyw43_state);
|
||||
static bool done_lwip_init;
|
||||
if (!done_lwip_init) {
|
||||
lwip_init();
|
||||
done_lwip_init = true;
|
||||
async_context_t *context = cyw43_arch_async_context();
|
||||
if (!context) {
|
||||
context = cyw43_arch_init_default_async_context();
|
||||
if (!context) return PICO_ERROR_GENERIC;
|
||||
cyw43_arch_set_async_context(context);
|
||||
}
|
||||
bool ok = cyw43_driver_init(context);
|
||||
#if CYW43_LWIP
|
||||
ok &= lwip_nosys_init(context);
|
||||
#endif
|
||||
if (!ok) {
|
||||
cyw43_arch_deinit();
|
||||
return PICO_ERROR_GENERIC;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
gpio_add_raw_irq_handler_with_order_priority(CYW43_PIN_WL_HOST_WAKE, gpio_irq_handler, CYW43_GPIO_IRQ_HANDLER_PRIORITY);
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
|
||||
irq_set_enabled(IO_IRQ_BANK0, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cyw43_arch_deinit(void) {
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
|
||||
gpio_remove_raw_irq_handler(CYW43_PIN_WL_HOST_WAKE, gpio_irq_handler);
|
||||
cyw43_deinit(&cyw43_state);
|
||||
}
|
||||
|
||||
|
||||
void cyw43_schedule_internal_poll_dispatch(__unused void (*func)(void)) {
|
||||
cyw43_poll_required = true;
|
||||
}
|
||||
|
||||
void cyw43_arch_poll(void)
|
||||
{
|
||||
CYW43_STAT_INC(LWIP_RUN_COUNT);
|
||||
sys_check_timeouts();
|
||||
if (cyw43_poll) {
|
||||
if (cyw43_sleep > 0) {
|
||||
// todo check this; but we don't want to advance too quickly
|
||||
static absolute_time_t last_poll_time;
|
||||
absolute_time_t current = get_absolute_time();
|
||||
if (absolute_time_diff_us(last_poll_time, current) > 1000) {
|
||||
if (--cyw43_sleep == 0) {
|
||||
cyw43_poll_required = 1;
|
||||
}
|
||||
last_poll_time = current;
|
||||
}
|
||||
}
|
||||
// todo graham i removed this because otherwise polling can do nothing during connect.
|
||||
// in the polling only case, the caller is responsible for throttling how often they call anyway.
|
||||
// The alternative would be to have the call to this function from the init set the poll_required flag first
|
||||
// if (cyw43_poll_required) {
|
||||
cyw43_poll();
|
||||
// cyw43_poll_required = false;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void cyw43_thread_check() {
|
||||
if (__get_current_exception() || get_core_num() != cyw43_core_num) {
|
||||
panic("cyw43_thread_lock_check failed");
|
||||
}
|
||||
}
|
||||
async_context_t *context = cyw43_arch_async_context();
|
||||
// there is a bit of a circular dependency here between lwIP and cyw43_driver. We
|
||||
// shut down cyw43_driver first as it has IRQs calling back into lwIP. Also lwIP itself
|
||||
// does not actually get shut down.
|
||||
// todo add a "pause" method to async_context if we need to provide some atomicity (we
|
||||
// don't want to take the lock as these methods may invoke execute_sync()
|
||||
cyw43_driver_deinit(context);
|
||||
#if CYW43_LWIP
|
||||
lwip_nosys_deinit(context);
|
||||
#endif
|
||||
// if it is our context, then we de-init it.
|
||||
if (context == &cyw43_async_context_poll.core) {
|
||||
async_context_deinit(context);
|
||||
cyw43_arch_set_async_context(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -4,317 +4,68 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include "pico/mutex.h"
|
||||
#include "pico/sem.h"
|
||||
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/irq.h"
|
||||
|
||||
#include "cyw43_stats.h"
|
||||
|
||||
#if CYW43_LWIP
|
||||
#include <lwip/init.h>
|
||||
#include "lwip/timeouts.h"
|
||||
#endif
|
||||
|
||||
// note same code
|
||||
#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND
|
||||
|
||||
#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND && CYW43_LWIP && !NO_SYS
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include "pico/cyw43_driver.h"
|
||||
#include "pico/async_context_threadsafe_background.h"
|
||||
|
||||
#if CYW43_LWIP
|
||||
#include "pico/lwip_nosys.h"
|
||||
#endif
|
||||
|
||||
#if CYW43_LWIP && !NO_SYS
|
||||
#error PICO_CYW43_ARCH_THREADSAFE_BACKGROUND requires lwIP NO_SYS=1
|
||||
#endif
|
||||
#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND && CYW43_LWIP && MEM_LIBC_MALLOC
|
||||
#if CYW43_LWIP && MEM_LIBC_MALLOC
|
||||
// would attempt to use malloc from IRQ context
|
||||
#error MEM_LIBC_MALLOC is incompatible with PICO_CYW43_ARCH_THREADSAFE_BACKGROUND
|
||||
#endif
|
||||
// todo right now we are now always doing a cyw43_dispatch along with a lwip one when hopping cores in low_prio_irq_schedule_dispatch
|
||||
|
||||
#ifndef CYW43_SLEEP_CHECK_MS
|
||||
#define CYW43_SLEEP_CHECK_MS 50 // How often to run lwip callback
|
||||
#endif
|
||||
static alarm_id_t periodic_alarm = -1;
|
||||
static async_context_threadsafe_background_t cyw43_async_context_threadsafe_background;
|
||||
|
||||
static inline uint recursive_mutex_enter_count(recursive_mutex_t *mutex) {
|
||||
return mutex->enter_count;
|
||||
}
|
||||
|
||||
static inline lock_owner_id_t recursive_mutex_owner(recursive_mutex_t *mutex) {
|
||||
return mutex->owner;
|
||||
}
|
||||
|
||||
#define CYW43_GPIO_IRQ_HANDLER_PRIORITY 0x40
|
||||
|
||||
enum {
|
||||
CYW43_DISPATCH_SLOT_CYW43 = 0,
|
||||
CYW43_DISPATCH_SLOT_ADAPTER,
|
||||
CYW43_DISPATCH_SLOT_ENUM_COUNT
|
||||
};
|
||||
#ifndef CYW43_DISPATCH_SLOT_COUNT
|
||||
#define CYW43_DISPATCH_SLOT_COUNT CYW43_DISPATCH_SLOT_ENUM_COUNT
|
||||
#endif
|
||||
|
||||
typedef void (*low_prio_irq_dispatch_t)(void);
|
||||
static void low_prio_irq_schedule_dispatch(size_t slot, low_prio_irq_dispatch_t f);
|
||||
|
||||
static uint8_t cyw43_core_num;
|
||||
#ifndef NDEBUG
|
||||
static bool in_low_priority_irq;
|
||||
#endif
|
||||
static uint8_t low_priority_irq_num;
|
||||
static bool low_priority_irq_missed;
|
||||
static low_prio_irq_dispatch_t low_priority_irq_dispatch_slots[CYW43_DISPATCH_SLOT_COUNT];
|
||||
static recursive_mutex_t cyw43_mutex;
|
||||
semaphore_t cyw43_irq_sem;
|
||||
|
||||
// Called in low priority pendsv interrupt only to do lwip processing and check cyw43 sleep
|
||||
static void periodic_worker(void)
|
||||
{
|
||||
#if CYW43_USE_STATS
|
||||
static uint32_t counter;
|
||||
if (counter++ % (30000 / LWIP_SYS_CHECK_MS) == 0) {
|
||||
cyw43_dump_stats();
|
||||
}
|
||||
#endif
|
||||
|
||||
CYW43_STAT_INC(LWIP_RUN_COUNT);
|
||||
#if CYW43_LWIP
|
||||
sys_check_timeouts();
|
||||
#endif
|
||||
if (cyw43_poll) {
|
||||
if (cyw43_sleep > 0) {
|
||||
if (--cyw43_sleep == 0) {
|
||||
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Regular callback to get lwip to check for timeouts
|
||||
static int64_t periodic_alarm_handler(__unused alarm_id_t id, __unused void *user_data)
|
||||
{
|
||||
// Do lwip processing in low priority pendsv interrupt
|
||||
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_ADAPTER, periodic_worker);
|
||||
return CYW43_SLEEP_CHECK_MS * 1000;
|
||||
}
|
||||
|
||||
void cyw43_await_background_or_timeout_us(uint32_t timeout_us) {
|
||||
// if we are called from within an IRQ, then don't wait (we are only ever called in a polling loop)
|
||||
if (!__get_current_exception()) {
|
||||
sem_acquire_timeout_us(&cyw43_irq_sem, timeout_us);
|
||||
}
|
||||
}
|
||||
|
||||
// GPIO interrupt handler to tell us there's cyw43 has work to do
|
||||
static void gpio_irq_handler(void)
|
||||
{
|
||||
uint32_t events = gpio_get_irq_event_mask(CYW43_PIN_WL_HOST_WAKE);
|
||||
if (events & GPIO_IRQ_LEVEL_HIGH) {
|
||||
// As we use a high level interrupt, it will go off forever until it's serviced
|
||||
// So disable the interrupt until this is done. It's re-enabled again by CYW43_POST_POLL_HOOK
|
||||
// which is called at the end of cyw43_poll_func
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
|
||||
// also clear the force bit which we use to progratically cause this handler to fire (on the right core)
|
||||
io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ?
|
||||
&iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
|
||||
hw_clear_bits(&irq_ctrl_base->intf[CYW43_PIN_WL_HOST_WAKE/8], GPIO_IRQ_LEVEL_HIGH << (4 * (CYW43_PIN_WL_HOST_WAKE & 7)));
|
||||
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
|
||||
CYW43_STAT_INC(IRQ_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
// Low priority interrupt handler to perform background processing
|
||||
static void low_priority_irq_handler(void) {
|
||||
assert(cyw43_core_num == get_core_num());
|
||||
if (recursive_mutex_try_enter(&cyw43_mutex, NULL)) {
|
||||
if (recursive_mutex_enter_count(&cyw43_mutex) != 1) {
|
||||
low_priority_irq_missed = true;
|
||||
CYW43_STAT_INC(PENDSV_DISABLED_COUNT);
|
||||
} else {
|
||||
CYW43_STAT_INC(PENDSV_RUN_COUNT);
|
||||
#ifndef NDEBUG
|
||||
in_low_priority_irq = true;
|
||||
#endif
|
||||
for (size_t i = 0; i < count_of(low_priority_irq_dispatch_slots); i++) {
|
||||
if (low_priority_irq_dispatch_slots[i] != NULL) {
|
||||
low_prio_irq_dispatch_t f = low_priority_irq_dispatch_slots[i];
|
||||
low_priority_irq_dispatch_slots[i] = NULL;
|
||||
f();
|
||||
}
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
in_low_priority_irq = false;
|
||||
#endif
|
||||
}
|
||||
recursive_mutex_exit(&cyw43_mutex);
|
||||
} else {
|
||||
CYW43_STAT_INC(PENDSV_DISABLED_COUNT);
|
||||
low_priority_irq_missed = true;
|
||||
}
|
||||
sem_release(&cyw43_irq_sem);
|
||||
}
|
||||
|
||||
static bool low_prio_irq_init(uint8_t priority) {
|
||||
assert(get_core_num() == cyw43_core_num);
|
||||
int irq = user_irq_claim_unused(false);
|
||||
if (irq < 0) return false;
|
||||
low_priority_irq_num = (uint8_t) irq;
|
||||
irq_set_exclusive_handler(low_priority_irq_num, low_priority_irq_handler);
|
||||
irq_set_enabled(low_priority_irq_num, true);
|
||||
irq_set_priority(low_priority_irq_num, priority);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void low_prio_irq_deinit(void) {
|
||||
if (low_priority_irq_num > 0) {
|
||||
irq_set_enabled(low_priority_irq_num, false);
|
||||
irq_remove_handler(low_priority_irq_num, low_priority_irq_handler);
|
||||
user_irq_unclaim(low_priority_irq_num);
|
||||
low_priority_irq_num = 0;
|
||||
}
|
||||
async_context_t *cyw43_arch_init_default_async_context(void) {
|
||||
async_context_threadsafe_background_config_t config = async_context_threadsafe_background_default_config();
|
||||
if (async_context_threadsafe_background_init(&cyw43_async_context_threadsafe_background, &config))
|
||||
return &cyw43_async_context_threadsafe_background.core;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int cyw43_arch_init(void) {
|
||||
cyw43_core_num = get_core_num();
|
||||
recursive_mutex_init(&cyw43_mutex);
|
||||
cyw43_init(&cyw43_state);
|
||||
sem_init(&cyw43_irq_sem, 0, 1);
|
||||
|
||||
// Start regular lwip callback to handle timeouts
|
||||
periodic_alarm = add_alarm_in_us(CYW43_SLEEP_CHECK_MS * 1000, periodic_alarm_handler, NULL, true);
|
||||
if (periodic_alarm < 0) {
|
||||
return PICO_ERROR_GENERIC;
|
||||
async_context_t *context = cyw43_arch_async_context();
|
||||
if (!context) {
|
||||
context = cyw43_arch_init_default_async_context();
|
||||
if (!context) return PICO_ERROR_GENERIC;
|
||||
cyw43_arch_set_async_context(context);
|
||||
}
|
||||
|
||||
gpio_add_raw_irq_handler_with_order_priority(CYW43_PIN_WL_HOST_WAKE, gpio_irq_handler, CYW43_GPIO_IRQ_HANDLER_PRIORITY);
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
|
||||
irq_set_enabled(IO_IRQ_BANK0, true);
|
||||
|
||||
bool ok = cyw43_driver_init(context);
|
||||
#if CYW43_LWIP
|
||||
lwip_init();
|
||||
ok &= lwip_nosys_init(context);
|
||||
#endif
|
||||
// start low priority handler (no background work is done before this)
|
||||
bool ok = low_prio_irq_init(PICO_LOWEST_IRQ_PRIORITY);
|
||||
if (!ok) {
|
||||
cyw43_arch_deinit();
|
||||
return PICO_ERROR_GENERIC;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return PICO_OK;
|
||||
}
|
||||
|
||||
void cyw43_arch_deinit(void) {
|
||||
if (periodic_alarm >= 0) {
|
||||
cancel_alarm(periodic_alarm);
|
||||
periodic_alarm = -1;
|
||||
}
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
|
||||
gpio_remove_raw_irq_handler(CYW43_PIN_WL_HOST_WAKE, gpio_irq_handler);
|
||||
low_prio_irq_deinit();
|
||||
cyw43_deinit(&cyw43_state);
|
||||
}
|
||||
|
||||
void cyw43_post_poll_hook(void) {
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
|
||||
}
|
||||
|
||||
// This is called in the gpio and low_prio_irq interrupts and on either core
|
||||
static void low_prio_irq_schedule_dispatch(size_t slot, low_prio_irq_dispatch_t f) {
|
||||
assert(slot < count_of(low_priority_irq_dispatch_slots));
|
||||
low_priority_irq_dispatch_slots[slot] = f;
|
||||
if (cyw43_core_num == get_core_num()) {
|
||||
//on same core, can dispatch directly
|
||||
irq_set_pending(low_priority_irq_num);
|
||||
} else {
|
||||
// on wrong core, so force via GPIO IRQ which itself calls this method for the CYW43 slot.
|
||||
// since the CYW43 slot always uses the same function, this is fine with the addition of an
|
||||
// extra (but harmless) CYW43 slot call when another SLOT is invoked.
|
||||
// We could do better, but would have to track why the IRQ was called.
|
||||
io_irq_ctrl_hw_t *irq_ctrl_base = cyw43_core_num ?
|
||||
&iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
|
||||
hw_set_bits(&irq_ctrl_base->intf[CYW43_PIN_WL_HOST_WAKE/8], GPIO_IRQ_LEVEL_HIGH << (4 * (CYW43_PIN_WL_HOST_WAKE & 7)));
|
||||
}
|
||||
}
|
||||
|
||||
void cyw43_schedule_internal_poll_dispatch(void (*func)(void)) {
|
||||
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, func);
|
||||
}
|
||||
|
||||
// Prevent background processing in pensv and access by the other core
|
||||
// These methods are called in pensv context and on either core
|
||||
// They can be called recursively
|
||||
void cyw43_thread_enter(void) {
|
||||
// Lock the other core and stop low_prio_irq running
|
||||
recursive_mutex_enter_blocking(&cyw43_mutex);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void cyw43_thread_lock_check(void) {
|
||||
// Lock the other core and stop low_prio_irq running
|
||||
if (recursive_mutex_enter_count(&cyw43_mutex) < 1 || recursive_mutex_owner(&cyw43_mutex) != lock_get_caller_owner_id()) {
|
||||
panic("cyw43_thread_lock_check failed");
|
||||
}
|
||||
}
|
||||
async_context_t *context = cyw43_arch_async_context();
|
||||
// there is a bit of a circular dependency here between lwIP and cyw43_driver. We
|
||||
// shut down cyw43_driver first as it has IRQs calling back into lwIP. Also lwIP itself
|
||||
// does not actually get shut down.
|
||||
// todo add a "pause" method to async_context if we need to provide some atomicity (we
|
||||
// don't want to take the lock as these methods may invoke execute_sync()
|
||||
cyw43_driver_deinit(context);
|
||||
#if CYW43_LWIP
|
||||
lwip_nosys_deinit(context);
|
||||
#endif
|
||||
|
||||
// Re-enable background processing
|
||||
void cyw43_thread_exit(void) {
|
||||
// Run low_prio_irq if needed
|
||||
if (1 == recursive_mutex_enter_count(&cyw43_mutex)) {
|
||||
// note the outer release of the mutex is not via cyw43_exit in the low_priority_irq case (it is a direct mutex exit)
|
||||
assert(!in_low_priority_irq);
|
||||
// if (low_priority_irq_missed) {
|
||||
// low_priority_irq_missed = false;
|
||||
if (low_priority_irq_dispatch_slots[CYW43_DISPATCH_SLOT_CYW43]) {
|
||||
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
|
||||
}
|
||||
// }
|
||||
}
|
||||
recursive_mutex_exit(&cyw43_mutex);
|
||||
}
|
||||
|
||||
|
||||
static void cyw43_delay_until(absolute_time_t until) {
|
||||
// sleep can be called in IRQs, so there's not much we can do there
|
||||
if (__get_current_exception()) {
|
||||
busy_wait_until(until);
|
||||
} else {
|
||||
sleep_until(until);
|
||||
// if it is our context, then we de-init it.
|
||||
if (context == &cyw43_async_context_threadsafe_background.core) {
|
||||
async_context_deinit(context);
|
||||
cyw43_arch_set_async_context(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void cyw43_delay_ms(uint32_t ms) {
|
||||
cyw43_delay_until(make_timeout_time_ms(ms));
|
||||
}
|
||||
|
||||
void cyw43_delay_us(uint32_t us) {
|
||||
cyw43_delay_until(make_timeout_time_us(us));
|
||||
}
|
||||
|
||||
void cyw43_arch_poll() {
|
||||
// should not be necessary
|
||||
// if (cyw43_poll) {
|
||||
// low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
|
||||
// }
|
||||
}
|
||||
|
||||
#if !CYW43_LWIP
|
||||
static void no_lwip_fail() {
|
||||
panic("You cannot use IP with pico_cyw43_arch_none");
|
||||
}
|
||||
void cyw43_cb_tcpip_init(cyw43_t *self, int itf) {
|
||||
}
|
||||
void cyw43_cb_tcpip_deinit(cyw43_t *self, int itf) {
|
||||
}
|
||||
void cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) {
|
||||
no_lwip_fail();
|
||||
}
|
||||
void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
|
||||
no_lwip_fail();
|
||||
}
|
||||
void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf) {
|
||||
no_lwip_fail();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -104,12 +104,12 @@ extern "C" {
|
||||
#define PARAM_ASSERTIONS_ENABLED_CYW43_ARCH 0
|
||||
#endif
|
||||
|
||||
// PICO_CONFIG: CYW43_ARCH_DEBUG_ENABLED, Enable/disable some debugging output in the pico_cyw43_arch module, type=bool, default=1 in debug builds, group=pico_cyw43_arch
|
||||
#ifndef CYW43_ARCH_DEBUG_ENABLED
|
||||
// PICO_CONFIG: PICO_CYW43_ARCH_DEBUG_ENABLED, Enable/disable some debugging output in the pico_cyw43_arch module, type=bool, default=1 in debug builds, group=pico_cyw43_arch
|
||||
#ifndef PICO_CYW43_ARCH_DEBUG_ENABLED
|
||||
#ifndef NDEBUG
|
||||
#define CYW43_ARCH_DEBUG_ENABLED 1
|
||||
#define PICO_CYW43_ARCH_DEBUG_ENABLED 1
|
||||
#else
|
||||
#define CYW43_ARCH_DEBUG_ENABLED 0
|
||||
#define PICO_CYW43_ARCH_DEBUG_ENABLED 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -129,6 +129,11 @@ extern "C" {
|
||||
* \note this method initializes wireless with a country code of \c PICO_CYW43_ARCH_DEFAULT_COUNTRY_CODE
|
||||
* which defaults to \c CYW43_COUNTRY_WORLDWIDE. Worldwide settings may not give the best performance; consider
|
||||
* setting PICO_CYW43_ARCH_DEFAULT_COUNTRY_CODE to a different value or calling \ref cyw43_arch_init_with_country
|
||||
*
|
||||
* By default this method initializes the cyw43_arch code's own \ref async_context by calling
|
||||
* \ref cyw43_arch_init_default_async_context, however the user can specify use of their own async_context
|
||||
* by calling \ref cyw43_arch_set_async_context() before calling this method
|
||||
*
|
||||
* \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
|
||||
*/
|
||||
int cyw43_arch_init(void);
|
||||
@ -141,31 +146,15 @@ int cyw43_arch_init(void);
|
||||
* was enabled at build time). This method must be called prior to using any other \c pico_cyw43_arch,
|
||||
* \c cyw43_driver or lwIP functions.
|
||||
*
|
||||
* By default this method initializes the cyw43_arch code's own \ref async_context by calling
|
||||
* \ref cyw43_arch_init_default_async_context, however the user can specify use of their own async_context
|
||||
* by calling \ref cyw43_arch_set_async_context() before calling this method
|
||||
*
|
||||
* \param country the country code to use (see \ref CYW43_COUNTRY_)
|
||||
* \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
|
||||
*/
|
||||
int cyw43_arch_init_with_country(uint32_t country);
|
||||
|
||||
/*!
|
||||
* \brief Enables Wi-Fi STA (Station) mode.
|
||||
* \ingroup pico_cyw43_arch
|
||||
*
|
||||
* This enables the Wi-Fi in \em Station mode such that connections can be made to other Wi-Fi Access Points
|
||||
*/
|
||||
void cyw43_arch_enable_sta_mode(void);
|
||||
|
||||
/*!
|
||||
* \brief Enables Wi-Fi AP (Access point) mode.
|
||||
* \ingroup pico_cyw43_arch
|
||||
*
|
||||
* This enables the Wi-Fi in \em Access \em Point mode such that connections can be made to the device by other Wi-Fi clients
|
||||
* \param ssid the name for the access point
|
||||
* \param password the password to use or NULL for no password.
|
||||
* \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
|
||||
* \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
|
||||
*/
|
||||
void cyw43_arch_enable_ap_mode(const char *ssid, const char *password, uint32_t auth);
|
||||
|
||||
/*!
|
||||
* \brief De-initialize the CYW43 architecture
|
||||
* \ingroup pico_cyw43_arch
|
||||
@ -173,80 +162,41 @@ void cyw43_arch_enable_ap_mode(const char *ssid, const char *password, uint32_t
|
||||
* This method de-initializes the `cyw43_driver` code and de-initializes the lwIP stack (if it
|
||||
* was enabled at build time). Note this method should always be called from the same core (or RTOS
|
||||
* task, depending on the environment) as \ref cyw43_arch_init.
|
||||
*
|
||||
* Additionally if the cyw43_arch is using its own async_context instance, then that instance is de-initialized.
|
||||
*/
|
||||
void cyw43_arch_deinit(void);
|
||||
|
||||
/*!
|
||||
* \brief Attempt to connect to a wireless access point, blocking until the network is joined or a failure is detected.
|
||||
* \brief Return the current async_context currently in use by the cyw43_arch code
|
||||
* \ingroup pico_cyw43_arch
|
||||
*
|
||||
* \param ssid the network name to connect to
|
||||
* \param pw the network password or NULL if there is no password required
|
||||
* \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
|
||||
* \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
|
||||
*
|
||||
* \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
|
||||
* \return the async_context.
|
||||
*/
|
||||
int cyw43_arch_wifi_connect_blocking(const char *ssid, const char *pw, uint32_t auth);
|
||||
async_context_t *cyw43_arch_async_context(void);
|
||||
|
||||
/*!
|
||||
* \brief Attempt to connect to a wireless access point, blocking until the network is joined, a failure is detected or a timeout occurs
|
||||
* \brief Set the async_context to be used by the cyw43_arch_init
|
||||
* \ingroup pico_cyw43_arch
|
||||
*
|
||||
* \param ssid the network name to connect to
|
||||
* \param pw the network password or NULL if there is no password required
|
||||
* \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
|
||||
* \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
|
||||
* \note This method must be called before calling cyw43_arch_init or cyw43_arch_init_with_country
|
||||
* if you wish to use a custom async_context instance.
|
||||
*
|
||||
* \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
|
||||
* \param context the async_context to be used
|
||||
*/
|
||||
int cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout_ms);
|
||||
void cyw43_arch_set_async_context(async_context_t *context);
|
||||
|
||||
/*!
|
||||
* \brief Start attempting to connect to a wireless access point
|
||||
* \brief Initialize the default \ref async_context for the current cyw43_arch type
|
||||
* \ingroup pico_cyw43_arch
|
||||
*
|
||||
* This method tells the CYW43 driver to start connecting to an access point. You should subsequently check the
|
||||
* status by calling \ref cyw43_wifi_link_status.
|
||||
* This method initializes and returns a pointer to the static async_context associated
|
||||
* with cyw43_arch. This method is called by \ref cyw43_arch_init automatically
|
||||
* if a different async_context has not been set by \ref cyw43_arch_set_async_context
|
||||
*
|
||||
* \param ssid the network name to connect to
|
||||
* \param pw the network password or NULL if there is no password required
|
||||
* \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
|
||||
* \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
|
||||
*
|
||||
* \return 0 if the scan was started successfully, an error code otherwise \see pico_error_codes
|
||||
* \return the context or NULL if initialization failed.
|
||||
*/
|
||||
int cyw43_arch_wifi_connect_async(const char *ssid, const char *pw, uint32_t auth);
|
||||
|
||||
/*!
|
||||
* \brief Return the country code used to initialize cyw43_arch
|
||||
* \ingroup pico_cyw43_arch
|
||||
*
|
||||
* \return the country code (see \ref CYW43_COUNTRY_)
|
||||
*/
|
||||
uint32_t cyw43_arch_get_country_code(void);
|
||||
|
||||
/*!
|
||||
* \brief Set a GPIO pin on the wireless chip to a given value
|
||||
* \ingroup pico_cyw43_arch
|
||||
* \note this method does not check for errors setting the GPIO. You can use the lower level \ref cyw43_gpio_set instead if you wish
|
||||
* to check for errors.
|
||||
*
|
||||
* \param wl_gpio the GPIO number on the wireless chip
|
||||
* \param value true to set the GPIO, false to clear it.
|
||||
*/
|
||||
void cyw43_arch_gpio_put(uint wl_gpio, bool value);
|
||||
|
||||
/*!
|
||||
* \brief Read the value of a GPIO pin on the wireless chip
|
||||
* \ingroup pico_cyw43_arch
|
||||
* \note this method does not check for errors setting the GPIO. You can use the lower level \ref cyw43_gpio_get instead if you wish
|
||||
* to check for errors.
|
||||
*
|
||||
* \param wl_gpio the GPIO number on the wireless chip
|
||||
* \return true if the GPIO is high, false otherwise
|
||||
*/
|
||||
bool cyw43_arch_gpio_get(uint wl_gpio);
|
||||
async_context_t *cyw43_arch_init_default_async_context(void);
|
||||
|
||||
/*!
|
||||
* \brief Perform any processing required by the \c cyw43_driver or the TCP/IP stack
|
||||
@ -258,6 +208,18 @@ bool cyw43_arch_gpio_get(uint wl_gpio);
|
||||
*/
|
||||
void cyw43_arch_poll(void);
|
||||
|
||||
/*!
|
||||
* \brief Sleep until there is cyw43_driver work to be done
|
||||
* \ingroup pico_cyw43_arch
|
||||
*
|
||||
* This method may be called by code that is waiting for an event to
|
||||
* come from the cyw43_driver, and has no work to do, but would like
|
||||
* to sleep without blocking any background work associated with the cyw43_driver.
|
||||
*
|
||||
* \param until the time to wait until if there is no work to do.
|
||||
*/
|
||||
void cyw43_arch_wait_for_work_until(absolute_time_t until);
|
||||
|
||||
/*!
|
||||
* \fn cyw43_arch_lwip_begin
|
||||
* \brief Acquire any locks required to call into lwIP
|
||||
@ -321,6 +283,98 @@ void cyw43_arch_poll(void);
|
||||
* \sa cyw43_arch_lwip_protect
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Return the country code used to initialize cyw43_arch
|
||||
* \ingroup pico_cyw43_arch
|
||||
*
|
||||
* \return the country code (see \ref CYW43_COUNTRY_)
|
||||
*/
|
||||
uint32_t cyw43_arch_get_country_code(void);
|
||||
|
||||
/*!
|
||||
* \brief Enables Wi-Fi STA (Station) mode.
|
||||
* \ingroup pico_cyw43_arch
|
||||
*
|
||||
* This enables the Wi-Fi in \emStation mode such that connections can be made to other Wi-Fi Access Points
|
||||
*/
|
||||
void cyw43_arch_enable_sta_mode(void);
|
||||
|
||||
/*!
|
||||
* \brief Enables Wi-Fi AP (Access point) mode.
|
||||
* \ingroup pico_cyw43_arch
|
||||
*
|
||||
* This enables the Wi-Fi in \em Access \em Point mode such that connections can be made to the device by other Wi-Fi clients
|
||||
* \param ssid the name for the access point
|
||||
* \param password the password to use or NULL for no password.
|
||||
* \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
|
||||
* \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
|
||||
*/
|
||||
void cyw43_arch_enable_ap_mode(const char *ssid, const char *password, uint32_t auth);
|
||||
|
||||
/*!
|
||||
* \brief Attempt to connect to a wireless access point, blocking until the network is joined or a failure is detected.
|
||||
* \ingroup pico_cyw43_arch
|
||||
*
|
||||
* \param ssid the network name to connect to
|
||||
* \param pw the network password or NULL if there is no password required
|
||||
* \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
|
||||
* \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
|
||||
*
|
||||
* \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
|
||||
*/
|
||||
int cyw43_arch_wifi_connect_blocking(const char *ssid, const char *pw, uint32_t auth);
|
||||
|
||||
/*!
|
||||
* \brief Attempt to connect to a wireless access point, blocking until the network is joined, a failure is detected or a timeout occurs
|
||||
* \ingroup pico_cyw43_arch
|
||||
*
|
||||
* \param ssid the network name to connect to
|
||||
* \param pw the network password or NULL if there is no password required
|
||||
* \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
|
||||
* \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
|
||||
*
|
||||
* \return 0 if the initialization is successful, an error code otherwise \see pico_error_codes
|
||||
*/
|
||||
int cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout);
|
||||
|
||||
/*!
|
||||
* \brief Start attempting to connect to a wireless access point
|
||||
* \ingroup pico_cyw43_arch
|
||||
*
|
||||
* This method tells the CYW43 driver to start connecting to an access point. You should subsequently check the
|
||||
* status by calling \ref cyw43_wifi_link_status.
|
||||
*
|
||||
* \param ssid the network name to connect to
|
||||
* \param pw the network password or NULL if there is no password required
|
||||
* \param auth the authorization type to use when the password is enabled. Values are \ref CYW43_AUTH_WPA_TKIP_PSK,
|
||||
* \ref CYW43_AUTH_WPA2_AES_PSK, or \ref CYW43_AUTH_WPA2_MIXED_PSK (see \ref CYW43_AUTH_)
|
||||
*
|
||||
* \return 0 if the scan was started successfully, an error code otherwise \see pico_error_codes
|
||||
*/
|
||||
int cyw43_arch_wifi_connect_async(const char *ssid, const char *pw, uint32_t auth);
|
||||
|
||||
/*!
|
||||
* \brief Set a GPIO pin on the wireless chip to a given value
|
||||
* \ingroup pico_cyw43_arch
|
||||
* \note this method does not check for errors setting the GPIO. You can use the lower level \ref cyw43_gpio_set instead if you wish
|
||||
* to check for errors.
|
||||
*
|
||||
* \param wl_gpio the GPIO number on the wireless chip
|
||||
* \param value true to set the GPIO, false to clear it.
|
||||
*/
|
||||
void cyw43_arch_gpio_put(uint wl_gpio, bool value);
|
||||
|
||||
/*!
|
||||
* \brief Read the value of a GPIO pin on the wireless chip
|
||||
* \ingroup pico_cyw43_arch
|
||||
* \note this method does not check for errors setting the GPIO. You can use the lower level \ref cyw43_gpio_get instead if you wish
|
||||
* to check for errors.
|
||||
*
|
||||
* \param wl_gpio the GPIO number on the wireless chip
|
||||
* \return true if the GPIO is high, false otherwise
|
||||
*/
|
||||
bool cyw43_arch_gpio_get(uint wl_gpio);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "pico/time.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "pico/error.h"
|
||||
#include "pico/async_context.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -66,6 +67,62 @@ void cyw43_hal_get_mac(int idx, uint8_t buf[6]);
|
||||
|
||||
void cyw43_hal_generate_laa_mac(int idx, uint8_t buf[6]);
|
||||
|
||||
|
||||
void cyw43_thread_enter(void);
|
||||
void cyw43_thread_exit(void);
|
||||
|
||||
#define CYW43_THREAD_ENTER cyw43_thread_enter();
|
||||
#define CYW43_THREAD_EXIT cyw43_thread_exit();
|
||||
#ifndef NDEBUG
|
||||
void cyw43_thread_lock_check(void);
|
||||
#define cyw43_arch_lwip_check() cyw43_thread_lock_check()
|
||||
#define CYW43_THREAD_LOCK_CHECK cyw43_arch_lwip_check();
|
||||
#else
|
||||
#define cyw43_arch_lwip_check() ((void)0)
|
||||
#define CYW43_THREAD_LOCK_CHECK
|
||||
#endif
|
||||
|
||||
void cyw43_await_background_or_timeout_us(uint32_t timeout_us);
|
||||
// todo not 100% sure about the timeouts here; MP uses __WFI which will always wakeup periodically
|
||||
#define CYW43_SDPCM_SEND_COMMON_WAIT cyw43_await_background_or_timeout_us(1000);
|
||||
#define CYW43_DO_IOCTL_WAIT cyw43_await_background_or_timeout_us(1000);
|
||||
|
||||
void cyw43_delay_ms(uint32_t ms);
|
||||
void cyw43_delay_us(uint32_t us);
|
||||
|
||||
void cyw43_schedule_internal_poll_dispatch(void (*func)(void));
|
||||
|
||||
void cyw43_post_poll_hook(void);
|
||||
#define CYW43_POST_POLL_HOOK cyw43_post_poll_hook();
|
||||
|
||||
static inline void cyw43_arch_lwip_begin(void) {
|
||||
cyw43_thread_enter();
|
||||
}
|
||||
|
||||
static inline void cyw43_arch_lwip_end(void) {
|
||||
cyw43_thread_exit();
|
||||
}
|
||||
|
||||
static inline int cyw43_arch_lwip_protect(int (*func)(void *param), void *param) {
|
||||
cyw43_arch_lwip_begin();
|
||||
int rc = func(param);
|
||||
cyw43_arch_lwip_end();
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if CYW43_USE_BTSTACK
|
||||
static inline int cyw43_bt_init(void) { return 0; }
|
||||
static inline void cyw43_bt_deinit(void) {}
|
||||
|
||||
static inline void cyw43_arch_btstack_begin(void) {
|
||||
cyw43_thread_enter();
|
||||
}
|
||||
|
||||
static inline void cyw43_arch_btstack_end(void) {
|
||||
cyw43_thread_exit();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -13,49 +13,18 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void cyw43_thread_enter(void);
|
||||
void cyw43_thread_exit(void);
|
||||
|
||||
#define CYW43_THREAD_ENTER cyw43_thread_enter();
|
||||
#define CYW43_THREAD_EXIT cyw43_thread_exit();
|
||||
#ifndef NDEBUG
|
||||
void cyw43_thread_lock_check(void);
|
||||
#define cyw43_arch_lwip_check() cyw43_thread_lock_check()
|
||||
#define CYW43_THREAD_LOCK_CHECK cyw43_arch_lwip_check();
|
||||
#else
|
||||
#define cyw43_arch_lwip_check() ((void)0)
|
||||
#define CYW43_THREAD_LOCK_CHECK
|
||||
// PICO_CONFIG: CYW43_TASK_STACK_SIZE, Stack size for the CYW43 FreeRTOS task in 4-byte words, type=int, default=1024, group=pico_cyw43_arch
|
||||
#ifndef CYW43_TASK_STACK_SIZE
|
||||
#define CYW43_TASK_STACK_SIZE 1024
|
||||
#endif
|
||||
|
||||
void cyw43_await_background_or_timeout_us(uint32_t timeout_us);
|
||||
// todo not 100% sure about the timeouts here; MP uses __WFI which will always wakeup periodically
|
||||
#define CYW43_SDPCM_SEND_COMMON_WAIT cyw43_await_background_or_timeout_us(1000);
|
||||
#define CYW43_DO_IOCTL_WAIT cyw43_await_background_or_timeout_us(1000);
|
||||
|
||||
void cyw43_delay_ms(uint32_t ms);
|
||||
void cyw43_delay_us(uint32_t us);
|
||||
|
||||
void cyw43_schedule_internal_poll_dispatch(void (*func)(void));
|
||||
|
||||
void cyw43_post_poll_hook(void);
|
||||
#define CYW43_POST_POLL_HOOK cyw43_post_poll_hook();
|
||||
|
||||
static inline void cyw43_arch_lwip_begin(void) {
|
||||
cyw43_thread_enter();
|
||||
}
|
||||
static inline void cyw43_arch_lwip_end(void) {
|
||||
cyw43_thread_exit();
|
||||
}
|
||||
|
||||
static inline int cyw43_arch_lwip_protect(int (*func)(void *param), void *param) {
|
||||
cyw43_arch_lwip_begin();
|
||||
int rc = func(param);
|
||||
cyw43_arch_lwip_end();
|
||||
return rc;
|
||||
}
|
||||
// PICO_CONFIG: CYW43_TASK_PRIORITY, Priority for the CYW43 FreeRTOS task, type=int default=4, group=pico_cyw43_arch
|
||||
#ifndef CYW43_TASK_PRIORITY
|
||||
#define CYW43_TASK_PRIORITY (tskIDLE_PRIORITY + 4)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -15,42 +15,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CYW43_THREAD_ENTER
|
||||
#define CYW43_THREAD_EXIT
|
||||
#ifndef NDEBUG
|
||||
|
||||
void cyw43_thread_check(void);
|
||||
|
||||
#define cyw43_arch_lwip_check() cyw43_thread_check()
|
||||
#define CYW43_THREAD_LOCK_CHECK cyw43_arch_lwip_check();
|
||||
#else
|
||||
#define cyw43_arch_lwip_check() ((void)0)
|
||||
#define CYW43_THREAD_LOCK_CHECK
|
||||
#endif
|
||||
|
||||
#define CYW43_SDPCM_SEND_COMMON_WAIT cyw43_poll_required = true;
|
||||
#define CYW43_DO_IOCTL_WAIT cyw43_poll_required = true;
|
||||
|
||||
#define cyw43_delay_ms sleep_ms
|
||||
#define cyw43_delay_us sleep_us
|
||||
|
||||
void cyw43_schedule_internal_poll_dispatch(void (*func)(void));
|
||||
|
||||
void cyw43_post_poll_hook(void);
|
||||
|
||||
extern bool cyw43_poll_required;
|
||||
|
||||
#define CYW43_POST_POLL_HOOK cyw43_post_poll_hook();
|
||||
#endif
|
||||
|
||||
#ifndef DOXYGEN_GENERATION // multiple definitions in separate headers seems to confused doxygen
|
||||
#define cyw43_arch_lwip_begin() ((void)0)
|
||||
#define cyw43_arch_lwip_end() ((void)0)
|
||||
|
||||
static inline int cyw43_arch_lwip_protect(int (*func)(void *param), void *param) {
|
||||
return func(param);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -13,53 +13,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void cyw43_thread_enter(void);
|
||||
|
||||
void cyw43_thread_exit(void);
|
||||
|
||||
#define CYW43_THREAD_ENTER cyw43_thread_enter();
|
||||
#define CYW43_THREAD_EXIT cyw43_thread_exit();
|
||||
#ifndef NDEBUG
|
||||
|
||||
void cyw43_thread_lock_check(void);
|
||||
|
||||
#define cyw43_arch_lwip_check() cyw43_thread_lock_check()
|
||||
#define CYW43_THREAD_LOCK_CHECK cyw43_arch_lwip_check();
|
||||
#else
|
||||
#define cyw43_arch_lwip_check() ((void)0)
|
||||
#define CYW43_THREAD_LOCK_CHECK
|
||||
#endif
|
||||
|
||||
void cyw43_await_background_or_timeout_us(uint32_t timeout_us);
|
||||
// todo not 100% sure about the timeouts here; MP uses __WFI which will always wakeup periodically
|
||||
#define CYW43_SDPCM_SEND_COMMON_WAIT cyw43_await_background_or_timeout_us(1000);
|
||||
#define CYW43_DO_IOCTL_WAIT cyw43_await_background_or_timeout_us(1000);
|
||||
|
||||
void cyw43_delay_ms(uint32_t ms);
|
||||
|
||||
void cyw43_delay_us(uint32_t us);
|
||||
|
||||
void cyw43_schedule_internal_poll_dispatch(void (*func)(void));
|
||||
|
||||
void cyw43_post_poll_hook(void);
|
||||
|
||||
#define CYW43_POST_POLL_HOOK cyw43_post_poll_hook();
|
||||
|
||||
static inline void cyw43_arch_lwip_begin(void) {
|
||||
cyw43_thread_enter();
|
||||
}
|
||||
|
||||
static inline void cyw43_arch_lwip_end(void) {
|
||||
cyw43_thread_exit();
|
||||
}
|
||||
|
||||
static inline int cyw43_arch_lwip_protect(int (*func)(void *param), void *param) {
|
||||
cyw43_arch_lwip_begin();
|
||||
int rc = func(param);
|
||||
cyw43_arch_lwip_end();
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user