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:
@ -6,10 +6,10 @@ endif ()
|
||||
set(LWIP_TEST_PATH "src/Filelists.cmake")
|
||||
if (NOT PICO_LWIP_PATH)
|
||||
set(PICO_LWIP_PATH ${PROJECT_SOURCE_DIR}/lib/lwip)
|
||||
# if (NOT EXISTS ${PICO_LWIP_PATH}/${LWIP_TEST_PATH})
|
||||
# message(WARNING "LWIP submodule has not been initialized; Pico W wireless support will be unavailable
|
||||
if (PICO_CYW43_SUPPORTED AND NOT EXISTS ${PICO_LWIP_PATH}/${LWIP_TEST_PATH})
|
||||
message(WARNING "LWIP submodule has not been initialized; Pico W wireless support will be unavailable
|
||||
#hint: try 'git submodule update --init' from your SDK directory (${PICO_SDK_PATH}).")
|
||||
# endif()
|
||||
endif()
|
||||
elseif (NOT EXISTS ${PICO_LWIP_PATH}/${LWIP_TEST_PATH})
|
||||
message(WARNING "PICO_LWIP_PATH specified but content not present.")
|
||||
endif()
|
||||
@ -46,7 +46,7 @@ if (EXISTS ${PICO_LWIP_PATH}/${LWIP_TEST_PATH})
|
||||
${PICO_LWIP_PATH}/src/core/tcp_out.c
|
||||
${PICO_LWIP_PATH}/src/core/timeouts.c
|
||||
${PICO_LWIP_PATH}/src/core/udp.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/random.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/lwip_random.c
|
||||
)
|
||||
target_include_directories(pico_lwip_core INTERFACE
|
||||
${PICO_LWIP_PATH}/src/include)
|
||||
@ -269,11 +269,12 @@ if (EXISTS ${PICO_LWIP_PATH}/${LWIP_TEST_PATH})
|
||||
# our nosys impl
|
||||
add_library(pico_lwip_nosys INTERFACE)
|
||||
target_sources(pico_lwip_nosys INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/nosys.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/lwip_nosys.c
|
||||
)
|
||||
target_link_libraries(pico_lwip_nosys INTERFACE
|
||||
pico_lwip_arch)
|
||||
|
||||
pico_async_context_base
|
||||
pico_lwip_arch
|
||||
pico_lwip)
|
||||
|
||||
if (NOT PICO_LWIP_CONTRIB_PATH)
|
||||
set(PICO_LWIP_CONTRIB_PATH ${PICO_LWIP_PATH}/contrib)
|
||||
@ -291,5 +292,14 @@ if (EXISTS ${PICO_LWIP_PATH}/${LWIP_TEST_PATH})
|
||||
target_link_libraries(pico_lwip_contrib_freertos INTERFACE
|
||||
pico_lwip_arch)
|
||||
|
||||
add_library(pico_lwip_freertos INTERFACE)
|
||||
target_sources(pico_lwip_freertos INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/lwip_freertos.c
|
||||
)
|
||||
target_link_libraries(pico_lwip_freertos INTERFACE
|
||||
pico_async_context_base
|
||||
pico_lwip
|
||||
pico_lwip_contrib_freertos)
|
||||
|
||||
pico_promote_common_scope_vars()
|
||||
endif()
|
||||
|
@ -34,9 +34,18 @@
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifndef PICO_LWIP_CUSTOM_LOCK_TCPIP_CORE
|
||||
#define PICO_LWIP_CUSTOM_LOCK_TCPIP_CORE 1
|
||||
#endif
|
||||
|
||||
#if NO_SYS
|
||||
// todo really we should just not allow SYS_LIGHTWEIGHT_PROT for nosys mode (it doesn't do anything anyway)
|
||||
typedef int sys_prot_t;
|
||||
#elif PICO_LWIP_CUSTOM_LOCK_TCPIP_CORE
|
||||
void pico_lwip_custom_lock_tcpip_core(void);
|
||||
void pico_lwip_custom_unlock_tcpip_core(void);
|
||||
#define LOCK_TCPIP_CORE() pico_lwip_custom_lock_tcpip_core()
|
||||
#define UNLOCK_TCPIP_CORE() pico_lwip_custom_unlock_tcpip_core()
|
||||
#endif
|
||||
|
||||
/* define compiler specific symbols */
|
||||
@ -76,8 +85,14 @@ typedef int sys_prot_t;
|
||||
#define LWIP_PLATFORM_ASSERT(x) panic(x)
|
||||
#endif
|
||||
|
||||
unsigned int pico_lwip_rand(void);
|
||||
#ifndef LWIP_RAND
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
unsigned int pico_lwip_rand(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
// Use ROSC based random number generation, more for the fact that rand() may not be seeded, than anything else
|
||||
#define LWIP_RAND pico_lwip_rand
|
||||
#endif
|
||||
|
44
src/rp2_common/pico_lwip/include/pico/lwip_freertos.h
Normal file
44
src/rp2_common/pico_lwip/include/pico/lwip_freertos.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _PICO_LWIP_FREERTOS_H
|
||||
#define _PICO_LWIP_FREERTOS_H
|
||||
|
||||
#include "pico.h"
|
||||
#include "pico/async_context.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \brief Initializes lwIP (NO_SYS=0 mode) support support for FreeRTOS using the provided async_context
|
||||
* \ingroup pico_lwip
|
||||
*
|
||||
* If the initialization succeeds, \ref lwip_freertos_deinit() can be called to shutdown lwIP support
|
||||
*
|
||||
* \param context the async_context instance that provides the abstraction for handling asynchronous work. Note in general
|
||||
* this would be an \ref async_context_freertos instance, though it doesn't have to be.
|
||||
*
|
||||
* \return true if the initialization succeeded
|
||||
*/
|
||||
bool lwip_freertos_init(async_context_t *context);
|
||||
|
||||
/*! \brief De-initialize lwIP (NO_SYS=0 mode) support for FreeRTOS
|
||||
* \ingroup pico_lwip
|
||||
*
|
||||
* Note that since lwIP may only be initialized once, and doesn't itself provide a shutdown mechanism, lwIP
|
||||
* itself may still consume resources.
|
||||
*
|
||||
* It is however safe to call \ref lwip_freertos_init again later.
|
||||
*
|
||||
* \param context the async_context the lwip_freertos support was added to via \ref lwip_freertos_init
|
||||
*/
|
||||
void lwip_freertos_deinit(async_context_t *context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
42
src/rp2_common/pico_lwip/include/pico/lwip_nosys.h
Normal file
42
src/rp2_common/pico_lwip/include/pico/lwip_nosys.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _PICO_LWIP_NOSYS_H
|
||||
#define _PICO_LWIP_NOSYS_H
|
||||
|
||||
#include "pico.h"
|
||||
#include "pico/async_context.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \brief Initializes lwIP (NO_SYS=1 mode) support support using the provided async_context
|
||||
* \ingroup pico_lwip
|
||||
*
|
||||
* If the initialization succeeds, \ref lwip_nosys_deinit() can be called to shutdown lwIP support
|
||||
*
|
||||
* \param context the async_context instance that provides the abstraction for handling asynchronous work.
|
||||
* \return true if the initialization succeeded
|
||||
*/
|
||||
bool lwip_nosys_init(async_context_t *context);
|
||||
|
||||
/*! \brief De-initialize lwIP (NO_SYS=1 mode) support
|
||||
* \ingroup pico_lwip
|
||||
*
|
||||
* Note that since lwIP may only be initialized once, and doesn't itself provide a shutdown mechanism, lwIP
|
||||
* itself may still consume resources
|
||||
*
|
||||
* It is however safe to call \ref lwip_nosys_init again later.
|
||||
*
|
||||
* \param context the async_context the lwip_nosys support was added to via \ref lwip_nosys_init
|
||||
*/
|
||||
void lwip_nosys_deinit(async_context_t *context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
65
src/rp2_common/pico_lwip/lwip_freertos.c
Normal file
65
src/rp2_common/pico_lwip/lwip_freertos.c
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
// todo graham #ifdef for LWIP inclusion?
|
||||
|
||||
#include "pico/async_context.h"
|
||||
#include "pico/time.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "lwip/timeouts.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "semphr.h"
|
||||
|
||||
#if NO_SYS
|
||||
#error lwip_freertos_async_context_bindings requires NO_SYS=0
|
||||
#endif
|
||||
|
||||
static async_context_t * volatile lwip_context;
|
||||
// lwIP tcpip_task cannot be shutdown, so we block it when we are de-initialized.
|
||||
static SemaphoreHandle_t tcpip_task_blocker;
|
||||
|
||||
static void tcpip_init_done(void *param) {
|
||||
xSemaphoreGive((SemaphoreHandle_t)param);
|
||||
}
|
||||
|
||||
bool lwip_freertos_init(async_context_t *context) {
|
||||
assert(!lwip_context);
|
||||
lwip_context = context;
|
||||
static bool done_lwip_init;
|
||||
if (!done_lwip_init) {
|
||||
done_lwip_init = true;
|
||||
SemaphoreHandle_t init_sem = xSemaphoreCreateBinary();
|
||||
tcpip_task_blocker = xSemaphoreCreateBinary();
|
||||
tcpip_init(tcpip_init_done, init_sem);
|
||||
xSemaphoreTake(init_sem, portMAX_DELAY);
|
||||
vSemaphoreDelete(init_sem);
|
||||
} else {
|
||||
xSemaphoreGive(tcpip_task_blocker);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t clear_lwip_context(__unused void *param) {
|
||||
lwip_context = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lwip_freertos_deinit(__unused async_context_t *context) {
|
||||
// clear the lwip context under lock as lwIP may still be running in tcpip_task
|
||||
async_context_execute_sync(context, clear_lwip_context, NULL);
|
||||
}
|
||||
|
||||
void pico_lwip_custom_lock_tcpip_core(void) {
|
||||
while (!lwip_context) {
|
||||
xSemaphoreTake(tcpip_task_blocker, portMAX_DELAY);
|
||||
}
|
||||
async_context_acquire_lock_blocking(lwip_context);
|
||||
}
|
||||
|
||||
void pico_lwip_custom_unlock_tcpip_core(void) {
|
||||
async_context_release_lock(lwip_context);
|
||||
}
|
74
src/rp2_common/pico_lwip/lwip_nosys.c
Normal file
74
src/rp2_common/pico_lwip/lwip_nosys.c
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico/async_context.h"
|
||||
|
||||
#include <lwip/init.h>
|
||||
#include "lwip/timeouts.h"
|
||||
|
||||
static void update_next_timeout(async_context_t *context, async_when_pending_worker_t *worker);
|
||||
static void lwip_timeout_reached(async_context_t *context, async_at_time_worker_t *worker);
|
||||
|
||||
static async_when_pending_worker_t always_pending_update_timeout_worker = {
|
||||
.do_work = update_next_timeout
|
||||
};
|
||||
|
||||
static async_at_time_worker_t lwip_timeout_worker = {
|
||||
.do_work = lwip_timeout_reached,
|
||||
};
|
||||
|
||||
static void lwip_timeout_reached(__unused async_context_t *context, __unused async_at_time_worker_t *worker) {
|
||||
assert(worker == &lwip_timeout_worker);
|
||||
sys_check_timeouts();
|
||||
}
|
||||
|
||||
static void update_next_timeout(async_context_t *context, async_when_pending_worker_t *worker) {
|
||||
assert(worker == &always_pending_update_timeout_worker);
|
||||
// we want to run on every execution of the helper to re-reflect any changes
|
||||
// to the underlying lwIP timers which may have happened in the interim
|
||||
// (note that worker will be called on every outermost exit of the async_context
|
||||
// lock, and lwIP timers should not be modified whilst not holding the lock.
|
||||
worker->work_pending = true;
|
||||
uint32_t sleep_ms = sys_timeouts_sleeptime();
|
||||
if (sleep_ms == SYS_TIMEOUTS_SLEEPTIME_INFINITE) {
|
||||
lwip_timeout_worker.next_time = at_the_end_of_time;
|
||||
} else {
|
||||
lwip_timeout_worker.next_time = make_timeout_time_ms(sleep_ms);
|
||||
}
|
||||
async_context_add_at_time_worker(context, &lwip_timeout_worker);
|
||||
}
|
||||
|
||||
bool lwip_nosys_init(async_context_t *context) {
|
||||
static bool done_lwip_init;
|
||||
if (!done_lwip_init) {
|
||||
lwip_init();
|
||||
done_lwip_init = true;
|
||||
}
|
||||
// we want the worker to be called on every async helper run (starting with the next)
|
||||
always_pending_update_timeout_worker.work_pending = true;
|
||||
async_context_add_when_pending_worker(context, &always_pending_update_timeout_worker);
|
||||
return true;
|
||||
}
|
||||
|
||||
void lwip_nosys_deinit(async_context_t *context) {
|
||||
async_context_remove_at_time_worker(context, &lwip_timeout_worker);
|
||||
async_context_remove_when_pending_worker(context, &always_pending_update_timeout_worker);
|
||||
}
|
||||
|
||||
#if NO_SYS
|
||||
/* lwip has provision for using a mutex, when applicable */
|
||||
sys_prot_t sys_arch_protect(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_arch_unprotect(__unused sys_prot_t pval) {
|
||||
}
|
||||
|
||||
/* lwip needs a millisecond time source, and the TinyUSB board support code has one available */
|
||||
uint32_t sys_now(void) {
|
||||
return to_ms_since_boot(get_absolute_time());
|
||||
}
|
||||
#endif
|
@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "lwip/init.h"
|
||||
#include "pico/time.h"
|
||||
|
||||
#if NO_SYS
|
||||
/* lwip has provision for using a mutex, when applicable */
|
||||
sys_prot_t sys_arch_protect(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_arch_unprotect(sys_prot_t pval) {
|
||||
(void) pval;
|
||||
}
|
||||
|
||||
/* lwip needs a millisecond time source, and the TinyUSB board support code has one available */
|
||||
uint32_t sys_now(void) {
|
||||
return to_ms_since_boot(get_absolute_time());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user