Compare commits

...
38 Commits
Author SHA1 Message Date
Earle F. Philhower, III 53cecae109 Update version 2022-07-17 05:52:01 -07:00
Earle F. Philhower, III 61742c9357 Disable WiFi.begin on plain Pico, add JSON (#682) 2022-07-17 05:51:03 -07:00
Earle F. Philhower, III fee036604c Provide dummy CYW43 callbacks when no WiFi used (#681)
Fixes #680
2022-07-16 11:57:27 -07:00
Earle F. Philhower, III 988940b25e Update version 2022-07-15 16:49:36 -07:00
Earle F. Philhower, III abf2c586c7 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
2022-07-15 16:47:53 -07:00
Earle F. Philhower, III c025c4a1f8 Fix ::printf/etc. due to mutex size conflict (#677)
When real multicore/lockign support was added to newlib, there was an opaque
field in FILE that was used as a mutex, but was only 4 bytes in size.  The
recursive mutexes on the RP2040 are 8 bytes.  This mismatch caused corruption
of the FILE structure and crashes of the system when ::printf/::puts/etc. were
run.

Adjust the lock field size in FILE to 8 bytes and rebuild the toolchain to
fix.
2022-07-14 09:04:02 -07:00
Earle F. Philhower, III fb05d96979 Add delay to 2nd core start for Picoprobe (#676)
No idea why, but when a Picoprobe upload and reset is used, the 2nd core
does not start w/o a __wfe() call on the first one before launch.

Fixes #674
Fixes #402
2022-07-14 07:43:27 -07:00
Earle F. Philhower, III 8eb030ed89 Update TinyUSB to 1.13.3 (#672)
Fix errors in WebUSB buffering
Fixes #642
2022-07-08 13:45:01 -07:00
Pontus Oldberg 5be405308e Add support for new SD/RTC and SubGHz boards (#663) 2022-06-30 10:16:44 -07:00
Earle F. Philhower, III af0c1c87f5 Automatically update the JSON file in makeboards (#664)
Keep the Arduino Board Manager list up-to-date from makeboards.py
2022-06-29 12:50:42 -07:00
Earle F. Philhower, III cfaae84813 Update version 2022-06-28 15:07:55 -07:00
Earle F. Philhower, III da8ab1e9dd Return # of bytes written by SerialUSB::write (#662)
Before always returned 0 on a ::write.  Now properly return the count
of bytes that were sent to the USB port.

Thanks to Terry Haas for the report.
2022-06-28 13:01:06 -07:00
Maximilian Gerhardt baf65f510f Add notes on TinyUSB documentation and quirks (#659)
Fixes #648
2022-06-26 15:26:23 -07:00
Maximilian Gerhardt 13f68fbc64 Make TinyUSB linking work automatically with PIO (#658) 2022-06-26 13:24:55 -07:00
Stefan Staub 3071b3f2dd Update GPIO docs (digital.rst) (#656) 2022-06-25 10:00:29 -07:00
Earle F. Philhower, III de069cf8c9 Update version 2022-06-24 11:25:21 -07:00
Earle F. Philhower, III 8cf8923a18 Update to Adafruit_TinyUSB_Arduino 1.12.0 (#654)
* Update to Adafruit_TinyUSB_Arduino 1.12.0

* DualRole requires add'l libraries, skip in CI
2022-06-24 11:24:31 -07:00
Earle F. Philhower, III d954510c9d Update to latest pico-sdk develop branch (#653)
Fixes #651
2022-06-24 02:19:24 -07:00
Earle F. Philhower, III 8966a9b094 Actually pass in the PIO key for auto-publishing (#652)
Need to manually list the secrets to export to the environment.
2022-06-23 17:12:21 -07:00
Earle F. Philhower, III 3d9611d020 Update FreeRTOS SMP branch to latest upstream (#649) 2022-06-22 17:18:50 -07:00
Earle F. Philhower, III 78b7f26076 Update README.md 2022-06-20 19:17:52 -07:00
Earle F. Philhower, III 7233c39166 Update to latest pico-sdk, allow lock.c->lock.cpp (#646)
Minor change to keep the core all CPP.  Patch just made it into pico-sdk
develop branch allowing recursive mutexes to be auto_init in C++.
Update and rebuild libpico.a.
2022-06-20 11:14:31 -07:00
Earle F. Philhower, III 0ee072671b Update version 2022-06-20 08:30:24 -07:00
Earle F. Philhower, III 1130007761 Make mutexes init in DATA, not ((counstructor)) (#645)
There was a race condition in making mutexes that were only init in
an __attribute((constructor)) code block.  For example, a global
object might do a `malloc` in its constructor which would depend on
the malloc mutex...which may not yet have been initted.

Make them initted in the .data section, instead, which is guaranteed
good before any global constructors are called.
2022-06-20 08:29:08 -07:00
Earle F. Philhower, III a0060d9c3a Add dependency file generation to build (#644)
Fixes #643
2022-06-20 07:50:28 -07:00
Earle F. Philhower, III 66eb0613b0 Major multicore fixes Newlib and FreeRTOS (#640)
Instead of wrapping the memory functions in the link stage, rebuild
Newlib and enable retargetable locks.  Override the weak definitions
in the libc.a with our own, SDK based ones.

The wrapping utilized before catches app-level memory allocations
but misses allocations inside Newlib libc (like printf/etc.).

Each core needs its own _impure_ptr or else crashes like the one seen
in parallel printf_floats can happen.  Enable it in the toolchain
build and implement a simple swapper here.

FreeRTOS SMP doesn't support Newlib's dynamic reent which is needed
to allow save MT support.  Minor patch to FreeRTOS and update the
FreeRTOS variant.cpp and setup to support it.
2022-06-20 07:35:30 -07:00
Earle F. Philhower, III af8f544913 Update pio publish to match PIO PR build (#641) 2022-06-19 09:14:08 -07:00
Earle F. Philhower, III 803184c164 Update to latest Adafruit_TinyUSB (#639)
Fixes #582
2022-06-19 08:57:14 -07:00
Earle F. Philhower, III 857f91771f Update to develop branch of pico-sdk (#636)
The realloc() wrapper was included in the develop branch of pico-sdk, so
use it instead of a local, unreproducible version of the SDK.

Should have no effect on code.
2022-06-17 12:13:01 -07:00
Maximilian Gerhardt 592418d9f3 Minor PIO Docs Fixup (#635)
* Fix link display in PlatformIO Docs, Remove JLink warning

* Remove unfinished sentence
2022-06-17 09:49:51 -07:00
Maximilian Gerhardt 0a23dfeb42 Update PlatformIO board files, add PIO CI (#634)
* Shift arduino attribute higher in JSON file

* Try out PlatformIO CI

* Trigger CI

* Clone recursively, actually use own repo

* Fix YAML

* Build Verbose

* Revert to checkout@v2 version, add TinyUSB to examples

* Try fix TInyUSB example

* Pull repo recursively

* Use v3 after all, correct path to example

* Only do CI on PR
2022-06-17 08:57:18 -07:00
Maximilian Gerhardt 4a94677ee5 Update PlatformIO builder script and docs (#633)
* Update board generation, use renamed function

* Update documentation with new platform integration state

* Remove accidentally pushed file

* Use correct update command

* Use correct highlighting

* Use correct language

* Add section on debugging

* Add docs on filesystem, minor corrections

* Use -iprefix in compilation, but still expose all include paths to IDE

* Add exception and RTTI support, document them

* Fix typo
2022-06-16 18:59:46 -07:00
mnltake 3414b73172 Add analogReadResolution() docs (#631) 2022-06-16 08:16:58 -07:00
Pontus Oldberg 3bcbb24603 Updated helper class for Challenger NB board. (#629) 2022-06-15 09:16:47 -07:00
Ha Thach 26752f6f90 Aadd f_cpu 120, 240 mhz option (#628) 2022-06-15 09:12:43 -07:00
Earle F. Philhower, III 8999ec2c7a Add Platform.IO publish to release process 2022-06-14 13:07:19 -07:00
Earle F. Philhower, III 778cf4cb9e Update version 2022-06-14 12:34:22 -07:00
Earle F. Philhower, III b6a9e756e4 Remove unneeded and invalid file changes
The makever script sets up the repo properly, so no need to patch things
in the package stage.
2022-06-14 12:32:26 -07:00
130 changed files with 10209 additions and 840 deletions
+40 -6
View File
@@ -14,7 +14,7 @@ jobs:
name: Check spelling
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
- name: Run codespell
@@ -28,7 +28,7 @@ jobs:
name: Style, Boards, Package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: false
- name: Check package references
@@ -59,7 +59,7 @@ jobs:
matrix:
chunk: [0, 1, 2, 3]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
- uses: actions/setup-python@v2
@@ -89,7 +89,7 @@ jobs:
name: Build TinyUSB Examples
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
- uses: actions/setup-python@v2
@@ -117,7 +117,7 @@ jobs:
name: Windows
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
- uses: actions/setup-python@v2
@@ -152,7 +152,7 @@ jobs:
name: Mac
runs-on: macOS-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
- uses: actions/setup-python@v2
@@ -178,3 +178,37 @@ jobs:
cd ..
bash ./tests/build.sh
# Build a few examples with PlatformIO to test if integration works
build-platformio:
name: Build PlatformIO Examples
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- name: Cache pip
uses: actions/cache@v2
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Cache PlatformIO
uses: actions/cache@v2
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
- name: Set up Python
uses: actions/setup-python@v2
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install --upgrade platformio
pio pkg install --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
pio pkg install --global --tool symlink://.
- name: Build Multicore Example
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino
- name: Build Fade Example
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Fade/Fade.ino
- name: Build TinyUSB Example
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" -O "build_flags=-DUSE_TINYUSB" libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino
+20
View File
@@ -12,16 +12,36 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: true
- name: Cache pip
uses: actions/cache@v2
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Cache PlatformIO
uses: actions/cache@v2
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
- uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install --upgrade platformio
- name: Deploy updated JSON
env:
TRAVIS_BUILD_DIR: ${{ github.workspace }}
BUILD_TYPE: package
CI_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
run: |
pip3 install PyGithub
TAG=$(git describe --exact-match --tags)
curl -L -o package_rp2040_index.json "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/package_rp2040_index.json"
./package/update_release.py --token ${CI_GITHUB_API_KEY} --repo "$GITHUB_REPOSITORY" --tag global package_rp2040_index.json
# Upload to Platform.IO
curl -LO $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/rp2040-$TAG.zip
pio package publish rp2040-$TAG.zip --non-interactive
+7 -1
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
@@ -28,6 +29,8 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
* Invector Labs Challenger NB RP2040 WiFi
* Invector Labs Challenger RP2040 LTE
* Invector Labs Challenger RP2040 LoRa
* Invector Labs Challenger RP2040 SubGHz
* Invector Labs Challenger RP2040 SD/RTC
* Invector Labs RPICO32
* Melopero Shake RP2040
* Seeed XIAO RP2040
@@ -144,6 +147,7 @@ The installed tools include a version of OpenOCD (in the pqt-openocd directory)
* Generic Arduino USB Serial, Keyboard, and Mouse emulation
* Filesystems (LittleFS and SD/SDFS)
* Multicore support (setup1() and loop1())
* FreeRTOS SMP support
* Overclocking and underclocking from the menus
* digitalWrite/Read, shiftIn/Out, tone, analogWrite(PWM)/Read, temperature
* Peripherals: SPI master, Wire(I2C) master/slave, dual UART, emulated EEPROM, I2S audio input, I2S audio output, Servo
@@ -174,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
+1885 -58
View File
File diff suppressed because it is too large Load Diff
+1 -4
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
+1 -4
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
+2 -4
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
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;
};
+7 -6
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
@@ -130,7 +130,7 @@ static uint8_t *GetDescHIDReport(int *len) {
return __hid_report;
}
static void __SetupDescHIDReport() {
void __SetupDescHIDReport() {
if (__USBInstallKeyboard && __USBInstallMouse) {
uint8_t desc_hid_report[] = {
TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(1)),
@@ -179,7 +179,7 @@ const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
return usbd_desc_cfg;
}
static void __SetupUSBDescriptor() {
void __SetupUSBDescriptor() {
if (!usbd_desc_cfg) {
bool hasHID = __USBInstallKeyboard || __USBInstallMouse;
@@ -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);
}
+3 -3
View File
@@ -1,5 +1,5 @@
#pragma once
#define ARDUINO_PICO_MAJOR 2
#define ARDUINO_PICO_MINOR 1
#define ARDUINO_PICO_REVISION 0
#define ARDUINO_PICO_VERSION_STR "2.1.0"
#define ARDUINO_PICO_MINOR 3
#define ARDUINO_PICO_REVISION 1
#define ARDUINO_PICO_VERSION_STR "2.3.1"
+3 -2
View File
@@ -123,7 +123,7 @@ size_t SerialUSB::write(const uint8_t *buf, size_t length) {
}
static uint64_t last_avail_time;
int i = 0;
int written = 0;
if (tud_cdc_connected()) {
for (size_t i = 0; i < length;) {
int n = length - i;
@@ -136,6 +136,7 @@ size_t SerialUSB::write(const uint8_t *buf, size_t length) {
tud_task();
tud_cdc_write_flush();
i += n2;
written += n2;
last_avail_time = time_us_64();
} else {
tud_task();
@@ -150,7 +151,7 @@ size_t SerialUSB::write(const uint8_t *buf, size_t length) {
// reset our timeout
last_avail_time = 0;
}
return i;
return written;
}
SerialUSB::operator bool() {
+1 -4
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
+185 -66
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
+192 -59
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;
}
+83
View File
@@ -0,0 +1,83 @@
/*
Newlib retargetable lock class using RP2040 SDK
Overrides weak functions in Newlib for locking to safely support
multi-core operation. Does not need any --wrap for memory allocators.
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/mutex.h>
#include <sys/lock.h>
// HACK ALERT
// Pico-SDK defines mutex which can be at global scope, but when the auto_init_
// macros are used they are defined as static. Newlib needs global access to
// these mutextes, so instead of hacking pico-sdk just make "static" a no-op.
#define static
auto_init_recursive_mutex(__lock___sinit_recursive_mutex);
auto_init_recursive_mutex(__lock___sfp_recursive_mutex);
auto_init_recursive_mutex(__lock___atexit_recursive_mutex);
auto_init_mutex(__lock___at_quick_exit_mutex);
auto_init_recursive_mutex(__lock___malloc_recursive_mutex);
auto_init_recursive_mutex(__lock___env_recursive_mutex);
auto_init_mutex(__lock___tz_mutex);
auto_init_mutex(__lock___dd_hash_mutex);
auto_init_mutex(__lock___arc4random_mutex);
#undef static
void __retarget_lock_init(_LOCK_T *lock) {
mutex_init((mutex_t*) lock);
}
void __retarget_lock_init_recursive(_LOCK_T *lock) {
recursive_mutex_init((recursive_mutex_t*) lock);
}
void __retarget_lock_close(_LOCK_T lock) {
(void) lock;
}
void __retarget_lock_close_recursive(_LOCK_T lock) {
(void) lock;
}
void __retarget_lock_acquire(_LOCK_T lock) {
mutex_enter_blocking((mutex_t*)lock);
}
void __retarget_lock_acquire_recursive(_LOCK_T lock) {
recursive_mutex_enter_blocking((recursive_mutex_t*)lock);
}
int __retarget_lock_try_acquire(_LOCK_T lock) {
return mutex_try_enter((mutex_t *)lock, NULL);
}
int __retarget_lock_try_acquire_recursive(_LOCK_T lock) {
return recursive_mutex_try_enter((recursive_mutex_t*)lock, NULL);
}
void __retarget_lock_release(_LOCK_T lock) {
mutex_exit((mutex_t*)lock);
}
void __retarget_lock_release_recursive(_LOCK_T lock) {
recursive_mutex_exit((recursive_mutex_t*)lock);
}
+33 -1
View File
@@ -22,6 +22,8 @@
#include "RP2040USB.h"
#include <pico/stdlib.h>
#include <pico/multicore.h>
#include "LWIPMutex.h"
#include <reent.h>
RP2040 rp2040;
extern "C" {
@@ -30,6 +32,8 @@ extern "C" {
mutex_t _pioMutex;
int LWIPMutex::_ref = 0;
extern void setup();
extern void loop();
@@ -72,6 +76,7 @@ extern void __loop() {
arduino::serialEvent2Run();
}
}
static struct _reent *_impure_ptr1 = nullptr;
extern "C" int main() {
#if F_CPU != 125000000
@@ -81,6 +86,12 @@ extern "C" int main() {
// Let rest of core know if we're using FreeRTOS
__isFreeRTOS = initFreeRTOS ? true : false;
// Allocate impure_ptr (newlib temps) if there is a 2nd core running
if (!__isFreeRTOS && (setup1 || loop1)) {
_impure_ptr1 = (struct _reent*)calloc(sizeof(struct _reent), 1);
_REENT_INIT_PTR(_impure_ptr1);
}
mutex_init(&_pioMutex);
rp2040.begin();
@@ -118,7 +129,6 @@ extern "C" int main() {
if (!__isFreeRTOS) {
if (setup1 || loop1) {
rp2040.fifo.begin(2);
multicore_launch_core1(main1);
} else {
rp2040.fifo.begin(1);
}
@@ -127,6 +137,10 @@ extern "C" int main() {
#endif
if (!__isFreeRTOS) {
if (setup1 || loop1) {
delay(1); // Needed to make Picoprobe upload start 2nd core
multicore_launch_core1(main1);
}
setup();
while (true) {
loop();
@@ -142,3 +156,21 @@ extern "C" int main() {
extern "C" unsigned long ulMainGetRunTimeCounterValue() {
return rp2040.getCycleCount64();
}
extern "C" void __register_impure_ptr(struct _reent *p) {
if (get_core_num() == 0) {
_impure_ptr = p;
} else {
_impure_ptr1 = p;
}
}
// TODO: FreeRTOS should implement this based on thread ID (and each thread should have its own struct _reent
extern "C" struct _reent *__wrap___getreent() {
if (get_core_num() == 0) {
return _impure_ptr;
} else {
return _impure_ptr1;
}
}
@@ -0,0 +1,349 @@
/*
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);
// }
}
#ifdef ARDUINO_RASPBERRY_PI_PICO_W
void __attribute__((weak)) cyw43_cb_tcpip_init(cyw43_t *self, int itf);
void cyw43_cb_tcpip_init(cyw43_t *self, int itf) {
(void) self;
(void) itf;
}
void __attribute__((weak)) cyw43_cb_tcpip_deinit(cyw43_t *self, int itf);
void cyw43_cb_tcpip_deinit(cyw43_t *self, int itf) {
(void) self;
(void) itf;
}
void __attribute__((weak)) cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf);
void cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) {
(void) self;
(void) itf;
}
void __attribute__((weak)) cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf);
void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
(void) self;
(void) itf;
}
void __attribute__((weak)) cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf);
void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf) {
(void) cb_data;
(void) itf;
(void) len;
(void) buf;
}
#endif
#endif
+1 -5
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
+6 -3
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;
+5
View File
@@ -13,6 +13,11 @@ int analogRead(pin_size_t pin = A0..A3)
Returns a value from 0...4095 correspionding to the ADC reading
of the specific pin.
void analogReadResolution(int bits)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Determines the resolution (in bits) of the value returned by the analogRead() function.
Default resolution is 10bit.
float analogReadTemp()
~~~~~~~~~~~~~~~~~~~~~~
Returns the temperature, in Celsius, of the onboard thermal sensor.
+8
View File
@@ -6,6 +6,14 @@ Board-Specific Pins
The Raspberry Pi Pico RP2040 chip supports up to 30 digital I/O pins,
however not all boards provide access to all pins.
Input Modes
-----------
The Raspberry Pi Pico has 3 Input modes settings for use with `pinMode`: `INPUT`, `INPUT_PULLUP` and `INPUT_PULLDOWN`
Output Modes (Pad Strength)
---------------------------
The Raspberry Pi Pico has the ability to set the current that a pin (actually the pad associated with it) is capable of supplying. The current can be set to values of 2mA, 4mA, 8mA and 12mA. By default, on a reset, the setting is 4mA. A `pinMode(x, OUTPUT)`, where `x` is the pin number, is also the default setting. 4 settings have been added for use with `pinMode`: `OUTPUT_2MA`, `OUTPUT_4MA`, which has the same behavior as `OUTPUT`, `OUTPUT_8MA` and `OUTPUT_12MA`.
Tone/noTone
-----------
Simple square wave tone generation is possible for up to 8 channels using
Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+3 -1
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>
-5
View File
@@ -60,8 +60,3 @@ it use a non-default pinout with a simple call
SPI.setCS(5);
SD.begin(5);
}
Pad Strength
============
The Raspberry Pi Pico has the ability to set the current that a pin (actually the pad associated with it) is capable of supplying. The current can be set to values of 2mA, 4mA, 8mA and 12mA. By default, on a reset, the setting is 4mA. A `pinMode(x, OUTPUT)`, where `x` is the pin number, is also the default setting. 4 settings have been added for use with `pinMode`: `OUTPUT_2MA`, `OUTPUT_4MA`, which has the same behavior as `OUTPUT`, `OUTPUT_8MA` and `OUTPUT_12MA`.
+100 -14
View File
@@ -19,14 +19,14 @@ The PlatformIO experience:
Refer to the general documentation at https://docs.platformio.org/.
Especially useful is the `Getting started with VSCode + PlatformIO <https://docs.platformio.org/en/latest/integration/ide/vscode.html#installation), [CLI reference](https://docs.platformio.org/en/latest/core/index.html) and [platformio.ini options](https://docs.platformio.org/en/latest/projectconf/index.html)>`__ page.
Especially useful is the `Getting started with VSCode + PlatformIO <https://docs.platformio.org/en/latest/integration/ide/vscode.html#installation>`_, `CLI reference <https://docs.platformio.org/en/latest/core/index.html>`_ and the `platformio.ini options <https://docs.platformio.org/en/latest/projectconf/index.html>`_ page.
Hereafter it is assumed that you have a basic understanding of PlatformIO in regards to project creation, project file structure and building and uploading PlatformIO projects, through reading the above pages.
Current state of development
----------------------------
At the time of writing, PlatformIO integration for this core is a work-in-progress and not yet merged into mainline PlatformIO. This is subject to change soon.
At the time of writing, PlatformIO integration for this core is a work-in-progress and not yet merged into mainline PlatformIO. This is subject to change once `this pull request <https://github.com/platformio/platform-raspberrypi/pull/36>`_ is merged.
If you want to use the PlatformIO integration right now, make sure you first create a standard Raspberry Pi Pico + Arduino project within PlatformIO.
This will give you a project with the ``platformio.ini``
@@ -38,8 +38,7 @@ This will give you a project with the ``platformio.ini``
board = pico
framework = arduino
Here, you need to change the `platform` to take advantage of the features described hereunder.
You *also* need to inject two PlatformIO packages, one for the compiler toolchain and one for the Arduino core package.
Here, you need to change the `platform` to take advantage of the features described hereunder and switch to the new core.
.. code:: ini
@@ -47,12 +46,32 @@ You *also* need to inject two PlatformIO packages, one for the compiler toolchai
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
board = pico
framework = arduino
board_build.core = earlephilhower
When the support for this core has been merged into mainline PlatformIO, this notice will be removed and a standard `platformio.ini` as shown above will work as a base.
Deprecation warnings
---------------------
Previous versions of this documentation told users to inject the framework and toolchain package into the project by using
.. code:: ini
; note that download link for toolchain is specific for OS. see https://github.com/earlephilhower/pico-quick-toolchain/releases.
platform_packages =
maxgerhardt/framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git
maxgerhardt/toolchain-pico@https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.1-a/x86_64-w64-mingw32.arm-none-eabi-7855b0c.210706.zip
When the support for this core has been merged into mainline PlatformIO, this notice will be removed and a standard `platformio.ini` as shown above will work as a base.
This is now **deprecated** and should not be done anymore. Users should delete these ``platform_packages`` lines and update the platform integration by issuing the command
.. code:: bash
pio pkg update -g -p https://github.com/maxgerhardt/platform-raspberrypi.git
in the `PlatformIO CLI <https://docs.platformio.org/en/latest/integration/ide/vscode.html#platformio-core-cli>`_. The same can be achieved by using the VSCode PIO Home -> Platforms -> Updates GUI.
The toolchain, which was also renamed to ``toolchain-rp2040-earlephilhower`` is downloaded automatically from the registry. The same goes for the ``framework-arduinopico`` toolchain package, which points directly to the Arduino-Pico Github repository.
However, users can still select a custom fork or branch of the core if desired so, as detailed in a chapter below.
Selecting the new core
----------------------
@@ -61,8 +80,8 @@ Prerequisite for using this core is to tell PlatformIO to switch to it.
There will be board definition files where the Earle-Philhower core will
be the default since it's a board that only exists in this core (and not
the other https://github.com/arduino/ArduinoCore-mbed). To switch boards
for which this is not the default core (e.g. the standard
``board = pico``), the directive
for which this is not the default core (which are only
``board = pico`` and ``board = nanorp2040connect``), the directive
.. code:: ini
@@ -72,6 +91,8 @@ must be added to the ``platformio.ini``. This controls the `core
switching
logic <https://github.com/maxgerhardt/platform-raspberrypi/blob/77e0d3a29d1dbf00fd3ec3271104e3bf4820869c/builder/frameworks/arduino/arduino.py#L27-L32>`__.
When using Arduino-Pico-only boards like ``board = rpipico`` or ``board = adafruit_feather``, this is not needed.
Flash size
----------
@@ -154,6 +175,37 @@ either a sing line or a newline-separated expression.
-DDEBUG_RP2040_CORE
-DDEBUG_RP2040_PORT=Serial2
C++ Exceptions
--------------
Exceptions are disabled by default. To enable them, use
.. code:: ini
; Enable Exceptions
build_flags = -DPIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS
Stack Protector
---------------
To enable GCC's stack protection feature, use
.. code:: ini
; Enable Stack Protector
build_flags = -fstack-protector
RTTI
----
RTTI (run-time type information) is disabled by default. To enable it, use
.. code:: ini
; Enable RTTI
build_flags = -DPIO_FRAMEWORK_ARDUINO_ENABLE_RTTI
USB Stack
---------
@@ -188,8 +240,8 @@ directive to do so. Simply specify that the framework package
Whereas the ``#master`` can also be replaced by a ``#branchname`` or a
``#commithash``. If left out, it will pull the default branch, which is ``master``.
The ``file://`` pseudo-protocol can also be used instead of ``https://`` to point to a
local copy of the core (with e.g. some modifications) on disk.
The ``file://`` and ``symlink://`` pseudo-protocols can also be used instead of ``https://`` to point to a
local copy of the core (with e.g. some modifications) on disk (`see documentation <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_install.html?#local-folder>`_).
Note that this can only be done for versions that have the PlatformIO
builder script it in, so versions before 1.9.2 are not supported.
@@ -206,14 +258,48 @@ and 0.5MByte filesystem.
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
board = pico
framework = arduino
; board can use both Arduino cores -- we select Arduino-Pico here
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
; note that download link for toolchain is specific for OS. see https://github.com/earlephilhower/pico-quick-toolchain/releases.
platform_packages =
maxgerhardt/framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git
maxgerhardt/toolchain-pico@https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.1-a/x86_64-w64-mingw32.arm-none-eabi-7855b0c.210706.zip
The initial project structure should be generated just creating a new
project for the Pico and the Arduino framework, after which the
auto-generated ``platformio.ini`` can be adapted per above.
Debugging
---------
With recent updates to the toolchain and OpenOCD, debugging firmwares is also possible.
To specify the debugging adapter, use ``debug_tool`` (`documentation <https://docs.platformio.org/en/latest/projectconf/section_env_debug.html#debug-tool>`_). Supported values are:
* ``picoprobe``
* ``cmsis-dap``
* ``jlink``
* ``raspberrypi-swd``
These values can also be used in ``upload_protocol`` if you want PlatformIO to upload the regular firmware through this method, which you likely want.
Especially the PicoProbe method is convenient when you have two Raspberry Pi Pico boards. One of them can be flashed with the PicoProbe firmware (`documentation <https://www.raspberrypi.com/documentation/microcontrollers/raspberry-pi-pico.html#debugging-using-another-raspberry-pi-pico>`_) and is then connected to the target Raspberry Pi Pico board (see `documentation <https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf>`_ chapter "Picoprobe Wiring"). Remember that on Windows, you have to use `Zadig <https://zadig.akeo.ie/>`_ to also load "WinUSB" drivers for the "Picoprobe (Interface 2)" device so that OpenOCD can speak to it.
With that set up, debugging can be started via the left debugging sidebar and works nicely: Setup breakpoints, inspect the value of variables in the code, step through the code line by line. When a breakpoint is hit or execution is halted, you can even see the execution state both Cortex-M0+ cores of the RP2040.
.. image:: images/pio_debugging.png
For further information on customizing debug options, like the initial breakpoint or debugging / SWD speed, consult `the documentation <https://docs.platformio.org/en/latest/projectconf/section_env_debug.html>`_.
Filesystem Uploading
--------------------
For the Arduino IDE, `a plugin <https://github.com/earlephilhower/arduino-pico#uploading-filesystem-images>`_ is available that enables a data folder to be packed as a LittleFS filesystem binary and uploaded to the Pico.
This functionality is also built-in in the PlatformIO integration. Open the `project tasks <https://docs.platformio.org/en/latest/integration/ide/vscode.html#project-tasks>`_ and expand the "Platform" tasks:
.. image:: images/pio_fs_upload.png
The files you want to upload should be placed in a folder called ``data`` inside the project. This can be customized `if needed <https://docs.platformio.org/en/latest/projectconf/section_platformio.html#data-dir>`_.
The task "Build Filesystem Image" will take all files in the data directory and create a ``littlefs.bin`` file from it using the ``mklittlefs`` tool.
The task "Upload Filesystem Image" will upload the filesystem image to the Pico via the specified ``upload_protocol``.
+58
View File
@@ -46,3 +46,61 @@ Also, this stack requires sketches to manually call
sketch upload from the IDE. If a sketch is run without this command
in ``setup()``, the user will need to use the standard "hold BOOTSEL
and plug in USB" method to enter program upload mode.
Adafruit TinyUSB Configuration and Quirks
-----------------------------------------
The Adafruit TinyUSB's configuration header for RP2040 devices is stored
in ``libraries/Adafruit_TinyUSB_Arduino/src/arduino/ports/rp2040/tusb_config_rp2040.h`` (`here <https://github.com/adafruit/Adafruit_TinyUSB_Arduino/blob/master/src/arduino/ports/rp2040/tusb_config_rp2040.h>`__).
In some cases it is important to know what TinyUSB is configured with. For example, by having set
.. code:: cpp
#define CFG_TUD_CDC 1
#define CFG_TUD_MSC 1
#define CFG_TUD_HID 1
#define CFG_TUD_MIDI 1
#define CFG_TUD_VENDOR 1
this configuration file defines the maximum number of USB CDC (serial)
devices as 1. Hence, the example sketch `cdc_multi.ino <https://github.com/adafruit/Adafruit_TinyUSB_Arduino/blob/master/examples/CDC/cdc_multi/cdc_multi.ino>`__
that is delivered with the library will not work, it will only create one
USB CDC device instead of two. It will however work when the above
``CFG_TUD_CDC`` macro is defined to 2 instead of 1.
To do such a modification when using the Arduino IDE, the file can be
locally modified in the Arduino core's package files. The base path can
be found per `this article <https://support.arduino.cc/hc/en-us/articles/360018448279-Open-the-Arduino15-folder>`__,
then navigate further to the ``packages/rp2040/hardware/rp2040/<core version>/libraries/Adafruit_TinyUSB_Arduino``
folder to find the Adafruit TinyUSB library.
When using PlatformIO, one can also make use of the feature that TinyUSB
allows redirecting the configuration file to another one if a certain
macro is set.
.. code:: cpp
#ifdef CFG_TUSB_CONFIG_FILE
#include CFG_TUSB_CONFIG_FILE
#else
#include "tusb_config.h"
#endif
And as such, in the ``platformio.ini`` of the project, one can add
.. code:: ini
build_flags =
-DUSE_TINYUSB
-DCFG_TUSB_CONFIG_FILE=\"custom_tusb_config.h\"
-Iinclude/
and further add create the file ``include/custom_tusb_config.h`` as a copy
of the original ``tusb_config_rp2040.h`` but with the needed modifications.
*Note:* Some configuration file changes have no effect because upper levels
of the library don't properly support them. In particular, even though the
maximum number of HID devices can be set to 2, and two ``Adafruit_USBD_HID``
can be created, it will not cause two HID devices to actually show up, because
of `code limitations <https://github.com/adafruit/Adafruit_TinyUSB_Arduino/blob/7264c1492a73d9a285512752b03f2550841c06bc/src/arduino/hid/Adafruit_USBD_HID.cpp#L36-L37>`__.
+47
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
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
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
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>`__
BIN
View File
Binary file not shown.
+1 -1
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);
+3 -3
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 1
#define PICO_SDK_VERSION_STRING "1.3.1"
#define PICO_SDK_VERSION_MINOR 4
#define PICO_SDK_VERSION_REVISION 0
#define PICO_SDK_VERSION_STRING "1.4.0"
#endif
+4
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 -4
View File
@@ -71,7 +71,6 @@
-Wl,--wrap=atanf
-Wl,--wrap=atanh
-Wl,--wrap=atanhf
-Wl,--wrap=calloc
-Wl,--wrap=cbrt
-Wl,--wrap=cbrtf
-Wl,--wrap=ceil
@@ -105,7 +104,6 @@
-Wl,--wrap=fmaf
-Wl,--wrap=fmod
-Wl,--wrap=fmodf
-Wl,--wrap=free
-Wl,--wrap=hypot
-Wl,--wrap=hypotf
-Wl,--wrap=ldexp
@@ -118,7 +116,6 @@
-Wl,--wrap=log2
-Wl,--wrap=log2f
-Wl,--wrap=logf
-Wl,--wrap=malloc
-Wl,--wrap=memcpy
-Wl,--wrap=memset
-Wl,--wrap=__popcountdi2
@@ -127,7 +124,6 @@
-Wl,--wrap=powf
-Wl,--wrap=powint
-Wl,--wrap=powintf
-Wl,--wrap=realloc
-Wl,--wrap=remainder
-Wl,--wrap=remainderf
-Wl,--wrap=remquo
@@ -148,3 +144,4 @@
-Wl,--wrap=tanhf
-Wl,--wrap=trunc
-Wl,--wrap=truncf
-Wl,--wrap=__getreent
+1
View File
@@ -8,3 +8,4 @@ category=Timing
url=https://github.com/FreeRTOS/FreeRTOS-Kernel
architectures=rp2040
license=MIT
dot_a_linkage=true
+6
View File
@@ -27,6 +27,12 @@
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSTACK_DEPTH_TYPE uint32_t
#define configUSE_NEWLIB_REENTRANT 1
#define configNEWLIB_REENTRANT_IS_DYNAMIC 0 /* Note that we have a different config option, portSET_IMPURE_PTR */
#include <reent.h>
extern void __register_impure_ptr(struct _reent *p);
#define portSET_IMPURE_PTR(x) __register_impure_ptr(x)
/* Run time stats related definitions. */
void vMainConfigureTimerForRunTimeStats( void );
unsigned long ulMainGetRunTimeCounterValue( void );
+6
View File
@@ -409,10 +409,16 @@ static void __usb(void *param)
}
}
extern void __SetupDescHIDReport();
extern void __SetupUSBDescriptor();
void __USBStart()
{
mutex_init(&__usb_mutex);
__SetupDescHIDReport();
__SetupUSBDescriptor();
// Make highest prio and locked to core 0
xTaskCreate(__usb, "USB", 256, 0, configMAX_PRIORITIES - 1, &__usbTask);
vTaskCoreAffinitySet( __usbTask, 1 << 0 );
+1 -1
View File
@@ -7,4 +7,4 @@ paragraph=
category=Communication
url=http://www.arduino.cc/en/Reference/I2S
architectures=rp2040
dot_a_linkage=true
@@ -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);
}
+70
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
*/
@@ -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;
}
@@ -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();
}
+67
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
+11
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
+2
View File
@@ -0,0 +1,2 @@
// Since things may just work, we'll redirect for now
#include "WiFi.h"
+13
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"
+545
View File
@@ -0,0 +1,545 @@
/*
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);
}
#ifdef ARDUINO_RASPBERRY_PI_PICO_W
/* 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;
}
#endif
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;
+304
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;
+414
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);
//}
+169
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;
};
+220
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);
}
+109
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);
};
+263
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();
}
}
}
+113
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);
};
+300
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);
}
@@ -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
+687
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;
};
+581
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
+38
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
+83
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
+61
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
+10
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
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include <LwipIntfDev.h>
#include <utility/CYW43shim.h>
using CYW43lwIP = LwipIntfDev<CYW43>;
@@ -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;
}
@@ -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;
};
@@ -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
+256
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
@@ -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);
}
@@ -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;
}
+185
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;
}
+68
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);
};
@@ -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);
// });
// });
}
+545
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();
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "framework-arduinopico",
"version": "1.20100.0",
"version": "1.20301.0",
"description": "Arduino Wiring-based Framework (RPi Pico RP2040)",
"keywords": [
"framework",
-10
View File
@@ -116,16 +116,6 @@ sed "s/version=.*/version=$ver/g" |\
sed -E "s/name=([a-zA-Z0-9\ -]+).*/name=\1($ver)/g"\
> $outdir/platform.txt
# Put core version and short hash of git version into core_version.h
ver_define=`echo $plain_ver | tr "[:lower:].\055" "[:upper:]_"`
echo Ver define: $ver_define
echo \#define ARDUINO_RP2040_GIT_VER 0x`git rev-parse --short=8 HEAD 2>/dev/null` >$outdir/cores/rp2040/core_version.h
echo \#define ARDUINO_RP2040_GIT_DESC `git describe --tags 2>/dev/null` >>$outdir/cores/rp2040/core_version.h
echo \#define ARDUINO_RP2040_RELEASE_$ver_define >>$outdir/cores/rp2040/core_version.h
echo \#define ARDUINO_RP2040_RELEASE \"$ver_define\" >>$outdir/cores/rp2040/core_version.h
sed -i 's/"version": .*/"version": "'$visible_ver'"/' $outdir/package.json
# Zip the package
pushd package/versions/$visible_ver
echo "Making $package_name.zip"
+180 -171
View File
@@ -20,6 +20,9 @@
{
"name": "Raspberry Pi Pico"
},
{
"name": "Raspberry Pi Pico W"
},
{
"name": "Adafruit Feather RP2040"
},
@@ -27,13 +30,7 @@
"name": "Adafruit ItsyBitsy RP2040"
},
{
"name": "Adafruit KB2040"
},
{
"name": "Adafruit Macropad RP2040"
},
{
"name": "Adafruit QTPy RP2040"
"name": "Adafruit QT Py RP2040"
},
{
"name": "Adafruit STEMMA Friend RP2040"
@@ -41,6 +38,12 @@
{
"name": "Adafruit Trinkey RP2040 QT"
},
{
"name": "Adafruit MacroPad RP2040"
},
{
"name": "Adafruit KB2040"
},
{
"name": "Arduino Nano RP2040 Connect"
},
@@ -51,31 +54,37 @@
"name": "Cytron Maker Pi RP2040"
},
{
"name": "DeRuiLab FlyBoard2040 Core"
"name": "DeRuiLab FlyBoard2040Core"
},
{
"name": "DFRobot Beetle RP2040"
},
{
"name": "Invector Labs Challenger RP2040 WiFi"
"name": "iLabs Challenger 2040 LoRa"
},
{
"name": "Invector Labs Challenger RP2040 WiFi/BLE"
"name": "iLabs Challenger 2040 SubGHz"
},
{
"name": "Invector Labs Challenger NB RP2040 WiFi"
"name": "iLabs Challenger 2040 WiFi"
},
{
"name": "Invector Labs Challenger RP2040 LTE"
"name": "iLabs Challenger 2040 LTE"
},
{
"name": "Invector Labs Challenger RP2040 LoRa"
"name": "iLabs Challenger 2040 WiFi/BLE"
},
{
"name": "Invector Labs RPICO32"
"name": "iLabs Challenger NB 2040 WiFi"
},
{
"name": "Seeed XIAO RP2040"
"name": "iLabs Challenger 2040 SD/RTC"
},
{
"name": "iLabs RPICO32"
},
{
"name": "Melopero Shake RP2040"
},
{
"name": "Solder Party RP2040 Stamp"
@@ -87,43 +96,43 @@
"name": "SparkFun Thing Plus RP2040"
},
{
"name": "Melopero Shake RP2040"
"name": "uPesy RP2040 DevKit"
},
{
"name": "uPesy RP2040 DevKit"
"name": "Seeed XAIO RP2040"
},
{
"name": "WIZnet W5100S-EVB-Pico"
},
{
"name": "WIZnet 5500-EVB-Pico"
},
{
"name": "WIZnet WizFi360-EVB-Pico"
},
{
"name": "Generic RP2040 Module"
"name": "WIZnet W5500-EVB-Pico"
},
{
"name": "Generic RP2040"
}
],
"toolsDependencies": [
{
"packager": "rp2040",
"version": "1.3.4-c-5dd03b9",
"version": "1.4.0-c-0196c06",
"name": "pqt-gcc"
},
{
"packager": "rp2040",
"version": "1.3.4-c-5dd03b9",
"version": "1.4.0-c-0196c06",
"name": "pqt-mklittlefs"
},
{
"packager": "rp2040",
"version": "1.3.4-c-5dd03b9",
"version": "1.4.0-c-0196c06",
"name": "pqt-elf2uf2"
},
{
"packager": "rp2040",
"version": "1.3.4-c-5dd03b9",
"version": "1.4.0-c-0196c06",
"name": "pqt-pioasm"
},
{
@@ -133,7 +142,7 @@
},
{
"packager": "rp2040",
"version": "1.3.4-c-5dd03b9",
"version": "1.4.0-c-0196c06",
"name": "pqt-openocd"
}
],
@@ -144,57 +153,57 @@
],
"tools": [
{
"version": "1.3.4-c-5dd03b9",
"version": "1.4.0-c-0196c06",
"name": "pqt-openocd",
"systems": [
{
"host": "aarch64-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/aarch64-linux-gnu.openocd-e3428fadb.220607.tar.gz",
"archiveFileName": "aarch64-linux-gnu.openocd-e3428fadb.220607.tar.gz",
"checksum": "SHA-256:e796e6d2eac20cf90be4e61fc0a5ed16d1d26269cf749ec7829650d2595810b2",
"size": "5607245"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/aarch64-linux-gnu.openocd-e3428fadb.220714.tar.gz",
"archiveFileName": "aarch64-linux-gnu.openocd-e3428fadb.220714.tar.gz",
"checksum": "SHA-256:8da4fd922fd7392e87c0057b193e67962606cd13450af935c9846992f2bce916",
"size": "5607131"
},
{
"host": "arm-linux-gnueabihf",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/arm-linux-gnueabihf.openocd-e3428fadb.220607.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.openocd-e3428fadb.220607.tar.gz",
"checksum": "SHA-256:bbb9b2b1504555b1804538786074e776ebc4b2dded36f12f85a72ad6ba67f402",
"size": "5344211"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/arm-linux-gnueabihf.openocd-e3428fadb.220714.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.openocd-e3428fadb.220714.tar.gz",
"checksum": "SHA-256:ce7650961c8200fe2cc2d4a88efc952fe1bb7b4175f2cf650a9a7d992ae08298",
"size": "5344149"
},
{
"host": "i686-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/i686-linux-gnu.openocd-e3428fadb.220607.tar.gz",
"archiveFileName": "i686-linux-gnu.openocd-e3428fadb.220607.tar.gz",
"checksum": "SHA-256:7162ff1807748f11bb711b33c64139eae37b05d03458d9b0ac9a8e0d36aeb1a9",
"size": "5168326"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-linux-gnu.openocd-e3428fadb.220714.tar.gz",
"archiveFileName": "i686-linux-gnu.openocd-e3428fadb.220714.tar.gz",
"checksum": "SHA-256:9391ae74c6474f685f45ccefb82e18f382f1a59f3e13e2b22fe00967264d2482",
"size": "5168334"
},
{
"host": "i686-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/i686-w64-mingw32.openocd-e3428fadb.220607.zip",
"archiveFileName": "i686-w64-mingw32.openocd-e3428fadb.220607.zip",
"checksum": "SHA-256:3cbdcd63ca2084c9b479c781f8efefdec1481917c1fc3fe33d230ea38464e624",
"size": "2156819"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-w64-mingw32.openocd-e3428fadb.220714.zip",
"archiveFileName": "i686-w64-mingw32.openocd-e3428fadb.220714.zip",
"checksum": "SHA-256:f4b7803527a0a587fe95e52bcf056fcbe58d64b78705edd38810655d3abee1fe",
"size": "2156831"
},
{
"host": "x86_64-apple-darwin",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/x86_64-apple-darwin14.openocd-e3428fadb.220607.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.openocd-e3428fadb.220607.tar.gz",
"checksum": "SHA-256:1159ad88b998e040c2f33d8ce83e5e0130c4cf73c05320efe70ffdd1f6a52055",
"size": "2002498"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-apple-darwin14.openocd-e3428fadb.220714.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.openocd-e3428fadb.220714.tar.gz",
"checksum": "SHA-256:4e6a8da43758941478e6740e023ea5be051f09bf92e49d65c2b54a1ca4a2660c",
"size": "2002508"
},
{
"host": "x86_64-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/x86_64-linux-gnu.openocd-e3428fadb.220607.tar.gz",
"archiveFileName": "x86_64-linux-gnu.openocd-e3428fadb.220607.tar.gz",
"checksum": "SHA-256:388d53ab399bbac0c1ed097fc1bfe08788e765ee78faf970c6e06b1eeb88bdac",
"size": "5540543"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-linux-gnu.openocd-e3428fadb.220714.tar.gz",
"archiveFileName": "x86_64-linux-gnu.openocd-e3428fadb.220714.tar.gz",
"checksum": "SHA-256:2518c6451c0e4c148c8c6cb9330e216075177003b064c509b168f42a44a6eb5a",
"size": "5540574"
},
{
"host": "x86_64-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/x86_64-w64-mingw32.openocd-e3428fadb.220607.zip",
"archiveFileName": "x86_64-w64-mingw32.openocd-e3428fadb.220607.zip",
"checksum": "SHA-256:df3b5ed63c93f24a49ade6ecd1ec5bf84eb97677b7f3bd66e302b7871f20c2ed",
"size": "2156820"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-w64-mingw32.openocd-e3428fadb.220714.zip",
"archiveFileName": "x86_64-w64-mingw32.openocd-e3428fadb.220714.zip",
"checksum": "SHA-256:c2da993d74152ec8ca80b350ede77ee94942518081a48dafd7a3b49631778e75",
"size": "2156831"
}
]
},
@@ -261,222 +270,222 @@
]
},
{
"version": "1.3.4-c-5dd03b9",
"version": "1.4.0-c-0196c06",
"name": "pqt-gcc",
"systems": [
{
"host": "aarch64-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/aarch64-linux-gnu.arm-none-eabi-5dd03b9.220607.tar.gz",
"archiveFileName": "aarch64-linux-gnu.arm-none-eabi-5dd03b9.220607.tar.gz",
"checksum": "SHA-256:ec0bbb010f8acbcddcb4671a98eada560d6dd9ea2bc8c6a2247198eaa8b15be0",
"size": "78042296"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/aarch64-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
"archiveFileName": "aarch64-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
"checksum": "SHA-256:0bc906c2eb4b3999285ea8a71ec0c95a20a21f2ff46b1bdd264f2fd3c30fe580",
"size": "77889379"
},
{
"host": "arm-linux-gnueabihf",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/arm-linux-gnueabihf.arm-none-eabi-5dd03b9.220607.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.arm-none-eabi-5dd03b9.220607.tar.gz",
"checksum": "SHA-256:c18839a74fe1ec1b449d80e6b7de358bd1d9444ff454edaf57d79fe2f734d60e",
"size": "73499374"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/arm-linux-gnueabihf.arm-none-eabi-0196c06.220714.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.arm-none-eabi-0196c06.220714.tar.gz",
"checksum": "SHA-256:2bf9f691d1fa97cea3b835a364fc24d06102181725001a00fe3e77526f90e2bd",
"size": "73342377"
},
{
"host": "i686-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/i686-linux-gnu.arm-none-eabi-5dd03b9.220607.tar.gz",
"archiveFileName": "i686-linux-gnu.arm-none-eabi-5dd03b9.220607.tar.gz",
"checksum": "SHA-256:e6546899155267e5539889764610439fdbeba38df0e498a9fd643aad13ba49f0",
"size": "79642507"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
"archiveFileName": "i686-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
"checksum": "SHA-256:e0fe347f2602247ffbc16bb7b74653fdb78c4f75b90037f2e82fc5498b5d1cb9",
"size": "79511866"
},
{
"host": "i686-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/i686-w64-mingw32.arm-none-eabi-5dd03b9.220607.zip",
"archiveFileName": "i686-w64-mingw32.arm-none-eabi-5dd03b9.220607.zip",
"checksum": "SHA-256:867c4bc810db9388fe0d814fc21ac81479a1e2be1c45f8e150981bb33846e04d",
"size": "82878616"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-w64-mingw32.arm-none-eabi-0196c06.220714.zip",
"archiveFileName": "i686-w64-mingw32.arm-none-eabi-0196c06.220714.zip",
"checksum": "SHA-256:d1ee0f00c97dc50dc06487d6fb6b5dd94bbb3cf1579c975bcd23d7a7922e53b7",
"size": "82626868"
},
{
"host": "x86_64-apple-darwin",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/x86_64-apple-darwin14.arm-none-eabi-5dd03b9.220607.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.arm-none-eabi-5dd03b9.220607.tar.gz",
"checksum": "SHA-256:ef91ab4e0d7a66b3ae683d6d4b5ca8526eab7a7572a3aec60dd6a04795061bbe",
"size": "82271912"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-apple-darwin14.arm-none-eabi-0196c06.220714.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.arm-none-eabi-0196c06.220714.tar.gz",
"checksum": "SHA-256:1b030451a5a6ddf42ac796c46b2f077f90f6d56586f4537a3486ce47670996cd",
"size": "82119254"
},
{
"host": "x86_64-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/x86_64-linux-gnu.arm-none-eabi-5dd03b9.220607.tar.gz",
"archiveFileName": "x86_64-linux-gnu.arm-none-eabi-5dd03b9.220607.tar.gz",
"checksum": "SHA-256:59d16d192b8f623261f2c0605164da24e9257b1de210c367ea872131ef4d9f45",
"size": "80508303"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
"archiveFileName": "x86_64-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
"checksum": "SHA-256:73d032ba42d33f6e9c1d5de79b73bf5e9740b8e6b7fee37de3db03814c553694",
"size": "80363125"
},
{
"host": "x86_64-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/x86_64-w64-mingw32.arm-none-eabi-5dd03b9.220607.zip",
"archiveFileName": "x86_64-w64-mingw32.arm-none-eabi-5dd03b9.220607.zip",
"checksum": "SHA-256:b140ec4e5986b73249a6350a53d9826ad5d74a8a2af12adf3d6c13bebc720c88",
"size": "86320223"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-w64-mingw32.arm-none-eabi-0196c06.220714.zip",
"archiveFileName": "x86_64-w64-mingw32.arm-none-eabi-0196c06.220714.zip",
"checksum": "SHA-256:3f67e15adbe49ebaee72734e9d469bd6b34fd1be30ccdb6e55a1e05a0be4e1db",
"size": "86064664"
}
]
},
{
"version": "1.3.4-c-5dd03b9",
"version": "1.4.0-c-0196c06",
"name": "pqt-elf2uf2",
"systems": [
{
"host": "aarch64-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/aarch64-linux-gnu.elf2uf2-2062372.220607.tar.gz",
"archiveFileName": "aarch64-linux-gnu.elf2uf2-2062372.220607.tar.gz",
"checksum": "SHA-256:a98b46d71e837927867789810b8577dcbc8f53c618adb9bb4083c1e2fa1cf483",
"size": "79853"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/aarch64-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
"archiveFileName": "aarch64-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
"checksum": "SHA-256:14d7c1be08151bcddcc19fdb5741bf52b435f08f52daff2d498a07c5ebfb5bfb",
"size": "82682"
},
{
"host": "arm-linux-gnueabihf",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/arm-linux-gnueabihf.elf2uf2-2062372.220607.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.elf2uf2-2062372.220607.tar.gz",
"checksum": "SHA-256:64df2a9dbc6b5546a07bd15c26c4b6e0310d0b937e5d921f83b0f51ef02f1734",
"size": "54249"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/arm-linux-gnueabihf.elf2uf2-2e6142b.220714.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.elf2uf2-2e6142b.220714.tar.gz",
"checksum": "SHA-256:31b790b5a19bbb5950212098aa42be43702fb4db50aa541c9f40b2320e2280be",
"size": "55991"
},
{
"host": "i686-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/i686-linux-gnu.elf2uf2-2062372.220607.tar.gz",
"archiveFileName": "i686-linux-gnu.elf2uf2-2062372.220607.tar.gz",
"checksum": "SHA-256:1b877ef797c281b5dd2f4d98409ba83db120e528aac94f4a9a34effa2262eaa7",
"size": "87893"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
"archiveFileName": "i686-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
"checksum": "SHA-256:a3dd93861857fd81f8c9ed01509a0af012f446f23f405bc696f6a4d2f344262c",
"size": "91386"
},
{
"host": "i686-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/i686-w64-mingw32.elf2uf2-2062372.220607.zip",
"archiveFileName": "i686-w64-mingw32.elf2uf2-2062372.220607.zip",
"checksum": "SHA-256:eed4693771f27851092d182e8477eee9c393cce7ddffde18d7492e78bd65140c",
"size": "70405"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-w64-mingw32.elf2uf2-2e6142b.220714.zip",
"archiveFileName": "i686-w64-mingw32.elf2uf2-2e6142b.220714.zip",
"checksum": "SHA-256:25d6a934643074590c3006468ec051f62d02298abbff27d7e3643ee147e818e0",
"size": "71949"
},
{
"host": "x86_64-apple-darwin",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/x86_64-apple-darwin14.elf2uf2-2062372.220607.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.elf2uf2-2062372.220607.tar.gz",
"checksum": "SHA-256:af65feef470ce6b4b48102ea996703890f8d8d9604207f0781022b7912ce2cbd",
"size": "81982"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-apple-darwin14.elf2uf2-2e6142b.220714.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.elf2uf2-2e6142b.220714.tar.gz",
"checksum": "SHA-256:f2743d086d1992599d656aaa9a38a736d443bdc96619fd5bcabdc7fcb05225c8",
"size": "86600"
},
{
"host": "x86_64-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/x86_64-linux-gnu.elf2uf2-2062372.220607.tar.gz",
"archiveFileName": "x86_64-linux-gnu.elf2uf2-2062372.220607.tar.gz",
"checksum": "SHA-256:968240efe170187c4ece497c7abbb81bca274b6484f0df28e2b7a12e1c088f5f",
"size": "79588"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
"archiveFileName": "x86_64-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
"checksum": "SHA-256:5b0e79bfd9d7e5f4d5e5cb0e6e2b685e10fdf3071139c00bf6274a5ca9b9717e",
"size": "82339"
},
{
"host": "x86_64-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/x86_64-w64-mingw32.elf2uf2-2062372.220607.zip",
"archiveFileName": "x86_64-w64-mingw32.elf2uf2-2062372.220607.zip",
"checksum": "SHA-256:04b85b5b515ec620a5b4106fb1025485de0b3d36482aab7024088e618e605e9d",
"size": "78280"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-w64-mingw32.elf2uf2-2e6142b.220714.zip",
"archiveFileName": "x86_64-w64-mingw32.elf2uf2-2e6142b.220714.zip",
"checksum": "SHA-256:f09e022cbb1fe73315ccf16a2af6bc687b64d0c44066f801fb9dee8326e941b1",
"size": "80399"
}
]
},
{
"version": "1.3.4-c-5dd03b9",
"version": "1.4.0-c-0196c06",
"name": "pqt-pioasm",
"systems": [
{
"host": "aarch64-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/aarch64-linux-gnu.pioasm-2062372.220607.tar.gz",
"archiveFileName": "aarch64-linux-gnu.pioasm-2062372.220607.tar.gz",
"checksum": "SHA-256:d08d22b2eecbf17a8afd199eb4ce89c0f6fe2ffa90408d7762d4de7f91c88e13",
"size": "453559"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/aarch64-linux-gnu.pioasm-2e6142b.220714.tar.gz",
"archiveFileName": "aarch64-linux-gnu.pioasm-2e6142b.220714.tar.gz",
"checksum": "SHA-256:d4ac4b39841984178babd75f5c09cad87e06bd2fb18cf04e40f561d72e604a5d",
"size": "453440"
},
{
"host": "arm-linux-gnueabihf",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/arm-linux-gnueabihf.pioasm-2062372.220607.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.pioasm-2062372.220607.tar.gz",
"checksum": "SHA-256:7bc20faea8b8d115fec189248b3dd3470128d0f7da855a61cb8a1fb6d4955450",
"size": "360566"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/arm-linux-gnueabihf.pioasm-2e6142b.220714.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.pioasm-2e6142b.220714.tar.gz",
"checksum": "SHA-256:568ebdd7b1a47c6dbf45793f9bf019855a1b14182fbeb7ed7e342979c6632eef",
"size": "360675"
},
{
"host": "i686-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/i686-linux-gnu.pioasm-2062372.220607.tar.gz",
"archiveFileName": "i686-linux-gnu.pioasm-2062372.220607.tar.gz",
"checksum": "SHA-256:b8d26abd632e9599bc82c67619debac45fca0e5dd0daabe5a0ecad4cfd11183e",
"size": "511402"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-linux-gnu.pioasm-2e6142b.220714.tar.gz",
"archiveFileName": "i686-linux-gnu.pioasm-2e6142b.220714.tar.gz",
"checksum": "SHA-256:2abac2bef690f7ffadfcf74af4832bfcc0e212606efbed21b385bda0517554ef",
"size": "511442"
},
{
"host": "i686-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/i686-w64-mingw32.pioasm-2062372.220607.zip",
"archiveFileName": "i686-w64-mingw32.pioasm-2062372.220607.zip",
"checksum": "SHA-256:ab52ae2fd59fe3093060a238297f88d50645dca02cd12f59e882ce7cb4533b25",
"size": "385748"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-w64-mingw32.pioasm-2e6142b.220714.zip",
"archiveFileName": "i686-w64-mingw32.pioasm-2e6142b.220714.zip",
"checksum": "SHA-256:0b1336b999a31d164248248d37fa550aa14a06dae8ef5b215818c5f0597ca80b",
"size": "385882"
},
{
"host": "x86_64-apple-darwin",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/x86_64-apple-darwin14.pioasm-2062372.220607.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.pioasm-2062372.220607.tar.gz",
"checksum": "SHA-256:fb22e0c5d6b3e681a8518992a8183b277ebeb5a3876b1c98a247dda4e2c495e7",
"size": "480494"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-apple-darwin14.pioasm-2e6142b.220714.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.pioasm-2e6142b.220714.tar.gz",
"checksum": "SHA-256:7057ba222a54ff9bd43a6a4232a6355100f29e0cc20d3facb5d600180f418e68",
"size": "480538"
},
{
"host": "x86_64-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/x86_64-linux-gnu.pioasm-2062372.220607.tar.gz",
"archiveFileName": "x86_64-linux-gnu.pioasm-2062372.220607.tar.gz",
"checksum": "SHA-256:f5ea7d22357db358c7185896858463d63310391678bf7425f203cc2baf35789d",
"size": "458726"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-linux-gnu.pioasm-2e6142b.220714.tar.gz",
"archiveFileName": "x86_64-linux-gnu.pioasm-2e6142b.220714.tar.gz",
"checksum": "SHA-256:30b367e8d2cd4ccdf151e728b4137bad1d993c42f0d640307e27d5fc55fce2c0",
"size": "458691"
},
{
"host": "x86_64-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/x86_64-w64-mingw32.pioasm-2062372.220607.zip",
"archiveFileName": "x86_64-w64-mingw32.pioasm-2062372.220607.zip",
"checksum": "SHA-256:5b63d07bb53ec4e25817d3a1195cd03f156c47dc00c5fdaf4921edb1baa9da9c",
"size": "408649"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-w64-mingw32.pioasm-2e6142b.220714.zip",
"archiveFileName": "x86_64-w64-mingw32.pioasm-2e6142b.220714.zip",
"checksum": "SHA-256:b7b340862e673f9e57287f02219b2d56094a497fe9d8c451acf28aaef721e038",
"size": "409101"
}
]
},
{
"version": "1.3.4-c-5dd03b9",
"version": "1.4.0-c-0196c06",
"name": "pqt-mklittlefs",
"systems": [
{
"host": "aarch64-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/aarch64-linux-gnu.mklittlefs-affa497.220607.tar.gz",
"archiveFileName": "aarch64-linux-gnu.mklittlefs-affa497.220607.tar.gz",
"checksum": "SHA-256:46a2ee723b6dcad3f229aa6f97a8efd55224f7aafea77ac5c232aa5261720589",
"size": "47271"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/aarch64-linux-gnu.mklittlefs-affa497.220714.tar.gz",
"archiveFileName": "aarch64-linux-gnu.mklittlefs-affa497.220714.tar.gz",
"checksum": "SHA-256:ad0af70d568e10a9a2a74c6e0a3cf8659a47b80fbf594b01731579bc21a5c212",
"size": "47287"
},
{
"host": "arm-linux-gnueabihf",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/arm-linux-gnueabihf.mklittlefs-affa497.220607.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.mklittlefs-affa497.220607.tar.gz",
"checksum": "SHA-256:39462b3b88b614484c9fbfd7617af17440f9de4ddeb17bdb62b7bc615cae3a18",
"size": "40810"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/arm-linux-gnueabihf.mklittlefs-affa497.220714.tar.gz",
"archiveFileName": "arm-linux-gnueabihf.mklittlefs-affa497.220714.tar.gz",
"checksum": "SHA-256:f8f1a1dd7b02220f11cf0f6a6c88692f7e056eb245fbc41017c33d333751980e",
"size": "40826"
},
{
"host": "i686-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/i686-linux-gnu.mklittlefs-affa497.220607.tar.gz",
"archiveFileName": "i686-linux-gnu.mklittlefs-affa497.220607.tar.gz",
"checksum": "SHA-256:c8eb593e6fc8bdc386566a72dd9a75f970a9a71fd4e069c0dca217cbe4b22060",
"size": "50913"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-linux-gnu.mklittlefs-affa497.220714.tar.gz",
"archiveFileName": "i686-linux-gnu.mklittlefs-affa497.220714.tar.gz",
"checksum": "SHA-256:4d10a2bc6a8fa41a7e5642aa30128f797f84b099e1bb2282c6c2d62a06e81e21",
"size": "50925"
},
{
"host": "i686-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/i686-w64-mingw32.mklittlefs-affa497.220607.zip",
"archiveFileName": "i686-w64-mingw32.mklittlefs-affa497.220607.zip",
"checksum": "SHA-256:6fc3c989850ab4acf00509b86c77edf1cdd2f38ec95c3614ed633f8131d3f86d",
"size": "334050"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-w64-mingw32.mklittlefs-affa497.220714.zip",
"archiveFileName": "i686-w64-mingw32.mklittlefs-affa497.220714.zip",
"checksum": "SHA-256:71117412351ea2486848848d76f4d1e3c7a507a4d7546f6b0646bbc10c96d557",
"size": "334062"
},
{
"host": "x86_64-apple-darwin",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/x86_64-apple-darwin14.mklittlefs-affa497.220607.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.mklittlefs-affa497.220607.tar.gz",
"checksum": "SHA-256:a949b054259cea773779305f60b2748b51e1f40c53fe7c00ae3959d6688ce754",
"size": "365751"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-apple-darwin14.mklittlefs-affa497.220714.tar.gz",
"archiveFileName": "x86_64-apple-darwin14.mklittlefs-affa497.220714.tar.gz",
"checksum": "SHA-256:b3d0c30f942982337cd4c0e4f70855f8eabcf1d378eac78465c7fee39ab5915f",
"size": "365780"
},
{
"host": "x86_64-pc-linux-gnu",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/x86_64-linux-gnu.mklittlefs-affa497.220607.tar.gz",
"archiveFileName": "x86_64-linux-gnu.mklittlefs-affa497.220607.tar.gz",
"checksum": "SHA-256:d1910196398bdeffae320cb69b1df79126ea086688d9e36a078dd0816f88dace",
"size": "49774"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-linux-gnu.mklittlefs-affa497.220714.tar.gz",
"archiveFileName": "x86_64-linux-gnu.mklittlefs-affa497.220714.tar.gz",
"checksum": "SHA-256:9241e8e642748048bd32c7ccf4a8200e8bc104d6e328fe7437e8727866f29d94",
"size": "49787"
},
{
"host": "x86_64-mingw32",
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.4-c/x86_64-w64-mingw32.mklittlefs-affa497.220607.zip",
"archiveFileName": "x86_64-w64-mingw32.mklittlefs-affa497.220607.zip",
"checksum": "SHA-256:8be0f754073e036dc9a144fd3cf62a46fbd6d215cad179c2ba17e598848a1b57",
"size": "347601"
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-w64-mingw32.mklittlefs-affa497.220714.zip",
"archiveFileName": "x86_64-w64-mingw32.mklittlefs-affa497.220714.zip",
"checksum": "SHA-256:2f39dd727e9cb61dbc631d00f543a99b6224fb24ffde0dff0cb2b70c9561ae69",
"size": "347612"
}
]
}
+6 -5
View File
@@ -20,7 +20,7 @@
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
name=Raspberry Pi RP2040 Boards
version=2.1.0
version=2.3.1
runtime.tools.pqt-gcc.path={runtime.platform.path}/system/arm-none-eabi
runtime.tools.pqt-python3.path={runtime.platform.path}/system/python3
@@ -41,20 +41,21 @@ 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"
compiler.c.cmd=arm-none-eabi-gcc
compiler.c.flags=-c {compiler.warning_flags} {compiler.defines} {compiler.flags} {compiler.includes} -std=gnu17 -g
compiler.c.flags=-c {compiler.warning_flags} {compiler.defines} {compiler.flags} -MMD {compiler.includes} -std=gnu17 -g
compiler.c.elf.cmd=arm-none-eabi-g++
compiler.c.elf.flags={compiler.warning_flags} {compiler.defines} {compiler.flags} {build.flags.optimize} -u _printf_float -u _scanf_float
compiler.S.cmd=arm-none-eabi-gcc
compiler.S.flags=-c {compiler.warning_flags} -g -x assembler-with-cpp -MMD {compiler.includes} -g
compiler.cpp.cmd=arm-none-eabi-g++
compiler.cpp.flags=-c {compiler.warning_flags} {compiler.defines} {compiler.flags} {compiler.includes} {build.flags.rtti} -std=gnu++17 -g
compiler.cpp.flags=-c {compiler.warning_flags} {compiler.defines} {compiler.flags} -MMD {compiler.includes} {build.flags.rtti} -std=gnu++17 -g
compiler.ar.cmd=arm-none-eabi-ar
compiler.ar.flags=rcs
+2
View File
@@ -23,6 +23,8 @@ function skip_ino()
/msc_sd/
/msc_sdfat/
/midi_pizza_box_dj/
/msc_esp32_file_browser/
/DualRole/
EOL
echo $ino | grep -q -F "$skiplist"
echo $(( 1 - $? ))
+2 -1
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
+2
View File
@@ -65,6 +65,8 @@ def compile(tmp_dir, sketch, cache, tools_dir, hardware_dir, ide_path, f, args):
'dbgport={dbgport},' \
'dbglvl={dbglvl},' \
'usbstack={usbstack}'.format(**vars(args))
if "/WiFi" in sketch:
fqbn = fqbn.replace("rpipico", "rpipicow")
cmd += [fqbn]
cmd += ['-built-in-libraries', ide_path + '/libraries']
cmd += ['-ide-version=10607']
+9 -11
View File
@@ -1,5 +1,12 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25x10cl_4_padded_checksum.S",
"usb_vid": "0x239a",
"usb_pid": "0x80f1"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_ADAFRUIT_FEATHER_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
@@ -11,16 +18,7 @@
]
],
"mcu": "rp2040",
"arduino": {
"earlephilhower": {
"variant": "adafruit_feather",
"boot2_source": "boot2_w25x10cl_4_padded_checksum.S",
"usb_vid": "0x239a",
"usb_pid": "0x80f1",
"usb_manufacturer": "Adafruit",
"usb_product": "Feather RP2040"
}
}
"variant": "adafruit_feather"
},
"debug": {
"jlink_device": "RP2040_M0_0",
@@ -49,4 +47,4 @@
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "Adafruit"
}
}
+9 -11
View File
@@ -1,5 +1,12 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x239a",
"usb_pid": "0x80fd"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_ADAFRUIT_ITSYBITSY_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
@@ -11,16 +18,7 @@
]
],
"mcu": "rp2040",
"arduino": {
"earlephilhower": {
"variant": "adafruit_itsybitsy",
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x239a",
"usb_pid": "0x80fd",
"usb_manufacturer": "Adafruit",
"usb_product": "ItsyBitsy RP2040"
}
}
"variant": "adafruit_itsybitsy"
},
"debug": {
"jlink_device": "RP2040_M0_0",
@@ -49,4 +47,4 @@
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "Adafruit"
}
}
+9 -11
View File
@@ -1,5 +1,12 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x239a",
"usb_pid": "0x8105"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_ADAFRUIT_KB2040_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
@@ -11,16 +18,7 @@
]
],
"mcu": "rp2040",
"arduino": {
"earlephilhower": {
"variant": "adafruit_kb2040",
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x239a",
"usb_pid": "0x8105",
"usb_manufacturer": "Adafruit",
"usb_product": "KB2040"
}
}
"variant": "adafruit_kb2040"
},
"debug": {
"jlink_device": "RP2040_M0_0",
@@ -49,4 +47,4 @@
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "Adafruit"
}
}
+9 -11
View File
@@ -1,5 +1,12 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x239a",
"usb_pid": "0x8107"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_ADAFRUIT_MACROPAD_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
@@ -11,16 +18,7 @@
]
],
"mcu": "rp2040",
"arduino": {
"earlephilhower": {
"variant": "adafruit_macropad2040",
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x239a",
"usb_pid": "0x8107",
"usb_manufacturer": "Adafruit",
"usb_product": "MacroPad RP2040"
}
}
"variant": "adafruit_macropad2040"
},
"debug": {
"jlink_device": "RP2040_M0_0",
@@ -49,4 +47,4 @@
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "Adafruit"
}
}
+9 -11
View File
@@ -1,5 +1,12 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x239a",
"usb_pid": "0x80f7"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_ADAFRUIT_QTPY_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
@@ -11,16 +18,7 @@
]
],
"mcu": "rp2040",
"arduino": {
"earlephilhower": {
"variant": "adafruit_qtpy",
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x239a",
"usb_pid": "0x80f7",
"usb_manufacturer": "Adafruit",
"usb_product": "QT Py RP2040"
}
}
"variant": "adafruit_qtpy"
},
"debug": {
"jlink_device": "RP2040_M0_0",
@@ -49,4 +47,4 @@
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "Adafruit"
}
}
+9 -11
View File
@@ -1,5 +1,12 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x239a",
"usb_pid": "0x80e3"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_ADAFRUIT_STEMMAFRIEND_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
@@ -11,16 +18,7 @@
]
],
"mcu": "rp2040",
"arduino": {
"earlephilhower": {
"variant": "adafruit_stemmafriend",
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x239a",
"usb_pid": "0x80e3",
"usb_manufacturer": "Adafruit",
"usb_product": "STEMMA Friend RP2040"
}
}
"variant": "adafruit_stemmafriend"
},
"debug": {
"jlink_device": "RP2040_M0_0",
@@ -49,4 +47,4 @@
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "Adafruit"
}
}
+9 -11
View File
@@ -1,5 +1,12 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x239a",
"usb_pid": "0x8109"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_ADAFRUIT_TRINKEYQT_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
@@ -11,16 +18,7 @@
]
],
"mcu": "rp2040",
"arduino": {
"earlephilhower": {
"variant": "adafruit_trinkeyrp2040qt",
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x239a",
"usb_pid": "0x8109",
"usb_manufacturer": "Adafruit",
"usb_product": "Trinkey RP2040 QT"
}
}
"variant": "adafruit_trinkeyrp2040qt"
},
"debug": {
"jlink_device": "RP2040_M0_0",
@@ -49,4 +47,4 @@
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "Adafruit"
}
}
+9 -11
View File
@@ -1,5 +1,12 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2341",
"usb_pid": "0x0058"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_NANO_RP2040_CONNECT -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
@@ -11,16 +18,7 @@
]
],
"mcu": "rp2040",
"arduino": {
"earlephilhower": {
"variant": "arduino_nano_connect",
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2341",
"usb_pid": "0x0058",
"usb_manufacturer": "Arduino",
"usb_product": "Nano RP2040 Connect"
}
}
"variant": "arduino_nano_connect"
},
"debug": {
"jlink_device": "RP2040_M0_0",
@@ -49,4 +47,4 @@
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "Arduino"
}
}
+9 -11
View File
@@ -1,5 +1,12 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2e8a",
"usb_pid": "0x1023"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_CHALLENGER_2040_LORA_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
@@ -11,16 +18,7 @@
]
],
"mcu": "rp2040",
"arduino": {
"earlephilhower": {
"variant": "challenger_2040_lora",
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2e8a",
"usb_pid": "0x1023",
"usb_manufacturer": "iLabs",
"usb_product": "Challenger 2040 LoRa"
}
}
"variant": "challenger_2040_lora"
},
"debug": {
"jlink_device": "RP2040_M0_0",
@@ -49,4 +47,4 @@
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "iLabs"
}
}
+9 -11
View File
@@ -1,5 +1,12 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2e8a",
"usb_pid": "0x100b"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_CHALLENGER_2040_LTE_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
@@ -11,16 +18,7 @@
]
],
"mcu": "rp2040",
"arduino": {
"earlephilhower": {
"variant": "challenger_2040_lte",
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2e8a",
"usb_pid": "0x100b",
"usb_manufacturer": "iLabs",
"usb_product": "Challenger 2040 LTE"
}
}
"variant": "challenger_2040_lte"
},
"debug": {
"jlink_device": "RP2040_M0_0",
@@ -49,4 +47,4 @@
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "iLabs"
}
}
+50
View File
@@ -0,0 +1,50 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2e8a",
"usb_pid": "0x102d"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_CHALLENGER_NB_2040_SDRTC_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
"f_cpu": "133000000L",
"hwids": [
[
"0x2E8A",
"0x00C0"
]
],
"mcu": "rp2040",
"variant": "challenger_2040_sdrtc"
},
"debug": {
"jlink_device": "RP2040_M0_0",
"openocd_target": "rp2040.cfg",
"svd_path": "rp2040.svd"
},
"frameworks": [
"arduino"
],
"name": "Challenger 2040 SD/RTC",
"upload": {
"maximum_ram_size": 270336,
"maximum_size": 8388608,
"require_upload_port": true,
"native_usb": true,
"use_1200bps_touch": true,
"wait_for_upload_port": false,
"protocol": "picotool",
"protocols": [
"cmsis-dap",
"jlink",
"raspberrypi-swd",
"picotool",
"picoprobe"
]
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "iLabs"
}
+50
View File
@@ -0,0 +1,50 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2e8a",
"usb_pid": "0x1032"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_CHALLENGER_2040_SUBGHZ_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
"f_cpu": "133000000L",
"hwids": [
[
"0x2E8A",
"0x00C0"
]
],
"mcu": "rp2040",
"variant": "challenger_2040_subghz"
},
"debug": {
"jlink_device": "RP2040_M0_0",
"openocd_target": "rp2040.cfg",
"svd_path": "rp2040.svd"
},
"frameworks": [
"arduino"
],
"name": "Challenger 2040 SubGHz",
"upload": {
"maximum_ram_size": 270336,
"maximum_size": 8388608,
"require_upload_port": true,
"native_usb": true,
"use_1200bps_touch": true,
"wait_for_upload_port": false,
"protocol": "picotool",
"protocols": [
"cmsis-dap",
"jlink",
"raspberrypi-swd",
"picotool",
"picoprobe"
]
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "iLabs"
}
+9 -11
View File
@@ -1,5 +1,12 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2e8a",
"usb_pid": "0x1006"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_CHALLENGER_2040_WIFI_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
@@ -11,16 +18,7 @@
]
],
"mcu": "rp2040",
"arduino": {
"earlephilhower": {
"variant": "challenger_2040_wifi",
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2e8a",
"usb_pid": "0x1006",
"usb_manufacturer": "iLabs",
"usb_product": "Challenger 2040 WiFi"
}
}
"variant": "challenger_2040_wifi"
},
"debug": {
"jlink_device": "RP2040_M0_0",
@@ -49,4 +47,4 @@
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "iLabs"
}
}
+9 -11
View File
@@ -1,5 +1,12 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2e8a",
"usb_pid": "0x102C"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_CHALLENGER_2040_WIFI_BLE_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
@@ -11,16 +18,7 @@
]
],
"mcu": "rp2040",
"arduino": {
"earlephilhower": {
"variant": "challenger_2040_wifi_ble",
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2e8a",
"usb_pid": "0x102C",
"usb_manufacturer": "iLabs",
"usb_product": "Challenger 2040 WiFi/BLE"
}
}
"variant": "challenger_2040_wifi_ble"
},
"debug": {
"jlink_device": "RP2040_M0_0",
@@ -49,4 +47,4 @@
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "iLabs"
}
}
+9 -11
View File
@@ -1,5 +1,12 @@
{
"build": {
"arduino": {
"earlephilhower": {
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2e8a",
"usb_pid": "0x100b"
}
},
"core": "earlephilhower",
"cpu": "cortex-m0plus",
"extra_flags": "-D ARDUINO_CHALLENGER_NB_2040_WIFI_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
@@ -11,16 +18,7 @@
]
],
"mcu": "rp2040",
"arduino": {
"earlephilhower": {
"variant": "challenger_nb_2040_wifi",
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
"usb_vid": "0x2e8a",
"usb_pid": "0x100b",
"usb_manufacturer": "iLabs",
"usb_product": "Challenger NB 2040 WiFi"
}
}
"variant": "challenger_nb_2040_wifi"
},
"debug": {
"jlink_device": "RP2040_M0_0",
@@ -49,4 +47,4 @@
},
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
"vendor": "iLabs"
}
}

Some files were not shown because too many files have changed in this diff Show More