Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
988940b25e | ||
|
|
abf2c586c7 | ||
|
|
c025c4a1f8 | ||
|
|
fb05d96979 | ||
|
|
8eb030ed89 | ||
|
|
5be405308e | ||
|
|
af0c1c87f5 |
@@ -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
|
||||
@@ -175,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
|
||||
|
||||
+1537
-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
|
||||
@@ -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 2
|
||||
#define ARDUINO_PICO_REVISION 2
|
||||
#define ARDUINO_PICO_VERSION_STR "2.2.2"
|
||||
#define ARDUINO_PICO_MINOR 3
|
||||
#define ARDUINO_PICO_REVISION 0
|
||||
#define ARDUINO_PICO_VERSION_STR "2.3.0"
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "RP2040USB.h"
|
||||
#include <pico/stdlib.h>
|
||||
#include <pico/multicore.h>
|
||||
#include "LWIPMutex.h"
|
||||
#include <reent.h>
|
||||
|
||||
RP2040 rp2040;
|
||||
@@ -31,6 +32,8 @@ extern "C" {
|
||||
|
||||
mutex_t _pioMutex;
|
||||
|
||||
int LWIPMutex::_ref = 0;
|
||||
|
||||
extern void setup();
|
||||
extern void loop();
|
||||
|
||||
@@ -126,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);
|
||||
}
|
||||
@@ -135,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();
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
|
||||
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
// Taken from the Pico-SDK v1.4.0 and hacked by EFP3 to allow overriding the LWIP setup
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include "pico/mutex.h"
|
||||
#include "pico/sem.h"
|
||||
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/irq.h"
|
||||
|
||||
#include "cyw43_stats.h"
|
||||
|
||||
#include <lwip/init.h>
|
||||
#include "lwip/timeouts.h"
|
||||
|
||||
#ifndef CYW43_PIN_WL_HOST_WAKE
|
||||
#define CYW43_PIN_WL_HOST_WAKE 24
|
||||
#endif
|
||||
|
||||
#ifndef CYW43_PIN_WL_REG_ON
|
||||
#define CYW43_PIN_WL_REG_ON 23
|
||||
#endif
|
||||
|
||||
#ifndef CYW43_WL_GPIO_COUNT
|
||||
#define CYW43_WL_GPIO_COUNT 3
|
||||
#endif
|
||||
|
||||
#ifndef CYW43_WL_GPIO_LED_PIN
|
||||
#define CYW43_WL_GPIO_LED_PIN 0
|
||||
#endif
|
||||
|
||||
|
||||
volatile bool __inLWIP = false;
|
||||
|
||||
// note same code
|
||||
#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND
|
||||
|
||||
#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND && CYW43_LWIP && !NO_SYS
|
||||
#error PICO_CYW43_ARCH_THREADSAFE_BACKGROUND requires lwIP NO_SYS=1
|
||||
#endif
|
||||
#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND && CYW43_LWIP && MEM_LIBC_MALLOC
|
||||
#error MEM_LIBC_MALLOC is incompatible with PICO_CYW43_ARCH_THREADSAFE_BACKGROUND
|
||||
#endif
|
||||
// todo right now we are now always doing a cyw43_dispatch along with a lwip one when hopping cores in low_prio_irq_schedule_dispatch
|
||||
|
||||
#ifndef CYW43_SLEEP_CHECK_MS
|
||||
#define CYW43_SLEEP_CHECK_MS 50 // How often to run lwip callback
|
||||
#endif
|
||||
static alarm_id_t periodic_alarm = -1;
|
||||
|
||||
static inline uint recursive_mutex_enter_count(recursive_mutex_t *mutex) {
|
||||
return mutex->enter_count;
|
||||
}
|
||||
|
||||
static inline lock_owner_id_t recursive_mutex_owner(recursive_mutex_t *mutex) {
|
||||
return mutex->owner;
|
||||
}
|
||||
|
||||
#define CYW43_GPIO_IRQ_HANDLER_PRIORITY 0x40
|
||||
|
||||
enum {
|
||||
CYW43_DISPATCH_SLOT_CYW43 = 0,
|
||||
CYW43_DISPATCH_SLOT_ADAPTER,
|
||||
CYW43_DISPATCH_SLOT_ENUM_COUNT
|
||||
};
|
||||
#ifndef CYW43_DISPATCH_SLOT_COUNT
|
||||
#define CYW43_DISPATCH_SLOT_COUNT CYW43_DISPATCH_SLOT_ENUM_COUNT
|
||||
#endif
|
||||
|
||||
typedef void (*low_prio_irq_dispatch_t)(void);
|
||||
static void low_prio_irq_schedule_dispatch(size_t slot, low_prio_irq_dispatch_t f);
|
||||
|
||||
static uint8_t cyw43_core_num;
|
||||
#ifndef NDEBUG
|
||||
static bool in_low_priority_irq;
|
||||
#endif
|
||||
static uint8_t low_priority_irq_num;
|
||||
static bool low_priority_irq_missed;
|
||||
static low_prio_irq_dispatch_t low_priority_irq_dispatch_slots[CYW43_DISPATCH_SLOT_COUNT];
|
||||
static recursive_mutex_t cyw43_mutex;
|
||||
semaphore_t cyw43_irq_sem;
|
||||
|
||||
// Called in low priority pendsv interrupt only to do lwip processing and check cyw43 sleep
|
||||
static void periodic_worker(void) {
|
||||
#if CYW43_USE_STATS
|
||||
static uint32_t counter;
|
||||
if (counter++ % (30000 / LWIP_SYS_CHECK_MS) == 0) {
|
||||
cyw43_dump_stats();
|
||||
}
|
||||
#endif
|
||||
|
||||
CYW43_STAT_INC(LWIP_RUN_COUNT);
|
||||
//#if CYW43_LWIP
|
||||
if (!__inLWIP) {
|
||||
sys_check_timeouts();
|
||||
}
|
||||
//#endif
|
||||
if (cyw43_poll) {
|
||||
if (cyw43_sleep > 0) {
|
||||
if (--cyw43_sleep == 0) {
|
||||
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Regular callback to get lwip to check for timeouts
|
||||
static int64_t periodic_alarm_handler(__unused alarm_id_t id, __unused void *user_data) {
|
||||
// Do lwip processing in low priority pendsv interrupt
|
||||
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_ADAPTER, periodic_worker);
|
||||
return CYW43_SLEEP_CHECK_MS * 1000;
|
||||
}
|
||||
|
||||
void cyw43_await_background_or_timeout_us(uint32_t timeout_us) {
|
||||
// if we are called from within an IRQ, then don't wait (we are only ever called in a polling loop)
|
||||
if (!__get_current_exception()) {
|
||||
sem_acquire_timeout_us(&cyw43_irq_sem, timeout_us);
|
||||
}
|
||||
}
|
||||
|
||||
// GPIO interrupt handler to tell us there's cyw43 has work to do
|
||||
static void gpio_irq_handler(void) {
|
||||
uint32_t events = gpio_get_irq_event_mask(CYW43_PIN_WL_HOST_WAKE);
|
||||
if (events & GPIO_IRQ_LEVEL_HIGH) {
|
||||
// As we use a high level interrupt, it will go off forever until it's serviced
|
||||
// So disable the interrupt until this is done. It's re-enabled again by CYW43_POST_POLL_HOOK
|
||||
// which is called at the end of cyw43_poll_func
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
|
||||
// also clear the force bit which we use to progratically cause this handler to fire (on the right core)
|
||||
io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ?
|
||||
&iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
|
||||
hw_clear_bits(&irq_ctrl_base->intf[CYW43_PIN_WL_HOST_WAKE / 8], GPIO_IRQ_LEVEL_HIGH << (4 * (CYW43_PIN_WL_HOST_WAKE & 7)));
|
||||
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
|
||||
CYW43_STAT_INC(IRQ_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
// Low priority interrupt handler to perform background processing
|
||||
static void low_priority_irq_handler(void) {
|
||||
assert(cyw43_core_num == get_core_num());
|
||||
if (recursive_mutex_try_enter(&cyw43_mutex, NULL)) {
|
||||
if (recursive_mutex_enter_count(&cyw43_mutex) != 1) {
|
||||
low_priority_irq_missed = true;
|
||||
CYW43_STAT_INC(PENDSV_DISABLED_COUNT);
|
||||
} else {
|
||||
CYW43_STAT_INC(PENDSV_RUN_COUNT);
|
||||
#ifndef NDEBUG
|
||||
in_low_priority_irq = true;
|
||||
#endif
|
||||
for (size_t i = 0; i < count_of(low_priority_irq_dispatch_slots); i++) {
|
||||
if (low_priority_irq_dispatch_slots[i] != NULL) {
|
||||
low_prio_irq_dispatch_t f = low_priority_irq_dispatch_slots[i];
|
||||
low_priority_irq_dispatch_slots[i] = NULL;
|
||||
f();
|
||||
}
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
in_low_priority_irq = false;
|
||||
#endif
|
||||
}
|
||||
recursive_mutex_exit(&cyw43_mutex);
|
||||
} else {
|
||||
CYW43_STAT_INC(PENDSV_DISABLED_COUNT);
|
||||
low_priority_irq_missed = true;
|
||||
}
|
||||
sem_release(&cyw43_irq_sem);
|
||||
}
|
||||
|
||||
static bool low_prio_irq_init(uint8_t priority) {
|
||||
assert(get_core_num() == cyw43_core_num);
|
||||
int irq = user_irq_claim_unused(false);
|
||||
if (irq < 0) {
|
||||
return false;
|
||||
}
|
||||
low_priority_irq_num = (uint8_t) irq;
|
||||
irq_set_exclusive_handler(low_priority_irq_num, low_priority_irq_handler);
|
||||
irq_set_enabled(low_priority_irq_num, true);
|
||||
irq_set_priority(low_priority_irq_num, priority);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void low_prio_irq_deinit(void) {
|
||||
if (low_priority_irq_num > 0) {
|
||||
irq_set_enabled(low_priority_irq_num, false);
|
||||
irq_remove_handler(low_priority_irq_num, low_priority_irq_handler);
|
||||
user_irq_unclaim(low_priority_irq_num);
|
||||
low_priority_irq_num = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int cyw43_arch_init(void) {
|
||||
cyw43_core_num = get_core_num();
|
||||
recursive_mutex_init(&cyw43_mutex);
|
||||
cyw43_init(&cyw43_state);
|
||||
sem_init(&cyw43_irq_sem, 0, 1);
|
||||
|
||||
// Start regular lwip callback to handle timeouts
|
||||
periodic_alarm = add_alarm_in_us(CYW43_SLEEP_CHECK_MS * 1000, periodic_alarm_handler, NULL, true);
|
||||
if (periodic_alarm < 0) {
|
||||
return PICO_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
gpio_add_raw_irq_handler_with_order_priority(IO_IRQ_BANK0, gpio_irq_handler, CYW43_GPIO_IRQ_HANDLER_PRIORITY);
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
|
||||
irq_set_enabled(IO_IRQ_BANK0, true);
|
||||
|
||||
lwip_init();
|
||||
|
||||
// start low priority handler (no background work is done before this)
|
||||
bool ok = low_prio_irq_init(PICO_LOWEST_IRQ_PRIORITY);
|
||||
if (!ok) {
|
||||
cyw43_arch_deinit();
|
||||
return PICO_ERROR_GENERIC;
|
||||
}
|
||||
return PICO_OK;
|
||||
}
|
||||
|
||||
void cyw43_arch_deinit(void) {
|
||||
if (periodic_alarm >= 0) {
|
||||
cancel_alarm(periodic_alarm);
|
||||
periodic_alarm = -1;
|
||||
}
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, false);
|
||||
gpio_remove_raw_irq_handler(IO_IRQ_BANK0, gpio_irq_handler);
|
||||
low_prio_irq_deinit();
|
||||
}
|
||||
|
||||
void cyw43_post_poll_hook(void) {
|
||||
gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, GPIO_IRQ_LEVEL_HIGH, true);
|
||||
}
|
||||
|
||||
// This is called in the gpio and low_prio_irq interrupts and on either core
|
||||
static void low_prio_irq_schedule_dispatch(size_t slot, low_prio_irq_dispatch_t f) {
|
||||
assert(slot < count_of(low_priority_irq_dispatch_slots));
|
||||
low_priority_irq_dispatch_slots[slot] = f;
|
||||
if (cyw43_core_num == get_core_num()) {
|
||||
//on same core, can dispatch directly
|
||||
irq_set_pending(low_priority_irq_num);
|
||||
} else {
|
||||
// on wrong core, so force via GPIO IRQ which itself calls this method for the CYW43 slot.
|
||||
// since the CYW43 slot always uses the same function, this is fine with the addition of an
|
||||
// extra (but harmless) CYW43 slot call when another SLOT is invoked.
|
||||
// We could do better, but would have to track why the IRQ was called.
|
||||
io_irq_ctrl_hw_t *irq_ctrl_base = cyw43_core_num ?
|
||||
&iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
|
||||
hw_set_bits(&irq_ctrl_base->intf[CYW43_PIN_WL_HOST_WAKE / 8], GPIO_IRQ_LEVEL_HIGH << (4 * (CYW43_PIN_WL_HOST_WAKE & 7)));
|
||||
}
|
||||
}
|
||||
|
||||
void cyw43_schedule_internal_poll_dispatch(void (*func)(void)) {
|
||||
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, func);
|
||||
}
|
||||
|
||||
// Prevent background processing in pensv and access by the other core
|
||||
// These methods are called in pensv context and on either core
|
||||
// They can be called recursively
|
||||
void cyw43_thread_enter(void) {
|
||||
// Lock the other core and stop low_prio_irq running
|
||||
recursive_mutex_enter_blocking(&cyw43_mutex);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void cyw43_thread_lock_check(void) {
|
||||
// Lock the other core and stop low_prio_irq running
|
||||
if (recursive_mutex_enter_count(&cyw43_mutex) < 1 || recursive_mutex_owner(&cyw43_mutex) != lock_get_caller_owner_id()) {
|
||||
panic("cyw43_thread_lock_check failed");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Re-enable background processing
|
||||
void cyw43_thread_exit(void) {
|
||||
// Run low_prio_irq if needed
|
||||
if (1 == recursive_mutex_enter_count(&cyw43_mutex)) {
|
||||
// note the outer release of the mutex is not via cyw43_exit in the low_priority_irq case (it is a direct mutex exit)
|
||||
assert(!in_low_priority_irq);
|
||||
// if (low_priority_irq_missed) {
|
||||
// low_priority_irq_missed = false;
|
||||
if (low_priority_irq_dispatch_slots[CYW43_DISPATCH_SLOT_CYW43]) {
|
||||
low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
|
||||
}
|
||||
// }
|
||||
}
|
||||
recursive_mutex_exit(&cyw43_mutex);
|
||||
}
|
||||
|
||||
|
||||
static void cyw43_delay_until(absolute_time_t until) {
|
||||
// sleep can be called in IRQs, so there's not much we can do there
|
||||
if (__get_current_exception()) {
|
||||
busy_wait_until(until);
|
||||
} else {
|
||||
sleep_until(until);
|
||||
}
|
||||
}
|
||||
|
||||
void cyw43_delay_ms(uint32_t ms) {
|
||||
cyw43_delay_until(make_timeout_time_ms(ms));
|
||||
}
|
||||
|
||||
void cyw43_delay_us(uint32_t us) {
|
||||
cyw43_delay_until(make_timeout_time_us(us));
|
||||
}
|
||||
|
||||
void cyw43_arch_poll() {
|
||||
// should not be necessary
|
||||
// if (cyw43_poll) {
|
||||
// low_prio_irq_schedule_dispatch(CYW43_DISPATCH_SLOT_CYW43, cyw43_poll);
|
||||
// }
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -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;
|
||||
|
||||
+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>
|
||||
|
||||
|
||||
@@ -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 2
|
||||
#define PICO_SDK_VERSION_STRING "1.3.2-develop"
|
||||
#define PICO_SDK_VERSION_MINOR 4
|
||||
#define PICO_SDK_VERSION_REVISION 0
|
||||
#define PICO_SDK_VERSION_STRING "1.4.0"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
|
||||
Submodule libraries/Adafruit_TinyUSB_Arduino updated: 7264c1492a...5be0b21c0a
@@ -8,3 +8,4 @@ category=Timing
|
||||
url=https://github.com/FreeRTOS/FreeRTOS-Kernel
|
||||
architectures=rp2040
|
||||
license=MIT
|
||||
dot_a_linkage=true
|
||||
|
||||
@@ -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,543 @@
|
||||
/*
|
||||
WiFiClass.cpp - WiFi class "compat" w/WiFiNINA for Raspberry Pi Pico W
|
||||
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
Implements the API defined by the Arduino WiFiNINA library,
|
||||
copyright (c) 2018 Arduino SA. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <pico/cyw43_arch.h>
|
||||
#include <cyw43.h>
|
||||
#include "lwip/raw.h"
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include <map>
|
||||
#include "WiFi.h"
|
||||
|
||||
// This is the real WiFi network object, we just tickle it to do our magic
|
||||
#include <LwipEthernet.h>
|
||||
static CYW43lwIP _wifi(1);
|
||||
|
||||
WiFiClass::WiFiClass() {
|
||||
}
|
||||
|
||||
/*
|
||||
Get firmware version
|
||||
*/
|
||||
const char* WiFiClass::firmwareVersion() {
|
||||
// TODO - does not look like driver reports this now
|
||||
return PICO_SDK_VERSION_STRING;
|
||||
}
|
||||
|
||||
void WiFiClass::mode(_wifiModeESP m) {
|
||||
_calledESP = true;
|
||||
switch (m) {
|
||||
case WIFI_OFF:
|
||||
end();
|
||||
break;
|
||||
case WIFI_AP:
|
||||
_modeESP = WIFI_AP;
|
||||
break;
|
||||
case WIFI_STA:
|
||||
_modeESP = WIFI_STA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Start WiFi connection for OPEN networks
|
||||
|
||||
param ssid: Pointer to the SSID string.
|
||||
*/
|
||||
int WiFiClass::begin(const char* ssid) {
|
||||
return begin(ssid, nullptr);
|
||||
}
|
||||
|
||||
/* Start WiFi connection with passphrase
|
||||
the most secure supported mode will be automatically selected
|
||||
|
||||
param ssid: Pointer to the SSID string.
|
||||
param passphrase: Passphrase. Valid characters in a passphrase
|
||||
must be between ASCII 32-126 (decimal).
|
||||
*/
|
||||
int WiFiClass::begin(const char* ssid, const char *passphrase) {
|
||||
// Simple ESP8266 compatibility hack
|
||||
if (_modeESP == WIFI_AP) {
|
||||
return beginAP(ssid, passphrase);
|
||||
}
|
||||
|
||||
end();
|
||||
|
||||
_ssid = ssid;
|
||||
_password = passphrase;
|
||||
_wifi.setSSID(ssid);
|
||||
_wifi.setPassword(passphrase);
|
||||
_wifi.setTimeout(_timeout);
|
||||
_wifi.setSTA();
|
||||
_apMode = false;
|
||||
_wifiHWInitted = true;
|
||||
uint32_t start = millis(); // The timeout starts from network init, not network link up
|
||||
if (!_wifi.begin()) {
|
||||
return WL_IDLE_STATUS;
|
||||
}
|
||||
while (!_calledESP && ((millis() - start < (uint32_t)2 * _timeout)) && !connected()) {
|
||||
delay(10);
|
||||
}
|
||||
return status();
|
||||
}
|
||||
|
||||
uint8_t WiFiClass::beginAP(const char *ssid) {
|
||||
return beginAP(ssid, nullptr);
|
||||
}
|
||||
|
||||
uint8_t WiFiClass::beginAP(const char *ssid, uint8_t channel) {
|
||||
(void) channel;
|
||||
return beginAP(ssid, nullptr);
|
||||
}
|
||||
|
||||
uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase, uint8_t channel) {
|
||||
(void) channel;
|
||||
return beginAP(ssid, passphrase);
|
||||
}
|
||||
|
||||
uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase) {
|
||||
end();
|
||||
|
||||
_ssid = ssid;
|
||||
_password = passphrase;
|
||||
_wifi.setSSID(ssid);
|
||||
_wifi.setPassword(passphrase);
|
||||
_wifi.setTimeout(_timeout);
|
||||
_wifi.setAP();
|
||||
_apMode = true;
|
||||
if (!_wifi.begin()) {
|
||||
return WL_IDLE_STATUS;
|
||||
}
|
||||
IPAddress gw = _wifi.gatewayIP();
|
||||
if (!gw.isSet()) {
|
||||
gw = IPAddress(192, 168, 42, 1);
|
||||
}
|
||||
IPAddress mask = _wifi.subnetMask();
|
||||
if (!mask.isSet()) {
|
||||
mask = IPAddress(255, 255, 255, 0);
|
||||
}
|
||||
config(gw);
|
||||
_dhcpServer = (dhcp_server_t *)malloc(sizeof(dhcp_server_t));
|
||||
if (!_dhcpServer) {
|
||||
// OOM
|
||||
return WL_IDLE_STATUS;
|
||||
}
|
||||
dhcp_server_init(_dhcpServer, gw, mask);
|
||||
|
||||
_wifiHWInitted = true;
|
||||
|
||||
return WL_CONNECTED;
|
||||
}
|
||||
|
||||
bool WiFiClass::connected() {
|
||||
return _wifi.connected() && localIP().isSet();
|
||||
}
|
||||
|
||||
/* Change Ip configuration settings disabling the dhcp client
|
||||
|
||||
param local_ip: Static ip configuration
|
||||
*/
|
||||
void WiFiClass::config(IPAddress local_ip) {
|
||||
ip4_addr_set_u32(ip_2_ip4(&_wifi.getNetIf()->ip_addr), local_ip.v4());
|
||||
}
|
||||
|
||||
/* Change Ip configuration settings disabling the dhcp client
|
||||
|
||||
param local_ip: Static ip configuration
|
||||
param dns_server: IP configuration for DNS server 1
|
||||
*/
|
||||
void WiFiClass::config(IPAddress local_ip, IPAddress dns_server) {
|
||||
ip4_addr_set_u32(ip_2_ip4(&_wifi.getNetIf()->ip_addr), local_ip.v4());
|
||||
dns_setserver(0, dns_server);
|
||||
}
|
||||
|
||||
/* Change Ip configuration settings disabling the dhcp client
|
||||
|
||||
param local_ip: Static ip configuration
|
||||
param dns_server: IP configuration for DNS server 1
|
||||
param gateway : Static gateway configuration
|
||||
*/
|
||||
void WiFiClass::config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway) {
|
||||
ip4_addr_set_u32(ip_2_ip4(&_wifi.getNetIf()->ip_addr), local_ip.v4());
|
||||
dns_setserver(0, dns_server);
|
||||
ip4_addr_set_u32(ip_2_ip4(&_wifi.getNetIf()->gw), gateway.v4());
|
||||
}
|
||||
|
||||
/* Change Ip configuration settings disabling the dhcp client
|
||||
|
||||
param local_ip: Static ip configuration
|
||||
param dns_server: IP configuration for DNS server 1
|
||||
param gateway: Static gateway configuration
|
||||
param subnet: Static Subnet mask
|
||||
*/
|
||||
void WiFiClass::config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet) {
|
||||
_wifi.config(local_ip, gateway, subnet, dns_server);
|
||||
}
|
||||
|
||||
/* Change DNS Ip configuration
|
||||
|
||||
param dns_server1: ip configuration for DNS server 1
|
||||
*/
|
||||
void WiFiClass::setDNS(IPAddress dns_server1) {
|
||||
dns_setserver(0, dns_server1);
|
||||
}
|
||||
|
||||
/* Change DNS Ip configuration
|
||||
|
||||
param dns_server1: ip configuration for DNS server 1
|
||||
param dns_server2: ip configuration for DNS server 2
|
||||
|
||||
*/
|
||||
void WiFiClass::setDNS(IPAddress dns_server1, IPAddress dns_server2) {
|
||||
dns_setserver(0, dns_server1);
|
||||
dns_setserver(1, dns_server2);
|
||||
}
|
||||
|
||||
/* Set the hostname used for DHCP requests
|
||||
|
||||
param name: hostname to set
|
||||
|
||||
*/
|
||||
void WiFiClass::setHostname(const char* name) {
|
||||
_wifi.setHostname(name);
|
||||
}
|
||||
|
||||
/*
|
||||
Disconnect from the network
|
||||
|
||||
return: one value of wl_status_t enum
|
||||
*/
|
||||
int WiFiClass::disconnect(void) {
|
||||
if (_wifiHWInitted) {
|
||||
cyw43_wifi_leave(&cyw43_state, _apMode ? 1 : 0);
|
||||
}
|
||||
_wifiHWInitted = false;
|
||||
if (_dhcpServer) {
|
||||
dhcp_server_deinit(_dhcpServer);
|
||||
free(_dhcpServer);
|
||||
_dhcpServer = nullptr;
|
||||
}
|
||||
_wifi.end();
|
||||
return WL_DISCONNECTED;
|
||||
}
|
||||
|
||||
void WiFiClass::end(void) {
|
||||
if (_wifiHWInitted) {
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Get the interface MAC address.
|
||||
|
||||
return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
|
||||
*/
|
||||
uint8_t* WiFiClass::macAddress(uint8_t* mac) {
|
||||
if (!_wifiHWInitted) {
|
||||
_apMode = false;
|
||||
cyw43_wifi_set_up(&cyw43_state, _apMode ? 1 : 0, true, CYW43_COUNTRY_WORLDWIDE);
|
||||
}
|
||||
cyw43_wifi_get_mac(&cyw43_state, _apMode ? 1 : 0, mac);
|
||||
return mac;
|
||||
}
|
||||
|
||||
/*
|
||||
Get the interface IP address.
|
||||
|
||||
return: Ip address value
|
||||
*/
|
||||
IPAddress WiFiClass::localIP() {
|
||||
return _wifi.localIP();
|
||||
}
|
||||
|
||||
/*
|
||||
Get the interface subnet mask address.
|
||||
|
||||
return: subnet mask address value
|
||||
*/
|
||||
IPAddress WiFiClass::subnetMask() {
|
||||
return _wifi.subnetMask();
|
||||
}
|
||||
|
||||
/*
|
||||
Get the gateway ip address.
|
||||
|
||||
return: gateway ip address value
|
||||
*/
|
||||
IPAddress WiFiClass::gatewayIP() {
|
||||
return _wifi.gatewayIP();
|
||||
}
|
||||
|
||||
/*
|
||||
Return the current SSID associated with the network
|
||||
|
||||
return: ssid string
|
||||
*/
|
||||
const char* WiFiClass::SSID() {
|
||||
return _ssid;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the current BSSID associated with the network.
|
||||
It is the MAC address of the Access Point
|
||||
|
||||
return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
|
||||
*/
|
||||
uint8_t* WiFiClass::BSSID(uint8_t* bssid) {
|
||||
// TODO - driver does not return this?!
|
||||
memset(bssid, 0xee, WL_MAC_ADDR_LENGTH);
|
||||
return bssid;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the current RSSI /Received Signal Strength in dBm)
|
||||
associated with the network
|
||||
|
||||
return: signed value
|
||||
*/
|
||||
int32_t WiFiClass::RSSI() {
|
||||
// TODO - driver does not return this?!
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the Encryption Type associated with the network
|
||||
|
||||
return: one value of wl_enc_type enum
|
||||
*/
|
||||
uint8_t WiFiClass::encryptionType() {
|
||||
// TODO - Driver does not return this?!
|
||||
if (_password == nullptr) {
|
||||
return ENC_TYPE_NONE;
|
||||
}
|
||||
return ENC_TYPE_AUTO;
|
||||
}
|
||||
|
||||
//TODO - this can be in the class
|
||||
static uint64_t _to64(uint8_t b[8]) {
|
||||
uint64_t x = 0;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
x <<= 8LL;
|
||||
x |= b[i] & 255;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int WiFiClass::_scanCB(void *env, const cyw43_ev_scan_result_t *result) {
|
||||
WiFiClass *w = (WiFiClass *)env;
|
||||
if (result) {
|
||||
cyw43_ev_scan_result_t s;
|
||||
memcpy(&s, result, sizeof(s));
|
||||
w->_scan.insert_or_assign(_to64(s.bssid), s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Start scan WiFi networks available
|
||||
|
||||
return: Number of discovered networks
|
||||
*/
|
||||
int8_t WiFiClass::scanNetworks() {
|
||||
cyw43_wifi_scan_options_t scan_options;
|
||||
memset(&scan_options, 0, sizeof(scan_options));
|
||||
_scan.clear();
|
||||
if (!_wifiHWInitted) {
|
||||
_apMode = false;
|
||||
cyw43_arch_enable_sta_mode();
|
||||
_wifiHWInitted = true;
|
||||
}
|
||||
int err = cyw43_wifi_scan(&cyw43_state, &scan_options, this, _scanCB);
|
||||
if (err) {
|
||||
return 0;
|
||||
}
|
||||
uint32_t now = millis();
|
||||
while (cyw43_wifi_scan_active(&cyw43_state) && (millis() - now < 10000)) {
|
||||
delay(10);
|
||||
}
|
||||
return _scan.size();
|
||||
}
|
||||
|
||||
/*
|
||||
Return the SSID discovered during the network scan.
|
||||
|
||||
param networkItem: specify from which network item want to get the information
|
||||
|
||||
return: ssid string of the specified item on the networks scanned list
|
||||
*/
|
||||
const char*WiFiClass::SSID(uint8_t networkItem) {
|
||||
if (networkItem >= _scan.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto it = _scan.begin();
|
||||
for (int i = 0; i < networkItem; i++) {
|
||||
++it;
|
||||
}
|
||||
return (const char *)it->second.ssid;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the encryption type of the networks discovered during the scanNetworks
|
||||
|
||||
param networkItem: specify from which network item want to get the information
|
||||
|
||||
return: encryption type (enum wl_enc_type) of the specified item on the networks scanned list
|
||||
*/
|
||||
uint8_t WiFiClass::encryptionType(uint8_t networkItem) {
|
||||
if (networkItem >= _scan.size()) {
|
||||
return ENC_TYPE_UNKNOWN;
|
||||
}
|
||||
auto it = _scan.begin();
|
||||
for (int i = 0; i < networkItem; i++) {
|
||||
++it;
|
||||
}
|
||||
// TODO - the driver returns a small integer but does not actually provide a way of mapping that to the proper enc type. My best guesses here...
|
||||
switch (it->second.auth_mode) {
|
||||
case 0: return ENC_TYPE_NONE;
|
||||
case 3: return ENC_TYPE_TKIP;
|
||||
case 5: return ENC_TYPE_CCMP;
|
||||
case 7: return ENC_TYPE_AUTO;
|
||||
}
|
||||
return ENC_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
uint8_t* WiFiClass::BSSID(uint8_t networkItem, uint8_t* bssid) {
|
||||
if (networkItem >= _scan.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto it = _scan.begin();
|
||||
for (int i = 0; i < networkItem; i++) {
|
||||
++it;
|
||||
}
|
||||
memcpy(bssid, it->second.bssid, 6);
|
||||
return bssid;
|
||||
}
|
||||
|
||||
uint8_t WiFiClass::channel(uint8_t networkItem) {
|
||||
if (networkItem >= _scan.size()) {
|
||||
return 255;
|
||||
}
|
||||
auto it = _scan.begin();
|
||||
for (int i = 0; i < networkItem; i++) {
|
||||
++it;
|
||||
}
|
||||
return it->second.channel;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the RSSI of the networks discovered during the scanNetworks
|
||||
|
||||
param networkItem: specify from which network item want to get the information
|
||||
|
||||
return: signed value of RSSI of the specified item on the networks scanned list
|
||||
*/
|
||||
int32_t WiFiClass::RSSI(uint8_t networkItem) {
|
||||
if (networkItem >= _scan.size()) {
|
||||
return -9999;
|
||||
}
|
||||
auto it = _scan.begin();
|
||||
for (int i = 0; i < networkItem; i++) {
|
||||
++it;
|
||||
}
|
||||
return it->second.rssi;
|
||||
}
|
||||
|
||||
/*
|
||||
Return Connection status.
|
||||
|
||||
return: one of the value defined in wl_status_t
|
||||
*/
|
||||
uint8_t WiFiClass::status() {
|
||||
switch (cyw43_wifi_link_status(&cyw43_state, _apMode ? 1 : 0)) {
|
||||
case CYW43_LINK_DOWN: return WL_IDLE_STATUS;
|
||||
case CYW43_LINK_JOIN: return localIP().isSet() ? WL_CONNECTED : WL_CONNECTING;
|
||||
case CYW43_LINK_FAIL: return WL_CONNECT_FAILED;
|
||||
case CYW43_LINK_NONET: return WL_CONNECT_FAILED;
|
||||
case CYW43_LINK_BADAUTH: return WL_CONNECT_FAILED;
|
||||
}
|
||||
return WL_NO_MODULE;
|
||||
}
|
||||
|
||||
/*
|
||||
Return The deauthentication reason code.
|
||||
|
||||
return: the deauthentication reason code
|
||||
*/
|
||||
uint8_t WiFiClass::reasonCode() {
|
||||
// TODO - driver does not report this?!
|
||||
return WL_NO_SHIELD;
|
||||
}
|
||||
|
||||
/**
|
||||
Resolve the given hostname to an IP address.
|
||||
@param aHostname Name to be resolved
|
||||
@param aResult IPAddress structure to store the returned IP address
|
||||
@return 1 if aIPAddrString was successfully converted to an IP address,
|
||||
else 0
|
||||
*/
|
||||
|
||||
int WiFiClass::hostByName(const char* aHostname, IPAddress& aResult, int timeout_ms) {
|
||||
return _wifi.hostByName(aHostname, aResult, timeout_ms);
|
||||
}
|
||||
|
||||
// TODO
|
||||
unsigned long WiFiClass::getTime() {
|
||||
return millis();
|
||||
}
|
||||
|
||||
void WiFiClass::lowPowerMode() {
|
||||
cyw43_wifi_pm(&cyw43_state, CYW43_AGGRESSIVE_PM);
|
||||
}
|
||||
|
||||
void WiFiClass::noLowPowerMode() {
|
||||
cyw43_wifi_pm(&cyw43_state, CYW43_DEFAULT_PM);
|
||||
}
|
||||
|
||||
int WiFiClass::ping(const char* hostname, uint8_t ttl) {
|
||||
IPAddress ip;
|
||||
if (!hostByName(hostname, ip)) {
|
||||
return WL_PING_UNKNOWN_HOST;
|
||||
}
|
||||
return ping(ip, ttl);
|
||||
}
|
||||
|
||||
int WiFiClass::ping(const String &hostname, uint8_t ttl) {
|
||||
return ping(hostname.c_str(), ttl);
|
||||
}
|
||||
|
||||
int WiFiClass::ping(IPAddress host, uint8_t ttl) {
|
||||
return _wifi.ping(host, ttl, _timeout);
|
||||
}
|
||||
|
||||
void WiFiClass::setTimeout(unsigned long timeout) {
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
||||
void WiFiClass::setFeedWatchdogFunc(FeedHostProcessorWatchdogFuncPointer func) {
|
||||
(void) func;
|
||||
}
|
||||
void WiFiClass::feedWatchdog() {
|
||||
}
|
||||
|
||||
|
||||
WiFiClass WiFi;
|
||||
@@ -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.20202.0",
|
||||
"version": "1.20300.0",
|
||||
"description": "Arduino Wiring-based Framework (RPi Pico RP2040)",
|
||||
"keywords": [
|
||||
"framework",
|
||||
|
||||
@@ -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.4.0-b-cb31b54",
|
||||
"version": "1.4.0-c-0196c06",
|
||||
"name": "pqt-gcc"
|
||||
},
|
||||
{
|
||||
"packager": "rp2040",
|
||||
"version": "1.4.0-b-cb31b54",
|
||||
"version": "1.4.0-c-0196c06",
|
||||
"name": "pqt-mklittlefs"
|
||||
},
|
||||
{
|
||||
"packager": "rp2040",
|
||||
"version": "1.4.0-b-cb31b54",
|
||||
"version": "1.4.0-c-0196c06",
|
||||
"name": "pqt-elf2uf2"
|
||||
},
|
||||
{
|
||||
"packager": "rp2040",
|
||||
"version": "1.4.0-b-cb31b54",
|
||||
"version": "1.4.0-c-0196c06",
|
||||
"name": "pqt-pioasm"
|
||||
},
|
||||
{
|
||||
@@ -133,7 +142,7 @@
|
||||
},
|
||||
{
|
||||
"packager": "rp2040",
|
||||
"version": "1.4.0-b-cb31b54",
|
||||
"version": "1.4.0-c-0196c06",
|
||||
"name": "pqt-openocd"
|
||||
}
|
||||
],
|
||||
@@ -144,57 +153,57 @@
|
||||
],
|
||||
"tools": [
|
||||
{
|
||||
"version": "1.4.0-b-cb31b54",
|
||||
"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.4.0-b/aarch64-linux-gnu.openocd-e3428fadb.220619.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.openocd-e3428fadb.220619.tar.gz",
|
||||
"checksum": "SHA-256:8cdddf73090b6d7f5ef7fdb1b60e9f755166ce494d774b91004e6655a80abfa1",
|
||||
"size": "5607149"
|
||||
"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.4.0-b/arm-linux-gnueabihf.openocd-e3428fadb.220619.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.openocd-e3428fadb.220619.tar.gz",
|
||||
"checksum": "SHA-256:07d4e170396f57d5180569168d9bc24b258207900fbc8c87b38056ac1b2fed1e",
|
||||
"size": "5344134"
|
||||
"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.4.0-b/i686-linux-gnu.openocd-e3428fadb.220619.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.openocd-e3428fadb.220619.tar.gz",
|
||||
"checksum": "SHA-256:9e3f18ccfb47ee4051bb93c8b9b177e3135eedbbfb3fd9207524b649efe09aed",
|
||||
"size": "5168404"
|
||||
"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.4.0-b/i686-w64-mingw32.openocd-e3428fadb.220619.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.openocd-e3428fadb.220619.zip",
|
||||
"checksum": "SHA-256:c38bf855c099d933c09d92d57fd1473853eee205957fe22b618e3514d638fe4f",
|
||||
"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.4.0-b/x86_64-apple-darwin14.openocd-e3428fadb.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.openocd-e3428fadb.220619.tar.gz",
|
||||
"checksum": "SHA-256:c36483c5cecfdeba8466b6e112552736c99a2409e6f8e80287b80a3f8d8fdb16",
|
||||
"size": "2002506"
|
||||
"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.4.0-b/x86_64-linux-gnu.openocd-e3428fadb.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.openocd-e3428fadb.220619.tar.gz",
|
||||
"checksum": "SHA-256:57083723758814567f6b54e4f81713ce1ce070c6878362a97636da73362f00c9",
|
||||
"size": "5540547"
|
||||
"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.4.0-b/x86_64-w64-mingw32.openocd-e3428fadb.220619.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.openocd-e3428fadb.220619.zip",
|
||||
"checksum": "SHA-256:b05d1dbf32d277e214664ae44dd86be96bae61f615c0bac6c1c1c281d6b52b71",
|
||||
"size": "2156832"
|
||||
"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.4.0-b-cb31b54",
|
||||
"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.4.0-b/aarch64-linux-gnu.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"checksum": "SHA-256:27dd4a1fe0b6010588928acc9b61937d149ebcd7a4aa47ce944506d71827c460",
|
||||
"size": "77881122"
|
||||
"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.4.0-b/arm-linux-gnueabihf.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"checksum": "SHA-256:3e3547998b6c2382d7c6e91b43f0a7a3190e2955160bb471de4cc204b599a757",
|
||||
"size": "73345531"
|
||||
"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.4.0-b/i686-linux-gnu.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"checksum": "SHA-256:fca37e1e49a6e25dd507a24e2e9a6947fd0eec7d0a8a30f4bdcac524c9bd18a1",
|
||||
"size": "79497966"
|
||||
"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.4.0-b/i686-w64-mingw32.arm-none-eabi-cb31b54.220619.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.arm-none-eabi-cb31b54.220619.zip",
|
||||
"checksum": "SHA-256:61f31ae875a67e8334e031c188fbe30d98c5f1bceb33305acf49d985d9ca71ce",
|
||||
"size": "82625221"
|
||||
"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.4.0-b/x86_64-apple-darwin14.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"checksum": "SHA-256:d32c7797be2c31d20dc4b5182a0dd77be67324c3c6a52737bfb4e63e1d622f80",
|
||||
"size": "82123114"
|
||||
"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.4.0-b/x86_64-linux-gnu.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"checksum": "SHA-256:470cbe690b2553d3b780ece36cda9fc26c7b53db47362ced3a937d701e696e9e",
|
||||
"size": "80361816"
|
||||
"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.4.0-b/x86_64-w64-mingw32.arm-none-eabi-cb31b54.220619.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.arm-none-eabi-cb31b54.220619.zip",
|
||||
"checksum": "SHA-256:7b50d3f34cd602a28d8cf1580c65dd22e683088ce5b954be5bfb67ba50094134",
|
||||
"size": "86068608"
|
||||
"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.4.0-b-cb31b54",
|
||||
"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.4.0-b/aarch64-linux-gnu.elf2uf2-2062372.220619.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.elf2uf2-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:74dd8cf38160bd9f972ea22e02bd6fa6b11bc510aa7738b603c7fbd016fe4b50",
|
||||
"size": "79874"
|
||||
"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.4.0-b/arm-linux-gnueabihf.elf2uf2-2062372.220619.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.elf2uf2-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:efa24ac288a5eacad7b535ce4d9ac66a25686d993f80daf86248858310b3fc63",
|
||||
"size": "54265"
|
||||
"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.4.0-b/i686-linux-gnu.elf2uf2-2062372.220619.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.elf2uf2-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:c0816a703fe5821a1d1bf60dcb584d98185b83e926d532fd37c69e8801e211ff",
|
||||
"size": "87908"
|
||||
"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.4.0-b/i686-w64-mingw32.elf2uf2-2062372.220619.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.elf2uf2-2062372.220619.zip",
|
||||
"checksum": "SHA-256:7a2f86735220fef0946856f418a136ff4ed3ad4cf0cacc17d8016f6cbd1ca735",
|
||||
"size": "70416"
|
||||
"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.4.0-b/x86_64-apple-darwin14.elf2uf2-2062372.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.elf2uf2-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:2ae3ffd477eaabb891e68e1b4525e3d4d4b2fee3c6f70e6ae68c45746c03fb54",
|
||||
"size": "81995"
|
||||
"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.4.0-b/x86_64-linux-gnu.elf2uf2-2062372.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.elf2uf2-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:2be1052db1e676418c59a4331ef688f686b4a31053330c90348219ab1ecd6bcf",
|
||||
"size": "79610"
|
||||
"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.4.0-b/x86_64-w64-mingw32.elf2uf2-2062372.220619.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.elf2uf2-2062372.220619.zip",
|
||||
"checksum": "SHA-256:2a39f7f20e42c5b981286dfdf50bc3d7201cbe63d191caf38a0ffa306422ed08",
|
||||
"size": "78291"
|
||||
"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.4.0-b-cb31b54",
|
||||
"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.4.0-b/aarch64-linux-gnu.pioasm-2062372.220619.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.pioasm-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:71887999ad64e64f75658a1883029b337cb9738d87e04944b1dbc0321d3c7a67",
|
||||
"size": "453580"
|
||||
"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.4.0-b/arm-linux-gnueabihf.pioasm-2062372.220619.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.pioasm-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:5b2e863e5764b0c4d53f536b5ea217e2a27f02f04b74da799e19b1fa6c8b39a8",
|
||||
"size": "360581"
|
||||
"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.4.0-b/i686-linux-gnu.pioasm-2062372.220619.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.pioasm-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:fd5ec8b1940e51db6ec2e2beea73d7be7f1e9cf09f6e66d739e3ed1be177a7a6",
|
||||
"size": "511417"
|
||||
"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.4.0-b/i686-w64-mingw32.pioasm-2062372.220619.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.pioasm-2062372.220619.zip",
|
||||
"checksum": "SHA-256:6a4a5f4f3c0b7a3bc08b2b3bd8111d33a5619633de9b04e03bf0bca6f17d1337",
|
||||
"size": "385759"
|
||||
"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.4.0-b/x86_64-apple-darwin14.pioasm-2062372.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.pioasm-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:9d9d7a3addaaca00712fdf5516a21fdae94926210f12f7ae16dc8ebf7beacfe8",
|
||||
"size": "480510"
|
||||
"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.4.0-b/x86_64-linux-gnu.pioasm-2062372.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.pioasm-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:be77c350eb7777de01c93312919c370e4ef3e5e281f122f46a2348a21693c480",
|
||||
"size": "458738"
|
||||
"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.4.0-b/x86_64-w64-mingw32.pioasm-2062372.220619.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.pioasm-2062372.220619.zip",
|
||||
"checksum": "SHA-256:451ad335a5cebcee3b6acda73d887a488f98c4a8839b8e98d557425f8d7f47ea",
|
||||
"size": "408660"
|
||||
"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.4.0-b-cb31b54",
|
||||
"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.4.0-b/aarch64-linux-gnu.mklittlefs-affa497.220619.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.mklittlefs-affa497.220619.tar.gz",
|
||||
"checksum": "SHA-256:1752294e6cc6ce3edd8b417e773c8703a1dc4e616f158ed6c928b62bec7289b5",
|
||||
"size": "47286"
|
||||
"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.4.0-b/arm-linux-gnueabihf.mklittlefs-affa497.220619.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.mklittlefs-affa497.220619.tar.gz",
|
||||
"checksum": "SHA-256:07e182ca15cf60d0f266030ff796ffc566c78e5e1fd148948a6ec3cbab444103",
|
||||
"size": "40823"
|
||||
"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.4.0-b/i686-linux-gnu.mklittlefs-affa497.220619.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.mklittlefs-affa497.220619.tar.gz",
|
||||
"checksum": "SHA-256:774657fbfaca1793acd8461e90399de1be0e99715b9135af0b935adc40211c72",
|
||||
"size": "50926"
|
||||
"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.4.0-b/i686-w64-mingw32.mklittlefs-affa497.220619.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.mklittlefs-affa497.220619.zip",
|
||||
"checksum": "SHA-256:473ba014d011737d97e703059cf2819d9ee2328f2af2f93f52c43eba53e34f55",
|
||||
"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.4.0-b/x86_64-apple-darwin14.mklittlefs-affa497.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.mklittlefs-affa497.220619.tar.gz",
|
||||
"checksum": "SHA-256:ffc1fef60f4c359978f6476a8cc33995638d826e4820ca96fc17f3cf47250bec",
|
||||
"size": "365767"
|
||||
"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.4.0-b/x86_64-linux-gnu.mklittlefs-affa497.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.mklittlefs-affa497.220619.tar.gz",
|
||||
"checksum": "SHA-256:0a05281f13ae48a1ce4894107525e7027258746c1cac3a568b51b8082f99e93f",
|
||||
"size": "49786"
|
||||
"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.4.0-b/x86_64-w64-mingw32.mklittlefs-affa497.220619.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.mklittlefs-affa497.220619.zip",
|
||||
"checksum": "SHA-256:039981ec41f38a9c89de3466d9fd8c9e7c0723ab53798223ceb4d122fdcac914",
|
||||
"size": "347613"
|
||||
"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: e7267f99fe...2e6142b15b
+4
-3
@@ -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.2.2
|
||||
version=2.3.0
|
||||
|
||||
runtime.tools.pqt-gcc.path={runtime.platform.path}/system/arm-none-eabi
|
||||
runtime.tools.pqt-python3.path={runtime.platform.path}/system/python3
|
||||
@@ -41,8 +41,9 @@ compiler.warning_flags.default=-Werror=return-type
|
||||
compiler.warning_flags.more=-Wall -Werror=return-type -Wno-ignored-qualifiers
|
||||
compiler.warning_flags.all=-Wall -Wextra -Werror=return-type -Wno-ignored-qualifiers
|
||||
|
||||
compiler.defines={build.led} {build.usbstack_flags} -DCFG_TUSB_MCU=OPT_MCU_RP2040 -DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}'
|
||||
compiler.includes="-iprefix{runtime.platform.path}/" "@{runtime.platform.path}/lib/platform_inc.txt"
|
||||
compiler.netdefines=-DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 -DCYW43_LWIP=0 -DLWIP_IPV6=1 -DLWIP_IPV4=1 -DLWIP_IGMP=1 -DLWIP_CHECKSUM_CTRL_PER_NETIF=1
|
||||
compiler.defines={build.led} {build.usbstack_flags} -DCFG_TUSB_MCU=OPT_MCU_RP2040 -DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' {compiler.netdefines}
|
||||
compiler.includes="-iprefix{runtime.platform.path}/" "@{runtime.platform.path}/lib/platform_inc.txt" "-I{runtime.platform.path}/tools/libpico"
|
||||
compiler.flags=-march=armv6-m -mcpu=cortex-m0plus -mthumb -ffunction-sections -fdata-sections {build.flags.exceptions} {build.flags.stackprotect}
|
||||
compiler.wrap="@{runtime.platform.path}/lib/platform_wrap.txt"
|
||||
compiler.libpico="{runtime.platform.path}/lib/libpico.a"
|
||||
|
||||
+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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -7,6 +7,9 @@ set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_BUILD_TYPE RelWithDebInfo)
|
||||
|
||||
# Enable PicoW driver support. Compatible with standard Pico
|
||||
set(PICO_BOARD pico_w)
|
||||
|
||||
# Initialize the SDK
|
||||
pico_sdk_init()
|
||||
|
||||
@@ -17,6 +20,12 @@ target_compile_definitions(pico PUBLIC
|
||||
PICO_PRINTF_ALWAYS_INCLUDED=1
|
||||
PICO_FLASH_SIZE_BYTES=16777216
|
||||
PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64
|
||||
LWIP_IPV4=1
|
||||
LWIP_IPV6=1
|
||||
LWIP_UDP=1
|
||||
LWIP_IGMP=1
|
||||
LWIP_CHECKSUM_CTRL_PER_NETIF=1
|
||||
CYW43_WARN=//
|
||||
)
|
||||
|
||||
target_compile_options(pico PUBLIC
|
||||
@@ -29,6 +38,7 @@ include_directories(BEFORE ${PICO_SDK_PATH}/../tools/libpico)
|
||||
|
||||
target_link_libraries(pico
|
||||
boot_stage2
|
||||
cyw43_driver
|
||||
hardware_adc
|
||||
hardware_base
|
||||
hardware_claim
|
||||
@@ -58,11 +68,15 @@ target_link_libraries(pico
|
||||
pico_bootrom
|
||||
pico_bootsel_via_double_reset
|
||||
pico_cxx_options
|
||||
pico_cyw43_arch_none
|
||||
pico_divider
|
||||
pico_double
|
||||
pico_fix
|
||||
pico_float
|
||||
pico_int64_ops
|
||||
pico_lwip
|
||||
pico_lwip_nosys
|
||||
pico_lwip_sntp
|
||||
pico_malloc
|
||||
pico_mem_ops
|
||||
pico_multicore
|
||||
@@ -74,10 +88,9 @@ target_link_libraries(pico
|
||||
pico_util
|
||||
tinyusb
|
||||
tinyusb_device_unmarked
|
||||
pico_audio
|
||||
pico_audio_i2s
|
||||
)
|
||||
|
||||
add_custom_command(TARGET pico POST_BUILD
|
||||
COMMAND ar d libpico.a stdio.c.obj stdio_usb.c.obj stdio_usb_descriptors.c.obj
|
||||
COMMAND ar d libpico.a stdio.c.obj stdio_usb.c.obj stdio_usb_descriptors.c.obj cyw43_arch_threadsafe_background.c.obj
|
||||
COMMAND ar q libpico.a pico-sdk/src/rp2_common/cyw43_driver/cyw43_resource.o
|
||||
)
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
#ifndef _LWIPOPTS_EXAMPLE_COMMONH_H
|
||||
#define _LWIPOPTS_EXAMPLE_COMMONH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// Critical section protection
|
||||
extern void noInterrupts();
|
||||
extern void interrupts();
|
||||
//static int lwipNoInterrupts() { noInterrupts(); return 0; }
|
||||
//static void lwipInterrupts(int ign) { interrupts(); }
|
||||
#define SYS_ARCH_DECL_PROTECT int
|
||||
#define SYS_ARCH_PROTECT(lev) noInterrupts
|
||||
#define SYS_ARCH_UNPROTECT(lev) interrupts
|
||||
|
||||
// Common settings used in most of the pico_w examples
|
||||
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details)
|
||||
|
||||
#define NO_SYS 1
|
||||
#define LWIP_SOCKET 0
|
||||
#define MEM_LIBC_MALLOC 0
|
||||
|
||||
|
||||
#define MEM_ALIGNMENT 4
|
||||
#define MEM_SIZE 4000
|
||||
#define MEMP_NUM_TCP_SEG 32
|
||||
#define MEMP_NUM_ARP_QUEUE 10
|
||||
#define PBUF_POOL_SIZE 24
|
||||
#define LWIP_ARP 1
|
||||
#define LWIP_ETHERNET 1
|
||||
#define LWIP_ICMP 1
|
||||
#define LWIP_RAW 1
|
||||
#define TCP_WND (8 * TCP_MSS)
|
||||
#define TCP_MSS 1460
|
||||
#define TCP_SND_BUF (8 * TCP_MSS)
|
||||
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
|
||||
#define LWIP_NETIF_STATUS_CALLBACK 1
|
||||
#define LWIP_NETIF_LINK_CALLBACK 1
|
||||
#define LWIP_NETIF_HOSTNAME 1
|
||||
#define LWIP_NETCONN 0
|
||||
#define MEM_STATS 0
|
||||
#define SYS_STATS 0
|
||||
#define MEMP_STATS 0
|
||||
#define LINK_STATS 0
|
||||
// #define ETH_PAD_SIZE 2
|
||||
#define LWIP_CHKSUM_ALGORITHM 3
|
||||
#define LWIP_DHCP 1
|
||||
#define LWIP_IPV4 1
|
||||
#define LWIP_TCP 1
|
||||
#define LWIP_UDP 1
|
||||
#define LWIP_DNS 1
|
||||
#define LWIP_TCP_KEEPALIVE 1
|
||||
#define LWIP_NETIF_TX_SINGLE_PBUF 1
|
||||
#define DHCP_DOES_ARP_CHECK 0
|
||||
#define LWIP_DHCP_DOES_ACD_CHECK 0
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define LWIP_DEBUG 1
|
||||
#define LWIP_STATS 1
|
||||
#define LWIP_STATS_DISPLAY 1
|
||||
#endif
|
||||
|
||||
#define ETHARP_DEBUG LWIP_DBG_OFF
|
||||
#define NETIF_DEBUG LWIP_DBG_OFF
|
||||
#define PBUF_DEBUG LWIP_DBG_OFF
|
||||
#define API_LIB_DEBUG LWIP_DBG_OFF
|
||||
#define API_MSG_DEBUG LWIP_DBG_OFF
|
||||
#define SOCKETS_DEBUG LWIP_DBG_OFF
|
||||
#define ICMP_DEBUG LWIP_DBG_OFF
|
||||
#define INET_DEBUG LWIP_DBG_OFF
|
||||
#define IP_DEBUG LWIP_DBG_OFF
|
||||
#define IP_REASS_DEBUG LWIP_DBG_OFF
|
||||
#define RAW_DEBUG LWIP_DBG_OFF
|
||||
#define MEM_DEBUG LWIP_DBG_OFF
|
||||
#define MEMP_DEBUG LWIP_DBG_OFF
|
||||
#define SYS_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_RTO_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_CWND_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_WND_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_FR_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_RST_DEBUG LWIP_DBG_OFF
|
||||
#define UDP_DEBUG LWIP_DBG_OFF
|
||||
#define TCPIP_DEBUG LWIP_DBG_OFF
|
||||
#define PPP_DEBUG LWIP_DBG_OFF
|
||||
#define SLIP_DEBUG LWIP_DBG_OFF
|
||||
#define DHCP_DEBUG LWIP_DBG_OFF
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
#endif /* __LWIPOPTS_H__ */
|
||||
+14
-2
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
|
||||
def BuildFlashMenu(name, flashsize, fssizelist):
|
||||
for fssize in fssizelist:
|
||||
@@ -74,7 +75,7 @@ def BuildBoot(name):
|
||||
|
||||
def BuildUSBStack(name):
|
||||
print("%s.menu.usbstack.picosdk=Pico SDK" % (name))
|
||||
print('%s.menu.usbstack.picosdk.build.usbstack_flags="-I{runtime.platform.path}/tools/libpico"' % (name))
|
||||
print('%s.menu.usbstack.picosdk.build.usbstack_flags=' % (name))
|
||||
print("%s.menu.usbstack.tinyusb=Adafruit TinyUSB" % (name))
|
||||
print('%s.menu.usbstack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"' % (name))
|
||||
|
||||
@@ -173,6 +174,10 @@ def MakeBoard(name, vendor_name, product_name, vid, pid, pwr, boarddefine, flash
|
||||
if name == "generic":
|
||||
BuildBoot(n)
|
||||
MakeBoardJSON(name, vendor_name, product_name, vid, pid, pwr, boarddefine, flashsizemb, boot2)
|
||||
global pkgjson
|
||||
thisbrd = {}
|
||||
thisbrd['name'] = "%s %s" % (vendor_name, product_name)
|
||||
pkgjson['packages'][0]['platforms'][0]['boards'].append(thisbrd)
|
||||
|
||||
def MakeBoardJSON(name, vendor_name, product_name, vid, pid, pwr, boarddefine, flashsizemb, boot2):
|
||||
json = """{
|
||||
@@ -230,6 +235,9 @@ def MakeBoardJSON(name, vendor_name, product_name, vid, pid, pwr, boarddefine, f
|
||||
f.write(json)
|
||||
f.close()
|
||||
|
||||
pkgjson = json.load(open(os.path.abspath(os.path.dirname(__file__)) + '/../package/package_pico_index.template.json'))
|
||||
pkgjson['packages'][0]['platforms'][0]['boards'] = []
|
||||
|
||||
sys.stdout = open(os.path.abspath(os.path.dirname(__file__)) + "/../boards.txt", "w")
|
||||
WriteWarning()
|
||||
BuildGlobalMenuList()
|
||||
@@ -240,6 +248,7 @@ BuildGlobalMenuList()
|
||||
|
||||
# Raspberry Pi
|
||||
MakeBoard("rpipico", "Raspberry Pi", "Pico", "0x2e8a", "0x000a", 250, "RASPBERRY_PI_PICO", 2, "boot2_w25q080_2_padded_checksum")
|
||||
MakeBoard("rpipicow", "Raspberry Pi", "Pico W", "0x2e8a", "0xf00a", 250, "RASPBERRY_PI_PICO_W", 2, "boot2_w25q080_2_padded_checksum")
|
||||
|
||||
# Adafruit
|
||||
MakeBoard("adafruit_feather", "Adafruit", "Feather RP2040", "0x239a", "0x80f1", 250, "ADAFRUIT_FEATHER_RP2040", 8, "boot2_w25x10cl_4_padded_checksum")
|
||||
@@ -265,10 +274,12 @@ MakeBoard("dfrobot_beetle_rp2040", "DFRobot", "Beetle RP2040", "0x3343", "0x4253
|
||||
|
||||
# iLabs
|
||||
MakeBoard("challenger_2040_lora", "iLabs", "Challenger 2040 LoRa", "0x2e8a", "0x1023", 250, "CHALLENGER_2040_LORA_RP2040", 8, "boot2_w25q080_2_padded_checksum")
|
||||
MakeBoard("challenger_2040_subghz", "iLabs", "Challenger 2040 SubGHz", "0x2e8a", "0x1032", 250, "CHALLENGER_2040_SUBGHZ_RP2040", 8, "boot2_w25q080_2_padded_checksum")
|
||||
MakeBoard("challenger_2040_wifi", "iLabs", "Challenger 2040 WiFi", "0x2e8a", "0x1006", 250, "CHALLENGER_2040_WIFI_RP2040", 8, "boot2_w25q080_2_padded_checksum")
|
||||
MakeBoard("challenger_2040_lte", "iLabs", "Challenger 2040 LTE", "0x2e8a", "0x100b", 500, "CHALLENGER_2040_LTE_RP2040", 8, "boot2_w25q080_2_padded_checksum")
|
||||
MakeBoard("challenger_2040_wifi_ble", "iLabs", "Challenger 2040 WiFi/BLE", "0x2e8a", "0x102C", 500, "CHALLENGER_2040_WIFI_BLE_RP2040", 8, "boot2_w25q080_2_padded_checksum")
|
||||
MakeBoard("challenger_nb_2040_wifi", "iLabs", "Challenger NB 2040 WiFi", "0x2e8a", "0x100b", 500, "CHALLENGER_NB_2040_WIFI_RP2040", 8, "boot2_w25q080_2_padded_checksum")
|
||||
MakeBoard("challenger_2040_sdrtc", "iLabs", "Challenger 2040 SD/RTC", "0x2e8a", "0x102d", 250, "CHALLENGER_NB_2040_SDRTC_RP2040", 8, "boot2_w25q080_2_padded_checksum")
|
||||
MakeBoard("ilabs_rpico32", "iLabs", "RPICO32", "0x2e8a", "0x1010", 250, "ILABS_2040_RPICO32_RP2040", 8, "boot2_w25q080_2_padded_checksum")
|
||||
|
||||
# Melopera
|
||||
@@ -295,5 +306,6 @@ MakeBoard("wiznet_5500_evb_pico", "WIZnet", "W5500-EVB-Pico", "0x2e8a", "0x1029"
|
||||
# Generic
|
||||
MakeBoard("generic", "Generic", "RP2040", "0x2e8a", "0xf00a", 250, "GENERIC_RP2040", 16, "boot2_generic_03h_4_padded_checksum")
|
||||
|
||||
|
||||
sys.stdout.close()
|
||||
with open(os.path.abspath(os.path.dirname(__file__)) + '/../package/package_pico_index.template.json', 'w') as f:
|
||||
f.write(json.dumps(pkgjson, indent=3))
|
||||
|
||||
@@ -106,6 +106,13 @@ env.Append(
|
||||
"ARDUINO_ARCH_RP2040",
|
||||
("F_CPU", "$BOARD_F_CPU"),
|
||||
("BOARD_NAME", '\\"%s\\"' % env.subst("$BOARD")),
|
||||
# LWIP-related
|
||||
("PICO_CYW43_ARCH_THREADSAFE_BACKGROUND", 1),
|
||||
("CYW43_LWIP", 0),
|
||||
("LWIP_IPV6", 1),
|
||||
("LWIP_IPV4", 1),
|
||||
("LWIP_IGMP", 1),
|
||||
("LWIP_LWIP_CHECKSUM_CTRL_PER_NETIF", 1),
|
||||
],
|
||||
|
||||
CPPPATH=[
|
||||
@@ -164,7 +171,6 @@ def configure_usb_flags(cpp_defines):
|
||||
platform.config.set(env_section, "lib_archive", False)
|
||||
elif "PIO_FRAMEWORK_ARDUINO_NO_USB" in cpp_defines:
|
||||
env.Append(
|
||||
CPPPATH=[os.path.join(FRAMEWORK_DIR, "tools", "libpico")],
|
||||
CPPDEFINES=[
|
||||
"NO_USB",
|
||||
"DISABLE_USB_SERIAL"
|
||||
@@ -173,8 +179,8 @@ def configure_usb_flags(cpp_defines):
|
||||
# do not further add more USB flags or update sizes. no USB used.
|
||||
return
|
||||
else:
|
||||
# standard Pico SDK USB stack used.
|
||||
env.Append(CPPPATH=[os.path.join(FRAMEWORK_DIR, "tools", "libpico")])
|
||||
# standard Pico SDK USB stack used, will get include path later on
|
||||
pass
|
||||
# in any case, add standard flags
|
||||
# preferably use USB information from arduino.earlephilhower section,
|
||||
# but fallback to sensible values derived from other parts otherwise.
|
||||
@@ -240,6 +246,9 @@ if not "USE_TINYUSB" in cpp_defines:
|
||||
# configure USB stuff
|
||||
configure_usb_flags(cpp_defines)
|
||||
|
||||
# ensure LWIP headers are in path after any TINYUSB distributed versions, also PicoSDK USB path headers
|
||||
env.Append(CPPPATH=[os.path.join(FRAMEWORK_DIR, "tools", "libpico")])
|
||||
|
||||
# info about the filesystem is already parsed by the platform's main.py
|
||||
# script. We can just use the info here
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#define PINS_COUNT (26u)
|
||||
#define NUM_DIGITAL_PINS (26u)
|
||||
#define NUM_ANALOG_INPUTS (4u)
|
||||
#define NUM_ANALOG_OUTPUTS (0u)
|
||||
#define ADC_RESOLUTION (12u)
|
||||
|
||||
// LEDs
|
||||
#define PIN_LED (24u)
|
||||
|
||||
// Serial
|
||||
#define PIN_SERIAL1_TX (16u)
|
||||
#define PIN_SERIAL1_RX (17u)
|
||||
|
||||
// SPI
|
||||
#define PIN_SPI0_MISO (20u)
|
||||
#define PIN_SPI0_MOSI (23u)
|
||||
#define PIN_SPI0_SCK (22u)
|
||||
#define PIN_SPI0_SS (21u)
|
||||
|
||||
// Connected to SD card reader
|
||||
#define PIN_SPI1_MISO (12u)
|
||||
#define PIN_SPI1_MOSI (11u)
|
||||
#define PIN_SPI1_SCK (10u)
|
||||
#define PIN_SPI1_SS (9u)
|
||||
#define SD_SS PIN_SPI1_SS
|
||||
#define SS SD_SS
|
||||
#define SD_SPI SPI1
|
||||
#define SD_CARD_DETECT (13u)
|
||||
#define EXTERNAL_FLASH_USE_SPI SD_SPI
|
||||
#define EXTERNAL_FLASH_USE_CS SD_SS
|
||||
#define SDCARD_CS_PIN SD_SS
|
||||
|
||||
// Wire
|
||||
#define PIN_WIRE0_SDA (0u)
|
||||
#define PIN_WIRE0_SCL (1u)
|
||||
|
||||
// Not pinned out
|
||||
#define PIN_WIRE1_SDA (31u)
|
||||
#define PIN_WIRE1_SCL (31u)
|
||||
#define PIN_SERIAL2_RX (31u)
|
||||
#define PIN_SERIAL2_TX (31u)
|
||||
|
||||
#define SERIAL_HOWMANY (1u)
|
||||
#define SPI_HOWMANY (2u)
|
||||
#define WIRE_HOWMANY (1u)
|
||||
|
||||
#define LED_BUILTIN PIN_LED
|
||||
|
||||
static const uint8_t D0 = (16u);
|
||||
static const uint8_t D1 = (17u);
|
||||
static const uint8_t D2 = (20u);
|
||||
static const uint8_t D3 = (23u);
|
||||
static const uint8_t D4 = (22u);
|
||||
static const uint8_t D5 = (2u);
|
||||
static const uint8_t D6 = (3u);
|
||||
static const uint8_t D7 = (0u);
|
||||
static const uint8_t D8 = (1u);
|
||||
static const uint8_t D9 = (4u);
|
||||
static const uint8_t D10 = (5u);
|
||||
static const uint8_t D11 = (6u);
|
||||
static const uint8_t D12 = (7u);
|
||||
static const uint8_t D13 = (8u);
|
||||
static const uint8_t D14 = (13u);
|
||||
static const uint8_t D18 = (24u);
|
||||
|
||||
static const uint8_t A0 = (26u);
|
||||
static const uint8_t A1 = (27u);
|
||||
static const uint8_t A2 = (28u);
|
||||
static const uint8_t A3 = (29u);
|
||||
static const uint8_t A4 = (19u);
|
||||
static const uint8_t A5 = (21u);
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#define PINS_COUNT (25u)
|
||||
#define NUM_DIGITAL_PINS (25u)
|
||||
#define NUM_ANALOG_INPUTS (4u)
|
||||
#define NUM_ANALOG_OUTPUTS (0u)
|
||||
#define ADC_RESOLUTION (12u)
|
||||
|
||||
// LEDs
|
||||
#define PIN_LED (24u)
|
||||
|
||||
// Serial
|
||||
#define PIN_SERIAL1_TX (16u)
|
||||
#define PIN_SERIAL1_RX (17u)
|
||||
|
||||
// SPI
|
||||
#define PIN_SPI0_MISO (20u)
|
||||
#define PIN_SPI0_MOSI (23u)
|
||||
#define PIN_SPI0_SCK (22u)
|
||||
#define PIN_SPI0_SS (21u)
|
||||
|
||||
// Connected to sub GHz radio module
|
||||
#define PIN_SPI1_MISO (12u)
|
||||
#define PIN_SPI1_MOSI (11u)
|
||||
#define PIN_SPI1_SCK (10u)
|
||||
#define PIN_SPI1_SS (9u)
|
||||
#define RFM69HCW_SS (9u)
|
||||
#define RFM69HCW_DIO0 (14u)
|
||||
#define RFM69HCW_DIO1 (15u)
|
||||
#define RFM69HCW_DIO2 (18u)
|
||||
#define RFM69HCW_RST (13u)
|
||||
#define RFM69HCW_SPI SPI1
|
||||
|
||||
// Wire
|
||||
#define PIN_WIRE0_SDA (0u)
|
||||
#define PIN_WIRE0_SCL (1u)
|
||||
|
||||
// Not pinned out
|
||||
#define PIN_WIRE1_SDA (31u)
|
||||
#define PIN_WIRE1_SCL (31u)
|
||||
#define PIN_SERIAL2_RX (31u)
|
||||
#define PIN_SERIAL2_TX (31u)
|
||||
|
||||
#define SERIAL_HOWMANY (1u)
|
||||
#define SPI_HOWMANY (2u)
|
||||
#define WIRE_HOWMANY (1u)
|
||||
|
||||
#define LED_BUILTIN PIN_LED
|
||||
|
||||
static const uint8_t D0 = (16u);
|
||||
static const uint8_t D1 = (17u);
|
||||
static const uint8_t D2 = (20u);
|
||||
static const uint8_t D3 = (23u);
|
||||
static const uint8_t D4 = (22u);
|
||||
static const uint8_t D5 = (2u);
|
||||
static const uint8_t D6 = (3u);
|
||||
static const uint8_t D7 = (0u);
|
||||
static const uint8_t D8 = (1u);
|
||||
static const uint8_t D9 = (4u);
|
||||
static const uint8_t D10 = (5u);
|
||||
static const uint8_t D11 = (6u);
|
||||
static const uint8_t D12 = (7u);
|
||||
static const uint8_t D13 = (8u);
|
||||
static const uint8_t D14 = (13u);
|
||||
static const uint8_t D15 = (14u);
|
||||
static const uint8_t D16 = (15u);
|
||||
static const uint8_t D17 = (18u);
|
||||
static const uint8_t D18 = (24u);
|
||||
|
||||
static const uint8_t A0 = (26u);
|
||||
static const uint8_t A1 = (27u);
|
||||
static const uint8_t A2 = (28u);
|
||||
static const uint8_t A3 = (29u);
|
||||
static const uint8_t A4 = (19u);
|
||||
static const uint8_t A5 = (21u);
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
pinMode and digitalRead/Write for the Raspberry Pi Pico W RP2040
|
||||
Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <pico/cyw43_arch.h>
|
||||
|
||||
extern "C" void __pinMode(pin_size_t pin, PinMode mode);
|
||||
extern "C" void __digitalWrite(pin_size_t pin, PinStatus val);
|
||||
extern "C" PinStatus __digitalRead(pin_size_t pin);
|
||||
|
||||
extern "C" void pinMode(pin_size_t pin, PinMode mode) {
|
||||
if (pin < 32) {
|
||||
__pinMode(pin, mode);
|
||||
} else {
|
||||
// TBD - There is no GPIO direction control in the driver
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void digitalWrite(pin_size_t pin, PinStatus val) {
|
||||
if (pin < 32) {
|
||||
__digitalWrite(pin, val);
|
||||
} else {
|
||||
cyw43_arch_gpio_put(pin - 32, val == HIGH ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" PinStatus digitalRead(pin_size_t pin) {
|
||||
if (pin < 32) {
|
||||
return __digitalRead(pin);
|
||||
} else {
|
||||
return cyw43_arch_gpio_get(pin - 32) ? HIGH : LOW;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Initialize the Pico W WiFi driver
|
||||
|
||||
Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <pico/cyw43_arch.h>
|
||||
|
||||
extern "C" void initVariant() {
|
||||
cyw43_arch_init();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
// Pin definitions taken from:
|
||||
// https://datasheets.raspberrypi.org/pico/pico-datasheet.pdf
|
||||
|
||||
|
||||
// LEDs
|
||||
#define PIN_LED (32u)
|
||||
|
||||
// Serial
|
||||
#define PIN_SERIAL1_TX (0u)
|
||||
#define PIN_SERIAL1_RX (1u)
|
||||
|
||||
#define PIN_SERIAL2_TX (8u)
|
||||
#define PIN_SERIAL2_RX (9u)
|
||||
|
||||
// SPI
|
||||
#define PIN_SPI0_MISO (16u)
|
||||
#define PIN_SPI0_MOSI (19u)
|
||||
#define PIN_SPI0_SCK (18u)
|
||||
#define PIN_SPI0_SS (17u)
|
||||
|
||||
#define PIN_SPI1_MISO (12u)
|
||||
#define PIN_SPI1_MOSI (15u)
|
||||
#define PIN_SPI1_SCK (14u)
|
||||
#define PIN_SPI1_SS (13u)
|
||||
|
||||
// Wire
|
||||
#define PIN_WIRE0_SDA (4u)
|
||||
#define PIN_WIRE0_SCL (5u)
|
||||
|
||||
#define PIN_WIRE1_SDA (26u)
|
||||
#define PIN_WIRE1_SCL (27u)
|
||||
|
||||
#define SERIAL_HOWMANY (3u)
|
||||
#define SPI_HOWMANY (2u)
|
||||
#define WIRE_HOWMANY (2u)
|
||||
|
||||
#include "../generic/common.h"
|
||||
Reference in New Issue
Block a user