Add Pico W WiFi support (#670)

* Add support for the WiFi chip on the Pico W board.
* USB interrupt now no longer hard coded (conflicted with the WiFi IRQ).
* Add in Pico W board to makeboards.py
* Add in GPIO and variant support
* Initialize WiFi in the Variant
* Use manual LWIP, fix size accounting
* Remove the SDK WiFi overrides
* Pulling in work done in the ESP8266 core.
* Make IPAddress support IPv6
* Build LWIP with IPv4 and IPv6 support
* Use proper MAC
* Avoid cyw_warn crash.  Make macro to a comment while building
* Add WiFiServer
* Add WiFiUdp
* Move LWIP-specific support files to LWIP_Ethernet
* Add WiFi::ping (ICMP ping)
* Move ICMP echo (ping) to LWIPIntfDev
* Move hostByName to LwipIntfDev
* Add AP mode with simple DHCP server
* Add some examples and basic ESP8266 compat hacks
* Update Adafruit TinyUSB to fix crash
* Set DHCP hostname
* Make Wifi.begin() return CONNECTED with link + IP
* Return connected() on WiFi::begin
* Fix spurious TCP retransmission
* Protect LWIP from reentrancy

The Pico SDK calls "sys_check_timeouts() from inside a periodic interrupt.
This appears unsafe, as the interrupt could happen while already in the
(non-reentrant) LWIP code.

Block the interrupt from calling sys_check_timeouts by using a global flag
manually set via an RAII recursive lock.

Add interrupt protection macros around critical sections inside LWIP via
the standard defines.

These two changes should make LWIP significantly more stable and long
running.

* Support disconnecting and reconnecting WiFi
* Add WiFiServer simple example
* Update documentation

Fixes #666
Fixed #665
This commit is contained in:
Earle F. Philhower, III 2022-07-15 16:47:53 -07:00 committed by GitHub
parent c025c4a1f8
commit abf2c586c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
72 changed files with 7504 additions and 234 deletions

View file

@ -11,6 +11,7 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
# Supported Boards
* Raspberry Pi Pico
* Raspberry Pi Pico W
* Adafruit Feather RP2040
* Adafruit ItsyBitsy RP2040
* Adafruit KB2040
@ -177,8 +178,10 @@ If you want to contribute or have bugfixes, drop me a note at <earlephilhower@ya
* [Arduino-Pico](https://github.com/earlephilhower/arduino-pico) core files are licensed under the LGPL.
* [LittleFS](https://github.com/ARMmbed/littlefs) library written by ARM Limited and released under the [BSD 3-clause license](https://github.com/ARMmbed/littlefs/blob/master/LICENSE.md).
* [UF2CONV.PY](https://github.com/microsoft/uf2) is by Microsoft Corporation and licensed under the MIT license.
* Some filesystem code taken from the [ESP8266 Arduino Core](https://github.com/esp8266/Arduino) and licensed under the LGPL.
* Networking and filesystem code taken from the [ESP8266 Arduino Core](https://github.com/esp8266/Arduino) and licensed under the LGPL.
* DHCP server for AP host mode from the [Micropython Project](https://micropython.org), distributed under the MIT License.
* [FreeRTOS](https://freertos.org) is Copyright Amazon.com, Inc. or its affiliates, and distributed under the MIT license.
* [lwIP](https://savannah.nongnu.org/projects/lwip/) is (c) the Swedish Institute of Computer Science and licenced under the BSD license.
-Earle F. Philhower, III
earlephilhower@yahoo.com

View file

@ -151,7 +151,7 @@ rpipico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI
rpipico.menu.dbglvl.NDEBUG=NDEBUG
rpipico.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
rpipico.menu.usbstack.picosdk=Pico SDK
rpipico.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
rpipico.menu.usbstack.picosdk.build.usbstack_flags=
rpipico.menu.usbstack.tinyusb=Adafruit TinyUSB
rpipico.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -292,7 +292,7 @@ rpipicopicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_R
rpipicopicoprobe.menu.dbglvl.NDEBUG=NDEBUG
rpipicopicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
rpipicopicoprobe.menu.usbstack.picosdk=Pico SDK
rpipicopicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
rpipicopicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
rpipicopicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
rpipicopicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -435,6 +435,427 @@ rpipicopicodebug.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
rpipicopicodebug.menu.usbstack.nousb=No USB
rpipicopicodebug.menu.usbstack.nousb.build.usbstack_flags="-DNO_USB -DDISABLE_USB_SERIAL -I{runtime.platform.path}/tools/libpico"
# -----------------------------------
# Raspberry Pi Pico W
# -----------------------------------
rpipicow.name=Raspberry Pi Pico W
rpipicow.vid.0=0x2e8a
rpipicow.pid.0=0xf00a
rpipicow.build.usbpid=-DSERIALUSB_PID=0xf00a
rpipicow.build.usbpwr=-DUSBD_MAX_POWER_MA=250
rpipicow.build.board=RASPBERRY_PI_PICO_W
rpipicow.build.mcu=cortex-m0plus
rpipicow.build.variant=rpipicow
rpipicow.upload.tool=uf2conv
rpipicow.upload.maximum_size=2097152
rpipicow.upload.maximum_data_size=262144
rpipicow.upload.wait_for_upload_port=true
rpipicow.upload.erase_cmd=
rpipicow.serial.disableDTR=false
rpipicow.serial.disableRTS=false
rpipicow.build.f_cpu=125000000
rpipicow.build.led=
rpipicow.build.core=rp2040
rpipicow.build.ldscript=memmap_default.ld
rpipicow.build.ram_length=256k
rpipicow.build.boot2=boot2_w25q080_2_padded_checksum
rpipicow.build.vid=0x2e8a
rpipicow.build.pid=0xf00a
rpipicow.build.usb_manufacturer="Raspberry Pi"
rpipicow.build.usb_product="Pico W"
rpipicow.menu.flash.2097152_0=2MB (no FS)
rpipicow.menu.flash.2097152_0.upload.maximum_size=2093056
rpipicow.menu.flash.2097152_0.build.flash_length=2093056
rpipicow.menu.flash.2097152_0.build.eeprom_start=270528512
rpipicow.menu.flash.2097152_0.build.fs_start=270528512
rpipicow.menu.flash.2097152_0.build.fs_end=270528512
rpipicow.menu.flash.2097152_65536=2MB (Sketch: 1984KB, FS: 64KB)
rpipicow.menu.flash.2097152_65536.upload.maximum_size=2027520
rpipicow.menu.flash.2097152_65536.build.flash_length=2027520
rpipicow.menu.flash.2097152_65536.build.eeprom_start=270528512
rpipicow.menu.flash.2097152_65536.build.fs_start=270462976
rpipicow.menu.flash.2097152_65536.build.fs_end=270528512
rpipicow.menu.flash.2097152_131072=2MB (Sketch: 1920KB, FS: 128KB)
rpipicow.menu.flash.2097152_131072.upload.maximum_size=1961984
rpipicow.menu.flash.2097152_131072.build.flash_length=1961984
rpipicow.menu.flash.2097152_131072.build.eeprom_start=270528512
rpipicow.menu.flash.2097152_131072.build.fs_start=270397440
rpipicow.menu.flash.2097152_131072.build.fs_end=270528512
rpipicow.menu.flash.2097152_262144=2MB (Sketch: 1792KB, FS: 256KB)
rpipicow.menu.flash.2097152_262144.upload.maximum_size=1830912
rpipicow.menu.flash.2097152_262144.build.flash_length=1830912
rpipicow.menu.flash.2097152_262144.build.eeprom_start=270528512
rpipicow.menu.flash.2097152_262144.build.fs_start=270266368
rpipicow.menu.flash.2097152_262144.build.fs_end=270528512
rpipicow.menu.flash.2097152_524288=2MB (Sketch: 1536KB, FS: 512KB)
rpipicow.menu.flash.2097152_524288.upload.maximum_size=1568768
rpipicow.menu.flash.2097152_524288.build.flash_length=1568768
rpipicow.menu.flash.2097152_524288.build.eeprom_start=270528512
rpipicow.menu.flash.2097152_524288.build.fs_start=270004224
rpipicow.menu.flash.2097152_524288.build.fs_end=270528512
rpipicow.menu.flash.2097152_1048576=2MB (Sketch: 1MB, FS: 1MB)
rpipicow.menu.flash.2097152_1048576.upload.maximum_size=1044480
rpipicow.menu.flash.2097152_1048576.build.flash_length=1044480
rpipicow.menu.flash.2097152_1048576.build.eeprom_start=270528512
rpipicow.menu.flash.2097152_1048576.build.fs_start=269479936
rpipicow.menu.flash.2097152_1048576.build.fs_end=270528512
rpipicow.menu.freq.133=133 MHz
rpipicow.menu.freq.133.build.f_cpu=133000000L
rpipicow.menu.freq.50=50 MHz
rpipicow.menu.freq.50.build.f_cpu=50000000L
rpipicow.menu.freq.100=100 MHz
rpipicow.menu.freq.100.build.f_cpu=100000000L
rpipicow.menu.freq.120=120 MHz
rpipicow.menu.freq.120.build.f_cpu=120000000L
rpipicow.menu.freq.125=125 MHz
rpipicow.menu.freq.125.build.f_cpu=125000000L
rpipicow.menu.freq.150=150 MHz (Overclock)
rpipicow.menu.freq.150.build.f_cpu=150000000L
rpipicow.menu.freq.175=175 MHz (Overclock)
rpipicow.menu.freq.175.build.f_cpu=175000000L
rpipicow.menu.freq.200=200 MHz (Overclock)
rpipicow.menu.freq.200.build.f_cpu=200000000L
rpipicow.menu.freq.225=225 MHz (Overclock)
rpipicow.menu.freq.225.build.f_cpu=225000000L
rpipicow.menu.freq.240=240 MHz (Overclock)
rpipicow.menu.freq.240.build.f_cpu=240000000L
rpipicow.menu.freq.250=250 MHz (Overclock)
rpipicow.menu.freq.250.build.f_cpu=250000000L
rpipicow.menu.freq.275=275 MHz (Overclock)
rpipicow.menu.freq.275.build.f_cpu=275000000L
rpipicow.menu.freq.300=300 MHz (Overclock)
rpipicow.menu.freq.300.build.f_cpu=300000000L
rpipicow.menu.opt.Small=Small (-Os) (standard)
rpipicow.menu.opt.Small.build.flags.optimize=-Os
rpipicow.menu.opt.Optimize=Optimize (-O)
rpipicow.menu.opt.Optimize.build.flags.optimize=-O
rpipicow.menu.opt.Optimize2=Optimize More (-O2)
rpipicow.menu.opt.Optimize2.build.flags.optimize=-O2
rpipicow.menu.opt.Optimize3=Optimize Even More (-O3)
rpipicow.menu.opt.Optimize3.build.flags.optimize=-O3
rpipicow.menu.opt.Fast=Fast (-Ofast) (maybe slower)
rpipicow.menu.opt.Fast.build.flags.optimize=-Ofast
rpipicow.menu.opt.Debug=Debug (-Og)
rpipicow.menu.opt.Debug.build.flags.optimize=-Og
rpipicow.menu.rtti.Disabled=Disabled
rpipicow.menu.rtti.Disabled.build.flags.rtti=-fno-rtti
rpipicow.menu.rtti.Enabled=Enabled
rpipicow.menu.rtti.Enabled.build.flags.rtti=
rpipicow.menu.stackprotect.Disabled=Disabled
rpipicow.menu.stackprotect.Disabled.build.flags.stackprotect=
rpipicow.menu.stackprotect.Enabled=Enabled
rpipicow.menu.stackprotect.Enabled.build.flags.stackprotect=-fstack-protector
rpipicow.menu.exceptions.Disabled=Disabled
rpipicow.menu.exceptions.Disabled.build.flags.exceptions=-fno-exceptions
rpipicow.menu.exceptions.Disabled.build.flags.libstdcpp=-lstdc++
rpipicow.menu.exceptions.Enabled=Enabled
rpipicow.menu.exceptions.Enabled.build.flags.exceptions=-fexceptions
rpipicow.menu.exceptions.Enabled.build.flags.libstdcpp=-lstdc++-exc
rpipicow.menu.dbgport.Disabled=Disabled
rpipicow.menu.dbgport.Disabled.build.debug_port=
rpipicow.menu.dbgport.Serial=Serial
rpipicow.menu.dbgport.Serial.build.debug_port=-DDEBUG_RP2040_PORT=Serial
rpipicow.menu.dbgport.Serial1=Serial1
rpipicow.menu.dbgport.Serial1.build.debug_port=-DDEBUG_RP2040_PORT=Serial1
rpipicow.menu.dbgport.Serial2=Serial2
rpipicow.menu.dbgport.Serial2.build.debug_port=-DDEBUG_RP2040_PORT=Serial2
rpipicow.menu.dbglvl.None=None
rpipicow.menu.dbglvl.None.build.debug_level=
rpipicow.menu.dbglvl.Core=Core
rpipicow.menu.dbglvl.Core.build.debug_level=-DDEBUG_RP2040_CORE
rpipicow.menu.dbglvl.SPI=SPI
rpipicow.menu.dbglvl.SPI.build.debug_level=-DDEBUG_RP2040_SPI
rpipicow.menu.dbglvl.Wire=Wire
rpipicow.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE
rpipicow.menu.dbglvl.All=All
rpipicow.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE
rpipicow.menu.dbglvl.NDEBUG=NDEBUG
rpipicow.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
rpipicow.menu.usbstack.picosdk=Pico SDK
rpipicow.menu.usbstack.picosdk.build.usbstack_flags=
rpipicow.menu.usbstack.tinyusb=Adafruit TinyUSB
rpipicow.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
# -----------------------------------
# Raspberry Pi Pico W (Picoprobe)
# -----------------------------------
rpipicowpicoprobe.name=Raspberry Pi Pico W (Picoprobe)
rpipicowpicoprobe.vid.0=0x2e8a
rpipicowpicoprobe.pid.0=0x0004
rpipicowpicoprobe.build.usbpid=-DSERIALUSB_PID=0xf00a
rpipicowpicoprobe.build.usbpwr=-DUSBD_MAX_POWER_MA=250
rpipicowpicoprobe.build.board=RASPBERRY_PI_PICO_W
rpipicowpicoprobe.build.mcu=cortex-m0plus
rpipicowpicoprobe.build.variant=rpipicow
rpipicowpicoprobe.upload.tool=picoprobe
rpipicowpicoprobe.upload.maximum_size=2097152
rpipicowpicoprobe.upload.maximum_data_size=262144
rpipicowpicoprobe.upload.wait_for_upload_port=true
rpipicowpicoprobe.upload.erase_cmd=
rpipicowpicoprobe.serial.disableDTR=false
rpipicowpicoprobe.serial.disableRTS=false
rpipicowpicoprobe.build.f_cpu=125000000
rpipicowpicoprobe.build.led=
rpipicowpicoprobe.build.core=rp2040
rpipicowpicoprobe.build.ldscript=memmap_default.ld
rpipicowpicoprobe.build.ram_length=256k
rpipicowpicoprobe.build.boot2=boot2_w25q080_2_padded_checksum
rpipicowpicoprobe.build.vid=0x2e8a
rpipicowpicoprobe.build.pid=0xf00a
rpipicowpicoprobe.build.usb_manufacturer="Raspberry Pi"
rpipicowpicoprobe.build.usb_product="Pico W (Picoprobe)"
rpipicowpicoprobe.menu.flash.2097152_0=2MB (no FS)
rpipicowpicoprobe.menu.flash.2097152_0.upload.maximum_size=2093056
rpipicowpicoprobe.menu.flash.2097152_0.build.flash_length=2093056
rpipicowpicoprobe.menu.flash.2097152_0.build.eeprom_start=270528512
rpipicowpicoprobe.menu.flash.2097152_0.build.fs_start=270528512
rpipicowpicoprobe.menu.flash.2097152_0.build.fs_end=270528512
rpipicowpicoprobe.menu.flash.2097152_65536=2MB (Sketch: 1984KB, FS: 64KB)
rpipicowpicoprobe.menu.flash.2097152_65536.upload.maximum_size=2027520
rpipicowpicoprobe.menu.flash.2097152_65536.build.flash_length=2027520
rpipicowpicoprobe.menu.flash.2097152_65536.build.eeprom_start=270528512
rpipicowpicoprobe.menu.flash.2097152_65536.build.fs_start=270462976
rpipicowpicoprobe.menu.flash.2097152_65536.build.fs_end=270528512
rpipicowpicoprobe.menu.flash.2097152_131072=2MB (Sketch: 1920KB, FS: 128KB)
rpipicowpicoprobe.menu.flash.2097152_131072.upload.maximum_size=1961984
rpipicowpicoprobe.menu.flash.2097152_131072.build.flash_length=1961984
rpipicowpicoprobe.menu.flash.2097152_131072.build.eeprom_start=270528512
rpipicowpicoprobe.menu.flash.2097152_131072.build.fs_start=270397440
rpipicowpicoprobe.menu.flash.2097152_131072.build.fs_end=270528512
rpipicowpicoprobe.menu.flash.2097152_262144=2MB (Sketch: 1792KB, FS: 256KB)
rpipicowpicoprobe.menu.flash.2097152_262144.upload.maximum_size=1830912
rpipicowpicoprobe.menu.flash.2097152_262144.build.flash_length=1830912
rpipicowpicoprobe.menu.flash.2097152_262144.build.eeprom_start=270528512
rpipicowpicoprobe.menu.flash.2097152_262144.build.fs_start=270266368
rpipicowpicoprobe.menu.flash.2097152_262144.build.fs_end=270528512
rpipicowpicoprobe.menu.flash.2097152_524288=2MB (Sketch: 1536KB, FS: 512KB)
rpipicowpicoprobe.menu.flash.2097152_524288.upload.maximum_size=1568768
rpipicowpicoprobe.menu.flash.2097152_524288.build.flash_length=1568768
rpipicowpicoprobe.menu.flash.2097152_524288.build.eeprom_start=270528512
rpipicowpicoprobe.menu.flash.2097152_524288.build.fs_start=270004224
rpipicowpicoprobe.menu.flash.2097152_524288.build.fs_end=270528512
rpipicowpicoprobe.menu.flash.2097152_1048576=2MB (Sketch: 1MB, FS: 1MB)
rpipicowpicoprobe.menu.flash.2097152_1048576.upload.maximum_size=1044480
rpipicowpicoprobe.menu.flash.2097152_1048576.build.flash_length=1044480
rpipicowpicoprobe.menu.flash.2097152_1048576.build.eeprom_start=270528512
rpipicowpicoprobe.menu.flash.2097152_1048576.build.fs_start=269479936
rpipicowpicoprobe.menu.flash.2097152_1048576.build.fs_end=270528512
rpipicowpicoprobe.menu.freq.133=133 MHz
rpipicowpicoprobe.menu.freq.133.build.f_cpu=133000000L
rpipicowpicoprobe.menu.freq.50=50 MHz
rpipicowpicoprobe.menu.freq.50.build.f_cpu=50000000L
rpipicowpicoprobe.menu.freq.100=100 MHz
rpipicowpicoprobe.menu.freq.100.build.f_cpu=100000000L
rpipicowpicoprobe.menu.freq.120=120 MHz
rpipicowpicoprobe.menu.freq.120.build.f_cpu=120000000L
rpipicowpicoprobe.menu.freq.125=125 MHz
rpipicowpicoprobe.menu.freq.125.build.f_cpu=125000000L
rpipicowpicoprobe.menu.freq.150=150 MHz (Overclock)
rpipicowpicoprobe.menu.freq.150.build.f_cpu=150000000L
rpipicowpicoprobe.menu.freq.175=175 MHz (Overclock)
rpipicowpicoprobe.menu.freq.175.build.f_cpu=175000000L
rpipicowpicoprobe.menu.freq.200=200 MHz (Overclock)
rpipicowpicoprobe.menu.freq.200.build.f_cpu=200000000L
rpipicowpicoprobe.menu.freq.225=225 MHz (Overclock)
rpipicowpicoprobe.menu.freq.225.build.f_cpu=225000000L
rpipicowpicoprobe.menu.freq.240=240 MHz (Overclock)
rpipicowpicoprobe.menu.freq.240.build.f_cpu=240000000L
rpipicowpicoprobe.menu.freq.250=250 MHz (Overclock)
rpipicowpicoprobe.menu.freq.250.build.f_cpu=250000000L
rpipicowpicoprobe.menu.freq.275=275 MHz (Overclock)
rpipicowpicoprobe.menu.freq.275.build.f_cpu=275000000L
rpipicowpicoprobe.menu.freq.300=300 MHz (Overclock)
rpipicowpicoprobe.menu.freq.300.build.f_cpu=300000000L
rpipicowpicoprobe.menu.opt.Small=Small (-Os) (standard)
rpipicowpicoprobe.menu.opt.Small.build.flags.optimize=-Os
rpipicowpicoprobe.menu.opt.Optimize=Optimize (-O)
rpipicowpicoprobe.menu.opt.Optimize.build.flags.optimize=-O
rpipicowpicoprobe.menu.opt.Optimize2=Optimize More (-O2)
rpipicowpicoprobe.menu.opt.Optimize2.build.flags.optimize=-O2
rpipicowpicoprobe.menu.opt.Optimize3=Optimize Even More (-O3)
rpipicowpicoprobe.menu.opt.Optimize3.build.flags.optimize=-O3
rpipicowpicoprobe.menu.opt.Fast=Fast (-Ofast) (maybe slower)
rpipicowpicoprobe.menu.opt.Fast.build.flags.optimize=-Ofast
rpipicowpicoprobe.menu.opt.Debug=Debug (-Og)
rpipicowpicoprobe.menu.opt.Debug.build.flags.optimize=-Og
rpipicowpicoprobe.menu.rtti.Disabled=Disabled
rpipicowpicoprobe.menu.rtti.Disabled.build.flags.rtti=-fno-rtti
rpipicowpicoprobe.menu.rtti.Enabled=Enabled
rpipicowpicoprobe.menu.rtti.Enabled.build.flags.rtti=
rpipicowpicoprobe.menu.stackprotect.Disabled=Disabled
rpipicowpicoprobe.menu.stackprotect.Disabled.build.flags.stackprotect=
rpipicowpicoprobe.menu.stackprotect.Enabled=Enabled
rpipicowpicoprobe.menu.stackprotect.Enabled.build.flags.stackprotect=-fstack-protector
rpipicowpicoprobe.menu.exceptions.Disabled=Disabled
rpipicowpicoprobe.menu.exceptions.Disabled.build.flags.exceptions=-fno-exceptions
rpipicowpicoprobe.menu.exceptions.Disabled.build.flags.libstdcpp=-lstdc++
rpipicowpicoprobe.menu.exceptions.Enabled=Enabled
rpipicowpicoprobe.menu.exceptions.Enabled.build.flags.exceptions=-fexceptions
rpipicowpicoprobe.menu.exceptions.Enabled.build.flags.libstdcpp=-lstdc++-exc
rpipicowpicoprobe.menu.dbgport.Disabled=Disabled
rpipicowpicoprobe.menu.dbgport.Disabled.build.debug_port=
rpipicowpicoprobe.menu.dbgport.Serial=Serial
rpipicowpicoprobe.menu.dbgport.Serial.build.debug_port=-DDEBUG_RP2040_PORT=Serial
rpipicowpicoprobe.menu.dbgport.Serial1=Serial1
rpipicowpicoprobe.menu.dbgport.Serial1.build.debug_port=-DDEBUG_RP2040_PORT=Serial1
rpipicowpicoprobe.menu.dbgport.Serial2=Serial2
rpipicowpicoprobe.menu.dbgport.Serial2.build.debug_port=-DDEBUG_RP2040_PORT=Serial2
rpipicowpicoprobe.menu.dbglvl.None=None
rpipicowpicoprobe.menu.dbglvl.None.build.debug_level=
rpipicowpicoprobe.menu.dbglvl.Core=Core
rpipicowpicoprobe.menu.dbglvl.Core.build.debug_level=-DDEBUG_RP2040_CORE
rpipicowpicoprobe.menu.dbglvl.SPI=SPI
rpipicowpicoprobe.menu.dbglvl.SPI.build.debug_level=-DDEBUG_RP2040_SPI
rpipicowpicoprobe.menu.dbglvl.Wire=Wire
rpipicowpicoprobe.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE
rpipicowpicoprobe.menu.dbglvl.All=All
rpipicowpicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE
rpipicowpicoprobe.menu.dbglvl.NDEBUG=NDEBUG
rpipicowpicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
rpipicowpicoprobe.menu.usbstack.picosdk=Pico SDK
rpipicowpicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
rpipicowpicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
rpipicowpicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
# -----------------------------------
# Raspberry Pi Pico W (pico-debug)
# -----------------------------------
rpipicowpicodebug.name=Raspberry Pi Pico W (pico-debug)
rpipicowpicodebug.vid.0=0x1209
rpipicowpicodebug.pid.0=0x2488
rpipicowpicodebug.build.usbpid=-DSERIALUSB_PID=0xf00a
rpipicowpicodebug.build.usbpwr=-DUSBD_MAX_POWER_MA=250
rpipicowpicodebug.build.board=RASPBERRY_PI_PICO_W
rpipicowpicodebug.build.mcu=cortex-m0plus
rpipicowpicodebug.build.variant=rpipicow
rpipicowpicodebug.upload.tool=picodebug
rpipicowpicodebug.upload.maximum_size=2097152
rpipicowpicodebug.upload.maximum_data_size=245760
rpipicowpicodebug.upload.wait_for_upload_port=true
rpipicowpicodebug.upload.erase_cmd=
rpipicowpicodebug.serial.disableDTR=false
rpipicowpicodebug.serial.disableRTS=false
rpipicowpicodebug.build.f_cpu=125000000
rpipicowpicodebug.build.led=
rpipicowpicodebug.build.core=rp2040
rpipicowpicodebug.build.ldscript=memmap_default.ld
rpipicowpicodebug.build.ram_length=240k
rpipicowpicodebug.build.boot2=boot2_w25q080_2_padded_checksum
rpipicowpicodebug.build.vid=0x2e8a
rpipicowpicodebug.build.pid=0xf00a
rpipicowpicodebug.build.usb_manufacturer="Raspberry Pi"
rpipicowpicodebug.build.usb_product="Pico W (pico-debug)"
rpipicowpicodebug.menu.flash.2097152_0=2MB (no FS)
rpipicowpicodebug.menu.flash.2097152_0.upload.maximum_size=2093056
rpipicowpicodebug.menu.flash.2097152_0.build.flash_length=2093056
rpipicowpicodebug.menu.flash.2097152_0.build.eeprom_start=270528512
rpipicowpicodebug.menu.flash.2097152_0.build.fs_start=270528512
rpipicowpicodebug.menu.flash.2097152_0.build.fs_end=270528512
rpipicowpicodebug.menu.flash.2097152_65536=2MB (Sketch: 1984KB, FS: 64KB)
rpipicowpicodebug.menu.flash.2097152_65536.upload.maximum_size=2027520
rpipicowpicodebug.menu.flash.2097152_65536.build.flash_length=2027520
rpipicowpicodebug.menu.flash.2097152_65536.build.eeprom_start=270528512
rpipicowpicodebug.menu.flash.2097152_65536.build.fs_start=270462976
rpipicowpicodebug.menu.flash.2097152_65536.build.fs_end=270528512
rpipicowpicodebug.menu.flash.2097152_131072=2MB (Sketch: 1920KB, FS: 128KB)
rpipicowpicodebug.menu.flash.2097152_131072.upload.maximum_size=1961984
rpipicowpicodebug.menu.flash.2097152_131072.build.flash_length=1961984
rpipicowpicodebug.menu.flash.2097152_131072.build.eeprom_start=270528512
rpipicowpicodebug.menu.flash.2097152_131072.build.fs_start=270397440
rpipicowpicodebug.menu.flash.2097152_131072.build.fs_end=270528512
rpipicowpicodebug.menu.flash.2097152_262144=2MB (Sketch: 1792KB, FS: 256KB)
rpipicowpicodebug.menu.flash.2097152_262144.upload.maximum_size=1830912
rpipicowpicodebug.menu.flash.2097152_262144.build.flash_length=1830912
rpipicowpicodebug.menu.flash.2097152_262144.build.eeprom_start=270528512
rpipicowpicodebug.menu.flash.2097152_262144.build.fs_start=270266368
rpipicowpicodebug.menu.flash.2097152_262144.build.fs_end=270528512
rpipicowpicodebug.menu.flash.2097152_524288=2MB (Sketch: 1536KB, FS: 512KB)
rpipicowpicodebug.menu.flash.2097152_524288.upload.maximum_size=1568768
rpipicowpicodebug.menu.flash.2097152_524288.build.flash_length=1568768
rpipicowpicodebug.menu.flash.2097152_524288.build.eeprom_start=270528512
rpipicowpicodebug.menu.flash.2097152_524288.build.fs_start=270004224
rpipicowpicodebug.menu.flash.2097152_524288.build.fs_end=270528512
rpipicowpicodebug.menu.flash.2097152_1048576=2MB (Sketch: 1MB, FS: 1MB)
rpipicowpicodebug.menu.flash.2097152_1048576.upload.maximum_size=1044480
rpipicowpicodebug.menu.flash.2097152_1048576.build.flash_length=1044480
rpipicowpicodebug.menu.flash.2097152_1048576.build.eeprom_start=270528512
rpipicowpicodebug.menu.flash.2097152_1048576.build.fs_start=269479936
rpipicowpicodebug.menu.flash.2097152_1048576.build.fs_end=270528512
rpipicowpicodebug.menu.freq.133=133 MHz
rpipicowpicodebug.menu.freq.133.build.f_cpu=133000000L
rpipicowpicodebug.menu.freq.50=50 MHz
rpipicowpicodebug.menu.freq.50.build.f_cpu=50000000L
rpipicowpicodebug.menu.freq.100=100 MHz
rpipicowpicodebug.menu.freq.100.build.f_cpu=100000000L
rpipicowpicodebug.menu.freq.120=120 MHz
rpipicowpicodebug.menu.freq.120.build.f_cpu=120000000L
rpipicowpicodebug.menu.freq.125=125 MHz
rpipicowpicodebug.menu.freq.125.build.f_cpu=125000000L
rpipicowpicodebug.menu.freq.150=150 MHz (Overclock)
rpipicowpicodebug.menu.freq.150.build.f_cpu=150000000L
rpipicowpicodebug.menu.freq.175=175 MHz (Overclock)
rpipicowpicodebug.menu.freq.175.build.f_cpu=175000000L
rpipicowpicodebug.menu.freq.200=200 MHz (Overclock)
rpipicowpicodebug.menu.freq.200.build.f_cpu=200000000L
rpipicowpicodebug.menu.freq.225=225 MHz (Overclock)
rpipicowpicodebug.menu.freq.225.build.f_cpu=225000000L
rpipicowpicodebug.menu.freq.240=240 MHz (Overclock)
rpipicowpicodebug.menu.freq.240.build.f_cpu=240000000L
rpipicowpicodebug.menu.freq.250=250 MHz (Overclock)
rpipicowpicodebug.menu.freq.250.build.f_cpu=250000000L
rpipicowpicodebug.menu.freq.275=275 MHz (Overclock)
rpipicowpicodebug.menu.freq.275.build.f_cpu=275000000L
rpipicowpicodebug.menu.freq.300=300 MHz (Overclock)
rpipicowpicodebug.menu.freq.300.build.f_cpu=300000000L
rpipicowpicodebug.menu.opt.Small=Small (-Os) (standard)
rpipicowpicodebug.menu.opt.Small.build.flags.optimize=-Os
rpipicowpicodebug.menu.opt.Optimize=Optimize (-O)
rpipicowpicodebug.menu.opt.Optimize.build.flags.optimize=-O
rpipicowpicodebug.menu.opt.Optimize2=Optimize More (-O2)
rpipicowpicodebug.menu.opt.Optimize2.build.flags.optimize=-O2
rpipicowpicodebug.menu.opt.Optimize3=Optimize Even More (-O3)
rpipicowpicodebug.menu.opt.Optimize3.build.flags.optimize=-O3
rpipicowpicodebug.menu.opt.Fast=Fast (-Ofast) (maybe slower)
rpipicowpicodebug.menu.opt.Fast.build.flags.optimize=-Ofast
rpipicowpicodebug.menu.opt.Debug=Debug (-Og)
rpipicowpicodebug.menu.opt.Debug.build.flags.optimize=-Og
rpipicowpicodebug.menu.rtti.Disabled=Disabled
rpipicowpicodebug.menu.rtti.Disabled.build.flags.rtti=-fno-rtti
rpipicowpicodebug.menu.rtti.Enabled=Enabled
rpipicowpicodebug.menu.rtti.Enabled.build.flags.rtti=
rpipicowpicodebug.menu.stackprotect.Disabled=Disabled
rpipicowpicodebug.menu.stackprotect.Disabled.build.flags.stackprotect=
rpipicowpicodebug.menu.stackprotect.Enabled=Enabled
rpipicowpicodebug.menu.stackprotect.Enabled.build.flags.stackprotect=-fstack-protector
rpipicowpicodebug.menu.exceptions.Disabled=Disabled
rpipicowpicodebug.menu.exceptions.Disabled.build.flags.exceptions=-fno-exceptions
rpipicowpicodebug.menu.exceptions.Disabled.build.flags.libstdcpp=-lstdc++
rpipicowpicodebug.menu.exceptions.Enabled=Enabled
rpipicowpicodebug.menu.exceptions.Enabled.build.flags.exceptions=-fexceptions
rpipicowpicodebug.menu.exceptions.Enabled.build.flags.libstdcpp=-lstdc++-exc
rpipicowpicodebug.menu.dbgport.Disabled=Disabled
rpipicowpicodebug.menu.dbgport.Disabled.build.debug_port=
rpipicowpicodebug.menu.dbgport.Serial=Serial
rpipicowpicodebug.menu.dbgport.Serial.build.debug_port=-DDEBUG_RP2040_PORT=Serial
rpipicowpicodebug.menu.dbgport.Serial1=Serial1
rpipicowpicodebug.menu.dbgport.Serial1.build.debug_port=-DDEBUG_RP2040_PORT=Serial1
rpipicowpicodebug.menu.dbgport.Serial2=Serial2
rpipicowpicodebug.menu.dbgport.Serial2.build.debug_port=-DDEBUG_RP2040_PORT=Serial2
rpipicowpicodebug.menu.dbglvl.None=None
rpipicowpicodebug.menu.dbglvl.None.build.debug_level=
rpipicowpicodebug.menu.dbglvl.Core=Core
rpipicowpicodebug.menu.dbglvl.Core.build.debug_level=-DDEBUG_RP2040_CORE
rpipicowpicodebug.menu.dbglvl.SPI=SPI
rpipicowpicodebug.menu.dbglvl.SPI.build.debug_level=-DDEBUG_RP2040_SPI
rpipicowpicodebug.menu.dbglvl.Wire=Wire
rpipicowpicodebug.menu.dbglvl.Wire.build.debug_level=-DDEBUG_RP2040_WIRE
rpipicowpicodebug.menu.dbglvl.All=All
rpipicowpicodebug.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI -DDEBUG_RP2040_CORE
rpipicowpicodebug.menu.dbglvl.NDEBUG=NDEBUG
rpipicowpicodebug.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
rpipicowpicodebug.menu.usbstack.nousb=No USB
rpipicowpicodebug.menu.usbstack.nousb.build.usbstack_flags="-DNO_USB -DDISABLE_USB_SERIAL -I{runtime.platform.path}/tools/libpico"
# -----------------------------------
# Adafruit Feather RP2040
# -----------------------------------
@ -608,7 +1029,7 @@ adafruit_feather.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_R
adafruit_feather.menu.dbglvl.NDEBUG=NDEBUG
adafruit_feather.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
adafruit_feather.menu.usbstack.picosdk=Pico SDK
adafruit_feather.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
adafruit_feather.menu.usbstack.picosdk.build.usbstack_flags=
adafruit_feather.menu.usbstack.tinyusb=Adafruit TinyUSB
adafruit_feather.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -785,7 +1206,7 @@ adafruit_featherpicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE
adafruit_featherpicoprobe.menu.dbglvl.NDEBUG=NDEBUG
adafruit_featherpicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
adafruit_featherpicoprobe.menu.usbstack.picosdk=Pico SDK
adafruit_featherpicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
adafruit_featherpicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
adafruit_featherpicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
adafruit_featherpicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -1137,7 +1558,7 @@ adafruit_itsybitsy.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG
adafruit_itsybitsy.menu.dbglvl.NDEBUG=NDEBUG
adafruit_itsybitsy.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
adafruit_itsybitsy.menu.usbstack.picosdk=Pico SDK
adafruit_itsybitsy.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
adafruit_itsybitsy.menu.usbstack.picosdk.build.usbstack_flags=
adafruit_itsybitsy.menu.usbstack.tinyusb=Adafruit TinyUSB
adafruit_itsybitsy.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -1314,7 +1735,7 @@ adafruit_itsybitsypicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIR
adafruit_itsybitsypicoprobe.menu.dbglvl.NDEBUG=NDEBUG
adafruit_itsybitsypicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
adafruit_itsybitsypicoprobe.menu.usbstack.picosdk=Pico SDK
adafruit_itsybitsypicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
adafruit_itsybitsypicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
adafruit_itsybitsypicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
adafruit_itsybitsypicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -1666,7 +2087,7 @@ adafruit_qtpy.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP20
adafruit_qtpy.menu.dbglvl.NDEBUG=NDEBUG
adafruit_qtpy.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
adafruit_qtpy.menu.usbstack.picosdk=Pico SDK
adafruit_qtpy.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
adafruit_qtpy.menu.usbstack.picosdk.build.usbstack_flags=
adafruit_qtpy.menu.usbstack.tinyusb=Adafruit TinyUSB
adafruit_qtpy.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -1843,7 +2264,7 @@ adafruit_qtpypicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DD
adafruit_qtpypicoprobe.menu.dbglvl.NDEBUG=NDEBUG
adafruit_qtpypicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
adafruit_qtpypicoprobe.menu.usbstack.picosdk=Pico SDK
adafruit_qtpypicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
adafruit_qtpypicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
adafruit_qtpypicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
adafruit_qtpypicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -2195,7 +2616,7 @@ adafruit_stemmafriend.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDE
adafruit_stemmafriend.menu.dbglvl.NDEBUG=NDEBUG
adafruit_stemmafriend.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
adafruit_stemmafriend.menu.usbstack.picosdk=Pico SDK
adafruit_stemmafriend.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
adafruit_stemmafriend.menu.usbstack.picosdk.build.usbstack_flags=
adafruit_stemmafriend.menu.usbstack.tinyusb=Adafruit TinyUSB
adafruit_stemmafriend.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -2372,7 +2793,7 @@ adafruit_stemmafriendpicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_
adafruit_stemmafriendpicoprobe.menu.dbglvl.NDEBUG=NDEBUG
adafruit_stemmafriendpicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
adafruit_stemmafriendpicoprobe.menu.usbstack.picosdk=Pico SDK
adafruit_stemmafriendpicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
adafruit_stemmafriendpicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
adafruit_stemmafriendpicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
adafruit_stemmafriendpicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -2724,7 +3145,7 @@ adafruit_trinkeyrp2040qt.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -
adafruit_trinkeyrp2040qt.menu.dbglvl.NDEBUG=NDEBUG
adafruit_trinkeyrp2040qt.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
adafruit_trinkeyrp2040qt.menu.usbstack.picosdk=Pico SDK
adafruit_trinkeyrp2040qt.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
adafruit_trinkeyrp2040qt.menu.usbstack.picosdk.build.usbstack_flags=
adafruit_trinkeyrp2040qt.menu.usbstack.tinyusb=Adafruit TinyUSB
adafruit_trinkeyrp2040qt.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -2901,7 +3322,7 @@ adafruit_trinkeyrp2040qtpicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP20
adafruit_trinkeyrp2040qtpicoprobe.menu.dbglvl.NDEBUG=NDEBUG
adafruit_trinkeyrp2040qtpicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
adafruit_trinkeyrp2040qtpicoprobe.menu.usbstack.picosdk=Pico SDK
adafruit_trinkeyrp2040qtpicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
adafruit_trinkeyrp2040qtpicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
adafruit_trinkeyrp2040qtpicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
adafruit_trinkeyrp2040qtpicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -3253,7 +3674,7 @@ adafruit_macropad2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDE
adafruit_macropad2040.menu.dbglvl.NDEBUG=NDEBUG
adafruit_macropad2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
adafruit_macropad2040.menu.usbstack.picosdk=Pico SDK
adafruit_macropad2040.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
adafruit_macropad2040.menu.usbstack.picosdk.build.usbstack_flags=
adafruit_macropad2040.menu.usbstack.tinyusb=Adafruit TinyUSB
adafruit_macropad2040.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -3430,7 +3851,7 @@ adafruit_macropad2040picoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_
adafruit_macropad2040picoprobe.menu.dbglvl.NDEBUG=NDEBUG
adafruit_macropad2040picoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
adafruit_macropad2040picoprobe.menu.usbstack.picosdk=Pico SDK
adafruit_macropad2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
adafruit_macropad2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags=
adafruit_macropad2040picoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
adafruit_macropad2040picoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -3782,7 +4203,7 @@ adafruit_kb2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP
adafruit_kb2040.menu.dbglvl.NDEBUG=NDEBUG
adafruit_kb2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
adafruit_kb2040.menu.usbstack.picosdk=Pico SDK
adafruit_kb2040.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
adafruit_kb2040.menu.usbstack.picosdk.build.usbstack_flags=
adafruit_kb2040.menu.usbstack.tinyusb=Adafruit TinyUSB
adafruit_kb2040.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -3959,7 +4380,7 @@ adafruit_kb2040picoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -
adafruit_kb2040picoprobe.menu.dbglvl.NDEBUG=NDEBUG
adafruit_kb2040picoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
adafruit_kb2040picoprobe.menu.usbstack.picosdk=Pico SDK
adafruit_kb2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
adafruit_kb2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags=
adafruit_kb2040picoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
adafruit_kb2040picoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -4359,7 +4780,7 @@ arduino_nano_connect.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEB
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
arduino_nano_connect.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
arduino_nano_connect.menu.usbstack.picosdk.build.usbstack_flags=
arduino_nano_connect.menu.usbstack.tinyusb=Adafruit TinyUSB
arduino_nano_connect.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -4584,7 +5005,7 @@ arduino_nano_connectpicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_W
arduino_nano_connectpicoprobe.menu.dbglvl.NDEBUG=NDEBUG
arduino_nano_connectpicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
arduino_nano_connectpicoprobe.menu.usbstack.picosdk=Pico SDK
arduino_nano_connectpicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
arduino_nano_connectpicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
arduino_nano_connectpicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
arduino_nano_connectpicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -4948,7 +5369,7 @@ cytron_maker_nano_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -
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
cytron_maker_nano_rp2040.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
cytron_maker_nano_rp2040.menu.usbstack.picosdk.build.usbstack_flags=
cytron_maker_nano_rp2040.menu.usbstack.tinyusb=Adafruit TinyUSB
cytron_maker_nano_rp2040.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -5089,7 +5510,7 @@ cytron_maker_nano_rp2040picoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP20
cytron_maker_nano_rp2040picoprobe.menu.dbglvl.NDEBUG=NDEBUG
cytron_maker_nano_rp2040picoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
cytron_maker_nano_rp2040picoprobe.menu.usbstack.picosdk=Pico SDK
cytron_maker_nano_rp2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
cytron_maker_nano_rp2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags=
cytron_maker_nano_rp2040picoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
cytron_maker_nano_rp2040picoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -5369,7 +5790,7 @@ cytron_maker_pi_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DD
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
cytron_maker_pi_rp2040.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
cytron_maker_pi_rp2040.menu.usbstack.picosdk.build.usbstack_flags=
cytron_maker_pi_rp2040.menu.usbstack.tinyusb=Adafruit TinyUSB
cytron_maker_pi_rp2040.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -5510,7 +5931,7 @@ cytron_maker_pi_rp2040picoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040
cytron_maker_pi_rp2040picoprobe.menu.dbglvl.NDEBUG=NDEBUG
cytron_maker_pi_rp2040picoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
cytron_maker_pi_rp2040picoprobe.menu.usbstack.picosdk=Pico SDK
cytron_maker_pi_rp2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
cytron_maker_pi_rp2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags=
cytron_maker_pi_rp2040picoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
cytron_maker_pi_rp2040picoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -5802,7 +6223,7 @@ flyboard2040_core.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_
flyboard2040_core.menu.dbglvl.NDEBUG=NDEBUG
flyboard2040_core.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
flyboard2040_core.menu.usbstack.picosdk=Pico SDK
flyboard2040_core.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
flyboard2040_core.menu.usbstack.picosdk.build.usbstack_flags=
flyboard2040_core.menu.usbstack.tinyusb=Adafruit TinyUSB
flyboard2040_core.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -5955,7 +6376,7 @@ flyboard2040_corepicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE
flyboard2040_corepicoprobe.menu.dbglvl.NDEBUG=NDEBUG
flyboard2040_corepicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
flyboard2040_corepicoprobe.menu.usbstack.picosdk=Pico SDK
flyboard2040_corepicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
flyboard2040_corepicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
flyboard2040_corepicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
flyboard2040_corepicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -6247,7 +6668,7 @@ dfrobot_beetle_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDE
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
dfrobot_beetle_rp2040.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
dfrobot_beetle_rp2040.menu.usbstack.picosdk.build.usbstack_flags=
dfrobot_beetle_rp2040.menu.usbstack.tinyusb=Adafruit TinyUSB
dfrobot_beetle_rp2040.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -6388,7 +6809,7 @@ dfrobot_beetle_rp2040picoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_
dfrobot_beetle_rp2040picoprobe.menu.dbglvl.NDEBUG=NDEBUG
dfrobot_beetle_rp2040picoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
dfrobot_beetle_rp2040picoprobe.menu.usbstack.picosdk=Pico SDK
dfrobot_beetle_rp2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
dfrobot_beetle_rp2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags=
dfrobot_beetle_rp2040picoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
dfrobot_beetle_rp2040picoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -6704,7 +7125,7 @@ challenger_2040_lora.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEB
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
challenger_2040_lora.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
challenger_2040_lora.menu.usbstack.picosdk.build.usbstack_flags=
challenger_2040_lora.menu.usbstack.tinyusb=Adafruit TinyUSB
challenger_2040_lora.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -6881,7 +7302,7 @@ challenger_2040_lorapicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_W
challenger_2040_lorapicoprobe.menu.dbglvl.NDEBUG=NDEBUG
challenger_2040_lorapicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
challenger_2040_lorapicoprobe.menu.usbstack.picosdk=Pico SDK
challenger_2040_lorapicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
challenger_2040_lorapicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
challenger_2040_lorapicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
challenger_2040_lorapicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -7233,7 +7654,7 @@ challenger_2040_subghz.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DD
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
challenger_2040_subghz.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
challenger_2040_subghz.menu.usbstack.picosdk.build.usbstack_flags=
challenger_2040_subghz.menu.usbstack.tinyusb=Adafruit TinyUSB
challenger_2040_subghz.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -7410,7 +7831,7 @@ challenger_2040_subghzpicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040
challenger_2040_subghzpicoprobe.menu.dbglvl.NDEBUG=NDEBUG
challenger_2040_subghzpicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
challenger_2040_subghzpicoprobe.menu.usbstack.picosdk=Pico SDK
challenger_2040_subghzpicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
challenger_2040_subghzpicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
challenger_2040_subghzpicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
challenger_2040_subghzpicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -7762,7 +8183,7 @@ challenger_2040_wifi.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEB
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
challenger_2040_wifi.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
challenger_2040_wifi.menu.usbstack.picosdk.build.usbstack_flags=
challenger_2040_wifi.menu.usbstack.tinyusb=Adafruit TinyUSB
challenger_2040_wifi.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -7939,7 +8360,7 @@ challenger_2040_wifipicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_W
challenger_2040_wifipicoprobe.menu.dbglvl.NDEBUG=NDEBUG
challenger_2040_wifipicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
challenger_2040_wifipicoprobe.menu.usbstack.picosdk=Pico SDK
challenger_2040_wifipicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
challenger_2040_wifipicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
challenger_2040_wifipicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
challenger_2040_wifipicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -8291,7 +8712,7 @@ challenger_2040_lte.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBU
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
challenger_2040_lte.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
challenger_2040_lte.menu.usbstack.picosdk.build.usbstack_flags=
challenger_2040_lte.menu.usbstack.tinyusb=Adafruit TinyUSB
challenger_2040_lte.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -8468,7 +8889,7 @@ challenger_2040_ltepicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WI
challenger_2040_ltepicoprobe.menu.dbglvl.NDEBUG=NDEBUG
challenger_2040_ltepicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
challenger_2040_ltepicoprobe.menu.usbstack.picosdk=Pico SDK
challenger_2040_ltepicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
challenger_2040_ltepicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
challenger_2040_ltepicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
challenger_2040_ltepicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -8820,7 +9241,7 @@ challenger_2040_wifi_ble.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -
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
challenger_2040_wifi_ble.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
challenger_2040_wifi_ble.menu.usbstack.picosdk.build.usbstack_flags=
challenger_2040_wifi_ble.menu.usbstack.tinyusb=Adafruit TinyUSB
challenger_2040_wifi_ble.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -8997,7 +9418,7 @@ challenger_2040_wifi_blepicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP20
challenger_2040_wifi_blepicoprobe.menu.dbglvl.NDEBUG=NDEBUG
challenger_2040_wifi_blepicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
challenger_2040_wifi_blepicoprobe.menu.usbstack.picosdk=Pico SDK
challenger_2040_wifi_blepicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
challenger_2040_wifi_blepicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
challenger_2040_wifi_blepicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
challenger_2040_wifi_blepicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -9349,7 +9770,7 @@ challenger_nb_2040_wifi.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -D
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
challenger_nb_2040_wifi.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
challenger_nb_2040_wifi.menu.usbstack.picosdk.build.usbstack_flags=
challenger_nb_2040_wifi.menu.usbstack.tinyusb=Adafruit TinyUSB
challenger_nb_2040_wifi.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -9526,7 +9947,7 @@ challenger_nb_2040_wifipicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP204
challenger_nb_2040_wifipicoprobe.menu.dbglvl.NDEBUG=NDEBUG
challenger_nb_2040_wifipicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
challenger_nb_2040_wifipicoprobe.menu.usbstack.picosdk=Pico SDK
challenger_nb_2040_wifipicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
challenger_nb_2040_wifipicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
challenger_nb_2040_wifipicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
challenger_nb_2040_wifipicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -9878,7 +10299,7 @@ challenger_2040_sdrtc.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDE
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
challenger_2040_sdrtc.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
challenger_2040_sdrtc.menu.usbstack.picosdk.build.usbstack_flags=
challenger_2040_sdrtc.menu.usbstack.tinyusb=Adafruit TinyUSB
challenger_2040_sdrtc.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -10055,7 +10476,7 @@ challenger_2040_sdrtcpicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_
challenger_2040_sdrtcpicoprobe.menu.dbglvl.NDEBUG=NDEBUG
challenger_2040_sdrtcpicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
challenger_2040_sdrtcpicoprobe.menu.usbstack.picosdk=Pico SDK
challenger_2040_sdrtcpicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
challenger_2040_sdrtcpicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
challenger_2040_sdrtcpicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
challenger_2040_sdrtcpicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -10407,7 +10828,7 @@ ilabs_rpico32.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP20
ilabs_rpico32.menu.dbglvl.NDEBUG=NDEBUG
ilabs_rpico32.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
ilabs_rpico32.menu.usbstack.picosdk=Pico SDK
ilabs_rpico32.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
ilabs_rpico32.menu.usbstack.picosdk.build.usbstack_flags=
ilabs_rpico32.menu.usbstack.tinyusb=Adafruit TinyUSB
ilabs_rpico32.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -10584,7 +11005,7 @@ ilabs_rpico32picoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DD
ilabs_rpico32picoprobe.menu.dbglvl.NDEBUG=NDEBUG
ilabs_rpico32picoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
ilabs_rpico32picoprobe.menu.usbstack.picosdk=Pico SDK
ilabs_rpico32picoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
ilabs_rpico32picoprobe.menu.usbstack.picosdk.build.usbstack_flags=
ilabs_rpico32picoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
ilabs_rpico32picoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -10984,7 +11405,7 @@ melopero_shake_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDE
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
melopero_shake_rp2040.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
melopero_shake_rp2040.menu.usbstack.picosdk.build.usbstack_flags=
melopero_shake_rp2040.menu.usbstack.tinyusb=Adafruit TinyUSB
melopero_shake_rp2040.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -11209,7 +11630,7 @@ melopero_shake_rp2040picoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_
melopero_shake_rp2040picoprobe.menu.dbglvl.NDEBUG=NDEBUG
melopero_shake_rp2040picoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
melopero_shake_rp2040picoprobe.menu.usbstack.picosdk=Pico SDK
melopero_shake_rp2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
melopero_shake_rp2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags=
melopero_shake_rp2040picoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
melopero_shake_rp2040picoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -11609,7 +12030,7 @@ solderparty_rp2040_stamp.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -
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
solderparty_rp2040_stamp.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
solderparty_rp2040_stamp.menu.usbstack.picosdk.build.usbstack_flags=
solderparty_rp2040_stamp.menu.usbstack.tinyusb=Adafruit TinyUSB
solderparty_rp2040_stamp.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -11786,7 +12207,7 @@ solderparty_rp2040_stamppicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP20
solderparty_rp2040_stamppicoprobe.menu.dbglvl.NDEBUG=NDEBUG
solderparty_rp2040_stamppicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
solderparty_rp2040_stamppicoprobe.menu.usbstack.picosdk=Pico SDK
solderparty_rp2040_stamppicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
solderparty_rp2040_stamppicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
solderparty_rp2040_stamppicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
solderparty_rp2040_stamppicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -12186,7 +12607,7 @@ sparkfun_promicrorp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -D
sparkfun_promicrorp2040.menu.dbglvl.NDEBUG=NDEBUG
sparkfun_promicrorp2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
sparkfun_promicrorp2040.menu.usbstack.picosdk=Pico SDK
sparkfun_promicrorp2040.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
sparkfun_promicrorp2040.menu.usbstack.picosdk.build.usbstack_flags=
sparkfun_promicrorp2040.menu.usbstack.tinyusb=Adafruit TinyUSB
sparkfun_promicrorp2040.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -12411,7 +12832,7 @@ sparkfun_promicrorp2040picoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP204
sparkfun_promicrorp2040picoprobe.menu.dbglvl.NDEBUG=NDEBUG
sparkfun_promicrorp2040picoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
sparkfun_promicrorp2040picoprobe.menu.usbstack.picosdk=Pico SDK
sparkfun_promicrorp2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
sparkfun_promicrorp2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags=
sparkfun_promicrorp2040picoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
sparkfun_promicrorp2040picoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -12859,7 +13280,7 @@ sparkfun_thingplusrp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -
sparkfun_thingplusrp2040.menu.dbglvl.NDEBUG=NDEBUG
sparkfun_thingplusrp2040.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
sparkfun_thingplusrp2040.menu.usbstack.picosdk=Pico SDK
sparkfun_thingplusrp2040.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
sparkfun_thingplusrp2040.menu.usbstack.picosdk.build.usbstack_flags=
sparkfun_thingplusrp2040.menu.usbstack.tinyusb=Adafruit TinyUSB
sparkfun_thingplusrp2040.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -13084,7 +13505,7 @@ sparkfun_thingplusrp2040picoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP20
sparkfun_thingplusrp2040picoprobe.menu.dbglvl.NDEBUG=NDEBUG
sparkfun_thingplusrp2040picoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
sparkfun_thingplusrp2040picoprobe.menu.usbstack.picosdk=Pico SDK
sparkfun_thingplusrp2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
sparkfun_thingplusrp2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags=
sparkfun_thingplusrp2040picoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
sparkfun_thingplusrp2040picoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -13448,7 +13869,7 @@ upesy_rp2040_devkit.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBU
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
upesy_rp2040_devkit.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
upesy_rp2040_devkit.menu.usbstack.picosdk.build.usbstack_flags=
upesy_rp2040_devkit.menu.usbstack.tinyusb=Adafruit TinyUSB
upesy_rp2040_devkit.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -13589,7 +14010,7 @@ upesy_rp2040_devkitpicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WI
upesy_rp2040_devkitpicoprobe.menu.dbglvl.NDEBUG=NDEBUG
upesy_rp2040_devkitpicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
upesy_rp2040_devkitpicoprobe.menu.usbstack.picosdk=Pico SDK
upesy_rp2040_devkitpicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
upesy_rp2040_devkitpicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
upesy_rp2040_devkitpicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
upesy_rp2040_devkitpicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -13869,7 +14290,7 @@ seeed_xiao_rp2040.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_
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
seeed_xiao_rp2040.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
seeed_xiao_rp2040.menu.usbstack.picosdk.build.usbstack_flags=
seeed_xiao_rp2040.menu.usbstack.tinyusb=Adafruit TinyUSB
seeed_xiao_rp2040.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -14010,7 +14431,7 @@ seeed_xiao_rp2040picoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE
seeed_xiao_rp2040picoprobe.menu.dbglvl.NDEBUG=NDEBUG
seeed_xiao_rp2040picoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
seeed_xiao_rp2040picoprobe.menu.usbstack.picosdk=Pico SDK
seeed_xiao_rp2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
seeed_xiao_rp2040picoprobe.menu.usbstack.picosdk.build.usbstack_flags=
seeed_xiao_rp2040picoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
seeed_xiao_rp2040picoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -14290,7 +14711,7 @@ wiznet_5100s_evb_pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDE
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
wiznet_5100s_evb_pico.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
wiznet_5100s_evb_pico.menu.usbstack.picosdk.build.usbstack_flags=
wiznet_5100s_evb_pico.menu.usbstack.tinyusb=Adafruit TinyUSB
wiznet_5100s_evb_pico.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -14431,7 +14852,7 @@ wiznet_5100s_evb_picopicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_
wiznet_5100s_evb_picopicoprobe.menu.dbglvl.NDEBUG=NDEBUG
wiznet_5100s_evb_picopicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
wiznet_5100s_evb_picopicoprobe.menu.usbstack.picosdk=Pico SDK
wiznet_5100s_evb_picopicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
wiznet_5100s_evb_picopicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
wiznet_5100s_evb_picopicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
wiznet_5100s_evb_picopicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -14711,7 +15132,7 @@ wiznet_wizfi360_evb_pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -
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
wiznet_wizfi360_evb_pico.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
wiznet_wizfi360_evb_pico.menu.usbstack.picosdk.build.usbstack_flags=
wiznet_wizfi360_evb_pico.menu.usbstack.tinyusb=Adafruit TinyUSB
wiznet_wizfi360_evb_pico.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -14852,7 +15273,7 @@ wiznet_wizfi360_evb_picopicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP20
wiznet_wizfi360_evb_picopicoprobe.menu.dbglvl.NDEBUG=NDEBUG
wiznet_wizfi360_evb_picopicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
wiznet_wizfi360_evb_picopicoprobe.menu.usbstack.picosdk=Pico SDK
wiznet_wizfi360_evb_picopicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
wiznet_wizfi360_evb_picopicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
wiznet_wizfi360_evb_picopicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
wiznet_wizfi360_evb_picopicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -15132,7 +15553,7 @@ wiznet_5500_evb_pico.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEB
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
wiznet_5500_evb_pico.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
wiznet_5500_evb_pico.menu.usbstack.picosdk.build.usbstack_flags=
wiznet_5500_evb_pico.menu.usbstack.tinyusb=Adafruit TinyUSB
wiznet_5500_evb_pico.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -15273,7 +15694,7 @@ wiznet_5500_evb_picopicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_W
wiznet_5500_evb_picopicoprobe.menu.dbglvl.NDEBUG=NDEBUG
wiznet_5500_evb_picopicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
wiznet_5500_evb_picopicoprobe.menu.usbstack.picosdk=Pico SDK
wiznet_5500_evb_picopicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
wiznet_5500_evb_picopicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
wiznet_5500_evb_picopicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
wiznet_5500_evb_picopicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
@ -15565,7 +15986,7 @@ generic.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_RP2040_SPI
generic.menu.dbglvl.NDEBUG=NDEBUG
generic.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
generic.menu.usbstack.picosdk=Pico SDK
generic.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
generic.menu.usbstack.picosdk.build.usbstack_flags=
generic.menu.usbstack.tinyusb=Adafruit TinyUSB
generic.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
generic.menu.boot2.boot2_generic_03h_2_padded_checksum=Generic SPI /2
@ -15734,7 +16155,7 @@ genericpicoprobe.menu.dbglvl.All.build.debug_level=-DDEBUG_RP2040_WIRE -DDEBUG_R
genericpicoprobe.menu.dbglvl.NDEBUG=NDEBUG
genericpicoprobe.menu.dbglvl.NDEBUG.build.debug_level=-DNDEBUG
genericpicoprobe.menu.usbstack.picosdk=Pico SDK
genericpicoprobe.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"
genericpicoprobe.menu.usbstack.picosdk.build.usbstack_flags=
genericpicoprobe.menu.usbstack.tinyusb=Adafruit TinyUSB
genericpicoprobe.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
genericpicoprobe.menu.boot2.boot2_generic_03h_2_padded_checksum=Generic SPI /2

View file

@ -18,8 +18,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef Arduino_h
#define Arduino_h
#pragma once
#include <stdint.h>
#include <stdlib.h>
@ -112,5 +111,3 @@ constexpr uint32_t __bitset(const int (&a)[N], size_t i = 0U) {
return i < N ? (1L << a[i]) | __bitset(a, i + 1) : 0;
}
#endif
#endif // Arduino_h

View file

@ -18,8 +18,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FS_H
#define FS_H
#pragma once
#include <memory>
#include <Arduino.h>
@ -264,5 +263,3 @@ using fs::SeekEnd;
using fs::FSInfo;
using fs::FSConfig;
#endif //FS_NO_GLOBALS
#endif //FS_H

View file

@ -17,8 +17,8 @@
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FSIMPL_H
#define FSIMPL_H
#pragma once
#include <stddef.h>
#include <stdint.h>
@ -149,5 +149,3 @@ protected:
};
} // namespace fs
#endif //FSIMPL_H

41
cores/rp2040/LWIPMutex.h Normal file
View file

@ -0,0 +1,41 @@
/*
WiFiMutex.h - Ensure the timer-driven sys_check_timeouts doesn't
get executed while we're in the user-level TCP stack.
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
Implements the API defined by the Arduino WiFiNINA library,
copyright (c) 2018 Arduino SA. All rights reserved.
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
extern "C" volatile bool __inLWIP;
class LWIPMutex {
public:
LWIPMutex() {
__inLWIP = true;
_ref++;
}
~LWIPMutex() {
if (0 == --_ref) {
__inLWIP = false;
}
}
private:
static int _ref;
};

View file

@ -40,7 +40,7 @@ mutex_t __usb_mutex;
// USB processing will be a periodic timer task
#define USB_TASK_INTERVAL 1000
#define USB_TASK_IRQ 31
static int __usb_task_irq;
// USB VID/PID (note that PID can change depending on the add'l interfaces)
#define USBD_VID (0x2E8A) // Raspberry Pi
@ -284,7 +284,7 @@ static void usb_irq() {
}
static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
irq_set_pending(USB_TASK_IRQ);
irq_set_pending(__usb_task_irq);
return USB_TASK_INTERVAL;
}
@ -303,8 +303,9 @@ void __USBStart() {
tusb_init();
irq_set_exclusive_handler(USB_TASK_IRQ, usb_irq);
irq_set_enabled(USB_TASK_IRQ, true);
__usb_task_irq = user_irq_claim_unused(true);
irq_set_exclusive_handler(__usb_task_irq, usb_irq);
irq_set_enabled(__usb_task_irq, true);
add_alarm_in_us(USB_TASK_INTERVAL, timer_task, NULL, true);
}

View file

@ -18,8 +18,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __SERIALUSB_H__
#define __SERIALUSB_H__
#pragma once
#include <Arduino.h>
#include "api/HardwareSerial.h"
@ -54,5 +53,3 @@ extern SerialUSB Serial;
namespace arduino {
extern void serialEventRun(void) __attribute__((weak));
};
#endif

View file

@ -1,55 +1,75 @@
/*
IPAddress.cpp - Base class that provides IPAddress
Copyright (c) 2011 Adrian McEwen. All right reserved.
IPAddress.cpp - Base class that provides IPAddress
Copyright (c) 2011 Adrian McEwen. All right reserved.
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 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.
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
*/
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
*/
#include "IPAddress.h"
#include "Print.h"
#include <Arduino.h>
#include <IPAddress.h>
#include <Print.h>
using namespace arduino;
IPAddress::IPAddress()
IPAddress::IPAddress(const IPAddress& from)
{
_address.dword = 0;
ip_addr_copy(_ip, from._ip);
}
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
{
_address.bytes[0] = first_octet;
_address.bytes[1] = second_octet;
_address.bytes[2] = third_octet;
_address.bytes[3] = fourth_octet;
IPAddress::IPAddress() {
_ip = *IP_ANY_TYPE; // lwIP's v4-or-v6 generic address
}
IPAddress::IPAddress(uint32_t address)
{
_address.dword = address;
bool IPAddress::isSet () const {
return !ip_addr_isany(&_ip) && ((*this) != IPADDR_NONE);
}
IPAddress::IPAddress(const uint8_t *address)
{
memcpy(_address.bytes, address, sizeof(_address.bytes));
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) {
setV4();
(*this)[0] = first_octet;
(*this)[1] = second_octet;
(*this)[2] = third_octet;
(*this)[3] = fourth_octet;
}
bool IPAddress::fromString(const char *address)
{
// TODO: add support for "a", "a.b", "a.b.c" formats
void IPAddress::ctor32(uint32_t address) {
setV4();
v4() = address;
}
int16_t acc = -1; // Accumulator
IPAddress::IPAddress(const uint8_t *address) {
setV4();
(*this)[0] = address[0];
(*this)[1] = address[1];
(*this)[2] = address[2];
(*this)[3] = address[3];
}
bool IPAddress::fromString(const char *address) {
if (!fromString4(address)) {
#if LWIP_IPV6
return fromString6(address);
#else
return false;
#endif
}
return true;
}
bool IPAddress::fromString4(const char *address) {
// TODO: (IPv4) add support for "a", "a.b", "a.b.c" formats
uint16_t acc = 0; // Accumulator
uint8_t dots = 0;
while (*address)
@ -57,7 +77,7 @@ bool IPAddress::fromString(const char *address)
char c = *address++;
if (c >= '0' && c <= '9')
{
acc = (acc < 0) ? (c - '0') : acc * 10 + (c - '0');
acc = acc * 10 + (c - '0');
if (acc > 255) {
// Value out of [0..255] range
return false;
@ -69,12 +89,8 @@ bool IPAddress::fromString(const char *address)
// Too much dots (there must be 3 dots)
return false;
}
if (acc < 0) {
/* No value between dots, e.g. '1..' */
return false;
}
_address.bytes[dots++] = acc;
acc = -1;
(*this)[dots++] = acc;
acc = 0;
}
else
{
@ -87,41 +103,144 @@ bool IPAddress::fromString(const char *address)
// Too few dots (there must be 3 dots)
return false;
}
if (acc < 0) {
/* No value between dots, e.g. '1..' */
return false;
}
_address.bytes[3] = acc;
(*this)[3] = acc;
setV4();
return true;
}
IPAddress& IPAddress::operator=(const uint8_t *address)
{
memcpy(_address.bytes, address, sizeof(_address.bytes));
IPAddress& IPAddress::operator=(const uint8_t *address) {
setV4();
v4() = *reinterpret_cast<const uint32_t*>(address);
return *this;
}
IPAddress& IPAddress::operator=(uint32_t address)
{
_address.dword = address;
IPAddress& IPAddress::operator=(uint32_t address) {
setV4();
v4() = address;
return *this;
}
bool IPAddress::operator==(const uint8_t* addr) const
{
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
bool IPAddress::operator==(const uint8_t* addr) const {
return isV4() && v4() == *reinterpret_cast<const uint32_t*>(addr);
}
size_t IPAddress::printTo(Print& p) const
size_t IPAddress::printTo(Print& p) const {
String s = toString();
return p.print(s);
}
String IPAddress::toString() const
{
size_t n = 0;
for (int i =0; i < 3; i++)
{
n += p.print(_address.bytes[i], DEC);
n += p.print('.');
String s;
if (!isSet())
return "(IP unset)";
#if LWIP_IPV6
if (isV6()) {
int count0 = 0;
for (int i = 0; i < 8; i++) {
uint16_t bit = PP_NTOHS(raw6()[i]);
if (bit || count0 < 0) {
char buff[64];
snprintf(buff, 64, "%x", bit);
buff[63] = 0;
s += buff;
if (count0 > 0)
// no more hiding 0
count0 = -8;
} else
count0++;
if ((i != 7 && count0 < 2) || count0 == 7)
s += ':';
}
return s;
}
n += p.print(_address.bytes[3], DEC);
return n;
#endif
for(int i = 0; i < 4; i++) {
char buff[16];
snprintf(buff, 16, "%d", (*this)[i]);
buff[15] = 0;
s += buff;
if (i != 3)
s += '.';
}
return s;
}
const IPAddress arduino::INADDR_NONE(0,0,0,0);
bool IPAddress::isValid(const String& arg) {
return IPAddress().fromString(arg);
}
bool IPAddress::isValid(const char* arg) {
return IPAddress().fromString(arg);
}
const IPAddress INADDR_ANY; // generic "0.0.0.0" for IPv4 & IPv6
const IPAddress INADDR_NONE(255,255,255,255);
void IPAddress::clear() {
(*this) = INADDR_ANY;
}
/**************************************/
#if LWIP_IPV6
bool IPAddress::fromString6(const char *address) {
// TODO: test test test
uint32_t acc = 0; // Accumulator
int dots = 0, doubledots = -1;
while (*address)
{
char c = tolower(*address++);
if (isalnum(c)) {
if (c >= 'a')
c -= 'a' - '0' - 10;
acc = acc * 16 + (c - '0');
if (acc > 0xffff)
// Value out of range
return false;
}
else if (c == ':') {
if (*address == ':') {
if (doubledots >= 0)
// :: allowed once
return false;
// remember location
doubledots = dots + !!acc;
address++;
}
if (dots == 7)
// too many separators
return false;
raw6()[dots++] = PP_HTONS(acc);
acc = 0;
}
else
// Invalid char
return false;
}
if (doubledots == -1 && dots != 7)
// Too few separators
return false;
raw6()[dots++] = PP_HTONS(acc);
if (doubledots != -1) {
for (int i = dots - doubledots - 1; i >= 0; i--)
raw6()[8 - dots + doubledots + i] = raw6()[doubledots + i];
for (int i = doubledots; i < 8 - dots + doubledots; i++)
raw6()[i] = 0;
}
setV6();
return true;
}
#endif

View file

@ -1,85 +1,218 @@
/*
IPAddress.h - Base class that provides IPAddress
Copyright (c) 2011 Adrian McEwen. All right reserved.
IPAddress.h - Base class that provides IPAddress
Copyright (c) 2011 Adrian McEwen. All right reserved.
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 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.
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
*/
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 <stdint.h>
#include "Printable.h"
#include "String.h"
#include <api/String.h>
#include <Printable.h>
// forward declartions of global name space friend classes
class EthernetClass;
class DhcpClass;
class DNSClient;
#include <lwip/init.h>
#include <lwip/ip_addr.h>
#include <lwip/ip4_addr.h>
namespace arduino {
#if !LWIP_IPV6
struct ip_addr: ipv4_addr { };
#endif // !LWIP_IPV6
// to display a netif id with printf:
#define NETIFID_STR "%c%c%u"
#define NETIFID_VAL(netif) \
((netif)? (netif)->name[0]: '-'), \
((netif)? (netif)->name[1]: '-'), \
((netif)? netif_get_index(netif): 42)
// A class to make it easier to handle and pass around IP addresses
// IPv6 update:
// IPAddress is now a decorator class for lwIP's ip_addr_t
// fully backward compatible with legacy IPv4-only Arduino's
// with unchanged footprint when IPv6 is disabled
class IPAddress : public Printable {
private:
union {
uint8_t bytes[4]; // IPv4 address
uint32_t dword;
} _address;
class IPAddress: public Printable {
private:
// Access the raw byte array containing the address. Because this returns a pointer
// to the internal structure rather than a copy of the address this function should only
// be used when you know that the usage of the returned uint8_t* will be transient and not
// stored.
uint8_t* raw_address() { return _address.bytes; };
ip_addr_t _ip;
public:
// Constructors
IPAddress();
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
IPAddress(uint32_t address);
IPAddress(const uint8_t *address);
// Access the raw byte array containing the address. Because this returns a pointer
// to the internal structure rather than a copy of the address this function should only
// be used when you know that the usage of the returned uint8_t* will be transient and not
// stored.
uint8_t* raw_address() {
return reinterpret_cast<uint8_t*>(&v4());
}
const uint8_t* raw_address() const {
return reinterpret_cast<const uint8_t*>(&v4());
}
bool fromString(const char *address);
bool fromString(const String &address) { return fromString(address.c_str()); }
void ctor32 (uint32_t);
// Overloaded cast operator to allow IPAddress objects to be used where a pointer
// to a four-byte uint8_t array is expected
operator uint32_t() const { return _address.dword; };
bool operator==(const IPAddress& addr) const { return _address.dword == addr._address.dword; };
bool operator!=(const IPAddress& addr) const { return _address.dword != addr._address.dword; };
bool operator==(const uint8_t* addr) const;
public:
// Constructors
IPAddress();
IPAddress(const IPAddress& from);
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
IPAddress(uint32_t address) { ctor32(address); }
// IPAddress(unsigned long address) { ctor32(address); }
IPAddress(int address) { ctor32(address); }
IPAddress(const uint8_t *address);
// Overloaded index operator to allow getting and setting individual octets of the address
uint8_t operator[](int index) const { return _address.bytes[index]; };
uint8_t& operator[](int index) { return _address.bytes[index]; };
bool fromString(const char *address);
bool fromString(const String &address) { return fromString(address.c_str()); }
// Overloaded copy operators to allow initialisation of IPAddress objects from other types
IPAddress& operator=(const uint8_t *address);
IPAddress& operator=(uint32_t address);
// Overloaded cast operator to allow IPAddress objects to be used where a pointer
// to a four-byte uint8_t array is expected
operator uint32_t() const { return isV4()? v4(): (uint32_t)0; }
operator uint32_t() { return isV4()? v4(): (uint32_t)0; }
virtual size_t printTo(Print& p) const;
bool isSet () const;
operator bool () const { return isSet(); } // <-
operator bool () { return isSet(); } // <- both are needed
// generic IPv4 wrapper to uint32-view like arduino loves to see it
const uint32_t& v4() const { return ip_2_ip4(&_ip)->addr; } // for raw_address(const)
uint32_t& v4() { return ip_2_ip4(&_ip)->addr; }
bool operator==(const IPAddress& addr) const {
return ip_addr_cmp(&_ip, &addr._ip);
}
bool operator!=(const IPAddress& addr) const {
return !ip_addr_cmp(&_ip, &addr._ip);
}
bool operator==(uint32_t addr) const {
return isV4() && v4() == addr;
}
// bool operator==(unsigned long addr) const {
// return isV4() && v4() == (uint32_t)addr;
// }
bool operator!=(uint32_t addr) const {
return !(isV4() && v4() == addr);
}
// bool operator!=(unsigned long addr) const {
// return isV4() && v4() != (uint32_t)addr;
// }
bool operator==(const uint8_t* addr) const;
int operator>>(int n) const {
return isV4()? v4() >> n: 0;
}
// Overloaded index operator to allow getting and setting individual octets of the address
uint8_t operator[](int index) const {
return isV4()? *(raw_address() + index): 0;
}
uint8_t& operator[](int index) {
setV4();
return *(raw_address() + index);
}
// Overloaded copy operators to allow initialisation of IPAddress objects from other types
IPAddress& operator=(const uint8_t *address);
IPAddress& operator=(uint32_t address);
IPAddress& operator=(const IPAddress&) = default;
virtual size_t printTo(Print& p) const;
String toString() const;
void clear();
/*
check if input string(arg) is a valid IPV4 address or not.
return true on valid.
return false on invalid.
*/
static bool isValid(const String& arg);
static bool isValid(const char* arg);
friend class WiFiClass;
friend class EthernetClass;
friend class UDP;
friend class Client;
friend class Server;
friend class DhcpClass;
friend class DNSClient;
/*
lwIP address compatibility
*/
//IPAddress(const ipv4_addr& fw_addr) { setV4(); v4() = fw_addr.addr; }
//IPAddress(const ipv4_addr* fw_addr) { setV4(); v4() = fw_addr->addr; }
//IPAddress& operator=(const ipv4_addr& fw_addr) { setV4(); v4() = fw_addr.addr; return *this; }
//IPAddress& operator=(const ipv4_addr* fw_addr) { setV4(); v4() = fw_addr->addr; return *this; }
operator ip_addr_t () const { return _ip; }
operator const ip_addr_t*() const { return &_ip; }
operator ip_addr_t*() { return &_ip; }
bool isV4() const { return IP_IS_V4_VAL(_ip); }
void setV4() { IP_SET_TYPE_VAL(_ip, IPADDR_TYPE_V4); }
bool isLocal () const { return ip_addr_islinklocal(&_ip); }
#if LWIP_IPV6
IPAddress(const ip_addr_t& lwip_addr) { ip_addr_copy(_ip, lwip_addr); }
IPAddress(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *lwip_addr); }
IPAddress& operator=(const ip_addr_t& lwip_addr) { ip_addr_copy(_ip, lwip_addr); return *this; }
IPAddress& operator=(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *lwip_addr); return *this; }
uint16_t* raw6()
{
setV6();
return reinterpret_cast<uint16_t*>(ip_2_ip6(&_ip));
}
const uint16_t* raw6() const
{
return isV6()? reinterpret_cast<const uint16_t*>(ip_2_ip6(&_ip)): nullptr;
}
// when not IPv6, ip_addr_t == ip4_addr_t so this one would be ambiguous
// required otherwise
operator const ip4_addr_t*() const { return isV4()? ip_2_ip4(&_ip): nullptr; }
bool isV6() const { return IP_IS_V6_VAL(_ip); }
void setV6() { IP_SET_TYPE_VAL(_ip, IPADDR_TYPE_V6); }
protected:
bool fromString6(const char *address);
#else
// allow portable code when IPv6 is not enabled
uint16_t* raw6() { return nullptr; }
const uint16_t* raw6() const { return nullptr; }
bool isV6() const { return false; }
void setV6() { }
#endif
protected:
bool fromString4(const char *address);
friend class UDP;
friend class Client;
friend class Server;
friend ::EthernetClass;
friend ::DhcpClass;
friend ::DNSClient;
};
extern const IPAddress INADDR_ANY;
extern const IPAddress INADDR_NONE;
}

View file

@ -22,6 +22,7 @@
#include "RP2040USB.h"
#include <pico/stdlib.h>
#include <pico/multicore.h>
#include "LWIPMutex.h"
#include <reent.h>
RP2040 rp2040;
@ -31,6 +32,8 @@ extern "C" {
mutex_t _pioMutex;
int LWIPMutex::_ref = 0;
extern void setup();
extern void loop();

View file

@ -0,0 +1,319 @@
/*
Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
SPDX-License-Identifier: BSD-3-Clause
*/
// Taken from the Pico-SDK v1.4.0 and hacked by EFP3 to allow overriding the LWIP setup
#include <stdio.h>
#include "pico/cyw43_arch.h"
#include "pico/mutex.h"
#include "pico/sem.h"
#include "hardware/gpio.h"
#include "hardware/irq.h"
#include "cyw43_stats.h"
#include <lwip/init.h>
#include "lwip/timeouts.h"
#ifndef CYW43_PIN_WL_HOST_WAKE
#define CYW43_PIN_WL_HOST_WAKE 24
#endif
#ifndef CYW43_PIN_WL_REG_ON
#define CYW43_PIN_WL_REG_ON 23
#endif
#ifndef CYW43_WL_GPIO_COUNT
#define CYW43_WL_GPIO_COUNT 3
#endif
#ifndef CYW43_WL_GPIO_LED_PIN
#define CYW43_WL_GPIO_LED_PIN 0
#endif
volatile bool __inLWIP = false;
// note same code
#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND
#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND && CYW43_LWIP && !NO_SYS
#error PICO_CYW43_ARCH_THREADSAFE_BACKGROUND requires lwIP NO_SYS=1
#endif
#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND && CYW43_LWIP && MEM_LIBC_MALLOC
#error MEM_LIBC_MALLOC is incompatible with PICO_CYW43_ARCH_THREADSAFE_BACKGROUND
#endif
// todo right now we are now always doing a cyw43_dispatch along with a lwip one when hopping cores in low_prio_irq_schedule_dispatch
#ifndef CYW43_SLEEP_CHECK_MS
#define CYW43_SLEEP_CHECK_MS 50 // How often to run lwip callback
#endif
static alarm_id_t periodic_alarm = -1;
static inline uint recursive_mutex_enter_count(recursive_mutex_t *mutex) {
return mutex->enter_count;
}
static inline lock_owner_id_t recursive_mutex_owner(recursive_mutex_t *mutex) {
return mutex->owner;
}
#define CYW43_GPIO_IRQ_HANDLER_PRIORITY 0x40
enum {
CYW43_DISPATCH_SLOT_CYW43 = 0,
CYW43_DISPATCH_SLOT_ADAPTER,
CYW43_DISPATCH_SLOT_ENUM_COUNT
};
#ifndef CYW43_DISPATCH_SLOT_COUNT
#define CYW43_DISPATCH_SLOT_COUNT CYW43_DISPATCH_SLOT_ENUM_COUNT
#endif
typedef void (*low_prio_irq_dispatch_t)(void);
static void low_prio_irq_schedule_dispatch(size_t slot, low_prio_irq_dispatch_t f);
static uint8_t cyw43_core_num;
#ifndef NDEBUG
static bool in_low_priority_irq;
#endif
static uint8_t low_priority_irq_num;
static bool low_priority_irq_missed;
static low_prio_irq_dispatch_t low_priority_irq_dispatch_slots[CYW43_DISPATCH_SLOT_COUNT];
static recursive_mutex_t cyw43_mutex;
semaphore_t cyw43_irq_sem;
// Called in low priority pendsv interrupt only to do lwip processing and check cyw43 sleep
static void periodic_worker(void) {
#if CYW43_USE_STATS
static uint32_t counter;
if (counter++ % (30000 / LWIP_SYS_CHECK_MS) == 0) {
cyw43_dump_stats();
}
#endif
CYW43_STAT_INC(LWIP_RUN_COUNT);
//#if CYW43_LWIP
if (!__inLWIP) {
sys_check_timeouts();
}
//#endif
if (cyw43_poll) {
if (cyw43_sleep > 0) {
if (--cyw43_sleep == 0) {
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
}
}
}
}
// Regular callback to get lwip to check for timeouts
static int64_t periodic_alarm_handler(__unused alarm_id_t id, __unused void *user_data) {
// Do lwip processing in low priority pendsv interrupt
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_ADAPTER, periodic_worker);
return CYW43_SLEEP_CHECK_MS * 1000;
}
void cyw43_await_background_or_timeout_us(uint32_t timeout_us) {
// if we are called from within an IRQ, then don't wait (we are only ever called in a polling loop)
if (!__get_current_exception()) {
sem_acquire_timeout_us(&cyw43_irq_sem, timeout_us);
}
}
// GPIO interrupt handler to tell us there's cyw43 has work to do
static void gpio_irq_handler(void) {
uint32_t events = gpio_get_irq_event_mask(CYW43_PIN_WL_HOST_WAKE);
if (events & GPIO_IRQ_LEVEL_HIGH) {
// As we use a high level interrupt, it will go off forever until it's serviced
// So disable the interrupt until this is done. It's re-enabled again by CYW43_POST_POLL_HOOK
// which is called at the end of cyw43_poll_func
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
// also clear the force bit which we use to progratically cause this handler to fire (on the right core)
io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ?
&iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
hw_clear_bits(&irq_ctrl_base->intf[CYW43_PIN_WL_HOST_WAKE / 8], GPIO_IRQ_LEVEL_HIGH << (4 * (CYW43_PIN_WL_HOST_WAKE & 7)));
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
CYW43_STAT_INC(IRQ_COUNT);
}
}
// Low priority interrupt handler to perform background processing
static void low_priority_irq_handler(void) {
assert(cyw43_core_num == get_core_num());
if (recursive_mutex_try_enter(&cyw43_mutex, NULL)) {
if (recursive_mutex_enter_count(&cyw43_mutex) != 1) {
low_priority_irq_missed = true;
CYW43_STAT_INC(PENDSV_DISABLED_COUNT);
} else {
CYW43_STAT_INC(PENDSV_RUN_COUNT);
#ifndef NDEBUG
in_low_priority_irq = true;
#endif
for (size_t i = 0; i < count_of(low_priority_irq_dispatch_slots); i++) {
if (low_priority_irq_dispatch_slots[i] != NULL) {
low_prio_irq_dispatch_t f = low_priority_irq_dispatch_slots[i];
low_priority_irq_dispatch_slots[i] = NULL;
f();
}
}
#ifndef NDEBUG
in_low_priority_irq = false;
#endif
}
recursive_mutex_exit(&cyw43_mutex);
} else {
CYW43_STAT_INC(PENDSV_DISABLED_COUNT);
low_priority_irq_missed = true;
}
sem_release(&cyw43_irq_sem);
}
static bool low_prio_irq_init(uint8_t priority) {
assert(get_core_num() == cyw43_core_num);
int irq = user_irq_claim_unused(false);
if (irq < 0) {
return false;
}
low_priority_irq_num = (uint8_t) irq;
irq_set_exclusive_handler(low_priority_irq_num, low_priority_irq_handler);
irq_set_enabled(low_priority_irq_num, true);
irq_set_priority(low_priority_irq_num, priority);
return true;
}
static void low_prio_irq_deinit(void) {
if (low_priority_irq_num > 0) {
irq_set_enabled(low_priority_irq_num, false);
irq_remove_handler(low_priority_irq_num, low_priority_irq_handler);
user_irq_unclaim(low_priority_irq_num);
low_priority_irq_num = 0;
}
}
int cyw43_arch_init(void) {
cyw43_core_num = get_core_num();
recursive_mutex_init(&cyw43_mutex);
cyw43_init(&cyw43_state);
sem_init(&cyw43_irq_sem, 0, 1);
// Start regular lwip callback to handle timeouts
periodic_alarm = add_alarm_in_us(CYW43_SLEEP_CHECK_MS * 1000, periodic_alarm_handler, NULL, true);
if (periodic_alarm < 0) {
return PICO_ERROR_GENERIC;
}
gpio_add_raw_irq_handler_with_order_priority(IO_IRQ_BANK0, gpio_irq_handler, CYW43_GPIO_IRQ_HANDLER_PRIORITY);
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
irq_set_enabled(IO_IRQ_BANK0, true);
lwip_init();
// start low priority handler (no background work is done before this)
bool ok = low_prio_irq_init(PICO_LOWEST_IRQ_PRIORITY);
if (!ok) {
cyw43_arch_deinit();
return PICO_ERROR_GENERIC;
}
return PICO_OK;
}
void cyw43_arch_deinit(void) {
if (periodic_alarm >= 0) {
cancel_alarm(periodic_alarm);
periodic_alarm = -1;
}
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
gpio_remove_raw_irq_handler(IO_IRQ_BANK0, gpio_irq_handler);
low_prio_irq_deinit();
}
void cyw43_post_poll_hook(void) {
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
}
// This is called in the gpio and low_prio_irq interrupts and on either core
static void low_prio_irq_schedule_dispatch(size_t slot, low_prio_irq_dispatch_t f) {
assert(slot < count_of(low_priority_irq_dispatch_slots));
low_priority_irq_dispatch_slots[slot] = f;
if (cyw43_core_num == get_core_num()) {
//on same core, can dispatch directly
irq_set_pending(low_priority_irq_num);
} else {
// on wrong core, so force via GPIO IRQ which itself calls this method for the CYW43 slot.
// since the CYW43 slot always uses the same function, this is fine with the addition of an
// extra (but harmless) CYW43 slot call when another SLOT is invoked.
// We could do better, but would have to track why the IRQ was called.
io_irq_ctrl_hw_t *irq_ctrl_base = cyw43_core_num ?
&iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
hw_set_bits(&irq_ctrl_base->intf[CYW43_PIN_WL_HOST_WAKE / 8], GPIO_IRQ_LEVEL_HIGH << (4 * (CYW43_PIN_WL_HOST_WAKE & 7)));
}
}
void cyw43_schedule_internal_poll_dispatch(void (*func)(void)) {
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, func);
}
// Prevent background processing in pensv and access by the other core
// These methods are called in pensv context and on either core
// They can be called recursively
void cyw43_thread_enter(void) {
// Lock the other core and stop low_prio_irq running
recursive_mutex_enter_blocking(&cyw43_mutex);
}
#ifndef NDEBUG
void cyw43_thread_lock_check(void) {
// Lock the other core and stop low_prio_irq running
if (recursive_mutex_enter_count(&cyw43_mutex) < 1 || recursive_mutex_owner(&cyw43_mutex) != lock_get_caller_owner_id()) {
panic("cyw43_thread_lock_check failed");
}
}
#endif
// Re-enable background processing
void cyw43_thread_exit(void) {
// Run low_prio_irq if needed
if (1 == recursive_mutex_enter_count(&cyw43_mutex)) {
// note the outer release of the mutex is not via cyw43_exit in the low_priority_irq case (it is a direct mutex exit)
assert(!in_low_priority_irq);
// if (low_priority_irq_missed) {
// low_priority_irq_missed = false;
if (low_priority_irq_dispatch_slots[CYW43_DISPATCH_SLOT_CYW43]) {
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
}
// }
}
recursive_mutex_exit(&cyw43_mutex);
}
static void cyw43_delay_until(absolute_time_t until) {
// sleep can be called in IRQs, so there's not much we can do there
if (__get_current_exception()) {
busy_wait_until(until);
} else {
sleep_until(until);
}
}
void cyw43_delay_ms(uint32_t ms) {
cyw43_delay_until(make_timeout_time_ms(ms));
}
void cyw43_delay_us(uint32_t us) {
cyw43_delay_until(make_timeout_time_us(us));
}
void cyw43_arch_poll() {
// should not be necessary
// if (cyw43_poll) {
// low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
// }
}
#endif

View file

@ -19,8 +19,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef STDLIB_NONISO_H
#define STDLIB_NONISO_H
#pragma once
#ifdef __cplusplus
extern "C" {
@ -54,6 +53,3 @@ const char* strrstr(const char*__restrict p_pcString,
#ifdef __cplusplus
} // extern "C"
#endif
#endif

View file

@ -23,7 +23,8 @@
static PinMode _pm[30];
extern "C" void pinMode(pin_size_t ulPin, PinMode ulMode) {
extern "C" void pinMode(pin_size_t ulPin, PinMode ulMode) __attribute__((weak, alias("__pinMode")));
extern "C" void __pinMode(pin_size_t ulPin, PinMode ulMode) {
switch (ulMode) {
case INPUT:
gpio_init(ulPin);
@ -76,7 +77,8 @@ extern "C" void pinMode(pin_size_t ulPin, PinMode ulMode) {
_pm[ulPin] = ulMode;
}
extern "C" void digitalWrite(pin_size_t ulPin, PinStatus ulVal) {
extern "C" void digitalWrite(pin_size_t ulPin, PinStatus ulVal) __attribute__((weak, alias("__digitalWrite")));
extern "C" void __digitalWrite(pin_size_t ulPin, PinStatus ulVal) {
if (ulPin > 29) {
DEBUGCORE("ERROR: Illegal pin in pinMode (%d)\n", ulPin);
return;
@ -99,7 +101,8 @@ extern "C" void digitalWrite(pin_size_t ulPin, PinStatus ulVal) {
}
}
extern "C" PinStatus digitalRead(pin_size_t ulPin) {
extern "C" PinStatus digitalRead(pin_size_t ulPin) __attribute__((weak, alias("__digitalRead")));
extern "C" PinStatus __digitalRead(pin_size_t ulPin) {
if (ulPin > 29) {
DEBUGCORE("ERROR: Illegal pin in digitalRead (%d)\n", ulPin);
return LOW;

View file

@ -7,7 +7,7 @@ Arduino-Pico. Arduino-Pico is a community port of the RP2040
to make it easier and more fun to use and program the Raspberry Pi
Pico / RP2040 based boards.
This Arduino core uses a custom toolset with GCC 10.2 and Newlib 4.0.0
This Arduino core uses a custom toolset with GCC 10.3 and Newlib 4.0.0
and doesn't require any system-installed prerequisites.
For the latest version, always check https://github.com/earlephilhower/arduino-pico
@ -39,6 +39,8 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
FreeRTOS SMP (multicore) <freertos>
WiFi (Raspberry Pi Pico-W Support) <wifi>
Ported/Optimized Libraries <libraries>
Using Pico-SDK <sdk>

47
docs/wifi.rst Normal file
View file

@ -0,0 +1,47 @@
WiFi (Raspberry Pi Pico W) Support
==================================
WiFi is supported on the Raspberry Pi Pico W by selecting the "Raspbery Pi Pico W" board in the Boards Manager. It is generally compatible with the `Arduino WiFi library <https://www.arduino.cc/en/Reference/WiFi>`__ and the `ESP8266 Arduino WiFi library <https://github.com/esp8266/Arduino>`__.
Enable WiFi support by selecting the `Raspberry Pi Pico W` board in the IDE and adding ``#include <WiFi.h>`` in your sketch.
Supported Features
------------------
* WiFi connection (Open, WPA/WPA2)
* Static IP or dynamic DHCP supported
* Station Mode (STA, connects to an existing network)
* Access Point Mode (AP, creates its own wireless network) with 4 clients
* WiFi Scanning and Reporting
* See the ``ScanNetworks.ino`` example to better understand the process.
* `WiFiClient (TCP/IP client) <wificlient.rst>`__
* See the ``WiFiClient.ino`` example which connects the Pico W to a remote internet service and retrieves some data
* `WiFiServer (TCP/IP server) <wifiserver.rst>`__
* See the ``WiFiServer.ino`` example which implements a frientdy TCP/IP server
* `WiFiUDP (UDP packet input/output) <wifiudp.rst>`__
* See the ``UDP.ino`` example for a simple send/receive UDP application
In the near future TLS (SSL/https) encryption is planned, but is not yet implemented.
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 > 220KB.
* There is a binary firmware blob for the WiFi chip (CYW43-series) which the Pico W uses. It's 220KB of code that needs to be included in any Pico W sketch, even one that simply flashes the onboard LED. There are hopes to reduce this via compression (see `this issue <https://github.com/raspberrypi/pico-sdk/issues/909>`__ )
* Adding WiFi increases RAM usage by ~40KB.
* 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
* Extensible Authentication Protocol (EAP) is not supported
* Combined STA/AP mode is not supported
* Certain WiFi status values (RSSI, BSSID, etc.) are not available.
* Multicore is supported, but only one core may run ``WiFi`` code.
* FreeRTOS is not yet supported due to the requirement for a very different LWIP implementation. PRs always appreciated!
The WiFi library borrows much work from the `ESP8266 Arduino Core <https://github.com/esp8266/Arduino>`__ , especially the ``WiFiClient`` and ``WiFiServer`` classes.
Special Thanks
--------------
Special thanks to:
* @todbot for donating one of his Pico W boards to the effort
* @d-a-v for much patient explanation about LWIP internals
* The whole ESP8266 Arduino team for their network classes

110
docs/wificlient.rst Normal file
View file

@ -0,0 +1,110 @@
:orphan:
Client Class
------------
Methods documented for `Client <https://www.arduino.cc/en/Reference/WiFiClientConstructor>`__ in `Arduino <https://github.com/arduino/Arduino>`__
1. `WiFiClient() <https://www.arduino.cc/en/Reference/WiFiClient>`__
2. `connected() <https://www.arduino.cc/en/Reference/WiFiClientConnected>`__
3. `connect() <https://www.arduino.cc/en/Reference/WiFiClientConnect>`__
4. `write() <https://www.arduino.cc/en/Reference/WiFiClientWrite>`__
5. `print() <https://www.arduino.cc/en/Reference/WiFiClientPrint>`__
6. `println() <https://www.arduino.cc/en/Reference/WiFiClientPrintln>`__
7. `available() <https://www.arduino.cc/en/Reference/WiFiClientAvailable>`__
8. `read() <https://www.arduino.cc/en/Reference/WiFiClientRead>`__
9. `flush() <https://www.arduino.cc/en/Reference/WiFiClientFlush>`__
10. `stop() <https://www.arduino.cc/en/Reference/WiFIClientStop>`__
Methods and properties described further down are specific to ESP8266. They are not covered in `Arduino WiFi library <https://www.arduino.cc/en/Reference/WiFi>`__ documentation. Before they are fully documented please refer to information below.
flush and stop
~~~~~~~~~~~~~~
``flush(timeoutMs)`` and ``stop(timeoutMs)`` both have now an optional argument: ``timeout`` in millisecond, and both return a boolean.
Default input value 0 means that effective value is left at the discretion of the implementer.
``flush()`` returning ``true`` indicates that output data have effectively been sent, and ``false`` that a timeout has occurred.
``stop()`` returns ``false`` in case of an issue when closing the client (for instance a timed-out ``flush``). Depending on implementation, its parameter can be passed to ``flush()``.
setNoDelay
~~~~~~~~~~
.. code:: cpp
setNoDelay(nodelay)
With ``nodelay`` set to ``true``, this function will to disable `Nagle algorithm <https://en.wikipedia.org/wiki/Nagle%27s_algorithm>`__.
This algorithm is intended to reduce TCP/IP traffic of small packets sent over the network by combining a number of small outgoing messages, and sending them all at once. The downside of such approach is effectively delaying individual messages until a big enough packet is assembled.
*Example:*
.. code:: cpp
client.setNoDelay(true);
getNoDelay
~~~~~~~~~~
Returns whether NoDelay is enabled or not for the current connection.
setSync
~~~~~~~
This is an experimental API that will set the client in synchronized mode.
In this mode, every ``write()`` is flushed. It means that after a call to
``write()``, data are ensured to be received where they went sent to (that is
``flush`` semantic).
When set to ``true`` in ``WiFiClient`` implementation,
- It slows down transfers, and implicitly disable the Nagle algorithm.
- It also allows to avoid a temporary copy of data that otherwise consumes
at most ``TCP_SND_BUF`` = (2 * ``MSS``) bytes per connection,
getSync
~~~~~~~
Returns whether Sync is enabled or not for the current connection.
setDefaultNoDelay and setDefaultSync
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
These set the default value for both ``setSync`` and ``setNoDelay`` for
every future instance of ``WiFiClient`` (including those coming from
``WiFiServer.available()`` by default).
Default values are false for both ``NoDelay`` and ``Sync``.
This means that Nagle is enabled by default *for all new connections*.
getDefaultNoDelay and getDefaultSync
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Return the values to be used as default for NoDelay and Sync for all future connections.
Other Function Calls
~~~~~~~~~~~~~~~~~~~~
.. code:: cpp
uint8_t status ()
virtual size_t write (const uint8_t *buf, size_t size)
size_t write_P (PGM_P buf, size_t size)
size_t write (Stream &stream)
size_t write (Stream &stream, size_t unitSize) __attribute__((deprecated))
virtual int read (uint8_t *buf, size_t size)
virtual int peek ()
virtual size_t peekBytes (uint8_t *buffer, size_t length)
size_t peekBytes (char *buffer, size_t length)
virtual operator bool ()
IPAddress remoteIP ()
uint16_t remotePort ()
IPAddress localIP ()
uint16_t localPort ()
Documentation for the above functions is not yet available.

75
docs/wifiserver.rst Normal file
View file

@ -0,0 +1,75 @@
:orphan:
Server Class
------------
Methods documented for the `Server Class <https://www.arduino.cc/en/Reference/WiFiServerConstructor>`__ in `Arduino <https://github.com/arduino/Arduino>`__
1. `WiFiServer() <https://www.arduino.cc/en/Reference/WiFiServer>`__
2. `begin() <https://www.arduino.cc/en/Reference/WiFiServerBegin>`__
3. `available() <https://www.arduino.cc/en/Reference/WiFiServerAvailable>`__
4. `write() <https://www.arduino.cc/en/Reference/WiFiServerWrite>`__
5. `print() <https://www.arduino.cc/en/Reference/WiFiServerPrint>`__
6. `println() <https://www.arduino.cc/en/Reference/WiFiServerPrintln>`__
In ESP8266WiFi library the ``ArduinoWiFiServer`` class implements ``available`` and the write-to-all-clients functionality as described in the Arduino WiFi library reference. The PageServer example shows how ``available`` and the write-to-all-clients works.
For most use cases the basic WiFiServer class of the ESP8266WiFi library is suitable.
Methods and properties described further down are specific to ESP8266. They are not covered in `Arduino WiFi library <https://www.arduino.cc/en/Reference/WiFi>`__ documentation. Before they are fully documented please refer to information below.
accept
~~~~~~
Method ``accept()`` returns a waiting client connection. `accept() is documented <https://www.arduino.cc/en/Reference/EthernetServerAccept>`__ for the Arduino Ethernet library.
available
~~~~~~~~~
see ``accept``
``available`` in the ESP8266WiFi library's WiFiServer class doesn't work as documented for the Arduino WiFi library. It works the same way as ``accept``.
write (write to all clients) not supported
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Please note that the ``write`` method on the ``WiFiServer`` object is not implemented and returns failure always. Use the returned
``WiFiClient`` object from the ``WiFiServer::accept()`` method to communicate with individual clients. If you need to send
the exact same packets to a series of clients, your application must maintain a list of connected clients and iterate over them manually.
setNoDelay
~~~~~~~~~~
.. code:: cpp
setNoDelay(nodelay)
With ``nodelay`` set to ``true``, this function will to disable `Nagle algorithm <https://en.wikipedia.org/wiki/Nagle%27s_algorithm>`__.
This algorithm is intended to reduce TCP/IP traffic of small packets sent over the network by combining a number of small outgoing messages, and sending them all at once. The downside of such approach is effectively delaying individual messages until a big enough packet is assembled.
*Example:*
.. code:: cpp
server.begin();
server.setNoDelay(true);
By default, ``nodelay`` value will depends on global ``WiFiClient::getDefaultNoDelay()`` (currently false by default).
However, a call to ``wiFiServer.setNoDelay()`` will override ``NoDelay`` for all new ``WiFiClient`` provided by the calling instance (``wiFiServer``).
Other Function Calls
~~~~~~~~~~~~~~~~~~~~
.. code:: cpp
bool hasClient ()
size_t hasClientData ()
bool hasMaxPendingClients ()
bool getNoDelay ()
virtual size_t write (const uint8_t *buf, size_t size)
uint8_t status ()
void close ()
void stop ()
Documentation for the above functions is not yet prepared.

19
docs/wifiudp.rst Normal file
View file

@ -0,0 +1,19 @@
:orphan:
UDP Class
---------
Methods documented for `WiFiUDP Class <https://www.arduino.cc/en/Reference/WiFiUDPConstructor>`__ in `Arduino <https://github.com/arduino/Arduino>`__
1. `begin() <https://www.arduino.cc/en/Reference/WiFiUDPBegin>`__
2. `available() <https://www.arduino.cc/en/Reference/WiFiUDPAvailable>`__
3. `beginPacket() <https://www.arduino.cc/en/Reference/WiFiUDPBeginPacket>`__
4. `endPacket() <https://www.arduino.cc/en/Reference/WiFiUDPEndPacket>`__
5. `write() <https://www.arduino.cc/en/Reference/WiFiUDPWrite>`__
6. `parsePacket() <https://www.arduino.cc/en/Reference/WiFiUDPParsePacket>`__
7. `peek() <https://www.arduino.cc/en/Reference/WiFiUDPPeek>`__
8. `read() <https://www.arduino.cc/en/Reference/WiFiUDPRead>`__
9. `flush() <https://www.arduino.cc/en/Reference/WiFiUDPFlush>`__
10. `stop() <https://www.arduino.cc/en/Reference/WiFIUDPStop>`__
11. `remoteIP() <https://www.arduino.cc/en/Reference/WiFiUDPRemoteIP>`__
12. `remotePort() <https://www.arduino.cc/en/Reference/WiFiUDPRemotePort>`__

Binary file not shown.

View file

@ -92,7 +92,7 @@ SECTIONS
} > FLASH
.rodata : {
*(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*)
*(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata* .big_const*)
. = ALIGN(4);
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
. = ALIGN(4);

View file

@ -12,8 +12,8 @@
#define _PICO_VERSION_H
#define PICO_SDK_VERSION_MAJOR 1
#define PICO_SDK_VERSION_MINOR 3
#define PICO_SDK_VERSION_REVISION 2
#define PICO_SDK_VERSION_STRING "1.3.2-develop"
#define PICO_SDK_VERSION_MINOR 4
#define PICO_SDK_VERSION_REVISION 0
#define PICO_SDK_VERSION_STRING "1.4.0"
#endif

View file

@ -40,9 +40,11 @@
-iwithprefixbefore/pico-sdk/src/rp2_common/hardware_watchdog/include
-iwithprefixbefore/pico-sdk/src/rp2_common/hardware_xosc/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_bootrom/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_cyw43_arch/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_double/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_float/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_int64_ops/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_lwip/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_multicore/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_platform/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_printf/include
@ -50,3 +52,5 @@
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_stdio/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_stdio_uart/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_unique_id/include
-iwithprefixbefore/pico-sdk/lib/cyw43-driver/src
-iwithprefixbefore/pico-sdk/lib/lwip/src/include

@ -1 +1 @@
Subproject commit 122544ce7346a81beac52347d88509b788ecadd6
Subproject commit 5be0b21c0a5cf396b139bce0c6c0d403df051b0a

View file

@ -8,3 +8,4 @@ category=Timing
url=https://github.com/FreeRTOS/FreeRTOS-Kernel
architectures=rp2040
license=MIT
dot_a_linkage=true

View file

@ -7,4 +7,4 @@ paragraph=
category=Communication
url=http://www.arduino.cc/en/Reference/I2S
architectures=rp2040
dot_a_linkage=true

View file

@ -0,0 +1,42 @@
// Simple WiFi network scanner application
// Released to the public domain in 2022 by Earle F. Philhower, III
#include <WiFi.h>
void setup() {
Serial.begin(115200);
}
const char *macToString(uint8_t mac[6]) {
static char s[20];
sprintf(s, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return s;
}
const char *encToString(uint8_t enc) {
switch (enc) {
case ENC_TYPE_NONE: return "NONE";
case ENC_TYPE_TKIP: return "WPA";
case ENC_TYPE_CCMP: return "WPA2";
case ENC_TYPE_AUTO: return "AUTO";
}
return "UNKN";
}
void loop() {
delay(5000);
Serial.printf("Beginning scan at %d\n", millis());
auto cnt = WiFi.scanNetworks();
if (!cnt) {
Serial.printf("No networks found\n");
} else {
Serial.printf("Found %d networks\n\n", cnt);
Serial.printf("%32s %5s %17s %2s %4s\n", "SSID", "ENC", "BSSID ", "CH", "RSSI");
for (auto i = 0; i < cnt; i++) {
uint8_t bssid[6];
WiFi.BSSID(i, bssid);
Serial.printf("%32s %5s %17s %2d %4d\n", WiFi.SSID(i), encToString(WiFi.encryptionType(i)), macToString(bssid), WiFi.channel(i), WiFi.RSSI(i));
}
}
Serial.printf("\n--- Sleeping ---\n\n\n");
delay(5000);
}

View file

@ -0,0 +1,70 @@
/*
UDPSendReceive.pde:
This sketch receives UDP message strings, prints them to the serial port
and sends an "acknowledge" string back to the sender
A Processing sketch is included at the end of file that can be used to send
and received messages for testing with a computer.
created 21 Aug 2010
by Michael Margolis
This code is in the public domain.
adapted from Ethernet library examples
*/
#include <WiFi.h>
#include <WiFiUdp.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
unsigned int localPort = 8888; // local port to listen on
// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE + 1]; // buffer to hold incoming packet,
char ReplyBuffer[] = "acknowledged\r\n"; // a string to send back
WiFiUDP Udp;
void setup() {
Serial.begin(115200);
WiFi.begin(STASSID, STAPSK);
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(500);
}
Serial.print("Connected! IP address: ");
Serial.println(WiFi.localIP());
Serial.printf("UDP server on port %d\n", localPort);
Udp.begin(localPort);
}
void loop() {
// if there's data available, read a packet
int packetSize = Udp.parsePacket();
if (packetSize) {
Serial.printf("Received packet of size %d from %s:%d\n (to %s:%d)\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort(), Udp.destinationIP().toString().c_str(), Udp.localPort());
// read the packet into packetBufffer
int n = Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
packetBuffer[n] = 0;
Serial.println("Contents:");
Serial.println(packetBuffer);
// send a reply, to the IP address and port that sent us the packet we received
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
Udp.write(ReplyBuffer);
Udp.endPacket();
}
}
/*
test (shell/netcat):
--------------------
nc -u 192.168.pico.address 8888
*/

View file

@ -0,0 +1,92 @@
/*
This sketch establishes a TCP connection to a "quote of the day" service.
It sends a "hello" message, and then prints received data.
*/
#include <WiFi.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
const char* host = "djxmmx.net";
const uint16_t port = 17;
void setup() {
Serial.begin(115200);
// We start by connecting to a WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
static bool wait = false;
Serial.print("connecting to ");
Serial.print(host);
Serial.print(':');
Serial.println(port);
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (!client.connect(host, port)) {
Serial.println("connection failed");
delay(5000);
return;
}
// This will send a string to the server
Serial.println("sending data to server");
if (client.connected()) {
client.println("hello from ESP8266");
}
// wait for data to be available
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println(">>> Client Timeout !");
client.stop();
delay(60000);
return;
}
}
// Read all the lines of the reply from server and print them to Serial
Serial.println("receiving from remote server");
// not testing 'client.connected()' since we do not need to send data here
while (client.available()) {
char ch = static_cast<char>(client.read());
Serial.print(ch);
}
// Close the connection
Serial.println();
Serial.println("closing connection");
client.stop();
if (wait) {
delay(300000); // execute once every 5 minutes, don't flood remote service
}
wait = true;
}

View file

@ -0,0 +1,49 @@
// Placed in the public domain by Earle F. Philhower, III, 2022
#include <WiFi.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
int port = 4242;
WiFiServer server(port);
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.setHostname("PicoW2");
Serial.printf("Connecting to '%s' with '%s'\n", ssid, password);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(100);
}
Serial.printf("\nConnected to WiFi\n\nConnect to server at %s:%d\n", WiFi.localIP().toString().c_str(), port);
server.begin();
}
void loop() {
static int i;
delay(1000);
Serial.printf("--loop %d\n", ++i);
delay(10);
WiFiClient client = server.available();
if (!client) {
return;
}
client.println("Type anything and hit return");
while (!client.available()) {
delay(10);
}
String req = client.readStringUntil('\n');
Serial.println(req);
client.printf("Hello from Pico-W\r\n");
client.flush();
}

View file

@ -0,0 +1,67 @@
#######################################
# Syntax Coloring Map For WiFiNINA
#######################################
#######################################
# Library (KEYWORD1)
#######################################
WiFi KEYWORD1
WiFiPico KEYWORD1
WiFiUdp KEYWORD1
WiFiClient KEYWORD1
WiFiSSLClient KEYWORD1
WiFiServer KEYWORD1
WiFiUDP KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
firmwareVersion KEYWORD2
status KEYWORD2
reasonCode KEYWORD2
connect KEYWORD2
write KEYWORD2
available KEYWORD2
config KEYWORD2
setDNS KEYWORD2
read KEYWORD2
flush KEYWORD2
stop KEYWORD2
connected KEYWORD2
begin KEYWORD2
disconnect KEYWORD2
macAddress KEYWORD2
localIP KEYWORD2
subnetMask KEYWORD2
gatewayIP KEYWORD2
SSID KEYWORD2
BSSID KEYWORD2
RSSI KEYWORD2
encryptionType KEYWORD2
beginPacket KEYWORD2
endPacket KEYWORD2
parsePacket KEYWORD2
remoteIP KEYWORD2
remotePort KEYWORD2
mode KEYWORD2
beginAP KEYWORD2
beginEnterprise KEYWORD2
setHostname KEYWORD2
end KEYWORD2
getTime KEYWORD2
lowPowerMode KEYWORD2
noLowPowerMode KEYWORD2
ping KEYWORD2
beginMulticast KEYWORD2
setTimeout KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
WIFI_STA LITERAL1
WIFI_AP LITERAL1

View file

@ -0,0 +1,11 @@
name=WiFi
version=1.0.0
author=Earle F. Philhower, III
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
sentence=Enables network connection (local and Internet) with the Raspberry Pi Pico W RP2040
paragraph=With this library you can instantiate Servers, Clients and send/receive UDP packets through WiFi. The board can connect either to open or encrypted networks (WEP, WPA). The IP address can be assigned statically or through a DHCP. The library can also manage DNS.
category=Communication
url=http://github.com/earlephilhower/arduino-pico
architectures=rp2040
includes=WiFi.h
dot_a_linkage=true

View file

@ -0,0 +1,2 @@
// Since things may just work, we'll redirect for now
#include "WiFi.h"

13
libraries/WiFi/src/WiFi.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#include "wl_definitions.h"
#include "wl_types.h"
#include "LWIPMutex.h"
#include "WiFiClass.h"
#include "WiFiClient.h"
#include "WiFiServer.h"
//#include "WiFiClientSecure.h"
//#include "WiFiServerSecure.h"
#include "WiFiUdp.h"

View file

@ -0,0 +1,543 @@
/*
WiFiClass.cpp - WiFi class "compat" w/WiFiNINA for Raspberry Pi Pico W
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
Implements the API defined by the Arduino WiFiNINA library,
copyright (c) 2018 Arduino SA. All rights reserved.
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
*/
#include <inttypes.h>
#include <pico/cyw43_arch.h>
#include <cyw43.h>
#include "lwip/raw.h"
#include "lwip/icmp.h"
#include "lwip/inet_chksum.h"
#include <map>
#include "WiFi.h"
// This is the real WiFi network object, we just tickle it to do our magic
#include <LwipEthernet.h>
static CYW43lwIP _wifi(1);
WiFiClass::WiFiClass() {
}
/*
Get firmware version
*/
const char* WiFiClass::firmwareVersion() {
// TODO - does not look like driver reports this now
return PICO_SDK_VERSION_STRING;
}
void WiFiClass::mode(_wifiModeESP m) {
_calledESP = true;
switch (m) {
case WIFI_OFF:
end();
break;
case WIFI_AP:
_modeESP = WIFI_AP;
break;
case WIFI_STA:
_modeESP = WIFI_STA;
break;
}
}
/* Start WiFi connection for OPEN networks
param ssid: Pointer to the SSID string.
*/
int WiFiClass::begin(const char* ssid) {
return begin(ssid, nullptr);
}
/* Start WiFi connection with passphrase
the most secure supported mode will be automatically selected
param ssid: Pointer to the SSID string.
param passphrase: Passphrase. Valid characters in a passphrase
must be between ASCII 32-126 (decimal).
*/
int WiFiClass::begin(const char* ssid, const char *passphrase) {
// Simple ESP8266 compatibility hack
if (_modeESP == WIFI_AP) {
return beginAP(ssid, passphrase);
}
end();
_ssid = ssid;
_password = passphrase;
_wifi.setSSID(ssid);
_wifi.setPassword(passphrase);
_wifi.setTimeout(_timeout);
_wifi.setSTA();
_apMode = false;
_wifiHWInitted = true;
uint32_t start = millis(); // The timeout starts from network init, not network link up
if (!_wifi.begin()) {
return WL_IDLE_STATUS;
}
while (!_calledESP && ((millis() - start < (uint32_t)2 * _timeout)) && !connected()) {
delay(10);
}
return status();
}
uint8_t WiFiClass::beginAP(const char *ssid) {
return beginAP(ssid, nullptr);
}
uint8_t WiFiClass::beginAP(const char *ssid, uint8_t channel) {
(void) channel;
return beginAP(ssid, nullptr);
}
uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase, uint8_t channel) {
(void) channel;
return beginAP(ssid, passphrase);
}
uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase) {
end();
_ssid = ssid;
_password = passphrase;
_wifi.setSSID(ssid);
_wifi.setPassword(passphrase);
_wifi.setTimeout(_timeout);
_wifi.setAP();
_apMode = true;
if (!_wifi.begin()) {
return WL_IDLE_STATUS;
}
IPAddress gw = _wifi.gatewayIP();
if (!gw.isSet()) {
gw = IPAddress(192, 168, 42, 1);
}
IPAddress mask = _wifi.subnetMask();
if (!mask.isSet()) {
mask = IPAddress(255, 255, 255, 0);
}
config(gw);
_dhcpServer = (dhcp_server_t *)malloc(sizeof(dhcp_server_t));
if (!_dhcpServer) {
// OOM
return WL_IDLE_STATUS;
}
dhcp_server_init(_dhcpServer, gw, mask);
_wifiHWInitted = true;
return WL_CONNECTED;
}
bool WiFiClass::connected() {
return _wifi.connected() && localIP().isSet();
}
/* Change Ip configuration settings disabling the dhcp client
param local_ip: Static ip configuration
*/
void WiFiClass::config(IPAddress local_ip) {
ip4_addr_set_u32(ip_2_ip4(&_wifi.getNetIf()->ip_addr), local_ip.v4());
}
/* Change Ip configuration settings disabling the dhcp client
param local_ip: Static ip configuration
param dns_server: IP configuration for DNS server 1
*/
void WiFiClass::config(IPAddress local_ip, IPAddress dns_server) {
ip4_addr_set_u32(ip_2_ip4(&_wifi.getNetIf()->ip_addr), local_ip.v4());
dns_setserver(0, dns_server);
}
/* Change Ip configuration settings disabling the dhcp client
param local_ip: Static ip configuration
param dns_server: IP configuration for DNS server 1
param gateway : Static gateway configuration
*/
void WiFiClass::config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway) {
ip4_addr_set_u32(ip_2_ip4(&_wifi.getNetIf()->ip_addr), local_ip.v4());
dns_setserver(0, dns_server);
ip4_addr_set_u32(ip_2_ip4(&_wifi.getNetIf()->gw), gateway.v4());
}
/* Change Ip configuration settings disabling the dhcp client
param local_ip: Static ip configuration
param dns_server: IP configuration for DNS server 1
param gateway: Static gateway configuration
param subnet: Static Subnet mask
*/
void WiFiClass::config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet) {
_wifi.config(local_ip, gateway, subnet, dns_server);
}
/* Change DNS Ip configuration
param dns_server1: ip configuration for DNS server 1
*/
void WiFiClass::setDNS(IPAddress dns_server1) {
dns_setserver(0, dns_server1);
}
/* Change DNS Ip configuration
param dns_server1: ip configuration for DNS server 1
param dns_server2: ip configuration for DNS server 2
*/
void WiFiClass::setDNS(IPAddress dns_server1, IPAddress dns_server2) {
dns_setserver(0, dns_server1);
dns_setserver(1, dns_server2);
}
/* Set the hostname used for DHCP requests
param name: hostname to set
*/
void WiFiClass::setHostname(const char* name) {
_wifi.setHostname(name);
}
/*
Disconnect from the network
return: one value of wl_status_t enum
*/
int WiFiClass::disconnect(void) {
if (_wifiHWInitted) {
cyw43_wifi_leave(&cyw43_state, _apMode ? 1 : 0);
}
_wifiHWInitted = false;
if (_dhcpServer) {
dhcp_server_deinit(_dhcpServer);
free(_dhcpServer);
_dhcpServer = nullptr;
}
_wifi.end();
return WL_DISCONNECTED;
}
void WiFiClass::end(void) {
if (_wifiHWInitted) {
disconnect();
}
}
/*
Get the interface MAC address.
return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
*/
uint8_t* WiFiClass::macAddress(uint8_t* mac) {
if (!_wifiHWInitted) {
_apMode = false;
cyw43_wifi_set_up(&cyw43_state, _apMode ? 1 : 0, true, CYW43_COUNTRY_WORLDWIDE);
}
cyw43_wifi_get_mac(&cyw43_state, _apMode ? 1 : 0, mac);
return mac;
}
/*
Get the interface IP address.
return: Ip address value
*/
IPAddress WiFiClass::localIP() {
return _wifi.localIP();
}
/*
Get the interface subnet mask address.
return: subnet mask address value
*/
IPAddress WiFiClass::subnetMask() {
return _wifi.subnetMask();
}
/*
Get the gateway ip address.
return: gateway ip address value
*/
IPAddress WiFiClass::gatewayIP() {
return _wifi.gatewayIP();
}
/*
Return the current SSID associated with the network
return: ssid string
*/
const char* WiFiClass::SSID() {
return _ssid;
}
/*
Return the current BSSID associated with the network.
It is the MAC address of the Access Point
return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
*/
uint8_t* WiFiClass::BSSID(uint8_t* bssid) {
// TODO - driver does not return this?!
memset(bssid, 0xee, WL_MAC_ADDR_LENGTH);
return bssid;
}
/*
Return the current RSSI /Received Signal Strength in dBm)
associated with the network
return: signed value
*/
int32_t WiFiClass::RSSI() {
// TODO - driver does not return this?!
return 0;
}
/*
Return the Encryption Type associated with the network
return: one value of wl_enc_type enum
*/
uint8_t WiFiClass::encryptionType() {
// TODO - Driver does not return this?!
if (_password == nullptr) {
return ENC_TYPE_NONE;
}
return ENC_TYPE_AUTO;
}
//TODO - this can be in the class
static uint64_t _to64(uint8_t b[8]) {
uint64_t x = 0;
for (int i = 0; i < 6; i++) {
x <<= 8LL;
x |= b[i] & 255;
}
return x;
}
int WiFiClass::_scanCB(void *env, const cyw43_ev_scan_result_t *result) {
WiFiClass *w = (WiFiClass *)env;
if (result) {
cyw43_ev_scan_result_t s;
memcpy(&s, result, sizeof(s));
w->_scan.insert_or_assign(_to64(s.bssid), s);
}
return 0;
}
/*
Start scan WiFi networks available
return: Number of discovered networks
*/
int8_t WiFiClass::scanNetworks() {
cyw43_wifi_scan_options_t scan_options;
memset(&scan_options, 0, sizeof(scan_options));
_scan.clear();
if (!_wifiHWInitted) {
_apMode = false;
cyw43_arch_enable_sta_mode();
_wifiHWInitted = true;
}
int err = cyw43_wifi_scan(&cyw43_state, &scan_options, this, _scanCB);
if (err) {
return 0;
}
uint32_t now = millis();
while (cyw43_wifi_scan_active(&cyw43_state) && (millis() - now < 10000)) {
delay(10);
}
return _scan.size();
}
/*
Return the SSID discovered during the network scan.
param networkItem: specify from which network item want to get the information
return: ssid string of the specified item on the networks scanned list
*/
const char*WiFiClass::SSID(uint8_t networkItem) {
if (networkItem >= _scan.size()) {
return nullptr;
}
auto it = _scan.begin();
for (int i = 0; i < networkItem; i++) {
++it;
}
return (const char *)it->second.ssid;
}
/*
Return the encryption type of the networks discovered during the scanNetworks
param networkItem: specify from which network item want to get the information
return: encryption type (enum wl_enc_type) of the specified item on the networks scanned list
*/
uint8_t WiFiClass::encryptionType(uint8_t networkItem) {
if (networkItem >= _scan.size()) {
return ENC_TYPE_UNKNOWN;
}
auto it = _scan.begin();
for (int i = 0; i < networkItem; i++) {
++it;
}
// TODO - the driver returns a small integer but does not actually provide a way of mapping that to the proper enc type. My best guesses here...
switch (it->second.auth_mode) {
case 0: return ENC_TYPE_NONE;
case 3: return ENC_TYPE_TKIP;
case 5: return ENC_TYPE_CCMP;
case 7: return ENC_TYPE_AUTO;
}
return ENC_TYPE_UNKNOWN;
}
uint8_t* WiFiClass::BSSID(uint8_t networkItem, uint8_t* bssid) {
if (networkItem >= _scan.size()) {
return nullptr;
}
auto it = _scan.begin();
for (int i = 0; i < networkItem; i++) {
++it;
}
memcpy(bssid, it->second.bssid, 6);
return bssid;
}
uint8_t WiFiClass::channel(uint8_t networkItem) {
if (networkItem >= _scan.size()) {
return 255;
}
auto it = _scan.begin();
for (int i = 0; i < networkItem; i++) {
++it;
}
return it->second.channel;
}
/*
Return the RSSI of the networks discovered during the scanNetworks
param networkItem: specify from which network item want to get the information
return: signed value of RSSI of the specified item on the networks scanned list
*/
int32_t WiFiClass::RSSI(uint8_t networkItem) {
if (networkItem >= _scan.size()) {
return -9999;
}
auto it = _scan.begin();
for (int i = 0; i < networkItem; i++) {
++it;
}
return it->second.rssi;
}
/*
Return Connection status.
return: one of the value defined in wl_status_t
*/
uint8_t WiFiClass::status() {
switch (cyw43_wifi_link_status(&cyw43_state, _apMode ? 1 : 0)) {
case CYW43_LINK_DOWN: return WL_IDLE_STATUS;
case CYW43_LINK_JOIN: return localIP().isSet() ? WL_CONNECTED : WL_CONNECTING;
case CYW43_LINK_FAIL: return WL_CONNECT_FAILED;
case CYW43_LINK_NONET: return WL_CONNECT_FAILED;
case CYW43_LINK_BADAUTH: return WL_CONNECT_FAILED;
}
return WL_NO_MODULE;
}
/*
Return The deauthentication reason code.
return: the deauthentication reason code
*/
uint8_t WiFiClass::reasonCode() {
// TODO - driver does not report this?!
return WL_NO_SHIELD;
}
/**
Resolve the given hostname to an IP address.
@param aHostname Name to be resolved
@param aResult IPAddress structure to store the returned IP address
@return 1 if aIPAddrString was successfully converted to an IP address,
else 0
*/
int WiFiClass::hostByName(const char* aHostname, IPAddress& aResult, int timeout_ms) {
return _wifi.hostByName(aHostname, aResult, timeout_ms);
}
// TODO
unsigned long WiFiClass::getTime() {
return millis();
}
void WiFiClass::lowPowerMode() {
cyw43_wifi_pm(&cyw43_state, CYW43_AGGRESSIVE_PM);
}
void WiFiClass::noLowPowerMode() {
cyw43_wifi_pm(&cyw43_state, CYW43_DEFAULT_PM);
}
int WiFiClass::ping(const char* hostname, uint8_t ttl) {
IPAddress ip;
if (!hostByName(hostname, ip)) {
return WL_PING_UNKNOWN_HOST;
}
return ping(ip, ttl);
}
int WiFiClass::ping(const String &hostname, uint8_t ttl) {
return ping(hostname.c_str(), ttl);
}
int WiFiClass::ping(IPAddress host, uint8_t ttl) {
return _wifi.ping(host, ttl, _timeout);
}
void WiFiClass::setTimeout(unsigned long timeout) {
_timeout = timeout;
}
void WiFiClass::setFeedWatchdogFunc(FeedHostProcessorWatchdogFuncPointer func) {
(void) func;
}
void WiFiClass::feedWatchdog() {
}
WiFiClass WiFi;

View file

@ -0,0 +1,304 @@
/*
WiFi.h - WiFi class "compat" w/WiFiNINA for Raspberry Pi Pico W
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
Implements the API defined by the Arduino WiFiNINA library,
copyright (c) 2018 Arduino SA. All rights reserved.
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 <Arduino.h>
#include "WiFi.h"
#include <inttypes.h>
#include <map>
#include <cyw43.h>
#include "dhcpserver/dhcpserver.h"
#define WIFI_FIRMWARE_LATEST_VERSION PICO_SDK_VERSION_STRING
typedef void(*FeedHostProcessorWatchdogFuncPointer)();
typedef enum { WIFI_STA, WIFI_AP, WIFI_OFF } _wifiModeESP; // For ESP8266 compatibility
class WiFiClass {
public:
WiFiClass();
/*
Get firmware version
*/
static const char* firmwareVersion();
void mode(_wifiModeESP m); // For ESP8266 compatibility
/* Start WiFi connection for OPEN networks
param ssid: Pointer to the SSID string.
*/
int begin(const char* ssid);
/* Start WiFi connection with WEP encryption.
Configure a key into the device. The key type (WEP-40, WEP-104)
is determined by the size of the key (5 bytes for WEP-40, 13 bytes for WEP-104).
param ssid: Pointer to the SSID string.
param key_idx: The key index to set. Valid values are 0-3.
param key: Key input buffer.
*/
// TODO - WEP is not supported in the driver
// int begin(const char* ssid, uint8_t key_idx, const char* key);
/* Start WiFi connection with passphrase
the most secure supported mode will be automatically selected
param ssid: Pointer to the SSID string.
param passphrase: Passphrase. Valid characters in a passphrase
must be between ASCII 32-126 (decimal).
*/
int begin(const char* ssid, const char *passphrase);
bool connected();
uint8_t beginAP(const char *ssid);
uint8_t beginAP(const char *ssid, uint8_t channel);
uint8_t beginAP(const char *ssid, const char* passphrase);
uint8_t beginAP(const char *ssid, const char* passphrase, uint8_t channel);
// TODO - EAP is not supported by the driver. Maybe some way of user-level wap-supplicant in the future?
//uint8_t beginEnterprise(const char* ssid, const char* username, const char* password);
//uint8_t beginEnterprise(const char* ssid, const char* username, const char* password, const char* identity);
//uint8_t beginEnterprise(const char* ssid, const char* username, const char* password, const char* identity, const char* ca);
/* Change Ip configuration settings disabling the dhcp client
param local_ip: Static ip configuration
*/
void config(IPAddress local_ip);
/* Change Ip configuration settings disabling the dhcp client
param local_ip: Static ip configuration
param dns_server: IP configuration for DNS server 1
*/
void config(IPAddress local_ip, IPAddress dns_server);
/* Change Ip configuration settings disabling the dhcp client
param local_ip: Static ip configuration
param dns_server: IP configuration for DNS server 1
param gateway : Static gateway configuration
*/
void config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway);
/* Change Ip configuration settings disabling the dhcp client
param local_ip: Static ip configuration
param dns_server: IP configuration for DNS server 1
param gateway: Static gateway configuration
param subnet: Static Subnet mask
*/
void config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet);
/* Change DNS Ip configuration
param dns_server1: ip configuration for DNS server 1
*/
void setDNS(IPAddress dns_server1);
/* Change DNS Ip configuration
param dns_server1: ip configuration for DNS server 1
param dns_server2: ip configuration for DNS server 2
*/
void setDNS(IPAddress dns_server1, IPAddress dns_server2);
/* Set the hostname used for DHCP requests
param name: hostname to set
*/
void setHostname(const char* name);
/*
Disconnect from the network
return: one value of wl_status_t enum
*/
int disconnect(void);
void end(void);
/*
Get the interface MAC address.
return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
*/
uint8_t* macAddress(uint8_t* mac);
/*
Get the interface IP address.
return: Ip address value
*/
IPAddress localIP();
/*
Get the interface subnet mask address.
return: subnet mask address value
*/
IPAddress subnetMask();
/*
Get the gateway ip address.
return: gateway ip address value
*/
IPAddress gatewayIP();
/*
Return the current SSID associated with the network
return: ssid string
*/
const char* SSID();
/*
Return the current BSSID associated with the network.
It is the MAC address of the Access Point
return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
*/
uint8_t* BSSID(uint8_t* bssid);
/*
Return the current RSSI /Received Signal Strength in dBm)
associated with the network
return: signed value
*/
int32_t RSSI();
/*
Return the Encryption Type associated with the network
return: one value of wl_enc_type enum
*/
uint8_t encryptionType();
/*
Start scan WiFi networks available
return: Number of discovered networks
*/
int8_t scanNetworks();
/*
Return the SSID discovered during the network scan.
param networkItem: specify from which network item want to get the information
return: ssid string of the specified item on the networks scanned list
*/
const char* SSID(uint8_t networkItem);
/*
Return the encryption type of the networks discovered during the scanNetworks
param networkItem: specify from which network item want to get the information
return: encryption type (enum wl_enc_type) of the specified item on the networks scanned list
*/
uint8_t encryptionType(uint8_t networkItem);
uint8_t* BSSID(uint8_t networkItem, uint8_t* bssid);
uint8_t channel(uint8_t networkItem);
/*
Return the RSSI of the networks discovered during the scanNetworks
param networkItem: specify from which network item want to get the information
return: signed value of RSSI of the specified item on the networks scanned list
*/
int32_t RSSI(uint8_t networkItem);
/*
Return Connection status.
return: one of the value defined in wl_status_t
*/
uint8_t status();
/*
Return The deauthentication reason code.
return: the deauthentication reason code
*/
uint8_t reasonCode();
/*
Resolve the given hostname to an IP address.
param aHostname: Name to be resolved
param aResult: IPAddress structure to store the returned IP address
result: 1 if aIPAddrString was successfully converted to an IP address,
else error code
*/
int hostByName(const char* aHostname, IPAddress& aResult) {
return hostByName(aHostname, aResult, _timeout);
}
int hostByName(const char* aHostname, IPAddress& aResult, int timeout);
unsigned long getTime();
void lowPowerMode();
void noLowPowerMode();
int ping(const char* hostname, uint8_t ttl = 128);
int ping(const String &hostname, uint8_t ttl = 128);
int ping(IPAddress host, uint8_t ttl = 128);
void setTimeout(unsigned long timeout);
void setFeedWatchdogFunc(FeedHostProcessorWatchdogFuncPointer func);
void feedWatchdog();
private:
int _timeout = 10000;
const char * _ssid = nullptr;
const char * _password = nullptr;
bool _wifiHWInitted = false;
bool _apMode = false;
// WiFi Scan callback
std::map<uint64_t, cyw43_ev_scan_result_t> _scan;
static int _scanCB(void *env, const cyw43_ev_scan_result_t *result);
// DHCP for AP mode
dhcp_server_t *_dhcpServer = nullptr;
// ESP compat
bool _calledESP = false; // Should we behave like the ESP8266 for connect?
_wifiModeESP _modeESP = WIFI_STA;
};
extern WiFiClass WiFi;

View file

@ -0,0 +1,414 @@
/*
WiFiClient.cpp - TCP/IP client for esp8266, mostly compatible
with Arduino WiFi shield library
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
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
*/
#include "WiFi.h"
#include "lwip/opt.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/inet.h"
#include "lwip/netif.h"
#include <include/ClientContext.h>
//#include <StreamDev.h>
uint16_t WiFiClient::_localPort = 0;
static bool defaultNoDelay = false; // false == Nagle enabled by default
static bool defaultSync = false;
bool getDefaultPrivateGlobalSyncValue() {
return defaultSync;
}
void WiFiClient::setDefaultNoDelay(bool noDelay) {
defaultNoDelay = noDelay;
}
void WiFiClient::setDefaultSync(bool sync) {
defaultSync = sync;
}
bool WiFiClient::getDefaultNoDelay() {
return defaultNoDelay;
}
bool WiFiClient::getDefaultSync() {
return defaultSync;
}
template<>
WiFiClient* SList<WiFiClient>::_s_first = 0;
WiFiClient::WiFiClient()
: _client(0), _owned(0) {
_timeout = 5000;
WiFiClient::_add(this);
}
WiFiClient::WiFiClient(ClientContext* client)
: _client(client), _owned(0) {
_timeout = 5000;
_client->ref();
WiFiClient::_add(this);
setSync(defaultSync);
setNoDelay(defaultNoDelay);
}
WiFiClient::~WiFiClient() {
WiFiClient::_remove(this);
if (_client) {
_client->unref();
}
}
std::unique_ptr<WiFiClient> WiFiClient::clone() const {
return std::make_unique<WiFiClient>(*this);
}
WiFiClient::WiFiClient(const WiFiClient& other) {
_client = other._client;
_timeout = other._timeout;
_localPort = other._localPort;
_owned = other._owned;
if (_client) {
_client->ref();
}
WiFiClient::_add(this);
}
WiFiClient& WiFiClient::operator=(const WiFiClient& other) {
if (_client) {
_client->unref();
}
_client = other._client;
_timeout = other._timeout;
_localPort = other._localPort;
_owned = other._owned;
if (_client) {
_client->ref();
}
return *this;
}
int WiFiClient::connect(const char* host, uint16_t port) {
IPAddress remote_addr;
if (WiFi.hostByName(host, remote_addr, _timeout)) {
return connect(remote_addr, port);
}
return 0;
}
int WiFiClient::connect(const String& host, uint16_t port) {
return connect(host.c_str(), port);
}
int WiFiClient::connect(IPAddress ip, uint16_t port) {
if (_client) {
stop();
_client->unref();
_client = nullptr;
}
LWIPMutex m; // Block the timer sys_check_timeouts call
tcp_pcb* pcb = tcp_new();
if (!pcb) {
return 0;
}
if (_localPort > 0) {
pcb->local_port = _localPort++;
}
_client = new ClientContext(pcb, nullptr, nullptr);
_client->ref();
_client->setTimeout(_timeout);
int res = _client->connect(ip, port);
if (res == 0) {
_client->unref();
_client = nullptr;
return 0;
}
setSync(defaultSync);
setNoDelay(defaultNoDelay);
return 1;
}
void WiFiClient::setNoDelay(bool nodelay) {
if (!_client) {
return;
}
_client->setNoDelay(nodelay);
}
bool WiFiClient::getNoDelay() const {
if (!_client) {
return false;
}
return _client->getNoDelay();
}
void WiFiClient::setSync(bool sync) {
if (!_client) {
return;
}
_client->setSync(sync);
}
bool WiFiClient::getSync() const {
if (!_client) {
return false;
}
return _client->getSync();
}
int WiFiClient::availableForWrite() {
return _client ? _client->availableForWrite() : 0;
}
size_t WiFiClient::write(uint8_t b) {
return write(&b, 1);
}
size_t WiFiClient::write(const uint8_t *buf, size_t size) {
if (!_client || !size) {
return 0;
}
_client->setTimeout(_timeout);
return _client->write((const char*)buf, size);
}
//TODO - implement!
//size_t WiFiClient::write(Stream& stream)
//{
// // (this method is deprecated)
//
// if (!_client || !stream.available())
// {
// return 0;
// }
// // core up to 2.7.4 was equivalent to this
// return _client->write(stream);
//}
int WiFiClient::available() {
if (!_client) {
return 0;
}
int result = _client->getSize();
return result;
}
int WiFiClient::read() {
if (!available()) {
return -1;
}
return _client->read();
}
int WiFiClient::read(uint8_t* buf, size_t size) {
return (int)_client->read((char*)buf, size);
}
int WiFiClient::read(char* buf, size_t size) {
return (int)_client->read(buf, size);
}
int WiFiClient::peek() {
if (!available()) {
return -1;
}
return _client->peek();
}
size_t WiFiClient::peekBytes(uint8_t *buffer, size_t length) {
size_t count = 0;
if (!_client) {
return 0;
}
_startMillis = millis();
while ((available() < (int) length) && ((millis() - _startMillis) < _timeout)) {
yield();
}
if (available() < (int) length) {
count = available();
} else {
count = length;
}
return _client->peekBytes((char *)buffer, count);
}
bool WiFiClient::flush(unsigned int maxWaitMs) {
if (!_client) {
return true;
}
if (maxWaitMs == 0) {
maxWaitMs = WIFICLIENT_MAX_FLUSH_WAIT_MS;
}
return _client->wait_until_acked(maxWaitMs);
}
bool WiFiClient::stop(unsigned int maxWaitMs) {
if (!_client) {
return true;
}
bool ret = flush(maxWaitMs); // virtual, may be ssl's
if (_client->close() != ERR_OK) {
ret = false;
}
return ret;
}
uint8_t WiFiClient::connected() {
if (!_client || _client->state() == CLOSED) {
return 0;
}
return _client->state() == ESTABLISHED || available();
}
uint8_t WiFiClient::status() {
if (!_client) {
return CLOSED;
}
return _client->state();
}
WiFiClient::operator bool() {
return available() || connected();
}
IPAddress WiFiClient::remoteIP() {
if (!_client || !_client->getRemoteAddress()) {
return IPAddress(0);
}
return _client->getRemoteAddress();
}
uint16_t WiFiClient::remotePort() {
if (!_client) {
return 0;
}
return _client->getRemotePort();
}
IPAddress WiFiClient::localIP() {
if (!_client || !_client->getLocalAddress()) {
return IPAddress(0);
}
return IPAddress(_client->getLocalAddress());
}
uint16_t WiFiClient::localPort() {
if (!_client) {
return 0;
}
return _client->getLocalPort();
}
void WiFiClient::stopAll() {
for (WiFiClient* it = _s_first; it; it = it->_next) {
it->stop();
}
}
void WiFiClient::stopAllExcept(WiFiClient* except) {
// Stop all will look at the lowest-level wrapper connections only
while (except->_owned) {
except = except->_owned;
}
for (WiFiClient* it = _s_first; it; it = it->_next) {
WiFiClient* conn = it;
// Find the lowest-level owner of the current list entry
while (conn->_owned) {
conn = conn->_owned;
}
if (conn != except) {
conn->stop();
}
}
}
void WiFiClient::keepAlive(uint16_t idle_sec, uint16_t intv_sec, uint8_t count) {
_client->keepAlive(idle_sec, intv_sec, count);
}
bool WiFiClient::isKeepAliveEnabled() const {
return _client->isKeepAliveEnabled();
}
uint16_t WiFiClient::getKeepAliveIdle() const {
return _client->getKeepAliveIdle();
}
uint16_t WiFiClient::getKeepAliveInterval() const {
return _client->getKeepAliveInterval();
}
uint8_t WiFiClient::getKeepAliveCount() const {
return _client->getKeepAliveCount();
}
//bool WiFiClient::hasPeekBufferAPI () const
//{
// return true;
//}
// return a pointer to available data buffer (size = peekAvailable())
// semantic forbids any kind of read() before calling peekConsume()
//const char* WiFiClient::peekBuffer ()
//{
// return _client? _client->peekBuffer(): nullptr;
//}
// return number of byte accessible by peekBuffer()
//size_t WiFiClient::peekAvailable ()
//{
// return _client? _client->peekAvailable(): 0;
//}
// consume bytes after use (see peekBuffer)
//void WiFiClient::peekConsume (size_t consume)
//{
// if (_client)
// _client->peekConsume(consume);
//}

View file

@ -0,0 +1,169 @@
/*
WiFiClient.h - Library for Arduino Wifi shield.
Copyright (c) 2011-2014 Arduino. All right reserved.
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
Modified by Ivan Grokhotkov, December 2014 - esp8266 support
Hacked to tiny bits and set on fire by Earle F. Philhower, III - 2022 - Pico W support
*/
#pragma once
#include <memory>
#include "WiFi.h"
#include "Print.h"
#include "Client.h"
#include "IPAddress.h"
#include "include/slist.h"
#ifndef TCP_MSS
#define TCP_MSS 1460 // lwip1.4
#endif
#define WIFICLIENT_MAX_PACKET_SIZE TCP_MSS
#define WIFICLIENT_MAX_FLUSH_WAIT_MS 300
#define TCP_DEFAULT_KEEPALIVE_IDLE_SEC 7200 // 2 hours
#define TCP_DEFAULT_KEEPALIVE_INTERVAL_SEC 75 // 75 sec
#define TCP_DEFAULT_KEEPALIVE_COUNT 9 // fault after 9 failures
class ClientContext;
class WiFiServer;
class WiFiClient : public Client, public SList<WiFiClient> {
protected:
WiFiClient(ClientContext* client);
public:
WiFiClient();
virtual ~WiFiClient();
WiFiClient(const WiFiClient&);
WiFiClient& operator=(const WiFiClient&);
// b/c this is both a real class and a virtual parent of the secure client, make sure
// there's a safe way to copy from the pointer without 'slicing' it; i.e. only the base
// portion of a derived object will be copied, and the polymorphic behavior will be corrupted.
//
// this class still implements the copy and assignment though, so this is not yet enforced
// (but, *should* be inside the Core itself, see httpclient & server)
//
// ref.
// - https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-copy-virtual
// - https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rh-copy
virtual std::unique_ptr<WiFiClient> clone() const;
virtual uint8_t status();
virtual int connect(IPAddress ip, uint16_t port) override;
virtual int connect(const char *host, uint16_t port) override;
virtual int connect(const String& host, uint16_t port);
virtual size_t write(uint8_t) override;
virtual size_t write(const uint8_t *buf, size_t size) override;
//size_t write(Stream& stream);
virtual int available() override;
virtual int read() override;
virtual int read(uint8_t* buf, size_t size) override;
int read(char* buf, size_t size);
virtual int peek() override;
virtual size_t peekBytes(uint8_t *buffer, size_t length);
size_t peekBytes(char *buffer, size_t length) {
return peekBytes((uint8_t *) buffer, length);
}
virtual void flush() override {
(void)flush(0); // wait for all outgoing characters to be sent, output buffer should be empty after this call
}
virtual void stop() override {
(void)stop(0);
}
bool flush(unsigned int maxWaitMs);
bool stop(unsigned int maxWaitMs);
virtual uint8_t connected() override;
virtual operator bool() override;
IPAddress remoteIP();
uint16_t remotePort();
IPAddress localIP();
uint16_t localPort();
static void setLocalPortStart(uint16_t port) {
_localPort = port;
}
int availableForWrite() override;
friend class WiFiServer;
using Print::write;
static void stopAll();
static void stopAllExcept(WiFiClient * c);
void keepAlive(uint16_t idle_sec = TCP_DEFAULT_KEEPALIVE_IDLE_SEC, uint16_t intv_sec = TCP_DEFAULT_KEEPALIVE_INTERVAL_SEC, uint8_t count = TCP_DEFAULT_KEEPALIVE_COUNT);
bool isKeepAliveEnabled() const;
uint16_t getKeepAliveIdle() const;
uint16_t getKeepAliveInterval() const;
uint8_t getKeepAliveCount() const;
void disableKeepAlive() {
keepAlive(0, 0, 0);
}
// default NoDelay=False (Nagle=True=!NoDelay)
// Nagle is for shortly delaying outgoing data, to send less/bigger packets
// Nagle should be disabled for telnet-like/interactive streams
// Nagle is meaningless/ignored when Sync=true
static void setDefaultNoDelay(bool noDelay);
static bool getDefaultNoDelay();
bool getNoDelay() const;
void setNoDelay(bool nodelay);
// default Sync=false
// When sync is true, all writes are automatically flushed.
// This is slower but also does not allocate
// temporary memory for sending data
static void setDefaultSync(bool sync);
static bool getDefaultSync();
bool getSync() const;
void setSync(bool sync);
// peek buffer API is present
//virtual bool hasPeekBufferAPI () const override;
// return number of byte accessible by peekBuffer()
//virtual size_t peekAvailable () override;
// return a pointer to available data buffer (size = peekAvailable())
// semantic forbids any kind of read() before calling peekConsume()
//virtual const char* peekBuffer () override;
// consume bytes after use (see peekBuffer)
//virtual void peekConsume (size_t consume) override;
//virtual bool outputCanTimeout () override { return connected(); }
//virtual bool inputCanTimeout () override { return connected(); }
protected:
static int8_t _s_connected(void* arg, void* tpcb, int8_t err);
static void _s_err(void* arg, int8_t err);
int8_t _connected(void* tpcb, int8_t err);
void _err(int8_t err);
ClientContext* _client;
WiFiClient* _owned;
static uint16_t _localPort;
};

View file

@ -0,0 +1,220 @@
/*
WiFiServer.cpp - TCP/IP server for esp8266, mostly compatible
with Arduino WiFi shield library
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
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
*/
#include "WiFi.h"
#include "lwip/opt.h"
#include "lwip/tcp.h"
#include "lwip/inet.h"
#include <include/ClientContext.h>
#ifndef MAX_PENDING_CLIENTS_PER_PORT
#define MAX_PENDING_CLIENTS_PER_PORT 5
#endif
WiFiServer::WiFiServer(const IPAddress& addr, uint16_t port)
: _port(port)
, _addr(addr) {
}
WiFiServer::WiFiServer(uint16_t port)
: _port(port)
, _addr(IP_ANY_TYPE) {
}
void WiFiServer::begin() {
begin(_port);
}
void WiFiServer::begin(uint16_t port) {
return begin(port, MAX_PENDING_CLIENTS_PER_PORT);
}
void WiFiServer::begin(uint16_t port, uint8_t backlog) {
close();
if (!backlog) {
return;
}
_port = port;
LWIPMutex m; // Block the timer sys_check_timeouts call
tcp_pcb* pcb = tcp_new();
if (!pcb) {
return;
}
pcb->so_options |= SOF_REUSEADDR;
// (IPAddress _addr) operator-converted to (const ip_addr_t*)
if (tcp_bind(pcb, _addr, _port) != ERR_OK) {
tcp_close(pcb);
return;
}
tcp_pcb* listen_pcb = tcp_listen_with_backlog(pcb, backlog);
if (!listen_pcb) {
tcp_close(pcb);
return;
}
_listen_pcb = listen_pcb;
_port = _listen_pcb->local_port;
tcp_accept(listen_pcb, &WiFiServer::_s_accept);
tcp_arg(listen_pcb, (void*) this);
}
void WiFiServer::setNoDelay(bool nodelay) {
_noDelay = nodelay ? _ndTrue : _ndFalse;
}
bool WiFiServer::getNoDelay() {
switch (_noDelay) {
case _ndFalse: return false;
case _ndTrue: return true;
default: return WiFiClient::getDefaultNoDelay();
}
}
bool WiFiServer::hasClient() {
if (_unclaimed) {
return true;
}
return false;
}
size_t WiFiServer::hasClientData() {
ClientContext *next = _unclaimed;
while (next) {
size_t s = next->getSize();
// return the amount of data available from the first connection that has any
if (s) {
return s;
}
next = next->next();
}
return 0;
}
bool WiFiServer::hasMaxPendingClients() {
#if TCP_LISTEN_BACKLOG
return ((struct tcp_pcb_listen *)_listen_pcb)->accepts_pending >= MAX_PENDING_CLIENTS_PER_PORT;
#else
return false;
#endif
}
WiFiClient WiFiServer::available(byte* status) {
(void) status;
return accept();
}
WiFiClient WiFiServer::accept() {
if (_unclaimed) {
WiFiClient result(_unclaimed);
// pcb can be null when peer has already closed the connection
if (_unclaimed->getPCB()) {
LWIPMutex m; // Block the timer sys_check_timeouts call
// give permission to lwIP to accept one more peer
tcp_backlog_accepted(_unclaimed->getPCB());
}
_unclaimed = _unclaimed->next();
result.setNoDelay(getNoDelay());
DEBUGV("WS:av status=%d WCav=%d\r\n", result.status(), result.available());
return result;
}
return WiFiClient();
}
uint8_t WiFiServer::status() {
if (!_listen_pcb) {
return CLOSED;
}
return _listen_pcb->state;
}
uint16_t WiFiServer::port() const {
return _port;
}
void WiFiServer::close() {
if (!_listen_pcb) {
return;
}
LWIPMutex m; // Block the timer sys_check_timeouts call
tcp_close(_listen_pcb);
_listen_pcb = nullptr;
}
void WiFiServer::stop() {
close();
}
template<typename T>
T* slist_append_tail(T* head, T* item) {
if (!head) {
return item;
}
T* last = head;
while (last->next()) {
last = last->next();
}
last->next(item);
return head;
}
err_t WiFiServer::_accept(tcp_pcb* apcb, err_t err) {
(void) err;
DEBUGV("WS:ac\r\n");
// always accept new PCB so incoming data can be stored in our buffers even before
// user calls ::available()
ClientContext* client = new ClientContext(apcb, &WiFiServer::_s_discard, this);
// backlog doc:
// http://lwip.100.n7.nabble.com/Problem-re-opening-listening-pbc-tt32484.html#a32494
// https://www.nongnu.org/lwip/2_1_x/group__tcp__raw.html#gaeff14f321d1eecd0431611f382fcd338
// increase lwIP's backlog
LWIPMutex m; // Block the timer sys_check_timeouts call
tcp_backlog_delayed(apcb);
_unclaimed = slist_append_tail(_unclaimed, client);
return ERR_OK;
}
void WiFiServer::_discard(ClientContext* client) {
(void) client;
// _discarded = slist_append_tail(_discarded, client);
DEBUGV("WS:dis\r\n");
}
err_t WiFiServer::_s_accept(void *arg, tcp_pcb* newpcb, err_t err) {
return reinterpret_cast<WiFiServer*>(arg)->_accept(newpcb, err);
}
void WiFiServer::_s_discard(void* server, ClientContext* ctx) {
reinterpret_cast<WiFiServer*>(server)->_discard(ctx);
}

View file

@ -0,0 +1,109 @@
/*
WiFiServer.h - Library for Arduino Wifi shield.
Copyright (c) 2011-2014 Arduino LLC. All right reserved.
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
Modified by Ivan Grokhotkov, December 2014 - esp8266 support
*/
#pragma once
#include <wl_definitions.h>
struct tcp_pcb;
#include <LWIPMutex.h>
#include <Server.h>
#include <IPAddress.h>
#include <lwip/err.h>
// lwIP-v2 backlog facility allows to keep memory safe by limiting the
// maximum number of incoming *pending clients*. Default number of possibly
// simultaneously pending clients is defined in WiFiServer.cpp
// (MAX_PENDING_CLIENTS_PER_PORT=5). User can override it at runtime from
// sketch:
// WiFiServer::begin(port, max-simultaneous-pending-clients);
//
// An "incoming pending" client is a new incoming TCP connection trying to
// reach the TCP server. It is "pending" until lwIP acknowledges it and
// "accepted / no more pending" when user calls WiFiServer::available().
//
// Before the backlog feature or with lwIP-v1.4, there was no pending
// connections: They were immediately accepted and filling RAM.
//
// Several pending clients can appear during the time when one client is
// served by a long not-async service like ESP8266WebServer. During that
// time WiFiServer::available() cannot be called.
//
// Note: This *does not limit* the number of *simultaneously accepted
// clients*. Such limit management is left to the user.
//
// Thus, when the maximum number of pending connections is reached, new
// connections are delayed.
// By "delayed", it is meant that WiFiServer(lwIP) will not answer to the
// SYN packet until there is room for a new one: The TCP server on that port
// will be mute. The TCP client will regularly try to connect until success
// or a timeout occurs (72s on windows).
//
// When user calls WiFiServer::available(), the tcp server stops muting and
// answers to newcomers (until the "backlog" pending list is full again).
class ClientContext;
class WiFiClient;
class WiFiServer {
// Secure server needs access to all the private entries here
protected:
uint16_t _port;
IPAddress _addr;
tcp_pcb* _listen_pcb = nullptr;
ClientContext* _unclaimed = nullptr;
ClientContext* _discarded = nullptr;
enum { _ndDefault, _ndFalse, _ndTrue } _noDelay = _ndDefault;
public:
WiFiServer(const IPAddress& addr, uint16_t port);
WiFiServer(uint16_t port);
virtual ~WiFiServer() {}
WiFiClient accept(); // https://www.arduino.cc/en/Reference/EthernetServerAccept
WiFiClient available(uint8_t* status = NULL);
bool hasClient();
// hasClientData():
// returns the amount of data available from the first client
// or 0 if there is none
size_t hasClientData();
// hasMaxPendingClients():
// returns true if the queue of pending clients is full
bool hasMaxPendingClients();
void begin();
void begin(uint16_t port);
void begin(uint16_t port, uint8_t backlog);
void setNoDelay(bool nodelay);
bool getNoDelay();
uint8_t status();
uint16_t port() const;
void close();
void stop();
using ClientType = WiFiClient;
protected:
err_t _accept(tcp_pcb* newpcb, err_t err);
void _discard(ClientContext* client);
static err_t _s_accept(void *arg, tcp_pcb* newpcb, err_t err);
static void _s_discard(void* server, ClientContext* ctx);
};

View file

@ -0,0 +1,263 @@
/*
WiFiUdp.cpp - UDP client/server for esp8266, mostly compatible
with Arduino WiFi shield library
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
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
*/
#include <functional>
#include "wl_definitions.h"
//#include "debug.h"
#include "WiFi.h"
#include "WiFiUdp.h"
#include "lwip/opt.h"
#include "lwip/udp.h"
#include "lwip/inet.h"
#include "lwip/igmp.h"
#include "lwip/mem.h"
#include <include/UdpContext.h>
template<>
WiFiUDP* SList<WiFiUDP>::_s_first = 0;
/* Constructor */
WiFiUDP::WiFiUDP() : _ctx(0) {
WiFiUDP::_add(this);
}
WiFiUDP::WiFiUDP(const WiFiUDP& other) {
_ctx = other._ctx;
if (_ctx) {
_ctx->ref();
}
WiFiUDP::_add(this);
}
WiFiUDP& WiFiUDP::operator=(const WiFiUDP& rhs) {
_ctx = rhs._ctx;
if (_ctx) {
_ctx->ref();
}
return *this;
}
WiFiUDP::~WiFiUDP() {
WiFiUDP::_remove(this);
if (_ctx) {
_ctx->unref();
}
}
/* Start WiFiUDP socket, listening at local port */
uint8_t WiFiUDP::begin(uint16_t port) {
if (_ctx) {
_ctx->unref();
_ctx = 0;
}
_ctx = new UdpContext;
_ctx->ref();
return (_ctx->listen(IPAddress(), port)) ? 1 : 0;
}
uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port) {
if (_ctx) {
_ctx->unref();
_ctx = 0;
}
if (igmp_joingroup(interfaceAddr, multicast) != ERR_OK) {
return 0;
}
_ctx = new UdpContext;
_ctx->ref();
ip_addr_t addr = IPADDR4_INIT(INADDR_ANY);
if (!_ctx->listen(&addr, port)) {
return 0;
}
return 1;
}
/* return number of bytes available in the current packet,
will return zero if parsePacket hasn't been called yet */
int WiFiUDP::available() {
int result = 0;
if (_ctx) {
result = static_cast<int>(_ctx->getSize());
}
if (!result) {
// yielding here will not make more data "available",
// but it will prevent the system from going into WDT reset
delay(1);
}
return result;
}
/* Release any resources being used by this WiFiUDP instance */
void WiFiUDP::stop() {
if (_ctx) {
_ctx->disconnect();
_ctx->unref();
}
_ctx = 0;
}
int WiFiUDP::beginPacket(const char *host, uint16_t port) {
IPAddress remote_addr;
if (WiFi.hostByName(host, remote_addr)) {
return beginPacket(remote_addr, port);
}
return 0;
}
int WiFiUDP::beginPacket(IPAddress ip, uint16_t port) {
if (!_ctx) {
_ctx = new UdpContext;
_ctx->ref();
}
return (_ctx->connect(ip, port)) ? 1 : 0;
}
int WiFiUDP::beginPacketMulticast(IPAddress multicastAddress, uint16_t port,
IPAddress interfaceAddress, int ttl) {
if (!_ctx) {
_ctx = new UdpContext;
_ctx->ref();
}
if (!_ctx->connect(multicastAddress, port)) {
return 0;
}
_ctx->setMulticastInterface(interfaceAddress);
_ctx->setMulticastTTL(ttl);
return 1;
}
int WiFiUDP::endPacket() {
if (!_ctx) {
return 0;
}
return (_ctx->send()) ? 1 : 0;
}
size_t WiFiUDP::write(uint8_t byte) {
return write(&byte, 1);
}
size_t WiFiUDP::write(const uint8_t *buffer, size_t size) {
if (!_ctx) {
return 0;
}
return _ctx->append(reinterpret_cast<const char*>(buffer), size);
}
int WiFiUDP::parsePacket() {
if (!_ctx) {
return 0;
}
if (!_ctx->next()) {
return 0;
}
return _ctx->getSize();
}
int WiFiUDP::read() {
if (!_ctx) {
return -1;
}
return _ctx->read();
}
int WiFiUDP::read(unsigned char* buffer, size_t len) {
if (!_ctx) {
return 0;
}
return _ctx->read(reinterpret_cast<char*>(buffer), len);
}
int WiFiUDP::peek() {
if (!_ctx) {
return -1;
}
return _ctx->peek();
}
void WiFiUDP::flush() {
endPacket();
}
IPAddress WiFiUDP::remoteIP() {
if (!_ctx) {
return INADDR_ANY;
}
return _ctx->getRemoteAddress();
}
uint16_t WiFiUDP::remotePort() {
if (!_ctx) {
return 0;
}
return _ctx->getRemotePort();
}
IPAddress WiFiUDP::destinationIP() const {
if (!_ctx) {
return INADDR_ANY;
}
return _ctx->getDestAddress();
}
uint16_t WiFiUDP::localPort() const {
if (!_ctx) {
return 0;
}
return _ctx->getLocalPort();
}
void WiFiUDP::stopAll() {
for (WiFiUDP* it = _s_first; it; it = it->_next) {
DEBUGV("%s %p %p\n", __func__, it, _s_first);
it->stop();
}
}
void WiFiUDP::stopAllExcept(WiFiUDP * exC) {
for (WiFiUDP* it = _s_first; it; it = it->_next) {
if (it->_ctx != exC->_ctx) {
DEBUGV("%s %p %p\n", __func__, it, _s_first);
it->stop();
}
}
}

View file

@ -0,0 +1,113 @@
/*
WiFiUdp.h - Library for Arduino Wifi shield.
Copyright (c) 2011-2014 Arduino LLC. All right reserved.
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
Modified by Ivan Grokhotkov, January 2015 - esp8266 support
*/
#pragma once
#include <Udp.h>
#include <include/slist.h>
#define UDP_TX_PACKET_MAX_SIZE 8192
class UdpContext;
class WiFiUDP : public UDP, public SList<WiFiUDP> {
private:
UdpContext* _ctx;
public:
WiFiUDP(); // Constructor
WiFiUDP(const WiFiUDP& other);
WiFiUDP& operator=(const WiFiUDP& rhs);
virtual ~WiFiUDP();
operator bool() const {
return _ctx != 0;
}
// initialize, start listening on specified port.
// Returns 1 if successful, 0 if there are no sockets available to use
uint8_t begin(uint16_t port) override;
// Finish with the UDP connection
void stop() override;
// join a multicast group and listen on the given port
uint8_t beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port);
// Sending UDP packets
// Start building up a packet to send to the remote host specific in ip and port
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
int beginPacket(IPAddress ip, uint16_t port) override;
// Start building up a packet to send to the remote host specific in host and port
// Returns 1 if successful, 0 if there was a problem resolving the hostname or port
int beginPacket(const char *host, uint16_t port) override;
// Start building up a packet to send to the multicast address
// multicastAddress - multicast address to send to
// interfaceAddress - the local IP address of the interface that should be used
// use WiFi.localIP() or WiFi.softAPIP() depending on the interface you need
// ttl - multicast packet TTL (default is 1)
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
virtual int beginPacketMulticast(IPAddress multicastAddress,
uint16_t port,
IPAddress interfaceAddress,
int ttl = 1);
// Finish off this packet and send it
// Returns 1 if the packet was sent successfully, 0 if there was an error
int endPacket() override;
// Write a single byte into the packet
size_t write(uint8_t) override;
// Write size bytes from buffer into the packet
size_t write(const uint8_t *buffer, size_t size) override;
using Print::write;
// Start processing the next available incoming packet
// Returns the size of the packet in bytes, or 0 if no packets are available
int parsePacket() override;
// Number of bytes remaining in the current packet
int available() override;
// Read a single byte from the current packet
int read() override;
// Read up to len bytes from the current packet and place them into buffer
// Returns the number of bytes read, or 0 if none are available
int read(unsigned char* buffer, size_t len) override;
// Read up to len characters from the current packet and place them into buffer
// Returns the number of characters read, or 0 if none are available
int read(char* buffer, size_t len) override {
return read((unsigned char*)buffer, len);
};
// Return the next byte from the current packet without moving on to the next byte
int peek() override;
void flush() override; // wait for all outgoing characters to be sent, output buffer is empty after this call
// Return the IP address of the host who sent the current incoming packet
IPAddress remoteIP() override;
// Return the port of the host who sent the current incoming packet
uint16_t remotePort() override;
// Return the destination address for incoming packets,
// useful to distinguish multicast and ordinary packets
IPAddress destinationIP() const;
// Return the local port for outgoing packets
uint16_t localPort() const;
static void stopAll();
static void stopAllExcept(WiFiUDP * exC);
};

View file

@ -0,0 +1,300 @@
/*
This file is part of the MicroPython project, http://micropython.org/
The MIT License (MIT)
Copyright (c) 2018-2019 Damien P. George
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// For DHCP specs see:
// https://www.ietf.org/rfc/rfc2131.txt
// https://tools.ietf.org/html/rfc2132 -- DHCP Options and BOOTP Vendor Extensions
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "cyw43_config.h"
#include "dhcpserver.h"
#include "lwip/udp.h"
#define DHCPDISCOVER (1)
#define DHCPOFFER (2)
#define DHCPREQUEST (3)
#define DHCPDECLINE (4)
#define DHCPACK (5)
#define DHCPNACK (6)
#define DHCPRELEASE (7)
#define DHCPINFORM (8)
#define DHCP_OPT_PAD (0)
#define DHCP_OPT_SUBNET_MASK (1)
#define DHCP_OPT_ROUTER (3)
#define DHCP_OPT_DNS (6)
#define DHCP_OPT_HOST_NAME (12)
#define DHCP_OPT_REQUESTED_IP (50)
#define DHCP_OPT_IP_LEASE_TIME (51)
#define DHCP_OPT_MSG_TYPE (53)
#define DHCP_OPT_SERVER_ID (54)
#define DHCP_OPT_PARAM_REQUEST_LIST (55)
#define DHCP_OPT_MAX_MSG_SIZE (57)
#define DHCP_OPT_VENDOR_CLASS_ID (60)
#define DHCP_OPT_CLIENT_ID (61)
#define DHCP_OPT_END (255)
#define PORT_DHCP_SERVER (67)
#define PORT_DHCP_CLIENT (68)
#define DEFAULT_DNS MAKE_IP4(8, 8, 8, 8)
#define DEFAULT_LEASE_TIME_S (24 * 60 * 60) // in seconds
#define MAC_LEN (6)
#define MAKE_IP4(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
typedef struct {
uint8_t op; // message opcode
uint8_t htype; // hardware address type
uint8_t hlen; // hardware address length
uint8_t hops;
uint32_t xid; // transaction id, chosen by client
uint16_t secs; // client seconds elapsed
uint16_t flags;
uint8_t ciaddr[4]; // client IP address
uint8_t yiaddr[4]; // your IP address
uint8_t siaddr[4]; // next server IP address
uint8_t giaddr[4]; // relay agent IP address
uint8_t chaddr[16]; // client hardware address
uint8_t sname[64]; // server host name
uint8_t file[128]; // boot file name
uint8_t options[312]; // optional parameters, variable, starts with magic
} dhcp_msg_t;
static int dhcp_socket_new_dgram(struct udp_pcb **udp, void *cb_data, udp_recv_fn cb_udp_recv) {
// family is AF_INET
// type is SOCK_DGRAM
*udp = udp_new();
if (*udp == NULL) {
return -ENOMEM;
}
// Register callback
udp_recv(*udp, cb_udp_recv, (void *)cb_data);
return 0; // success
}
static void dhcp_socket_free(struct udp_pcb **udp) {
if (*udp != NULL) {
udp_remove(*udp);
*udp = NULL;
}
}
static int dhcp_socket_bind(struct udp_pcb **udp, uint32_t ip, uint16_t port) {
ip_addr_t addr;
IP_ADDR4(&addr, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff);
// TODO convert lwIP errors to errno
return udp_bind(*udp, &addr, port);
}
static int dhcp_socket_sendto(struct udp_pcb **udp, const void *buf, size_t len, uint32_t ip, uint16_t port) {
if (len > 0xffff) {
len = 0xffff;
}
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
if (p == NULL) {
return -ENOMEM;
}
memcpy(p->payload, buf, len);
ip_addr_t dest;
IP_ADDR4(&dest, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff);
err_t err = udp_sendto(*udp, p, &dest, port);
pbuf_free(p);
if (err != ERR_OK) {
return err;
}
return len;
}
static uint8_t *opt_find(uint8_t *opt, uint8_t cmd) {
for (int i = 0; i < 308 && opt[i] != DHCP_OPT_END;) {
if (opt[i] == cmd) {
return &opt[i];
}
i += 2 + opt[i + 1];
}
return NULL;
}
static void opt_write_n(uint8_t **opt, uint8_t cmd, size_t n, void *data) {
uint8_t *o = *opt;
*o++ = cmd;
*o++ = n;
memcpy(o, data, n);
*opt = o + n;
}
static void opt_write_u8(uint8_t **opt, uint8_t cmd, uint8_t val) {
uint8_t *o = *opt;
*o++ = cmd;
*o++ = 1;
*o++ = val;
*opt = o;
}
static void opt_write_u32(uint8_t **opt, uint8_t cmd, uint32_t val) {
uint8_t *o = *opt;
*o++ = cmd;
*o++ = 4;
*o++ = val >> 24;
*o++ = val >> 16;
*o++ = val >> 8;
*o++ = val;
*opt = o;
}
static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *src_addr, u16_t src_port) {
dhcp_server_t *d = arg;
(void)upcb;
(void)src_addr;
(void)src_port;
// This is around 548 bytes
dhcp_msg_t dhcp_msg;
#define DHCP_MIN_SIZE (240 + 3)
if (p->tot_len < DHCP_MIN_SIZE) {
goto ignore_request;
}
size_t len = pbuf_copy_partial(p, &dhcp_msg, sizeof(dhcp_msg), 0);
if (len < DHCP_MIN_SIZE) {
goto ignore_request;
}
dhcp_msg.op = DHCPOFFER;
memcpy(&dhcp_msg.yiaddr, ip_2_ip4(&d->ip), 4);
uint8_t *opt = (uint8_t *)&dhcp_msg.options;
opt += 4; // assume magic cookie: 99, 130, 83, 99
switch (opt[2]) {
case DHCPDISCOVER: {
int yi = DHCPS_MAX_IP;
for (int i = 0; i < DHCPS_MAX_IP; ++i) {
if (memcmp(d->lease[i].mac, dhcp_msg.chaddr, MAC_LEN) == 0) {
// MAC match, use this IP address
yi = i;
break;
}
if (yi == DHCPS_MAX_IP) {
// Look for a free IP address
if (memcmp(d->lease[i].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) {
// IP available
yi = i;
}
uint32_t expiry = d->lease[i].expiry << 16 | 0xffff;
if ((int32_t)(expiry - cyw43_hal_ticks_ms()) < 0) {
// IP expired, reuse it
memset(d->lease[i].mac, 0, MAC_LEN);
yi = i;
}
}
}
if (yi == DHCPS_MAX_IP) {
// No more IP addresses left
goto ignore_request;
}
dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi;
opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPOFFER);
break;
}
case DHCPREQUEST: {
uint8_t *o = opt_find(opt, DHCP_OPT_REQUESTED_IP);
if (o == NULL) {
// Should be NACK
goto ignore_request;
}
if (memcmp(o + 2, ip_2_ip4(&d->ip), 3) != 0) {
// Should be NACK
goto ignore_request;
}
uint8_t yi = o[5] - DHCPS_BASE_IP;
if (yi >= DHCPS_MAX_IP) {
// Should be NACK
goto ignore_request;
}
if (memcmp(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN) == 0) {
// MAC match, ok to use this IP address
} else if (memcmp(d->lease[yi].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) {
// IP unused, ok to use this IP address
memcpy(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN);
} else {
// IP already in use
// Should be NACK
goto ignore_request;
}
d->lease[yi].expiry = (cyw43_hal_ticks_ms() + DEFAULT_LEASE_TIME_S * 1000) >> 16;
dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi;
opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPACK);
/* printf("DHCPS: client connected: MAC=%02x:%02x:%02x:%02x:%02x:%02x IP=%u.%u.%u.%u\n",
dhcp_msg.chaddr[0], dhcp_msg.chaddr[1], dhcp_msg.chaddr[2], dhcp_msg.chaddr[3], dhcp_msg.chaddr[4], dhcp_msg.chaddr[5],
dhcp_msg.yiaddr[0], dhcp_msg.yiaddr[1], dhcp_msg.yiaddr[2], dhcp_msg.yiaddr[3]);*/
break;
}
default:
goto ignore_request;
}
opt_write_n(&opt, DHCP_OPT_SERVER_ID, 4, ip_2_ip4(&d->ip));
opt_write_n(&opt, DHCP_OPT_SUBNET_MASK, 4, ip_2_ip4(&d->nm));
opt_write_n(&opt, DHCP_OPT_ROUTER, 4, ip_2_ip4(&d->ip)); // aka gateway; can have multiple addresses
opt_write_u32(&opt, DHCP_OPT_DNS, DEFAULT_DNS); // can have multiple addresses
opt_write_u32(&opt, DHCP_OPT_IP_LEASE_TIME, DEFAULT_LEASE_TIME_S);
*opt++ = DHCP_OPT_END;
dhcp_socket_sendto(&d->udp, &dhcp_msg, opt - (uint8_t *)&dhcp_msg, 0xffffffff, PORT_DHCP_CLIENT);
ignore_request:
pbuf_free(p);
}
void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm) {
ip_addr_copy(d->ip, *ip);
ip_addr_copy(d->nm, *nm);
memset(d->lease, 0, sizeof(d->lease));
if (dhcp_socket_new_dgram(&d->udp, d, dhcp_server_process) != 0) {
return;
}
dhcp_socket_bind(&d->udp, 0, PORT_DHCP_SERVER);
}
void dhcp_server_deinit(dhcp_server_t *d) {
dhcp_socket_free(&d->udp);
}

View file

@ -0,0 +1,57 @@
/*
This file is part of the MicroPython project, http://micropython.org/
The MIT License (MIT)
Copyright (c) 2018-2019 Damien P. George
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H
#define MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "lwip/ip_addr.h"
#define DHCPS_BASE_IP (16)
#define DHCPS_MAX_IP (8)
typedef struct _dhcp_server_lease_t {
uint8_t mac[6];
uint16_t expiry;
} dhcp_server_lease_t;
typedef struct _dhcp_server_t {
ip_addr_t ip;
ip_addr_t nm;
dhcp_server_lease_t lease[DHCPS_MAX_IP];
struct udp_pcb *udp;
} dhcp_server_t;
void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm);
void dhcp_server_deinit(dhcp_server_t *d);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H

View file

@ -0,0 +1,687 @@
/*
ClientContext.h - TCP connection handling on top of lwIP
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
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
class ClientContext;
class WiFiClient;
typedef void (*discard_cb_t)(void*, ClientContext*);
#include <assert.h>
//#include <esp_priv.h>
//#include <coredecls.h>
bool getDefaultPrivateGlobalSyncValue();
template <typename T>
inline void esp_delay(const uint32_t timeout_ms, T&& blocked, const uint32_t intvl_ms) {
const auto start_ms = millis();
while ((((uint32_t)millis() - start_ms) < timeout_ms) && blocked()) {
delay(intvl_ms);
}
}
class ClientContext {
public:
ClientContext(tcp_pcb* pcb, discard_cb_t discard_cb, void* discard_cb_arg) :
_pcb(pcb), _rx_buf(0), _rx_buf_offset(0), _discard_cb(discard_cb), _discard_cb_arg(discard_cb_arg), _refcnt(0), _next(0),
_sync(::getDefaultPrivateGlobalSyncValue()) {
tcp_setprio(_pcb, TCP_PRIO_MIN);
tcp_arg(_pcb, this);
tcp_recv(_pcb, &_s_recv);
tcp_sent(_pcb, &_s_acked);
tcp_err(_pcb, &_s_error);
tcp_poll(_pcb, &_s_poll, 1);
// keep-alive not enabled by default
//keepAlive();
}
tcp_pcb* getPCB() {
return _pcb;
}
err_t abort() {
if (_pcb) {
DEBUGV(":abort\r\n");
tcp_arg(_pcb, NULL);
tcp_sent(_pcb, NULL);
tcp_recv(_pcb, NULL);
tcp_err(_pcb, NULL);
tcp_poll(_pcb, NULL, 0);
LWIPMutex m; // Block the timer sys_check_timeouts call
tcp_abort(_pcb);
_pcb = nullptr;
}
return ERR_ABRT;
}
err_t close() {
err_t err = ERR_OK;
if (_pcb) {
DEBUGV(":close\r\n");
tcp_arg(_pcb, NULL);
tcp_sent(_pcb, NULL);
tcp_recv(_pcb, NULL);
tcp_err(_pcb, NULL);
tcp_poll(_pcb, NULL, 0);
LWIPMutex m; // Block the timer sys_check_timeouts call
err = tcp_close(_pcb);
if (err != ERR_OK) {
DEBUGV(":tc err %d\r\n", (int) err);
tcp_abort(_pcb);
err = ERR_ABRT;
}
_pcb = nullptr;
}
return err;
}
~ClientContext() {
}
ClientContext* next() const {
return _next;
}
ClientContext* next(ClientContext* new_next) {
_next = new_next;
return _next;
}
void ref() {
++_refcnt;
DEBUGV(":ref %d\r\n", _refcnt);
}
void unref() {
DEBUGV(":ur %d\r\n", _refcnt);
if (--_refcnt == 0) {
discard_received();
close();
if (_discard_cb) {
_discard_cb(_discard_cb_arg, this);
}
DEBUGV(":del\r\n");
delete this;
}
}
int connect(ip_addr_t* addr, uint16_t port) {
// note: not using `const ip_addr_t* addr` because
// - `ip6_addr_assign_zone()` below modifies `*addr`
// - caller's parameter `WiFiClient::connect` is a local copy
#if LWIP_IPV6
// Set zone so that link local addresses use the default interface
if (IP_IS_V6(addr) && ip6_addr_lacks_zone(ip_2_ip6(addr), IP6_UNKNOWN)) {
ip6_addr_assign_zone(ip_2_ip6(addr), IP6_UNKNOWN, netif_default);
}
#endif
LWIPMutex m; // Block the timer sys_check_timeouts call
err_t err = tcp_connect(_pcb, addr, port, &ClientContext::_s_connected);
if (err != ERR_OK) {
return 0;
}
_connect_pending = true;
_op_start_time = millis();
// will resume on timeout or when _connected or _notify_error fires
// give scheduled functions a chance to run (e.g. Ethernet uses recurrent)
esp_delay(_timeout_ms, [this]() {
return this->_connect_pending;
}, 1);
_connect_pending = false;
if (!_pcb) {
DEBUGV(":cabrt\r\n");
return 0;
}
if (state() != ESTABLISHED) {
DEBUGV(":ctmo\r\n");
abort();
return 0;
}
return 1;
}
size_t availableForWrite() const {
LWIPMutex m; // Block the timer sys_check_timeouts call
return _pcb ? tcp_sndbuf(_pcb) : 0;
}
void setNoDelay(bool nodelay) {
if (!_pcb) {
return;
}
LWIPMutex m; // Block the timer sys_check_timeouts call
if (nodelay) {
tcp_nagle_disable(_pcb);
} else {
tcp_nagle_enable(_pcb);
}
}
bool getNoDelay() const {
if (!_pcb) {
return false;
}
LWIPMutex m; // Block the timer sys_check_timeouts call
return tcp_nagle_disabled(_pcb);
}
void setTimeout(int timeout_ms) {
_timeout_ms = timeout_ms;
}
int getTimeout() const {
return _timeout_ms;
}
const ip_addr_t* getRemoteAddress() const {
if (!_pcb) {
return 0;
}
return &_pcb->remote_ip;
}
uint16_t getRemotePort() const {
if (!_pcb) {
return 0;
}
return _pcb->remote_port;
}
const ip_addr_t* getLocalAddress() const {
if (!_pcb) {
return 0;
}
return &_pcb->local_ip;
}
uint16_t getLocalPort() const {
if (!_pcb) {
return 0;
}
return _pcb->local_port;
}
size_t getSize() const {
if (!_rx_buf) {
return 0;
}
return _rx_buf->tot_len - _rx_buf_offset;
}
char read() {
if (!_rx_buf) {
return 0;
}
char c = reinterpret_cast<char*>(_rx_buf->payload)[_rx_buf_offset];
_consume(1);
return c;
}
size_t read(char* dst, size_t size) {
if (!_rx_buf) {
return 0;
}
size_t max_size = _rx_buf->tot_len - _rx_buf_offset;
size = (size < max_size) ? size : max_size;
DEBUGV(":rd %d, %d, %d\r\n", size, _rx_buf->tot_len, _rx_buf_offset);
size_t size_read = 0;
while (size) {
size_t buf_size = _rx_buf->len - _rx_buf_offset;
size_t copy_size = (size < buf_size) ? size : buf_size;
DEBUGV(":rdi %d, %d\r\n", buf_size, copy_size);
memcpy(dst, reinterpret_cast<char*>(_rx_buf->payload) + _rx_buf_offset, copy_size);
dst += copy_size;
_consume(copy_size);
size -= copy_size;
size_read += copy_size;
}
return size_read;
}
char peek() const {
if (!_rx_buf) {
return 0;
}
return reinterpret_cast<char*>(_rx_buf->payload)[_rx_buf_offset];
}
size_t peekBytes(char *dst, size_t size) const {
if (!_rx_buf) {
return 0;
}
size_t max_size = _rx_buf->tot_len - _rx_buf_offset;
size = (size < max_size) ? size : max_size;
DEBUGV(":pd %d, %d, %d\r\n", size, _rx_buf->tot_len, _rx_buf_offset);
size_t buf_size = _rx_buf->len - _rx_buf_offset;
size_t copy_size = (size < buf_size) ? size : buf_size;
DEBUGV(":rpi %d, %d\r\n", buf_size, copy_size);
memcpy(dst, reinterpret_cast<char*>(_rx_buf->payload) + _rx_buf_offset, copy_size);
return copy_size;
}
void discard_received() {
DEBUGV(":dsrcv %d\n", _rx_buf ? _rx_buf->tot_len : 0);
if (!_rx_buf) {
return;
}
LWIPMutex m; // Block the timer sys_check_timeouts call
if (_pcb) {
tcp_recved(_pcb, (size_t) _rx_buf->tot_len);
}
pbuf_free(_rx_buf);
_rx_buf = 0;
_rx_buf_offset = 0;
}
bool wait_until_acked(int max_wait_ms = WIFICLIENT_MAX_FLUSH_WAIT_MS) {
// https://github.com/esp8266/Arduino/pull/3967#pullrequestreview-83451496
// option 1 done
// option 2 / _write_some() not necessary since _datasource is always nullptr here
if (!_pcb) {
return true;
}
int prevsndbuf = -1;
// wait for peer's acks to flush lwIP's output buffer
uint32_t last_sent = millis();
while (1) {
if (millis() - last_sent > (uint32_t) max_wait_ms) {
#ifdef DEBUGV
// wait until sent: timeout
DEBUGV(":wustmo\n");
#endif
// All data was not flushed, timeout hit
return false;
}
LWIPMutex m; // Block the timer sys_check_timeouts call
// force lwIP to send what can be sent
tcp_output(_pcb);
int sndbuf = tcp_sndbuf(_pcb);
if (sndbuf != prevsndbuf) {
// send buffer has changed (or first iteration)
prevsndbuf = sndbuf;
// We just sent a bit, move timeout forward
last_sent = millis();
}
// esp_yield(); // from sys or os context
if ((state() != ESTABLISHED) || (sndbuf == TCP_SND_BUF)) {
// peer has closed or all bytes are sent and acked
// ((TCP_SND_BUF-sndbuf) is the amount of un-acked bytes)
break;
}
}
// All data flushed
return true;
}
uint8_t state() const {
if (!_pcb || _pcb->state == CLOSE_WAIT || _pcb->state == CLOSING) {
// CLOSED for WiFIClient::status() means nothing more can be written
return CLOSED;
}
return _pcb->state;
}
size_t write(const char* ds, const size_t dl) {
if (!_pcb) {
return 0;
}
return _write_from_source(ds, dl);
}
void keepAlive(uint16_t idle_sec = TCP_DEFAULT_KEEPALIVE_IDLE_SEC, uint16_t intv_sec = TCP_DEFAULT_KEEPALIVE_INTERVAL_SEC, uint8_t count = TCP_DEFAULT_KEEPALIVE_COUNT) {
if (idle_sec && intv_sec && count) {
_pcb->so_options |= SOF_KEEPALIVE;
_pcb->keep_idle = (uint32_t)1000 * idle_sec;
_pcb->keep_intvl = (uint32_t)1000 * intv_sec;
_pcb->keep_cnt = count;
} else {
_pcb->so_options &= ~SOF_KEEPALIVE;
}
}
bool isKeepAliveEnabled() const {
return !!(_pcb->so_options & SOF_KEEPALIVE);
}
uint16_t getKeepAliveIdle() const {
return isKeepAliveEnabled() ? (_pcb->keep_idle + 500) / 1000 : 0;
}
uint16_t getKeepAliveInterval() const {
return isKeepAliveEnabled() ? (_pcb->keep_intvl + 500) / 1000 : 0;
}
uint8_t getKeepAliveCount() const {
return isKeepAliveEnabled() ? _pcb->keep_cnt : 0;
}
bool getSync() const {
return _sync;
}
void setSync(bool sync) {
_sync = sync;
}
// return a pointer to available data buffer (size = peekAvailable())
// semantic forbids any kind of read() before calling peekConsume()
const char* peekBuffer() {
if (!_rx_buf) {
return nullptr;
}
return (const char*)_rx_buf->payload + _rx_buf_offset;
}
// return number of byte accessible by peekBuffer()
size_t peekAvailable() {
if (!_rx_buf) {
return 0;
}
return _rx_buf->len - _rx_buf_offset;
}
// consume bytes after use (see peekBuffer)
void peekConsume(size_t consume) {
_consume(consume);
}
protected:
bool _is_timeout() {
return millis() - _op_start_time > _timeout_ms;
}
void _notify_error() {
if (_connect_pending || _send_waiting) {
// resume connect or _write_from_source
_send_waiting = false;
_connect_pending = false;
//esp_schedule();
}
}
size_t _write_from_source(const char* ds, const size_t dl) {
assert(_datasource == nullptr);
assert(!_send_waiting);
_datasource = ds;
_datalen = dl;
_written = 0;
_op_start_time = millis();
do {
if (_write_some()) {
_op_start_time = millis();
}
if (_written == _datalen || _is_timeout() || state() == CLOSED) {
if (_is_timeout()) {
DEBUGV(":wtmo\r\n");
}
_datasource = nullptr;
_datalen = 0;
break;
}
_send_waiting = true;
// will resume on timeout or when _write_some_from_cb or _notify_error fires
// give scheduled functions a chance to run (e.g. Ethernet uses recurrent)
esp_delay(_timeout_ms, [this]() {
return this->_send_waiting;
}, 1);
_send_waiting = false;
} while (true);
if (_sync) {
wait_until_acked();
}
return _written;
}
bool _write_some() {
if (!_datasource || !_pcb) {
return false;
}
DEBUGV(":wr %d %d\r\n", _datalen - _written, _written);
bool has_written = false;
while (_written < _datalen) {
if (state() == CLOSED) {
return false;
}
const auto remaining = _datalen - _written;
size_t next_chunk_size;
{
LWIPMutex m; // Block the timer sys_check_timeouts call, just for this call
next_chunk_size = std::min((size_t)tcp_sndbuf(_pcb), remaining);
}
if (!next_chunk_size) {
break;
}
const char* buf = _datasource + _written;
uint8_t flags = 0;
if (next_chunk_size < remaining)
// PUSH is meant for peer, telling to give data to user app as soon as received
// PUSH "may be set" when sender has finished sending a "meaningful" data block
// PUSH does not break Nagle
// #5173: windows needs this flag
// more info: https://lists.gnu.org/archive/html/lwip-users/2009-11/msg00018.html
{
flags |= TCP_WRITE_FLAG_MORE; // do not tcp-PuSH (yet)
}
if (!_sync)
// user data must be copied when data are sent but not yet acknowledged
// (with sync, we wait for acknowledgment before returning to user)
{
flags |= TCP_WRITE_FLAG_COPY;
}
err_t err = tcp_write(_pcb, buf, next_chunk_size, flags);
DEBUGV(":wrc %d %d %d\r\n", next_chunk_size, remaining, (int)err);
if (err == ERR_OK) {
_written += next_chunk_size;
has_written = true;
} else {
// ERR_MEM(-1) is a valid error meaning
// "come back later". It leaves state() opened
break;
}
}
if (has_written) {
// lwIP's tcp_output doc: "Find out what we can send and send it"
// *with respect to Nagle*
// more info: https://lists.gnu.org/archive/html/lwip-users/2017-11/msg00134.html
LWIPMutex m; // Block the timer sys_check_timeouts call
tcp_output(_pcb);
}
return has_written;
}
void _write_some_from_cb() {
if (_send_waiting) {
// resume _write_from_source
_send_waiting = false;
//esp_schedule();
}
}
err_t _acked(tcp_pcb* pcb, uint16_t len) {
(void) pcb;
(void) len;
DEBUGV(":ack %d\r\n", len);
_write_some_from_cb();
return ERR_OK;
}
void _consume(size_t size) {
ptrdiff_t left = _rx_buf->len - _rx_buf_offset - size;
LWIPMutex m; // Block the timer sys_check_timeouts call
if (left > 0) {
_rx_buf_offset += size;
} else if (!_rx_buf->next) {
DEBUGV(":c0 %d, %d\r\n", size, _rx_buf->tot_len);
pbuf_free(_rx_buf);
_rx_buf = 0;
_rx_buf_offset = 0;
} else {
DEBUGV(":c %d, %d, %d\r\n", size, _rx_buf->len, _rx_buf->tot_len);
auto head = _rx_buf;
_rx_buf = _rx_buf->next;
_rx_buf_offset = 0;
pbuf_ref(_rx_buf);
pbuf_free(head);
}
if (_pcb) {
tcp_recved(_pcb, size);
}
}
err_t _recv(tcp_pcb* pcb, pbuf* pb, err_t err) {
(void) pcb;
(void) err;
if (pb == 0) {
// connection closed by peer
DEBUGV(":rcl pb=%p sz=%d\r\n", _rx_buf, _rx_buf ? _rx_buf->tot_len : -1);
_notify_error();
if (_rx_buf && _rx_buf->tot_len) {
// there is still something to read
return ERR_OK;
} else {
// nothing in receive buffer,
// peer closed = nothing can be written:
// closing in the legacy way
abort();
return ERR_ABRT;
}
}
if (_rx_buf) {
DEBUGV(":rch %d, %d\r\n", _rx_buf->tot_len, pb->tot_len);
LWIPMutex m; // Block the timer sys_check_timeouts call
pbuf_cat(_rx_buf, pb);
} else {
DEBUGV(":rn %d\r\n", pb->tot_len);
_rx_buf = pb;
_rx_buf_offset = 0;
}
return ERR_OK;
}
void _error(err_t err) {
(void) err;
DEBUGV(":er %d 0x%08x\r\n", (int) err, (uint32_t) _datasource);
tcp_arg(_pcb, NULL);
tcp_sent(_pcb, NULL);
tcp_recv(_pcb, NULL);
tcp_err(_pcb, NULL);
_pcb = nullptr;
_notify_error();
}
err_t _connected(struct tcp_pcb *pcb, err_t err) {
(void) err;
(void) pcb;
assert(pcb == _pcb);
if (_connect_pending) {
// resume connect
_connect_pending = false;
//esp_schedule();
}
return ERR_OK;
}
err_t _poll(tcp_pcb*) {
_write_some_from_cb();
return ERR_OK;
}
static err_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, err_t err) {
return reinterpret_cast<ClientContext*>(arg)->_recv(tpcb, pb, err);
}
static void _s_error(void *arg, err_t err) {
reinterpret_cast<ClientContext*>(arg)->_error(err);
}
static err_t _s_poll(void *arg, struct tcp_pcb *tpcb) {
return reinterpret_cast<ClientContext*>(arg)->_poll(tpcb);
}
static err_t _s_acked(void *arg, struct tcp_pcb *tpcb, uint16_t len) {
return reinterpret_cast<ClientContext*>(arg)->_acked(tpcb, len);
}
static err_t _s_connected(void* arg, struct tcp_pcb *pcb, err_t err) {
return reinterpret_cast<ClientContext*>(arg)->_connected(pcb, err);
}
private:
tcp_pcb* _pcb;
pbuf* _rx_buf;
size_t _rx_buf_offset;
discard_cb_t _discard_cb;
void* _discard_cb_arg;
const char* _datasource = nullptr;
size_t _datalen = 0;
size_t _written = 0;
uint32_t _timeout_ms = 5000;
uint32_t _op_start_time = 0;
bool _send_waiting = false;
bool _connect_pending = false;
int8_t _refcnt;
ClientContext* _next;
bool _sync;
};

View file

@ -0,0 +1,581 @@
/*
UdpContext.h - UDP connection handling on top of lwIP
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
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
*/
#ifndef UDPCONTEXT_H
#define UDPCONTEXT_H
class UdpContext;
extern "C" {
#include <assert.h>
}
#include <AddrList.h>
//#include <PolledTimeout.h>
#define PBUF_ALIGNER_ADJUST 4
#define PBUF_ALIGNER(x) ((void*)((((intptr_t)(x))+3)&~3))
#define PBUF_HELPER_FLAG 0xff // lwIP pbuf flag: u8_t
class UdpContext {
public:
typedef std::function<void(void)> rxhandler_t;
UdpContext()
: _pcb(0)
, _rx_buf(0)
, _first_buf_taken(false)
, _rx_buf_offset(0)
, _rx_buf_size(0)
, _refcnt(0)
, _tx_buf_head(0)
, _tx_buf_cur(0)
, _tx_buf_offset(0) {
_pcb = udp_new();
#ifdef LWIP_MAYBE_XCC
_mcast_ttl = 1;
#endif
}
~UdpContext() {
udp_remove(_pcb);
_pcb = 0;
if (_tx_buf_head) {
pbuf_free(_tx_buf_head);
_tx_buf_head = 0;
_tx_buf_cur = 0;
_tx_buf_offset = 0;
}
if (_rx_buf) {
pbuf_free(_rx_buf);
_rx_buf = 0;
_rx_buf_offset = 0;
_rx_buf_size = 0;
}
}
void ref() {
++_refcnt;
}
void unref() {
DEBUGV(":ur %d\r\n", _refcnt);
if (--_refcnt == 0) {
delete this;
}
}
bool connect(const IPAddress& addr, uint16_t port) {
_pcb->remote_ip = addr;
_pcb->remote_port = port;
#if LWIP_IPV6
// Set zone so that link local addresses use the default interface
if (IP_IS_V6(&_pcb->remote_ip) && ip6_addr_lacks_zone(ip_2_ip6(&_pcb->remote_ip), IP6_UNKNOWN)) {
ip6_addr_assign_zone(ip_2_ip6(&_pcb->remote_ip), IP6_UNKNOWN, netif_default);
}
#endif
return true;
}
bool listen(const IPAddress& addr, uint16_t port) {
udp_recv(_pcb, &_s_recv, (void *) this);
err_t err = udp_bind(_pcb, addr, port);
return err == ERR_OK;
}
void disconnect() {
udp_disconnect(_pcb);
}
#if LWIP_IPV6
void setMulticastInterface(IPAddress addr) {
// Per 'udp_set_multicast_netif_addr()' signature and comments
// in lwIP sources:
// An IPv4 address designating a specific interface must be used.
// When an IPv6 address is given, the matching IPv4 in the same
// interface must be selected.
if (!addr.isV4()) {
for (auto a : addrList)
if (a.addr() == addr) {
// found the IPv6 address,
// redirect parameter to IPv4 address in this interface
addr = a.ipv4();
break;
}
assert(addr.isV4());
}
udp_set_multicast_netif_addr(_pcb, ip_2_ip4((const ip_addr_t*)addr));
}
#else // !LWIP_IPV6
void setMulticastInterface(const IPAddress& addr) {
udp_set_multicast_netif_addr(_pcb, ip_2_ip4((const ip_addr_t*)addr));
}
#endif // !LWIP_IPV6
/*
Add a netif (by its index) as the multicast interface
*/
void setMulticastInterface(netif* p_pNetIf) {
udp_set_multicast_netif_index(_pcb, (p_pNetIf ? netif_get_index(p_pNetIf) : NETIF_NO_INDEX));
}
/*
Allow access to pcb to change eg. options
*/
udp_pcb* pcb(void) {
return _pcb;
}
void setMulticastTTL(int ttl) {
#ifdef LWIP_MAYBE_XCC
_mcast_ttl = ttl;
#else
udp_set_multicast_ttl(_pcb, ttl);
#endif
}
// warning: handler is called from tcp stack context
// esp_suspend and non-reentrant functions which depend on it will fail
void onRx(rxhandler_t handler) {
_on_rx = handler;
}
#ifdef DEBUG_ESP_CORE
// this helper is ready to be used when debugging UDP
void printChain(const pbuf* pb, const char* msg, size_t n) const {
// printf the pb pbuf chain, buffered and all at once
char buf[128];
int l = snprintf(buf, sizeof(buf), "UDP: %s %u: ", msg, n);
while (pb) {
l += snprintf(&buf[l], sizeof(buf) - l, "%p(H=%d,%d<=%d)-",
pb, pb->flags == PBUF_HELPER_FLAG, pb->len, pb->tot_len);
pb = pb->next;
}
l += snprintf(&buf[l], sizeof(buf) - l, "(end)");
DEBUGV("%s\n", buf);
}
#else
void printChain(const pbuf* pb, const char* msg) const {
(void)pb;
(void)msg;
}
#endif
size_t getSize() const {
if (!_rx_buf) {
return 0;
}
return _rx_buf_size - _rx_buf_offset;
}
size_t tell() const {
return _rx_buf_offset;
}
void seek(const size_t pos) {
assert(isValidOffset(pos));
_rx_buf_offset = pos;
}
bool isValidOffset(const size_t pos) const {
return (pos <= _rx_buf_size);
}
netif* getInputNetif() const {
return _currentAddr.input_netif;
}
const IPAddress& getRemoteAddress() const {
return _currentAddr.srcaddr;
}
uint16_t getRemotePort() const {
return _currentAddr.srcport;
}
const IPAddress& getDestAddress() const {
return _currentAddr.dstaddr;
}
uint16_t getLocalPort() const {
if (!_pcb) {
return 0;
}
return _pcb->local_port;
}
bool next() {
if (!_rx_buf) {
return false;
}
if (!_first_buf_taken) {
_first_buf_taken = true;
return true;
}
// We have interleaved information on addresses within received pbuf chain:
// (before ipv6 code we had: (data-pbuf) -> (data-pbuf) -> (data-pbuf) -> ... in the receiving order)
// Now: (address-info-pbuf -> chained-data-pbuf [-> chained-data-pbuf...]) ->
// (chained-address-info-pbuf -> chained-data-pbuf [-> chained...]) -> ...
// _rx_buf is currently addressing a data pbuf,
// in this function it is going to be discarded.
auto deleteme = _rx_buf;
// forward in the chain until next address-info pbuf or end of chain
while (_rx_buf && _rx_buf->flags != PBUF_HELPER_FLAG) {
_rx_buf = _rx_buf->next;
}
if (_rx_buf) {
assert(_rx_buf->flags == PBUF_HELPER_FLAG);
// copy address helper to "current address"
auto helper = (AddrHelper*)PBUF_ALIGNER(_rx_buf->payload);
_currentAddr = *helper;
// destroy the helper in the about-to-be-released pbuf
helper->~AddrHelper();
// forward in rx_buf list, next one is effective data
// current (not ref'ed) one will be pbuf_free'd
// with the 'deleteme' pointer above
_rx_buf = _rx_buf->next;
// this rx_buf is not nullptr by construction,
assert(_rx_buf);
// ref'ing it to prevent release from the below pbuf_free(deleteme)
// (ref counter prevents release and will be decreased by pbuf_free)
pbuf_ref(_rx_buf);
}
// release in chain previous data, and if any:
// current helper, but not start of current data
pbuf_free(deleteme);
_rx_buf_offset = 0;
_rx_buf_size = _processSize(_rx_buf);
return _rx_buf != nullptr;
}
int read() {
if (!_rx_buf || _rx_buf_offset >= _rx_buf_size) {
return -1;
}
char c = pbuf_get_at(_rx_buf, _rx_buf_offset);
_consume(1);
return c;
}
size_t read(char* dst, size_t size) {
if (!_rx_buf) {
return 0;
}
size_t max_size = _rx_buf_size - _rx_buf_offset;
size = (size < max_size) ? size : max_size;
DEBUGV(":urd %d, %d, %d\r\n", size, _rx_buf_size, _rx_buf_offset);
void* buf = pbuf_get_contiguous(_rx_buf, dst, size, size, _rx_buf_offset);
if (!buf) {
return 0;
}
if (buf != dst) {
memcpy(dst, buf, size);
}
_consume(size);
return size;
}
int peek() const {
if (!_rx_buf || _rx_buf_offset == _rx_buf_size) {
return -1;
}
return pbuf_get_at(_rx_buf, _rx_buf_offset);
}
void flush() {
//XXX this does not follow Arduino's flush definition
if (!_rx_buf) {
return;
}
_consume(_rx_buf_size - _rx_buf_offset);
}
size_t append(const char* data, size_t size) {
if (!_tx_buf_head || _tx_buf_head->tot_len < _tx_buf_offset + size) {
_reserve(_tx_buf_offset + size);
}
if (!_tx_buf_head || _tx_buf_head->tot_len < _tx_buf_offset + size) {
DEBUGV("failed _reserve");
return 0;
}
size_t left_to_copy = size;
while (left_to_copy) {
// size already used in current pbuf
size_t used_cur = _tx_buf_offset - (_tx_buf_head->tot_len - _tx_buf_cur->tot_len);
size_t free_cur = _tx_buf_cur->len - used_cur;
if (free_cur == 0) {
_tx_buf_cur = _tx_buf_cur->next;
continue;
}
size_t will_copy = (left_to_copy < free_cur) ? left_to_copy : free_cur;
memcpy(reinterpret_cast<char*>(_tx_buf_cur->payload) + used_cur, data, will_copy);
_tx_buf_offset += will_copy;
left_to_copy -= will_copy;
data += will_copy;
}
return size;
}
void cancelBuffer() {
if (_tx_buf_head) {
pbuf_free(_tx_buf_head);
}
_tx_buf_head = 0;
_tx_buf_cur = 0;
_tx_buf_offset = 0;
}
bool send(const ip_addr_t* addr = 0, uint16_t port = 0) {
return trySend(addr, port, /* don't keep buffer */false) == ERR_OK;
}
bool sendTimeout(const ip_addr_t* addr, uint16_t port, uint32_t timeoutMs) {
err_t err;
uint32_t start = millis();
while (((err = trySend(addr, port, /* keep buffer on error */true)) != ERR_OK) && (millis() - start < timeoutMs)) {
delay(1);
}
if (err != ERR_OK) {
cancelBuffer(); // get rid of buffer kept on error after timeout
}
return err == ERR_OK;
}
private:
err_t trySend(const ip_addr_t* addr, uint16_t port, bool keepBufferOnError) {
size_t data_size = _tx_buf_offset;
pbuf* tx_copy = pbuf_alloc(PBUF_TRANSPORT, data_size, PBUF_RAM);
if (tx_copy) {
uint8_t* dst = reinterpret_cast<uint8_t*>(tx_copy->payload);
for (pbuf* p = _tx_buf_head; p; p = p->next) {
size_t will_copy = (data_size < p->len) ? data_size : p->len;
memcpy(dst, p->payload, will_copy);
dst += will_copy;
data_size -= will_copy;
}
}
if (!keepBufferOnError) {
cancelBuffer();
}
if (!tx_copy) {
DEBUGV("failed pbuf_alloc");
return ERR_MEM;
}
if (!addr) {
addr = &_pcb->remote_ip;
port = _pcb->remote_port;
}
err_t err = udp_sendto(_pcb, tx_copy, addr, port);
if (err != ERR_OK) {
DEBUGV(":ust rc=%d\r\n", (int) err);
}
pbuf_free(tx_copy);
if (err == ERR_OK) {
cancelBuffer(); // no error: get rid of buffer
}
return err;
}
size_t _processSize(const pbuf* pb) {
size_t ret = 0;
for (; pb && pb->flags != PBUF_HELPER_FLAG; pb = pb->next) {
ret += pb->len;
}
return ret;
}
void _reserve(size_t size) {
const size_t pbuf_unit_size = 128;
if (!_tx_buf_head) {
_tx_buf_head = pbuf_alloc(PBUF_TRANSPORT, pbuf_unit_size, PBUF_RAM);
if (!_tx_buf_head) {
return;
}
_tx_buf_cur = _tx_buf_head;
_tx_buf_offset = 0;
}
size_t cur_size = _tx_buf_head->tot_len;
if (size < cur_size) {
return;
}
size_t grow_size = size - cur_size;
while (grow_size) {
pbuf* pb = pbuf_alloc(PBUF_TRANSPORT, pbuf_unit_size, PBUF_RAM);
if (!pb) {
return;
}
pbuf_cat(_tx_buf_head, pb);
if (grow_size < pbuf_unit_size) {
return;
}
grow_size -= pbuf_unit_size;
}
}
void _consume(size_t size) {
_rx_buf_offset += size;
if (_rx_buf_offset > _rx_buf_size) {
_rx_buf_offset = _rx_buf_size;
}
}
void _recv(udp_pcb *upcb, pbuf *pb,
const ip_addr_t *srcaddr, u16_t srcport) {
(void) upcb;
// check receive pbuf chain depth
// optimization path: cache the pbuf chain length
{
pbuf* p;
int count = 0;
for (p = _rx_buf; p && ++count < rxBufMaxDepth * 2; p = p->next);
if (p) {
// pbuf chain too deep, dropping
pbuf_free(pb);
DEBUGV(":udr\r\n");
return;
}
}
// chain this helper pbuf first
if (_rx_buf) {
// there is some unread data
// chain pbuf
// Addresses/ports are stored from this callback because lwIP's
// macro are valid only now.
//
// When peeking data from before payload start (like it was done
// before IPv6), there's no easy way to safely guess whether
// packet is from v4 or v6.
//
// Now storing data in an intermediate chained pbuf containing
// AddrHelper
// allocate new pbuf to store addresses/ports
pbuf* pb_helper = pbuf_alloc(PBUF_RAW, sizeof(AddrHelper) + PBUF_ALIGNER_ADJUST, PBUF_RAM);
if (!pb_helper) {
// memory issue - discard received data
pbuf_free(pb);
return;
}
// construct in place
new (PBUF_ALIGNER(pb_helper->payload)) AddrHelper(srcaddr, ip_current_dest_addr(), srcport, ip_current_input_netif());
pb_helper->flags = PBUF_HELPER_FLAG; // mark helper pbuf
// chain it
pbuf_cat(_rx_buf, pb_helper);
// now chain the new data pbuf
DEBUGV(":urch %d, %d\r\n", _rx_buf->tot_len, pb->tot_len);
pbuf_cat(_rx_buf, pb);
} else {
_currentAddr.srcaddr = srcaddr;
_currentAddr.dstaddr = ip_current_dest_addr();
_currentAddr.srcport = srcport;
_currentAddr.input_netif = ip_current_input_netif();
DEBUGV(":urn %d\r\n", pb->tot_len);
_first_buf_taken = false;
_rx_buf = pb;
_rx_buf_offset = 0;
_rx_buf_size = pb->tot_len;
}
if (_on_rx) {
_on_rx();
}
}
static void _s_recv(void *arg,
udp_pcb *upcb, pbuf *p,
const ip_addr_t *srcaddr, u16_t srcport) {
reinterpret_cast<UdpContext*>(arg)->_recv(upcb, p, srcaddr, srcport);
}
private:
udp_pcb* _pcb;
pbuf* _rx_buf;
bool _first_buf_taken;
size_t _rx_buf_offset;
size_t _rx_buf_size;
int _refcnt;
pbuf* _tx_buf_head;
pbuf* _tx_buf_cur;
size_t _tx_buf_offset;
rxhandler_t _on_rx;
#ifdef LWIP_MAYBE_XCC
uint16_t _mcast_ttl;
#endif
struct AddrHelper {
IPAddress srcaddr, dstaddr;
int16_t srcport;
netif* input_netif;
AddrHelper() { }
AddrHelper(const ip_addr_t* src, const ip_addr_t* dst, uint16_t srcport, netif* input_netif):
srcaddr(src), dstaddr(dst), srcport(srcport), input_netif(input_netif) { }
};
AddrHelper _currentAddr;
// rx pbuf depth barrier (counter of buffered UDP received packets)
// keep it small
static constexpr int rxBufMaxDepth = 4;
};
#endif//UDPCONTEXT_H

View file

@ -0,0 +1,38 @@
#ifndef SLIST_H
#define SLIST_H
template<typename T>
class SList {
public:
SList() : _next(0) { }
protected:
static void _add(T* self) {
T* tmp = _s_first;
_s_first = self;
self->_next = tmp;
}
static void _remove(T* self) {
if (_s_first == self) {
_s_first = self->_next;
self->_next = 0;
return;
}
for (T* prev = _s_first; prev->_next; prev = prev->_next) {
if (prev->_next == self) {
prev->_next = self->_next;
self->_next = 0;
return;
}
}
}
static T* _s_first;
T* _next;
};
#endif //SLIST_H

View file

@ -0,0 +1,83 @@
/*
wl_definitions.h - Library for Arduino Wifi shield.
Copyright (c) 2018 Arduino SA. All rights reserved.
Copyright (c) 2011-2014 Arduino. All right reserved.
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
*/
/*
wl_definitions.h
Created on: Mar 6, 2011
Author: dlafauci
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
// Maximum size of a SSID
#define WL_SSID_MAX_LENGTH 32
// Length of passphrase. Valid lengths are 8-63.
#define WL_WPA_KEY_MAX_LENGTH 63
// Length of key in bytes. Valid values are 5 and 13.
#define WL_WEP_KEY_MAX_LENGTH 13
// Size of a MAC-address or BSSID
#define WL_MAC_ADDR_LENGTH 6
// Size of a MAC-address or BSSID
#define WL_IPV4_LENGTH 4
// Maximum size of a SSID list
#define WL_NETWORKS_LIST_MAXNUM 10
// Maxmium number of socket
#define WIFI_MAX_SOCK_NUM 10
// Socket not available constant
#define SOCK_NOT_AVAIL 255
// Default state value for WiFi state field
#define NA_STATE -1
typedef enum {
WL_NO_SHIELD = 255,
WL_NO_MODULE = WL_NO_SHIELD,
WL_IDLE_STATUS = 0,
WL_NO_SSID_AVAIL,
WL_SCAN_COMPLETED,
WL_CONNECTED,
WL_CONNECT_FAILED,
WL_CONNECTION_LOST,
WL_DISCONNECTED,
WL_AP_LISTENING,
WL_AP_CONNECTED,
WL_AP_FAILED,
WL_CONNECTING
} wl_status_t;
/* Encryption modes */
enum wl_enc_type { /* Values map to 802.11 encryption suites... */
ENC_TYPE_WEP = 5,
ENC_TYPE_TKIP = 2,
ENC_TYPE_CCMP = 4,
/* ... except these two, 7 and 8 are reserved in 802.11-2007 */
ENC_TYPE_NONE = 7,
ENC_TYPE_AUTO = 8,
ENC_TYPE_UNKNOWN = 255
};
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,61 @@
/*
wl_types.h - Library for Arduino Wifi shield.
Copyright (c) 2018 Arduino SA. All rights reserved.
Copyright (c) 2011-2014 Arduino. All right reserved.
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
*/
/*
wl_types.h
Created on: Jul 30, 2010
Author: dlafauci
*/
#pragma once
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
WL_FAILURE = -1,
WL_SUCCESS = 1,
} wl_error_code_t;
/* Authentication modes */
enum wl_auth_mode {
AUTH_MODE_INVALID,
AUTH_MODE_AUTO,
AUTH_MODE_OPEN_SYSTEM,
AUTH_MODE_SHARED_KEY,
AUTH_MODE_WPA,
AUTH_MODE_WPA2,
AUTH_MODE_WPA_PSK,
AUTH_MODE_WPA2_PSK
};
typedef enum {
WL_PING_DEST_UNREACHABLE = -1,
WL_PING_TIMEOUT = -2,
WL_PING_UNKNOWN_HOST = -3,
WL_PING_ERROR = -4
} wl_ping_result_t;
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,10 @@
name=lwIP_CYW43
version=1
author=Earle F. Philhower, III
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
sentence=RP2040 Cyw43XX wifi driver
paragraph=Driver for the raspberry Pi Pico W wireless chip, CYW43439, to integrate witrh arduino-pico
category=Communication
url=https://github.com/earlephilhower/arduino-pico
architectures=rp2040
dot_a_linkage=true

View file

@ -0,0 +1,6 @@
#pragma once
#include <LwipIntfDev.h>
#include <utility/CYW43shim.h>
using CYW43lwIP = LwipIntfDev<CYW43>;

View file

@ -0,0 +1,144 @@
/*
WiFi <-> LWIP driver for the CYG43 chip on the Raspberry Pico W
Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
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
*/
#include "CYW43shim.h"
extern "C" {
#include "cyw43.h"
#include "cyw43_stats.h"
}
#include "pico/cyw43_arch.h"
#include <Arduino.h>
netif *CYW43::_netif = nullptr;
CYW43::CYW43(int8_t cs, arduino::SPIClass& spi, int8_t intrpin) {
(void) cs;
(void) spi;
(void) intrpin;
_netif = nullptr;
}
bool CYW43::begin(const uint8_t* address, netif* netif) {
(void) address;
_netif = netif;
_self = &cyw43_state;
if (!_ap) {
_itf = 0;
cyw43_arch_enable_sta_mode();
cyw43_wifi_get_mac(_self, _itf, netif->hwaddr);
auto authmode = CYW43_AUTH_WPA2_AES_PSK;
if (_password == nullptr) {
authmode = CYW43_AUTH_OPEN;
}
if (cyw43_arch_wifi_connect_timeout_ms(_ssid, _password, authmode, _timeout)) {
return false;
} else {
return true;
}
} else {
_itf = 1;
cyw43_arch_enable_ap_mode(_ssid, _password, _password ? CYW43_AUTH_WPA2_AES_PSK : CYW43_AUTH_OPEN);
cyw43_wifi_get_mac(_self, _itf, netif->hwaddr);
return true;
}
}
void CYW43::end() {
_netif = nullptr;
cyw43_deinit(&cyw43_state);
}
uint16_t CYW43::sendFrame(const uint8_t* data, uint16_t datalen) {
if (0 == cyw43_send_ethernet(_self, _itf, datalen, data, false)) {
return datalen;
}
return 0;
}
uint16_t CYW43::readFrame(uint8_t* buffer, uint16_t bufsize) {
// This is the polling method, but we hand this thru the interrupts
(void) buffer;
(void) bufsize;
return 0;
}
// CB from the cyg32_driver
extern "C" void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf) {
//cyw43_t *self = (cyw43_t *)cb_data
(void) cb_data;
(void) itf;
struct netif *netif = CYW43::_netif; // &self->netif[itf];
#if CYW43_NETUTILS
if (self->trace_flags) {
cyw43_ethernet_trace(self, netif, len, buf, NETUTILS_TRACE_NEWLINE);
}
#endif
if (netif->flags & NETIF_FLAG_LINK_UP) {
struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
if (p != NULL) {
pbuf_take(p, buf, len);
if (netif->input(p, netif) != ERR_OK) {
pbuf_free(p);
}
CYW43_STAT_INC(PACKET_IN_COUNT);
}
}
}
extern "C" void cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) {
(void) self;
(void) itf;
if (CYW43::_netif) {
netif_set_link_up(CYW43::_netif);
}
}
extern "C" void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
(void) self;
(void) itf;
if (CYW43::_netif) {
netif_set_link_down(CYW43::_netif);
}
}
extern "C" int cyw43_tcpip_link_status(cyw43_t *self, int itf) {
//if ((CYW43::_netif->flags & (NETIF_FLAG_UP | NETIF_FLAG_LINK_UP)) == (NETIF_FLAG_UP | NETIF_FLAG_LINK_UP))
// Fake this since it's only used in the SDK
if ((CYW43::_netif->flags & (NETIF_FLAG_LINK_UP)) == (NETIF_FLAG_LINK_UP)) {
return CYW43_LINK_UP;
} else {
return cyw43_wifi_link_status(self, itf);
}
}
// CBs from the SDK, not needed here as we do TCP later in the game
extern "C" void cyw43_cb_tcpip_init(cyw43_t *self, int itf) {
(void) self;
(void) itf;
}
extern "C" void cyw43_cb_tcpip_deinit(cyw43_t *self, int itf) {
(void) self;
(void) itf;
}

View file

@ -0,0 +1,102 @@
/*
WiFi <-> LWIP driver for the CYG43 chip on the Raspberry Pico W
Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
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 <Arduino.h>
#include <SPI.h>
#include "lwip/netif.h"
extern "C" {
#include "cyw43.h"
#include "cyw43_stats.h"
}
class CYW43 {
public:
/**
Constructor that uses the default hardware SPI pins
@param cs the Arduino Chip Select / Slave Select pin (default 10)
*/
CYW43(int8_t cs, arduino::SPIClass& spi, int8_t intrpin);
/**
Initialise the Ethernet controller
Must be called before sending or receiving Ethernet frames
@param address the local MAC address for the Ethernet interface
@return Returns true if setting up the Ethernet interface was successful
*/
bool begin(const uint8_t* address, netif *netif);
/**
Shut down the Ethernet controlled
*/
void end();
/**
Send an Ethernet frame
@param data a pointer to the data to send
@param datalen the length of the data in the packet
@return the number of bytes transmitted
*/
uint16_t sendFrame(const uint8_t* data, uint16_t datalen);
/**
Read an Ethernet frame
@param buffer a pointer to a buffer to write the packet to
@param bufsize the available space in the buffer
@return the length of the received packet
or 0 if no packet was received
*/
uint16_t readFrame(uint8_t* buffer, uint16_t bufsize);
bool interruptIsPossible() {
return true;
}
void setSSID(const char *p) {
_ssid = p;
}
void setPassword(const char *p) {
_password = p;
}
void setSTA() {
_ap = false;
}
void setAP() {
_ap = true;
}
void setTimeout(int timeout) {
_timeout = timeout;
}
// LWIP netif for the IRQ packet processing
static netif *_netif;
protected:
int _timeout = 10000;
bool _ap = false;
// The WiFi driver object
cyw43_t *_self;
int _itf;
const char *_ssid = nullptr;
const char *_password = nullptr;
};

View file

@ -0,0 +1,10 @@
name=lwIP-Ethernet
version=1
author=esp8266/Arduino
maintainer=esp8266/Arduino
sentence=Helper for ethernet drivers
paragraph=Example repository for Ethernet drivers
category=Communication
url=https://github.com/esp8266/Arduino
architectures=esp8266,rp2040
dot_a_linkage=true

View file

@ -0,0 +1,256 @@
/*
AddrList.h - cycle through lwIP netif's ip addresses like a c++ list
Copyright (c) 2018 david gauchard. All right reserved.
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
*/
/*
This class allows to explore all configured IP addresses
in lwIP netifs, with that kind of c++ loop:
for (auto a: addrList)
out.printf("IF='%s' index=%d legacy=%d IPv4=%d local=%d hostname='%s' addr= %s\n",
a.iface().c_str(),
a.ifnumber(),
a.addr().isLegacy(),
a.addr().isV4(),
a.addr().isLocal(),
a.hostname().c_str(),
a.addr().toString().c_str());
This loop:
while (WiFi.status() != WL_CONNECTED()) {
Serial.print('.');
delay(500);
}
can be replaced by:
for (bool configured = false; !configured; ) {
for (auto iface: addrList)
if ((configured = !iface.addr().isLocal())
break;
Serial.print('.');
delay(500);
}
waiting for an IPv6 global address:
for (bool configured = false; !configured; ) {
for (auto iface: addrList)
if ((configured = ( !iface.addr().isV4()
&& !iface.addr().isLocal())))
break;
Serial.print('.');
delay(500);
}
waiting for an IPv6 global address, on a specific interface:
for (bool configured = false; !configured; ) {
for (auto iface: addrList)
if ((configured = ( !iface.addr().isV4()
&& !iface.addr().isLocal()
&& iface.ifnumber() == STATION_IF)))
break;
Serial.print('.');
delay(500);
}
*/
#ifndef __ADDRLIST_H
#define __ADDRLIST_H
#include <IPAddress.h>
#include <lwip/netif.h>
#if LWIP_IPV6
#define IF_NUM_ADDRESSES (1 + LWIP_IPV6_NUM_ADDRESSES)
#else
#define IF_NUM_ADDRESSES (1)
#endif
namespace esp8266 {
namespace AddressListImplementation {
struct netifWrapper {
netifWrapper(netif* netif) : _netif(netif), _num(-1) {}
netifWrapper(const netifWrapper& o) : _netif(o._netif), _num(o._num) {}
netifWrapper& operator= (const netifWrapper& o) {
_netif = o._netif;
_num = o._num;
return *this;
}
bool equal(const netifWrapper& o) {
return _netif == o._netif && (!_netif || _num == o._num);
}
// address properties
IPAddress addr() const {
return ipFromNetifNum();
}
bool isLegacy() const {
return _num == 0;
}
bool isLocal() const {
return addr().isLocal();
}
bool isV4() const {
return addr().isV4();
}
bool isV6() const {
return !addr().isV4();
}
String toString() const {
return addr().toString();
}
// related to legacy address (_num=0, ipv4)
IPAddress ipv4() const {
return _netif->ip_addr;
}
IPAddress netmask() const {
return _netif->netmask;
}
IPAddress gw() const {
return _netif->gw;
}
// common to all addresses of this interface
String ifname() const {
return String(_netif->name[0]) + _netif->name[1];
}
const char* ifhostname() const {
return _netif->hostname ? : "";
}
const char* ifmac() const {
return (const char*)_netif->hwaddr;
}
int ifnumber() const {
return _netif->num;
}
bool ifUp() const {
return !!(_netif->flags & NETIF_FLAG_UP);
}
const netif* interface() const {
return _netif;
}
const ip_addr_t* ipFromNetifNum() const {
#if LWIP_IPV6
return _num ? &_netif->ip6_addr[_num - 1] : &_netif->ip_addr;
#else
return &_netif->ip_addr;
#endif
}
// lwIP interface
netif* _netif;
// address index within interface
// 0: legacy address (IPv4)
// n>0: (_num-1) is IPv6 index for netif->ip6_addr[]
int _num;
};
class AddressListIterator {
public:
AddressListIterator(const netifWrapper& o) : netIf(o) {}
AddressListIterator(netif* netif) : netIf(netif) {
// This constructor is called with lwIP's global netif_list, or
// nullptr. operator++() is designed to loop through _configured_
// addresses. That's why netIf's _num is initialized to -1 to allow
// returning the first usable address to AddressList::begin().
(void)operator++();
}
const netifWrapper& operator* () const {
return netIf;
}
const netifWrapper* operator-> () const {
return &netIf;
}
bool operator== (AddressListIterator& o) {
return netIf.equal(*o);
}
bool operator!= (AddressListIterator& o) {
return !netIf.equal(*o);
}
AddressListIterator operator++ (int) {
AddressListIterator ret = *this;
(void)operator++();
return ret;
}
AddressListIterator& operator++ () {
while (netIf._netif) {
if (++netIf._num == IF_NUM_ADDRESSES) {
// all addresses from current interface were iterated,
// switching to next interface
netIf = netifWrapper(netIf._netif->next);
continue;
}
if (!ip_addr_isany(netIf.ipFromNetifNum()))
// found an initialized address
{
break;
}
}
return *this;
}
netifWrapper netIf;
};
class AddressList {
public:
using const_iterator = const AddressListIterator;
const_iterator begin() const {
return const_iterator(netif_list);
}
const_iterator end() const {
return const_iterator(nullptr);
}
};
inline AddressList::const_iterator begin(const AddressList& a) {
return a.begin();
}
inline AddressList::const_iterator end(const AddressList& a) {
return a.end();
}
} // AddressListImplementation
} // esp8266
extern esp8266::AddressListImplementation::AddressList addrList;
#endif

View file

@ -0,0 +1,14 @@
#include <LwipEthernet.h>
#include <SPI.h>
//#ifndef ETHERNET_SPI_CLOCK_DIV
//#define ETHERNET_SPI_CLOCK_DIV SPI_CLOCK_DIV4 // 4MHz (SPI.h)
//#endif
void SPI4EthInit() {
SPI.begin();
// SPI.setClockDivider(ETHERNET_SPI_CLOCK_DIV);
// SPI.setBitOrder(MSBFIRST);
// SPI.setDataMode(SPI_MODE0);
}

View file

@ -0,0 +1,50 @@
//#include <ESP8266WiFi.h> // tcp API
//#include <debug.h>
#include <Arduino.h>
#include <lwIP_CYW43.h>
//#include <W5100lwIP.h>
//#include <W5500lwIP.h>
//#include <ENC28J60lwIP.h>
// One of them is to be declared in the main sketch
// and passed to ethInitDHCP() or ethInitStatic():
// Wiznet5500lwIP eth(CSPIN);
// Wiznet5100lwIP eth(CSPIN);
// ENC28J60lwIP eth(CSPIN);
void SPI4EthInit();
template<class EthImpl>
bool ethInitDHCP(EthImpl& eth) {
SPI4EthInit();
if (!eth.begin()) {
// hardware not responding
// DEBUGV("ethInitDHCP: hardware not responding\n");
return false;
}
return true;
}
template<class EthImpl>
bool ethInitStatic(EthImpl& eth, IPAddress IP, IPAddress gateway, IPAddress netmask, IPAddress dns1,
IPAddress dns2 = IPADDR_NONE) {
SPI4EthInit();
if (!eth.config(IP, gateway, netmask, dns1, dns2)) {
// invalid arguments
// DEBUGV("ethInitStatic: invalid arguments\n");
return false;
}
if (!eth.begin()) {
// hardware not responding
// DEBUGV("ethInitStatic: hardware not responding\n");
return false;
}
return true;
}

View file

@ -0,0 +1,185 @@
/*
LwipIntf.cpp
Arduino interface for lwIP generic callbacks and functions
Original Copyright (c) 2020 esp8266 Arduino All rights reserved.
This file is part of the esp8266 Arduino core environment.
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
*/
extern "C"
{
#include "lwip/err.h"
#include "lwip/ip_addr.h"
#include "lwip/dns.h"
#include "lwip/dhcp.h"
#include "lwip/init.h" // LWIP_VERSION_
#if LWIP_IPV6
#include "lwip/netif.h" // struct netif
#endif
}
#include "LwipIntf.h"
using arduino::IPAddress;
using arduino::String;
// wifi_station_hostname is SDK's station(=global) hostname location
// - It is never nullptr but wifi_station_get_hostname()
// can return nullptr when STA is down
// - Because WiFi is started in off mode at boot time,
// wifi_station_set/get_hostname() is now no more used
// because setting hostname first does not work anymore
// - wifi_station_hostname is overwritten by SDK when wifi is
// woken up in WiFi::mode()
//
char wifi_station_hostname[64] = "PicoW";
// args | esp order arduino order
// ---- + --------- -------------
// local_ip | local_ip local_ip
// arg1 | gateway dns1
// arg2 | netmask gateway
// arg3 | dns1 netmask
//
// result stored into gateway/netmask/dns1
bool LwipIntf::ipAddressReorder(const IPAddress& local_ip, const IPAddress& arg1,
const IPAddress& arg2, const IPAddress& arg3, IPAddress& gateway,
IPAddress& netmask, IPAddress& dns1) {
// To allow compatibility, check first octet of 3rd arg. If 255, interpret as ESP order,
// otherwise Arduino order.
gateway = arg1;
netmask = arg2;
dns1 = arg3;
if (netmask[0] != 255) {
// octet is not 255 => interpret as Arduino order
gateway = arg2;
netmask = arg3[0] == 0 ? IPAddress(255, 255, 255, 0)
: arg3; // arg order is arduino and 4th arg not given => assign it
// arduino default
dns1 = arg1;
}
// check whether all is IPv4 (or gateway not set)
if (!(local_ip.isV4() && netmask.isV4() && (!gateway.isSet() || gateway.isV4()))) {
return false;
}
// ip and gateway must be in the same netmask
if (gateway.isSet() && (local_ip.v4() & netmask.v4()) != (gateway.v4() & netmask.v4())) {
return false;
}
return true;
}
/**
Get ESP8266 station DHCP hostname
@return hostname
*/
String LwipIntf::hostname(void) {
return wifi_station_hostname;
}
/**
Get ESP8266 station DHCP hostname
@return hostname
*/
const char* LwipIntf::getHostname(void) {
return wifi_station_hostname;
}
/**
Set ESP8266 station DHCP hostname
@param aHostname max length:24
@return ok
*/
bool LwipIntf::hostname(const char* aHostname) {
/*
vvvv RFC952 vvvv
ASSUMPTIONS
1. A "name" (Net, Host, Gateway, or Domain name) is a text string up
to 24 characters drawn from the alphabet (A-Z), digits (0-9), minus
sign (-), and period (.). Note that periods are only allowed when
they serve to delimit components of "domain style names". (See
RFC-921, "Domain Name System Implementation Schedule", for
background). No blank or space characters are permitted as part of a
name. No distinction is made between upper and lower case. The first
character must be an alpha character. The last character must not be
a minus sign or period. A host which serves as a GATEWAY should have
"-GATEWAY" or "-GW" as part of its name. Hosts which do not serve as
Internet gateways should not use "-GATEWAY" and "-GW" as part of
their names. A host which is a TAC should have "-TAC" as the last
part of its host name, if it is a DoD host. Single character names
or nicknames are not allowed.
^^^^ RFC952 ^^^^
- 24 chars max
- only a..z A..Z 0..9 '-'
- no '-' as last char
*/
size_t len = strlen(aHostname);
if (len == 0 || len > 32) {
// nonos-sdk limit is 32
// (dhcp hostname option minimum size is ~60)
// DEBUGV("WiFi.(set)hostname(): empty or large(>32) name\n");
return false;
}
// check RFC compliance
bool compliant = (len <= 24);
for (size_t i = 0; compliant && i < len; i++)
if (!isalnum(aHostname[i]) && aHostname[i] != '-') {
compliant = false;
}
if (aHostname[len - 1] == '-') {
compliant = false;
}
if (!compliant) {
// DEBUGV("hostname '%s' is not compliant with RFC952\n", aHostname);
}
bool ret = true;
strcpy(wifi_station_hostname, aHostname);
// now we should inform dhcp server for this change, using lwip_renew()
// looping through all existing interface
// harmless for AP, also compatible with ethernet adapters (to come)
for (netif* intf = netif_list; intf; intf = intf->next) {
// unconditionally update all known interfaces
intf->hostname = wifi_station_hostname;
if (netif_dhcp_data(intf) != nullptr) {
// renew already started DHCP leases
err_t lwipret = dhcp_renew(intf);
if (lwipret != ERR_OK) {
// DEBUGV("WiFi.hostname(%s): lwIP error %d on interface %c%c (index %d)\n",
// intf->hostname, (int)lwipret, intf->name[0], intf->name[1], intf->num);
ret = false;
}
}
}
return ret && compliant;
}

View file

@ -0,0 +1,68 @@
/*
LwipIntf.h
Arduino interface for lwIP generic callbacks and functions
Original Copyright (c) 2020 esp8266 Arduino All rights reserved.
This file is part of the esp8266 Arduino core environment.
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 <lwip/netif.h>
#include <IPAddress.h>
#include <functional>
class LwipIntf {
public:
using CBType = std::function<void(netif*)>;
static bool stateUpCB(LwipIntf::CBType&& cb);
// reorder WiFi.config() parameters for a esp8266/official Arduino dual-compatibility API
// args | esp order arduino order
// ---- + --------- -------------
// local_ip | local_ip local_ip
// arg1 | gateway dns1
// arg2 | netmask [Agateway
// arg3 | dns1 netmask
//
// result stored into gateway/netmask/dns1
static bool ipAddressReorder(const arduino::IPAddress& local_ip, const arduino::IPAddress& arg1,
const arduino::IPAddress& arg2, const arduino::IPAddress& arg3, arduino::IPAddress& gateway,
arduino::IPAddress& netmask, arduino::IPAddress& dns1);
arduino::String hostname();
bool hostname(const arduino::String& aHostname) {
return hostname(aHostname.c_str());
}
bool hostname(const char* aHostname);
// ESP32 API compatibility
bool setHostname(const char* aHostName) {
return hostname(aHostName);
}
// ESP32 API compatibility
const char* getHostname();
protected:
static bool stateChangeSysCB(LwipIntf::CBType&& cb);
};

View file

@ -0,0 +1,66 @@
/*
LwipIntfCB.cpp
network generic callback implementation
Original Copyright (c) 2020 esp8266 Arduino All rights reserved.
This file is part of the esp8266 Arduino core environment.
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
*/
#include <LwipIntf.h>
//#include <Schedule.h>
//#include <debug.h>
#define NETIF_STATUS_CB_SIZE 3
static int netifStatusChangeListLength = 0;
LwipIntf::CBType netifStatusChangeList[NETIF_STATUS_CB_SIZE];
extern "C" void netif_status_changed(struct netif* netif) {
// override the default empty weak function
for (int i = 0; i < netifStatusChangeListLength; i++) {
netifStatusChangeList[i](netif);
}
}
bool LwipIntf::stateChangeSysCB(LwipIntf::CBType&& cb) {
if (netifStatusChangeListLength >= NETIF_STATUS_CB_SIZE) {
#if defined(DEBUG_ESP_CORE)
DEBUGV("NETIF_STATUS_CB_SIZE is too low\n");
#endif
return false;
}
netifStatusChangeList[netifStatusChangeListLength++] = cb;
return true;
}
bool LwipIntf::stateUpCB(LwipIntf::CBType&& cb) {
(void) cb;
return false;
//TODO - this is not used now, but was used in LeaMDNS
// return stateChangeSysCB(
// [cb](netif* nif)
// {
// if (netif_is_up(nif))
// schedule_function(
// [cb, nif]()
// {
// cb(nif);
// });
// });
}

View file

@ -0,0 +1,545 @@
/*
LwipIntfDev.h
Arduino network template class for generic device
Original Copyright (c) 2020 esp8266 Arduino All rights reserved.
This file is part of the esp8266 Arduino core environment.
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
// TODO:
// unchain pbufs
#include <LWIPMutex.h>
#include <netif/ethernet.h>
#include <lwip/init.h>
#include <lwip/netif.h>
#include <lwip/etharp.h>
#include <lwip/dhcp.h>
#include <lwip/dns.h>
#include <lwip/raw.h>
#include <lwip/icmp.h>
#include <lwip/timeouts.h>
#include <lwip/inet_chksum.h>
#include <lwip/apps/sntp.h>
//#include <user_interface.h> // wifi_get_macaddr()
#include "SPI.h"
//#include "Schedule.h"
#include "LwipIntf.h"
#include "wl_definitions.h"
#ifndef DEFAULT_MTU
#define DEFAULT_MTU 1500
#endif
extern "C" void cyw43_hal_generate_laa_mac(__unused int idx, uint8_t buf[6]);
template<class RawDev>
class LwipIntfDev: public LwipIntf, public RawDev {
public:
LwipIntfDev(int8_t cs = SS, SPIClass& spi = SPI, int8_t intr = -1) :
RawDev(cs, spi, intr), _mtu(DEFAULT_MTU), _intrPin(intr), _started(false), _default(false) {
memset(&_netif, 0, sizeof(_netif));
}
bool config(const IPAddress& local_ip, const IPAddress& arg1, const IPAddress& arg2,
const IPAddress& arg3 = IPADDR_NONE, const IPAddress& dns2 = IPADDR_NONE);
// default mac-address is inferred from esp8266's STA interface
bool begin(const uint8_t* macAddress = nullptr, const uint16_t mtu = DEFAULT_MTU);
void end();
netif* getNetIf() {
return &_netif;
}
IPAddress localIP() const {
return IPAddress(ip4_addr_get_u32(ip_2_ip4(&_netif.ip_addr)));
}
IPAddress subnetMask() const {
return IPAddress(ip4_addr_get_u32(ip_2_ip4(&_netif.netmask)));
}
IPAddress gatewayIP() const {
return IPAddress(ip4_addr_get_u32(ip_2_ip4(&_netif.gw)));
}
// 1. Currently when no default is set, esp8266-Arduino uses the first
// DHCP client interface receiving a valid address and gateway to
// become the new lwIP default interface.
// 2. Otherwise - when using static addresses - lwIP for every packets by
// defaults selects automatically the best suited output interface
// matching the destination address. If several interfaces match,
// the first one is picked. On esp8266/Arduno: WiFi interfaces are
// checked first.
// 3. Or, use `::setDefault(true)` to force using this interface's gateway
// as default router.
void setDefault(bool deflt = true);
// true if interface has a valid IPv4 address
bool connected() {
return !!ip4_addr_get_u32(ip_2_ip4(&_netif.ip_addr));
}
bool routable() {
return !ip_addr_isany(&_netif.gw);
}
// ICMP echo, returns TTL
int ping(IPAddress host, uint8_t ttl, uint32_t timeout = 5000);
int hostByName(const char* aHostname, IPAddress& aResult, int timeout);
// ESP8266WiFi API compatibility
wl_status_t status();
protected:
err_t netif_init();
void check_route();
void netif_status_callback();
static err_t netif_init_s(netif* netif);
static err_t linkoutput_s(netif* netif, struct pbuf* p);
static void netif_status_callback_s(netif* netif);
// called on a regular basis or on interrupt
err_t handlePackets();
// members
netif _netif;
uint16_t _mtu;
int8_t _intrPin;
uint8_t _macAddress[6];
bool _started;
bool _default;
// ICMP Ping
int _ping_seq_num = 1;
const int _ping_id = 0xfade;
volatile int _ping_ttl;
static u8_t _pingCB(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr);
// DNS lookup callback
bool _dns_lookup_pending = false;
typedef struct {
IPAddress *ip;
LwipIntfDev<RawDev> *wifi;
} _dns_cb_t;
static void _dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg);
};
template<class RawDev>
void LwipIntfDev<RawDev>::_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg) {
(void) name;
_dns_cb_t *cb = (_dns_cb_t *)callback_arg;
if (!cb->wifi->_dns_lookup_pending) {
return;
}
if (ipaddr) {
*(cb->ip) = IPAddress(ipaddr);
}
cb->wifi->_dns_lookup_pending = false; // resume hostByName
}
template<class RawDev>
int LwipIntfDev<RawDev>::hostByName(const char* aHostname, IPAddress& aResult, int timeout_ms) {
ip_addr_t addr;
aResult = static_cast<uint32_t>(0xffffffff);
if (aResult.fromString(aHostname)) {
// Host name is a IP address use it!
return 1;
}
LWIPMutex m;
_dns_cb_t cb = { &aResult, this };
#if LWIP_IPV4 && LWIP_IPV6
err_t err = dns_gethostbyname_addrtype(aHostname, &addr, &_dns_found_callback, &cb, LWIP_DNS_ADDRTYPE_DEFAULT);
#else
err_t err = dns_gethostbyname(aHostname, &addr, &wifi_dns_found_callback, &cb);
#endif
if (err == ERR_OK) {
aResult = IPAddress(&addr);
} else if (err == ERR_INPROGRESS) {
_dns_lookup_pending = true;
uint32_t now = millis();
while ((millis() - now < (uint32_t)timeout_ms) && _dns_lookup_pending) {
sys_check_timeouts();
delay(10);
}
_dns_lookup_pending = false;
if (aResult.isSet()) {
err = ERR_OK;
}
}
if (err == ERR_OK) {
return 1;
}
return 0;
}
template<class RawDev>
u8_t LwipIntfDev<RawDev>::_pingCB(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) {
(void) addr;
LwipIntfDev<RawDev> *w = (LwipIntfDev<RawDev> *)arg;
struct icmp_echo_hdr *iecho;
if (pbuf_header(p, -20) == 0) {
iecho = (struct icmp_echo_hdr *)p->payload;
if ((iecho->id == w->_ping_id) && (iecho->seqno == htons(w->_ping_seq_num))) {
w->_ping_ttl = pcb->ttl;
pbuf_free(p);
return 1; // We've processed it
}
}
return 0; // Wasn't ours
}
template<class RawDev>
int LwipIntfDev<RawDev>::ping(IPAddress host, uint8_t ttl, uint32_t _timeout) {
const int PING_DATA_SIZE = 32;
struct pbuf *p;
int ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;
auto ping_pcb = raw_new(IP_PROTO_ICMP);
ping_pcb->ttl = ttl;
LWIPMutex m;
raw_recv(ping_pcb, _pingCB, this);
raw_bind(ping_pcb, IP_ADDR_ANY);
p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM);
if (!p) {
return 0;
}
if ((p->len == p->tot_len) && (p->next == nullptr)) {
struct icmp_echo_hdr *iecho = (struct icmp_echo_hdr *)p->payload;
ICMPH_TYPE_SET(iecho, ICMP_ECHO);
ICMPH_CODE_SET(iecho, 0);
iecho->chksum = 0;
iecho->id = _ping_id;
iecho->seqno = htons(++_ping_seq_num);
/* fill the additional data buffer with some data */
for (size_t i = 0; i < PING_DATA_SIZE; i++) {
((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)(i + 'A');
}
iecho->chksum = inet_chksum(iecho, ping_size);
_ping_ttl = -1;
raw_sendto(ping_pcb, p, host);
uint32_t now = millis();
while ((millis() - now < _timeout) && (_ping_ttl < 0)) {
sys_check_timeouts();
delay(10);
}
pbuf_free(p);
raw_remove(ping_pcb);
return _ping_ttl;
} else {
pbuf_free(p);
raw_remove(ping_pcb);
return -1;
}
}
template<class RawDev>
bool LwipIntfDev<RawDev>::config(const IPAddress& localIP, const IPAddress& gateway,
const IPAddress& netmask, const IPAddress& dns1,
const IPAddress& dns2) {
if (_started) {
DEBUGV("LwipIntfDev: use config() then begin()\n");
return false;
}
IPAddress realGateway, realNetmask, realDns1;
if (!ipAddressReorder(localIP, gateway, netmask, dns1, realGateway, realNetmask, realDns1)) {
return false;
}
ip4_addr_set_u32(ip_2_ip4(&_netif.ip_addr), localIP.v4());
ip4_addr_set_u32(ip_2_ip4(&_netif.gw), realGateway.v4());
ip4_addr_set_u32(ip_2_ip4(&_netif.netmask), realNetmask.v4());
if (realDns1.isSet()) {
// Set DNS1-Server
dns_setserver(0, realDns1);
}
if (dns2.isSet()) {
// Set DNS2-Server
dns_setserver(1, dns2);
}
return true;
}
extern char wifi_station_hostname[];
template<class RawDev>
boolean LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu) {
if (mtu) {
_mtu = mtu;
}
if (macAddress) {
memcpy(_macAddress, macAddress, 6);
} else {
_netif.num = 2;
for (auto n = netif_list; n; n = n->next)
if (n->num >= _netif.num) {
_netif.num = n->num + 1;
}
#if 1
// forge a new mac-address from the esp's wifi sta one
// I understand this is cheating with an official mac-address
cyw43_hal_generate_laa_mac(0, _macAddress);
#else
// https://serverfault.com/questions/40712/what-range-of-mac-addresses-can-i-safely-use-for-my-virtual-machines
memset(_macAddress, 0, 6);
_macAddress[0] = 0xEE;
#endif
_macAddress[3] += _netif.num; // alter base mac address
_macAddress[0] &= 0xfe; // set as locally administered, unicast, per
_macAddress[0] |= 0x02; // https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local
}
// setup lwIP netif
_netif.hwaddr_len = sizeof _macAddress;
memcpy(_netif.hwaddr, _macAddress, sizeof _macAddress);
// due to netif_add() api: ...
ip_addr_t ip_addr, netmask, gw;
ip_addr_copy(ip_addr, _netif.ip_addr);
ip_addr_copy(netmask, _netif.netmask);
ip_addr_copy(gw, _netif.gw);
_netif.hostname = wifi_station_hostname;
if (!netif_add(&_netif, ip_2_ip4(&ip_addr), ip_2_ip4(&netmask), ip_2_ip4(&gw), this,
netif_init_s, ethernet_input)) {
return false;
}
if (!RawDev::begin(_macAddress, &_netif)) {
return false;
}
if (localIP().v4() == 0) {
// IP not set, starting DHCP
_netif.flags |= NETIF_FLAG_UP;
switch (dhcp_start(&_netif)) {
case ERR_OK:
break;
case ERR_IF:
return false;
default:
netif_remove(&_netif);
return false;
}
} else {
// IP is set, static config
netif_set_link_up(&_netif);
netif_set_up(&_netif);
}
_started = true;
if (_intrPin >= 0) {
if (RawDev::interruptIsPossible()) {
// attachInterrupt(_intrPin, [&]() { this->handlePackets(); }, FALLING);
} else {
::printf((PGM_P)F(
"lwIP_Intf: Interrupt not implemented yet, enabling transparent polling\r\n"));
_intrPin = -1;
}
}
#if 0
if (_intrPin < 0
&& !schedule_recurrent_function_us(
[&]() {
this->handlePackets();
return true;
},
100)) {
netif_remove(&_netif);
return false;
}
#endif
return true;
}
template<class RawDev>
void LwipIntfDev<RawDev>::end() {
RawDev::end();
netif_remove(&_netif);
memset(&_netif, 0, sizeof(_netif));
}
template<class RawDev>
wl_status_t LwipIntfDev<RawDev>::status() {
return _started ? (connected() ? WL_CONNECTED : WL_DISCONNECTED) : WL_NO_SHIELD;
}
template<class RawDev>
err_t LwipIntfDev<RawDev>::linkoutput_s(netif* netif, struct pbuf* pbuf) {
LwipIntfDev* lid = (LwipIntfDev*)netif->state;
if (pbuf->len != pbuf->tot_len || pbuf->next) {
Serial.println("ERRTOT\r\n");
}
uint16_t len = lid->sendFrame((const uint8_t*)pbuf->payload, pbuf->len);
#if PHY_HAS_CAPTURE
if (phy_capture) {
phy_capture(lid->_netif.num, (const char*)pbuf->payload, pbuf->len, /*out*/ 1,
/*success*/ len == pbuf->len);
}
#endif
return len == pbuf->len ? ERR_OK : ERR_MEM;
}
template<class RawDev>
err_t LwipIntfDev<RawDev>::netif_init_s(struct netif* netif) {
return ((LwipIntfDev*)netif->state)->netif_init();
}
template<class RawDev>
void LwipIntfDev<RawDev>::netif_status_callback_s(struct netif* netif) {
((LwipIntfDev*)netif->state)->netif_status_callback();
}
template<class RawDev>
err_t LwipIntfDev<RawDev>::netif_init() {
_netif.name[0] = 'e';
_netif.name[1] = '0' + _netif.num;
_netif.mtu = _mtu;
_netif.chksum_flags = NETIF_CHECKSUM_ENABLE_ALL;
_netif.flags = NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP | NETIF_FLAG_BROADCAST | NETIF_FLAG_LINK_UP;
// lwIP's doc: This function typically first resolves the hardware
// address, then sends the packet. For ethernet physical layer, this is
// usually lwIP's etharp_output()
_netif.output = etharp_output;
// lwIP's doc: This function outputs the pbuf as-is on the link medium
// (this must points to the raw ethernet driver, meaning: us)
_netif.linkoutput = linkoutput_s;
_netif.status_callback = netif_status_callback_s;
return ERR_OK;
}
template<class RawDev>
void LwipIntfDev<RawDev>::netif_status_callback() {
check_route();
if (connected()) {
sntp_stop();
sntp_init();
}
}
template<class RawDev>
void LwipIntfDev<RawDev>::check_route() {
if (connected()) {
if (_default || (netif_default == nullptr && routable())) {
// on user request,
// or if there is no current default interface, but our gateway is valid
netif_set_default(&_netif);
}
} else if (netif_default == &_netif) {
netif_set_default(nullptr);
}
}
template<class RawDev>
err_t LwipIntfDev<RawDev>::handlePackets() {
int pkt = 0;
while (1) {
if (++pkt == 10)
// prevent starvation
{
return ERR_OK;
}
uint16_t tot_len = RawDev::readFrameSize();
if (!tot_len) {
return ERR_OK;
}
// from doc: use PBUF_RAM for TX, PBUF_POOL from RX
// however:
// PBUF_POOL can return chained pbuf (not in one piece)
// and WiznetDriver does not have the proper API to deal with that
// so in the meantime, we use PBUF_RAM instead which is currently
// guarantying to deliver a continuous chunk of memory.
// 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);
if (!pbuf || pbuf->len < tot_len) {
if (pbuf) {
pbuf_free(pbuf);
}
RawDev::discardFrame(tot_len);
return ERR_BUF;
}
uint16_t len = RawDev::readFrameData((uint8_t*)pbuf->payload, tot_len);
if (len != tot_len) {
// tot_len is given by readFrameSize()
// and is supposed to be honoured by readFrameData()
// todo: ensure this test is unneeded, remove the print
pbuf_free(pbuf);
return ERR_BUF;
}
err_t err = _netif.input(pbuf, &_netif);
#if PHY_HAS_CAPTURE
if (phy_capture) {
phy_capture(_netif.num, (const char*)pbuf->payload, tot_len, /*out*/ 0,
/*success*/ err == ERR_OK);
}
#endif
if (err != ERR_OK) {
pbuf_free(pbuf);
return err;
}
// (else) allocated pbuf is now lwIP's responsibility
}
}
template<class RawDev>
void LwipIntfDev<RawDev>::setDefault(bool deflt) {
_default = deflt;
check_route();
}

View file

@ -20,6 +20,9 @@
{
"name": "Raspberry Pi Pico"
},
{
"name": "Raspberry Pi Pico W"
},
{
"name": "Adafruit Feather RP2040"
},

@ -1 +1 @@
Subproject commit e7267f99febc70486923e17a8210088af058c915
Subproject commit 2e6142b15b8a75c1227dd3edbe839193b2bf9041

View file

@ -41,8 +41,9 @@ compiler.warning_flags.default=-Werror=return-type
compiler.warning_flags.more=-Wall -Werror=return-type -Wno-ignored-qualifiers
compiler.warning_flags.all=-Wall -Wextra -Werror=return-type -Wno-ignored-qualifiers
compiler.defines={build.led} {build.usbstack_flags} -DCFG_TUSB_MCU=OPT_MCU_RP2040 -DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}'
compiler.includes="-iprefix{runtime.platform.path}/" "@{runtime.platform.path}/lib/platform_inc.txt"
compiler.netdefines=-DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 -DCYW43_LWIP=0 -DLWIP_IPV6=1 -DLWIP_IPV4=1 -DLWIP_IGMP=1 -DLWIP_CHECKSUM_CTRL_PER_NETIF=1
compiler.defines={build.led} {build.usbstack_flags} -DCFG_TUSB_MCU=OPT_MCU_RP2040 -DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' {compiler.netdefines}
compiler.includes="-iprefix{runtime.platform.path}/" "@{runtime.platform.path}/lib/platform_inc.txt" "-I{runtime.platform.path}/tools/libpico"
compiler.flags=-march=armv6-m -mcpu=cortex-m0plus -mthumb -ffunction-sections -fdata-sections {build.flags.exceptions} {build.flags.stackprotect}
compiler.wrap="@{runtime.platform.path}/lib/platform_wrap.txt"
compiler.libpico="{runtime.platform.path}/lib/libpico.a"

View file

@ -3,7 +3,8 @@
for dir in ./cores/rp2040 ./libraries/EEPROM ./libraries/I2S \
./libraries/LittleFS/src ./libraries/LittleFS/examples \
./libraries/rp2040 ./libraries/SD ./libraries/ESP8266SdFat \
./libraries/Servo ./libraries/SPI ./libraries/Wire; do
./libraries/Servo ./libraries/SPI ./libraries/Wire \
./libraries/WiFi ./libraries/lwIP_Ethernet ./libraries/lwIP_CYW43; do
find $dir -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" \) -a \! -path '*api*' -exec astyle --suffix=none --options=./tests/astyle_core.conf \{\} \;
find $dir -type f -name "*.ino" -exec astyle --suffix=none --options=./tests/astyle_examples.conf \{\} \;
done

View file

@ -7,6 +7,9 @@ set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_BUILD_TYPE RelWithDebInfo)
# Enable PicoW driver support. Compatible with standard Pico
set(PICO_BOARD pico_w)
# Initialize the SDK
pico_sdk_init()
@ -17,6 +20,12 @@ target_compile_definitions(pico PUBLIC
PICO_PRINTF_ALWAYS_INCLUDED=1
PICO_FLASH_SIZE_BYTES=16777216
PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64
LWIP_IPV4=1
LWIP_IPV6=1
LWIP_UDP=1
LWIP_IGMP=1
LWIP_CHECKSUM_CTRL_PER_NETIF=1
CYW43_WARN=//
)
target_compile_options(pico PUBLIC
@ -29,6 +38,7 @@ include_directories(BEFORE ${PICO_SDK_PATH}/../tools/libpico)
target_link_libraries(pico
boot_stage2
cyw43_driver
hardware_adc
hardware_base
hardware_claim
@ -58,11 +68,15 @@ target_link_libraries(pico
pico_bootrom
pico_bootsel_via_double_reset
pico_cxx_options
pico_cyw43_arch_none
pico_divider
pico_double
pico_fix
pico_float
pico_int64_ops
pico_lwip
pico_lwip_nosys
pico_lwip_sntp
pico_malloc
pico_mem_ops
pico_multicore
@ -74,10 +88,9 @@ target_link_libraries(pico
pico_util
tinyusb
tinyusb_device_unmarked
pico_audio
pico_audio_i2s
)
add_custom_command(TARGET pico POST_BUILD
COMMAND ar d libpico.a stdio.c.obj stdio_usb.c.obj stdio_usb_descriptors.c.obj
COMMAND ar d libpico.a stdio.c.obj stdio_usb.c.obj stdio_usb_descriptors.c.obj cyw43_arch_threadsafe_background.c.obj
COMMAND ar q libpico.a pico-sdk/src/rp2_common/cyw43_driver/cyw43_resource.o
)

99
tools/libpico/lwipopts.h Normal file
View file

@ -0,0 +1,99 @@
#ifndef _LWIPOPTS_EXAMPLE_COMMONH_H
#define _LWIPOPTS_EXAMPLE_COMMONH_H
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// Critical section protection
extern void noInterrupts();
extern void interrupts();
//static int lwipNoInterrupts() { noInterrupts(); return 0; }
//static void lwipInterrupts(int ign) { interrupts(); }
#define SYS_ARCH_DECL_PROTECT int
#define SYS_ARCH_PROTECT(lev) noInterrupts
#define SYS_ARCH_UNPROTECT(lev) interrupts
// Common settings used in most of the pico_w examples
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details)
#define NO_SYS 1
#define LWIP_SOCKET 0
#define MEM_LIBC_MALLOC 0
#define MEM_ALIGNMENT 4
#define MEM_SIZE 4000
#define MEMP_NUM_TCP_SEG 32
#define MEMP_NUM_ARP_QUEUE 10
#define PBUF_POOL_SIZE 24
#define LWIP_ARP 1
#define LWIP_ETHERNET 1
#define LWIP_ICMP 1
#define LWIP_RAW 1
#define TCP_WND (8 * TCP_MSS)
#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 LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
#define LWIP_NETIF_HOSTNAME 1
#define LWIP_NETCONN 0
#define MEM_STATS 0
#define SYS_STATS 0
#define MEMP_STATS 0
#define LINK_STATS 0
// #define ETH_PAD_SIZE 2
#define LWIP_CHKSUM_ALGORITHM 3
#define LWIP_DHCP 1
#define LWIP_IPV4 1
#define LWIP_TCP 1
#define LWIP_UDP 1
#define LWIP_DNS 1
#define LWIP_TCP_KEEPALIVE 1
#define LWIP_NETIF_TX_SINGLE_PBUF 1
#define DHCP_DOES_ARP_CHECK 0
#define LWIP_DHCP_DOES_ACD_CHECK 0
#ifndef NDEBUG
#define LWIP_DEBUG 1
#define LWIP_STATS 1
#define LWIP_STATS_DISPLAY 1
#endif
#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
#ifdef __cplusplus
}
#endif // __cplusplus
#endif /* __LWIPOPTS_H__ */

View file

@ -75,7 +75,7 @@ def BuildBoot(name):
def BuildUSBStack(name):
print("%s.menu.usbstack.picosdk=Pico SDK" % (name))
print('%s.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"' % (name))
print('%s.menu.usbstack.picosdk.build.usbstack_flags=' % (name))
print("%s.menu.usbstack.tinyusb=Adafruit TinyUSB" % (name))
print('%s.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"' % (name))
@ -248,6 +248,7 @@ BuildGlobalMenuList()
# Raspberry Pi
MakeBoard("rpipico", "Raspberry Pi", "Pico", "0x2e8a", "0x000a", 250, "RASPBERRY_PI_PICO", 2, "boot2_w25q080_2_padded_checksum")
MakeBoard("rpipicow", "Raspberry Pi", "Pico W", "0x2e8a", "0xf00a", 250, "RASPBERRY_PI_PICO_W", 2, "boot2_w25q080_2_padded_checksum")
# Adafruit
MakeBoard("adafruit_feather", "Adafruit", "Feather RP2040", "0x239a", "0x80f1", 250, "ADAFRUIT_FEATHER_RP2040", 8, "boot2_w25x10cl_4_padded_checksum")

View file

@ -106,6 +106,13 @@ env.Append(
"ARDUINO_ARCH_RP2040",
("F_CPU", "$BOARD_F_CPU"),
("BOARD_NAME", '\\"%s\\"' % env.subst("$BOARD")),
# LWIP-related
("PICO_CYW43_ARCH_THREADSAFE_BACKGROUND", 1),
("CYW43_LWIP", 0),
("LWIP_IPV6", 1),
("LWIP_IPV4", 1),
("LWIP_IGMP", 1),
("LWIP_LWIP_CHECKSUM_CTRL_PER_NETIF", 1),
],
CPPPATH=[
@ -164,7 +171,6 @@ def configure_usb_flags(cpp_defines):
platform.config.set(env_section, "lib_archive", False)
elif "PIO_FRAMEWORK_ARDUINO_NO_USB" in cpp_defines:
env.Append(
CPPPATH=[os.path.join(FRAMEWORK_DIR, "tools", "libpico")],
CPPDEFINES=[
"NO_USB",
"DISABLE_USB_SERIAL"
@ -173,8 +179,8 @@ def configure_usb_flags(cpp_defines):
# do not further add more USB flags or update sizes. no USB used.
return
else:
# standard Pico SDK USB stack used.
env.Append(CPPPATH=[os.path.join(FRAMEWORK_DIR, "tools", "libpico")])
# standard Pico SDK USB stack used, will get include path later on
pass
# in any case, add standard flags
# preferably use USB information from arduino.earlephilhower section,
# but fallback to sensible values derived from other parts otherwise.
@ -240,6 +246,9 @@ if not "USE_TINYUSB" in cpp_defines:
# configure USB stuff
configure_usb_flags(cpp_defines)
# ensure LWIP headers are in path after any TINYUSB distributed versions, also PicoSDK USB path headers
env.Append(CPPPATH=[os.path.join(FRAMEWORK_DIR, "tools", "libpico")])
# info about the filesystem is already parsed by the platform's main.py
# script. We can just use the info here

View file

@ -0,0 +1,49 @@
/*
pinMode and digitalRead/Write for the Raspberry Pi Pico W RP2040
Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
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
*/
#include "Arduino.h"
#include <pico/cyw43_arch.h>
extern "C" void __pinMode(pin_size_t pin, PinMode mode);
extern "C" void __digitalWrite(pin_size_t pin, PinStatus val);
extern "C" PinStatus __digitalRead(pin_size_t pin);
extern "C" void pinMode(pin_size_t pin, PinMode mode) {
if (pin < 32) {
__pinMode(pin, mode);
} else {
// TBD - There is no GPIO direction control in the driver
}
}
extern "C" void digitalWrite(pin_size_t pin, PinStatus val) {
if (pin < 32) {
__digitalWrite(pin, val);
} else {
cyw43_arch_gpio_put(pin - 32, val == HIGH ? 1 : 0);
}
}
extern "C" PinStatus digitalRead(pin_size_t pin) {
if (pin < 32) {
return __digitalRead(pin);
} else {
return cyw43_arch_gpio_get(pin - 32) ? HIGH : LOW;
}
}

View file

@ -0,0 +1,25 @@
/*
Initialize the Pico W WiFi driver
Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
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
*/
#include <pico/cyw43_arch.h>
extern "C" void initVariant() {
cyw43_arch_init();
}

View file

@ -0,0 +1,39 @@
#pragma once
// Pin definitions taken from:
// https://datasheets.raspberrypi.org/pico/pico-datasheet.pdf
// LEDs
#define PIN_LED (32u)
// Serial
#define PIN_SERIAL1_TX (0u)
#define PIN_SERIAL1_RX (1u)
#define PIN_SERIAL2_TX (8u)
#define PIN_SERIAL2_RX (9u)
// SPI
#define PIN_SPI0_MISO (16u)
#define PIN_SPI0_MOSI (19u)
#define PIN_SPI0_SCK (18u)
#define PIN_SPI0_SS (17u)
#define PIN_SPI1_MISO (12u)
#define PIN_SPI1_MOSI (15u)
#define PIN_SPI1_SCK (14u)
#define PIN_SPI1_SS (13u)
// Wire
#define PIN_WIRE0_SDA (4u)
#define PIN_WIRE0_SCL (5u)
#define PIN_WIRE1_SDA (26u)
#define PIN_WIRE1_SCL (27u)
#define SERIAL_HOWMANY (3u)
#define SPI_HOWMANY (2u)
#define WIRE_HOWMANY (2u)
#include "../generic/common.h"