Compare commits
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
|
||||
@@ -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
@@ -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``.
|
||||
|
||||
@@ -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>`__.
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -0,0 +1,19 @@
|
||||
:orphan:
|
||||
|
||||
UDP Class
|
||||
---------
|
||||
|
||||
Methods documented for `WiFiUDP Class <https://www.arduino.cc/en/Reference/WiFiUDPConstructor>`__ in `Arduino <https://github.com/arduino/Arduino>`__
|
||||
|
||||
1. `begin() <https://www.arduino.cc/en/Reference/WiFiUDPBegin>`__
|
||||
2. `available() <https://www.arduino.cc/en/Reference/WiFiUDPAvailable>`__
|
||||
3. `beginPacket() <https://www.arduino.cc/en/Reference/WiFiUDPBeginPacket>`__
|
||||
4. `endPacket() <https://www.arduino.cc/en/Reference/WiFiUDPEndPacket>`__
|
||||
5. `write() <https://www.arduino.cc/en/Reference/WiFiUDPWrite>`__
|
||||
6. `parsePacket() <https://www.arduino.cc/en/Reference/WiFiUDPParsePacket>`__
|
||||
7. `peek() <https://www.arduino.cc/en/Reference/WiFiUDPPeek>`__
|
||||
8. `read() <https://www.arduino.cc/en/Reference/WiFiUDPRead>`__
|
||||
9. `flush() <https://www.arduino.cc/en/Reference/WiFiUDPFlush>`__
|
||||
10. `stop() <https://www.arduino.cc/en/Reference/WiFIUDPStop>`__
|
||||
11. `remoteIP() <https://www.arduino.cc/en/Reference/WiFiUDPRemoteIP>`__
|
||||
12. `remotePort() <https://www.arduino.cc/en/Reference/WiFiUDPRemotePort>`__
|
||||
Binary file not shown.
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Submodule libraries/Adafruit_TinyUSB_Arduino updated: 4f2c0ab42a...5be0b21c0a
Submodule libraries/FreeRTOS/lib/FreeRTOS-Kernel updated: f361238875...f5fe79dacd
@@ -8,3 +8,4 @@ category=Timing
|
||||
url=https://github.com/FreeRTOS/FreeRTOS-Kernel
|
||||
architectures=rp2040
|
||||
license=MIT
|
||||
dot_a_linkage=true
|
||||
|
||||
Executable → Regular
+6
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,2 @@
|
||||
// Since things may just work, we'll redirect for now
|
||||
#include "WiFi.h"
|
||||
@@ -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"
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
//}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
};
|
||||
@@ -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
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
// });
|
||||
// });
|
||||
}
|
||||
@@ -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
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+1
-1
Submodule pico-sdk updated: 426e46126b...2e6142b15b
+6
-5
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user