From 3109f1d91c8832d58d389e1b325b6a9a816ecab4 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Fri, 8 Aug 2025 09:51:04 -0700 Subject: [PATCH 01/36] WIP - Make FreeRTOS a first-class citizen With the expanded performance and memory of the Pico 2, having a full operating system with threads could really improve developer life and get the best possible algorithm performance. Start by moving FreeRTOS checks from a global bool set by weak function linkage checks to a compiler definition. This can allow the build process to differ between bare metal and FreeRTOS builds (i.e. async_context implementations) and save a few bytes of program space. --- boards.txt | 529 ++++++++++++++++++ cores/rp2040/Arduino.h | 3 - cores/rp2040/Bootsel.cpp | 12 +- cores/rp2040/CoreMutex.cpp | 52 +- cores/rp2040/CoreMutex.h | 2 + cores/rp2040/RP2040Support.h | 135 ++--- cores/rp2040/SerialUSB.cpp | 6 +- cores/rp2040/_freertos.cpp | 4 + cores/rp2040/_freertos.h | 6 +- cores/rp2040/lock.cpp | 35 ++ cores/rp2040/main.cpp | 85 ++- .../rp2040/sdkoverride/btstack_flash_bank.cpp | 24 +- cores/rp2040/wiring_private.cpp | 32 +- docs/platformio.rst | 13 + libraries/EEPROM/src/EEPROM.cpp | 12 +- libraries/FatFS/lib/SPIFTL | 2 +- libraries/FreeRTOS/src/FreeRTOS.h | 4 + libraries/LittleFS/src/LittleFS.cpp | 24 +- libraries/Updater/src/Updater.cpp | 12 +- platform.txt | 3 +- tools/build.py | 2 + tools/makeboards.py | 8 + 22 files changed, 793 insertions(+), 212 deletions(-) diff --git a/boards.txt b/boards.txt index f36ad85f4..4ed052213 100644 --- a/boards.txt +++ b/boards.txt @@ -11,6 +11,7 @@ menu.psramfreq=PSRAM Speed menu.freq=CPU Speed menu.arch=CPU Architecture menu.opt=Optimize +menu.os=Operating System menu.profile=Profiling menu.rtti=RTTI menu.stackprotect=Stack Protector @@ -167,6 +168,10 @@ rpipico.menu.opt.Debug=Debug (-Og) rpipico.menu.opt.Debug.build.flags.optimize=-Og rpipico.menu.opt.Disabled=Disabled (-O0) rpipico.menu.opt.Disabled.build.flags.optimize=-O0 +rpipico.menu.os.none=None +rpipico.menu.os.none.build.os= +rpipico.menu.os.freertos=FreeRTOS SMP +rpipico.menu.os.freertos.build.os=-D__FREERTOS rpipico.menu.profile.Disabled=Disabled rpipico.menu.profile.Disabled.build.flags.profile= rpipico.menu.profile.Enabled=Enabled @@ -382,6 +387,10 @@ rpipicow.menu.opt.Debug=Debug (-Og) rpipicow.menu.opt.Debug.build.flags.optimize=-Og rpipicow.menu.opt.Disabled=Disabled (-O0) rpipicow.menu.opt.Disabled.build.flags.optimize=-O0 +rpipicow.menu.os.none=None +rpipicow.menu.os.none.build.os= +rpipicow.menu.os.freertos=FreeRTOS SMP +rpipicow.menu.os.freertos.build.os=-D__FREERTOS rpipicow.menu.profile.Disabled=Disabled rpipicow.menu.profile.Disabled.build.flags.profile= rpipicow.menu.profile.Enabled=Enabled @@ -747,6 +756,10 @@ rpipico2.menu.opt.Debug=Debug (-Og) rpipico2.menu.opt.Debug.build.flags.optimize=-Og rpipico2.menu.opt.Disabled=Disabled (-O0) rpipico2.menu.opt.Disabled.build.flags.optimize=-O0 +rpipico2.menu.os.none=None +rpipico2.menu.os.none.build.os= +rpipico2.menu.os.freertos=FreeRTOS SMP +rpipico2.menu.os.freertos.build.os=-D__FREERTOS rpipico2.menu.profile.Disabled=Disabled rpipico2.menu.profile.Disabled.build.flags.profile= rpipico2.menu.profile.Enabled=Enabled @@ -985,6 +998,10 @@ rpipico2w.menu.opt.Debug=Debug (-Og) rpipico2w.menu.opt.Debug.build.flags.optimize=-Og rpipico2w.menu.opt.Disabled=Disabled (-O0) rpipico2w.menu.opt.Disabled.build.flags.optimize=-O0 +rpipico2w.menu.os.none=None +rpipico2w.menu.os.none.build.os= +rpipico2w.menu.os.freertos=FreeRTOS SMP +rpipico2w.menu.os.freertos.build.os=-D__FREERTOS rpipico2w.menu.profile.Disabled=Disabled rpipico2w.menu.profile.Disabled.build.flags.profile= rpipico2w.menu.profile.Enabled=Enabled @@ -1397,6 +1414,10 @@ rpipico2w.menu.uploadmethod.picoprobe_cmsis_dap.upload.tool.default=picoprobe_cm 0xcb_helios.menu.opt.Debug.build.flags.optimize=-Og 0xcb_helios.menu.opt.Disabled=Disabled (-O0) 0xcb_helios.menu.opt.Disabled.build.flags.optimize=-O0 +0xcb_helios.menu.os.none=None +0xcb_helios.menu.os.none.build.os= +0xcb_helios.menu.os.freertos=FreeRTOS SMP +0xcb_helios.menu.os.freertos.build.os=-D__FREERTOS 0xcb_helios.menu.profile.Disabled=Disabled 0xcb_helios.menu.profile.Disabled.build.flags.profile= 0xcb_helios.menu.profile.Enabled=Enabled @@ -1661,6 +1682,10 @@ adafruit_feather.menu.opt.Debug=Debug (-Og) adafruit_feather.menu.opt.Debug.build.flags.optimize=-Og adafruit_feather.menu.opt.Disabled=Disabled (-O0) adafruit_feather.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_feather.menu.os.none=None +adafruit_feather.menu.os.none.build.os= +adafruit_feather.menu.os.freertos=FreeRTOS SMP +adafruit_feather.menu.os.freertos.build.os=-D__FREERTOS adafruit_feather.menu.profile.Disabled=Disabled adafruit_feather.menu.profile.Disabled.build.flags.profile= adafruit_feather.menu.profile.Enabled=Enabled @@ -1917,6 +1942,10 @@ adafruit_feather_scorpio.menu.opt.Debug=Debug (-Og) adafruit_feather_scorpio.menu.opt.Debug.build.flags.optimize=-Og adafruit_feather_scorpio.menu.opt.Disabled=Disabled (-O0) adafruit_feather_scorpio.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_feather_scorpio.menu.os.none=None +adafruit_feather_scorpio.menu.os.none.build.os= +adafruit_feather_scorpio.menu.os.freertos=FreeRTOS SMP +adafruit_feather_scorpio.menu.os.freertos.build.os=-D__FREERTOS adafruit_feather_scorpio.menu.profile.Disabled=Disabled adafruit_feather_scorpio.menu.profile.Disabled.build.flags.profile= adafruit_feather_scorpio.menu.profile.Enabled=Enabled @@ -2177,6 +2206,10 @@ adafruit_feather_dvi.menu.opt.Debug=Debug (-Og) adafruit_feather_dvi.menu.opt.Debug.build.flags.optimize=-Og adafruit_feather_dvi.menu.opt.Disabled=Disabled (-O0) adafruit_feather_dvi.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_feather_dvi.menu.os.none=None +adafruit_feather_dvi.menu.os.none.build.os= +adafruit_feather_dvi.menu.os.freertos=FreeRTOS SMP +adafruit_feather_dvi.menu.os.freertos.build.os=-D__FREERTOS adafruit_feather_dvi.menu.profile.Disabled=Disabled adafruit_feather_dvi.menu.profile.Disabled.build.flags.profile= adafruit_feather_dvi.menu.profile.Enabled=Enabled @@ -2437,6 +2470,10 @@ adafruit_feather_adalogger.menu.opt.Debug=Debug (-Og) adafruit_feather_adalogger.menu.opt.Debug.build.flags.optimize=-Og adafruit_feather_adalogger.menu.opt.Disabled=Disabled (-O0) adafruit_feather_adalogger.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_feather_adalogger.menu.os.none=None +adafruit_feather_adalogger.menu.os.none.build.os= +adafruit_feather_adalogger.menu.os.freertos=FreeRTOS SMP +adafruit_feather_adalogger.menu.os.freertos.build.os=-D__FREERTOS adafruit_feather_adalogger.menu.profile.Disabled=Disabled adafruit_feather_adalogger.menu.profile.Disabled.build.flags.profile= adafruit_feather_adalogger.menu.profile.Enabled=Enabled @@ -2697,6 +2734,10 @@ adafruit_feather_rfm.menu.opt.Debug=Debug (-Og) adafruit_feather_rfm.menu.opt.Debug.build.flags.optimize=-Og adafruit_feather_rfm.menu.opt.Disabled=Disabled (-O0) adafruit_feather_rfm.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_feather_rfm.menu.os.none=None +adafruit_feather_rfm.menu.os.none.build.os= +adafruit_feather_rfm.menu.os.freertos=FreeRTOS SMP +adafruit_feather_rfm.menu.os.freertos.build.os=-D__FREERTOS adafruit_feather_rfm.menu.profile.Disabled=Disabled adafruit_feather_rfm.menu.profile.Disabled.build.flags.profile= adafruit_feather_rfm.menu.profile.Enabled=Enabled @@ -2957,6 +2998,10 @@ adafruit_feather_thinkink.menu.opt.Debug=Debug (-Og) adafruit_feather_thinkink.menu.opt.Debug.build.flags.optimize=-Og adafruit_feather_thinkink.menu.opt.Disabled=Disabled (-O0) adafruit_feather_thinkink.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_feather_thinkink.menu.os.none=None +adafruit_feather_thinkink.menu.os.none.build.os= +adafruit_feather_thinkink.menu.os.freertos=FreeRTOS SMP +adafruit_feather_thinkink.menu.os.freertos.build.os=-D__FREERTOS adafruit_feather_thinkink.menu.profile.Disabled=Disabled adafruit_feather_thinkink.menu.profile.Disabled.build.flags.profile= adafruit_feather_thinkink.menu.profile.Enabled=Enabled @@ -3217,6 +3262,10 @@ adafruit_feather_usb_host.menu.opt.Debug=Debug (-Og) adafruit_feather_usb_host.menu.opt.Debug.build.flags.optimize=-Og adafruit_feather_usb_host.menu.opt.Disabled=Disabled (-O0) adafruit_feather_usb_host.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_feather_usb_host.menu.os.none=None +adafruit_feather_usb_host.menu.os.none.build.os= +adafruit_feather_usb_host.menu.os.freertos=FreeRTOS SMP +adafruit_feather_usb_host.menu.os.freertos.build.os=-D__FREERTOS adafruit_feather_usb_host.menu.profile.Disabled=Disabled adafruit_feather_usb_host.menu.profile.Disabled.build.flags.profile= adafruit_feather_usb_host.menu.profile.Enabled=Enabled @@ -3477,6 +3526,10 @@ adafruit_feather_can.menu.opt.Debug=Debug (-Og) adafruit_feather_can.menu.opt.Debug.build.flags.optimize=-Og adafruit_feather_can.menu.opt.Disabled=Disabled (-O0) adafruit_feather_can.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_feather_can.menu.os.none=None +adafruit_feather_can.menu.os.none.build.os= +adafruit_feather_can.menu.os.freertos=FreeRTOS SMP +adafruit_feather_can.menu.os.freertos.build.os=-D__FREERTOS adafruit_feather_can.menu.profile.Disabled=Disabled adafruit_feather_can.menu.profile.Disabled.build.flags.profile= adafruit_feather_can.menu.profile.Enabled=Enabled @@ -3737,6 +3790,10 @@ adafruit_feather_prop_maker.menu.opt.Debug=Debug (-Og) adafruit_feather_prop_maker.menu.opt.Debug.build.flags.optimize=-Og adafruit_feather_prop_maker.menu.opt.Disabled=Disabled (-O0) adafruit_feather_prop_maker.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_feather_prop_maker.menu.os.none=None +adafruit_feather_prop_maker.menu.os.none.build.os= +adafruit_feather_prop_maker.menu.os.freertos=FreeRTOS SMP +adafruit_feather_prop_maker.menu.os.freertos.build.os=-D__FREERTOS adafruit_feather_prop_maker.menu.profile.Disabled=Disabled adafruit_feather_prop_maker.menu.profile.Disabled.build.flags.profile= adafruit_feather_prop_maker.menu.profile.Enabled=Enabled @@ -4005,6 +4062,10 @@ adafruit_itsybitsy.menu.opt.Debug=Debug (-Og) adafruit_itsybitsy.menu.opt.Debug.build.flags.optimize=-Og adafruit_itsybitsy.menu.opt.Disabled=Disabled (-O0) adafruit_itsybitsy.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_itsybitsy.menu.os.none=None +adafruit_itsybitsy.menu.os.none.build.os= +adafruit_itsybitsy.menu.os.freertos=FreeRTOS SMP +adafruit_itsybitsy.menu.os.freertos.build.os=-D__FREERTOS adafruit_itsybitsy.menu.profile.Disabled=Disabled adafruit_itsybitsy.menu.profile.Disabled.build.flags.profile= adafruit_itsybitsy.menu.profile.Enabled=Enabled @@ -4321,6 +4382,10 @@ adafruit_metro.menu.opt.Debug=Debug (-Og) adafruit_metro.menu.opt.Debug.build.flags.optimize=-Og adafruit_metro.menu.opt.Disabled=Disabled (-O0) adafruit_metro.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_metro.menu.os.none=None +adafruit_metro.menu.os.none.build.os= +adafruit_metro.menu.os.freertos=FreeRTOS SMP +adafruit_metro.menu.os.freertos.build.os=-D__FREERTOS adafruit_metro.menu.profile.Disabled=Disabled adafruit_metro.menu.profile.Disabled.build.flags.profile= adafruit_metro.menu.profile.Enabled=Enabled @@ -4589,6 +4654,10 @@ adafruit_qtpy.menu.opt.Debug=Debug (-Og) adafruit_qtpy.menu.opt.Debug.build.flags.optimize=-Og adafruit_qtpy.menu.opt.Disabled=Disabled (-O0) adafruit_qtpy.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_qtpy.menu.os.none=None +adafruit_qtpy.menu.os.none.build.os= +adafruit_qtpy.menu.os.freertos=FreeRTOS SMP +adafruit_qtpy.menu.os.freertos.build.os=-D__FREERTOS adafruit_qtpy.menu.profile.Disabled=Disabled adafruit_qtpy.menu.profile.Disabled.build.flags.profile= adafruit_qtpy.menu.profile.Enabled=Enabled @@ -4857,6 +4926,10 @@ adafruit_stemmafriend.menu.opt.Debug=Debug (-Og) adafruit_stemmafriend.menu.opt.Debug.build.flags.optimize=-Og adafruit_stemmafriend.menu.opt.Disabled=Disabled (-O0) adafruit_stemmafriend.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_stemmafriend.menu.os.none=None +adafruit_stemmafriend.menu.os.none.build.os= +adafruit_stemmafriend.menu.os.freertos=FreeRTOS SMP +adafruit_stemmafriend.menu.os.freertos.build.os=-D__FREERTOS adafruit_stemmafriend.menu.profile.Disabled=Disabled adafruit_stemmafriend.menu.profile.Disabled.build.flags.profile= adafruit_stemmafriend.menu.profile.Enabled=Enabled @@ -5117,6 +5190,10 @@ adafruit_trinkeyrp2040qt.menu.opt.Debug=Debug (-Og) adafruit_trinkeyrp2040qt.menu.opt.Debug.build.flags.optimize=-Og adafruit_trinkeyrp2040qt.menu.opt.Disabled=Disabled (-O0) adafruit_trinkeyrp2040qt.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_trinkeyrp2040qt.menu.os.none=None +adafruit_trinkeyrp2040qt.menu.os.none.build.os= +adafruit_trinkeyrp2040qt.menu.os.freertos=FreeRTOS SMP +adafruit_trinkeyrp2040qt.menu.os.freertos.build.os=-D__FREERTOS adafruit_trinkeyrp2040qt.menu.profile.Disabled=Disabled adafruit_trinkeyrp2040qt.menu.profile.Disabled.build.flags.profile= adafruit_trinkeyrp2040qt.menu.profile.Enabled=Enabled @@ -5377,6 +5454,10 @@ adafruit_macropad2040.menu.opt.Debug=Debug (-Og) adafruit_macropad2040.menu.opt.Debug.build.flags.optimize=-Og adafruit_macropad2040.menu.opt.Disabled=Disabled (-O0) adafruit_macropad2040.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_macropad2040.menu.os.none=None +adafruit_macropad2040.menu.os.none.build.os= +adafruit_macropad2040.menu.os.freertos=FreeRTOS SMP +adafruit_macropad2040.menu.os.freertos.build.os=-D__FREERTOS adafruit_macropad2040.menu.profile.Disabled=Disabled adafruit_macropad2040.menu.profile.Disabled.build.flags.profile= adafruit_macropad2040.menu.profile.Enabled=Enabled @@ -5637,6 +5718,10 @@ adafruit_kb2040.menu.opt.Debug=Debug (-Og) adafruit_kb2040.menu.opt.Debug.build.flags.optimize=-Og adafruit_kb2040.menu.opt.Disabled=Disabled (-O0) adafruit_kb2040.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_kb2040.menu.os.none=None +adafruit_kb2040.menu.os.none.build.os= +adafruit_kb2040.menu.os.freertos=FreeRTOS SMP +adafruit_kb2040.menu.os.freertos.build.os=-D__FREERTOS adafruit_kb2040.menu.profile.Disabled=Disabled adafruit_kb2040.menu.profile.Disabled.build.flags.profile= adafruit_kb2040.menu.profile.Enabled=Enabled @@ -5906,6 +5991,10 @@ adafruit_feather_rp2350_adalogger.menu.opt.Debug=Debug (-Og) adafruit_feather_rp2350_adalogger.menu.opt.Debug.build.flags.optimize=-Og adafruit_feather_rp2350_adalogger.menu.opt.Disabled=Disabled (-O0) adafruit_feather_rp2350_adalogger.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_feather_rp2350_adalogger.menu.os.none=None +adafruit_feather_rp2350_adalogger.menu.os.none.build.os= +adafruit_feather_rp2350_adalogger.menu.os.freertos=FreeRTOS SMP +adafruit_feather_rp2350_adalogger.menu.os.freertos.build.os=-D__FREERTOS adafruit_feather_rp2350_adalogger.menu.profile.Disabled=Disabled adafruit_feather_rp2350_adalogger.menu.profile.Disabled.build.flags.profile= adafruit_feather_rp2350_adalogger.menu.profile.Enabled=Enabled @@ -6179,6 +6268,10 @@ adafruit_feather_rp2350_hstx.menu.opt.Debug=Debug (-Og) adafruit_feather_rp2350_hstx.menu.opt.Debug.build.flags.optimize=-Og adafruit_feather_rp2350_hstx.menu.opt.Disabled=Disabled (-O0) adafruit_feather_rp2350_hstx.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_feather_rp2350_hstx.menu.os.none=None +adafruit_feather_rp2350_hstx.menu.os.none.build.os= +adafruit_feather_rp2350_hstx.menu.os.freertos=FreeRTOS SMP +adafruit_feather_rp2350_hstx.menu.os.freertos.build.os=-D__FREERTOS adafruit_feather_rp2350_hstx.menu.profile.Disabled=Disabled adafruit_feather_rp2350_hstx.menu.profile.Disabled.build.flags.profile= adafruit_feather_rp2350_hstx.menu.profile.Enabled=Enabled @@ -6491,6 +6584,10 @@ adafruit_floppsy.menu.opt.Debug=Debug (-Og) adafruit_floppsy.menu.opt.Debug.build.flags.optimize=-Og adafruit_floppsy.menu.opt.Disabled=Disabled (-O0) adafruit_floppsy.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_floppsy.menu.os.none=None +adafruit_floppsy.menu.os.none.build.os= +adafruit_floppsy.menu.os.freertos=FreeRTOS SMP +adafruit_floppsy.menu.os.freertos.build.os=-D__FREERTOS adafruit_floppsy.menu.profile.Disabled=Disabled adafruit_floppsy.menu.profile.Disabled.build.flags.profile= adafruit_floppsy.menu.profile.Enabled=Enabled @@ -6824,6 +6921,10 @@ adafruit_metro_rp2350.menu.opt.Debug=Debug (-Og) adafruit_metro_rp2350.menu.opt.Debug.build.flags.optimize=-Og adafruit_metro_rp2350.menu.opt.Disabled=Disabled (-O0) adafruit_metro_rp2350.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_metro_rp2350.menu.os.none=None +adafruit_metro_rp2350.menu.os.none.build.os= +adafruit_metro_rp2350.menu.os.freertos=FreeRTOS SMP +adafruit_metro_rp2350.menu.os.freertos.build.os=-D__FREERTOS adafruit_metro_rp2350.menu.profile.Disabled=Disabled adafruit_metro_rp2350.menu.profile.Disabled.build.flags.profile= adafruit_metro_rp2350.menu.profile.Enabled=Enabled @@ -7145,6 +7246,10 @@ adafruit_fruitjam.menu.opt.Debug=Debug (-Og) adafruit_fruitjam.menu.opt.Debug.build.flags.optimize=-Og adafruit_fruitjam.menu.opt.Disabled=Disabled (-O0) adafruit_fruitjam.menu.opt.Disabled.build.flags.optimize=-O0 +adafruit_fruitjam.menu.os.none=None +adafruit_fruitjam.menu.os.none.build.os= +adafruit_fruitjam.menu.os.freertos=FreeRTOS SMP +adafruit_fruitjam.menu.os.freertos.build.os=-D__FREERTOS adafruit_fruitjam.menu.profile.Disabled=Disabled adafruit_fruitjam.menu.profile.Disabled.build.flags.profile= adafruit_fruitjam.menu.profile.Enabled=Enabled @@ -8238,6 +8343,10 @@ amken_bunny.menu.opt.Debug=Debug (-Og) amken_bunny.menu.opt.Debug.build.flags.optimize=-Og amken_bunny.menu.opt.Disabled=Disabled (-O0) amken_bunny.menu.opt.Disabled.build.flags.optimize=-O0 +amken_bunny.menu.os.none=None +amken_bunny.menu.os.none.build.os= +amken_bunny.menu.os.freertos=FreeRTOS SMP +amken_bunny.menu.os.freertos.build.os=-D__FREERTOS amken_bunny.menu.profile.Disabled=Disabled amken_bunny.menu.profile.Disabled.build.flags.profile= amken_bunny.menu.profile.Enabled=Enabled @@ -8659,6 +8768,10 @@ amken_revelop.menu.opt.Debug=Debug (-Og) amken_revelop.menu.opt.Debug.build.flags.optimize=-Og amken_revelop.menu.opt.Disabled=Disabled (-O0) amken_revelop.menu.opt.Disabled.build.flags.optimize=-O0 +amken_revelop.menu.os.none=None +amken_revelop.menu.os.none.build.os= +amken_revelop.menu.os.freertos=FreeRTOS SMP +amken_revelop.menu.os.freertos.build.os=-D__FREERTOS amken_revelop.menu.profile.Disabled=Disabled amken_revelop.menu.profile.Disabled.build.flags.profile= amken_revelop.menu.profile.Enabled=Enabled @@ -9080,6 +9193,10 @@ amken_revelop_plus.menu.opt.Debug=Debug (-Og) amken_revelop_plus.menu.opt.Debug.build.flags.optimize=-Og amken_revelop_plus.menu.opt.Disabled=Disabled (-O0) amken_revelop_plus.menu.opt.Disabled.build.flags.optimize=-O0 +amken_revelop_plus.menu.os.none=None +amken_revelop_plus.menu.os.none.build.os= +amken_revelop_plus.menu.os.freertos=FreeRTOS SMP +amken_revelop_plus.menu.os.freertos.build.os=-D__FREERTOS amken_revelop_plus.menu.profile.Disabled=Disabled amken_revelop_plus.menu.profile.Disabled.build.flags.profile= amken_revelop_plus.menu.profile.Enabled=Enabled @@ -9389,6 +9506,10 @@ amken_revelop_es.menu.opt.Debug=Debug (-Og) amken_revelop_es.menu.opt.Debug.build.flags.optimize=-Og amken_revelop_es.menu.opt.Disabled=Disabled (-O0) amken_revelop_es.menu.opt.Disabled.build.flags.optimize=-O0 +amken_revelop_es.menu.os.none=None +amken_revelop_es.menu.os.none.build.os= +amken_revelop_es.menu.os.freertos=FreeRTOS SMP +amken_revelop_es.menu.os.freertos.build.os=-D__FREERTOS amken_revelop_es.menu.profile.Disabled=Disabled amken_revelop_es.menu.profile.Disabled.build.flags.profile= amken_revelop_es.menu.profile.Enabled=Enabled @@ -9710,6 +9831,10 @@ jumperless_v1.menu.opt.Debug=Debug (-Og) jumperless_v1.menu.opt.Debug.build.flags.optimize=-Og jumperless_v1.menu.opt.Disabled=Disabled (-O0) jumperless_v1.menu.opt.Disabled.build.flags.optimize=-O0 +jumperless_v1.menu.os.none=None +jumperless_v1.menu.os.none.build.os= +jumperless_v1.menu.os.freertos=FreeRTOS SMP +jumperless_v1.menu.os.freertos.build.os=-D__FREERTOS jumperless_v1.menu.profile.Disabled=Disabled jumperless_v1.menu.profile.Disabled.build.flags.profile= jumperless_v1.menu.profile.Enabled=Enabled @@ -10040,6 +10165,10 @@ jumperless_v5.menu.opt.Debug=Debug (-Og) jumperless_v5.menu.opt.Debug.build.flags.optimize=-Og jumperless_v5.menu.opt.Disabled=Disabled (-O0) jumperless_v5.menu.opt.Disabled.build.flags.optimize=-O0 +jumperless_v5.menu.os.none=None +jumperless_v5.menu.os.none.build.os= +jumperless_v5.menu.os.freertos=FreeRTOS SMP +jumperless_v5.menu.os.freertos.build.os=-D__FREERTOS jumperless_v5.menu.profile.Disabled=Disabled jumperless_v5.menu.profile.Disabled.build.flags.profile= jumperless_v5.menu.profile.Enabled=Enabled @@ -10360,6 +10489,10 @@ arduino_nano_connect.menu.opt.Debug=Debug (-Og) arduino_nano_connect.menu.opt.Debug.build.flags.optimize=-Og arduino_nano_connect.menu.opt.Disabled=Disabled (-O0) arduino_nano_connect.menu.opt.Disabled.build.flags.optimize=-O0 +arduino_nano_connect.menu.os.none=None +arduino_nano_connect.menu.os.none.build.os= +arduino_nano_connect.menu.os.freertos=FreeRTOS SMP +arduino_nano_connect.menu.os.freertos.build.os=-D__FREERTOS arduino_nano_connect.menu.profile.Disabled=Disabled arduino_nano_connect.menu.profile.Disabled.build.flags.profile= arduino_nano_connect.menu.profile.Enabled=Enabled @@ -10598,6 +10731,10 @@ artronshop_rp2_nano.menu.opt.Debug=Debug (-Og) artronshop_rp2_nano.menu.opt.Debug.build.flags.optimize=-Og artronshop_rp2_nano.menu.opt.Disabled=Disabled (-O0) artronshop_rp2_nano.menu.opt.Disabled.build.flags.optimize=-O0 +artronshop_rp2_nano.menu.os.none=None +artronshop_rp2_nano.menu.os.none.build.os= +artronshop_rp2_nano.menu.os.freertos=FreeRTOS SMP +artronshop_rp2_nano.menu.os.freertos.build.os=-D__FREERTOS artronshop_rp2_nano.menu.profile.Disabled=Disabled artronshop_rp2_nano.menu.profile.Disabled.build.flags.profile= artronshop_rp2_nano.menu.profile.Enabled=Enabled @@ -10812,6 +10949,10 @@ bigtreetech_SKR_Pico.menu.opt.Debug=Debug (-Og) bigtreetech_SKR_Pico.menu.opt.Debug.build.flags.optimize=-Og bigtreetech_SKR_Pico.menu.opt.Disabled=Disabled (-O0) bigtreetech_SKR_Pico.menu.opt.Disabled.build.flags.optimize=-O0 +bigtreetech_SKR_Pico.menu.os.none=None +bigtreetech_SKR_Pico.menu.os.none.build.os= +bigtreetech_SKR_Pico.menu.os.freertos=FreeRTOS SMP +bigtreetech_SKR_Pico.menu.os.freertos.build.os=-D__FREERTOS bigtreetech_SKR_Pico.menu.profile.Disabled=Disabled bigtreetech_SKR_Pico.menu.profile.Disabled.build.flags.profile= bigtreetech_SKR_Pico.menu.profile.Enabled=Enabled @@ -11148,6 +11289,10 @@ breadstick_raspberry.menu.opt.Debug=Debug (-Og) breadstick_raspberry.menu.opt.Debug.build.flags.optimize=-Og breadstick_raspberry.menu.opt.Disabled=Disabled (-O0) breadstick_raspberry.menu.opt.Disabled.build.flags.optimize=-O0 +breadstick_raspberry.menu.os.none=None +breadstick_raspberry.menu.os.none.build.os= +breadstick_raspberry.menu.os.freertos=FreeRTOS SMP +breadstick_raspberry.menu.os.freertos.build.os=-D__FREERTOS breadstick_raspberry.menu.profile.Disabled=Disabled breadstick_raspberry.menu.profile.Disabled.build.flags.profile= breadstick_raspberry.menu.profile.Enabled=Enabled @@ -11429,6 +11574,10 @@ bridgetek_idm2040_7a.menu.opt.Debug=Debug (-Og) bridgetek_idm2040_7a.menu.opt.Debug.build.flags.optimize=-Og bridgetek_idm2040_7a.menu.opt.Disabled=Disabled (-O0) bridgetek_idm2040_7a.menu.opt.Disabled.build.flags.optimize=-O0 +bridgetek_idm2040_7a.menu.os.none=None +bridgetek_idm2040_7a.menu.os.none.build.os= +bridgetek_idm2040_7a.menu.os.freertos=FreeRTOS SMP +bridgetek_idm2040_7a.menu.os.freertos.build.os=-D__FREERTOS bridgetek_idm2040_7a.menu.profile.Disabled=Disabled bridgetek_idm2040_7a.menu.profile.Disabled.build.flags.profile= bridgetek_idm2040_7a.menu.profile.Enabled=Enabled @@ -11686,6 +11835,10 @@ bridgetek_idm2040_43a.menu.opt.Debug=Debug (-Og) bridgetek_idm2040_43a.menu.opt.Debug.build.flags.optimize=-Og bridgetek_idm2040_43a.menu.opt.Disabled=Disabled (-O0) bridgetek_idm2040_43a.menu.opt.Disabled.build.flags.optimize=-O0 +bridgetek_idm2040_43a.menu.os.none=None +bridgetek_idm2040_43a.menu.os.none.build.os= +bridgetek_idm2040_43a.menu.os.freertos=FreeRTOS SMP +bridgetek_idm2040_43a.menu.os.freertos.build.os=-D__FREERTOS bridgetek_idm2040_43a.menu.profile.Disabled=Disabled bridgetek_idm2040_43a.menu.profile.Disabled.build.flags.profile= bridgetek_idm2040_43a.menu.profile.Enabled=Enabled @@ -11933,6 +12086,10 @@ cytron_iriv_io_controller.menu.opt.Debug=Debug (-Og) cytron_iriv_io_controller.menu.opt.Debug.build.flags.optimize=-Og cytron_iriv_io_controller.menu.opt.Disabled=Disabled (-O0) cytron_iriv_io_controller.menu.opt.Disabled.build.flags.optimize=-O0 +cytron_iriv_io_controller.menu.os.none=None +cytron_iriv_io_controller.menu.os.none.build.os= +cytron_iriv_io_controller.menu.os.freertos=FreeRTOS SMP +cytron_iriv_io_controller.menu.os.freertos.build.os=-D__FREERTOS cytron_iriv_io_controller.menu.profile.Disabled=Disabled cytron_iriv_io_controller.menu.profile.Disabled.build.flags.profile= cytron_iriv_io_controller.menu.profile.Enabled=Enabled @@ -12171,6 +12328,10 @@ cytron_maker_nano_rp2040.menu.opt.Debug=Debug (-Og) cytron_maker_nano_rp2040.menu.opt.Debug.build.flags.optimize=-Og cytron_maker_nano_rp2040.menu.opt.Disabled=Disabled (-O0) cytron_maker_nano_rp2040.menu.opt.Disabled.build.flags.optimize=-O0 +cytron_maker_nano_rp2040.menu.os.none=None +cytron_maker_nano_rp2040.menu.os.none.build.os= +cytron_maker_nano_rp2040.menu.os.freertos=FreeRTOS SMP +cytron_maker_nano_rp2040.menu.os.freertos.build.os=-D__FREERTOS cytron_maker_nano_rp2040.menu.profile.Disabled=Disabled cytron_maker_nano_rp2040.menu.profile.Disabled.build.flags.profile= cytron_maker_nano_rp2040.menu.profile.Enabled=Enabled @@ -12409,6 +12570,10 @@ cytron_maker_pi_rp2040.menu.opt.Debug=Debug (-Og) cytron_maker_pi_rp2040.menu.opt.Debug.build.flags.optimize=-Og cytron_maker_pi_rp2040.menu.opt.Disabled=Disabled (-O0) cytron_maker_pi_rp2040.menu.opt.Disabled.build.flags.optimize=-O0 +cytron_maker_pi_rp2040.menu.os.none=None +cytron_maker_pi_rp2040.menu.os.none.build.os= +cytron_maker_pi_rp2040.menu.os.freertos=FreeRTOS SMP +cytron_maker_pi_rp2040.menu.os.freertos.build.os=-D__FREERTOS cytron_maker_pi_rp2040.menu.profile.Disabled=Disabled cytron_maker_pi_rp2040.menu.profile.Disabled.build.flags.profile= cytron_maker_pi_rp2040.menu.profile.Enabled=Enabled @@ -12647,6 +12812,10 @@ cytron_maker_uno_rp2040.menu.opt.Debug=Debug (-Og) cytron_maker_uno_rp2040.menu.opt.Debug.build.flags.optimize=-Og cytron_maker_uno_rp2040.menu.opt.Disabled=Disabled (-O0) cytron_maker_uno_rp2040.menu.opt.Disabled.build.flags.optimize=-O0 +cytron_maker_uno_rp2040.menu.os.none=None +cytron_maker_uno_rp2040.menu.os.none.build.os= +cytron_maker_uno_rp2040.menu.os.freertos=FreeRTOS SMP +cytron_maker_uno_rp2040.menu.os.freertos.build.os=-D__FREERTOS cytron_maker_uno_rp2040.menu.profile.Disabled=Disabled cytron_maker_uno_rp2040.menu.profile.Disabled.build.flags.profile= cytron_maker_uno_rp2040.menu.profile.Enabled=Enabled @@ -12894,6 +13063,10 @@ cytron_motion_2350_pro.menu.opt.Debug=Debug (-Og) cytron_motion_2350_pro.menu.opt.Debug.build.flags.optimize=-Og cytron_motion_2350_pro.menu.opt.Disabled=Disabled (-O0) cytron_motion_2350_pro.menu.opt.Disabled.build.flags.optimize=-O0 +cytron_motion_2350_pro.menu.os.none=None +cytron_motion_2350_pro.menu.os.none.build.os= +cytron_motion_2350_pro.menu.os.freertos=FreeRTOS SMP +cytron_motion_2350_pro.menu.os.freertos.build.os=-D__FREERTOS cytron_motion_2350_pro.menu.profile.Disabled=Disabled cytron_motion_2350_pro.menu.profile.Disabled.build.flags.profile= cytron_motion_2350_pro.menu.profile.Enabled=Enabled @@ -13132,6 +13305,10 @@ datanoisetv_picoadk.menu.opt.Debug=Debug (-Og) datanoisetv_picoadk.menu.opt.Debug.build.flags.optimize=-Og datanoisetv_picoadk.menu.opt.Disabled=Disabled (-O0) datanoisetv_picoadk.menu.opt.Disabled.build.flags.optimize=-O0 +datanoisetv_picoadk.menu.os.none=None +datanoisetv_picoadk.menu.os.none.build.os= +datanoisetv_picoadk.menu.os.freertos=FreeRTOS SMP +datanoisetv_picoadk.menu.os.freertos.build.os=-D__FREERTOS datanoisetv_picoadk.menu.profile.Disabled=Disabled datanoisetv_picoadk.menu.profile.Disabled.build.flags.profile= datanoisetv_picoadk.menu.profile.Enabled=Enabled @@ -13405,6 +13582,10 @@ datanoisetv_picoadk_v2.menu.opt.Debug=Debug (-Og) datanoisetv_picoadk_v2.menu.opt.Debug.build.flags.optimize=-Og datanoisetv_picoadk_v2.menu.opt.Disabled=Disabled (-O0) datanoisetv_picoadk_v2.menu.opt.Disabled.build.flags.optimize=-O0 +datanoisetv_picoadk_v2.menu.os.none=None +datanoisetv_picoadk_v2.menu.os.none.build.os= +datanoisetv_picoadk_v2.menu.os.freertos=FreeRTOS SMP +datanoisetv_picoadk_v2.menu.os.freertos.build.os=-D__FREERTOS datanoisetv_picoadk_v2.menu.profile.Disabled=Disabled datanoisetv_picoadk_v2.menu.profile.Disabled.build.flags.profile= datanoisetv_picoadk_v2.menu.profile.Enabled=Enabled @@ -13717,6 +13898,10 @@ degz_suibo.menu.opt.Debug=Debug (-Og) degz_suibo.menu.opt.Debug.build.flags.optimize=-Og degz_suibo.menu.opt.Disabled=Disabled (-O0) degz_suibo.menu.opt.Disabled.build.flags.optimize=-O0 +degz_suibo.menu.os.none=None +degz_suibo.menu.os.none.build.os= +degz_suibo.menu.os.freertos=FreeRTOS SMP +degz_suibo.menu.os.freertos.build.os=-D__FREERTOS degz_suibo.menu.profile.Disabled=Disabled degz_suibo.menu.profile.Disabled.build.flags.profile= degz_suibo.menu.profile.Enabled=Enabled @@ -13969,6 +14154,10 @@ flyboard2040_core.menu.opt.Debug=Debug (-Og) flyboard2040_core.menu.opt.Debug.build.flags.optimize=-Og flyboard2040_core.menu.opt.Disabled=Disabled (-O0) flyboard2040_core.menu.opt.Disabled.build.flags.optimize=-O0 +flyboard2040_core.menu.os.none=None +flyboard2040_core.menu.os.none.build.os= +flyboard2040_core.menu.os.freertos=FreeRTOS SMP +flyboard2040_core.menu.os.freertos.build.os=-D__FREERTOS flyboard2040_core.menu.profile.Disabled=Disabled flyboard2040_core.menu.profile.Disabled.build.flags.profile= flyboard2040_core.menu.profile.Enabled=Enabled @@ -14191,6 +14380,10 @@ dfrobot_beetle_rp2040.menu.opt.Debug=Debug (-Og) dfrobot_beetle_rp2040.menu.opt.Debug.build.flags.optimize=-Og dfrobot_beetle_rp2040.menu.opt.Disabled=Disabled (-O0) dfrobot_beetle_rp2040.menu.opt.Disabled.build.flags.optimize=-O0 +dfrobot_beetle_rp2040.menu.os.none=None +dfrobot_beetle_rp2040.menu.os.none.build.os= +dfrobot_beetle_rp2040.menu.os.freertos=FreeRTOS SMP +dfrobot_beetle_rp2040.menu.os.freertos.build.os=-D__FREERTOS dfrobot_beetle_rp2040.menu.profile.Disabled=Disabled dfrobot_beetle_rp2040.menu.profile.Disabled.build.flags.profile= dfrobot_beetle_rp2040.menu.profile.Enabled=Enabled @@ -14443,6 +14636,10 @@ DudesCab.menu.opt.Debug=Debug (-Og) DudesCab.menu.opt.Debug.build.flags.optimize=-Og DudesCab.menu.opt.Disabled=Disabled (-O0) DudesCab.menu.opt.Disabled.build.flags.optimize=-O0 +DudesCab.menu.os.none=None +DudesCab.menu.os.none.build.os= +DudesCab.menu.os.freertos=FreeRTOS SMP +DudesCab.menu.os.freertos.build.os=-D__FREERTOS DudesCab.menu.profile.Disabled=Disabled DudesCab.menu.profile.Disabled.build.flags.profile= DudesCab.menu.profile.Enabled=Enabled @@ -14681,6 +14878,10 @@ electroniccats_huntercat_nfc.menu.opt.Debug=Debug (-Og) electroniccats_huntercat_nfc.menu.opt.Debug.build.flags.optimize=-Og electroniccats_huntercat_nfc.menu.opt.Disabled=Disabled (-O0) electroniccats_huntercat_nfc.menu.opt.Disabled.build.flags.optimize=-O0 +electroniccats_huntercat_nfc.menu.os.none=None +electroniccats_huntercat_nfc.menu.os.none.build.os= +electroniccats_huntercat_nfc.menu.os.freertos=FreeRTOS SMP +electroniccats_huntercat_nfc.menu.os.freertos.build.os=-D__FREERTOS electroniccats_huntercat_nfc.menu.profile.Disabled=Disabled electroniccats_huntercat_nfc.menu.profile.Disabled.build.flags.profile= electroniccats_huntercat_nfc.menu.profile.Enabled=Enabled @@ -14993,6 +15194,10 @@ evn_alpha.menu.opt.Debug=Debug (-Og) evn_alpha.menu.opt.Debug.build.flags.optimize=-Og evn_alpha.menu.opt.Disabled=Disabled (-O0) evn_alpha.menu.opt.Disabled.build.flags.optimize=-O0 +evn_alpha.menu.os.none=None +evn_alpha.menu.os.none.build.os= +evn_alpha.menu.os.freertos=FreeRTOS SMP +evn_alpha.menu.os.freertos.build.os=-D__FREERTOS evn_alpha.menu.profile.Disabled=Disabled evn_alpha.menu.profile.Disabled.build.flags.profile= evn_alpha.menu.profile.Enabled=Enabled @@ -15207,6 +15412,10 @@ extelec_rc2040.menu.opt.Debug=Debug (-Og) extelec_rc2040.menu.opt.Debug.build.flags.optimize=-Og extelec_rc2040.menu.opt.Disabled=Disabled (-O0) extelec_rc2040.menu.opt.Disabled.build.flags.optimize=-O0 +extelec_rc2040.menu.os.none=None +extelec_rc2040.menu.os.none.build.os= +extelec_rc2040.menu.os.freertos=FreeRTOS SMP +extelec_rc2040.menu.os.freertos.build.os=-D__FREERTOS extelec_rc2040.menu.profile.Disabled=Disabled extelec_rc2040.menu.profile.Disabled.build.flags.profile= extelec_rc2040.menu.profile.Enabled=Enabled @@ -15487,6 +15696,10 @@ groundstudio_marble_pico.menu.opt.Debug=Debug (-Og) groundstudio_marble_pico.menu.opt.Debug.build.flags.optimize=-Og groundstudio_marble_pico.menu.opt.Disabled=Disabled (-O0) groundstudio_marble_pico.menu.opt.Disabled.build.flags.optimize=-O0 +groundstudio_marble_pico.menu.os.none=None +groundstudio_marble_pico.menu.os.none.build.os= +groundstudio_marble_pico.menu.os.freertos=FreeRTOS SMP +groundstudio_marble_pico.menu.os.freertos.build.os=-D__FREERTOS groundstudio_marble_pico.menu.profile.Disabled=Disabled groundstudio_marble_pico.menu.profile.Disabled.build.flags.profile= groundstudio_marble_pico.menu.profile.Enabled=Enabled @@ -15767,6 +15980,10 @@ challenger_2040_lte.menu.opt.Debug=Debug (-Og) challenger_2040_lte.menu.opt.Debug.build.flags.optimize=-Og challenger_2040_lte.menu.opt.Disabled=Disabled (-O0) challenger_2040_lte.menu.opt.Disabled.build.flags.optimize=-O0 +challenger_2040_lte.menu.os.none=None +challenger_2040_lte.menu.os.none.build.os= +challenger_2040_lte.menu.os.freertos=FreeRTOS SMP +challenger_2040_lte.menu.os.freertos.build.os=-D__FREERTOS challenger_2040_lte.menu.profile.Disabled=Disabled challenger_2040_lte.menu.profile.Disabled.build.flags.profile= challenger_2040_lte.menu.profile.Enabled=Enabled @@ -16047,6 +16264,10 @@ challenger_2040_lora.menu.opt.Debug=Debug (-Og) challenger_2040_lora.menu.opt.Debug.build.flags.optimize=-Og challenger_2040_lora.menu.opt.Disabled=Disabled (-O0) challenger_2040_lora.menu.opt.Disabled.build.flags.optimize=-O0 +challenger_2040_lora.menu.os.none=None +challenger_2040_lora.menu.os.none.build.os= +challenger_2040_lora.menu.os.freertos=FreeRTOS SMP +challenger_2040_lora.menu.os.freertos.build.os=-D__FREERTOS challenger_2040_lora.menu.profile.Disabled=Disabled challenger_2040_lora.menu.profile.Disabled.build.flags.profile= challenger_2040_lora.menu.profile.Enabled=Enabled @@ -16327,6 +16548,10 @@ challenger_2040_subghz.menu.opt.Debug=Debug (-Og) challenger_2040_subghz.menu.opt.Debug.build.flags.optimize=-Og challenger_2040_subghz.menu.opt.Disabled=Disabled (-O0) challenger_2040_subghz.menu.opt.Disabled.build.flags.optimize=-O0 +challenger_2040_subghz.menu.os.none=None +challenger_2040_subghz.menu.os.none.build.os= +challenger_2040_subghz.menu.os.freertos=FreeRTOS SMP +challenger_2040_subghz.menu.os.freertos.build.os=-D__FREERTOS challenger_2040_subghz.menu.profile.Disabled=Disabled challenger_2040_subghz.menu.profile.Disabled.build.flags.profile= challenger_2040_subghz.menu.profile.Enabled=Enabled @@ -16608,6 +16833,10 @@ challenger_2040_wifi.menu.opt.Debug=Debug (-Og) challenger_2040_wifi.menu.opt.Debug.build.flags.optimize=-Og challenger_2040_wifi.menu.opt.Disabled=Disabled (-O0) challenger_2040_wifi.menu.opt.Disabled.build.flags.optimize=-O0 +challenger_2040_wifi.menu.os.none=None +challenger_2040_wifi.menu.os.none.build.os= +challenger_2040_wifi.menu.os.freertos=FreeRTOS SMP +challenger_2040_wifi.menu.os.freertos.build.os=-D__FREERTOS challenger_2040_wifi.menu.profile.Disabled=Disabled challenger_2040_wifi.menu.profile.Disabled.build.flags.profile= challenger_2040_wifi.menu.profile.Enabled=Enabled @@ -16989,6 +17218,10 @@ challenger_2040_wifi_ble.menu.opt.Debug=Debug (-Og) challenger_2040_wifi_ble.menu.opt.Debug.build.flags.optimize=-Og challenger_2040_wifi_ble.menu.opt.Disabled=Disabled (-O0) challenger_2040_wifi_ble.menu.opt.Disabled.build.flags.optimize=-O0 +challenger_2040_wifi_ble.menu.os.none=None +challenger_2040_wifi_ble.menu.os.none.build.os= +challenger_2040_wifi_ble.menu.os.freertos=FreeRTOS SMP +challenger_2040_wifi_ble.menu.os.freertos.build.os=-D__FREERTOS challenger_2040_wifi_ble.menu.profile.Disabled=Disabled challenger_2040_wifi_ble.menu.profile.Disabled.build.flags.profile= challenger_2040_wifi_ble.menu.profile.Enabled=Enabled @@ -17270,6 +17503,10 @@ challenger_2040_wifi6_ble.menu.opt.Debug=Debug (-Og) challenger_2040_wifi6_ble.menu.opt.Debug.build.flags.optimize=-Og challenger_2040_wifi6_ble.menu.opt.Disabled=Disabled (-O0) challenger_2040_wifi6_ble.menu.opt.Disabled.build.flags.optimize=-O0 +challenger_2040_wifi6_ble.menu.os.none=None +challenger_2040_wifi6_ble.menu.os.none.build.os= +challenger_2040_wifi6_ble.menu.os.freertos=FreeRTOS SMP +challenger_2040_wifi6_ble.menu.os.freertos.build.os=-D__FREERTOS challenger_2040_wifi6_ble.menu.profile.Disabled=Disabled challenger_2040_wifi6_ble.menu.profile.Disabled.build.flags.profile= challenger_2040_wifi6_ble.menu.profile.Enabled=Enabled @@ -17551,6 +17788,10 @@ challenger_nb_2040_wifi.menu.opt.Debug=Debug (-Og) challenger_nb_2040_wifi.menu.opt.Debug.build.flags.optimize=-Og challenger_nb_2040_wifi.menu.opt.Disabled=Disabled (-O0) challenger_nb_2040_wifi.menu.opt.Disabled.build.flags.optimize=-O0 +challenger_nb_2040_wifi.menu.os.none=None +challenger_nb_2040_wifi.menu.os.none.build.os= +challenger_nb_2040_wifi.menu.os.freertos=FreeRTOS SMP +challenger_nb_2040_wifi.menu.os.freertos.build.os=-D__FREERTOS challenger_nb_2040_wifi.menu.profile.Disabled=Disabled challenger_nb_2040_wifi.menu.profile.Disabled.build.flags.profile= challenger_nb_2040_wifi.menu.profile.Enabled=Enabled @@ -17831,6 +18072,10 @@ challenger_2040_sdrtc.menu.opt.Debug=Debug (-Og) challenger_2040_sdrtc.menu.opt.Debug.build.flags.optimize=-Og challenger_2040_sdrtc.menu.opt.Disabled=Disabled (-O0) challenger_2040_sdrtc.menu.opt.Disabled.build.flags.optimize=-O0 +challenger_2040_sdrtc.menu.os.none=None +challenger_2040_sdrtc.menu.os.none.build.os= +challenger_2040_sdrtc.menu.os.freertos=FreeRTOS SMP +challenger_2040_sdrtc.menu.os.freertos.build.os=-D__FREERTOS challenger_2040_sdrtc.menu.profile.Disabled=Disabled challenger_2040_sdrtc.menu.profile.Disabled.build.flags.profile= challenger_2040_sdrtc.menu.profile.Enabled=Enabled @@ -18111,6 +18356,10 @@ challenger_2040_nfc.menu.opt.Debug=Debug (-Og) challenger_2040_nfc.menu.opt.Debug.build.flags.optimize=-Og challenger_2040_nfc.menu.opt.Disabled=Disabled (-O0) challenger_2040_nfc.menu.opt.Disabled.build.flags.optimize=-O0 +challenger_2040_nfc.menu.os.none=None +challenger_2040_nfc.menu.os.none.build.os= +challenger_2040_nfc.menu.os.freertos=FreeRTOS SMP +challenger_2040_nfc.menu.os.freertos.build.os=-D__FREERTOS challenger_2040_nfc.menu.profile.Disabled=Disabled challenger_2040_nfc.menu.profile.Disabled.build.flags.profile= challenger_2040_nfc.menu.profile.Enabled=Enabled @@ -18391,6 +18640,10 @@ challenger_2040_uwb.menu.opt.Debug=Debug (-Og) challenger_2040_uwb.menu.opt.Debug.build.flags.optimize=-Og challenger_2040_uwb.menu.opt.Disabled=Disabled (-O0) challenger_2040_uwb.menu.opt.Disabled.build.flags.optimize=-O0 +challenger_2040_uwb.menu.os.none=None +challenger_2040_uwb.menu.os.none.build.os= +challenger_2040_uwb.menu.os.freertos=FreeRTOS SMP +challenger_2040_uwb.menu.os.freertos.build.os=-D__FREERTOS challenger_2040_uwb.menu.profile.Disabled=Disabled challenger_2040_uwb.menu.profile.Disabled.build.flags.profile= challenger_2040_uwb.menu.profile.Enabled=Enabled @@ -18672,6 +18925,10 @@ connectivity_2040_lte_wifi_ble.menu.opt.Debug=Debug (-Og) connectivity_2040_lte_wifi_ble.menu.opt.Debug.build.flags.optimize=-Og connectivity_2040_lte_wifi_ble.menu.opt.Disabled=Disabled (-O0) connectivity_2040_lte_wifi_ble.menu.opt.Disabled.build.flags.optimize=-O0 +connectivity_2040_lte_wifi_ble.menu.os.none=None +connectivity_2040_lte_wifi_ble.menu.os.none.build.os= +connectivity_2040_lte_wifi_ble.menu.os.freertos=FreeRTOS SMP +connectivity_2040_lte_wifi_ble.menu.os.freertos.build.os=-D__FREERTOS connectivity_2040_lte_wifi_ble.menu.profile.Disabled=Disabled connectivity_2040_lte_wifi_ble.menu.profile.Disabled.build.flags.profile= connectivity_2040_lte_wifi_ble.menu.profile.Enabled=Enabled @@ -18953,6 +19210,10 @@ ilabs_rpico32.menu.opt.Debug=Debug (-Og) ilabs_rpico32.menu.opt.Debug.build.flags.optimize=-Og ilabs_rpico32.menu.opt.Disabled=Disabled (-O0) ilabs_rpico32.menu.opt.Disabled.build.flags.optimize=-O0 +ilabs_rpico32.menu.os.none=None +ilabs_rpico32.menu.os.none.build.os= +ilabs_rpico32.menu.os.freertos=FreeRTOS SMP +ilabs_rpico32.menu.os.freertos.build.os=-D__FREERTOS ilabs_rpico32.menu.profile.Disabled=Disabled ilabs_rpico32.menu.profile.Disabled.build.flags.profile= ilabs_rpico32.menu.profile.Enabled=Enabled @@ -19343,6 +19604,10 @@ challenger_2350_wifi6_ble5.menu.opt.Debug=Debug (-Og) challenger_2350_wifi6_ble5.menu.opt.Debug.build.flags.optimize=-Og challenger_2350_wifi6_ble5.menu.opt.Disabled=Disabled (-O0) challenger_2350_wifi6_ble5.menu.opt.Disabled.build.flags.optimize=-O0 +challenger_2350_wifi6_ble5.menu.os.none=None +challenger_2350_wifi6_ble5.menu.os.none.build.os= +challenger_2350_wifi6_ble5.menu.os.freertos=FreeRTOS SMP +challenger_2350_wifi6_ble5.menu.os.freertos.build.os=-D__FREERTOS challenger_2350_wifi6_ble5.menu.profile.Disabled=Disabled challenger_2350_wifi6_ble5.menu.profile.Disabled.build.flags.profile= challenger_2350_wifi6_ble5.menu.profile.Enabled=Enabled @@ -19632,6 +19897,10 @@ challenger_2350_bconnect.menu.opt.Debug=Debug (-Og) challenger_2350_bconnect.menu.opt.Debug.build.flags.optimize=-Og challenger_2350_bconnect.menu.opt.Disabled=Disabled (-O0) challenger_2350_bconnect.menu.opt.Disabled.build.flags.optimize=-O0 +challenger_2350_bconnect.menu.os.none=None +challenger_2350_bconnect.menu.os.none.build.os= +challenger_2350_bconnect.menu.os.freertos=FreeRTOS SMP +challenger_2350_bconnect.menu.os.freertos.build.os=-D__FREERTOS challenger_2350_bconnect.menu.profile.Disabled=Disabled challenger_2350_bconnect.menu.profile.Disabled.build.flags.profile= challenger_2350_bconnect.menu.profile.Enabled=Enabled @@ -19863,6 +20132,10 @@ mksthr36.menu.opt.Debug=Debug (-Og) mksthr36.menu.opt.Debug.build.flags.optimize=-Og mksthr36.menu.opt.Disabled=Disabled (-O0) mksthr36.menu.opt.Disabled.build.flags.optimize=-O0 +mksthr36.menu.os.none=None +mksthr36.menu.os.none.build.os= +mksthr36.menu.os.freertos=FreeRTOS SMP +mksthr36.menu.os.freertos.build.os=-D__FREERTOS mksthr36.menu.profile.Disabled=Disabled mksthr36.menu.profile.Disabled.build.flags.profile= mksthr36.menu.profile.Enabled=Enabled @@ -20094,6 +20367,10 @@ mksthr42.menu.opt.Debug=Debug (-Og) mksthr42.menu.opt.Debug.build.flags.optimize=-Og mksthr42.menu.opt.Disabled=Disabled (-O0) mksthr42.menu.opt.Disabled.build.flags.optimize=-O0 +mksthr42.menu.os.none=None +mksthr42.menu.os.none.build.os= +mksthr42.menu.os.freertos=FreeRTOS SMP +mksthr42.menu.os.freertos.build.os=-D__FREERTOS mksthr42.menu.profile.Disabled=Disabled mksthr42.menu.profile.Disabled.build.flags.profile= mksthr42.menu.profile.Enabled=Enabled @@ -20374,6 +20651,10 @@ melopero_cookie_rp2040.menu.opt.Debug=Debug (-Og) melopero_cookie_rp2040.menu.opt.Debug.build.flags.optimize=-Og melopero_cookie_rp2040.menu.opt.Disabled=Disabled (-O0) melopero_cookie_rp2040.menu.opt.Disabled.build.flags.optimize=-O0 +melopero_cookie_rp2040.menu.os.none=None +melopero_cookie_rp2040.menu.os.none.build.os= +melopero_cookie_rp2040.menu.os.freertos=FreeRTOS SMP +melopero_cookie_rp2040.menu.os.freertos.build.os=-D__FREERTOS melopero_cookie_rp2040.menu.profile.Disabled=Disabled melopero_cookie_rp2040.menu.profile.Disabled.build.flags.profile= melopero_cookie_rp2040.menu.profile.Enabled=Enabled @@ -20710,6 +20991,10 @@ melopero_shake_rp2040.menu.opt.Debug=Debug (-Og) melopero_shake_rp2040.menu.opt.Debug.build.flags.optimize=-Og melopero_shake_rp2040.menu.opt.Disabled=Disabled (-O0) melopero_shake_rp2040.menu.opt.Disabled.build.flags.optimize=-O0 +melopero_shake_rp2040.menu.os.none=None +melopero_shake_rp2040.menu.os.none.build.os= +melopero_shake_rp2040.menu.os.freertos=FreeRTOS SMP +melopero_shake_rp2040.menu.os.freertos.build.os=-D__FREERTOS melopero_shake_rp2040.menu.profile.Disabled=Disabled melopero_shake_rp2040.menu.profile.Disabled.build.flags.profile= melopero_shake_rp2040.menu.profile.Enabled=Enabled @@ -21025,6 +21310,10 @@ akana_r1.menu.opt.Debug=Debug (-Og) akana_r1.menu.opt.Debug.build.flags.optimize=-Og akana_r1.menu.opt.Disabled=Disabled (-O0) akana_r1.menu.opt.Disabled.build.flags.optimize=-O0 +akana_r1.menu.os.none=None +akana_r1.menu.os.none.build.os= +akana_r1.menu.os.freertos=FreeRTOS SMP +akana_r1.menu.os.freertos.build.os=-D__FREERTOS akana_r1.menu.profile.Disabled=Disabled akana_r1.menu.profile.Disabled.build.flags.profile= akana_r1.menu.profile.Enabled=Enabled @@ -21263,6 +21552,10 @@ MyRP_bot.menu.opt.Debug=Debug (-Og) MyRP_bot.menu.opt.Debug.build.flags.optimize=-Og MyRP_bot.menu.opt.Disabled=Disabled (-O0) MyRP_bot.menu.opt.Disabled.build.flags.optimize=-O0 +MyRP_bot.menu.os.none=None +MyRP_bot.menu.os.none.build.os= +MyRP_bot.menu.os.freertos=FreeRTOS SMP +MyRP_bot.menu.os.freertos.build.os=-D__FREERTOS MyRP_bot.menu.profile.Disabled=Disabled MyRP_bot.menu.profile.Disabled.build.flags.profile= MyRP_bot.menu.profile.Enabled=Enabled @@ -21515,6 +21808,10 @@ nekosystems_bl2040_mini.menu.opt.Debug=Debug (-Og) nekosystems_bl2040_mini.menu.opt.Debug.build.flags.optimize=-Og nekosystems_bl2040_mini.menu.opt.Disabled=Disabled (-O0) nekosystems_bl2040_mini.menu.opt.Disabled.build.flags.optimize=-O0 +nekosystems_bl2040_mini.menu.os.none=None +nekosystems_bl2040_mini.menu.os.none.build.os= +nekosystems_bl2040_mini.menu.os.freertos=FreeRTOS SMP +nekosystems_bl2040_mini.menu.os.freertos.build.os=-D__FREERTOS nekosystems_bl2040_mini.menu.profile.Disabled=Disabled nekosystems_bl2040_mini.menu.profile.Disabled.build.flags.profile= nekosystems_bl2040_mini.menu.profile.Enabled=Enabled @@ -21767,6 +22064,10 @@ newsan_archi.menu.opt.Debug=Debug (-Og) newsan_archi.menu.opt.Debug.build.flags.optimize=-Og newsan_archi.menu.opt.Disabled=Disabled (-O0) newsan_archi.menu.opt.Disabled.build.flags.optimize=-O0 +newsan_archi.menu.os.none=None +newsan_archi.menu.os.none.build.os= +newsan_archi.menu.os.freertos=FreeRTOS SMP +newsan_archi.menu.os.freertos.build.os=-D__FREERTOS newsan_archi.menu.profile.Disabled=Disabled newsan_archi.menu.profile.Disabled.build.flags.profile= newsan_archi.menu.profile.Enabled=Enabled @@ -22003,6 +22304,10 @@ nullbits_bit_c_pro.menu.opt.Debug=Debug (-Og) nullbits_bit_c_pro.menu.opt.Debug.build.flags.optimize=-Og nullbits_bit_c_pro.menu.opt.Disabled=Disabled (-O0) nullbits_bit_c_pro.menu.opt.Disabled.build.flags.optimize=-O0 +nullbits_bit_c_pro.menu.os.none=None +nullbits_bit_c_pro.menu.os.none.build.os= +nullbits_bit_c_pro.menu.os.freertos=FreeRTOS SMP +nullbits_bit_c_pro.menu.os.freertos.build.os=-D__FREERTOS nullbits_bit_c_pro.menu.profile.Disabled=Disabled nullbits_bit_c_pro.menu.profile.Disabled.build.flags.profile= nullbits_bit_c_pro.menu.profile.Enabled=Enabled @@ -22250,6 +22555,10 @@ olimex_pico2xl.menu.opt.Debug=Debug (-Og) olimex_pico2xl.menu.opt.Debug.build.flags.optimize=-Og olimex_pico2xl.menu.opt.Disabled=Disabled (-O0) olimex_pico2xl.menu.opt.Disabled.build.flags.optimize=-O0 +olimex_pico2xl.menu.os.none=None +olimex_pico2xl.menu.os.none.build.os= +olimex_pico2xl.menu.os.freertos=FreeRTOS SMP +olimex_pico2xl.menu.os.freertos.build.os=-D__FREERTOS olimex_pico2xl.menu.profile.Disabled=Disabled olimex_pico2xl.menu.profile.Disabled.build.flags.profile= olimex_pico2xl.menu.profile.Enabled=Enabled @@ -22595,6 +22904,10 @@ olimex_pico2xxl.menu.opt.Debug=Debug (-Og) olimex_pico2xxl.menu.opt.Debug.build.flags.optimize=-Og olimex_pico2xxl.menu.opt.Disabled=Disabled (-O0) olimex_pico2xxl.menu.opt.Disabled.build.flags.optimize=-O0 +olimex_pico2xxl.menu.os.none=None +olimex_pico2xxl.menu.os.none.build.os= +olimex_pico2xxl.menu.os.freertos=FreeRTOS SMP +olimex_pico2xxl.menu.os.freertos.build.os=-D__FREERTOS olimex_pico2xxl.menu.profile.Disabled=Disabled olimex_pico2xxl.menu.profile.Disabled.build.flags.profile= olimex_pico2xxl.menu.profile.Enabled=Enabled @@ -22882,6 +23195,10 @@ olimex_rp2040pico30.menu.opt.Debug=Debug (-Og) olimex_rp2040pico30.menu.opt.Debug.build.flags.optimize=-Og olimex_rp2040pico30.menu.opt.Disabled=Disabled (-O0) olimex_rp2040pico30.menu.opt.Disabled.build.flags.optimize=-O0 +olimex_rp2040pico30.menu.os.none=None +olimex_rp2040pico30.menu.os.none.build.os= +olimex_rp2040pico30.menu.os.freertos=FreeRTOS SMP +olimex_rp2040pico30.menu.os.freertos.build.os=-D__FREERTOS olimex_rp2040pico30.menu.profile.Disabled=Disabled olimex_rp2040pico30.menu.profile.Disabled.build.flags.profile= olimex_rp2040pico30.menu.profile.Enabled=Enabled @@ -23162,6 +23479,10 @@ pimoroni_pga2040.menu.opt.Debug=Debug (-Og) pimoroni_pga2040.menu.opt.Debug.build.flags.optimize=-Og pimoroni_pga2040.menu.opt.Disabled=Disabled (-O0) pimoroni_pga2040.menu.opt.Disabled.build.flags.optimize=-O0 +pimoroni_pga2040.menu.os.none=None +pimoroni_pga2040.menu.os.none.build.os= +pimoroni_pga2040.menu.os.freertos=FreeRTOS SMP +pimoroni_pga2040.menu.os.freertos.build.os=-D__FREERTOS pimoroni_pga2040.menu.profile.Disabled=Disabled pimoroni_pga2040.menu.profile.Disabled.build.flags.profile= pimoroni_pga2040.menu.profile.Enabled=Enabled @@ -23507,6 +23828,10 @@ pimoroni_pga2350.menu.opt.Debug=Debug (-Og) pimoroni_pga2350.menu.opt.Debug.build.flags.optimize=-Og pimoroni_pga2350.menu.opt.Disabled=Disabled (-O0) pimoroni_pga2350.menu.opt.Disabled.build.flags.optimize=-O0 +pimoroni_pga2350.menu.os.none=None +pimoroni_pga2350.menu.os.none.build.os= +pimoroni_pga2350.menu.os.freertos=FreeRTOS SMP +pimoroni_pga2350.menu.os.freertos.build.os=-D__FREERTOS pimoroni_pga2350.menu.profile.Disabled=Disabled pimoroni_pga2350.menu.profile.Disabled.build.flags.profile= pimoroni_pga2350.menu.profile.Enabled=Enabled @@ -23852,6 +24177,10 @@ pimoroni_pico_plus_2.menu.opt.Debug=Debug (-Og) pimoroni_pico_plus_2.menu.opt.Debug.build.flags.optimize=-Og pimoroni_pico_plus_2.menu.opt.Disabled=Disabled (-O0) pimoroni_pico_plus_2.menu.opt.Disabled.build.flags.optimize=-O0 +pimoroni_pico_plus_2.menu.os.none=None +pimoroni_pico_plus_2.menu.os.none.build.os= +pimoroni_pico_plus_2.menu.os.freertos=FreeRTOS SMP +pimoroni_pico_plus_2.menu.os.freertos.build.os=-D__FREERTOS pimoroni_pico_plus_2.menu.profile.Disabled=Disabled pimoroni_pico_plus_2.menu.profile.Disabled.build.flags.profile= pimoroni_pico_plus_2.menu.profile.Enabled=Enabled @@ -24198,6 +24527,10 @@ pimoroni_pico_plus_2w.menu.opt.Debug=Debug (-Og) pimoroni_pico_plus_2w.menu.opt.Debug.build.flags.optimize=-Og pimoroni_pico_plus_2w.menu.opt.Disabled=Disabled (-O0) pimoroni_pico_plus_2w.menu.opt.Disabled.build.flags.optimize=-O0 +pimoroni_pico_plus_2w.menu.os.none=None +pimoroni_pico_plus_2w.menu.os.none.build.os= +pimoroni_pico_plus_2w.menu.os.freertos=FreeRTOS SMP +pimoroni_pico_plus_2w.menu.os.freertos.build.os=-D__FREERTOS pimoroni_pico_plus_2w.menu.profile.Disabled=Disabled pimoroni_pico_plus_2w.menu.profile.Disabled.build.flags.profile= pimoroni_pico_plus_2w.menu.profile.Enabled=Enabled @@ -24540,6 +24873,10 @@ pimoroni_plasma2040.menu.opt.Debug=Debug (-Og) pimoroni_plasma2040.menu.opt.Debug.build.flags.optimize=-Og pimoroni_plasma2040.menu.opt.Disabled=Disabled (-O0) pimoroni_plasma2040.menu.opt.Disabled.build.flags.optimize=-O0 +pimoroni_plasma2040.menu.os.none=None +pimoroni_plasma2040.menu.os.none.build.os= +pimoroni_plasma2040.menu.os.freertos=FreeRTOS SMP +pimoroni_plasma2040.menu.os.freertos.build.os=-D__FREERTOS pimoroni_plasma2040.menu.profile.Disabled=Disabled pimoroni_plasma2040.menu.profile.Disabled.build.flags.profile= pimoroni_plasma2040.menu.profile.Enabled=Enabled @@ -24787,6 +25124,10 @@ pimoroni_plasma2350.menu.opt.Debug=Debug (-Og) pimoroni_plasma2350.menu.opt.Debug.build.flags.optimize=-Og pimoroni_plasma2350.menu.opt.Disabled=Disabled (-O0) pimoroni_plasma2350.menu.opt.Disabled.build.flags.optimize=-O0 +pimoroni_plasma2350.menu.os.none=None +pimoroni_plasma2350.menu.os.none.build.os= +pimoroni_plasma2350.menu.os.freertos=FreeRTOS SMP +pimoroni_plasma2350.menu.os.freertos.build.os=-D__FREERTOS pimoroni_plasma2350.menu.profile.Disabled=Disabled pimoroni_plasma2350.menu.profile.Disabled.build.flags.profile= pimoroni_plasma2350.menu.profile.Enabled=Enabled @@ -25025,6 +25366,10 @@ pimoroni_servo2040.menu.opt.Debug=Debug (-Og) pimoroni_servo2040.menu.opt.Debug.build.flags.optimize=-Og pimoroni_servo2040.menu.opt.Disabled=Disabled (-O0) pimoroni_servo2040.menu.opt.Disabled.build.flags.optimize=-O0 +pimoroni_servo2040.menu.os.none=None +pimoroni_servo2040.menu.os.none.build.os= +pimoroni_servo2040.menu.os.freertos=FreeRTOS SMP +pimoroni_servo2040.menu.os.freertos.build.os=-D__FREERTOS pimoroni_servo2040.menu.profile.Disabled=Disabled pimoroni_servo2040.menu.profile.Disabled.build.flags.profile= pimoroni_servo2040.menu.profile.Enabled=Enabled @@ -25291,6 +25636,10 @@ pimoroni_tiny2040.menu.opt.Debug=Debug (-Og) pimoroni_tiny2040.menu.opt.Debug.build.flags.optimize=-Og pimoroni_tiny2040.menu.opt.Disabled=Disabled (-O0) pimoroni_tiny2040.menu.opt.Disabled.build.flags.optimize=-O0 +pimoroni_tiny2040.menu.os.none=None +pimoroni_tiny2040.menu.os.none.build.os= +pimoroni_tiny2040.menu.os.freertos=FreeRTOS SMP +pimoroni_tiny2040.menu.os.freertos.build.os=-D__FREERTOS pimoroni_tiny2040.menu.profile.Disabled=Disabled pimoroni_tiny2040.menu.profile.Disabled.build.flags.profile= pimoroni_tiny2040.menu.profile.Enabled=Enabled @@ -25552,6 +25901,10 @@ pimoroni_tiny2350.menu.opt.Debug=Debug (-Og) pimoroni_tiny2350.menu.opt.Debug.build.flags.optimize=-Og pimoroni_tiny2350.menu.opt.Disabled=Disabled (-O0) pimoroni_tiny2350.menu.opt.Disabled.build.flags.optimize=-O0 +pimoroni_tiny2350.menu.os.none=None +pimoroni_tiny2350.menu.os.none.build.os= +pimoroni_tiny2350.menu.os.freertos=FreeRTOS SMP +pimoroni_tiny2350.menu.os.freertos.build.os=-D__FREERTOS pimoroni_tiny2350.menu.profile.Disabled=Disabled pimoroni_tiny2350.menu.profile.Disabled.build.flags.profile= pimoroni_tiny2350.menu.profile.Enabled=Enabled @@ -25780,6 +26133,10 @@ pintronix_pinmax.menu.opt.Debug=Debug (-Og) pintronix_pinmax.menu.opt.Debug.build.flags.optimize=-Og pintronix_pinmax.menu.opt.Disabled=Disabled (-O0) pintronix_pinmax.menu.opt.Disabled.build.flags.optimize=-O0 +pintronix_pinmax.menu.os.none=None +pintronix_pinmax.menu.os.none.build.os= +pintronix_pinmax.menu.os.freertos=FreeRTOS SMP +pintronix_pinmax.menu.os.freertos.build.os=-D__FREERTOS pintronix_pinmax.menu.profile.Disabled=Disabled pintronix_pinmax.menu.profile.Disabled.build.flags.profile= pintronix_pinmax.menu.profile.Enabled=Enabled @@ -26018,6 +26375,10 @@ rakwireless_rak11300.menu.opt.Debug=Debug (-Og) rakwireless_rak11300.menu.opt.Debug.build.flags.optimize=-Og rakwireless_rak11300.menu.opt.Disabled=Disabled (-O0) rakwireless_rak11300.menu.opt.Disabled.build.flags.optimize=-O0 +rakwireless_rak11300.menu.os.none=None +rakwireless_rak11300.menu.os.none.build.os= +rakwireless_rak11300.menu.os.freertos=FreeRTOS SMP +rakwireless_rak11300.menu.os.freertos.build.os=-D__FREERTOS rakwireless_rak11300.menu.profile.Disabled=Disabled rakwireless_rak11300.menu.profile.Disabled.build.flags.profile= rakwireless_rak11300.menu.profile.Enabled=Enabled @@ -26338,6 +26699,10 @@ redscorp_rp2040_eins.menu.opt.Debug=Debug (-Og) redscorp_rp2040_eins.menu.opt.Debug.build.flags.optimize=-Og redscorp_rp2040_eins.menu.opt.Disabled=Disabled (-O0) redscorp_rp2040_eins.menu.opt.Disabled.build.flags.optimize=-O0 +redscorp_rp2040_eins.menu.os.none=None +redscorp_rp2040_eins.menu.os.none.build.os= +redscorp_rp2040_eins.menu.os.freertos=FreeRTOS SMP +redscorp_rp2040_eins.menu.os.freertos.build.os=-D__FREERTOS redscorp_rp2040_eins.menu.profile.Disabled=Disabled redscorp_rp2040_eins.menu.profile.Disabled.build.flags.profile= redscorp_rp2040_eins.menu.profile.Enabled=Enabled @@ -26658,6 +27023,10 @@ redscorp_rp2040_promini.menu.opt.Debug=Debug (-Og) redscorp_rp2040_promini.menu.opt.Debug.build.flags.optimize=-Og redscorp_rp2040_promini.menu.opt.Disabled=Disabled (-O0) redscorp_rp2040_promini.menu.opt.Disabled.build.flags.optimize=-O0 +redscorp_rp2040_promini.menu.os.none=None +redscorp_rp2040_promini.menu.os.none.build.os= +redscorp_rp2040_promini.menu.os.freertos=FreeRTOS SMP +redscorp_rp2040_promini.menu.os.freertos.build.os=-D__FREERTOS redscorp_rp2040_promini.menu.profile.Disabled=Disabled redscorp_rp2040_promini.menu.profile.Disabled.build.flags.profile= redscorp_rp2040_promini.menu.profile.Enabled=Enabled @@ -26914,6 +27283,10 @@ sea_picro.menu.opt.Debug=Debug (-Og) sea_picro.menu.opt.Debug.build.flags.optimize=-Og sea_picro.menu.opt.Disabled=Disabled (-O0) sea_picro.menu.opt.Disabled.build.flags.optimize=-O0 +sea_picro.menu.os.none=None +sea_picro.menu.os.none.build.os= +sea_picro.menu.os.freertos=FreeRTOS SMP +sea_picro.menu.os.freertos.build.os=-D__FREERTOS sea_picro.menu.profile.Disabled=Disabled sea_picro.menu.profile.Disabled.build.flags.profile= sea_picro.menu.profile.Enabled=Enabled @@ -27138,6 +27511,10 @@ silicognition_rp2040_shim.menu.opt.Debug=Debug (-Og) silicognition_rp2040_shim.menu.opt.Debug.build.flags.optimize=-Og silicognition_rp2040_shim.menu.opt.Disabled=Disabled (-O0) silicognition_rp2040_shim.menu.opt.Disabled.build.flags.optimize=-O0 +silicognition_rp2040_shim.menu.os.none=None +silicognition_rp2040_shim.menu.os.none.build.os= +silicognition_rp2040_shim.menu.os.freertos=FreeRTOS SMP +silicognition_rp2040_shim.menu.os.freertos.build.os=-D__FREERTOS silicognition_rp2040_shim.menu.profile.Disabled=Disabled silicognition_rp2040_shim.menu.profile.Disabled.build.flags.profile= silicognition_rp2040_shim.menu.profile.Enabled=Enabled @@ -27394,6 +27771,10 @@ solderparty_rp2040_stamp.menu.opt.Debug=Debug (-Og) solderparty_rp2040_stamp.menu.opt.Debug.build.flags.optimize=-Og solderparty_rp2040_stamp.menu.opt.Disabled=Disabled (-O0) solderparty_rp2040_stamp.menu.opt.Disabled.build.flags.optimize=-O0 +solderparty_rp2040_stamp.menu.os.none=None +solderparty_rp2040_stamp.menu.os.none.build.os= +solderparty_rp2040_stamp.menu.os.freertos=FreeRTOS SMP +solderparty_rp2040_stamp.menu.os.freertos.build.os=-D__FREERTOS solderparty_rp2040_stamp.menu.profile.Disabled=Disabled solderparty_rp2040_stamp.menu.profile.Disabled.build.flags.profile= solderparty_rp2040_stamp.menu.profile.Enabled=Enabled @@ -27715,6 +28096,10 @@ solderparty_rp2350_stamp.menu.opt.Debug=Debug (-Og) solderparty_rp2350_stamp.menu.opt.Debug.build.flags.optimize=-Og solderparty_rp2350_stamp.menu.opt.Disabled=Disabled (-O0) solderparty_rp2350_stamp.menu.opt.Disabled.build.flags.optimize=-O0 +solderparty_rp2350_stamp.menu.os.none=None +solderparty_rp2350_stamp.menu.os.none.build.os= +solderparty_rp2350_stamp.menu.os.freertos=FreeRTOS SMP +solderparty_rp2350_stamp.menu.os.freertos.build.os=-D__FREERTOS solderparty_rp2350_stamp.menu.profile.Disabled=Disabled solderparty_rp2350_stamp.menu.profile.Disabled.build.flags.profile= solderparty_rp2350_stamp.menu.profile.Enabled=Enabled @@ -28036,6 +28421,10 @@ solderparty_rp2350_stamp_xl.menu.opt.Debug=Debug (-Og) solderparty_rp2350_stamp_xl.menu.opt.Debug.build.flags.optimize=-Og solderparty_rp2350_stamp_xl.menu.opt.Disabled=Disabled (-O0) solderparty_rp2350_stamp_xl.menu.opt.Disabled.build.flags.optimize=-O0 +solderparty_rp2350_stamp_xl.menu.os.none=None +solderparty_rp2350_stamp_xl.menu.os.none.build.os= +solderparty_rp2350_stamp_xl.menu.os.freertos=FreeRTOS SMP +solderparty_rp2350_stamp_xl.menu.os.freertos.build.os=-D__FREERTOS solderparty_rp2350_stamp_xl.menu.profile.Disabled=Disabled solderparty_rp2350_stamp_xl.menu.profile.Disabled.build.flags.profile= solderparty_rp2350_stamp_xl.menu.profile.Enabled=Enabled @@ -28382,6 +28771,10 @@ sparkfun_iotredboard_rp2350.menu.opt.Debug=Debug (-Og) sparkfun_iotredboard_rp2350.menu.opt.Debug.build.flags.optimize=-Og sparkfun_iotredboard_rp2350.menu.opt.Disabled=Disabled (-O0) sparkfun_iotredboard_rp2350.menu.opt.Disabled.build.flags.optimize=-O0 +sparkfun_iotredboard_rp2350.menu.os.none=None +sparkfun_iotredboard_rp2350.menu.os.none.build.os= +sparkfun_iotredboard_rp2350.menu.os.freertos=FreeRTOS SMP +sparkfun_iotredboard_rp2350.menu.os.freertos.build.os=-D__FREERTOS sparkfun_iotredboard_rp2350.menu.profile.Disabled=Disabled sparkfun_iotredboard_rp2350.menu.profile.Disabled.build.flags.profile= sparkfun_iotredboard_rp2350.menu.profile.Enabled=Enabled @@ -28718,6 +29111,10 @@ sparkfun_micromodrp2040.menu.opt.Debug=Debug (-Og) sparkfun_micromodrp2040.menu.opt.Debug.build.flags.optimize=-Og sparkfun_micromodrp2040.menu.opt.Disabled=Disabled (-O0) sparkfun_micromodrp2040.menu.opt.Disabled.build.flags.optimize=-O0 +sparkfun_micromodrp2040.menu.os.none=None +sparkfun_micromodrp2040.menu.os.none.build.os= +sparkfun_micromodrp2040.menu.os.freertos=FreeRTOS SMP +sparkfun_micromodrp2040.menu.os.freertos.build.os=-D__FREERTOS sparkfun_micromodrp2040.menu.profile.Disabled=Disabled sparkfun_micromodrp2040.menu.profile.Disabled.build.flags.profile= sparkfun_micromodrp2040.menu.profile.Enabled=Enabled @@ -29054,6 +29451,10 @@ sparkfun_promicrorp2040.menu.opt.Debug=Debug (-Og) sparkfun_promicrorp2040.menu.opt.Debug.build.flags.optimize=-Og sparkfun_promicrorp2040.menu.opt.Disabled=Disabled (-O0) sparkfun_promicrorp2040.menu.opt.Disabled.build.flags.optimize=-O0 +sparkfun_promicrorp2040.menu.os.none=None +sparkfun_promicrorp2040.menu.os.none.build.os= +sparkfun_promicrorp2040.menu.os.freertos=FreeRTOS SMP +sparkfun_promicrorp2040.menu.os.freertos.build.os=-D__FREERTOS sparkfun_promicrorp2040.menu.profile.Disabled=Disabled sparkfun_promicrorp2040.menu.profile.Disabled.build.flags.profile= sparkfun_promicrorp2040.menu.profile.Enabled=Enabled @@ -29399,6 +29800,10 @@ sparkfun_promicrorp2350.menu.opt.Debug=Debug (-Og) sparkfun_promicrorp2350.menu.opt.Debug.build.flags.optimize=-Og sparkfun_promicrorp2350.menu.opt.Disabled=Disabled (-O0) sparkfun_promicrorp2350.menu.opt.Disabled.build.flags.optimize=-O0 +sparkfun_promicrorp2350.menu.os.none=None +sparkfun_promicrorp2350.menu.os.none.build.os= +sparkfun_promicrorp2350.menu.os.freertos=FreeRTOS SMP +sparkfun_promicrorp2350.menu.os.freertos.build.os=-D__FREERTOS sparkfun_promicrorp2350.menu.profile.Disabled=Disabled sparkfun_promicrorp2350.menu.profile.Disabled.build.flags.profile= sparkfun_promicrorp2350.menu.profile.Enabled=Enabled @@ -29735,6 +30140,10 @@ sparkfun_thingplusrp2040.menu.opt.Debug=Debug (-Og) sparkfun_thingplusrp2040.menu.opt.Debug.build.flags.optimize=-Og sparkfun_thingplusrp2040.menu.opt.Disabled=Disabled (-O0) sparkfun_thingplusrp2040.menu.opt.Disabled.build.flags.optimize=-O0 +sparkfun_thingplusrp2040.menu.os.none=None +sparkfun_thingplusrp2040.menu.os.none.build.os= +sparkfun_thingplusrp2040.menu.os.freertos=FreeRTOS SMP +sparkfun_thingplusrp2040.menu.os.freertos.build.os=-D__FREERTOS sparkfun_thingplusrp2040.menu.profile.Disabled=Disabled sparkfun_thingplusrp2040.menu.profile.Disabled.build.flags.profile= sparkfun_thingplusrp2040.menu.profile.Enabled=Enabled @@ -30081,6 +30490,10 @@ sparkfun_thingplusrp2350.menu.opt.Debug=Debug (-Og) sparkfun_thingplusrp2350.menu.opt.Debug.build.flags.optimize=-Og sparkfun_thingplusrp2350.menu.opt.Disabled=Disabled (-O0) sparkfun_thingplusrp2350.menu.opt.Disabled.build.flags.optimize=-O0 +sparkfun_thingplusrp2350.menu.os.none=None +sparkfun_thingplusrp2350.menu.os.none.build.os= +sparkfun_thingplusrp2350.menu.os.freertos=FreeRTOS SMP +sparkfun_thingplusrp2350.menu.os.freertos.build.os=-D__FREERTOS sparkfun_thingplusrp2350.menu.profile.Disabled=Disabled sparkfun_thingplusrp2350.menu.profile.Disabled.build.flags.profile= sparkfun_thingplusrp2350.menu.profile.Enabled=Enabled @@ -30530,6 +30943,10 @@ sparkfun_iotnode_lorawanrp2350.menu.opt.Debug=Debug (-Og) sparkfun_iotnode_lorawanrp2350.menu.opt.Debug.build.flags.optimize=-Og sparkfun_iotnode_lorawanrp2350.menu.opt.Disabled=Disabled (-O0) sparkfun_iotnode_lorawanrp2350.menu.opt.Disabled.build.flags.optimize=-O0 +sparkfun_iotnode_lorawanrp2350.menu.os.none=None +sparkfun_iotnode_lorawanrp2350.menu.os.none.build.os= +sparkfun_iotnode_lorawanrp2350.menu.os.freertos=FreeRTOS SMP +sparkfun_iotnode_lorawanrp2350.menu.os.freertos.build.os=-D__FREERTOS sparkfun_iotnode_lorawanrp2350.menu.profile.Disabled=Disabled sparkfun_iotnode_lorawanrp2350.menu.profile.Disabled.build.flags.profile= sparkfun_iotnode_lorawanrp2350.menu.profile.Enabled=Enabled @@ -30769,6 +31186,10 @@ sparkfun_xrp_controller_beta.menu.opt.Debug=Debug (-Og) sparkfun_xrp_controller_beta.menu.opt.Debug.build.flags.optimize=-Og sparkfun_xrp_controller_beta.menu.opt.Disabled=Disabled (-O0) sparkfun_xrp_controller_beta.menu.opt.Disabled.build.flags.optimize=-O0 +sparkfun_xrp_controller_beta.menu.os.none=None +sparkfun_xrp_controller_beta.menu.os.none.build.os= +sparkfun_xrp_controller_beta.menu.os.freertos=FreeRTOS SMP +sparkfun_xrp_controller_beta.menu.os.freertos.build.os=-D__FREERTOS sparkfun_xrp_controller_beta.menu.profile.Disabled=Disabled sparkfun_xrp_controller_beta.menu.profile.Disabled.build.flags.profile= sparkfun_xrp_controller_beta.menu.profile.Enabled=Enabled @@ -31115,6 +31536,10 @@ sparkfun_xrp_controller.menu.opt.Debug=Debug (-Og) sparkfun_xrp_controller.menu.opt.Debug.build.flags.optimize=-Og sparkfun_xrp_controller.menu.opt.Disabled=Disabled (-O0) sparkfun_xrp_controller.menu.opt.Disabled.build.flags.optimize=-O0 +sparkfun_xrp_controller.menu.os.none=None +sparkfun_xrp_controller.menu.os.none.build.os= +sparkfun_xrp_controller.menu.os.freertos=FreeRTOS SMP +sparkfun_xrp_controller.menu.os.freertos.build.os=-D__FREERTOS sparkfun_xrp_controller.menu.profile.Disabled=Disabled sparkfun_xrp_controller.menu.profile.Disabled.build.flags.profile= sparkfun_xrp_controller.menu.profile.Enabled=Enabled @@ -31353,6 +31778,10 @@ seeed_indicator_rp2040.menu.opt.Debug=Debug (-Og) seeed_indicator_rp2040.menu.opt.Debug.build.flags.optimize=-Og seeed_indicator_rp2040.menu.opt.Disabled=Disabled (-O0) seeed_indicator_rp2040.menu.opt.Disabled.build.flags.optimize=-O0 +seeed_indicator_rp2040.menu.os.none=None +seeed_indicator_rp2040.menu.os.none.build.os= +seeed_indicator_rp2040.menu.os.freertos=FreeRTOS SMP +seeed_indicator_rp2040.menu.os.freertos.build.os=-D__FREERTOS seeed_indicator_rp2040.menu.profile.Disabled=Disabled seeed_indicator_rp2040.menu.profile.Disabled.build.flags.profile= seeed_indicator_rp2040.menu.profile.Enabled=Enabled @@ -31591,6 +32020,10 @@ seeed_xiao_rp2040.menu.opt.Debug=Debug (-Og) seeed_xiao_rp2040.menu.opt.Debug.build.flags.optimize=-Og seeed_xiao_rp2040.menu.opt.Disabled=Disabled (-O0) seeed_xiao_rp2040.menu.opt.Disabled.build.flags.optimize=-O0 +seeed_xiao_rp2040.menu.os.none=None +seeed_xiao_rp2040.menu.os.none.build.os= +seeed_xiao_rp2040.menu.os.freertos=FreeRTOS SMP +seeed_xiao_rp2040.menu.os.freertos.build.os=-D__FREERTOS seeed_xiao_rp2040.menu.profile.Disabled=Disabled seeed_xiao_rp2040.menu.profile.Disabled.build.flags.profile= seeed_xiao_rp2040.menu.profile.Enabled=Enabled @@ -31838,6 +32271,10 @@ seeed_xiao_rp2350.menu.opt.Debug=Debug (-Og) seeed_xiao_rp2350.menu.opt.Debug.build.flags.optimize=-Og seeed_xiao_rp2350.menu.opt.Disabled=Disabled (-O0) seeed_xiao_rp2350.menu.opt.Disabled.build.flags.optimize=-O0 +seeed_xiao_rp2350.menu.os.none=None +seeed_xiao_rp2350.menu.os.none.build.os= +seeed_xiao_rp2350.menu.os.freertos=FreeRTOS SMP +seeed_xiao_rp2350.menu.os.freertos.build.os=-D__FREERTOS seeed_xiao_rp2350.menu.profile.Disabled=Disabled seeed_xiao_rp2350.menu.profile.Disabled.build.flags.profile= seeed_xiao_rp2350.menu.profile.Enabled=Enabled @@ -32076,6 +32513,10 @@ upesy_rp2040_devkit.menu.opt.Debug=Debug (-Og) upesy_rp2040_devkit.menu.opt.Debug.build.flags.optimize=-Og upesy_rp2040_devkit.menu.opt.Disabled=Disabled (-O0) upesy_rp2040_devkit.menu.opt.Disabled.build.flags.optimize=-O0 +upesy_rp2040_devkit.menu.os.none=None +upesy_rp2040_devkit.menu.os.none.build.os= +upesy_rp2040_devkit.menu.os.freertos=FreeRTOS SMP +upesy_rp2040_devkit.menu.os.freertos.build.os=-D__FREERTOS upesy_rp2040_devkit.menu.profile.Disabled=Disabled upesy_rp2040_devkit.menu.profile.Disabled.build.flags.profile= upesy_rp2040_devkit.menu.profile.Enabled=Enabled @@ -32396,6 +32837,10 @@ vccgnd_yd_rp2040.menu.opt.Debug=Debug (-Og) vccgnd_yd_rp2040.menu.opt.Debug.build.flags.optimize=-Og vccgnd_yd_rp2040.menu.opt.Disabled=Disabled (-O0) vccgnd_yd_rp2040.menu.opt.Disabled.build.flags.optimize=-O0 +vccgnd_yd_rp2040.menu.os.none=None +vccgnd_yd_rp2040.menu.os.none.build.os= +vccgnd_yd_rp2040.menu.os.freertos=FreeRTOS SMP +vccgnd_yd_rp2040.menu.os.freertos.build.os=-D__FREERTOS vccgnd_yd_rp2040.menu.profile.Disabled=Disabled vccgnd_yd_rp2040.menu.profile.Disabled.build.flags.profile= vccgnd_yd_rp2040.menu.profile.Enabled=Enabled @@ -32676,6 +33121,10 @@ viyalab_mizu.menu.opt.Debug=Debug (-Og) viyalab_mizu.menu.opt.Debug.build.flags.optimize=-Og viyalab_mizu.menu.opt.Disabled=Disabled (-O0) viyalab_mizu.menu.opt.Disabled.build.flags.optimize=-O0 +viyalab_mizu.menu.os.none=None +viyalab_mizu.menu.os.none.build.os= +viyalab_mizu.menu.os.freertos=FreeRTOS SMP +viyalab_mizu.menu.os.freertos.build.os=-D__FREERTOS viyalab_mizu.menu.profile.Disabled=Disabled viyalab_mizu.menu.profile.Disabled.build.flags.profile= viyalab_mizu.menu.profile.Enabled=Enabled @@ -32914,6 +33363,10 @@ waveshare_rp2040_zero.menu.opt.Debug=Debug (-Og) waveshare_rp2040_zero.menu.opt.Debug.build.flags.optimize=-Og waveshare_rp2040_zero.menu.opt.Disabled=Disabled (-O0) waveshare_rp2040_zero.menu.opt.Disabled.build.flags.optimize=-O0 +waveshare_rp2040_zero.menu.os.none=None +waveshare_rp2040_zero.menu.os.none.build.os= +waveshare_rp2040_zero.menu.os.freertos=FreeRTOS SMP +waveshare_rp2040_zero.menu.os.freertos.build.os=-D__FREERTOS waveshare_rp2040_zero.menu.profile.Disabled=Disabled waveshare_rp2040_zero.menu.profile.Disabled.build.flags.profile= waveshare_rp2040_zero.menu.profile.Enabled=Enabled @@ -33166,6 +33619,10 @@ waveshare_rp2040_one.menu.opt.Debug=Debug (-Og) waveshare_rp2040_one.menu.opt.Debug.build.flags.optimize=-Og waveshare_rp2040_one.menu.opt.Disabled=Disabled (-O0) waveshare_rp2040_one.menu.opt.Disabled.build.flags.optimize=-O0 +waveshare_rp2040_one.menu.os.none=None +waveshare_rp2040_one.menu.os.none.build.os= +waveshare_rp2040_one.menu.os.freertos=FreeRTOS SMP +waveshare_rp2040_one.menu.os.freertos.build.os=-D__FREERTOS waveshare_rp2040_one.menu.profile.Disabled=Disabled waveshare_rp2040_one.menu.profile.Disabled.build.flags.profile= waveshare_rp2040_one.menu.profile.Enabled=Enabled @@ -33404,6 +33861,10 @@ waveshare_rp2040_matrix.menu.opt.Debug=Debug (-Og) waveshare_rp2040_matrix.menu.opt.Debug.build.flags.optimize=-Og waveshare_rp2040_matrix.menu.opt.Disabled=Disabled (-O0) waveshare_rp2040_matrix.menu.opt.Disabled.build.flags.optimize=-O0 +waveshare_rp2040_matrix.menu.os.none=None +waveshare_rp2040_matrix.menu.os.none.build.os= +waveshare_rp2040_matrix.menu.os.freertos=FreeRTOS SMP +waveshare_rp2040_matrix.menu.os.freertos.build.os=-D__FREERTOS waveshare_rp2040_matrix.menu.profile.Disabled=Disabled waveshare_rp2040_matrix.menu.profile.Disabled.build.flags.profile= waveshare_rp2040_matrix.menu.profile.Enabled=Enabled @@ -33740,6 +34201,10 @@ waveshare_rp2040_pizero.menu.opt.Debug=Debug (-Og) waveshare_rp2040_pizero.menu.opt.Debug.build.flags.optimize=-Og waveshare_rp2040_pizero.menu.opt.Disabled=Disabled (-O0) waveshare_rp2040_pizero.menu.opt.Disabled.build.flags.optimize=-O0 +waveshare_rp2040_pizero.menu.os.none=None +waveshare_rp2040_pizero.menu.os.none.build.os= +waveshare_rp2040_pizero.menu.os.freertos=FreeRTOS SMP +waveshare_rp2040_pizero.menu.os.freertos.build.os=-D__FREERTOS waveshare_rp2040_pizero.menu.profile.Disabled=Disabled waveshare_rp2040_pizero.menu.profile.Disabled.build.flags.profile= waveshare_rp2040_pizero.menu.profile.Enabled=Enabled @@ -34041,6 +34506,10 @@ waveshare_rp2040_plus.menu.opt.Debug=Debug (-Og) waveshare_rp2040_plus.menu.opt.Debug.build.flags.optimize=-Og waveshare_rp2040_plus.menu.opt.Disabled=Disabled (-O0) waveshare_rp2040_plus.menu.opt.Disabled.build.flags.optimize=-O0 +waveshare_rp2040_plus.menu.os.none=None +waveshare_rp2040_plus.menu.os.none.build.os= +waveshare_rp2040_plus.menu.os.freertos=FreeRTOS SMP +waveshare_rp2040_plus.menu.os.freertos.build.os=-D__FREERTOS waveshare_rp2040_plus.menu.profile.Disabled=Disabled waveshare_rp2040_plus.menu.profile.Disabled.build.flags.profile= waveshare_rp2040_plus.menu.profile.Enabled=Enabled @@ -34279,6 +34748,10 @@ waveshare_rp2040_lcd_0_96.menu.opt.Debug=Debug (-Og) waveshare_rp2040_lcd_0_96.menu.opt.Debug.build.flags.optimize=-Og waveshare_rp2040_lcd_0_96.menu.opt.Disabled=Disabled (-O0) waveshare_rp2040_lcd_0_96.menu.opt.Disabled.build.flags.optimize=-O0 +waveshare_rp2040_lcd_0_96.menu.os.none=None +waveshare_rp2040_lcd_0_96.menu.os.none.build.os= +waveshare_rp2040_lcd_0_96.menu.os.freertos=FreeRTOS SMP +waveshare_rp2040_lcd_0_96.menu.os.freertos.build.os=-D__FREERTOS waveshare_rp2040_lcd_0_96.menu.profile.Disabled=Disabled waveshare_rp2040_lcd_0_96.menu.profile.Disabled.build.flags.profile= waveshare_rp2040_lcd_0_96.menu.profile.Enabled=Enabled @@ -34517,6 +34990,10 @@ waveshare_rp2040_lcd_1_28.menu.opt.Debug=Debug (-Og) waveshare_rp2040_lcd_1_28.menu.opt.Debug.build.flags.optimize=-Og waveshare_rp2040_lcd_1_28.menu.opt.Disabled=Disabled (-O0) waveshare_rp2040_lcd_1_28.menu.opt.Disabled.build.flags.optimize=-O0 +waveshare_rp2040_lcd_1_28.menu.os.none=None +waveshare_rp2040_lcd_1_28.menu.os.none.build.os= +waveshare_rp2040_lcd_1_28.menu.os.freertos=FreeRTOS SMP +waveshare_rp2040_lcd_1_28.menu.os.freertos.build.os=-D__FREERTOS waveshare_rp2040_lcd_1_28.menu.profile.Disabled=Disabled waveshare_rp2040_lcd_1_28.menu.profile.Disabled.build.flags.profile= waveshare_rp2040_lcd_1_28.menu.profile.Enabled=Enabled @@ -34778,6 +35255,10 @@ waveshare_rp2350_zero.menu.opt.Debug=Debug (-Og) waveshare_rp2350_zero.menu.opt.Debug.build.flags.optimize=-Og waveshare_rp2350_zero.menu.opt.Disabled=Disabled (-O0) waveshare_rp2350_zero.menu.opt.Disabled.build.flags.optimize=-O0 +waveshare_rp2350_zero.menu.os.none=None +waveshare_rp2350_zero.menu.os.none.build.os= +waveshare_rp2350_zero.menu.os.freertos=FreeRTOS SMP +waveshare_rp2350_zero.menu.os.freertos.build.os=-D__FREERTOS waveshare_rp2350_zero.menu.profile.Disabled=Disabled waveshare_rp2350_zero.menu.profile.Disabled.build.flags.profile= waveshare_rp2350_zero.menu.profile.Enabled=Enabled @@ -35088,6 +35569,10 @@ waveshare_rp2350_plus.menu.opt.Debug=Debug (-Og) waveshare_rp2350_plus.menu.opt.Debug.build.flags.optimize=-Og waveshare_rp2350_plus.menu.opt.Disabled=Disabled (-O0) waveshare_rp2350_plus.menu.opt.Disabled.build.flags.optimize=-O0 +waveshare_rp2350_plus.menu.os.none=None +waveshare_rp2350_plus.menu.os.none.build.os= +waveshare_rp2350_plus.menu.os.freertos=FreeRTOS SMP +waveshare_rp2350_plus.menu.os.freertos.build.os=-D__FREERTOS waveshare_rp2350_plus.menu.profile.Disabled=Disabled waveshare_rp2350_plus.menu.profile.Disabled.build.flags.profile= waveshare_rp2350_plus.menu.profile.Enabled=Enabled @@ -35349,6 +35834,10 @@ waveshare_rp2350_lcd_0_96.menu.opt.Debug=Debug (-Og) waveshare_rp2350_lcd_0_96.menu.opt.Debug.build.flags.optimize=-Og waveshare_rp2350_lcd_0_96.menu.opt.Disabled=Disabled (-O0) waveshare_rp2350_lcd_0_96.menu.opt.Disabled.build.flags.optimize=-O0 +waveshare_rp2350_lcd_0_96.menu.os.none=None +waveshare_rp2350_lcd_0_96.menu.os.none.build.os= +waveshare_rp2350_lcd_0_96.menu.os.freertos=FreeRTOS SMP +waveshare_rp2350_lcd_0_96.menu.os.freertos.build.os=-D__FREERTOS waveshare_rp2350_lcd_0_96.menu.profile.Disabled=Disabled waveshare_rp2350_lcd_0_96.menu.profile.Disabled.build.flags.profile= waveshare_rp2350_lcd_0_96.menu.profile.Enabled=Enabled @@ -35587,6 +36076,10 @@ wiznet_5100s_evb_pico.menu.opt.Debug=Debug (-Og) wiznet_5100s_evb_pico.menu.opt.Debug.build.flags.optimize=-Og wiznet_5100s_evb_pico.menu.opt.Disabled=Disabled (-O0) wiznet_5100s_evb_pico.menu.opt.Disabled.build.flags.optimize=-O0 +wiznet_5100s_evb_pico.menu.os.none=None +wiznet_5100s_evb_pico.menu.os.none.build.os= +wiznet_5100s_evb_pico.menu.os.freertos=FreeRTOS SMP +wiznet_5100s_evb_pico.menu.os.freertos.build.os=-D__FREERTOS wiznet_5100s_evb_pico.menu.profile.Disabled=Disabled wiznet_5100s_evb_pico.menu.profile.Disabled.build.flags.profile= wiznet_5100s_evb_pico.menu.profile.Enabled=Enabled @@ -35834,6 +36327,10 @@ wiznet_5100s_evb_pico2.menu.opt.Debug=Debug (-Og) wiznet_5100s_evb_pico2.menu.opt.Debug.build.flags.optimize=-Og wiznet_5100s_evb_pico2.menu.opt.Disabled=Disabled (-O0) wiznet_5100s_evb_pico2.menu.opt.Disabled.build.flags.optimize=-O0 +wiznet_5100s_evb_pico2.menu.os.none=None +wiznet_5100s_evb_pico2.menu.os.none.build.os= +wiznet_5100s_evb_pico2.menu.os.freertos=FreeRTOS SMP +wiznet_5100s_evb_pico2.menu.os.freertos.build.os=-D__FREERTOS wiznet_5100s_evb_pico2.menu.profile.Disabled=Disabled wiznet_5100s_evb_pico2.menu.profile.Disabled.build.flags.profile= wiznet_5100s_evb_pico2.menu.profile.Enabled=Enabled @@ -36072,6 +36569,10 @@ wiznet_wizfi360_evb_pico.menu.opt.Debug=Debug (-Og) wiznet_wizfi360_evb_pico.menu.opt.Debug.build.flags.optimize=-Og wiznet_wizfi360_evb_pico.menu.opt.Disabled=Disabled (-O0) wiznet_wizfi360_evb_pico.menu.opt.Disabled.build.flags.optimize=-O0 +wiznet_wizfi360_evb_pico.menu.os.none=None +wiznet_wizfi360_evb_pico.menu.os.none.build.os= +wiznet_wizfi360_evb_pico.menu.os.freertos=FreeRTOS SMP +wiznet_wizfi360_evb_pico.menu.os.freertos.build.os=-D__FREERTOS wiznet_wizfi360_evb_pico.menu.profile.Disabled=Disabled wiznet_wizfi360_evb_pico.menu.profile.Disabled.build.flags.profile= wiznet_wizfi360_evb_pico.menu.profile.Enabled=Enabled @@ -36310,6 +36811,10 @@ wiznet_5500_evb_pico.menu.opt.Debug=Debug (-Og) wiznet_5500_evb_pico.menu.opt.Debug.build.flags.optimize=-Og wiznet_5500_evb_pico.menu.opt.Disabled=Disabled (-O0) wiznet_5500_evb_pico.menu.opt.Disabled.build.flags.optimize=-O0 +wiznet_5500_evb_pico.menu.os.none=None +wiznet_5500_evb_pico.menu.os.none.build.os= +wiznet_5500_evb_pico.menu.os.freertos=FreeRTOS SMP +wiznet_5500_evb_pico.menu.os.freertos.build.os=-D__FREERTOS wiznet_5500_evb_pico.menu.profile.Disabled=Disabled wiznet_5500_evb_pico.menu.profile.Disabled.build.flags.profile= wiznet_5500_evb_pico.menu.profile.Enabled=Enabled @@ -36557,6 +37062,10 @@ wiznet_5500_evb_pico2.menu.opt.Debug=Debug (-Og) wiznet_5500_evb_pico2.menu.opt.Debug.build.flags.optimize=-Og wiznet_5500_evb_pico2.menu.opt.Disabled=Disabled (-O0) wiznet_5500_evb_pico2.menu.opt.Disabled.build.flags.optimize=-O0 +wiznet_5500_evb_pico2.menu.os.none=None +wiznet_5500_evb_pico2.menu.os.none.build.os= +wiznet_5500_evb_pico2.menu.os.freertos=FreeRTOS SMP +wiznet_5500_evb_pico2.menu.os.freertos.build.os=-D__FREERTOS wiznet_5500_evb_pico2.menu.profile.Disabled=Disabled wiznet_5500_evb_pico2.menu.profile.Disabled.build.flags.profile= wiznet_5500_evb_pico2.menu.profile.Enabled=Enabled @@ -36795,6 +37304,10 @@ wiznet_55rp20_evb_pico.menu.opt.Debug=Debug (-Og) wiznet_55rp20_evb_pico.menu.opt.Debug.build.flags.optimize=-Og wiznet_55rp20_evb_pico.menu.opt.Disabled=Disabled (-O0) wiznet_55rp20_evb_pico.menu.opt.Disabled.build.flags.optimize=-O0 +wiznet_55rp20_evb_pico.menu.os.none=None +wiznet_55rp20_evb_pico.menu.os.none.build.os= +wiznet_55rp20_evb_pico.menu.os.freertos=FreeRTOS SMP +wiznet_55rp20_evb_pico.menu.os.freertos.build.os=-D__FREERTOS wiznet_55rp20_evb_pico.menu.profile.Disabled=Disabled wiznet_55rp20_evb_pico.menu.profile.Disabled.build.flags.profile= wiznet_55rp20_evb_pico.menu.profile.Enabled=Enabled @@ -37033,6 +37546,10 @@ wiznet_6300_evb_pico.menu.opt.Debug=Debug (-Og) wiznet_6300_evb_pico.menu.opt.Debug.build.flags.optimize=-Og wiznet_6300_evb_pico.menu.opt.Disabled=Disabled (-O0) wiznet_6300_evb_pico.menu.opt.Disabled.build.flags.optimize=-O0 +wiznet_6300_evb_pico.menu.os.none=None +wiznet_6300_evb_pico.menu.os.none.build.os= +wiznet_6300_evb_pico.menu.os.freertos=FreeRTOS SMP +wiznet_6300_evb_pico.menu.os.freertos.build.os=-D__FREERTOS wiznet_6300_evb_pico.menu.profile.Disabled=Disabled wiznet_6300_evb_pico.menu.profile.Disabled.build.flags.profile= wiznet_6300_evb_pico.menu.profile.Enabled=Enabled @@ -37280,6 +37797,10 @@ wiznet_6300_evb_pico2.menu.opt.Debug=Debug (-Og) wiznet_6300_evb_pico2.menu.opt.Debug.build.flags.optimize=-Og wiznet_6300_evb_pico2.menu.opt.Disabled=Disabled (-O0) wiznet_6300_evb_pico2.menu.opt.Disabled.build.flags.optimize=-O0 +wiznet_6300_evb_pico2.menu.os.none=None +wiznet_6300_evb_pico2.menu.os.none.build.os= +wiznet_6300_evb_pico2.menu.os.freertos=FreeRTOS SMP +wiznet_6300_evb_pico2.menu.os.freertos.build.os=-D__FREERTOS wiznet_6300_evb_pico2.menu.profile.Disabled=Disabled wiznet_6300_evb_pico2.menu.profile.Disabled.build.flags.profile= wiznet_6300_evb_pico2.menu.profile.Enabled=Enabled @@ -37592,6 +38113,10 @@ generic.menu.opt.Debug=Debug (-Og) generic.menu.opt.Debug.build.flags.optimize=-Og generic.menu.opt.Disabled=Disabled (-O0) generic.menu.opt.Disabled.build.flags.optimize=-O0 +generic.menu.os.none=None +generic.menu.os.none.build.os= +generic.menu.os.freertos=FreeRTOS SMP +generic.menu.os.freertos.build.os=-D__FREERTOS generic.menu.profile.Disabled=Disabled generic.menu.profile.Disabled.build.flags.profile= generic.menu.profile.Enabled=Enabled @@ -38048,6 +38573,10 @@ generic_rp2350.menu.opt.Debug=Debug (-Og) generic_rp2350.menu.opt.Debug.build.flags.optimize=-Og generic_rp2350.menu.opt.Disabled=Disabled (-O0) generic_rp2350.menu.opt.Disabled.build.flags.optimize=-O0 +generic_rp2350.menu.os.none=None +generic_rp2350.menu.os.none.build.os= +generic_rp2350.menu.os.freertos=FreeRTOS SMP +generic_rp2350.menu.os.freertos.build.os=-D__FREERTOS generic_rp2350.menu.profile.Disabled=Disabled generic_rp2350.menu.profile.Disabled.build.flags.profile= generic_rp2350.menu.profile.Enabled=Enabled diff --git a/cores/rp2040/Arduino.h b/cores/rp2040/Arduino.h index 515caf7f4..494731c4f 100644 --- a/cores/rp2040/Arduino.h +++ b/cores/rp2040/Arduino.h @@ -109,9 +109,6 @@ void analogWriteResolution(int res); } // extern "C" #endif -// FreeRTOS potential calls -extern bool __isFreeRTOS; - // Ancient AVR defines #define HAVE_HWSERIAL0 #define HAVE_HWSERIAL1 diff --git a/cores/rp2040/Bootsel.cpp b/cores/rp2040/Bootsel.cpp index 31bfa5829..b1a2fd3de 100644 --- a/cores/rp2040/Bootsel.cpp +++ b/cores/rp2040/Bootsel.cpp @@ -26,9 +26,9 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() { // Must disable interrupts, as interrupt handlers may be in flash, and we // are about to temporarily disable flash access! - if (!__isFreeRTOS) { - noInterrupts(); - } +#ifndef __FREERTOS + noInterrupts(); +#endif rp2040.idleOtherCore(); // Set chip select to Hi-Z @@ -55,9 +55,9 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() { IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS); rp2040.resumeOtherCore(); - if (!__isFreeRTOS) { - interrupts(); - } +#ifndef __FREERTOS + interrupts(); +#endif return button_state; } diff --git a/cores/rp2040/CoreMutex.cpp b/cores/rp2040/CoreMutex.cpp index 42af54ea8..334df81f6 100644 --- a/cores/rp2040/CoreMutex.cpp +++ b/cores/rp2040/CoreMutex.cpp @@ -28,45 +28,45 @@ CoreMutex::CoreMutex(mutex_t *mutex, uint8_t option) { _mutex = mutex; _acquired = false; _option = option; +#ifdef __FREERTOS _pxHigherPriorityTaskWoken = 0; // pdFALSE - if (__isFreeRTOS) { - auto m = __get_freertos_mutex_for_ptr(mutex); + auto m = __get_freertos_mutex_for_ptr(mutex); - if (__freertos_check_if_in_isr()) { - if (!__freertos_mutex_take_from_isr(m, &_pxHigherPriorityTaskWoken)) { - return; - } - // At this point we have the mutex in ISR - } else { - // Grab the mutex normally, possibly waking other tasks to get it - __freertos_mutex_take(m); + if (__freertos_check_if_in_isr()) { + if (!__freertos_mutex_take_from_isr(m, &_pxHigherPriorityTaskWoken)) { + return; } + // At this point we have the mutex in ISR } else { - uint32_t owner; - if (!mutex_try_enter(_mutex, &owner)) { - if (owner == get_core_num()) { // Deadlock! - if (_option & DebugEnable) { - DEBUGCORE("CoreMutex - Deadlock detected!\n"); - } - return; + // Grab the mutex normally, possibly waking other tasks to get it + __freertos_mutex_take(m); + } +#else + uint32_t owner; + if (!mutex_try_enter(_mutex, &owner)) { + if (owner == get_core_num()) { // Deadlock! + if (_option & DebugEnable) { + DEBUGCORE("CoreMutex - Deadlock detected!\n"); } - mutex_enter_blocking(_mutex); + return; } + mutex_enter_blocking(_mutex); } +#endif _acquired = true; } CoreMutex::~CoreMutex() { if (_acquired) { - if (__isFreeRTOS) { - auto m = __get_freertos_mutex_for_ptr(_mutex); - if (__freertos_check_if_in_isr()) { - __freertos_mutex_give_from_isr(m, &_pxHigherPriorityTaskWoken); - } else { - __freertos_mutex_give(m); - } +#ifdef __FREERTOS + auto m = __get_freertos_mutex_for_ptr(_mutex); + if (__freertos_check_if_in_isr()) { + __freertos_mutex_give_from_isr(m, &_pxHigherPriorityTaskWoken); } else { - mutex_exit(_mutex); + __freertos_mutex_give(m); } +#else + mutex_exit(_mutex); +#endif } } diff --git a/cores/rp2040/CoreMutex.h b/cores/rp2040/CoreMutex.h index c49edcc6b..9750d618f 100644 --- a/cores/rp2040/CoreMutex.h +++ b/cores/rp2040/CoreMutex.h @@ -43,5 +43,7 @@ class CoreMutex { mutex_t *_mutex; bool _acquired; uint8_t _option; +#ifdef __FREERTOS BaseType_t _pxHigherPriorityTaskWoken; +#endif }; diff --git a/cores/rp2040/RP2040Support.h b/cores/rp2040/RP2040Support.h index e2c49e24b..650a41392 100644 --- a/cores/rp2040/RP2040Support.h +++ b/cores/rp2040/RP2040Support.h @@ -72,17 +72,18 @@ class _MFIFO { } void registerCore() { - if (!__isFreeRTOS) { - multicore_fifo_clear_irq(); +#ifndef __FREERTOS + multicore_fifo_clear_irq(); #ifdef PICO_RP2350 - irq_set_exclusive_handler(SIO_IRQ_FIFO, _irq); - irq_set_enabled(SIO_IRQ_FIFO, true); + irq_set_exclusive_handler(SIO_IRQ_FIFO, _irq); + irq_set_enabled(SIO_IRQ_FIFO, true); #else - irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq); - irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true); + irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq); + irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true); #endif - } +#else // FreeRTOS port.c will handle the IRQ hooking +#endif } void push(uint32_t val) { @@ -113,14 +114,14 @@ class _MFIFO { if (!_multicore) { return; } - if (__isFreeRTOS) { - __freertos_idle_other_core(); - } else { - mutex_enter_blocking(&_idleMutex); - __otherCoreIdled = false; - multicore_fifo_push_blocking(_GOTOSLEEP); - while (!__otherCoreIdled) { /* noop */ } - } +#ifdef __FREERTOS + __freertos_idle_other_core(); +#else + mutex_enter_blocking(&_idleMutex); + __otherCoreIdled = false; + multicore_fifo_push_blocking(_GOTOSLEEP); + while (!__otherCoreIdled) { /* noop */ } +#endif } void resumeOtherCore() { @@ -129,9 +130,9 @@ class _MFIFO { } mutex_exit(&_idleMutex); __otherCoreIdled = false; - if (__isFreeRTOS) { - __freertos_resume_other_core(); - } +#ifdef __FREERTOS + __freertos_resume_other_core(); +#endif // Other core will exit busy-loop and return to operation // once __otherCoreIdled == false. @@ -151,18 +152,18 @@ class _MFIFO { private: static void __no_inline_not_in_flash_func(_irq)() { - if (!__isFreeRTOS) { - multicore_fifo_clear_irq(); - noInterrupts(); // We need total control, can't run anything - while (multicore_fifo_rvalid()) { - if (_GOTOSLEEP == multicore_fifo_pop_blocking()) { - __otherCoreIdled = true; - while (__otherCoreIdled) { /* noop */ } - break; - } +#ifndef __FREERTOS + multicore_fifo_clear_irq(); + noInterrupts(); // We need total control, can't run anything + while (multicore_fifo_rvalid()) { + if (_GOTOSLEEP == multicore_fifo_pop_blocking()) { + __otherCoreIdled = true; + while (__otherCoreIdled) { /* noop */ } + break; } - interrupts(); } + interrupts(); +#endif } bool _multicore = false; @@ -192,23 +193,19 @@ class RP2040 { void begin(int cpuid) { _epoch[cpuid] = 0; -#if !defined(__riscv) && !defined(__PROFILE) - if (!__isFreeRTOS) { - // Enable SYSTICK exception - exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler); - systick_hw->csr = 0x7; - systick_hw->rvr = 0x00FFFFFF; - } else { -#endif - // Only start 1 instance of the PIO SM - if (cpuid == 0) { - int off = 0; - _ccountPgm = new PIOProgram(&ccount_program); - _ccountPgm->prepare(&_pio, &_sm, &off); - ccount_program_init(_pio, _sm, off); - pio_sm_set_enabled(_pio, _sm, true); - } -#if !defined(__riscv) && !defined(__PROFILE) +#if !defined(__riscv) && !defined(__PROFILE) && !defined(__FREERTOS) + // Enable SYSTICK exception + exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler); + systick_hw->csr = 0x7; + systick_hw->rvr = 0x00FFFFFF; +#else + // Only start 1 instance of the PIO SM + if (cpuid == 0) { + int off = 0; + _ccountPgm = new PIOProgram(&ccount_program); + _ccountPgm->prepare(&_pio, &_sm, &off); + ccount_program_init(_pio, _sm, off); + pio_sm_set_enabled(_pio, _sm, true); } #endif } @@ -255,21 +252,17 @@ class RP2040 { @returns CPU clock cycles since power up */ inline uint32_t getCycleCount() { -#if !defined(__riscv) && !defined(__PROFILE) +#if !defined(__riscv) && !defined(__PROFILE) && !defined(__FREERTOS) // Get CPU cycle count. Needs to do magic to extend 24b HW to something longer - if (!__isFreeRTOS) { - uint32_t epoch; - uint32_t ctr; - do { - epoch = (uint32_t)_epoch[sio_hw->cpuid]; - ctr = systick_hw->cvr; - } while (epoch != (uint32_t)_epoch[sio_hw->cpuid]); - return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */ - } else { -#endif - return ccount_read(_pio, _sm); -#if !defined(__riscv) && !defined(__PROFILE) - } + uint32_t epoch; + uint32_t ctr; + do { + epoch = (uint32_t)_epoch[sio_hw->cpuid]; + ctr = systick_hw->cvr; + } while (epoch != (uint32_t)_epoch[sio_hw->cpuid]); + return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */ +#else + return ccount_read(_pio, _sm); #endif } /** @@ -278,20 +271,16 @@ class RP2040 { @returns CPU clock cycles since power up */ inline uint64_t getCycleCount64() { -#if !defined(__riscv) && !defined(__PROFILE) - if (!__isFreeRTOS) { - uint64_t epoch; - uint64_t ctr; - do { - epoch = _epoch[sio_hw->cpuid]; - ctr = systick_hw->cvr; - } while (epoch != _epoch[sio_hw->cpuid]); - return epoch + (1LL << 24) - ctr; - } else { -#endif - return ccount_read(_pio, _sm); -#if !defined(__riscv) && !defined(__PROFILE) - } +#if !defined(__riscv) && !defined(__PROFILE) && !defined(__FREERTOS) + uint64_t epoch; + uint64_t ctr; + do { + epoch = _epoch[sio_hw->cpuid]; + ctr = systick_hw->cvr; + } while (epoch != _epoch[sio_hw->cpuid]); + return epoch + (1LL << 24) - ctr; +#else + return ccount_read(_pio, _sm); #endif } diff --git a/cores/rp2040/SerialUSB.cpp b/cores/rp2040/SerialUSB.cpp index 719116040..5741730b8 100644 --- a/cores/rp2040/SerialUSB.cpp +++ b/cores/rp2040/SerialUSB.cpp @@ -181,9 +181,9 @@ static int _bps = 115200; static bool _rebooting = false; static void CheckSerialReset() { if (!_rebooting && (_bps == 1200) && (!_dtr)) { - if (__isFreeRTOS) { - __freertos_idle_other_core(); - } +#ifdef __FREERTOS + __freertos_idle_other_core(); +#endif _rebooting = true; // Disable NVIC IRQ, so that we don't get bothered anymore irq_set_enabled(USBCTRL_IRQ, false); diff --git a/cores/rp2040/_freertos.cpp b/cores/rp2040/_freertos.cpp index 69ecdf7ee..c1fd96f8e 100644 --- a/cores/rp2040/_freertos.cpp +++ b/cores/rp2040/_freertos.cpp @@ -18,6 +18,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifdef __FREERTOS + #include "_freertos.h" #include #include @@ -60,3 +62,5 @@ SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive) { } return nullptr; // Need to make space for more mutex maps! } + +#endif diff --git a/cores/rp2040/_freertos.h b/cores/rp2040/_freertos.h index 58c375061..96fc717cb 100644 --- a/cores/rp2040/_freertos.h +++ b/cores/rp2040/_freertos.h @@ -18,6 +18,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifdef __FREERTOS + #pragma once #include @@ -25,8 +27,6 @@ // are implemented as macros, so we have a wrapper in our variant hook // to handle it. -extern bool __isFreeRTOS; - // FreeRTOS has been set up extern volatile bool __freeRTOSinitted; @@ -63,3 +63,5 @@ extern void __freertos_task_enter_critical() __attribute__((weak)); } extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false); #endif // __cplusplus + +#endif // __FREERTOS diff --git a/cores/rp2040/lock.cpp b/cores/rp2040/lock.cpp index 3c3d7aa8b..e1742058e 100644 --- a/cores/rp2040/lock.cpp +++ b/cores/rp2040/lock.cpp @@ -44,6 +44,8 @@ auto_init_mutex(__lock___dd_hash_mutex); auto_init_mutex(__lock___arc4random_mutex); #undef static +#ifdef __FREERTOS + // FreeRTOS hack - Allow Newlib to use FreeRTOS mutexes which preserve TASKID which // is needed to support multithread @@ -98,8 +100,10 @@ static SemaphoreHandle_t __getFreeRTOSRecursiveMutex(_LOCK_T lock) { } return __get_freertos_mutex_for_ptr((mutex_t *)l, true); } +#endif void __retarget_lock_init(_LOCK_T lock) { +#ifdef __FREERTOS if (__freeRTOSinitted) { mutex_t *l = (mutex_t *)lock; if ((l == &__lock___at_quick_exit_mutex) || (l == &__lock___tz_mutex) || (l == &__lock___dd_hash_mutex) || (l == &__lock___arc4random_mutex)) { @@ -111,9 +115,13 @@ void __retarget_lock_init(_LOCK_T lock) { } else { mutex_init((mutex_t*) lock); } +#else + mutex_init((mutex_t*) lock); +#endif } void __retarget_lock_init_recursive(_LOCK_T lock) { +#ifdef __FREERTOS if (__freeRTOSinitted) { recursive_mutex_t *l = (recursive_mutex_t *)lock; if ((l == &__lock___sinit_recursive_mutex) || (l == &__lock___sfp_recursive_mutex) || (l == &__lock___atexit_recursive_mutex) || (l == &__lock___malloc_recursive_mutex) || (l == &__lock___env_recursive_mutex)) { @@ -125,6 +133,9 @@ void __retarget_lock_init_recursive(_LOCK_T lock) { } else { recursive_mutex_init((recursive_mutex_t*) lock); } +#else + recursive_mutex_init((recursive_mutex_t*) lock); +#endif } void __retarget_lock_close(_LOCK_T lock) { @@ -136,59 +147,83 @@ void __retarget_lock_close_recursive(_LOCK_T lock) { } void __retarget_lock_acquire(_LOCK_T lock) { +#ifdef __FREERTOS if (__freeRTOSinitted) { auto mtx = __getFreeRTOSMutex(lock); __freertos_mutex_take(mtx); } else { mutex_enter_blocking((mutex_t*)lock); } +#else + mutex_enter_blocking((mutex_t*)lock); +#endif } void __retarget_lock_acquire_recursive(_LOCK_T lock) { +#ifdef __FREERTOS if (__freeRTOSinitted) { auto mtx = __getFreeRTOSRecursiveMutex(lock); __freertos_recursive_mutex_take(mtx); } else { recursive_mutex_enter_blocking((recursive_mutex_t*)lock); } +#else + recursive_mutex_enter_blocking((recursive_mutex_t*)lock); +#endif } int __retarget_lock_try_acquire(_LOCK_T lock) { int ret; +#ifdef __FREERTOS if (__freeRTOSinitted) { auto mtx = __getFreeRTOSMutex(lock); ret = __freertos_mutex_try_take(mtx); } else { ret = mutex_try_enter((mutex_t *)lock, nullptr); } +#else + ret = mutex_try_enter((mutex_t *)lock, nullptr); +#endif return ret; } int __retarget_lock_try_acquire_recursive(_LOCK_T lock) { int ret; +#ifdef __FREERTOS if (__freeRTOSinitted) { auto mtx = __getFreeRTOSRecursiveMutex(lock); ret = __freertos_recursive_mutex_try_take(mtx); } else { ret = recursive_mutex_try_enter((recursive_mutex_t*)lock, nullptr); } +#else + ret = recursive_mutex_try_enter((recursive_mutex_t*)lock, nullptr); +#endif return ret; } void __retarget_lock_release(_LOCK_T lock) { +#ifdef __FREERTOS if (__freeRTOSinitted) { auto mtx = __getFreeRTOSMutex(lock); __freertos_mutex_give(mtx); } else { mutex_exit((mutex_t*)lock); } +#else + mutex_exit((mutex_t*)lock); +#endif } void __retarget_lock_release_recursive(_LOCK_T lock) { +#ifdef __FREERTOS if (__freeRTOSinitted) { auto mtx = __getFreeRTOSRecursiveMutex(lock); __freertos_recursive_mutex_give(mtx); } else { recursive_mutex_exit((recursive_mutex_t*)lock); } +#else + recursive_mutex_exit((recursive_mutex_t*)lock); +#endif } diff --git a/cores/rp2040/main.cpp b/cores/rp2040/main.cpp index f6a264bb8..5db9e4e8e 100644 --- a/cores/rp2040/main.cpp +++ b/cores/rp2040/main.cpp @@ -37,11 +37,12 @@ extern "C" { extern void setup(); extern void loop(); +#ifdef __FREERTOS // FreeRTOS potential includes -extern void initFreeRTOS() __attribute__((weak)); -extern void startFreeRTOS() __attribute__((weak)); -bool __isFreeRTOS; -volatile bool __freeRTOSinitted; +extern void initFreeRTOS(); +extern void startFreeRTOS(); +volatile bool __freeRTOSinitted = false; +#endif extern void __EnableBluetoothDebug(Print &); @@ -124,76 +125,66 @@ extern "C" int main() { #endif // over/underclock - // Let rest of core know if we're using FreeRTOS - __isFreeRTOS = initFreeRTOS ? true : false; - +#ifndef __FREERTOS // Allocate impure_ptr (newlib temps) if there is a 2nd core running - if (!__isFreeRTOS && (setup1 || loop1)) { + if (setup1 || loop1) { _impure_ptr1 = (struct _reent*)calloc(1, sizeof(struct _reent)); _REENT_INIT_PTR(_impure_ptr1); } +#endif rp2040.begin(0); initVariant(); - if (__isFreeRTOS) { - initFreeRTOS(); - } +#ifdef __FREERTOS + initFreeRTOS(); +#endif #ifndef NO_USB #ifdef USE_TINYUSB TinyUSB_Device_Init(0); - #else __USBStart(); - -#ifndef DISABLE_USB_SERIAL - - if (!__isFreeRTOS) { - // Enable serial port for reset/upload always - Serial.begin(115200); - } +#if !defined(DISABLE_USB_SERIAL) && !defined(__FREERTOS) + // Enable serial port for reset/upload always + Serial.begin(115200); #endif #endif #endif -#if defined DEBUG_RP2040_PORT - if (!__isFreeRTOS) { - DEBUG_RP2040_PORT.begin(115200); +#if defined DEBUG_RP2040_PORT && !defined(__FREERTOS) + DEBUG_RP2040_PORT.begin(115200); #if (defined(ENABLE_BLUETOOTH) || defined(ENABLE_BLE)) && defined(DEBUG_RP2040_BLUETOOTH) - __EnableBluetoothDebug(DEBUG_RP2040_PORT); + __EnableBluetoothDebug(DEBUG_RP2040_PORT); #endif - } #endif - if (!__isFreeRTOS) { - if (setup1 || loop1) { - rp2040.fifo.begin(2); +#ifndef __FREERTOS + if (setup1 || loop1) { + rp2040.fifo.begin(2); + } else { + rp2040.fifo.begin(1); + } + rp2040.fifo.registerCore(); + if (setup1 || loop1) { + delay(1); // Needed to make Picoprobe upload start 2nd core + if (core1_separate_stack) { + core1_separate_stack_address = (uint32_t*)malloc(0x2000); + multicore_launch_core1_with_stack(main1, core1_separate_stack_address, 0x2000); } else { - rp2040.fifo.begin(1); + multicore_launch_core1(main1); } - rp2040.fifo.registerCore(); } - if (!__isFreeRTOS) { - if (setup1 || loop1) { - delay(1); // Needed to make Picoprobe upload start 2nd core - if (core1_separate_stack) { - core1_separate_stack_address = (uint32_t*)malloc(0x2000); - multicore_launch_core1_with_stack(main1, core1_separate_stack_address, 0x2000); - } else { - multicore_launch_core1(main1); - } - } - setup(); - while (true) { - loop(); - __loop(); - } - } else { - rp2040.fifo.begin(2); - startFreeRTOS(); + setup(); + while (true) { + loop(); + __loop(); } +#else // __FREERTOS + rp2040.fifo.begin(2); + startFreeRTOS(); +#endif return 0; } diff --git a/cores/rp2040/sdkoverride/btstack_flash_bank.cpp b/cores/rp2040/sdkoverride/btstack_flash_bank.cpp index eaf17c532..c31470f94 100644 --- a/cores/rp2040/sdkoverride/btstack_flash_bank.cpp +++ b/cores/rp2040/sdkoverride/btstack_flash_bank.cpp @@ -49,15 +49,15 @@ static uint32_t pico_flash_bank_get_alignment(void * context) { static void pico_flash_bank_erase(void * context, int bank) { (void)(context); DEBUG_PRINT("erase: bank %d\n", bank); - if (!__isFreeRTOS) { - noInterrupts(); - } +#ifndef __FREERTOS + noInterrupts(); +#endif rp2040.idleOtherCore(); flash_range_erase(PICO_FLASH_BANK_STORAGE_OFFSET + (PICO_FLASH_BANK_SIZE * bank), PICO_FLASH_BANK_SIZE); rp2040.resumeOtherCore(); - if (!__isFreeRTOS) { - interrupts(); - } +#ifndef __FREERTOS + interrupts(); +#endif } static void pico_flash_bank_read(void *context, int bank, uint32_t offset, uint8_t *buffer, uint32_t size) { @@ -151,15 +151,15 @@ static void pico_flash_bank_write(void * context, int bank, uint32_t offset, con offset = 0; // Now program the entire page - if (!__isFreeRTOS) { - noInterrupts(); - } +#ifndef __FREERTOS + noInterrupts(); +#endif rp2040.idleOtherCore(); flash_range_program(bank_start_pos + (page * FLASH_PAGE_SIZE), page_data, FLASH_PAGE_SIZE); rp2040.resumeOtherCore(); - if (!__isFreeRTOS) { - interrupts(); - } +#ifndef __FREERTOS + interrupts(); +#endif } } diff --git a/cores/rp2040/wiring_private.cpp b/cores/rp2040/wiring_private.cpp index 7a7410372..422cfd6f2 100644 --- a/cores/rp2040/wiring_private.cpp +++ b/cores/rp2040/wiring_private.cpp @@ -33,29 +33,33 @@ static uint32_t _irqStackTop[2] = { 0, 0 }; static uint32_t _irqStack[2][maxIRQs]; extern "C" void interrupts() { +#ifdef __FREERTOS if (__freeRTOSinitted) { __freertos_task_exit_critical(); - } else { - auto core = get_core_num(); - if (!_irqStackTop[core]) { - // ERROR - return; - } - restore_interrupts(_irqStack[core][--_irqStackTop[core]]); + return; + } +#endif + auto core = get_core_num(); + if (!_irqStackTop[core]) { + // ERROR + return; } + restore_interrupts(_irqStack[core][--_irqStackTop[core]]); } extern "C" void noInterrupts() { +#ifdef __FREERTOS if (__freeRTOSinitted) { __freertos_task_enter_critical(); - } else { - auto core = get_core_num(); - if (_irqStackTop[core] == maxIRQs) { - // ERROR - panic("IRQ stack overflow"); - } - _irqStack[core][_irqStackTop[core]++] = save_and_disable_interrupts(); + return; + } +#endif + auto core = get_core_num(); + if (_irqStackTop[core] == maxIRQs) { + // ERROR + panic("IRQ stack overflow"); } + _irqStack[core][_irqStackTop[core]++] = save_and_disable_interrupts(); } auto_init_mutex(_irqMutex); diff --git a/docs/platformio.rst b/docs/platformio.rst index a74e1cdcd..35a300576 100644 --- a/docs/platformio.rst +++ b/docs/platformio.rst @@ -343,6 +343,19 @@ The Bluetooth Classic (BTC) and Bluetooth Low Energy (BLE) stack can be activate to the ``platformio.ini``. +FreeRTOS +-------- + +FreeRTOS support can be activated by adding + +.. code:: ini + + ; Set the compiler flag. Still need to #include in your application + build_flags = -D__FREERTOS + +to the ``platformio.ini``. + + Selecting a different core version ---------------------------------- diff --git a/libraries/EEPROM/src/EEPROM.cpp b/libraries/EEPROM/src/EEPROM.cpp index 12f3fafa2..624174f7a 100644 --- a/libraries/EEPROM/src/EEPROM.cpp +++ b/libraries/EEPROM/src/EEPROM.cpp @@ -118,16 +118,16 @@ bool EEPROMClass::commit() { return false; } - if (!__isFreeRTOS) { - noInterrupts(); - } +#ifndef __FREERTOS + noInterrupts(); +#endif rp2040.idleOtherCore(); flash_range_erase((intptr_t)_sector - (intptr_t)XIP_BASE, 4096); flash_range_program((intptr_t)_sector - (intptr_t)XIP_BASE, _data, _size); rp2040.resumeOtherCore(); - if (!__isFreeRTOS) { - interrupts(); - } +#ifndef __FREERTOS + interrupts(); +#endif _dirty = false; return true; diff --git a/libraries/FatFS/lib/SPIFTL b/libraries/FatFS/lib/SPIFTL index bf7742310..89a198d96 160000 --- a/libraries/FatFS/lib/SPIFTL +++ b/libraries/FatFS/lib/SPIFTL @@ -1 +1 @@ -Subproject commit bf7742310b422977d245833815fd46275cefdebe +Subproject commit 89a198d968e27bad5065fca7c7ce3eec478bd449 diff --git a/libraries/FreeRTOS/src/FreeRTOS.h b/libraries/FreeRTOS/src/FreeRTOS.h index 1db1c270b..4a0d8c33d 100644 --- a/libraries/FreeRTOS/src/FreeRTOS.h +++ b/libraries/FreeRTOS/src/FreeRTOS.h @@ -1 +1,5 @@ +#if !defined(__FREERTOS) +#error Please select Tools->Operating System->FreeRTOS SMP or define __FREERTOS in your platform.ini to use FreeRTOS +#else #include "../lib/FreeRTOS-Kernel/include/FreeRTOS.h" +#endif diff --git a/libraries/LittleFS/src/LittleFS.cpp b/libraries/LittleFS/src/LittleFS.cpp index 1aa7ab8e2..ca9f08368 100644 --- a/libraries/LittleFS/src/LittleFS.cpp +++ b/libraries/LittleFS/src/LittleFS.cpp @@ -182,16 +182,16 @@ int LittleFSImpl::lfs_flash_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size) { LittleFSImpl *me = reinterpret_cast(c->context); uint8_t *addr = me->_start + (block * me->_blockSize) + off; - if (!__isFreeRTOS) { - noInterrupts(); - } +#ifndef __FREERTOS + noInterrupts(); +#endif rp2040.idleOtherCore(); // Serial.printf("WRITE: %p, $d\n", (intptr_t)addr - (intptr_t)XIP_BASE, size); flash_range_program((intptr_t)addr - (intptr_t)XIP_BASE, (const uint8_t *)buffer, size); rp2040.resumeOtherCore(); - if (!__isFreeRTOS) { - interrupts(); - } +#ifndef __FREERTOS + interrupts(); +#endif return 0; } @@ -199,15 +199,15 @@ int LittleFSImpl::lfs_flash_erase(const struct lfs_config *c, lfs_block_t block) LittleFSImpl *me = reinterpret_cast(c->context); uint8_t *addr = me->_start + (block * me->_blockSize); // Serial.printf("ERASE: %p, %d\n", (intptr_t)addr - (intptr_t)XIP_BASE, me->_blockSize); - if (!__isFreeRTOS) { - noInterrupts(); - } +#ifndef __FREERTOS + noInterrupts(); +#endif rp2040.idleOtherCore(); flash_range_erase((intptr_t)addr - (intptr_t)XIP_BASE, me->_blockSize); rp2040.resumeOtherCore(); - if (!__isFreeRTOS) { - interrupts(); - } +#ifndef __FREERTOS + interrupts(); +#endif return 0; } diff --git a/libraries/Updater/src/Updater.cpp b/libraries/Updater/src/Updater.cpp index 4281e1909..cef70c479 100644 --- a/libraries/Updater/src/Updater.cpp +++ b/libraries/Updater/src/Updater.cpp @@ -298,16 +298,16 @@ bool UpdaterClass::_writeBuffer() { return false; } } else { - if (!__isFreeRTOS) { - noInterrupts(); - } +#ifndef __FREERTOS + noInterrupts(); +#endif rp2040.idleOtherCore(); flash_range_erase((intptr_t)_currentAddress - (intptr_t)XIP_BASE, 4096); flash_range_program((intptr_t)_currentAddress - (intptr_t)XIP_BASE, _buffer, 4096); rp2040.resumeOtherCore(); - if (!__isFreeRTOS) { - interrupts(); - } +#ifndef __FREERTOS + interrupts(); +#endif } if (!_verify) { _md5.add(_buffer, _bufferLen); diff --git a/platform.txt b/platform.txt index 27572aaa0..798bbb842 100644 --- a/platform.txt +++ b/platform.txt @@ -51,7 +51,7 @@ compiler.warning_flags.all=-Wall -Wextra -Werror=return-type -Wno-psabi -Wno-typ compiler.netdefines={build.libpicowdefs} -DLWIP_IGMP=1 -DLWIP_CHECKSUM_CTRL_PER_NETIF=1 compiler.psramdefines={build.psram_cs} {build.psram_freq} -compiler.defines={build.led} {build.usbstack_flags} {build.usbpid} {build.usbvid} {build.usbpwr} {compiler.psramdefines} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' {compiler.netdefines} {build.sdfatdefines} {build.variantdefines} -DARDUINO_VARIANT="{build.variant}" -DPICO_FLASH_SIZE_BYTES={build.flash_total} "@{runtime.platform.path}/lib/platform_def.txt" "@{runtime.platform.path}/lib/{build.chip}/platform_def.txt" +compiler.defines={build.os} {build.led} {build.usbstack_flags} {build.usbpid} {build.usbvid} {build.usbpwr} {compiler.psramdefines} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' {compiler.netdefines} {build.sdfatdefines} {build.variantdefines} -DARDUINO_VARIANT="{build.variant}" -DPICO_FLASH_SIZE_BYTES={build.flash_total} "@{runtime.platform.path}/lib/platform_def.txt" "@{runtime.platform.path}/lib/{build.chip}/platform_def.txt" compiler.includes="-iprefix{runtime.platform.path}/" "@{runtime.platform.path}/lib/{build.chip}/platform_inc.txt" "@{runtime.platform.path}/lib/core_inc.txt" "-I{runtime.platform.path}/include" compiler.flags={build.toolchainopts} -ffunction-sections -fdata-sections {build.flags.exceptions} {build.flags.stackprotect} {build.picodebugflags} compiler.wrap="@{runtime.platform.path}/lib/{build.chip}/platform_wrap.txt" "@{runtime.platform.path}/lib/core_wrap.txt" @@ -105,6 +105,7 @@ build.usbstack_flags= build.flags.libstdcpp=-lstdc++ build.flags.exceptions=-fno-exceptions build.flags.stackprotect= +build.os= build.libpico=libpico.a build.libpicow=liblwip.a build.boot2=boot2_generic_03h_4_padded_checksum diff --git a/tools/build.py b/tools/build.py index eeb4cf051..3e845a4e5 100755 --- a/tools/build.py +++ b/tools/build.py @@ -74,6 +74,8 @@ def compile(tmp_dir, sketch, cache, tools_dir, hardware_dir, ide_path, f, args): fqbn = fqbn + ",ipbtstack=ipv4btcble" if '/Profiling' in sketch: fqbn = fqbn + ",profile=Enabled" + if '/FreeRTOS' in sketch: + fqbn = fqbn + ",os=freertos" cmd += [fqbn] cmd += ['-built-in-libraries', ide_path + '/libraries'] cmd += ['-ide-version=10607'] diff --git a/tools/makeboards.py b/tools/makeboards.py index fb17b5dfb..f9110b244 100755 --- a/tools/makeboards.py +++ b/tools/makeboards.py @@ -96,6 +96,12 @@ def BuildOptimize(name): print("%s.menu.opt.%s=%s (%s)%s" % (name, l[0], l[1], l[2], l[3])) print("%s.menu.opt.%s.build.flags.optimize=%s" % (name, l[0], l[2])) +def BuildOS(name): + print("%s.menu.os.none=None" % (name)) + print("%s.menu.os.none.build.os=" % (name)) + print("%s.menu.os.freertos=FreeRTOS SMP" % (name)) + print("%s.menu.os.freertos.build.os=-D__FREERTOS" % (name)) + def BuildProfile(name): print("%s.menu.profile.Disabled=Disabled" % (name)) print("%s.menu.profile.Disabled.build.flags.profile=" % (name)) @@ -293,6 +299,7 @@ def BuildGlobalMenuList(): print("menu.freq=CPU Speed") print("menu.arch=CPU Architecture") print("menu.opt=Optimize") + print("menu.os=Operating System") print("menu.profile=Profiling") print("menu.rtti=RTTI") print("menu.stackprotect=Stack Protector") @@ -376,6 +383,7 @@ def MakeBoard(name, chip, vendor_name, product_name, vid, pid, pwr, boarddefine, else: BuildFreq(name, 200) BuildOptimize(name) + BuildOS(name) BuildProfile(name) BuildRTTI(name) BuildStackProtect(name) From b5193a41dc35c9d557c20fe196644e79299a3ffa Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 13 Aug 2025 20:22:52 -0700 Subject: [PATCH 02/36] Move FreeRTOS to main core, refactor async_context, move to LWIP task Implement the LWIP task (the only task allowed to call actual LWIP calls) using a work queue accessible from any other task/core. Move FreeRTOS into the main cores/rp2040 directory to allow for easier core usage. Dynamically build the proper async_context for raw or FreeRTOS in the IDE, not at libpico time. --- .gitmodules | 2 +- cores/rp2040/freertos/FreeRTOS.h | 3 + .../rp2040/freertos}/FreeRTOSConfig.h | 6 +- cores/rp2040/freertos/StackMacros.h | 3 + cores/rp2040/freertos/atomic.h | 3 + cores/rp2040/freertos/croutine.c | 3 + cores/rp2040/freertos/croutine.h | 3 + .../rp2040/freertos/deprecated_definitions.h | 3 + cores/rp2040/freertos/event_groups.c | 3 + cores/rp2040/freertos/event_groups.h | 3 + cores/rp2040/freertos/freertos_sdk_config.h | 3 + cores/rp2040/freertos/heap_3a.c | 108 +++++ cores/rp2040/freertos/list.c | 3 + cores/rp2040/freertos/list.h | 3 + cores/rp2040/freertos/lwip_freertos.c | 15 + cores/rp2040/freertos/message_buffer.h | 3 + cores/rp2040/freertos/mpu_prototypes.h | 3 + cores/rp2040/freertos/mpu_syscall_numbers.h | 3 + cores/rp2040/freertos/mpu_wrappers.h | 3 + cores/rp2040/freertos/mpu_wrappers_v2_asm.c | 7 + cores/rp2040/freertos/port.c | 11 + cores/rp2040/freertos/portASM.S | 7 + cores/rp2040/freertos/portContext.h | 8 + cores/rp2040/freertos/portable.h | 3 + cores/rp2040/freertos/portasm.c | 7 + cores/rp2040/freertos/portmacro.h | 11 + cores/rp2040/freertos/projdefs.h | 3 + cores/rp2040/freertos/queue.c | 3 + cores/rp2040/freertos/queue.h | 3 + cores/rp2040/freertos/rp2040_config.h | 11 + cores/rp2040/freertos/semphr.h | 3 + cores/rp2040/freertos/stack_macros.h | 3 + cores/rp2040/freertos/stream_buffer.c | 3 + cores/rp2040/freertos/stream_buffer.h | 3 + cores/rp2040/freertos/task.h | 3 + .../src => cores/rp2040/freertos}/tasks.c | 4 +- cores/rp2040/freertos/timers.c | 3 + cores/rp2040/freertos/timers.h | 3 + .../rp2040/freertos}/variantHooks.cpp | 386 +++++++++++++++++- cores/rp2040/lwip_wrap.cpp | 346 +++++++++++++--- cores/rp2040/main.cpp | 6 +- .../sdkoverride/async_context_freertos.c | 3 + .../async_context_threadsafe_background.c | 3 + .../rp2040/sdkoverride/cyw43_arch_freertos.c | 96 +++++ .../cyw43_arch_threadsafe_background.c | 4 + include/lwipopts.h | 62 +-- lib/core_inc.txt | 2 + lib/core_wrap.txt | 4 +- lib/platform_def.txt | 4 +- lib/rp2040/liblwip-bt.a | Bin 6055414 -> 6006160 bytes lib/rp2040/liblwip.a | Bin 687368 -> 638402 bytes lib/rp2040/libpico.a | Bin 1480332 -> 1480332 bytes lib/rp2350-riscv/liblwip-bt.a | Bin 16541512 -> 16425860 bytes lib/rp2350-riscv/liblwip.a | Bin 1525700 -> 1410800 bytes lib/rp2350-riscv/libpico.a | Bin 3661846 -> 3661846 bytes lib/rp2350/liblwip-bt.a | Bin 6106222 -> 6056268 bytes lib/rp2350/liblwip.a | Bin 757416 -> 707744 bytes lib/rp2350/libpico.a | Bin 1564426 -> 1564426 bytes .../Multicore-FreeRTOS/Multicore-FreeRTOS.ino | 87 ---- .../StaticMulticore-FreeRTOS.ino | 94 ----- libraries/FreeRTOS/examples/Stress.ino | 319 --------------- libraries/FreeRTOS/keywords.txt | 64 --- libraries/FreeRTOS/lib/FreeRTOS-Kernel | 1 - libraries/FreeRTOS/library.properties | 11 - libraries/FreeRTOS/readme.md | 39 -- libraries/FreeRTOS/src/FreeRTOS.h | 5 - libraries/FreeRTOS/src/StackMacros.h | 1 - libraries/FreeRTOS/src/atomic.h | 1 - libraries/FreeRTOS/src/croutine.c | 1 - libraries/FreeRTOS/src/croutine.h | 1 - .../FreeRTOS/src/deprecated_definitions.h | 1 - libraries/FreeRTOS/src/event_groups.c | 1 - libraries/FreeRTOS/src/event_groups.h | 1 - libraries/FreeRTOS/src/freertos_sdk_config.h | 1 - libraries/FreeRTOS/src/heap_3.c | 1 - libraries/FreeRTOS/src/list.c | 1 - libraries/FreeRTOS/src/list.h | 1 - libraries/FreeRTOS/src/message_buffer.h | 1 - libraries/FreeRTOS/src/mpu_prototypes.h | 1 - libraries/FreeRTOS/src/mpu_syscall_numbers.h | 1 - libraries/FreeRTOS/src/mpu_wrappers.h | 1 - libraries/FreeRTOS/src/mpu_wrappers_v2_asm.c | 5 - libraries/FreeRTOS/src/port.c | 9 - libraries/FreeRTOS/src/portASM.S | 5 - libraries/FreeRTOS/src/portContext.h | 6 - libraries/FreeRTOS/src/portable.h | 1 - libraries/FreeRTOS/src/portasm.c | 5 - libraries/FreeRTOS/src/portmacro.h | 9 - libraries/FreeRTOS/src/projdefs.h | 1 - libraries/FreeRTOS/src/queue.c | 1 - libraries/FreeRTOS/src/queue.h | 1 - libraries/FreeRTOS/src/rp2040_config.h | 9 - libraries/FreeRTOS/src/semphr.h | 1 - libraries/FreeRTOS/src/stack_macros.h | 1 - libraries/FreeRTOS/src/stream_buffer.c | 1 - libraries/FreeRTOS/src/stream_buffer.h | 1 - libraries/FreeRTOS/src/task.h | 1 - libraries/FreeRTOS/src/timers.c | 1 - libraries/FreeRTOS/src/timers.h | 1 - libraries/FreeRTOS/tests/README.md | 1 - .../FreeRTOS/tests/corefreeze/corefreeze.ino | 25 -- .../tests/freertos_reent/freertos_reent.ino | 32 -- .../freertos_syscallmutex.ino | 319 --------------- .../FreeRTOS/tests/switching/switching.ino | 57 --- .../lwIP_CYW43/src/utility/CYW43shim.cpp | 1 + libraries/lwIP_Ethernet/src/LwipEthernet.cpp | 91 +++-- libraries/lwIP_Ethernet/src/LwipIntfDev.h | 6 +- tools/libpico/CMakeLists.txt | 9 +- 108 files changed, 1163 insertions(+), 1263 deletions(-) create mode 100644 cores/rp2040/freertos/FreeRTOS.h rename {libraries/FreeRTOS/src => cores/rp2040/freertos}/FreeRTOSConfig.h (98%) create mode 100644 cores/rp2040/freertos/StackMacros.h create mode 100644 cores/rp2040/freertos/atomic.h create mode 100644 cores/rp2040/freertos/croutine.c create mode 100644 cores/rp2040/freertos/croutine.h create mode 100644 cores/rp2040/freertos/deprecated_definitions.h create mode 100644 cores/rp2040/freertos/event_groups.c create mode 100644 cores/rp2040/freertos/event_groups.h create mode 100644 cores/rp2040/freertos/freertos_sdk_config.h create mode 100644 cores/rp2040/freertos/heap_3a.c create mode 100644 cores/rp2040/freertos/list.c create mode 100644 cores/rp2040/freertos/list.h create mode 100644 cores/rp2040/freertos/lwip_freertos.c create mode 100644 cores/rp2040/freertos/message_buffer.h create mode 100644 cores/rp2040/freertos/mpu_prototypes.h create mode 100644 cores/rp2040/freertos/mpu_syscall_numbers.h create mode 100644 cores/rp2040/freertos/mpu_wrappers.h create mode 100644 cores/rp2040/freertos/mpu_wrappers_v2_asm.c create mode 100644 cores/rp2040/freertos/port.c create mode 100644 cores/rp2040/freertos/portASM.S create mode 100644 cores/rp2040/freertos/portContext.h create mode 100644 cores/rp2040/freertos/portable.h create mode 100644 cores/rp2040/freertos/portasm.c create mode 100644 cores/rp2040/freertos/portmacro.h create mode 100644 cores/rp2040/freertos/projdefs.h create mode 100644 cores/rp2040/freertos/queue.c create mode 100644 cores/rp2040/freertos/queue.h create mode 100644 cores/rp2040/freertos/rp2040_config.h create mode 100644 cores/rp2040/freertos/semphr.h create mode 100644 cores/rp2040/freertos/stack_macros.h create mode 100644 cores/rp2040/freertos/stream_buffer.c create mode 100644 cores/rp2040/freertos/stream_buffer.h create mode 100644 cores/rp2040/freertos/task.h rename {libraries/FreeRTOS/src => cores/rp2040/freertos}/tasks.c (86%) create mode 100644 cores/rp2040/freertos/timers.c create mode 100644 cores/rp2040/freertos/timers.h rename {libraries/FreeRTOS/src => cores/rp2040/freertos}/variantHooks.cpp (52%) create mode 100644 cores/rp2040/sdkoverride/async_context_freertos.c create mode 100644 cores/rp2040/sdkoverride/async_context_threadsafe_background.c create mode 100644 cores/rp2040/sdkoverride/cyw43_arch_freertos.c create mode 100644 cores/rp2040/sdkoverride/cyw43_arch_threadsafe_background.c delete mode 100644 libraries/FreeRTOS/examples/Multicore-FreeRTOS/Multicore-FreeRTOS.ino delete mode 100644 libraries/FreeRTOS/examples/StaticMulticore-FreeRTOS/StaticMulticore-FreeRTOS.ino delete mode 100644 libraries/FreeRTOS/examples/Stress.ino delete mode 100644 libraries/FreeRTOS/keywords.txt delete mode 160000 libraries/FreeRTOS/lib/FreeRTOS-Kernel delete mode 100644 libraries/FreeRTOS/library.properties delete mode 100644 libraries/FreeRTOS/readme.md delete mode 100644 libraries/FreeRTOS/src/FreeRTOS.h delete mode 100644 libraries/FreeRTOS/src/StackMacros.h delete mode 100644 libraries/FreeRTOS/src/atomic.h delete mode 100644 libraries/FreeRTOS/src/croutine.c delete mode 100644 libraries/FreeRTOS/src/croutine.h delete mode 100644 libraries/FreeRTOS/src/deprecated_definitions.h delete mode 100644 libraries/FreeRTOS/src/event_groups.c delete mode 100644 libraries/FreeRTOS/src/event_groups.h delete mode 100644 libraries/FreeRTOS/src/freertos_sdk_config.h delete mode 100644 libraries/FreeRTOS/src/heap_3.c delete mode 100644 libraries/FreeRTOS/src/list.c delete mode 100644 libraries/FreeRTOS/src/list.h delete mode 100644 libraries/FreeRTOS/src/message_buffer.h delete mode 100644 libraries/FreeRTOS/src/mpu_prototypes.h delete mode 100644 libraries/FreeRTOS/src/mpu_syscall_numbers.h delete mode 100644 libraries/FreeRTOS/src/mpu_wrappers.h delete mode 100644 libraries/FreeRTOS/src/mpu_wrappers_v2_asm.c delete mode 100644 libraries/FreeRTOS/src/port.c delete mode 100644 libraries/FreeRTOS/src/portASM.S delete mode 100644 libraries/FreeRTOS/src/portContext.h delete mode 100644 libraries/FreeRTOS/src/portable.h delete mode 100644 libraries/FreeRTOS/src/portasm.c delete mode 100644 libraries/FreeRTOS/src/portmacro.h delete mode 100644 libraries/FreeRTOS/src/projdefs.h delete mode 100644 libraries/FreeRTOS/src/queue.c delete mode 100644 libraries/FreeRTOS/src/queue.h delete mode 100644 libraries/FreeRTOS/src/rp2040_config.h delete mode 100644 libraries/FreeRTOS/src/semphr.h delete mode 100644 libraries/FreeRTOS/src/stack_macros.h delete mode 100644 libraries/FreeRTOS/src/stream_buffer.c delete mode 100644 libraries/FreeRTOS/src/stream_buffer.h delete mode 100644 libraries/FreeRTOS/src/task.h delete mode 100644 libraries/FreeRTOS/src/timers.c delete mode 100644 libraries/FreeRTOS/src/timers.h delete mode 100644 libraries/FreeRTOS/tests/README.md delete mode 100644 libraries/FreeRTOS/tests/corefreeze/corefreeze.ino delete mode 100644 libraries/FreeRTOS/tests/freertos_reent/freertos_reent.ino delete mode 100644 libraries/FreeRTOS/tests/freertos_syscallmutex/freertos_syscallmutex.ino delete mode 100644 libraries/FreeRTOS/tests/switching/switching.ino diff --git a/.gitmodules b/.gitmodules index 8b55777d8..044503bc5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -23,7 +23,7 @@ path = libraries/Adafruit_TinyUSB_Arduino url = https://github.com/adafruit/Adafruit_TinyUSB_Arduino.git [submodule "libraries/FreeRTOS/lib/FreeRTOS-Kernel"] - path = libraries/FreeRTOS/lib/FreeRTOS-Kernel + path = FreeRTOS-Kernel url = https://github.com/earlephilhower/FreeRTOS-Kernel.git [submodule "tools/libbearssl/bearssl"] path = tools/libbearssl/bearssl diff --git a/cores/rp2040/freertos/FreeRTOS.h b/cores/rp2040/freertos/FreeRTOS.h new file mode 100644 index 000000000..c8781f33c --- /dev/null +++ b/cores/rp2040/freertos/FreeRTOS.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/FreeRTOS.h" +#endif diff --git a/libraries/FreeRTOS/src/FreeRTOSConfig.h b/cores/rp2040/freertos/FreeRTOSConfig.h similarity index 98% rename from libraries/FreeRTOS/src/FreeRTOSConfig.h rename to cores/rp2040/freertos/FreeRTOSConfig.h index e28ec4d4a..a5dc3b3f6 100644 --- a/libraries/FreeRTOS/src/FreeRTOSConfig.h +++ b/cores/rp2040/freertos/FreeRTOSConfig.h @@ -1,3 +1,4 @@ +#ifdef __FREERTOS #ifndef configNUMBER_OF_CORES #define configNUMBER_OF_CORES 2 #endif @@ -80,7 +81,9 @@ #ifndef configUSE_TASK_PREEMPTION_DISABLE #define configUSE_TASK_PREEMPTION_DISABLE 1 #endif - +#ifndef configTASK_NOTIFICATION_ARRAY_ENTRIES +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 4 +#endif #ifndef configUSE_NEWLIB_REENTRANT #define configUSE_NEWLIB_REENTRANT 1 #endif @@ -262,3 +265,4 @@ void rtosFatalError(void); #endif #include "rp2040_config.h" +#endif diff --git a/cores/rp2040/freertos/StackMacros.h b/cores/rp2040/freertos/StackMacros.h new file mode 100644 index 000000000..d52e2e2ba --- /dev/null +++ b/cores/rp2040/freertos/StackMacros.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/StackMacros.h" +#endif diff --git a/cores/rp2040/freertos/atomic.h b/cores/rp2040/freertos/atomic.h new file mode 100644 index 000000000..cc375fcda --- /dev/null +++ b/cores/rp2040/freertos/atomic.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/atomic.h" +#endif diff --git a/cores/rp2040/freertos/croutine.c b/cores/rp2040/freertos/croutine.c new file mode 100644 index 000000000..b83901a25 --- /dev/null +++ b/cores/rp2040/freertos/croutine.c @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/croutine.c" +#endif diff --git a/cores/rp2040/freertos/croutine.h b/cores/rp2040/freertos/croutine.h new file mode 100644 index 000000000..d09dc0120 --- /dev/null +++ b/cores/rp2040/freertos/croutine.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/croutine.h" +#endif diff --git a/cores/rp2040/freertos/deprecated_definitions.h b/cores/rp2040/freertos/deprecated_definitions.h new file mode 100644 index 000000000..af9f1d5cd --- /dev/null +++ b/cores/rp2040/freertos/deprecated_definitions.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/deprecated_definitions.h" +#endif diff --git a/cores/rp2040/freertos/event_groups.c b/cores/rp2040/freertos/event_groups.c new file mode 100644 index 000000000..461234970 --- /dev/null +++ b/cores/rp2040/freertos/event_groups.c @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/event_groups.c" +#endif diff --git a/cores/rp2040/freertos/event_groups.h b/cores/rp2040/freertos/event_groups.h new file mode 100644 index 000000000..efc74cdd7 --- /dev/null +++ b/cores/rp2040/freertos/event_groups.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/event_groups.h" +#endif diff --git a/cores/rp2040/freertos/freertos_sdk_config.h b/cores/rp2040/freertos/freertos_sdk_config.h new file mode 100644 index 000000000..60c86fcbc --- /dev/null +++ b/cores/rp2040/freertos/freertos_sdk_config.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/include/freertos_sdk_config.h" +#endif diff --git a/cores/rp2040/freertos/heap_3a.c b/cores/rp2040/freertos/heap_3a.c new file mode 100644 index 000000000..81bc88924 --- /dev/null +++ b/cores/rp2040/freertos/heap_3a.c @@ -0,0 +1,108 @@ +// Hacked to remove the vTaskSuspendAll from heap_3.c + +/* + * FreeRTOS Kernel + * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + * + * 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. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + + +/* + * Implementation of pvPortMalloc() and vPortFree() that relies on the + * compilers own malloc() and free() implementations. + * + * This file can only be used if the linker is configured to to generate + * a heap memory area. + * + * See heap_1.c, heap_2.c and heap_4.c for alternative implementations, and the + * memory management pages of https://www.FreeRTOS.org for more information. + */ + +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining + * all the API functions to use the MPU wrappers. That should only be done when + * task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "FreeRTOS.h" +#include "task.h" + +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) + #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0 +#endif + +/*-----------------------------------------------------------*/ + +void * pvPortMalloc( size_t xWantedSize ) +{ + void * pvReturn; + + //vTaskSuspendAll(); + { + pvReturn = malloc( xWantedSize ); + traceMALLOC( pvReturn, xWantedSize ); + } + //( void ) xTaskResumeAll(); + + #if ( configUSE_MALLOC_FAILED_HOOK == 1 ) + { + if( pvReturn == NULL ) + { + vApplicationMallocFailedHook(); + } + } + #endif + + return pvReturn; +} +/*-----------------------------------------------------------*/ + +void vPortFree( void * pv ) +{ + if( pv != NULL ) + { + //vTaskSuspendAll(); + { + free( pv ); + traceFREE( pv, 0 ); + } + // ( void ) xTaskResumeAll(); + } +} +/*-----------------------------------------------------------*/ + +/* + * Reset the state in this file. This state is normally initialized at start up. + * This function must be called by the application before restarting the + * scheduler. + */ +void vPortHeapResetState( void ) +{ + /* No state needs to be re-initialised in heap_3. */ +} +/*-----------------------------------------------------------*/ diff --git a/cores/rp2040/freertos/list.c b/cores/rp2040/freertos/list.c new file mode 100644 index 000000000..e0e4bc00b --- /dev/null +++ b/cores/rp2040/freertos/list.c @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/list.c" +#endif diff --git a/cores/rp2040/freertos/list.h b/cores/rp2040/freertos/list.h new file mode 100644 index 000000000..7ccaee640 --- /dev/null +++ b/cores/rp2040/freertos/list.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/list.h" +#endif diff --git a/cores/rp2040/freertos/lwip_freertos.c b/cores/rp2040/freertos/lwip_freertos.c new file mode 100644 index 000000000..999a1be47 --- /dev/null +++ b/cores/rp2040/freertos/lwip_freertos.c @@ -0,0 +1,15 @@ +// For FreeRTOS, we'll just use the NOSYS version because we already safely handle it +#ifdef __FREERTOS + +#include "pico/async_context.h" + +extern bool lwip_nosys_init(async_context_t *context); +extern void lwip_nosys_deinit(async_context_t *context); + +bool lwip_freertos_init(async_context_t *context) { + return lwip_nosys_init(context); +} +void lwip_freertos_deinit(__unused async_context_t *context) { + lwip_nosys_deinit(context); +} +#endif diff --git a/cores/rp2040/freertos/message_buffer.h b/cores/rp2040/freertos/message_buffer.h new file mode 100644 index 000000000..ff1efcfd1 --- /dev/null +++ b/cores/rp2040/freertos/message_buffer.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/message_buffer.h" +#endif diff --git a/cores/rp2040/freertos/mpu_prototypes.h b/cores/rp2040/freertos/mpu_prototypes.h new file mode 100644 index 000000000..2495203aa --- /dev/null +++ b/cores/rp2040/freertos/mpu_prototypes.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/mpu_prototypes.h" +#endif diff --git a/cores/rp2040/freertos/mpu_syscall_numbers.h b/cores/rp2040/freertos/mpu_syscall_numbers.h new file mode 100644 index 000000000..3ccd4685e --- /dev/null +++ b/cores/rp2040/freertos/mpu_syscall_numbers.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/mpu_syscall_numbers.h" +#endif diff --git a/cores/rp2040/freertos/mpu_wrappers.h b/cores/rp2040/freertos/mpu_wrappers.h new file mode 100644 index 000000000..3c8448165 --- /dev/null +++ b/cores/rp2040/freertos/mpu_wrappers.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/mpu_wrappers.h" +#endif diff --git a/cores/rp2040/freertos/mpu_wrappers_v2_asm.c b/cores/rp2040/freertos/mpu_wrappers_v2_asm.c new file mode 100644 index 000000000..09b2d87ab --- /dev/null +++ b/cores/rp2040/freertos/mpu_wrappers_v2_asm.c @@ -0,0 +1,7 @@ +#ifdef __FREERTOS +#ifdef PICO_RP2350 +#ifndef __riscv +#include "../../../FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure/mpu_wrappers_v2_asm.c" +#endif +#endif +#endif diff --git a/cores/rp2040/freertos/port.c b/cores/rp2040/freertos/port.c new file mode 100644 index 000000000..48ee30b68 --- /dev/null +++ b/cores/rp2040/freertos/port.c @@ -0,0 +1,11 @@ +#ifdef __FREERTOS +#ifdef PICO_RP2040 +#include "../../../FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/port.c" +#else +#ifndef __riscv +#include "../../../FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure/port.c" +#else +#include "../../../FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_RISC-V/port.c" +#endif +#endif +#endif diff --git a/cores/rp2040/freertos/portASM.S b/cores/rp2040/freertos/portASM.S new file mode 100644 index 000000000..17ad0a513 --- /dev/null +++ b/cores/rp2040/freertos/portASM.S @@ -0,0 +1,7 @@ +#ifdef __FREERTOS +#ifdef PICO_RP2350 +#ifdef __riscv +#include "../../../FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_RISC-V/portASM.S" +#endif +#endif +#endif diff --git a/cores/rp2040/freertos/portContext.h b/cores/rp2040/freertos/portContext.h new file mode 100644 index 000000000..3b60c6ceb --- /dev/null +++ b/cores/rp2040/freertos/portContext.h @@ -0,0 +1,8 @@ +#ifdef __FREERTOS +#ifdef PICO_RP2350 +#ifdef __riscv +#include "../../../FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_RISC-V/include/portContext.h" +#endif +#endif + +#endif diff --git a/cores/rp2040/freertos/portable.h b/cores/rp2040/freertos/portable.h new file mode 100644 index 000000000..b3d087014 --- /dev/null +++ b/cores/rp2040/freertos/portable.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/portable.h" +#endif diff --git a/cores/rp2040/freertos/portasm.c b/cores/rp2040/freertos/portasm.c new file mode 100644 index 000000000..4520e1f20 --- /dev/null +++ b/cores/rp2040/freertos/portasm.c @@ -0,0 +1,7 @@ +#ifdef __FREERTOS +#ifdef PICO_RP2350 +#ifndef __riscv +#include "../../../FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure/portasm.c" +#endif +#endif +#endif diff --git a/cores/rp2040/freertos/portmacro.h b/cores/rp2040/freertos/portmacro.h new file mode 100644 index 000000000..b1d48834c --- /dev/null +++ b/cores/rp2040/freertos/portmacro.h @@ -0,0 +1,11 @@ +#ifdef __FREERTOS +#ifdef PICO_RP2350 +#ifndef __riscv +#include "../../../FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure/portmacro.h" +#else +#include "../../../FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_RISC-V/include/portmacro.h" +#endif +#else +#include "../../../FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/include/portmacro.h" +#endif +#endif diff --git a/cores/rp2040/freertos/projdefs.h b/cores/rp2040/freertos/projdefs.h new file mode 100644 index 000000000..746274ac0 --- /dev/null +++ b/cores/rp2040/freertos/projdefs.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/projdefs.h" +#endif diff --git a/cores/rp2040/freertos/queue.c b/cores/rp2040/freertos/queue.c new file mode 100644 index 000000000..eb248772f --- /dev/null +++ b/cores/rp2040/freertos/queue.c @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/queue.c" +#endif diff --git a/cores/rp2040/freertos/queue.h b/cores/rp2040/freertos/queue.h new file mode 100644 index 000000000..52f8a5702 --- /dev/null +++ b/cores/rp2040/freertos/queue.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/queue.h" +#endif diff --git a/cores/rp2040/freertos/rp2040_config.h b/cores/rp2040/freertos/rp2040_config.h new file mode 100644 index 000000000..88e6f06dc --- /dev/null +++ b/cores/rp2040/freertos/rp2040_config.h @@ -0,0 +1,11 @@ +#ifdef __FREERTOS +#ifdef PICO_RP2350 +#ifndef __riscv +#include "../../../FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure//rp2040_config.h" +#else +#include "../../../FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_RISC-V/include/rp2040_config.h" +#endif +#else +#include "../../../FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/include/rp2040_config.h" +#endif +#endif diff --git a/cores/rp2040/freertos/semphr.h b/cores/rp2040/freertos/semphr.h new file mode 100644 index 000000000..ceb340a3f --- /dev/null +++ b/cores/rp2040/freertos/semphr.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/semphr.h" +#endif diff --git a/cores/rp2040/freertos/stack_macros.h b/cores/rp2040/freertos/stack_macros.h new file mode 100644 index 000000000..8ef9cc0db --- /dev/null +++ b/cores/rp2040/freertos/stack_macros.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/stack_macros.h" +#endif diff --git a/cores/rp2040/freertos/stream_buffer.c b/cores/rp2040/freertos/stream_buffer.c new file mode 100644 index 000000000..f28a0233f --- /dev/null +++ b/cores/rp2040/freertos/stream_buffer.c @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/stream_buffer.c" +#endif diff --git a/cores/rp2040/freertos/stream_buffer.h b/cores/rp2040/freertos/stream_buffer.h new file mode 100644 index 000000000..253327ad1 --- /dev/null +++ b/cores/rp2040/freertos/stream_buffer.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/stream_buffer.h" +#endif diff --git a/cores/rp2040/freertos/task.h b/cores/rp2040/freertos/task.h new file mode 100644 index 000000000..8aad6e2e6 --- /dev/null +++ b/cores/rp2040/freertos/task.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/task.h" +#endif diff --git a/libraries/FreeRTOS/src/tasks.c b/cores/rp2040/freertos/tasks.c similarity index 86% rename from libraries/FreeRTOS/src/tasks.c rename to cores/rp2040/freertos/tasks.c index 5333830be..6b63d1374 100644 --- a/libraries/FreeRTOS/src/tasks.c +++ b/cores/rp2040/freertos/tasks.c @@ -1,4 +1,5 @@ -#include "../lib/FreeRTOS-Kernel/tasks.c" +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/tasks.c" // See https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/496 struct _reent* __wrap___getreent(void) { @@ -12,3 +13,4 @@ struct _reent* __wrap___getreent(void) { return &pxCurTask->xTLSBlock; } } +#endif diff --git a/cores/rp2040/freertos/timers.c b/cores/rp2040/freertos/timers.c new file mode 100644 index 000000000..527315ca7 --- /dev/null +++ b/cores/rp2040/freertos/timers.c @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/timers.c" +#endif diff --git a/cores/rp2040/freertos/timers.h b/cores/rp2040/freertos/timers.h new file mode 100644 index 000000000..7dc8cb0ec --- /dev/null +++ b/cores/rp2040/freertos/timers.h @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../FreeRTOS-Kernel/include/timers.h" +#endif diff --git a/libraries/FreeRTOS/src/variantHooks.cpp b/cores/rp2040/freertos/variantHooks.cpp similarity index 52% rename from libraries/FreeRTOS/src/variantHooks.cpp rename to cores/rp2040/freertos/variantHooks.cpp index e8a062dc4..a7dfbc489 100644 --- a/libraries/FreeRTOS/src/variantHooks.cpp +++ b/cores/rp2040/freertos/variantHooks.cpp @@ -1,3 +1,4 @@ +#ifdef __FREERTOS /* Copyright (C) 2021 Phillip Stevens All Rights Reserved. Modifications by Earle F. Philhower, III, for Arduino-Pico @@ -42,6 +43,17 @@ #include <_freertos.h> +#include + +static TaskHandle_t __lwipTask; +static QueueHandle_t __lwipQueue; +typedef struct { + __lwip_op op; + void *req; + TaskHandle_t wakeup; +} LWIPWork; + +#define TASK_NOTIFY_LWIP_WAKEUP (configTASK_NOTIFICATION_ARRAY_ENTRIES - 1) // Interfaces for the main core to use FreeRTOS mutexes extern "C" { extern volatile bool __otherCoreIdled; @@ -126,8 +138,18 @@ extern void loop1() __attribute__((weak)); extern void __loop(); volatile bool __usbInitted = false; +extern void initVariant(); +static void __core1(void *params); static void __core0(void *params) { (void) params; + initVariant(); + + if (setup1 || loop1) { + TaskHandle_t c1; + xTaskCreate(__core1, "CORE1", 1024, 0, configMAX_PRIORITIES / 2, &c1); + vTaskCoreAffinitySet(c1, 1 << 1); + } + #if !defined(NO_USB) && !defined(USE_TINYUSB) while (!__usbInitted) { delay(1); @@ -215,24 +237,25 @@ extern mutex_t __usb_mutex; static TaskHandle_t __usbTask; static void __usb(void *param); extern volatile bool __freeRTOSinitted; +static void lwipThread(void *params); void startFreeRTOS(void) { TaskHandle_t c0; xTaskCreate(__core0, "CORE0", 1024, 0, configMAX_PRIORITIES / 2, &c0); vTaskCoreAffinitySet(c0, 1 << 0); - if (setup1 || loop1) { - TaskHandle_t c1; - xTaskCreate(__core1, "CORE1", 1024, 0, configMAX_PRIORITIES / 2, &c1); - vTaskCoreAffinitySet(c1, 1 << 1); - } - // Create the idle-other-core tasks (for when flash is being written) xTaskCreate(IdleThisCore, "IdleCore0", 128, 0, configMAX_PRIORITIES - 1, __idleCoreTask + 0); vTaskCoreAffinitySet(__idleCoreTask[0], 1 << 0); xTaskCreate(IdleThisCore, "IdleCore1", 128, 0, configMAX_PRIORITIES - 1, __idleCoreTask + 1); vTaskCoreAffinitySet(__idleCoreTask[1], 1 << 1); + // LWIP runs on core 0 only + __lwipQueue = xQueueCreate(16, sizeof(LWIPWork)); + //__hwMutex = xSemaphoreCreateMutex(); + xTaskCreate(lwipThread, "LWIP", 1024, 0, configMAX_PRIORITIES / 2 - 1, &__lwipTask); + vTaskCoreAffinitySet(__lwipTask, 1 << 0); + // Initialise and run the freeRTOS scheduler. Execution should never return here. __freeRTOSinitted = true; vTaskStartScheduler(); @@ -494,6 +517,7 @@ void vApplicationAssertHook() { } #endif +BaseType_t ss; static void __usb(void *param) { (void) param; @@ -505,10 +529,13 @@ static void __usb(void *param) { __usbInitted = true; while (true) { - auto m = __get_freertos_mutex_for_ptr(&__usb_mutex); - if (xSemaphoreTake(m, 0)) { - tud_task(); - xSemaphoreGive(m); + ss = xTaskGetSchedulerState(); + if (ss != taskSCHEDULER_SUSPENDED) { + auto m = __get_freertos_mutex_for_ptr(&__usb_mutex); + if (xSemaphoreTake(m, 0)) { + tud_task(); + xSemaphoreGive(m); + } } vTaskDelay(1 / portTICK_PERIOD_MS); } @@ -527,3 +554,342 @@ void __USBStart() { xTaskCreate(__usb, "USB", 256, 0, configMAX_PRIORITIES - 2, &__usbTask); vTaskCoreAffinitySet(__usbTask, 1 << 0); } + + + + + +extern "C" void __lwip(__lwip_op op, void *req) { + LWIPWork w; + TaskStatus_t t; + vTaskGetInfo(nullptr, &t, pdFALSE, eInvalid); // TODO - can we speed this up??? + w.op = op; + w.req = req; + w.wakeup = t.xHandle; + if (!xQueueSend(__lwipQueue, &w, portMAX_DELAY)) { + panic("LWIP task send failed"); + } + ulTaskNotifyTakeIndexed(TASK_NOTIFY_LWIP_WAKEUP, pdTRUE, portMAX_DELAY); +} + +extern "C" bool __isLWIPThread() { + TaskStatus_t t; + vTaskGetInfo(nullptr, &t, pdFALSE, eInvalid); // TODO - can we speed this up??? + return t.xHandle == __lwipTask; +} + + +static void lwipThread(void *params) { + (void) params; + LWIPWork w; + assert(__isLWIPThread()); + + while (true) { + if (xQueueReceive(__lwipQueue, &w, portMAX_DELAY)) { + switch (w.op) { + case __lwip_init: + { + __real_lwip_init(); + break; + } + case __pbuf_header: + { + __pbuf_header_req *r = (__pbuf_header_req *)w.req; + *(r->ret) = __real_pbuf_header(r->p, r->header_size); + break; + } + case __pbuf_free: + { + __pbuf_free_req *r = (__pbuf_free_req *)w.req; + *(r->ret) = __real_pbuf_free(r->p); + break; + } + case __pbuf_alloc: + { + __pbuf_alloc_req *r = (__pbuf_alloc_req *)w.req; + *(r->ret) = __real_pbuf_alloc(r->l, r->length, r->type); + break; + } + case __pbuf_take: + { + __pbuf_take_req *r = (__pbuf_take_req *)w.req; + *(r->ret) = __real_pbuf_take(r->buf, r->dataptr, r->len); + break; + } + case __pbuf_copy_partial: + { + __pbuf_copy_partial_req *r = (__pbuf_copy_partial_req *)w.req; + *(r->ret) = __real_pbuf_copy_partial(r->p, r->dataptr, r->len, r->offset); + break; + } + case __pbuf_ref: + { + __pbuf_ref_req *r = (__pbuf_ref_req *)w.req; + __real_pbuf_ref(r->p); + break; + } + case __pbuf_get_at: + { + __pbuf_get_at_req *r = (__pbuf_get_at_req *)w.req; + *(r->ret) = __real_pbuf_get_at(r->p, r->offset); + break; + } + case __pbuf_get_contiguous: + { + __pbuf_get_contiguous_req *r = (__pbuf_get_contiguous_req *)w.req; + *(r->ret) = __real_pbuf_get_contiguous(r->p, r->buffer, r->bufsize, r->len, r->offset); + break; + } + case __pbuf_cat: + { + __pbuf_cat_req *r = (__pbuf_cat_req *)w.req; + __real_pbuf_cat(r->head, r->tail); + break; + } + case __tcp_arg: + { + __tcp_arg_req *r = (__tcp_arg_req *)w.req; + __real_tcp_arg(r->pcb, r->arg); + break; + } + case __tcp_new: + { + __tcp_new_req *r = (__tcp_new_req *)w.req; + *(r->ret) = __real_tcp_new(); + break; + } + case __tcp_bind: + { + __tcp_bind_req *r = (__tcp_bind_req *)w.req; + *(r->ret) = __real_tcp_bind(r->pcb, r->ipaddr, r->port); + break; + } + case __tcp_listen_with_backlog: + { + __tcp_listen_with_backlog_req *r = (__tcp_listen_with_backlog_req *)w.req; + *(r->ret) = __real_tcp_listen_with_backlog(r->pcb, r->backlog); + break; + } + case __tcp_accept: + { + __tcp_accept_req *r = (__tcp_accept_req *)w.req; + __real_tcp_accept(r->pcb, r->accept); + break; + } + case __tcp_connect: + { + __tcp_connect_req *r = (__tcp_connect_req *)w.req; + *(r->ret) = __real_tcp_connect(r->pcb, r->ipaddr, r->port, r->connected); + break; + } + case __tcp_write: + { + __tcp_write_req *r = (__tcp_write_req *)w.req; + *(r->ret) = __real_tcp_write(r->pcb, r->dataptr, r->len, r->apiflags); + break; + } + case __tcp_sent: + { + __tcp_sent_req *r = (__tcp_sent_req *)w.req; + __real_tcp_sent(r->pcb, r->sent); + break; + } + case __tcp_recv: + { + __tcp_recv_req *r = (__tcp_recv_req *)w.req; + __real_tcp_recv(r->pcb, r->recv); + break; + } + case __tcp_recved: + { + __tcp_recved_req *r = (__tcp_recved_req *)w.req; + __real_tcp_recved(r->pcb, r->len); + break; + } + case __tcp_poll: + { + __tcp_poll_req *r = (__tcp_poll_req *)w.req; + __real_tcp_poll(r->pcb, r->poll, r->interval); + break; + } + case __tcp_close: + { + __tcp_close_req *r = (__tcp_close_req *)w.req; + *(r->ret) = __real_tcp_close(r->pcb); + break; + } + case __tcp_abort: + { + __tcp_abort_req *r = (__tcp_abort_req *)w.req; + __real_tcp_abort(r->pcb); + break; + } + case __tcp_err: + { + __tcp_err_req *r = (__tcp_err_req *)w.req; + __real_tcp_err(r->pcb, r->err); + break; + } + case __tcp_output: + { + __tcp_output_req *r = (__tcp_output_req *)w.req; + *(r->ret) = __real_tcp_output(r->pcb); + break; + } + case __tcp_setprio: + { + __tcp_setprio_req *r = (__tcp_setprio_req *)w.req; + __real_tcp_setprio(r->pcb, r->prio); + break; + } + case __tcp_backlog_delayed: + { + __tcp_backlog_delayed_req *r = (__tcp_backlog_delayed_req *)w.req; + __real_tcp_backlog_delayed(r->pcb); + break; + } + case __tcp_backlog_accepted: + { + __tcp_backlog_accepted_req *r = (__tcp_backlog_accepted_req *)w.req; + __real_tcp_backlog_accepted(r->pcb); + break; + } + case __udp_new: + { + __udp_new_req *r = (__udp_new_req *)w.req; + *(r->ret) = __real_udp_new(); + break; + } + case __udp_new_ip_type: + { + __udp_new_ip_type_req *r = (__udp_new_ip_type_req *)w.req; + *(r->ret) = __real_udp_new_ip_type(r->type); + break; + } + case __udp_remove: + { + __udp_remove_req *r = (__udp_remove_req *)w.req; + __real_udp_remove(r->pcb); + break; + } + case __udp_bind: + { + __udp_bind_req *r = (__udp_bind_req *)w.req; + *(r->ret) = __real_udp_bind(r->pcb, r->ipaddr, r->port); + break; + } + case __udp_connect: + { + __udp_connect_req *r = (__udp_connect_req *)w.req; + *(r->ret) = __real_udp_connect(r->pcb, r->ipaddr, r->port); + break; + } + case __udp_disconnect: + { + __udp_disconnect_req *r = (__udp_disconnect_req *)w.req; + *(r->ret) = __real_udp_disconnect(r->pcb); + break; + } + case __udp_send: + { + __udp_send_req *r = (__udp_send_req *)w.req; + *(r->ret) = __real_udp_send(r->pcb, r->p); + break; + } + case __udp_recv: + { + __udp_recv_req *r = (__udp_recv_req *)w.req; + __real_udp_recv(r->pcb, r->recv, r->recv_arg); + break; + } + case __udp_sendto: + { + __udp_sendto_req *r = (__udp_sendto_req *)w.req; + *(r->ret) = __real_udp_sendto(r->pcb, r->p, r->dst_ip, r->dst_port); + break; + } + case __udp_sendto_if: + { + __udp_sendto_if_req *r = (__udp_sendto_if_req *)w.req; + *(r->ret) = __real_udp_sendto_if(r->pcb, r->p, r->dst_ip, r->dst_port, r->netif); + break; + } + case __udp_sendto_if_src: + { + __udp_sendto_if_src_req *r = (__udp_sendto_if_src_req *)w.req; + *(r->ret) = __real_udp_sendto_if_src(r->pcb, r->p, r->dst_ip, r->dst_port, r->netif, r->src_ip); + break; + } + case __sys_check_timeouts: + { + __real_sys_check_timeouts(); + break; + } + case __dns_gethostbyname: + { + __dns_gethostbyname_req *r = (__dns_gethostbyname_req *)w.req; + *(r->ret) = __real_dns_gethostbyname(r->hostname, r->addr, r->found, r->callback_arg); + break; + } + case __dns_gethostbyname_addrtype: + { + __dns_gethostbyname_addrtype_req *r = (__dns_gethostbyname_addrtype_req *)w.req; + *(r->ret) = __real_dns_gethostbyname_addrtype(r->hostname, r->addr, r->found, r->callback_arg, r->dns_addrtype); + break; + } + case __raw_new: + { + __raw_new_req *r = (__raw_new_req *)w.req; + *(r->ret) = __real_raw_new(r->proto); + break; + } + case __raw_recv: + { + __raw_recv_req *r = (__raw_recv_req *)w.req; + __real_raw_recv(r->pcb, r->recv, r->recv_arg); + break; + } + case __raw_bind: + { + __raw_bind_req *r = (__raw_bind_req *)w.req; + *(r->ret) = __real_raw_bind(r->pcb, r->ipaddr); + break; + } + case __raw_sendto: + { + __raw_sendto_req *r = (__raw_sendto_req *)w.req; + *(r->ret) = __real_raw_sendto(r->pcb, r->p, r->ipaddr); + break; + } + case __raw_remove: + { + __raw_remove_req *r = (__raw_remove_req *)w.req; + __real_raw_remove(r->pcb); + break; + } + case __netif_add: + { + __netif_add_req *r = (__netif_add_req *)w.req; + *(r->ret) = __real_netif_add(r->netif, r->ipaddr, r->netmask, r->gw, r->state, r->init, r->input); + break; + } + case __netif_remove: + { + __netif_remove_req *r = (__netif_remove_req *)w.req; + __real_netif_remove(r->netif); + break; + } + default: + { + // Any new unimplemented calls = ERROR!!! + panic("Unimplemented LWIP thread action"); + break; + } + } + // Work done, return value set, just tickle the calling task + xTaskNotifyGiveIndexed(w.wakeup, TASK_NOTIFY_LWIP_WAKEUP); + } + } +} + +#endif diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index 97f271db3..4a5002783 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -30,55 +30,22 @@ #include #include #include "_xoshiro.h" +#include "lwip_wrap.h" -extern void ethernet_arch_lwip_begin() __attribute__((weak)); -extern void ethernet_arch_lwip_end() __attribute__((weak)); -extern void ethernet_arch_lwip_gpio_mask() __attribute__((weak)); -extern void ethernet_arch_lwip_gpio_unmask() __attribute__((weak)); - -auto_init_recursive_mutex(__lwipMutex); // Only for case with no Ethernet or PicoW, but still doing LWIP (PPP?) - -class LWIPMutex { -public: - LWIPMutex() { - if (ethernet_arch_lwip_gpio_mask) { - ethernet_arch_lwip_gpio_mask(); - } -#if defined(PICO_CYW43_SUPPORTED) - if (rp2040.isPicoW()) { - cyw43_arch_lwip_begin(); - return; - } +#if defined(__FREERTOS) +#define __isFreeRTOS 1 +#else +#define __isFreeRTOS 0 #endif - if (ethernet_arch_lwip_begin) { - ethernet_arch_lwip_begin(); - } else { - recursive_mutex_enter_blocking(&__lwipMutex); - } - } - ~LWIPMutex() { -#if defined(PICO_CYW43_SUPPORTED) - if (rp2040.isPicoW()) { - cyw43_arch_lwip_end(); - } else { -#endif - if (ethernet_arch_lwip_end) { - ethernet_arch_lwip_end(); - } else { - recursive_mutex_exit(&__lwipMutex); - } -#if defined(PICO_CYW43_SUPPORTED) - } -#endif - if (ethernet_arch_lwip_gpio_unmask) { - ethernet_arch_lwip_gpio_unmask(); - } - } -}; +//auto_init_recursive_mutex(__lwipMutex); // Only for case with no Ethernet or PicoW, but still doing LWIP (PPP?) +recursive_mutex_t __lwipMutex; extern "C" { + extern void __lwip(__lwip_op op, void *req) __attribute((weak)); + extern bool __isLWIPThread(); + static XoshiroCpp::Xoshiro256PlusPlus *_lwip_rng = nullptr; // Random number generator for LWIP unsigned long __lwip_rand() { @@ -89,6 +56,7 @@ extern "C" { extern void __real_lwip_init(); void __wrap_lwip_init() { if (!_lwip_rng) { + recursive_mutex_init(&__lwipMutex); _lwip_rng = new XoshiroCpp::Xoshiro256PlusPlus(micros() * rp2040.getCycleCount()); __real_lwip_init(); } @@ -96,276 +64,556 @@ extern "C" { extern u8_t __real_pbuf_header(struct pbuf *p, s16_t header_size); u8_t __wrap_pbuf_header(struct pbuf *p, s16_t header_size) { + if (__isFreeRTOS && !__isLWIPThread()) { + u8_t ret; + __pbuf_header_req req = { p, header_size, &ret }; + __lwip(__pbuf_header, &req); + return ret; + } LWIPMutex m; return __real_pbuf_header(p, header_size); } extern u8_t __real_pbuf_free(struct pbuf *p); u8_t __wrap_pbuf_free(struct pbuf *p) { + if (__isFreeRTOS && !__isLWIPThread()) { + u8_t ret; + __pbuf_free_req req = { p, &ret }; + __lwip(__pbuf_free, &req); + return ret; + } LWIPMutex m; return __real_pbuf_free(p); } extern struct pbuf *__real_pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type); struct pbuf *__wrap_pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type) { + if (__isFreeRTOS && !__isLWIPThread()) { + struct pbuf *ret; + __pbuf_alloc_req req = {l, length, type, &ret }; + __lwip(__pbuf_alloc, &req); + return ret; + } LWIPMutex m; return __real_pbuf_alloc(l, length, type); } extern err_t __real_pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len); err_t __wrap_pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __pbuf_take_req req = { buf, dataptr, len, &ret }; + __lwip(__pbuf_take, &req); + return ret; + } LWIPMutex m; return __real_pbuf_take(buf, dataptr, len); } extern u16_t __real_pbuf_copy_partial(const struct pbuf *p, void *dataptr, u16_t len, u16_t offset); u16_t __wrap_pbuf_copy_partial(const struct pbuf *p, void *dataptr, u16_t len, u16_t offset) { + if (__isFreeRTOS && !__isLWIPThread()) { + u16_t ret; + __pbuf_copy_partial_req req = { p, dataptr, len, offset, &ret }; + __lwip(__pbuf_copy_partial, &req); + return ret; + } LWIPMutex m; return __real_pbuf_copy_partial(p, dataptr, len, offset); } extern void __real_pbuf_ref(struct pbuf *p); void __wrap_pbuf_ref(struct pbuf *p) { + if (__isFreeRTOS && !__isLWIPThread()) { + __pbuf_ref_req req = { p }; + __lwip(__pbuf_ref, &req); + return; + } LWIPMutex m; __real_pbuf_ref(p); } extern u8_t __real_pbuf_get_at(const struct pbuf* p, u16_t offset); u8_t __wrap_pbuf_get_at(const struct pbuf* p, u16_t offset) { + if (__isFreeRTOS && !__isLWIPThread()) { + u8_t ret; + __pbuf_get_at_req req = { p, offset, &ret }; + __lwip(__pbuf_get_at, &req); + return ret; + } LWIPMutex m; return __real_pbuf_get_at(p, offset); } extern void *__real_pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset); void *__wrap_pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset) { + if (__isFreeRTOS && !__isLWIPThread()) { + void *ret; + __pbuf_get_contiguous_req req = { p, buffer, bufsize, len, offset, &ret }; + __lwip(__pbuf_get_contiguous, &req); + return ret; + } LWIPMutex m; return __real_pbuf_get_contiguous(p, buffer, bufsize, len, offset); } extern void __real_pbuf_cat(struct pbuf *head, struct pbuf *tail); void __wrap_pbuf_cat(struct pbuf *head, struct pbuf *tail) { + if (__isFreeRTOS && !__isLWIPThread()) { + __pbuf_cat_req req = { head, tail }; + __lwip(__pbuf_cat, &req); + return; + } LWIPMutex m; __real_pbuf_cat(head, tail); } extern void __real_tcp_arg(struct tcp_pcb *pcb, void *arg); void __wrap_tcp_arg(struct tcp_pcb *pcb, void *arg) { + if (__isFreeRTOS && !__isLWIPThread()) { + __tcp_arg_req req = { pcb, arg }; + __lwip(__tcp_arg, &req); + return; + } LWIPMutex m; __real_tcp_arg(pcb, arg); } extern struct tcp_pcb *__real_tcp_new(void); struct tcp_pcb *__wrap_tcp_new(void) { + if (__isFreeRTOS && !__isLWIPThread()) { + struct tcp_pcb *ret; + __tcp_new_req req = { &ret }; + __lwip(__tcp_new, &req); + return ret; + } LWIPMutex m; return __real_tcp_new(); } extern err_t __real_tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port); err_t __wrap_tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __tcp_bind_req req = { pcb, ipaddr, port, &ret }; + __lwip(__tcp_bind, &req); + return ret; + } LWIPMutex m; return __real_tcp_bind(pcb, ipaddr, port); } - extern struct tcp_pcb *__real_tcp_listen(struct tcp_pcb *pcb); - struct tcp_pcb *__wrap_tcp_listen(struct tcp_pcb *pcb) { - LWIPMutex m; - return __real_tcp_listen(pcb); - } - extern struct tcp_pcb *__real_tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); struct tcp_pcb *__wrap_tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) { + if (__isFreeRTOS && !__isLWIPThread()) { + struct tcp_pcb *ret; + __tcp_listen_with_backlog_req req = { pcb, backlog, &ret }; + __lwip(__tcp_listen_with_backlog, &req); + return ret; + } LWIPMutex m; return __real_tcp_listen_with_backlog(pcb, backlog); } extern void __real_tcp_accept(struct tcp_pcb *pcb, err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)); void __wrap_tcp_accept(struct tcp_pcb *pcb, err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)) { + if (__isFreeRTOS && !__isLWIPThread()) { + __tcp_accept_req req = { pcb, accept }; + __lwip(__tcp_accept, &req); + return; + } LWIPMutex m; __real_tcp_accept(pcb, accept); } extern err_t __real_tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)); err_t __wrap_tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __tcp_connect_req req = { pcb, ipaddr, port, connected, &ret }; + __lwip(__tcp_connect, &req); + return ret; + } LWIPMutex m; return __real_tcp_connect(pcb, ipaddr, port, connected); } extern err_t __real_tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len, u8_t apiflags); err_t __wrap_tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len, u8_t apiflags) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __tcp_write_req req = { pcb, dataptr, len, apiflags, &ret }; + __lwip(__tcp_write, &req); + return ret; + } LWIPMutex m; return __real_tcp_write(pcb, dataptr, len, apiflags); } extern void __real_tcp_sent(struct tcp_pcb *pcb, err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len)); void __wrap_tcp_sent(struct tcp_pcb *pcb, err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len)) { + if (__isFreeRTOS && !__isLWIPThread()) { + __tcp_sent_req req = { pcb, sent }; + __lwip(__tcp_sent, &req); + return; + } LWIPMutex m; __real_tcp_sent(pcb, sent); } extern void __real_tcp_recv(struct tcp_pcb *pcb, err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)); void __wrap_tcp_recv(struct tcp_pcb *pcb, err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)) { + if (__isFreeRTOS && !__isLWIPThread()) { + __tcp_recv_req req = { pcb, recv }; + __lwip(__tcp_recv, &req); + return; + } LWIPMutex m; __real_tcp_recv(pcb, recv); } extern void __real_tcp_recved(struct tcp_pcb *pcb, u16_t len); void __wrap_tcp_recved(struct tcp_pcb *pcb, u16_t len) { + if (__isFreeRTOS && !__isLWIPThread()) { + __tcp_recved_req req = { pcb, len }; + __lwip(__tcp_recved, &req); + return; + } LWIPMutex m; __real_tcp_recved(pcb, len); } extern void __real_tcp_poll(struct tcp_pcb *pcb, err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval); void __wrap_tcp_poll(struct tcp_pcb *pcb, err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval) { + if (__isFreeRTOS && !__isLWIPThread()) { + __tcp_poll_req req = { pcb, poll, interval }; + __lwip(__tcp_poll, &req); + return; + } LWIPMutex m; __real_tcp_poll(pcb, poll, interval); } extern err_t __real_tcp_close(struct tcp_pcb *pcb); err_t __wrap_tcp_close(struct tcp_pcb *pcb) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __tcp_close_req req = { pcb, &ret }; + __lwip(__tcp_close, &req); + return ret; + } LWIPMutex m; return __real_tcp_close(pcb); } extern void __real_tcp_abort(struct tcp_pcb *pcb); void __wrap_tcp_abort(struct tcp_pcb *pcb) { + if (__isFreeRTOS && !__isLWIPThread()) { + __tcp_abort_req req = { pcb }; + __lwip(__tcp_abort, &req); + return; + } LWIPMutex m; __real_tcp_abort(pcb); } extern void __real_tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg, err_t err)); void __wrap_tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg, err_t err)) { + if (__isFreeRTOS && !__isLWIPThread()) { + __tcp_err_req req = { pcb, err }; + __lwip(__tcp_err, &req); + return; + } LWIPMutex m; __real_tcp_err(pcb, err); } extern err_t __real_tcp_output(struct tcp_pcb *pcb); err_t __wrap_tcp_output(struct tcp_pcb *pcb) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __tcp_output_req req = { pcb, &ret }; + __lwip(__tcp_output, &req); + return ret; + } LWIPMutex m; return __real_tcp_output(pcb); } extern void __real_tcp_setprio(struct tcp_pcb *pcb, u8_t prio); void __wrap_tcp_setprio(struct tcp_pcb *pcb, u8_t prio) { + if (__isFreeRTOS && !__isLWIPThread()) { + __tcp_setprio_req req = { pcb, prio }; + __lwip(__tcp_setprio, &req); + return; + } LWIPMutex m; __real_tcp_setprio(pcb, prio); } extern void __real_tcp_backlog_delayed(struct tcp_pcb* pcb); void __wrap_tcp_backlog_delayed(struct tcp_pcb* pcb) { + if (__isFreeRTOS && !__isLWIPThread()) { + __tcp_backlog_delayed_req req = { pcb }; + __lwip(__tcp_backlog_delayed, &req); + return; + } LWIPMutex m; __real_tcp_backlog_delayed(pcb); } extern void __real_tcp_backlog_accepted(struct tcp_pcb* pcb); void __wrap_tcp_backlog_accepted(struct tcp_pcb* pcb) { + if (__isFreeRTOS && !__isLWIPThread()) { + __tcp_backlog_accepted_req req = { pcb }; + __lwip(__tcp_backlog_accepted, &req); + return; + } LWIPMutex m; __real_tcp_backlog_accepted(pcb); } extern struct udp_pcb *__real_udp_new(void); struct udp_pcb *__wrap_udp_new(void) { + if (__isFreeRTOS && !__isLWIPThread()) { + struct udp_pcb *ret; + __udp_new_req req = { &ret }; + __lwip(__udp_new, &req); + return ret; + } LWIPMutex m; return __real_udp_new(); } + extern struct udp_pcb *__real_udp_new_ip_type(u8_t type); + struct udp_pcb *__wrap_udp_new_ip_type(u8_t type) { + if (__isFreeRTOS && !__isLWIPThread()) { + struct udp_pcb *ret; + __udp_new_ip_type_req req = { type, &ret }; + __lwip(__udp_new_ip_type, &req); + return ret; + } + LWIPMutex m; + return __real_udp_new_ip_type(type); + } + extern void __real_udp_remove(struct udp_pcb *pcb); void __wrap_udp_remove(struct udp_pcb *pcb) { + if (__isFreeRTOS && !__isLWIPThread()) { + __udp_remove_req req = { pcb }; + __lwip(__udp_remove, &req); + return; + } LWIPMutex m; __real_udp_remove(pcb); } extern err_t __real_udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port); err_t __wrap_udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __udp_bind_req req = { pcb, ipaddr, port, &ret }; + __lwip(__udp_bind, &req); + return ret; + } LWIPMutex m; return __real_udp_bind(pcb, ipaddr, port); } extern err_t __real_udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port); err_t __wrap_udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __udp_connect_req req = { pcb, ipaddr, port, &ret }; + __lwip(__udp_connect, &req); + return ret; + } LWIPMutex m; return __real_udp_connect(pcb, ipaddr, port); } extern err_t __real_udp_disconnect(struct udp_pcb *pcb); err_t __wrap_udp_disconnect(struct udp_pcb *pcb) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __udp_disconnect_req req = { pcb, &ret }; + __lwip(__udp_disconnect, &req); + return ret; + } LWIPMutex m; return __real_udp_disconnect(pcb); } extern err_t __real_udp_send(struct udp_pcb *pcb, struct pbuf *p); err_t __wrap_udp_send(struct udp_pcb *pcb, struct pbuf *p) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __udp_send_req req = { pcb, p, &ret }; + __lwip(__udp_send, &req); + return ret; + } LWIPMutex m; return __real_udp_send(pcb, p); } extern void __real_udp_recv(struct udp_pcb *pcb, void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port), void *recv_arg); void __wrap_udp_recv(struct udp_pcb *pcb, void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port), void *recv_arg) { + if (__isFreeRTOS && !__isLWIPThread()) { + __udp_recv_req req = { pcb, recv, recv_arg }; + __lwip(__udp_recv, &req); + return; + } LWIPMutex m; __real_udp_recv(pcb, recv, recv_arg); } + extern err_t __real_udp_sendto(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port); + err_t __wrap_udp_sendto(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __udp_sendto_req req = { pcb, p, dst_ip, dst_port, &ret }; + __lwip(__udp_sendto, &req); + return ret; + } + LWIPMutex m; + return __real_udp_sendto(pcb, p, dst_ip, dst_port); + } + extern err_t __real_udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif); err_t __wrap_udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __udp_sendto_if_req req = { pcb, p, dst_ip, dst_port, netif, &ret }; + __lwip(__udp_sendto_if, &req); + return ret; + } LWIPMutex m; return __real_udp_sendto_if(pcb, p, dst_ip, dst_port, netif); } + extern err_t __real_udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, const ip_addr_t *src_ip); + err_t __wrap_udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, const ip_addr_t *src_ip) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __udp_sendto_if_src_req req = { pcb, p, dst_ip, dst_port, netif, src_ip, &ret }; + __lwip(__udp_sendto_if_src, &req); + return ret; + } + LWIPMutex m; + return __real_udp_sendto_if_src(pcb, p, dst_ip, dst_port, netif, src_ip); + } + // sys_check_timeouts is special case because the async process will call it. If we're already in a timeout check, just do a noop extern void __real_sys_check_timeouts(); void __wrap_sys_check_timeouts(void) { + if (__isFreeRTOS && !__isLWIPThread()) { + __lwip(__sys_check_timeouts, nullptr); + return; + } LWIPMutex m; __real_sys_check_timeouts(); } extern err_t __real_dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg); err_t __wrap_dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __dns_gethostbyname_req req = { hostname, addr, found, callback_arg, &ret }; + __lwip(__dns_gethostbyname, &req); + return ret; + } LWIPMutex m; return __real_dns_gethostbyname(hostname, addr, found, callback_arg); } extern err_t __real_dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg, u8_t dns_addrtype); err_t __wrap_dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg, u8_t dns_addrtype) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __dns_gethostbyname_addrtype_req req = { hostname, addr, found, callback_arg, dns_addrtype, &ret }; + __lwip(__dns_gethostbyname_addrtype, &req); + return ret; + } LWIPMutex m; return __real_dns_gethostbyname_addrtype(hostname, addr, found, callback_arg, dns_addrtype); } extern struct raw_pcb *__real_raw_new(u8_t proto); struct raw_pcb *__wrap_raw_new(u8_t proto) { + if (__isFreeRTOS && !__isLWIPThread()) { + struct raw_pcb *ret; + __raw_new_req req = { proto, &ret }; + __lwip(__raw_new, &req); + return ret; + } LWIPMutex m; return __real_raw_new(proto); } extern void __real_raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg); void __wrap_raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) { + if (__isFreeRTOS && !__isLWIPThread()) { + __raw_recv_req req = { pcb, recv, recv_arg }; + __lwip(__raw_recv, &req); + return; + } LWIPMutex m; __real_raw_recv(pcb, recv, recv_arg); } extern err_t __real_raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr); err_t __wrap_raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __raw_bind_req req = { pcb, ipaddr, &ret }; + __lwip(__raw_bind, &req); + return ret; + } LWIPMutex m; return __real_raw_bind(pcb, ipaddr); } extern err_t __real_raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr); err_t __wrap_raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) { + if (__isFreeRTOS && !__isLWIPThread()) { + err_t ret; + __raw_sendto_req req = { pcb, p, ipaddr, &ret }; + __lwip(__raw_sendto, &req); + return ret; + } LWIPMutex m; return __real_raw_sendto(pcb, p, ipaddr); } extern void __real_raw_remove(struct raw_pcb *pcb); void __wrap_raw_remove(struct raw_pcb *pcb) { + if (__isFreeRTOS && !__isLWIPThread()) { + __raw_remove_req req = { pcb }; + __lwip(__raw_remove, &req); + return; + } LWIPMutex m; __real_raw_remove(pcb); } extern struct netif *__real_netif_add(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input); struct netif *__wrap_netif_add(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input) { + if (__isFreeRTOS && !__isLWIPThread()) { + struct netif *ret; + __netif_add_req req = { netif, ipaddr, netmask, gw, state, init, input, &ret }; + __lwip(__netif_add, &req); + return ret; + } LWIPMutex m; return __real_netif_add(netif, ipaddr, netmask, gw, state, init, input); } extern void __real_netif_remove(struct netif *netif); void __wrap_netif_remove(struct netif *netif) { + if (__isFreeRTOS && !__isLWIPThread()) { + __netif_remove_req req = { netif }; + __lwip(__netif_remove, &req); + return; + } LWIPMutex m; __real_netif_remove(netif); } diff --git a/cores/rp2040/main.cpp b/cores/rp2040/main.cpp index 5db9e4e8e..f31ffa3b5 100644 --- a/cores/rp2040/main.cpp +++ b/cores/rp2040/main.cpp @@ -135,12 +135,14 @@ extern "C" int main() { rp2040.begin(0); - initVariant(); - #ifdef __FREERTOS initFreeRTOS(); + // initVariant will be done in the freertos task +#else + initVariant(); #endif + #ifndef NO_USB #ifdef USE_TINYUSB TinyUSB_Device_Init(0); diff --git a/cores/rp2040/sdkoverride/async_context_freertos.c b/cores/rp2040/sdkoverride/async_context_freertos.c new file mode 100644 index 000000000..27c75588e --- /dev/null +++ b/cores/rp2040/sdkoverride/async_context_freertos.c @@ -0,0 +1,3 @@ +#ifdef __FREERTOS +#include "../../../pico-sdk/src/rp2_common/pico_async_context/async_context_freertos.c" +#endif diff --git a/cores/rp2040/sdkoverride/async_context_threadsafe_background.c b/cores/rp2040/sdkoverride/async_context_threadsafe_background.c new file mode 100644 index 000000000..ba5282af5 --- /dev/null +++ b/cores/rp2040/sdkoverride/async_context_threadsafe_background.c @@ -0,0 +1,3 @@ +#ifndef __FREERTOS +#include "../../../pico-sdk/src/rp2_common/pico_async_context/async_context_threadsafe_background.c" +#endif diff --git a/cores/rp2040/sdkoverride/cyw43_arch_freertos.c b/cores/rp2040/sdkoverride/cyw43_arch_freertos.c new file mode 100644 index 000000000..6b55f66d6 --- /dev/null +++ b/cores/rp2040/sdkoverride/cyw43_arch_freertos.c @@ -0,0 +1,96 @@ +#if defined(__FREERTOS) +// Taken from SDK because we need to remove the !NO_SYS check +#define PICO_CYW43_ARCH_FREERTOS 1 +/* + * Copyright (c) 2022 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#if PICO_CYW43_ARCH_FREERTOS + +#include "pico/cyw43_arch.h" +#include "pico/cyw43_driver.h" +#include "pico/async_context_freertos.h" + +#if CYW43_LWIP +#include "pico/lwip_freertos.h" +#include +#endif + +#if CYW43_ENABLE_BLUETOOTH +#include "pico/btstack_cyw43.h" +#endif + +//#if NO_SYS +//#error example_cyw43_arch_freetos_sys requires NO_SYS=0 +//#endif + +static async_context_freertos_t cyw43_async_context_freertos; + +#if configSUPPORT_STATIC_ALLOCATION && !CYW43_NO_DEFAULT_TASK_STACK +static StackType_t cyw43_async_context_freertos_task_stack[CYW43_TASK_STACK_SIZE]; +#endif + +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 +#ifdef CYW43_TASK_STACK_SIZE + config.task_stack_size = CYW43_TASK_STACK_SIZE; +#endif +#if configSUPPORT_STATIC_ALLOCATION && !CYW43_NO_DEFAULT_TASK_STACK + config.task_stack = cyw43_async_context_freertos_task_stack; +#endif + if (async_context_freertos_init(&cyw43_async_context_freertos, &config)) + return &cyw43_async_context_freertos.core; + return NULL; +} + +int cyw43_arch_init(void) { + 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_freertos_init(context); +#endif +#if CYW43_ENABLE_BLUETOOTH + ok &= btstack_cyw43_init(context); +#endif + if (!ok) { + cyw43_arch_deinit(); + return PICO_ERROR_GENERIC; + } else { + return 0; + } +} + +void cyw43_arch_deinit(void) { + async_context_t *context = cyw43_arch_async_context(); +#if CYW43_ENABLE_BLUETOOTH + btstack_cyw43_deinit(context); +#endif + // 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 + // 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); + } +} + +#endif + +#endif diff --git a/cores/rp2040/sdkoverride/cyw43_arch_threadsafe_background.c b/cores/rp2040/sdkoverride/cyw43_arch_threadsafe_background.c new file mode 100644 index 000000000..cd8a0619e --- /dev/null +++ b/cores/rp2040/sdkoverride/cyw43_arch_threadsafe_background.c @@ -0,0 +1,4 @@ +#if !defined(__FREERTOS) +#define PICO_CYW43_ARCH_THREADSAFE_BACKGROUND 1 +#include "../../../pico-sdk/src/rp2_common/pico_cyw43_arch/cyw43_arch_threadsafe_background.c" +#endif diff --git a/include/lwipopts.h b/include/lwipopts.h index 6e8b5e016..294f6da0f 100644 --- a/include/lwipopts.h +++ b/include/lwipopts.h @@ -38,6 +38,8 @@ extern unsigned long __lwip_rand(void); #define TCP_MSS 1460 #define TCP_SND_BUF (8 * TCP_MSS) #define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS)) +#define TCP_LISTEN_BACKLOG 1 +#define TCP_DEFAULT_LISTEN_BACKLOG (2 * __LWIP_MEMMULT) #define LWIP_NETIF_STATUS_CALLBACK 1 #define LWIP_NETIF_LINK_CALLBACK 1 #define LWIP_NETIF_HOSTNAME 1 @@ -80,35 +82,37 @@ extern void __setSystemTime(unsigned long long sec, unsigned long us); //#define SNTP_SERVER_ADDRESS "pool.ntp.org" #define SNTP_SERVER_DNS 1 -#define LWIP_DEBUG 0 -#define ETHARP_DEBUG LWIP_DBG_OFF -#define NETIF_DEBUG LWIP_DBG_OFF -#define PBUF_DEBUG LWIP_DBG_OFF -#define API_LIB_DEBUG LWIP_DBG_OFF -#define API_MSG_DEBUG LWIP_DBG_OFF -#define SOCKETS_DEBUG LWIP_DBG_OFF -#define ICMP_DEBUG LWIP_DBG_OFF -#define INET_DEBUG LWIP_DBG_OFF -#define IP_DEBUG LWIP_DBG_OFF -#define IP_REASS_DEBUG LWIP_DBG_OFF -#define RAW_DEBUG LWIP_DBG_OFF -#define MEM_DEBUG LWIP_DBG_OFF -#define MEMP_DEBUG LWIP_DBG_OFF -#define SYS_DEBUG LWIP_DBG_OFF -#define TCP_DEBUG LWIP_DBG_OFF -#define TCP_INPUT_DEBUG LWIP_DBG_OFF -#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF -#define TCP_RTO_DEBUG LWIP_DBG_OFF -#define TCP_CWND_DEBUG LWIP_DBG_OFF -#define TCP_WND_DEBUG LWIP_DBG_OFF -#define TCP_FR_DEBUG LWIP_DBG_OFF -#define TCP_QLEN_DEBUG LWIP_DBG_OFF -#define TCP_RST_DEBUG LWIP_DBG_OFF -#define UDP_DEBUG LWIP_DBG_OFF -#define TCPIP_DEBUG LWIP_DBG_OFF -#define PPP_DEBUG LWIP_DBG_OFF -#define SLIP_DEBUG LWIP_DBG_OFF -#define DHCP_DEBUG LWIP_DBG_OFF +#ifndef LWIP_DEBUG +#define LWIP_DEBUG 1 +#endif +#define ETHARP_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define NETIF_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define PBUF_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define API_LIB_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define API_MSG_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define SOCKETS_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define ICMP_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define INET_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define IP_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define IP_REASS_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define RAW_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define MEM_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define MEMP_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define SYS_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define TCP_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define TCP_INPUT_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define TCP_OUTPUT_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define TCP_RTO_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define TCP_CWND_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define TCP_WND_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define TCP_FR_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define TCP_QLEN_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define TCP_RST_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define UDP_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define TCPIP_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define PPP_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define SLIP_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) +#define DHCP_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) #ifdef __cplusplus } diff --git a/lib/core_inc.txt b/lib/core_inc.txt index ae6e3275d..01b7d955c 100644 --- a/lib/core_inc.txt +++ b/lib/core_inc.txt @@ -66,3 +66,5 @@ -iwithprefixbefore/pico-sdk/src/rp2_common/pico_stdio_uart/include -iwithprefixbefore/pico-sdk/src/rp2_common/pico_unique_id/include -iwithprefixbefore/pico-sdk/lib/lwip/src/include + +-iwithprefixbefore/cores/rp2040/freertos diff --git a/lib/core_wrap.txt b/lib/core_wrap.txt index 3b94fd31e..40606172f 100644 --- a/lib/core_wrap.txt +++ b/lib/core_wrap.txt @@ -21,7 +21,6 @@ -Wl,--wrap=tcp_arg -Wl,--wrap=tcp_new -Wl,--wrap=tcp_bind --Wl,--wrap=tcp_listen -Wl,--wrap=tcp_listen_with_backlog -Wl,--wrap=tcp_accept -Wl,--wrap=tcp_connect @@ -39,13 +38,16 @@ -Wl,--wrap=tcp_backlog_accepted -Wl,--wrap=udp_new +-Wl,--wrap=udp_new_ip_type -Wl,--wrap=udp_remove -Wl,--wrap=udp_bind -Wl,--wrap=udp_connect -Wl,--wrap=udp_disconnect -Wl,--wrap=udp_send -Wl,--wrap=udp_recv +-Wl,--wrap=udp_sendto -Wl,--wrap=udp_sendto_if +-Wl,--wrap=udp_sendto_if_src -Wl,--wrap=sys_check_timeouts diff --git a/lib/platform_def.txt b/lib/platform_def.txt index 9a8be6f09..ba73b65bf 100644 --- a/lib/platform_def.txt +++ b/lib/platform_def.txt @@ -62,7 +62,6 @@ -DPICO_32BIT=1 -DPICO_BUILD=1 -DPICO_COPY_TO_RAM=0 --DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 -DPICO_NO_BINARY_INFO=1 -DPICO_NO_FLASH=0 -DPICO_NO_HARDWARE=0 @@ -71,3 +70,6 @@ -DPICO_RP2040_USB_DEVICE_UFRAME_FIX=1 -DPICO_USE_BLOCKED_RAM=0 -DPICO_XOSC_STARTUP_DELAY_MULTIPLIER=64 + +-DPICO_CYW43_ARCH_HEADER=stdint.h +-DCYW43_TASK_STACK_SIZE=1024 diff --git a/lib/rp2040/liblwip-bt.a b/lib/rp2040/liblwip-bt.a index 712a0bb8fab08245bdab0924e9ae9c0c4f496d2b..0e95fc6f834df5a086baa334bd0ebf6d071dcd24 100644 GIT binary patch delta 29758 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 B65{{> delta 67479 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 diff --git a/lib/rp2040/liblwip.a b/lib/rp2040/liblwip.a index c7a50285e37332e597b98b1bdda24d2133acc048..fe30c59ba55acda0bdeac457535d66eeac9a4db6 100644 GIT binary patch delta 17753 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∾eUkR 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 delta 58475 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 BvGD)^ diff --git a/lib/rp2040/libpico.a b/lib/rp2040/libpico.a index 0b8ae3fd40bae5ff3e36c555e2b69e3885699490..1db040389a38a3c9f5d803e48bf085382cce3bce 100644 GIT binary patch delta 1547 zcmY+ET}V_>5XaeF_pV;uyY8<05muz7SqPEkmWf(c4`vDmMQv$RAQ-t(5#&o>V5zuU zCVKrqK_!Ds!}eh+vh*nsjf_4Gg$x6;U9cePp{;Yzy))X|o!^<6GxMLhr@r4?-|xMd zXv*BUDJvtxGnhQFU;ECK1G-pO(0X8C8IggNQLfM8bQ`uHf%$ zVJnhgxTSh68gkjR(G_eMZc8T88IWATg3l)%MEErmzrHsU@mcL|n7N@FX+hK&ZgIkJ zn*O-~39wqa3el3oX%;sWU(g?mC#2+s@f!VuDnd$+(4jY!yEWvIm3km4(QxY{da=9Q z@am`G4YdI*)m#mpL+72S*$rqhZx?jEi`rL!L{?M+Tat0M2oXel#zUvcVycuTp`}*v z;ji(l6A{n($ti@>k*H3gox7cNF6(Qy3M(I)^oUanD(vTo>SqPCOv+~^_ z)(TD3gPMKlq432{sknM0V?rbr5wB|Mz0jMzgt(zQ!Q@|$L}rb;peWCje2NfP*xzUB zT`Zj^FBvxZuAmneeR@Z!v(r{4gS5 zDC9+pS3S2}yt_Cbo_Mfa)Gv0+7h|GI99`Ugjvh6NUfh*T_4C3c8uG|oa&x;`Y9PdCm6a})9mhamv+}#p;!gq;^h#|c0asJ^ zO!93eC%%UMA5z9@LR{b}r$w}B$OG*ET;$(j2(?XmxAZ& zGL%-wKLtW+`8n47LxhxCuD3Q@p|#moybUpgU)qMUG)tS}sA%sH$bmgLmF@pI$el5c zLfGAJ--BLS;6Tvcg-BDi^07Ui7Fk`A7ugA|Fmyi-UM3x#exx%re4>tF%I_ye)6Lar7nz|8j;TKAr?YsT~C0XDa delta 1547 zcmY+EZAepL6vx@-?%dVgy}yJNX=x@xq{}i<%j$!ff-tT3Q}rVmq%%15;fNi{;RQdQ}QBBveyQGJ8JR#*Tx`TB(04CpVLMtxZHN93F-HoKh*Fopl&D@PMg$R$x~zs-q$}l# zXvrCT`m6qCLqucF*|=~z5?K`5&%L)WB=r{Nj&o_77?N&o6Y7iLQZ09l4GAJwxDc~M zlD-4@Ca#^;AV(j2%zZVpP|{Rje3FaAA);B$e&hyo)({5_STx==BqAx)4#oMJq;m|> z4ts|*gR802;H3eL=PIgb(}VkB6{%6;6s6UIm8#hJXDAXQHmd_7DcVpTL&0$^sismp zbpjC(6mp?OvtC@!-(Q^%4Ln-OD_5(fi!oixPvG{;?*X2)@h;qzO!@kZ2fQ&KqsyJE zSmIM~cupX(3YSm-!S8X~b~8&zj?dkNmh4=0GG57?Wz=*b-aUgVAnBgR=S9+zmaERK zyUPYjDzw4gO5L3lbP?;ekUlBBx{xl4obqeX_2`6FhUl!a(*^fwbObUhuN^J=OMt>b zp_{dUc2n^}@Hm->uA%p*kg=H|+TdB6o;O926Uh5qzJmf9Wo1&|9K+6i)A~f;nsXaW zo-$la#&dZY${P&N0Y&nvW#<|T%9u*Zm0BHH-nQd`e~ Ee>5cGasU7T diff --git a/lib/rp2350-riscv/liblwip-bt.a b/lib/rp2350-riscv/liblwip-bt.a index 297a39cd2d7da5865a42291acc26cdb810d08d2c..0a582be5ac696d5854c2734bf549dae574cb5b6d 100644 GIT binary patch delta 63029 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%0AJc+mco|&Rb4rSCJWC%ZXi+R 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 diff --git a/lib/rp2350-riscv/liblwip.a b/lib/rp2350-riscv/liblwip.a index bafe97962ef47940851c7ff435c0727395809a6a..014885575158f2b065c6852f99bf3b96618b3fe2 100644 GIT binary patch delta 52265 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 Wc}>TCmAkC7)n;B(N+j=r%Krzm0GX2j delta 150120 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 diff --git a/lib/rp2350/liblwip-bt.a b/lib/rp2350/liblwip-bt.a index 0c9ae4538fc951962e74de8bd7311084fc0356df..6c5cf8cc4ef8b54f625bb39e16a2c3c20cd8691c 100644 GIT binary patch delta 30456 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 An&ph+Y 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 A8UO$Q diff --git a/lib/rp2350/liblwip.a b/lib/rp2350/liblwip.a index 189fd8e37e54b89b2e8a7cadf5b6928943ed4cc9..4d0e9faf64f258e1cc1295025ed6c7bec9d55423 100644 GIT binary patch delta 18460 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 delta 1514 zcmY+ETSydP6vt6_XWZNDy6f(YT9HO+CFHuZt|o#Hr77s*Mg>YK7Cv;*9xHtiyShr6 zrUTtp)Q5<~Y^xK6W(4)11tAqBrDgTdMWrk-Mf-NKTzr)C~b~o zMYl7}Bc}ExJo72vE?02cr;BA|gDbdr_!mbFsnU2r%LmOh3#>{8hj}5Gd@9DOl8!P? z2p(w9OQH(Wl$jBNLj(Wf5d?hULU3ZdB8vj>t_l0pjMhg)5xl)&%+=#+&Xp%y?!n{+neIrHgmLoir zmS_^%Xn?d>6e&PpT62lE$|XX!QTt^F4G^UcQVnd|rESYc4IpjO9mPvv+RU7e$CE@( zBwHu5HDS2|58rn(<>{(db8Z9=hZ>o$c8c6`@1d%b>GY~zN4=~7DZiK=8=}@}(yKWw z`+!Fh%8!SU)oi;H5s)}-G@hivZKUBB_p?2E70EHBmFz+mMRJ)uRNrL(CR5}IwW{eY zd+-?cmb7Ye6>5a6hN{TUS_De7ho>TSNfc#Ba+$w*-HkV@S7^oH;gqg;4@IK1)@Btz z%+)*hQbe0^vRnUQH$@&P`-(+?+ByBz#+6!`=M0y0sMYQx)10|rn8iFriA+-fW3S<7 zp5i2?+?zE#|EP+{JM!b5@fGffOWC+Fjfsm|>1A}7>JwEY?`1H{WW~2Z>z(kL%9rYu z(>{>M#p5fZ@?CB&R+X2>I-0``#87oNkhJ=-ksc+Z>UysDHabXye{7`GOtU=)5m@TX z$5BCq=F8@f0=0RR^=i6f-nXA3kzDEkya@}DS*N_$LEI*_Rslqeyh{0}+XP-%sR zO4}JaD3^RW4_ofr{OXTL!89?wG?C2C*~tQSI^ztYN^-*@v`CUX#qyH;MQf=~xy)k{}W9 w%#IOM$p}54A-m)0`IV*gc02SP6uE)C+|>qjXzwHcp?NRgU$bN%=JT!p0rJn*6aWAK diff --git a/libraries/FreeRTOS/examples/Multicore-FreeRTOS/Multicore-FreeRTOS.ino b/libraries/FreeRTOS/examples/Multicore-FreeRTOS/Multicore-FreeRTOS.ino deleted file mode 100644 index c4cd6329c..000000000 --- a/libraries/FreeRTOS/examples/Multicore-FreeRTOS/Multicore-FreeRTOS.ino +++ /dev/null @@ -1,87 +0,0 @@ -// Demonstrates a simple use of the setup1()/loop1() functions -// for a multiprocessor run. - -// Will output something like, where C0 is running on core 0 and -// C1 is on core 1, in parallel. - -// 11:23:07.507 -> C0: Blue leader standing by... -// 11:23:07.507 -> C1: Red leader standing by... -// 11:23:07.507 -> C1: Stay on target... -// 11:23:08.008 -> C1: Stay on target... -// 11:23:08.505 -> C0: Blue leader standing by... -// 11:23:08.505 -> C1: Stay on target... -// 11:23:09.007 -> C1: Stay on target... -// 11:23:09.511 -> C0: Blue leader standing by... -// 11:23:09.511 -> C1: Stay on target... -// 11:23:10.015 -> C1: Stay on target... - -// Released to the public domain -#include -#include -#include -#include - -std::map eTaskStateName { {eReady, "Ready"}, { eRunning, "Running" }, {eBlocked, "Blocked"}, {eSuspended, "Suspended"}, {eDeleted, "Deleted"} }; -void ps() { - int tasks = uxTaskGetNumberOfTasks(); - TaskStatus_t *pxTaskStatusArray = new TaskStatus_t[tasks]; - unsigned long runtime; - tasks = uxTaskGetSystemState( pxTaskStatusArray, tasks, &runtime ); - Serial.printf("# Tasks: %d\n", tasks); - Serial.println("ID, NAME, STATE, PRIO, CYCLES"); - for (int i=0; i < tasks; i++) { - Serial.printf("%d: %-16s %-10s %d %lu\n", i, pxTaskStatusArray[i].pcTaskName, eTaskStateName[pxTaskStatusArray[i].eCurrentState], (int)pxTaskStatusArray[i].uxCurrentPriority, pxTaskStatusArray[i].ulRunTimeCounter); - } - delete[] pxTaskStatusArray; -} - - -void blink(void *param) { - (void) param; - delay(500); - pinMode(LED_BUILTIN, OUTPUT); - while (true) { - digitalWrite(LED_BUILTIN, LOW); - delay(750); - digitalWrite(LED_BUILTIN, HIGH); - delay(250); - } -} - - -void setup() { - TaskHandle_t blinkTask; - Serial.begin(115200); - xTaskCreate(blink, "BLINK", 256, nullptr, 1, &blinkTask); -#if defined(PICO_CYW43_SUPPORTED) - // The PicoW WiFi chip controls the LED, and only core 0 can make calls to it safely - vTaskCoreAffinitySet(blinkTask, 1 << 0); -#endif - delay(5000); -} - -volatile int val = 0; -void loop() { - Serial.printf("C0: Blue leader standing by...\n"); - ps(); - Serial.printf("val: %d\n", val); - delay(1000); -} - -// Running on core1 -void setup1() { - delay(5000); - Serial.printf("C1: Red leader standing by...\n"); -} - -void loop1() { - static int x = 0; - Serial.printf("C1: Stay on target...\n"); - val++; - if (++x < 10) { - EEPROM.begin(512); - EEPROM.write(0,x); - EEPROM.commit(); - } - delay(1000); -} diff --git a/libraries/FreeRTOS/examples/StaticMulticore-FreeRTOS/StaticMulticore-FreeRTOS.ino b/libraries/FreeRTOS/examples/StaticMulticore-FreeRTOS/StaticMulticore-FreeRTOS.ino deleted file mode 100644 index 2e8cef17d..000000000 --- a/libraries/FreeRTOS/examples/StaticMulticore-FreeRTOS/StaticMulticore-FreeRTOS.ino +++ /dev/null @@ -1,94 +0,0 @@ -/* The code in this example is mostly derived from the official FreeRTOS - * code examples. - * - * For more information on static allocation and to read the original - * code visit the following links: - * https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html - * https://www.freertos.org/xTaskCreateStatic.html - * https://www.freertos.org/xSemaphoreCreateMutexStatic.html - */ - -#include -#include -#include - -#define SERIAL_PORT Serial -#define BLINK_ON_TIME 250 -#define BLINK_OFF_TIME 500 - -/* Dimensions of the buffer that the task being created will use as its stack. - NOTE: This is the number of words the stack will hold, not the number of - bytes. For example, if each stack item is 32-bits, and this is set to 100, - then 400 bytes (100 * 32-bits) will be allocated. */ -#define STACK_SIZE 200 - -/* Structure that will hold the TCB of the task being created. */ -StaticTask_t xTaskBuffer_A; -StaticTask_t xTaskBuffer_B; - -/* Buffer that the task being created will use as its stack. Note this is - an array of StackType_t variables. The size of StackType_t is dependent on - the RTOS port. */ -StackType_t xStack_A[ STACK_SIZE ]; -StackType_t xStack_B[ STACK_SIZE ]; - -SemaphoreHandle_t xSemaphore = NULL; -StaticSemaphore_t xMutexBuffer; - -TaskHandle_t ledOnTask, ledOffTask; - -void setup() { - SERIAL_PORT.begin(115200); - pinMode(LED_BUILTIN, OUTPUT); - - /* Create a mutex semaphore without using any dynamic memory - allocation. The mutex's data structures will be saved into - the xMutexBuffer variable. */ - xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer ); - - ledOnTask = xTaskCreateStatic(led_ON, "led_ON", STACK_SIZE, NULL, configMAX_PRIORITIES - 1, xStack_A, &xTaskBuffer_A); -#if defined(PICO_CYW43_SUPPORTED) - // The PicoW WiFi chip controls the LED, and only core 0 can make calls to it safely - vTaskCoreAffinitySet(ledOnTask, 1 << 0); -#endif - ledOffTask = xTaskCreateStatic(led_OFF, "led_OFF", STACK_SIZE, NULL, configMAX_PRIORITIES - 1, xStack_B, &xTaskBuffer_B); -#if defined(PICO_CYW43_SUPPORTED) - // The PicoW WiFi chip controls the LED, and only core 0 can make calls to it safely - vTaskCoreAffinitySet(ledOffTask, 1 << 0); -#endif - } - -void led_ON(void *pvParameters) -{ - (void) pvParameters; - delay(100); - while (1) - { - xSemaphoreTake( xSemaphore, ( TickType_t ) portMAX_DELAY ); - SERIAL_PORT.println("LED ON!"); - digitalWrite(LED_BUILTIN, HIGH); - delay(BLINK_ON_TIME); - xSemaphoreGive( xSemaphore ); - delay(1); - } -} - -void led_OFF(void *pvParameters) -{ - (void) pvParameters; - delay(100); - while (1) - { - xSemaphoreTake( xSemaphore, ( TickType_t ) portMAX_DELAY ); - SERIAL_PORT.println("LED OFF!"); - digitalWrite(LED_BUILTIN, LOW); - delay(BLINK_OFF_TIME); - xSemaphoreGive( xSemaphore ); - delay(1); - } -} - -void loop() { - SERIAL_PORT.println("Hello!"); - delay(1000); -} diff --git a/libraries/FreeRTOS/examples/Stress.ino b/libraries/FreeRTOS/examples/Stress.ino deleted file mode 100644 index 6c9414bc2..000000000 --- a/libraries/FreeRTOS/examples/Stress.ino +++ /dev/null @@ -1,319 +0,0 @@ -// FreeRTOS system call/mutex stress test - -#include -#include -#include -#include -#define DELAY 1 -#define SERIAL_DEBUG Serial1 -#define STACK_SIZE 512 -#define CORE_0 (1 << 0) -#define CORE_1 (1 << 1) - -void semphrTakeConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore); -void semphrGiveConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore); - -/* - I want to keep the possibility of using different and independent - mutexes for each of the functions that operate on the heap. - - If you want to enable the use of these mutexes remove the defines - on lines 30 and 31 and enable the their initialization in setup() -*/ -SemaphoreHandle_t xSemaphoreMalloc = NULL; -// SemaphoreHandle_t xSemaphoreRealloc = NULL; -// SemaphoreHandle_t xSemaphoreFree = NULL; - -/* - A lazy way to use the same mutex for malloc, realloc and free - in order to bring us back to the same situation as the MCVE - posted here: https://github.com/earlephilhower/arduino-pico/issues/795#issuecomment-1227122082 -*/ -#define xSemaphoreRealloc xSemaphoreMalloc -#define xSemaphoreFree xSemaphoreMalloc - -const bool useMutexOnMalloc = false; -const bool useMutexOnRealloc = false; -const bool useMutexOnFree = false; - -/* - Enabling this, a realloc will be performed and the string "_realloc" - will be concateneted to *tmp -*/ -const bool tryRealloc = true; - -TaskHandle_t loop2Handle = NULL; -TaskHandle_t loop3Handle = NULL; -TaskHandle_t loop4Handle = NULL; -TaskHandle_t loop5Handle = NULL; -TaskHandle_t loop6Handle = NULL; -TaskHandle_t loop7Handle = NULL; - -void loop2(void *pvPramaters); -void loop3(void *pvPramaters); -void loop4(void *pvPramaters); -void loop5(void *pvPramaters); -void loop6(void *pvPramaters); -void loop7(void *pvPramaters); - -void setup() -{ - pinMode(LED_BUILTIN, OUTPUT); - - xSemaphoreMalloc = xSemaphoreCreateMutex(); - // xSemaphoreRealloc = xSemaphoreCreateMutex(); - // xSemaphoreFree = xSemaphoreCreateMutex(); - - xTaskCreate(loop2, "loop2", STACK_SIZE, NULL, 1, &loop2Handle); - vTaskCoreAffinitySet(loop2Handle, CORE_0); - xTaskCreate(loop3, "loop3", STACK_SIZE, NULL, 1, &loop3Handle); - vTaskCoreAffinitySet(loop3Handle, CORE_1); - xTaskCreate(loop4, "loop4", STACK_SIZE, NULL, 1, &loop4Handle); - vTaskCoreAffinitySet(loop4Handle, CORE_0); - xTaskCreate(loop5, "loop5", STACK_SIZE, NULL, 1, &loop5Handle); - vTaskCoreAffinitySet(loop5Handle, CORE_1); - // xTaskCreate(loop6, "loop6", STACK_SIZE, NULL, 1, &loop6Handle); - // vTaskCoreAffinitySet(loop6Handle, CORE_0); - // xTaskCreate(loop7, "loop7", STACK_SIZE, NULL, 1, &loop7Handle); - // vTaskCoreAffinitySet(loop7Handle, CORE_1); -} -static int _loop[8]; - -void loop() -{ - while (1) - { - _loop[0]++; - digitalWrite(LED_BUILTIN, HIGH); - delay(500); - digitalWrite(LED_BUILTIN, LOW); - delay(500); - for (int i=0; i<8; i++) Serial.printf("%d ", _loop[i]); - Serial.println(""); - } -} - -void loop1() -{ - while (1) - { - _loop[1]++; - char *tmp; - - semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); - tmp = (char *)malloc(10 * sizeof(char)); - semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); - - strcpy(tmp, "foo"); - - if (tryRealloc) - { - semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); - tmp = (char *)realloc(tmp, 20 * sizeof(char)); - semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); - strcat(tmp, "_realloc"); - } - - semphrTakeConditional(useMutexOnFree, xSemaphoreFree); - free(tmp); - semphrGiveConditional(useMutexOnFree, xSemaphoreFree); - - delay(DELAY); - } -} - -void loop2(void *pvPramaters) -{ - (void) pvPramaters; - while (1) - { - _loop[2]++; - char *tmp; - - semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); - tmp = (char *)malloc(10 * sizeof(char)); - semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); - - strcpy(tmp, "bar"); - - if (tryRealloc) - { - semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); - tmp = (char *)realloc(tmp, 20 * sizeof(char)); - semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); - strcat(tmp, "_realloc"); - } - - semphrTakeConditional(useMutexOnFree, xSemaphoreFree); - free(tmp); - semphrGiveConditional(useMutexOnFree, xSemaphoreFree); - - delay(DELAY); - } -} - -void loop3(void *pvPramaters) -{ - (void) pvPramaters; - while (1) - { - _loop[3]++; - char *tmp; - - semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); - tmp = (char *)malloc(10 * sizeof(char)); - semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); - - strcpy(tmp, "yeah"); - - if (tryRealloc) - { - semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); - tmp = (char *)realloc(tmp, 20 * sizeof(char)); - semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); - strcat(tmp, "_realloc"); - } - - semphrTakeConditional(useMutexOnFree, xSemaphoreFree); - free(tmp); - semphrGiveConditional(useMutexOnFree, xSemaphoreFree); - - delay(DELAY); - } -} - -void loop4(void *pvPramaters) -{ - (void) pvPramaters; - while (1) - { - _loop[4]++; - char *tmp; - - semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); - tmp = (char *)malloc(10 * sizeof(char)); - semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); - - strcpy(tmp, "baz"); - - if (tryRealloc) - { - semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); - tmp = (char *)realloc(tmp, 20 * sizeof(char)); - semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); - strcat(tmp, "_realloc"); - } - - semphrTakeConditional(useMutexOnFree, xSemaphoreFree); - free(tmp); - semphrGiveConditional(useMutexOnFree, xSemaphoreFree); - - delay(DELAY); - } -} - -void loop5(void *pvPramaters) -{ - (void) pvPramaters; - while (1) - { - _loop[5]++; - char *tmp; - - semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); - tmp = (char *)malloc(10 * sizeof(char)); - semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); - - strcpy(tmp, "asd"); - - if (tryRealloc) - { - semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); - tmp = (char *)realloc(tmp, 20 * sizeof(char)); - semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); - strcat(tmp, "_realloc"); - } - - semphrTakeConditional(useMutexOnFree, xSemaphoreFree); - free(tmp); - semphrGiveConditional(useMutexOnFree, xSemaphoreFree); - - delay(DELAY); - } -} - -void loop6(void *pvPramaters) -{ - (void) pvPramaters; - while (1) - { - _loop[6]++; - char *tmp; - - semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); - tmp = (char *)malloc(10 * sizeof(char)); - semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); - - strcpy(tmp, "lol"); - - if (tryRealloc) - { - semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); - tmp = (char *)realloc(tmp, 20 * sizeof(char)); - semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); - strcat(tmp, "_realloc"); - } - - semphrTakeConditional(useMutexOnFree, xSemaphoreFree); - free(tmp); - semphrGiveConditional(useMutexOnFree, xSemaphoreFree); - - delay(DELAY); - } -} - -void loop7(void *pvPramaters) -{ - (void) pvPramaters; - while (1) - { - _loop[7]++; - char *tmp; - - semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); - tmp = (char *)malloc(10 * sizeof(char)); - semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); - - strcpy(tmp, "yay"); - - if (tryRealloc) - { - semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); - tmp = (char *)realloc(tmp, 20 * sizeof(char)); - semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); - strcat(tmp, "_realloc"); - } - - semphrTakeConditional(useMutexOnFree, xSemaphoreFree); - free(tmp); - semphrGiveConditional(useMutexOnFree, xSemaphoreFree); - - delay(DELAY); - } -} - -void semphrTakeConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore) -{ - if (useMutexOn) - { - xSemaphoreTake(xSemaphore, TickType_t(portMAX_DELAY)); - } -} - -void semphrGiveConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore) -{ - if (useMutexOn) - { - xSemaphoreGive(xSemaphore); - } -} diff --git a/libraries/FreeRTOS/keywords.txt b/libraries/FreeRTOS/keywords.txt deleted file mode 100644 index d11db89bd..000000000 --- a/libraries/FreeRTOS/keywords.txt +++ /dev/null @@ -1,64 +0,0 @@ -# Syntax Coloring Map For FreeRTOS -# https://arduino.github.io/arduino-cli/library-specification/#keywords -# Formatted by a single true tab (not spaces) - -FreeRTOS KEYWORD1 - -# Datatypes (KEYWORD1) -StackType_t KEYWORD1 -BaseType_t KEYWORD1 -UBaseType_t KEYWORD1 -TickType_t KEYWORD1 - -TaskHandle_t KEYWORD1 -QueueHandle_t KEYWORD1 -TimerHandle_t KEYWORD1 -SemaphoreHandle_t KEYWORD1 -StreamBufferHandle_t KEYWORD1 -MessageBufferHandle_t KEYWORD1 -EventGroupHandle_t KEYWORD1 - -# Methods and Functions (KEYWORD2) -xSemaphoreCreateMutex KEYWORD2 -xSemaphoreCreateBinary KEYWORD2 -xSemaphoreTake KEYWORD2 -xSemaphoreTakeFromISR KEYWORD2 -xSemaphoreGive KEYWORD2 -xSemaphoreGiveFromISR KEYWORD2 -xTaskCreate KEYWORD2 -vTaskDelete KEYWORD2 -vTaskDelay KEYWORD2 -xTaskDelayUntil KEYWORD2 -xQueueCreate KEYWORD2 -xQueueSend KEYWORD2 -xQueueReceive KEYWORD2 -pcTaskGetName KEYWORD2 -ulTaskNotifyTake KEYWORD2 -vTaskNotifyGiveFromISR KEYWORD2 -taskYIELD KEYWORD2 -vTaskCoreAffinitySet KEYWORD2 -vTaskSuspend KEYWORD2 -vTaskResume KEYWORD2 -xTaskResumeFromISR KEYWORD2 -xTaskGetTickCount KEYWORD2 -xTaskGetTickCountFromISR KEYWORD2 -uxTaskGetNumberOfTasks KEYWORD2 -uxTaskGetStackHighWaterMark KEYWORD2 -uxTaskGetSystemState KEYWORD2 - -# Instances (KEYWORD2) - -# Structures (KEYWORD3) -TaskParameters_t KEYWORD3 -TaskStatus_t KEYWORD3 -ListItem_t KEYWORD3 -MiniListItem_t KEYWORD3 -HeapStats_t KEYWORD3 - -# Constants (LITERAL1) -portUSE_WDTO LITERAL1 -portTICK_PERIOD_MS LITERAL1 -configTICK_RATE_HZ LITERAL1 -configCPU_CLOCK_HZ LITERAL1 -configMAX_PRIORITIES LITERAL1 -configMINIMAL_STACK_SIZE LITERAL1 diff --git a/libraries/FreeRTOS/lib/FreeRTOS-Kernel b/libraries/FreeRTOS/lib/FreeRTOS-Kernel deleted file mode 160000 index 2e588af95..000000000 --- a/libraries/FreeRTOS/lib/FreeRTOS-Kernel +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2e588af95bad29aef577373512883370c9408c1c diff --git a/libraries/FreeRTOS/library.properties b/libraries/FreeRTOS/library.properties deleted file mode 100644 index 06c778ca9..000000000 --- a/libraries/FreeRTOS/library.properties +++ /dev/null @@ -1,11 +0,0 @@ -name=FreeRTOS -version=1.0.0 -author=Graham Sanderson -maintainer=Graham Sanderson -sentence=

FreeRTOS Real Time Operating System implemented for RP2040.

-paragraph=Taken from the official FreeRTOS SMP branch. -category=Timing -url=https://github.com/FreeRTOS/FreeRTOS-Kernel -architectures=rp2040 -license=MIT -dot_a_linkage=true diff --git a/libraries/FreeRTOS/readme.md b/libraries/FreeRTOS/readme.md deleted file mode 100644 index 6c4e4bba8..000000000 --- a/libraries/FreeRTOS/readme.md +++ /dev/null @@ -1,39 +0,0 @@ -**ATTENTION** -Please be aware that this library was copied from the original Arduino AVR FreeRTOS library and may still contain files from that library that have no meaning in the context of this package, i.e. the licensing and code of conduct file! Each file retains the license and copyright from where it was taken (FreeRTOS repository or AVR FreeRTOS library, respectively.) - -______ - -This is a copy of the RP2040 port of the FreeRTOS SMP branch, packaged as an Arduino library. - -It has been created to provide access to FreeRTOS capabilities, with full compatibility to the Arduino environment. -It does this by keeping hands off almost everything, and only touching the minimum of hardware to be successful. - -## General - -FreeRTOS has a multitude of configuration options, which can be specified from within the FreeRTOSConfig.h file. -To keep commonality with all of the Arduino hardware options, some sensible defaults have been selected. - -System ticks are 1ms, which means that Tasks can only be scheduled to run up to 1000 times per second. - -Stack for the `loop()` function has been set at 256 bytes. This can be configured by adjusting the `configMINIMAL_STACK_SIZE` parameter. If you have stack overflow issues, just increase it. -Users should prefer to allocate larger structures, arrays, or buffers using `pvPortMalloc()`, rather than defining them locally on the stack. - -Memory for the heap is allocated by the normal `malloc()` function, wrapped by `pvPortMalloc()`. -This option has been selected because it is automatically adjusted to use the capabilities of each device. -Other heap allocation schemes are supported by FreeRTOS, and they can used with additional configuration. - -## Errors - -* Stack Overflow: If any stack (for the `loop()` or) for any Task overflows, there will be a slow LED blink, with 4 second cycle. -* Heap Overflow: If any Task tries to allocate memory and that allocation fails, there will be a fast LED blink, with 100 millisecond cycle. - -## Files & Configuration - -* `RP2040_FreeRTOS.h` : Must always be `#include` first. It references other configuration files, and sets defaults where necessary. -* `FreeRTOSConfig.h` : Contains a multitude of API and environment configurations. -* `variantHooks.cpp` : Contains the RP2040 specific configurations for this port of FreeRTOS. -* `heap_3.c` : Contains the heap allocation scheme based on `malloc()`. Other schemes are available, but depend on user configuration for specific MCU choice. - -## Sources / Credits ✨ - -This library is built on the efforts of the authors of the FreeRTOS SMP port for the RP2040, using the original Arduino FreeRTOS library as a template for the library package and the Arduino specific behavior. diff --git a/libraries/FreeRTOS/src/FreeRTOS.h b/libraries/FreeRTOS/src/FreeRTOS.h deleted file mode 100644 index 4a0d8c33d..000000000 --- a/libraries/FreeRTOS/src/FreeRTOS.h +++ /dev/null @@ -1,5 +0,0 @@ -#if !defined(__FREERTOS) -#error Please select Tools->Operating System->FreeRTOS SMP or define __FREERTOS in your platform.ini to use FreeRTOS -#else -#include "../lib/FreeRTOS-Kernel/include/FreeRTOS.h" -#endif diff --git a/libraries/FreeRTOS/src/StackMacros.h b/libraries/FreeRTOS/src/StackMacros.h deleted file mode 100644 index d0fe8ccb0..000000000 --- a/libraries/FreeRTOS/src/StackMacros.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/StackMacros.h" diff --git a/libraries/FreeRTOS/src/atomic.h b/libraries/FreeRTOS/src/atomic.h deleted file mode 100644 index 48e0dbf9b..000000000 --- a/libraries/FreeRTOS/src/atomic.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/atomic.h" diff --git a/libraries/FreeRTOS/src/croutine.c b/libraries/FreeRTOS/src/croutine.c deleted file mode 100644 index f9f313019..000000000 --- a/libraries/FreeRTOS/src/croutine.c +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/croutine.c" diff --git a/libraries/FreeRTOS/src/croutine.h b/libraries/FreeRTOS/src/croutine.h deleted file mode 100644 index e9b128380..000000000 --- a/libraries/FreeRTOS/src/croutine.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/croutine.h" diff --git a/libraries/FreeRTOS/src/deprecated_definitions.h b/libraries/FreeRTOS/src/deprecated_definitions.h deleted file mode 100644 index cde8163f1..000000000 --- a/libraries/FreeRTOS/src/deprecated_definitions.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/deprecated_definitions.h" diff --git a/libraries/FreeRTOS/src/event_groups.c b/libraries/FreeRTOS/src/event_groups.c deleted file mode 100644 index 1d356b23f..000000000 --- a/libraries/FreeRTOS/src/event_groups.c +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/event_groups.c" diff --git a/libraries/FreeRTOS/src/event_groups.h b/libraries/FreeRTOS/src/event_groups.h deleted file mode 100644 index 6f50a091a..000000000 --- a/libraries/FreeRTOS/src/event_groups.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/event_groups.h" diff --git a/libraries/FreeRTOS/src/freertos_sdk_config.h b/libraries/FreeRTOS/src/freertos_sdk_config.h deleted file mode 100644 index 0c77d9cc5..000000000 --- a/libraries/FreeRTOS/src/freertos_sdk_config.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/include/freertos_sdk_config.h" diff --git a/libraries/FreeRTOS/src/heap_3.c b/libraries/FreeRTOS/src/heap_3.c deleted file mode 100644 index 2b2c8a983..000000000 --- a/libraries/FreeRTOS/src/heap_3.c +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/portable/MemMang/heap_3.c" diff --git a/libraries/FreeRTOS/src/list.c b/libraries/FreeRTOS/src/list.c deleted file mode 100644 index 310e95942..000000000 --- a/libraries/FreeRTOS/src/list.c +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/list.c" diff --git a/libraries/FreeRTOS/src/list.h b/libraries/FreeRTOS/src/list.h deleted file mode 100644 index 29aefcba2..000000000 --- a/libraries/FreeRTOS/src/list.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/list.h" diff --git a/libraries/FreeRTOS/src/message_buffer.h b/libraries/FreeRTOS/src/message_buffer.h deleted file mode 100644 index cb67683ae..000000000 --- a/libraries/FreeRTOS/src/message_buffer.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/message_buffer.h" diff --git a/libraries/FreeRTOS/src/mpu_prototypes.h b/libraries/FreeRTOS/src/mpu_prototypes.h deleted file mode 100644 index b4313789d..000000000 --- a/libraries/FreeRTOS/src/mpu_prototypes.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/mpu_prototypes.h" diff --git a/libraries/FreeRTOS/src/mpu_syscall_numbers.h b/libraries/FreeRTOS/src/mpu_syscall_numbers.h deleted file mode 100644 index fb175c2f2..000000000 --- a/libraries/FreeRTOS/src/mpu_syscall_numbers.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/mpu_syscall_numbers.h" diff --git a/libraries/FreeRTOS/src/mpu_wrappers.h b/libraries/FreeRTOS/src/mpu_wrappers.h deleted file mode 100644 index 2c0116cd9..000000000 --- a/libraries/FreeRTOS/src/mpu_wrappers.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/mpu_wrappers.h" diff --git a/libraries/FreeRTOS/src/mpu_wrappers_v2_asm.c b/libraries/FreeRTOS/src/mpu_wrappers_v2_asm.c deleted file mode 100644 index 7350e5527..000000000 --- a/libraries/FreeRTOS/src/mpu_wrappers_v2_asm.c +++ /dev/null @@ -1,5 +0,0 @@ -#ifdef PICO_RP2350 -#ifndef __riscv -#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure/mpu_wrappers_v2_asm.c" -#endif -#endif diff --git a/libraries/FreeRTOS/src/port.c b/libraries/FreeRTOS/src/port.c deleted file mode 100644 index a75ee26dd..000000000 --- a/libraries/FreeRTOS/src/port.c +++ /dev/null @@ -1,9 +0,0 @@ -#ifdef PICO_RP2040 -#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/port.c" -#else -#ifndef __riscv -#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure/port.c" -#else -#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_RISC-V/port.c" -#endif -#endif diff --git a/libraries/FreeRTOS/src/portASM.S b/libraries/FreeRTOS/src/portASM.S deleted file mode 100644 index 52920480e..000000000 --- a/libraries/FreeRTOS/src/portASM.S +++ /dev/null @@ -1,5 +0,0 @@ -#ifdef PICO_RP2350 -#ifdef __riscv -#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_RISC-V/portASM.S" -#endif -#endif diff --git a/libraries/FreeRTOS/src/portContext.h b/libraries/FreeRTOS/src/portContext.h deleted file mode 100644 index a7224f065..000000000 --- a/libraries/FreeRTOS/src/portContext.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifdef PICO_RP2350 -#ifdef __riscv -#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_RISC-V/include/portContext.h" -#endif -#endif - diff --git a/libraries/FreeRTOS/src/portable.h b/libraries/FreeRTOS/src/portable.h deleted file mode 100644 index c2bedb522..000000000 --- a/libraries/FreeRTOS/src/portable.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/portable.h" diff --git a/libraries/FreeRTOS/src/portasm.c b/libraries/FreeRTOS/src/portasm.c deleted file mode 100644 index 830e60a98..000000000 --- a/libraries/FreeRTOS/src/portasm.c +++ /dev/null @@ -1,5 +0,0 @@ -#ifdef PICO_RP2350 -#ifndef __riscv -#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure/portasm.c" -#endif -#endif diff --git a/libraries/FreeRTOS/src/portmacro.h b/libraries/FreeRTOS/src/portmacro.h deleted file mode 100644 index 60ddec8f7..000000000 --- a/libraries/FreeRTOS/src/portmacro.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifdef PICO_RP2350 -#ifndef __riscv -#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure/portmacro.h" -#else -#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_RISC-V/include/portmacro.h" -#endif -#else -#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/include/portmacro.h" -#endif diff --git a/libraries/FreeRTOS/src/projdefs.h b/libraries/FreeRTOS/src/projdefs.h deleted file mode 100644 index 712d61391..000000000 --- a/libraries/FreeRTOS/src/projdefs.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/projdefs.h" diff --git a/libraries/FreeRTOS/src/queue.c b/libraries/FreeRTOS/src/queue.c deleted file mode 100644 index 59a8f7e91..000000000 --- a/libraries/FreeRTOS/src/queue.c +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/queue.c" diff --git a/libraries/FreeRTOS/src/queue.h b/libraries/FreeRTOS/src/queue.h deleted file mode 100644 index 091e73900..000000000 --- a/libraries/FreeRTOS/src/queue.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/queue.h" diff --git a/libraries/FreeRTOS/src/rp2040_config.h b/libraries/FreeRTOS/src/rp2040_config.h deleted file mode 100644 index 4e7b5697a..000000000 --- a/libraries/FreeRTOS/src/rp2040_config.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifdef PICO_RP2350 -#ifndef __riscv -#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure//rp2040_config.h" -#else -#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_RISC-V/include/rp2040_config.h" -#endif -#else -#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/include/rp2040_config.h" -#endif diff --git a/libraries/FreeRTOS/src/semphr.h b/libraries/FreeRTOS/src/semphr.h deleted file mode 100644 index c85953698..000000000 --- a/libraries/FreeRTOS/src/semphr.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/semphr.h" diff --git a/libraries/FreeRTOS/src/stack_macros.h b/libraries/FreeRTOS/src/stack_macros.h deleted file mode 100644 index aff6f3c0a..000000000 --- a/libraries/FreeRTOS/src/stack_macros.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/stack_macros.h" diff --git a/libraries/FreeRTOS/src/stream_buffer.c b/libraries/FreeRTOS/src/stream_buffer.c deleted file mode 100644 index 0f93af555..000000000 --- a/libraries/FreeRTOS/src/stream_buffer.c +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/stream_buffer.c" diff --git a/libraries/FreeRTOS/src/stream_buffer.h b/libraries/FreeRTOS/src/stream_buffer.h deleted file mode 100644 index dcdf5af61..000000000 --- a/libraries/FreeRTOS/src/stream_buffer.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/stream_buffer.h" diff --git a/libraries/FreeRTOS/src/task.h b/libraries/FreeRTOS/src/task.h deleted file mode 100644 index 2e38c2e95..000000000 --- a/libraries/FreeRTOS/src/task.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/task.h" diff --git a/libraries/FreeRTOS/src/timers.c b/libraries/FreeRTOS/src/timers.c deleted file mode 100644 index ca907b665..000000000 --- a/libraries/FreeRTOS/src/timers.c +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/timers.c" diff --git a/libraries/FreeRTOS/src/timers.h b/libraries/FreeRTOS/src/timers.h deleted file mode 100644 index db546520b..000000000 --- a/libraries/FreeRTOS/src/timers.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/FreeRTOS-Kernel/include/timers.h" diff --git a/libraries/FreeRTOS/tests/README.md b/libraries/FreeRTOS/tests/README.md deleted file mode 100644 index 50d477e9c..000000000 --- a/libraries/FreeRTOS/tests/README.md +++ /dev/null @@ -1 +0,0 @@ -This folder contains FreeRTOS functionality tests, not generally useful for users. diff --git a/libraries/FreeRTOS/tests/corefreeze/corefreeze.ino b/libraries/FreeRTOS/tests/corefreeze/corefreeze.ino deleted file mode 100644 index 8ffd85bf0..000000000 --- a/libraries/FreeRTOS/tests/corefreeze/corefreeze.ino +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include "LittleFS.h" - -void setup() { - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, LOW); - LittleFS.format(); -} - -void setup1() { -} - -void loop() { - digitalWrite(LED_BUILTIN, HIGH); - delay(200); -} - -int x = 0; -void loop1() { - delay(100); - digitalWrite(LED_BUILTIN, LOW); - delay(100); - Serial.printf("%d\n", x++); -} diff --git a/libraries/FreeRTOS/tests/freertos_reent/freertos_reent.ino b/libraries/FreeRTOS/tests/freertos_reent/freertos_reent.ino deleted file mode 100644 index 1c207a643..000000000 --- a/libraries/FreeRTOS/tests/freertos_reent/freertos_reent.ino +++ /dev/null @@ -1,32 +0,0 @@ -// Simple stress test to ensure each thread has its own Newlib reent structure -// The random numbers from each task should be identical. - -#include -#include - -void go(void *param) { - (void) param; - srand(0); - int i = 0; - while(1) { - char buff[100]; - TaskStatus_t st; - vTaskGetInfo(NULL, &st, pdFALSE, eInvalid); - sprintf(buff, "task %ld: %d = %d\n", st.xTaskNumber, i++, rand()); - Serial.print(buff); - delay(1000); - } -} - -void setup() { - delay(5000); - // put your setup code here, to run once: - xTaskCreate(go, "c1", 1024, nullptr, 1, nullptr); - xTaskCreate(go, "c2", 1024, nullptr, 1, nullptr); - xTaskCreate(go, "c3", 1024, nullptr, 1, nullptr); -} - -void loop() { - // put your main code here, to run repeatedly: - -} diff --git a/libraries/FreeRTOS/tests/freertos_syscallmutex/freertos_syscallmutex.ino b/libraries/FreeRTOS/tests/freertos_syscallmutex/freertos_syscallmutex.ino deleted file mode 100644 index 498e79088..000000000 --- a/libraries/FreeRTOS/tests/freertos_syscallmutex/freertos_syscallmutex.ino +++ /dev/null @@ -1,319 +0,0 @@ -// FreeRTOS system call/mutex stress test - -#include -#include -#include -#include -#define DELAY 1 -#define SERIAL_DEBUG Serial1 -#define STACK_SIZE 512 -#define CORE_0 (1 << 0) -#define CORE_1 (1 << 1) - -void semphrTakeConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore); -void semphrGiveConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore); - -/* - I want to keep the possibility of using different and independent - mutexes for each of the functions that operate on the heap. - - If you want to enable the use of these mutexes remove the defines - on lines 30 and 31 and enable the their initialization in setup() -*/ -SemaphoreHandle_t xSemaphoreMalloc = NULL; -// SemaphoreHandle_t xSemaphoreRealloc = NULL; -// SemaphoreHandle_t xSemaphoreFree = NULL; - -/* - A lazy way to use the same mutex for malloc, realloc and free - in order to bring us back to the same situation as the MCVE - posted here: https://github.com/earlephilhower/arduino-pico/issues/795#issuecomment-1227122082 -*/ -#define xSemaphoreRealloc xSemaphoreMalloc -#define xSemaphoreFree xSemaphoreMalloc - -const bool useMutexOnMalloc = false; -const bool useMutexOnRealloc = false; -const bool useMutexOnFree = false; - -/* - Enabling this, a realloc will be performed and the string "_realloc" - will be concateneted to *tmp -*/ -const bool tryRealloc = true; - -TaskHandle_t loop2Handle = NULL; -TaskHandle_t loop3Handle = NULL; -TaskHandle_t loop4Handle = NULL; -TaskHandle_t loop5Handle = NULL; -TaskHandle_t loop6Handle = NULL; -TaskHandle_t loop7Handle = NULL; - -void loop2(void *pvPramaters); -void loop3(void *pvPramaters); -void loop4(void *pvPramaters); -void loop5(void *pvPramaters); -void loop6(void *pvPramaters); -void loop7(void *pvPramaters); - -void setup() -{ - pinMode(LED_BUILTIN, OUTPUT); - - xSemaphoreMalloc = xSemaphoreCreateMutex(); - // xSemaphoreRealloc = xSemaphoreCreateMutex(); - // xSemaphoreFree = xSemaphoreCreateMutex(); - - xTaskCreate(loop2, "loop2", STACK_SIZE, NULL, 1, &loop2Handle); - vTaskCoreAffinitySet(loop2Handle, CORE_0); - xTaskCreate(loop3, "loop3", STACK_SIZE, NULL, 1, &loop3Handle); - vTaskCoreAffinitySet(loop3Handle, CORE_1); - xTaskCreate(loop4, "loop4", STACK_SIZE, NULL, 1, &loop4Handle); - vTaskCoreAffinitySet(loop4Handle, CORE_0); - xTaskCreate(loop5, "loop5", STACK_SIZE, NULL, 1, &loop5Handle); - vTaskCoreAffinitySet(loop5Handle, CORE_1); - xTaskCreate(loop6, "loop6", STACK_SIZE, NULL, 1, &loop6Handle); - vTaskCoreAffinitySet(loop6Handle, CORE_0); - xTaskCreate(loop7, "loop7", STACK_SIZE, NULL, 1, &loop7Handle); - vTaskCoreAffinitySet(loop7Handle, CORE_1); -} -static int _loop[8]; - -void loop() -{ - while (1) - { - _loop[0]++; - digitalWrite(LED_BUILTIN, HIGH); - delay(500); - digitalWrite(LED_BUILTIN, LOW); - delay(500); - for (int i=0; i<8; i++) Serial.printf("%d ", _loop[i]); - Serial.println(""); - } -} - -void loop1() -{ - while (1) - { - _loop[1]++; - char *tmp; - - semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); - tmp = (char *)malloc(10 * sizeof(char)); - semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); - - strcpy(tmp, "foo"); - - if (tryRealloc) - { - semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); - tmp = (char *)realloc(tmp, 20 * sizeof(char)); - semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); - strcat(tmp, "_realloc"); - } - - semphrTakeConditional(useMutexOnFree, xSemaphoreFree); - free(tmp); - semphrGiveConditional(useMutexOnFree, xSemaphoreFree); - - delay(DELAY); - } -} - -void loop2(void *pvPramaters) -{ - (void) pvPramaters; - while (1) - { - _loop[2]++; - char *tmp; - - semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); - tmp = (char *)malloc(10 * sizeof(char)); - semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); - - strcpy(tmp, "bar"); - - if (tryRealloc) - { - semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); - tmp = (char *)realloc(tmp, 20 * sizeof(char)); - semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); - strcat(tmp, "_realloc"); - } - - semphrTakeConditional(useMutexOnFree, xSemaphoreFree); - free(tmp); - semphrGiveConditional(useMutexOnFree, xSemaphoreFree); - - delay(DELAY); - } -} - -void loop3(void *pvPramaters) -{ - (void) pvPramaters; - while (1) - { - _loop[3]++; - char *tmp; - - semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); - tmp = (char *)malloc(10 * sizeof(char)); - semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); - - strcpy(tmp, "yeah"); - - if (tryRealloc) - { - semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); - tmp = (char *)realloc(tmp, 20 * sizeof(char)); - semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); - strcat(tmp, "_realloc"); - } - - semphrTakeConditional(useMutexOnFree, xSemaphoreFree); - free(tmp); - semphrGiveConditional(useMutexOnFree, xSemaphoreFree); - - delay(DELAY); - } -} - -void loop4(void *pvPramaters) -{ - (void) pvPramaters; - while (1) - { - _loop[4]++; - char *tmp; - - semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); - tmp = (char *)malloc(10 * sizeof(char)); - semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); - - strcpy(tmp, "baz"); - - if (tryRealloc) - { - semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); - tmp = (char *)realloc(tmp, 20 * sizeof(char)); - semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); - strcat(tmp, "_realloc"); - } - - semphrTakeConditional(useMutexOnFree, xSemaphoreFree); - free(tmp); - semphrGiveConditional(useMutexOnFree, xSemaphoreFree); - - delay(DELAY); - } -} - -void loop5(void *pvPramaters) -{ - (void) pvPramaters; - while (1) - { - _loop[5]++; - char *tmp; - - semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); - tmp = (char *)malloc(10 * sizeof(char)); - semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); - - strcpy(tmp, "asd"); - - if (tryRealloc) - { - semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); - tmp = (char *)realloc(tmp, 20 * sizeof(char)); - semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); - strcat(tmp, "_realloc"); - } - - semphrTakeConditional(useMutexOnFree, xSemaphoreFree); - free(tmp); - semphrGiveConditional(useMutexOnFree, xSemaphoreFree); - - delay(DELAY); - } -} - -void loop6(void *pvPramaters) -{ - (void) pvPramaters; - while (1) - { - _loop[6]++; - char *tmp; - - semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); - tmp = (char *)malloc(10 * sizeof(char)); - semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); - - strcpy(tmp, "lol"); - - if (tryRealloc) - { - semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); - tmp = (char *)realloc(tmp, 20 * sizeof(char)); - semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); - strcat(tmp, "_realloc"); - } - - semphrTakeConditional(useMutexOnFree, xSemaphoreFree); - free(tmp); - semphrGiveConditional(useMutexOnFree, xSemaphoreFree); - - delay(DELAY); - } -} - -void loop7(void *pvPramaters) -{ - (void) pvPramaters; - while (1) - { - _loop[7]++; - char *tmp; - - semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); - tmp = (char *)malloc(10 * sizeof(char)); - semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); - - strcpy(tmp, "yay"); - - if (tryRealloc) - { - semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); - tmp = (char *)realloc(tmp, 20 * sizeof(char)); - semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); - strcat(tmp, "_realloc"); - } - - semphrTakeConditional(useMutexOnFree, xSemaphoreFree); - free(tmp); - semphrGiveConditional(useMutexOnFree, xSemaphoreFree); - - delay(DELAY); - } -} - -void semphrTakeConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore) -{ - if (useMutexOn) - { - xSemaphoreTake(xSemaphore, TickType_t(portMAX_DELAY)); - } -} - -void semphrGiveConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore) -{ - if (useMutexOn) - { - xSemaphoreGive(xSemaphore); - } -} diff --git a/libraries/FreeRTOS/tests/switching/switching.ino b/libraries/FreeRTOS/tests/switching/switching.ino deleted file mode 100644 index 44aa5a142..000000000 --- a/libraries/FreeRTOS/tests/switching/switching.ino +++ /dev/null @@ -1,57 +0,0 @@ -// Released to the public domain -#include -#include -#include -#define STACK_SIZE 512 -#define CORE_0 (1 << 0) -#define CORE_1 (1 << 1) - -std::map eTaskStateName { {eReady, "Ready"}, { eRunning, "Running" }, {eBlocked, "Blocked"}, {eSuspended, "Suspended"}, {eDeleted, "Deleted"} }; -void ps() { - int tasks = uxTaskGetNumberOfTasks(); - TaskStatus_t *pxTaskStatusArray = new TaskStatus_t[tasks]; - unsigned long runtime; - tasks = uxTaskGetSystemState( pxTaskStatusArray, tasks, &runtime ); - Serial.printf("# Tasks: %d\n", tasks); - Serial.printf("%-3s %-16s %-10s %s %s\n", "ID", "NAME", "STATE", "PRIO", "CYCLES"); - for (int i = 0; i < tasks; i++) { - Serial.printf("%2d: %-16s %-10s %4d %lu\n", i, pxTaskStatusArray[i].pcTaskName, eTaskStateName[pxTaskStatusArray[i].eCurrentState], (int)pxTaskStatusArray[i].uxCurrentPriority, pxTaskStatusArray[i].ulRunTimeCounter); - } - delete[] pxTaskStatusArray; -} - -static TaskHandle_t l[16]; - -void loop() { - ps(); - delay(1000); -} - -#define LOOP(z) \ -void loop##z(void *params) {\ - (void) params;\ - while (true) {\ - srand(z);\ - int sum = 0;\ - for (int i = 0; i < 500000; i++) sum+= rand();\ - Serial.printf("L%d: %08x\n", z, sum);\ - delay(1000 + z * 10);\ - }\ -} - -LOOP(0); -LOOP(1); -LOOP(2); -LOOP(3); - - -void setup() { - xTaskCreate(loop0, "loop0", STACK_SIZE, NULL, 1, &l[0]); - vTaskCoreAffinitySet(l[0], CORE_0); -// xTaskCreate(loop1, "loop1", STACK_SIZE, NULL, 1, &l[1]); -// vTaskCoreAffinitySet(l[1], CORE_0); -// xTaskCreate(loop2, "loop2", STACK_SIZE, NULL, 1, &l[2]); -// vTaskCoreAffinitySet(l[2], CORE_0); -// xTaskCreate(loop3, "loop3", STACK_SIZE, NULL, 1, &l[3]); -// vTaskCoreAffinitySet(l[3], CORE_1); -} diff --git a/libraries/lwIP_CYW43/src/utility/CYW43shim.cpp b/libraries/lwIP_CYW43/src/utility/CYW43shim.cpp index d80734abf..46b9cf551 100644 --- a/libraries/lwIP_CYW43/src/utility/CYW43shim.cpp +++ b/libraries/lwIP_CYW43/src/utility/CYW43shim.cpp @@ -111,6 +111,7 @@ uint16_t CYW43::sendFrame(const uint8_t* data, uint16_t datalen) { if (0 == cyw43_send_ethernet(_self, _itf, datalen, data, false)) { return datalen; } + printf("c++\n"); fails++; return 0; } diff --git a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp index 6e3593959..0c51c085f 100644 --- a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp +++ b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp @@ -25,14 +25,42 @@ #if defined(PICO_CYW43_SUPPORTED) #include #endif +#if defined(__FREERTOS) +#include +static async_context_freertos_t lwip_ethernet_async_context_threadsafe_background; +static StackType_t lwip_ethernet_async_context_freertos_task_stack[CYW43_TASK_STACK_SIZE]; + +static async_context_t *lwip_ethernet_init_default_async_context(void) { + async_context_freertos_config_t config = async_context_freertos_default_config(); +#if configSUPPORT_STATIC_ALLOCATION && !CYW43_NO_DEFAULT_TASK_STACK + config.task_stack = lwip_ethernet_async_context_freertos_task_stack; +#endif + if (async_context_freertos_init(&lwip_ethernet_async_context_threadsafe_background, &config)) { + return &lwip_ethernet_async_context_threadsafe_background.core; + } + return NULL; +} + +#else #include +static async_context_threadsafe_background_t lwip_ethernet_async_context_threadsafe_background; + +static async_context_t *lwip_ethernet_init_default_async_context(void) { + async_context_threadsafe_background_config_t config = async_context_threadsafe_background_default_config(); + if (async_context_threadsafe_background_init(&lwip_ethernet_async_context_threadsafe_background, &config)) { + return &lwip_ethernet_async_context_threadsafe_background.core; + } + return NULL; +} + +#endif + #include #include bool __ethernetContextInitted = false; // Async context that pumps the ethernet controllers -static async_context_threadsafe_background_t lwip_ethernet_async_context_threadsafe_background; static async_when_pending_worker_t always_pending_update_timeout_worker; static async_at_time_worker_t ethernet_timeout_worker; static async_context_t *_context = nullptr; @@ -41,22 +69,23 @@ static async_context_t *_context = nullptr; static std::map> _handlePacketList; void ethernet_arch_lwip_begin() { -#if defined(PICO_CYW43_SUPPORTED) - if (rp2040.isPicoW()) { - cyw43_arch_lwip_begin(); - return; - } -#endif +//#if defined(PICO_CYW43_SUPPORTED) +// if (rp2040.isPicoW()) { +// cyw43_arch_lwip_begin(); +// return; +// } +//#endif + __startEthernetContext(); async_context_acquire_lock_blocking(_context); } void ethernet_arch_lwip_end() { -#if defined(PICO_CYW43_SUPPORTED) - if (rp2040.isPicoW()) { - cyw43_arch_lwip_end(); - return; - } -#endif +//#if defined(PICO_CYW43_SUPPORTED) +// if (rp2040.isPicoW()) { +// cyw43_arch_lwip_end(); +// return; +// } +//#endif async_context_release_lock(_context); } @@ -169,14 +198,6 @@ int hostByName(const char* aHostname, IPAddress& aResult, int timeout_ms) { return 0; } -static async_context_t *lwip_ethernet_init_default_async_context(void) { - async_context_threadsafe_background_config_t config = async_context_threadsafe_background_default_config(); - if (async_context_threadsafe_background_init(&lwip_ethernet_async_context_threadsafe_background, &config)) { - return &lwip_ethernet_async_context_threadsafe_background.core; - } - return NULL; -} - uint32_t __ethernet_timeout_reached_calls = 0; static uint32_t _pollingPeriod = 20; // This will only be called under the protection of the async context mutex, so no re-entrancy checks needed @@ -187,13 +208,13 @@ static void ethernet_timeout_reached(__unused async_context_t *context, __unused for (auto handlePacket : _handlePacketList) { handlePacket.second(); } -#if defined(PICO_CYW43_SUPPORTED) - if (!rp2040.isPicoW()) { - sys_check_timeouts(); - } -#else +//#if defined(PICO_CYW43_SUPPORTED) +// if (!rp2040.isPicoW()) { +// sys_check_timeouts(); +// } +//#else sys_check_timeouts(); -#endif +//#endif ethernet_arch_lwip_gpio_unmask(); } @@ -207,15 +228,15 @@ void __startEthernetContext() { if (__ethernetContextInitted) { return; } -#if defined(PICO_CYW43_SUPPORTED) - if (rp2040.isPicoW()) { - _context = cyw43_arch_async_context(); - } else { - _context = lwip_ethernet_init_default_async_context(); - } -#else +//#if defined(PICO_CYW43_SUPPORTED) +// if (rp2040.isPicoW()) { +// _context = cyw43_arch_async_context(); +// } else { +// _context = lwip_ethernet_init_default_async_context(); +// } +//#else _context = lwip_ethernet_init_default_async_context(); -#endif +//#endif ethernet_timeout_worker.do_work = ethernet_timeout_reached; always_pending_update_timeout_worker.work_pending = true; always_pending_update_timeout_worker.do_work = update_next_timeout; diff --git a/libraries/lwIP_Ethernet/src/LwipIntfDev.h b/libraries/lwIP_Ethernet/src/LwipIntfDev.h index 88fade569..284cfb195 100644 --- a/libraries/lwIP_Ethernet/src/LwipIntfDev.h +++ b/libraries/lwIP_Ethernet/src/LwipIntfDev.h @@ -483,7 +483,8 @@ EthernetLinkStatus LwipIntfDev::linkStatus() { template err_t LwipIntfDev::linkoutput_s(netif* netif, struct pbuf* pbuf) { LwipIntfDev* lid = (LwipIntfDev*)netif->state; - ethernet_arch_lwip_begin(); + printf("presend %d\n", pbuf->len); +// ethernet_arch_lwip_begin(); uint16_t len = lid->sendFrame((const uint8_t*)pbuf->payload, pbuf->len); lid->_packetsSent++; #if PHY_HAS_CAPTURE @@ -492,7 +493,8 @@ err_t LwipIntfDev::linkoutput_s(netif* netif, struct pbuf* pbuf) { /*success*/ len == pbuf->len); } #endif - ethernet_arch_lwip_end(); + printf("sent len %d\n", len); +// ethernet_arch_lwip_end(); return len == pbuf->len ? ERR_OK : ERR_MEM; } diff --git a/tools/libpico/CMakeLists.txt b/tools/libpico/CMakeLists.txt index c4eaf8a4c..5086f00eb 100644 --- a/tools/libpico/CMakeLists.txt +++ b/tools/libpico/CMakeLists.txt @@ -90,7 +90,7 @@ target_compile_definitions(common-${cpu} INTERFACE LWIP_CHECKSUM_CTRL_PER_NETIF=1 PICO_CYW43_SUPPORTED=1 - PICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 +# PICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 CFG_TUSB_DEBUG=0 CFG_TUSB_MCU=OPT_MCU_RP2040 CFG_TUSB_OS=OPT_OS_PICO @@ -98,6 +98,7 @@ target_compile_definitions(common-${cpu} INTERFACE LIB_TINYUSB_DEVICE=1 CYW43_WARN=// + PICO_CYW43_ARCH_DEBUG_ENABLED=1 CYW43_PIO_CLOCK_DIV_DYNAMIC=1 CYW43_PIN_WL_DYNAMIC=1 CYW43_DEFAULT_PIN_WL_REG_ON=23u @@ -142,6 +143,8 @@ target_compile_definitions(common-${cpu} INTERFACE LIB_PICO_UNIQUE_ID=1 LIB_PICO_UTIL=1 + PICO_CYW43_ARCH_HEADER=stdint.h + ${xcd} ) @@ -227,10 +230,10 @@ set(picow_link_libraries cyw43_driver cyw43_driver_picow pico_async_context - pico_async_context_threadsafe_background +# pico_async_context_threadsafe_background pico_cyw43_driver pico_cyw43_arch - pico_cyw43_arch_threadsafe_background +# pico_cyw43_arch_threadsafe_background pico_lwip pico_lwip_nosys pico_lwip_sntp From e2f324eb2c99ec255a50c1b92f1ab9e15e3177f2 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 13 Aug 2025 21:46:43 -0700 Subject: [PATCH 03/36] Clean up and fill in RAW, UDP, and TCP wrappers --- cores/rp2040/freertos/variantHooks.cpp | 44 ++++ cores/rp2040/lwip_wrap.cpp | 304 ++++++++++++++++++++----- lib/core_wrap.txt | 10 +- 3 files changed, 302 insertions(+), 56 deletions(-) diff --git a/cores/rp2040/freertos/variantHooks.cpp b/cores/rp2040/freertos/variantHooks.cpp index a7dfbc489..c69470608 100644 --- a/cores/rp2040/freertos/variantHooks.cpp +++ b/cores/rp2040/freertos/variantHooks.cpp @@ -658,18 +658,38 @@ static void lwipThread(void *params) { *(r->ret) = __real_tcp_new(); break; } + case __tcp_new_ip_type: + { + __tcp_new_ip_type_req *r = (__tcp_new_ip_type_req *)w.req; + *(r->ret) = __real_tcp_new_ip_type(r->type); + break; + } case __tcp_bind: { __tcp_bind_req *r = (__tcp_bind_req *)w.req; *(r->ret) = __real_tcp_bind(r->pcb, r->ipaddr, r->port); break; } + case __tcp_bind_netif: + { + __tcp_bind_netif_req *r = (__tcp_bind_netif_req *)w.req; + *(r->ret) = __real_tcp_bind_netif(r->pcb, r->netif); + break; + } case __tcp_listen_with_backlog: { __tcp_listen_with_backlog_req *r = (__tcp_listen_with_backlog_req *)w.req; *(r->ret) = __real_tcp_listen_with_backlog(r->pcb, r->backlog); break; } +#if 0 + case __tcp_listen_with_backlog_and_err: + { + __tcp_listen_with_backlog_and_err_req *r = (__tcp_listen_with_backlog_and_err_req *)w.req; + *(r->ret) = __real_tcp_listen_with_backlog_and_err(r->pcb, r->backlog, r->err); + break; + } +#endif case __tcp_accept: { __tcp_accept_req *r = (__tcp_accept_req *)w.req; @@ -742,6 +762,12 @@ static void lwipThread(void *params) { __real_tcp_setprio(r->pcb, r->prio); break; } + case __tcp_shutdown: + { + __tcp_shutdown_req *r = (__tcp_shutdown_req *)w.req; + *(r->ret) = __real_tcp_shutdown(r->pcb, r->shut_rx, r->shut_tx); + break; + } case __tcp_backlog_delayed: { __tcp_backlog_delayed_req *r = (__tcp_backlog_delayed_req *)w.req; @@ -843,6 +869,18 @@ static void lwipThread(void *params) { *(r->ret) = __real_raw_new(r->proto); break; } + case __raw_new_ip_type: + { + __raw_new_ip_type_req *r = (__raw_new_ip_type_req *)w.req; + *(r->ret) = __real_raw_new_ip_type(r->type, r->proto); + break; + } + case __raw_connect: + { + __raw_connect_req *r = (__raw_connect_req *)w.req; + *(r->ret) = __real_raw_connect(r->pcb, r->ipaddr); + break; + } case __raw_recv: { __raw_recv_req *r = (__raw_recv_req *)w.req; @@ -861,6 +899,12 @@ static void lwipThread(void *params) { *(r->ret) = __real_raw_sendto(r->pcb, r->p, r->ipaddr); break; } + case __raw_send: + { + __raw_send_req *r = (__raw_send_req *)w.req; + *(r->ret) = __real_raw_send(r->pcb, r->p); + break; + } case __raw_remove: { __raw_remove_req *r = (__raw_remove_req *)w.req; diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index 4a5002783..3d1769f3d 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -32,12 +32,6 @@ #include "_xoshiro.h" #include "lwip_wrap.h" -#if defined(__FREERTOS) -#define __isFreeRTOS 1 -#else -#define __isFreeRTOS 0 -#endif - //auto_init_recursive_mutex(__lwipMutex); // Only for case with no Ethernet or PicoW, but still doing LWIP (PPP?) recursive_mutex_t __lwipMutex; @@ -64,333 +58,455 @@ extern "C" { extern u8_t __real_pbuf_header(struct pbuf *p, s16_t header_size); u8_t __wrap_pbuf_header(struct pbuf *p, s16_t header_size) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { u8_t ret; __pbuf_header_req req = { p, header_size, &ret }; __lwip(__pbuf_header, &req); return ret; } +#endif LWIPMutex m; return __real_pbuf_header(p, header_size); } extern u8_t __real_pbuf_free(struct pbuf *p); u8_t __wrap_pbuf_free(struct pbuf *p) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { u8_t ret; __pbuf_free_req req = { p, &ret }; __lwip(__pbuf_free, &req); return ret; } +#endif LWIPMutex m; return __real_pbuf_free(p); } extern struct pbuf *__real_pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type); struct pbuf *__wrap_pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { struct pbuf *ret; __pbuf_alloc_req req = {l, length, type, &ret }; __lwip(__pbuf_alloc, &req); return ret; } +#endif LWIPMutex m; return __real_pbuf_alloc(l, length, type); } extern err_t __real_pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len); err_t __wrap_pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __pbuf_take_req req = { buf, dataptr, len, &ret }; __lwip(__pbuf_take, &req); return ret; } +#endif LWIPMutex m; return __real_pbuf_take(buf, dataptr, len); } extern u16_t __real_pbuf_copy_partial(const struct pbuf *p, void *dataptr, u16_t len, u16_t offset); u16_t __wrap_pbuf_copy_partial(const struct pbuf *p, void *dataptr, u16_t len, u16_t offset) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { u16_t ret; __pbuf_copy_partial_req req = { p, dataptr, len, offset, &ret }; __lwip(__pbuf_copy_partial, &req); return ret; } +#endif LWIPMutex m; return __real_pbuf_copy_partial(p, dataptr, len, offset); } extern void __real_pbuf_ref(struct pbuf *p); void __wrap_pbuf_ref(struct pbuf *p) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __pbuf_ref_req req = { p }; __lwip(__pbuf_ref, &req); return; } +#endif LWIPMutex m; __real_pbuf_ref(p); } extern u8_t __real_pbuf_get_at(const struct pbuf* p, u16_t offset); u8_t __wrap_pbuf_get_at(const struct pbuf* p, u16_t offset) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { u8_t ret; __pbuf_get_at_req req = { p, offset, &ret }; __lwip(__pbuf_get_at, &req); return ret; } +#endif LWIPMutex m; return __real_pbuf_get_at(p, offset); } extern void *__real_pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset); void *__wrap_pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { void *ret; __pbuf_get_contiguous_req req = { p, buffer, bufsize, len, offset, &ret }; __lwip(__pbuf_get_contiguous, &req); return ret; } +#endif LWIPMutex m; return __real_pbuf_get_contiguous(p, buffer, bufsize, len, offset); } extern void __real_pbuf_cat(struct pbuf *head, struct pbuf *tail); void __wrap_pbuf_cat(struct pbuf *head, struct pbuf *tail) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __pbuf_cat_req req = { head, tail }; __lwip(__pbuf_cat, &req); return; } +#endif LWIPMutex m; __real_pbuf_cat(head, tail); } extern void __real_tcp_arg(struct tcp_pcb *pcb, void *arg); void __wrap_tcp_arg(struct tcp_pcb *pcb, void *arg) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __tcp_arg_req req = { pcb, arg }; __lwip(__tcp_arg, &req); return; } +#endif LWIPMutex m; __real_tcp_arg(pcb, arg); } extern struct tcp_pcb *__real_tcp_new(void); struct tcp_pcb *__wrap_tcp_new(void) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { struct tcp_pcb *ret; __tcp_new_req req = { &ret }; __lwip(__tcp_new, &req); return ret; } +#endif LWIPMutex m; return __real_tcp_new(); } + extern struct tcp_pcb *__real_tcp_new_ip_type(u8_t type); + struct tcp_pcb *__wrap_tcp_new_ip_type(u8_t type) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { + struct tcp_pcb *ret; + __tcp_new_ip_type_req req = { type, &ret }; + __lwip(__tcp_new_ip_type, &req); + return ret; + } +#endif + LWIPMutex m; + return __real_tcp_new_ip_type(type); + } + + extern err_t __real_tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port); err_t __wrap_tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __tcp_bind_req req = { pcb, ipaddr, port, &ret }; __lwip(__tcp_bind, &req); return ret; } +#endif LWIPMutex m; return __real_tcp_bind(pcb, ipaddr, port); } + extern err_t __real_tcp_bind_netif(struct tcp_pcb *pcb, const struct netif *netif); + err_t __wrap_tcp_bind_netif(struct tcp_pcb *pcb, const struct netif *netif) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { + err_t ret; + __tcp_bind_netif_req req = { pcb, netif, &ret }; + __lwip(__tcp_bind_netif, &req); + return ret; + } +#endif + LWIPMutex m; + return __real_tcp_bind_netif(pcb, netif); + } + + + + extern struct tcp_pcb *__real_tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); struct tcp_pcb *__wrap_tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { struct tcp_pcb *ret; __tcp_listen_with_backlog_req req = { pcb, backlog, &ret }; __lwip(__tcp_listen_with_backlog, &req); return ret; } +#endif LWIPMutex m; return __real_tcp_listen_with_backlog(pcb, backlog); } +#if 0 + extern struct tcp_pcb *__real_tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err); + struct tcp_pcb *__wrap_tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { + struct tcp_pcb *ret; + __tcp_listen_with_backlog_and_err_req req = { pcb, backlog, err, &ret }; + __lwip(__tcp_listen_with_backlog_and_err, &req); + return ret; + } +#endif + LWIPMutex m; + return __real_tcp_listen_with_backlog_and_err(pcb, backlog, err); + } +#endif + + extern void __real_tcp_accept(struct tcp_pcb *pcb, err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)); void __wrap_tcp_accept(struct tcp_pcb *pcb, err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __tcp_accept_req req = { pcb, accept }; __lwip(__tcp_accept, &req); return; } +#endif LWIPMutex m; __real_tcp_accept(pcb, accept); } extern err_t __real_tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)); err_t __wrap_tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __tcp_connect_req req = { pcb, ipaddr, port, connected, &ret }; __lwip(__tcp_connect, &req); return ret; } +#endif LWIPMutex m; return __real_tcp_connect(pcb, ipaddr, port, connected); } extern err_t __real_tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len, u8_t apiflags); err_t __wrap_tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len, u8_t apiflags) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __tcp_write_req req = { pcb, dataptr, len, apiflags, &ret }; __lwip(__tcp_write, &req); return ret; } +#endif LWIPMutex m; return __real_tcp_write(pcb, dataptr, len, apiflags); } extern void __real_tcp_sent(struct tcp_pcb *pcb, err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len)); void __wrap_tcp_sent(struct tcp_pcb *pcb, err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len)) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __tcp_sent_req req = { pcb, sent }; __lwip(__tcp_sent, &req); return; } +#endif LWIPMutex m; __real_tcp_sent(pcb, sent); } extern void __real_tcp_recv(struct tcp_pcb *pcb, err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)); void __wrap_tcp_recv(struct tcp_pcb *pcb, err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __tcp_recv_req req = { pcb, recv }; __lwip(__tcp_recv, &req); return; } +#endif LWIPMutex m; __real_tcp_recv(pcb, recv); } extern void __real_tcp_recved(struct tcp_pcb *pcb, u16_t len); void __wrap_tcp_recved(struct tcp_pcb *pcb, u16_t len) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __tcp_recved_req req = { pcb, len }; __lwip(__tcp_recved, &req); return; } +#endif LWIPMutex m; __real_tcp_recved(pcb, len); } extern void __real_tcp_poll(struct tcp_pcb *pcb, err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval); void __wrap_tcp_poll(struct tcp_pcb *pcb, err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __tcp_poll_req req = { pcb, poll, interval }; __lwip(__tcp_poll, &req); return; } +#endif LWIPMutex m; __real_tcp_poll(pcb, poll, interval); } extern err_t __real_tcp_close(struct tcp_pcb *pcb); err_t __wrap_tcp_close(struct tcp_pcb *pcb) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __tcp_close_req req = { pcb, &ret }; __lwip(__tcp_close, &req); return ret; } +#endif LWIPMutex m; return __real_tcp_close(pcb); } extern void __real_tcp_abort(struct tcp_pcb *pcb); void __wrap_tcp_abort(struct tcp_pcb *pcb) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __tcp_abort_req req = { pcb }; __lwip(__tcp_abort, &req); return; } +#endif LWIPMutex m; __real_tcp_abort(pcb); } extern void __real_tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg, err_t err)); void __wrap_tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg, err_t err)) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __tcp_err_req req = { pcb, err }; __lwip(__tcp_err, &req); return; } +#endif LWIPMutex m; __real_tcp_err(pcb, err); } extern err_t __real_tcp_output(struct tcp_pcb *pcb); err_t __wrap_tcp_output(struct tcp_pcb *pcb) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __tcp_output_req req = { pcb, &ret }; __lwip(__tcp_output, &req); return ret; } +#endif LWIPMutex m; return __real_tcp_output(pcb); } extern void __real_tcp_setprio(struct tcp_pcb *pcb, u8_t prio); void __wrap_tcp_setprio(struct tcp_pcb *pcb, u8_t prio) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __tcp_setprio_req req = { pcb, prio }; __lwip(__tcp_setprio, &req); return; } +#endif LWIPMutex m; __real_tcp_setprio(pcb, prio); } + extern err_t __real_tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx); + err_t __wrap_tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { + err_t ret; + __tcp_shutdown_req req = { pcb, shut_rx, shut_tx, &ret }; + __lwip(__tcp_shutdown, &req); + return ret; + } +#endif + LWIPMutex m; + return __real_tcp_shutdown(pcb, shut_rx, shut_tx); + } + + extern void __real_tcp_backlog_delayed(struct tcp_pcb* pcb); void __wrap_tcp_backlog_delayed(struct tcp_pcb* pcb) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __tcp_backlog_delayed_req req = { pcb }; __lwip(__tcp_backlog_delayed, &req); return; } +#endif LWIPMutex m; __real_tcp_backlog_delayed(pcb); } extern void __real_tcp_backlog_accepted(struct tcp_pcb* pcb); void __wrap_tcp_backlog_accepted(struct tcp_pcb* pcb) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __tcp_backlog_accepted_req req = { pcb }; __lwip(__tcp_backlog_accepted, &req); return; } +#endif LWIPMutex m; __real_tcp_backlog_accepted(pcb); } extern struct udp_pcb *__real_udp_new(void); struct udp_pcb *__wrap_udp_new(void) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { struct udp_pcb *ret; __udp_new_req req = { &ret }; __lwip(__udp_new, &req); return ret; } +#endif LWIPMutex m; return __real_udp_new(); } extern struct udp_pcb *__real_udp_new_ip_type(u8_t type); struct udp_pcb *__wrap_udp_new_ip_type(u8_t type) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { struct udp_pcb *ret; __udp_new_ip_type_req req = { type, &ret }; __lwip(__udp_new_ip_type, &req); return ret; } +#endif LWIPMutex m; return __real_udp_new_ip_type(type); } @@ -398,106 +514,124 @@ extern "C" { extern void __real_udp_remove(struct udp_pcb *pcb); void __wrap_udp_remove(struct udp_pcb *pcb) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __udp_remove_req req = { pcb }; __lwip(__udp_remove, &req); return; } +#endif LWIPMutex m; __real_udp_remove(pcb); } extern err_t __real_udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port); err_t __wrap_udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __udp_bind_req req = { pcb, ipaddr, port, &ret }; __lwip(__udp_bind, &req); return ret; } +#endif LWIPMutex m; return __real_udp_bind(pcb, ipaddr, port); } extern err_t __real_udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port); err_t __wrap_udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __udp_connect_req req = { pcb, ipaddr, port, &ret }; __lwip(__udp_connect, &req); return ret; } +#endif LWIPMutex m; return __real_udp_connect(pcb, ipaddr, port); } extern err_t __real_udp_disconnect(struct udp_pcb *pcb); err_t __wrap_udp_disconnect(struct udp_pcb *pcb) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __udp_disconnect_req req = { pcb, &ret }; __lwip(__udp_disconnect, &req); return ret; } +#endif LWIPMutex m; return __real_udp_disconnect(pcb); } extern err_t __real_udp_send(struct udp_pcb *pcb, struct pbuf *p); err_t __wrap_udp_send(struct udp_pcb *pcb, struct pbuf *p) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __udp_send_req req = { pcb, p, &ret }; __lwip(__udp_send, &req); return ret; } +#endif LWIPMutex m; return __real_udp_send(pcb, p); } extern void __real_udp_recv(struct udp_pcb *pcb, void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port), void *recv_arg); void __wrap_udp_recv(struct udp_pcb *pcb, void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port), void *recv_arg) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __udp_recv_req req = { pcb, recv, recv_arg }; __lwip(__udp_recv, &req); return; } +#endif LWIPMutex m; __real_udp_recv(pcb, recv, recv_arg); } extern err_t __real_udp_sendto(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port); err_t __wrap_udp_sendto(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __udp_sendto_req req = { pcb, p, dst_ip, dst_port, &ret }; __lwip(__udp_sendto, &req); return ret; } +#endif LWIPMutex m; return __real_udp_sendto(pcb, p, dst_ip, dst_port); } extern err_t __real_udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif); err_t __wrap_udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __udp_sendto_if_req req = { pcb, p, dst_ip, dst_port, netif, &ret }; __lwip(__udp_sendto_if, &req); return ret; } +#endif LWIPMutex m; return __real_udp_sendto_if(pcb, p, dst_ip, dst_port, netif); } extern err_t __real_udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, const ip_addr_t *src_ip); err_t __wrap_udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, const ip_addr_t *src_ip) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __udp_sendto_if_src_req req = { pcb, p, dst_ip, dst_port, netif, src_ip, &ret }; __lwip(__udp_sendto_if_src, &req); return ret; } +#endif LWIPMutex m; return __real_udp_sendto_if_src(pcb, p, dst_ip, dst_port, netif, src_ip); } @@ -505,115 +639,177 @@ extern "C" { // sys_check_timeouts is special case because the async process will call it. If we're already in a timeout check, just do a noop extern void __real_sys_check_timeouts(); void __wrap_sys_check_timeouts(void) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __lwip(__sys_check_timeouts, nullptr); return; } +#endif LWIPMutex m; __real_sys_check_timeouts(); } extern err_t __real_dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg); err_t __wrap_dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __dns_gethostbyname_req req = { hostname, addr, found, callback_arg, &ret }; __lwip(__dns_gethostbyname, &req); return ret; } +#endif LWIPMutex m; return __real_dns_gethostbyname(hostname, addr, found, callback_arg); } extern err_t __real_dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg, u8_t dns_addrtype); err_t __wrap_dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg, u8_t dns_addrtype) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __dns_gethostbyname_addrtype_req req = { hostname, addr, found, callback_arg, dns_addrtype, &ret }; __lwip(__dns_gethostbyname_addrtype, &req); return ret; } +#endif LWIPMutex m; return __real_dns_gethostbyname_addrtype(hostname, addr, found, callback_arg, dns_addrtype); } extern struct raw_pcb *__real_raw_new(u8_t proto); struct raw_pcb *__wrap_raw_new(u8_t proto) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { struct raw_pcb *ret; __raw_new_req req = { proto, &ret }; __lwip(__raw_new, &req); return ret; } +#endif LWIPMutex m; return __real_raw_new(proto); } + extern struct raw_pcb *__real_raw_new_ip_type(u8_t type, u8_t proto); + struct raw_pcb *__wrap_raw_new_ip_type(u8_t type, u8_t proto) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { + struct raw_pcb *ret; + __raw_new_ip_type_req req = { type, proto, &ret }; + __lwip(__raw_new_ip_type, &req); + return ret; + } +#endif + LWIPMutex m; + return __real_raw_new_ip_type(type, proto); + } + + extern err_t __real_raw_connect (struct raw_pcb *pcb, const ip_addr_t *ipaddr); + err_t __wrap_raw_connect (struct raw_pcb *pcb, const ip_addr_t *ipaddr) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { + err_t ret; + __raw_connect_req req = { pcb, ipaddr, &ret }; + __lwip(__raw_connect, &req); + return ret; + } +#endif + LWIPMutex m; + return __real_raw_connect(pcb, ipaddr); + } + extern void __real_raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg); void __wrap_raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __raw_recv_req req = { pcb, recv, recv_arg }; __lwip(__raw_recv, &req); return; } +#endif LWIPMutex m; __real_raw_recv(pcb, recv, recv_arg); } extern err_t __real_raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr); err_t __wrap_raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __raw_bind_req req = { pcb, ipaddr, &ret }; __lwip(__raw_bind, &req); return ret; } +#endif LWIPMutex m; return __real_raw_bind(pcb, ipaddr); } extern err_t __real_raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr); err_t __wrap_raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { err_t ret; __raw_sendto_req req = { pcb, p, ipaddr, &ret }; __lwip(__raw_sendto, &req); return ret; } +#endif LWIPMutex m; return __real_raw_sendto(pcb, p, ipaddr); } + extern err_t __real_raw_send(struct raw_pcb *pcb, struct pbuf *p); + err_t __wrap_raw_send(struct raw_pcb *pcb, struct pbuf *p) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { + err_t ret; + __raw_send_req req = { pcb, p, &ret }; + __lwip(__raw_send, &req); + return ret; + } +#endif + LWIPMutex m; + return __real_raw_send(pcb, p); + } + extern void __real_raw_remove(struct raw_pcb *pcb); void __wrap_raw_remove(struct raw_pcb *pcb) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __raw_remove_req req = { pcb }; __lwip(__raw_remove, &req); return; } +#endif LWIPMutex m; __real_raw_remove(pcb); } extern struct netif *__real_netif_add(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input); struct netif *__wrap_netif_add(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { struct netif *ret; __netif_add_req req = { netif, ipaddr, netmask, gw, state, init, input, &ret }; __lwip(__netif_add, &req); return ret; } +#endif LWIPMutex m; return __real_netif_add(netif, ipaddr, netmask, gw, state, init, input); } extern void __real_netif_remove(struct netif *netif); void __wrap_netif_remove(struct netif *netif) { - if (__isFreeRTOS && !__isLWIPThread()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { __netif_remove_req req = { netif }; __lwip(__netif_remove, &req); return; } +#endif LWIPMutex m; __real_netif_remove(netif); } diff --git a/lib/core_wrap.txt b/lib/core_wrap.txt index 40606172f..4466aa4ec 100644 --- a/lib/core_wrap.txt +++ b/lib/core_wrap.txt @@ -18,9 +18,12 @@ -Wl,--wrap=pbuf_get_contiguous -Wl,--wrap=pbuf_cat +-Wl,--wrap=tcp_shutdown -Wl,--wrap=tcp_arg -Wl,--wrap=tcp_new +-Wl,--wrap=tcp_new_ip_type -Wl,--wrap=tcp_bind +-Wl,--wrap=tcp_bind_netif -Wl,--wrap=tcp_listen_with_backlog -Wl,--wrap=tcp_accept -Wl,--wrap=tcp_connect @@ -54,11 +57,14 @@ -Wl,--wrap=dns_gethostbyname -Wl,--wrap=dns_gethostbyname_addrtype --Wl,--wrap=raw_new --Wl,--wrap=raw_recv -Wl,--wrap=raw_bind +-Wl,--wrap=raw_connect +-Wl,--wrap=raw_recv -Wl,--wrap=raw_sendto +-Wl,--wrap=raw_send -Wl,--wrap=raw_remove +-Wl,--wrap=raw_new +-Wl,--wrap=raw_new_ip_type -Wl,--wrap=netif_add -Wl,--wrap=netif_remove From 31177da15ffee3cdb7fa399f5834e982457cbd5a Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 14 Aug 2025 14:07:40 -0700 Subject: [PATCH 04/36] More debug, identified deadlock conditions The CYW43 driver can come up and start processing data. Unfortunately when it needs to send data out through LWIP we have a deadlock. There is an CYW43 async_context semaphore owned by the calling task. In this case, the task is the periodic callback in "asyn_con" (i.e. the background timer). 1. When the timeout hits, the async context task is woken up and the first thing it does is take the async_context semaphore. 2. During background processing (sys_check_timeouts) an LWIP call is made. 3. The LWIP call sends a message to the LWIP task and wakes it up. The ASYN_CON task is now suspended waiting for the LWIP task done notification. It holds the ASYN_CON semaphore while asleep. 4. LWIP does a bunch of stuff and tries to do an ethernet_output to send bits over the wire (i.e. accept DHCP or something). 5. Eventually LWIP's netif call stack goes to the CYW43 object (while still in the LWIP task) who tries to acquire the CYW43 semaphore and fails (because it's already held by the async task that's sleeping). 6. There is no 6, it's deadlocked at this point. --- lib/rp2040/liblwip-bt.a | Bin 6006160 -> 6006748 bytes lib/rp2040/liblwip.a | Bin 638402 -> 638990 bytes lib/rp2040/libpico.a | Bin 1480332 -> 1480332 bytes lib/rp2350-riscv/liblwip-bt.a | Bin 16425860 -> 16426940 bytes lib/rp2350-riscv/liblwip.a | Bin 1410800 -> 1411872 bytes lib/rp2350-riscv/libpico.a | Bin 3661846 -> 3661846 bytes lib/rp2350/liblwip-bt.a | Bin 6056268 -> 6056788 bytes lib/rp2350/liblwip.a | Bin 707744 -> 708268 bytes lib/rp2350/libpico.a | Bin 1564426 -> 1564426 bytes .../lwIP_CYW43/src/utility/CYW43shim.cpp | 1 - libraries/lwIP_Ethernet/src/LwipEthernet.cpp | 8 +++++--- libraries/lwIP_Ethernet/src/LwipIntfDev.h | 4 ++-- 12 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/rp2040/liblwip-bt.a b/lib/rp2040/liblwip-bt.a index 0e95fc6f834df5a086baa334bd0ebf6d071dcd24..9987b43f354c6fc7283f86292368056fb4c741ba 100644 GIT binary patch delta 20445 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 Z+&O25dLr@XFZFEf$Nu7VD?HD1{TJ3>=sf@c diff --git a/lib/rp2040/libpico.a b/lib/rp2040/libpico.a index 1db040389a38a3c9f5d803e48bf085382cce3bce..2246c71fa7e7896bb6eb4e2adf534c042799cc4e 100644 GIT binary patch delta 1460 zcmY*ZT}V@57{>ja>E<@Kxu3`)HGeRnX=yD)J z?O8dwSwl&a$LY@;hu;&WvGRr!gBuVS*sQSfGj5X}0Z*pP#_Jl!RR{=2v{wFaupeaRaO;;3Zf*uX_E1E$PwFuPMQ3?4LM>RkhoFq{lqxL#RikV zBU4vdg)XE8j}@P3&qdw30QO8r z7d4`D??ehcvDRhXj$}mWFlQ`!jS)4;f9=;p7EpziG5sBd1dtI;=#xBauND}qjJuq| zUZvHXxfwSCj3V8UW3Qp`6mrBGZguz!(BU&4-NSewyfqFxB1z(nyi%LGIF*UzBGhY5D8-xypx;z zl-3D*7PNYv+{-D_xWDa!3Kg%qEgZ}`c CV$1aa delta 1460 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 H>HYr?{?U+9 delta 36417 zcmeIb3!F{W|Np=C+{`(1F*9do&diu$oEdw@eJ}=@am&4tyU6`6Nl2wq+qH2k(PdFS zQYjQd*phOILKH%hMCp?x5tSr<@7G>yowH0O`c|LE|MB>*&*y#S`FgGQy6nr@w{wox zeQ=`0gm+Jrcq}!nT8%o@YuB3LTVvfajJf~Ch+MRo>0#;OdN?L5hW%k&=*D8MEv(;7 zjO&rZ{&EZ$!{V+vtU$77(KPmVMEv>Y?DrzU8peJbnwc2fm?g&T`g>znCQH=g=ano` z3riPQV{heo%!x<)G4CHl@(TwTBIW5+CrWkMz*0YI%+l(l|4~??V)YP~rpLh!EKNq~ zGAr5N73s^4Fn??v#?rUa>Q8sz+Wz{Q9$?oMFLqQypJpzt%stWY;zU>z`Y-*E9j^AKI?hG&qg@?{ELQGp4aXSi1Nh zuyw_3{{0D9fmQME4^CrS+P3&#OyK|D{{Pz@@c$#*zhKt{b}dn_{S)k}v3(k=r-!AB z{{dT9%;qmn;HC+T-L&JFKMKd~Wh!p&J&9c%|c5f{Z)h89$C!(EN-u`kojZh9Co{mA!9}{J?_{#pIuW} z*P8eb%fC4I-CIYpKMBj9aL>Bt?B5UT+6NsIzkywMEE>heTrI4tRm!>v$(A)hhp}?%|bV*xwY^-__Ay?1!HJ{n3(4-BXDn9(jMBKc?60!2Z^-{-ndl zdYokcWLSUH`HXiqvwtD1zck2GyYt!K6W0H|qo?0YW!DmO-g$!kCam8xi+OW@9mTFC zo~ts8U2j;|+u(1`x2}7}fA0jW>tAKpGl2zLlGq={<;84)g_nOY7Pp$kt`-(5mo%@< zmYiMun^?MW7+d<|R`zPe4*yhGf4Soow@hOH_pm0hm6f;t@51_*247pg8~eSme$V_D zJ?nR8b-feVw0Ic%E3vtUHJ@$n@jndfUmSefu8?q zN(}oyhIQ2rzUZCA{z@D>HJTNVFMpZEej9ZDFK&LdYyo%p>t zUYngL7T*+xFcl~37BVN+on$9ve4C!izMcI9v+$zFsq~ZV)S_iq#OW#N?2qF6yd&)U zpDtcgoP8sg6$^`Trg*5Hn$XuS~mFrV*JC>U_b6Z|v&!7EP*SPy|r~Q-n~2QiM^I zpa{1o)p3pL=`^Ut&s6hz?bO+>-DV+NGY7Ao)Ca3M>i7Q-XV|Vsx{C$HxjaRhrwVc_q<-|rU zcufAQiD5HahV~vehL2w1D#Hh^aHa5PR=6q#g~#yJS%sPWtv5DB^9w6nj~O05^)*-7 zAkRU*JOBH#{DaqA%?&S4TIsUtCt=bdC2EA9q-6+#D3R-Gg5_Z$j;fQqo0JFDWnqMy zMm&V)S9vn#x;K@*J(;*YIzB^yEfKf z>k&%R5Tdsu#55xMI3iNi^mRnE5d9nxBSe1^7GrTj4REUBg%}ux6`CZ(plGb(R3UD2 zM7j`z9g!)-5NAte3vq`dDhV;v5jjk3naKCUCWkTRYz!7IwhT++ZC-aJWjXng2cycB zU@ShmXEhf2Npwx(6j5;~>L6`~(m{NBAo;WCpUCSF-LnRZJmPRCk$lui?i|G5f8EuE z_PXq~t{O&J-fgWb#R#(RUF&+#h>NGD>}#XGi}sG1!Nl=AY@O@2YL36wSnK!GkQgyG zY=_@Th7+|t6z{YjUEE&hDj(scr7_AQ#mm20=PG3t_zk2PsAo>Y=(Z)c&`Rx&dJJq} zXEPRKFL&xA9&+mMQuRzs;Qp{F$}vDJY%uKuPF=~{<6c4?b|j+P(@W_oht$_q)9 zfs;)Mq8M|6DbpD>+o*KKsM$uI>fPz43QZ}Pms#)1xFJ((-%GX6G%8%tKGVp(qCIvG zr+rnU4R5{PRo7}0B_`p_JJyI+%^e*VSjd`4%NxdwWFyfzoRD;yPNFVdM8U?bMozHN zHRwLVZozIkE;;oBslL3Z4;n{RU4teffzntl#_BTGM6V1V&qgs{#@<*~8w0kX#R@(*wWa*TK4yVL&dbdEi+GbM`7uy`Y!#hcL~*ytWK zqjRv)!&&T}p|oF8aT;Mi9^!8#JnZsgbdL^bY&w~N?1Y#KIr+%%6^ zG`thlqDA1~w~z87D^qX5EE7{G!uwSfV@@=^bz&fkDyu!(Sw+57r=xDcqjpfG)AF_} zTRz6?ZgRECbFzPQR%q9t8G~r!M!XRGVx+l{cJ^wtTj!&5%HZ-`MZBBE?a3(pM^btCFT7~~~+jNs^q2x;);3x<^9Pi}U_@xD8{$3;i6 z;P4yDy6cA4iD==e&5dKJ$&t;C2aRz?GCC~7W4rH8<>6ago}@$;98JAAnRI^6CYee{ zs|?;|iz}6n-n}W3n_FD5e8?8p+x%5tDUmnWSvRa^ZiEqQ#D!rhH6x6UUV2;QVo=#r z5E->FA`)shXJTmnz&oxyK6CS@3A8a;58C@e#c7{6Ji4-!{nb0J@HxpA~0KBB(SJ*55!qkqVVnSAW@74g4m*&sLa z0T$k^^!?6z@!62vJdc0%Yj)nyE9~(yd+1DqSAEx2DuL125f?mBG_j~$qfba~fpM#y zu+23hh|iwY$K%cpsa`LnWnoC0&V25Bu5#X)2Av}5Sg5_`u#sVW*o!@T^45nvq5Rpx z?xFnhsZ(x#r0w@%PkndF!@oPcDKreH2^MBsJ6w%IS_B)k<gBcn$3w7Cg#<=-_Z+ zT)XCNM-4~_afJmlUUj#ty6YaNgV@Ontf1mmy##q2l@20EC8wV7{@$MzdyZE#p?hWUa_qaOpiwonD?dSKnb{h6WdtE(( z?4$c#2TJfGU1FkmmHVS&d9BY})A{?KQS%9xZ};$BoxL%9*xB3Sc)e#fJa+BYq4lg#0IB~)h!(yKoMQG=6 zn+hi8^7`U`qpCg{fg-U zf1(E!s~@3sXSswUl_51wbfSm}71v`_wahQBXY#VO%9d(!<<^ZYwv)t)(}cgP-`1mj z3h#Zfpmz_`BGt1+}bXETeTGY=iro~MZ8j1SB{x_J=tBdJiaqXe<>8B`H8Z51tHjC+6 z#dO1Bx_L2ub1~iJ3T-jg_X>lt!Nv55V*0*fdO|Tht(bnYn0`jrJoc=seZ`snl`h^9 zfn$c)Z3EiFd%oR1fiCVZ+7vxOLO_nv1H+`J2olX%m)mPEs&@EWy7? zp)*)2=?*}rWUvg<&LzL2OS6hs8P`g003Ko{cST7GZR z6}1JpjWiZY6wAkklc=VxvinGhD42|ttmR2$Hs$-q-f>>}MrNopTUy1b^7Nq?c~vZUYE`Y%tqxtK7GPaRYv z<8f_(I;7vymI#MxtTs`6tOeIwf22TyR#KT7SQnz#m82VF-+@l zE$JV%CD=qda0c|T?W9*yh~i^=h-0<(2T2D`kUsV~>DROcJV82&`WNHV1imNZZf(XF zNcYnk1QAcv>fQc2Ou@(ENPp}1e5@346Kz5nq+iz-s3Pf3{_&}U8f28y2B=Fqg+de` zyOH=7t^Ov`UubXB_N0$%19T&ON~`Zrx}WNf#v4ld(Ga=(Sb}@Wn5zvihIEY9!DQ0E zYI-JVoUqgcpCMgYTjKeoZ=|)T>X(qdUCUoh`kt2_>lWwb}$?NPnRXm`wbF&;Y59-hiF=|pLrw|DwE^alKBcYFMWjb-dIjk&+8TI+^qpFJ z9Hu|i^iI+bYUAy<$XKRz_!;RD+7cWmeSw`n{Uoh@BfS)>nW6Urf-OCgGn)geBwO`s9!9@;*16Y1*O5_TY6QX8;4>B<3Z zu>oW}sWrHhbe^^Zqe$=8mS8ODL7JXIx;cfK;N!#zTKhTvI%FiU`J{7XHth`wY%v+D zv<_F14&1z_us2Bu?xj=M7SeR&k|l-hB%P@w4e%l9z(s2U`!m?ZTe9Ngwkkq_8;BziJv!qV)W-r0ThVdqJY*XkL) z$(Cz6oOHH-geX>$bW2SqlFp?N#mCB6egP|jWs&||Rzp`My-^#W7HM26ijuaRto!=jGo#m`keG?e?kiTnsi_SDeN@q2L1_#Iah?8wE+SrZzP4Y z5_Dh<9D2f?1MgYYKMpmClo07(WhpF;bl`N7!ZJxW(dsLb4xHaoSas5YJNj@|hjgGM zum)FX4{N4r+W%wO&6o-Y=@FVfO!^*8e@QysucO#W($4A2 z8J|9RJ4;5smT-Y|U_w#O7c&BTd6e^|fRX9211I1x)|hnQ&>Y5EUeP{`wISWk-#(1pLORAj zK5eZYWYGU*31|ID_;-4$A3{2?PlPjkP#Gv*HkNc?pD4+SNCzfVl08EDR)2$%>~Ycq zSbgP`WV6W#tfG?aS<-=3T#~&=T7S6x3h6O;c%95I-P6xkeK~1WXvx_6VtP+8{ezo7 zlyxAn&gYaHM_V9Gdk%>9m5S-SV!Aos8160;+qal~7e5p3_9kOn#nF!SM6v3*y!-0D z-Y!(@d^WpUR?l?OX~!;>{z)IAOYoZ(tYo#Uh@ zu>N*gw>#Jfs$PTVM7Y!Vh;54#>^>3htRSNn-(6Jp-Qa4q>e$P-X6`e1`55=hLA7)E z;TU(4k;{AkoKmVnqegkGN@1fWcx~9eX|=qX1cmK8)TmB>I~C^PkK^a@{8+c?&QZD+ z9}?>>ms!)_ur}2+ZB(r$S~P7U{yHt|@Qw4AWbpbw^@-tAD;$aA58wA?G>@t?FWjwq zua(2I9BTn-rD0X;4gaIF)=l3IQ{0LVW+~} zJifuskLO1`?kXijO-+7z>{|(G7?0}ZpE^Rxw$=H@);m1>sVB-t^Ga=Zg!5tX?x%Un zXIm%P?gV$b!K)>@OY?T0yOa2kMEBkN^q#kp_^_DVQ2z0O2fV>4-Gg}5r4fli^mqLo z@d?469zp!oyLKe<-d=Z3l)QGuF~rl8&-J>!)xF{@nh2|xI3t5=P@p((ie!<~fOJY9 z>aVIN(dff3dEL!|`UdguDwIp4uZ{Ica(jc43~uqRiAF#EC}e;7O4J8U5=zFTh#uxs z51s)*yktSs#GrxHbiJKW!!t+>yMZdzut$h1mlBO|)~kdk>QvGxJcEPyv%$HELAM9- z57yDL(%<^)A`%KJrHLdQ(_=~t#wpb^L<|5{1K_w`xs1p$i7W9LUUwOOx>3`RzLnC2 z-yCi6Z9OVr)wUn8%E7_OBcE4+RZblI5uz>l3V$R`_b$Pq2*> zqESnT4XCIs_yceq!JmL{5PT9`SMYgozTgo0V-yI+Zf(>Pj1_Ct7mQ^xgZ{Ws*TL>SI{*9J`r-N@2 zj5~hIC=>!Waz-n`&w=qd50wSr)`FLS<#Yenz-@*9I=G$S_2Bk`-vM_Jya(J-@Mqvo z4qNP7h+9O(C9u4>PNO~8=py_K@U4Q&gS!f@3dRRcRBD2|3&u?)eYwZ+JA$!VsdNMP z65I#e+Y$oD0i%y#yrqo3g7KWm=qGqG7~6!(Q{VxDUjWPdB6mxF+^091m7Vz5j<3IUGSZP@zh;S;ui2Q;r9n)$Drc$IYRIw@b40g&n}IT zf)|1B#%F(2Y>0bA1wQmJuvby}5IjooQSg0&zXRVd7|)=M2Lva9M+-K=a_Muy*gL7T z20tX2zJ6peLvDics2C$ER)FQBhL6DGgnt%{U7JcPdg^9O5Zn_yQSj~HhXvzVqfsPy zCRi@mv*1baY55mJ$eF$l#`}fJJK!mTKLk$|d;~mA@VDSc1miKF@u=Vu^ti~tdyPsw z_%Xp{!7~I`0b4VLs0;D9U_41Po)Fv-j5jJ3d#P23tlDoQLua~J_BAYeEKm1Gi<>@bT4PD z5gZN1;gL#J@LIvRM>pOe#`~`=#5z$i2>hnt$>6sHzYJb47>=0ZI zyi;&_;*9qLoF)BSL} z!-C!5&jd#kXB?4ik;sx2$w-m|WP*>1q+Ialf^mmsd?C0u_?X~<;4cN=PMq=I0B1@6 z9^`x_{ITHU^7uak;%iay9QcIb<=}4wuLjG>Z3Leb{ySi~nRbJ}75;wkDZyWYzY}}{ zd|I$O3djF5LR6ruPvd*RO~GdccLJXi+!g$T;GV=8KL$8U`h$@pCpr@RlgJqlJ}>w& z@Xug+|2+vImtY?Ff=GH1{EOh%!50N@2mdPg1Mnrm9};I=4se$A4EsR7QC{sJ_RlUokPl_{0Cz@-Jh4VDA%0GAQ|C*X9!C%|O| ze+TvvWBF;*(`}ciz-?E)#s!i+@af2PnF?6>^d)b<4_1DX^y!cDQ!eF~(|oX{Doj*V z6O#Zdzk=q2m0uCQJhp?CUx!#NOg-et1pup@`tZfVSeGGG#f^cA%V6acv`CfEB_hza#e$szk*nu&1~ezH32S=yav7;46OX^(#QA=LRGwn3ON{9 z`Ck$n;&*NA1adSkko*n&>S7-PEB`yq2P^+H_Wyi&swLsCxJ0Z53#QGh1_P_cA@FO6 z!NAH7*L<+@UGU{tVByp9dr27bi$PbGzk@T#9(0M<5o}kVC6poUk(OV{v2X8*mKB{3kFs>&%>vypvx8= z&mmOBOR9o=u<{qczd=k6tbE)MDIcu-#qj0iz{-DvSWRvNv884Qp^`Qdt9=5jeB3uE zAFTX$;LCjitbE)mC?BkR+&0L`Sqwr|;O(hqhl^r0Ik3vXj;{6zu=2mte6aFyt*Isr zR(=?*%=|og{D)8#xO!5v1}h(@edU9dk4pfxs=>-HAU3k-g-RpjXj~xqMvR|NSHQHn zFW*S4Dw=6NSozK2*QFOKVC5HTK3Ms!;GY%!gO%To*vJlYu0Pl)9ezD}p#oOJ5`b0C zY50xlg$h{t=QJOz{2y@s$!{VW{Ge4_Km+N6RfCK0<tL2!>Fh#lE4KrX^Q59l|L1JoX7_&e>SliY%X$SKVX&fEc_Ot z?X!4RuPR>9D!|I055J{o09O8T%?B%g1$;Rs8@i<3-mH!!h zxrV^XKLWo{EDTur$NWAmKZL6I5*2cGVCA19HgZHqKO;xu0?GKcets*F16KYe%?B(0 zGJGplG=NYQQTUWYc8ag`tHHo3#{>Un(H5+HujYf5kB?^ZePYdlm2ahL6<}47247AN ztbF`tKusEl6}(N_5QT7i1V6_5R2J>`n03iXr=k5Bwht%&_kt&kHdI!Z^5d`6Us z9J#i@>e*2?a^!QsO30Dt09B>iKR1 zy->k3 zMB@hsSq1Qqf~$ak5?meEKgM|>@=)=!;2Xdf1Y_?tei4jW8y5xN43=N9Zx6;pBPyLK zjLQx(JiasNe<*#xhTwtVATTZe5C}Y3qB0zer%6=q0f!2H030TG47h~giC{csqA~@H zCrebOgWZCk07nR(3#QKsQC^|&@w6M$@8YQ|Z%>Lk42`!5mBakLHm9=-5`@B|F*9B; z)|LiNkB*7{0Qvz(t93OnVXQ+V96mIT$ zGOq$2IQdEoA8e)xz7c+z0Gp-xLkqikD@hBFj(pfJsDRCM2c2ID`|$3f(v7z`**C+w z6RFs3sDMqp;i%jVKP$kd%y|et4zN_frpy@!KayUkfK8c$XEX*5yi}e>PUQfbmE@O2 z=c5AeRw`gqCgB;15AR$mU{mI-girf13fPo6>)_WA{yM&M>?0ZcG1tkYa(m%pSEm9t zYYN6^hQ3;oxp6ungU@^9=cFinVCBQxfy#M)_qazgqTE4b;W$9W&F@3%j#~C~~xpZ1Nyy2+exNSBQ zjKiuAM+_=pvjx8)B$t3nvpQxQ+MWeJa_MIrqcI!G#LglsV(zx88wh46<7A8g8;j_`*we(#CFu~A(iMu?=Y{MSa`WJKXc&^J<8 z1NkFo%?xW4EF4y;fX%xFkAr`2fK8b*8U85YgH4$;9sYg72b(en|5$_Xe&K^nnS(Dr z`5qAGItF3NB-~B;MvDeu6UTWfOW;2kU{mJ22LB=9gH4(9I(#~npny%8gBvB^7{_KC zgZY3LkNK>f@Wu%bY>pL-FI)M>2iTN3hu}{TKG>8wxS#Qr6z>MGDRWK`8sF*4$z@|(J4k3S<@WH0calwB?_+V4!;FiQUUHD*A=HN%ezQ=?QHf4?v zKlb&_5EVXD$Rzv##y3;=U{mH)hmSKT6|gCD@XKW1lfnm^G6%om_dO+iuqks|!RO>- zD?yktsUs?8i3VU3NmRPRpB-RR=JbaDwD7^E%()%@Gr|X(GG`?GIl>29rc8Pe6>~)e z*px{R!+%!zU{mHyhd)pFU{mHi3I93agH4$;7yk3Y2b&_tWD8L7f~WwSGHDt7`NChu zKh69&!`cWdM(kr?^F>kp9e6T5Vj=^6ne6T5VzJ8wQSes?A8g8;1o*EBA8g8;H2g5xw^CH3 zp+Y8=Lxa`A2b(gdGJIS3U{mJQguh1kU{mJQga5kl!KTb<27fL2*jFJ;nbZaqZ-@q9 z6G>F?Z(I7-1=y51ec-<-e6T5V2El(z_+V4!42Qp7_}~OnCf$dM4Wi;czWnf$?c?wj zO5YY?fz7x1j}1T1vuya=g%38j3dXOpeX(L!0-G{t3$gLO$k~IOT>&Ua5dh znd5vDbFaw%7CHOnE(2l83jA8z=Mjy;=6=xt|GtTFP;ht{<$MxgQ~J^H4+$S^${hT2 zHNL~b2b(gdOc-D7`99IY54e3tL_OI2OmJ2BM+0oioZ9d|7e3gOISt`|A$+hYb6Ubb zCVa3dbK1cFlJSr3_$t=w1o2;y1UA1E+!Ov+0XAjMK={Xn4>n~EehlvWTKHg7=G+B8 zUaVNKDRbf})krY-2Y1lFpxEl;V@dq$hH+kgytO;oNZ>(j+|B4uOYvu>_;Zl{SP7!5 z9caE#42SKU@m_$lq>qvEHVYqIZk6C)=ugdU0nU9_FlI?pazqk%r||J{f5vXX10b?w zMJAGDgKY4JBB>G@d=%g;>E~+swZR{YoP6Y;2yoWNymUMFW&S|uS{H9H&lAQMEO*88 z3J=jg?>Mi$JIAiEno>k@!%iy|itG59{ODAdhgaH} z7!!4jQijNsl6+^W^QA)ZkxPn`@>J^in96MiiSG}glUNEm&N@HgZia;*&WaK9!iUe8bh_2)DFES@U)sVHT=t8k$lFRojtrw z&9s=x^C@Lelt}SXni_bn9M~C^UOIRf`ww5f#N$a=Uaaa&BHi`#-A~cdE^HGQQ#tY; z#v0HyHpA_m4n6Fy+-YB;b;1u zi^r~ntOgV)b0#qsLu&{3oi~@ z7#=##hdZ+2i)s17s0Yk52VGKGUy-qwc*CD7csz;4s`^)Dd_8w1#Fdd1q6H0Em0z0R zN=(T8jZd@XM=vCLc+xBBF%{;`5g*lJ#wLYYW_(geTWXlZlv6q!d98ywGtL;s!{ic>?PurU~vb;2Ad=sB+m%fzvevL5apU$trFD;4m z+OF!}1-(=ocZ|1a$4o?$y<=u_=LD5{vytVs8!k-F`cXRe(77pd*Q@Hc)~0!j%J(Q` zm+z4}@ImD|{V(|>wWQbrwYf8egSFCThN_e*)AxDp$pvXuAJms)@7lB-87gJzg$iE# z&BJLoHjyd22h*xf%`8n(#!k&lkC~yjZN4gfq*q^_13S{~13StVJ`~7GvK!vy8`wk7 z+PuhDw0ThmMW(%ZQMonu$V!@Wl07@!{Hl_g4=q)aJ-3zF?iS7Q+EFi>b-PK&rq%W6 z$-sDC`~0_A%c4~6(qFRfAE4JZ?vp(&Q#VdNoSp5HMsIACoJH9bJ&97aw%$3U1W^$x0)2Tq-aEOBSmA1 zCKOF6no%^TXknjwzh&pwRhQ02zHQP??>5(#+AiFE)819maJG7WQK6k*)av{JVcN8H zni{s%`{s@zTDzjt{comdZJ+MnX5Axt#n!WJ?5$_pPV#7-+CxgTYctJ1kxMaN`{T#k z)ljQ{0>-3J}@4Cf~zpHb%Ld~?Nt?#_+Khkhk(WvfS zibi$6m7=RXs(ZHvNA&Ey1>JK7NyAy#^q0EZ=`Zz&c}6!28}=+JY}kvUw_VtR&+L8ui?a6(pcrUp?;EsB zEvhrE_?fra@iPY>nWJ|RQ}y-(&+A6Wp4&I9kOnnNDmpr0h<$Xz9VOKUb_R;vc}G#? z&Y=`{QVgRQPBDVwE<1AP$OC89W^oQB#>TtXi=%RFPVb6j`|ystSD)116O%( zMp2dbW>P#(@dU+_c9r*@y49_c@ZU_CzwapuPBF`#zi;;DZ}bUF*!XnOgpJSG6E@E2 z=F%%JZl6r=9vZz}1RTQf!Y>G8@wd$|m`-@7#df!}mEyWuY>nPr&c#C2^ z#RiIv_U6i)&X3cFI@oe1HCGGeym^j&e{8|A@4t)+^q4f!`0py?tB5O3I@znfD#~7U+|FM0^*VK_ z;p}zIPULsf2C+N8aH5i0`AD$mojkFuubwfa%{P_4lZLZ-R@Ogx{BGUoHS^nrL3Xb- zCl7?{4LfW+8Gl7j6EeTua7VF*W7NUX8T{gZzRgz`k&e-!+^L0EY>}j;r|hJq-*r%@ zA!HRzdi1nC>CrRu7i+^WXkPdGjheRmUHm@vZQYo&{%o&dx{;J~ZlQjFun!G5*Z5s6 zqbR@14|aZ)AJa?g=BUCS?NNn4&DpD&c23#zIaPFHbnElS`|HM-Rp&RP=tj3)=TEAu cKxg6m9Y241x1KRSgB?|Wu4d~?;v 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 delta 26681 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 O`dHJ`3N*j7|9=Dfsn|yV diff --git a/lib/rp2350-riscv/libpico.a b/lib/rp2350-riscv/libpico.a index fad94e09b0bf33b09c9e627aa771ae7faa81dd5c..65d5bb2940cb5cc28e37310c10f7970eec8497fb 100644 GIT binary patch delta 1494 zcmZWpSxggA6it;DRF+a|JGBC(h^Ww72I#^Es9=nW(TKQ&SgSuSpnwrSOhhG-F#^Wm zG7&WrQ~5A1#o}C}A_{8M2rfiFAVD;^L{J+gXpB+c%)DD6e%xf{ymRk4_r5!G{Pruw zaT158s#sf^-R5dG`{v7!PTn&d$M^&D+pP#RrYm*+t{r6t3LNuk^!}nlHIv2=#x-~o zMiV-27(GZRYmQ>zmr=2Nj0lvhSIkP0IW9hsV_~?KS_QP!j{A8A(Ph3Q1J{{4oHcJKCtk9l=$P)!1;$G;TbQy8+ zqFHX}M<|If82T~cV=Lu~eZx0lV(v<$5)TZwB4QG(hzPIRizN@=(lRhy7v7Xb5g_(n zJ`E;`UXPrJhKZ%4-K~s-yOmK*EG7{jZ}N~rUi45p64jl9NTZjyS!Y+5?n6YJ zAPj*za;A*9gxBf~&+$~eMX2;ghnWx&FB-hv(JBi?uKF~Kw$W#yR1-NJnd-7w16Yn} zwnk9|h`PHDk0o46Dh=?o*Nv| z!r;i{jT=W-Ds}4|tC1#(aUFt=gdREsW;V6q;-wBF^9*zTAXi$8;@l~T1BjT;ni;r| zY^;BTh$LI|)d)pjr(WJIqfQ_lAEM2=cxgvk_rxkQMkVQ>&mZf=-H^5mGRot&! zbTq{AYiJTj<_(_Vc=!D=ReG+Q@^2s#IG?~k-p+(3R04u@Wzu7*WN&}Ms&&YhCcku! zdBHqHq#<0XGH;5f2#}U{J(ORZ&{&*!Nr_x>QMr=xL=w}Wq&%rF8)>BDccVWDJy$T0 z1O)@r7k|QJN$C2sWYcGgaQ$sFNX#TL3;Nqqx_XdGhRML=hE(AstDSq*UU8hcX# zYn_(5P%J@K7y>y~x0e#ZbBYxdyzh%OnKzHv-h%GE^=R-HK&rSWponyjDc`M-@_lyk z4$LPMIX|BFY_o+x#a7#XRI9GARac}573{}YqzCHREm%?1UWqR}IWfSCbL^7;kkbl& zuh+7f4>YqXSklbSrS+Y`E*JjG5r1;pb{4el>A&lP){7GjTv}lUiA+cav|v1h=cz=AWs4in4bgi4TNkwmVe7DK|T{ra;%`3Nr%^`VCy5WMAD#%%Fr} zO}><&gpMl~FDg{D#`EyYqFKa>IB5|mTcw$lfg+)NJ1tAPu9hy6T`=t6&*S?bIj zP9g$2Gqs&MrU|5|Ap&X5cVjqs=+>sc4ovS#VH382>aMk!Bxpvoc3t zz7r9pLFfm4+(d>1U+Gsr!CmE&pgJ%r%8H0`(cpVJN@r)tMZaOrM$9cY#En!LR#dcp4tTHsWqN+qY62xskulY z207{DpbDjrS3uWlO$Vpycb=bK4jSq~m?qtW0O*+V(`PI3&pgF9M0VI2&}jK&(vK zgojU^cQhr*%UO~{&KtY~$(}p^sB~Yp&bxw0=u`?1gS;HfuT}^bpS1*w!X91W3zU@8P1kH1(`jUASarP^GfUR1)K$tTOGzRHTuP-wypD zIH{;F4T}24&;5kSw9w_p>DJE-k$T%EkeEnf67;rZbagW|Wqf#e(3BZGf{6cnx!hQ6eneT zcRki8_w hmB#$grx$9r=Iqupu0(z$(AT+xI3OzJb(>qX{skW`^s4{> diff --git a/lib/rp2350/liblwip-bt.a b/lib/rp2350/liblwip-bt.a index 6c5cf8cc4ef8b54f625bb39e16a2c3c20cd8691c..962042ee39fe93f6e52c80926532ce64adac4669 100644 GIT binary patch delta 21207 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 delta 20928 zcmeHvd3+Sbwtw}^bWhKk$xO&h_MI${jV%d*gs>BqENlsh7!)-?*g_CQpxGo`1qDP) zyiw4n5)ruILs}7Kxgc<5Q&I0#6#R$^?{RUtEOEnkPEB<(Aklz;zdwHS@!Q`zr_NT@ z)z#gT!J{91t2^-Sx4NaFQhNKWb{XxKMZc;%d4fo{5XPw;h%Xdh;ab}A=1|fcOkq7q z3!z-y@QHe2x(=A*PLgYb(u~8_G-AFQeyAYk-+(3gRbt6p&~hj(F`l=SSZ)%O>k7OM zMyTP9jl^=T_@abZyil~p_3_0;#L@y-#eL-JP@3y#M(-xX+8ol35i6o{PP4FCdJ=}d zmBfZnrne=w{}5sitNCr@*AcrfMuCrp`%e)2bwat)(QifoX~bW862EIj!#U#Dawx!2gryKd8q> za*LqcszlA?QEu5tuU>$1>!$ju1t_=ZJYO|Agu&sf_Top=l9StPTw%Uu_3KDlE-W^TiZUmIy2-5mX13|=hUEFfi zb|LY;__~tBb0nnfBUeJXQqi28IKoPP7hf$Ui5yAELr5d4eBqi z*OB%uh0;>Pn`Ec7xY8>M=%|(uM5nvEG~rAg>2z&SuGQf(`;0kf$R7iI|8qS7GTTIw z8v^A<1@eiLwe}=wDU_BPUawuYdja_kC{3N8my_)4K$p$kNK4Rl&SLUw!1q7DR^CFL za@DGCT>;9UIr`lFp$dV+)$v6G$-T+Q>!TbYd3}BdOXiTggPVVa?ouJ?9&wIz&+2mh zQ2vPXZ}|2Y*p{>e%I_MTn@)P%JSaCacne}H-qH1HI7$8#D7PSS-<=JlIVjC_puXQg za;%6PUuha)|B?#QEasGu{?~~CrHe?jP=2e^r*GgS2f1Dh%34R7gVJ0F>I?J- zejlBNkb>)n@<*IW!Ml~eiNXLv8c{r&6#fdz)s#0zSM+oZ`CTY2F>1zU@bV+%dN3r= zLo_H_W5~2cq(!*&6B%;jp#0%rL*K6_3_p9w(5qlrcqaK3`Yj;C7!+tMYVcxv0vV>^ z(<(AtI`wO$bs)n_CtZe;_?e_xeD)J5&0o+w6yMGVJCM>V@p=s@^~HOuNh!yOyv^jQ z*mHo4XaUM*B#?1b-W=5T8)Onj*t?wnBvT{Xwx2Pa}hm3YqsBk7Y z^9X*#4vZ2=5=m75w^&*x6epi<=z&ja+lC8Ag|y!PYB-sh)$@ryk(<(bzj3Oe2lQ+Qo=+o(O5K#D z4oF7?114;3*Ao&p4O&w~LPA&#-h)Xt{tPXX!T1W8m<0I+iI8}MIA%f(F{D6`?hAJ^ z8pvWF9g<-eL@=ZXgy<99mDnRlGe9y7fVRGk2M1`_sv`=~XLxF{UnhPGF%9uD^k)S< z$yCMysLNy!BO#`t9uE3~pv~B0FrF|Hl3;*JzJrGA4NywE;b2$~{)PZ&Ikpo`aPYV$ zLfiEbDoU|}NZ0+?F2|U$O2ES?s1U@E7EllEL_HXp1l@9|Mv8=Xl3^E&S)An!F$*lk z*{(zAbp&#Wit8e_yP$rq3!UAfPzfrjqx~(A%*!DWk)MZJ6!`=2m@R(->RIyh(4MKt zw?Ur!4oxYMJRNjDqw*7`^dr)2 zklK8QV`pPCuaZ1ain%Aa5c5wE8H##>&M1*$l|zuU+-wu%3N*)h%nrdn6U>S69Q2u6 z2{xQ2gYiBHY7X>Da_BwNh}+w?8mGa~&542&LpY2FFjcDHdH|#V;{upHa|gk_86=Of zJ6h%nq5lFY)Hu}umjqPB#7N`Mn0$c1CLq?h8`BLEOc78-g7IDqQ!F_4LtQNr_j;H~tMGn@0+AD!2_W-i1Lb1U4_l#vBZChgTYGw4i0{(SnRiVo2zO zspH8#-o9bRV>t3zLg;z0DItcQbXTbqD;VfkrBaG;I}IEGQUJ{!A%zHp4j&74D7s-#zNLhfW6NbPFrJM0Kbe`giJ7 z40ku{3eY9P`LNu>POwL}3WZ8LUKydf#Ta1>6C!mhu+p(ih}F%-aaFM^EJ2q86J#0B zgtofvXf}ZfY1(yVJtQr`sTqT3o|uE#;`8{^ugfHNg02d>tRLADp)Tq&5c}=ziS-0)57RvaKGx5eb%{=)aNYca=haYBjV9Wvf|mECSJZfqq;rg)340U_Pu?K|dCh>62h=`%Jbf$6oN(je_ym z#yeI*4-vP(NGGxsg|avsVokE+{x?Jxzl827Za)x8WHAVY8rD-TivggUYQYP-LKX!G zd9URJ97oII5{Ne49DrL=r7RXhh8Z9cGDa5dU~xYa#>(PY(9LARI9cohg2G}~$>M2P zXmeOSlVtG-)IFC8lVx!TjA$Mcs$~)H2lH+HAi)$_jE4XVY+pcvM`aPO{6!|`d616E z;yaIzl!9S}hm4f^-!mSnvpu1I0lfV7!@(vBVm1Uyh7%yL14={^K@Nz6IH!dk*u}Pu zfOZh^lrW@G;Wr<`nc@Tqx2$ofX8WDrWAxxixamAe&yJKLlz@&9ajWoVqg&W}Fha{* z=}4m{=q}1TBPU_97$R+eTqOj*yiv;6_7&9)U6}vswQ%t)GPb9kny0hc%6WEh3GF znF>1%q5Q@<*J2+|h)@n%5|Ek>@jen>*IYo9onhgn3U-{+gP`0CAmM1@Z=!-JBfL+99xM`| z8|D!p)J1?ZD@VE>2+5ggBfu!_hPUT>XzD|l%p_4htT?U(7?T#;By-*#UZrE zSTBP7JnHZs>=1Hsq2X%Sg}OVY-VM6J80RaHj{{oa-1-Z49GVk`ZU(S+XfF zBHeT}05g)&9r_>e?USdG8WJ6IRPiU7gP;?yOqla8;SjSP+80pF1PFCOFyRgy!G$;+ zz=u%Jdw@t>92Zh?KCskp03j2|4{SVsusCc0Hb{eau>^zcK|QW6yrN}@t5<|VEHDrU zh(dHp)S^s7f~OBMI=I?7yv7xJ{gPX17aQ^D*@N|i+<>#TUG)! z?P4{Jg1*}UosU7K!dn6OU}7tTy_VqRv;~WS+}?>>R)Q0^tXwY))-9{h>t+$%Gy-H0 zApm@A_;ihzuT6}SvH#3?u8!M9pE>UP-kOi{j|j{ z5;zn3aA)zVVcWomtqx#kO@mQ4!8<%yd!F3MSOEVlfY{&`*N`s8}}n{hB9 zUDiP!VK{qT08`SM6~zh~o{9y9LIoZ`B)qQoz~z<=LPr40U4psGKq>`<;JO@X!XN;jKwO z7wn2DLT-@W-Z{#gEoMbY@j+dJ1W>o4lRuXOQUd!5v*2omR{(>MW3gEJxjI|2Em;;c z@wf!N-C}7{1kt&LQGr4*Em~y@5JKpQd!zt!sEz1l7M-ph6z`_T|LK%$;TU$F5QLE< zXklklD9x;t0zH8QDzQKzkO*Eh5&d=WT3RXj(^ZwyTXfTflu%a( zi{LLfC9J2TMHmYI@Szjk^q$e>%)k_=&g@IPx#;FGQYSj-<42 zNyi1Dm_9Q>iU}?N8xgGVBf{E-X0Rc=ts$)g{dj^D2WG-V$z^;FrdCgm&~Jwh&8Inf zxqzOS+HE>reJYRA4M)v=>C%3Z0bBmGX0o)FCRW2^k))PXO948?Gw5~Rd|U?Q>An@XR6d$r`ArBM7_Ff zhP1{&$LC8CR9;kOr4@=aT}Y#O%i2bp?=&CUzi;nbdv^bw=H<0>(K&Zo9NxpEFt^w{cH2i+JQ;-I0=K3xZeQ7whU(eWb+mM zxIH%YyU6EP^y9vWs#xaViukEJ7f25Zw0NNuPM=*UdFYab(o6-`3*JL@uswA_PV_!Q z>0m!j1KA9lvlF=uyq6-w_FjUVLdZzuRCp6W2IFevba+8PZU;{Tz`FK?EJcQgz!k`N z55RtSY{tqun>)dM13NOj3Ud}u+?f#E_`_kBgjz^=SI)WKg2MA?_4Ly23b+v+MC!r0 zh%*+6`r9~<<2;Eo-oUW`LC%kGev0#RoL}Uua^AuDu$L9`F;|@7+`!oYlaC49oTEA8 z_id=}%(*w`3eILhl2;XVkzgxIoEN1mUBJl4V-a7VIf;N@8G0SmILj^ah}3i;k=kLej|Z) zFL2($`5>@@9r)D}@(-M?u=AqqEV3VDDlmUCXk8Ga|o0!Xm4Vjw5y_MGwSU(^rfT*Y|_=M9{} z;tS6IgA9SsbNPGDm$=>p@44t_ah#Kop|E_;V>vJ6{J4!@|9?dVJRh$` zhQynZA;GJh_i}!l^FKKslk4{~`0GT1-C`6;en!{wJaZ{+%|URfb;@{Ygrjssji!ucdJBr-s? zSg0Q|OlvTgW04_o0_TpLvpB;)l3;#)xZI!f2*z;!M{>n@&XYOciwucc5n#9+`*0r5 z`4DFd-p}E3!f(5f@o!Lgb=<*uJ~AxAwVc`W0m!FNR-oa++b(c7&f7Wv6B!l_{_P9d zq4#nK=Okn(vM=X5I8R1~Q~4+|%-qYI;daa9A2^2@;17Q|!YP5-hSo_s&~t67GBibMKh2MoE8PX)waBZ1js6+|OL1qsN|nSu-z!^0~Z5x&9W z$n%gP9-Cr_HxOkAavVnvBPr$;uR(@5Cx8_UG!ZL=sX2iRfqLP67y^|cL!imX5GVix z#=&bkGU(cJISm;KWCMZz0VqR)3f?~&8S*UR@?vDj_Z)mZ!2;H!0uuj|8yrK1ET_19 z1{n%z;POw%p>$BE_|A`yHX3N;3h7n4Hc7Ipeve801gf03ETJbKmtw^;@CFb`izX(y zXe5;~b=LOu>4`~!bP@=rfcEg^8ib0co2WFAZtP<-nEIj&u+Vq9_6VVUpO6x4qrncx zjCvd0nQnDGzBN)7cGIFRdG4(5Knr(6(hY#0nLgHV)v-5R%n}SM75?+S=>rE+|CN$E zD-d+P?klvSz{DQ_=Y$oRdxd)}a}UbC!o5y&r$g7v5wzR>0t4N=QVO7L=f^vg=d@l3 zidUo-d=U>0D)t!$OJ)U}G3^80?1PW{zQwMCc!i+AnQ;TOcq^`m_dia!8|VquFE#nM zdf|%Br{T;mr2boE7d`S?nSoY`=~nTlE)b6HtWI*Z!dC|-;0a4!u1siGnxSU1R7N=g^0T$bZc6) z!4f0ZT6@IYo680WJ8-}vl+W;8heDpqduE& zdm)v3se@+N4$aWIQ?i|IHS4@hiEFAlNc|w#zO`|>-n`g8Slt+5my@}Z`sM)p$UrSZ z&K5aP&AijTJD5l4xog9pUbbw#G}r7$nVjKnhC2T`A5HxW4xNI zS}0t#NBDnmMl)ff6|Bx_F0N5$M>yApXaYodIaafUqCD!Q+ns0c@zJ`Y(lcr&F zHU1r^D^b%N${rM?uKK~*FMw;*vv${3E@Y`2VqBf}un}a?qHSjP!qcvWrvnzAZnf}q z;KI}HEvG#P%Ds+RY>m~P?iHk-?iKv@!&(A%GTuEJyu6)e$29YdAup%$z<3SR7G;D0 zLIGibaJ48S;&7Pe0;6`TU57?I8m?(rkh4=F4tc|7q)`~ZTm9Dy5xLp~tKor>yS%3q zx?w6|dV(W|tzKAZMorruySPv@gJA@zAN$2Ulg>0y!<%P2 zdDJKK;=Ww&>sWU*POUrIdVzNxXrt|Vs`a?xJd_H>ukFX9s3ZRp-?~yu!fJWu+xQ;7 zwJc0e*pi-@&_?q}DNmferIYdg49JnE*+$sxmh$9Kw{QhUmr3P@8=nbX_0*8Jh( z4^rEwr@;GbCcufvU!e*1`57r|eJdzQ&Qwd1v+5OJW$5}WHFSOF1yx!KxRyNX zn?c!I-)=JVsE>V-z4wT(;=V0iQV(zio60@&y4LQQm!s~Pm+S7P1!GhB!>-&MnQ1y@ zsX1@weh}Ie$X%OuDpyTA)ot4-&4-`~7i&YPXdLUp2S zH(MlkU*z3_y{j!yZ5!RaZIExan(XdsO?Ho?E+3^jx}Zne8m?et*>s^t?WPMo)lC^r zz1L*mk3ECb<@5SG|K$^`c1PI&bw}C2s=y|tN9|WVP}%RR_#%6d{vSNDdR8o$*SM{) zm9-?Z;No8|OZ?2yg8TC>(_{q}_VM2LSt;(?x*>&X-H@Vl{e6eBesz($esyu~xu)!H zReo%6+xfnVLeG#PqkI)R?i*54+obTQ9fhHfd~jL*&psSFI9}5{d}5eeE&64sK1$QT zO7N)Fk;78j@Gy7|)HnJM8=iZaNxO%Jed)dHWu&R$uMKPMU2U)k*d{z`=dkz)?w~@J z{75dm^6Bs^BaGyhMmuU_ZacxWfN}L zH=^5S%>?fCZgtemvX@$E8diPc^0MqCP4jeOiASBct?VC8O~V3@Ib8OVpQd46>Br0b Z8ZSOJg}23)-x=0)5`xv^dF4|R{|`j*aNYm_ diff --git a/lib/rp2350/liblwip.a b/lib/rp2350/liblwip.a index 4d0e9faf64f258e1cc1295025ed6c7bec9d55423..2689092852665e0dc97d056f016f738eb628fd76 100644 GIT binary patch delta 10819 zcmchd33yf2wa53q=j?OOId{lSZjzfo$V3uCLP8>82=ioQ)G%p4gg^r(i~#}y3Ks;$ z*II^JJZMo+QLwEQD>c>;r~}m2q2d5&t<_q5)vA4#YAf*mYu^66*iBSkaN<>q`9VD!xkZpV&iu zZFzLE@c-*2e%{IM^RW20%Fm7o``<3{zdJj1LVRV}Q6ZdvRGzy*IIm9r_e%V09NpY{ z@&8fc|8yf`CJVQ%T)s}Y|7zJ#EZqND;$Nlw$GYux!u@B;T|0#Pzm`G&gwcT)h5OaT zTlb<$eQ>L3rX^N%Z*TKiGkwGU%uV||&r-J0s zySkb@GGw*)R+Zg7I(>wokE+rr7Nw%3^_{ckHYrPQ+HGZ8xrGg`D8pf=xDaLUe>TFZ z3D%^IO0L;alU8%?FK5q9?>c>i^#{|r<+E z&E5<39PW?^24 z5x45YW$@0NLOu8QvOk1ibjO#!%DE7Lb`gfuU!D0YNU0x6%)$IxINC)L5>#jLmEo6k zew?Y{L1@zb1w8t=6*$ay8<0uZU5N0)y$LxWU^?8LW+Q_748KpGxNTt?-L6Yuu+Ha( z;3M6B&0;^RAi-j56NQ;5BS(?fNXv!0J4HIxNNiM>g)PfPT|yXRJxWzG zq}>y4UF zImK&Ks=$}#_ckk4CY!y-Aj(4TZKXO(zjsEdsqtDZI7pPB} z1=z-4$ZS?zORlj2t0XX63qfNQS`BQ(?Wsa`NT94SfG1UY>dI61r}p7K z@iIm^_-1G{bUERf7l`1mwe?VAxc4EflZ>5Y{kFEQGq!qBTaC|~hL(cw7}R#^RMhv} zfTLPF=*kF9Ve5>y-d5T1{An1EU{D(Kpsc(er{steS`c{z-bN$36IvL#1vSEd7#&@# zo2a$@TM(-`Ok3h)+y5b|m&KAG)Y<-A2ras1y6x`_-SPmf@p{{zf{-f$FXOwx_TPeN zE8SGur5bJjH_*arNJ2E({v23bt%Z5Ee+hKgXkotX9|0k*V=u7%f5xD!)A=;p{`Zjg zdMzxm{d3TxYqhY{_OC$W8}!gEv;E}=urc&H8o0^!(`ImklX42uG28#TcaNi{hE^f3 z&<^7sB$RZ*3%V+&AgvOH@5??oWm0byX(QlrN?vqck+j9T#8v6?9&fIT3(F6@P4F9) zj+RCEc{KoNCEKGo=q1ty0*}Ze=e@JvLQewgtrO=p>BlgnT7HbR%6dwQ3l#nq<NfZ1uQRh=Vbx6{VEbm9pMfz?; z4XoAm>)Yx@_AzG`)T^x>Z7NAeLM_C|WPglUk@+bHsE+n$IUQP&HVE-f$fw&pMA{PM zc38f8UXf%&;r>`AQ4WECcPyZa;_0W*&*b4cfuaC{>D=_NS7jlhEKhU}ErT+~@8 zI7z zP;@Ywu8COjJ1}k$=&{sLr^vV-Zn{Y*N9jXDy$7Csn}zHo z)9L)~MY#(lbOGw(h;SL|G1jsIW9(aw!-I^<(0S&PJ9^;rBDgilcP z0GWyDcoy;(C^{?J9L6IsrHW*t#Rx-N2+1utE_fOZ?!$rDi6VD4C26D$^u&*% zlh_w8qby1x7ot>G(JHz(iClc!>X6f6ozsP=8-ddQPe?*OlS;QYp;|c7g8dukvO*8f zwmKT`ZPR^nl5bnR&$mXbc;?4KZ)9q@mk*s#F`By?GatIGND@l-EGhf zVqHrjeuD_XL(m3PcitK&#<=RnsEA&JD%!hfFvu)GcWkR*7c7Hhh`e-cA)9E2qt8g( zbzy`aLVbi*|E4lp{F6~GMv0cdq(ldsXtewSLf%Pqys6E53^a1*D9i)x+%$xoSD-9K ziBQ8$b+mDAhq#4QM=^R$*L;repF(^Pr7%vjV;-HCHzB@;GGO7XZwNU*)E!qD-?rvx z6q8*Yrkq7nbB05cVl2ebq*^+sMaL!;XlaCm5$+!t5U37}j`j-(@4jU9O8zLh20H<^=OS&L zRxXER!Yt1npsMq%ZkYo!z0T*1EN|FZBef{Ql!F5SxF^C$_+>_=5e@|YuIQw^J5p3M z)R`h*D>Es0mbdN>C$+c>GO!b&6Df#nZcb-KjZw%PZ^=fLe>bno$~%F4`7Ph_qr zbIjCYh*{`pfwvpg-tnkMf54Tsrdua3 zHR~EZ+2~{jf^vcx%#f4Kj7D!*sTuVahfFIFl@rZqk(^={HF~#)OpJt_WJc>`9sFF( zBty@nU1*Iy7FLHag^AeaM8uvrn`{!7v^E=Uhgl0dUvP=Ar)M|oO>~#(GZXR(md!}8 zh3ebnNNx14^tOv)JAG|^C+|#9Wu_&XuxO_@MF2?z^5tc%(G2yml#SjM+pL(^xswXU zXe-CSP$ohZ;L8-9%E^ic;SKdYCCn4^@*~^<2w3Ib1 z!X>A5LKl_li>o>-xm+nL9|sYz*veIP#>!l!`dB?x*plVSE?15r}Fpr+N%lDosf%isvk!Eu>V{LSa#%BX|3xg4e(?q#Z!o z&ZNG#y}Eas@qOMWIjYiXUW%7CbG<_=?M|%&a#fx$JaeY*M$@91&C6SswO*dDzVMm) z@X|u{ebc-0wAsbWDp4EDdQhwUX#|Idb2r!<{nuI7t4-z&#((%W%X!ZqJ@V``Pe1ju zaO+DY>ZJ5uyw?qT7eAv?R6acFy_Z_t&fceKPQ-g`IcoCLofL2XIf#?f@%7?4C+w|W z?&f-bUG7G_|D>-w<4y&hEWcHza%8vGN6VBWp-m zdU-EluZUEtRdHNg=q7>Q^w3SeuQYKN>cduF0olc%WB(K`u3I$S-JaN~iKwL84;LFP zjfRWGvXs~h&rC#IFKz^Vcs;k3i23?mB3FlhuR0KF<8&Sy3=>GDtdZ!)(qZ)5IZ-b)vLGHhkVLFNn0lgtm8 zpE2omDEY;h`Am9vBz=Eo4YQs(m$`tsG|mSrnQNIFncrk?Wzr0$26i&@66lNxKFmoJp8ncmkEpsdLc1@iBAF|>R<`L$r%y*f8Vus8_ z0-c%NnSGfPnRJ&#iC)kA3G)Q=G%*eXdIL*_vzd#SH!!y|?_}Q3e2jUN`6}}r=EqEW zjY{!dE5R7E0E|;bB`XFq$1>}fbC~Oyo0yxKdzlBBzhu70JjbLLR@B}!=6pY`e<uL>u+W5=K80({yAb69urvp z9T5$`pI}^k&WbZkUohcNLPP=;L|iF`usnu{02ec7FlRHbB*K0R5&qkWxWnGV^8G~k zKd6cG|1(xR%Y2P_lKBVbN6b%&2z-uZJj>{SHWB(L%Q0pau>kLsSnkE_M~ox0IywMX zGQZ2boB0qC*UZB#zrgZIA{zV+5ziGLvHUp^Jv_q<(vvyl2(t?_4~$bq5h)O;k}G;M z`x6oPV&+UD>>7x;i&)0;8Y1GXXKrPFmw5{je*0NI!2D^L*Z8m>e zeLyk-rBc9d_zjT=T@RKkh)7U(1oh)cM*MoNZy=(b8(6*(@APzodswlLh=z}`{5lZ{ zyvy<_A`4<3VTBbtB1V`iHG#^%S_vQ`Asv!n5w}-1(^$_TAf!31*zz+hPDh}zP2B%D?PCtgVcVCfkZ|LA|w{uTz=f0(b`$lj5 z2o;NetAl%_ojW~BwYB~LyF;ZvwDjJi-th<3`g320co~RCHz+h1G^TCw9#6!>Ud*4( zn3j9JZ8tg5IWKf*t2ZXhJaXhuTU*a{Xln&(PwEsRtq`uhr(0I>tJ^&)@)SI)-?LrqkR?&XgPa_*0@pc z;nDs`$-1G5=XmOMAxc}*1K@|9q!}vxSy1L>SJ_3OJ!Kd_7)Vw7e&3@PbPJS!0F%BdFF>HLBs~^jA-P@Jelh6Wi37Y_&Ef z`+qT*{}gK0F(=kqTk8)twfj@3^wyO>_4ioDCNI^f*xrLZY`cBry>C?6-)^sH{p^sv z^SbtbV731uXP?<#(K60C@+C#x1ZTfiB(lqBExgo;4ked1#gv`#!=uiA zx4p@#W6npT*`#$*w)@BKU$S30%8ewqRd1f^-r4O-)#KK?sVQI5Tyv9Kz=Oz5K6Zzj Nbw0$ef9xL4{BN^Y|FHl7 delta 10409 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 diff --git a/lib/rp2350/libpico.a b/lib/rp2350/libpico.a index 81eff77115931004f320c521e785d5e948fef389..4c71d8a2505ec5cd06a079360ae260f3c5feb141 100644 GIT binary patch delta 1439 zcmY*ZT}V@57{`3LR!dDcEeA%NfIVbh|a~f4<#9Xl@MKBt}i8k2hQZAtn|}^Vkm%bA|*IP4Z;b(9p-CP@lW#u5!4$2wl&%rfl;vW+XGtJ zK@mVAE|Z04%LNhc2DRfnK|CarK$CWtj>Aomwny4Og@of(I@9+-+i;b-O#5}~cxQ^e z9wnx4){Sl@<_CKT;wC;NH}nH(RE1_H!q#p5KbD@1W+p=VgnqqBp|~XH^k4n_ z7iNHy{kfRFK$pNx)@ey?FlFrFq}vUl0*2rfjg}g$c=9P07@rD+a{4r+HM+ar%2c<&;GWe>Pk%Z3W|Wa)6|+&_Yas> zM8?JK>w9bp1gSZGM!aZ#mPY}3`9Y=#UrWp<4NQc0x~$5aU&AL9$*wo8f*z5DCy|Yih}%NLF4#cTbZAdYY`=bR-hlxZ_W)J;`4J zDs_$9SZ8>IJp%EuZui0q}&(iRd zWxFK>vbJoWG)#cZ5oFx9#TkT1>+CurSku{=zzZk=Bv>@r-)S_sOX1xsBFx$BuWl)x lsB7fji7~r=nB0OyU6JOj#*n)4ICIt$V#l>Y>tfseWxu-tU6k; zodXM2L5_{bm$!1DFPJLFW~XcRA>e@{n^R`G@ZeUNp$viHlyEQcyBC5^n5axmq!9qj z;PqiTAiujWwMHU`(UH`qW=?G_NE0{U!3SOCX_a5NPRkQk3Uy^WNO!ePhESDm+jTle zgGL#87j!+OcSA{re(oSeRhEPTrN{Nr3Pe1>dLuUC!3C`9b88iAEr9Mqp*Z(HwG3a6 z3E?6Vs4O`dYA*?&9h{@}8XEeAfdJ<;1`G=9`5_G131PjFVOei@D07k4TzI+3pcWDZ zm`KRt4r8UV0@uQZA#t4`RBu?Nak#b0WN5x)_*H-$kJg#aw}#p?q!|qw=V@n>F;jza zpmohp>uch>QKSX%VP!w%^xJR9FS$kV@OygINv_&rw<+K$7hR{;aoPvPsS}8J)sh>M z05(5LuiMEO9nq4!_YSpOSjuhLjD}`IcOIIkeXUUdskD zb|+`|uFUc{8+|>%vWZjIym(3TMN8FP3aevFc2-=m)mg>`Qk%7j)NbhNvCb$M@nUB> z?^#1(;wE2_s7Q~tA>dZ0Z)GX)saV=?CJL@}$ssAPl5>))(5_0LL!=1U5TcQ_ur}+( zyv!Fn5%FWzvqv-iPZ03|n`~tjsa5SEobRZ&K}Ws)JWa%l3%C1$y@RhHuu|s)azM|g zEB5l6h`2%O$@)NH*4QQcFbwo(`MCgCWsx@IdZ2NaV}>G>UW3cgJx1aC(@t9o$!lLGsv>+NN|Xe=E=f?f;pq}pMWL61d~?hD-!s%2Q%()KD&&bbnoz>)6~arVGnV$ W2@k&L2>X?+1mt+jS~MY7*!}_)_`>l3 diff --git a/libraries/lwIP_CYW43/src/utility/CYW43shim.cpp b/libraries/lwIP_CYW43/src/utility/CYW43shim.cpp index 46b9cf551..d80734abf 100644 --- a/libraries/lwIP_CYW43/src/utility/CYW43shim.cpp +++ b/libraries/lwIP_CYW43/src/utility/CYW43shim.cpp @@ -111,7 +111,6 @@ uint16_t CYW43::sendFrame(const uint8_t* data, uint16_t datalen) { if (0 == cyw43_send_ethernet(_self, _itf, datalen, data, false)) { return datalen; } - printf("c++\n"); fails++; return 0; } diff --git a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp index 0c51c085f..7b36657a3 100644 --- a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp +++ b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp @@ -63,7 +63,7 @@ bool __ethernetContextInitted = false; // Async context that pumps the ethernet controllers static async_when_pending_worker_t always_pending_update_timeout_worker; static async_at_time_worker_t ethernet_timeout_worker; -static async_context_t *_context = nullptr; +//static async_context_t *_context = nullptr; // Theoretically support multiple interfaces static std::map> _handlePacketList; @@ -76,7 +76,7 @@ void ethernet_arch_lwip_begin() { // } //#endif __startEthernetContext(); - async_context_acquire_lock_blocking(_context); +// async_context_acquire_lock_blocking(_context); } void ethernet_arch_lwip_end() { @@ -86,7 +86,7 @@ void ethernet_arch_lwip_end() { // return; // } //#endif - async_context_release_lock(_context); +// async_context_release_lock(_context); } int __addEthernetPacketHandler(std::function _packetHandler) { @@ -228,6 +228,7 @@ void __startEthernetContext() { if (__ethernetContextInitted) { return; } +#if 0 //#if defined(PICO_CYW43_SUPPORTED) // if (rp2040.isPicoW()) { // _context = cyw43_arch_async_context(); @@ -241,6 +242,7 @@ void __startEthernetContext() { always_pending_update_timeout_worker.work_pending = true; always_pending_update_timeout_worker.do_work = update_next_timeout; async_context_add_when_pending_worker(_context, &always_pending_update_timeout_worker); +#endif __ethernetContextInitted = true; } diff --git a/libraries/lwIP_Ethernet/src/LwipIntfDev.h b/libraries/lwIP_Ethernet/src/LwipIntfDev.h index 284cfb195..96dd636ac 100644 --- a/libraries/lwIP_Ethernet/src/LwipIntfDev.h +++ b/libraries/lwIP_Ethernet/src/LwipIntfDev.h @@ -464,10 +464,10 @@ void LwipIntfDev::end() { template void LwipIntfDev::_irq(void *param) { LwipIntfDev *d = static_cast(param); - ethernet_arch_lwip_begin(); + //ethernet_arch_lwip_begin(); d->handlePackets(); sys_check_timeouts(); - ethernet_arch_lwip_end(); + //ethernet_arch_lwip_end(); } template From f412d288c7dda28e13d0ac82b83cbd90d68e9500 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 14 Aug 2025 14:27:44 -0700 Subject: [PATCH 05/36] Update FreeRTOS submnodule --- .gitmodules | 3 +++ FreeRTOS-Kernel | 1 + 2 files changed, 4 insertions(+) create mode 160000 FreeRTOS-Kernel diff --git a/.gitmodules b/.gitmodules index 044503bc5..b1b342927 100644 --- a/.gitmodules +++ b/.gitmodules @@ -49,3 +49,6 @@ [submodule "libraries/SdFat"] path = libraries/SdFat url = https://github.com/greiman/SdFat.git +[submodule "FreeRTOS-Kernel"] + path = FreeRTOS-Kernel + url = https://github.com/earlephilhower/FreeRTOS-Kernel.git diff --git a/FreeRTOS-Kernel b/FreeRTOS-Kernel new file mode 160000 index 000000000..2e588af95 --- /dev/null +++ b/FreeRTOS-Kernel @@ -0,0 +1 @@ +Subproject commit 2e588af95bad29aef577373512883370c9408c1c From b94aa52e762f0ffb817f977f8d1995d8caaab875 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Fri, 15 Aug 2025 21:11:32 -0700 Subject: [PATCH 06/36] Wrap ethernet_output --- cores/rp2040/freertos/variantHooks.cpp | 7 ++++ cores/rp2040/lwip_wrap.cpp | 15 ++++++++ lib/core_wrap.txt | 2 ++ libraries/lwIP_Ethernet/src/LwipEthernet.cpp | 36 +++++++++++++++----- libraries/lwIP_Ethernet/src/LwipIntfDev.h | 4 ++- 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/cores/rp2040/freertos/variantHooks.cpp b/cores/rp2040/freertos/variantHooks.cpp index c69470608..691ec4cce 100644 --- a/cores/rp2040/freertos/variantHooks.cpp +++ b/cores/rp2040/freertos/variantHooks.cpp @@ -923,6 +923,13 @@ static void lwipThread(void *params) { __real_netif_remove(r->netif); break; } + case __ethernet_input: + { + __ethernet_input_req *r = (__ethernet_input_req *)w.req; + printf("__real_ethernet_input\n"); + *(r->ret) = __real_ethernet_input(r->p, r->netif); + break; + } default: { // Any new unimplemented calls = ERROR!!! diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index 3d1769f3d..62a05d857 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -814,4 +814,19 @@ extern "C" { __real_netif_remove(netif); } + extern err_t __real_ethernet_input(struct pbuf *p, struct netif *netif); + err_t __wrap_ethernet_input(struct pbuf *p, struct netif *netif) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { + err_t ret; + __ethernet_input_req req = { p, netif, &ret }; + __lwip(__ethernet_input, &req); + return ret; + } +#endif + LWIPMutex m; + return __real_ethernet_input(p, netif); + } + + }; // extern "C" diff --git a/lib/core_wrap.txt b/lib/core_wrap.txt index 4466aa4ec..516a2de82 100644 --- a/lib/core_wrap.txt +++ b/lib/core_wrap.txt @@ -69,6 +69,8 @@ -Wl,--wrap=netif_add -Wl,--wrap=netif_remove +-Wl,--wrap=ethernet_input + -Wl,--wrap=cyw43_cb_process_ethernet -Wl,--wrap=cyw43_cb_tcpip_set_link_up -Wl,--wrap=cyw43_cb_tcpip_set_link_down diff --git a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp index 7b36657a3..28776d23d 100644 --- a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp +++ b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp @@ -25,9 +25,12 @@ #if defined(PICO_CYW43_SUPPORTED) #include #endif + #if defined(__FREERTOS) #include -static async_context_freertos_t lwip_ethernet_async_context_threadsafe_background; +#include "FreeRTOS.h" +#include "task.h" +static async_context_freertos_t lwip_ethernet_async_context; static StackType_t lwip_ethernet_async_context_freertos_task_stack[CYW43_TASK_STACK_SIZE]; static async_context_t *lwip_ethernet_init_default_async_context(void) { @@ -35,20 +38,20 @@ static async_context_t *lwip_ethernet_init_default_async_context(void) { #if configSUPPORT_STATIC_ALLOCATION && !CYW43_NO_DEFAULT_TASK_STACK config.task_stack = lwip_ethernet_async_context_freertos_task_stack; #endif - if (async_context_freertos_init(&lwip_ethernet_async_context_threadsafe_background, &config)) { - return &lwip_ethernet_async_context_threadsafe_background.core; + if (async_context_freertos_init(&lwip_ethernet_async_context, &config)) { + return &lwip_ethernet_async_context.core; } return NULL; } #else #include -static async_context_threadsafe_background_t lwip_ethernet_async_context_threadsafe_background; +static async_context_threadsafe_background_t lwip_ethernet_async_context; static async_context_t *lwip_ethernet_init_default_async_context(void) { async_context_threadsafe_background_config_t config = async_context_threadsafe_background_default_config(); - if (async_context_threadsafe_background_init(&lwip_ethernet_async_context_threadsafe_background, &config)) { - return &lwip_ethernet_async_context_threadsafe_background.core; + if (async_context_threadsafe_background_init(&lwip_ethernet_async_context, &config)) { + return &lwip_ethernet_async_context.core; } return NULL; } @@ -63,7 +66,7 @@ bool __ethernetContextInitted = false; // Async context that pumps the ethernet controllers static async_when_pending_worker_t always_pending_update_timeout_worker; static async_at_time_worker_t ethernet_timeout_worker; -//static async_context_t *_context = nullptr; +static async_context_t *_context = nullptr; // Theoretically support multiple interfaces static std::map> _handlePacketList; @@ -75,7 +78,7 @@ void ethernet_arch_lwip_begin() { // return; // } //#endif - __startEthernetContext(); +// __startEthernetContext(); // async_context_acquire_lock_blocking(_context); } @@ -224,11 +227,26 @@ static void update_next_timeout(async_context_t *context, async_when_pending_wor async_context_add_at_time_worker_in_ms(context, ðernet_timeout_worker, _pollingPeriod); } +TaskHandle_t sctTask; + +void sct(void *param) { + (void) param; + while (true) { + vTaskDelay(100); + ethernet_arch_lwip_gpio_mask(); // Ensure non-polled devices won't interrupt us + for (auto handlePacket : _handlePacketList) { + handlePacket.second(); + } + sys_check_timeouts(); + ethernet_arch_lwip_gpio_unmask(); + } +} void __startEthernetContext() { if (__ethernetContextInitted) { return; } -#if 0 +// xTaskCreate(sct, "SCT", 256, nullptr, 1, &sctTask); +#if 1 //#if defined(PICO_CYW43_SUPPORTED) // if (rp2040.isPicoW()) { // _context = cyw43_arch_async_context(); diff --git a/libraries/lwIP_Ethernet/src/LwipIntfDev.h b/libraries/lwIP_Ethernet/src/LwipIntfDev.h index 96dd636ac..e995cd53b 100644 --- a/libraries/lwIP_Ethernet/src/LwipIntfDev.h +++ b/libraries/lwIP_Ethernet/src/LwipIntfDev.h @@ -606,7 +606,9 @@ err_t LwipIntfDev::handlePackets() { } _packetsReceived++; - +printf("recv pkt %d: ", tot_len); +for (int i=0; i < tot_len; i++) printf("%02x ", ((uint8_t*)pbuf->payload)[i]); +printf("\n"); err_t err = _netif.input(pbuf, &_netif); #if PHY_HAS_CAPTURE From 5fd15b904e920ac1faf165be8536d64f7a0ac4cd Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sat, 16 Aug 2025 11:53:30 -0700 Subject: [PATCH 07/36] Debug --- libraries/lwIP_Ethernet/src/LwipEthernet.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp index 28776d23d..8ce1b9590 100644 --- a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp +++ b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp @@ -206,6 +206,7 @@ static uint32_t _pollingPeriod = 20; // This will only be called under the protection of the async context mutex, so no re-entrancy checks needed static void ethernet_timeout_reached(__unused async_context_t *context, __unused async_at_time_worker_t *worker) { assert(worker == ðernet_timeout_worker); + printf("__ethernet_timeout_reached_calls %d\n",__ethernet_timeout_reached_calls); __ethernet_timeout_reached_calls++; ethernet_arch_lwip_gpio_mask(); // Ensure non-polled devices won't interrupt us for (auto handlePacket : _handlePacketList) { From ac8c05f158a9b70626773f01169e6d285fcdcf7f Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sat, 16 Aug 2025 13:33:39 -0700 Subject: [PATCH 08/36] HW semaphore` --- cores/rp2040/freertos/variantHooks.cpp | 4 +++- cores/rp2040/lwip_wrap.cpp | 1 + libraries/lwIP_Ethernet/src/LwipEthernet.cpp | 24 ++++++++++++++------ libraries/lwIP_Ethernet/src/LwipIntfDev.h | 16 ++++++++++++- 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/cores/rp2040/freertos/variantHooks.cpp b/cores/rp2040/freertos/variantHooks.cpp index 691ec4cce..b5b7c291e 100644 --- a/cores/rp2040/freertos/variantHooks.cpp +++ b/cores/rp2040/freertos/variantHooks.cpp @@ -253,7 +253,7 @@ void startFreeRTOS(void) { // LWIP runs on core 0 only __lwipQueue = xQueueCreate(16, sizeof(LWIPWork)); //__hwMutex = xSemaphoreCreateMutex(); - xTaskCreate(lwipThread, "LWIP", 1024, 0, configMAX_PRIORITIES / 2 - 1, &__lwipTask); + xTaskCreate(lwipThread, "LWIP", 1024, 0, configMAX_PRIORITIES - 1, &__lwipTask); vTaskCoreAffinitySet(__lwipTask, 1 << 0); // Initialise and run the freeRTOS scheduler. Execution should never return here. @@ -586,6 +586,7 @@ static void lwipThread(void *params) { while (true) { if (xQueueReceive(__lwipQueue, &w, portMAX_DELAY)) { + printf("+LWIPTHREAD %p\n", w.wakeup); switch (w.op) { case __lwip_init: { @@ -938,6 +939,7 @@ static void lwipThread(void *params) { } } // Work done, return value set, just tickle the calling task + printf("-LWIPTHREAD %p\n", w.wakeup); xTaskNotifyGiveIndexed(w.wakeup, TASK_NOTIFY_LWIP_WAKEUP); } } diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index 62a05d857..5aa5d6832 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -820,6 +820,7 @@ extern "C" { if (!__isLWIPThread()) { err_t ret; __ethernet_input_req req = { p, netif, &ret }; + printf("__ethernet_input_req\n"); __lwip(__ethernet_input, &req); return ret; } diff --git a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp index 8ce1b9590..5712a2a08 100644 --- a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp +++ b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp @@ -228,26 +228,36 @@ static void update_next_timeout(async_context_t *context, async_when_pending_wor async_context_add_at_time_worker_in_ms(context, ðernet_timeout_worker, _pollingPeriod); } -TaskHandle_t sctTask; -void sct(void *param) { +// We have a background pump which calls sys_check_timeouts on a periodic basis +// and polls all Ethernet interfaces +static TaskHandle_t _ethernetTask;; + +static void ethernetTask(void *param) { (void) param; while (true) { - vTaskDelay(100); - ethernet_arch_lwip_gpio_mask(); // Ensure non-polled devices won't interrupt us + uint32_t sleep_ms = sys_timeouts_sleeptime(); + if (sleep_ms > _pollingPeriod) { + sleep_ms = _pollingPeriod; + } + vTaskDelay(sleep_ms / portTICK_PERIOD_MS); + // Scan the installed Ethernet drivers for (auto handlePacket : _handlePacketList) { + // Note that each NIC needs to use its own mutex to ensure LWIP isn't doing something with it at the time we want to poll handlePacket.second(); } + // Do LWIP stuff as needed sys_check_timeouts(); - ethernet_arch_lwip_gpio_unmask(); } } + void __startEthernetContext() { if (__ethernetContextInitted) { return; } -// xTaskCreate(sct, "SCT", 256, nullptr, 1, &sctTask); -#if 1 + xTaskCreate(ethernetTask, "Ethernet", 256, nullptr, 1, &_ethernetTask); +// vTaskCoreAffinitySet(_ethernetTask, 1 << 0); +#if 0 //#if defined(PICO_CYW43_SUPPORTED) // if (rp2040.isPicoW()) { // _context = cyw43_arch_async_context(); diff --git a/libraries/lwIP_Ethernet/src/LwipIntfDev.h b/libraries/lwIP_Ethernet/src/LwipIntfDev.h index e995cd53b..175c0c01e 100644 --- a/libraries/lwIP_Ethernet/src/LwipIntfDev.h +++ b/libraries/lwIP_Ethernet/src/LwipIntfDev.h @@ -46,6 +46,9 @@ #include "LwipEthernet.h" #include "wl_definitions.h" +#include "FreeRTOS.h" +#include "semphr.h" + #ifndef DEFAULT_MTU #define DEFAULT_MTU 1500 #endif @@ -75,6 +78,7 @@ class LwipIntfDev: public LwipIntf, public RawDev { LwipIntfDev(int8_t cs = SS, SPIClass& spi = SPI, int8_t intr = -1) : RawDev(cs, spi, intr), _spiUnit(spi), _mtu(DEFAULT_MTU), _intrPin(intr), _started(false), _default(false) { memset(&_netif, 0, sizeof(_netif)); + _hwMutex = xSemaphoreCreateMutex(); } //The argument order for ESP is not the same as for Arduino. However, there is compatibility code under the hood @@ -181,6 +185,7 @@ class LwipIntfDev: public LwipIntf, public RawDev { public: // called on a regular basis or on interrupt err_t handlePackets(); + SemaphoreHandle_t _hwMutex; protected: // members SPIClass& _spiUnit; @@ -205,6 +210,7 @@ class LwipIntfDev: public LwipIntf, public RawDev { uint32_t _packetsReceived = 0; uint32_t _packetsSent = 0; + }; @@ -485,7 +491,9 @@ err_t LwipIntfDev::linkoutput_s(netif* netif, struct pbuf* pbuf) { LwipIntfDev* lid = (LwipIntfDev*)netif->state; printf("presend %d\n", pbuf->len); // ethernet_arch_lwip_begin(); + xSemaphoreTake(lid->_hwMutex, portMAX_DELAY); uint16_t len = lid->sendFrame((const uint8_t*)pbuf->payload, pbuf->len); + xSemaphoreGive(lid->_hwMutex); lid->_packetsSent++; #if PHY_HAS_CAPTURE if (phy_capture) { @@ -573,11 +581,14 @@ err_t LwipIntfDev::handlePackets() { { return ERR_OK; } - +printf("handlePackets1\n"); + xSemaphoreTake(_hwMutex, portMAX_DELAY); uint16_t tot_len = RawDev::readFrameSize(); if (!tot_len) { + xSemaphoreGive(_hwMutex); return ERR_OK; } +printf("handlePackets2\n"); // from doc: use PBUF_RAM for TX, PBUF_POOL from RX // however: @@ -588,15 +599,18 @@ err_t LwipIntfDev::handlePackets() { // TODO: tweak the wiznet driver to allow copying partial chunk // of received data and use PBUF_POOL. pbuf* pbuf = pbuf_alloc(PBUF_RAW, tot_len, PBUF_RAM); + printf("pballoc ret %p\n", pbuf); if (!pbuf || pbuf->len < tot_len) { if (pbuf) { pbuf_free(pbuf); } RawDev::discardFrame(tot_len); + xSemaphoreGive(_hwMutex); return ERR_BUF; } uint16_t len = RawDev::readFrameData((uint8_t*)pbuf->payload, tot_len); + xSemaphoreGive(_hwMutex); if (len != tot_len) { // tot_len is given by readFrameSize() // and is supposed to be honoured by readFrameData() From 452abcbec28a68778024d2d9e8d68a9df7d69972 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sat, 16 Aug 2025 15:24:06 -0700 Subject: [PATCH 09/36] Use callback from LWIP thread to process Ethernet Deadlocks/pauses seem to be unavoidable when running Ethernet packet receive outside of the LWIP thread. Add a callback queue message to the LWIP thread to allow for it to run whatever ethernet processing needed. These messages still get stuffed by another simple periodic task. --- cores/rp2040/freertos/variantHooks.cpp | 9 ++++++--- cores/rp2040/lwip_wrap.cpp | 12 ++++++++++++ libraries/lwIP_Ethernet/src/LwipEthernet.cpp | 13 +++++++++++++ libraries/lwIP_Ethernet/src/LwipIntfDev.h | 10 ++++------ 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/cores/rp2040/freertos/variantHooks.cpp b/cores/rp2040/freertos/variantHooks.cpp index b5b7c291e..126a4cca0 100644 --- a/cores/rp2040/freertos/variantHooks.cpp +++ b/cores/rp2040/freertos/variantHooks.cpp @@ -578,7 +578,6 @@ extern "C" bool __isLWIPThread() { return t.xHandle == __lwipTask; } - static void lwipThread(void *params) { (void) params; LWIPWork w; @@ -586,7 +585,6 @@ static void lwipThread(void *params) { while (true) { if (xQueueReceive(__lwipQueue, &w, portMAX_DELAY)) { - printf("+LWIPTHREAD %p\n", w.wakeup); switch (w.op) { case __lwip_init: { @@ -931,6 +929,12 @@ static void lwipThread(void *params) { *(r->ret) = __real_ethernet_input(r->p, r->netif); break; } + case __callback: + { + __callback_req *r = (__callback_req *)w.req; + r->cb(); + break; + } default: { // Any new unimplemented calls = ERROR!!! @@ -939,7 +943,6 @@ static void lwipThread(void *params) { } } // Work done, return value set, just tickle the calling task - printf("-LWIPTHREAD %p\n", w.wakeup); xTaskNotifyGiveIndexed(w.wakeup, TASK_NOTIFY_LWIP_WAKEUP); } } diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index 5aa5d6832..a38dd291a 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -829,5 +829,17 @@ extern "C" { return __real_ethernet_input(p, netif); } + void lwip_callback(void (*cb)()) { +#ifdef __FREERTOS + if (!__isLWIPThread()) { + __callback_req req = { cb }; + __lwip(__callback, &req); + return; + } +#endif + cb(); + return; + } + }; // extern "C" diff --git a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp index 5712a2a08..399bbc4e5 100644 --- a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp +++ b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp @@ -233,6 +233,16 @@ static void update_next_timeout(async_context_t *context, async_when_pending_wor // and polls all Ethernet interfaces static TaskHandle_t _ethernetTask;; +static void stage2() { + // Scan the installed Ethernet drivers + for (auto handlePacket : _handlePacketList) { + // Note that each NIC needs to use its own mutex to ensure LWIP isn't doing something with it at the time we want to poll + handlePacket.second(); + } + // Do LWIP stuff as needed + sys_check_timeouts(); +} +extern "C" void lwip_callback(void (*cb)()); static void ethernetTask(void *param) { (void) param; while (true) { @@ -241,6 +251,8 @@ static void ethernetTask(void *param) { sleep_ms = _pollingPeriod; } vTaskDelay(sleep_ms / portTICK_PERIOD_MS); + lwip_callback(stage2); +#if 0 // Scan the installed Ethernet drivers for (auto handlePacket : _handlePacketList) { // Note that each NIC needs to use its own mutex to ensure LWIP isn't doing something with it at the time we want to poll @@ -248,6 +260,7 @@ static void ethernetTask(void *param) { } // Do LWIP stuff as needed sys_check_timeouts(); +#endif } } diff --git a/libraries/lwIP_Ethernet/src/LwipIntfDev.h b/libraries/lwIP_Ethernet/src/LwipIntfDev.h index 175c0c01e..545a16791 100644 --- a/libraries/lwIP_Ethernet/src/LwipIntfDev.h +++ b/libraries/lwIP_Ethernet/src/LwipIntfDev.h @@ -581,14 +581,13 @@ err_t LwipIntfDev::handlePackets() { { return ERR_OK; } -printf("handlePackets1\n"); + xSemaphoreTake(_hwMutex, portMAX_DELAY); uint16_t tot_len = RawDev::readFrameSize(); if (!tot_len) { xSemaphoreGive(_hwMutex); return ERR_OK; } -printf("handlePackets2\n"); // from doc: use PBUF_RAM for TX, PBUF_POOL from RX // however: @@ -599,7 +598,6 @@ printf("handlePackets2\n"); // TODO: tweak the wiznet driver to allow copying partial chunk // of received data and use PBUF_POOL. pbuf* pbuf = pbuf_alloc(PBUF_RAW, tot_len, PBUF_RAM); - printf("pballoc ret %p\n", pbuf); if (!pbuf || pbuf->len < tot_len) { if (pbuf) { pbuf_free(pbuf); @@ -620,9 +618,9 @@ printf("handlePackets2\n"); } _packetsReceived++; -printf("recv pkt %d: ", tot_len); -for (int i=0; i < tot_len; i++) printf("%02x ", ((uint8_t*)pbuf->payload)[i]); -printf("\n"); +//printf("recv pkt %d: ", tot_len); +//for (int i=0; i < tot_len; i++) printf("%02x ", ((uint8_t*)pbuf->payload)[i]); +//printf("\n"); err_t err = _netif.input(pbuf, &_netif); #if PHY_HAS_CAPTURE From 623c2df30afd9010c9c8f04e6a5231e82203f053 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sat, 16 Aug 2025 15:46:18 -0700 Subject: [PATCH 10/36] lwip_callback can take a cbData --- cores/rp2040/freertos/variantHooks.cpp | 2 +- cores/rp2040/lwip_wrap.cpp | 6 +++--- include/lwipopts.h | 2 +- libraries/lwIP_Ethernet/src/LwipEthernet.cpp | 22 +++++++++++--------- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/cores/rp2040/freertos/variantHooks.cpp b/cores/rp2040/freertos/variantHooks.cpp index 126a4cca0..b7570b917 100644 --- a/cores/rp2040/freertos/variantHooks.cpp +++ b/cores/rp2040/freertos/variantHooks.cpp @@ -932,7 +932,7 @@ static void lwipThread(void *params) { case __callback: { __callback_req *r = (__callback_req *)w.req; - r->cb(); + r->cb(r->cbData); break; } default: diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index a38dd291a..2527dc324 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -829,15 +829,15 @@ extern "C" { return __real_ethernet_input(p, netif); } - void lwip_callback(void (*cb)()) { + void lwip_callback(void (*cb)(void *), void *cbData) { #ifdef __FREERTOS if (!__isLWIPThread()) { - __callback_req req = { cb }; + __callback_req req = { cb, cbData }; __lwip(__callback, &req); return; } #endif - cb(); + cb(cbData); return; } diff --git a/include/lwipopts.h b/include/lwipopts.h index 294f6da0f..d388dc597 100644 --- a/include/lwipopts.h +++ b/include/lwipopts.h @@ -83,7 +83,7 @@ extern void __setSystemTime(unsigned long long sec, unsigned long us); #define SNTP_SERVER_DNS 1 #ifndef LWIP_DEBUG -#define LWIP_DEBUG 1 +#define LWIP_DEBUG 0 #endif #define ETHARP_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) #define NETIF_DEBUG (LWIP_DEBUG ? LWIP_DBG_ON : LWIP_DBG_OFF) diff --git a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp index 399bbc4e5..37933c712 100644 --- a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp +++ b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp @@ -233,16 +233,18 @@ static void update_next_timeout(async_context_t *context, async_when_pending_wor // and polls all Ethernet interfaces static TaskHandle_t _ethernetTask;; -static void stage2() { - // Scan the installed Ethernet drivers - for (auto handlePacket : _handlePacketList) { - // Note that each NIC needs to use its own mutex to ensure LWIP isn't doing something with it at the time we want to poll - handlePacket.second(); - } - // Do LWIP stuff as needed - sys_check_timeouts(); +static void stage2(void *cbData) { + (void) cbData; + // Scan the installed Ethernet drivers + for (auto handlePacket : _handlePacketList) { + // Note that each NIC needs to use its own mutex to ensure LWIP isn't doing something with it at the time we want to poll + handlePacket.second(); + } + // Do LWIP stuff as needed + sys_check_timeouts(); } -extern "C" void lwip_callback(void (*cb)()); + +extern "C" void lwip_callback(void (*cb)(void *), void *cbData); static void ethernetTask(void *param) { (void) param; while (true) { @@ -251,7 +253,7 @@ static void ethernetTask(void *param) { sleep_ms = _pollingPeriod; } vTaskDelay(sleep_ms / portTICK_PERIOD_MS); - lwip_callback(stage2); + lwip_callback(stage2, nullptr); #if 0 // Scan the installed Ethernet drivers for (auto handlePacket : _handlePacketList) { From 0b1454712d7207e73aba6bc0340d6d8fada7640a Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sat, 16 Aug 2025 18:21:41 -0700 Subject: [PATCH 11/36] Add IRQ support IRQs will send a work queue callback instad of actually doing anything. Disable all IRQs when the work noted, and then reset it when done. --- cores/rp2040/freertos/variantHooks.cpp | 39 +++++++++++++------- cores/rp2040/lwip_wrap.cpp | 15 +++++--- libraries/lwIP_Ethernet/src/LwipEthernet.cpp | 6 +-- libraries/lwIP_Ethernet/src/LwipIntfDev.h | 21 +++++++++-- 4 files changed, 54 insertions(+), 27 deletions(-) diff --git a/cores/rp2040/freertos/variantHooks.cpp b/cores/rp2040/freertos/variantHooks.cpp index b7570b917..cfa9e0b82 100644 --- a/cores/rp2040/freertos/variantHooks.cpp +++ b/cores/rp2040/freertos/variantHooks.cpp @@ -556,20 +556,28 @@ void __USBStart() { } - - - -extern "C" void __lwip(__lwip_op op, void *req) { +extern "C" void __lwip(__lwip_op op, void *req, bool fromISR) { LWIPWork w; - TaskStatus_t t; - vTaskGetInfo(nullptr, &t, pdFALSE, eInvalid); // TODO - can we speed this up??? - w.op = op; - w.req = req; - w.wakeup = t.xHandle; - if (!xQueueSend(__lwipQueue, &w, portMAX_DELAY)) { - panic("LWIP task send failed"); + if (fromISR) { + w.op = op; + w.req = req; + w.wakeup = 0; // Don't try and wake up a task when done, we're not in one! + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + if (!xQueueSendFromISR(__lwipQueue, &w, &xHigherPriorityTaskWoken)) { + panic("LWIP task send failed"); + } + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + } else { + TaskStatus_t t; + vTaskGetInfo(nullptr, &t, pdFALSE, eInvalid); // TODO - can we speed this up??? + w.op = op; + w.req = req; + w.wakeup = t.xHandle; + if (!xQueueSend(__lwipQueue, &w, portMAX_DELAY)) { + panic("LWIP task send failed"); + } + ulTaskNotifyTakeIndexed(TASK_NOTIFY_LWIP_WAKEUP, pdTRUE, portMAX_DELAY); } - ulTaskNotifyTakeIndexed(TASK_NOTIFY_LWIP_WAKEUP, pdTRUE, portMAX_DELAY); } extern "C" bool __isLWIPThread() { @@ -585,7 +593,8 @@ static void lwipThread(void *params) { while (true) { if (xQueueReceive(__lwipQueue, &w, portMAX_DELAY)) { - switch (w.op) { + switch (w.op) + { case __lwip_init: { __real_lwip_init(); @@ -943,7 +952,9 @@ static void lwipThread(void *params) { } } // Work done, return value set, just tickle the calling task - xTaskNotifyGiveIndexed(w.wakeup, TASK_NOTIFY_LWIP_WAKEUP); + if (w.wakeup) { + xTaskNotifyGiveIndexed(w.wakeup, TASK_NOTIFY_LWIP_WAKEUP); + } } } } diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index 2527dc324..d6c17ef6d 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -37,7 +37,7 @@ recursive_mutex_t __lwipMutex; extern "C" { - extern void __lwip(__lwip_op op, void *req) __attribute((weak)); + extern void __lwip(__lwip_op op, void *req, bool fromISR = false); extern bool __isLWIPThread(); static XoshiroCpp::Xoshiro256PlusPlus *_lwip_rng = nullptr; @@ -820,7 +820,6 @@ extern "C" { if (!__isLWIPThread()) { err_t ret; __ethernet_input_req req = { p, netif, &ret }; - printf("__ethernet_input_req\n"); __lwip(__ethernet_input, &req); return ret; } @@ -829,11 +828,16 @@ extern "C" { return __real_ethernet_input(p, netif); } - void lwip_callback(void (*cb)(void *), void *cbData) { + void lwip_callback(void (*cb)(void *), void *cbData, bool fromISR) { #ifdef __FREERTOS - if (!__isLWIPThread()) { + if (fromISR) { + // In ISR we can't check what the current thread is + __callback_req req = { cb, cbData }; + __lwip(__callback, &req, fromISR); + return; + } else if (!__isLWIPThread()) { __callback_req req = { cb, cbData }; - __lwip(__callback, &req); + __lwip(__callback, &req, fromISR); return; } #endif @@ -841,5 +845,4 @@ extern "C" { return; } - }; // extern "C" diff --git a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp index 37933c712..30bf476b6 100644 --- a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp +++ b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp @@ -238,13 +238,13 @@ static void stage2(void *cbData) { // Scan the installed Ethernet drivers for (auto handlePacket : _handlePacketList) { // Note that each NIC needs to use its own mutex to ensure LWIP isn't doing something with it at the time we want to poll - handlePacket.second(); +// handlePacket.second(); } // Do LWIP stuff as needed sys_check_timeouts(); } -extern "C" void lwip_callback(void (*cb)(void *), void *cbData); +extern "C" void lwip_callback(void (*cb)(void *), void *cbData, bool fromISR); static void ethernetTask(void *param) { (void) param; while (true) { @@ -253,7 +253,7 @@ static void ethernetTask(void *param) { sleep_ms = _pollingPeriod; } vTaskDelay(sleep_ms / portTICK_PERIOD_MS); - lwip_callback(stage2, nullptr); + lwip_callback(stage2, nullptr, false); #if 0 // Scan the installed Ethernet drivers for (auto handlePacket : _handlePacketList) { diff --git a/libraries/lwIP_Ethernet/src/LwipIntfDev.h b/libraries/lwIP_Ethernet/src/LwipIntfDev.h index 545a16791..0558c7511 100644 --- a/libraries/lwIP_Ethernet/src/LwipIntfDev.h +++ b/libraries/lwIP_Ethernet/src/LwipIntfDev.h @@ -72,6 +72,9 @@ enum EthernetLinkStatus { LinkOFF }; +extern "C" void lwip_callback(void (*cb)(void *), void *cbData, bool fromISR); + + template class LwipIntfDev: public LwipIntf, public RawDev { public: @@ -211,6 +214,7 @@ class LwipIntfDev: public LwipIntf, public RawDev { uint32_t _packetsReceived = 0; uint32_t _packetsSent = 0; + static void _lwipCallback(void *param); }; @@ -468,12 +472,23 @@ void LwipIntfDev::end() { } template -void LwipIntfDev::_irq(void *param) { +void LwipIntfDev::_lwipCallback(void *param) { LwipIntfDev *d = static_cast(param); - //ethernet_arch_lwip_begin(); d->handlePackets(); sys_check_timeouts(); + ethernet_arch_lwip_gpio_unmask(); +} + +template +void LwipIntfDev::_irq(void *param) { + LwipIntfDev *d = static_cast(param); + ethernet_arch_lwip_gpio_mask(); // Disable other IRQs until we're done processing this one + lwip_callback(_lwipCallback, param, true); + //ethernet_arch_lwip_begin(); +// d->handlePackets(); +// sys_check_timeouts(); //ethernet_arch_lwip_end(); + } template @@ -489,7 +504,6 @@ EthernetLinkStatus LwipIntfDev::linkStatus() { template err_t LwipIntfDev::linkoutput_s(netif* netif, struct pbuf* pbuf) { LwipIntfDev* lid = (LwipIntfDev*)netif->state; - printf("presend %d\n", pbuf->len); // ethernet_arch_lwip_begin(); xSemaphoreTake(lid->_hwMutex, portMAX_DELAY); uint16_t len = lid->sendFrame((const uint8_t*)pbuf->payload, pbuf->len); @@ -501,7 +515,6 @@ err_t LwipIntfDev::linkoutput_s(netif* netif, struct pbuf* pbuf) { /*success*/ len == pbuf->len); } #endif - printf("sent len %d\n", len); // ethernet_arch_lwip_end(); return len == pbuf->len ? ERR_OK : ERR_MEM; } From 946f973f8d375f09a947031937df73eae6661614 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 17 Aug 2025 17:47:41 -0700 Subject: [PATCH 12/36] Fix polling and IRQ memory corruption The IRQ callback routine ended up passing in a stack variable address. For main app code this is legal because the app blocks until the LWIP call returns. But for IRQs, it returns immediately (can't block in IRQ) and the stack pointer we passed in will be corrupt. Use a dumb static (heap) variable for now. W5100 is now running with multiple AdvancedWebServer clients in parallel with a WiFiClient MOTD process on core 1, in parallel. Rewriting the CYW43 driver to work with this TBD. --- cores/rp2040/freertos/FreeRTOSConfig.h | 6 ++++++ cores/rp2040/lwip_wrap.cpp | 14 +++++++++++++- libraries/lwIP_Ethernet/src/LwipEthernet.cpp | 4 +++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/cores/rp2040/freertos/FreeRTOSConfig.h b/cores/rp2040/freertos/FreeRTOSConfig.h index a5dc3b3f6..406a386f6 100644 --- a/cores/rp2040/freertos/FreeRTOSConfig.h +++ b/cores/rp2040/freertos/FreeRTOSConfig.h @@ -96,8 +96,14 @@ #define configGENERATE_RUN_TIME_STATS 1 #endif #ifdef configGENERATE_RUN_TIME_STATS +#ifdef __cplusplus +extern "C" { +#endif extern void vMainConfigureTimerForRunTimeStats(void); extern unsigned long ulMainGetRunTimeCounterValue(void); +#ifdef __cplusplus +}; +#endif #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() //vMainConfigureTimerForRunTimeStats() #define portGET_RUN_TIME_COUNTER_VALUE() ulMainGetRunTimeCounterValue() #endif diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index d6c17ef6d..9a17c1d33 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -832,7 +832,19 @@ extern "C" { #ifdef __FREERTOS if (fromISR) { // In ISR we can't check what the current thread is - __callback_req req = { cb, cbData }; + static __callback_req req = { cb, cbData }; // TODO HACK HERE + // We pass in the address of an unknown sized request to the LWIP work queue + // For normal mode that address is on the app stack, which will be frozen until + // the callback is performed. So no problem, that stack address will remain valid. + // Here, we're in an ISR and won't block, just put a pointer on the queue and + // return from the interrupt. The stack address, there, is no longer safe and you + // will see memory corruption when the actual app thread uses its stack. + // We can't allocate memory in an IRQ in FreeRTOS, so for now we'll just have + // a single heap-based (static) request which will live forever. As long as + // only a single lwip_callback from IRQ is present we're OK. Should you have 2 + // IRQ driver network cards, this will fail. + // A more satisfying method might have the NIC driver pass in its own class local + // preallocated storage space which we can use. __lwip(__callback, &req, fromISR); return; } else if (!__isLWIPThread()) { diff --git a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp index 30bf476b6..f9e3e201f 100644 --- a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp +++ b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp @@ -235,11 +235,13 @@ static TaskHandle_t _ethernetTask;; static void stage2(void *cbData) { (void) cbData; + ethernet_arch_lwip_gpio_mask(); // Scan the installed Ethernet drivers for (auto handlePacket : _handlePacketList) { // Note that each NIC needs to use its own mutex to ensure LWIP isn't doing something with it at the time we want to poll -// handlePacket.second(); + handlePacket.second(); } + ethernet_arch_lwip_gpio_unmask(); // Do LWIP stuff as needed sys_check_timeouts(); } From ef0ce09a53c073228c11c83ee95e991bc532af46 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 17 Aug 2025 18:07:50 -0700 Subject: [PATCH 13/36] Use driver local storage for IRQ request area Trying not to end up on thedailywtf.com --- cores/rp2040/lwip_wrap.cpp | 27 ++++++-------------- libraries/lwIP_Ethernet/src/LwipEthernet.cpp | 4 +-- libraries/lwIP_Ethernet/src/LwipIntfDev.h | 5 ++-- 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index 9a17c1d33..cf2240ba4 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -828,28 +828,17 @@ extern "C" { return __real_ethernet_input(p, netif); } - void lwip_callback(void (*cb)(void *), void *cbData, bool fromISR) { -#ifdef __FREERTOS - if (fromISR) { - // In ISR we can't check what the current thread is - static __callback_req req = { cb, cbData }; // TODO HACK HERE - // We pass in the address of an unknown sized request to the LWIP work queue - // For normal mode that address is on the app stack, which will be frozen until - // the callback is performed. So no problem, that stack address will remain valid. - // Here, we're in an ISR and won't block, just put a pointer on the queue and - // return from the interrupt. The stack address, there, is no longer safe and you - // will see memory corruption when the actual app thread uses its stack. - // We can't allocate memory in an IRQ in FreeRTOS, so for now we'll just have - // a single heap-based (static) request which will live forever. As long as - // only a single lwip_callback from IRQ is present we're OK. Should you have 2 - // IRQ driver network cards, this will fail. - // A more satisfying method might have the NIC driver pass in its own class local - // preallocated storage space which we can use. - __lwip(__callback, &req, fromISR); + void lwip_callback(void (*cb)(void *), void *cbData, void *buffer) { +#ifdef __FREERTOS + if (buffer) { + __callback_req *req = (__callback_req *)buffer; + req->cb = cb; + req->cbData = cbData; + __lwip(__callback, req, true); return; } else if (!__isLWIPThread()) { __callback_req req = { cb, cbData }; - __lwip(__callback, &req, fromISR); + __lwip(__callback, &req, false); return; } #endif diff --git a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp index f9e3e201f..4b1a0ec8c 100644 --- a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp +++ b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp @@ -246,7 +246,7 @@ static void stage2(void *cbData) { sys_check_timeouts(); } -extern "C" void lwip_callback(void (*cb)(void *), void *cbData, bool fromISR); +#include static void ethernetTask(void *param) { (void) param; while (true) { @@ -255,7 +255,7 @@ static void ethernetTask(void *param) { sleep_ms = _pollingPeriod; } vTaskDelay(sleep_ms / portTICK_PERIOD_MS); - lwip_callback(stage2, nullptr, false); + lwip_callback(stage2, nullptr); #if 0 // Scan the installed Ethernet drivers for (auto handlePacket : _handlePacketList) { diff --git a/libraries/lwIP_Ethernet/src/LwipIntfDev.h b/libraries/lwIP_Ethernet/src/LwipIntfDev.h index 0558c7511..d6014da90 100644 --- a/libraries/lwIP_Ethernet/src/LwipIntfDev.h +++ b/libraries/lwIP_Ethernet/src/LwipIntfDev.h @@ -72,7 +72,7 @@ enum EthernetLinkStatus { LinkOFF }; -extern "C" void lwip_callback(void (*cb)(void *), void *cbData, bool fromISR); +#include template @@ -189,6 +189,7 @@ class LwipIntfDev: public LwipIntf, public RawDev { // called on a regular basis or on interrupt err_t handlePackets(); SemaphoreHandle_t _hwMutex; + uint8_t _irqBuffer[LWIP_CALLBACK_BUFFER_SIZE]; protected: // members SPIClass& _spiUnit; @@ -483,7 +484,7 @@ template void LwipIntfDev::_irq(void *param) { LwipIntfDev *d = static_cast(param); ethernet_arch_lwip_gpio_mask(); // Disable other IRQs until we're done processing this one - lwip_callback(_lwipCallback, param, true); + lwip_callback(_lwipCallback, param, (void *)d->_irqBuffer); //ethernet_arch_lwip_begin(); // d->handlePackets(); // sys_check_timeouts(); From 9e92724abac6bce6690f4e91ac8dfac41e3de666 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 17 Aug 2025 18:56:01 -0700 Subject: [PATCH 14/36] Fix race condition in WiFiServer It is possible under heavy load with multithreading that a connection gets a tcp_abort just before tcp_accept will be called. When we abort, we clear the this pointer, and so when we try and recover our object we crash. Check for aborted connections (and ignore) on WiFiServer, like we do in WiFiClient --- libraries/WiFi/src/WiFiServer.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libraries/WiFi/src/WiFiServer.cpp b/libraries/WiFi/src/WiFiServer.cpp index 8ed7c1fe6..3fb3d3fa5 100644 --- a/libraries/WiFi/src/WiFiServer.cpp +++ b/libraries/WiFi/src/WiFiServer.cpp @@ -77,8 +77,8 @@ void WiFiServer::begin(uint16_t port, uint8_t backlog) { } _listen_pcb = listen_pcb; _port = _listen_pcb->local_port; - tcp_accept(listen_pcb, &WiFiServer::_s_accept); tcp_arg(listen_pcb, (void*) this); + tcp_accept(listen_pcb, &WiFiServer::_s_accept); } void WiFiServer::setNoDelay(bool nodelay) { @@ -215,9 +215,15 @@ void WiFiServer::_discard(ClientContext* client) { } err_t WiFiServer::_s_accept(void *arg, tcp_pcb* newpcb, err_t err) { - return reinterpret_cast(arg)->_accept(newpcb, err); + if (arg) { + return reinterpret_cast(arg)->_accept(newpcb, err); + } else { + return ERR_OK; + } } void WiFiServer::_s_discard(void* server, ClientContext* ctx) { - reinterpret_cast(server)->_discard(ctx); + if (server) { + reinterpret_cast(server)->_discard(ctx); + } } From b0e272e42d8f6ee7eaab1d93be38be5b50d066c7 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 18 Aug 2025 10:11:32 -0700 Subject: [PATCH 15/36] LWIP task calls lwip_init and sys_check_timeouts The LWIP processor thread should initialize LWIP since it's the only person actually calling it directly. LWIP thread can also handle the sys_check_timeout calls for all drivers, no need for Ethernet loop to worry about that. --- cores/rp2040/freertos/variantHooks.cpp | 16 +++++++++++++++- libraries/lwIP_Ethernet/src/LwipEthernet.cpp | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cores/rp2040/freertos/variantHooks.cpp b/cores/rp2040/freertos/variantHooks.cpp index cfa9e0b82..d02d00209 100644 --- a/cores/rp2040/freertos/variantHooks.cpp +++ b/cores/rp2040/freertos/variantHooks.cpp @@ -590,9 +590,14 @@ static void lwipThread(void *params) { (void) params; LWIPWork w; assert(__isLWIPThread()); + unsigned int scd = 100 / portTICK_PERIOD_MS; + + lwip_init(); // Will call our wrapper and set up the RNG while (true) { - if (xQueueReceive(__lwipQueue, &w, portMAX_DELAY)) { + auto ret = xQueueReceive(__lwipQueue, &w, scd); + if (ret) + { switch (w.op) { case __lwip_init: @@ -955,6 +960,15 @@ static void lwipThread(void *params) { if (w.wakeup) { xTaskNotifyGiveIndexed(w.wakeup, TASK_NOTIFY_LWIP_WAKEUP); } + } else + { + // No work received, do periodic processing + __real_sys_check_timeouts(); + // When should we wake up next to redo timeouts? + scd = sys_timeouts_sleeptime(); + if (scd == SYS_TIMEOUTS_SLEEPTIME_INFINITE) { + scd = portMAX_DELAY / portTICK_PERIOD_MS; + } } } } diff --git a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp index 4b1a0ec8c..995ad93ba 100644 --- a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp +++ b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp @@ -211,13 +211,13 @@ static void ethernet_timeout_reached(__unused async_context_t *context, __unused ethernet_arch_lwip_gpio_mask(); // Ensure non-polled devices won't interrupt us for (auto handlePacket : _handlePacketList) { handlePacket.second(); + sys_check_timeouts(); } //#if defined(PICO_CYW43_SUPPORTED) // if (!rp2040.isPicoW()) { // sys_check_timeouts(); // } //#else - sys_check_timeouts(); //#endif ethernet_arch_lwip_gpio_unmask(); } From 6cdf3f334cc1adff6764f58bf74d6d17ea323ae3 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 18 Aug 2025 10:19:05 -0700 Subject: [PATCH 16/36] Re-add FreeRTOS examples, update spellcheck --- .github/workflows/pull-request.yml | 4 +- boards.txt | 4 + .../Multicore-FreeRTOS/Multicore-FreeRTOS.ino | 87 +++++ .../rp2040/examples/PSRAMTest/PSRAMTest.ino | 64 ++++ .../StaticMulticore-FreeRTOS.ino | 94 ++++++ .../Stress-FreeRTOS/Stress-FreeRTOS.ino | 319 ++++++++++++++++++ 6 files changed, 570 insertions(+), 2 deletions(-) create mode 100644 libraries/rp2040/examples/Multicore-FreeRTOS/Multicore-FreeRTOS.ino create mode 100644 libraries/rp2040/examples/PSRAMTest/PSRAMTest.ino create mode 100644 libraries/rp2040/examples/StaticMulticore-FreeRTOS/StaticMulticore-FreeRTOS.ino create mode 100644 libraries/rp2040/examples/Stress-FreeRTOS/Stress-FreeRTOS.ino diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index c367c74af..64cc425ca 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -20,8 +20,8 @@ jobs: - name: Run codespell uses: codespell-project/actions-codespell@v2 with: - skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server,./ota/uzlib,./libraries/http-parser/lib,./libraries/WebServer/examples/HelloServerBearSSL/HelloServerBearSSL.ino,./libraries/HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino,./.git,./libraries/FatFS/lib/fatfs,./libraries/FatFS/src/diskio.h,./libraries/FatFS/src/ff.cpp,./libraries/FatFS/src/ffconf.h,./libraries/FatFS/src/ffsystem.cpp,./libraries/FatFS/src/ff.h,./libraries/lwIP_WINC1500/src/driver,./libraries/lwIP_WINC1500/src/common,./libraries/lwIP_WINC1500/src/bus_wrapper,./libraries/lwIP_WINC1500/src/spi_flash,./libraries/WiFi/examples/BearSSL_Validation/certs.h - ignore_words_list: ser,dout,shiftIn,acount,froms + skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server,./ota/uzlib,./libraries/http-parser/lib,./libraries/WebServer/examples/HelloServerBearSSL/HelloServerBearSSL.ino,./libraries/HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino,./.git,./libraries/FatFS/lib/fatfs,./libraries/FatFS/src/diskio.h,./libraries/FatFS/src/ff.cpp,./libraries/FatFS/src/ffconf.h,./libraries/FatFS/src/ffsystem.cpp,./libraries/FatFS/src/ff.h,./libraries/lwIP_WINC1500/src/driver,./libraries/lwIP_WINC1500/src/common,./libraries/lwIP_WINC1500/src/bus_wrapper,./libraries/lwIP_WINC1500/src/spi_flash,./libraries/WiFi/examples/BearSSL_Validation/certs.h + ignore_words_list: ser,dout,shiftIn,acount,froms,ThirdParty - name: Check boards.txt was not edited after makeboards.py run: | ./tools/makeboards.py diff --git a/boards.txt b/boards.txt index cf0a8a67c..f84bf0e61 100644 --- a/boards.txt +++ b/boards.txt @@ -26250,6 +26250,10 @@ pimoroni_explorer.menu.opt.Debug=Debug (-Og) pimoroni_explorer.menu.opt.Debug.build.flags.optimize=-Og pimoroni_explorer.menu.opt.Disabled=Disabled (-O0) pimoroni_explorer.menu.opt.Disabled.build.flags.optimize=-O0 +pimoroni_explorer.menu.os.none=None +pimoroni_explorer.menu.os.none.build.os= +pimoroni_explorer.menu.os.freertos=FreeRTOS SMP +pimoroni_explorer.menu.os.freertos.build.os=-D__FREERTOS pimoroni_explorer.menu.profile.Disabled=Disabled pimoroni_explorer.menu.profile.Disabled.build.flags.profile= pimoroni_explorer.menu.profile.Enabled=Enabled diff --git a/libraries/rp2040/examples/Multicore-FreeRTOS/Multicore-FreeRTOS.ino b/libraries/rp2040/examples/Multicore-FreeRTOS/Multicore-FreeRTOS.ino new file mode 100644 index 000000000..c4cd6329c --- /dev/null +++ b/libraries/rp2040/examples/Multicore-FreeRTOS/Multicore-FreeRTOS.ino @@ -0,0 +1,87 @@ +// Demonstrates a simple use of the setup1()/loop1() functions +// for a multiprocessor run. + +// Will output something like, where C0 is running on core 0 and +// C1 is on core 1, in parallel. + +// 11:23:07.507 -> C0: Blue leader standing by... +// 11:23:07.507 -> C1: Red leader standing by... +// 11:23:07.507 -> C1: Stay on target... +// 11:23:08.008 -> C1: Stay on target... +// 11:23:08.505 -> C0: Blue leader standing by... +// 11:23:08.505 -> C1: Stay on target... +// 11:23:09.007 -> C1: Stay on target... +// 11:23:09.511 -> C0: Blue leader standing by... +// 11:23:09.511 -> C1: Stay on target... +// 11:23:10.015 -> C1: Stay on target... + +// Released to the public domain +#include +#include +#include +#include + +std::map eTaskStateName { {eReady, "Ready"}, { eRunning, "Running" }, {eBlocked, "Blocked"}, {eSuspended, "Suspended"}, {eDeleted, "Deleted"} }; +void ps() { + int tasks = uxTaskGetNumberOfTasks(); + TaskStatus_t *pxTaskStatusArray = new TaskStatus_t[tasks]; + unsigned long runtime; + tasks = uxTaskGetSystemState( pxTaskStatusArray, tasks, &runtime ); + Serial.printf("# Tasks: %d\n", tasks); + Serial.println("ID, NAME, STATE, PRIO, CYCLES"); + for (int i=0; i < tasks; i++) { + Serial.printf("%d: %-16s %-10s %d %lu\n", i, pxTaskStatusArray[i].pcTaskName, eTaskStateName[pxTaskStatusArray[i].eCurrentState], (int)pxTaskStatusArray[i].uxCurrentPriority, pxTaskStatusArray[i].ulRunTimeCounter); + } + delete[] pxTaskStatusArray; +} + + +void blink(void *param) { + (void) param; + delay(500); + pinMode(LED_BUILTIN, OUTPUT); + while (true) { + digitalWrite(LED_BUILTIN, LOW); + delay(750); + digitalWrite(LED_BUILTIN, HIGH); + delay(250); + } +} + + +void setup() { + TaskHandle_t blinkTask; + Serial.begin(115200); + xTaskCreate(blink, "BLINK", 256, nullptr, 1, &blinkTask); +#if defined(PICO_CYW43_SUPPORTED) + // The PicoW WiFi chip controls the LED, and only core 0 can make calls to it safely + vTaskCoreAffinitySet(blinkTask, 1 << 0); +#endif + delay(5000); +} + +volatile int val = 0; +void loop() { + Serial.printf("C0: Blue leader standing by...\n"); + ps(); + Serial.printf("val: %d\n", val); + delay(1000); +} + +// Running on core1 +void setup1() { + delay(5000); + Serial.printf("C1: Red leader standing by...\n"); +} + +void loop1() { + static int x = 0; + Serial.printf("C1: Stay on target...\n"); + val++; + if (++x < 10) { + EEPROM.begin(512); + EEPROM.write(0,x); + EEPROM.commit(); + } + delay(1000); +} diff --git a/libraries/rp2040/examples/PSRAMTest/PSRAMTest.ino b/libraries/rp2040/examples/PSRAMTest/PSRAMTest.ino new file mode 100644 index 000000000..ed11ab410 --- /dev/null +++ b/libraries/rp2040/examples/PSRAMTest/PSRAMTest.ino @@ -0,0 +1,64 @@ +/* + PSRAM Test + + This section of code tests the onboard ram of RP2350 based boards with external + PSRAM. + + This example code is in the public domain. + +*/ + +#if !defined(RP2350_PSRAM_CS) + +void setup() { + Serial.println("This example needs an RP2350 with PSRAM attached"); +} + +void loop() { +} + +#else + +#define CHUNK_SIZE 131072 +uint8_t tmp[CHUNK_SIZE]; +uint8_t mems[1024 * 1024 * 8] PSRAM; + +// the setup function runs once when you press reset or power the board +void setup() { + // initialize digital pin LED_BUILTIN as an output. + pinMode(LED_BUILTIN, OUTPUT); + while (!Serial) { + delay(10); + } + Serial.begin(115200); + Serial.printf("Memory size: %d\r\n", rp2040.getPSRAMSize()); +} + +// the loop function runs over and over again forever +void loop() { + int i; + static int cntr = 1; + + uint8_t *mem = mems; + Serial.printf("%05d: Filling %d memory locations @0x%p with random values and verifying in %d byte chunks.\r\n", cntr++, rp2040.getPSRAMSize(), mem, CHUNK_SIZE); + + for (size_t m = 0; m < (rp2040.getPSRAMSize() / CHUNK_SIZE); m++) { + for (i = 0; i < CHUNK_SIZE; i++) { + tmp[i] = (char)random(0, 255); + mem[i] = tmp[i]; + } + + for (i = 0; i < CHUNK_SIZE; i++) { + if (mem[i] != tmp[i]) { + Serial.printf("Memory error @0x%p(%d), was 0x%02x, should be 0x%02x\n", mem, i, *mem, tmp[i]); + delay(10); + } + } + Serial.write('.'); + Serial.flush(); + mem += CHUNK_SIZE; + } + Serial.printf("\nDone, testing %d bytes again\r\n", rp2040.getPSRAMSize()); +} + +#endif // RAM_CHIP_SELECT diff --git a/libraries/rp2040/examples/StaticMulticore-FreeRTOS/StaticMulticore-FreeRTOS.ino b/libraries/rp2040/examples/StaticMulticore-FreeRTOS/StaticMulticore-FreeRTOS.ino new file mode 100644 index 000000000..2e8cef17d --- /dev/null +++ b/libraries/rp2040/examples/StaticMulticore-FreeRTOS/StaticMulticore-FreeRTOS.ino @@ -0,0 +1,94 @@ +/* The code in this example is mostly derived from the official FreeRTOS + * code examples. + * + * For more information on static allocation and to read the original + * code visit the following links: + * https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html + * https://www.freertos.org/xTaskCreateStatic.html + * https://www.freertos.org/xSemaphoreCreateMutexStatic.html + */ + +#include +#include +#include + +#define SERIAL_PORT Serial +#define BLINK_ON_TIME 250 +#define BLINK_OFF_TIME 500 + +/* Dimensions of the buffer that the task being created will use as its stack. + NOTE: This is the number of words the stack will hold, not the number of + bytes. For example, if each stack item is 32-bits, and this is set to 100, + then 400 bytes (100 * 32-bits) will be allocated. */ +#define STACK_SIZE 200 + +/* Structure that will hold the TCB of the task being created. */ +StaticTask_t xTaskBuffer_A; +StaticTask_t xTaskBuffer_B; + +/* Buffer that the task being created will use as its stack. Note this is + an array of StackType_t variables. The size of StackType_t is dependent on + the RTOS port. */ +StackType_t xStack_A[ STACK_SIZE ]; +StackType_t xStack_B[ STACK_SIZE ]; + +SemaphoreHandle_t xSemaphore = NULL; +StaticSemaphore_t xMutexBuffer; + +TaskHandle_t ledOnTask, ledOffTask; + +void setup() { + SERIAL_PORT.begin(115200); + pinMode(LED_BUILTIN, OUTPUT); + + /* Create a mutex semaphore without using any dynamic memory + allocation. The mutex's data structures will be saved into + the xMutexBuffer variable. */ + xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer ); + + ledOnTask = xTaskCreateStatic(led_ON, "led_ON", STACK_SIZE, NULL, configMAX_PRIORITIES - 1, xStack_A, &xTaskBuffer_A); +#if defined(PICO_CYW43_SUPPORTED) + // The PicoW WiFi chip controls the LED, and only core 0 can make calls to it safely + vTaskCoreAffinitySet(ledOnTask, 1 << 0); +#endif + ledOffTask = xTaskCreateStatic(led_OFF, "led_OFF", STACK_SIZE, NULL, configMAX_PRIORITIES - 1, xStack_B, &xTaskBuffer_B); +#if defined(PICO_CYW43_SUPPORTED) + // The PicoW WiFi chip controls the LED, and only core 0 can make calls to it safely + vTaskCoreAffinitySet(ledOffTask, 1 << 0); +#endif + } + +void led_ON(void *pvParameters) +{ + (void) pvParameters; + delay(100); + while (1) + { + xSemaphoreTake( xSemaphore, ( TickType_t ) portMAX_DELAY ); + SERIAL_PORT.println("LED ON!"); + digitalWrite(LED_BUILTIN, HIGH); + delay(BLINK_ON_TIME); + xSemaphoreGive( xSemaphore ); + delay(1); + } +} + +void led_OFF(void *pvParameters) +{ + (void) pvParameters; + delay(100); + while (1) + { + xSemaphoreTake( xSemaphore, ( TickType_t ) portMAX_DELAY ); + SERIAL_PORT.println("LED OFF!"); + digitalWrite(LED_BUILTIN, LOW); + delay(BLINK_OFF_TIME); + xSemaphoreGive( xSemaphore ); + delay(1); + } +} + +void loop() { + SERIAL_PORT.println("Hello!"); + delay(1000); +} diff --git a/libraries/rp2040/examples/Stress-FreeRTOS/Stress-FreeRTOS.ino b/libraries/rp2040/examples/Stress-FreeRTOS/Stress-FreeRTOS.ino new file mode 100644 index 000000000..6c9414bc2 --- /dev/null +++ b/libraries/rp2040/examples/Stress-FreeRTOS/Stress-FreeRTOS.ino @@ -0,0 +1,319 @@ +// FreeRTOS system call/mutex stress test + +#include +#include +#include +#include +#define DELAY 1 +#define SERIAL_DEBUG Serial1 +#define STACK_SIZE 512 +#define CORE_0 (1 << 0) +#define CORE_1 (1 << 1) + +void semphrTakeConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore); +void semphrGiveConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore); + +/* + I want to keep the possibility of using different and independent + mutexes for each of the functions that operate on the heap. + + If you want to enable the use of these mutexes remove the defines + on lines 30 and 31 and enable the their initialization in setup() +*/ +SemaphoreHandle_t xSemaphoreMalloc = NULL; +// SemaphoreHandle_t xSemaphoreRealloc = NULL; +// SemaphoreHandle_t xSemaphoreFree = NULL; + +/* + A lazy way to use the same mutex for malloc, realloc and free + in order to bring us back to the same situation as the MCVE + posted here: https://github.com/earlephilhower/arduino-pico/issues/795#issuecomment-1227122082 +*/ +#define xSemaphoreRealloc xSemaphoreMalloc +#define xSemaphoreFree xSemaphoreMalloc + +const bool useMutexOnMalloc = false; +const bool useMutexOnRealloc = false; +const bool useMutexOnFree = false; + +/* + Enabling this, a realloc will be performed and the string "_realloc" + will be concateneted to *tmp +*/ +const bool tryRealloc = true; + +TaskHandle_t loop2Handle = NULL; +TaskHandle_t loop3Handle = NULL; +TaskHandle_t loop4Handle = NULL; +TaskHandle_t loop5Handle = NULL; +TaskHandle_t loop6Handle = NULL; +TaskHandle_t loop7Handle = NULL; + +void loop2(void *pvPramaters); +void loop3(void *pvPramaters); +void loop4(void *pvPramaters); +void loop5(void *pvPramaters); +void loop6(void *pvPramaters); +void loop7(void *pvPramaters); + +void setup() +{ + pinMode(LED_BUILTIN, OUTPUT); + + xSemaphoreMalloc = xSemaphoreCreateMutex(); + // xSemaphoreRealloc = xSemaphoreCreateMutex(); + // xSemaphoreFree = xSemaphoreCreateMutex(); + + xTaskCreate(loop2, "loop2", STACK_SIZE, NULL, 1, &loop2Handle); + vTaskCoreAffinitySet(loop2Handle, CORE_0); + xTaskCreate(loop3, "loop3", STACK_SIZE, NULL, 1, &loop3Handle); + vTaskCoreAffinitySet(loop3Handle, CORE_1); + xTaskCreate(loop4, "loop4", STACK_SIZE, NULL, 1, &loop4Handle); + vTaskCoreAffinitySet(loop4Handle, CORE_0); + xTaskCreate(loop5, "loop5", STACK_SIZE, NULL, 1, &loop5Handle); + vTaskCoreAffinitySet(loop5Handle, CORE_1); + // xTaskCreate(loop6, "loop6", STACK_SIZE, NULL, 1, &loop6Handle); + // vTaskCoreAffinitySet(loop6Handle, CORE_0); + // xTaskCreate(loop7, "loop7", STACK_SIZE, NULL, 1, &loop7Handle); + // vTaskCoreAffinitySet(loop7Handle, CORE_1); +} +static int _loop[8]; + +void loop() +{ + while (1) + { + _loop[0]++; + digitalWrite(LED_BUILTIN, HIGH); + delay(500); + digitalWrite(LED_BUILTIN, LOW); + delay(500); + for (int i=0; i<8; i++) Serial.printf("%d ", _loop[i]); + Serial.println(""); + } +} + +void loop1() +{ + while (1) + { + _loop[1]++; + char *tmp; + + semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); + tmp = (char *)malloc(10 * sizeof(char)); + semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); + + strcpy(tmp, "foo"); + + if (tryRealloc) + { + semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); + tmp = (char *)realloc(tmp, 20 * sizeof(char)); + semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); + strcat(tmp, "_realloc"); + } + + semphrTakeConditional(useMutexOnFree, xSemaphoreFree); + free(tmp); + semphrGiveConditional(useMutexOnFree, xSemaphoreFree); + + delay(DELAY); + } +} + +void loop2(void *pvPramaters) +{ + (void) pvPramaters; + while (1) + { + _loop[2]++; + char *tmp; + + semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); + tmp = (char *)malloc(10 * sizeof(char)); + semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); + + strcpy(tmp, "bar"); + + if (tryRealloc) + { + semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); + tmp = (char *)realloc(tmp, 20 * sizeof(char)); + semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); + strcat(tmp, "_realloc"); + } + + semphrTakeConditional(useMutexOnFree, xSemaphoreFree); + free(tmp); + semphrGiveConditional(useMutexOnFree, xSemaphoreFree); + + delay(DELAY); + } +} + +void loop3(void *pvPramaters) +{ + (void) pvPramaters; + while (1) + { + _loop[3]++; + char *tmp; + + semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); + tmp = (char *)malloc(10 * sizeof(char)); + semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); + + strcpy(tmp, "yeah"); + + if (tryRealloc) + { + semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); + tmp = (char *)realloc(tmp, 20 * sizeof(char)); + semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); + strcat(tmp, "_realloc"); + } + + semphrTakeConditional(useMutexOnFree, xSemaphoreFree); + free(tmp); + semphrGiveConditional(useMutexOnFree, xSemaphoreFree); + + delay(DELAY); + } +} + +void loop4(void *pvPramaters) +{ + (void) pvPramaters; + while (1) + { + _loop[4]++; + char *tmp; + + semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); + tmp = (char *)malloc(10 * sizeof(char)); + semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); + + strcpy(tmp, "baz"); + + if (tryRealloc) + { + semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); + tmp = (char *)realloc(tmp, 20 * sizeof(char)); + semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); + strcat(tmp, "_realloc"); + } + + semphrTakeConditional(useMutexOnFree, xSemaphoreFree); + free(tmp); + semphrGiveConditional(useMutexOnFree, xSemaphoreFree); + + delay(DELAY); + } +} + +void loop5(void *pvPramaters) +{ + (void) pvPramaters; + while (1) + { + _loop[5]++; + char *tmp; + + semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); + tmp = (char *)malloc(10 * sizeof(char)); + semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); + + strcpy(tmp, "asd"); + + if (tryRealloc) + { + semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); + tmp = (char *)realloc(tmp, 20 * sizeof(char)); + semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); + strcat(tmp, "_realloc"); + } + + semphrTakeConditional(useMutexOnFree, xSemaphoreFree); + free(tmp); + semphrGiveConditional(useMutexOnFree, xSemaphoreFree); + + delay(DELAY); + } +} + +void loop6(void *pvPramaters) +{ + (void) pvPramaters; + while (1) + { + _loop[6]++; + char *tmp; + + semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); + tmp = (char *)malloc(10 * sizeof(char)); + semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); + + strcpy(tmp, "lol"); + + if (tryRealloc) + { + semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); + tmp = (char *)realloc(tmp, 20 * sizeof(char)); + semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); + strcat(tmp, "_realloc"); + } + + semphrTakeConditional(useMutexOnFree, xSemaphoreFree); + free(tmp); + semphrGiveConditional(useMutexOnFree, xSemaphoreFree); + + delay(DELAY); + } +} + +void loop7(void *pvPramaters) +{ + (void) pvPramaters; + while (1) + { + _loop[7]++; + char *tmp; + + semphrTakeConditional(useMutexOnMalloc, xSemaphoreMalloc); + tmp = (char *)malloc(10 * sizeof(char)); + semphrGiveConditional(useMutexOnMalloc, xSemaphoreMalloc); + + strcpy(tmp, "yay"); + + if (tryRealloc) + { + semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); + tmp = (char *)realloc(tmp, 20 * sizeof(char)); + semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); + strcat(tmp, "_realloc"); + } + + semphrTakeConditional(useMutexOnFree, xSemaphoreFree); + free(tmp); + semphrGiveConditional(useMutexOnFree, xSemaphoreFree); + + delay(DELAY); + } +} + +void semphrTakeConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore) +{ + if (useMutexOn) + { + xSemaphoreTake(xSemaphore, TickType_t(portMAX_DELAY)); + } +} + +void semphrGiveConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore) +{ + if (useMutexOn) + { + xSemaphoreGive(xSemaphore); + } +} From 00a99e432e743e79a8a89031bb8451144a36a20f Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 18 Aug 2025 10:30:28 -0700 Subject: [PATCH 17/36] Astyle --- cores/rp2040/freertos/heap_3a.c | 115 ++- cores/rp2040/freertos/variantHooks.cpp | 656 ++++++++---------- cores/rp2040/lwip_wrap.cpp | 4 +- .../rp2040/sdkoverride/cyw43_arch_freertos.c | 15 +- libraries/lwIP_Ethernet/src/LwipEthernet.cpp | 62 +- libraries/lwIP_Ethernet/src/LwipIntfDev.h | 14 +- .../Multicore-FreeRTOS/Multicore-FreeRTOS.ino | 6 +- .../StaticMulticore-FreeRTOS.ino | 40 +- .../Stress-FreeRTOS/Stress-FreeRTOS.ino | 88 +-- 9 files changed, 453 insertions(+), 547 deletions(-) diff --git a/cores/rp2040/freertos/heap_3a.c b/cores/rp2040/freertos/heap_3a.c index 81bc88924..cc57d45d3 100644 --- a/cores/rp2040/freertos/heap_3a.c +++ b/cores/rp2040/freertos/heap_3a.c @@ -1,50 +1,50 @@ // Hacked to remove the vTaskSuspendAll from heap_3.c /* - * FreeRTOS Kernel - * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * SPDX-License-Identifier: MIT - * - * 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. - * - * https://www.FreeRTOS.org - * https://github.com/FreeRTOS - * - */ + FreeRTOS Kernel + Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + SPDX-License-Identifier: MIT + + 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. + + https://www.FreeRTOS.org + https://github.com/FreeRTOS + +*/ /* - * Implementation of pvPortMalloc() and vPortFree() that relies on the - * compilers own malloc() and free() implementations. - * - * This file can only be used if the linker is configured to to generate - * a heap memory area. - * - * See heap_1.c, heap_2.c and heap_4.c for alternative implementations, and the - * memory management pages of https://www.FreeRTOS.org for more information. - */ + Implementation of pvPortMalloc() and vPortFree() that relies on the + compilers own malloc() and free() implementations. + + This file can only be used if the linker is configured to to generate + a heap memory area. + + See heap_1.c, heap_2.c and heap_4.c for alternative implementations, and the + memory management pages of https://www.FreeRTOS.org for more information. +*/ #include -/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining - * all the API functions to use the MPU wrappers. That should only be done when - * task.h is included from an application file. */ +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining + all the API functions to use the MPU wrappers. That should only be done when + task.h is included from an application file. */ #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE #include "FreeRTOS.h" @@ -53,56 +53,51 @@ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE #if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) - #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0 +#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0 #endif /*-----------------------------------------------------------*/ -void * pvPortMalloc( size_t xWantedSize ) -{ +void * pvPortMalloc(size_t xWantedSize) { void * pvReturn; //vTaskSuspendAll(); { - pvReturn = malloc( xWantedSize ); - traceMALLOC( pvReturn, xWantedSize ); + pvReturn = malloc(xWantedSize); + traceMALLOC(pvReturn, xWantedSize); } //( void ) xTaskResumeAll(); - #if ( configUSE_MALLOC_FAILED_HOOK == 1 ) +#if ( configUSE_MALLOC_FAILED_HOOK == 1 ) { - if( pvReturn == NULL ) - { + if (pvReturn == NULL) { vApplicationMallocFailedHook(); } } - #endif +#endif return pvReturn; } /*-----------------------------------------------------------*/ -void vPortFree( void * pv ) -{ - if( pv != NULL ) - { +void vPortFree(void * pv) { + if (pv != NULL) { //vTaskSuspendAll(); { - free( pv ); - traceFREE( pv, 0 ); + free(pv); + traceFREE(pv, 0); } - // ( void ) xTaskResumeAll(); + // ( void ) xTaskResumeAll(); } } /*-----------------------------------------------------------*/ /* - * Reset the state in this file. This state is normally initialized at start up. - * This function must be called by the application before restarting the - * scheduler. - */ -void vPortHeapResetState( void ) -{ + Reset the state in this file. This state is normally initialized at start up. + This function must be called by the application before restarting the + scheduler. +*/ +void vPortHeapResetState(void) { /* No state needs to be re-initialised in heap_3. */ } /*-----------------------------------------------------------*/ diff --git a/cores/rp2040/freertos/variantHooks.cpp b/cores/rp2040/freertos/variantHooks.cpp index d02d00209..380776d80 100644 --- a/cores/rp2040/freertos/variantHooks.cpp +++ b/cores/rp2040/freertos/variantHooks.cpp @@ -596,372 +596,310 @@ static void lwipThread(void *params) { while (true) { auto ret = xQueueReceive(__lwipQueue, &w, scd); - if (ret) - { - switch (w.op) - { - case __lwip_init: - { - __real_lwip_init(); - break; - } - case __pbuf_header: - { - __pbuf_header_req *r = (__pbuf_header_req *)w.req; - *(r->ret) = __real_pbuf_header(r->p, r->header_size); - break; - } - case __pbuf_free: - { - __pbuf_free_req *r = (__pbuf_free_req *)w.req; - *(r->ret) = __real_pbuf_free(r->p); - break; - } - case __pbuf_alloc: - { - __pbuf_alloc_req *r = (__pbuf_alloc_req *)w.req; - *(r->ret) = __real_pbuf_alloc(r->l, r->length, r->type); - break; - } - case __pbuf_take: - { - __pbuf_take_req *r = (__pbuf_take_req *)w.req; - *(r->ret) = __real_pbuf_take(r->buf, r->dataptr, r->len); - break; - } - case __pbuf_copy_partial: - { - __pbuf_copy_partial_req *r = (__pbuf_copy_partial_req *)w.req; - *(r->ret) = __real_pbuf_copy_partial(r->p, r->dataptr, r->len, r->offset); - break; - } - case __pbuf_ref: - { - __pbuf_ref_req *r = (__pbuf_ref_req *)w.req; - __real_pbuf_ref(r->p); - break; - } - case __pbuf_get_at: - { - __pbuf_get_at_req *r = (__pbuf_get_at_req *)w.req; - *(r->ret) = __real_pbuf_get_at(r->p, r->offset); - break; - } - case __pbuf_get_contiguous: - { - __pbuf_get_contiguous_req *r = (__pbuf_get_contiguous_req *)w.req; - *(r->ret) = __real_pbuf_get_contiguous(r->p, r->buffer, r->bufsize, r->len, r->offset); - break; - } - case __pbuf_cat: - { - __pbuf_cat_req *r = (__pbuf_cat_req *)w.req; - __real_pbuf_cat(r->head, r->tail); - break; - } - case __tcp_arg: - { - __tcp_arg_req *r = (__tcp_arg_req *)w.req; - __real_tcp_arg(r->pcb, r->arg); - break; - } - case __tcp_new: - { - __tcp_new_req *r = (__tcp_new_req *)w.req; - *(r->ret) = __real_tcp_new(); - break; - } - case __tcp_new_ip_type: - { - __tcp_new_ip_type_req *r = (__tcp_new_ip_type_req *)w.req; - *(r->ret) = __real_tcp_new_ip_type(r->type); - break; - } - case __tcp_bind: - { - __tcp_bind_req *r = (__tcp_bind_req *)w.req; - *(r->ret) = __real_tcp_bind(r->pcb, r->ipaddr, r->port); - break; - } - case __tcp_bind_netif: - { - __tcp_bind_netif_req *r = (__tcp_bind_netif_req *)w.req; - *(r->ret) = __real_tcp_bind_netif(r->pcb, r->netif); - break; - } - case __tcp_listen_with_backlog: - { - __tcp_listen_with_backlog_req *r = (__tcp_listen_with_backlog_req *)w.req; - *(r->ret) = __real_tcp_listen_with_backlog(r->pcb, r->backlog); - break; - } + if (ret) { + switch (w.op) { + case __lwip_init: { + __real_lwip_init(); + break; + } + case __pbuf_header: { + __pbuf_header_req *r = (__pbuf_header_req *)w.req; + *(r->ret) = __real_pbuf_header(r->p, r->header_size); + break; + } + case __pbuf_free: { + __pbuf_free_req *r = (__pbuf_free_req *)w.req; + *(r->ret) = __real_pbuf_free(r->p); + break; + } + case __pbuf_alloc: { + __pbuf_alloc_req *r = (__pbuf_alloc_req *)w.req; + *(r->ret) = __real_pbuf_alloc(r->l, r->length, r->type); + break; + } + case __pbuf_take: { + __pbuf_take_req *r = (__pbuf_take_req *)w.req; + *(r->ret) = __real_pbuf_take(r->buf, r->dataptr, r->len); + break; + } + case __pbuf_copy_partial: { + __pbuf_copy_partial_req *r = (__pbuf_copy_partial_req *)w.req; + *(r->ret) = __real_pbuf_copy_partial(r->p, r->dataptr, r->len, r->offset); + break; + } + case __pbuf_ref: { + __pbuf_ref_req *r = (__pbuf_ref_req *)w.req; + __real_pbuf_ref(r->p); + break; + } + case __pbuf_get_at: { + __pbuf_get_at_req *r = (__pbuf_get_at_req *)w.req; + *(r->ret) = __real_pbuf_get_at(r->p, r->offset); + break; + } + case __pbuf_get_contiguous: { + __pbuf_get_contiguous_req *r = (__pbuf_get_contiguous_req *)w.req; + *(r->ret) = __real_pbuf_get_contiguous(r->p, r->buffer, r->bufsize, r->len, r->offset); + break; + } + case __pbuf_cat: { + __pbuf_cat_req *r = (__pbuf_cat_req *)w.req; + __real_pbuf_cat(r->head, r->tail); + break; + } + case __tcp_arg: { + __tcp_arg_req *r = (__tcp_arg_req *)w.req; + __real_tcp_arg(r->pcb, r->arg); + break; + } + case __tcp_new: { + __tcp_new_req *r = (__tcp_new_req *)w.req; + *(r->ret) = __real_tcp_new(); + break; + } + case __tcp_new_ip_type: { + __tcp_new_ip_type_req *r = (__tcp_new_ip_type_req *)w.req; + *(r->ret) = __real_tcp_new_ip_type(r->type); + break; + } + case __tcp_bind: { + __tcp_bind_req *r = (__tcp_bind_req *)w.req; + *(r->ret) = __real_tcp_bind(r->pcb, r->ipaddr, r->port); + break; + } + case __tcp_bind_netif: { + __tcp_bind_netif_req *r = (__tcp_bind_netif_req *)w.req; + *(r->ret) = __real_tcp_bind_netif(r->pcb, r->netif); + break; + } + case __tcp_listen_with_backlog: { + __tcp_listen_with_backlog_req *r = (__tcp_listen_with_backlog_req *)w.req; + *(r->ret) = __real_tcp_listen_with_backlog(r->pcb, r->backlog); + break; + } #if 0 - case __tcp_listen_with_backlog_and_err: - { - __tcp_listen_with_backlog_and_err_req *r = (__tcp_listen_with_backlog_and_err_req *)w.req; - *(r->ret) = __real_tcp_listen_with_backlog_and_err(r->pcb, r->backlog, r->err); - break; - } + case __tcp_listen_with_backlog_and_err: { + __tcp_listen_with_backlog_and_err_req *r = (__tcp_listen_with_backlog_and_err_req *)w.req; + *(r->ret) = __real_tcp_listen_with_backlog_and_err(r->pcb, r->backlog, r->err); + break; + } #endif - case __tcp_accept: - { - __tcp_accept_req *r = (__tcp_accept_req *)w.req; - __real_tcp_accept(r->pcb, r->accept); - break; - } - case __tcp_connect: - { - __tcp_connect_req *r = (__tcp_connect_req *)w.req; - *(r->ret) = __real_tcp_connect(r->pcb, r->ipaddr, r->port, r->connected); - break; - } - case __tcp_write: - { - __tcp_write_req *r = (__tcp_write_req *)w.req; - *(r->ret) = __real_tcp_write(r->pcb, r->dataptr, r->len, r->apiflags); - break; - } - case __tcp_sent: - { - __tcp_sent_req *r = (__tcp_sent_req *)w.req; - __real_tcp_sent(r->pcb, r->sent); - break; - } - case __tcp_recv: - { - __tcp_recv_req *r = (__tcp_recv_req *)w.req; - __real_tcp_recv(r->pcb, r->recv); - break; - } - case __tcp_recved: - { - __tcp_recved_req *r = (__tcp_recved_req *)w.req; - __real_tcp_recved(r->pcb, r->len); - break; - } - case __tcp_poll: - { - __tcp_poll_req *r = (__tcp_poll_req *)w.req; - __real_tcp_poll(r->pcb, r->poll, r->interval); - break; - } - case __tcp_close: - { - __tcp_close_req *r = (__tcp_close_req *)w.req; - *(r->ret) = __real_tcp_close(r->pcb); - break; - } - case __tcp_abort: - { - __tcp_abort_req *r = (__tcp_abort_req *)w.req; - __real_tcp_abort(r->pcb); - break; - } - case __tcp_err: - { - __tcp_err_req *r = (__tcp_err_req *)w.req; - __real_tcp_err(r->pcb, r->err); - break; - } - case __tcp_output: - { - __tcp_output_req *r = (__tcp_output_req *)w.req; - *(r->ret) = __real_tcp_output(r->pcb); - break; - } - case __tcp_setprio: - { - __tcp_setprio_req *r = (__tcp_setprio_req *)w.req; - __real_tcp_setprio(r->pcb, r->prio); - break; - } - case __tcp_shutdown: - { - __tcp_shutdown_req *r = (__tcp_shutdown_req *)w.req; - *(r->ret) = __real_tcp_shutdown(r->pcb, r->shut_rx, r->shut_tx); - break; - } - case __tcp_backlog_delayed: - { - __tcp_backlog_delayed_req *r = (__tcp_backlog_delayed_req *)w.req; - __real_tcp_backlog_delayed(r->pcb); - break; - } - case __tcp_backlog_accepted: - { - __tcp_backlog_accepted_req *r = (__tcp_backlog_accepted_req *)w.req; - __real_tcp_backlog_accepted(r->pcb); - break; - } - case __udp_new: - { - __udp_new_req *r = (__udp_new_req *)w.req; - *(r->ret) = __real_udp_new(); - break; - } - case __udp_new_ip_type: - { - __udp_new_ip_type_req *r = (__udp_new_ip_type_req *)w.req; - *(r->ret) = __real_udp_new_ip_type(r->type); - break; - } - case __udp_remove: - { - __udp_remove_req *r = (__udp_remove_req *)w.req; - __real_udp_remove(r->pcb); - break; - } - case __udp_bind: - { - __udp_bind_req *r = (__udp_bind_req *)w.req; - *(r->ret) = __real_udp_bind(r->pcb, r->ipaddr, r->port); - break; - } - case __udp_connect: - { - __udp_connect_req *r = (__udp_connect_req *)w.req; - *(r->ret) = __real_udp_connect(r->pcb, r->ipaddr, r->port); - break; - } - case __udp_disconnect: - { - __udp_disconnect_req *r = (__udp_disconnect_req *)w.req; - *(r->ret) = __real_udp_disconnect(r->pcb); - break; - } - case __udp_send: - { - __udp_send_req *r = (__udp_send_req *)w.req; - *(r->ret) = __real_udp_send(r->pcb, r->p); - break; - } - case __udp_recv: - { - __udp_recv_req *r = (__udp_recv_req *)w.req; - __real_udp_recv(r->pcb, r->recv, r->recv_arg); - break; - } - case __udp_sendto: - { - __udp_sendto_req *r = (__udp_sendto_req *)w.req; - *(r->ret) = __real_udp_sendto(r->pcb, r->p, r->dst_ip, r->dst_port); - break; - } - case __udp_sendto_if: - { - __udp_sendto_if_req *r = (__udp_sendto_if_req *)w.req; - *(r->ret) = __real_udp_sendto_if(r->pcb, r->p, r->dst_ip, r->dst_port, r->netif); - break; - } - case __udp_sendto_if_src: - { - __udp_sendto_if_src_req *r = (__udp_sendto_if_src_req *)w.req; - *(r->ret) = __real_udp_sendto_if_src(r->pcb, r->p, r->dst_ip, r->dst_port, r->netif, r->src_ip); - break; - } - case __sys_check_timeouts: - { - __real_sys_check_timeouts(); - break; - } - case __dns_gethostbyname: - { - __dns_gethostbyname_req *r = (__dns_gethostbyname_req *)w.req; - *(r->ret) = __real_dns_gethostbyname(r->hostname, r->addr, r->found, r->callback_arg); - break; - } - case __dns_gethostbyname_addrtype: - { - __dns_gethostbyname_addrtype_req *r = (__dns_gethostbyname_addrtype_req *)w.req; - *(r->ret) = __real_dns_gethostbyname_addrtype(r->hostname, r->addr, r->found, r->callback_arg, r->dns_addrtype); - break; - } - case __raw_new: - { - __raw_new_req *r = (__raw_new_req *)w.req; - *(r->ret) = __real_raw_new(r->proto); - break; - } - case __raw_new_ip_type: - { - __raw_new_ip_type_req *r = (__raw_new_ip_type_req *)w.req; - *(r->ret) = __real_raw_new_ip_type(r->type, r->proto); - break; - } - case __raw_connect: - { - __raw_connect_req *r = (__raw_connect_req *)w.req; - *(r->ret) = __real_raw_connect(r->pcb, r->ipaddr); - break; - } - case __raw_recv: - { - __raw_recv_req *r = (__raw_recv_req *)w.req; - __real_raw_recv(r->pcb, r->recv, r->recv_arg); - break; - } - case __raw_bind: - { - __raw_bind_req *r = (__raw_bind_req *)w.req; - *(r->ret) = __real_raw_bind(r->pcb, r->ipaddr); - break; - } - case __raw_sendto: - { - __raw_sendto_req *r = (__raw_sendto_req *)w.req; - *(r->ret) = __real_raw_sendto(r->pcb, r->p, r->ipaddr); - break; - } - case __raw_send: - { - __raw_send_req *r = (__raw_send_req *)w.req; - *(r->ret) = __real_raw_send(r->pcb, r->p); - break; - } - case __raw_remove: - { - __raw_remove_req *r = (__raw_remove_req *)w.req; - __real_raw_remove(r->pcb); - break; - } - case __netif_add: - { - __netif_add_req *r = (__netif_add_req *)w.req; - *(r->ret) = __real_netif_add(r->netif, r->ipaddr, r->netmask, r->gw, r->state, r->init, r->input); - break; - } - case __netif_remove: - { - __netif_remove_req *r = (__netif_remove_req *)w.req; - __real_netif_remove(r->netif); - break; - } - case __ethernet_input: - { - __ethernet_input_req *r = (__ethernet_input_req *)w.req; - printf("__real_ethernet_input\n"); - *(r->ret) = __real_ethernet_input(r->p, r->netif); - break; - } - case __callback: - { - __callback_req *r = (__callback_req *)w.req; - r->cb(r->cbData); - break; - } - default: - { - // Any new unimplemented calls = ERROR!!! - panic("Unimplemented LWIP thread action"); - break; - } + case __tcp_accept: { + __tcp_accept_req *r = (__tcp_accept_req *)w.req; + __real_tcp_accept(r->pcb, r->accept); + break; + } + case __tcp_connect: { + __tcp_connect_req *r = (__tcp_connect_req *)w.req; + *(r->ret) = __real_tcp_connect(r->pcb, r->ipaddr, r->port, r->connected); + break; + } + case __tcp_write: { + __tcp_write_req *r = (__tcp_write_req *)w.req; + *(r->ret) = __real_tcp_write(r->pcb, r->dataptr, r->len, r->apiflags); + break; + } + case __tcp_sent: { + __tcp_sent_req *r = (__tcp_sent_req *)w.req; + __real_tcp_sent(r->pcb, r->sent); + break; + } + case __tcp_recv: { + __tcp_recv_req *r = (__tcp_recv_req *)w.req; + __real_tcp_recv(r->pcb, r->recv); + break; + } + case __tcp_recved: { + __tcp_recved_req *r = (__tcp_recved_req *)w.req; + __real_tcp_recved(r->pcb, r->len); + break; + } + case __tcp_poll: { + __tcp_poll_req *r = (__tcp_poll_req *)w.req; + __real_tcp_poll(r->pcb, r->poll, r->interval); + break; + } + case __tcp_close: { + __tcp_close_req *r = (__tcp_close_req *)w.req; + *(r->ret) = __real_tcp_close(r->pcb); + break; + } + case __tcp_abort: { + __tcp_abort_req *r = (__tcp_abort_req *)w.req; + __real_tcp_abort(r->pcb); + break; + } + case __tcp_err: { + __tcp_err_req *r = (__tcp_err_req *)w.req; + __real_tcp_err(r->pcb, r->err); + break; + } + case __tcp_output: { + __tcp_output_req *r = (__tcp_output_req *)w.req; + *(r->ret) = __real_tcp_output(r->pcb); + break; + } + case __tcp_setprio: { + __tcp_setprio_req *r = (__tcp_setprio_req *)w.req; + __real_tcp_setprio(r->pcb, r->prio); + break; + } + case __tcp_shutdown: { + __tcp_shutdown_req *r = (__tcp_shutdown_req *)w.req; + *(r->ret) = __real_tcp_shutdown(r->pcb, r->shut_rx, r->shut_tx); + break; + } + case __tcp_backlog_delayed: { + __tcp_backlog_delayed_req *r = (__tcp_backlog_delayed_req *)w.req; + __real_tcp_backlog_delayed(r->pcb); + break; + } + case __tcp_backlog_accepted: { + __tcp_backlog_accepted_req *r = (__tcp_backlog_accepted_req *)w.req; + __real_tcp_backlog_accepted(r->pcb); + break; + } + case __udp_new: { + __udp_new_req *r = (__udp_new_req *)w.req; + *(r->ret) = __real_udp_new(); + break; + } + case __udp_new_ip_type: { + __udp_new_ip_type_req *r = (__udp_new_ip_type_req *)w.req; + *(r->ret) = __real_udp_new_ip_type(r->type); + break; + } + case __udp_remove: { + __udp_remove_req *r = (__udp_remove_req *)w.req; + __real_udp_remove(r->pcb); + break; + } + case __udp_bind: { + __udp_bind_req *r = (__udp_bind_req *)w.req; + *(r->ret) = __real_udp_bind(r->pcb, r->ipaddr, r->port); + break; + } + case __udp_connect: { + __udp_connect_req *r = (__udp_connect_req *)w.req; + *(r->ret) = __real_udp_connect(r->pcb, r->ipaddr, r->port); + break; + } + case __udp_disconnect: { + __udp_disconnect_req *r = (__udp_disconnect_req *)w.req; + *(r->ret) = __real_udp_disconnect(r->pcb); + break; + } + case __udp_send: { + __udp_send_req *r = (__udp_send_req *)w.req; + *(r->ret) = __real_udp_send(r->pcb, r->p); + break; + } + case __udp_recv: { + __udp_recv_req *r = (__udp_recv_req *)w.req; + __real_udp_recv(r->pcb, r->recv, r->recv_arg); + break; + } + case __udp_sendto: { + __udp_sendto_req *r = (__udp_sendto_req *)w.req; + *(r->ret) = __real_udp_sendto(r->pcb, r->p, r->dst_ip, r->dst_port); + break; + } + case __udp_sendto_if: { + __udp_sendto_if_req *r = (__udp_sendto_if_req *)w.req; + *(r->ret) = __real_udp_sendto_if(r->pcb, r->p, r->dst_ip, r->dst_port, r->netif); + break; + } + case __udp_sendto_if_src: { + __udp_sendto_if_src_req *r = (__udp_sendto_if_src_req *)w.req; + *(r->ret) = __real_udp_sendto_if_src(r->pcb, r->p, r->dst_ip, r->dst_port, r->netif, r->src_ip); + break; + } + case __sys_check_timeouts: { + __real_sys_check_timeouts(); + break; + } + case __dns_gethostbyname: { + __dns_gethostbyname_req *r = (__dns_gethostbyname_req *)w.req; + *(r->ret) = __real_dns_gethostbyname(r->hostname, r->addr, r->found, r->callback_arg); + break; + } + case __dns_gethostbyname_addrtype: { + __dns_gethostbyname_addrtype_req *r = (__dns_gethostbyname_addrtype_req *)w.req; + *(r->ret) = __real_dns_gethostbyname_addrtype(r->hostname, r->addr, r->found, r->callback_arg, r->dns_addrtype); + break; + } + case __raw_new: { + __raw_new_req *r = (__raw_new_req *)w.req; + *(r->ret) = __real_raw_new(r->proto); + break; + } + case __raw_new_ip_type: { + __raw_new_ip_type_req *r = (__raw_new_ip_type_req *)w.req; + *(r->ret) = __real_raw_new_ip_type(r->type, r->proto); + break; + } + case __raw_connect: { + __raw_connect_req *r = (__raw_connect_req *)w.req; + *(r->ret) = __real_raw_connect(r->pcb, r->ipaddr); + break; + } + case __raw_recv: { + __raw_recv_req *r = (__raw_recv_req *)w.req; + __real_raw_recv(r->pcb, r->recv, r->recv_arg); + break; + } + case __raw_bind: { + __raw_bind_req *r = (__raw_bind_req *)w.req; + *(r->ret) = __real_raw_bind(r->pcb, r->ipaddr); + break; + } + case __raw_sendto: { + __raw_sendto_req *r = (__raw_sendto_req *)w.req; + *(r->ret) = __real_raw_sendto(r->pcb, r->p, r->ipaddr); + break; + } + case __raw_send: { + __raw_send_req *r = (__raw_send_req *)w.req; + *(r->ret) = __real_raw_send(r->pcb, r->p); + break; + } + case __raw_remove: { + __raw_remove_req *r = (__raw_remove_req *)w.req; + __real_raw_remove(r->pcb); + break; + } + case __netif_add: { + __netif_add_req *r = (__netif_add_req *)w.req; + *(r->ret) = __real_netif_add(r->netif, r->ipaddr, r->netmask, r->gw, r->state, r->init, r->input); + break; + } + case __netif_remove: { + __netif_remove_req *r = (__netif_remove_req *)w.req; + __real_netif_remove(r->netif); + break; + } + case __ethernet_input: { + __ethernet_input_req *r = (__ethernet_input_req *)w.req; + printf("__real_ethernet_input\n"); + *(r->ret) = __real_ethernet_input(r->p, r->netif); + break; + } + case __callback: { + __callback_req *r = (__callback_req *)w.req; + r->cb(r->cbData); + break; + } + default: { + // Any new unimplemented calls = ERROR!!! + panic("Unimplemented LWIP thread action"); + break; + } } // Work done, return value set, just tickle the calling task if (w.wakeup) { xTaskNotifyGiveIndexed(w.wakeup, TASK_NOTIFY_LWIP_WAKEUP); } - } else - { + } else { // No work received, do periodic processing __real_sys_check_timeouts(); // When should we wake up next to redo timeouts? diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index c02402c55..2c482971f 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -702,8 +702,8 @@ extern "C" { return __real_raw_new_ip_type(type, proto); } - extern err_t __real_raw_connect (struct raw_pcb *pcb, const ip_addr_t *ipaddr); - err_t __wrap_raw_connect (struct raw_pcb *pcb, const ip_addr_t *ipaddr) { + extern err_t __real_raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr); + err_t __wrap_raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr) { #ifdef __FREERTOS if (!__isLWIPThread()) { err_t ret; diff --git a/cores/rp2040/sdkoverride/cyw43_arch_freertos.c b/cores/rp2040/sdkoverride/cyw43_arch_freertos.c index 6b55f66d6..01949f796 100644 --- a/cores/rp2040/sdkoverride/cyw43_arch_freertos.c +++ b/cores/rp2040/sdkoverride/cyw43_arch_freertos.c @@ -2,10 +2,10 @@ // Taken from SDK because we need to remove the !NO_SYS check #define PICO_CYW43_ARCH_FREERTOS 1 /* - * Copyright (c) 2022 Raspberry Pi (Trading) Ltd. - * - * SPDX-License-Identifier: BSD-3-Clause - */ + Copyright (c) 2022 Raspberry Pi (Trading) Ltd. + + SPDX-License-Identifier: BSD-3-Clause +*/ #if PICO_CYW43_ARCH_FREERTOS @@ -43,8 +43,9 @@ async_context_t *cyw43_arch_init_default_async_context(void) { #if configSUPPORT_STATIC_ALLOCATION && !CYW43_NO_DEFAULT_TASK_STACK config.task_stack = cyw43_async_context_freertos_task_stack; #endif - if (async_context_freertos_init(&cyw43_async_context_freertos, &config)) + if (async_context_freertos_init(&cyw43_async_context_freertos, &config)) { return &cyw43_async_context_freertos.core; + } return NULL; } @@ -52,7 +53,9 @@ int cyw43_arch_init(void) { async_context_t *context = cyw43_arch_async_context(); if (!context) { context = cyw43_arch_init_default_async_context(); - if (!context) return PICO_ERROR_GENERIC; + if (!context) { + return PICO_ERROR_GENERIC; + } cyw43_arch_set_async_context(context); } bool ok = cyw43_driver_init(context); diff --git a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp index 995ad93ba..05cc803ce 100644 --- a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp +++ b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp @@ -72,24 +72,24 @@ static async_context_t *_context = nullptr; static std::map> _handlePacketList; void ethernet_arch_lwip_begin() { -//#if defined(PICO_CYW43_SUPPORTED) -// if (rp2040.isPicoW()) { -// cyw43_arch_lwip_begin(); -// return; -// } -//#endif -// __startEthernetContext(); -// async_context_acquire_lock_blocking(_context); + //#if defined(PICO_CYW43_SUPPORTED) + // if (rp2040.isPicoW()) { + // cyw43_arch_lwip_begin(); + // return; + // } + //#endif + // __startEthernetContext(); + // async_context_acquire_lock_blocking(_context); } void ethernet_arch_lwip_end() { -//#if defined(PICO_CYW43_SUPPORTED) -// if (rp2040.isPicoW()) { -// cyw43_arch_lwip_end(); -// return; -// } -//#endif -// async_context_release_lock(_context); + //#if defined(PICO_CYW43_SUPPORTED) + // if (rp2040.isPicoW()) { + // cyw43_arch_lwip_end(); + // return; + // } + //#endif + // async_context_release_lock(_context); } int __addEthernetPacketHandler(std::function _packetHandler) { @@ -206,19 +206,19 @@ static uint32_t _pollingPeriod = 20; // This will only be called under the protection of the async context mutex, so no re-entrancy checks needed static void ethernet_timeout_reached(__unused async_context_t *context, __unused async_at_time_worker_t *worker) { assert(worker == ðernet_timeout_worker); - printf("__ethernet_timeout_reached_calls %d\n",__ethernet_timeout_reached_calls); + printf("__ethernet_timeout_reached_calls %d\n", __ethernet_timeout_reached_calls); __ethernet_timeout_reached_calls++; ethernet_arch_lwip_gpio_mask(); // Ensure non-polled devices won't interrupt us for (auto handlePacket : _handlePacketList) { handlePacket.second(); sys_check_timeouts(); } -//#if defined(PICO_CYW43_SUPPORTED) -// if (!rp2040.isPicoW()) { -// sys_check_timeouts(); -// } -//#else -//#endif + //#if defined(PICO_CYW43_SUPPORTED) + // if (!rp2040.isPicoW()) { + // sys_check_timeouts(); + // } + //#else + //#endif ethernet_arch_lwip_gpio_unmask(); } @@ -273,17 +273,17 @@ void __startEthernetContext() { return; } xTaskCreate(ethernetTask, "Ethernet", 256, nullptr, 1, &_ethernetTask); -// vTaskCoreAffinitySet(_ethernetTask, 1 << 0); + // vTaskCoreAffinitySet(_ethernetTask, 1 << 0); #if 0 -//#if defined(PICO_CYW43_SUPPORTED) -// if (rp2040.isPicoW()) { -// _context = cyw43_arch_async_context(); -// } else { -// _context = lwip_ethernet_init_default_async_context(); -// } -//#else + //#if defined(PICO_CYW43_SUPPORTED) + // if (rp2040.isPicoW()) { + // _context = cyw43_arch_async_context(); + // } else { + // _context = lwip_ethernet_init_default_async_context(); + // } + //#else _context = lwip_ethernet_init_default_async_context(); -//#endif + //#endif ethernet_timeout_worker.do_work = ethernet_timeout_reached; always_pending_update_timeout_worker.work_pending = true; always_pending_update_timeout_worker.do_work = update_next_timeout; diff --git a/libraries/lwIP_Ethernet/src/LwipIntfDev.h b/libraries/lwIP_Ethernet/src/LwipIntfDev.h index d6014da90..9cc39bf2e 100644 --- a/libraries/lwIP_Ethernet/src/LwipIntfDev.h +++ b/libraries/lwIP_Ethernet/src/LwipIntfDev.h @@ -486,8 +486,8 @@ void LwipIntfDev::_irq(void *param) { ethernet_arch_lwip_gpio_mask(); // Disable other IRQs until we're done processing this one lwip_callback(_lwipCallback, param, (void *)d->_irqBuffer); //ethernet_arch_lwip_begin(); -// d->handlePackets(); -// sys_check_timeouts(); + // d->handlePackets(); + // sys_check_timeouts(); //ethernet_arch_lwip_end(); } @@ -505,7 +505,7 @@ EthernetLinkStatus LwipIntfDev::linkStatus() { template err_t LwipIntfDev::linkoutput_s(netif* netif, struct pbuf* pbuf) { LwipIntfDev* lid = (LwipIntfDev*)netif->state; -// ethernet_arch_lwip_begin(); + // ethernet_arch_lwip_begin(); xSemaphoreTake(lid->_hwMutex, portMAX_DELAY); uint16_t len = lid->sendFrame((const uint8_t*)pbuf->payload, pbuf->len); xSemaphoreGive(lid->_hwMutex); @@ -516,7 +516,7 @@ err_t LwipIntfDev::linkoutput_s(netif* netif, struct pbuf* pbuf) { /*success*/ len == pbuf->len); } #endif -// ethernet_arch_lwip_end(); + // ethernet_arch_lwip_end(); return len == pbuf->len ? ERR_OK : ERR_MEM; } @@ -632,9 +632,9 @@ err_t LwipIntfDev::handlePackets() { } _packetsReceived++; -//printf("recv pkt %d: ", tot_len); -//for (int i=0; i < tot_len; i++) printf("%02x ", ((uint8_t*)pbuf->payload)[i]); -//printf("\n"); + //printf("recv pkt %d: ", tot_len); + //for (int i=0; i < tot_len; i++) printf("%02x ", ((uint8_t*)pbuf->payload)[i]); + //printf("\n"); err_t err = _netif.input(pbuf, &_netif); #if PHY_HAS_CAPTURE diff --git a/libraries/rp2040/examples/Multicore-FreeRTOS/Multicore-FreeRTOS.ino b/libraries/rp2040/examples/Multicore-FreeRTOS/Multicore-FreeRTOS.ino index c4cd6329c..c0a671111 100644 --- a/libraries/rp2040/examples/Multicore-FreeRTOS/Multicore-FreeRTOS.ino +++ b/libraries/rp2040/examples/Multicore-FreeRTOS/Multicore-FreeRTOS.ino @@ -26,10 +26,10 @@ void ps() { int tasks = uxTaskGetNumberOfTasks(); TaskStatus_t *pxTaskStatusArray = new TaskStatus_t[tasks]; unsigned long runtime; - tasks = uxTaskGetSystemState( pxTaskStatusArray, tasks, &runtime ); + tasks = uxTaskGetSystemState(pxTaskStatusArray, tasks, &runtime); Serial.printf("# Tasks: %d\n", tasks); Serial.println("ID, NAME, STATE, PRIO, CYCLES"); - for (int i=0; i < tasks; i++) { + for (int i = 0; i < tasks; i++) { Serial.printf("%d: %-16s %-10s %d %lu\n", i, pxTaskStatusArray[i].pcTaskName, eTaskStateName[pxTaskStatusArray[i].eCurrentState], (int)pxTaskStatusArray[i].uxCurrentPriority, pxTaskStatusArray[i].ulRunTimeCounter); } delete[] pxTaskStatusArray; @@ -80,7 +80,7 @@ void loop1() { val++; if (++x < 10) { EEPROM.begin(512); - EEPROM.write(0,x); + EEPROM.write(0, x); EEPROM.commit(); } delay(1000); diff --git a/libraries/rp2040/examples/StaticMulticore-FreeRTOS/StaticMulticore-FreeRTOS.ino b/libraries/rp2040/examples/StaticMulticore-FreeRTOS/StaticMulticore-FreeRTOS.ino index 2e8cef17d..89e07cdac 100644 --- a/libraries/rp2040/examples/StaticMulticore-FreeRTOS/StaticMulticore-FreeRTOS.ino +++ b/libraries/rp2040/examples/StaticMulticore-FreeRTOS/StaticMulticore-FreeRTOS.ino @@ -1,12 +1,12 @@ /* The code in this example is mostly derived from the official FreeRTOS - * code examples. - * - * For more information on static allocation and to read the original - * code visit the following links: - * https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html - * https://www.freertos.org/xTaskCreateStatic.html - * https://www.freertos.org/xSemaphoreCreateMutexStatic.html - */ + code examples. + + For more information on static allocation and to read the original + code visit the following links: + https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html + https://www.freertos.org/xTaskCreateStatic.html + https://www.freertos.org/xSemaphoreCreateMutexStatic.html +*/ #include #include @@ -44,7 +44,7 @@ void setup() { /* Create a mutex semaphore without using any dynamic memory allocation. The mutex's data structures will be saved into the xMutexBuffer variable. */ - xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer ); + xSemaphore = xSemaphoreCreateMutexStatic(&xMutexBuffer); ledOnTask = xTaskCreateStatic(led_ON, "led_ON", STACK_SIZE, NULL, configMAX_PRIORITIES - 1, xStack_A, &xTaskBuffer_A); #if defined(PICO_CYW43_SUPPORTED) @@ -56,34 +56,30 @@ void setup() { // The PicoW WiFi chip controls the LED, and only core 0 can make calls to it safely vTaskCoreAffinitySet(ledOffTask, 1 << 0); #endif - } +} -void led_ON(void *pvParameters) -{ +void led_ON(void *pvParameters) { (void) pvParameters; delay(100); - while (1) - { - xSemaphoreTake( xSemaphore, ( TickType_t ) portMAX_DELAY ); + while (1) { + xSemaphoreTake(xSemaphore, (TickType_t) portMAX_DELAY); SERIAL_PORT.println("LED ON!"); digitalWrite(LED_BUILTIN, HIGH); delay(BLINK_ON_TIME); - xSemaphoreGive( xSemaphore ); + xSemaphoreGive(xSemaphore); delay(1); } } -void led_OFF(void *pvParameters) -{ +void led_OFF(void *pvParameters) { (void) pvParameters; delay(100); - while (1) - { - xSemaphoreTake( xSemaphore, ( TickType_t ) portMAX_DELAY ); + while (1) { + xSemaphoreTake(xSemaphore, (TickType_t) portMAX_DELAY); SERIAL_PORT.println("LED OFF!"); digitalWrite(LED_BUILTIN, LOW); delay(BLINK_OFF_TIME); - xSemaphoreGive( xSemaphore ); + xSemaphoreGive(xSemaphore); delay(1); } } diff --git a/libraries/rp2040/examples/Stress-FreeRTOS/Stress-FreeRTOS.ino b/libraries/rp2040/examples/Stress-FreeRTOS/Stress-FreeRTOS.ino index 6c9414bc2..9e307a7e8 100644 --- a/libraries/rp2040/examples/Stress-FreeRTOS/Stress-FreeRTOS.ino +++ b/libraries/rp2040/examples/Stress-FreeRTOS/Stress-FreeRTOS.ino @@ -56,8 +56,7 @@ void loop5(void *pvPramaters); void loop6(void *pvPramaters); void loop7(void *pvPramaters); -void setup() -{ +void setup() { pinMode(LED_BUILTIN, OUTPUT); xSemaphoreMalloc = xSemaphoreCreateMutex(); @@ -79,24 +78,22 @@ void setup() } static int _loop[8]; -void loop() -{ - while (1) - { +void loop() { + while (1) { _loop[0]++; digitalWrite(LED_BUILTIN, HIGH); delay(500); digitalWrite(LED_BUILTIN, LOW); delay(500); - for (int i=0; i<8; i++) Serial.printf("%d ", _loop[i]); + for (int i = 0; i < 8; i++) { + Serial.printf("%d ", _loop[i]); + } Serial.println(""); } } -void loop1() -{ - while (1) - { +void loop1() { + while (1) { _loop[1]++; char *tmp; @@ -106,8 +103,7 @@ void loop1() strcpy(tmp, "foo"); - if (tryRealloc) - { + if (tryRealloc) { semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); tmp = (char *)realloc(tmp, 20 * sizeof(char)); semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); @@ -122,11 +118,9 @@ void loop1() } } -void loop2(void *pvPramaters) -{ +void loop2(void *pvPramaters) { (void) pvPramaters; - while (1) - { + while (1) { _loop[2]++; char *tmp; @@ -136,8 +130,7 @@ void loop2(void *pvPramaters) strcpy(tmp, "bar"); - if (tryRealloc) - { + if (tryRealloc) { semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); tmp = (char *)realloc(tmp, 20 * sizeof(char)); semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); @@ -152,11 +145,9 @@ void loop2(void *pvPramaters) } } -void loop3(void *pvPramaters) -{ +void loop3(void *pvPramaters) { (void) pvPramaters; - while (1) - { + while (1) { _loop[3]++; char *tmp; @@ -166,8 +157,7 @@ void loop3(void *pvPramaters) strcpy(tmp, "yeah"); - if (tryRealloc) - { + if (tryRealloc) { semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); tmp = (char *)realloc(tmp, 20 * sizeof(char)); semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); @@ -182,11 +172,9 @@ void loop3(void *pvPramaters) } } -void loop4(void *pvPramaters) -{ +void loop4(void *pvPramaters) { (void) pvPramaters; - while (1) - { + while (1) { _loop[4]++; char *tmp; @@ -196,8 +184,7 @@ void loop4(void *pvPramaters) strcpy(tmp, "baz"); - if (tryRealloc) - { + if (tryRealloc) { semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); tmp = (char *)realloc(tmp, 20 * sizeof(char)); semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); @@ -212,11 +199,9 @@ void loop4(void *pvPramaters) } } -void loop5(void *pvPramaters) -{ +void loop5(void *pvPramaters) { (void) pvPramaters; - while (1) - { + while (1) { _loop[5]++; char *tmp; @@ -226,8 +211,7 @@ void loop5(void *pvPramaters) strcpy(tmp, "asd"); - if (tryRealloc) - { + if (tryRealloc) { semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); tmp = (char *)realloc(tmp, 20 * sizeof(char)); semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); @@ -242,11 +226,9 @@ void loop5(void *pvPramaters) } } -void loop6(void *pvPramaters) -{ +void loop6(void *pvPramaters) { (void) pvPramaters; - while (1) - { + while (1) { _loop[6]++; char *tmp; @@ -256,8 +238,7 @@ void loop6(void *pvPramaters) strcpy(tmp, "lol"); - if (tryRealloc) - { + if (tryRealloc) { semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); tmp = (char *)realloc(tmp, 20 * sizeof(char)); semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); @@ -272,11 +253,9 @@ void loop6(void *pvPramaters) } } -void loop7(void *pvPramaters) -{ +void loop7(void *pvPramaters) { (void) pvPramaters; - while (1) - { + while (1) { _loop[7]++; char *tmp; @@ -286,8 +265,7 @@ void loop7(void *pvPramaters) strcpy(tmp, "yay"); - if (tryRealloc) - { + if (tryRealloc) { semphrTakeConditional(useMutexOnRealloc, xSemaphoreRealloc); tmp = (char *)realloc(tmp, 20 * sizeof(char)); semphrGiveConditional(useMutexOnRealloc, xSemaphoreRealloc); @@ -302,18 +280,14 @@ void loop7(void *pvPramaters) } } -void semphrTakeConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore) -{ - if (useMutexOn) - { +void semphrTakeConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore) { + if (useMutexOn) { xSemaphoreTake(xSemaphore, TickType_t(portMAX_DELAY)); } } -void semphrGiveConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore) -{ - if (useMutexOn) - { +void semphrGiveConditional(bool useMutexOn, SemaphoreHandle_t xSemaphore) { + if (useMutexOn) { xSemaphoreGive(xSemaphore); } } From c447d4fd5f14090e08740ba02fd99de9b032055f Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 18 Aug 2025 11:42:26 -0700 Subject: [PATCH 18/36] WiFiClient/WiFiUDP list needs mutex protection We track a list of all connections to allow the WiFi.stopAll() call (used for updates). This linked list needs to be protected from multiple cores updating it in parallel under FreeRTOS. Add a mutex around the ops. --- libraries/WiFi/src/WiFiClient.cpp | 7 +++++- libraries/WiFi/src/WiFiUdp.cpp | 7 ++++++ libraries/WiFi/src/include/slist.h | 36 ++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/libraries/WiFi/src/WiFiClient.cpp b/libraries/WiFi/src/WiFiClient.cpp index ebb58793c..795ef9af6 100644 --- a/libraries/WiFi/src/WiFiClient.cpp +++ b/libraries/WiFi/src/WiFiClient.cpp @@ -57,7 +57,12 @@ bool WiFiClient::getDefaultSync() { template<> WiFiClient* SList::_s_first = 0; - +#ifdef __FREERTOS +template<> +SemaphoreHandle_t SList::_s_first_lock = 0; +template<> +bool SList::_s_first_lock_created = false; +#endif WiFiClient::WiFiClient() : _client(0), _owned(0) { diff --git a/libraries/WiFi/src/WiFiUdp.cpp b/libraries/WiFi/src/WiFiUdp.cpp index 72f6b74f8..8d8aa19b7 100644 --- a/libraries/WiFi/src/WiFiUdp.cpp +++ b/libraries/WiFi/src/WiFiUdp.cpp @@ -36,6 +36,13 @@ template<> WiFiUDP* SList::_s_first = 0; +#ifdef __FREERTOS +template<> +SemaphoreHandle_t SList::_s_first_lock = 0; +template<> +bool SList::_s_first_lock_created = false; +#endif + /* Constructor */ WiFiUDP::WiFiUDP() : _ctx(0), _multicast(false), _dirty(false) { diff --git a/libraries/WiFi/src/include/slist.h b/libraries/WiFi/src/include/slist.h index ba49ec52f..c38cfa837 100644 --- a/libraries/WiFi/src/include/slist.h +++ b/libraries/WiFi/src/include/slist.h @@ -1,6 +1,11 @@ #ifndef SLIST_H #define SLIST_H +#ifdef __FREERTOS +#include "FreeRTOS.h" +#include "semphr.h" +#endif + template class SList { public: @@ -9,15 +14,36 @@ class SList { protected: static void _add(T* self) { +#ifdef __FREERTOS + if (!_s_first_lock_created) { + _s_first_lock_created = true; + _s_first_lock = xSemaphoreCreateMutex(); + } + xSemaphoreTake(_s_first_lock, portMAX_DELAY); +#endif T* tmp = _s_first; _s_first = self; self->_next = tmp; +#ifdef __FREERTOS + xSemaphoreGive(_s_first_lock); +#endif } static void _remove(T* self) { +#ifdef __FREERTOS + if (!_s_first_lock_created) { + _s_first_lock_created = true; + _s_first_lock = xSemaphoreCreateMutex(); + } + xSemaphoreTake(_s_first_lock, portMAX_DELAY); +#endif + if (_s_first == self) { _s_first = self->_next; self->_next = 0; +#ifdef __FREERTOS + xSemaphoreGive(_s_first_lock); +#endif return; } @@ -25,11 +51,21 @@ class SList { if (prev->_next == self) { prev->_next = self->_next; self->_next = 0; +#ifdef __FREERTOS + xSemaphoreGive(_s_first_lock); +#endif return; } } +#ifdef __FREERTOS + xSemaphoreGive(_s_first_lock); +#endif } +#ifdef __FREERTOS + static SemaphoreHandle_t _s_first_lock; + static bool _s_first_lock_created; +#endif static T* _s_first; T* _next; }; From c54ec2bb9b3974edcfee86c748346043d6a38fab Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 18 Aug 2025 13:57:51 -0700 Subject: [PATCH 19/36] Restore bare-metal compilation Simple CYW43 WiFiClient test runs --- cores/rp2040/freertos/heap_3a.c | 4 +- libraries/lwIP_Ethernet/src/LwipEthernet.cpp | 101 +++++++++---------- libraries/lwIP_Ethernet/src/LwipIntfDev.h | 26 ++++- 3 files changed, 72 insertions(+), 59 deletions(-) diff --git a/cores/rp2040/freertos/heap_3a.c b/cores/rp2040/freertos/heap_3a.c index cc57d45d3..4a0c49a25 100644 --- a/cores/rp2040/freertos/heap_3a.c +++ b/cores/rp2040/freertos/heap_3a.c @@ -1,4 +1,5 @@ -// Hacked to remove the vTaskSuspendAll from heap_3.c +#ifdef __FREERTOS +// Hacked to remove the vTaskSuspendAll from heap_3.c. We handle that in malloc wrappers /* FreeRTOS Kernel @@ -101,3 +102,4 @@ void vPortHeapResetState(void) { /* No state needs to be re-initialised in heap_3. */ } /*-----------------------------------------------------------*/ +#endif diff --git a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp index 05cc803ce..761a39b63 100644 --- a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp +++ b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -30,19 +31,19 @@ #include #include "FreeRTOS.h" #include "task.h" -static async_context_freertos_t lwip_ethernet_async_context; -static StackType_t lwip_ethernet_async_context_freertos_task_stack[CYW43_TASK_STACK_SIZE]; - -static async_context_t *lwip_ethernet_init_default_async_context(void) { - async_context_freertos_config_t config = async_context_freertos_default_config(); -#if configSUPPORT_STATIC_ALLOCATION && !CYW43_NO_DEFAULT_TASK_STACK - config.task_stack = lwip_ethernet_async_context_freertos_task_stack; -#endif - if (async_context_freertos_init(&lwip_ethernet_async_context, &config)) { - return &lwip_ethernet_async_context.core; - } - return NULL; -} +//static async_context_freertos_t lwip_ethernet_async_context; +//static StackType_t lwip_ethernet_async_context_freertos_task_stack[CYW43_TASK_STACK_SIZE]; + +//static async_context_t *lwip_ethernet_init_default_async_context(void) { +// async_context_freertos_config_t config = async_context_freertos_default_config(); +//#if configSUPPORT_STATIC_ALLOCATION && !CYW43_NO_DEFAULT_TASK_STACK +// config.task_stack = lwip_ethernet_async_context_freertos_task_stack; +//#endif +// if (async_context_freertos_init(&lwip_ethernet_async_context, &config)) { +// return &lwip_ethernet_async_context.core; +// } +// return NULL; +//} #else #include @@ -72,24 +73,27 @@ static async_context_t *_context = nullptr; static std::map> _handlePacketList; void ethernet_arch_lwip_begin() { - //#if defined(PICO_CYW43_SUPPORTED) - // if (rp2040.isPicoW()) { - // cyw43_arch_lwip_begin(); - // return; - // } - //#endif - // __startEthernetContext(); - // async_context_acquire_lock_blocking(_context); +#ifdef __FREERTOS + panic("oops"); +#endif + #if defined(PICO_CYW43_SUPPORTED) + if (rp2040.isPicoW()) { + cyw43_arch_lwip_begin(); + return; + } + #endif + __startEthernetContext(); + async_context_acquire_lock_blocking(_context); } void ethernet_arch_lwip_end() { - //#if defined(PICO_CYW43_SUPPORTED) - // if (rp2040.isPicoW()) { - // cyw43_arch_lwip_end(); - // return; - // } - //#endif - // async_context_release_lock(_context); + #if defined(PICO_CYW43_SUPPORTED) + if (rp2040.isPicoW()) { + cyw43_arch_lwip_end(); + return; + } + #endif + async_context_release_lock(_context); } int __addEthernetPacketHandler(std::function _packetHandler) { @@ -206,19 +210,12 @@ static uint32_t _pollingPeriod = 20; // This will only be called under the protection of the async context mutex, so no re-entrancy checks needed static void ethernet_timeout_reached(__unused async_context_t *context, __unused async_at_time_worker_t *worker) { assert(worker == ðernet_timeout_worker); - printf("__ethernet_timeout_reached_calls %d\n", __ethernet_timeout_reached_calls); __ethernet_timeout_reached_calls++; ethernet_arch_lwip_gpio_mask(); // Ensure non-polled devices won't interrupt us for (auto handlePacket : _handlePacketList) { handlePacket.second(); sys_check_timeouts(); } - //#if defined(PICO_CYW43_SUPPORTED) - // if (!rp2040.isPicoW()) { - // sys_check_timeouts(); - // } - //#else - //#endif ethernet_arch_lwip_gpio_unmask(); } @@ -231,6 +228,7 @@ static void update_next_timeout(async_context_t *context, async_when_pending_wor // We have a background pump which calls sys_check_timeouts on a periodic basis // and polls all Ethernet interfaces +#ifdef __FREERTOS static TaskHandle_t _ethernetTask;; static void stage2(void *cbData) { @@ -246,7 +244,6 @@ static void stage2(void *cbData) { sys_check_timeouts(); } -#include static void ethernetTask(void *param) { (void) param; while (true) { @@ -256,34 +253,26 @@ static void ethernetTask(void *param) { } vTaskDelay(sleep_ms / portTICK_PERIOD_MS); lwip_callback(stage2, nullptr); -#if 0 - // Scan the installed Ethernet drivers - for (auto handlePacket : _handlePacketList) { - // Note that each NIC needs to use its own mutex to ensure LWIP isn't doing something with it at the time we want to poll - handlePacket.second(); - } - // Do LWIP stuff as needed - sys_check_timeouts(); -#endif } } +#endif void __startEthernetContext() { if (__ethernetContextInitted) { return; } - xTaskCreate(ethernetTask, "Ethernet", 256, nullptr, 1, &_ethernetTask); - // vTaskCoreAffinitySet(_ethernetTask, 1 << 0); -#if 0 - //#if defined(PICO_CYW43_SUPPORTED) - // if (rp2040.isPicoW()) { - // _context = cyw43_arch_async_context(); - // } else { - // _context = lwip_ethernet_init_default_async_context(); - // } - //#else +#ifdef __FREERTOS + xTaskCreate(ethernetTask, "EthPoll", 256, nullptr, 1, &_ethernetTask); +#else + #if defined(PICO_CYW43_SUPPORTED) + if (rp2040.isPicoW()) { + _context = cyw43_arch_async_context(); + } else { + _context = lwip_ethernet_init_default_async_context(); + } + #else _context = lwip_ethernet_init_default_async_context(); - //#endif + #endif ethernet_timeout_worker.do_work = ethernet_timeout_reached; always_pending_update_timeout_worker.work_pending = true; always_pending_update_timeout_worker.do_work = update_next_timeout; diff --git a/libraries/lwIP_Ethernet/src/LwipIntfDev.h b/libraries/lwIP_Ethernet/src/LwipIntfDev.h index 9cc39bf2e..860d00e61 100644 --- a/libraries/lwIP_Ethernet/src/LwipIntfDev.h +++ b/libraries/lwIP_Ethernet/src/LwipIntfDev.h @@ -81,7 +81,9 @@ class LwipIntfDev: public LwipIntf, public RawDev { LwipIntfDev(int8_t cs = SS, SPIClass& spi = SPI, int8_t intr = -1) : RawDev(cs, spi, intr), _spiUnit(spi), _mtu(DEFAULT_MTU), _intrPin(intr), _started(false), _default(false) { memset(&_netif, 0, sizeof(_netif)); +#ifdef __FREERTOS _hwMutex = xSemaphoreCreateMutex(); +#endif } //The argument order for ESP is not the same as for Arduino. However, there is compatibility code under the hood @@ -188,7 +190,9 @@ class LwipIntfDev: public LwipIntf, public RawDev { public: // called on a regular basis or on interrupt err_t handlePackets(); +#ifdef __FREERTOS SemaphoreHandle_t _hwMutex; +#endif uint8_t _irqBuffer[LWIP_CALLBACK_BUFFER_SIZE]; protected: // members @@ -505,10 +509,21 @@ EthernetLinkStatus LwipIntfDev::linkStatus() { template err_t LwipIntfDev::linkoutput_s(netif* netif, struct pbuf* pbuf) { LwipIntfDev* lid = (LwipIntfDev*)netif->state; - // ethernet_arch_lwip_begin(); + +#ifdef __FREERTOS xSemaphoreTake(lid->_hwMutex, portMAX_DELAY); +#else + ethernet_arch_lwip_begin(); +#endif + uint16_t len = lid->sendFrame((const uint8_t*)pbuf->payload, pbuf->len); + +#ifdef __FREERTOS xSemaphoreGive(lid->_hwMutex); +#else + ethernet_arch_lwip_end(); +#endif + lid->_packetsSent++; #if PHY_HAS_CAPTURE if (phy_capture) { @@ -516,7 +531,6 @@ err_t LwipIntfDev::linkoutput_s(netif* netif, struct pbuf* pbuf) { /*success*/ len == pbuf->len); } #endif - // ethernet_arch_lwip_end(); return len == pbuf->len ? ERR_OK : ERR_MEM; } @@ -596,10 +610,14 @@ err_t LwipIntfDev::handlePackets() { return ERR_OK; } +#ifdef __FREERTOS xSemaphoreTake(_hwMutex, portMAX_DELAY); +#endif uint16_t tot_len = RawDev::readFrameSize(); if (!tot_len) { +#ifdef __FREERTOS xSemaphoreGive(_hwMutex); +#endif return ERR_OK; } @@ -617,12 +635,16 @@ err_t LwipIntfDev::handlePackets() { pbuf_free(pbuf); } RawDev::discardFrame(tot_len); +#ifdef __FREERTOS xSemaphoreGive(_hwMutex); +#endif return ERR_BUF; } uint16_t len = RawDev::readFrameData((uint8_t*)pbuf->payload, tot_len); +#ifdef __FREERTOS xSemaphoreGive(_hwMutex); +#endif if (len != tot_len) { // tot_len is given by readFrameSize() // and is supposed to be honoured by readFrameData() From 354ed53c3537d6d9f4ef653323dd5bfc27f576f0 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 18 Aug 2025 14:05:54 -0700 Subject: [PATCH 20/36] Add LWIP_DEBUG menu item --- boards.txt | 532 +++++++++++++++++++++++++++++++++----------- tools/makeboards.py | 2 +- 2 files changed, 400 insertions(+), 134 deletions(-) diff --git a/boards.txt b/boards.txt index f84bf0e61..85f148f52 100644 --- a/boards.txt +++ b/boards.txt @@ -210,8 +210,10 @@ rpipico.menu.dbglvl.Wire=Wire rpipico.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE rpipico.menu.dbglvl.Bluetooth=Bluetooth rpipico.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +rpipico.menu.dbglvl.LWIP=LWIP +rpipico.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 rpipico.menu.dbglvl.All=All -rpipico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +rpipico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 rpipico.menu.dbglvl.NDEBUG=NDEBUG rpipico.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG rpipico.menu.usbstack.picosdk=Pico SDK @@ -429,8 +431,10 @@ rpipicow.menu.dbglvl.Wire=Wire rpipicow.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE rpipicow.menu.dbglvl.Bluetooth=Bluetooth rpipicow.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +rpipicow.menu.dbglvl.LWIP=LWIP +rpipicow.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 rpipicow.menu.dbglvl.All=All -rpipicow.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +rpipicow.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 rpipicow.menu.dbglvl.NDEBUG=NDEBUG rpipicow.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG rpipicow.menu.usbstack.picosdk=Pico SDK @@ -798,8 +802,10 @@ rpipico2.menu.dbglvl.Wire=Wire rpipico2.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE rpipico2.menu.dbglvl.Bluetooth=Bluetooth rpipico2.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +rpipico2.menu.dbglvl.LWIP=LWIP +rpipico2.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 rpipico2.menu.dbglvl.All=All -rpipico2.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +rpipico2.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 rpipico2.menu.dbglvl.NDEBUG=NDEBUG rpipico2.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG rpipico2.menu.usbstack.picosdk=Pico SDK @@ -1040,8 +1046,10 @@ rpipico2w.menu.dbglvl.Wire=Wire rpipico2w.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE rpipico2w.menu.dbglvl.Bluetooth=Bluetooth rpipico2w.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +rpipico2w.menu.dbglvl.LWIP=LWIP +rpipico2w.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 rpipico2w.menu.dbglvl.All=All -rpipico2w.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +rpipico2w.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 rpipico2w.menu.dbglvl.NDEBUG=NDEBUG rpipico2w.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG rpipico2w.menu.usbstack.picosdk=Pico SDK @@ -1456,8 +1464,10 @@ rpipico2w.menu.uploadmethod.picoprobe_cmsis_dap.upload.tool.default=picoprobe_cm 0xcb_helios.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE 0xcb_helios.menu.dbglvl.Bluetooth=Bluetooth 0xcb_helios.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +0xcb_helios.menu.dbglvl.LWIP=LWIP +0xcb_helios.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 0xcb_helios.menu.dbglvl.All=All -0xcb_helios.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +0xcb_helios.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 0xcb_helios.menu.dbglvl.NDEBUG=NDEBUG 0xcb_helios.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG 0xcb_helios.menu.usbstack.picosdk=Pico SDK @@ -1724,8 +1734,10 @@ adafruit_feather.menu.dbglvl.Wire=Wire adafruit_feather.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_feather.menu.dbglvl.Bluetooth=Bluetooth adafruit_feather.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_feather.menu.dbglvl.LWIP=LWIP +adafruit_feather.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_feather.menu.dbglvl.All=All -adafruit_feather.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_feather.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_feather.menu.dbglvl.NDEBUG=NDEBUG adafruit_feather.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_feather.menu.usbstack.picosdk=Pico SDK @@ -1984,8 +1996,10 @@ adafruit_feather_scorpio.menu.dbglvl.Wire=Wire adafruit_feather_scorpio.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_feather_scorpio.menu.dbglvl.Bluetooth=Bluetooth adafruit_feather_scorpio.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_feather_scorpio.menu.dbglvl.LWIP=LWIP +adafruit_feather_scorpio.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_feather_scorpio.menu.dbglvl.All=All -adafruit_feather_scorpio.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_feather_scorpio.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_feather_scorpio.menu.dbglvl.NDEBUG=NDEBUG adafruit_feather_scorpio.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_feather_scorpio.menu.usbstack.picosdk=Pico SDK @@ -2248,8 +2262,10 @@ adafruit_feather_dvi.menu.dbglvl.Wire=Wire adafruit_feather_dvi.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_feather_dvi.menu.dbglvl.Bluetooth=Bluetooth adafruit_feather_dvi.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_feather_dvi.menu.dbglvl.LWIP=LWIP +adafruit_feather_dvi.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_feather_dvi.menu.dbglvl.All=All -adafruit_feather_dvi.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_feather_dvi.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_feather_dvi.menu.dbglvl.NDEBUG=NDEBUG adafruit_feather_dvi.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_feather_dvi.menu.usbstack.picosdk=Pico SDK @@ -2512,8 +2528,10 @@ adafruit_feather_adalogger.menu.dbglvl.Wire=Wire adafruit_feather_adalogger.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_feather_adalogger.menu.dbglvl.Bluetooth=Bluetooth adafruit_feather_adalogger.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_feather_adalogger.menu.dbglvl.LWIP=LWIP +adafruit_feather_adalogger.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_feather_adalogger.menu.dbglvl.All=All -adafruit_feather_adalogger.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_feather_adalogger.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_feather_adalogger.menu.dbglvl.NDEBUG=NDEBUG adafruit_feather_adalogger.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_feather_adalogger.menu.usbstack.picosdk=Pico SDK @@ -2776,8 +2794,10 @@ adafruit_feather_rfm.menu.dbglvl.Wire=Wire adafruit_feather_rfm.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_feather_rfm.menu.dbglvl.Bluetooth=Bluetooth adafruit_feather_rfm.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_feather_rfm.menu.dbglvl.LWIP=LWIP +adafruit_feather_rfm.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_feather_rfm.menu.dbglvl.All=All -adafruit_feather_rfm.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_feather_rfm.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_feather_rfm.menu.dbglvl.NDEBUG=NDEBUG adafruit_feather_rfm.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_feather_rfm.menu.usbstack.picosdk=Pico SDK @@ -3040,8 +3060,10 @@ adafruit_feather_thinkink.menu.dbglvl.Wire=Wire adafruit_feather_thinkink.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_feather_thinkink.menu.dbglvl.Bluetooth=Bluetooth adafruit_feather_thinkink.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_feather_thinkink.menu.dbglvl.LWIP=LWIP +adafruit_feather_thinkink.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_feather_thinkink.menu.dbglvl.All=All -adafruit_feather_thinkink.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_feather_thinkink.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_feather_thinkink.menu.dbglvl.NDEBUG=NDEBUG adafruit_feather_thinkink.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_feather_thinkink.menu.usbstack.picosdk=Pico SDK @@ -3304,8 +3326,10 @@ adafruit_feather_usb_host.menu.dbglvl.Wire=Wire adafruit_feather_usb_host.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_feather_usb_host.menu.dbglvl.Bluetooth=Bluetooth adafruit_feather_usb_host.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_feather_usb_host.menu.dbglvl.LWIP=LWIP +adafruit_feather_usb_host.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_feather_usb_host.menu.dbglvl.All=All -adafruit_feather_usb_host.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_feather_usb_host.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_feather_usb_host.menu.dbglvl.NDEBUG=NDEBUG adafruit_feather_usb_host.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_feather_usb_host.menu.usbstack.picosdk=Pico SDK @@ -3568,8 +3592,10 @@ adafruit_feather_can.menu.dbglvl.Wire=Wire adafruit_feather_can.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_feather_can.menu.dbglvl.Bluetooth=Bluetooth adafruit_feather_can.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_feather_can.menu.dbglvl.LWIP=LWIP +adafruit_feather_can.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_feather_can.menu.dbglvl.All=All -adafruit_feather_can.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_feather_can.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_feather_can.menu.dbglvl.NDEBUG=NDEBUG adafruit_feather_can.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_feather_can.menu.usbstack.picosdk=Pico SDK @@ -3832,8 +3858,10 @@ adafruit_feather_prop_maker.menu.dbglvl.Wire=Wire adafruit_feather_prop_maker.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_feather_prop_maker.menu.dbglvl.Bluetooth=Bluetooth adafruit_feather_prop_maker.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_feather_prop_maker.menu.dbglvl.LWIP=LWIP +adafruit_feather_prop_maker.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_feather_prop_maker.menu.dbglvl.All=All -adafruit_feather_prop_maker.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_feather_prop_maker.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_feather_prop_maker.menu.dbglvl.NDEBUG=NDEBUG adafruit_feather_prop_maker.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_feather_prop_maker.menu.usbstack.picosdk=Pico SDK @@ -4104,8 +4132,10 @@ adafruit_itsybitsy.menu.dbglvl.Wire=Wire adafruit_itsybitsy.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_itsybitsy.menu.dbglvl.Bluetooth=Bluetooth adafruit_itsybitsy.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_itsybitsy.menu.dbglvl.LWIP=LWIP +adafruit_itsybitsy.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_itsybitsy.menu.dbglvl.All=All -adafruit_itsybitsy.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_itsybitsy.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_itsybitsy.menu.dbglvl.NDEBUG=NDEBUG adafruit_itsybitsy.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_itsybitsy.menu.usbstack.picosdk=Pico SDK @@ -4424,8 +4454,10 @@ adafruit_metro.menu.dbglvl.Wire=Wire adafruit_metro.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_metro.menu.dbglvl.Bluetooth=Bluetooth adafruit_metro.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_metro.menu.dbglvl.LWIP=LWIP +adafruit_metro.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_metro.menu.dbglvl.All=All -adafruit_metro.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_metro.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_metro.menu.dbglvl.NDEBUG=NDEBUG adafruit_metro.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_metro.menu.usbstack.picosdk=Pico SDK @@ -4696,8 +4728,10 @@ adafruit_qtpy.menu.dbglvl.Wire=Wire adafruit_qtpy.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_qtpy.menu.dbglvl.Bluetooth=Bluetooth adafruit_qtpy.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_qtpy.menu.dbglvl.LWIP=LWIP +adafruit_qtpy.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_qtpy.menu.dbglvl.All=All -adafruit_qtpy.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_qtpy.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_qtpy.menu.dbglvl.NDEBUG=NDEBUG adafruit_qtpy.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_qtpy.menu.usbstack.picosdk=Pico SDK @@ -4968,8 +5002,10 @@ adafruit_stemmafriend.menu.dbglvl.Wire=Wire adafruit_stemmafriend.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_stemmafriend.menu.dbglvl.Bluetooth=Bluetooth adafruit_stemmafriend.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_stemmafriend.menu.dbglvl.LWIP=LWIP +adafruit_stemmafriend.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_stemmafriend.menu.dbglvl.All=All -adafruit_stemmafriend.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_stemmafriend.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_stemmafriend.menu.dbglvl.NDEBUG=NDEBUG adafruit_stemmafriend.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_stemmafriend.menu.usbstack.picosdk=Pico SDK @@ -5232,8 +5268,10 @@ adafruit_trinkeyrp2040qt.menu.dbglvl.Wire=Wire adafruit_trinkeyrp2040qt.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_trinkeyrp2040qt.menu.dbglvl.Bluetooth=Bluetooth adafruit_trinkeyrp2040qt.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_trinkeyrp2040qt.menu.dbglvl.LWIP=LWIP +adafruit_trinkeyrp2040qt.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_trinkeyrp2040qt.menu.dbglvl.All=All -adafruit_trinkeyrp2040qt.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_trinkeyrp2040qt.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_trinkeyrp2040qt.menu.dbglvl.NDEBUG=NDEBUG adafruit_trinkeyrp2040qt.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_trinkeyrp2040qt.menu.usbstack.picosdk=Pico SDK @@ -5496,8 +5534,10 @@ adafruit_macropad2040.menu.dbglvl.Wire=Wire adafruit_macropad2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_macropad2040.menu.dbglvl.Bluetooth=Bluetooth adafruit_macropad2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_macropad2040.menu.dbglvl.LWIP=LWIP +adafruit_macropad2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_macropad2040.menu.dbglvl.All=All -adafruit_macropad2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_macropad2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_macropad2040.menu.dbglvl.NDEBUG=NDEBUG adafruit_macropad2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_macropad2040.menu.usbstack.picosdk=Pico SDK @@ -5760,8 +5800,10 @@ adafruit_kb2040.menu.dbglvl.Wire=Wire adafruit_kb2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_kb2040.menu.dbglvl.Bluetooth=Bluetooth adafruit_kb2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_kb2040.menu.dbglvl.LWIP=LWIP +adafruit_kb2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_kb2040.menu.dbglvl.All=All -adafruit_kb2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_kb2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_kb2040.menu.dbglvl.NDEBUG=NDEBUG adafruit_kb2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_kb2040.menu.usbstack.picosdk=Pico SDK @@ -6033,8 +6075,10 @@ adafruit_feather_rp2350_adalogger.menu.dbglvl.Wire=Wire adafruit_feather_rp2350_adalogger.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_feather_rp2350_adalogger.menu.dbglvl.Bluetooth=Bluetooth adafruit_feather_rp2350_adalogger.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_feather_rp2350_adalogger.menu.dbglvl.LWIP=LWIP +adafruit_feather_rp2350_adalogger.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_feather_rp2350_adalogger.menu.dbglvl.All=All -adafruit_feather_rp2350_adalogger.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_feather_rp2350_adalogger.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_feather_rp2350_adalogger.menu.dbglvl.NDEBUG=NDEBUG adafruit_feather_rp2350_adalogger.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_feather_rp2350_adalogger.menu.usbstack.picosdk=Pico SDK @@ -6310,8 +6354,10 @@ adafruit_feather_rp2350_hstx.menu.dbglvl.Wire=Wire adafruit_feather_rp2350_hstx.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_feather_rp2350_hstx.menu.dbglvl.Bluetooth=Bluetooth adafruit_feather_rp2350_hstx.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_feather_rp2350_hstx.menu.dbglvl.LWIP=LWIP +adafruit_feather_rp2350_hstx.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_feather_rp2350_hstx.menu.dbglvl.All=All -adafruit_feather_rp2350_hstx.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_feather_rp2350_hstx.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_feather_rp2350_hstx.menu.dbglvl.NDEBUG=NDEBUG adafruit_feather_rp2350_hstx.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_feather_rp2350_hstx.menu.usbstack.picosdk=Pico SDK @@ -6626,8 +6672,10 @@ adafruit_floppsy.menu.dbglvl.Wire=Wire adafruit_floppsy.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_floppsy.menu.dbglvl.Bluetooth=Bluetooth adafruit_floppsy.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_floppsy.menu.dbglvl.LWIP=LWIP +adafruit_floppsy.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_floppsy.menu.dbglvl.All=All -adafruit_floppsy.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_floppsy.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_floppsy.menu.dbglvl.NDEBUG=NDEBUG adafruit_floppsy.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_floppsy.menu.usbstack.picosdk=Pico SDK @@ -6963,8 +7011,10 @@ adafruit_metro_rp2350.menu.dbglvl.Wire=Wire adafruit_metro_rp2350.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_metro_rp2350.menu.dbglvl.Bluetooth=Bluetooth adafruit_metro_rp2350.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_metro_rp2350.menu.dbglvl.LWIP=LWIP +adafruit_metro_rp2350.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_metro_rp2350.menu.dbglvl.All=All -adafruit_metro_rp2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_metro_rp2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_metro_rp2350.menu.dbglvl.NDEBUG=NDEBUG adafruit_metro_rp2350.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_metro_rp2350.menu.usbstack.picosdk=Pico SDK @@ -7288,8 +7338,10 @@ adafruit_fruitjam.menu.dbglvl.Wire=Wire adafruit_fruitjam.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE adafruit_fruitjam.menu.dbglvl.Bluetooth=Bluetooth adafruit_fruitjam.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +adafruit_fruitjam.menu.dbglvl.LWIP=LWIP +adafruit_fruitjam.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 adafruit_fruitjam.menu.dbglvl.All=All -adafruit_fruitjam.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +adafruit_fruitjam.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 adafruit_fruitjam.menu.dbglvl.NDEBUG=NDEBUG adafruit_fruitjam.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG adafruit_fruitjam.menu.usbstack.picosdk=Pico SDK @@ -8385,8 +8437,10 @@ amken_bunny.menu.dbglvl.Wire=Wire amken_bunny.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE amken_bunny.menu.dbglvl.Bluetooth=Bluetooth amken_bunny.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +amken_bunny.menu.dbglvl.LWIP=LWIP +amken_bunny.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 amken_bunny.menu.dbglvl.All=All -amken_bunny.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +amken_bunny.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 amken_bunny.menu.dbglvl.NDEBUG=NDEBUG amken_bunny.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG amken_bunny.menu.usbstack.picosdk=Pico SDK @@ -8810,8 +8864,10 @@ amken_revelop.menu.dbglvl.Wire=Wire amken_revelop.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE amken_revelop.menu.dbglvl.Bluetooth=Bluetooth amken_revelop.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +amken_revelop.menu.dbglvl.LWIP=LWIP +amken_revelop.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 amken_revelop.menu.dbglvl.All=All -amken_revelop.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +amken_revelop.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 amken_revelop.menu.dbglvl.NDEBUG=NDEBUG amken_revelop.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG amken_revelop.menu.usbstack.picosdk=Pico SDK @@ -9235,8 +9291,10 @@ amken_revelop_plus.menu.dbglvl.Wire=Wire amken_revelop_plus.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE amken_revelop_plus.menu.dbglvl.Bluetooth=Bluetooth amken_revelop_plus.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +amken_revelop_plus.menu.dbglvl.LWIP=LWIP +amken_revelop_plus.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 amken_revelop_plus.menu.dbglvl.All=All -amken_revelop_plus.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +amken_revelop_plus.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 amken_revelop_plus.menu.dbglvl.NDEBUG=NDEBUG amken_revelop_plus.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG amken_revelop_plus.menu.usbstack.picosdk=Pico SDK @@ -9548,8 +9606,10 @@ amken_revelop_es.menu.dbglvl.Wire=Wire amken_revelop_es.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE amken_revelop_es.menu.dbglvl.Bluetooth=Bluetooth amken_revelop_es.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +amken_revelop_es.menu.dbglvl.LWIP=LWIP +amken_revelop_es.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 amken_revelop_es.menu.dbglvl.All=All -amken_revelop_es.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +amken_revelop_es.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 amken_revelop_es.menu.dbglvl.NDEBUG=NDEBUG amken_revelop_es.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG amken_revelop_es.menu.usbstack.picosdk=Pico SDK @@ -9873,8 +9933,10 @@ jumperless_v1.menu.dbglvl.Wire=Wire jumperless_v1.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE jumperless_v1.menu.dbglvl.Bluetooth=Bluetooth jumperless_v1.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +jumperless_v1.menu.dbglvl.LWIP=LWIP +jumperless_v1.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 jumperless_v1.menu.dbglvl.All=All -jumperless_v1.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +jumperless_v1.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 jumperless_v1.menu.dbglvl.NDEBUG=NDEBUG jumperless_v1.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG jumperless_v1.menu.usbstack.picosdk=Pico SDK @@ -10207,8 +10269,10 @@ jumperless_v5.menu.dbglvl.Wire=Wire jumperless_v5.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE jumperless_v5.menu.dbglvl.Bluetooth=Bluetooth jumperless_v5.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +jumperless_v5.menu.dbglvl.LWIP=LWIP +jumperless_v5.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 jumperless_v5.menu.dbglvl.All=All -jumperless_v5.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +jumperless_v5.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 jumperless_v5.menu.dbglvl.NDEBUG=NDEBUG jumperless_v5.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG jumperless_v5.menu.usbstack.picosdk=Pico SDK @@ -10531,8 +10595,10 @@ arduino_nano_connect.menu.dbglvl.Wire=Wire arduino_nano_connect.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE arduino_nano_connect.menu.dbglvl.Bluetooth=Bluetooth arduino_nano_connect.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +arduino_nano_connect.menu.dbglvl.LWIP=LWIP +arduino_nano_connect.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 arduino_nano_connect.menu.dbglvl.All=All -arduino_nano_connect.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +arduino_nano_connect.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 arduino_nano_connect.menu.dbglvl.NDEBUG=NDEBUG arduino_nano_connect.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG arduino_nano_connect.menu.usbstack.picosdk=Pico SDK @@ -10773,8 +10839,10 @@ artronshop_rp2_nano.menu.dbglvl.Wire=Wire artronshop_rp2_nano.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE artronshop_rp2_nano.menu.dbglvl.Bluetooth=Bluetooth artronshop_rp2_nano.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +artronshop_rp2_nano.menu.dbglvl.LWIP=LWIP +artronshop_rp2_nano.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 artronshop_rp2_nano.menu.dbglvl.All=All -artronshop_rp2_nano.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +artronshop_rp2_nano.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 artronshop_rp2_nano.menu.dbglvl.NDEBUG=NDEBUG artronshop_rp2_nano.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG artronshop_rp2_nano.menu.usbstack.picosdk=Pico SDK @@ -10991,8 +11059,10 @@ bigtreetech_SKR_Pico.menu.dbglvl.Wire=Wire bigtreetech_SKR_Pico.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE bigtreetech_SKR_Pico.menu.dbglvl.Bluetooth=Bluetooth bigtreetech_SKR_Pico.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +bigtreetech_SKR_Pico.menu.dbglvl.LWIP=LWIP +bigtreetech_SKR_Pico.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 bigtreetech_SKR_Pico.menu.dbglvl.All=All -bigtreetech_SKR_Pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +bigtreetech_SKR_Pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 bigtreetech_SKR_Pico.menu.dbglvl.NDEBUG=NDEBUG bigtreetech_SKR_Pico.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG bigtreetech_SKR_Pico.menu.usbstack.picosdk=Pico SDK @@ -11331,8 +11401,10 @@ breadstick_raspberry.menu.dbglvl.Wire=Wire breadstick_raspberry.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE breadstick_raspberry.menu.dbglvl.Bluetooth=Bluetooth breadstick_raspberry.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +breadstick_raspberry.menu.dbglvl.LWIP=LWIP +breadstick_raspberry.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 breadstick_raspberry.menu.dbglvl.All=All -breadstick_raspberry.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +breadstick_raspberry.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 breadstick_raspberry.menu.dbglvl.NDEBUG=NDEBUG breadstick_raspberry.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG breadstick_raspberry.menu.usbstack.picosdk=Pico SDK @@ -11616,8 +11688,10 @@ bridgetek_idm2040_7a.menu.dbglvl.Wire=Wire bridgetek_idm2040_7a.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE bridgetek_idm2040_7a.menu.dbglvl.Bluetooth=Bluetooth bridgetek_idm2040_7a.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +bridgetek_idm2040_7a.menu.dbglvl.LWIP=LWIP +bridgetek_idm2040_7a.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 bridgetek_idm2040_7a.menu.dbglvl.All=All -bridgetek_idm2040_7a.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +bridgetek_idm2040_7a.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 bridgetek_idm2040_7a.menu.dbglvl.NDEBUG=NDEBUG bridgetek_idm2040_7a.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG bridgetek_idm2040_7a.menu.usbstack.picosdk=Pico SDK @@ -11877,8 +11951,10 @@ bridgetek_idm2040_43a.menu.dbglvl.Wire=Wire bridgetek_idm2040_43a.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE bridgetek_idm2040_43a.menu.dbglvl.Bluetooth=Bluetooth bridgetek_idm2040_43a.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +bridgetek_idm2040_43a.menu.dbglvl.LWIP=LWIP +bridgetek_idm2040_43a.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 bridgetek_idm2040_43a.menu.dbglvl.All=All -bridgetek_idm2040_43a.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +bridgetek_idm2040_43a.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 bridgetek_idm2040_43a.menu.dbglvl.NDEBUG=NDEBUG bridgetek_idm2040_43a.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG bridgetek_idm2040_43a.menu.usbstack.picosdk=Pico SDK @@ -12128,8 +12204,10 @@ cytron_iriv_io_controller.menu.dbglvl.Wire=Wire cytron_iriv_io_controller.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE cytron_iriv_io_controller.menu.dbglvl.Bluetooth=Bluetooth cytron_iriv_io_controller.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +cytron_iriv_io_controller.menu.dbglvl.LWIP=LWIP +cytron_iriv_io_controller.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 cytron_iriv_io_controller.menu.dbglvl.All=All -cytron_iriv_io_controller.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +cytron_iriv_io_controller.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 cytron_iriv_io_controller.menu.dbglvl.NDEBUG=NDEBUG cytron_iriv_io_controller.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG cytron_iriv_io_controller.menu.usbstack.picosdk=Pico SDK @@ -12370,8 +12448,10 @@ cytron_maker_nano_rp2040.menu.dbglvl.Wire=Wire cytron_maker_nano_rp2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE cytron_maker_nano_rp2040.menu.dbglvl.Bluetooth=Bluetooth cytron_maker_nano_rp2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +cytron_maker_nano_rp2040.menu.dbglvl.LWIP=LWIP +cytron_maker_nano_rp2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 cytron_maker_nano_rp2040.menu.dbglvl.All=All -cytron_maker_nano_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +cytron_maker_nano_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 cytron_maker_nano_rp2040.menu.dbglvl.NDEBUG=NDEBUG cytron_maker_nano_rp2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG cytron_maker_nano_rp2040.menu.usbstack.picosdk=Pico SDK @@ -12612,8 +12692,10 @@ cytron_maker_pi_rp2040.menu.dbglvl.Wire=Wire cytron_maker_pi_rp2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE cytron_maker_pi_rp2040.menu.dbglvl.Bluetooth=Bluetooth cytron_maker_pi_rp2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +cytron_maker_pi_rp2040.menu.dbglvl.LWIP=LWIP +cytron_maker_pi_rp2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 cytron_maker_pi_rp2040.menu.dbglvl.All=All -cytron_maker_pi_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +cytron_maker_pi_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 cytron_maker_pi_rp2040.menu.dbglvl.NDEBUG=NDEBUG cytron_maker_pi_rp2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG cytron_maker_pi_rp2040.menu.usbstack.picosdk=Pico SDK @@ -12854,8 +12936,10 @@ cytron_maker_uno_rp2040.menu.dbglvl.Wire=Wire cytron_maker_uno_rp2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE cytron_maker_uno_rp2040.menu.dbglvl.Bluetooth=Bluetooth cytron_maker_uno_rp2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +cytron_maker_uno_rp2040.menu.dbglvl.LWIP=LWIP +cytron_maker_uno_rp2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 cytron_maker_uno_rp2040.menu.dbglvl.All=All -cytron_maker_uno_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +cytron_maker_uno_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 cytron_maker_uno_rp2040.menu.dbglvl.NDEBUG=NDEBUG cytron_maker_uno_rp2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG cytron_maker_uno_rp2040.menu.usbstack.picosdk=Pico SDK @@ -13105,8 +13189,10 @@ cytron_motion_2350_pro.menu.dbglvl.Wire=Wire cytron_motion_2350_pro.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE cytron_motion_2350_pro.menu.dbglvl.Bluetooth=Bluetooth cytron_motion_2350_pro.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +cytron_motion_2350_pro.menu.dbglvl.LWIP=LWIP +cytron_motion_2350_pro.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 cytron_motion_2350_pro.menu.dbglvl.All=All -cytron_motion_2350_pro.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +cytron_motion_2350_pro.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 cytron_motion_2350_pro.menu.dbglvl.NDEBUG=NDEBUG cytron_motion_2350_pro.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG cytron_motion_2350_pro.menu.usbstack.picosdk=Pico SDK @@ -13347,8 +13433,10 @@ datanoisetv_picoadk.menu.dbglvl.Wire=Wire datanoisetv_picoadk.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE datanoisetv_picoadk.menu.dbglvl.Bluetooth=Bluetooth datanoisetv_picoadk.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +datanoisetv_picoadk.menu.dbglvl.LWIP=LWIP +datanoisetv_picoadk.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 datanoisetv_picoadk.menu.dbglvl.All=All -datanoisetv_picoadk.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +datanoisetv_picoadk.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 datanoisetv_picoadk.menu.dbglvl.NDEBUG=NDEBUG datanoisetv_picoadk.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG datanoisetv_picoadk.menu.usbstack.picosdk=Pico SDK @@ -13624,8 +13712,10 @@ datanoisetv_picoadk_v2.menu.dbglvl.Wire=Wire datanoisetv_picoadk_v2.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE datanoisetv_picoadk_v2.menu.dbglvl.Bluetooth=Bluetooth datanoisetv_picoadk_v2.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +datanoisetv_picoadk_v2.menu.dbglvl.LWIP=LWIP +datanoisetv_picoadk_v2.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 datanoisetv_picoadk_v2.menu.dbglvl.All=All -datanoisetv_picoadk_v2.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +datanoisetv_picoadk_v2.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 datanoisetv_picoadk_v2.menu.dbglvl.NDEBUG=NDEBUG datanoisetv_picoadk_v2.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG datanoisetv_picoadk_v2.menu.usbstack.picosdk=Pico SDK @@ -13940,8 +14030,10 @@ degz_suibo.menu.dbglvl.Wire=Wire degz_suibo.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE degz_suibo.menu.dbglvl.Bluetooth=Bluetooth degz_suibo.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +degz_suibo.menu.dbglvl.LWIP=LWIP +degz_suibo.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 degz_suibo.menu.dbglvl.All=All -degz_suibo.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +degz_suibo.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 degz_suibo.menu.dbglvl.NDEBUG=NDEBUG degz_suibo.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG degz_suibo.menu.usbstack.picosdk=Pico SDK @@ -14196,8 +14288,10 @@ flyboard2040_core.menu.dbglvl.Wire=Wire flyboard2040_core.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE flyboard2040_core.menu.dbglvl.Bluetooth=Bluetooth flyboard2040_core.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +flyboard2040_core.menu.dbglvl.LWIP=LWIP +flyboard2040_core.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 flyboard2040_core.menu.dbglvl.All=All -flyboard2040_core.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +flyboard2040_core.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 flyboard2040_core.menu.dbglvl.NDEBUG=NDEBUG flyboard2040_core.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG flyboard2040_core.menu.usbstack.picosdk=Pico SDK @@ -14422,8 +14516,10 @@ dfrobot_beetle_rp2040.menu.dbglvl.Wire=Wire dfrobot_beetle_rp2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE dfrobot_beetle_rp2040.menu.dbglvl.Bluetooth=Bluetooth dfrobot_beetle_rp2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +dfrobot_beetle_rp2040.menu.dbglvl.LWIP=LWIP +dfrobot_beetle_rp2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 dfrobot_beetle_rp2040.menu.dbglvl.All=All -dfrobot_beetle_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +dfrobot_beetle_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 dfrobot_beetle_rp2040.menu.dbglvl.NDEBUG=NDEBUG dfrobot_beetle_rp2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG dfrobot_beetle_rp2040.menu.usbstack.picosdk=Pico SDK @@ -14678,8 +14774,10 @@ DudesCab.menu.dbglvl.Wire=Wire DudesCab.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE DudesCab.menu.dbglvl.Bluetooth=Bluetooth DudesCab.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +DudesCab.menu.dbglvl.LWIP=LWIP +DudesCab.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 DudesCab.menu.dbglvl.All=All -DudesCab.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +DudesCab.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 DudesCab.menu.dbglvl.NDEBUG=NDEBUG DudesCab.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG DudesCab.menu.usbstack.picosdk=Pico SDK @@ -14920,8 +15018,10 @@ electroniccats_huntercat_nfc.menu.dbglvl.Wire=Wire electroniccats_huntercat_nfc.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE electroniccats_huntercat_nfc.menu.dbglvl.Bluetooth=Bluetooth electroniccats_huntercat_nfc.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +electroniccats_huntercat_nfc.menu.dbglvl.LWIP=LWIP +electroniccats_huntercat_nfc.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 electroniccats_huntercat_nfc.menu.dbglvl.All=All -electroniccats_huntercat_nfc.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +electroniccats_huntercat_nfc.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 electroniccats_huntercat_nfc.menu.dbglvl.NDEBUG=NDEBUG electroniccats_huntercat_nfc.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG electroniccats_huntercat_nfc.menu.usbstack.picosdk=Pico SDK @@ -15236,8 +15336,10 @@ evn_alpha.menu.dbglvl.Wire=Wire evn_alpha.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE evn_alpha.menu.dbglvl.Bluetooth=Bluetooth evn_alpha.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +evn_alpha.menu.dbglvl.LWIP=LWIP +evn_alpha.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 evn_alpha.menu.dbglvl.All=All -evn_alpha.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +evn_alpha.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 evn_alpha.menu.dbglvl.NDEBUG=NDEBUG evn_alpha.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG evn_alpha.menu.usbstack.picosdk=Pico SDK @@ -15454,8 +15556,10 @@ extelec_rc2040.menu.dbglvl.Wire=Wire extelec_rc2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE extelec_rc2040.menu.dbglvl.Bluetooth=Bluetooth extelec_rc2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +extelec_rc2040.menu.dbglvl.LWIP=LWIP +extelec_rc2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 extelec_rc2040.menu.dbglvl.All=All -extelec_rc2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +extelec_rc2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 extelec_rc2040.menu.dbglvl.NDEBUG=NDEBUG extelec_rc2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG extelec_rc2040.menu.usbstack.picosdk=Pico SDK @@ -15738,8 +15842,10 @@ groundstudio_marble_pico.menu.dbglvl.Wire=Wire groundstudio_marble_pico.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE groundstudio_marble_pico.menu.dbglvl.Bluetooth=Bluetooth groundstudio_marble_pico.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +groundstudio_marble_pico.menu.dbglvl.LWIP=LWIP +groundstudio_marble_pico.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 groundstudio_marble_pico.menu.dbglvl.All=All -groundstudio_marble_pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +groundstudio_marble_pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 groundstudio_marble_pico.menu.dbglvl.NDEBUG=NDEBUG groundstudio_marble_pico.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG groundstudio_marble_pico.menu.usbstack.picosdk=Pico SDK @@ -16022,8 +16128,10 @@ challenger_2040_lte.menu.dbglvl.Wire=Wire challenger_2040_lte.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE challenger_2040_lte.menu.dbglvl.Bluetooth=Bluetooth challenger_2040_lte.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +challenger_2040_lte.menu.dbglvl.LWIP=LWIP +challenger_2040_lte.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 challenger_2040_lte.menu.dbglvl.All=All -challenger_2040_lte.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +challenger_2040_lte.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 challenger_2040_lte.menu.dbglvl.NDEBUG=NDEBUG challenger_2040_lte.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG challenger_2040_lte.menu.usbstack.picosdk=Pico SDK @@ -16306,8 +16414,10 @@ challenger_2040_lora.menu.dbglvl.Wire=Wire challenger_2040_lora.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE challenger_2040_lora.menu.dbglvl.Bluetooth=Bluetooth challenger_2040_lora.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +challenger_2040_lora.menu.dbglvl.LWIP=LWIP +challenger_2040_lora.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 challenger_2040_lora.menu.dbglvl.All=All -challenger_2040_lora.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +challenger_2040_lora.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 challenger_2040_lora.menu.dbglvl.NDEBUG=NDEBUG challenger_2040_lora.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG challenger_2040_lora.menu.usbstack.picosdk=Pico SDK @@ -16590,8 +16700,10 @@ challenger_2040_subghz.menu.dbglvl.Wire=Wire challenger_2040_subghz.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE challenger_2040_subghz.menu.dbglvl.Bluetooth=Bluetooth challenger_2040_subghz.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +challenger_2040_subghz.menu.dbglvl.LWIP=LWIP +challenger_2040_subghz.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 challenger_2040_subghz.menu.dbglvl.All=All -challenger_2040_subghz.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +challenger_2040_subghz.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 challenger_2040_subghz.menu.dbglvl.NDEBUG=NDEBUG challenger_2040_subghz.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG challenger_2040_subghz.menu.usbstack.picosdk=Pico SDK @@ -16875,8 +16987,10 @@ challenger_2040_wifi.menu.dbglvl.Wire=Wire challenger_2040_wifi.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE challenger_2040_wifi.menu.dbglvl.Bluetooth=Bluetooth challenger_2040_wifi.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +challenger_2040_wifi.menu.dbglvl.LWIP=LWIP +challenger_2040_wifi.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 challenger_2040_wifi.menu.dbglvl.All=All -challenger_2040_wifi.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +challenger_2040_wifi.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 challenger_2040_wifi.menu.dbglvl.NDEBUG=NDEBUG challenger_2040_wifi.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG challenger_2040_wifi.menu.usbstack.picosdk=Pico SDK @@ -17260,8 +17374,10 @@ challenger_2040_wifi_ble.menu.dbglvl.Wire=Wire challenger_2040_wifi_ble.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE challenger_2040_wifi_ble.menu.dbglvl.Bluetooth=Bluetooth challenger_2040_wifi_ble.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +challenger_2040_wifi_ble.menu.dbglvl.LWIP=LWIP +challenger_2040_wifi_ble.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 challenger_2040_wifi_ble.menu.dbglvl.All=All -challenger_2040_wifi_ble.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +challenger_2040_wifi_ble.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 challenger_2040_wifi_ble.menu.dbglvl.NDEBUG=NDEBUG challenger_2040_wifi_ble.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG challenger_2040_wifi_ble.menu.usbstack.picosdk=Pico SDK @@ -17545,8 +17661,10 @@ challenger_2040_wifi6_ble.menu.dbglvl.Wire=Wire challenger_2040_wifi6_ble.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE challenger_2040_wifi6_ble.menu.dbglvl.Bluetooth=Bluetooth challenger_2040_wifi6_ble.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +challenger_2040_wifi6_ble.menu.dbglvl.LWIP=LWIP +challenger_2040_wifi6_ble.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 challenger_2040_wifi6_ble.menu.dbglvl.All=All -challenger_2040_wifi6_ble.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +challenger_2040_wifi6_ble.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 challenger_2040_wifi6_ble.menu.dbglvl.NDEBUG=NDEBUG challenger_2040_wifi6_ble.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG challenger_2040_wifi6_ble.menu.usbstack.picosdk=Pico SDK @@ -17830,8 +17948,10 @@ challenger_nb_2040_wifi.menu.dbglvl.Wire=Wire challenger_nb_2040_wifi.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE challenger_nb_2040_wifi.menu.dbglvl.Bluetooth=Bluetooth challenger_nb_2040_wifi.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +challenger_nb_2040_wifi.menu.dbglvl.LWIP=LWIP +challenger_nb_2040_wifi.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 challenger_nb_2040_wifi.menu.dbglvl.All=All -challenger_nb_2040_wifi.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +challenger_nb_2040_wifi.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 challenger_nb_2040_wifi.menu.dbglvl.NDEBUG=NDEBUG challenger_nb_2040_wifi.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG challenger_nb_2040_wifi.menu.usbstack.picosdk=Pico SDK @@ -18114,8 +18234,10 @@ challenger_2040_sdrtc.menu.dbglvl.Wire=Wire challenger_2040_sdrtc.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE challenger_2040_sdrtc.menu.dbglvl.Bluetooth=Bluetooth challenger_2040_sdrtc.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +challenger_2040_sdrtc.menu.dbglvl.LWIP=LWIP +challenger_2040_sdrtc.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 challenger_2040_sdrtc.menu.dbglvl.All=All -challenger_2040_sdrtc.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +challenger_2040_sdrtc.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 challenger_2040_sdrtc.menu.dbglvl.NDEBUG=NDEBUG challenger_2040_sdrtc.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG challenger_2040_sdrtc.menu.usbstack.picosdk=Pico SDK @@ -18398,8 +18520,10 @@ challenger_2040_nfc.menu.dbglvl.Wire=Wire challenger_2040_nfc.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE challenger_2040_nfc.menu.dbglvl.Bluetooth=Bluetooth challenger_2040_nfc.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +challenger_2040_nfc.menu.dbglvl.LWIP=LWIP +challenger_2040_nfc.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 challenger_2040_nfc.menu.dbglvl.All=All -challenger_2040_nfc.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +challenger_2040_nfc.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 challenger_2040_nfc.menu.dbglvl.NDEBUG=NDEBUG challenger_2040_nfc.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG challenger_2040_nfc.menu.usbstack.picosdk=Pico SDK @@ -18682,8 +18806,10 @@ challenger_2040_uwb.menu.dbglvl.Wire=Wire challenger_2040_uwb.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE challenger_2040_uwb.menu.dbglvl.Bluetooth=Bluetooth challenger_2040_uwb.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +challenger_2040_uwb.menu.dbglvl.LWIP=LWIP +challenger_2040_uwb.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 challenger_2040_uwb.menu.dbglvl.All=All -challenger_2040_uwb.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +challenger_2040_uwb.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 challenger_2040_uwb.menu.dbglvl.NDEBUG=NDEBUG challenger_2040_uwb.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG challenger_2040_uwb.menu.usbstack.picosdk=Pico SDK @@ -18967,8 +19093,10 @@ connectivity_2040_lte_wifi_ble.menu.dbglvl.Wire=Wire connectivity_2040_lte_wifi_ble.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE connectivity_2040_lte_wifi_ble.menu.dbglvl.Bluetooth=Bluetooth connectivity_2040_lte_wifi_ble.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +connectivity_2040_lte_wifi_ble.menu.dbglvl.LWIP=LWIP +connectivity_2040_lte_wifi_ble.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 connectivity_2040_lte_wifi_ble.menu.dbglvl.All=All -connectivity_2040_lte_wifi_ble.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +connectivity_2040_lte_wifi_ble.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 connectivity_2040_lte_wifi_ble.menu.dbglvl.NDEBUG=NDEBUG connectivity_2040_lte_wifi_ble.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG connectivity_2040_lte_wifi_ble.menu.usbstack.picosdk=Pico SDK @@ -19252,8 +19380,10 @@ ilabs_rpico32.menu.dbglvl.Wire=Wire ilabs_rpico32.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE ilabs_rpico32.menu.dbglvl.Bluetooth=Bluetooth ilabs_rpico32.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +ilabs_rpico32.menu.dbglvl.LWIP=LWIP +ilabs_rpico32.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 ilabs_rpico32.menu.dbglvl.All=All -ilabs_rpico32.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +ilabs_rpico32.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 ilabs_rpico32.menu.dbglvl.NDEBUG=NDEBUG ilabs_rpico32.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG ilabs_rpico32.menu.usbstack.picosdk=Pico SDK @@ -19646,8 +19776,10 @@ challenger_2350_wifi6_ble5.menu.dbglvl.Wire=Wire challenger_2350_wifi6_ble5.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE challenger_2350_wifi6_ble5.menu.dbglvl.Bluetooth=Bluetooth challenger_2350_wifi6_ble5.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +challenger_2350_wifi6_ble5.menu.dbglvl.LWIP=LWIP +challenger_2350_wifi6_ble5.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 challenger_2350_wifi6_ble5.menu.dbglvl.All=All -challenger_2350_wifi6_ble5.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +challenger_2350_wifi6_ble5.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 challenger_2350_wifi6_ble5.menu.dbglvl.NDEBUG=NDEBUG challenger_2350_wifi6_ble5.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG challenger_2350_wifi6_ble5.menu.usbstack.picosdk=Pico SDK @@ -19939,8 +20071,10 @@ challenger_2350_bconnect.menu.dbglvl.Wire=Wire challenger_2350_bconnect.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE challenger_2350_bconnect.menu.dbglvl.Bluetooth=Bluetooth challenger_2350_bconnect.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +challenger_2350_bconnect.menu.dbglvl.LWIP=LWIP +challenger_2350_bconnect.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 challenger_2350_bconnect.menu.dbglvl.All=All -challenger_2350_bconnect.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +challenger_2350_bconnect.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 challenger_2350_bconnect.menu.dbglvl.NDEBUG=NDEBUG challenger_2350_bconnect.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG challenger_2350_bconnect.menu.usbstack.picosdk=Pico SDK @@ -20174,8 +20308,10 @@ mksthr36.menu.dbglvl.Wire=Wire mksthr36.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE mksthr36.menu.dbglvl.Bluetooth=Bluetooth mksthr36.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +mksthr36.menu.dbglvl.LWIP=LWIP +mksthr36.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 mksthr36.menu.dbglvl.All=All -mksthr36.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +mksthr36.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 mksthr36.menu.dbglvl.NDEBUG=NDEBUG mksthr36.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG mksthr36.menu.usbstack.picosdk=Pico SDK @@ -20409,8 +20545,10 @@ mksthr42.menu.dbglvl.Wire=Wire mksthr42.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE mksthr42.menu.dbglvl.Bluetooth=Bluetooth mksthr42.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +mksthr42.menu.dbglvl.LWIP=LWIP +mksthr42.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 mksthr42.menu.dbglvl.All=All -mksthr42.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +mksthr42.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 mksthr42.menu.dbglvl.NDEBUG=NDEBUG mksthr42.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG mksthr42.menu.usbstack.picosdk=Pico SDK @@ -20693,8 +20831,10 @@ melopero_cookie_rp2040.menu.dbglvl.Wire=Wire melopero_cookie_rp2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE melopero_cookie_rp2040.menu.dbglvl.Bluetooth=Bluetooth melopero_cookie_rp2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +melopero_cookie_rp2040.menu.dbglvl.LWIP=LWIP +melopero_cookie_rp2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 melopero_cookie_rp2040.menu.dbglvl.All=All -melopero_cookie_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +melopero_cookie_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 melopero_cookie_rp2040.menu.dbglvl.NDEBUG=NDEBUG melopero_cookie_rp2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG melopero_cookie_rp2040.menu.usbstack.picosdk=Pico SDK @@ -21033,8 +21173,10 @@ melopero_shake_rp2040.menu.dbglvl.Wire=Wire melopero_shake_rp2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE melopero_shake_rp2040.menu.dbglvl.Bluetooth=Bluetooth melopero_shake_rp2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +melopero_shake_rp2040.menu.dbglvl.LWIP=LWIP +melopero_shake_rp2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 melopero_shake_rp2040.menu.dbglvl.All=All -melopero_shake_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +melopero_shake_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 melopero_shake_rp2040.menu.dbglvl.NDEBUG=NDEBUG melopero_shake_rp2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG melopero_shake_rp2040.menu.usbstack.picosdk=Pico SDK @@ -21352,8 +21494,10 @@ akana_r1.menu.dbglvl.Wire=Wire akana_r1.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE akana_r1.menu.dbglvl.Bluetooth=Bluetooth akana_r1.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +akana_r1.menu.dbglvl.LWIP=LWIP +akana_r1.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 akana_r1.menu.dbglvl.All=All -akana_r1.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +akana_r1.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 akana_r1.menu.dbglvl.NDEBUG=NDEBUG akana_r1.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG akana_r1.menu.usbstack.picosdk=Pico SDK @@ -21594,8 +21738,10 @@ MyRP_bot.menu.dbglvl.Wire=Wire MyRP_bot.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE MyRP_bot.menu.dbglvl.Bluetooth=Bluetooth MyRP_bot.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +MyRP_bot.menu.dbglvl.LWIP=LWIP +MyRP_bot.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 MyRP_bot.menu.dbglvl.All=All -MyRP_bot.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +MyRP_bot.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 MyRP_bot.menu.dbglvl.NDEBUG=NDEBUG MyRP_bot.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG MyRP_bot.menu.usbstack.picosdk=Pico SDK @@ -21850,8 +21996,10 @@ nekosystems_bl2040_mini.menu.dbglvl.Wire=Wire nekosystems_bl2040_mini.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE nekosystems_bl2040_mini.menu.dbglvl.Bluetooth=Bluetooth nekosystems_bl2040_mini.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +nekosystems_bl2040_mini.menu.dbglvl.LWIP=LWIP +nekosystems_bl2040_mini.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 nekosystems_bl2040_mini.menu.dbglvl.All=All -nekosystems_bl2040_mini.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +nekosystems_bl2040_mini.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 nekosystems_bl2040_mini.menu.dbglvl.NDEBUG=NDEBUG nekosystems_bl2040_mini.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG nekosystems_bl2040_mini.menu.usbstack.picosdk=Pico SDK @@ -22106,8 +22254,10 @@ newsan_archi.menu.dbglvl.Wire=Wire newsan_archi.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE newsan_archi.menu.dbglvl.Bluetooth=Bluetooth newsan_archi.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +newsan_archi.menu.dbglvl.LWIP=LWIP +newsan_archi.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 newsan_archi.menu.dbglvl.All=All -newsan_archi.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +newsan_archi.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 newsan_archi.menu.dbglvl.NDEBUG=NDEBUG newsan_archi.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG newsan_archi.menu.usbstack.picosdk=Pico SDK @@ -22346,8 +22496,10 @@ nullbits_bit_c_pro.menu.dbglvl.Wire=Wire nullbits_bit_c_pro.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE nullbits_bit_c_pro.menu.dbglvl.Bluetooth=Bluetooth nullbits_bit_c_pro.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +nullbits_bit_c_pro.menu.dbglvl.LWIP=LWIP +nullbits_bit_c_pro.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 nullbits_bit_c_pro.menu.dbglvl.All=All -nullbits_bit_c_pro.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +nullbits_bit_c_pro.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 nullbits_bit_c_pro.menu.dbglvl.NDEBUG=NDEBUG nullbits_bit_c_pro.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG nullbits_bit_c_pro.menu.usbstack.picosdk=Pico SDK @@ -22597,8 +22749,10 @@ olimex_pico2xl.menu.dbglvl.Wire=Wire olimex_pico2xl.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE olimex_pico2xl.menu.dbglvl.Bluetooth=Bluetooth olimex_pico2xl.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +olimex_pico2xl.menu.dbglvl.LWIP=LWIP +olimex_pico2xl.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 olimex_pico2xl.menu.dbglvl.All=All -olimex_pico2xl.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +olimex_pico2xl.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 olimex_pico2xl.menu.dbglvl.NDEBUG=NDEBUG olimex_pico2xl.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG olimex_pico2xl.menu.usbstack.picosdk=Pico SDK @@ -22946,8 +23100,10 @@ olimex_pico2xxl.menu.dbglvl.Wire=Wire olimex_pico2xxl.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE olimex_pico2xxl.menu.dbglvl.Bluetooth=Bluetooth olimex_pico2xxl.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +olimex_pico2xxl.menu.dbglvl.LWIP=LWIP +olimex_pico2xxl.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 olimex_pico2xxl.menu.dbglvl.All=All -olimex_pico2xxl.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +olimex_pico2xxl.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 olimex_pico2xxl.menu.dbglvl.NDEBUG=NDEBUG olimex_pico2xxl.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG olimex_pico2xxl.menu.usbstack.picosdk=Pico SDK @@ -23237,8 +23393,10 @@ olimex_rp2040pico30.menu.dbglvl.Wire=Wire olimex_rp2040pico30.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE olimex_rp2040pico30.menu.dbglvl.Bluetooth=Bluetooth olimex_rp2040pico30.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +olimex_rp2040pico30.menu.dbglvl.LWIP=LWIP +olimex_rp2040pico30.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 olimex_rp2040pico30.menu.dbglvl.All=All -olimex_rp2040pico30.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +olimex_rp2040pico30.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 olimex_rp2040pico30.menu.dbglvl.NDEBUG=NDEBUG olimex_rp2040pico30.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG olimex_rp2040pico30.menu.usbstack.picosdk=Pico SDK @@ -23521,8 +23679,10 @@ pimoroni_pga2040.menu.dbglvl.Wire=Wire pimoroni_pga2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE pimoroni_pga2040.menu.dbglvl.Bluetooth=Bluetooth pimoroni_pga2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +pimoroni_pga2040.menu.dbglvl.LWIP=LWIP +pimoroni_pga2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 pimoroni_pga2040.menu.dbglvl.All=All -pimoroni_pga2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +pimoroni_pga2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 pimoroni_pga2040.menu.dbglvl.NDEBUG=NDEBUG pimoroni_pga2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG pimoroni_pga2040.menu.usbstack.picosdk=Pico SDK @@ -23870,8 +24030,10 @@ pimoroni_pga2350.menu.dbglvl.Wire=Wire pimoroni_pga2350.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE pimoroni_pga2350.menu.dbglvl.Bluetooth=Bluetooth pimoroni_pga2350.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +pimoroni_pga2350.menu.dbglvl.LWIP=LWIP +pimoroni_pga2350.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 pimoroni_pga2350.menu.dbglvl.All=All -pimoroni_pga2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +pimoroni_pga2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 pimoroni_pga2350.menu.dbglvl.NDEBUG=NDEBUG pimoroni_pga2350.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG pimoroni_pga2350.menu.usbstack.picosdk=Pico SDK @@ -24219,8 +24381,10 @@ pimoroni_pico_plus_2.menu.dbglvl.Wire=Wire pimoroni_pico_plus_2.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE pimoroni_pico_plus_2.menu.dbglvl.Bluetooth=Bluetooth pimoroni_pico_plus_2.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +pimoroni_pico_plus_2.menu.dbglvl.LWIP=LWIP +pimoroni_pico_plus_2.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 pimoroni_pico_plus_2.menu.dbglvl.All=All -pimoroni_pico_plus_2.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +pimoroni_pico_plus_2.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 pimoroni_pico_plus_2.menu.dbglvl.NDEBUG=NDEBUG pimoroni_pico_plus_2.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG pimoroni_pico_plus_2.menu.usbstack.picosdk=Pico SDK @@ -24569,8 +24733,10 @@ pimoroni_pico_plus_2w.menu.dbglvl.Wire=Wire pimoroni_pico_plus_2w.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE pimoroni_pico_plus_2w.menu.dbglvl.Bluetooth=Bluetooth pimoroni_pico_plus_2w.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +pimoroni_pico_plus_2w.menu.dbglvl.LWIP=LWIP +pimoroni_pico_plus_2w.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 pimoroni_pico_plus_2w.menu.dbglvl.All=All -pimoroni_pico_plus_2w.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +pimoroni_pico_plus_2w.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 pimoroni_pico_plus_2w.menu.dbglvl.NDEBUG=NDEBUG pimoroni_pico_plus_2w.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG pimoroni_pico_plus_2w.menu.usbstack.picosdk=Pico SDK @@ -24915,8 +25081,10 @@ pimoroni_plasma2040.menu.dbglvl.Wire=Wire pimoroni_plasma2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE pimoroni_plasma2040.menu.dbglvl.Bluetooth=Bluetooth pimoroni_plasma2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +pimoroni_plasma2040.menu.dbglvl.LWIP=LWIP +pimoroni_plasma2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 pimoroni_plasma2040.menu.dbglvl.All=All -pimoroni_plasma2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +pimoroni_plasma2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 pimoroni_plasma2040.menu.dbglvl.NDEBUG=NDEBUG pimoroni_plasma2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG pimoroni_plasma2040.menu.usbstack.picosdk=Pico SDK @@ -25166,8 +25334,10 @@ pimoroni_plasma2350.menu.dbglvl.Wire=Wire pimoroni_plasma2350.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE pimoroni_plasma2350.menu.dbglvl.Bluetooth=Bluetooth pimoroni_plasma2350.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +pimoroni_plasma2350.menu.dbglvl.LWIP=LWIP +pimoroni_plasma2350.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 pimoroni_plasma2350.menu.dbglvl.All=All -pimoroni_plasma2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +pimoroni_plasma2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 pimoroni_plasma2350.menu.dbglvl.NDEBUG=NDEBUG pimoroni_plasma2350.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG pimoroni_plasma2350.menu.usbstack.picosdk=Pico SDK @@ -25408,8 +25578,10 @@ pimoroni_servo2040.menu.dbglvl.Wire=Wire pimoroni_servo2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE pimoroni_servo2040.menu.dbglvl.Bluetooth=Bluetooth pimoroni_servo2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +pimoroni_servo2040.menu.dbglvl.LWIP=LWIP +pimoroni_servo2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 pimoroni_servo2040.menu.dbglvl.All=All -pimoroni_servo2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +pimoroni_servo2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 pimoroni_servo2040.menu.dbglvl.NDEBUG=NDEBUG pimoroni_servo2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG pimoroni_servo2040.menu.usbstack.picosdk=Pico SDK @@ -25678,8 +25850,10 @@ pimoroni_tiny2040.menu.dbglvl.Wire=Wire pimoroni_tiny2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE pimoroni_tiny2040.menu.dbglvl.Bluetooth=Bluetooth pimoroni_tiny2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +pimoroni_tiny2040.menu.dbglvl.LWIP=LWIP +pimoroni_tiny2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 pimoroni_tiny2040.menu.dbglvl.All=All -pimoroni_tiny2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +pimoroni_tiny2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 pimoroni_tiny2040.menu.dbglvl.NDEBUG=NDEBUG pimoroni_tiny2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG pimoroni_tiny2040.menu.usbstack.picosdk=Pico SDK @@ -25943,8 +26117,10 @@ pimoroni_tiny2350.menu.dbglvl.Wire=Wire pimoroni_tiny2350.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE pimoroni_tiny2350.menu.dbglvl.Bluetooth=Bluetooth pimoroni_tiny2350.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +pimoroni_tiny2350.menu.dbglvl.LWIP=LWIP +pimoroni_tiny2350.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 pimoroni_tiny2350.menu.dbglvl.All=All -pimoroni_tiny2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +pimoroni_tiny2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 pimoroni_tiny2350.menu.dbglvl.NDEBUG=NDEBUG pimoroni_tiny2350.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG pimoroni_tiny2350.menu.usbstack.picosdk=Pico SDK @@ -26292,8 +26468,10 @@ pimoroni_explorer.menu.dbglvl.Wire=Wire pimoroni_explorer.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE pimoroni_explorer.menu.dbglvl.Bluetooth=Bluetooth pimoroni_explorer.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +pimoroni_explorer.menu.dbglvl.LWIP=LWIP +pimoroni_explorer.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 pimoroni_explorer.menu.dbglvl.All=All -pimoroni_explorer.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +pimoroni_explorer.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 pimoroni_explorer.menu.dbglvl.NDEBUG=NDEBUG pimoroni_explorer.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG pimoroni_explorer.menu.usbstack.picosdk=Pico SDK @@ -26524,8 +26702,10 @@ pintronix_pinmax.menu.dbglvl.Wire=Wire pintronix_pinmax.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE pintronix_pinmax.menu.dbglvl.Bluetooth=Bluetooth pintronix_pinmax.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +pintronix_pinmax.menu.dbglvl.LWIP=LWIP +pintronix_pinmax.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 pintronix_pinmax.menu.dbglvl.All=All -pintronix_pinmax.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +pintronix_pinmax.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 pintronix_pinmax.menu.dbglvl.NDEBUG=NDEBUG pintronix_pinmax.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG pintronix_pinmax.menu.usbstack.picosdk=Pico SDK @@ -26766,8 +26946,10 @@ rakwireless_rak11300.menu.dbglvl.Wire=Wire rakwireless_rak11300.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE rakwireless_rak11300.menu.dbglvl.Bluetooth=Bluetooth rakwireless_rak11300.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +rakwireless_rak11300.menu.dbglvl.LWIP=LWIP +rakwireless_rak11300.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 rakwireless_rak11300.menu.dbglvl.All=All -rakwireless_rak11300.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +rakwireless_rak11300.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 rakwireless_rak11300.menu.dbglvl.NDEBUG=NDEBUG rakwireless_rak11300.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG rakwireless_rak11300.menu.usbstack.picosdk=Pico SDK @@ -27090,8 +27272,10 @@ redscorp_rp2040_eins.menu.dbglvl.Wire=Wire redscorp_rp2040_eins.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE redscorp_rp2040_eins.menu.dbglvl.Bluetooth=Bluetooth redscorp_rp2040_eins.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +redscorp_rp2040_eins.menu.dbglvl.LWIP=LWIP +redscorp_rp2040_eins.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 redscorp_rp2040_eins.menu.dbglvl.All=All -redscorp_rp2040_eins.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +redscorp_rp2040_eins.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 redscorp_rp2040_eins.menu.dbglvl.NDEBUG=NDEBUG redscorp_rp2040_eins.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG redscorp_rp2040_eins.menu.usbstack.picosdk=Pico SDK @@ -27414,8 +27598,10 @@ redscorp_rp2040_promini.menu.dbglvl.Wire=Wire redscorp_rp2040_promini.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE redscorp_rp2040_promini.menu.dbglvl.Bluetooth=Bluetooth redscorp_rp2040_promini.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +redscorp_rp2040_promini.menu.dbglvl.LWIP=LWIP +redscorp_rp2040_promini.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 redscorp_rp2040_promini.menu.dbglvl.All=All -redscorp_rp2040_promini.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +redscorp_rp2040_promini.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 redscorp_rp2040_promini.menu.dbglvl.NDEBUG=NDEBUG redscorp_rp2040_promini.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG redscorp_rp2040_promini.menu.usbstack.picosdk=Pico SDK @@ -27674,8 +27860,10 @@ sea_picro.menu.dbglvl.Wire=Wire sea_picro.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE sea_picro.menu.dbglvl.Bluetooth=Bluetooth sea_picro.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +sea_picro.menu.dbglvl.LWIP=LWIP +sea_picro.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 sea_picro.menu.dbglvl.All=All -sea_picro.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +sea_picro.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 sea_picro.menu.dbglvl.NDEBUG=NDEBUG sea_picro.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG sea_picro.menu.usbstack.picosdk=Pico SDK @@ -27902,8 +28090,10 @@ silicognition_rp2040_shim.menu.dbglvl.Wire=Wire silicognition_rp2040_shim.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE silicognition_rp2040_shim.menu.dbglvl.Bluetooth=Bluetooth silicognition_rp2040_shim.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +silicognition_rp2040_shim.menu.dbglvl.LWIP=LWIP +silicognition_rp2040_shim.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 silicognition_rp2040_shim.menu.dbglvl.All=All -silicognition_rp2040_shim.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +silicognition_rp2040_shim.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 silicognition_rp2040_shim.menu.dbglvl.NDEBUG=NDEBUG silicognition_rp2040_shim.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG silicognition_rp2040_shim.menu.usbstack.picosdk=Pico SDK @@ -28162,8 +28352,10 @@ solderparty_rp2040_stamp.menu.dbglvl.Wire=Wire solderparty_rp2040_stamp.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE solderparty_rp2040_stamp.menu.dbglvl.Bluetooth=Bluetooth solderparty_rp2040_stamp.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +solderparty_rp2040_stamp.menu.dbglvl.LWIP=LWIP +solderparty_rp2040_stamp.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 solderparty_rp2040_stamp.menu.dbglvl.All=All -solderparty_rp2040_stamp.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +solderparty_rp2040_stamp.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 solderparty_rp2040_stamp.menu.dbglvl.NDEBUG=NDEBUG solderparty_rp2040_stamp.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG solderparty_rp2040_stamp.menu.usbstack.picosdk=Pico SDK @@ -28487,8 +28679,10 @@ solderparty_rp2350_stamp.menu.dbglvl.Wire=Wire solderparty_rp2350_stamp.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE solderparty_rp2350_stamp.menu.dbglvl.Bluetooth=Bluetooth solderparty_rp2350_stamp.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +solderparty_rp2350_stamp.menu.dbglvl.LWIP=LWIP +solderparty_rp2350_stamp.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 solderparty_rp2350_stamp.menu.dbglvl.All=All -solderparty_rp2350_stamp.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +solderparty_rp2350_stamp.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 solderparty_rp2350_stamp.menu.dbglvl.NDEBUG=NDEBUG solderparty_rp2350_stamp.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG solderparty_rp2350_stamp.menu.usbstack.picosdk=Pico SDK @@ -28812,8 +29006,10 @@ solderparty_rp2350_stamp_xl.menu.dbglvl.Wire=Wire solderparty_rp2350_stamp_xl.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE solderparty_rp2350_stamp_xl.menu.dbglvl.Bluetooth=Bluetooth solderparty_rp2350_stamp_xl.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +solderparty_rp2350_stamp_xl.menu.dbglvl.LWIP=LWIP +solderparty_rp2350_stamp_xl.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 solderparty_rp2350_stamp_xl.menu.dbglvl.All=All -solderparty_rp2350_stamp_xl.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +solderparty_rp2350_stamp_xl.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 solderparty_rp2350_stamp_xl.menu.dbglvl.NDEBUG=NDEBUG solderparty_rp2350_stamp_xl.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG solderparty_rp2350_stamp_xl.menu.usbstack.picosdk=Pico SDK @@ -29162,8 +29358,10 @@ sparkfun_iotredboard_rp2350.menu.dbglvl.Wire=Wire sparkfun_iotredboard_rp2350.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE sparkfun_iotredboard_rp2350.menu.dbglvl.Bluetooth=Bluetooth sparkfun_iotredboard_rp2350.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +sparkfun_iotredboard_rp2350.menu.dbglvl.LWIP=LWIP +sparkfun_iotredboard_rp2350.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 sparkfun_iotredboard_rp2350.menu.dbglvl.All=All -sparkfun_iotredboard_rp2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +sparkfun_iotredboard_rp2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 sparkfun_iotredboard_rp2350.menu.dbglvl.NDEBUG=NDEBUG sparkfun_iotredboard_rp2350.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG sparkfun_iotredboard_rp2350.menu.usbstack.picosdk=Pico SDK @@ -29502,8 +29700,10 @@ sparkfun_micromodrp2040.menu.dbglvl.Wire=Wire sparkfun_micromodrp2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE sparkfun_micromodrp2040.menu.dbglvl.Bluetooth=Bluetooth sparkfun_micromodrp2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +sparkfun_micromodrp2040.menu.dbglvl.LWIP=LWIP +sparkfun_micromodrp2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 sparkfun_micromodrp2040.menu.dbglvl.All=All -sparkfun_micromodrp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +sparkfun_micromodrp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 sparkfun_micromodrp2040.menu.dbglvl.NDEBUG=NDEBUG sparkfun_micromodrp2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG sparkfun_micromodrp2040.menu.usbstack.picosdk=Pico SDK @@ -29842,8 +30042,10 @@ sparkfun_promicrorp2040.menu.dbglvl.Wire=Wire sparkfun_promicrorp2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE sparkfun_promicrorp2040.menu.dbglvl.Bluetooth=Bluetooth sparkfun_promicrorp2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +sparkfun_promicrorp2040.menu.dbglvl.LWIP=LWIP +sparkfun_promicrorp2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 sparkfun_promicrorp2040.menu.dbglvl.All=All -sparkfun_promicrorp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +sparkfun_promicrorp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 sparkfun_promicrorp2040.menu.dbglvl.NDEBUG=NDEBUG sparkfun_promicrorp2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG sparkfun_promicrorp2040.menu.usbstack.picosdk=Pico SDK @@ -30191,8 +30393,10 @@ sparkfun_promicrorp2350.menu.dbglvl.Wire=Wire sparkfun_promicrorp2350.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE sparkfun_promicrorp2350.menu.dbglvl.Bluetooth=Bluetooth sparkfun_promicrorp2350.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +sparkfun_promicrorp2350.menu.dbglvl.LWIP=LWIP +sparkfun_promicrorp2350.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 sparkfun_promicrorp2350.menu.dbglvl.All=All -sparkfun_promicrorp2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +sparkfun_promicrorp2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 sparkfun_promicrorp2350.menu.dbglvl.NDEBUG=NDEBUG sparkfun_promicrorp2350.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG sparkfun_promicrorp2350.menu.usbstack.picosdk=Pico SDK @@ -30531,8 +30735,10 @@ sparkfun_thingplusrp2040.menu.dbglvl.Wire=Wire sparkfun_thingplusrp2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE sparkfun_thingplusrp2040.menu.dbglvl.Bluetooth=Bluetooth sparkfun_thingplusrp2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +sparkfun_thingplusrp2040.menu.dbglvl.LWIP=LWIP +sparkfun_thingplusrp2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 sparkfun_thingplusrp2040.menu.dbglvl.All=All -sparkfun_thingplusrp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +sparkfun_thingplusrp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 sparkfun_thingplusrp2040.menu.dbglvl.NDEBUG=NDEBUG sparkfun_thingplusrp2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG sparkfun_thingplusrp2040.menu.usbstack.picosdk=Pico SDK @@ -30881,8 +31087,10 @@ sparkfun_thingplusrp2350.menu.dbglvl.Wire=Wire sparkfun_thingplusrp2350.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE sparkfun_thingplusrp2350.menu.dbglvl.Bluetooth=Bluetooth sparkfun_thingplusrp2350.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +sparkfun_thingplusrp2350.menu.dbglvl.LWIP=LWIP +sparkfun_thingplusrp2350.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 sparkfun_thingplusrp2350.menu.dbglvl.All=All -sparkfun_thingplusrp2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +sparkfun_thingplusrp2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 sparkfun_thingplusrp2350.menu.dbglvl.NDEBUG=NDEBUG sparkfun_thingplusrp2350.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG sparkfun_thingplusrp2350.menu.usbstack.picosdk=Pico SDK @@ -31334,8 +31542,10 @@ sparkfun_iotnode_lorawanrp2350.menu.dbglvl.Wire=Wire sparkfun_iotnode_lorawanrp2350.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE sparkfun_iotnode_lorawanrp2350.menu.dbglvl.Bluetooth=Bluetooth sparkfun_iotnode_lorawanrp2350.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +sparkfun_iotnode_lorawanrp2350.menu.dbglvl.LWIP=LWIP +sparkfun_iotnode_lorawanrp2350.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 sparkfun_iotnode_lorawanrp2350.menu.dbglvl.All=All -sparkfun_iotnode_lorawanrp2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +sparkfun_iotnode_lorawanrp2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 sparkfun_iotnode_lorawanrp2350.menu.dbglvl.NDEBUG=NDEBUG sparkfun_iotnode_lorawanrp2350.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG sparkfun_iotnode_lorawanrp2350.menu.usbstack.picosdk=Pico SDK @@ -31577,8 +31787,10 @@ sparkfun_xrp_controller_beta.menu.dbglvl.Wire=Wire sparkfun_xrp_controller_beta.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE sparkfun_xrp_controller_beta.menu.dbglvl.Bluetooth=Bluetooth sparkfun_xrp_controller_beta.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +sparkfun_xrp_controller_beta.menu.dbglvl.LWIP=LWIP +sparkfun_xrp_controller_beta.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 sparkfun_xrp_controller_beta.menu.dbglvl.All=All -sparkfun_xrp_controller_beta.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +sparkfun_xrp_controller_beta.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 sparkfun_xrp_controller_beta.menu.dbglvl.NDEBUG=NDEBUG sparkfun_xrp_controller_beta.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG sparkfun_xrp_controller_beta.menu.usbstack.picosdk=Pico SDK @@ -31927,8 +32139,10 @@ sparkfun_xrp_controller.menu.dbglvl.Wire=Wire sparkfun_xrp_controller.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE sparkfun_xrp_controller.menu.dbglvl.Bluetooth=Bluetooth sparkfun_xrp_controller.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +sparkfun_xrp_controller.menu.dbglvl.LWIP=LWIP +sparkfun_xrp_controller.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 sparkfun_xrp_controller.menu.dbglvl.All=All -sparkfun_xrp_controller.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +sparkfun_xrp_controller.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 sparkfun_xrp_controller.menu.dbglvl.NDEBUG=NDEBUG sparkfun_xrp_controller.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG sparkfun_xrp_controller.menu.usbstack.picosdk=Pico SDK @@ -32169,8 +32383,10 @@ seeed_indicator_rp2040.menu.dbglvl.Wire=Wire seeed_indicator_rp2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE seeed_indicator_rp2040.menu.dbglvl.Bluetooth=Bluetooth seeed_indicator_rp2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +seeed_indicator_rp2040.menu.dbglvl.LWIP=LWIP +seeed_indicator_rp2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 seeed_indicator_rp2040.menu.dbglvl.All=All -seeed_indicator_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +seeed_indicator_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 seeed_indicator_rp2040.menu.dbglvl.NDEBUG=NDEBUG seeed_indicator_rp2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG seeed_indicator_rp2040.menu.usbstack.picosdk=Pico SDK @@ -32411,8 +32627,10 @@ seeed_xiao_rp2040.menu.dbglvl.Wire=Wire seeed_xiao_rp2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE seeed_xiao_rp2040.menu.dbglvl.Bluetooth=Bluetooth seeed_xiao_rp2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +seeed_xiao_rp2040.menu.dbglvl.LWIP=LWIP +seeed_xiao_rp2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 seeed_xiao_rp2040.menu.dbglvl.All=All -seeed_xiao_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +seeed_xiao_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 seeed_xiao_rp2040.menu.dbglvl.NDEBUG=NDEBUG seeed_xiao_rp2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG seeed_xiao_rp2040.menu.usbstack.picosdk=Pico SDK @@ -32662,8 +32880,10 @@ seeed_xiao_rp2350.menu.dbglvl.Wire=Wire seeed_xiao_rp2350.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE seeed_xiao_rp2350.menu.dbglvl.Bluetooth=Bluetooth seeed_xiao_rp2350.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +seeed_xiao_rp2350.menu.dbglvl.LWIP=LWIP +seeed_xiao_rp2350.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 seeed_xiao_rp2350.menu.dbglvl.All=All -seeed_xiao_rp2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +seeed_xiao_rp2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 seeed_xiao_rp2350.menu.dbglvl.NDEBUG=NDEBUG seeed_xiao_rp2350.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG seeed_xiao_rp2350.menu.usbstack.picosdk=Pico SDK @@ -32904,8 +33124,10 @@ upesy_rp2040_devkit.menu.dbglvl.Wire=Wire upesy_rp2040_devkit.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE upesy_rp2040_devkit.menu.dbglvl.Bluetooth=Bluetooth upesy_rp2040_devkit.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +upesy_rp2040_devkit.menu.dbglvl.LWIP=LWIP +upesy_rp2040_devkit.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 upesy_rp2040_devkit.menu.dbglvl.All=All -upesy_rp2040_devkit.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +upesy_rp2040_devkit.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 upesy_rp2040_devkit.menu.dbglvl.NDEBUG=NDEBUG upesy_rp2040_devkit.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG upesy_rp2040_devkit.menu.usbstack.picosdk=Pico SDK @@ -33228,8 +33450,10 @@ vccgnd_yd_rp2040.menu.dbglvl.Wire=Wire vccgnd_yd_rp2040.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE vccgnd_yd_rp2040.menu.dbglvl.Bluetooth=Bluetooth vccgnd_yd_rp2040.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +vccgnd_yd_rp2040.menu.dbglvl.LWIP=LWIP +vccgnd_yd_rp2040.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 vccgnd_yd_rp2040.menu.dbglvl.All=All -vccgnd_yd_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +vccgnd_yd_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 vccgnd_yd_rp2040.menu.dbglvl.NDEBUG=NDEBUG vccgnd_yd_rp2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG vccgnd_yd_rp2040.menu.usbstack.picosdk=Pico SDK @@ -33512,8 +33736,10 @@ viyalab_mizu.menu.dbglvl.Wire=Wire viyalab_mizu.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE viyalab_mizu.menu.dbglvl.Bluetooth=Bluetooth viyalab_mizu.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +viyalab_mizu.menu.dbglvl.LWIP=LWIP +viyalab_mizu.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 viyalab_mizu.menu.dbglvl.All=All -viyalab_mizu.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +viyalab_mizu.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 viyalab_mizu.menu.dbglvl.NDEBUG=NDEBUG viyalab_mizu.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG viyalab_mizu.menu.usbstack.picosdk=Pico SDK @@ -33754,8 +33980,10 @@ waveshare_rp2040_zero.menu.dbglvl.Wire=Wire waveshare_rp2040_zero.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE waveshare_rp2040_zero.menu.dbglvl.Bluetooth=Bluetooth waveshare_rp2040_zero.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +waveshare_rp2040_zero.menu.dbglvl.LWIP=LWIP +waveshare_rp2040_zero.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 waveshare_rp2040_zero.menu.dbglvl.All=All -waveshare_rp2040_zero.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +waveshare_rp2040_zero.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 waveshare_rp2040_zero.menu.dbglvl.NDEBUG=NDEBUG waveshare_rp2040_zero.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG waveshare_rp2040_zero.menu.usbstack.picosdk=Pico SDK @@ -34010,8 +34238,10 @@ waveshare_rp2040_one.menu.dbglvl.Wire=Wire waveshare_rp2040_one.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE waveshare_rp2040_one.menu.dbglvl.Bluetooth=Bluetooth waveshare_rp2040_one.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +waveshare_rp2040_one.menu.dbglvl.LWIP=LWIP +waveshare_rp2040_one.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 waveshare_rp2040_one.menu.dbglvl.All=All -waveshare_rp2040_one.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +waveshare_rp2040_one.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 waveshare_rp2040_one.menu.dbglvl.NDEBUG=NDEBUG waveshare_rp2040_one.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG waveshare_rp2040_one.menu.usbstack.picosdk=Pico SDK @@ -34252,8 +34482,10 @@ waveshare_rp2040_matrix.menu.dbglvl.Wire=Wire waveshare_rp2040_matrix.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE waveshare_rp2040_matrix.menu.dbglvl.Bluetooth=Bluetooth waveshare_rp2040_matrix.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +waveshare_rp2040_matrix.menu.dbglvl.LWIP=LWIP +waveshare_rp2040_matrix.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 waveshare_rp2040_matrix.menu.dbglvl.All=All -waveshare_rp2040_matrix.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +waveshare_rp2040_matrix.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 waveshare_rp2040_matrix.menu.dbglvl.NDEBUG=NDEBUG waveshare_rp2040_matrix.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG waveshare_rp2040_matrix.menu.usbstack.picosdk=Pico SDK @@ -34592,8 +34824,10 @@ waveshare_rp2040_pizero.menu.dbglvl.Wire=Wire waveshare_rp2040_pizero.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE waveshare_rp2040_pizero.menu.dbglvl.Bluetooth=Bluetooth waveshare_rp2040_pizero.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +waveshare_rp2040_pizero.menu.dbglvl.LWIP=LWIP +waveshare_rp2040_pizero.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 waveshare_rp2040_pizero.menu.dbglvl.All=All -waveshare_rp2040_pizero.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +waveshare_rp2040_pizero.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 waveshare_rp2040_pizero.menu.dbglvl.NDEBUG=NDEBUG waveshare_rp2040_pizero.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG waveshare_rp2040_pizero.menu.usbstack.picosdk=Pico SDK @@ -34897,8 +35131,10 @@ waveshare_rp2040_plus.menu.dbglvl.Wire=Wire waveshare_rp2040_plus.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE waveshare_rp2040_plus.menu.dbglvl.Bluetooth=Bluetooth waveshare_rp2040_plus.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +waveshare_rp2040_plus.menu.dbglvl.LWIP=LWIP +waveshare_rp2040_plus.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 waveshare_rp2040_plus.menu.dbglvl.All=All -waveshare_rp2040_plus.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +waveshare_rp2040_plus.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 waveshare_rp2040_plus.menu.dbglvl.NDEBUG=NDEBUG waveshare_rp2040_plus.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG waveshare_rp2040_plus.menu.usbstack.picosdk=Pico SDK @@ -35139,8 +35375,10 @@ waveshare_rp2040_lcd_0_96.menu.dbglvl.Wire=Wire waveshare_rp2040_lcd_0_96.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE waveshare_rp2040_lcd_0_96.menu.dbglvl.Bluetooth=Bluetooth waveshare_rp2040_lcd_0_96.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +waveshare_rp2040_lcd_0_96.menu.dbglvl.LWIP=LWIP +waveshare_rp2040_lcd_0_96.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 waveshare_rp2040_lcd_0_96.menu.dbglvl.All=All -waveshare_rp2040_lcd_0_96.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +waveshare_rp2040_lcd_0_96.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 waveshare_rp2040_lcd_0_96.menu.dbglvl.NDEBUG=NDEBUG waveshare_rp2040_lcd_0_96.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG waveshare_rp2040_lcd_0_96.menu.usbstack.picosdk=Pico SDK @@ -35381,8 +35619,10 @@ waveshare_rp2040_lcd_1_28.menu.dbglvl.Wire=Wire waveshare_rp2040_lcd_1_28.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE waveshare_rp2040_lcd_1_28.menu.dbglvl.Bluetooth=Bluetooth waveshare_rp2040_lcd_1_28.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +waveshare_rp2040_lcd_1_28.menu.dbglvl.LWIP=LWIP +waveshare_rp2040_lcd_1_28.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 waveshare_rp2040_lcd_1_28.menu.dbglvl.All=All -waveshare_rp2040_lcd_1_28.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +waveshare_rp2040_lcd_1_28.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 waveshare_rp2040_lcd_1_28.menu.dbglvl.NDEBUG=NDEBUG waveshare_rp2040_lcd_1_28.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG waveshare_rp2040_lcd_1_28.menu.usbstack.picosdk=Pico SDK @@ -35646,8 +35886,10 @@ waveshare_rp2350_zero.menu.dbglvl.Wire=Wire waveshare_rp2350_zero.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE waveshare_rp2350_zero.menu.dbglvl.Bluetooth=Bluetooth waveshare_rp2350_zero.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +waveshare_rp2350_zero.menu.dbglvl.LWIP=LWIP +waveshare_rp2350_zero.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 waveshare_rp2350_zero.menu.dbglvl.All=All -waveshare_rp2350_zero.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +waveshare_rp2350_zero.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 waveshare_rp2350_zero.menu.dbglvl.NDEBUG=NDEBUG waveshare_rp2350_zero.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG waveshare_rp2350_zero.menu.usbstack.picosdk=Pico SDK @@ -35960,8 +36202,10 @@ waveshare_rp2350_plus.menu.dbglvl.Wire=Wire waveshare_rp2350_plus.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE waveshare_rp2350_plus.menu.dbglvl.Bluetooth=Bluetooth waveshare_rp2350_plus.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +waveshare_rp2350_plus.menu.dbglvl.LWIP=LWIP +waveshare_rp2350_plus.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 waveshare_rp2350_plus.menu.dbglvl.All=All -waveshare_rp2350_plus.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +waveshare_rp2350_plus.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 waveshare_rp2350_plus.menu.dbglvl.NDEBUG=NDEBUG waveshare_rp2350_plus.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG waveshare_rp2350_plus.menu.usbstack.picosdk=Pico SDK @@ -36225,8 +36469,10 @@ waveshare_rp2350_lcd_0_96.menu.dbglvl.Wire=Wire waveshare_rp2350_lcd_0_96.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE waveshare_rp2350_lcd_0_96.menu.dbglvl.Bluetooth=Bluetooth waveshare_rp2350_lcd_0_96.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +waveshare_rp2350_lcd_0_96.menu.dbglvl.LWIP=LWIP +waveshare_rp2350_lcd_0_96.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 waveshare_rp2350_lcd_0_96.menu.dbglvl.All=All -waveshare_rp2350_lcd_0_96.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +waveshare_rp2350_lcd_0_96.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 waveshare_rp2350_lcd_0_96.menu.dbglvl.NDEBUG=NDEBUG waveshare_rp2350_lcd_0_96.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG waveshare_rp2350_lcd_0_96.menu.usbstack.picosdk=Pico SDK @@ -36467,8 +36713,10 @@ wiznet_5100s_evb_pico.menu.dbglvl.Wire=Wire wiznet_5100s_evb_pico.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE wiznet_5100s_evb_pico.menu.dbglvl.Bluetooth=Bluetooth wiznet_5100s_evb_pico.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +wiznet_5100s_evb_pico.menu.dbglvl.LWIP=LWIP +wiznet_5100s_evb_pico.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 wiznet_5100s_evb_pico.menu.dbglvl.All=All -wiznet_5100s_evb_pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +wiznet_5100s_evb_pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 wiznet_5100s_evb_pico.menu.dbglvl.NDEBUG=NDEBUG wiznet_5100s_evb_pico.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG wiznet_5100s_evb_pico.menu.usbstack.picosdk=Pico SDK @@ -36718,8 +36966,10 @@ wiznet_5100s_evb_pico2.menu.dbglvl.Wire=Wire wiznet_5100s_evb_pico2.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE wiznet_5100s_evb_pico2.menu.dbglvl.Bluetooth=Bluetooth wiznet_5100s_evb_pico2.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +wiznet_5100s_evb_pico2.menu.dbglvl.LWIP=LWIP +wiznet_5100s_evb_pico2.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 wiznet_5100s_evb_pico2.menu.dbglvl.All=All -wiznet_5100s_evb_pico2.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +wiznet_5100s_evb_pico2.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 wiznet_5100s_evb_pico2.menu.dbglvl.NDEBUG=NDEBUG wiznet_5100s_evb_pico2.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG wiznet_5100s_evb_pico2.menu.usbstack.picosdk=Pico SDK @@ -36960,8 +37210,10 @@ wiznet_wizfi360_evb_pico.menu.dbglvl.Wire=Wire wiznet_wizfi360_evb_pico.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE wiznet_wizfi360_evb_pico.menu.dbglvl.Bluetooth=Bluetooth wiznet_wizfi360_evb_pico.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +wiznet_wizfi360_evb_pico.menu.dbglvl.LWIP=LWIP +wiznet_wizfi360_evb_pico.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 wiznet_wizfi360_evb_pico.menu.dbglvl.All=All -wiznet_wizfi360_evb_pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +wiznet_wizfi360_evb_pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 wiznet_wizfi360_evb_pico.menu.dbglvl.NDEBUG=NDEBUG wiznet_wizfi360_evb_pico.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG wiznet_wizfi360_evb_pico.menu.usbstack.picosdk=Pico SDK @@ -37202,8 +37454,10 @@ wiznet_5500_evb_pico.menu.dbglvl.Wire=Wire wiznet_5500_evb_pico.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE wiznet_5500_evb_pico.menu.dbglvl.Bluetooth=Bluetooth wiznet_5500_evb_pico.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +wiznet_5500_evb_pico.menu.dbglvl.LWIP=LWIP +wiznet_5500_evb_pico.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 wiznet_5500_evb_pico.menu.dbglvl.All=All -wiznet_5500_evb_pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +wiznet_5500_evb_pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 wiznet_5500_evb_pico.menu.dbglvl.NDEBUG=NDEBUG wiznet_5500_evb_pico.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG wiznet_5500_evb_pico.menu.usbstack.picosdk=Pico SDK @@ -37453,8 +37707,10 @@ wiznet_5500_evb_pico2.menu.dbglvl.Wire=Wire wiznet_5500_evb_pico2.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE wiznet_5500_evb_pico2.menu.dbglvl.Bluetooth=Bluetooth wiznet_5500_evb_pico2.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +wiznet_5500_evb_pico2.menu.dbglvl.LWIP=LWIP +wiznet_5500_evb_pico2.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 wiznet_5500_evb_pico2.menu.dbglvl.All=All -wiznet_5500_evb_pico2.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +wiznet_5500_evb_pico2.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 wiznet_5500_evb_pico2.menu.dbglvl.NDEBUG=NDEBUG wiznet_5500_evb_pico2.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG wiznet_5500_evb_pico2.menu.usbstack.picosdk=Pico SDK @@ -37695,8 +37951,10 @@ wiznet_55rp20_evb_pico.menu.dbglvl.Wire=Wire wiznet_55rp20_evb_pico.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE wiznet_55rp20_evb_pico.menu.dbglvl.Bluetooth=Bluetooth wiznet_55rp20_evb_pico.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +wiznet_55rp20_evb_pico.menu.dbglvl.LWIP=LWIP +wiznet_55rp20_evb_pico.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 wiznet_55rp20_evb_pico.menu.dbglvl.All=All -wiznet_55rp20_evb_pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +wiznet_55rp20_evb_pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 wiznet_55rp20_evb_pico.menu.dbglvl.NDEBUG=NDEBUG wiznet_55rp20_evb_pico.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG wiznet_55rp20_evb_pico.menu.usbstack.picosdk=Pico SDK @@ -37937,8 +38195,10 @@ wiznet_6300_evb_pico.menu.dbglvl.Wire=Wire wiznet_6300_evb_pico.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE wiznet_6300_evb_pico.menu.dbglvl.Bluetooth=Bluetooth wiznet_6300_evb_pico.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +wiznet_6300_evb_pico.menu.dbglvl.LWIP=LWIP +wiznet_6300_evb_pico.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 wiznet_6300_evb_pico.menu.dbglvl.All=All -wiznet_6300_evb_pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +wiznet_6300_evb_pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 wiznet_6300_evb_pico.menu.dbglvl.NDEBUG=NDEBUG wiznet_6300_evb_pico.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG wiznet_6300_evb_pico.menu.usbstack.picosdk=Pico SDK @@ -38188,8 +38448,10 @@ wiznet_6300_evb_pico2.menu.dbglvl.Wire=Wire wiznet_6300_evb_pico2.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE wiznet_6300_evb_pico2.menu.dbglvl.Bluetooth=Bluetooth wiznet_6300_evb_pico2.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +wiznet_6300_evb_pico2.menu.dbglvl.LWIP=LWIP +wiznet_6300_evb_pico2.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 wiznet_6300_evb_pico2.menu.dbglvl.All=All -wiznet_6300_evb_pico2.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +wiznet_6300_evb_pico2.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 wiznet_6300_evb_pico2.menu.dbglvl.NDEBUG=NDEBUG wiznet_6300_evb_pico2.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG wiznet_6300_evb_pico2.menu.usbstack.picosdk=Pico SDK @@ -38504,8 +38766,10 @@ generic.menu.dbglvl.Wire=Wire generic.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE generic.menu.dbglvl.Bluetooth=Bluetooth generic.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +generic.menu.dbglvl.LWIP=LWIP +generic.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 generic.menu.dbglvl.All=All -generic.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +generic.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 generic.menu.dbglvl.NDEBUG=NDEBUG generic.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG generic.menu.usbstack.picosdk=Pico SDK @@ -38964,8 +39228,10 @@ generic_rp2350.menu.dbglvl.Wire=Wire generic_rp2350.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE generic_rp2350.menu.dbglvl.Bluetooth=Bluetooth generic_rp2350.menu.dbglvl.Bluetooth.build.debug_level=-DDEBUG_RP2040_BLUETOOTH +generic_rp2350.menu.dbglvl.LWIP=LWIP +generic_rp2350.menu.dbglvl.LWIP.build.debug_level=-DLWIP_DEBUG=1 generic_rp2350.menu.dbglvl.All=All -generic_rp2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH +generic_rp2350.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1 generic_rp2350.menu.dbglvl.NDEBUG=NDEBUG generic_rp2350.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG generic_rp2350.menu.usbstack.picosdk=Pico SDK diff --git a/tools/makeboards.py b/tools/makeboards.py index ba2d3adbf..f5d29bed5 100755 --- a/tools/makeboards.py +++ b/tools/makeboards.py @@ -33,7 +33,7 @@ def BuildDebugPort(name): def BuildDebugLevel(name): for l in [ ("None", ""), ("Core", "-DDEBUG_RP2040_CORE"), ("SPI", "-DDEBUG_RP2040_SPI"), ("Wire", "-DDEBUG_RP2040_WIRE"), ("Bluetooth", "-DDEBUG_RP2040_BLUETOOTH"), - ("All", "-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH"), ("NDEBUG", "-DNDEBUG") ]: + ("LWIP", "-DLWIP_DEBUG=1"), ("All", "-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE -DDEBUG_RP2040_BLUETOOTH -DLWIP_DEBUG=1"), ("NDEBUG", "-DNDEBUG") ]: print("%s.menu.dbglvl.%s=%s" % (name, l[0], l[0])) print("%s.menu.dbglvl.%s.build.debug_level=%s" % (name, l[0], l[1])) From b84db3de08282bfcf509edc91b2c903d7b0a410d Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 18 Aug 2025 14:17:03 -0700 Subject: [PATCH 21/36] Unbreak FreeRTOS, clean up unused async_ctx method When in FreeRTOS, we don't use an async_context to drive our Ethernet NICs. Ifdef around any unused code/variables. --- libraries/lwIP_Ethernet/src/LwipEthernet.cpp | 105 +++++++++---------- 1 file changed, 50 insertions(+), 55 deletions(-) diff --git a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp index 761a39b63..3e92ac2dc 100644 --- a/libraries/lwIP_Ethernet/src/LwipEthernet.cpp +++ b/libraries/lwIP_Ethernet/src/LwipEthernet.cpp @@ -31,20 +31,8 @@ #include #include "FreeRTOS.h" #include "task.h" -//static async_context_freertos_t lwip_ethernet_async_context; -//static StackType_t lwip_ethernet_async_context_freertos_task_stack[CYW43_TASK_STACK_SIZE]; - -//static async_context_t *lwip_ethernet_init_default_async_context(void) { -// async_context_freertos_config_t config = async_context_freertos_default_config(); -//#if configSUPPORT_STATIC_ALLOCATION && !CYW43_NO_DEFAULT_TASK_STACK -// config.task_stack = lwip_ethernet_async_context_freertos_task_stack; -//#endif -// if (async_context_freertos_init(&lwip_ethernet_async_context, &config)) { -// return &lwip_ethernet_async_context.core; -// } -// return NULL; -//} - +#include "semphr.h" +static SemaphoreHandle_t _lwip_ethernet_mutex; #else #include static async_context_threadsafe_background_t lwip_ethernet_async_context; @@ -56,6 +44,10 @@ static async_context_t *lwip_ethernet_init_default_async_context(void) { } return NULL; } +// Async context that pumps the ethernet controllers +static async_when_pending_worker_t always_pending_update_timeout_worker; +static async_at_time_worker_t ethernet_timeout_worker; +static async_context_t *_context = nullptr; #endif @@ -64,36 +56,37 @@ static async_context_t *lwip_ethernet_init_default_async_context(void) { bool __ethernetContextInitted = false; -// Async context that pumps the ethernet controllers -static async_when_pending_worker_t always_pending_update_timeout_worker; -static async_at_time_worker_t ethernet_timeout_worker; -static async_context_t *_context = nullptr; // Theoretically support multiple interfaces static std::map> _handlePacketList; void ethernet_arch_lwip_begin() { + __startEthernetContext(); #ifdef __FREERTOS - panic("oops"); + xSemaphoreTake(_lwip_ethernet_mutex, portMAX_DELAY); +#else +#if defined(PICO_CYW43_SUPPORTED) + if (rp2040.isPicoW()) { + cyw43_arch_lwip_begin(); + return; + } +#endif + async_context_acquire_lock_blocking(_context); #endif - #if defined(PICO_CYW43_SUPPORTED) - if (rp2040.isPicoW()) { - cyw43_arch_lwip_begin(); - return; - } - #endif - __startEthernetContext(); - async_context_acquire_lock_blocking(_context); } void ethernet_arch_lwip_end() { - #if defined(PICO_CYW43_SUPPORTED) - if (rp2040.isPicoW()) { - cyw43_arch_lwip_end(); - return; - } - #endif - async_context_release_lock(_context); +#ifdef __FREERTOS + xSemaphoreGive(_lwip_ethernet_mutex); +#else +#if defined(PICO_CYW43_SUPPORTED) + if (rp2040.isPicoW()) { + cyw43_arch_lwip_end(); + return; + } +#endif + async_context_release_lock(_context); +#endif } int __addEthernetPacketHandler(std::function _packetHandler) { @@ -207,24 +200,6 @@ int hostByName(const char* aHostname, IPAddress& aResult, int timeout_ms) { uint32_t __ethernet_timeout_reached_calls = 0; static uint32_t _pollingPeriod = 20; -// This will only be called under the protection of the async context mutex, so no re-entrancy checks needed -static void ethernet_timeout_reached(__unused async_context_t *context, __unused async_at_time_worker_t *worker) { - assert(worker == ðernet_timeout_worker); - __ethernet_timeout_reached_calls++; - ethernet_arch_lwip_gpio_mask(); // Ensure non-polled devices won't interrupt us - for (auto handlePacket : _handlePacketList) { - handlePacket.second(); - sys_check_timeouts(); - } - ethernet_arch_lwip_gpio_unmask(); -} - -static void update_next_timeout(async_context_t *context, async_when_pending_worker_t *worker) { - assert(worker == &always_pending_update_timeout_worker); - worker->work_pending = true; - async_context_add_at_time_worker_in_ms(context, ðernet_timeout_worker, _pollingPeriod); -} - // We have a background pump which calls sys_check_timeouts on a periodic basis // and polls all Ethernet interfaces @@ -255,24 +230,44 @@ static void ethernetTask(void *param) { lwip_callback(stage2, nullptr); } } +#else +// This will only be called under the protection of the async context mutex, so no re-entrancy checks needed +static void ethernet_timeout_reached(__unused async_context_t *context, __unused async_at_time_worker_t *worker) { + assert(worker == ðernet_timeout_worker); + __ethernet_timeout_reached_calls++; + ethernet_arch_lwip_gpio_mask(); // Ensure non-polled devices won't interrupt us + for (auto handlePacket : _handlePacketList) { + handlePacket.second(); + sys_check_timeouts(); + } + ethernet_arch_lwip_gpio_unmask(); +} + +static void update_next_timeout(async_context_t *context, async_when_pending_worker_t *worker) { + assert(worker == &always_pending_update_timeout_worker); + worker->work_pending = true; + async_context_add_at_time_worker_in_ms(context, ðernet_timeout_worker, _pollingPeriod); +} #endif + void __startEthernetContext() { if (__ethernetContextInitted) { return; } #ifdef __FREERTOS + _lwip_ethernet_mutex = xSemaphoreCreateMutex(); xTaskCreate(ethernetTask, "EthPoll", 256, nullptr, 1, &_ethernetTask); #else - #if defined(PICO_CYW43_SUPPORTED) +#if defined(PICO_CYW43_SUPPORTED) if (rp2040.isPicoW()) { _context = cyw43_arch_async_context(); } else { _context = lwip_ethernet_init_default_async_context(); } - #else +#else _context = lwip_ethernet_init_default_async_context(); - #endif +#endif ethernet_timeout_worker.do_work = ethernet_timeout_reached; always_pending_update_timeout_worker.work_pending = true; always_pending_update_timeout_worker.do_work = update_next_timeout; From 50b1583e08b2183e4f465d684cb921ae11c8e732 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 18 Aug 2025 14:23:44 -0700 Subject: [PATCH 22/36] Forgot to add lwip_wrap.h, d'oh! --- cores/rp2040/lwip_wrap.h | 583 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 583 insertions(+) create mode 100644 cores/rp2040/lwip_wrap.h diff --git a/cores/rp2040/lwip_wrap.h b/cores/rp2040/lwip_wrap.h new file mode 100644 index 000000000..43d8a6c9c --- /dev/null +++ b/cores/rp2040/lwip_wrap.h @@ -0,0 +1,583 @@ +/* + FreeRTOS LWIP wrappers, implement a single LWIP work task + + Copyright (c) 2024 Earle F. Philhower, III + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + + +extern void ethernet_arch_lwip_begin() __attribute__((weak)); +extern void ethernet_arch_lwip_end() __attribute__((weak)); +extern void ethernet_arch_lwip_gpio_mask() __attribute__((weak)); +extern void ethernet_arch_lwip_gpio_unmask() __attribute__((weak)); + +//auto_init_recursive_mutex(__lwipMutex); // Only for case with no Ethernet or PicoW, but still doing LWIP (PPP?) +extern recursive_mutex_t __lwipMutex; + + +// LWIPMutex is a no-op under FreeRTOS because we wrap all calls and just send a request message to +// the LWIP task. No locking needed, many people can call LWIP in parallel but the messages will be +// processed 1-threaded in order or reception + +// Under Non-OS mode, we do need to lock the context because the threadsafe IRQ could come in + +class LWIPMutex { +public: + LWIPMutex() { + // if (ethernet_arch_lwip_gpio_mask) { + // ethernet_arch_lwip_gpio_mask(); + // } + //#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + // if (rp2040.isPicoW()) { + // cyw43_arch_lwip_begin(); + // return; + // } + //#endif +#if !defined(__FREERTOS) + if (ethernet_arch_lwip_begin) { + ethernet_arch_lwip_begin(); + } else { + recursive_mutex_enter_blocking(&__lwipMutex); + } +#endif + } + + ~LWIPMutex() { +#if !defined(__FREERTOS) + //#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + // if (rp2040.isPicoW()) { + // cyw43_arch_lwip_end(); + // } else { + //#endif + if (ethernet_arch_lwip_end) { + ethernet_arch_lwip_end(); + } else { + recursive_mutex_exit(&__lwipMutex); + } + //#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + // } + //#endif +#endif + // if (ethernet_arch_lwip_gpio_unmask) { + // ethernet_arch_lwip_gpio_unmask(); + // } + } +}; + + + +#ifdef __cplusplus +extern "C" { +#endif + +// Implement all LWIP operations in a single FreeRTOS task. Calls to LWIP will +// actually post work on the work queue and wait until the LWIP task indicates +// completion + +// Enumerated type for LWIP request +typedef enum { + __lwip_init = 1000, + + __pbuf_header = 2000, + __pbuf_free, + __pbuf_alloc, + __pbuf_take, + __pbuf_copy_partial, + __pbuf_ref, + __pbuf_get_at, + __pbuf_get_contiguous, + __pbuf_cat, + + __tcp_backlog_delayed = 3000, + __tcp_backlog_accepted, + __tcp_close, + __tcp_shutdown, + __tcp_abort, + __tcp_bind, + __tcp_bind_netif, + __tcp_listen_with_backlog, + // __tcp_listen_with_backlog_and_err, + __tcp_recved, + __tcp_connect, + __tcp_new, + __tcp_new_ip_type, + __tcp_arg, + __tcp_recv, + __tcp_sent, + __tcp_err, + __tcp_accept, + __tcp_poll, + __tcp_write, + __tcp_output, + + __tcp_setprio, + + __udp_send = 4000, + __udp_sendto, + __udp_sendto_if, + __udp_sendto_if_src, + __udp_bind, + __udp_connect, + __udp_disconnect, + __udp_recv, + __udp_remove, + __udp_new, + __udp_new_ip_type, + + __sys_check_timeouts = 5000, + + __dns_gethostbyname = 6000, + __dns_gethostbyname_addrtype, + + __raw_bind = 7000, + __raw_connect, + __raw_recv, + __raw_sendto, + __raw_send, + __raw_remove, + __raw_new, + __raw_new_ip_type, + + __netif_add = 8000, + __netif_remove, + + __ethernet_input = 9000, + + __callback = 10000, +} __lwip_op; + +// Set up a local request buffer and call this to add to lwip work queue. Will only return once lwip operation completed +// LWIP callbacks will happen from the LWIP task at some future time + +extern void __real_lwip_init(); +extern u8_t __real_pbuf_header(struct pbuf *p, s16_t header_size); +extern u8_t __real_pbuf_free(struct pbuf *p); +extern struct pbuf *__real_pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type); +extern err_t __real_pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len); +extern u16_t __real_pbuf_copy_partial(const struct pbuf *p, void *dataptr, u16_t len, u16_t offset); +extern void __real_pbuf_ref(struct pbuf *p); +extern u8_t __real_pbuf_get_at(const struct pbuf* p, u16_t offset); +extern void *__real_pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset); +extern void __real_pbuf_cat(struct pbuf *head, struct pbuf *tail); +extern void __real_tcp_arg(struct tcp_pcb *pcb, void *arg); +extern struct tcp_pcb *__real_tcp_new(void); +extern struct tcp_pcb *__real_tcp_new_ip_type(u8_t type); +extern err_t __real_tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port); +extern err_t __real_tcp_bind_netif(struct tcp_pcb *pcb, const struct netif *netif); +extern struct tcp_pcb *__real_tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); +//extern struct tcp_pcb *__real_tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err); +extern void __real_tcp_accept(struct tcp_pcb *pcb, err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)); +extern err_t __real_tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)); +extern err_t __real_tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len, u8_t apiflags); +extern void __real_tcp_sent(struct tcp_pcb *pcb, err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len)); +extern void __real_tcp_recv(struct tcp_pcb *pcb, err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)); +extern void __real_tcp_recved(struct tcp_pcb *pcb, u16_t len); +extern void __real_tcp_poll(struct tcp_pcb *pcb, err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval); +extern err_t __real_tcp_close(struct tcp_pcb *pcb); +extern void __real_tcp_abort(struct tcp_pcb *pcb); +extern void __real_tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg, err_t err)); +extern err_t __real_tcp_output(struct tcp_pcb *pcb); +extern void __real_tcp_setprio(struct tcp_pcb *pcb, u8_t prio); +extern void __real_tcp_backlog_delayed(struct tcp_pcb* pcb); +extern void __real_tcp_backlog_accepted(struct tcp_pcb* pcb); +extern err_t __real_tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx); +extern struct udp_pcb *__real_udp_new(void); +extern struct udp_pcb *__real_udp_new_ip_type(u8_t type); +extern void __real_udp_remove(struct udp_pcb *pcb); +extern err_t __real_udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port); +extern err_t __real_udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port); +extern err_t __real_udp_disconnect(struct udp_pcb *pcb); +extern err_t __real_udp_send(struct udp_pcb *pcb, struct pbuf *p); +extern void __real_udp_recv(struct udp_pcb *pcb, void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port), void *recv_arg); +extern err_t __real_udp_sendto(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port); +extern err_t __real_udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif); +extern err_t __real_udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, const ip_addr_t *src_ip); +extern void __real_sys_check_timeouts(); +extern err_t __real_dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg); +extern err_t __real_dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg, u8_t dns_addrtype); +extern struct raw_pcb *__real_raw_new(u8_t proto); +extern struct raw_pcb *__real_raw_new_ip_type(u8_t type, u8_t proto); +extern void __real_raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg); +extern err_t __real_raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr); +extern err_t __real_raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr); +extern err_t __real_raw_send(struct raw_pcb *pcb, struct pbuf *p); +extern err_t __real_raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr); +extern void __real_raw_remove(struct raw_pcb *pcb); +extern struct netif *__real_netif_add(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input); +extern void __real_netif_remove(struct netif *netif); +extern err_t __real_ethernet_input(struct pbuf *p, struct netif *netif); + + +typedef struct { + struct pbuf *p; + s16_t header_size; + u8_t *ret; +} __pbuf_header_req; + +typedef struct { + struct pbuf *p; + u8_t *ret; +} __pbuf_free_req; + +typedef struct { + pbuf_layer l; + u16_t length; + pbuf_type type; + struct pbuf **ret; +} __pbuf_alloc_req; + +typedef struct { + struct pbuf *buf; + const void *dataptr; + u16_t len; + err_t *ret; +} __pbuf_take_req; + +typedef struct { + const struct pbuf *p; + void *dataptr; + u16_t len; + u16_t offset; + u16_t *ret; +} __pbuf_copy_partial_req; + +typedef struct { + struct pbuf *p; +} __pbuf_ref_req; + +typedef struct { + const struct pbuf* p; + u16_t offset; + u8_t *ret; +} __pbuf_get_at_req; + +typedef struct { + const struct pbuf *p; + void *buffer; + size_t bufsize; + u16_t len; + u16_t offset; + void **ret; +} __pbuf_get_contiguous_req; + +typedef struct { + struct pbuf *head; + struct pbuf *tail; +} __pbuf_cat_req; + +typedef struct { + struct tcp_pcb *pcb; + void *arg; +} __tcp_arg_req; + +typedef struct { + struct tcp_pcb **ret; +} __tcp_new_req; + +typedef struct { + u8_t type; + struct tcp_pcb **ret; +} __tcp_new_ip_type_req; + + +typedef struct { + struct tcp_pcb *pcb; + ip_addr_t *ipaddr; + u16_t port; + err_t *ret; +} __tcp_bind_req; + +typedef struct { + struct tcp_pcb *pcb; + const struct netif *netif; + err_t *ret; +} __tcp_bind_netif_req; + +typedef struct { + struct tcp_pcb *pcb; + u8_t backlog; + struct tcp_pcb **ret; +} __tcp_listen_with_backlog_req; + +#if 0 +typedef struct { + struct tcp_pcb *pcb; + u8_t backlog; + err_t *err; + struct tcp_pcb **ret; +} __tcp_listen_with_backlog_and_err_req; +#endif + +typedef struct { + struct tcp_pcb *pcb; + err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err); +} __tcp_accept_req; + +typedef struct { + struct tcp_pcb *pcb; + ip_addr_t *ipaddr; + u16_t port; + err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err); + err_t *ret; +} __tcp_connect_req; + +typedef struct { + struct tcp_pcb *pcb; + const void *dataptr; + u16_t len; + u8_t apiflags; + err_t *ret; +} __tcp_write_req; + +typedef struct { + struct tcp_pcb *pcb; + err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len); +} __tcp_sent_req; + +typedef struct { + struct tcp_pcb *pcb; + err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err); +} __tcp_recv_req; + +typedef struct { + struct tcp_pcb *pcb; + u16_t len; +} __tcp_recved_req; + +typedef struct { + struct tcp_pcb *pcb; + err_t (* poll)(void *arg, struct tcp_pcb *tpcb); + u8_t interval; +} __tcp_poll_req; + +typedef struct { + struct tcp_pcb *pcb; + err_t *ret; +} __tcp_close_req; + +typedef struct { + struct tcp_pcb *pcb; +} __tcp_abort_req; + +typedef struct { + struct tcp_pcb *pcb; + void (* err)(void *arg, err_t err); +} __tcp_err_req; + +typedef struct { + struct tcp_pcb *pcb; + err_t *ret; +} __tcp_output_req; + +typedef struct { + struct tcp_pcb *pcb; + u8_t prio; +} __tcp_setprio_req; + +typedef struct { + struct tcp_pcb* pcb; +} __tcp_backlog_delayed_req; + +typedef struct { + struct tcp_pcb* pcb; +} __tcp_backlog_accepted_req; + +typedef struct { + struct tcp_pcb *pcb; + int shut_rx; + int shut_tx; + err_t *ret; +} __tcp_shutdown_req; + +typedef struct { + struct udp_pcb **ret; +} __udp_new_req; + +typedef struct { + u8_t type; + struct udp_pcb **ret; +} __udp_new_ip_type_req; + +typedef struct { + struct udp_pcb *pcb; +} __udp_remove_req; + +typedef struct { + struct udp_pcb *pcb; + ip_addr_t *ipaddr; + u16_t port; + err_t *ret; +} __udp_bind_req; + +typedef struct { + struct udp_pcb *pcb; + ip_addr_t *ipaddr; + u16_t port; + err_t *ret; +} __udp_connect_req; + +typedef struct { + struct udp_pcb *pcb; + err_t *ret; +} __udp_disconnect_req; + +typedef struct { + struct udp_pcb *pcb; + struct pbuf *p; + err_t *ret; +} __udp_send_req; + +typedef struct { + struct udp_pcb *pcb; + void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port); + void *recv_arg; +} __udp_recv_req; + +typedef struct { + struct udp_pcb *pcb; + struct pbuf *p; + const ip_addr_t *dst_ip; + u16_t dst_port; + struct netif *netif; + err_t *ret; +} __udp_sendto_if_req; + +typedef struct { + struct udp_pcb *pcb; + struct pbuf *p; + const ip_addr_t *dst_ip; + u16_t dst_port; + err_t *ret; +} __udp_sendto_req; + +typedef struct { + struct udp_pcb *pcb; + struct pbuf *p; + const ip_addr_t *dst_ip; + u16_t dst_port; + struct netif *netif; + const ip_addr_t *src_ip; + err_t *ret; +} __udp_sendto_if_src_req; + +typedef struct { + const char *hostname; + ip_addr_t *addr; + dns_found_callback found; + void *callback_arg; + err_t *ret; +} __dns_gethostbyname_req; + +typedef struct { + const char *hostname; + ip_addr_t *addr; + dns_found_callback found; + void *callback_arg; + u8_t dns_addrtype; + err_t *ret; +} __dns_gethostbyname_addrtype_req; + +typedef struct { + u8_t proto; + struct raw_pcb **ret; +} __raw_new_req; + +typedef struct { + u8_t type; + u8_t proto; + struct raw_pcb **ret; +} __raw_new_ip_type_req; + +typedef struct { + struct raw_pcb *pcb; + const ip_addr_t *ipaddr; + err_t *ret; +} __raw_connect_req; + +typedef struct { + struct raw_pcb *pcb; + raw_recv_fn recv; + void *recv_arg; +} __raw_recv_req; + +typedef struct { + struct raw_pcb *pcb; + const ip_addr_t *ipaddr; + err_t *ret; +} __raw_bind_req; + +typedef struct { + struct raw_pcb *pcb; + struct pbuf *p; + const ip_addr_t *ipaddr; + err_t *ret; +} __raw_sendto_req; + +typedef struct { + struct raw_pcb *pcb; + struct pbuf *p; + err_t *ret; +} __raw_send_req; + +typedef struct { + struct raw_pcb *pcb; +} __raw_remove_req; + +typedef struct { + struct netif *netif; + const ip4_addr_t *ipaddr; + const ip4_addr_t *netmask; + const ip4_addr_t *gw; + void *state; + netif_init_fn init; + netif_input_fn input; + struct netif **ret; +} __netif_add_req; + +typedef struct { + struct netif *netif; +} __netif_remove_req; + +typedef struct { + struct pbuf *p; + struct netif *netif; + err_t *ret; +} __ethernet_input_req; + +// Run a callback in the LWIP thread (i.e. for Ethernet device polling and packet reception) +// When in an interrupt, need to pass in a heap-allocated buffer (i.e. class variable) of +// size LWIP_CALLBACK_BUFFER_SIZE that will be used to store the request. +extern void lwip_callback(void (*cb)(void *), void *cbData, void *buffer = nullptr); +typedef struct { + void (*cb)(void *); + void *cbData; +} __callback_req; +#define LWIP_CALLBACK_BUFFER_SIZE sizeof(__callback_req) + +#ifdef __cplusplus +}; +#endif From 504de82cf4860acb13304acd36f6113e45640109 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 18 Aug 2025 18:10:04 -0700 Subject: [PATCH 23/36] Use __FREERTOS for example CI builds --- cores/rp2040/freertos/FreeRTOS.h | 2 ++ libraries/lwIP_Ethernet/src/LwipIntfDev.h | 2 ++ .../FreeRTOS-Multicore.ino} | 0 .../FreeRTOS-StaticMulticore.ino} | 0 .../Stress-FreeRTOS.ino => FreeRTOS-Stress/FreeRTOS-Stress.ino} | 0 tools/build.py | 2 ++ 6 files changed, 6 insertions(+) rename libraries/rp2040/examples/{Multicore-FreeRTOS/Multicore-FreeRTOS.ino => FreeRTOS-Multicore/FreeRTOS-Multicore.ino} (100%) rename libraries/rp2040/examples/{StaticMulticore-FreeRTOS/StaticMulticore-FreeRTOS.ino => FreeRTOS-StaticMulticore/FreeRTOS-StaticMulticore.ino} (100%) rename libraries/rp2040/examples/{Stress-FreeRTOS/Stress-FreeRTOS.ino => FreeRTOS-Stress/FreeRTOS-Stress.ino} (100%) diff --git a/cores/rp2040/freertos/FreeRTOS.h b/cores/rp2040/freertos/FreeRTOS.h index c8781f33c..fd743c12d 100644 --- a/cores/rp2040/freertos/FreeRTOS.h +++ b/cores/rp2040/freertos/FreeRTOS.h @@ -1,3 +1,5 @@ #ifdef __FREERTOS #include "../../../FreeRTOS-Kernel/include/FreeRTOS.h" +#else +#error "#define __FREERTOS 1 to use FreeRTOS in your application" #endif diff --git a/libraries/lwIP_Ethernet/src/LwipIntfDev.h b/libraries/lwIP_Ethernet/src/LwipIntfDev.h index 860d00e61..8a8ce2ecf 100644 --- a/libraries/lwIP_Ethernet/src/LwipIntfDev.h +++ b/libraries/lwIP_Ethernet/src/LwipIntfDev.h @@ -46,8 +46,10 @@ #include "LwipEthernet.h" #include "wl_definitions.h" +#ifdef __FREERTOS #include "FreeRTOS.h" #include "semphr.h" +#endif #ifndef DEFAULT_MTU #define DEFAULT_MTU 1500 diff --git a/libraries/rp2040/examples/Multicore-FreeRTOS/Multicore-FreeRTOS.ino b/libraries/rp2040/examples/FreeRTOS-Multicore/FreeRTOS-Multicore.ino similarity index 100% rename from libraries/rp2040/examples/Multicore-FreeRTOS/Multicore-FreeRTOS.ino rename to libraries/rp2040/examples/FreeRTOS-Multicore/FreeRTOS-Multicore.ino diff --git a/libraries/rp2040/examples/StaticMulticore-FreeRTOS/StaticMulticore-FreeRTOS.ino b/libraries/rp2040/examples/FreeRTOS-StaticMulticore/FreeRTOS-StaticMulticore.ino similarity index 100% rename from libraries/rp2040/examples/StaticMulticore-FreeRTOS/StaticMulticore-FreeRTOS.ino rename to libraries/rp2040/examples/FreeRTOS-StaticMulticore/FreeRTOS-StaticMulticore.ino diff --git a/libraries/rp2040/examples/Stress-FreeRTOS/Stress-FreeRTOS.ino b/libraries/rp2040/examples/FreeRTOS-Stress/FreeRTOS-Stress.ino similarity index 100% rename from libraries/rp2040/examples/Stress-FreeRTOS/Stress-FreeRTOS.ino rename to libraries/rp2040/examples/FreeRTOS-Stress/FreeRTOS-Stress.ino diff --git a/tools/build.py b/tools/build.py index 3e845a4e5..0197096a2 100755 --- a/tools/build.py +++ b/tools/build.py @@ -74,6 +74,8 @@ def compile(tmp_dir, sketch, cache, tools_dir, hardware_dir, ide_path, f, args): fqbn = fqbn + ",ipbtstack=ipv4btcble" if '/Profiling' in sketch: fqbn = fqbn + ",profile=Enabled" + if '/FreeRTOS' in sketch: + fqbn = fqbn + ",os=freertos" if '/FreeRTOS' in sketch: fqbn = fqbn + ",os=freertos" cmd += [fqbn] From b5cb7541068934739e73a374cbb154979dbb3252 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 19 Aug 2025 10:39:11 -0700 Subject: [PATCH 24/36] Move LWIPThread to its own file --- cores/rp2040/freertos/freertos-lwip.cpp | 412 ++++++++++++++++++++++++ cores/rp2040/freertos/freertos-lwip.h | 35 ++ cores/rp2040/freertos/variantHooks.cpp | 372 +-------------------- 3 files changed, 449 insertions(+), 370 deletions(-) create mode 100644 cores/rp2040/freertos/freertos-lwip.cpp create mode 100644 cores/rp2040/freertos/freertos-lwip.h diff --git a/cores/rp2040/freertos/freertos-lwip.cpp b/cores/rp2040/freertos/freertos-lwip.cpp new file mode 100644 index 000000000..f6375e6e0 --- /dev/null +++ b/cores/rp2040/freertos/freertos-lwip.cpp @@ -0,0 +1,412 @@ +/* + LWIP-on-FreeRTOs Plumbing + + Copyright (c) 2025 Earle F. Philhower, III + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifdef __FREERTOS + +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include +#include "freertos-lwip.h" + +// The data structure for the LWIP work queue +typedef struct { + __lwip_op op; + void *req; + TaskHandle_t wakeup; +} LWIPWork; + +#define LWIP_WORK_ENTRIES 16 + +// The notify item we'll use to wake the calling process back up +#define TASK_NOTIFY_LWIP_WAKEUP (configTASK_NOTIFICATION_ARRAY_ENTRIES - 1) + +static void lwipThread(void *params); +static TaskHandle_t __lwipTask; +static QueueHandle_t __lwipQueue; + + +void __startLWIPThread() { + __lwipQueue = xQueueCreate(LWIP_WORK_ENTRIES, sizeof(LWIPWork)); + if (!__lwipQueue) { + panic("Unable to allocate LWIP work queue"); + } + if (pdPASS != xTaskCreate(lwipThread, "LWIP", 1024, 0, configMAX_PRIORITIES - 1, &__lwipTask)) { + panic("Unable to create LWIP task"); + } + vTaskCoreAffinitySet(__lwipTask, 1 << 0); +} + +extern "C" void __lwip(__lwip_op op, void *req, bool fromISR) { + LWIPWork w; + if (fromISR) { + w.op = op; + w.req = req; + w.wakeup = 0; // Don't try and wake up a task when done, we're not in one! + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + if (!xQueueSendFromISR(__lwipQueue, &w, &xHigherPriorityTaskWoken)) { + panic("LWIP task send failed"); + } + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + } else { + TaskStatus_t t; + vTaskGetInfo(nullptr, &t, pdFALSE, eInvalid); // TODO - can we speed this up??? + w.op = op; + w.req = req; + w.wakeup = t.xHandle; + if (!xQueueSend(__lwipQueue, &w, portMAX_DELAY)) { + panic("LWIP task send failed"); + } + ulTaskNotifyTakeIndexed(TASK_NOTIFY_LWIP_WAKEUP, pdTRUE, portMAX_DELAY); + } +} + +extern "C" bool __isLWIPThread() { + TaskStatus_t t; + vTaskGetInfo(nullptr, &t, pdFALSE, eInvalid); // TODO - can we speed this up??? + return t.xHandle == __lwipTask; +} + +static void lwipThread(void *params) { + (void) params; + LWIPWork w; + assert(__isLWIPThread()); + unsigned int scd = 100 / portTICK_PERIOD_MS; + + lwip_init(); // Will call our wrapper and set up the RNG + + while (true) { + auto ret = xQueueReceive(__lwipQueue, &w, scd); + if (ret) { + switch (w.op) { + case __lwip_init: { + __real_lwip_init(); + break; + } + case __pbuf_header: { + __pbuf_header_req *r = (__pbuf_header_req *)w.req; + *(r->ret) = __real_pbuf_header(r->p, r->header_size); + break; + } + case __pbuf_free: { + __pbuf_free_req *r = (__pbuf_free_req *)w.req; + *(r->ret) = __real_pbuf_free(r->p); + break; + } + case __pbuf_alloc: { + __pbuf_alloc_req *r = (__pbuf_alloc_req *)w.req; + *(r->ret) = __real_pbuf_alloc(r->l, r->length, r->type); + break; + } + case __pbuf_take: { + __pbuf_take_req *r = (__pbuf_take_req *)w.req; + *(r->ret) = __real_pbuf_take(r->buf, r->dataptr, r->len); + break; + } + case __pbuf_copy_partial: { + __pbuf_copy_partial_req *r = (__pbuf_copy_partial_req *)w.req; + *(r->ret) = __real_pbuf_copy_partial(r->p, r->dataptr, r->len, r->offset); + break; + } + case __pbuf_ref: { + __pbuf_ref_req *r = (__pbuf_ref_req *)w.req; + __real_pbuf_ref(r->p); + break; + } + case __pbuf_get_at: { + __pbuf_get_at_req *r = (__pbuf_get_at_req *)w.req; + *(r->ret) = __real_pbuf_get_at(r->p, r->offset); + break; + } + case __pbuf_get_contiguous: { + __pbuf_get_contiguous_req *r = (__pbuf_get_contiguous_req *)w.req; + *(r->ret) = __real_pbuf_get_contiguous(r->p, r->buffer, r->bufsize, r->len, r->offset); + break; + } + case __pbuf_cat: { + __pbuf_cat_req *r = (__pbuf_cat_req *)w.req; + __real_pbuf_cat(r->head, r->tail); + break; + } + case __tcp_arg: { + __tcp_arg_req *r = (__tcp_arg_req *)w.req; + __real_tcp_arg(r->pcb, r->arg); + break; + } + case __tcp_new: { + __tcp_new_req *r = (__tcp_new_req *)w.req; + *(r->ret) = __real_tcp_new(); + break; + } + case __tcp_new_ip_type: { + __tcp_new_ip_type_req *r = (__tcp_new_ip_type_req *)w.req; + *(r->ret) = __real_tcp_new_ip_type(r->type); + break; + } + case __tcp_bind: { + __tcp_bind_req *r = (__tcp_bind_req *)w.req; + *(r->ret) = __real_tcp_bind(r->pcb, r->ipaddr, r->port); + break; + } + case __tcp_bind_netif: { + __tcp_bind_netif_req *r = (__tcp_bind_netif_req *)w.req; + *(r->ret) = __real_tcp_bind_netif(r->pcb, r->netif); + break; + } + case __tcp_listen_with_backlog: { + __tcp_listen_with_backlog_req *r = (__tcp_listen_with_backlog_req *)w.req; + *(r->ret) = __real_tcp_listen_with_backlog(r->pcb, r->backlog); + break; + } +#if 0 + case __tcp_listen_with_backlog_and_err: { + __tcp_listen_with_backlog_and_err_req *r = (__tcp_listen_with_backlog_and_err_req *)w.req; + *(r->ret) = __real_tcp_listen_with_backlog_and_err(r->pcb, r->backlog, r->err); + break; + } +#endif + case __tcp_accept: { + __tcp_accept_req *r = (__tcp_accept_req *)w.req; + __real_tcp_accept(r->pcb, r->accept); + break; + } + case __tcp_connect: { + __tcp_connect_req *r = (__tcp_connect_req *)w.req; + *(r->ret) = __real_tcp_connect(r->pcb, r->ipaddr, r->port, r->connected); + break; + } + case __tcp_write: { + __tcp_write_req *r = (__tcp_write_req *)w.req; + *(r->ret) = __real_tcp_write(r->pcb, r->dataptr, r->len, r->apiflags); + break; + } + case __tcp_sent: { + __tcp_sent_req *r = (__tcp_sent_req *)w.req; + __real_tcp_sent(r->pcb, r->sent); + break; + } + case __tcp_recv: { + __tcp_recv_req *r = (__tcp_recv_req *)w.req; + __real_tcp_recv(r->pcb, r->recv); + break; + } + case __tcp_recved: { + __tcp_recved_req *r = (__tcp_recved_req *)w.req; + __real_tcp_recved(r->pcb, r->len); + break; + } + case __tcp_poll: { + __tcp_poll_req *r = (__tcp_poll_req *)w.req; + __real_tcp_poll(r->pcb, r->poll, r->interval); + break; + } + case __tcp_close: { + __tcp_close_req *r = (__tcp_close_req *)w.req; + *(r->ret) = __real_tcp_close(r->pcb); + break; + } + case __tcp_abort: { + __tcp_abort_req *r = (__tcp_abort_req *)w.req; + __real_tcp_abort(r->pcb); + break; + } + case __tcp_err: { + __tcp_err_req *r = (__tcp_err_req *)w.req; + __real_tcp_err(r->pcb, r->err); + break; + } + case __tcp_output: { + __tcp_output_req *r = (__tcp_output_req *)w.req; + *(r->ret) = __real_tcp_output(r->pcb); + break; + } + case __tcp_setprio: { + __tcp_setprio_req *r = (__tcp_setprio_req *)w.req; + __real_tcp_setprio(r->pcb, r->prio); + break; + } + case __tcp_shutdown: { + __tcp_shutdown_req *r = (__tcp_shutdown_req *)w.req; + *(r->ret) = __real_tcp_shutdown(r->pcb, r->shut_rx, r->shut_tx); + break; + } + case __tcp_backlog_delayed: { + __tcp_backlog_delayed_req *r = (__tcp_backlog_delayed_req *)w.req; + __real_tcp_backlog_delayed(r->pcb); + break; + } + case __tcp_backlog_accepted: { + __tcp_backlog_accepted_req *r = (__tcp_backlog_accepted_req *)w.req; + __real_tcp_backlog_accepted(r->pcb); + break; + } + case __udp_new: { + __udp_new_req *r = (__udp_new_req *)w.req; + *(r->ret) = __real_udp_new(); + break; + } + case __udp_new_ip_type: { + __udp_new_ip_type_req *r = (__udp_new_ip_type_req *)w.req; + *(r->ret) = __real_udp_new_ip_type(r->type); + break; + } + case __udp_remove: { + __udp_remove_req *r = (__udp_remove_req *)w.req; + __real_udp_remove(r->pcb); + break; + } + case __udp_bind: { + __udp_bind_req *r = (__udp_bind_req *)w.req; + *(r->ret) = __real_udp_bind(r->pcb, r->ipaddr, r->port); + break; + } + case __udp_connect: { + __udp_connect_req *r = (__udp_connect_req *)w.req; + *(r->ret) = __real_udp_connect(r->pcb, r->ipaddr, r->port); + break; + } + case __udp_disconnect: { + __udp_disconnect_req *r = (__udp_disconnect_req *)w.req; + *(r->ret) = __real_udp_disconnect(r->pcb); + break; + } + case __udp_send: { + __udp_send_req *r = (__udp_send_req *)w.req; + *(r->ret) = __real_udp_send(r->pcb, r->p); + break; + } + case __udp_recv: { + __udp_recv_req *r = (__udp_recv_req *)w.req; + __real_udp_recv(r->pcb, r->recv, r->recv_arg); + break; + } + case __udp_sendto: { + __udp_sendto_req *r = (__udp_sendto_req *)w.req; + *(r->ret) = __real_udp_sendto(r->pcb, r->p, r->dst_ip, r->dst_port); + break; + } + case __udp_sendto_if: { + __udp_sendto_if_req *r = (__udp_sendto_if_req *)w.req; + *(r->ret) = __real_udp_sendto_if(r->pcb, r->p, r->dst_ip, r->dst_port, r->netif); + break; + } + case __udp_sendto_if_src: { + __udp_sendto_if_src_req *r = (__udp_sendto_if_src_req *)w.req; + *(r->ret) = __real_udp_sendto_if_src(r->pcb, r->p, r->dst_ip, r->dst_port, r->netif, r->src_ip); + break; + } + case __sys_check_timeouts: { + __real_sys_check_timeouts(); + break; + } + case __dns_gethostbyname: { + __dns_gethostbyname_req *r = (__dns_gethostbyname_req *)w.req; + *(r->ret) = __real_dns_gethostbyname(r->hostname, r->addr, r->found, r->callback_arg); + break; + } + case __dns_gethostbyname_addrtype: { + __dns_gethostbyname_addrtype_req *r = (__dns_gethostbyname_addrtype_req *)w.req; + *(r->ret) = __real_dns_gethostbyname_addrtype(r->hostname, r->addr, r->found, r->callback_arg, r->dns_addrtype); + break; + } + case __raw_new: { + __raw_new_req *r = (__raw_new_req *)w.req; + *(r->ret) = __real_raw_new(r->proto); + break; + } + case __raw_new_ip_type: { + __raw_new_ip_type_req *r = (__raw_new_ip_type_req *)w.req; + *(r->ret) = __real_raw_new_ip_type(r->type, r->proto); + break; + } + case __raw_connect: { + __raw_connect_req *r = (__raw_connect_req *)w.req; + *(r->ret) = __real_raw_connect(r->pcb, r->ipaddr); + break; + } + case __raw_recv: { + __raw_recv_req *r = (__raw_recv_req *)w.req; + __real_raw_recv(r->pcb, r->recv, r->recv_arg); + break; + } + case __raw_bind: { + __raw_bind_req *r = (__raw_bind_req *)w.req; + *(r->ret) = __real_raw_bind(r->pcb, r->ipaddr); + break; + } + case __raw_sendto: { + __raw_sendto_req *r = (__raw_sendto_req *)w.req; + *(r->ret) = __real_raw_sendto(r->pcb, r->p, r->ipaddr); + break; + } + case __raw_send: { + __raw_send_req *r = (__raw_send_req *)w.req; + *(r->ret) = __real_raw_send(r->pcb, r->p); + break; + } + case __raw_remove: { + __raw_remove_req *r = (__raw_remove_req *)w.req; + __real_raw_remove(r->pcb); + break; + } + case __netif_add: { + __netif_add_req *r = (__netif_add_req *)w.req; + *(r->ret) = __real_netif_add(r->netif, r->ipaddr, r->netmask, r->gw, r->state, r->init, r->input); + break; + } + case __netif_remove: { + __netif_remove_req *r = (__netif_remove_req *)w.req; + __real_netif_remove(r->netif); + break; + } + case __ethernet_input: { + __ethernet_input_req *r = (__ethernet_input_req *)w.req; + printf("__real_ethernet_input\n"); + *(r->ret) = __real_ethernet_input(r->p, r->netif); + break; + } + case __callback: { + __callback_req *r = (__callback_req *)w.req; + r->cb(r->cbData); + break; + } + default: { + // Any new unimplemented calls = ERROR!!! + panic("Unimplemented LWIP thread action"); + break; + } + } + // Work done, return value set, just tickle the calling task + if (w.wakeup) { + xTaskNotifyGiveIndexed(w.wakeup, TASK_NOTIFY_LWIP_WAKEUP); + } + } else { + // No work received, do periodic processing + __real_sys_check_timeouts(); + // When should we wake up next to redo timeouts? + scd = sys_timeouts_sleeptime(); + if (scd == SYS_TIMEOUTS_SLEEPTIME_INFINITE) { + scd = portMAX_DELAY / portTICK_PERIOD_MS; + } + } + } +} + +#endif diff --git a/cores/rp2040/freertos/freertos-lwip.h b/cores/rp2040/freertos/freertos-lwip.h new file mode 100644 index 000000000..6d0386856 --- /dev/null +++ b/cores/rp2040/freertos/freertos-lwip.h @@ -0,0 +1,35 @@ +/* + LWIP-on-FreeRTOS Plumbing + + Copyright (c) 2025 Earle F. Philhower, III + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifdef __FREERTOS + +#pragma once + +// Create the thread and work queue +void __startLWIPThread(); + +// Send an LWIP request to the task. Will block unless fromISR==true +extern "C" void __lwip(__lwip_op op, void *req, bool fromISR); + +// Return true if __real_LWIP ops are safe (i.e. this is the LWIP thread) +extern "C" bool __isLWIPThread(); + +#endif diff --git a/cores/rp2040/freertos/variantHooks.cpp b/cores/rp2040/freertos/variantHooks.cpp index 380776d80..f4c88cde6 100644 --- a/cores/rp2040/freertos/variantHooks.cpp +++ b/cores/rp2040/freertos/variantHooks.cpp @@ -44,16 +44,8 @@ #include <_freertos.h> #include +#include "freertos-lwip.h" -static TaskHandle_t __lwipTask; -static QueueHandle_t __lwipQueue; -typedef struct { - __lwip_op op; - void *req; - TaskHandle_t wakeup; -} LWIPWork; - -#define TASK_NOTIFY_LWIP_WAKEUP (configTASK_NOTIFICATION_ARRAY_ENTRIES - 1) // Interfaces for the main core to use FreeRTOS mutexes extern "C" { extern volatile bool __otherCoreIdled; @@ -250,11 +242,7 @@ void startFreeRTOS(void) { xTaskCreate(IdleThisCore, "IdleCore1", 128, 0, configMAX_PRIORITIES - 1, __idleCoreTask + 1); vTaskCoreAffinitySet(__idleCoreTask[1], 1 << 1); - // LWIP runs on core 0 only - __lwipQueue = xQueueCreate(16, sizeof(LWIPWork)); - //__hwMutex = xSemaphoreCreateMutex(); - xTaskCreate(lwipThread, "LWIP", 1024, 0, configMAX_PRIORITIES - 1, &__lwipTask); - vTaskCoreAffinitySet(__lwipTask, 1 << 0); + __startLWIPThread(); // Initialise and run the freeRTOS scheduler. Execution should never return here. __freeRTOSinitted = true; @@ -555,360 +543,4 @@ void __USBStart() { vTaskCoreAffinitySet(__usbTask, 1 << 0); } - -extern "C" void __lwip(__lwip_op op, void *req, bool fromISR) { - LWIPWork w; - if (fromISR) { - w.op = op; - w.req = req; - w.wakeup = 0; // Don't try and wake up a task when done, we're not in one! - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - if (!xQueueSendFromISR(__lwipQueue, &w, &xHigherPriorityTaskWoken)) { - panic("LWIP task send failed"); - } - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); - } else { - TaskStatus_t t; - vTaskGetInfo(nullptr, &t, pdFALSE, eInvalid); // TODO - can we speed this up??? - w.op = op; - w.req = req; - w.wakeup = t.xHandle; - if (!xQueueSend(__lwipQueue, &w, portMAX_DELAY)) { - panic("LWIP task send failed"); - } - ulTaskNotifyTakeIndexed(TASK_NOTIFY_LWIP_WAKEUP, pdTRUE, portMAX_DELAY); - } -} - -extern "C" bool __isLWIPThread() { - TaskStatus_t t; - vTaskGetInfo(nullptr, &t, pdFALSE, eInvalid); // TODO - can we speed this up??? - return t.xHandle == __lwipTask; -} - -static void lwipThread(void *params) { - (void) params; - LWIPWork w; - assert(__isLWIPThread()); - unsigned int scd = 100 / portTICK_PERIOD_MS; - - lwip_init(); // Will call our wrapper and set up the RNG - - while (true) { - auto ret = xQueueReceive(__lwipQueue, &w, scd); - if (ret) { - switch (w.op) { - case __lwip_init: { - __real_lwip_init(); - break; - } - case __pbuf_header: { - __pbuf_header_req *r = (__pbuf_header_req *)w.req; - *(r->ret) = __real_pbuf_header(r->p, r->header_size); - break; - } - case __pbuf_free: { - __pbuf_free_req *r = (__pbuf_free_req *)w.req; - *(r->ret) = __real_pbuf_free(r->p); - break; - } - case __pbuf_alloc: { - __pbuf_alloc_req *r = (__pbuf_alloc_req *)w.req; - *(r->ret) = __real_pbuf_alloc(r->l, r->length, r->type); - break; - } - case __pbuf_take: { - __pbuf_take_req *r = (__pbuf_take_req *)w.req; - *(r->ret) = __real_pbuf_take(r->buf, r->dataptr, r->len); - break; - } - case __pbuf_copy_partial: { - __pbuf_copy_partial_req *r = (__pbuf_copy_partial_req *)w.req; - *(r->ret) = __real_pbuf_copy_partial(r->p, r->dataptr, r->len, r->offset); - break; - } - case __pbuf_ref: { - __pbuf_ref_req *r = (__pbuf_ref_req *)w.req; - __real_pbuf_ref(r->p); - break; - } - case __pbuf_get_at: { - __pbuf_get_at_req *r = (__pbuf_get_at_req *)w.req; - *(r->ret) = __real_pbuf_get_at(r->p, r->offset); - break; - } - case __pbuf_get_contiguous: { - __pbuf_get_contiguous_req *r = (__pbuf_get_contiguous_req *)w.req; - *(r->ret) = __real_pbuf_get_contiguous(r->p, r->buffer, r->bufsize, r->len, r->offset); - break; - } - case __pbuf_cat: { - __pbuf_cat_req *r = (__pbuf_cat_req *)w.req; - __real_pbuf_cat(r->head, r->tail); - break; - } - case __tcp_arg: { - __tcp_arg_req *r = (__tcp_arg_req *)w.req; - __real_tcp_arg(r->pcb, r->arg); - break; - } - case __tcp_new: { - __tcp_new_req *r = (__tcp_new_req *)w.req; - *(r->ret) = __real_tcp_new(); - break; - } - case __tcp_new_ip_type: { - __tcp_new_ip_type_req *r = (__tcp_new_ip_type_req *)w.req; - *(r->ret) = __real_tcp_new_ip_type(r->type); - break; - } - case __tcp_bind: { - __tcp_bind_req *r = (__tcp_bind_req *)w.req; - *(r->ret) = __real_tcp_bind(r->pcb, r->ipaddr, r->port); - break; - } - case __tcp_bind_netif: { - __tcp_bind_netif_req *r = (__tcp_bind_netif_req *)w.req; - *(r->ret) = __real_tcp_bind_netif(r->pcb, r->netif); - break; - } - case __tcp_listen_with_backlog: { - __tcp_listen_with_backlog_req *r = (__tcp_listen_with_backlog_req *)w.req; - *(r->ret) = __real_tcp_listen_with_backlog(r->pcb, r->backlog); - break; - } -#if 0 - case __tcp_listen_with_backlog_and_err: { - __tcp_listen_with_backlog_and_err_req *r = (__tcp_listen_with_backlog_and_err_req *)w.req; - *(r->ret) = __real_tcp_listen_with_backlog_and_err(r->pcb, r->backlog, r->err); - break; - } -#endif - case __tcp_accept: { - __tcp_accept_req *r = (__tcp_accept_req *)w.req; - __real_tcp_accept(r->pcb, r->accept); - break; - } - case __tcp_connect: { - __tcp_connect_req *r = (__tcp_connect_req *)w.req; - *(r->ret) = __real_tcp_connect(r->pcb, r->ipaddr, r->port, r->connected); - break; - } - case __tcp_write: { - __tcp_write_req *r = (__tcp_write_req *)w.req; - *(r->ret) = __real_tcp_write(r->pcb, r->dataptr, r->len, r->apiflags); - break; - } - case __tcp_sent: { - __tcp_sent_req *r = (__tcp_sent_req *)w.req; - __real_tcp_sent(r->pcb, r->sent); - break; - } - case __tcp_recv: { - __tcp_recv_req *r = (__tcp_recv_req *)w.req; - __real_tcp_recv(r->pcb, r->recv); - break; - } - case __tcp_recved: { - __tcp_recved_req *r = (__tcp_recved_req *)w.req; - __real_tcp_recved(r->pcb, r->len); - break; - } - case __tcp_poll: { - __tcp_poll_req *r = (__tcp_poll_req *)w.req; - __real_tcp_poll(r->pcb, r->poll, r->interval); - break; - } - case __tcp_close: { - __tcp_close_req *r = (__tcp_close_req *)w.req; - *(r->ret) = __real_tcp_close(r->pcb); - break; - } - case __tcp_abort: { - __tcp_abort_req *r = (__tcp_abort_req *)w.req; - __real_tcp_abort(r->pcb); - break; - } - case __tcp_err: { - __tcp_err_req *r = (__tcp_err_req *)w.req; - __real_tcp_err(r->pcb, r->err); - break; - } - case __tcp_output: { - __tcp_output_req *r = (__tcp_output_req *)w.req; - *(r->ret) = __real_tcp_output(r->pcb); - break; - } - case __tcp_setprio: { - __tcp_setprio_req *r = (__tcp_setprio_req *)w.req; - __real_tcp_setprio(r->pcb, r->prio); - break; - } - case __tcp_shutdown: { - __tcp_shutdown_req *r = (__tcp_shutdown_req *)w.req; - *(r->ret) = __real_tcp_shutdown(r->pcb, r->shut_rx, r->shut_tx); - break; - } - case __tcp_backlog_delayed: { - __tcp_backlog_delayed_req *r = (__tcp_backlog_delayed_req *)w.req; - __real_tcp_backlog_delayed(r->pcb); - break; - } - case __tcp_backlog_accepted: { - __tcp_backlog_accepted_req *r = (__tcp_backlog_accepted_req *)w.req; - __real_tcp_backlog_accepted(r->pcb); - break; - } - case __udp_new: { - __udp_new_req *r = (__udp_new_req *)w.req; - *(r->ret) = __real_udp_new(); - break; - } - case __udp_new_ip_type: { - __udp_new_ip_type_req *r = (__udp_new_ip_type_req *)w.req; - *(r->ret) = __real_udp_new_ip_type(r->type); - break; - } - case __udp_remove: { - __udp_remove_req *r = (__udp_remove_req *)w.req; - __real_udp_remove(r->pcb); - break; - } - case __udp_bind: { - __udp_bind_req *r = (__udp_bind_req *)w.req; - *(r->ret) = __real_udp_bind(r->pcb, r->ipaddr, r->port); - break; - } - case __udp_connect: { - __udp_connect_req *r = (__udp_connect_req *)w.req; - *(r->ret) = __real_udp_connect(r->pcb, r->ipaddr, r->port); - break; - } - case __udp_disconnect: { - __udp_disconnect_req *r = (__udp_disconnect_req *)w.req; - *(r->ret) = __real_udp_disconnect(r->pcb); - break; - } - case __udp_send: { - __udp_send_req *r = (__udp_send_req *)w.req; - *(r->ret) = __real_udp_send(r->pcb, r->p); - break; - } - case __udp_recv: { - __udp_recv_req *r = (__udp_recv_req *)w.req; - __real_udp_recv(r->pcb, r->recv, r->recv_arg); - break; - } - case __udp_sendto: { - __udp_sendto_req *r = (__udp_sendto_req *)w.req; - *(r->ret) = __real_udp_sendto(r->pcb, r->p, r->dst_ip, r->dst_port); - break; - } - case __udp_sendto_if: { - __udp_sendto_if_req *r = (__udp_sendto_if_req *)w.req; - *(r->ret) = __real_udp_sendto_if(r->pcb, r->p, r->dst_ip, r->dst_port, r->netif); - break; - } - case __udp_sendto_if_src: { - __udp_sendto_if_src_req *r = (__udp_sendto_if_src_req *)w.req; - *(r->ret) = __real_udp_sendto_if_src(r->pcb, r->p, r->dst_ip, r->dst_port, r->netif, r->src_ip); - break; - } - case __sys_check_timeouts: { - __real_sys_check_timeouts(); - break; - } - case __dns_gethostbyname: { - __dns_gethostbyname_req *r = (__dns_gethostbyname_req *)w.req; - *(r->ret) = __real_dns_gethostbyname(r->hostname, r->addr, r->found, r->callback_arg); - break; - } - case __dns_gethostbyname_addrtype: { - __dns_gethostbyname_addrtype_req *r = (__dns_gethostbyname_addrtype_req *)w.req; - *(r->ret) = __real_dns_gethostbyname_addrtype(r->hostname, r->addr, r->found, r->callback_arg, r->dns_addrtype); - break; - } - case __raw_new: { - __raw_new_req *r = (__raw_new_req *)w.req; - *(r->ret) = __real_raw_new(r->proto); - break; - } - case __raw_new_ip_type: { - __raw_new_ip_type_req *r = (__raw_new_ip_type_req *)w.req; - *(r->ret) = __real_raw_new_ip_type(r->type, r->proto); - break; - } - case __raw_connect: { - __raw_connect_req *r = (__raw_connect_req *)w.req; - *(r->ret) = __real_raw_connect(r->pcb, r->ipaddr); - break; - } - case __raw_recv: { - __raw_recv_req *r = (__raw_recv_req *)w.req; - __real_raw_recv(r->pcb, r->recv, r->recv_arg); - break; - } - case __raw_bind: { - __raw_bind_req *r = (__raw_bind_req *)w.req; - *(r->ret) = __real_raw_bind(r->pcb, r->ipaddr); - break; - } - case __raw_sendto: { - __raw_sendto_req *r = (__raw_sendto_req *)w.req; - *(r->ret) = __real_raw_sendto(r->pcb, r->p, r->ipaddr); - break; - } - case __raw_send: { - __raw_send_req *r = (__raw_send_req *)w.req; - *(r->ret) = __real_raw_send(r->pcb, r->p); - break; - } - case __raw_remove: { - __raw_remove_req *r = (__raw_remove_req *)w.req; - __real_raw_remove(r->pcb); - break; - } - case __netif_add: { - __netif_add_req *r = (__netif_add_req *)w.req; - *(r->ret) = __real_netif_add(r->netif, r->ipaddr, r->netmask, r->gw, r->state, r->init, r->input); - break; - } - case __netif_remove: { - __netif_remove_req *r = (__netif_remove_req *)w.req; - __real_netif_remove(r->netif); - break; - } - case __ethernet_input: { - __ethernet_input_req *r = (__ethernet_input_req *)w.req; - printf("__real_ethernet_input\n"); - *(r->ret) = __real_ethernet_input(r->p, r->netif); - break; - } - case __callback: { - __callback_req *r = (__callback_req *)w.req; - r->cb(r->cbData); - break; - } - default: { - // Any new unimplemented calls = ERROR!!! - panic("Unimplemented LWIP thread action"); - break; - } - } - // Work done, return value set, just tickle the calling task - if (w.wakeup) { - xTaskNotifyGiveIndexed(w.wakeup, TASK_NOTIFY_LWIP_WAKEUP); - } - } else { - // No work received, do periodic processing - __real_sys_check_timeouts(); - // When should we wake up next to redo timeouts? - scd = sys_timeouts_sleeptime(); - if (scd == SYS_TIMEOUTS_SLEEPTIME_INFINITE) { - scd = portMAX_DELAY / portTICK_PERIOD_MS; - } - } - } -} - #endif From b4ec9249e5ab6d386256c567f4b60578ed6e7e9c Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 19 Aug 2025 10:43:12 -0700 Subject: [PATCH 25/36] Just panic() on FreeRTOS fatal error Blinking the LED doesn't work on all boards (CYW43), but panic() will show on any debugger quite nicely. --- cores/rp2040/freertos/variantHooks.cpp | 48 ++------------------------ 1 file changed, 3 insertions(+), 45 deletions(-) diff --git a/cores/rp2040/freertos/variantHooks.cpp b/cores/rp2040/freertos/variantHooks.cpp index f4c88cde6..a14269d3b 100644 --- a/cores/rp2040/freertos/variantHooks.cpp +++ b/cores/rp2040/freertos/variantHooks.cpp @@ -229,7 +229,6 @@ extern mutex_t __usb_mutex; static TaskHandle_t __usbTask; static void __usb(void *param); extern volatile bool __freeRTOSinitted; -static void lwipThread(void *params); void startFreeRTOS(void) { TaskHandle_t c0; @@ -330,29 +329,6 @@ void vApplicationTickHook(void) { #endif /* configUSE_TICK_HOOK == 1 */ /*-----------------------------------------------------------*/ -#if ( configUSE_MALLOC_FAILED_HOOK == 1 || configCHECK_FOR_STACK_OVERFLOW >= 1 || configDEFAULT_ASSERT == 1 ) - -/** - Private function to enable board led to use it in application hooks -*/ -void prvSetMainLedOn(void) { -#ifdef LED_BUILTIN - gpio_init(LED_BUILTIN); - gpio_set_dir(LED_BUILTIN, true); - gpio_put(LED_BUILTIN, true); -#endif -} - -/** - Private function to blink board led to use it in application hooks -*/ -void prvBlinkMainLed(void) { -#ifdef LED_BUILTIN - gpio_put(LED_BUILTIN, !gpio_get(LED_BUILTIN)); -#endif -} - -#endif /* ---------------------------------------------------------------------------*\ Usage: @@ -360,15 +336,7 @@ void prvBlinkMainLed(void) { \*---------------------------------------------------------------------------*/ extern "C" void rtosFatalError(void) { - prvSetMainLedOn(); // Main LED on. - - for (;;) { - // Main LED slow flash - sleep_ms(100); - prvBlinkMainLed(); - sleep_ms(2000); - prvBlinkMainLed(); - } + panic("Fatal error"); } #if ( configUSE_MALLOC_FAILED_HOOK == 1 ) @@ -391,12 +359,7 @@ extern "C" void vApplicationMallocFailedHook(void) __attribute__((weak)); void vApplicationMallocFailedHook(void) { - prvSetMainLedOn(); // Main LED on. - - for (;;) { - sleep_ms(50); - prvBlinkMainLed(); // Main LED fast blink. - } + panic("Malloc failed"); } #endif /* configUSE_MALLOC_FAILED_HOOK == 1 */ @@ -411,12 +374,7 @@ void vApplicationStackOverflowHook(TaskHandle_t xTask, void vApplicationStackOverflowHook(TaskHandle_t xTask __attribute__((unused)), char * pcTaskName __attribute__((unused))) { - prvSetMainLedOn(); // Main LED on. - - for (;;) { - sleep_ms(2000); - prvBlinkMainLed(); // Main LED slow blink. - } + panic("Stack overflow"); } #endif /* configCHECK_FOR_STACK_OVERFLOW >= 1 */ From 002d9c03a82e1dd35f49e5d24b0163371144fa60 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 19 Aug 2025 14:25:49 -0700 Subject: [PATCH 26/36] The IRQ temp callback buffer needs 4-byte align We write pointers to the data, make sure it doesn't bus fault --- lib/rp2040/liblwip.a | Bin 638990 -> 602362 bytes libraries/lwIP_Ethernet/src/LwipIntfDev.h | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rp2040/liblwip.a b/lib/rp2040/liblwip.a index 378bc3b1270bc49380f81e9c58aa701e90ea04af..4961070e98fcb2141bc83a1a20ac30f046bf4b44 100644 GIT binary patch delta 700 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�d_?1oNkNpd^*Qa#2u_yDb3a4sR9Sd zc+O%@1s1?TfnTsR%3=nOSInFW+{NNIkmIRGSP% zzL8WhumFRcwDAawcu)aud>17$h|`M(eg}eCN4d}R@t^{nfCDq3KI_PfJ=}`RVMl@Q zL;Byx+2-T*g{nA;arwOwLSK9X(KoM%E>aaPm<{GY7WGu{J%tjrcs5pyoWF*6JveX) ztWWrCZjT0CdEAv~KYX4|onK=S_une}30{AN^{tQ!(8i$|h|KZZx>TycCZJWJo*FbE z7xNhzbqFcVuqq&C&jXYDK-NroLnKU!QMdKY#OKkF^H&rs1-%$4oyyn&m46l3q|E3| zI6~OI6`b|RuS2qrf#^i01F3)#&copBLuN0DCqUeW%q=8-2jXYQ`~(S~q%s_~knmMkBsfD+o)3Q*-p+SZlGEGI!*n~{k&;(*Vf zIS5&*4(;H@o$@|Q*{{hCYdGUW736-WGB91WURl1CoOqi)FO#$Ed)UuPoI0^Ze zb)D>ESPR3~^j7*aDh+9A+@U@gct5!BLh27lL)LHGpgtJQ(jeUILrP)*Jzj|Q58Vj< z(09ZbbkoS2KrA)JA+nxAY4)W!FNLq8_A(^nP%A9c+TT2l+J{5UU?i>m%_Y=6ALMCB zWgS>`-_GO8Y+lk)2tA5x`C=%b*LI5~YED+LtyZ+tjFdVRhm-Rt`%UC{!zT4%vYN=c0lDjt(y8MXR94x~qU*U;$f;Vy z9~8fqfhxSeaC|sVRlh*)A*7T=7$LgJZeoKKMK}y^Mk~)GMK)$3RpdQ;sz3Sr8e+zO0SDu0a3OD^T`hdS>V==w$9lTc5K) zb3Pb{?!ZWC?`#`N?@WiziAaNKN(v=d-+0nm3ps5@9ZGq-OPjG78D5WhW}r&nPU-lA z9Z*$@LYC`wNIU5%>j-tu0Czi7bW>*)h;JZs0a8X;e|4Z$I_o~p{!BW7A!#R158k1~ zEa^%6B=+PWR7AgvL+X>1YvkVOPLQ`DB{5tI^R=~{9ZJuRF@M59#>S%PG4$RzE6ErQ zwV4bb6jLsZAmLd$^guymYn>;MiHdhbI@;&^b^6c>WLw$+WNivblXiR!rJLA)AcV9ybH zW_pi36(}|ioru{peF*JIgZ{9M@gH1*7TGxk0cFgx4%3#&v}GO+BOx~&$u0*m37H8< zNfhNat;aA#v*}dBgVaP@ehd-Mo{$&UK7UDW;4uUO@bDiF0aGCN<*=3xjO<^RX zV3Q8z(tp4?W}A`D4s*78vTeq~UfDLI+mjtbm35vh*HKTl&REbZTW4(jBnp+P^bYoM zfhT-!kMIJcrdN1@u}NRMl%7x7$(}5iAW!jRqqbLevayA-OSg1Ua`#7cT@EANJe5s? zr(!)}%~Mg`&rHro^VDiyPi1n-n5Q}!qpFDOfcbj5k0)ZU%Ino^2qhR+^OPpUoUENXuX6NvJq=n7c35fv)HHZ%*jU3N z)}We3sELZ6rZ_ztM9-aQ&YG$9aLuUdR=8R+&gm69Vx9r9s7fe9O^9uN3YAsq9!wP9U{jCNw|i<1HgyA&-$83b z&3qP2-i~Q9+)Ta{c@^L{Pyv4PRaA`8@%=sB$8B|{w(jp^*s99;C1!$uUml5PP+0tH zI4$bGAf!u|af10fb*Zn&2T^BMy6+U^;6G>9B<3>bVsUY1&C#P3pf7S(AwHa{Y;w4E zQ?_cN_RN`n$Px@21a`H0|$v89t z%bD{hupWVyhmZ!-!<^;bhG1;g>uhTyn7>Eq?~n=@u}(KQy#9U-$=L%UDFFXl2>0dm z2Q{$YdL!-|YL0~IY`Fp~eZa_YZ5)F3SFruUabR$vOaq5&9nJ*P!1~fjOrNjf&JQbj zBIc(N?W0G$in4RSTMt{#K(Ysd_$D%6M@pe|3B`FRLc&RRFRM`MdPrQyDy)AWGWQ^j z<|0CAv!_aPl6?i3kD>Gtir)YNx67jHIa2#Uy@t#yNUJ!bSn4~XUK83``Na=%6pf6lTbFP!(YO5U$d3_xkb>MNEiPxe0q9YSY zUxE%qrj*3_C^;RO1tfS0T8GS;Nc`k;ah;EhQO3ijq^aDT+Fn@cz3JtUybLL09t1E< z<~AI?)16wKHWM3lrZv3n@)`CA`R?aWI{Da9)L@V8uTf_9ZVa)NseIu{36m2hCXjDi zsxo3`-8&Ob4f)ytMPa8%}#DJQldB&~* zMijYlF{~Jc%E@IaAz@mA4+*{&DgVTxw3B_U2LqeR_V3}$FmdGBzW8* z@Ru{GN2@o~L#fy`_F36ce9v78!-w~nRGdCIM?5oPtoFpnh#?*>4ziQwdboiRrKtD~%Xm?1Nmd@s;txVrI?Jp*On6bPm^QZ9F#6HENF$VboSZKRRK-HN_c> z(6JK6+5$W{~tgmRWpe7dA6Z$Ieb=bt1g<WY;hTnTU`AHVt1-^Z zB<=25GUFKGoIIzYs?{4jvnj=CHzz|4hM%z>Ct%9VM>dz|dat`8^W^J>cjq z&NCMHA{m8+iFh1k8&&_li0oe>PCZ(7n5Lnw;((NaAw zxX4QIKuqK8#C1rimAyXq#%7hfXR(tJT}@-A%MxqN~Ew=qPE9SDe2LQHB<$ze}% zpL*F*Hjd_bkWP$4C&pF(r%s@ozL2qkhV#-z*((qFSHW=D`IR(8VX-b6=-Cqbqwl6c z1xM^bC27|Wa+fc4GN-Y)ET%~tuPdbXuW?r+#m1Q5GvJiPLK8k*8|E(ksL~EOGPZ$9dB~zmaPiJ~FO3h`yXgN*EGx@FVy0Me#hi zQ}c}I3PzI7$08|4`<&4_d_2Jwc(6*#`86NQ(IDNbEZkUQzLM6$SVwhX0hW%?;>T{% z3#fyKbx)mg&sgfDRIt?PGpV(Fs7L;AUj=&M#8=r4FA)a70e8DgN}LFv;?*C{41O5O z{LJ&fyPQOxW6qDh2n0523h^x%tEblz@M?u`3&!fl+7XQEyJ(bID}vR6v4%(v#X=c7 z6I3f>+@p`_`k11R^Yqct$FhL# zb%iGQ#7C@xC(1j1@T5N4`dFrqp1SzsTFtN4#|kwEH$;5uUdLTB!av)sxWq1UU-+&) z)17{aZMnxYgJE}6N^q5X{8D?m`_UzKiu>vTd&RxChlA~g`%t-mg?r8KoKEI~KD-3t zR$gY!b2~=)8{KPO2qXo!wY6;B)>PNh=zes-zSLd3Cy?aUJ@3qO?|dS(R+-q7B;1r+?> z-Lj?0jb3TZt!S@XU*ER50&GMZEJ6nRGd%O%(B0Vz0;Any6v!m^jtYN96f0(ZXG1d> za7R;Trq2z zg$h$mAC=*mBu*ve8>0oXY_JNgtYW{<%C>!f^_9bnh~IDJ`JOmWOC;F_%I5p-^_8=^ zBAnc}S>sU6vWqPg78ON{{G@!}I**crZQsY}Okuf|Q^W#?d%>)?tx*o z#_agBVl$D5)oLeOR_T{}{Wt|Otx7v=S!I?{YFWwlC^VGrd)JzRs+m!1IL#@yhQqj` za=&5wE(~3sfVbq@Dd(Thv4Byq~qFT6!8g1VjemWr2n&N4kLXA_X z@yc_JsSA2_HpFzER7RBM1yP|P&kC0D=#+sTW#xdESdPArf^QA5DvGT{WRh&(+4HgA z=79Nr17}zfzhxErp5M(ZGIvCoiHw45q3x^GL?n_KvBI|R9AiG}WpONgk72iD;(?|O zdNA0W<`-It#YMhk1BRo2*X~9ONp`+&?RDLnXIT-x&kPUql?AS#qlv%6BByD z8!oHHPO+>K9jQ^q<0vn@M#tp-PC4JNaU5;?jz$qThVMlMclvf3MV@b9P@-=F2O-Bd z4<&XfIN81`c2_K%k3vLNt>>zP@y1Kh2fN{a40REn=0|Z=to>&_*(ywc{9>!B&~l0~ z08=B{3!myvNE`H0(Dq#v^%}Xde#v8`Bp*^Ckn=7m;nu_QxH?| zFHb>1oPwra1-YJrrd|cPM%2?#9n)}uUVHQ!^0|&^HePM}_8113mTylK0f1EnZujj) zU^tBBRh%(;7VOo*k6CbkpIK0VCb3NP%mP-|li=E@F`t} zY|svRz%v-DfbIL)E;23Oqvm`oZ8hAaV_Pp-*ll<|-tR50C5SDn*eXfVuEqqmeHTQF z-0~Nkq3#bhI$_*U_Cq)c)6H{V*%aGRp`HQ0lnwD0se%| zzTfWVP8E_qp4wAcT-*0&b9`gO()cKE54-J(B9cp$4BOy>)RSz zn>tm^(j|4X7Ohyg-2KZjxN@1B-|Q@M|9Z^Maj&`AN^`sR1m?JRUS=o7-sse?iIz90 z_RdDUF51!A(%#w9z0*B;vz6a``s~ve*DYJKtZsSD>9ZHDSgz(Su31#aCTeG|oLyTt zuV(H%HLG^ftOd)+g<&n--A#?EtGm9tNpTZVCnx*$?e(3F*oVOEuX^#cw#6AdSifA_ zgqKlw*5Ny^E%lq5>UfTB-`1^>%b1Wp3S3 z%PQ!jM2RxBY;jE`UFP0@)EYAdHRKgs#TGD(O*lB@3I{>esh6xwTuI0dDISXY_zR{lHtpT4f#I8+LEsg6|$$I`sBTky8ij z8aAtL41ZT$S4&$%Q{DRZ_HISbq3WjgmbSXHJL;9ZirmuHv8}r|wq~C;cXr*mR9BYpb^ov4KX#Y3c>4b4s|o=Y1>Bk$*f?WdmM3=h*z!oX0+aq zx>>I}gR&)VTU)vq^=t>0bk=WipKWt$M)b@j-QPJgYHJlov7%=brLor5x^DNwGyJE! zkF`75lk4=$*$vw|JDb|N>-xvZm*4vCXomtXs@%iBu=DlaUhC*LHG6&16WGmXqv?vf ztt@w4hlBUZJDifzvzwdRVpE__cg^!j{A=S+cR1g5FW%}DxX-Tj=eVzKb?gE0Qf*D0 zSRm?J>+AJf=Joej1Ki|JCq1plC*Jx}yJ(eL(&@}_AL(>5+`o1@#ToH|r(&y$o89FM zcF*i`YTUE#vx?l8yPWVauR-r6d4^-1j&D5xN-u0nXU|x+?6eunXSlE4XAP;W@2K0{ zv{SWgz%sQ1V=k*~-?)!ohuymSt#J{rnLh8(yb0R4{>y9ieZg`v1 z>~8#twZI*F!WpVx=a(XcSZvKhv>aTLnC-r{%_&{k*n}9;R-Zm&wKp%g{Og&zoq@pV z5R1-Ofu6#RYQ>DD%k^TTx+`N#h}t%0G{*Ll?M|M%=mEIDOPVkOn1N7 zjz#ll58yi^nIN4_8?k83SUOuT|6^2FGbU0IeB>E}%e4N>XWiK?-OY70* zSBS5!E?kLk*x?LW&gQt(#+I0#^@vkW$w_wRjD-s-6uZj7iYdTi-liIH>0OUuKbvPs znXm4jcR15{s!w-6|EZN(+SkeT4O_RhV6&jtXMLi=Im~@zr!#zdC+t!xv_-i0h*K;?Wi?0g?JZvTE2gP`a z%TKL)>LDvPz`H?E>OS|7mF?f--|KU?o{O>Dey)>Z%yiq&b+Q0~H?a&%d(=vFe~=rr z-5nnV!fyGS2=O-tS^INhx4pDl+_k{9KEG^GA$QSRPDaG)xu50YPe7y_*Af;zMwi^%Xv5QOq5e!wI{A{GcBmD zQ0|UhPTt&vepM6H?NXI@+W2z=@gJW`>L;J1RTsHuzU|~>C-*B%)`cUKTXe!6u%d6D zQ`HmFP@`@rRm(2!X)RU#Uh>&mZe&jhGd}oQ>vIpEuyZr|s?N}=65VHiZuKw9(nUku z55HWLql+fE$-l62jTCqIFRVhq0zg0Yg<3GhZHHjLqGBmJ{N;pQg_zZXKLxDT`(GP$oi?@=~ zFsjFerfizZP#+7;d$DOM3or5`BOl7(mBpS9X}(npf8LCwA$1!Lj@BXH#f%@$R($$(C ztP=H8J0S33k8(h>yaFjr4efV7u|bt#A@6ft5x3!tdYg&9d+^47^8K$v%5hE6)s3xV zM|p)R!$pCzus$TL=^{voBzFK?;!FD>o80N=>;+4hN=|NQ$(UvVAc^~>8k_uUnHm(O%&|9v`c zM>llrWNTsk^i%x4yXWVcB#?S`F?DtIP4(+r>RPvKYwaOLA;rBo3zCho4s8sL-*t-&{1 zL`atq&%nEsBB$vyz1QAMOgHFK=GX9AGI5R=gnC*Z4AF+d5KY%B{_2i0*K2+Fg$xvM z3Yw^0MTFUGDAee^BEj-0A4N+YmHflttHMR+!C%8}WBEic9qgP4h zX2GL^j|e_3_@dz3f`1VVUL3I0j& z3&8{oIu&ILRtatt+%L!%=qPuS;8DT5HNyWt5yr!UJg>0AQ-Z%19{!EC`o!I8M3t}DzG#zMg} z1UCqF3hoxXSnvwLTLkYF{JG$Bg0BdEDyU!4hoOZQ#-A2f<0(4g9Kl*aJR_(1s|C*z zY!uui*dfRlsi@~X!F_^!8H)TX1P=?|z;}ySaF5`Ff{zP6FZh<=Uj-Afma^Ue!6Aa< z1o=xeEMF?PPOwezJi(|dnInRC3G(rGDmWqdo*=(OCx5yizhEc5NAM-VKL~Q^V|kL` z073pP5cqgQRTwh_7YgzbY*uU*+$MOw;CBTN3EnJtkKkj1#|2Lcz9;ApQa{E&UuW=A zl;AAEwSp~z_X<8P_e{F?=TEc|-~p9DtP(6b`&TPb)$@EyTVr2OB4e(bMVj}H?QQw1{w z3j|99hYOApoJ53y({Up~_h^w6EE8NS0`-F1guhdeKmA4p`vor{!ZTM(`L%+#2p$!@ ziwL;~g??E7LJoTHgfN~Kd|vP+!9Nhu;CnE28#0u==(}7T&B{)cMnBXWPxKghQ{U;(C_(1SuDgU=%G9IpGc|w$h85wm@)(h5@A3EF&D8G6-Esa4V^ByQUuNpGf92qJ!54@$wP{GKerJN3ej1@=C$E zM93`@TqoEjxSfcLm9GnZ2@(3fFLY3>Owh^m8pseV6&xivMX*M2m0+{rHo?7umkS;N>iz$Zh4HB1vw|lC z|0ZbR&1d$sjF^DmnId9LCkxIYVw%-T`Ff$Z5L1-eLxlVVg5S>P{71p1WFX3~lY$!r zZx#OCLf~{!4e`29a_NokAkUWAT1`s!sUWr6Ra29 zL_}&A+$a1C1rG>*Pw;9Y(shDA7XCeg4@D*OnBY@_#|2*`BE2H`q457E_?hsHLQgJ( zhz{fk76^ZYV5Q&;DUZ&U%tFDXf@ccW2{sG13T_kJDfkT{jJcSIp}c~Kv*{0|{6@js zh>&}j$m{=~dl~hF;M0QGkLc@xv4YD48w9%qFA%(4@FBtH1iv6o!%c49Hw5Y%lE9go zj^Y-H6!66{3hWpBf#5xY9}p+wG|T&Xz%s#^f=dP03w8-!A$Y5xzTb%YZ;*~6qj>ua zm?Eg}1A?v;dX->{;10nb2p%EMQ|fl1e?y#rm?6S_?-8-r3;8`9L9D<#r@$yPTgWKK z?{W&>DELbvHYR@%{D6ot)wj{W5AkLcFqL>3PSZjU6vSJ_x?JB~!+v2MX<)11*%s$N z7`w@Uf(xbKdqnI5ekAw|aUgm^#EHtbJ&X`@ar<6yvfzB8gNBHx^G(4UiCDNEC1TpY zz+cE==51kwdDjXwe^r=K`YpjDg8WHf@_#P)BykRY*i`7(1>YC^r(h7quwIVfAi;$L zC9_U&tKb!auuGZq-SZyz7fys-6(r#pjIMS>H4zS&M}+>x#8RbJ6XCFR#3Al)ANLQA zA`%XeMBU4Yh_Gvj({OK`I77akKr=YSYPHay)m9RRV3{OBPYn@zRuG}5UT}-xPQkAe zq5l$Kl$oo^KtneR9wS;xJwQa4A0c9Zeno^KPZKk+uoJWKYe_`(_f;bL`!*5%eUAuh z|3ZYJpAZq5pA!+;KK>R9Lp^AKfw_=OL{Bn^=m~%QkUh~~U%=48q-Wrlu3!`m{D6p* z#hZOFa3T=~;%95Mfv*!`;4t26gMqt=Fc1%dXaigMTe!6FAQ`YQEfEL{zej|HcMxIV zTSOS>@XiwqtRcd{ZxLbOrZ5l&zCnb6xXMxH5_}CpgrOsZhAM3^W|c0VhxWDQYlX3n zh#qtcy@Lo>?-%+25n8Vo`X(ZJ_Mp%Y6VbyLgg!yUP<$lx--+n3Lr=oMDBhFPJueal zf0>3J;4kx0pqdCzEEjq;5#7*V5TTs^H-MhGNXqp(4G&!-G@po|r}!)H)b}6}9(%!~ zv(yP@;JQym;4|V3_qD(JN4X6{gOO107yRzJNr8+6ei1FteYwTMf;lPuztMLKZwlmp zzuLBnC>nbjxg3u^mh(yEa_>uHeg*F)|HH{k^k~X9Ho03T1TyriU^8wCWL7rH_x1fN zceHomTY5ek+T7m0S@jmX=RR!>%Iu{*-QM@yE>+g{{m#2r@++R}j??Su>HkHy`{5T> zh7Vl#y)UesF|jAk@W6HFm+Hm}`8Zl{tL`t?`v*pQX|Xr*s2jf4x#g;8hDhX3sA`LtjEqhi+5uo)i8|_b0aoQbv}cR?Lb7 zNXBZt=hf<|bT{ZSchyZ!Y0`+ehLYT?a-3ZA1?5)E2xPj?^@4lFST9!gtG@&F zF%~)8=Ec`Pg!+0c-SH>*Q6BrmMvR-t z_*Q=leOS{}H4@LVF{@c0e`oeMKhf+BN60CV`omQ%UZKCC*9};mdlbInDeTdgX1d2s zJ9E-Y{pu&8ek`PMwbWDJhXx_qQ-6Z#c1*=Eoa$FUFRp%JT>aSdVzDVzEA?}sH{Sjc zarPI-)t}O@{dHdb=!AattK#aH#?@cluYNaZp88^+*Z}b{wRn4`KwlArs*!N^>hZ^g zp1$5Gb=-7Qrdyel_VrV+Hcr9dI0e^u3VIxx;?whI(xHC!&qIBjc2zaf(75{dOMM@B z{8amNTu(jLum1N?KQ=FhLoOC!zw1|@PYYzbe;I5=COy|r#i2MABjZ%?2?wf1g) z>Sx*xNTisa1dnWypKtWD%)cAml&(%idCW3CjDo)oT?vPaR=L%m_y;B3y$X79@|*$Q za<~1CK(77sv#?0}+yi$6O6=1x8aMjf2S4#=-&;M@S#Y5_vBE7r=8U@c!8@G>zpt{g p(*4ezPWioyk2x3k&8mqW<^PFOG0PlZ Date: Tue, 19 Aug 2025 15:28:09 -0700 Subject: [PATCH 27/36] Don't his the lwip_callback data structure No need to add obscure __align__ if we don't pretend it's an array of bytes --- cores/rp2040/lwip_wrap.cpp | 9 ++++----- cores/rp2040/lwip_wrap.h | 6 ++---- libraries/lwIP_Ethernet/src/LwipIntfDev.h | 4 ++-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index 2c482971f..b1b6d7aa4 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -825,13 +825,12 @@ extern "C" { return __real_ethernet_input(p, netif); } - void lwip_callback(void (*cb)(void *), void *cbData, void *buffer) { + void lwip_callback(void (*cb)(void *), void *cbData, __callback_req *buffer) { #ifdef __FREERTOS if (buffer) { - __callback_req *req = (__callback_req *)buffer; - req->cb = cb; - req->cbData = cbData; - __lwip(__callback, req, true); + buffer->cb = cb; + buffer->cbData = cbData; + __lwip(__callback, buffer, true); return; } else if (!__isLWIPThread()) { __callback_req req = { cb, cbData }; diff --git a/cores/rp2040/lwip_wrap.h b/cores/rp2040/lwip_wrap.h index 43d8a6c9c..c2a3011a5 100644 --- a/cores/rp2040/lwip_wrap.h +++ b/cores/rp2040/lwip_wrap.h @@ -569,14 +569,12 @@ typedef struct { } __ethernet_input_req; // Run a callback in the LWIP thread (i.e. for Ethernet device polling and packet reception) -// When in an interrupt, need to pass in a heap-allocated buffer (i.e. class variable) of -// size LWIP_CALLBACK_BUFFER_SIZE that will be used to store the request. -extern void lwip_callback(void (*cb)(void *), void *cbData, void *buffer = nullptr); +// When in an interrupt, need to pass in a heap-allocated buffer typedef struct { void (*cb)(void *); void *cbData; } __callback_req; -#define LWIP_CALLBACK_BUFFER_SIZE sizeof(__callback_req) +extern void lwip_callback(void (*cb)(void *), void *cbData, __callback_req *buffer = nullptr); #ifdef __cplusplus }; diff --git a/libraries/lwIP_Ethernet/src/LwipIntfDev.h b/libraries/lwIP_Ethernet/src/LwipIntfDev.h index 685872043..36529ed05 100644 --- a/libraries/lwIP_Ethernet/src/LwipIntfDev.h +++ b/libraries/lwIP_Ethernet/src/LwipIntfDev.h @@ -194,8 +194,8 @@ class LwipIntfDev: public LwipIntf, public RawDev { err_t handlePackets(); #ifdef __FREERTOS SemaphoreHandle_t _hwMutex; + __callback_req _irqBuffer; #endif - uint8_t _irqBuffer[LWIP_CALLBACK_BUFFER_SIZE] __attribute__ ((aligned (4)));; protected: // members SPIClass& _spiUnit; @@ -490,7 +490,7 @@ template void LwipIntfDev::_irq(void *param) { LwipIntfDev *d = static_cast(param); ethernet_arch_lwip_gpio_mask(); // Disable other IRQs until we're done processing this one - lwip_callback(_lwipCallback, param, (void *)d->_irqBuffer); + lwip_callback(_lwipCallback, param, &d->_irqBuffer); //ethernet_arch_lwip_begin(); // d->handlePackets(); // sys_check_timeouts(); From 5912d410ad255ba1b6aedcb2daeed3a671703d4d Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 19 Aug 2025 16:06:01 -0700 Subject: [PATCH 28/36] Rewrite CYW43 driver for LWIP thread processing Don't use any async_context for the __FREERTOS case because the extra context mutex causes deadlocks. Rewrite and simplify the CYW43 driver from the SDK to use FreeRTOS native primitives, no TaskHandle, and hook into the LWIP thread. --- cores/rp2040/lwip_wrap.cpp | 40 ++++ lib/core_wrap.txt | 10 + .../lwIP_CYW43/src/cyw43_driver_freertos.cpp | 187 ++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index b1b6d7aa4..1d12f3f69 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -842,4 +842,44 @@ extern "C" { return; } +#ifndef __FREERTOS + extern bool __real_cyw43_driver_init(async_context_t *context)' + bool __wrap_cyw43_driver_init(async_context_t *context) { + return __real_cyw43_driver_init(async_context_t *context); + } + extern void __real_cyw43_driver_deinit(async_context_t *context); + void __wrap_cyw43_driver_deinit(async_context_t *context) { + __real_cyw43_driver_deinit(context); + } + extern void __real_cyw43_thread_enter(void); + void __wrap_cyw43_thread_enter() { + __real_cyw43_thread_enter(); + } + extern void __real_cyw43_thread_exit(void); + void __wrap_cyw43_thread_exit() { + __real_cyw43_thread_exit(); + } + extern void __real_cyw43_thread_lock_check(void); + void __wrap_cyw43_thread_lock_check() { + __real_cyw43_thread_lock_check(); + } + extern void __real_cyw43_await_background_or_timeout_us(uint32_t timeout_us); + void _wrap_cyw43_await_background_or_timeout_us(uint32_t timeout_us) { + __real_cyw43_await_background_or_timeout_us(timeout_us); + } + extern void __real_cyw43_delay_ms(uint32_t ms); + void __wrap_cyw43_delay_ms(uint32_t ms) { + __real_cyw43_delay_ms(ms); + } + extern void __real_cyw43_delay_us(uint32_t us); + void __wrap_cyw43_delay_us(uint32_t us) { + __real_cyw43_delay_us(us); + } + extern void __real_cyw43_post_poll_hook(void); + void __wrap_cyw43_post_poll_hook(void) { + __real_cyw43_post_poll_hook(); + } + +#endif + }; // extern "C" diff --git a/lib/core_wrap.txt b/lib/core_wrap.txt index 516a2de82..df9b3f069 100644 --- a/lib/core_wrap.txt +++ b/lib/core_wrap.txt @@ -79,3 +79,13 @@ -Wl,--wrap=cyw43_cb_tcpip_deinit -Wl,--wrap=__stack_chk_fail + +-Wl,--wrap=cyw43_driver_init +-Wl,--wrap=cyw43_driver_deinit +-Wl,--wrap=cyw43_thread_enter +-Wl,--wrap=cyw43_thread_exit +-Wl,--wrap=cyw43_thread_lock_check +-Wl,--wrap=cyw43_await_background_or_timeout_us +-Wl,--wrap=cyw43_delay_ms +-Wl,--wrap=cyw43_delay_us +-Wl,--wrap=cyw43_post_poll_hook diff --git a/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp b/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp new file mode 100644 index 000000000..8af3daa73 --- /dev/null +++ b/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp @@ -0,0 +1,187 @@ +// Rewrite the CYW43 driver to use a native FreeRTOS task and primitives +// It seems hard(impossible?) to have both an async_context mutex and the +// LWIP one, owned by different TaskHandle_t's, and not end up in a +// deadlock case. LWIP task may need to call CYW43 functions but if LWIP +// was invoked *by* the CYW43 async_context that mutex is already taken by +// the async_context task and any cyw43 calls from the LWIP task will +// deadlock since they can't re-active the async_context task to resolve +// the mutex. Ouroboros time... + +// Based off of pico-sdk/src/rp2_common/pico_cyw43_driver/cyw43_driver.c, +// Copyright (c) 2022 Raspberry Pi (Trading) Ltd., +// SPDX-License-Identifier: BSD-3-Clause + +#ifdef __FREERTOS + +#include +#include "task.h" +#include "semphr.h" + + + +#include "hardware/gpio.h" +#include "hardware/irq.h" +#include "pico/unique_id.h" +extern "C" { +#include "cyw43.h" +#include "pico/cyw43_driver.h" +} +#include "pico/async_context.h" +#include + +#ifndef CYW43_GPIO_IRQ_HANDLER_PRIORITY +#define CYW43_GPIO_IRQ_HANDLER_PRIORITY 0x40 +#endif + +#ifndef CYW43_SLEEP_CHECK_MS +#define CYW43_SLEEP_CHECK_MS 50 +#endif + +static SemaphoreHandle_t _cyw43_arch_mutex; +static SemaphoreHandle_t _cyw43_irq_called_binary; + +static void cb_cyw43_do_poll(void *context); +static __callback_req _irqBuffer; + +static void cyw43_set_irq_enabled(bool enabled) { +#ifndef NDEBUG + assert(get_core_num() == 0); +#endif + gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, enabled); +} + +// GPIO interrupt handler to tell us there's cyw43 has work to do +static void cyw43_gpio_irq_handler() { +#ifndef NDEBUG + assert(get_core_num() == 0); +#endif + 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 + cyw43_set_irq_enabled(false); + lwip_callback(cb_cyw43_do_poll, nullptr, &_irqBuffer); + } +} + +static uint32_t cyw43_irq_init(__unused void *param) { +#ifndef NDEBUG + assert(get_core_num() == 0); +#endif + gpio_add_raw_irq_handler_with_order_priority(CYW43_PIN_WL_HOST_WAKE, cyw43_gpio_irq_handler, CYW43_GPIO_IRQ_HANDLER_PRIORITY); + cyw43_set_irq_enabled(true); + irq_set_enabled(IO_IRQ_BANK0, true); + return 0; +} + +extern "C" void __wrap_cyw43_post_poll_hook() { +#ifndef NDEBUG + assert(get_core_num() == 0); +#endif + cyw43_set_irq_enabled(true); +} + +void cyw43_schedule_internal_poll_dispatch(__unused void (*func)()) { + lwip_callback(cb_cyw43_do_poll, nullptr); +} + +static int64_t cb_cyw43_sleep_timeout_reached(alarm_id_t id, void *ptr) { + (void) id; + (void) ptr; + static __callback_req _sleepIRQBuffer; + // 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 + lwip_callback(cb_cyw43_do_poll, nullptr, &_sleepIRQBuffer); + return 0; // Don't reschedule +} + +// By construction, this will only be called from the LWIP thread on core 0 +static void cb_cyw43_do_poll(void *context) { //, __unused async_when_pending_worker_t *worker) { +#ifndef NDEBUG + assert(get_core_num() == 0); +#endif + if (cyw43_poll) { + if (cyw43_sleep > 0) { + cyw43_sleep--; + } + cyw43_poll(); + if (cyw43_sleep) { + add_alarm_in_ms(CYW43_SLEEP_CHECK_MS, cb_cyw43_sleep_timeout_reached, nullptr, true); + } else { + // Nothing to do. We have 1-shot alarms + } + } +} + +extern "C" bool __wrap_cyw43_driver_init(async_context_t *context) { + assert(get_core_num() == 0); + _cyw43_arch_mutex = xSemaphoreCreateRecursiveMutex(); + _cyw43_irq_called_binary = xSemaphoreCreateBinary(); + cyw43_init(&cyw43_state); + cyw43_irq_init(nullptr); + return true; +} + +extern "C" void __wrap_cyw43_driver_deinit(async_context_t *context) { + panic("unsipported"); +} + +// 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 +extern "C" void __wrap_cyw43_thread_enter() { + xSemaphoreTakeRecursive(_cyw43_arch_mutex, portTICK_PERIOD_MS); +} + +extern "C" void __wrap_cyw43_thread_exit() { + xSemaphoreGiveRecursive(_cyw43_arch_mutex); +} + +#ifndef NDEBUG +extern "C" void __wrap_cyw43_thread_lock_check() { + // TODO +} +#endif + +extern "C" void __wrap_cyw43_await_background_or_timeout_us(uint32_t timeout_us) { + if (__get_current_exception() > 0) { + vTaskDelay((timeout_us / 1000) / portTICK_PERIOD_MS); + return; + } + // Try and take a binary semaphore that only the IRQ will give or timeout trying + xSemaphoreTake(_cyw43_irq_called_binary, (timeout_us / 1000) / portTICK_PERIOD_MS); +} + +extern "C" void __wrap_cyw43_delay_ms(uint32_t ms) { + vTaskDelay(ms / portTICK_PERIOD_MS); +} + +extern "C" void __wrap_cyw43_delay_us(uint32_t us) { + if (us >= 1000) { + uint32_t ms = us / 1000; + vTaskDelay(ms / portTICK_PERIOD_MS); + us -= ms * 1000; + } + delayMicroseconds(us); +} + +// Generate a mac address if one is not set in otp +extern "C" void cyw43_hal_generate_laa_mac(__unused int idx, uint8_t buf[6]) { + CYW43_DEBUG("Warning. No mac in otp. Generating mac from board id\n"); + pico_unique_board_id_t board_id; + pico_get_unique_board_id(&board_id); + memcpy(buf, &board_id.id[2], 6); + buf[0] &= (uint8_t)~0x1; // unicast + buf[0] |= 0x2; // locally administered +} + +// Return mac address +extern "C" void cyw43_hal_get_mac(__unused int idx, uint8_t buf[6]) { + // The mac should come from cyw43 otp. + // This is loaded into the state after the driver is initialised + // cyw43_hal_generate_laa_mac is called by the driver to generate a mac if otp is not set + memcpy(buf, cyw43_state.mac, 6); +} + + +#endif From 9eae58cd1a012dfecf14de3048c09991a60a59fd Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 19 Aug 2025 16:24:29 -0700 Subject: [PATCH 29/36] Unbreak bare metal, fix missing library --- cores/rp2040/lwip_wrap.cpp | 22 ++++++++++++------ lib/core_wrap.txt | 2 ++ lib/rp2040/liblwip-bt.a | Bin 6006748 -> 6006160 bytes lib/rp2040/liblwip.a | Bin 602362 -> 638402 bytes lib/rp2040/libpico.a | Bin 1480332 -> 1480332 bytes lib/rp2350-riscv/liblwip-bt.a | Bin 16426940 -> 16425860 bytes lib/rp2350-riscv/liblwip.a | Bin 1411872 -> 1410800 bytes lib/rp2350-riscv/libpico.a | Bin 3661846 -> 3661846 bytes lib/rp2350/liblwip-bt.a | Bin 6056788 -> 6056268 bytes lib/rp2350/liblwip.a | Bin 708268 -> 707744 bytes lib/rp2350/libpico.a | Bin 1564426 -> 1564426 bytes .../lwIP_CYW43/src/cyw43_driver_freertos.cpp | 21 +---------------- libraries/lwIP_Ethernet/src/LwipIntfDev.h | 2 +- 13 files changed, 19 insertions(+), 28 deletions(-) diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index 1d12f3f69..3dea60bd8 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -843,23 +843,23 @@ extern "C" { } #ifndef __FREERTOS - extern bool __real_cyw43_driver_init(async_context_t *context)' + extern bool __real_cyw43_driver_init(async_context_t *context); bool __wrap_cyw43_driver_init(async_context_t *context) { - return __real_cyw43_driver_init(async_context_t *context); + return __real_cyw43_driver_init(context); } extern void __real_cyw43_driver_deinit(async_context_t *context); void __wrap_cyw43_driver_deinit(async_context_t *context) { __real_cyw43_driver_deinit(context); } - extern void __real_cyw43_thread_enter(void); + extern void __real_cyw43_thread_enter(); void __wrap_cyw43_thread_enter() { __real_cyw43_thread_enter(); } - extern void __real_cyw43_thread_exit(void); + extern void __real_cyw43_thread_exit(); void __wrap_cyw43_thread_exit() { __real_cyw43_thread_exit(); } - extern void __real_cyw43_thread_lock_check(void); + extern void __real_cyw43_thread_lock_check(); void __wrap_cyw43_thread_lock_check() { __real_cyw43_thread_lock_check(); } @@ -875,10 +875,18 @@ extern "C" { void __wrap_cyw43_delay_us(uint32_t us) { __real_cyw43_delay_us(us); } - extern void __real_cyw43_post_poll_hook(void); - void __wrap_cyw43_post_poll_hook(void) { + extern void __real_cyw43_post_poll_hook(); + void __wrap_cyw43_post_poll_hook() { __real_cyw43_post_poll_hook(); } + extern void __real_cyw43_await_background_or_timeout_us(uint32_t timeout_us); + void __wrap_cyw43_await_background_or_timeout_us(uint32_t timeout_us) { + __real_cyw43_await_background_or_timeout_us(timeout_us); + } + extern void __real_cyw43_schedule_internal_poll_dispatch(void (*func)()); + void __wrap_cyw43_schedule_internal_poll_dispatch(void (*func)()) { + __real_cyw43_schedule_internal_poll_dispatch(func); + } #endif diff --git a/lib/core_wrap.txt b/lib/core_wrap.txt index df9b3f069..19014cf6d 100644 --- a/lib/core_wrap.txt +++ b/lib/core_wrap.txt @@ -89,3 +89,5 @@ -Wl,--wrap=cyw43_delay_ms -Wl,--wrap=cyw43_delay_us -Wl,--wrap=cyw43_post_poll_hook +-Wl,--wrap=cyw43_schedule_internal_poll_dispatch + diff --git a/lib/rp2040/liblwip-bt.a b/lib/rp2040/liblwip-bt.a index 9987b43f354c6fc7283f86292368056fb4c741ba..cf1b86592fcedf5c418ef1ebc35412874d68458c 100644 GIT binary patch delta 20140 zcmeHPd3;pW^}lbHH*eNVGD&6{76X``A@N zy}04hCCqvqur=w+t_|uX9Ja4vwu|A55@x#$?9EabM^Oc{UjhzR!8iuYVGflZb8495 zY%Oy(y8?zV<_yN9V&)8B!7=8%4yYG%a#gKj4OqH{xvmi*Y!$mosD8ud3Jdv3px&H@ zL&JBl2BaKkp#j|PW}(4QgN3^evCvx#^{N{@u$qN_u>Yb6v!pSOCNo)BhT~eGUW@Tf zuvM=q+sh|#W)};)R;btNaD(mDYtHz_CV=_Bu>r3!o_ZZ~b|Vx1KRf@vsXN&%fO;z$ zxl9}CE$QW@6Hsr>FkdnO^%l(WB^yWE|3Cjf?E<`^^B?tH4Z9jdXRc-fYM^jFk4{51!a^ zGW*eZVhKyU5{_(TiRVGRQ1L@KDWi~ajLl|A7vhwOCH)wvSK*v&&0riQCYF4)`1Kr? z9E29(DXalQPp}pOYM^knoHD1DT?whmBG!OG^H^#C51(VHL1^h*tuj1*La0Aw<7it& z@6!%eUNzD)Q`n7!dLx5Ttc=k~*8UU~8?GU@sXqVt-SA=>s zMmNz$y<&z}Xguq~?TpZVSzZG=M3%6tgnG4xm$%#UF6(ezP_Ng~@7FOui~T65KQ_Q+ z{5!pKj9m%pl?-lFeV0B<*hQfJK-tw(!>$Ye8qT_21+t&r#TtR{|3={_D68jXbL$gO zf70GRyG!N6-$SZrmqgrF*5jrD_dg2Wb7Ae3@z>)l$CL0w4DZWwrtV@ni?0Lf^*CLF zPp`V|>~c^qR~cM)TbB}c6QJIVpw|#nJ-=6ddS$R%3iTE?*w;CST?q9;#YN?n=UCsH z1NCMFzRI}j4|~>sZ9Tgr_MBk-uM-2-*03Kyy_oVcx`EFvVb_a6b9%E2pcy0Q+`$Sj#FZ8R8Q-L_q6;v}d5m$y*0NETLg_g+im-71`1@vO zwHs4jKBjD1*}_%L^i|EI!y#t=PhzxZHru?_we2Lp02l!iVAgBf$p@U=C`0>fxz(r7 z&yinp2!-^l&1dS=DWj7%f19m^=U6XBKjth>DXb++)wRL$W@+S^=ZljE-zKdL9Z((h zjju_inT@hU|83=OUP+8%EMX{PE5ASU-S?(A_kQV7_866w0SWB1&oW>$*-u`52TL*R zPheDY=6AbpZ((KZfWp{O%{oMm)m%g5{^~q8nr4!T8gD)ukJxi~oPt#xsl<;}u`G}n zvzja`jUY)WkQqxhnaiflWTw_IGW^S%4zeodeFh@a3^QYaUcjIBY6PcUB!-}c=9+iEbyHO55NQw_Bg9Oh5R6as6lhp8KBuqjOQ$~0_ z$|*+bsATAcY~%!#Q%&p8vU#qDhe(H|xythN3n&-akC*DOtjN^bAk z1IgxvH&Y(P*sIE7cvLCl(DYm-ALTi!;)LS^N*6ruS8`x`%3 zj0qE&^`M7pT!sZ?_5rU6VR9AXwcJmA=Y6w1F8fe#dkv<{wiQ8;R9|hza5+h>LZiht zr=;Mw*UUos*xXWRCzvzK2GrRiBqt4%$?_e7+9Lgu5;JKw^ZLsUOAB<}mMVo&2)E_e z)KnYE^D{`{mP(ACElct~2gzso4@T71LyCD1QjBGoiFIJM-hMH`vVa;GDDeSEvh<@c zgC%P`l1Q=KMPY_Y?$?l4Z_6QVK)xK^YAK@FMoUT?m<+UhO70~RAA_M58YHH{Tq)*DI2JO~DYN!czT8ZDPWwl`+*<0UxeDZ@*xi)ld+vY1M*b9!G_scX zh?tm`TOf~A_fVWCrASiBcC>4XL&@GPq%%g!_X(QLvJX>cAW%qUSt+v@_}8PM0NL9M zd4?tfb=O|R1+$?Pw)SE!$b6dZqq$%){1>g;OTxyYNySh{W@A+@*$jzj$Ucq>4nr|U z$UdG6E<-xilybpsD5X{>a3Rbv332Qbxe#vnfWl4U^XoI@VixU_U9>S`4A~T*j0*{d zD9ZFME+iRbBP(L|a^9m9Lkwj%l?!Qx-efn83mJiZ<#gWwHI5_Py3lZsHla`+q<&4hkBroG_(+snC!&<6IBb%82}H{S=%vFhxky0Lbdo)a zVjDWwJqDK00>k8RNXEOM%=i-h+G}-|yZ?l|4IjhSIn_<(%)AQyzneFmr-31mYw!_iDG^RaqhJrM&wfXAY7#_9QBhGvjH{t zbD>NzzYO64F5IPUCo35DKqDu?7 zFheoZYhocE(|Z*2Rzz6j{1;MKshH_NSQ7RngaeAX06l*wbShLe*37A6$1~?jXDTw; zWi>yD*mXRIJysUh74hDOk3_wa-q+d`$!(ki&>QD!<0d$`@6)Cf$qCJj2=$3{8`i3S zM@9S-mB*yv4GQ;IZCjBXDfQ9*2zzOn_HmIMpBd2}VPBM9ZZL~|2F=^&%ljKNQTJf< zov)iIle1QB&?q@p{R>)iwvo85i4AS0lQ}QZ7&Dnxn0p!Wb|(6*avH2C4mV{{w8LFP zEcAjKOZBwvB|5XEr_n6JS#Nw&( z1FP-llxmv4Z)kwgt4><;IIN;iAyS%@OhXb5tpo6s&725b2KBu!&=ZKH1(7a!C|(uh znLxWpJjme@1R5OqdvvCaq z@-bR(4H2;wIDT*=Vaz&Qg! zjgp!tWf-L)rnzjD!6*$i+Hiw#wS~zPm<;14d4`!V9AaEiD#LL}}6(vT)TxOWXjH+R-$qZloxJKhan{h{jA9IyLN85H^ zkgfu{mC$`Gboct>monG=sNrV<(rjqiIIG6Pobymc$BAE!qk^tki6J<;9qFhtvS!a? zimK_yu45Mam2smXxjwy~MI%xs!bv0emjV*P;-oI|?u=+d8L0?b_5dF76>P+9 zv`OeXz8c_-7gFOdL)r;6p@lixN^9axhBym%1SZ*vTqK?g zpX-_0@hp3++>aT2RX#0uocyh}esoy4&ufyp+wJy#o-X#T_Re<6gLBIx8C}}B79*3i zrpKK|6c3Bx@nk{J=1W}Cd&)Y=@10BPOfCPhdFg-MdRGc#j^k?5}slJ?@47s~@x78A* zFPo7dob7hB~F<0ItX|;m~xXrY$^0a3@ zu{P0m1>|t;RBhQ9r(4_R>5-s4c23FAK8#9nYjN{r zx0I~s&XcW@O7F`s{Ffp3i(`qhr&sLHE|8aBAk&?fRJ0$%SSWk$f_gfs8tXmmqYLWK z`0H)_1{202SconykROt?hZo9m+CLY{KJAT#@*Mo5LDmUP7_jBDiE)(nCdS!FXQZvQ z|F&amgHJ}1GZ{W-z<9%!5VylylsF5wa$;OO=MZ_rX24DuqWyMJMhlhN zCh;M`%LV^ZFwY6~n}w_k-X-`g!S4$`F8C|KCJZaZ_Xn&75sO>M+MV6pZuLBKQ|GaD!8NIp>!D_ z!?8lKSn%_L4+=glI1eu$vL7dSn&2gZ9})b7;HL%e6#SatzYG4zjQOX4Cxqf#!8V-j zr1uI=5}YZxyWjzW3k6RQJYO(0weoOEn!Jh~|E!e2|{Z#t?qX4mjTMF(dxVPXTf=3IUBDhlU&jdd#_;JB6 z3YKwRQafRS+xb~#y@euQaJk^6g0~6&z2LtH{zh<99J~~`m*8=ND+R9-yhZR%!EbP; z`NtQ;9g*r9PT0o0#p#= z0)+oCj>``bBfv7jYXv_c_&0)I5WGk5>w@1RM%;r!{!s8oLjSpg_CFf!B z3jT-~fzJq5@Et~WPGa0nVuYMbjCd^tcNW}Da4%x`jTG{oswj*T71M|j@Nr`7)r~^_ zt>8BV|64F!56He5F#@L%;}GjA$u z6}(pH>xH~k@H0aHqL5z}{8wVM^IuW_9kCPhZ$O@jYMjJZ5RjG>D(`8iu~x!`%k z=;7mne=qng!7{znoZ9FAE%ItlElX6i*Oucl8@tlxjzV|yME4PZcLPI&R<-V@io7b4 z;dfmmiQ6Tw?oEtQ=}#Qw{txOM8X6~({Vg$KeoKrv8z>pXiKb*QTJ(2O6z31bh;xh> zZPTZkA=Q74S1DkcP-GBe6b1^J=Zyv?3%Q&a4J{FJ4KW(rAmn;tG`v^H`-qXiVIdzS zMk4&;iUiKlcOWv-=68s1tu6gsf=ydqhY#P974i=4>$QqY&wW_#CuvVlv@EU5YmsEl z#*ID!L0V`-R>^l*iy{* zg!P5bh=v{h_`jjSowOl!vNtvoI=muTPk?@o1`utf!iGZP7eNgn=~9nB4L@%;!DpB@|9075^sEZ~0K=r1{gd$T4eL|jmaBNv2t5FygEoKbdQ5eTjwiOYythmG;MT*HB#HZAYaiAC50&FIcfOH)7GECFlWqmxm#xS z#I+p}s6RDrrjgeF^`OUHP?C`FT2XT+Ps@s*matv}~zX5QVC ze$|xo1x7e8N0znLkI63aPcBYYIlOw|WAdDXL5k`VGcEdwnaa-2LYecJ?A7;fQ?^eE zR;-G&PM*&HA1E0ewAPsgK0SJg^-W7-AfIlowf<^pu;P!gwqe!6M~~ZRTV@IbfZ)?# z-)yTpUsJWsR%PN5GPNOp>lvj-KWp36y;0%QKR9XI(oQJG*7f!28=Ko(brgyfWm?RX)!>5mJ>RcX3 zj5q5{b`DDy7Sr2?`SiKNoIN4~F^(pB^>@ph6-|VKCsz71XYDsav3`6~lpZ$U^{Ibq zGBsHE^r%|b`!fPDD34HM$cR856r*}kix7QL3-_uogcX{O(mQxVBg2K_cYXphuD(1@-+eX}*JRYNPJ zI2jxEKtLfav3m6-ZNpaoNx0+;mc7;4XTtyw5Dr8Dk$U!7@8Ma(h71c(7*_4@H~lOu!yAB6P#; z4Xj+A;EwT0TOSq{q^O>EI!T{*y16@$0$TIwPuY|8g5Wsw#w8aAwgfDq^s`%&mz|g3 zhR7CM0~?R$Q=Z>KFV9a|6j&3yd54iIop--b zAg-@E!rc;RrAN5aUfL}x_yYXwK-&NKj~B5!zC4t+GSCa2(uQ{F)f?Ki2HNNw+GQM0 z3(7=aSCVlca4ztXsa>6+*RIZV3vDK?MT+5r-K#yYTKWx4ptoUbtrx$STTHChn|~-f@i;dL`Qx5h)$~)1S?AqcG61^ zc3u=%mOLj@-!8}A2#%#hcHR1yV8#A_cg=gVF^;dg+Y8x1H@({n-G31nf4&sH{HD7{ z5te+0l1x30#WcElt5cfx&{LZB+*=ylfMapbp1F+*95H|E>FpV;_+> zz0>IGtyb0#(3SNA4+r)WC9a$Ff$IVX9iO3HRfA&oHpcPkU*A61lG&*6J{eOvcuk}1 z(>sUfzTYcYkvSrF`FRJxp}JiCP+i`+zxB`j`J4a@&bUSFb+&?V)LbRm9U- zlRwOHr?B7&@BYoOU5kQU)^!{{`MqF8QfU6pDGaV9I!6`;O-?YT6jotCzb9b|wl1&4>n`M_7n$^6i+R5*stqh2-b(u0MPq{c s;??WFEm{{A>{99;RTH!)a2-h)m3v39MdhSXI|3uk6C1dARBhA$1;Q)wSpWb4 delta 20448 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 diff --git a/lib/rp2040/liblwip.a b/lib/rp2040/liblwip.a index 4961070e98fcb2141bc83a1a20ac30f046bf4b44..e1669eca9fa004f7b5c3e52ea9fc45c54af5f5ea 100644 GIT binary patch delta 38925 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 ORB@S=U%FQe|Nj8!)ORKT delta 10320 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 diff --git a/lib/rp2040/libpico.a b/lib/rp2040/libpico.a index 2246c71fa7e7896bb6eb4e2adf534c042799cc4e..62750c3ddafb76b4b58c1eb62b549d9dafd6de43 100644 GIT binary patch delta 1460 zcmY+ET}V@57{_sQXKr(w+uY6~i`4wUgkrM~leDrf%rqp5nx$l5NTnbJd80*STDlTp zM;i*Q& z)K;H@#*!HgFSZ2z2?#p9CSJ^&yJ$y13yl9=@*$|S*qrd?Uc}2bMp~sd2Lw}9uha|x z(GbW-e<{`Mgu-j8vKS^w;=0)_>Jn;&&-EZal*tO^#{}r zB+d5*W`)k~$ocJSt~@-Pj69ylfFKVAtnr%p0`y<0)Of1!L8ed=kG{0>r&Y~@gAr1h zhgk==n7+>CXD&Axi$tCy%%0-5Z9yWJY&F&8!_^w@CN2Y3u5%JT1ftmq`bN%&!j-OH zJmJ3DFb$p6$SAjJV1%lf{>XJ_tpO(lVzu5hj3K@8P>`cdyo7}I)ZC-(4hg1ti-Ov! z8{uhY4n(O^72p=+!-3_BsJZ8uX2oH5!b-AE%0@CXq9ZMo>&A*10YW4XOF^}Mi_`an z7D00kmh07_2I=a@YxHkICr!!IR(&x$2A4qVx_b529IQ(lI=7%tVM}rYi8`_n67j>3 zwg(@kr0DG3>jEpzM5{4SnR#P%bmwCB7olOKDgql*|eRb`+HJ+bB`lRFU! z9p<#dY_KZC4dh$<{fL=qhUHQ7-AJ^0$IS`eHLC+gOJlAiF{`rfv$tY~0g0k{pC$J+ z5?RCTcAo{>eb!@p83pN`btqGLuwA{@+d4TklRu0~f4Eub)Ydqfl`9y_ihY1SPuP(YvRdn19w;_0{tt?9ja>E<@Kxu3`)HGeRnX=yD)J z?O8dwSwl&a$LY@;hu;&WvGRr!gBuVS*sQSfGj5X}0Z*pP#_Jl!RR{=2v{wFaupeaRaO;;3Zf*uX_E1E$PwFuPMQ3?4LM>RkhoFq{lqxL#RikV zBU4vdg)XE8j}@P3&qdw30QO8r z7d4`D??ehcvDRhXj$}mWFlQ`!jS)4;f9=;p7EpziG5sBd1dtI;=#xBauND}qjJuq| zUZvHXxfwSCj3V8UW3Qp`6mrBGZguz!(BU&4-NSewyfqFxB1z(nyi%LGIF*UzBGhY5D8-xypx;z zl-3D*7PNYv+{-D_xWDa!3Kg%qEgZ}`c CV$1aa diff --git a/lib/rp2350-riscv/liblwip-bt.a b/lib/rp2350-riscv/liblwip-bt.a index 3b7999f90dfe066e2d571f37926ef454b402dea7..16d1786537d98ab78ca2be1b3c432362de400872 100644 GIT binary patch delta 36415 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 UhSwgx?&n^&=*G#!3wvh$KMo_Pz5oCK delta 36924 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 HPagPxGi;JO diff --git a/lib/rp2350-riscv/liblwip.a b/lib/rp2350-riscv/liblwip.a index d80f887602af5e34932e651ffe5fa0114f458635..b1850ffa47084ff6b1396e72b3b9d2c3388f61cc 100644 GIT binary patch delta 26677 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 diff --git a/lib/rp2350-riscv/libpico.a b/lib/rp2350-riscv/libpico.a index 65d5bb2940cb5cc28e37310c10f7970eec8497fb..e457e2f550a079b57a7618e66b057a6c6c0b6d13 100644 GIT binary patch delta 1494 zcmZWpSxggQ5KfU6kgJy3ZmmEmA_}y?_98rp2gG;~jo=kxt-g408}WfeR1#SuVhkP| zQ6n*x2cuG~c8sVfpiv`u5Pg6|k$@TwZIFO5M*VmDPXqB`lI}O(%=gXgbk9BdC^<*s z)O?xMY+)_t7QHLS_mkxv6ETe2o6~MYpwT2%xx4q5X(({krBJ&IPS%FbAOtixvWdka;$t8ii^zi-N+%5;xne^3o%S2pfb^ zkVh=0i06}h=UdDQZxO28bAok<2rn9(J#%CRirjH2R+nIHsUl(_GUa8_8Zewy6h~47 zh`PNF)1o;o8zQC1-G!TUEolrTUf2 z5fPVgt6IN1mi7cPa^-WHhQ`A9n^KzLg+t|v%Hv5afTHq*4@;0nCjLDA525Dr1`{A} zaN(LUEEa|Cy-C!4qX^gEwur=H5=qeCmfYQoRI*G4UN)q7F3|qGYs{#D8+Y0J64;hu zs0+dt$+RI*eKDT#e*#DsdkBh%?=gAG2+32ah5NCd zP<-{VyrU#75Gsn(j-pykMOsZox~GC2jz+q-p5043vV!&|eBen&1MjY~x&I-TB>Z8g zVGr+ZVP%lp!Y-rzS^t!){3gYZoU)w-WxMH5z2ACayoO8PXeMES^o>?afzmr=2Nj0lvhSIkP0IW9hsV_~?KS_QP!j{A8A(Ph3Q1J{{4oHcJKCtk9l=$P)!1;$G;TbQy8+ zqFHX}M<|If82T~cV=Lu~eZx0lV(v<$5)TZwB4QG(hzPIRizN@=(lRhy7v7Xb5g_(n zJ`E;`UXPrJhKZ%4-K~s-yOmK*EG7{jZ}N~rUi45p64jl9NTZjyS!Y+5?n6YJ zAPj*za;A*9gxBf~&+$~eMX2;ghnWx&FB-hv(JBi?uKF~Kw$W#yR1-NJnd-7w16Yn} zwnk9|h`PHDk0o46Dh=?o*Nv| z!r;i{jT=W-Ds}4|tC1#(aUFt=gdREsW;V6q;-wBF^9*zTAXi$8;@l~T1BjT;ni;r| zY^;BTh$LI|)d)pjr(WJIqfQ_lAEM2=cxgvk_rxkQMkVQ>&mZf=-H^5mGRot&! zbTq{AYiJTj<_(_Vc=!D=ReG+Q@^2s#IG?~k-p+(3R04u@Wzu7*WN&}Ms&&YhCcku! zdBHqHq#<0XGH;5f2#}U{J(ORZ&{&*!Nr_x>QMr=xL=w}Wq&%rF8)>BDccVWDJy$T0 z1O)@r7k|QJN$C2sWYcGgaQ$sFNX#TL3;Nqqx_XdGhRML=hE(AstDSq*UU8hcX# zYn_(5P%J@K7y>y~x0e#ZbBYxdyzh%OnKzHv-h%GE^=R-HK&rSWponyjDc`M-@_lyk z4$LPMIX|BFY_o+x#a7#XRI9GARac}573{}YqzCHREm%?1UWqR}IWfSCbL^7;kkbl& zuh+7f4>YqXSklbSrS+Y`E*JjG5r1;pb{4el>A&lP){7GjTv}lUiA+c*L* zJ-d4{c<95^y1nn6)-4JX+NQT@)h2au^lQ>%N0@LEVVs!G{2}=ZS5p?(hp~oWYTAi4 z64I3oA6>;v*8p?eQFe8Z8fdUFm6@-EABQmW@4%A$8na}~X*{IH7|&Y7EH?V(#|6|PFwEFi^Sj+7G7z%AP+ zVJH7WNY_8O)3l4#qiF?mYRI%Q=jD(z#VtFS^DltZsGx5hV9x#NS4Q11<^;H`dzmY0 z!PP>#+6LFzUb^axubjZKUCebYkglcCb!;PDQ`Xln0hs^m=j(p6 z!B=kMVWBq-(#;7L(bvEt#;?DGXI8KXgansJ&yK$gk{bN23>FE9%5nHG=QS3!?7JI| z7{MShxcoUx8^&V(2%G9y%oQOuR8hy`Y%6@o9m3)+$9uzA-1UI;J5HJ%GcZJahXsvC zO*V`7$G4R%o{*5Ti(L-saz#UO;vg&gLwvo6B@&X7`>}ddU0_N6_%4qn`5_$Vn(EsFXaz@_s7`Sjg?=HeW|P*ak#EQR7A%z6}ivI-|pdKXRnA;R>W~D z-0E+j(lh1oiAkQC!5uh&4xk4Z0K77|gODQntWs4gWp!uan3c!hPNmBSJ9|BbjP!P` zWNwHv!I{tS!>6m1z>-*^@}Cl6F;|j&qORc4E)_BQpSUyZKL*pXy7)|EmvW=`gNI*9 z>{4`QTNR7^<^088gf27I<#$Qyf@Q+=Cr7Y}7G{>Dzf~uwKWX2A_s_ z5$ZF&kEtqS5#(hu@R8utunI2vBJX;vF&K{+8A~ugCf`HB^(H8V9dI$c2<;6)&I&9i zn&9GbjfJx7V^ox329d6Nv0Q;ZW2K-6P*A{$AvI_floRz}Wa4y7AR8eP%1MUp&}V*{ z&&4#bui3GhNu&&2yEY6580`2Fbhx0x|Jf$VC!Agcj4qPeDCR zd=|=6CGi%BbFVlbu2aNbV04f83{+1RKZT%^#M5AOx402%CyM>SQMI@g0!{{=x84Hsj&sWT90Z-XHG9=*$m%y`mFekQzW<8B}ppzk-IxZ!~9CUJ3J%>c z40;C$u>PGo1>N1LRt4#jVLmK(sT1tcEk~i!jyoevw*Wm1SA|I3Qp|LOD#Yq$V!uYI zJ1jw$0|R6ktqLu4ThMHbDx_-r%KEOb5QknHY1D2M2N!ivK-JjlXzJLQxLv`&LAT0ghr5!BCqYinjbqLv5f?uRzkFI4MN zog|O05PC&*he*~h^%&e$2K6ngpj0ec&75N%h{kjBClx}t6xAKZ!)oR9BS4up4*Iss zWEnHNZpn8Hk0EAMJ_kvKZ)>Mdm z5a=daa6=Cfc@A9OZ8-whVIsc}yiGO-;gM7+@+A;q3P_9%7kN8a+^Y&BM1BP5rmDh7 zk_e@n7FY^7MN3&F+O62i=Fx%E00!$G3cyKVs_7wzp zNaS(n&oepCf^A6vqj8WQ|0%dfo**Ebki(H=W1iQ-g&FDX0y2 z+{kUNZ`SmE=%Hn%aG+k}{U;2&?Hx6hA5mMM3fB=DbFdj1hoi^>qR_IXFY8dVW~!D{ z0|8f7z-N%DEn2mbSbn`3c8)_^=A8@P?0t-QZySpB*h4ja4i6gUeGt;HOjqkCY4xn> zKT$hHctF!|SYpCx7^$Wwz*WFV=W49O0pTh@%Ys^_fxnNrH?$@!Xb2>?o!eWl2sjTj zVSa@RP;-#`3=!fb@4uj*j*e>lFpHL&It{HI;E-$K8v=;HVgX$3Mz9L$1g=|f&2adF zKx+j!hgaVTx>W3Y7eF4M2`-Uj&V~L)fjkV59t;<3@Gv+EYtkMTUQ5o7W4aHNI{_>l zO#)3aXKEMTH9`*-2~Z8=2;gcXps|`j0@nf)FhiXHP!mYt+F}B@PGbP!*rXL0>E%y{ z3K1cDK#T>w=4+1TD^^}NRB(A?xpZuf`}P*CIWA0JbLn9i5r^8m1gyB)MK(y~5cJW( zHG2azaIa?g+@_}D;98@v=RtlJb$AbUaJjh9a5Zd4-E9-^1YKYB^EJqy1DfF226A@n zniINi2B_ock&b7qxz*N5jgpOf9s{ILo#bE=eoiz9sO9;pw z)Z^;H9W8=iy~Gt`g2C89j0>I9RYN&uJp^0@1y&2-YGVT^iB&O}L?Sqf0jNo=O2#C* zf|w7;Ou#k%d;qr4EiQ$ewyQY}g}Pe-?GHny+}lC;U}7tVvzFm@+JMPGY~R2wF2#Xc zT%qUs>J|^t>!vZ?BnD*Q!2x`1_;iii@}2r-%yt{-a0h?pryB*jhd@_Hx@vV^77t^# zyP*b72l&|}*_v$KwFu z-mFQ+tvL=b0uY=8wUMf?5`Fbv5MuX3$A@c;r9!o}9$tdf*28nL^%B4X0LOWVF}xIy zwRIrAfU1AM@C~2(16)4NzqTf>?rLwzvSeD&#N*=hc8leb!Yj`#jtb^N z^3Y=9i!^7H!Vu&HUg&{Rv{$z|0 z2WH$@!DV~~hE~rG$fx`FFO+liVv&4gV%}tV#qoSuUVF&gObsP^(vI|k0rD<2zYvmuR z1uOT0EKC&Al$?n|d!14*p3Au?{8>yyln&10RFKVZI6IM>!+R+*9Pg#bDU1z9ZV7J! z$Y5NBoCYrl$gSXM09e%65V#Z>?*Uj3kIk4_dvja3Z(v0`pTe9;f!i~N2Y)!6 zl8_4v??9aEODH^Fu9{rdQG#Yn2c8Ou`w(N2sK14HB=I<6yn$i;eBuX*pCEpQ_<3T5 zcq{RKA4}{LQk*2NBR0U`V*odCG%fzxC105yB_rx}XFM&|vMB;YDCB#FC=Muk4{4w!4;$k?7G0tto zV~FSBcOzKwFe#oUeu;P!@owS|iN7TNj`(L{Gu)}rpPM+AIE^@mxCe2mM1?zuXA;*C zKR~>acq{QfV*FwV1O7s6g>wSsLBu18rw~6zypmXYl?vO5_Y)r`K0$nrSPu_^7{Ec? zlsJjF9Wg#IqFo>2!NenpC;M1p_mN@=@p5ALsi5jWfRhy+If+{npx z;w{7niGL!Ff>Ti!3-jMmEx_U+o=m)y_yyuk#QTVK@Ft82G$l?%4ujhP$py%f@YX^+ zkhq+92r};fk)#+)T#XElW+FrV0@5!ceuV1Zp!#jd@ECG{RPj%$*h}&O;-knA$N<@5 zq5;S-tRW=FB17N=;x@#Y#PIJV)OKA-?m;|AWtjiLq!>*+p7?HL2-JiD!*=XSJev4j zVhi5SVLRcsUC8)1DBK;l5zj`3MYx(+eLevBILZ_!&E+m3?ugnG2Cud`A6cW2Kd7t_Ana?$Q8tu#M6o4-okX@@|YD7 zZuxIZ;K}#X$IT-AYaG@ME1=88G!)=N?Fo#Qnn5%&WRQRil_|)OF+9AgJ;FD5?0G&i z_)~`%{PjW^oP3Twhn|#B#w(G*&kNM3*p@t%RNCsc>4PyvDeO$LXNAtLu@Cks`N4?vtJG&io#<2{S)e4%{HR@BU3{ zb6}0j>mZQ4W~EuQ;kw6<6b0Y(%K6h{T=L;hJB#=hs(wnE%i*tz!E$w&!@*ZJhvAVI zPcXXVQB?sB{wO$GB=@OKayjvbIz7s?2vhS3^z##C?GjV4=-(P zY<$K1w!g-!ELY4g8puOhUX(`}zRB#$^H(gpV9shyifzwDc$CvEEiaibS$LJr?JcLe zlVawe9$w|0IhGF-NdcYrC~vN{1O)n9e6z(eKi=PB@z)lY^OC}?Z2iF!YbOPSb;H1f zX)aJ!GQ8HUUNRW^eUe9M(%M?njueYK!(hHP!n*2de~W20o3Vqx;;BO0%9fWDZe`dM z+iO!uk)NF5Q8Lfkq&QNj3#mPR<2hLS?Fx$r2aUCyqi zOFlfx=z~s|Hk)Zxy}ZhkKROGwwLNr0wpS4XTu*BXb>w%%xFX+Dd)y{f?mflkuHjC& z06~BzfM9@I;ZAt=RQN@zInmjxoah{~=K(*Za_~^dL#_N3GmWADXsJ1e;q=s$v4>E#I0oak60Q`3LHG;zY`+%xAL13xAM_*5xLrcs}tQOIPwK;qSa1a z2#G9RdAnxyJn%U-4Z9U3k`EkdV zXqv%U9lbTn55+0V4>g;qtqZj;*~goW8t5PJt=#yBv^}g^RR1mBQR#2-)am#FN-0yG z9^r&JO-oR?w8Z%46i-R1NSt1O9N{qUK9RVxv%iytEtBro6cEO%w4IpLY?`lqrVMA4 zyXKznlK{os%qf7DfK=rhb6Qd} z|JZ41Y31!Sb9GFguS`>(uWWU1Uor!)9wmQMD`kP!ql?{IZ(K`lYBry5t!zG@zF`~H z%24Z3mb~8PZ8FJF23NKnG*@d36H>TT6YR6wrK~1TxDwnoWyu*zS#st|$xrL434bwD z34gKutWnfZK4o`#l+E6(je9g#)4$64?7*+8r)!pc+zXBB+oA}31kqJl0fsn)j+)}1S; zS$D3JvhG~xBD!Z~%DBsF!hh-v=%R%G)b-phEekwll(Ze){xknqUNVci*JKtIDw#z+ z3M~GsVcDP_pTujXn|s>b%Hml)Tpwu~b%Ady@2PAn?=>=5)4rS48#Z}Wuj#u4^Bh3(#O-UFU?=33=7huY`>@9fEsG0gme9$ z`_O+RzW7)FzBCdUYJ8>7Fa7mVnosq?p(=7finh&t{dlv-fPuM}+<28%_YXLx-3QeP zPk()YgMK-ip&l5@&}{?aBgn4;JuQs%TQRSm8FG1vKF9c{BwfkwGmj`s#G`Jp>TVgA2Z>nijn@{sACMEtKB|?DM delta 21202 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 q-#Bi&J2a$b=eWm$ZvlE?>F#tq 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 delta 1436 zcmY*ZT}V@57{pm)99k0(M3g(MVf{|g^C$b3ikbuygT3XKF{<1eD8O{@nAR}?B6LA zDlWHDG?Du}fIo|Up4e(Y%%b1!`;BX6_NmSf>7P$kCV+9wpY#bOqXO?4i z(dvC%vT6~e*o*kao+Klnkz$MU^`#W>!ttDxg?@Ixh7$P4Q$j<`AhH^8!pj;>B9$4y za6t3+7>iPVWLQ&gWe$@Qn$|W>?I=hUv+=>LD9~S-TJw!XR9q))y0jJhneKX{1i@Nu z-c81c1`HAmt!f8|9?b;G(sfHm8Cyj~$WVSt7p-OppxKBmObn>&OUaJ$2q5ATN^)5k zt0nk;QV4lDf{K%%p;!3oV18uQ&^#iH`Z=e?ua`kt6Ykj=f@UMZhE6{vaSAbhy-TmU z7y?KnWb*J#xg^7lkp7-X5ihMI*reZL*WsZ^+g<(d0v%a~$kuro`rhjsE-;tLfMJ>J zOtH_4r)F$6jCSx0WUh%7gGd&@t+-Uu*-t6$&O6HS(axq;(rVA}Dt6m#G90cH3(s-{ zZyI!siF2p9s_d3khK>z!u$Lkp>Qi#rIFQCv=+0zVzh?Z)%Tv*v$&fy7T&}_tw^BIy z$N2IyHz39Sm`#7nmcT>TX-;dhWNhQ4J5Awyj*u0Nm745i>60xk`b{C$qDLjg*5#XX z+0$Xpqs8WI?o2N4Lxp*I2Q~HrDksjyrqD{-u9$1@)38sS`DI7ll~|k=3;}DWr8TMU zAFwRQoJ+>n_rMYiF>~^aMA`Z{j{)lZ?MxZIlvt0LxQOg@S(SBf4d;+`>Qb$s#RwW7 zpvI!%WEel9^}QLd4$!cRR=s#4!}Ek93ZSd4silV^6~Bb;o+cagG}*hW@P4@!bqGJD zLyzn|$v*<>bV=A|`E=7>IfxOob6_3F{6xa&fTuDJqa&FfE&$Y6xRY~R4muVDmS`IN ztf0Bj5t(7phx1Nb3S_N2KI%9hc_YZY;Ye@@k(PNjDp)c&xxfb~KN8GZoNtH#%?Q7V p7Y^sMtN*7RA9EUqX%eIn{sFTa!dCzQ diff --git a/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp b/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp index 8af3daa73..bd7639055 100644 --- a/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp +++ b/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp @@ -82,7 +82,7 @@ extern "C" void __wrap_cyw43_post_poll_hook() { cyw43_set_irq_enabled(true); } -void cyw43_schedule_internal_poll_dispatch(__unused void (*func)()) { +extern "C" void __wrap_cyw43_schedule_internal_poll_dispatch(__unused void (*func)()) { lwip_callback(cb_cyw43_do_poll, nullptr); } @@ -165,23 +165,4 @@ extern "C" void __wrap_cyw43_delay_us(uint32_t us) { delayMicroseconds(us); } -// Generate a mac address if one is not set in otp -extern "C" void cyw43_hal_generate_laa_mac(__unused int idx, uint8_t buf[6]) { - CYW43_DEBUG("Warning. No mac in otp. Generating mac from board id\n"); - pico_unique_board_id_t board_id; - pico_get_unique_board_id(&board_id); - memcpy(buf, &board_id.id[2], 6); - buf[0] &= (uint8_t)~0x1; // unicast - buf[0] |= 0x2; // locally administered -} - -// Return mac address -extern "C" void cyw43_hal_get_mac(__unused int idx, uint8_t buf[6]) { - // The mac should come from cyw43 otp. - // This is loaded into the state after the driver is initialised - // cyw43_hal_generate_laa_mac is called by the driver to generate a mac if otp is not set - memcpy(buf, cyw43_state.mac, 6); -} - - #endif diff --git a/libraries/lwIP_Ethernet/src/LwipIntfDev.h b/libraries/lwIP_Ethernet/src/LwipIntfDev.h index 36529ed05..2f8a74f81 100644 --- a/libraries/lwIP_Ethernet/src/LwipIntfDev.h +++ b/libraries/lwIP_Ethernet/src/LwipIntfDev.h @@ -194,8 +194,8 @@ class LwipIntfDev: public LwipIntf, public RawDev { err_t handlePackets(); #ifdef __FREERTOS SemaphoreHandle_t _hwMutex; - __callback_req _irqBuffer; #endif + __callback_req _irqBuffer; protected: // members SPIClass& _spiUnit; From ade00f7f407f842f749cc438e6b5e1c2650b7a0f Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 20 Aug 2025 10:46:27 -0700 Subject: [PATCH 30/36] Only 1 outstanding sleep poll, remove async_ctx Completely null out the async_context used by the CYW43 driver to ensure it will crash immediately instead of just doing nothing should there be some driver code which uses it. Replace the connect routines to use our custom methods directly. Limit the outstanding sleep poll messages in the LWIP queue to 1. This avoids the case where, due to some long running operation, the sleep alarm ends up being called multiple times before actually processing the callback (which would flood the LWIP work queue and crash the machine). --- cores/rp2040/lwip_wrap.cpp | 8 +++ .../rp2040/sdkoverride/cyw43_arch_freertos.c | 19 +++--- lib/core_wrap.txt | 3 +- .../lwIP_CYW43/src/cyw43_driver_freertos.cpp | 59 ++++++++++++++++++- 4 files changed, 79 insertions(+), 10 deletions(-) diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index 3dea60bd8..21a752d47 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -887,6 +887,14 @@ extern "C" { void __wrap_cyw43_schedule_internal_poll_dispatch(void (*func)()) { __real_cyw43_schedule_internal_poll_dispatch(func); } + extern int __real_cyw43_arch_wifi_connect_bssid_timeout_ms(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth, uint32_t timeout_ms); + int __wrap_cyw43_arch_wifi_connect_bssid_timeout_ms(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth, uint32_t timeout_ms) { + return __real_cyw43_arch_wifi_connect_bssid_timeout_ms(ssid, bssid, pw, auth, timeout_ms); + } + extern int __real_cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout_ms); + extern "C" int __wrap_cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout_ms) { + return __real_cyw43_arch_wifi_connect_timeout_ms(ssid, pw, auth, timeout_ms); + } #endif diff --git a/cores/rp2040/sdkoverride/cyw43_arch_freertos.c b/cores/rp2040/sdkoverride/cyw43_arch_freertos.c index 01949f796..18bdf4080 100644 --- a/cores/rp2040/sdkoverride/cyw43_arch_freertos.c +++ b/cores/rp2040/sdkoverride/cyw43_arch_freertos.c @@ -50,14 +50,17 @@ async_context_t *cyw43_arch_init_default_async_context(void) { } int cyw43_arch_init(void) { - 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); - } +// 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); +// } + async_context_t *context = NULL; + cyw43_arch_set_async_context(context); + bool ok = cyw43_driver_init(context); #if CYW43_LWIP ok &= lwip_freertos_init(context); diff --git a/lib/core_wrap.txt b/lib/core_wrap.txt index 19014cf6d..d2aa6182e 100644 --- a/lib/core_wrap.txt +++ b/lib/core_wrap.txt @@ -90,4 +90,5 @@ -Wl,--wrap=cyw43_delay_us -Wl,--wrap=cyw43_post_poll_hook -Wl,--wrap=cyw43_schedule_internal_poll_dispatch - +-Wl,--wrap=cyw43_arch_wifi_connect_bssid_timeout_ms +-Wl,--wrap=cyw43_arch_wifi_connect_timeout_ms diff --git a/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp b/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp index bd7639055..c6cdd830d 100644 --- a/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp +++ b/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp @@ -39,6 +39,7 @@ extern "C" { static SemaphoreHandle_t _cyw43_arch_mutex; static SemaphoreHandle_t _cyw43_irq_called_binary; +static SemaphoreHandle_t _cyw43_sleep_poll_binary; static void cb_cyw43_do_poll(void *context); static __callback_req _irqBuffer; @@ -86,12 +87,17 @@ extern "C" void __wrap_cyw43_schedule_internal_poll_dispatch(__unused void (*fun lwip_callback(cb_cyw43_do_poll, nullptr); } + + static int64_t cb_cyw43_sleep_timeout_reached(alarm_id_t id, void *ptr) { (void) id; (void) ptr; static __callback_req _sleepIRQBuffer; // 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 - lwip_callback(cb_cyw43_do_poll, nullptr, &_sleepIRQBuffer); + BaseType_t pxHigherPriorityTaskWoken; + if (xSemaphoreTakeFromISR(_cyw43_sleep_poll_binary, &pxHigherPriorityTaskWoken)) { + lwip_callback(cb_cyw43_do_poll, nullptr, &_sleepIRQBuffer); + } return 0; // Don't reschedule } @@ -100,6 +106,7 @@ static void cb_cyw43_do_poll(void *context) { //, __unused async_when_pending_wo #ifndef NDEBUG assert(get_core_num() == 0); #endif + cyw43_thread_enter(); if (cyw43_poll) { if (cyw43_sleep > 0) { cyw43_sleep--; @@ -111,12 +118,17 @@ static void cb_cyw43_do_poll(void *context) { //, __unused async_when_pending_wo // Nothing to do. We have 1-shot alarms } } + cyw43_thread_exit(); + xSemaphoreGive(_cyw43_irq_called_binary); + xSemaphoreGive(_cyw43_sleep_poll_binary); } extern "C" bool __wrap_cyw43_driver_init(async_context_t *context) { assert(get_core_num() == 0); _cyw43_arch_mutex = xSemaphoreCreateRecursiveMutex(); _cyw43_irq_called_binary = xSemaphoreCreateBinary(); + _cyw43_sleep_poll_binary = xSemaphoreCreateBinary(); + xSemaphoreGive(_cyw43_sleep_poll_binary); cyw43_init(&cyw43_state); cyw43_irq_init(nullptr); return true; @@ -144,6 +156,7 @@ extern "C" void __wrap_cyw43_thread_lock_check() { #endif extern "C" void __wrap_cyw43_await_background_or_timeout_us(uint32_t timeout_us) { +// cyw43_set_irq_enabled(true); if (__get_current_exception() > 0) { vTaskDelay((timeout_us / 1000) / portTICK_PERIOD_MS); return; @@ -165,4 +178,48 @@ extern "C" void __wrap_cyw43_delay_us(uint32_t us) { delayMicroseconds(us); } + + +static int this_cyw43_arch_wifi_connect_bssid_until(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth, uint32_t timeout_ms) { + uint32_t start = millis(); + int err = cyw43_arch_wifi_connect_bssid_async(ssid, bssid, pw, auth); + if (err) return err; + int status = CYW43_LINK_UP + 1; + while(status >= 0 && status != CYW43_LINK_UP) { + int new_status = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA); + // If there was no network, keep trying + if (new_status == CYW43_LINK_NONET) { + new_status = CYW43_LINK_JOIN; + err = cyw43_arch_wifi_connect_bssid_async(ssid, bssid, pw, auth); + if (err) return err; + } + if (new_status != status) { + status = new_status; + } + uint32_t delta = millis() - start; + if (delta > timeout_ms) { + return PICO_ERROR_TIMEOUT; + } + // Do polling + //cyw43_arch_poll(); + __wrap_cyw43_await_background_or_timeout_us((timeout_ms - delta) * 1000); //cyw43_arch_wait_for_work_until(until); + } + // Turn status into a pico_error_codes, CYW43_LINK_NONET shouldn't happen as we fail with PICO_ERROR_TIMEOUT instead + assert(status == CYW43_LINK_UP || status == CYW43_LINK_BADAUTH || status == CYW43_LINK_FAIL); + if (status == CYW43_LINK_UP) { + return PICO_OK; // success + } else if (status == CYW43_LINK_BADAUTH) { + return PICO_ERROR_BADAUTH; + } else { + return PICO_ERROR_CONNECT_FAILED; + } +} +extern "C" int __wrap_cyw43_arch_wifi_connect_bssid_timeout_ms(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth, uint32_t timeout_ms) { + return this_cyw43_arch_wifi_connect_bssid_until(ssid, bssid, pw, auth, timeout_ms); //make_timeout_time_ms(timeout_ms)); +} + +extern "C" int __wrap_cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout_ms) { + return __wrap_cyw43_arch_wifi_connect_bssid_timeout_ms(ssid, nullptr, pw, auth, timeout_ms); +} + #endif From 4255caab17ed1c2f09ba5c8bbf5f8d7a48fa5324 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 20 Aug 2025 10:53:24 -0700 Subject: [PATCH 31/36] Astyle --- cores/rp2040/sdkoverride/cyw43_arch_freertos.c | 16 ++++++++-------- .../lwIP_CYW43/src/cyw43_driver_freertos.cpp | 12 ++++++++---- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/cores/rp2040/sdkoverride/cyw43_arch_freertos.c b/cores/rp2040/sdkoverride/cyw43_arch_freertos.c index 18bdf4080..505dcd0f6 100644 --- a/cores/rp2040/sdkoverride/cyw43_arch_freertos.c +++ b/cores/rp2040/sdkoverride/cyw43_arch_freertos.c @@ -50,14 +50,14 @@ async_context_t *cyw43_arch_init_default_async_context(void) { } int cyw43_arch_init(void) { -// 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); -// } + // 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); + // } async_context_t *context = NULL; cyw43_arch_set_async_context(context); diff --git a/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp b/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp index c6cdd830d..43fcf47c8 100644 --- a/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp +++ b/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp @@ -156,7 +156,7 @@ extern "C" void __wrap_cyw43_thread_lock_check() { #endif extern "C" void __wrap_cyw43_await_background_or_timeout_us(uint32_t timeout_us) { -// cyw43_set_irq_enabled(true); + // cyw43_set_irq_enabled(true); if (__get_current_exception() > 0) { vTaskDelay((timeout_us / 1000) / portTICK_PERIOD_MS); return; @@ -183,15 +183,19 @@ extern "C" void __wrap_cyw43_delay_us(uint32_t us) { static int this_cyw43_arch_wifi_connect_bssid_until(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth, uint32_t timeout_ms) { uint32_t start = millis(); int err = cyw43_arch_wifi_connect_bssid_async(ssid, bssid, pw, auth); - if (err) return err; + if (err) { + return err; + } int status = CYW43_LINK_UP + 1; - while(status >= 0 && status != CYW43_LINK_UP) { + while (status >= 0 && status != CYW43_LINK_UP) { int new_status = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA); // If there was no network, keep trying if (new_status == CYW43_LINK_NONET) { new_status = CYW43_LINK_JOIN; err = cyw43_arch_wifi_connect_bssid_async(ssid, bssid, pw, auth); - if (err) return err; + if (err) { + return err; + } } if (new_status != status) { status = new_status; From f943d2e6e0fe162331f408dcaaaab7624298569c Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 20 Aug 2025 11:24:42 -0700 Subject: [PATCH 32/36] Make sure CYW43 GPIO writes also protected --- cores/rp2040/lwip_wrap.cpp | 7 ++++++- lib/core_wrap.txt | 1 + libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index 21a752d47..d6776d395 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -892,9 +892,14 @@ extern "C" { return __real_cyw43_arch_wifi_connect_bssid_timeout_ms(ssid, bssid, pw, auth, timeout_ms); } extern int __real_cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout_ms); - extern "C" int __wrap_cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout_ms) { + int __wrap_cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout_ms) { return __real_cyw43_arch_wifi_connect_timeout_ms(ssid, pw, auth, timeout_ms); } + extern void __real_cyw43_arch_gpio_put(uint wl_gpio, bool value); + void __wrap_cyw43_arch_gpio_put(uint wl_gpio, bool value) { + __real_cyw43_arch_gpio_put(wl_gpio, value); + } + #endif diff --git a/lib/core_wrap.txt b/lib/core_wrap.txt index d2aa6182e..97a7a3da8 100644 --- a/lib/core_wrap.txt +++ b/lib/core_wrap.txt @@ -92,3 +92,4 @@ -Wl,--wrap=cyw43_schedule_internal_poll_dispatch -Wl,--wrap=cyw43_arch_wifi_connect_bssid_timeout_ms -Wl,--wrap=cyw43_arch_wifi_connect_timeout_ms +-Wl,--wrap=cyw43_arch_gpio_put diff --git a/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp b/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp index 43fcf47c8..2f852f8e2 100644 --- a/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp +++ b/libraries/lwIP_CYW43/src/cyw43_driver_freertos.cpp @@ -226,4 +226,18 @@ extern "C" int __wrap_cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const return __wrap_cyw43_arch_wifi_connect_bssid_timeout_ms(ssid, nullptr, pw, auth, timeout_ms); } +extern "C" void __real_cyw43_arch_gpio_put(uint wl_gpio, bool value); +void do_cyw43_arch_gpio_put(void *data) { + uint32_t d = (uint32_t)data; + uint wl_gpio = d >> 1; + bool value = d & 1; + __real_cyw43_arch_gpio_put(wl_gpio, value); +} + +extern "C" void __wrap_cyw43_arch_gpio_put(uint wl_gpio, bool value) { + uint32_t cbdata = (wl_gpio << 1) | (value ? 1 : 0); + lwip_callback(do_cyw43_arch_gpio_put, (void *)cbdata); +} + + #endif From 9d33d90ea3b20e1ae696d8d188a080cb8859b1a4 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 20 Aug 2025 12:00:30 -0700 Subject: [PATCH 33/36] Remove FreeRTOS wrapper functions --- cores/rp2040/CoreMutex.cpp | 13 ++--- cores/rp2040/_freertos.cpp | 4 +- cores/rp2040/_freertos.h | 39 ++++----------- cores/rp2040/freertos/variantHooks.cpp | 69 -------------------------- cores/rp2040/lock.cpp | 30 +++++------ cores/rp2040/wiring_private.cpp | 16 +++++- 6 files changed, 47 insertions(+), 124 deletions(-) diff --git a/cores/rp2040/CoreMutex.cpp b/cores/rp2040/CoreMutex.cpp index 334df81f6..37bcb73d7 100644 --- a/cores/rp2040/CoreMutex.cpp +++ b/cores/rp2040/CoreMutex.cpp @@ -32,14 +32,14 @@ CoreMutex::CoreMutex(mutex_t *mutex, uint8_t option) { _pxHigherPriorityTaskWoken = 0; // pdFALSE auto m = __get_freertos_mutex_for_ptr(mutex); - if (__freertos_check_if_in_isr()) { - if (!__freertos_mutex_take_from_isr(m, &_pxHigherPriorityTaskWoken)) { + if (portCHECK_IF_IN_ISR()) { + if (!xSemaphoreTakeFromISR(m, &_pxHigherPriorityTaskWoken)) { return; } // At this point we have the mutex in ISR } else { // Grab the mutex normally, possibly waking other tasks to get it - __freertos_mutex_take(m); + xSemaphoreTake(m, portMAX_DELAY); } #else uint32_t owner; @@ -60,10 +60,11 @@ CoreMutex::~CoreMutex() { if (_acquired) { #ifdef __FREERTOS auto m = __get_freertos_mutex_for_ptr(_mutex); - if (__freertos_check_if_in_isr()) { - __freertos_mutex_give_from_isr(m, &_pxHigherPriorityTaskWoken); + if (portCHECK_IF_IN_ISR()) { + xSemaphoreGiveFromISR(m, &_pxHigherPriorityTaskWoken); + portYIELD_FROM_ISR(_pxHigherPriorityTaskWoken); } else { - __freertos_mutex_give(m); + xSemaphoreGive(m); } #else mutex_exit(_mutex); diff --git a/cores/rp2040/_freertos.cpp b/cores/rp2040/_freertos.cpp index c1fd96f8e..4ccaef6cd 100644 --- a/cores/rp2040/_freertos.cpp +++ b/cores/rp2040/_freertos.cpp @@ -47,9 +47,9 @@ SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive) { // Make a new mutex SemaphoreHandle_t fm; if (recursive) { - fm = _freertos_recursive_mutex_create(); + fm = xSemaphoreCreateRecursiveMutex(); } else { - fm = __freertos_mutex_create(); + fm = xSemaphoreCreateMutex(); } if (fm == nullptr) { return nullptr; diff --git a/cores/rp2040/_freertos.h b/cores/rp2040/_freertos.h index 96fc717cb..aa42cfd4a 100644 --- a/cores/rp2040/_freertos.h +++ b/cores/rp2040/_freertos.h @@ -18,50 +18,29 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifdef __FREERTOS - #pragma once -#include - -// Cannot include refs to FreeRTOS's actual semaphore calls because they -// are implemented as macros, so we have a wrapper in our variant hook -// to handle it. - -// FreeRTOS has been set up -extern volatile bool __freeRTOSinitted; +#ifdef __FREERTOS #ifdef __cplusplus extern "C" { #endif // __cplusplus -struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */ -typedef struct QueueDefinition * QueueHandle_t; -typedef QueueHandle_t SemaphoreHandle_t; -typedef int32_t BaseType_t; -extern bool __freertos_check_if_in_isr() __attribute__((weak)); +#include +#include "semphr.h" +#include "task.h" -extern SemaphoreHandle_t __freertos_mutex_create() __attribute__((weak)); -extern SemaphoreHandle_t _freertos_recursive_mutex_create() __attribute__((weak)); - -extern void __freertos_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak)); - -extern int __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak)); -extern int __freertos_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak)); -extern void __freertos_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak)); -extern void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak)); +#include -extern void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak)); -extern int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak)); -extern void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak)); +// FreeRTOS has been set up +extern volatile bool __freeRTOSinitted; extern void __freertos_idle_other_core() __attribute__((weak)); extern void __freertos_resume_other_core() __attribute__((weak)); -extern void __freertos_task_exit_critical() __attribute__((weak)); -extern void __freertos_task_enter_critical() __attribute__((weak)); +extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false); + #ifdef __cplusplus } -extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false); #endif // __cplusplus #endif // __FREERTOS diff --git a/cores/rp2040/freertos/variantHooks.cpp b/cores/rp2040/freertos/variantHooks.cpp index a14269d3b..01bbb90a9 100644 --- a/cores/rp2040/freertos/variantHooks.cpp +++ b/cores/rp2040/freertos/variantHooks.cpp @@ -46,75 +46,6 @@ #include #include "freertos-lwip.h" -// Interfaces for the main core to use FreeRTOS mutexes -extern "C" { - extern volatile bool __otherCoreIdled; - static UBaseType_t __savedIrqs[configNUMBER_OF_CORES]; - - SemaphoreHandle_t __freertos_mutex_create() { - return xSemaphoreCreateMutex(); - } - - SemaphoreHandle_t _freertos_recursive_mutex_create() { - return xSemaphoreCreateRecursiveMutex(); - } - - void __freertos_mutex_take(SemaphoreHandle_t mtx) { - xSemaphoreTake(mtx, portMAX_DELAY); - } - - int __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) { - return xSemaphoreTakeFromISR(mtx, pxHigherPriorityTaskWoken); - } - - int __freertos_mutex_try_take(SemaphoreHandle_t mtx) { - return xSemaphoreTake(mtx, 0); - } - - void __freertos_mutex_give(SemaphoreHandle_t mtx) { - xSemaphoreGive(mtx); - } - - void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) { - BaseType_t hiPrio = pxHigherPriorityTaskWoken ? *pxHigherPriorityTaskWoken : pdFALSE; - xSemaphoreGiveFromISR(mtx, &hiPrio); - portYIELD_FROM_ISR(hiPrio); - } - - void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) { - xSemaphoreTakeRecursive(mtx, portMAX_DELAY); - } - - int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) { - return xSemaphoreTakeRecursive(mtx, 0); - } - - void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) { - xSemaphoreGiveRecursive(mtx); - } - - bool __freertos_check_if_in_isr() { - return portCHECK_IF_IN_ISR(); - } - - void __freertos_task_exit_critical() { - if (portGET_CRITICAL_NESTING_COUNT() == 1U && portCHECK_IF_IN_ISR()) { - taskEXIT_CRITICAL_FROM_ISR(__savedIrqs[portGET_CORE_ID()]); - } else { - taskEXIT_CRITICAL(); - } - } - - void __freertos_task_enter_critical() { - if (portGET_CRITICAL_NESTING_COUNT() == 0U && portCHECK_IF_IN_ISR()) { - __savedIrqs[portGET_CORE_ID()] = taskENTER_CRITICAL_FROM_ISR(); - } else { - taskENTER_CRITICAL(); - } - } -} - - /*-----------------------------------------------------------*/ extern void __initFreeRTOSMutexes(); diff --git a/cores/rp2040/lock.cpp b/cores/rp2040/lock.cpp index e1742058e..f44865887 100644 --- a/cores/rp2040/lock.cpp +++ b/cores/rp2040/lock.cpp @@ -60,15 +60,15 @@ SemaphoreHandle_t __lock___dd_hash_mutex_freertos; SemaphoreHandle_t __lock___arc4random_mutex_freertos; void __initFreeRTOSMutexes() { - __lock___sinit_recursive_mutex_freertos = _freertos_recursive_mutex_create(); - __lock___sfp_recursive_mutex_freertos = _freertos_recursive_mutex_create(); - __lock___atexit_recursive_mutex_freertos = _freertos_recursive_mutex_create(); - __lock___at_quick_exit_mutex_freertos = __freertos_mutex_create(); - __lock___malloc_recursive_mutex_freertos = _freertos_recursive_mutex_create(); - __lock___env_recursive_mutex_freertos = _freertos_recursive_mutex_create(); - __lock___tz_mutex_freertos = __freertos_mutex_create(); - __lock___dd_hash_mutex_freertos = __freertos_mutex_create(); - __lock___arc4random_mutex_freertos = __freertos_mutex_create(); + __lock___sinit_recursive_mutex_freertos = xSemaphoreCreateRecursiveMutex(); + __lock___sfp_recursive_mutex_freertos = xSemaphoreCreateRecursiveMutex(); + __lock___atexit_recursive_mutex_freertos = xSemaphoreCreateRecursiveMutex(); + __lock___at_quick_exit_mutex_freertos = xSemaphoreCreateMutex(); + __lock___malloc_recursive_mutex_freertos = xSemaphoreCreateRecursiveMutex(); + __lock___env_recursive_mutex_freertos = xSemaphoreCreateRecursiveMutex(); + __lock___tz_mutex_freertos = xSemaphoreCreateMutex(); + __lock___dd_hash_mutex_freertos = xSemaphoreCreateMutex(); + __lock___arc4random_mutex_freertos = xSemaphoreCreateMutex(); } static SemaphoreHandle_t __getFreeRTOSMutex(_LOCK_T lock) { @@ -150,7 +150,7 @@ void __retarget_lock_acquire(_LOCK_T lock) { #ifdef __FREERTOS if (__freeRTOSinitted) { auto mtx = __getFreeRTOSMutex(lock); - __freertos_mutex_take(mtx); + xSemaphoreTake(mtx, portMAX_DELAY); } else { mutex_enter_blocking((mutex_t*)lock); } @@ -163,7 +163,7 @@ void __retarget_lock_acquire_recursive(_LOCK_T lock) { #ifdef __FREERTOS if (__freeRTOSinitted) { auto mtx = __getFreeRTOSRecursiveMutex(lock); - __freertos_recursive_mutex_take(mtx); + xSemaphoreTakeRecursive(mtx, portMAX_DELAY); } else { recursive_mutex_enter_blocking((recursive_mutex_t*)lock); } @@ -177,7 +177,7 @@ int __retarget_lock_try_acquire(_LOCK_T lock) { #ifdef __FREERTOS if (__freeRTOSinitted) { auto mtx = __getFreeRTOSMutex(lock); - ret = __freertos_mutex_try_take(mtx); + ret = xSemaphoreTake(mtx, 0); } else { ret = mutex_try_enter((mutex_t *)lock, nullptr); } @@ -192,7 +192,7 @@ int __retarget_lock_try_acquire_recursive(_LOCK_T lock) { #ifdef __FREERTOS if (__freeRTOSinitted) { auto mtx = __getFreeRTOSRecursiveMutex(lock); - ret = __freertos_recursive_mutex_try_take(mtx); + ret = xSemaphoreTakeRecursive(mtx, 0); } else { ret = recursive_mutex_try_enter((recursive_mutex_t*)lock, nullptr); } @@ -206,7 +206,7 @@ void __retarget_lock_release(_LOCK_T lock) { #ifdef __FREERTOS if (__freeRTOSinitted) { auto mtx = __getFreeRTOSMutex(lock); - __freertos_mutex_give(mtx); + xSemaphoreGive(mtx); } else { mutex_exit((mutex_t*)lock); } @@ -219,7 +219,7 @@ void __retarget_lock_release_recursive(_LOCK_T lock) { #ifdef __FREERTOS if (__freeRTOSinitted) { auto mtx = __getFreeRTOSRecursiveMutex(lock); - __freertos_recursive_mutex_give(mtx); + xSemaphoreGiveRecursive(mtx); } else { recursive_mutex_exit((recursive_mutex_t*)lock); } diff --git a/cores/rp2040/wiring_private.cpp b/cores/rp2040/wiring_private.cpp index 422cfd6f2..29704f4f6 100644 --- a/cores/rp2040/wiring_private.cpp +++ b/cores/rp2040/wiring_private.cpp @@ -32,10 +32,18 @@ static uint32_t _irqStackTop[2] = { 0, 0 }; static uint32_t _irqStack[2][maxIRQs]; +#ifdef __FREERTOS +static UBaseType_t __savedIrqs[configNUMBER_OF_CORES]; +#endif + extern "C" void interrupts() { #ifdef __FREERTOS if (__freeRTOSinitted) { - __freertos_task_exit_critical(); + if (portGET_CRITICAL_NESTING_COUNT() == 1U && portCHECK_IF_IN_ISR()) { + taskEXIT_CRITICAL_FROM_ISR(__savedIrqs[portGET_CORE_ID()]); + } else { + taskEXIT_CRITICAL(); + } return; } #endif @@ -50,7 +58,11 @@ extern "C" void interrupts() { extern "C" void noInterrupts() { #ifdef __FREERTOS if (__freeRTOSinitted) { - __freertos_task_enter_critical(); + if (portGET_CRITICAL_NESTING_COUNT() == 0U && portCHECK_IF_IN_ISR()) { + __savedIrqs[portGET_CORE_ID()] = taskENTER_CRITICAL_FROM_ISR(); + } else { + taskENTER_CRITICAL(); + } return; } #endif From caf7fc81b67aa5d6a058d592f0b889d6bdf98b22 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 20 Aug 2025 12:23:06 -0700 Subject: [PATCH 34/36] Update docs --- docs/freertos.rst | 10 ++++++++-- docs/platformio.rst | 4 ++-- docs/wifi.rst | 9 ++------- tools/platformio-build.py | 8 ++++++++ 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/docs/freertos.rst b/docs/freertos.rst index ae811b2ad..54e1eee57 100644 --- a/docs/freertos.rst +++ b/docs/freertos.rst @@ -15,13 +15,19 @@ To enable FreeRTOS, simply add #include -to your sketch and it will be included and enabled automatically. +to your sketch and select ``Tools->Operating System->FreeRTOS SMP`` to enable it. + +When using Platform.IO you need to add the following define to your .ini file: + +.. code:: + + -D__FREERTOS=1 Configuration and Predefined Tasks ---------------------------------- FreeRTOS is configured with 8 priority levels (0 through 7) and a process for -``setup()/loop()``, ``setup1()/loop1()``, and the USB port will be created. The task +``setup()/loop()``, ``setup1()/loop1()``, LWIP, and the USB port will be created. The task quantum is 1 millisecond (i.e. 1,000 switches per second). ``setup()`` and ``loop()`` are assigned to only run on core 0, while ``setup1()`` and ``loop1()`` diff --git a/docs/platformio.rst b/docs/platformio.rst index 35a300576..b750f4948 100644 --- a/docs/platformio.rst +++ b/docs/platformio.rst @@ -350,8 +350,8 @@ FreeRTOS support can be activated by adding .. code:: ini - ; Set the compiler flag. Still need to #include in your application - build_flags = -D__FREERTOS + ; Enable FreeRTOS Support + build_flags = -DPIO_FRAMEWORK_ARDUINO_ENABLE_FREERTOS to the ``platformio.ini``. diff --git a/docs/wifi.rst b/docs/wifi.rst index f10b3d065..2c5ff2afd 100644 --- a/docs/wifi.rst +++ b/docs/wifi.rst @@ -24,8 +24,6 @@ Supported Features Important Information --------------------- -Please note that WiFi on the Pico W is a work-in-progress and there are some important caveats: - * Adding WiFi increases flash usage by over 220KB * There is a 220KB binary firmware blob for the WiFi chip (CYW43-series) which the Pico W uses, even to control the onboard LED. @@ -34,17 +32,14 @@ Please note that WiFi on the Pico W is a work-in-progress and there are some imp * LWIP, the TCP/IP driver, requires preallocated buffers to allow it to run in non-polling mode (i.e. packets can be sent and received in the background without the application needing to explicitly do anything). -* The WiFi driver is a little limited as of now, but fully functional for sending and receiving data +* The WiFi driver has some limitations stemming from the upstream SDK: * Extensible Authentication Protocol (EAP) is not supported * Combined STA/AP mode is not supported -* Multicore is supported, but only core 0 may run ``WiFi`` related code. - - * FreeRTOS is supported only on core 0 and from within ``setup`` and ``loop``, not tasks, due to the requirement for a very different LWIP implementation. PRs always appreciated! +* Multicore is supported, but only core 0 may run ``WiFi`` related code when in bare metal. When using FreeRTOS, any Task on any core can perform networking operations. - * LEAmDNS (``MDNS``) is not supported in FreeRTOS due to internal IRQ-time memory allocations. Instead, use the SimpleMDNS library ( ``#include `` ) which has no such allocations. The WiFi library borrows much work from the `ESP8266 Arduino Core `__ , especially the ``WiFiClient`` and ``WiFiServer`` classes. diff --git a/tools/platformio-build.py b/tools/platformio-build.py index 440cb0a05..be8483c62 100755 --- a/tools/platformio-build.py +++ b/tools/platformio-build.py @@ -95,6 +95,14 @@ def is_pio_build(): else: libpicow = File(os.path.join(FRAMEWORK_DIR, "lib", chip, "liblwip.a")) +if "PIO_FRAMEWORK_ARDUINO_ENABLE_FREERTOS" in flatten_cppdefines: + env.Append( + CPPDEFINES=[ + ("__FREERTOS", 1) + ] + ) + + env.Append( ASFLAGS=env.get("CCFLAGS", [])[:], ) From 2dd01308e100c21cf190c9e6a035c00237e3d988 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 20 Aug 2025 13:00:09 -0700 Subject: [PATCH 35/36] RP2350 fixes, tested on 2W-compatible --- cores/rp2040/freertos/lwip_freertos.c | 13 ++++++++----- cores/rp2040/lwip_wrap.cpp | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/cores/rp2040/freertos/lwip_freertos.c b/cores/rp2040/freertos/lwip_freertos.c index 999a1be47..b3ee2acd8 100644 --- a/cores/rp2040/freertos/lwip_freertos.c +++ b/cores/rp2040/freertos/lwip_freertos.c @@ -1,15 +1,18 @@ // For FreeRTOS, we'll just use the NOSYS version because we already safely handle it #ifdef __FREERTOS +#include "lwip/init.h" #include "pico/async_context.h" -extern bool lwip_nosys_init(async_context_t *context); -extern void lwip_nosys_deinit(async_context_t *context); - bool lwip_freertos_init(async_context_t *context) { - return lwip_nosys_init(context); + static bool done_lwip_init; + if (!done_lwip_init) { + lwip_init(); + done_lwip_init = true; + } + return true; } void lwip_freertos_deinit(__unused async_context_t *context) { - lwip_nosys_deinit(context); + panic("unsupported"); } #endif diff --git a/cores/rp2040/lwip_wrap.cpp b/cores/rp2040/lwip_wrap.cpp index d6776d395..159e110a3 100644 --- a/cores/rp2040/lwip_wrap.cpp +++ b/cores/rp2040/lwip_wrap.cpp @@ -51,7 +51,7 @@ extern "C" { void __wrap_lwip_init() { if (!_lwip_rng) { recursive_mutex_init(&__lwipMutex); - _lwip_rng = new XoshiroCpp::Xoshiro256PlusPlus(micros() * rp2040.getCycleCount()); + _lwip_rng = new XoshiroCpp::Xoshiro256PlusPlus(micros()); __real_lwip_init(); } } From 61e98681e4e014c327e712a5a1b3209ddd87725a Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 20 Aug 2025 13:30:33 -0700 Subject: [PATCH 36/36] Reorganize/cleanup varianthooks --- cores/rp2040/_freertos.h | 2 + cores/rp2040/freertos/freertos-lwip.cpp | 3 +- cores/rp2040/freertos/freertos-lwip.h | 3 +- cores/rp2040/freertos/freertos-main.cpp | 169 ++++++++++++++ cores/rp2040/freertos/freertos-usb.cpp | 88 ++++++++ cores/rp2040/freertos/freertos-usb.h | 27 +++ cores/rp2040/freertos/variantHooks.cpp | 279 ++---------------------- cores/rp2040/lock.cpp | 2 +- 8 files changed, 303 insertions(+), 270 deletions(-) create mode 100644 cores/rp2040/freertos/freertos-main.cpp create mode 100644 cores/rp2040/freertos/freertos-usb.cpp create mode 100644 cores/rp2040/freertos/freertos-usb.h diff --git a/cores/rp2040/_freertos.h b/cores/rp2040/_freertos.h index aa42cfd4a..1c33a1ce7 100644 --- a/cores/rp2040/_freertos.h +++ b/cores/rp2040/_freertos.h @@ -37,6 +37,8 @@ extern volatile bool __freeRTOSinitted; extern void __freertos_idle_other_core() __attribute__((weak)); extern void __freertos_resume_other_core() __attribute__((weak)); +extern void __initFreeRTOSMutexes(); + extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false); #ifdef __cplusplus diff --git a/cores/rp2040/freertos/freertos-lwip.cpp b/cores/rp2040/freertos/freertos-lwip.cpp index f6375e6e0..f37fc02e2 100644 --- a/cores/rp2040/freertos/freertos-lwip.cpp +++ b/cores/rp2040/freertos/freertos-lwip.cpp @@ -1,5 +1,5 @@ /* - LWIP-on-FreeRTOs Plumbing + LWIP-on-FreeRTOS Plumbing Copyright (c) 2025 Earle F. Philhower, III @@ -42,7 +42,6 @@ static void lwipThread(void *params); static TaskHandle_t __lwipTask; static QueueHandle_t __lwipQueue; - void __startLWIPThread() { __lwipQueue = xQueueCreate(LWIP_WORK_ENTRIES, sizeof(LWIPWork)); if (!__lwipQueue) { diff --git a/cores/rp2040/freertos/freertos-lwip.h b/cores/rp2040/freertos/freertos-lwip.h index 6d0386856..29d2f2731 100644 --- a/cores/rp2040/freertos/freertos-lwip.h +++ b/cores/rp2040/freertos/freertos-lwip.h @@ -18,11 +18,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#pragma once #ifdef __FREERTOS -#pragma once - // Create the thread and work queue void __startLWIPThread(); diff --git a/cores/rp2040/freertos/freertos-main.cpp b/cores/rp2040/freertos/freertos-main.cpp new file mode 100644 index 000000000..4dd615f43 --- /dev/null +++ b/cores/rp2040/freertos/freertos-main.cpp @@ -0,0 +1,169 @@ +/* + Main app loop and infrastructure for FreeRTOS mode + + Copyright (c) 2025 Earle F. Philhower, III + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifdef __FREERTOS + +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "timers.h" +#include "semphr.h" + +/* Arduino Core includes */ +#include + +#include +#include <_freertos.h> +#include "freertos-lwip.h" +#include "freertos-usb.h" + +/*-----------------------------------------------------------*/ + +extern void setup() __attribute__((weak)); +extern void loop() __attribute__((weak)); +extern void setup1() __attribute__((weak)); +extern void loop1() __attribute__((weak)); +extern void initVariant(); +extern void __loop(); +static void __core1(void *params); +extern volatile bool __freeRTOSinitted; + +static TaskHandle_t __idleCoreTask[2]; + +void initFreeRTOS(void) { + __initFreeRTOSMutexes(); +} + +static void __core0(void *params) { + (void) params; + initVariant(); + + if (setup1 || loop1) { + TaskHandle_t c1; + xTaskCreate(__core1, "CORE1", 1024, 0, configMAX_PRIORITIES / 2, &c1); + vTaskCoreAffinitySet(c1, 1 << 1); + } + +#if !defined(NO_USB) && !defined(USE_TINYUSB) + while (!__usbInitted) { + delay(1); + } +#endif + if (setup) { + setup(); + } + if (loop) { + while (1) { + loop(); + __loop(); + } + } else { + while (1) { + __loop(); + } + } +} + +static void __core1(void *params) { + (void) params; +#if !defined(NO_USB) && !defined(USE_TINYUSB) + while (!__usbInitted) { + delay(1); + } +#endif + if (setup1) { + setup1(); + } + if (loop1) { + while (1) { + loop1(); + } + } else { + while (1) { + vTaskDelay(1000); + } + } +} + +extern "C" void delay(unsigned long ms) { + vTaskDelay(ms / portTICK_PERIOD_MS); +} + +extern "C" void yield() { + taskYIELD(); +} + +static void __no_inline_not_in_flash_func(IdleThisCore)(void *param) { + (void) param; + while (true) { + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + vTaskPreemptionDisable(nullptr); + portDISABLE_INTERRUPTS(); + __otherCoreIdled = true; + while (__otherCoreIdled) { + /* noop */ + } + portENABLE_INTERRUPTS(); + vTaskPreemptionEnable(nullptr); + } +} + +extern "C" void __no_inline_not_in_flash_func(__freertos_idle_other_core)() { + vTaskPreemptionDisable(nullptr); + xTaskNotifyGive(__idleCoreTask[ 1 ^ sio_hw->cpuid ]); + while (!__otherCoreIdled) { + /* noop */ + } + portDISABLE_INTERRUPTS(); + vTaskSuspendAll(); +} + +extern "C" void __no_inline_not_in_flash_func(__freertos_resume_other_core)() { + __otherCoreIdled = false; + portENABLE_INTERRUPTS(); + xTaskResumeAll(); + vTaskPreemptionEnable(nullptr); +} + +void startFreeRTOS(void) { + TaskHandle_t c0; + xTaskCreate(__core0, "CORE0", 1024, 0, configMAX_PRIORITIES / 2, &c0); + vTaskCoreAffinitySet(c0, 1 << 0); + + // Create the idle-other-core tasks (for when flash is being written) + xTaskCreate(IdleThisCore, "IdleCore0", 128, 0, configMAX_PRIORITIES - 1, __idleCoreTask + 0); + vTaskCoreAffinitySet(__idleCoreTask[0], 1 << 0); + xTaskCreate(IdleThisCore, "IdleCore1", 128, 0, configMAX_PRIORITIES - 1, __idleCoreTask + 1); + vTaskCoreAffinitySet(__idleCoreTask[1], 1 << 1); + + __startLWIPThread(); + + // Initialise and run the freeRTOS scheduler. Execution should never return here. + __freeRTOSinitted = true; + vTaskStartScheduler(); + + while (true) { + /* noop */ + } +} + +#endif diff --git a/cores/rp2040/freertos/freertos-usb.cpp b/cores/rp2040/freertos/freertos-usb.cpp new file mode 100644 index 000000000..39b4bbfad --- /dev/null +++ b/cores/rp2040/freertos/freertos-usb.cpp @@ -0,0 +1,88 @@ +/* + FreeRTOS USB task + + Copyright (c) 2025 Earle F. Philhower, III + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifdef __FREERTOS + +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "timers.h" +#include "semphr.h" + +/* Arduino Core includes */ +#include +#include +#include "tusb.h" + +/* Raspberry PI Pico includes */ +#include +#include + +#include <_freertos.h> + +#include "freertos-usb.h" + + + +extern mutex_t __usb_mutex; +static TaskHandle_t __usbTask; +static void __usb(void *param); + +volatile bool __usbInitted = false; + +static void __usb(void *param) { + (void) param; + + tusb_init(); + + Serial.begin(115200); + + __usbInitted = true; + + while (true) { + BaseType_t ss = xTaskGetSchedulerState(); + if (ss != taskSCHEDULER_SUSPENDED) { + auto m = __get_freertos_mutex_for_ptr(&__usb_mutex); + if (xSemaphoreTake(m, 0)) { + tud_task(); + xSemaphoreGive(m); + } + } + vTaskDelay(1 / portTICK_PERIOD_MS); + } +} + +extern void __SetupDescHIDReport(); +extern void __SetupUSBDescriptor(); + +void __USBStart() { + mutex_init(&__usb_mutex); + + __SetupDescHIDReport(); + __SetupUSBDescriptor(); + + // Make high prio and locked to core 0 + xTaskCreate(__usb, "USB", 256, 0, configMAX_PRIORITIES - 2, &__usbTask); + vTaskCoreAffinitySet(__usbTask, 1 << 0); +} + +#endif diff --git a/cores/rp2040/freertos/freertos-usb.h b/cores/rp2040/freertos/freertos-usb.h new file mode 100644 index 000000000..7f65f8a6f --- /dev/null +++ b/cores/rp2040/freertos/freertos-usb.h @@ -0,0 +1,27 @@ +/* + FreeRTOS USB task + + Copyright (c) 2025 Earle F. Philhower, III + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#ifdef __FREERTOS +extern void __USBStart(); +extern volatile bool __usbInitted; + +#endif diff --git a/cores/rp2040/freertos/variantHooks.cpp b/cores/rp2040/freertos/variantHooks.cpp index 01bbb90a9..d0cf4408a 100644 --- a/cores/rp2040/freertos/variantHooks.cpp +++ b/cores/rp2040/freertos/variantHooks.cpp @@ -24,165 +24,13 @@ This file is NOT part of the FreeRTOS distribution. */ -#include -/* FreeRTOS includes. */ +#include #include "FreeRTOS.h" #include "task.h" #include "timers.h" #include "semphr.h" - -/* Arduino Core includes */ -#include -#include -#include "tusb.h" - -/* Raspberry PI Pico includes */ -#include -#include - -#include <_freertos.h> - -#include -#include "freertos-lwip.h" - -/*-----------------------------------------------------------*/ - -extern void __initFreeRTOSMutexes(); -void initFreeRTOS(void) { - __initFreeRTOSMutexes(); -} - -extern void setup() __attribute__((weak)); -extern void loop() __attribute__((weak)); -extern void setup1() __attribute__((weak)); -extern void loop1() __attribute__((weak)); -// Idle functions (USB, events, ...) from the core -extern void __loop(); -volatile bool __usbInitted = false; - -extern void initVariant(); -static void __core1(void *params); -static void __core0(void *params) { - (void) params; - initVariant(); - - if (setup1 || loop1) { - TaskHandle_t c1; - xTaskCreate(__core1, "CORE1", 1024, 0, configMAX_PRIORITIES / 2, &c1); - vTaskCoreAffinitySet(c1, 1 << 1); - } - -#if !defined(NO_USB) && !defined(USE_TINYUSB) - while (!__usbInitted) { - delay(1); - } -#endif - if (setup) { - setup(); - } - if (loop) { - while (1) { - loop(); - __loop(); - } - } else { - while (1) { - __loop(); - } - } -} - -static void __core1(void *params) { - (void) params; -#if !defined(NO_USB) && !defined(USE_TINYUSB) - while (!__usbInitted) { - delay(1); - } -#endif - if (setup1) { - setup1(); - } - if (loop1) { - while (1) { - loop1(); - } - } else { - while (1) { - vTaskDelay(1000); - } - } -} - -extern "C" void delay(unsigned long ms) { - vTaskDelay(ms / portTICK_PERIOD_MS); -} - -extern "C" void yield() { - taskYIELD(); -} - -static TaskHandle_t __idleCoreTask[2]; -static void __no_inline_not_in_flash_func(IdleThisCore)(void *param) { - (void) param; - while (true) { - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - vTaskPreemptionDisable(nullptr); - portDISABLE_INTERRUPTS(); - __otherCoreIdled = true; - while (__otherCoreIdled) { - /* noop */ - } - portENABLE_INTERRUPTS(); - vTaskPreemptionEnable(nullptr); - } -} - -extern "C" void __no_inline_not_in_flash_func(__freertos_idle_other_core)() { - vTaskPreemptionDisable(nullptr); - xTaskNotifyGive(__idleCoreTask[ 1 ^ sio_hw->cpuid ]); - while (!__otherCoreIdled) { - /* noop */ - } - portDISABLE_INTERRUPTS(); - vTaskSuspendAll(); -} - -extern "C" void __no_inline_not_in_flash_func(__freertos_resume_other_core)() { - __otherCoreIdled = false; - portENABLE_INTERRUPTS(); - xTaskResumeAll(); - vTaskPreemptionEnable(nullptr); -} - - -extern mutex_t __usb_mutex; -static TaskHandle_t __usbTask; -static void __usb(void *param); -extern volatile bool __freeRTOSinitted; -void startFreeRTOS(void) { - - TaskHandle_t c0; - xTaskCreate(__core0, "CORE0", 1024, 0, configMAX_PRIORITIES / 2, &c0); - vTaskCoreAffinitySet(c0, 1 << 0); - - // Create the idle-other-core tasks (for when flash is being written) - xTaskCreate(IdleThisCore, "IdleCore0", 128, 0, configMAX_PRIORITIES - 1, __idleCoreTask + 0); - vTaskCoreAffinitySet(__idleCoreTask[0], 1 << 0); - xTaskCreate(IdleThisCore, "IdleCore1", 128, 0, configMAX_PRIORITIES - 1, __idleCoreTask + 1); - vTaskCoreAffinitySet(__idleCoreTask[1], 1 << 1); - - __startLWIPThread(); - - // Initialise and run the freeRTOS scheduler. Execution should never return here. - __freeRTOSinitted = true; - vTaskStartScheduler(); - - while (true) { - /* noop */ - } -} - +#include /*-----------------------------------------------------------*/ @@ -205,10 +53,7 @@ void prvEnableInterrupts() { */ -extern "C" -void vApplicationIdleHook(void) __attribute__((weak)); - - +extern "C" void vApplicationIdleHook(void) __attribute__((weak)); void vApplicationIdleHook(void) { __wfe(); // Low power idle if nothing to do... } @@ -216,7 +61,6 @@ void vApplicationIdleHook(void) { #endif /* configUSE_IDLE_HOOK == 1 */ /*-----------------------------------------------------------*/ -//#if ( configUSE_MINIMAL_IDLE_HOOK == 1 ) /* Call the user defined minimalIdle() function from within the idle task. This allows the application designer to add background functionality @@ -228,14 +72,10 @@ void vApplicationIdleHook(void) { void passiveIdle(void) __attribute__((weak)); void passiveIdle() {} //Empty minimalIdle function -extern "C" -//void vApplicationPassiveIdleHook(void) __attribute__((weak)); - -void vApplicationPassiveIdleHook(void) { +extern "C" void vApplicationPassiveIdleHook(void) { passiveIdle(); } -//#endif /* configUSE_MINIMAL_IDLE_HOOK == 1 */ /*-----------------------------------------------------------*/ #if ( configUSE_TICK_HOOK == 1 ) @@ -250,9 +90,7 @@ void vApplicationPassiveIdleHook(void) { void tick(void) __attribute__((weak)); void tick() {} //Empty minimalIdle function -extern "C" -void vApplicationTickHook(void) __attribute__((weak)); - +extern "C" void vApplicationTickHook(void) __attribute__((weak)); void vApplicationTickHook(void) { tick(); } @@ -265,8 +103,7 @@ void vApplicationTickHook(void) { Usage: called on fatal error (interrupts disabled already) \*---------------------------------------------------------------------------*/ -extern "C" -void rtosFatalError(void) { +extern "C" void rtosFatalError(void) { panic("Fatal error"); } @@ -274,21 +111,9 @@ void rtosFatalError(void) { /* ---------------------------------------------------------------------------*\ Usage: called by task system when a malloc failure is noticed - Description: - Malloc failure handler -- Shut down all interrupts, send serious complaint - to command port. FAST Blink on main LED. - Arguments: - pxTask - pointer to task handle - pcTaskName - pointer to task name - Results: - - Notes: - This routine will never return. - This routine is referenced in the task.c file of FreeRTOS as an extern. \*---------------------------------------------------------------------------*/ extern "C" void vApplicationMallocFailedHook(void) __attribute__((weak)); - void vApplicationMallocFailedHook(void) { panic("Malloc failed"); } @@ -299,24 +124,15 @@ void vApplicationMallocFailedHook(void) { #if ( configCHECK_FOR_STACK_OVERFLOW >= 1 ) -extern "C" -void vApplicationStackOverflowHook(TaskHandle_t xTask, - char * pcTaskName) __attribute__((weak)); - -void vApplicationStackOverflowHook(TaskHandle_t xTask __attribute__((unused)), - char * pcTaskName __attribute__((unused))) { +extern "C" void vApplicationStackOverflowHook(TaskHandle_t xTask, char * pcTaskName) __attribute__((weak)); +void vApplicationStackOverflowHook(TaskHandle_t xTask __attribute__((unused)), char * pcTaskName __attribute__((unused))) { panic("Stack overflow"); } #endif /* configCHECK_FOR_STACK_OVERFLOW >= 1 */ /*-----------------------------------------------------------*/ - - -extern "C" void vApplicationGetPassiveIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer, - StackType_t ** ppxIdleTaskStackBuffer, - configSTACK_DEPTH_TYPE * puxIdleTaskStackSize, - BaseType_t xPassiveIdleTaskIndex) { +extern "C" void vApplicationGetPassiveIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer, StackType_t ** ppxIdleTaskStackBuffer, configSTACK_DEPTH_TYPE * puxIdleTaskStackSize, BaseType_t xPassiveIdleTaskIndex) { static StaticTask_t xIdleTaskTCBs[ configNUMBER_OF_CORES ]; static StackType_t uxIdleTaskStacks[ configNUMBER_OF_CORES ][ configMINIMAL_STACK_SIZE ]; @@ -326,17 +142,11 @@ extern "C" void vApplicationGetPassiveIdleTaskMemory(StaticTask_t ** ppxIdleTask } - #if ( configSUPPORT_STATIC_ALLOCATION >= 1 ) extern "C" -void vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer, - StackType_t ** ppxIdleTaskStackBuffer, - configSTACK_DEPTH_TYPE * pulIdleTaskStackSize) __attribute__((weak)); - -void vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer, - StackType_t ** ppxIdleTaskStackBuffer, - configSTACK_DEPTH_TYPE * pulIdleTaskStackSize) { +void vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer, StackType_t ** ppxIdleTaskStackBuffer, configSTACK_DEPTH_TYPE * pulIdleTaskStackSize) __attribute__((weak)); +void vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer, StackType_t ** ppxIdleTaskStackBuffer, configSTACK_DEPTH_TYPE * pulIdleTaskStackSize) { static StaticTask_t xIdleTaskTCB; static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; @@ -347,14 +157,8 @@ void vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer, #if ( configUSE_TIMERS >= 1 ) -extern "C" -void vApplicationGetTimerTaskMemory(StaticTask_t ** ppxTimerTaskTCBBuffer, - StackType_t ** ppxTimerTaskStackBuffer, - configSTACK_DEPTH_TYPE * pulTimerTaskStackSize) __attribute__((weak)); - -void vApplicationGetTimerTaskMemory(StaticTask_t ** ppxTimerTaskTCBBuffer, - StackType_t ** ppxTimerTaskStackBuffer, - configSTACK_DEPTH_TYPE * pulTimerTaskStackSize) { +extern "C" void vApplicationGetTimerTaskMemory(StaticTask_t ** ppxTimerTaskTCBBuffer, StackType_t ** ppxTimerTaskStackBuffer, configSTACK_DEPTH_TYPE * pulTimerTaskStackSize) __attribute__((weak)); +void vApplicationGetTimerTaskMemory(StaticTask_t ** ppxTimerTaskTCBBuffer, StackType_t ** ppxTimerTaskStackBuffer, configSTACK_DEPTH_TYPE * pulTimerTaskStackSize) { static StaticTask_t xTimerTaskTCB; static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; @@ -371,65 +175,10 @@ void vApplicationGetTimerTaskMemory(StaticTask_t ** ppxTimerTaskTCBBuffer, configASSERT default implementation */ #if configDEFAULT_ASSERT == 1 - extern "C" void vApplicationAssertHook() { - - taskDISABLE_INTERRUPTS(); // Disable task interrupts - - prvSetMainLedOn(); // Main LED on. - for (;;) { - sleep_ms(100); - prvBlinkMainLed(); // Led off. - - sleep_ms(2000); - prvBlinkMainLed(); // Led on. - - sleep_ms(100); - prvBlinkMainLed(); // Led off - - sleep_ms(100); - prvBlinkMainLed(); // Led on. - } + panic("vApplicationAssertHook"); } #endif -BaseType_t ss; - -static void __usb(void *param) { - (void) param; - - tusb_init(); - - Serial.begin(115200); - - __usbInitted = true; - - while (true) { - ss = xTaskGetSchedulerState(); - if (ss != taskSCHEDULER_SUSPENDED) { - auto m = __get_freertos_mutex_for_ptr(&__usb_mutex); - if (xSemaphoreTake(m, 0)) { - tud_task(); - xSemaphoreGive(m); - } - } - vTaskDelay(1 / portTICK_PERIOD_MS); - } -} - -extern void __SetupDescHIDReport(); -extern void __SetupUSBDescriptor(); - -void __USBStart() { - mutex_init(&__usb_mutex); - - __SetupDescHIDReport(); - __SetupUSBDescriptor(); - - // Make high prio and locked to core 0 - xTaskCreate(__usb, "USB", 256, 0, configMAX_PRIORITIES - 2, &__usbTask); - vTaskCoreAffinitySet(__usbTask, 1 << 0); -} - #endif diff --git a/cores/rp2040/lock.cpp b/cores/rp2040/lock.cpp index f44865887..85b427087 100644 --- a/cores/rp2040/lock.cpp +++ b/cores/rp2040/lock.cpp @@ -59,7 +59,7 @@ SemaphoreHandle_t __lock___tz_mutex_freertos; SemaphoreHandle_t __lock___dd_hash_mutex_freertos; SemaphoreHandle_t __lock___arc4random_mutex_freertos; -void __initFreeRTOSMutexes() { +extern "C" void __initFreeRTOSMutexes() { __lock___sinit_recursive_mutex_freertos = xSemaphoreCreateRecursiveMutex(); __lock___sfp_recursive_mutex_freertos = xSemaphoreCreateRecursiveMutex(); __lock___atexit_recursive_mutex_freertos = xSemaphoreCreateRecursiveMutex();