Compare commits

...
35 Commits
Author SHA1 Message Date
Earle F. Philhower, III 8aad2ca3d2 Update version 2022-08-21 19:54:11 -07:00
Earle F. Philhower, III de215a6e1b Add WiFi.getHostname() call 2022-08-21 19:53:18 -07:00
Earle F. Philhower, III 0b390d7dc4 Add HTTPUpdate class to pull updates from HTTP(S) (#789)
* Add HTTPUpdate class to pull updates from HTTP(S)
* Increase GH runners for pulls
WiFi builds and examples are taking some serious time now
* HTTPUpdate tests build on Pico W
2022-08-21 18:24:59 -07:00
Earle F. Philhower, III a3f5fee6a5 Make StreamDev stubs private to HTTPClient (#788) 2022-08-21 17:20:34 -07:00
Earle F. Philhower, III a3f4d89bc4 Ensure OTA errors are sent in single UDP packet (#787)
OTA text error messages were getting lost because they were sent in
multiple UDP packets, one per print(). Now collect the full error and
report in a single print, allowing text messages to appear in ESPOTA.
2022-08-21 15:29:23 -07:00
Earle F. Philhower, III 2044d2e51c Fix OTA signing (#786)
Force the builder to include the path where we build the signing header.

Undo a breaking bug in the Updater class (TBD fix in ESP8266)

Fixes #783
2022-08-21 15:20:00 -07:00
Earle F. Philhower, III f9e3278863 Report "no filesystem" on OTA uploads w/o a FS (#785)
Give a meaningful error when OTA is attempted against a chip which does
not have a filesystem configured.
2022-08-21 13:19:26 -07:00
Earle F. Philhower, III 0d15723444 Add HTTPClient, ported from the ESP8266 (#784)
Remove the need to have a separate WiFiClient that's destroyed after
the HTTPClient.  Let the object handle its own client, and pass through
any SSL requests.

Also supports the original ::begin methods which need a
WiFiClient(Secure) to be passed in and managed by the app.
2022-08-21 12:49:06 -07:00
Earle F. Philhower, III 6e0d6a27ec Avoid rescanning/connecting on WiFiMulti.run (#782)
If the WiFi network is already up, don't run the scan and connection
algorithm in WiFiMulti.
2022-08-21 08:33:17 -07:00
Earle F. Philhower, III a2465f5fb7 Port ESP8266 DNSServer (#779)
Add a simple DNS server for AP mode
Point DHCP server DNS entry to GW for DNSServer
2022-08-20 17:58:54 -07:00
arturo182 88e98f17b6 EEPROM: Add an update function (#780)
According to the Arduino docs, update works just like put, but it first checks if the value is different from the current one.
This is how our put already works, so we just alias update to put and we're done.
Function added to be more compatible with the Arduino API.
Also see #778
2022-08-20 17:50:40 -07:00
Earle F. Philhower, III b4db1ad54a Fix softAP config call 2022-08-20 12:24:08 -07:00
Earle F. Philhower, III 7be472932b Add ESP8266 compat functions for AP mode (#777)
Fixes #767
2022-08-20 12:00:05 -07:00
Earle F. Philhower, III d019f31ef1 Report ::connected() as false when WiFi link drops (#774)
There may be an issue in the CYW43 driver that causes a link to never be
reported as going down once it has connected, when it was disassociated or
when the wlan shuts off unexpectedly.

Work around it by clearing the internal link active in a TCP callback for
the CYW43 driver.

Reports disconnection properly now, as well as reconnection.

Fixes #762
2022-08-19 18:03:21 -07:00
Earle F. Philhower, III e2afeaef27 Add simple WiFiMulti support (#771)
Takes a list of APs, finds the one with highest RSSI, and tries to connect.
2022-08-19 12:28:56 -07:00
Earle F. Philhower, III 2b6ab6c19d Don't return from reboot (#772)
rp2040.reboot() would set a reboot timer for 100ms in the future, but then
return to user code and ran it until the timer expired.  Now infinite loop
until the WDT fires.
2022-08-19 12:21:17 -07:00
Earle F. Philhower, III 0ef026cfa4 Avoid spurious -O3 warning (#770)
Fixes #768
2022-08-18 13:56:09 -07:00
Earle F. Philhower, III 5787b4c02b Allow selecting SPI port for SD/SDFS filesystem (#759)
Fixes #758
2022-08-14 21:59:13 -07:00
Earle F. Philhower, III e947895119 Update version 2022-08-12 12:29:32 -07:00
Earle F. Philhower, III bb91d978b1 Add OTA.O to make p.io builds function (#755)
Partial #754
2022-08-12 06:09:29 -07:00
Earle F. Philhower, III da86a8942b Add OTA update support (#711)
Adds a 12K OTA stub 3rd stage bootloader, which reads new firmware
from the LittleFS filesystem and flashes on reboot.

By storing the OTA commands in a file in flash, it is possible to
recover from a power failure during OTA programming.  On power
resume, the OTA block will simply re-program from the beginning.

Support cryptographic signed OTA updates, if desired.  Includes
host-side signing logic via openssl.

Add PicoOTA library which encapsulates the file format for
the updater, including CRC32 checking.

Add LEAmDNS support to allow Arduino IDE discovery

Add ArduinoOTA class for IDE uploads

Add MD5Builder class

Add Updater class which supports writing and validating
cryptographically signed binaries from any source (http,
Ethernet, WiFi, Serial, etc.)

Add documentation and readmes.
2022-08-12 00:26:51 -07:00
freeasabeer 71be07e69f Increase FreeRTOS timer task stack to 1024 (#752) 2022-08-11 14:30:57 -07:00
Odd Stråbø be18c76c99 Udp: default local_ip to IP_ANY_TYPE when IPv6 is enabled (#750) 2022-08-10 15:25:02 -07:00
Earle F. Philhower, IIIandOdd Stråbø af2671d8eb IPv6 initial support from @oddstr13 (#748)
* Apply @oddstr13 multicast patch to cyw43 driver
* Initial work for enabling IPv6
* Allow accessing CYW43 stats when LWIP_SYS_CHECK_MS is not set
* Use cyw43_set_allmulti to allow receiving multicast
* Add tools/libpico/build to gitignore

Co-authored-by: Odd Stråbø <oddstr13@openshell.no>
2022-08-09 18:05:43 -07:00
Maximilian Gerhardt 11cb82b058 Fix typo in XIAO board name (#745) 2022-08-09 09:57:51 -07:00
Earle F. Philhower, III ab6a2aaadb Update README.md 2022-08-07 21:36:23 -07:00
Sabas a358f892d3 Add board ElectronicCats Hunter Cat NFC (#741)
* add board ElectronicCats Hunter Cat NFC

* update huntercat nfc
2022-08-07 21:36:04 -07:00
Earle F. Philhower, III cabb06d495 Fix UART wrong ::available() during wraparound (#739)
Fixes #735 .  Thanks to @ Haggarman for the find and fix.
2022-08-06 09:38:16 -07:00
Earle F. Philhower, III 005cba3acd Stop random crashes while writing to flash (#730)
FreeRTOS SMP was updated to:
a) Move ths SYSTICK handler, which cannot be disabled and can fire
   even with IRQs disabled, to RAM
b) Add a flag from the core to the SYSTICK handler to hold off on
   any PendSV (task switch) calls while we are doing the idleOtherCore.

The core now sets this flag, _holdPendSV, and adds add'l FreeRTOS SMP
calls to really, really tell the OS we can't, don't, and better not
be swapped out while writing to flash.

Fixes #719
2022-07-29 22:40:48 -07:00
Earle F. Philhower, III bb029cc287 Increase LWIP MEM_SIZE to > TCP_SND_BUF (#731)
The send buffers are set to 8 * MSS = ~11.5K.  MEM_SIZE is now set to
be larger than that, 16K, in order to help avoid having tcp_write fail
with ENOMEM.  The attempt to use a smaller size is still included, which
will allow a tcp_write of up to 16 * 16K = 256K, i.e. all of memory.

Fixes #725
2022-07-29 22:35:37 -07:00
Earle F. Philhower, III 8fd56ada8b Adjust tcp_write size when memory is tight (#729)
Increases the MEM_SIZE outstanding write buffer to 8K

Allows the ClientContext to attempt to send smaller buffer chunks in the
case where MEM_SIZE won't allow the full tcp_sndbuf() transfer.

Fixes #725
2022-07-29 13:40:03 -07:00
Earle F. Philhower, III 5ab19e9a9f Fix I2S timing (#728)
BCLK was running at 50% of expected speed.

Fixes #714
2022-07-29 12:40:04 -07:00
Earle F. Philhower, III 82abc76e0c Add CMSIS defines to Platform.io (#721)
Ref: https://github.com/earlephilhower/arduino-pico/pull/717#issuecomment-1197921851
2022-07-28 12:29:16 -07:00
AngeloGioacchino Del Regno 6e0175bd8e platform.txt: Add compiler flags for ARM CMSIS (#717)
Adds compiler flags to correctly build Cortex-M0/M0+ code variants for
libraries inside of the ARM CMSIS codebase.

This was tested with the Arduino_CMSIS-DSP library.
2022-07-27 19:11:50 -07:00
Pontus OldbergandEarle F. Philhower, III e6e87fd307 Added to possibility to have extra compiler directives for a board. (#713)
* Adds support for Challenger RP2040 WiFi boards

* Added Challenger board to makeboards build script

* Adds new challenger board with LTE modem.

* Updated after getting approved PID from Raspberry Pi

* Add support for reverse numbering of analog pins.

* Added minimal HW support for onboard WiFi modem.

* Added challenger-nb-rp2040-wifi and RPICO32 module.

* Updated PID for RPICO32

* Added a simple support class for challenger LTE boards

* Update ChallengerLTE.cpp

Fixed spelling error

* Adds option for setting USB max power in makeboards.py

* Added new board Challenger RP2040 LoRa

* Added new lora board to readme.

* Added missing SERIAL2 and LoRa module GIO pins.

* Added support for enabling UART CTS and RTS pins.

* Updated boards.txt after merge conflict of makeboards.py

* Fixed incorrect indention

* Fixed PR comments

* Add new Challenger RP2040 WiFi/BLE board (https://ilabs.se/challenger-rp2040-wifi-ble-datasheet)

* * Updated PID for WiFi/BLE board
* Added abstraction pins for both versions of wifi modules
* Added support for replacing support class serial port.
* Added support for retrieving support class serial port.

* Fixed spelling errors.

* Updated helper class for Challenger NB board.

* Added Challenger sdrtc and subghz boards.

* Updated readme.

* Re ran makeboards to generate new index.

* Added to possibility to have extra compiler directives for a board.

* Added extra compiler options to JSON generation.

* Allows having a list of extra macros to define

* Fixed incorrect USB PID for Challenger NB board.

* Added board initialization for all wifi boards.

Co-authored-by: Earle F. Philhower, III <earlephilhower@yahoo.com>
2022-07-27 08:36:50 -07:00
164 changed files with 29979 additions and 958 deletions
+5 -3
View File
@@ -20,7 +20,7 @@ jobs:
- name: Run codespell
uses: codespell-project/actions-codespell@master
with:
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server,./ota/uzlib
ignore_words_list: ser,dout
# Consistent style
@@ -57,7 +57,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
chunk: [0, 1, 2, 3]
chunk: [0, 1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v3
with:
@@ -76,7 +76,7 @@ jobs:
TRAVIS_BUILD_DIR: ${{ github.workspace }}
TRAVIS_TAG: ${{ github.ref }}
BUILD_PARITY: custom
mod: 4
mod: 6
rem: ${{ matrix.chunk }}
run: |
cd pico-sdk
@@ -221,3 +221,5 @@ jobs:
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" -O "build_flags=-DUSE_TINYUSB" libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino
- name: Build WiFi Example
run: pio ci --board=rpipicow -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/WiFi/examples/ScanNetworks/ScanNetworks.ino
- name: Build Signed OTA Example
run: pio ci --board=rpipicow -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/ArduinoOTA/examples/SignedOTA/SignedOTA.ino
+3
View File
@@ -1,3 +1,6 @@
.DS_Store
system
tools/dist
docs/_build
ota/build
tools/libpico/build
+4 -1
View File
@@ -3,7 +3,7 @@
url = https://github.com/earlephilhower/ArduinoCore-API.git
[submodule "pico-sdk"]
path = pico-sdk
url = https://github.com/raspberrypi/pico-sdk.git
url = https://github.com/earlephilhower/pico-sdk.git
[submodule "system/pyserial"]
path = tools/pyserial
url = https://github.com/pyserial/pyserial.git
@@ -31,3 +31,6 @@
[submodule "tools/libbearssl/bearssl"]
path = tools/libbearssl/bearssl
url = https://github.com/earlephilhower/bearssl-esp8266.git
[submodule "ota/uzlib"]
path = ota/uzlib
url = https://github.com/pfalcon/uzlib.git
+5
View File
@@ -24,6 +24,7 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
* Cytron Maker Nano RP2040
* DeRuiLab FlyBoard2040 Core
* DFRobot Beetle RP2040
* ElectronicCats Hunter Cat NFC
* Invector Labs Challenger RP2040 WiFi
* Invector Labs Challenger RP2040 WiFi/BLE
* Invector Labs Challenger NB RP2040 WiFi
@@ -145,6 +146,8 @@ The installed tools include a version of OpenOCD (in the pqt-openocd directory)
# Features
* Adafruit TinyUSB Arduino (USB mouse, keyboard, flash drive, generic HID, CDC Serial, MIDI, WebUSB, others)
* Generic Arduino USB Serial, Keyboard, and Mouse emulation
* WiFi (Pico W)
* Over-the-Air (OTA) upgrades
* Filesystems (LittleFS and SD/SDFS)
* Multicore support (setup1() and loop1())
* FreeRTOS SMP support
@@ -183,6 +186,8 @@ If you want to contribute or have bugfixes, drop me a note at <earlephilhower@ya
* [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.
* [BearSSL](https://bearssl.org) library written by Thomas Pornin, is distributed under the [MIT License](https://bearssl.org/#legal-details).
* [UZLib](https://github.com/pfalcon/uzlib) is copyright (c) 2003 Joergen Ibsen and distributed under the zlib license.
* [LEAmDMS](https://github.com/LaborEtArs/ESP8266mDNS) is copyright multiple authors and distributed under the MIT license.
-Earle F. Philhower, III
earlephilhower@yahoo.com
+1014 -566
View File
File diff suppressed because it is too large Load Diff
+4 -3
View File
@@ -50,7 +50,9 @@ enum SeekMode {
class File : public Stream {
public:
File(FileImplPtr p = FileImplPtr(), FS *baseFS = nullptr) : _p(p), _fakeDir(nullptr), _baseFS(baseFS) { }
File(FileImplPtr p = FileImplPtr(), FS *baseFS = nullptr) : _p(p), _fakeDir(nullptr), _baseFS(baseFS) {
_startMillis = millis(); /* workaround -O3 spurious warning #768 */
}
// Print methods:
size_t write(uint8_t) override;
@@ -90,9 +92,8 @@ public:
uint8_t obuf[256];
size_t doneLen = 0;
size_t sentLen;
int i;
while (src.available() > sizeof(obuf)) {
while ((size_t)src.available() > sizeof(obuf)) {
src.read(obuf, sizeof(obuf));
sentLen = write(obuf, sizeof(obuf));
doneLen = doneLen + sentLen;
+44
View File
@@ -21,7 +21,9 @@
#include <hardware/clocks.h>
#include <hardware/irq.h>
#include <hardware/pio.h>
#include <pico/unique_id.h>
#include <hardware/exception.h>
#include <hardware/watchdog.h>
#include <hardware/structs/rosc.h>
#include <hardware/structs/systick.h>
#include <pico/multicore.h>
@@ -32,6 +34,18 @@
extern "C" volatile bool __otherCoreIdled;
// Halt the FreeRTOS PendSV task switching magic
extern "C" int __holdUpPendSV;
// FreeRTOS weak functions, to be overridden when we really are running FreeRTOS
extern "C" {
extern void vTaskSuspendAll() __attribute__((weak));
extern int32_t xTaskResumeAll() __attribute__((weak));
typedef struct tskTaskControlBlock * TaskHandle_t;
extern void vTaskPreemptionDisable(TaskHandle_t p) __attribute__((weak));
extern void vTaskPreemptionEnable(TaskHandle_t p) __attribute__((weak));
}
class _MFIFO {
public:
_MFIFO() { /* noop */ };
@@ -86,6 +100,11 @@ public:
if (!_multicore) {
return;
}
__holdUpPendSV = 1;
if (__isFreeRTOS) {
vTaskPreemptionDisable(nullptr);
vTaskSuspendAll();
}
mutex_enter_blocking(&_idleMutex);
__otherCoreIdled = false;
multicore_fifo_push_blocking(_GOTOSLEEP);
@@ -98,6 +117,12 @@ public:
}
mutex_exit(&_idleMutex);
__otherCoreIdled = false;
if (__isFreeRTOS) {
xTaskResumeAll();
vTaskPreemptionEnable(nullptr);
}
__holdUpPendSV = 0;
// Other core will exit busy-loop and return to operation
// once __otherCoreIdled == false.
}
@@ -288,6 +313,25 @@ public:
multicore_launch_core1(main1);
}
void reboot() {
watchdog_reboot(0, 0, 10);
while (1) {
continue;
}
}
inline void restart() {
reboot();
}
const char *getChipID() {
static char id[PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1] = { 0 };
if (!id[0]) {
pico_get_unique_board_id_string(id, sizeof(id));
}
return id;
}
// Multicore comms FIFO
_MFIFO fifo;
+3 -3
View File
@@ -1,5 +1,5 @@
#pragma once
#define ARDUINO_PICO_MAJOR 2
#define ARDUINO_PICO_MINOR 3
#define ARDUINO_PICO_REVISION 3
#define ARDUINO_PICO_VERSION_STR "2.3.3"
#define ARDUINO_PICO_MINOR 4
#define ARDUINO_PICO_REVISION 1
#define ARDUINO_PICO_VERSION_STR "2.4.1"
+1 -1
View File
@@ -292,7 +292,7 @@ int SerialUART::available() {
} else {
_pumpFIFO();
}
return (_writer - _reader) % _fifoSize;
return (_fifoSize + _writer - _reader) % _fifoSize;
}
int SerialUART::availableForWrite() {
+247
View File
@@ -0,0 +1,247 @@
/**
StreamString.h
Copyright (c) 2020 D. Gauchard. 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 __STREAMSTRING_H
#define __STREAMSTRING_H
#include <limits>
#include <algorithm>
#include "Stream.h"
#include "api/String.h"
///////////////////////////////////////////////////////////////
// S2Stream points to a String and makes it a Stream
// (it is also the helper for StreamString)
class S2Stream: public Stream {
public:
S2Stream(String& string, int peekPointer = -1) : string(&string), peekPointer(peekPointer) { }
S2Stream(String* string, int peekPointer = -1) : string(string), peekPointer(peekPointer) { }
virtual int available() override {
return string->length();
}
virtual int availableForWrite() override {
return std::numeric_limits<int16_t>::max();
}
virtual int read() override {
if (peekPointer < 0) {
// consume chars
if (string->length()) {
char c = string->charAt(0);
string->remove(0, 1);
return c;
}
} else if (peekPointer < (int)string->length()) {
// return pointed and move pointer
return string->charAt(peekPointer++);
}
// everything is read
return -1;
}
virtual size_t write(uint8_t data) override {
return string->concat((char)data);
}
// virtual int read(uint8_t* buffer, size_t len) override
// {
// if (peekPointer < 0)
// {
// // string will be consumed
// size_t l = std::min(len, (size_t)string->length());
// memcpy(buffer, string->c_str(), l);
// string->remove(0, l);
// return l;
// }
//
// if (peekPointer >= (int)string->length())
// {
// return 0;
// }
//
// // only the pointer is moved
// size_t l = std::min(len, (size_t)(string->length() - peekPointer));
// memcpy(buffer, string->c_str() + peekPointer, l);
// peekPointer += l;
// return l;
// }
virtual size_t write(const uint8_t* buffer, size_t len) override {
return string->concat((const char*)buffer, len) ? len : 0;
}
virtual int peek() override {
if (peekPointer < 0) {
if (string->length()) {
return string->charAt(0);
}
} else if (peekPointer < (int)string->length()) {
return string->charAt(peekPointer);
}
return -1;
}
virtual void flush() override {
// nothing to do
}
#if 0
virtual bool inputCanTimeout() override {
return false;
}
virtual bool outputCanTimeout() override {
return false;
}
//// Stream's peekBufferAPI
virtual bool hasPeekBufferAPI() const override {
return true;
}
virtual size_t peekAvailable() {
if (peekPointer < 0) {
return string->length();
}
return string->length() - peekPointer;
}
virtual const char* peekBuffer() override {
if (peekPointer < 0) {
return string->c_str();
}
if (peekPointer < (int)string->length()) {
return string->c_str() + peekPointer;
}
return nullptr;
}
virtual void peekConsume(size_t consume) override {
if (peekPointer < 0) {
// string is really consumed
string->remove(0, consume);
} else {
// only the pointer is moved
peekPointer = std::min((size_t)string->length(), peekPointer + consume);
}
}
virtual ssize_t streamRemaining() override {
return peekPointer < 0 ? string->length() : string->length() - peekPointer;
}
// calling setConsume() will consume bytes as the stream is read
// (enabled by default)
void setConsume() {
peekPointer = -1;
}
#endif
// Reading this stream will mark the string as read without consuming
// (not enabled by default)
// Calling resetPointer() resets the read state and allows rereading.
void resetPointer(int pointer = 0) {
peekPointer = pointer;
}
protected:
String* string;
int peekPointer; // -1:String is consumed / >=0:resettable pointer
};
// StreamString is a S2Stream holding the String
class StreamString: public String, public S2Stream {
protected:
void resetpp() {
if (peekPointer > 0) {
peekPointer = 0;
}
}
public:
StreamString(StreamString&& bro) : String(bro), S2Stream(this) { }
StreamString(const StreamString& bro) : String(bro), S2Stream(this) { }
// duplicate String constructors and operator=:
StreamString(const char* text = nullptr) : String(text), S2Stream(this) { }
StreamString(const String& string) : String(string), S2Stream(this) { }
StreamString(const __FlashStringHelper* str) : String(str), S2Stream(this) { }
StreamString(String&& string) : String(string), S2Stream(this) { }
explicit StreamString(char c) : String(c), S2Stream(this) { }
explicit StreamString(unsigned char c, unsigned char base = 10) :
String(c, base), S2Stream(this) {
}
explicit StreamString(int i, unsigned char base = 10) : String(i, base), S2Stream(this) { }
explicit StreamString(unsigned int i, unsigned char base = 10) : String(i, base), S2Stream(this) {
}
explicit StreamString(long l, unsigned char base = 10) : String(l, base), S2Stream(this) { }
explicit StreamString(unsigned long l, unsigned char base = 10) :
String(l, base), S2Stream(this) {
}
explicit StreamString(float f, unsigned char decimalPlaces = 2) :
String(f, decimalPlaces), S2Stream(this) {
}
explicit StreamString(double d, unsigned char decimalPlaces = 2) :
String(d, decimalPlaces), S2Stream(this) {
}
StreamString& operator=(const StreamString& rhs) {
String::operator=(rhs);
resetpp();
return *this;
}
StreamString& operator=(const String& rhs) {
String::operator=(rhs);
resetpp();
return *this;
}
StreamString& operator=(const char* cstr) {
String::operator=(cstr);
resetpp();
return *this;
}
StreamString& operator=(const __FlashStringHelper* str) {
String::operator=(str);
resetpp();
return *this;
}
StreamString& operator=(String&& rval) {
String::operator=(rval);
resetpp();
return *this;
}
};
#endif // __STREAMSTRING_H
+1
View File
@@ -28,6 +28,7 @@
RP2040 rp2040;
extern "C" {
volatile bool __otherCoreIdled = false;
int __holdUpPendSV = 0;
};
mutex_t _pioMutex;
@@ -36,7 +36,6 @@
#define CYW43_WL_GPIO_LED_PIN 0
#endif
volatile bool __inLWIP = false;
// note same code
@@ -89,7 +88,7 @@ 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
#if CYW43_USE_STATS && LWIP_SYS_CHECK_MS
static uint32_t counter;
if (counter++ % (30000 / LWIP_SYS_CHECK_MS) == 0) {
cyw43_dump_stats();
+2 -2
View File
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
# built documents.
#
# The short X.Y version.
version = u'2.3.3'
version = u'2.4.1'
# The full version, including alpha/beta/rc tags.
release = u'2.3.3'
release = u'2.4.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
+11 -1
View File
@@ -98,9 +98,19 @@ The included ``SD`` library is the Arduino standard one. Please refer to
the [Arduino SD reference](https://www.arduino.cc/en/reference/SD) for
more information.
Using Second SPI port for SD
----------------------------
The ``SD`` library ``begin()`` has been modified to allow you to use the
second SPI port, ``SPI1``. Just use the following call in place of
``SD.begin(cspin)``
.. code:: cpp
SD.begin(cspin, SPI1);
File system object (LittleFS/SD/SDFS)
--------------------------------------------
-------------------------------------
setConfig
~~~~~~~~~
+40
View File
@@ -0,0 +1,40 @@
HTTPClient Library
==================
A simple HTTP requestor that can handle both HTTP and HTTP requests is
included as the ``HTTPClient`` library.
Check the examples for use under HTTP and HTTPS configurations. In general,
for HTTP connections (unsecured and very uncommon on the internet today) simply
passing in a URL and performiung a GET is sufficient to transfer data.
.. code:: cpp
// Error checking is left as an exercise for the reader...
HTTPClient http;
if (http.begin("http://my.server/url")) {
if (http.GET() > 0) {
String data = http.getString();
}
http.end();
}
For HTTPS connections, simply add the appropriate WiFiClientSecure calls
as needed (i.e. ``setInsecure()``, ``setTrustAnchor``, etc.). See the
WiFiClientSecure documentation for more details.
.. code:: cpp
// Error checking is left as an exercise for the reader...
HTTPClient https;
https.setInsecure(); // Use certs, but do not check their authenticity
if (https.begin("https://my.secure.server/url")) {
if (http.GET() > 0) {
String data = http.getString();
}
http.end();
}
Unlike the ESP8266 and ESP32 ``HTTPClient`` implementations it is not necessary
to create a ``WiFiClient`` or ``WiFiClientSecure`` to pass in to the ``HTTPClient``
object.
+1 -1
View File
@@ -38,7 +38,7 @@ for normal operations.
Generic RP2040 Support
----------------------
If your RP2040 board isn't in the menus you can still use it with the
IDE bu using the `Board->Generic RP2040` menu option. You will need to
IDE by using the `Board->Generic RP2040` menu option. You will need to
then set the flash size (see above) and tell the IDE how to communicate
with the flash chip using the `Tools->Boot Stage 2` menu.
+4
View File
@@ -50,6 +50,10 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
WiFiClientSecure (TLS/SSL/HTTPS) <bearssl-client-secure-class>
WiFiServerSecure (TLS/SSL/HTTPS) <bearssl-server-secure-class>
HTTP/HTTPS Client <httpclient>
Over-the-Air (OTA) Updates <ota>
Ported/Optimized Libraries <libraries>
Using Pico-SDK <sdk>
+1 -1
View File
@@ -5,7 +5,7 @@ The Arduino-Pico core can be installed using the Arduino IDE Boards Manager
or using `git`. If you want to simply write programs for your RP2040 board,
the Boards Manager installation will suffice, but if you want to try the
latest pre-release versions and submit improvements, you will need the `git`
instllation.
installation.
Installing via Arduino Boards Manager
-------------------------------------
Executable
+239
View File
@@ -0,0 +1,239 @@
OTA Updates
===========
Introduction
------------
OTA (Over the Air) update is the process of uploading firmware to a Pico using a Wi-Fi, Ethernet, or other connection rather than a serial port. This is especially useful for WiFi enabled Picos, like the Pico W, because it lets systems be updated remotely, without needing physical access.
OTA may be done using:
- `Arduino IDE <#arduino-ide>`__
- `Web Browser <#web-browser>`__ - Coming soon
- `HTTP Server <#http-server>`__ - Coming soon
The Arduino IDE option is intended primarily for the software development phase. The other two options would be more useful after deployment, to provide the module with application updates either manually with a web browser, or automatically using an HTTP server.
In any case, the first firmware upload has to be done over a serial port. If the OTA routines are correctly implemented in the sketch, then all subsequent uploads may be done over the air.
By default, there is no imposed security for the OTA process. It is up to the developer to ensure that updates are allowed only from legitimate / trusted sources. Once the update is complete, the module restarts, and the new code is executed. The developer should ensure that the application running on the module is shut down and restarted in a safe manner. Chapters below provide additional information regarding security and safety of OTA updates.
OTA Requirements
~~~~~~~~~~~~~~~~
OTA requires a LittleFS partition to store firmware upgrade files. Make sure that you configure the sketch with a filesystem large enough to handle whatever size firmware binary you expect. Updates may be compressed, minimizing the total space needed.
Power Fail Safety
~~~~~~~~~~~~~~~~~
The update commands are all stored in flash, so a power cycle during update (except if the OTA bootloader is being changed) should not brick the device because when power is restored the OTA bootloader will begin the process from scratch once again.
Security Disclaimer
~~~~~~~~~~~~~~~~~~~
No guarantees as to the level of security provided for your application by the following methods is implied. Please refer to the GNU LGPL license associated for this project for full disclaimers. If you do find security weaknesses, please don't hesitate to contact the maintainers or supply pull requests with fixes. The MD5 verification and password protection schemes are already known to supply a very weak level of security.
Basic Security
~~~~~~~~~~~~~~
The module has to be exposed wirelessly to get it updated with a new sketch. That poses a risk of the module being violently hacked and programmed with some other code. To reduce the likelihood of being hacked, consider protecting your uploads with a password, selecting certain OTA port, etc.
Check functionality provided with the `ArduinoOTA <https://github.com/earlephilhower/arduino-pico/tree/master/libraries/ArduinoOTA>`__ library that may improve security:
.. code:: cpp
void setPort(uint16_t port);
void setHostname(const char* hostname);
void setPassword(const char* password);
Certain basic protection is already built in and does not require any additional coding by the developer. `ArduinoOTA <https://github.com/earlephilhower/arduino-pico/tree/master/libraries/ArduinoOTA>`__ and espota.py use `Digest-MD5 <https://en.wikipedia.org/wiki/Digest_access_authentication>`__ to authenticate uploads. Integrity of transferred data is verified on the ESP side using `MD5 <https://en.wikipedia.org/wiki/MD5>`__ checksum.
Make your own risk analysis and, depending on the application, decide what library functions to implement. If required, consider implementation of other means of protection from being hacked, like exposing modules for uploads only according to a specific schedule, triggering OTA only when the user presses a dedicated “Update” button wired to the ESP, etc.
Advanced Security - Signed Updates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
While the above password-based security will dissuade casual hacking attempts, it is not highly secure. For applications where a higher level of security is needed, cryptographically signed OTA updates can be required. This uses SHA256 hashing in place of MD5 (which is known to be cryptographically broken) and RSA-2048 bit level public-key encryption to guarantee that only the holder of a cryptographic private key can produce signed updates accepted by the OTA update mechanisms.
Signed updates are updates whose compiled binaries are signed with a private key (held by the developer) and verified with a public key (stored in the application and available for all to see). The signing process computes a hash of the binary code, encrypts the hash with the developer's private key, and appends this encrypted hash (also called a signature) to the binary that is uploaded (via OTA, web, or HTTP server). If the code is modified or replaced in any way by anyone except the holder of the developer's private key, the signature will not match and the ESP8266 will reject the upload.
Cryptographic signing only protects against tampering with binaries delivered via OTA. If someone has physical access, they will always be able to flash the device over the serial port. Signing also does not encrypt anything but the hash (so that it can't be modified), so this does not protect code inside the device: if a user has physical access they can read out your program.
**Securing your private key is paramount. The same private/public key pair that was used with the original upload must also be used to sign later binaries. Loss of the private key associated with a binary means that you will not be able to OTA-update any of your devices in the field. Alternatively, if someone else copies the private key, then they will be able to use it to sign binaries which will be accepted by the Pico.**
Signed Binary Format
^^^^^^^^^^^^^^^^^^^^
The format of a signed binary is compatible with the standard binary format, and can be uploaded to a non-signed Pico via serial or OTA without any conditions. Note, however, that once an unsigned OTA app is overwritten by this signed version, further updates will require signing.
As shown below, the signed hash is appended to the unsigned binary, followed by the total length of the signed hash (i.e., if the signed hash was 64 bytes, then this uint32 data segment will contain 64). This format allows for extensibility (such as adding a CA-based validation scheme allowing multiple signing keys all based on a trust anchor). Pull requests are always welcome. (currently it uses SHA256 with RSASSA-PKCS1-V1_5-SIGN signature scheme from RSA PKCS #1 v1.5)
.. code:: bash
NORMAL-BINARY <SIGNATURE> <uint32 LENGTH-OF-SIGNATURE>
Signed Binary Prerequisites
^^^^^^^^^^^^^^^^^^^^^^^^^^^
OpenSSL is required to run the standard signing steps, and should be available on any UNIX-like or Windows system. As usual, the latest stable version of OpenSSL is recommended.
Signing requires the generation of an RSA-2048 key (other bit lengths are supported as well, but 2048 is a good selection today) using any appropriate tool. The following shell commands will generate a new public/private key pair. Run them in the sketch directory:
.. code:: bash
openssl genrsa -out private.key 2048
openssl rsa -in private.key -outform PEM -pubout -out public.key
Automatic Signing
^^^^^^^^^^^^^^^^^
The simplest way of implementing signing is to use the automatic mode, which presently is only possible on Linux and Mac due to some of the tools not being available for Windows. This mode uses the IDE to configure the source code to enable sigining verification with a given public key, and signs binaries as part of the standard build process using a given public key.
To enable this mode, just include `private.key` and `public.key` in the sketch `.ino` directory. The IDE will call a helper script (`tools/signing.py`) before the build begins to create a header to enable key validation using the given public key, and to actually do the signing after the build process, generating a `sketch.bin.signed` file. When OTA is enabled (ArduinoOTA, Web, or HTTP), the binary will automatically only accept signed updates.
When the signing process starts, the message:
.. code:: bash
Enabling binary signing
will appear in the IDE window before a compile is launched. At the completion of the build, the signed binary file well be displayed in the IDE build window as:
.. code:: bash
Signed binary: /full/path/to/sketch.bin.signed
If you receive either of the following messages in the IDE window, the signing was not completed and you will need to verify the `public.key` and `private.key`:
.. code:: bash
Not enabling binary signing
... or ...
Not signing the generated binary
Manual Signing of Binaries
^^^^^^^^^^^^^^^^^^^^^^^^^^
Users may also manually sign executables and require the OTA process to verify their signature. In the main code, before enabling any update methods, add the following declarations and function call:
.. code:: cpp
<in globals>
BearSSL::PublicKey signPubKey( ... key contents ... );
BearSSL::HashSHA256 hash;
BearSSL::SigningVerifier sign( &signPubKey );
...
<in setup()>
Update.installSignature( &hash, &sign );
The above snippet creates a BearSSL public key and a SHA256 hash verifier, and tells the Update object to use them to validate any updates it receives from any method.
Compile the sketch normally and, once a `.bin` file is available, sign it using the signer script:
.. code:: bash
<ESP8266ArduinoPath>/tools/signing.py --mode sign --privatekey <path-to-private.key> --bin <path-to-unsigned-bin> --out <path-to-signed-binary>
Compression
-----------
The eboot bootloader incorporates a GZIP decompressor, built for very low code requirements. For applications, this optional decompression is completely transparent. For uploading compressed filesystems, the application must be built with `ATOMIC_FS_UPDATE` defined because, otherwise, eboot will not be involved in writing the filesystem.
No changes to the application are required. The `Updater` class and `eboot` bootloader (which performs actual application overwriting on update) automatically search for the `gzip` header in the uploaded binary, and if found, handle it.
Compress an application `.bin` file or filesystem package using any `gzip` available, at any desired compression level (`gzip -9` is recommended because it provides the maximum compression and uncompresses as fast as any other compressino level). For example:
.. code:: bash
gzip -9 sketch.bin # Maximum compression, output sketch.bin.gz
<Upload the resultant sketch.bin.gz>
If signing is desired, sign the gzip compressed file *after* compression.
.. code:: bash
gzip -9 sketch.bin
<ESP8266ArduinoPath>/tools/signing.py --mode sign --privatekey <path-to-private.key> --bin sketch.bin.gz --out sketch.bin.gz.signed
Safety
~~~~~~
The OTA process consumes some of the ESPs resources and bandwidth during upload. Then, the module is restarted and a new sketch executed. Analyse and test how this affects the functionality of the existing and new sketches.
If the ESP is in a remote location and controlling some equipment, you should devote additional attention to what happens if operation of this equipment is suddenly interrupted by the update process. Therefore, decide how to put this equipment into a safe state before starting the update. For instance, your module may be controlling a garden watering system in a sequence. If this sequence is not properly shut down and a water valve is left open, the garden may be flooded.
The following functions are provided with the `ArduinoOTA <https://github.com/earlephilhower/arduino-pico/tree/master/libraries/ArduinoOTA>`__ library and intended to handle functionality of your application during specific stages of OTA, or on an OTA error:
.. code:: cpp
void onStart(OTA_CALLBACK(fn));
void onEnd(OTA_CALLBACK(fn));
void onProgress(OTA_CALLBACK_PROGRESS(fn));
void onError(OTA_CALLBACK_ERROR (fn));
Uploading from the Arduino IDE
------------------------------
Uploading modules wirelessly from Arduino IDE is intended for the following typical scenarios:
- During firmware development as a quicker alternative to loading over a serial port,
- For updating a small number of modules,
- Only if modules are accessible on the same network as the computer with the Arduino IDE.
- For all IDE uploads,m the Pico W and the computer must be connected to the same network.
To upload wirelessly from the IDE:
1. Build a sketch starts ``WiFi`` and includes the appropriare calls to ``ArduinoOTA`` (see the examples for reference). These include the ``ArduinoOTA.begin()`` call in ``setup()`` and periodically calling ``ArduinoOTA.handle();`` from the ``loop()``
2. Upload using standard USB connection the first time.
3. The ``Tools->Port`` should now list ``pico-######`` under the ``Network Ports``. Select it (you won't be able to use the serial monitor, of course).
4. Try another upload. It should display the OTA process in place of the serial port upload.
Password Protection
-------------------
Protecting your OTA uploads with password is really straightforward. All you need to do, is to include the following statement in your code:
.. code:: cpp
ArduinoOTA.setPassword((const char *)"123");
Where ``123`` is a sample password that you should replace with your own.
Before implementing it in your sketch, it is a good idea to check how it works using *BasicOTA.ino* sketch available under *File > Examples > ArduinoOTA*. Go ahead, open *BasicOTA.ino*, uncomment the above statement that is already there, and upload the sketch. To make troubleshooting easier, do not modify example sketch besides what is absolutely required. This is including original simple ``123`` OTA password. Then attempt to upload sketch again (using OTA). After compilation is complete, once upload is about to begin, you should see prompt for password.
Enter the password and upload should be initiated as usual with the only difference being ``Authenticating...OK`` message visible in upload log.
You will not be prompted for a reentering the same password next time. Arduino IDE will remember it for you. You will see prompt for password only after reopening IDE, or if you change it in your sketch, upload the sketch and then try to upload it again.
Please note, it is possible to reveal password entered previously in Arduino IDE, if IDE has not been closed since last upload. This can be done by enabling *Show verbose output during: upload* in *File > Preferences* and attempting to upload the module.
Stream Interface
----------------
The Stream Interface is the base for all other update modes like OTA, HTTP Server / client. Given a Stream-class variable `streamVar` providing `byteCount` bytes of firmware, it can store the firmware as follows:
.. code:: cpp
Update.begin(firmwareLengthInBytes);
Update.writeStream(streamVar);
Update.end();
OTA Bootloader and Memory Map
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A firmware file is uploaded via any method (Ethernet, WiFi, serial ZModem, etc.) and stored on the LittleFS filesystem as a normal file. The Updater class (or the underlying PicoOTA) will make a special "OTA command" file on the filesystem, which will be read by the OTA bootloader. On a reboot, this OTA bootloader will check for an upgrade file, verify its contents, and then perform the requested update and reboot. If no upgrade file is present, the OTA bootloader simply jumps to the main sketch.
The ROM layout consists of:
.. code:: cpp
[boot2.S] [OTA Bootloader] [0-pad] [OTA partition table] [Main sketch] [LittleFS filesystem] [EEPROM]
+4
View File
@@ -33,6 +33,10 @@ values returned may not meet the most stringent random tests. **If your
application needs absolute bulletproof random numbers, consider using
dedicated external hardware.**
void reboot()
~~~~~~~~~~~~~
Forces a hardware reboot of the Pico.
Memory Information
------------------
+1 -1
View File
@@ -1,7 +1,7 @@
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>`__.
WiFi is supported on the Raspberry Pi Pico W by selecting the "Raspberry 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.
+5 -1
View File
@@ -21,7 +21,7 @@ extern void interrupts();
#define MEM_LIBC_MALLOC 0
#define MEM_ALIGNMENT 4
#define MEM_SIZE 4000
#define MEM_SIZE 16384
#define MEMP_NUM_TCP_SEG 32
#define MEMP_NUM_ARP_QUEUE 10
#define PBUF_POOL_SIZE 24
@@ -53,6 +53,10 @@ extern void interrupts();
#define DHCP_DOES_ARP_CHECK 0
#define LWIP_DHCP_DOES_ACD_CHECK 0
#if LWIP_IPV6
#define LWIP_IPV6_DHCP6 1
#endif
// NTP
extern void __setSystemTime(unsigned long long sec, unsigned long us);
#define SNTP_SET_SYSTEM_TIME_US(sec, us) __setSystemTime(sec, us)
+50
View File
@@ -0,0 +1,50 @@
/*
ota_command.h - OTA stub that copies from LittleFS to flash
Copyright (c) 2022 Earle F. Philhower, III. 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 <stdint.h>
#define _OTA_WRITE 1
#define _OTA_VERIFY 1
typedef struct {
uint32_t command;
union {
struct {
char filename[64];
uint32_t fileOffset;
uint32_t fileLength;
uint32_t flashAddress; // Normally XIP_BASE
} write;
};
} commandEntry;
// Must fit within 4K page
typedef struct {
uint8_t sign[8]; // "Pico OTA"
// List of operations
uint32_t count;
commandEntry cmd[8];
uint32_t crc32; // CRC32 over just the contents of this struct, up until just before this value
} OTACmdPage;
#define _OTA_COMMAND_FILE "otacommand.bin"
+4
View File
@@ -2,6 +2,8 @@
# Syntax Coloring Map
#######################################
Arduino KEYWORD3 RESERVED_WORD
#######################################
# Datatypes (KEYWORD1)
#######################################
@@ -23,6 +25,8 @@ pop KEYWORD2
pop_nb KEYWORD2
rp2040 KEYWORD2
reboot KEYWORD2
restart KEYWORD2
RP2040 KEYWORD2
usToPIOCycles KEYWORD2
f_cpu KEYWORD2
Binary file not shown.
BIN
View File
Binary file not shown.
+22
View File
@@ -55,6 +55,28 @@ SECTIONS
ASSERT(__boot2_end__ - __boot2_start__ == 256,
"ERROR: Pico second stage bootloader must be 256 bytes in size")
.ota : {
/* Start image with OTA */
KEEP (*(.OTA))
/* Align to the last 16-bytes of the OTA region */
/* If anyone has a better way of doing this, please submit a PR! */
/* . = __flash_binary_start + 0x2ff0;
LONG(__FS_START__)
LONG(__FS_END__)
LONG(__EEPROM_START__)
LONG(__FLASH_LENGTH__)*/
} > FLASH
.partition : {
/* Align to the last 16-bytes of the OTA region */
/* If anyone has a better way of doing this, please submit a PR! */
. = __flash_binary_start + 0x2ff0;
LONG(__FS_START__)
LONG(__FS_END__)
LONG(__EEPROM_START__)
LONG(__FLASH_LENGTH__)
} > FLASH
/* The second stage will always enter the image at the start of .text.
The debugger will use the ELF entry point, which is the _entry_point
symbol if present, otherwise defaults to start of .text.
BIN
View File
Binary file not shown.
@@ -0,0 +1,77 @@
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
void setup() {
Serial.begin(115200);
Serial.println("Booting");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection Failed! Rebooting...");
delay(5000);
rp2040.restart();
}
// Port defaults to 8266
// ArduinoOTA.setPort(8266);
// Hostname defaults to esp8266-[ChipID]
// ArduinoOTA.setHostname("myesp8266");
// No authentication by default
// ArduinoOTA.setPassword("admin");
// Password can be set with it's md5 value as well
// MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
// ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
ArduinoOTA.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch";
} else { // U_FS
type = "filesystem";
}
// NOTE: if updating FS this would be the place to unmount FS using FS.end()
Serial.println("Start updating " + type);
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) {
Serial.println("Auth Failed");
} else if (error == OTA_BEGIN_ERROR) {
Serial.println("Begin Failed");
} else if (error == OTA_CONNECT_ERROR) {
Serial.println("Connect Failed");
} else if (error == OTA_RECEIVE_ERROR) {
Serial.println("Receive Failed");
} else if (error == OTA_END_ERROR) {
Serial.println("End Failed");
}
});
ArduinoOTA.begin();
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
ArduinoOTA.handle();
}
@@ -0,0 +1,74 @@
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
const char* host = "OTA-LEDS";
int led_pin = 13;
#define N_DIMMERS 3
int dimmer_pin[] = { 14, 5, 15 };
void setup() {
Serial.begin(115200);
/* switch on led */
pinMode(led_pin, OUTPUT);
digitalWrite(led_pin, LOW);
Serial.println("Booting");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
WiFi.begin(ssid, password);
Serial.println("Retrying connection...");
}
/* switch off led */
digitalWrite(led_pin, HIGH);
/* configure dimmers, and OTA server events */
analogWriteRange(1000);
analogWrite(led_pin, 990);
for (int i = 0; i < N_DIMMERS; i++) {
pinMode(dimmer_pin[i], OUTPUT);
analogWrite(dimmer_pin[i], 50);
}
ArduinoOTA.setHostname(host);
ArduinoOTA.onStart([]() { // switch off all the PWMs during upgrade
for (int i = 0; i < N_DIMMERS; i++) {
analogWrite(dimmer_pin[i], 0);
}
analogWrite(led_pin, 0);
});
ArduinoOTA.onEnd([]() { // do a fancy thing with our board led at end
for (int i = 0; i < 30; i++) {
analogWrite(led_pin, (i * 100) % 1001);
delay(50);
}
});
ArduinoOTA.onError([](ota_error_t error) {
(void)error;
rp2040.restart();
});
/* setup the OTA server */
ArduinoOTA.begin();
Serial.println("Ready");
}
void loop() {
ArduinoOTA.handle();
}
@@ -0,0 +1,19 @@
// To be used with SignedOTA. The IDE will sign the binary
// automatically and upload over WiFi
// Released to the public domain, Earle Philhower, 2022
#include <Arduino.h>
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
srand(123);
}
void loop() {
int del = rand() % 100;
digitalWrite(LED_BUILTIN, HIGH);
delay(del * 10);
digitalWrite(LED_BUILTIN, LOW);
delay(del * 10);
}
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAu1Pt7yEk/xI+6cozLj5Bu4xV8gXDXcHS0rSJFfl4wBTk4UXp
aJRaLfR1k0juEEa5LBRZaoA0iLj2e6kfCibONx0VVoWmeqN2HBc3zkA1eqCksI0Q
Uudzto4KhKHp0odiZ2zo6c/2Tn1zqD/m3OLoSjVTbsJmGuwx8RGMBXozpg/uL0hH
flihX+HND4Xfw92QXv7SaPBhgvM9xyRxn0/w3J2nNjtuPuVN5vcQkd8ncMexVfy9
AWp+HSA5AT5N8CJ/EeIsdDMY1US28bUePzj1WIo75bZHKZNFw/iXe2xoPpm74qri
MNSlW2craFP2K3KYnI28vJeUU6t9I6LS9zt2zQIDAQABAoIBAE5GpuDKb8Qp4qIc
fMBxAVSWMn+cSuONj0O+bp4BDaTt1ioP5ZVukDQtt0ehLOEePFgf9LEc+1a6Ozy3
EaJTTs4W2Ai8djE+xqa8SPRlPjOMluSzPUP3NRHuTpTXd3YiXksrZjP1U02+/Cos
8ZIROtFvcPqSPso3MjMyitjrFFPqEtf1P+UiamjDrMSM72YX4W55kOkiCWCnAOmw
mGTlXOIqDSTBb1lloKWJfpB3RdnNo2izkU1HMBn7hVi433NUBA22o+RZhDFSZdD4
3kbkUqXd4p+vc/sh6muJtWS/COSIPFkLzdEYpBdt3XQ4FhlsRtILJaPWXa4OPjR6
ZoOwMB0CgYEA6OHfIofQiu4+HlTDN5YdyTmtYEYcrtbaQUxuQSEa2mshBphHP8uT
mYRVl2BzuprFmXZPz+FcjnPnfxqEehljvA3wMjA/PE+nQo9yyOC0N4ulXpkkqHdR
f+4KZVR7D+hesGe+57OQmvTqYZSHEt/ubjC9wZ90UFonLjsa4zibbrsCgYEAzexn
XDnThb3ffyBgvprP0IJjgMAEY0pXD++PKPQqPu9JMz68t7roYzkKFCFVOsaWpKxC
vX9mvYjTBjLpWh+ltIAN+EFz6seIbeSJ0RNybsAXYwT/mFWGHx2tMtlW6DgBu3UD
J2Yf76n0JaddBkfNMQI00Dl41+MU+AwwTB9fTBcCgYB2+f6Pm6d1cyYVROS/X1g0
V9011FwPDwFOXwftCka31Ad5YQ71jsIHqk44GjTF3xCYyJMZ917cAGcCzr9jydjk
WJKgcXm9DEy9ep//9Jzdy+BepgrObrcajriM8E424FaP9VDY+yojoICl/cXMZM9h
SFGJvDcmXgiqW9PuxhrSxQKBgAMN2oqXoPd+1W3BQS4ShbqF9IvYTThbxebKmsj0
thuw2NkVuR7Qetnd4rRhui3g/CL9GxBMb22oNdkFsEhR59dBfvOLpPh6dR+MIC8l
prDV0IL7c/8CZbbYbdUvPAa9rejl12IiNZ8MWj6kuNB7CCQN8FKWR6CMEaeMJrs6
S+OJAoGAbehNOUwEzmUKkfxf+279kBkgabcQ3NTaeSx0QOnI9KWHFGLYLQk9cMSu
maQJ1TYpbIoP1njzJ4bI2tynhwEuSMEhh4afP6U5H10NJX4PqSd0Rqc1vSJYcszr
5mUWil8FfbCBZ8jod2NQ55KYMVY5CphCqaK/s2bw2pvIR3uqJGg=
-----END RSA PRIVATE KEY-----
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1Pt7yEk/xI+6cozLj5B
u4xV8gXDXcHS0rSJFfl4wBTk4UXpaJRaLfR1k0juEEa5LBRZaoA0iLj2e6kfCibO
Nx0VVoWmeqN2HBc3zkA1eqCksI0QUudzto4KhKHp0odiZ2zo6c/2Tn1zqD/m3OLo
SjVTbsJmGuwx8RGMBXozpg/uL0hHflihX+HND4Xfw92QXv7SaPBhgvM9xyRxn0/w
3J2nNjtuPuVN5vcQkd8ncMexVfy9AWp+HSA5AT5N8CJ/EeIsdDMY1US28bUePzj1
WIo75bZHKZNFw/iXe2xoPpm74qriMNSlW2craFP2K3KYnI28vJeUU6t9I6LS9zt2
zQIDAQAB
-----END PUBLIC KEY-----
@@ -0,0 +1,91 @@
// Simple Signed OTA example
// Released to the public domain by Earle Philhower, Aug 2022
//
// Note that the actual code of this is the same as the BasicOTA. No user
// code changes are needed, only the presence of public.key and private.key
// in the sketch directory. The core will automatically sign any binaries
// and include the necessary code to verify signatures. For more info
// check the documentation
//
// After uploading this sketch, try uploading the SignedOTA-Blink sketch
// All unsigned binaries, or binaries signed with a different private
// key will fail to upload.
#include <WiFi.h>
#include <LEAmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
void setup() {
Serial.begin(115200);
Serial.println("Booting");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection Failed! Rebooting...");
delay(5000);
rp2040.restart();
}
// Port defaults to 8266
// ArduinoOTA.setPort(8266);
// Hostname defaults to esp8266-[ChipID]
// ArduinoOTA.setHostname("myesp8266");
// No authentication by default
// ArduinoOTA.setPassword("admin");
// Password can be set with it's md5 value as well
// MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
// ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
ArduinoOTA.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch";
} else { // U_FS
type = "filesystem";
}
// NOTE: if updating FS this would be the place to unmount FS using FS.end()
Serial.println("Start updating " + type);
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r\n", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) {
Serial.println("Auth Failed");
} else if (error == OTA_BEGIN_ERROR) {
Serial.println("Begin Failed");
} else if (error == OTA_CONNECT_ERROR) {
Serial.println("Connect Failed");
} else if (error == OTA_RECEIVE_ERROR) {
Serial.println("Receive Failed");
} else if (error == OTA_END_ERROR) {
Serial.println("End Failed");
}
});
ArduinoOTA.begin();
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
ArduinoOTA.handle();
}
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAu1Pt7yEk/xI+6cozLj5Bu4xV8gXDXcHS0rSJFfl4wBTk4UXp
aJRaLfR1k0juEEa5LBRZaoA0iLj2e6kfCibONx0VVoWmeqN2HBc3zkA1eqCksI0Q
Uudzto4KhKHp0odiZ2zo6c/2Tn1zqD/m3OLoSjVTbsJmGuwx8RGMBXozpg/uL0hH
flihX+HND4Xfw92QXv7SaPBhgvM9xyRxn0/w3J2nNjtuPuVN5vcQkd8ncMexVfy9
AWp+HSA5AT5N8CJ/EeIsdDMY1US28bUePzj1WIo75bZHKZNFw/iXe2xoPpm74qri
MNSlW2craFP2K3KYnI28vJeUU6t9I6LS9zt2zQIDAQABAoIBAE5GpuDKb8Qp4qIc
fMBxAVSWMn+cSuONj0O+bp4BDaTt1ioP5ZVukDQtt0ehLOEePFgf9LEc+1a6Ozy3
EaJTTs4W2Ai8djE+xqa8SPRlPjOMluSzPUP3NRHuTpTXd3YiXksrZjP1U02+/Cos
8ZIROtFvcPqSPso3MjMyitjrFFPqEtf1P+UiamjDrMSM72YX4W55kOkiCWCnAOmw
mGTlXOIqDSTBb1lloKWJfpB3RdnNo2izkU1HMBn7hVi433NUBA22o+RZhDFSZdD4
3kbkUqXd4p+vc/sh6muJtWS/COSIPFkLzdEYpBdt3XQ4FhlsRtILJaPWXa4OPjR6
ZoOwMB0CgYEA6OHfIofQiu4+HlTDN5YdyTmtYEYcrtbaQUxuQSEa2mshBphHP8uT
mYRVl2BzuprFmXZPz+FcjnPnfxqEehljvA3wMjA/PE+nQo9yyOC0N4ulXpkkqHdR
f+4KZVR7D+hesGe+57OQmvTqYZSHEt/ubjC9wZ90UFonLjsa4zibbrsCgYEAzexn
XDnThb3ffyBgvprP0IJjgMAEY0pXD++PKPQqPu9JMz68t7roYzkKFCFVOsaWpKxC
vX9mvYjTBjLpWh+ltIAN+EFz6seIbeSJ0RNybsAXYwT/mFWGHx2tMtlW6DgBu3UD
J2Yf76n0JaddBkfNMQI00Dl41+MU+AwwTB9fTBcCgYB2+f6Pm6d1cyYVROS/X1g0
V9011FwPDwFOXwftCka31Ad5YQ71jsIHqk44GjTF3xCYyJMZ917cAGcCzr9jydjk
WJKgcXm9DEy9ep//9Jzdy+BepgrObrcajriM8E424FaP9VDY+yojoICl/cXMZM9h
SFGJvDcmXgiqW9PuxhrSxQKBgAMN2oqXoPd+1W3BQS4ShbqF9IvYTThbxebKmsj0
thuw2NkVuR7Qetnd4rRhui3g/CL9GxBMb22oNdkFsEhR59dBfvOLpPh6dR+MIC8l
prDV0IL7c/8CZbbYbdUvPAa9rejl12IiNZ8MWj6kuNB7CCQN8FKWR6CMEaeMJrs6
S+OJAoGAbehNOUwEzmUKkfxf+279kBkgabcQ3NTaeSx0QOnI9KWHFGLYLQk9cMSu
maQJ1TYpbIoP1njzJ4bI2tynhwEuSMEhh4afP6U5H10NJX4PqSd0Rqc1vSJYcszr
5mUWil8FfbCBZ8jod2NQ55KYMVY5CphCqaK/s2bw2pvIR3uqJGg=
-----END RSA PRIVATE KEY-----
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1Pt7yEk/xI+6cozLj5B
u4xV8gXDXcHS0rSJFfl4wBTk4UXpaJRaLfR1k0juEEa5LBRZaoA0iLj2e6kfCibO
Nx0VVoWmeqN2HBc3zkA1eqCksI0QUudzto4KhKHp0odiZ2zo6c/2Tn1zqD/m3OLo
SjVTbsJmGuwx8RGMBXozpg/uL0hHflihX+HND4Xfw92QXv7SaPBhgvM9xyRxn0/w
3J2nNjtuPuVN5vcQkd8ncMexVfy9AWp+HSA5AT5N8CJ/EeIsdDMY1US28bUePzj1
WIo75bZHKZNFw/iXe2xoPpm74qriMNSlW2craFP2K3KYnI28vJeUU6t9I6LS9zt2
zQIDAQAB
-----END PUBLIC KEY-----
+26
View File
@@ -0,0 +1,26 @@
#######################################
# Syntax Coloring Map For Ultrasound
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
ArduinoOTA KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
setup KEYWORD2
handle KEYWORD2
onStart KEYWORD2
onEnd KEYWORD2
onError KEYWORD2
onProgress KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
+10
View File
@@ -0,0 +1,10 @@
name=ArduinoOTA
version=1.0
author=Ivan Grokhotkov and Miguel Angel Ajo
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
sentence=Enables Over The Air upgrades, via wifi and espota.py UDP request/TCP download.
paragraph=With this library you can enable your sketch to be upgraded over network. Includes mdns announces to get discovered by the arduino IDE.
category=Communication
url=https://github.com/earlephilhower/arduino-pico
architectures=rp2040
dot_a_linkage=true
+402
View File
@@ -0,0 +1,402 @@
#include <functional>
#include <WiFiUdp.h>
#include "ArduinoOTA.h"
#include "MD5Builder.h"
#include <PicoOTA.h>
#include <StreamString.h>
#include "lwip/udp.h"
#include "include/UdpContext.h"
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
#include <LEAmDNS.h>
#endif
//#ifdef DEBUG_ESP_OTA
//#ifdef DEBUG_ESP_PORT
//#define OTA_DEBUG DEBUG_ESP_PORT
//#endif
//#endif
#define OTA_DEBUG Serial
ArduinoOTAClass::ArduinoOTAClass() {
}
ArduinoOTAClass::~ArduinoOTAClass() {
if (_udp_ota) {
_udp_ota->unref();
_udp_ota = 0;
}
}
void ArduinoOTAClass::onStart(THandlerFunction fn) {
_start_callback = fn;
}
void ArduinoOTAClass::onEnd(THandlerFunction fn) {
_end_callback = fn;
}
void ArduinoOTAClass::onProgress(THandlerFunction_Progress fn) {
_progress_callback = fn;
}
void ArduinoOTAClass::onError(THandlerFunction_Error fn) {
_error_callback = fn;
}
void ArduinoOTAClass::setPort(uint16_t port) {
if (!_initialized && !_port && port) {
_port = port;
}
}
void ArduinoOTAClass::setHostname(const char * hostname) {
if (!_initialized && !_hostname.length() && hostname) {
_hostname = hostname;
}
}
String ArduinoOTAClass::getHostname() {
return _hostname;
}
void ArduinoOTAClass::setPassword(const char * password) {
if (!_initialized && !_password.length() && password) {
MD5Builder passmd5;
passmd5.begin();
passmd5.add(password);
passmd5.calculate();
_password = passmd5.toString();
}
}
void ArduinoOTAClass::setPasswordHash(const char * password) {
if (!_initialized && !_password.length() && password) {
_password = password;
}
}
void ArduinoOTAClass::setRebootOnSuccess(bool reboot) {
_rebootOnSuccess = reboot;
}
void ArduinoOTAClass::begin(bool useMDNS) {
if (_initialized) {
return;
}
_useMDNS = useMDNS;
if (!_hostname.length()) {
char tmp[15];
sprintf(tmp, "pico-%s", rp2040.getChipID());
_hostname = tmp;
}
if (!_port) {
_port = 2040;
}
if (_udp_ota) {
_udp_ota->unref();
_udp_ota = 0;
}
_udp_ota = new UdpContext;
_udp_ota->ref();
if (!_udp_ota->listen(IP_ADDR_ANY, _port)) {
return;
}
_udp_ota->onRx(std::bind(&ArduinoOTAClass::_onRx, this));
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
if (_useMDNS) {
MDNS.begin(_hostname.c_str());
if (_password.length()) {
MDNS.enableArduino(_port, true);
} else {
MDNS.enableArduino(_port);
}
}
#endif
_initialized = true;
_state = OTA_IDLE;
#ifdef OTA_DEBUG
OTA_DEBUG.printf("OTA server at: %s.local:%u\n", _hostname.c_str(), _port);
#endif
}
int ArduinoOTAClass::parseInt() {
char data[16];
uint8_t index;
char value;
while (_udp_ota->peek() == ' ') {
_udp_ota->read();
}
for (index = 0; index < sizeof(data); ++index) {
value = _udp_ota->peek();
if (value < '0' || value > '9') {
data[index] = '\0';
return atoi(data);
}
data[index] = _udp_ota->read();
}
return 0;
}
String ArduinoOTAClass::readStringUntil(char end) {
String res;
int value;
while (true) {
value = _udp_ota->read();
if (value < 0 || value == '\0' || value == end) {
return res;
}
res += static_cast<char>(value);
}
return res;
}
void ArduinoOTAClass::_onRx() {
if (!_udp_ota->next()) {
return;
}
IPAddress ota_ip;
if (_state == OTA_IDLE) {
int cmd = parseInt();
if (cmd != U_FLASH && cmd != U_FS) {
return;
}
_ota_ip = _udp_ota->getRemoteAddress();
_cmd = cmd;
_ota_port = parseInt();
_ota_udp_port = _udp_ota->getRemotePort();
_size = parseInt();
_udp_ota->read();
_md5 = readStringUntil('\n');
_md5.trim();
if (_md5.length() != 32) {
return;
}
ota_ip = _ota_ip;
if (_password.length()) {
MD5Builder nonce_md5;
nonce_md5.begin();
nonce_md5.add(String(micros()));
nonce_md5.calculate();
_nonce = nonce_md5.toString();
char auth_req[38];
sprintf(auth_req, "AUTH %s", _nonce.c_str());
_udp_ota->append((const char *)auth_req, strlen(auth_req));
_udp_ota->send(ota_ip, _ota_udp_port);
_state = OTA_WAITAUTH;
return;
} else {
_state = OTA_RUNUPDATE;
}
} else if (_state == OTA_WAITAUTH) {
int cmd = parseInt();
if (cmd != U_AUTH) {
_state = OTA_IDLE;
return;
}
_udp_ota->read();
String cnonce = readStringUntil(' ');
String response = readStringUntil('\n');
if (cnonce.length() != 32 || response.length() != 32) {
_state = OTA_IDLE;
return;
}
String challenge = _password + ':' + String(_nonce) + ':' + cnonce;
MD5Builder _challengemd5;
_challengemd5.begin();
_challengemd5.add(challenge);
_challengemd5.calculate();
String result = _challengemd5.toString();
ota_ip = _ota_ip;
// if(result.equalsConstantTime(response)) {
if (result.equals(response)) {
_state = OTA_RUNUPDATE;
} else {
_udp_ota->append("Authentication Failed", 21);
_udp_ota->send(ota_ip, _ota_udp_port);
if (_error_callback) {
_error_callback(OTA_AUTH_ERROR);
}
_state = OTA_IDLE;
}
}
while (_udp_ota->next()) {
_udp_ota->flush();
}
}
void ArduinoOTAClass::_runUpdate() {
IPAddress ota_ip = _ota_ip;
if (!LittleFS.begin()) {
#ifdef OTA_DEBUG
OTA_DEBUG.println("LittleFS Begin Error");
#endif
_udp_ota->append("ERR: ", 5);
_udp_ota->append("No Filesystem", 13);
_udp_ota->send(ota_ip, _ota_udp_port);
delay(100);
_udp_ota->listen(IP_ADDR_ANY, _port);
_state = OTA_IDLE;
return;
}
if (!Update.begin(_size, _cmd)) {
#ifdef OTA_DEBUG
OTA_DEBUG.println("Update Begin Error");
#endif
if (_error_callback) {
_error_callback(OTA_BEGIN_ERROR);
}
StreamString ss;
Update.printError(ss);
_udp_ota->append("ERR: ", 5);
_udp_ota->append(ss.c_str(), ss.length());
_udp_ota->send(ota_ip, _ota_udp_port);
delay(100);
_udp_ota->listen(IP_ADDR_ANY, _port);
_state = OTA_IDLE;
return;
}
_udp_ota->append("OK", 2);
_udp_ota->send(ota_ip, _ota_udp_port);
delay(100);
Update.setMD5(_md5.c_str());
if (_start_callback) {
_start_callback();
}
if (_progress_callback) {
_progress_callback(0, _size);
}
WiFiClient client;
if (!client.connect(_ota_ip, _ota_port)) {
#ifdef OTA_DEBUG
OTA_DEBUG.printf("Connect Failed\n");
#endif
_udp_ota->listen(IP_ADDR_ANY, _port);
if (_error_callback) {
_error_callback(OTA_CONNECT_ERROR);
}
_state = OTA_IDLE;
}
// OTA sends little packets
client.setNoDelay(true);
uint32_t written, total = 0;
while (!Update.isFinished() && (client.connected() || client.available())) {
int waited = 1000;
while (!client.available() && waited--) {
delay(1);
}
if (!waited) {
#ifdef OTA_DEBUG
OTA_DEBUG.printf("Receive Failed\n");
#endif
_udp_ota->listen(IP_ADDR_ANY, _port);
if (_error_callback) {
_error_callback(OTA_RECEIVE_ERROR);
}
_state = OTA_IDLE;
}
written = Update.write(client);
if (written > 0) {
client.print(written, DEC);
total += written;
if (_progress_callback) {
_progress_callback(total, _size);
}
}
}
if (Update.end()) {
// Ensure last count packet has been sent out and not combined with the final OK
client.flush();
delay(1000);
client.print("OK");
client.flush();
delay(1000);
client.stop();
#ifdef OTA_DEBUG
OTA_DEBUG.printf("Update Success\n");
#endif
if (_end_callback) {
_end_callback();
}
if (_rebootOnSuccess) {
#ifdef OTA_DEBUG
OTA_DEBUG.printf("Rebooting...\n");
#endif
LittleFS.end();
//let serial/network finish tasks that might be given in _end_callback
delay(100);
rp2040.reboot();
}
} else {
_udp_ota->listen(IP_ADDR_ANY, _port);
if (_error_callback) {
_error_callback(OTA_END_ERROR);
}
Update.printError(client);
#ifdef OTA_DEBUG
Update.printError(OTA_DEBUG);
#endif
_state = OTA_IDLE;
}
}
void ArduinoOTAClass::end() {
_initialized = false;
_udp_ota->unref();
_udp_ota = 0;
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
if (_useMDNS) {
MDNS.end();
}
#endif
_state = OTA_IDLE;
#ifdef OTA_DEBUG
OTA_DEBUG.printf("OTA server stopped.\n");
#endif
}
//this needs to be called in the loop()
void ArduinoOTAClass::handle() {
if (_state == OTA_RUNUPDATE) {
_runUpdate();
_state = OTA_IDLE;
}
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
if (_useMDNS) {
MDNS.update(); //handle MDNS update as well, given that ArduinoOTA relies on it anyways
}
#endif
}
int ArduinoOTAClass::getCommand() {
return _cmd;
}
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA)
ArduinoOTAClass ArduinoOTA;
#endif
+103
View File
@@ -0,0 +1,103 @@
#pragma once
#include <WiFi.h>
#include <functional>
#include <LittleFS.h>
#include <Updater.h>
class UdpContext;
typedef enum {
OTA_IDLE,
OTA_WAITAUTH,
OTA_RUNUPDATE
} ota_state_t;
typedef enum {
OTA_AUTH_ERROR,
OTA_BEGIN_ERROR,
OTA_CONNECT_ERROR,
OTA_RECEIVE_ERROR,
OTA_END_ERROR
} ota_error_t;
class ArduinoOTAClass {
public:
typedef std::function<void(void)> THandlerFunction;
typedef std::function<void(ota_error_t)> THandlerFunction_Error;
typedef std::function<void(unsigned int, unsigned int)> THandlerFunction_Progress;
ArduinoOTAClass();
~ArduinoOTAClass();
//Sets the service port. Default 2040
void setPort(uint16_t port);
//Sets the device hostname. Default pico-xxxxxx
void setHostname(const char *hostname);
String getHostname();
//Sets the password that will be required for OTA. Default NULL
void setPassword(const char *password);
//Sets the password as above but in the form MD5(password). Default NULL
void setPasswordHash(const char *password);
//Sets if the device should be rebooted after successful update. Default true
void setRebootOnSuccess(bool reboot);
//This callback will be called when OTA connection has begun
void onStart(THandlerFunction fn);
//This callback will be called when OTA has finished
void onEnd(THandlerFunction fn);
//This callback will be called when OTA encountered Error
void onError(THandlerFunction_Error fn);
//This callback will be called when OTA is receiving data
void onProgress(THandlerFunction_Progress fn);
//Starts the ArduinoOTA service
void begin(bool useMDNS = true);
//Ends the ArduinoOTA service
void end();
//Call this in loop() to run the service. Also calls MDNS.update() when begin() or begin(true) is used.
void handle();
//Gets update command type after OTA has started. Either U_FLASH or U_FS
int getCommand();
private:
void _runUpdate(void);
void _onRx(void);
int parseInt(void);
String readStringUntil(char end);
int _port = 0;
String _password;
String _hostname;
String _nonce;
UdpContext *_udp_ota = nullptr;
bool _initialized = false;
bool _rebootOnSuccess = true;
bool _useMDNS = true;
ota_state_t _state = OTA_IDLE;
int _size = 0;
int _cmd = 0;
uint16_t _ota_port = 0;
uint16_t _ota_udp_port = 0;
IPAddress _ota_ip;
String _md5;
THandlerFunction _start_callback = nullptr;
THandlerFunction _end_callback = nullptr;
THandlerFunction_Error _error_callback = nullptr;
THandlerFunction_Progress _progress_callback = nullptr;
};
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA)
extern ArduinoOTAClass ArduinoOTA;
#endif
+45
View File
@@ -0,0 +1,45 @@
#######################################
# Syntax Coloring Map For DNSServer
#######################################
#######################################
# Library (KEYWORD3)
#######################################
DNSServer KEYWORD3 RESERVED_WORD
#######################################
# Datatypes (KEYWORD1)
#######################################
DNSReplyCode KEYWORD1 DATA_TYPE
DNSHeader KEYWORD1 DATA_TYPE
DNSServer KEYWORD1 DATA_TYPE
#######################################
# Methods and Functions (KEYWORD2)
#######################################
processNextRequest KEYWORD2
setErrorReplyCode KEYWORD2
setTTL KEYWORD2
start KEYWORD2
stop KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
DNS_QR_QUERY LITERAL1 RESERVED_WORD_2
DNS_QR_RESPONSE LITERAL1 RESERVED_WORD_2
DNS_OPCODE_QUERY LITERAL1 RESERVED_WORD_2
MAX_DNSNAME_LENGTH LITERAL1 RESERVED_WORD_2
NoError LITERAL1 RESERVED_WORD_2
FormError LITERAL1 RESERVED_WORD_2
ServerFailure LITERAL1 RESERVED_WORD_2
NonExistentDomain LITERAL1 RESERVED_WORD_2
NotImplemented LITERAL1 RESERVED_WORD_2
Refused LITERAL1 RESERVED_WORD_2
YXDomain LITERAL1 RESERVED_WORD_2
YXRRSet LITERAL1 RESERVED_WORD_2
NXRRSet LITERAL1 RESERVED_WORD_2
+10
View File
@@ -0,0 +1,10 @@
name=DNSServer
version=1.1.1
author=Kristijan Novoselić
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
sentence=A simple DNS server for ESP8266, ported to the Pico
paragraph=This library implements a simple DNS server.
category=Communication
url=
architectures=rp2040
dot_a_linkage=true
+447
View File
@@ -0,0 +1,447 @@
#include "WiFi.h"
#include "DNSServer.h"
#include <lwip/def.h>
#include <Arduino.h>
extern struct rst_info resetInfo;
#ifdef DEBUG_ESP_PORT
#define CONSOLE DEBUG_ESP_PORT
#else
#define CONSOLE Serial
#endif
#define _PRINTF(a, ...) printf(PSTR(a), ##__VA_ARGS__)
#define _PRINT(a) print(String(F(a)))
#define _PRINTLN(a) println(String(F(a)))
#define _PRINTLN2(a, b) println(String(F(a)) + b )
#define CONSOLE_PRINTF CONSOLE._PRINTF
#define CONSOLE_PRINT CONSOLE._PRINT
#define CONSOLE_PRINTLN CONSOLE._PRINTLN
#define CONSOLE_PRINTLN2 CONSOLE._PRINTLN2
#ifdef DEBUG_DNSSERVER
#define DEBUG_PRINTF CONSOLE_PRINTF
#define DEBUG_PRINT CONSOLE_PRINT
#define DEBUG_PRINTLN CONSOLE_PRINTLN
#define DEBUG_PRINTLN2 CONSOLE_PRINTLN2
#define DBGLOG_FAIL LOG_FAIL
#define DEBUG_(...) do { (__VA_ARGS__); } while(false)
#define DEBUG__(...) __VA_ARGS__
#define LOG_FAIL(a, fmt, ...) do { if (!(a)) { CONSOLE.printf( PSTR(fmt " line: %d, function: %s\r\n"), ##__VA_ARGS__, __LINE__, __FUNCTION__ ); } } while(false);
#else
#define DEBUG_PRINTF(...) do { } while(false)
#define DEBUG_PRINT(...) do { } while(false)
#define DEBUG_PRINTLN(...) do { } while(false)
#define DEBUG_PRINTLN2(...) do { } while(false)
#define DEBUG_(...) do { } while(false)
#define DEBUG__(...) do { } while(false)
#define LOG_FAIL(a, ...) do { a; } while(false)
#define DBGLOG_FAIL(...) do { } while(false)
#endif
#define DNS_HEADER_SIZE sizeof(DNSHeader)
// Want to keep IDs unique across restarts and continquious
static uint32_t _ids __attribute__((section(".noinit")));
DNSServer::DNSServer()
{
// I have observed that using 0 for captive and non-zero (600) when
// forwarding, will help Android devices recognize the change in connectivity.
// They will then report connected.
_ttl = lwip_htonl(60);
srand(rp2040.getCycleCount());
_ids = random(0, (1UL << 16) - 1);
_errorReplyCode = DNSReplyCode::NonExistentDomain;
}
void DNSServer::disableForwarder(const String &domainName, bool freeResources)
{
_forwarder = false;
if (domainName != "") {
_domainName = domainName;
downcaseAndRemoveWwwPrefix(_domainName);
}
if (freeResources) {
_dns = (uint32_t)0;
if (_que) {
_que = nullptr;
DEBUG_PRINTF("from stop, deleted _que\r\n");
DEBUG_(({
if (_que_ov) {
DEBUG_PRINTLN2("DNS forwarder que overflow or no reply to request: ", (_que_ov));
}
if (_que_drop) {
DEBUG_PRINTLN2("DNS forwarder que wrapped, reply dropped: ", (_que_drop));
}
}));
}
}
}
bool DNSServer::enableForwarder(const String &domainName, const IPAddress &dns)
{
disableForwarder(domainName, false); // Just happens to have the same logic needed here.
if (dns.isSet()) {
_dns = dns;
}
if (_dns.isSet()) {
if (!_que) {
_que = std::unique_ptr<DNSS_REQUESTER[]> (new (std::nothrow) DNSS_REQUESTER[kDNSSQueSize]);
DEBUG_PRINTF("Created new _que\r\n");
if (_que) {
for (size_t i = 0; i < kDNSSQueSize; i++) {
_que[i].ip = 0;
}
DEBUG_((_que_ov = 0));
DEBUG_((_que_drop = 0));
}
}
if (_que) {
_forwarder = true;
}
}
return _forwarder;
}
bool DNSServer::start(const uint16_t &port, const String &domainName,
const IPAddress &resolvedIP, const IPAddress &dns)
{
_port = (port) ? port : IANA_DNS_PORT;
_resolvedIP[0] = resolvedIP[0];
_resolvedIP[1] = resolvedIP[1];
_resolvedIP[2] = resolvedIP[2];
_resolvedIP[3] = resolvedIP[3];
if (!enableForwarder(domainName, dns) && (dns.isSet() || _dns.isSet())) {
return false;
}
return _udp.begin(_port) == 1;
}
void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode)
{
_errorReplyCode = replyCode;
}
void DNSServer::setTTL(const uint32_t &ttl)
{
_ttl = lwip_htonl(ttl);
}
uint32_t DNSServer::getTTL()
{
return lwip_ntohl(_ttl);
}
void DNSServer::stop()
{
_udp.stop();
disableForwarder("", true);
}
void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName)
{
domainName.toLowerCase();
if (domainName.startsWith("www."))
domainName.remove(0, 4);
}
void DNSServer::forwardReply(uint8_t *buffer, size_t length)
{
if (!_forwarder || !_que) {
return;
}
DNSHeader *dnsHeader = (DNSHeader *)buffer;
uint16_t id = dnsHeader->ID;
// if (kDNSSQueSize <= (uint16_t)((uint16_t)_ids - id)) {
if ((uint16_t)kDNSSQueSize <= (uint16_t)_ids - id) {
DEBUG_((++_que_drop));
DEBUG_PRINTLN2("Forward reply ID: 0x", (String(id, HEX) + F(" dropped!")));
return;
}
size_t i = id & (kDNSSQueSize - 1);
// Drop duplicate packets
if (0 == _que[i].ip) {
DEBUG_PRINTLN2("Duplicate reply dropped ID: 0x", String(id, HEX));
return;
}
dnsHeader->ID = _que[i].id;
_udp.beginPacket(_que[i].ip, _que[i].port);
_udp.write(buffer, length);
_udp.endPacket();
DEBUG_PRINTLN2("Forward reply ID: 0x", (String(id, HEX) + F(" to ") + IPAddress(_que[i].ip).toString()));
_que[i].ip = 0; // This gets used to detect duplicate packets and overflow
}
void DNSServer::forwardRequest(uint8_t *buffer, size_t length)
{
if (!_forwarder || !_dns.isSet() || !_que) {
return;
}
DNSHeader *dnsHeader = (DNSHeader *)buffer;
++_ids;
size_t i = _ids & (kDNSSQueSize - 1);
DEBUG_(({
if (0 != _que[i].ip) {
++_que_ov;
}
}));
_que[i].ip = _udp.remoteIP();
_que[i].port = _udp.remotePort();
_que[i].id = dnsHeader->ID;
dnsHeader->ID = (uint16_t)_ids;
_udp.beginPacket(_dns, IANA_DNS_PORT);
_udp.write(buffer, length);
_udp.endPacket();
DEBUG_PRINTLN2("Forward request ID: 0x", (String(dnsHeader->ID, HEX) + F(" to ") + _dns.toString()));
}
bool DNSServer::respondToRequest(uint8_t *buffer, size_t length)
{
DNSHeader *dnsHeader;
uint8_t *query, *start;
const char *matchString;
size_t remaining, labelLength, queryLength;
uint16_t qtype, qclass;
dnsHeader = (DNSHeader *)buffer;
// Must be a query for us to do anything with it
if (dnsHeader->QR != DNS_QR_QUERY) {
return false;
}
// If operation is anything other than query, we don't do it
if (dnsHeader->OPCode != DNS_OPCODE_QUERY) {
replyWithError(dnsHeader, DNSReplyCode::NotImplemented);
return false;
}
// Only support requests containing single queries - everything else
// is badly defined
if (dnsHeader->QDCount != lwip_htons(1)) {
replyWithError(dnsHeader, DNSReplyCode::FormError);
return false;
}
// We must return a FormError in the case of a non-zero ARCount to
// be minimally compatible with EDNS resolvers
if (dnsHeader->ANCount != 0 || dnsHeader->NSCount != 0
|| dnsHeader->ARCount != 0) {
replyWithError(dnsHeader, DNSReplyCode::FormError);
return false;
}
// Even if we're not going to use the query, we need to parse it
// so we can check the address type that's being queried
query = start = buffer + DNS_HEADER_SIZE;
remaining = length - DNS_HEADER_SIZE;
while (remaining != 0 && *start != 0) {
labelLength = *start;
if (labelLength + 1 > remaining) {
replyWithError(dnsHeader, DNSReplyCode::FormError);
return false;
}
remaining -= (labelLength + 1);
start += (labelLength + 1);
}
// 1 octet labelLength, 2 octet qtype, 2 octet qclass
if (remaining < 5) {
replyWithError(dnsHeader, DNSReplyCode::FormError);
return false;
}
start += 1; // Skip the 0 length label that we found above
memcpy(&qtype, start, sizeof(qtype));
start += 2;
memcpy(&qclass, start, sizeof(qclass));
start += 2;
queryLength = start - query;
if (qclass != lwip_htons(DNS_QCLASS_ANY)
&& qclass != lwip_htons(DNS_QCLASS_IN)) {
replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, query, queryLength);
return false;
}
if (qtype != lwip_htons(DNS_QTYPE_A)
&& qtype != lwip_htons(DNS_QTYPE_ANY)) {
replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, query, queryLength);
return false;
}
// If we have no domain name configured, just return an error
if (_domainName == "") {
if (_forwarder) {
return true;
} else {
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
return false;
}
}
// If we're running with a wildcard we can just return a result now
if (_domainName == "*") {
DEBUG_PRINTF("dnsServer - replyWithIP\r\n");
replyWithIP(dnsHeader, query, queryLength);
return false;
}
matchString = _domainName.c_str();
start = query;
// If there's a leading 'www', skip it
if (*start == 3 && strncasecmp("www", (char *) start + 1, 3) == 0)
start += 4;
while (*start != 0) {
labelLength = *start;
start += 1;
while (labelLength > 0) {
if (tolower(*start) != *matchString) {
if (_forwarder) {
return true;
} else {
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
return false;
}
}
++start;
++matchString;
--labelLength;
}
if (*start == 0 && *matchString == '\0') {
replyWithIP(dnsHeader, query, queryLength);
return false;
}
if (*matchString != '.') {
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
return false;
}
++matchString;
}
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
return false;
}
void DNSServer::processNextRequest()
{
size_t currentPacketSize;
currentPacketSize = _udp.parsePacket();
if (currentPacketSize == 0)
return;
// The DNS RFC requires that DNS packets be less than 512 bytes in size,
// so just discard them if they are larger
if (currentPacketSize > MAX_DNS_PACKETSIZE)
return;
// If the packet size is smaller than the DNS header, then someone is
// messing with us
if (currentPacketSize < DNS_HEADER_SIZE)
return;
std::unique_ptr<uint8_t[]> buffer(new (std::nothrow) uint8_t[currentPacketSize]);
if (buffer == nullptr)
return;
_udp.read(buffer.get(), currentPacketSize);
if (_dns.isSet() && _udp.remoteIP() == _dns) {
// _forwarder may have been set to false; however, for now allow in-flight
// replies to finish. //??
forwardReply(buffer.get(), currentPacketSize);
} else
if (respondToRequest(buffer.get(), currentPacketSize)) {
forwardRequest(buffer.get(), currentPacketSize);
}
}
void DNSServer::writeNBOShort(uint16_t value)
{
_udp.write((unsigned char *)&value, 2);
}
void DNSServer::replyWithIP(DNSHeader *dnsHeader,
unsigned char * query,
size_t queryLength)
{
uint16_t value;
dnsHeader->QR = DNS_QR_RESPONSE;
dnsHeader->QDCount = lwip_htons(1);
dnsHeader->ANCount = lwip_htons(1);
dnsHeader->NSCount = 0;
dnsHeader->ARCount = 0;
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
_udp.write((unsigned char *) dnsHeader, sizeof(DNSHeader));
_udp.write(query, queryLength);
// Rather than restate the name here, we use a pointer to the name contained
// in the query section. Pointers have the top two bits set.
value = 0xC000 | DNS_HEADER_SIZE;
writeNBOShort(lwip_htons(value));
// Answer is type A (an IPv4 address)
writeNBOShort(lwip_htons(DNS_QTYPE_A));
// Answer is in the Internet Class
writeNBOShort(lwip_htons(DNS_QCLASS_IN));
// Output TTL (already NBO)
_udp.write((unsigned char*)&_ttl, 4);
// Length of RData is 4 bytes (because, in this case, RData is IPv4)
writeNBOShort(lwip_htons(sizeof(_resolvedIP)));
_udp.write(_resolvedIP, sizeof(_resolvedIP));
_udp.endPacket();
}
void DNSServer::replyWithError(DNSHeader *dnsHeader,
DNSReplyCode rcode,
unsigned char *query,
size_t queryLength)
{
dnsHeader->QR = DNS_QR_RESPONSE;
dnsHeader->RCode = (unsigned char) rcode;
if (query)
dnsHeader->QDCount = lwip_htons(1);
else
dnsHeader->QDCount = 0;
dnsHeader->ANCount = 0;
dnsHeader->NSCount = 0;
dnsHeader->ARCount = 0;
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
_udp.write((unsigned char *)dnsHeader, sizeof(DNSHeader));
if (query != NULL)
_udp.write(query, queryLength);
_udp.endPacket();
}
void DNSServer::replyWithError(DNSHeader *dnsHeader,
DNSReplyCode rcode)
{
replyWithError(dnsHeader, rcode, NULL, 0);
}
+144
View File
@@ -0,0 +1,144 @@
#ifndef DNSServer_h
#define DNSServer_h
#include <memory>
#include <WiFiUdp.h>
// #define DEBUG_DNSSERVER
// https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
#ifndef IANA_DNS_PORT
#define IANA_DNS_PORT 53 // AKA domain
constexpr inline uint16_t kIanaDnsPort = IANA_DNS_PORT;
#endif
#define DNS_QR_QUERY 0
#define DNS_QR_RESPONSE 1
#define DNS_OPCODE_QUERY 0
#define DNS_QCLASS_IN 1
#define DNS_QCLASS_ANY 255
#define DNS_QTYPE_A 1
#define DNS_QTYPE_ANY 255
#define MAX_DNSNAME_LENGTH 253
#define MAX_DNS_PACKETSIZE 512
enum class DNSReplyCode
{
NoError = 0,
FormError = 1,
ServerFailure = 2,
NonExistentDomain = 3,
NotImplemented = 4,
Refused = 5,
YXDomain = 6,
YXRRSet = 7,
NXRRSet = 8
};
struct DNSHeader
{
uint16_t ID; // identification number
unsigned char RD : 1; // recursion desired
unsigned char TC : 1; // truncated message
unsigned char AA : 1; // authoritative answer
unsigned char OPCode : 4; // message_type
unsigned char QR : 1; // query/response flag
unsigned char RCode : 4; // response code
unsigned char Z : 3; // its z! reserved
unsigned char RA : 1; // recursion available
uint16_t QDCount; // number of question entries
uint16_t ANCount; // number of answer entries
uint16_t NSCount; // number of authority entries
uint16_t ARCount; // number of resource entries
};
constexpr inline size_t kDNSSQueSizeAddrBits = 3; // The number of bits used to address que entries
constexpr inline size_t kDNSSQueSize = (1UL << (kDNSSQueSizeAddrBits));
struct DNSS_REQUESTER {
uint32_t ip;
uint16_t port;
uint16_t id;
};
class DNSServer
{
public:
DNSServer();
~DNSServer() {
stop();
};
/*
If specified, `enableForwarder` will update the `domainName` that is used
to match DNS request to this AP's IP Address. A non-matching request will
be forwarded to the DNS server specified by `dns`.
Returns `true` on success.
Returns `false`,
* when forwarding `dns` is not set, or
* unable to allocate resources for managing the DNS forward function.
*/
bool enableForwarder(const String &domainName = String(""), const IPAddress &dns = (uint32_t)0);
/*
`disableForwarder` will stop forwarding DNS requests. If specified,
updates the `domainName` that is matched for returning this AP's IP Address.
Optionally, resources used for the DNS forward function can be freed.
*/
void disableForwarder(const String &domainName = String(""), bool freeResources = false);
bool isForwarding() { return _forwarder && _dns.isSet(); }
void setDNS(const IPAddress& dns) { _dns = dns; }
IPAddress getDNS() { return _dns; }
bool isDNSSet() { return _dns.isSet(); }
void processNextRequest();
void setErrorReplyCode(const DNSReplyCode &replyCode);
void setTTL(const uint32_t &ttl);
uint32_t getTTL();
String getDomainName() { return _domainName; }
// Returns true if successful, false if there are no sockets available
bool start(const uint16_t &port,
const String &domainName,
const IPAddress &resolvedIP,
const IPAddress &dns = (uint32_t)0);
// stops the DNS server
void stop();
private:
WiFiUDP _udp;
String _domainName;
IPAddress _dns;
std::unique_ptr<DNSS_REQUESTER[]> _que;
uint32_t _ttl;
#ifdef DEBUG_DNSSERVER
// There are 2 possibilities for overflow:
// 1) we have more than kDNSSQueSize request already outstanding.
// 2) we have request that never received a reply.
uint32_t _que_ov;
uint32_t _que_drop;
#endif
DNSReplyCode _errorReplyCode;
bool _forwarder;
unsigned char _resolvedIP[4];
uint16_t _port;
void downcaseAndRemoveWwwPrefix(String &domainName);
void replyWithIP(DNSHeader *dnsHeader,
unsigned char * query,
size_t queryLength);
void replyWithError(DNSHeader *dnsHeader,
DNSReplyCode rcode,
unsigned char *query,
size_t queryLength);
void replyWithError(DNSHeader *dnsHeader,
DNSReplyCode rcode);
bool respondToRequest(uint8_t *buffer, size_t length);
void forwardRequest(uint8_t *buffer, size_t length);
void forwardReply(uint8_t *buffer, size_t length);
void writeNBOShort(uint16_t value);
};
#endif
+4
View File
@@ -62,6 +62,10 @@ public:
return t;
}
template<typename T>
const T &update(int const address, const T &t) {
return put(address, t);
}
size_t length() {
return _size;
}
+31 -30
View File
@@ -26,6 +26,7 @@
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSTACK_DEPTH_TYPE uint32_t
#define configUSE_TASK_PREEMPTION_DISABLE 1
#define configUSE_NEWLIB_REENTRANT 1
#define configNEWLIB_REENTRANT_IS_DYNAMIC 0 /* Note that we have a different config option, portSET_IMPURE_PTR */
@@ -34,8 +35,8 @@ extern void __register_impure_ptr(struct _reent *p);
#define portSET_IMPURE_PTR(x) __register_impure_ptr(x)
/* Run time stats related definitions. */
void vMainConfigureTimerForRunTimeStats( void );
unsigned long ulMainGetRunTimeCounterValue( void );
void vMainConfigureTimerForRunTimeStats(void);
unsigned long ulMainGetRunTimeCounterValue(void);
#define configGENERATE_RUN_TIME_STATS 1
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() //vMainConfigureTimerForRunTimeStats()
#define portGET_RUN_TIME_COUNTER_VALUE() ulMainGetRunTimeCounterValue()
@@ -48,10 +49,10 @@ unsigned long ulMainGetRunTimeCounterValue( void );
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( 2 )
#define configTIMER_QUEUE_LENGTH 5
#define configTIMER_TASK_STACK_DEPTH ( 80 )
#define configTIMER_TASK_STACK_DEPTH ( 1024 )
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
@@ -62,10 +63,10 @@ to exclude the API function. */
#define INCLUDE_vTaskDelay 1
#define INCLUDE_eTaskGetState 1
/* This demo makes use of one or more example stats formatting functions. These
format the raw data provided by the uxTaskGetSystemState() function in to human
readable ASCII form. See the notes in the implementation of vTaskList() within
FreeRTOS/Source/tasks.c for limitations. */
/* This demo makes use of one or more example stats formatting functions. These
format the raw data provided by the uxTaskGetSystemState() function in to human
readable ASCII form. See the notes in the implementation of vTaskList() within
FreeRTOS/Source/tasks.c for limitations. */
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configUSE_MUTEXES 1
@@ -73,50 +74,50 @@ FreeRTOS/Source/tasks.c for limitations. */
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define configUSE_MALLOC_FAILED_HOOK 1
#define configCHECK_FOR_STACK_OVERFLOW 2
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
/* Cortex-M specific definitions. */
#undef __NVIC_PRIO_BITS
#ifdef __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 3 /* 8 priority levels */
#define configPRIO_BITS 3 /* 8 priority levels */
#endif
/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x7
/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
/* Interrupt priorities used by the kernel port layer itself. These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
/* Interrupt priorities used by the kernel port layer itself. These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
extern void rtosFatalError(void);
#define configASSERT( x ) \
if( ( x ) == 0 ) { portDISABLE_INTERRUPTS(); rtosFatalError(); }
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names - or at least those used in the unmodified vector table. */
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names - or at least those used in the unmodified vector table. */
//#define xPortPendSVHandler PendSV_Handler
//#define xPortSysTickHandler SysTick_Handler
//#define vPortSVCHandler SVC_Handler
/* The size of the global output buffer that is available for use when there
are multiple command interpreters running at once (for example, one on a UART
and one on TCP/IP). This is done to prevent an output buffer being defined by
each implementation - which would waste RAM. In this case, there is only one
command interpreter running. */
/* The size of the global output buffer that is available for use when there
are multiple command interpreters running at once (for example, one on a UART
and one on TCP/IP). This is done to prevent an output buffer being defined by
each implementation - which would waste RAM. In this case, there is only one
command interpreter running. */
#define configCOMMAND_INT_MAX_OUTPUT_SIZE 2048
+115 -146
View File
@@ -1,35 +1,34 @@
/*
* Copyright (C) 2021 Phillip Stevens All Rights Reserved.
* Modifications by Earle F. Philhower, III, for Arduino-Pico
*
* 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.
*
*
* This file is NOT part of the FreeRTOS distribution.
*
*/
Copyright (C) 2021 Phillip Stevens All Rights Reserved.
Modifications by Earle F. Philhower, III, for Arduino-Pico
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.
This file is NOT part of the FreeRTOS distribution.
*/
#include <stdlib.h>
/* Arduino Core includes */
#include <Arduino.h>
#include <RP2040USB.h>
#include "tusb.h"
#define USB_TASK_IRQ 31
/* Raspberry PI Pico includes */
@@ -43,8 +42,7 @@
/*-----------------------------------------------------------*/
void initFreeRTOS(void)
{
void initFreeRTOS(void) {
}
extern void setup() __attribute__((weak));
@@ -55,8 +53,7 @@ extern void loop1() __attribute__((weak));
extern void __loop();
volatile bool __usbInitted = false;
static void __core0(void *params)
{
static void __core0(void *params) {
(void) params;
#ifndef NO_USB
while (!__usbInitted) {
@@ -78,8 +75,7 @@ static void __core0(void *params)
}
}
static void __core1(void *params)
{
static void __core1(void *params) {
(void) params;
#ifndef NO_USB
while (!__usbInitted) {
@@ -98,7 +94,7 @@ static void __core1(void *params)
vTaskDelay(1000);
}
}
}
}
extern "C" void delay(unsigned long ms) {
vTaskDelay(ms / portTICK_PERIOD_MS);
@@ -112,17 +108,16 @@ extern mutex_t __usb_mutex;
static TaskHandle_t __usbTask;
static void __usb(void *param);
void startFreeRTOS(void)
{
void startFreeRTOS(void) {
TaskHandle_t c0;
xTaskCreate(__core0, "CORE0", 1024, 0, configMAX_PRIORITIES / 2, &c0);
vTaskCoreAffinitySet( c0, 1 << 0 );
vTaskCoreAffinitySet(c0, 1 << 0);
if (setup1 || loop1) {
TaskHandle_t c1;
xTaskCreate(__core1, "CORE1", 1024, 0, configMAX_PRIORITIES / 2, &c1);
vTaskCoreAffinitySet( c1, 1 << 1 );
vTaskCoreAffinitySet(c1, 1 << 1);
}
// Initialise and run the freeRTOS scheduler. Execution should never return here.
@@ -136,33 +131,30 @@ void startFreeRTOS(void)
/*-----------------------------------------------------------*/
void prvDisableInterrupts()
{
void prvDisableInterrupts() {
portDISABLE_INTERRUPTS();
}
void prvEnableInterrupts()
{
void prvEnableInterrupts() {
portENABLE_INTERRUPTS();
}
/*-----------------------------------------------------------*/
#if ( configUSE_IDLE_HOOK == 1 )
/*
* Call the user defined loop() function from within the idle task.
* This allows the application designer to add background functionality
* without the overhead of a separate task.
*
* NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, CALL A FUNCTION THAT MIGHT BLOCK.
*
*/
Call the user defined loop() function from within the idle task.
This allows the application designer to add background functionality
without the overhead of a separate task.
NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, CALL A FUNCTION THAT MIGHT BLOCK.
*/
extern "C"
void vApplicationIdleHook( void ) __attribute__((weak));
void vApplicationIdleHook(void) __attribute__((weak));
void vApplicationIdleHook( void )
{
void vApplicationIdleHook(void) {
__wfe(); // Low power idle if nothing to do...
}
@@ -171,22 +163,21 @@ void vApplicationIdleHook( void )
#if ( configUSE_MINIMAL_IDLE_HOOK == 1 )
/*
* Call the user defined minimalIdle() function from within the idle task.
* This allows the application designer to add background functionality
* without the overhead of a separate task.
*
* NOTE: vApplicationMinimalIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, CALL A FUNCTION THAT MIGHT BLOCK.
*
*/
void minimalIdle( void ) __attribute__((weak));
Call the user defined minimalIdle() function from within the idle task.
This allows the application designer to add background functionality
without the overhead of a separate task.
NOTE: vApplicationMinimalIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, CALL A FUNCTION THAT MIGHT BLOCK.
*/
void minimalIdle(void) __attribute__((weak));
void minimalIdle() {} //Empty minimalIdle function
extern "C"
void vApplicationMinimalIdleHook( void ) __attribute__((weak));
void vApplicationMinimalIdleHook(void) __attribute__((weak));
void vApplicationMinimalIdleHook( void )
{
minimalIdle();
void vApplicationMinimalIdleHook(void) {
minimalIdle();
}
#endif /* configUSE_MINIMAL_IDLE_HOOK == 1 */
@@ -194,22 +185,21 @@ void vApplicationMinimalIdleHook( void )
#if ( configUSE_TICK_HOOK == 1 )
/*
* Call the user defined minimalIdle() function from within the idle task.
* This allows the application designer to add background functionality
* without the overhead of a separate task.
*
* NOTE: vApplicationMinimalIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, CALL A FUNCTION THAT MIGHT BLOCK.
*
*/
void tick( void ) __attribute__((weak));
Call the user defined minimalIdle() function from within the idle task.
This allows the application designer to add background functionality
without the overhead of a separate task.
NOTE: vApplicationMinimalIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, CALL A FUNCTION THAT MIGHT BLOCK.
*/
void tick(void) __attribute__((weak));
void tick() {} //Empty minimalIdle function
extern "C"
void vApplicationTickHook( void ) __attribute__((weak));
void vApplicationTickHook(void) __attribute__((weak));
void vApplicationTickHook( void )
{
tick();
void vApplicationTickHook(void) {
tick();
}
#endif /* configUSE_TICK_HOOK == 1 */
@@ -218,37 +208,33 @@ void vApplicationTickHook( void )
#if ( configUSE_MALLOC_FAILED_HOOK == 1 || configCHECK_FOR_STACK_OVERFLOW >= 1 || configDEFAULT_ASSERT == 1 )
/**
* Private function to enable board led to use it in application hooks
*/
void prvSetMainLedOn( void )
{
gpio_init(LED_BUILTIN);
gpio_set_dir(LED_BUILTIN, true);
gpio_put(LED_BUILTIN, true);
Private function to enable board led to use it in application hooks
*/
void prvSetMainLedOn(void) {
gpio_init(LED_BUILTIN);
gpio_set_dir(LED_BUILTIN, true);
gpio_put(LED_BUILTIN, true);
}
/**
* Private function to blink board led to use it in application hooks
*/
void prvBlinkMainLed( void )
{
gpio_put(LED_BUILTIN, !gpio_get(LED_BUILTIN));
Private function to blink board led to use it in application hooks
*/
void prvBlinkMainLed(void) {
gpio_put(LED_BUILTIN, !gpio_get(LED_BUILTIN));
}
#endif
/*---------------------------------------------------------------------------*\
Usage:
/* ---------------------------------------------------------------------------*\
Usage:
called on fatal error (interrupts disabled already)
\*---------------------------------------------------------------------------*/
\*---------------------------------------------------------------------------*/
extern "C"
void rtosFatalError(void)
{
void rtosFatalError(void) {
prvSetMainLedOn(); // Main LED on.
for(;;)
{
// Main LED slow flash
for (;;) {
// Main LED slow flash
sleep_ms(100);
prvBlinkMainLed();
sleep_ms(2000);
@@ -257,30 +243,28 @@ void rtosFatalError(void)
}
#if ( configUSE_MALLOC_FAILED_HOOK == 1 )
/*---------------------------------------------------------------------------*\
Usage:
/* ---------------------------------------------------------------------------*\
Usage:
called by task system when a malloc failure is noticed
Description:
Description:
Malloc failure handler -- Shut down all interrupts, send serious complaint
to command port. FAST Blink on main LED.
Arguments:
Arguments:
pxTask - pointer to task handle
pcTaskName - pointer to task name
Results:
Results:
<none>
Notes:
Notes:
This routine will never return.
This routine is referenced in the task.c file of FreeRTOS as an extern.
\*---------------------------------------------------------------------------*/
\*---------------------------------------------------------------------------*/
extern "C"
void vApplicationMallocFailedHook( void ) __attribute__((weak));
void vApplicationMallocFailedHook(void) __attribute__((weak));
void vApplicationMallocFailedHook( void )
{
void vApplicationMallocFailedHook(void) {
prvSetMainLedOn(); // Main LED on.
for(;;)
{
for (;;) {
sleep_ms(50);
prvBlinkMainLed(); // Main LED fast blink.
}
@@ -293,16 +277,14 @@ void vApplicationMallocFailedHook( void )
#if ( configCHECK_FOR_STACK_OVERFLOW >= 1 )
extern "C"
void vApplicationStackOverflowHook( TaskHandle_t xTask,
char * pcTaskName ) __attribute__((weak));
void vApplicationStackOverflowHook(TaskHandle_t xTask,
char * pcTaskName) __attribute__((weak));
void vApplicationStackOverflowHook( TaskHandle_t xTask __attribute__((unused)),
char * pcTaskName __attribute__((unused)) )
{
void vApplicationStackOverflowHook(TaskHandle_t xTask __attribute__((unused)),
char * pcTaskName __attribute__((unused))) {
prvSetMainLedOn(); // Main LED on.
for(;;)
{
for (;;) {
sleep_ms(2000);
prvBlinkMainLed(); // Main LED slow blink.
}
@@ -314,14 +296,13 @@ void vApplicationStackOverflowHook( TaskHandle_t xTask __attribute__((unused)),
#if ( configSUPPORT_STATIC_ALLOCATION >= 1 )
extern "C"
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
configSTACK_DEPTH_TYPE * pulIdleTaskStackSize ) __attribute__((weak));
void vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
configSTACK_DEPTH_TYPE * pulIdleTaskStackSize) __attribute__((weak));
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
configSTACK_DEPTH_TYPE * pulIdleTaskStackSize )
{
void vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
configSTACK_DEPTH_TYPE * pulIdleTaskStackSize) {
static StaticTask_t xIdleTaskTCB;
static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
@@ -333,14 +314,13 @@ void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
#if ( configUSE_TIMERS >= 1 )
extern "C"
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
StackType_t ** ppxTimerTaskStackBuffer,
configSTACK_DEPTH_TYPE * pulTimerTaskStackSize ) __attribute__((weak));
void vApplicationGetTimerTaskMemory(StaticTask_t ** ppxTimerTaskTCBBuffer,
StackType_t ** ppxTimerTaskStackBuffer,
configSTACK_DEPTH_TYPE * pulTimerTaskStackSize) __attribute__((weak));
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
StackType_t ** ppxTimerTaskStackBuffer,
configSTACK_DEPTH_TYPE * pulTimerTaskStackSize )
{
void vApplicationGetTimerTaskMemory(StaticTask_t ** ppxTimerTaskTCBBuffer,
StackType_t ** ppxTimerTaskStackBuffer,
configSTACK_DEPTH_TYPE * pulTimerTaskStackSize) {
static StaticTask_t xTimerTaskTCB;
static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
@@ -354,8 +334,8 @@ void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
#endif /* configSUPPORT_STATIC_ALLOCATION >= 1 */
/**
* configASSERT default implementation
*/
configASSERT default implementation
*/
#if configDEFAULT_ASSERT == 1
extern "C"
@@ -364,8 +344,7 @@ void vApplicationAssertHook() {
taskDISABLE_INTERRUPTS(); // Disable task interrupts
prvSetMainLedOn(); // Main LED on.
for(;;)
{
for (;;) {
sleep_ms(100);
prvBlinkMainLed(); // Led off.
@@ -382,19 +361,10 @@ void vApplicationAssertHook() {
#endif
static void __usb_irq() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR( __usbTask, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
static void __usb(void *param)
{
static void __usb(void *param) {
(void) param;
tusb_init();
irq_set_exclusive_handler(USB_TASK_IRQ, __usb_irq);
irq_set_enabled(USB_TASK_IRQ, true);
Serial.begin(115200);
@@ -412,8 +382,7 @@ static void __usb(void *param)
extern void __SetupDescHIDReport();
extern void __SetupUSBDescriptor();
void __USBStart()
{
void __USBStart() {
mutex_init(&__usb_mutex);
__SetupDescHIDReport();
@@ -421,5 +390,5 @@ void __USBStart()
// Make highest prio and locked to core 0
xTaskCreate(__usb, "USB", 256, 0, configMAX_PRIORITIES - 1, &__usbTask);
vTaskCoreAffinitySet( __usbTask, 1 << 0 );
vTaskCoreAffinitySet(__usbTask, 1 << 0);
}
@@ -0,0 +1,87 @@
/**
Authorization.ino
Created on: 09.12.2015
*/
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char *ssid = STASSID;
const char *pass = STAPSK;
WiFiMulti WiFiMulti;
void setup() {
Serial.begin(115200);
// Serial.setDebugOutput(true);
Serial.println();
Serial.println();
Serial.println();
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
WiFi.mode(WIFI_STA);
WiFiMulti.addAP(ssid, pass);
}
void loop() {
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
HTTPClient http;
http.setInsecure();
Serial.print("[HTTP] begin...\n");
// configure traged server and url
http.begin("https://guest:guest@jigsaw.w3.org/HTTP/Basic/");
/*
// or
http.begin(client, "http://jigsaw.w3.org/HTTP/Basic/");
http.setAuthorization("guest", "guest");
// or
http.begin(client, "http://jigsaw.w3.org/HTTP/Basic/");
http.setAuthorization("Z3Vlc3Q6Z3Vlc3Q=");
*/
Serial.print("[HTTP] GET...\n");
// start connection and send HTTP header
int httpCode = http.GET();
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
Serial.println(payload);
}
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
}
delay(10000);
}
@@ -0,0 +1,75 @@
/**
BasicHTTPClient.ino
Created on: 24.05.2015
*/
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char *ssid = STASSID;
const char *pass = STAPSK;
WiFiMulti WiFiMulti;
void setup() {
Serial.begin(115200);
// Serial.setDebugOutput(true);
Serial.println();
Serial.println();
Serial.println();
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
WiFiMulti.addAP(ssid, pass);
}
void loop() {
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
HTTPClient http;
Serial.print("[HTTP] begin...\n");
if (http.begin("http://httpbin.org")) { // HTTP
Serial.print("[HTTP] GET...\n");
// start connection and send HTTP header
int httpCode = http.GET();
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = http.getString();
Serial.println(payload);
}
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
} else {
Serial.printf("[HTTP} Unable to connect\n");
}
}
delay(10000);
}
@@ -0,0 +1,80 @@
/**
BasicHTTPSClient-Hard.ino
Demonstrates the manual way of making a WiFiClient and passing it in to the HTTPClient
Created on: 20.08.2018
*/
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char *ssid = STASSID;
const char *pass = STAPSK;
WiFiMulti WiFiMulti;
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.println();
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
WiFi.mode(WIFI_STA);
WiFiMulti.addAP(ssid, pass);
}
void loop() {
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
WiFiClientSecure client;
client.setInsecure(); // Not safe against MITM attacks
HTTPClient https;
Serial.print("[HTTPS] begin...\n");
if (https.begin(client, "https://jigsaw.w3.org/HTTP/connection.html")) { // HTTPS
Serial.print("[HTTPS] GET...\n");
// start connection and send HTTP header
int httpCode = https.GET();
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = https.getString();
Serial.println(payload);
}
} else {
Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
}
https.end();
} else {
Serial.printf("[HTTPS] Unable to connect\n");
}
}
Serial.println("Wait 10s before next round...");
delay(10000);
}
@@ -0,0 +1,125 @@
/**
BasicHTTPSClient.ino
Created on: 20.08.2018
*/
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char *ssid = STASSID;
const char *pass = STAPSK;
WiFiMulti WiFiMulti;
void setup() {
Serial.begin(115200);
// Serial.setDebugOutput(true);
Serial.println();
Serial.println();
Serial.println();
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
WiFi.mode(WIFI_STA);
WiFiMulti.addAP(ssid, pass);
}
const char *jigsaw_cert = R"EOF(
-----BEGIN CERTIFICATE-----
MIIFKTCCBM+gAwIBAgIQAbTKhAICxb7iDJbE6qU/NzAKBggqhkjOPQQDAjBKMQsw
CQYDVQQGEwJVUzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEgMB4GA1UEAxMX
Q2xvdWRmbGFyZSBJbmMgRUNDIENBLTMwHhcNMjIwMzE3MDAwMDAwWhcNMjMwMzE2
MjM1OTU5WjB1MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQG
A1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEe
MBwGA1UEAxMVc25pLmNsb3VkZmxhcmVzc2wuY29tMFkwEwYHKoZIzj0CAQYIKoZI
zj0DAQcDQgAEYnkGDyrIltjRnxoVdy/xgndo+WGMOASzs2hHeCjbJ1KplKJc/ciK
XCWq/4+pTzSiVgTFhRmCdLcU1Fa05YFNQaOCA2owggNmMB8GA1UdIwQYMBaAFKXO
N+rrsHUOlGeItEX62SQQh5YfMB0GA1UdDgQWBBRIzOWGCDBB/PMrMucSrjIKqlgE
uDAvBgNVHREEKDAmghVzbmkuY2xvdWRmbGFyZXNzbC5jb22CDWppZ3Nhdy53My5v
cmcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
AjB7BgNVHR8EdDByMDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vQ2xv
dWRmbGFyZUluY0VDQ0NBLTMuY3JsMDegNaAzhjFodHRwOi8vY3JsNC5kaWdpY2Vy
dC5jb20vQ2xvdWRmbGFyZUluY0VDQ0NBLTMuY3JsMD4GA1UdIAQ3MDUwMwYGZ4EM
AQICMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzB2
BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0
LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0Ns
b3VkZmxhcmVJbmNFQ0NDQS0zLmNydDAMBgNVHRMBAf8EAjAAMIIBfwYKKwYBBAHW
eQIEAgSCAW8EggFrAWkAdQDoPtDaPvUGNTLnVyi8iWvJA9PL0RFr7Otp4Xd9bQa9
bgAAAX+aFPh6AAAEAwBGMEQCICivjuh2ywUYvVpTKHo65JEheR8dFq8QvBgEiXfw
m6q6AiAkxAgz77oboGQGetNmab45+peY+nAGOfyW9vi9S1gMaAB3ADXPGRu/sWxX
vw+tTG1Cy7u2JyAmUeo/4SrvqAPDO9ZMAAABf5oU+GEAAAQDAEgwRgIhANKeTNMy
GqUsCo7ph7YMWzrhMuDeyP8xPSiCtFzKcn/eAiEAyv5lgCUQ6K14V13zYfL99wZD
LFcIP/KZ1y7nuPAksTAAdwCzc3cH4YRQ+GOG1gWp3BEJSnktsWcMC4fc8AMOeTal
mgAAAX+aFPiWAAAEAwBIMEYCIQD6535jWw776D4vjyupP2fBw26CBMpVT5++k4rR
xqeOXwIhAIbEaEKkEq6JtpWWfVpTyDkMpMfTuiqYVe6REy2XsmEhMAoGCCqGSM49
BAMCA0gAMEUCIH3r/puXZcX1bfUoBq2njuHe0bxWtvzDaz5k6WLYrazTAiEA+ePL
N6K5xrmaof185pVCxACPLc/BoKyUwMeC8iXCm00=
-----END CERTIFICATE-----
)EOF";
static int cnt = 0;
void loop() {
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
HTTPClient https;
switch (cnt) {
case 0:
Serial.println("[HTTPS] using insecure SSL, not validating certificate");
https.setInsecure(); // Note this is unsafe against MITM attacks
cnt++;
break;
case 1:
Serial.println("[HTTPS] using secure SSL, validating certificate");
https.setCACert(jigsaw_cert);
cnt++;
break;
default:
Serial.println("[HTTPS] not setting any SSL verification settings, will fail");
cnt = 0;
}
Serial.print("[HTTPS] begin...\n");
if (https.begin("https://jigsaw.w3.org/HTTP/connection.html")) { // HTTPS
Serial.print("[HTTPS] GET...\n");
// start connection and send HTTP header
int httpCode = https.GET();
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = https.getString();
Serial.println(payload);
}
} else {
Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
}
https.end();
} else {
Serial.printf("[HTTPS] Unable to connect\n");
}
}
Serial.println("Wait 10s before next round...");
delay(10000);
}
@@ -0,0 +1,75 @@
/**
ChunkedClient.ino
*/
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char *ssid = STASSID;
const char *pass = STAPSK;
WiFiMulti WiFiMulti;
void setup() {
Serial.begin(115200);
// Serial.setDebugOutput(true);
Serial.println();
Serial.println();
Serial.println();
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
WiFi.mode(WIFI_STA);
WiFiMulti.addAP(ssid, pass);
}
void loop() {
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
HTTPClient http;
Serial.print("[HTTP] begin...\n");
if (http.begin("http://anglesharp.azurewebsites.net/Chunked")) {
Serial.print("[HTTP] GET...\n");
// start connection and send HTTP header
int httpCode = http.GET();
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = http.getString();
Serial.println(payload);
}
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
} else {
Serial.printf("[HTTP] Unable to connect\n");
}
}
Serial.println("Wait forever...");
while (1) {
continue;
}
}
@@ -0,0 +1,140 @@
/*
This sketch shows how to handle HTTP Digest Authorization.
Written by Parham Alvani and Sajjad Rahnama, 2018-01-07.
This example is released into public domain,
or, at your option, CC0 licensed.
*/
#include <WiFi.h>
#include <HTTPClient.h>
#ifndef STASSID
#define STASSID "NOBABIES"
#define STAPSK "ElephantsAreGreat"
#endif
const char* ssid = STASSID;
const char* ssidPassword = STAPSK;
const char* username = "admin";
const char* password = "admin";
const char* server = "http://httpbin.org";
const char* uri = "/digest-auth/auth/admin/admin/MD5";
String exractParam(String& authReq, const String& param, const char delimit) {
int _begin = authReq.indexOf(param);
if (_begin == -1) {
return "";
}
return authReq.substring(_begin + param.length(), authReq.indexOf(delimit, _begin + param.length()));
}
String getCNonce(const int len) {
static const char alphanum[] = "0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
String s = "";
for (int i = 0; i < len; ++i) {
s += alphanum[rand() % (sizeof(alphanum) - 1)];
}
return s;
}
String getDigestAuth(String& authReq, const String& username, const String& password, const String& method, const String& uri, unsigned int counter) {
// extracting required parameters for RFC 2069 simpler Digest
String realm = exractParam(authReq, "realm=\"", '"');
String nonce = exractParam(authReq, "nonce=\"", '"');
String cNonce = getCNonce(8);
char nc[9];
snprintf(nc, sizeof(nc), "%08x", counter);
// parameters for the RFC 2617 newer Digest
MD5Builder md5;
md5.begin();
md5.add(username + ":" + realm + ":" + password); // md5 of the user:realm:user
md5.calculate();
String h1 = md5.toString();
md5.begin();
md5.add(method + ":" + uri);
md5.calculate();
String h2 = md5.toString();
md5.begin();
md5.add(h1 + ":" + nonce + ":" + String(nc) + ":" + cNonce + ":" + "auth" + ":" + h2);
md5.calculate();
String response = md5.toString();
String authorization = "Digest username=\"" + username + "\", realm=\"" + realm + "\", nonce=\"" + nonce + "\", uri=\"" + uri + "\", algorithm=\"MD5\", qop=auth, nc=" + String(nc) + ", cnonce=\"" + cNonce + "\", response=\"" + response + "\"";
Serial.println(authorization);
return authorization;
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, ssidPassword);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
srand(rp2040.getCycleCount());
}
void loop() {
HTTPClient http;
Serial.print("[HTTP] begin...\n");
// configure target server and url
http.begin(String(server) + String(uri));
const char* keys[] = { "WWW-Authenticate" };
http.collectHeaders(keys, 1);
Serial.print("[HTTP] GET...\n");
// start connection and send HTTP header
int httpCode = http.GET();
if (httpCode > 0) {
String authReq = http.header("WWW-Authenticate");
Serial.println(authReq);
String authorization = getDigestAuth(authReq, String(username), String(password), "GET", String(uri), 1);
http.end();
http.begin(String(server) + String(uri));
http.addHeader("Authorization", authorization);
int httpCode = http.GET();
if (httpCode > 0) {
String payload = http.getString();
Serial.println(payload);
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
delay(10000);
}
@@ -0,0 +1,71 @@
/**
PostHTTPClient.ino
Created on: 21.11.2016
*/
#include <WiFi.h>
#include <HTTPClient.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.println();
WiFi.begin(STASSID, STAPSK);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected! IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
// wait for WiFi connection
if ((WiFi.status() == WL_CONNECTED)) {
HTTPClient http;
http.setInsecure();
Serial.print("[HTTP] begin...\n");
// configure target server and url
http.begin("https://httpbin.org/post");
http.addHeader("Content-Type", "application/json");
Serial.print("[HTTP] POST...\n");
// start connection and send HTTP header and body
int httpCode = http.POST("{\"hello\":\"world\"}");
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTP] POST... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK) {
const String& payload = http.getString();
Serial.println("received payload:\n<<");
Serial.println(payload);
Serial.println(">>");
}
} else {
Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
}
delay(10000);
}
@@ -0,0 +1,81 @@
/**
reuseConnectionV2.ino
Created on: 22.11.2015
This example reuses the http connection and also restores the connection if the connection is lost
*/
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
WiFiMulti WiFiMulti;
HTTPClient http;
void setup() {
Serial.begin(115200);
// Serial.setDebugOutput(true);
Serial.println();
Serial.println();
Serial.println("Connecting to WiFi...");
WiFi.mode(WIFI_STA);
WiFiMulti.addAP(STASSID, STAPSK);
// wait for WiFi connection
while ((WiFiMulti.run() != WL_CONNECTED)) {
Serial.write('.');
delay(500);
}
Serial.println(" connected to WiFi");
// allow reuse (if server supports it)
http.setReuse(true);
http.setInsecure();
http.begin("https://jigsaw.w3.org/HTTP/connection.html");
// http.begin(client, "jigsaw.w3.org", 80, "/HTTP/connection.html");
}
int pass = 0;
void loop() {
// First 10 loop()s, retrieve the URL
if (pass < 10) {
pass++;
Serial.printf("Reuse connection example, GET url for the %d time\n", pass);
int httpCode = http.GET();
if (httpCode > 0) {
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK) {
http.writeToStream(&Serial);
}
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
// Something went wrong with the connection, try to reconnect
http.end();
http.begin("https://jigsaw.w3.org/HTTP/connection.html");
// http.begin(client, "jigsaw.w3.org", 80, "/HTTP/connection.html");
}
if (pass == 10) {
http.end();
Serial.println("Done testing");
} else {
Serial.println("\n\n\nWait 5 second...\n");
delay(5000);
}
}
}
@@ -0,0 +1,105 @@
/**
StreamHTTPClient.ino
Created on: 24.05.2015
*/
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char *ssid = STASSID;
const char *pass = STAPSK;
WiFiMulti WiFiMulti;
void setup() {
Serial.begin(115200);
// Serial.setDebugOutput(true);
Serial.println();
Serial.println();
Serial.println();
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
WiFi.mode(WIFI_STA);
WiFiMulti.addAP(ssid, pass);
}
void loop() {
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
Serial.print("[HTTPS] begin...\n");
// configure server and url
const char *fp = "41:FA:FD:B6:96:5F:33:09:F4:ED:09:28:BF:66:4D:5B:A2:88:03:65";
HTTPClient https;
https.setFingerprint(fp);
if (https.begin("https://www.trustedfirmware.org/projects/mbed-tls")) {
Serial.print("[HTTPS] GET...\n");
// start connection and send HTTP header
int httpCode = https.GET();
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK) {
// get length of document (is -1 when Server sends no Content-Length header)
int len = https.getSize();
// create buffer for read
static uint8_t buff[128] = { 0 };
// read all data from server
while (https.connected() && (len > 0 || len == -1)) {
// get available data size
size_t size = https.getStreamPtr()->available();
if (size) {
// read up to 128 byte
int c = https.getStreamPtr()->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
// write it to Serial
Serial.write(buff, c);
if (len > 0) {
len -= c;
}
}
delay(1);
}
Serial.println();
Serial.print("[HTTPS] connection closed or file end.\n");
}
} else {
Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
}
https.end();
} else {
Serial.printf("Unable to connect\n");
}
}
Serial.println("Wait 10s before the next round...");
delay(10000);
}
+149
View File
@@ -0,0 +1,149 @@
#######################################
# Syntax Coloring Map For HTTPClient
#######################################
#######################################
# Library (KEYWORD3)
#######################################
HTTPClient KEYWORD3 RESERVED_WORD
#######################################
# Datatypes (KEYWORD1)
#######################################
t_http_codes KEYWORD1 DATA_TYPE
transferEncoding_t KEYWORD1 DATA_TYPE
TransportTraits KEYWORD1 DATA_TYPE
TransportTraitsPtr KEYWORD1 DATA_TYPE
StreamString KEYWORD1 DATA_TYPE
HTTPClient KEYWORD1 DATA_TYPE
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
end KEYWORD2
connected KEYWORD2
setReuse KEYWORD2
setUserAgent KEYWORD2
setAuthorization KEYWORD2
setTimeout KEYWORD2
useHTTP10 KEYWORD2
GET KEYWORD2
POST KEYWORD2
PUT KEYWORD2
PATCH KEYWORD2
sendRequest KEYWORD2
addHeader KEYWORD2
collectHeaders KEYWORD2
header KEYWORD2
headerName KEYWORD2
headers KEYWORD2
hasHeader KEYWORD2
getSize KEYWORD2
getStream KEYWORD2
getStreamPtr KEYWORD2
writeToStream KEYWORD2
getString KEYWORD2
errorToString KEYWORD2
setSession KEYWORD2
setInsecure KEYWORD2
setKnownKey KEYWORD2
setFingerprint KEYWORD2
allowSelfSignedCerts KEYWORD2
setTrustAnchors KEYWORD2
setX509Time KEYWORD2
setClientRSACert KEYWORD2
setClientECCert KEYWORD2
setBufferSizes KEYWORD2
setCertStore KEYWORD2
setCiphers KEYWORD2
setCiphersLessSecure KEYWORD2
setSSLVersion KEYWORD2
setCACert KEYWORD2
setCertificate KEYWORD2
setPrivateKey KEYWORD2
loadCACert KEYWORD2
loadCertificate KEYWORD2
loadPrivateKey KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
HTTPCLIENT_DEFAULT_TCP_TIMEOUT LITERAL1 RESERVED_WORD_2
HTTPC_ERROR_CONNECTION_REFUSED LITERAL1 RESERVED_WORD_2
HTTPC_ERROR_SEND_HEADER_FAILED LITERAL1 RESERVED_WORD_2
HTTPC_ERROR_SEND_PAYLOAD_FAILED LITERAL1 RESERVED_WORD_2
HTTPC_ERROR_NOT_CONNECTED LITERAL1 RESERVED_WORD_2
HTTPC_ERROR_CONNECTION_LOST LITERAL1 RESERVED_WORD_2
HTTPC_ERROR_NO_STREAM LITERAL1 RESERVED_WORD_2
HTTPC_ERROR_NO_HTTP_SERVER LITERAL1 RESERVED_WORD_2
HTTPC_ERROR_TOO_LESS_RAM LITERAL1 RESERVED_WORD_2
HTTPC_ERROR_ENCODING LITERAL1 RESERVED_WORD_2
HTTPC_ERROR_STREAM_WRITE LITERAL1 RESERVED_WORD_2
HTTPC_ERROR_READ_TIMEOUT LITERAL1 RESERVED_WORD_2
HTTP_TCP_BUFFER_SIZE LITERAL1 RESERVED_WORD_2
HTTP_CODE_CONTINUE LITERAL1 RESERVED_WORD_2
HTTP_CODE_SWITCHING_PROTOCOLS LITERAL1 RESERVED_WORD_2
HTTP_CODE_PROCESSING LITERAL1 RESERVED_WORD_2
HTTP_CODE_OK LITERAL1 RESERVED_WORD_2
HTTP_CODE_CREATED LITERAL1 RESERVED_WORD_2
HTTP_CODE_ACCEPTED LITERAL1 RESERVED_WORD_2
HTTP_CODE_NON_AUTHORITATIVE_INFORMATION LITERAL1 RESERVED_WORD_2
HTTP_CODE_NO_CONTENT LITERAL1 RESERVED_WORD_2
HTTP_CODE_RESET_CONTENT LITERAL1 RESERVED_WORD_2
HTTP_CODE_PARTIAL_CONTENT LITERAL1 RESERVED_WORD_2
HTTP_CODE_MULTI_STATUS LITERAL1 RESERVED_WORD_2
HTTP_CODE_ALREADY_REPORTED LITERAL1 RESERVED_WORD_2
HTTP_CODE_IM_USED LITERAL1 RESERVED_WORD_2
HTTP_CODE_MULTIPLE_CHOICES LITERAL1 RESERVED_WORD_2
HTTP_CODE_MOVED_PERMANENTLY LITERAL1 RESERVED_WORD_2
HTTP_CODE_FOUND LITERAL1 RESERVED_WORD_2
HTTP_CODE_SEE_OTHER LITERAL1 RESERVED_WORD_2
HTTP_CODE_NOT_MODIFIED LITERAL1 RESERVED_WORD_2
HTTP_CODE_USE_PROXY LITERAL1 RESERVED_WORD_2
HTTP_CODE_TEMPORARY_REDIRECT LITERAL1 RESERVED_WORD_2
HTTP_CODE_PERMANENT_REDIRECT LITERAL1 RESERVED_WORD_2
HTTP_CODE_BAD_REQUEST LITERAL1 RESERVED_WORD_2
HTTP_CODE_UNAUTHORIZED LITERAL1 RESERVED_WORD_2
HTTP_CODE_PAYMENT_REQUIRED LITERAL1 RESERVED_WORD_2
HTTP_CODE_FORBIDDEN LITERAL1 RESERVED_WORD_2
HTTP_CODE_NOT_FOUND LITERAL1 RESERVED_WORD_2
HTTP_CODE_METHOD_NOT_ALLOWED LITERAL1 RESERVED_WORD_2
HTTP_CODE_NOT_ACCEPTABLE LITERAL1 RESERVED_WORD_2
HTTP_CODE_PROXY_AUTHENTICATION_REQUIRED LITERAL1 RESERVED_WORD_2
HTTP_CODE_REQUEST_TIMEOUT LITERAL1 RESERVED_WORD_2
HTTP_CODE_CONFLICT LITERAL1 RESERVED_WORD_2
HTTP_CODE_GONE LITERAL1 RESERVED_WORD_2
HTTP_CODE_LENGTH_REQUIRED LITERAL1 RESERVED_WORD_2
HTTP_CODE_PRECONDITION_FAILED LITERAL1 RESERVED_WORD_2
HTTP_CODE_PAYLOAD_TOO_LARGE LITERAL1 RESERVED_WORD_2
HTTP_CODE_URI_TOO_LONG LITERAL1 RESERVED_WORD_2
HTTP_CODE_UNSUPPORTED_MEDIA_TYPE LITERAL1 RESERVED_WORD_2
HTTP_CODE_RANGE_NOT_SATISFIABLE LITERAL1 RESERVED_WORD_2
HTTP_CODE_EXPECTATION_FAILED LITERAL1 RESERVED_WORD_2
HTTP_CODE_MISDIRECTED_REQUEST LITERAL1 RESERVED_WORD_2
HTTP_CODE_UNPROCESSABLE_ENTITY LITERAL1 RESERVED_WORD_2
HTTP_CODE_LOCKED LITERAL1 RESERVED_WORD_2
HTTP_CODE_FAILED_DEPENDENCY LITERAL1 RESERVED_WORD_2
HTTP_CODE_UPGRADE_REQUIRED LITERAL1 RESERVED_WORD_2
HTTP_CODE_PRECONDITION_REQUIRED LITERAL1 RESERVED_WORD_2
HTTP_CODE_TOO_MANY_REQUESTS LITERAL1 RESERVED_WORD_2
HTTP_CODE_REQUEST_HEADER_FIELDS_TOO_LARGE LITERAL1 RESERVED_WORD_2
HTTP_CODE_INTERNAL_SERVER_ERROR LITERAL1 RESERVED_WORD_2
HTTP_CODE_NOT_IMPLEMENTED LITERAL1 RESERVED_WORD_2
HTTP_CODE_BAD_GATEWAY LITERAL1 RESERVED_WORD_2
HTTP_CODE_SERVICE_UNAVAILABLE LITERAL1 RESERVED_WORD_2
HTTP_CODE_GATEWAY_TIMEOUT LITERAL1 RESERVED_WORD_2
HTTP_CODE_HTTP_VERSION_NOT_SUPPORTED LITERAL1 RESERVED_WORD_2
HTTP_CODE_VARIANT_ALSO_NEGOTIATES LITERAL1 RESERVED_WORD_2
HTTP_CODE_INSUFFICIENT_STORAGE LITERAL1 RESERVED_WORD_2
HTTP_CODE_LOOP_DETECTED LITERAL1 RESERVED_WORD_2
HTTP_CODE_NOT_EXTENDED LITERAL1 RESERVED_WORD_2
HTTP_CODE_NETWORK_AUTHENTICATION_REQUIRED LITERAL1 RESERVED_WORD_2
HTTPC_TE_IDENTITY LITERAL1 RESERVED_WORD_2
HTTPC_TE_CHUNKED LITERAL1 RESERVED_WORD_2
+10
View File
@@ -0,0 +1,10 @@
name=HTTPClient
version=1.2
author=Markus Sattler
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
sentence=http Client for ESP8266, portes to the Pico
paragraph=
category=Communication
url=https://github.com/earlephilhower/arduino-pico/blob/master/libraries/HTTPClient
architectures=rp2040
dot_a_linkage=true
File diff suppressed because it is too large Load Diff
+373
View File
@@ -0,0 +1,373 @@
/**
HTTPClient.h
Modified 2022 by Earle F. Philhower, III
Created on: 02.11.2015
Copyright (c) 2015 Markus Sattler. All rights reserved.
This file is part of the ESP8266HTTPClient for Arduino.
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 Jeroen Döll, June 2018
*/
#pragma once
#include <Arduino.h>
#include <StreamString.h>
#include <WiFiClient.h>
#include <WiFiClientSecure.h>
#include <memory>
#ifdef DEBUG_ESP_HTTP_CLIENT
#ifdef DEBUG_ESP_PORT
#define DEBUG_HTTPCLIENT(fmt, ...) DEBUG_ESP_PORT.printf_P( (PGM_P)PSTR(fmt), ## __VA_ARGS__ )
#endif
#endif
//#define DEBUG_HTTPCLIENT(fmt, ...) Serial.printf(fmt, ## __VA_ARGS__ )
#ifndef DEBUG_HTTPCLIENT
#define DEBUG_HTTPCLIENT(...) do { (void)0; } while (0)
#endif
#define HTTPCLIENT_DEFAULT_TCP_TIMEOUT (5000)
/// HTTP client errors
#define HTTPC_ERROR_CONNECTION_FAILED (-1)
#define HTTPC_ERROR_SEND_HEADER_FAILED (-2)
#define HTTPC_ERROR_SEND_PAYLOAD_FAILED (-3)
#define HTTPC_ERROR_NOT_CONNECTED (-4)
#define HTTPC_ERROR_CONNECTION_LOST (-5)
#define HTTPC_ERROR_NO_STREAM (-6)
#define HTTPC_ERROR_NO_HTTP_SERVER (-7)
#define HTTPC_ERROR_TOO_LESS_RAM (-8)
#define HTTPC_ERROR_ENCODING (-9)
#define HTTPC_ERROR_STREAM_WRITE (-10)
#define HTTPC_ERROR_READ_TIMEOUT (-11)
constexpr int HTTPC_ERROR_CONNECTION_REFUSED __attribute__((deprecated)) = HTTPC_ERROR_CONNECTION_FAILED;
/// size for the stream handling
#define HTTP_TCP_BUFFER_SIZE (1460)
/// HTTP codes see RFC7231
typedef enum {
HTTP_CODE_CONTINUE = 100,
HTTP_CODE_SWITCHING_PROTOCOLS = 101,
HTTP_CODE_PROCESSING = 102,
HTTP_CODE_OK = 200,
HTTP_CODE_CREATED = 201,
HTTP_CODE_ACCEPTED = 202,
HTTP_CODE_NON_AUTHORITATIVE_INFORMATION = 203,
HTTP_CODE_NO_CONTENT = 204,
HTTP_CODE_RESET_CONTENT = 205,
HTTP_CODE_PARTIAL_CONTENT = 206,
HTTP_CODE_MULTI_STATUS = 207,
HTTP_CODE_ALREADY_REPORTED = 208,
HTTP_CODE_IM_USED = 226,
HTTP_CODE_MULTIPLE_CHOICES = 300,
HTTP_CODE_MOVED_PERMANENTLY = 301,
HTTP_CODE_FOUND = 302,
HTTP_CODE_SEE_OTHER = 303,
HTTP_CODE_NOT_MODIFIED = 304,
HTTP_CODE_USE_PROXY = 305,
HTTP_CODE_TEMPORARY_REDIRECT = 307,
HTTP_CODE_PERMANENT_REDIRECT = 308,
HTTP_CODE_BAD_REQUEST = 400,
HTTP_CODE_UNAUTHORIZED = 401,
HTTP_CODE_PAYMENT_REQUIRED = 402,
HTTP_CODE_FORBIDDEN = 403,
HTTP_CODE_NOT_FOUND = 404,
HTTP_CODE_METHOD_NOT_ALLOWED = 405,
HTTP_CODE_NOT_ACCEPTABLE = 406,
HTTP_CODE_PROXY_AUTHENTICATION_REQUIRED = 407,
HTTP_CODE_REQUEST_TIMEOUT = 408,
HTTP_CODE_CONFLICT = 409,
HTTP_CODE_GONE = 410,
HTTP_CODE_LENGTH_REQUIRED = 411,
HTTP_CODE_PRECONDITION_FAILED = 412,
HTTP_CODE_PAYLOAD_TOO_LARGE = 413,
HTTP_CODE_URI_TOO_LONG = 414,
HTTP_CODE_UNSUPPORTED_MEDIA_TYPE = 415,
HTTP_CODE_RANGE_NOT_SATISFIABLE = 416,
HTTP_CODE_EXPECTATION_FAILED = 417,
HTTP_CODE_MISDIRECTED_REQUEST = 421,
HTTP_CODE_UNPROCESSABLE_ENTITY = 422,
HTTP_CODE_LOCKED = 423,
HTTP_CODE_FAILED_DEPENDENCY = 424,
HTTP_CODE_UPGRADE_REQUIRED = 426,
HTTP_CODE_PRECONDITION_REQUIRED = 428,
HTTP_CODE_TOO_MANY_REQUESTS = 429,
HTTP_CODE_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
HTTP_CODE_INTERNAL_SERVER_ERROR = 500,
HTTP_CODE_NOT_IMPLEMENTED = 501,
HTTP_CODE_BAD_GATEWAY = 502,
HTTP_CODE_SERVICE_UNAVAILABLE = 503,
HTTP_CODE_GATEWAY_TIMEOUT = 504,
HTTP_CODE_HTTP_VERSION_NOT_SUPPORTED = 505,
HTTP_CODE_VARIANT_ALSO_NEGOTIATES = 506,
HTTP_CODE_INSUFFICIENT_STORAGE = 507,
HTTP_CODE_LOOP_DETECTED = 508,
HTTP_CODE_NOT_EXTENDED = 510,
HTTP_CODE_NETWORK_AUTHENTICATION_REQUIRED = 511
} t_http_codes;
typedef enum {
HTTPC_TE_IDENTITY,
HTTPC_TE_CHUNKED
} transferEncoding_t;
/**
redirection follow mode.
+ `HTTPC_DISABLE_FOLLOW_REDIRECTS` - no redirection will be followed.
+ `HTTPC_STRICT_FOLLOW_REDIRECTS` - strict RFC2616, only requests using
GET or HEAD methods will be redirected (using the same method),
since the RFC requires end-user confirmation in other cases.
+ `HTTPC_FORCE_FOLLOW_REDIRECTS` - all redirections will be followed,
regardless of a used method. New request will use the same method,
and they will include the same body data and the same headers.
In the sense of the RFC, it's just like every redirection is confirmed.
*/
typedef enum {
HTTPC_DISABLE_FOLLOW_REDIRECTS,
HTTPC_STRICT_FOLLOW_REDIRECTS,
HTTPC_FORCE_FOLLOW_REDIRECTS
} followRedirects_t;
class TransportTraits;
typedef std::unique_ptr<TransportTraits> TransportTraitsPtr;
class HTTPClient {
public:
HTTPClient() = default;
~HTTPClient() = default;
HTTPClient(HTTPClient&&) = default;
HTTPClient& operator=(HTTPClient&&) = default;
// The easier way
bool begin(String url);
bool begin(String host, uint16_t port, String uri = "/", bool https = false);
bool begin(String url, const uint8_t httpsFingerprint[20]) {
setFingerprint(httpsFingerprint);
return begin(url);
}
bool begin(String host, uint16_t port, String uri, const uint8_t httpsFingerprint[20]) {
setFingerprint(httpsFingerprint);
return begin(host, port, uri);
}
// Let's do it the hard way, too
bool begin(WiFiClient &client, const String& url);
bool begin(WiFiClient &client, const String& host, uint16_t port, const String& uri = "/", bool https = false);
void end(void);
bool connected(void);
void setReuse(bool reuse); /// keep-alive
void setUserAgent(const String& userAgent);
void setAuthorization(const char * user, const char * password);
void setAuthorization(const char * auth);
void setAuthorization(String auth);
void setTimeout(uint16_t timeout);
// Redirections
void setFollowRedirects(followRedirects_t follow);
void setRedirectLimit(uint16_t limit); // max redirects to follow for a single request
bool setURL(const String& url); // handy for handling redirects
void useHTTP10(bool usehttp10 = true);
/// request handling
int GET();
int DELETE();
int POST(const uint8_t* payload, size_t size);
int POST(const String& payload);
int PUT(const uint8_t* payload, size_t size);
int PUT(const String& payload);
int PATCH(const uint8_t* payload, size_t size);
int PATCH(const String& payload);
int sendRequest(const char* type, const String& payload);
int sendRequest(const char* type, const uint8_t* payload = NULL, size_t size = 0);
int sendRequest(const char* type, Stream * stream, size_t size = 0);
void addHeader(const String& name, const String& value, bool first = false, bool replace = true);
/// Response handling
void collectHeaders(const char* headerKeys[], const size_t headerKeysCount);
String header(const char* name); // get request header value by name
String header(size_t i); // get request header value by number
String headerName(size_t i); // get request header name by number
int headers(); // get header count
bool hasHeader(const char* name); // check if header exists
int getSize(void);
const String& getLocation(void); // Location header from redirect if 3XX
WiFiClient& getStream(void);
WiFiClient* getStreamPtr(void);
int writeToPrint(Print* print);
int writeToStream(Stream* stream);
const String& getString(void);
static String errorToString(int error);
// ----------------------------------------------------------------------------------------------
// HTTPS support, mirrors the WiFiClientSecure interface
// Could possibly use a virtual interface class between the two, but for now it is more
// straightforward to simply feed calls through manually here.
void setSession(Session *session) {
_tls()->setSession(session);
}
void setInsecure() {
_tls()->setInsecure();
}
void setKnownKey(const PublicKey *pk, unsigned usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN) {
_tls()->setKnownKey(pk, usages);
}
bool setFingerprint(const uint8_t fingerprint[20]) {
return _tls()->setFingerprint(fingerprint);
}
bool setFingerprint(const char *fpStr) {
return _tls()->setFingerprint(fpStr);
}
void allowSelfSignedCerts() {
_tls()->allowSelfSignedCerts();
}
void setTrustAnchors(const X509List *ta) {
_tls()->setTrustAnchors(ta);
}
void setX509Time(time_t now) {
_tls()->setX509Time(now);
}
void setClientRSACert(const X509List *cert, const PrivateKey *sk) {
_tls()->setClientRSACert(cert, sk);
}
void setClientECCert(const X509List *cert, const PrivateKey *sk, unsigned allowed_usages, unsigned cert_issuer_key_type) {
_tls()->setClientECCert(cert, sk, allowed_usages, cert_issuer_key_type);
}
void setBufferSizes(int recv, int xmit) {
_tls()->setBufferSizes(recv, xmit);
}
void setCertStore(CertStoreBase *certStore) {
_tls()->setCertStore(certStore);
}
bool setCiphers(const uint16_t *cipherAry, int cipherCount) {
return _tls()->setCiphers(cipherAry, cipherCount);
}
bool setCiphers(const std::vector<uint16_t>& list) {
return _tls()->setCiphers(list);
}
bool setCiphersLessSecure() {
return _tls()->setCiphersLessSecure();
}
bool setSSLVersion(uint32_t min = BR_TLS10, uint32_t max = BR_TLS12) {
return _tls()->setSSLVersion(min, max);
}
void setCACert(const char *rootCA) {
_tls()->setCACert(rootCA);
}
void setCertificate(const char *client_ca) {
_tls()->setCertificate(client_ca);
}
void setPrivateKey(const char *private_key) {
_tls()->setPrivateKey(private_key);
}
bool loadCACert(Stream& stream, size_t size) {
return _tls()->loadCACert(stream, size);
}
bool loadCertificate(Stream& stream, size_t size) {
return _tls()->loadCertificate(stream, size);
}
bool loadPrivateKey(Stream& stream, size_t size) {
return _tls()->loadPrivateKey(stream, size);
}
protected:
// HTTPS helpers
WiFiClientSecure *_tls() {
if (!_clientMade) {
_clientMade = new WiFiClientSecure();
_clientGiven = false;
}
_clientTLS = true;
return (WiFiClientSecure*)_clientMade;
}
struct RequestArgument {
String key;
String value;
};
bool beginInternal(const String& url, const char* expectedProtocol);
void disconnect(bool preserveClient = false);
void clear();
int returnError(int error);
bool connect(void);
bool sendHeader(const char * type);
int handleHeaderResponse();
int writeToStreamDataBlock(Stream * stream, int len);
WiFiClient *_clientMade = nullptr;
bool _clientTLS = false;
std::unique_ptr<WiFiClient> _clientIn;
bool _clientGiven = false;
WiFiClient *_client() {
if (_clientGiven) {
return _clientIn.get();
} else {
return _clientMade;
}
}
/// request handling
String _host;
uint16_t _port = 0;
bool _reuse = true;
uint16_t _tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
bool _useHTTP10 = false;
String _uri;
String _protocol;
String _headers;
String _base64Authorization;
static const String defaultUserAgent;
String _userAgent = defaultUserAgent;
/// Response handling
std::unique_ptr<RequestArgument[]> _currentHeaders;
size_t _headerKeysCount = 0;
int _returnCode = 0;
int _size = -1;
bool _canReuse = false;
followRedirects_t _followRedirects = HTTPC_DISABLE_FOLLOW_REDIRECTS;
uint16_t _redirectLimit = 10;
String _location;
transferEncoding_t _transferEncoding = HTTPC_TE_IDENTITY;
std::unique_ptr<StreamString> _payload;
};
+69
View File
@@ -0,0 +1,69 @@
/**
base64.cpp
Created on: 09.12.2015
Copyright (c) 2015 Markus Sattler. All rights reserved.
This file is part of the ESP8266 core for Arduino.
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"
extern "C" {
#include "libb64/cencode.h"
}
#include "base64.h"
/**
convert input data to base64
@param data const uint8_t
@param length size_t
@return String
*/
String base64::encode(const uint8_t * data, size_t length, bool doNewLines) {
String base64;
// base64 needs more size then the source data, use cencode.h macros
size_t size = ((doNewLines ? base64_encode_expected_len(length)
: base64_encode_expected_len_nonewlines(length)) + 1);
if (base64.reserve(size)) {
base64_encodestate _state;
if (doNewLines) {
base64_init_encodestate(&_state);
} else {
base64_init_encodestate_nonewlines(&_state);
}
constexpr size_t BUFSIZE = 48;
char buf[BUFSIZE + 1 /* newline */ + 1 /* NUL */];
for (size_t len = 0; len < length; len += BUFSIZE * 3 / 4) {
size_t blocklen = base64_encode_block((const char*) data + len,
std::min(BUFSIZE * 3 / 4, length - len), buf, &_state);
buf[blocklen] = '\0';
base64 += buf;
}
if (base64_encode_blockend(buf, &_state)) {
base64 += buf;
}
} else {
base64 = F("-FAIL-");
}
return base64;
}
+48
View File
@@ -0,0 +1,48 @@
/**
base64.h
Created on: 09.12.2015
Copyright (c) 2015 Markus Sattler. All rights reserved.
This file is part of the ESP8266 core for Arduino.
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 <api/String.h>
class base64 {
public:
// NOTE: The default behaviour of backend (lib64)
// is to add a newline every 72 (encoded) characters output.
// This may 'break' longer uris and json variables
static String encode(const uint8_t * data, size_t length, bool doNewLines);
static inline String encode(const String& text, bool doNewLines) {
return encode((const uint8_t *) text.c_str(), text.length(), doNewLines);
}
// esp32 compat:
static inline String encode(const uint8_t * data, size_t length) {
return encode(data, length, false);
}
static inline String encode(const String& text) {
return encode(text, false);
}
};
+7
View File
@@ -0,0 +1,7 @@
libb64: Base64 Encoding/Decoding Routines
======================================
Authors:
-------
Chris Venter chris.venter@gmail.com http://rocketpod.blogspot.com
+29
View File
@@ -0,0 +1,29 @@
Copyright-Only Dedication (based on United States law)
or Public Domain Certification
The person or persons who have associated work with this document (the
"Dedicator" or "Certifier") hereby either (a) certifies that, to the best of
his knowledge, the work of authorship identified is in the public domain of the
country from which the work is published, or (b) hereby dedicates whatever
copyright the dedicators holds in the work of authorship identified below (the
"Work") to the public domain. A certifier, moreover, dedicates any copyright
interest he may have in the associated work, and for these purposes, is
described as a "dedicator" below.
A certifier has taken reasonable steps to verify the copyright status of this
work. Certifier recognizes that his good faith efforts may not shield him from
liability if in fact the work certified is not in the public domain.
Dedicator makes this dedication for the benefit of the public at large and to
the detriment of the Dedicator's heirs and successors. Dedicator intends this
dedication to be an overt act of relinquishment in perpetuity of all present
and future rights under copyright law, whether vested or contingent, in the
Work. Dedicator understands that such relinquishment of all rights includes
the relinquishment of all rights to enforce (by lawsuit or otherwise) those
copyrights in the Work.
Dedicator recognizes that, once placed in the public domain, the Work may be
freely reproduced, distributed, transmitted, used, modified, built upon, or
otherwise exploited by anyone for any purpose, commercial or non-commercial,
and in any way, including by methods that have not yet been invented or
conceived.
+111
View File
@@ -0,0 +1,111 @@
/*
cdecoder.c - c source to a base64 decoding algorithm implementation
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#include <pgmspace.h>
#include <stdint.h>
#include "cdecode.h"
extern "C" {
static int base64_decode_value_signed(int8_t value_in) {
static const int8_t decoding[] PROGMEM = {62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
static const int8_t decoding_size = sizeof(decoding);
value_in -= 43;
if (value_in < 0 || value_in > decoding_size) {
return -1;
}
return pgm_read_byte(&decoding[(int)value_in]);
}
void base64_init_decodestate(base64_decodestate* state_in) {
state_in->step = step_a;
state_in->plainchar = 0;
}
static int base64_decode_block_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out, base64_decodestate* state_in) {
const int8_t* codechar = code_in;
int8_t* plainchar = plaintext_out;
int8_t fragment;
*plainchar = state_in->plainchar;
switch (state_in->step) {
while (1) {
case step_a:
do {
if (codechar == code_in + length_in) {
state_in->step = step_a;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (int8_t)base64_decode_value_signed(*codechar++);
} while (fragment < 0);
*plainchar = (fragment & 0x03f) << 2;
// falls through
case step_b:
do {
if (codechar == code_in + length_in) {
state_in->step = step_b;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (int8_t)base64_decode_value_signed(*codechar++);
} while (fragment < 0);
*plainchar++ |= (fragment & 0x030) >> 4;
*plainchar = (fragment & 0x00f) << 4;
// falls through
case step_c:
do {
if (codechar == code_in + length_in) {
state_in->step = step_c;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (int8_t)base64_decode_value_signed(*codechar++);
} while (fragment < 0);
*plainchar++ |= (fragment & 0x03c) >> 2;
*plainchar = (fragment & 0x003) << 6;
// falls through
case step_d:
do {
if (codechar == code_in + length_in) {
state_in->step = step_d;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (int8_t)base64_decode_value_signed(*codechar++);
} while (fragment < 0);
*plainchar++ |= (fragment & 0x03f);
}
}
/* control should not reach here */
return plainchar - plaintext_out;
}
static int base64_decode_chars_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out) {
base64_decodestate _state;
base64_init_decodestate(&_state);
int len = base64_decode_block_signed(code_in, length_in, plaintext_out, &_state);
if (len > 0) {
plaintext_out[len] = 0;
}
return len;
}
int base64_decode_value(char value_in) {
return base64_decode_value_signed(*((int8_t *) &value_in));
}
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in) {
return base64_decode_block_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out, state_in);
}
int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out) {
return base64_decode_chars_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out);
}
};
+38
View File
@@ -0,0 +1,38 @@
/*
cdecode.h - c header for a base64 decoding algorithm
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#ifndef BASE64_CDECODE_H
#define BASE64_CDECODE_H
#define base64_decode_expected_len(n) ((n * 3) / 4)
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
step_a, step_b, step_c, step_d
} base64_decodestep;
typedef struct {
base64_decodestep step;
char plainchar;
} base64_decodestate;
void base64_init_decodestate(base64_decodestate* state_in);
int base64_decode_value(char value_in);
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in);
int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* BASE64_CDECODE_H */
+126
View File
@@ -0,0 +1,126 @@
/*
cencoder.c - c source to a base64 encoding algorithm implementation
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#include "cencode.h"
extern "C" {
void base64_init_encodestate(base64_encodestate* state_in) {
state_in->step = step_A;
state_in->result = 0;
state_in->stepcount = 0;
state_in->stepsnewline = BASE64_CHARS_PER_LINE;
}
void base64_init_encodestate_nonewlines(base64_encodestate* state_in) {
base64_init_encodestate(state_in);
state_in->stepsnewline = -1;
}
char base64_encode_value(const char n) {
char r;
if (n < 26) {
r = n + 'A';
} else if (n < 26 + 26) {
r = n - 26 + 'a';
} else if (n < 26 + 26 + 10) {
r = n - 26 - 26 + '0';
} else if (n == 62) {
r = '+';
} else {
r = '/';
}
return r;
}
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) {
const char* plainchar = plaintext_in;
const char* const plaintextend = plaintext_in + length_in;
char* codechar = code_out;
char result;
char fragment;
result = state_in->result;
switch (state_in->step) {
while (1) {
case step_A:
if (plainchar == plaintextend) {
state_in->result = result;
state_in->step = step_A;
return codechar - code_out;
}
fragment = *plainchar++;
result = (fragment & 0x0fc) >> 2;
*codechar++ = base64_encode_value(result);
result = (fragment & 0x003) << 4;
// falls through
case step_B:
if (plainchar == plaintextend) {
state_in->result = result;
state_in->step = step_B;
return codechar - code_out;
}
fragment = *plainchar++;
result |= (fragment & 0x0f0) >> 4;
*codechar++ = base64_encode_value(result);
result = (fragment & 0x00f) << 2;
// falls through
case step_C:
if (plainchar == plaintextend) {
state_in->result = result;
state_in->step = step_C;
return codechar - code_out;
}
fragment = *plainchar++;
result |= (fragment & 0x0c0) >> 6;
*codechar++ = base64_encode_value(result);
result = (fragment & 0x03f) >> 0;
*codechar++ = base64_encode_value(result);
++(state_in->stepcount);
if ((state_in->stepcount == BASE64_CHARS_PER_LINE / 4) && (state_in->stepsnewline > 0)) {
*codechar++ = '\n';
state_in->stepcount = 0;
}
}
}
/* control should not reach here */
return codechar - code_out;
}
int base64_encode_blockend(char* code_out, base64_encodestate* state_in) {
char* codechar = code_out;
switch (state_in->step) {
case step_B:
*codechar++ = base64_encode_value(state_in->result);
*codechar++ = '=';
*codechar++ = '=';
break;
case step_C:
*codechar++ = base64_encode_value(state_in->result);
*codechar++ = '=';
break;
case step_A:
break;
}
*codechar = 0x00;
return codechar - code_out;
}
int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out) {
base64_encodestate _state;
base64_init_encodestate(&_state);
int len = base64_encode_block(plaintext_in, length_in, code_out, &_state);
return len + base64_encode_blockend((code_out + len), &_state);
}
};
+48
View File
@@ -0,0 +1,48 @@
/*
cencode.h - c header for a base64 encoding algorithm
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#ifndef BASE64_CENCODE_H
#define BASE64_CENCODE_H
#define BASE64_CHARS_PER_LINE 72
#define base64_encode_expected_len_nonewlines(n) ((((4 * (n)) / 3) + 3) & ~3)
#define base64_encode_expected_len(n) \
(base64_encode_expected_len_nonewlines(n) + ((n / ((BASE64_CHARS_PER_LINE * 3) / 4)) + 1))
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
step_A, step_B, step_C
} base64_encodestep;
typedef struct {
base64_encodestep step;
char result;
int stepcount;
int stepsnewline;
} base64_encodestate;
void base64_init_encodestate(base64_encodestate* state_in);
void base64_init_encodestate_nonewlines(base64_encodestate* state_in);
char base64_encode_value(char value_in);
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in);
int base64_encode_blockend(char* code_out, base64_encodestate* state_in);
int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* BASE64_CENCODE_H */
@@ -0,0 +1,83 @@
/**
httpUpdate.ino
Created on: 27.11.2015
*/
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <HTTPUpdate.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char *ssid = STASSID;
const char *pass = STAPSK;
#define UPDATE_URL "http://192.168.1.8/xfer/file.bin"
WiFiMulti WiFiMulti;
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.println();
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
WiFi.mode(WIFI_STA);
WiFiMulti.addAP(ssid, pass);
}
void update_started() {
Serial.println("CALLBACK: HTTP update process started");
}
void update_finished() {
Serial.println("CALLBACK: HTTP update process finished");
}
void update_progress(int cur, int total) {
Serial.printf("CALLBACK: HTTP update process at %d of %d bytes...\n", cur, total);
}
void update_error(int err) {
Serial.printf("CALLBACK: HTTP update fatal error code %d\n", err);
}
void loop() {
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
// Add optional callback notifiers
httpUpdate.onStart(update_started);
httpUpdate.onEnd(update_finished);
httpUpdate.onProgress(update_progress);
httpUpdate.onError(update_error);
t_httpUpdate_return ret = httpUpdate.update(UPDATE_URL);
// Or:
// t_httpUpdate_return ret = httpUpdate.update("server", 80, "file.bin");
switch (ret) {
case HTTP_UPDATE_FAILED: Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); break;
case HTTP_UPDATE_NO_UPDATES: Serial.println("HTTP_UPDATE_NO_UPDATES"); break;
case HTTP_UPDATE_OK: Serial.println("HTTP_UPDATE_OK"); break;
}
}
}
@@ -0,0 +1,85 @@
/**
httpUpdateSecure.ino
Created on: 27.11.2015
*/
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <HTTPUpdate.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char *ssid = STASSID;
const char *pass = STAPSK;
#define UPDATE_URL "https://www.ziplabel.com/file.bin"
WiFiMulti WiFiMulti;
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.println();
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
WiFi.mode(WIFI_STA);
WiFiMulti.addAP(ssid, pass);
}
void update_started() {
Serial.println("CALLBACK: HTTP update process started");
}
void update_finished() {
Serial.println("CALLBACK: HTTP update process finished");
}
void update_progress(int cur, int total) {
Serial.printf("CALLBACK: HTTP update process at %d of %d bytes...\n", cur, total);
}
void update_error(int err) {
Serial.printf("CALLBACK: HTTP update fatal error code %d\n", err);
}
void loop() {
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
// Add optional callback notifiers
httpUpdate.onStart(update_started);
httpUpdate.onEnd(update_finished);
httpUpdate.onProgress(update_progress);
httpUpdate.onError(update_error);
WiFiClientSecure client;
client.setInsecure();
t_httpUpdate_return ret = httpUpdate.update(client, UPDATE_URL);
// Or:
// t_httpUpdate_return ret = httpUpdate.update("server", 80, "file.bin");
switch (ret) {
case HTTP_UPDATE_FAILED: Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); break;
case HTTP_UPDATE_NO_UPDATES: Serial.println("HTTP_UPDATE_NO_UPDATES"); break;
case HTTP_UPDATE_OK: Serial.println("HTTP_UPDATE_OK"); break;
}
}
}
+44
View File
@@ -0,0 +1,44 @@
#######################################
# Syntax Coloring Map For ESP8266httpUpdate
#######################################
#######################################
# Library (KEYWORD3)
#######################################
HTTPUpdate KEYWORD3 RESERVED_WORD
#######################################
# Datatypes (KEYWORD1)
#######################################
HTTPUpdateResult KEYWORD1 DATA_TYPE
ESPhttpUpdate KEYWORD1 DATA_TYPE
#######################################
# Methods and Functions (KEYWORD2)
#######################################
rebootOnUpdate KEYWORD2
update KEYWORD2
updateSpiffs KEYWORD2
getLastError KEYWORD2
getLastErrorString KEYWORD2
setAuthorization KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
HTTP_UE_TOO_LESS_SPACE LITERAL1 RESERVED_WORD_2
HTTP_UE_SERVER_NOT_REPORT_SIZE LITERAL1 RESERVED_WORD_2
HTTP_UE_SERVER_FILE_NOT_FOUND LITERAL1 RESERVED_WORD_2
HTTP_UE_SERVER_FORBIDDEN LITERAL1 RESERVED_WORD_2
HTTP_UE_SERVER_WRONG_HTTP_CODE LITERAL1 RESERVED_WORD_2
HTTP_UE_SERVER_FAULTY_MD5 LITERAL1 RESERVED_WORD_2
HTTP_UE_BIN_VERIFY_HEADER_FAILED LITERAL1 RESERVED_WORD_2
HTTP_UE_BIN_FOR_WRONG_FLASH LITERAL1 RESERVED_WORD_2
HTTP_UE_SERVER_UNAUTHORIZED LITERAL1 RESERVED_WORD_2
HTTP_UPDATE_FAILED LITERAL1 RESERVED_WORD_2
HTTP_UPDATE_NO_UPDATES LITERAL1 RESERVED_WORD_2
HTTP_UPDATE_OK LITERAL1 RESERVED_WORD_2
+10
View File
@@ -0,0 +1,10 @@
name=HTTPUpdate
version=1.3
author=Markus Sattler
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
sentence=Http Update for ESP8266, ported to Pico
paragraph=
category=Data Processing
url=https://github.com/earlephilhower/arduino-pico
architectures=rp2040
dot_a_linkage=true
+392
View File
@@ -0,0 +1,392 @@
/**
@file HTTPUpdate.cpp
@date 21.06.2015
@author Markus Sattler
Copyright (c) 2015 Markus Sattler. All rights reserved.
This file is part of the Http Updater.
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 "HTTPUpdate.h"
#include <StreamString.h>
extern uint8_t _FS_start;
extern uint8_t _FS_end;
HTTPUpdate::HTTPUpdate(void)
: _httpClientTimeout(8000) {
}
HTTPUpdate::HTTPUpdate(int httpClientTimeout)
: _httpClientTimeout(httpClientTimeout) {
}
HTTPUpdate::~HTTPUpdate(void) {
}
/**
set the Authorization for the http request
@param user const String&
@param password const String&
*/
void HTTPUpdate::setAuthorization(const String &user, const String &password) {
_user = user;
_password = password;
}
/**
set the Authorization for the http request
@param auth const String& base64
*/
void HTTPUpdate::setAuthorization(const String &auth) {
_auth = auth;
}
HTTPUpdateResult HTTPUpdate::update(WiFiClient& client, const String& url, const String& currentVersion) {
HTTPClient http;
http.begin(client, url);
return handleUpdate(http, currentVersion, false);
}
HTTPUpdateResult HTTPUpdate::updateFS(WiFiClient& client, const String& url, const String& currentVersion) {
HTTPClient http;
http.begin(client, url);
return handleUpdate(http, currentVersion, true);
}
HTTPUpdateResult HTTPUpdate::update(WiFiClient& client, const String& host, uint16_t port, const String& uri,
const String& currentVersion) {
HTTPClient http;
http.begin(client, host, port, uri);
return handleUpdate(http, currentVersion, false);
}
HTTPUpdateResult HTTPUpdate::update(const String& url, const String& currentVersion) {
HTTPClient http;
http.begin(url);
return handleUpdate(http, currentVersion, false);
}
HTTPUpdateResult HTTPUpdate::update(const String& host, uint16_t port, const String& uri, const String& currentVersion) {
HTTPClient http;
http.begin(host, port, uri);
return handleUpdate(http, currentVersion, false);
}
HTTPUpdateResult HTTPUpdate::updateFS(const String& url, const String& currentVersion) {
HTTPClient http;
http.begin(url);
return handleUpdate(http, currentVersion, true);
}
/**
return error code as int
@return int error code
*/
int HTTPUpdate::getLastError(void) {
return _lastError;
}
/**
return error code as String
@return String error
*/
String HTTPUpdate::getLastErrorString(void) {
if (_lastError == 0) {
return String(); // no error
}
// error from Update class
if (_lastError > 0) {
StreamString error;
Update.printError(error);
error.trim(); // remove line ending
return String(F("Update error: ")) + error;
}
// error from http client
if (_lastError > -100) {
return String(F("HTTP error: ")) + HTTPClient::errorToString(_lastError);
}
switch (_lastError) {
case HTTP_UE_TOO_LESS_SPACE:
return F("Not Enough space");
case HTTP_UE_SERVER_NOT_REPORT_SIZE:
return F("Server Did Not Report Size");
case HTTP_UE_SERVER_FILE_NOT_FOUND:
return F("File Not Found (404)");
case HTTP_UE_SERVER_FORBIDDEN:
return F("Forbidden (403)");
case HTTP_UE_SERVER_WRONG_HTTP_CODE:
return F("Wrong HTTP Code");
case HTTP_UE_SERVER_FAULTY_MD5:
return F("Wrong MD5");
case HTTP_UE_BIN_VERIFY_HEADER_FAILED:
return F("Verify Bin Header Failed");
case HTTP_UE_BIN_FOR_WRONG_FLASH:
return F("New Binary Does Not Fit Flash Size");
case HTTP_UE_SERVER_UNAUTHORIZED:
return F("Unauthorized (401)");
}
return String();
}
/**
@param http HTTPClient
@param currentVersion const char
@return HTTPUpdateResult
*/
HTTPUpdateResult HTTPUpdate::handleUpdate(HTTPClient& http, const String& currentVersion, bool spiffs) {
HTTPUpdateResult ret = HTTP_UPDATE_FAILED;
// use HTTP/1.0 for update since the update handler not support any transfer Encoding
http.useHTTP10(true);
http.setTimeout(_httpClientTimeout);
http.setFollowRedirects(_followRedirects);
http.setUserAgent(F("-http-Update"));
http.addHeader(F("x--Chip-ID"), String(rp2040.getChipID()));
http.addHeader(F("x--STA-MAC"), WiFi.macAddress());
http.addHeader(F("x--AP-MAC"), WiFi.softAPmacAddress());
if (spiffs) {
http.addHeader(F("x--mode"), F("spiffs"));
} else {
http.addHeader(F("x--mode"), F("sketch"));
}
if (currentVersion && currentVersion[0] != 0x00) {
http.addHeader(F("x--version"), currentVersion);
}
if (_user != "" && _password != "") {
http.setAuthorization(_user.c_str(), _password.c_str());
}
if (_auth != "") {
http.setAuthorization(_auth.c_str());
}
const char * headerkeys[] = { "x-MD5" };
size_t headerkeyssize = sizeof(headerkeys) / sizeof(char*);
// track these headers
http.collectHeaders(headerkeys, headerkeyssize);
int code = http.GET();
int len = http.getSize();
if (code <= 0) {
DEBUG_HTTP_UPDATE("[httpUpdate] HTTP error: %s\n", http.errorToString(code).c_str());
_setLastError(code);
http.end();
return HTTP_UPDATE_FAILED;
}
DEBUG_HTTP_UPDATE("[httpUpdate] Header read fin.\n");
DEBUG_HTTP_UPDATE("[httpUpdate] Server header:\n");
DEBUG_HTTP_UPDATE("[httpUpdate] - code: %d\n", code);
DEBUG_HTTP_UPDATE("[httpUpdate] - len: %d\n", len);
String md5;
if (_md5Sum.length()) {
md5 = _md5Sum;
} else if (http.hasHeader("x-MD5")) {
md5 = http.header("x-MD5");
}
if (md5.length()) {
DEBUG_HTTP_UPDATE("[httpUpdate] - MD5: %s\n", md5.c_str());
}
DEBUG_HTTP_UPDATE("[httpUpdate] info:\n");
if (currentVersion && currentVersion[0] != 0x00) {
DEBUG_HTTP_UPDATE("[httpUpdate] - current version: %s\n", currentVersion.c_str());
}
switch (code) {
case HTTP_CODE_OK: ///< OK (Start Update)
if (len > 0) {
bool startUpdate = true;
if (spiffs) {
size_t spiffsSize = ((size_t)&_FS_end - (size_t)&_FS_start);
if (len > (int) spiffsSize) {
DEBUG_HTTP_UPDATE("[httpUpdate] spiffsSize to low (%d) needed: %d\n", spiffsSize, len);
startUpdate = false;
}
}
if (!startUpdate) {
_setLastError(HTTP_UE_TOO_LESS_SPACE);
ret = HTTP_UPDATE_FAILED;
} else {
// Warn main app we're starting up...
if (_cbStart) {
_cbStart();
}
WiFiClient * tcp = http.getStreamPtr();
if (!tcp) {
DEBUG_HTTP_UPDATE("[httpUpdate] WiFiClient connection unexpectedly absent\n");
_setLastError(HTTPC_ERROR_CONNECTION_LOST);
http.end();
return HTTP_UPDATE_FAILED;
}
if (_closeConnectionsOnUpdate) {
WiFiUDP::stopAll();
WiFiClient::stopAllExcept(tcp);
}
delay(100);
int command;
if (spiffs) {
command = U_FS;
DEBUG_HTTP_UPDATE("[httpUpdate] runUpdate filesystem...\n");
} else {
command = U_FLASH;
DEBUG_HTTP_UPDATE("[httpUpdate] runUpdate flash...\n");
}
if (runUpdate(*tcp, len, md5, command)) {
ret = HTTP_UPDATE_OK;
DEBUG_HTTP_UPDATE("[httpUpdate] Update ok\n");
http.end();
// Warn main app we're all done
if (_cbEnd) {
_cbEnd();
}
#ifdef ATOMIC_FS_UPDATE
if (_rebootOnUpdate) {
#else
if (_rebootOnUpdate && !spiffs) {
#endif
rp2040.restart();
}
} else {
ret = HTTP_UPDATE_FAILED;
DEBUG_HTTP_UPDATE("[httpUpdate] Update failed\n");
}
}
} else {
_setLastError(HTTP_UE_SERVER_NOT_REPORT_SIZE);
ret = HTTP_UPDATE_FAILED;
DEBUG_HTTP_UPDATE("[httpUpdate] Content-Length was 0 or wasn't set by Server?!\n");
}
break;
case HTTP_CODE_NOT_MODIFIED:
///< Not Modified (No updates)
ret = HTTP_UPDATE_NO_UPDATES;
break;
case HTTP_CODE_NOT_FOUND:
_setLastError(HTTP_UE_SERVER_FILE_NOT_FOUND);
ret = HTTP_UPDATE_FAILED;
break;
case HTTP_CODE_FORBIDDEN:
_setLastError(HTTP_UE_SERVER_FORBIDDEN);
ret = HTTP_UPDATE_FAILED;
break;
case HTTP_CODE_UNAUTHORIZED:
_setLastError(HTTP_UE_SERVER_UNAUTHORIZED);
ret = HTTP_UPDATE_FAILED;
break;
default:
_setLastError(HTTP_UE_SERVER_WRONG_HTTP_CODE);
ret = HTTP_UPDATE_FAILED;
DEBUG_HTTP_UPDATE("[httpUpdate] HTTP Code is (%d)\n", code);
//http.writeToStream(&Serial1);
break;
}
http.end();
return ret;
}
/**
write Update to flash
@param in Stream&
@param size uint32_t
@param md5 String
@return true if Update ok
*/
bool HTTPUpdate::runUpdate(Stream& in, uint32_t size, const String& md5, int command) {
StreamString error;
if (_cbProgress) {
Update.onProgress(_cbProgress);
}
if (!Update.begin(size, command)) {
_setLastError(Update.getError());
Update.printError(error);
error.trim(); // remove line ending
DEBUG_HTTP_UPDATE("[httpUpdate] Update.begin failed! (%s)\n", error.c_str());
return false;
}
if (_cbProgress) {
_cbProgress(0, size);
}
if (md5.length()) {
if (!Update.setMD5(md5.c_str())) {
_setLastError(HTTP_UE_SERVER_FAULTY_MD5);
DEBUG_HTTP_UPDATE("[httpUpdate] Update.setMD5 failed! (%s)\n", md5.c_str());
return false;
}
}
if (Update.writeStream(in) != size) {
_setLastError(Update.getError());
Update.printError(error);
error.trim(); // remove line ending
DEBUG_HTTP_UPDATE("[httpUpdate] Update.writeStream failed! (%s)\n", error.c_str());
return false;
}
if (_cbProgress) {
_cbProgress(size, size);
}
if (!Update.end()) {
_setLastError(Update.getError());
Update.printError(error);
error.trim(); // remove line ending
DEBUG_HTTP_UPDATE("[httpUpdate] Update.end failed! (%s)\n", error.c_str());
return false;
}
return true;
}
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_HTTPUPDATE)
HTTPUpdate httpUpdate;
#endif
+163
View File
@@ -0,0 +1,163 @@
/**
@file ESP8266HTTPUpdate.h
@date 21.06.2015
@author Markus Sattler
Copyright (c) 2015 Markus Sattler. All rights reserved.
This file is part of the ESP8266 Http Updater.
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 <WiFiClient.h>
#include <WiFiUdp.h>
#include <HTTPClient.h>
#ifdef DEBUG_ESP_HTTP_UPDATE
#ifdef DEBUG_ESP_PORT
#define DEBUG_HTTP_UPDATE(fmt, ...) DEBUG_ESP_PORT.printf_P( (PGM_P)PSTR(fmt), ## __VA_ARGS__ )
#endif
#endif
#ifndef DEBUG_HTTP_UPDATE
#define DEBUG_HTTP_UPDATE(...) do { (void)0; } while(0)
#endif
/// note we use HTTP client errors too so we start at 100
//TODO - in v3.0.0 make this an enum
constexpr int HTTP_UE_TOO_LESS_SPACE = (-100);
constexpr int HTTP_UE_SERVER_NOT_REPORT_SIZE = (-101);
constexpr int HTTP_UE_SERVER_FILE_NOT_FOUND = (-102);
constexpr int HTTP_UE_SERVER_FORBIDDEN = (-103);
constexpr int HTTP_UE_SERVER_WRONG_HTTP_CODE = (-104);
constexpr int HTTP_UE_SERVER_FAULTY_MD5 = (-105);
constexpr int HTTP_UE_BIN_VERIFY_HEADER_FAILED = (-106);
constexpr int HTTP_UE_BIN_FOR_WRONG_FLASH = (-107);
constexpr int HTTP_UE_SERVER_UNAUTHORIZED = (-108);
enum HTTPUpdateResult {
HTTP_UPDATE_FAILED,
HTTP_UPDATE_NO_UPDATES,
HTTP_UPDATE_OK
};
typedef HTTPUpdateResult t_httpUpdate_return; // backward compatibility
using HTTPUpdateStartCB = std::function<void()>;
using HTTPUpdateEndCB = std::function<void()>;
using HTTPUpdateErrorCB = std::function<void(int)>;
using HTTPUpdateProgressCB = std::function<void(int, int)>;
class HTTPUpdate {
public:
HTTPUpdate(void);
HTTPUpdate(int httpClientTimeout);
~HTTPUpdate(void);
void rebootOnUpdate(bool reboot) {
_rebootOnUpdate = reboot;
}
/**
set true to follow redirects.
@param follow
@deprecated Please use `setFollowRedirects(followRedirects_t follow)`
*/
void followRedirects(bool follow) __attribute__((deprecated)) {
_followRedirects = follow ? HTTPC_STRICT_FOLLOW_REDIRECTS : HTTPC_DISABLE_FOLLOW_REDIRECTS;
}
/**
set redirect follow mode. See `followRedirects_t` enum for available modes.
@param follow
*/
void setFollowRedirects(followRedirects_t follow) {
_followRedirects = follow;
}
void closeConnectionsOnUpdate(bool sever) {
_closeConnectionsOnUpdate = sever;
}
void setMD5sum(const String &md5Sum) {
_md5Sum = md5Sum;
}
void setAuthorization(const String& user, const String& password);
void setAuthorization(const String& auth);
t_httpUpdate_return update(WiFiClient& client, const String& url, const String& currentVersion = "");
t_httpUpdate_return update(WiFiClient& client, const String& host, uint16_t port, const String& uri = "/",
const String& currentVersion = "");
t_httpUpdate_return updateFS(WiFiClient& client, const String& url, const String& currentVersion = "");
t_httpUpdate_return update(const String& url, const String& currentVersion = "");
t_httpUpdate_return update(const String& host, uint16_t port, const String& uri = "/", const String& currentVersion = "");
t_httpUpdate_return updateFS(const String& url, const String& currentVersion = "");
// Notification callbacks
void onStart(HTTPUpdateStartCB cbOnStart) {
_cbStart = cbOnStart;
}
void onEnd(HTTPUpdateEndCB cbOnEnd) {
_cbEnd = cbOnEnd;
}
void onError(HTTPUpdateErrorCB cbOnError) {
_cbError = cbOnError;
}
void onProgress(HTTPUpdateProgressCB cbOnProgress) {
_cbProgress = cbOnProgress;
}
int getLastError(void);
String getLastErrorString(void);
protected:
t_httpUpdate_return handleUpdate(HTTPClient& http, const String& currentVersion, bool spiffs = false);
bool runUpdate(Stream& in, uint32_t size, const String& md5, int command = U_FLASH);
// Set the error and potentially use a CB to notify the application
void _setLastError(int err) {
_lastError = err;
if (_cbError) {
_cbError(err);
}
}
int _lastError;
bool _rebootOnUpdate = true;
bool _closeConnectionsOnUpdate = true;
String _user;
String _password;
String _auth;
String _md5Sum;
private:
int _httpClientTimeout;
followRedirects_t _followRedirects = HTTPC_DISABLE_FOLLOW_REDIRECTS;
// Callbacks
HTTPUpdateStartCB _cbStart;
HTTPUpdateEndCB _cbEnd;
HTTPUpdateErrorCB _cbError;
HTTPUpdateProgressCB _cbProgress;
};
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_HTTPUPDATE)
extern HTTPUpdate httpUpdate;
#endif
+1 -1
View File
@@ -78,7 +78,7 @@ bool I2S::setBuffers(size_t buffers, size_t bufferWords, int32_t silenceSample)
bool I2S::setFrequency(int newFreq) {
_freq = newFreq;
if (_running) {
float bitClk = _freq * _bps * 2.0;
float bitClk = _freq * _bps * 2.0 /* channels */ * 2.0 /* edges per clock */;
pio_sm_set_clkdiv(_pio, _sm, (float)clock_get_hz(clk_sys) / bitClk);
}
return true;
+2 -2
View File
@@ -74,7 +74,7 @@ public:
return write((uint32_t)s);
}
// Write 32 bit value to port, user responsbile for packing/alignment, etc.
// Write 32 bit value to port, user responsible for packing/alignment, etc.
size_t write(int32_t val, bool sync);
// Write sample to I2S port, will block until completed
@@ -83,7 +83,7 @@ public:
size_t write24(int32_t l, int32_t r); // Note that 24b must have values left-aligned (i.e. 0xABCDEF00)
size_t write32(int32_t l, int32_t r);
// Read 32 bit value to port, user responsbile for packing/alignment, etc.
// Read 32 bit value to port, user responsible for packing/alignment, etc.
size_t read(int32_t *val, bool sync);
// Read samples from I2S port, will block until data available
+61
View File
@@ -0,0 +1,61 @@
ESP8266 Multicast DNS
=====================
A port of CC3000 Multicast DNS library (version 1.1)
This is a simple implementation of multicast DNS query support for an
Arduino running on ESP8266 chip. Only support for resolving address
queries is currently implemented.
Requirements
------------
- ESP8266WiFi library
- MDNS support in your operating system/client machines:
- For Mac OSX support is built in through Bonjour already.
- For Linux, install `Avahi <http://avahi.org/>`__.
- For Windows, install
`Bonjour <http://www.apple.com/support/bonjour/>`__.
Usage
-----
1. Download this repository as a zip (button on the right) and follow
`these instructions to install into
Arduino <http://arduino.cc/en/Guide/Libraries>`__.
2. Include the ESP8266mDNS library in the sketch.
3. Call MDNS.begin method in the sketch's setup and provide a domain
name (without the '.local' suffix, i.e. just provide 'foo' to resolve
'foo.local'). Optionally provide the IP address to advertise and time
to live (in seconds) for the DNS record -- the default is 1 hour.
4. To advertise DNS-SD services, call MDNS.addService(service, proto,
port), where service and proto are strings with service and protocol
name (e.g. "http", "tcp"), and port is an integer port number for
this service (e.g. 80).
See the included MDNS + HTTP server sketch for a full example.
License
-------
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com) ESP8266 port (c)
2015 Ivan Grokhotkov (ivan@esp8266.com)
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.
+25
View File
@@ -0,0 +1,25 @@
#######################################
# Syntax Coloring Map For Ultrasound
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
LEAmDNS KEYWORD1
MDNSResponder KEYWORD1
MDNS KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
update KEYWORD2
addService KEYWORD2
enableArduino KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
+10
View File
@@ -0,0 +1,10 @@
name=LEAmDNS
version=1.2
author=multiple, see files
maintainer=LaborEtArs
sentence=Creates a mDNS responder.
paragraph=Creates a mDNS responder to ensure host domain uniqueness in local networks and to allow for mDNS service discovery and announcement.
category=Communication
url=https://github.com/LaborEtArs/ESP8266mDNS
architectures=rp2040
dot_a_linkage=true
+32
View File
@@ -0,0 +1,32 @@
/*
License (MIT license):
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.
*/
#include <ESP8266mDNS.h>
/*
MDNS responder global instance
Class type that is instantiated depends on the type mapping in ESP8266mDNS.h
*/
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
MDNSResponder MDNS;
#endif
+54
View File
@@ -0,0 +1,54 @@
/*
ESP8266mDNS.h - mDNSResponder for ESP8266 family
This file is part of the esp8266 core for Arduino environment.
mDNS implementation, that supports many mDNS features like:
- Presenting a DNS-SD service to interested observers, eg. a http server by presenting
_http._tcp service
- Support for multi-level compressed names in input; in output only a very simple one-leven
full-name compression is implemented
- Probing host and service domains for uniqueness in the local network
- Tiebreaking while probing is supported in a very minimalistic way (the 'higher' IP address
wins the tiebreak)
- Announcing available services after successful probing
- Using fixed service TXT items or
- Using dynamic service TXT items for presented services (via callback)
- Remove services (and un-announcing them to the observers by sending goodbye-messages)
- Static queries for DNS-SD services (creating a fixed answer set after a certain timeout
period)
- Dynamic queries for DNS-SD services with cached and updated answers and user notifications
- Support for multi-homed client host domains
See 'src/LEAmDNS.h' for implementation details, configuration and usage information.
See 'examples/LEAmDNS/' for examples of the new features.
LEAmDNS is expected to be compatible with the original ESP8266mDNS implementation, and it can be
used as a drop-in replacement in existing projects.
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 "LEAmDNS.h" // LEA
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
// Maps the implementation to use to the global namespace type
using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; // LEA
extern MDNSResponder MDNS;
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+671
View File
@@ -0,0 +1,671 @@
/*
LEAmDNS_Helpers.cpp
License (MIT license):
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.
*/
#include <lwip/igmp.h>
#include <stdlib_noniso.h> // strrstr()
#include "ESP8266mDNS.h"
#include "LEAmDNS_lwIPdefs.h"
#include "LEAmDNS_Priv.h"
namespace esp8266 {
/*
LEAmDNS
*/
namespace MDNSImplementation {
/**
HELPERS
*/
/*
MDNSResponder::indexDomain (static)
Updates the given domain 'p_rpcHostname' by appending a delimiter and an index number.
If the given domain already hasa numeric index (after the given delimiter), this index
incremented. If not, the delimiter and index '2' is added.
If 'p_rpcHostname' is empty (==0), the given default name 'p_pcDefaultHostname' is used,
if no default is given, 'esp8266' is used.
*/
/*static*/ bool MDNSResponder::indexDomain(char*& p_rpcDomain,
const char* p_pcDivider /*= "-"*/,
const char* p_pcDefaultDomain /*= 0*/) {
bool bResult = false;
// Ensure a divider exists; use '-' as default
const char* pcDivider = (p_pcDivider ? : "-");
if (p_rpcDomain) {
const char* pFoundDivider = strrstr(p_rpcDomain, pcDivider);
if (pFoundDivider) { // maybe already extended
char* pEnd = 0;
unsigned long ulIndex = strtoul((pFoundDivider + strlen(pcDivider)), &pEnd, 10);
if ((ulIndex) && ((pEnd - p_rpcDomain) == (ptrdiff_t)strlen(p_rpcDomain))
&& (!*pEnd)) { // Valid (old) index found
char acIndexBuffer[16];
sprintf(acIndexBuffer, "%lu", (++ulIndex));
size_t stLength = ((pFoundDivider - p_rpcDomain + strlen(pcDivider))
+ strlen(acIndexBuffer) + 1);
char* pNewHostname = new char[stLength];
if (pNewHostname) {
memcpy(pNewHostname, p_rpcDomain,
(pFoundDivider - p_rpcDomain + strlen(pcDivider)));
pNewHostname[pFoundDivider - p_rpcDomain + strlen(pcDivider)] = 0;
strcat(pNewHostname, acIndexBuffer);
delete[] p_rpcDomain;
p_rpcDomain = pNewHostname;
bResult = true;
} else {
DEBUG_EX_ERR(DEBUG_OUTPUT.println(
F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!")););
}
} else {
pFoundDivider = 0; // Flag the need to (base) extend the hostname
}
}
if (!pFoundDivider) // not yet extended (or failed to increment extension) -> start
// indexing
{
size_t stLength = strlen(p_rpcDomain)
+ (strlen(pcDivider) + 1 + 1); // Name + Divider + '2' + '\0'
char* pNewHostname = new char[stLength];
if (pNewHostname) {
sprintf(pNewHostname, "%s%s2", p_rpcDomain, pcDivider);
delete[] p_rpcDomain;
p_rpcDomain = pNewHostname;
bResult = true;
} else {
DEBUG_EX_ERR(DEBUG_OUTPUT.println(
F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!")););
}
}
} else {
// No given host domain, use base or default
const char* cpcDefaultName = (p_pcDefaultDomain ? : "esp8266");
size_t stLength = strlen(cpcDefaultName) + 1; // '\0'
p_rpcDomain = new char[stLength];
if (p_rpcDomain) {
strncpy(p_rpcDomain, cpcDefaultName, stLength);
bResult = true;
} else {
DEBUG_EX_ERR(DEBUG_OUTPUT.println(
F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!")););
}
}
DEBUG_EX_INFO(
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] indexDomain: %s\n"), p_rpcDomain););
return bResult;
}
/*
UDP CONTEXT
*/
bool MDNSResponder::_callProcess(void) {
DEBUG_EX_INFO(
DEBUG_OUTPUT.printf("[MDNSResponder] _callProcess (%lu, triggered by: %s)\n", millis(),
IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str()););
return _process(false);
}
/*
MDNSResponder::_allocUDPContext
(Re-)Creates the one-and-only UDP context for the MDNS responder.
The context is added to the 'multicast'-group and listens to the MDNS port (5353).
The travel-distance for multicast messages is set to 1 (local, via MDNS_MULTICAST_TTL).
Messages are received via the MDNSResponder '_update' function. CAUTION: This function
is called from the WiFi stack side of the ESP stack system.
*/
bool MDNSResponder::_allocUDPContext(void) {
DEBUG_EX_INFO(DEBUG_OUTPUT.println("[MDNSResponder] _allocUDPContext"););
_releaseUDPContext();
_joinMulticastGroups();
m_pUDPContext = new UdpContext;
m_pUDPContext->ref();
if (m_pUDPContext->listen(IP4_ADDR_ANY, DNS_MQUERY_PORT)) {
m_pUDPContext->setMulticastTTL(MDNS_MULTICAST_TTL);
m_pUDPContext->onRx(std::bind(&MDNSResponder::_callProcess, this));
} else {
return false;
}
return true;
}
/*
MDNSResponder::_releaseUDPContext
*/
bool MDNSResponder::_releaseUDPContext(void) {
if (m_pUDPContext) {
m_pUDPContext->unref();
m_pUDPContext = 0;
_leaveMulticastGroups();
}
return true;
}
/*
SERVICE QUERY
*/
/*
MDNSResponder::_allocServiceQuery
*/
MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_allocServiceQuery(void) {
stcMDNSServiceQuery* pServiceQuery = new stcMDNSServiceQuery;
if (pServiceQuery) {
// Link to query list
pServiceQuery->m_pNext = m_pServiceQueries;
m_pServiceQueries = pServiceQuery;
}
return m_pServiceQueries;
}
/*
MDNSResponder::_removeServiceQuery
*/
bool MDNSResponder::_removeServiceQuery(MDNSResponder::stcMDNSServiceQuery* p_pServiceQuery) {
bool bResult = false;
if (p_pServiceQuery) {
stcMDNSServiceQuery* pPred = m_pServiceQueries;
while ((pPred) && (pPred->m_pNext != p_pServiceQuery)) {
pPred = pPred->m_pNext;
}
if (pPred) {
pPred->m_pNext = p_pServiceQuery->m_pNext;
delete p_pServiceQuery;
bResult = true;
} else { // No predecessor
if (m_pServiceQueries == p_pServiceQuery) {
m_pServiceQueries = p_pServiceQuery->m_pNext;
delete p_pServiceQuery;
bResult = true;
} else {
DEBUG_EX_ERR(DEBUG_OUTPUT.println(
"[MDNSResponder] _releaseServiceQuery: INVALID service query!"););
}
}
}
return bResult;
}
/*
MDNSResponder::_removeLegacyServiceQuery
*/
bool MDNSResponder::_removeLegacyServiceQuery(void) {
stcMDNSServiceQuery* pLegacyServiceQuery = _findLegacyServiceQuery();
return (pLegacyServiceQuery ? _removeServiceQuery(pLegacyServiceQuery) : true);
}
/*
MDNSResponder::_findServiceQuery
'Convert' hMDNSServiceQuery to stcMDNSServiceQuery* (ensure existence)
*/
MDNSResponder::stcMDNSServiceQuery*
MDNSResponder::_findServiceQuery(MDNSResponder::hMDNSServiceQuery p_hServiceQuery) {
stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries;
while (pServiceQuery) {
if ((hMDNSServiceQuery)pServiceQuery == p_hServiceQuery) {
break;
}
pServiceQuery = pServiceQuery->m_pNext;
}
return pServiceQuery;
}
/*
MDNSResponder::_findLegacyServiceQuery
*/
MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findLegacyServiceQuery(void) {
stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries;
while (pServiceQuery) {
if (pServiceQuery->m_bLegacyQuery) {
break;
}
pServiceQuery = pServiceQuery->m_pNext;
}
return pServiceQuery;
}
/*
MDNSResponder::_releaseServiceQueries
*/
bool MDNSResponder::_releaseServiceQueries(void) {
while (m_pServiceQueries) {
stcMDNSServiceQuery* pNext = m_pServiceQueries->m_pNext;
delete m_pServiceQueries;
m_pServiceQueries = pNext;
}
return true;
}
/*
MDNSResponder::_findNextServiceQueryByServiceType
*/
MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findNextServiceQueryByServiceType(
const stcMDNS_RRDomain& p_ServiceTypeDomain, const stcMDNSServiceQuery* p_pPrevServiceQuery) {
stcMDNSServiceQuery* pMatchingServiceQuery = 0;
stcMDNSServiceQuery* pServiceQuery
= (p_pPrevServiceQuery ? p_pPrevServiceQuery->m_pNext : m_pServiceQueries);
while (pServiceQuery) {
if (p_ServiceTypeDomain == pServiceQuery->m_ServiceTypeDomain) {
pMatchingServiceQuery = pServiceQuery;
break;
}
pServiceQuery = pServiceQuery->m_pNext;
}
return pMatchingServiceQuery;
}
/*
HOSTNAME
*/
/*
MDNSResponder::_setHostname
*/
bool MDNSResponder::_setHostname(const char* p_pcHostname) {
// DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _allocHostname (%s)\n"),
// p_pcHostname););
bool bResult = false;
_releaseHostname();
size_t stLength = 0;
if ((p_pcHostname)
&& (MDNS_DOMAIN_LABEL_MAXLENGTH
>= (stLength = strlen(p_pcHostname)))) { // char max size for a single label
// Copy in hostname characters as lowercase
if ((bResult = (0 != (m_pcHostname = new char[stLength + 1])))) {
#ifdef MDNS_FORCE_LOWERCASE_HOSTNAME
size_t i = 0;
for (; i < stLength; ++i) {
m_pcHostname[i]
= (isupper(p_pcHostname[i]) ? tolower(p_pcHostname[i]) : p_pcHostname[i]);
}
m_pcHostname[i] = 0;
#else
strncpy(m_pcHostname, p_pcHostname, (stLength + 1));
#endif
}
}
return bResult;
}
/*
MDNSResponder::_releaseHostname
*/
bool MDNSResponder::_releaseHostname(void) {
if (m_pcHostname) {
delete[] m_pcHostname;
m_pcHostname = 0;
}
return true;
}
/*
SERVICE
*/
/*
MDNSResponder::_allocService
*/
MDNSResponder::stcMDNSService* MDNSResponder::_allocService(const char* p_pcName,
const char* p_pcService,
const char* p_pcProtocol,
uint16_t p_u16Port) {
stcMDNSService* pService = 0;
if (((!p_pcName) || (MDNS_DOMAIN_LABEL_MAXLENGTH >= strlen(p_pcName))) && (p_pcService)
&& (MDNS_SERVICE_NAME_LENGTH >= strlen(p_pcService)) && (p_pcProtocol)
&& (MDNS_SERVICE_PROTOCOL_LENGTH >= strlen(p_pcProtocol)) && (p_u16Port)
&& (0 != (pService = new stcMDNSService))
&& (pService->setName(p_pcName ? : m_pcHostname)) && (pService->setService(p_pcService))
&& (pService->setProtocol(p_pcProtocol))) {
pService->m_bAutoName = (0 == p_pcName);
pService->m_u16Port = p_u16Port;
// Add to list (or start list)
pService->m_pNext = m_pServices;
m_pServices = pService;
}
return pService;
}
/*
MDNSResponder::_releaseService
*/
bool MDNSResponder::_releaseService(MDNSResponder::stcMDNSService* p_pService) {
bool bResult = false;
if (p_pService) {
stcMDNSService* pPred = m_pServices;
while ((pPred) && (pPred->m_pNext != p_pService)) {
pPred = pPred->m_pNext;
}
if (pPred) {
pPred->m_pNext = p_pService->m_pNext;
delete p_pService;
bResult = true;
} else { // No predecessor
if (m_pServices == p_pService) {
m_pServices = p_pService->m_pNext;
delete p_pService;
bResult = true;
} else {
DEBUG_EX_ERR(
DEBUG_OUTPUT.println("[MDNSResponder] _releaseService: INVALID service!"););
}
}
}
return bResult;
}
/*
MDNSResponder::_releaseServices
*/
bool MDNSResponder::_releaseServices(void) {
stcMDNSService* pService = m_pServices;
while (pService) {
_releaseService(pService);
pService = m_pServices;
}
return true;
}
/*
MDNSResponder::_findService
*/
MDNSResponder::stcMDNSService* MDNSResponder::_findService(const char* p_pcName,
const char* p_pcService,
const char* p_pcProtocol) {
stcMDNSService* pService = m_pServices;
while (pService) {
if ((0 == strcmp(pService->m_pcName, p_pcName))
&& (0 == strcmp(pService->m_pcService, p_pcService))
&& (0 == strcmp(pService->m_pcProtocol, p_pcProtocol))) {
break;
}
pService = pService->m_pNext;
}
return pService;
}
/*
MDNSResponder::_findService
*/
MDNSResponder::stcMDNSService*
MDNSResponder::_findService(const MDNSResponder::hMDNSService p_hService) {
stcMDNSService* pService = m_pServices;
while (pService) {
if (p_hService == (hMDNSService)pService) {
break;
}
pService = pService->m_pNext;
}
return pService;
}
/*
SERVICE TXT
*/
/*
MDNSResponder::_allocServiceTxt
*/
MDNSResponder::stcMDNSServiceTxt*
MDNSResponder::_allocServiceTxt(MDNSResponder::stcMDNSService* p_pService, const char* p_pcKey,
const char* p_pcValue, bool p_bTemp) {
stcMDNSServiceTxt* pTxt = 0;
if ((p_pService) && (p_pcKey)
&& (MDNS_SERVICE_TXT_MAXLENGTH > (p_pService->m_Txts.length() + 1 + // Length byte
(p_pcKey ? strlen(p_pcKey) : 0) + 1 + // '='
(p_pcValue ? strlen(p_pcValue) : 0)))) {
pTxt = new stcMDNSServiceTxt;
if (pTxt) {
size_t stLength = (p_pcKey ? strlen(p_pcKey) : 0);
pTxt->m_pcKey = new char[stLength + 1];
if (pTxt->m_pcKey) {
strncpy(pTxt->m_pcKey, p_pcKey, stLength);
pTxt->m_pcKey[stLength] = 0;
}
if (p_pcValue) {
stLength = (p_pcValue ? strlen(p_pcValue) : 0);
pTxt->m_pcValue = new char[stLength + 1];
if (pTxt->m_pcValue) {
strncpy(pTxt->m_pcValue, p_pcValue, stLength);
pTxt->m_pcValue[stLength] = 0;
}
}
pTxt->m_bTemp = p_bTemp;
// Add to list (or start list)
p_pService->m_Txts.add(pTxt);
}
}
return pTxt;
}
/*
MDNSResponder::_releaseServiceTxt
*/
bool MDNSResponder::_releaseServiceTxt(MDNSResponder::stcMDNSService* p_pService,
MDNSResponder::stcMDNSServiceTxt* p_pTxt) {
return ((p_pService) && (p_pTxt) && (p_pService->m_Txts.remove(p_pTxt)));
}
/*
MDNSResponder::_updateServiceTxt
*/
MDNSResponder::stcMDNSServiceTxt*
MDNSResponder::_updateServiceTxt(MDNSResponder::stcMDNSService* p_pService,
MDNSResponder::stcMDNSServiceTxt* p_pTxt,
const char* p_pcValue, bool p_bTemp) {
if ((p_pService) && (p_pTxt)
&& (MDNS_SERVICE_TXT_MAXLENGTH
> (p_pService->m_Txts.length() - (p_pTxt->m_pcValue ? strlen(p_pTxt->m_pcValue) : 0)
+ (p_pcValue ? strlen(p_pcValue) : 0)))) {
p_pTxt->update(p_pcValue);
p_pTxt->m_bTemp = p_bTemp;
}
return p_pTxt;
}
/*
MDNSResponder::_findServiceTxt
*/
MDNSResponder::stcMDNSServiceTxt*
MDNSResponder::_findServiceTxt(MDNSResponder::stcMDNSService* p_pService, const char* p_pcKey) {
return (p_pService ? p_pService->m_Txts.find(p_pcKey) : 0);
}
/*
MDNSResponder::_findServiceTxt
*/
MDNSResponder::stcMDNSServiceTxt*
MDNSResponder::_findServiceTxt(MDNSResponder::stcMDNSService* p_pService, const hMDNSTxt p_hTxt) {
return (((p_pService) && (p_hTxt)) ? p_pService->m_Txts.find((stcMDNSServiceTxt*)p_hTxt)
: 0);
}
/*
MDNSResponder::_addServiceTxt
*/
MDNSResponder::stcMDNSServiceTxt*
MDNSResponder::_addServiceTxt(MDNSResponder::stcMDNSService* p_pService, const char* p_pcKey,
const char* p_pcValue, bool p_bTemp) {
stcMDNSServiceTxt* pResult = 0;
if ((p_pService) && (p_pcKey) && (strlen(p_pcKey))) {
stcMDNSServiceTxt* pTxt = p_pService->m_Txts.find(p_pcKey);
if (pTxt) {
pResult = _updateServiceTxt(p_pService, pTxt, p_pcValue, p_bTemp);
} else {
pResult = _allocServiceTxt(p_pService, p_pcKey, p_pcValue, p_bTemp);
}
}
return pResult;
}
MDNSResponder::stcMDNSServiceTxt*
MDNSResponder::_answerKeyValue(const hMDNSServiceQuery p_hServiceQuery,
const uint32_t p_u32AnswerIndex) {
stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery);
stcMDNSServiceQuery::stcAnswer* pSQAnswer
= (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
// Fill m_pcTxts (if not already done)
return (pSQAnswer) ? pSQAnswer->m_Txts.m_pTxts : 0;
}
/*
MDNSResponder::_collectServiceTxts
*/
bool MDNSResponder::_collectServiceTxts(MDNSResponder::stcMDNSService& p_rService) {
// Call Dynamic service callbacks
if (m_fnServiceTxtCallback) {
m_fnServiceTxtCallback((hMDNSService)&p_rService);
}
if (p_rService.m_fnTxtCallback) {
p_rService.m_fnTxtCallback((hMDNSService)&p_rService);
}
return true;
}
/*
MDNSResponder::_releaseTempServiceTxts
*/
bool MDNSResponder::_releaseTempServiceTxts(MDNSResponder::stcMDNSService& p_rService) {
return (p_rService.m_Txts.removeTempTxts());
}
/*
MISC
*/
#ifdef DEBUG_ESP_MDNS_RESPONDER
/*
MDNSResponder::_printRRDomain
*/
bool MDNSResponder::_printRRDomain(const MDNSResponder::stcMDNS_RRDomain& p_RRDomain) const {
// DEBUG_OUTPUT.printf_P(PSTR("Domain: "));
const char* pCursor = p_RRDomain.m_acName;
uint8_t u8Length = *pCursor++;
if (u8Length) {
while (u8Length) {
for (uint8_t u = 0; u < u8Length; ++u) {
DEBUG_OUTPUT.printf_P(PSTR("%c"), *(pCursor++));
}
u8Length = *pCursor++;
if (u8Length) {
DEBUG_OUTPUT.printf_P(PSTR("."));
}
}
} else { // empty domain
DEBUG_OUTPUT.printf_P(PSTR("-empty-"));
}
// DEBUG_OUTPUT.printf_P(PSTR("\n"));
return true;
}
/*
MDNSResponder::_printRRAnswer
*/
bool MDNSResponder::_printRRAnswer(const MDNSResponder::stcMDNS_RRAnswer& p_RRAnswer) const {
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] RRAnswer: "));
_printRRDomain(p_RRAnswer.m_Header.m_Domain);
DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X TTL:%u, "),
p_RRAnswer.m_Header.m_Attributes.m_u16Type,
p_RRAnswer.m_Header.m_Attributes.m_u16Class, p_RRAnswer.m_u32TTL);
switch (p_RRAnswer.m_Header.m_Attributes.m_u16Type
& (~0x8000)) { // Topmost bit might carry 'cache flush' flag
#ifdef MDNS_IP4_SUPPORT
case DNS_RRTYPE_A:
DEBUG_OUTPUT.printf_P(
PSTR("A IP:%s"),
((const stcMDNS_RRAnswerA*)&p_RRAnswer)->m_IPAddress.toString().c_str());
break;
#endif
case DNS_RRTYPE_PTR:
DEBUG_OUTPUT.printf_P(PSTR("PTR "));
_printRRDomain(((const stcMDNS_RRAnswerPTR*)&p_RRAnswer)->m_PTRDomain);
break;
case DNS_RRTYPE_TXT: {
size_t stTxtLength = ((const stcMDNS_RRAnswerTXT*)&p_RRAnswer)->m_Txts.c_strLength();
char* pTxts = new char[stTxtLength];
if (pTxts) {
((/*const c_str()!!*/ stcMDNS_RRAnswerTXT*)&p_RRAnswer)->m_Txts.c_str(pTxts);
DEBUG_OUTPUT.printf_P(PSTR("TXT(%zu) %s"), stTxtLength, pTxts);
delete[] pTxts;
}
break;
}
#ifdef MDNS_IP6_SUPPORT
case DNS_RRTYPE_AAAA:
DEBUG_OUTPUT.printf_P(
PSTR("AAAA IP:%s"),
((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str());
break;
#endif
case DNS_RRTYPE_SRV:
DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "),
((const stcMDNS_RRAnswerSRV*)&p_RRAnswer)->m_u16Port);
_printRRDomain(((const stcMDNS_RRAnswerSRV*)&p_RRAnswer)->m_SRVDomain);
break;
default:
DEBUG_OUTPUT.printf_P(PSTR("generic "));
break;
}
DEBUG_OUTPUT.printf_P(PSTR("\n"));
return true;
}
#endif
} // namespace MDNSImplementation
} // namespace esp8266
+190
View File
@@ -0,0 +1,190 @@
/*
LEAmDNS_Priv.h
License (MIT license):
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 MDNS_PRIV_H
#define MDNS_PRIV_H
namespace esp8266 {
/*
LEAmDNS
*/
namespace MDNSImplementation {
// Enable class debug functions
#define ESP_8266_MDNS_INCLUDE
//#define DEBUG_ESP_MDNS_RESPONDER
#if !defined(DEBUG_ESP_MDNS_RESPONDER) && defined(DEBUG_ESP_MDNS)
#define DEBUG_ESP_MDNS_RESPONDER
#endif
//
// If ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE is defined, the mDNS responder ignores a successful
// probing This allows to drive the responder in a environment, where 'update()' isn't called in the
// loop
//#define ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE
// Enable/disable debug trace macros
#if defined(DEBUG_ESP_PORT) && defined(DEBUG_ESP_MDNS_RESPONDER)
#define DEBUG_ESP_MDNS_INFO
#define DEBUG_ESP_MDNS_ERR
#define DEBUG_ESP_MDNS_TX
#define DEBUG_ESP_MDNS_RX
#endif
#ifdef DEBUG_ESP_MDNS_RESPONDER
#ifdef DEBUG_ESP_MDNS_INFO
#define DEBUG_EX_INFO(A) A
#else
#define DEBUG_EX_INFO(A)
#endif
#ifdef DEBUG_ESP_MDNS_ERR
#define DEBUG_EX_ERR(A) A
#else
#define DEBUG_EX_ERR(A)
#endif
#ifdef DEBUG_ESP_MDNS_TX
#define DEBUG_EX_TX(A) A
#else
#define DEBUG_EX_TX(A)
#endif
#ifdef DEBUG_ESP_MDNS_RX
#define DEBUG_EX_RX(A) A
#else
#define DEBUG_EX_RX(A)
#endif
#ifdef DEBUG_ESP_PORT
#define DEBUG_OUTPUT DEBUG_ESP_PORT
#else
#define DEBUG_OUTPUT Serial
#endif
#else
#define DEBUG_EX_INFO(A) \
do \
{ \
(void)0; \
} while (0)
#define DEBUG_EX_ERR(A) \
do \
{ \
(void)0; \
} while (0)
#define DEBUG_EX_TX(A) \
do \
{ \
(void)0; \
} while (0)
#define DEBUG_EX_RX(A) \
do \
{ \
(void)0; \
} while (0)
#endif
/* already defined in lwIP ('lwip/prot/dns.h')
#ifdef MDNS_IP4_SUPPORT
#define DNS_MQUERY_IPV4_GROUP_INIT (IPAddress(224, 0, 0, 251)) // ip_addr_t
v4group = DNS_MQUERY_IPV4_GROUP_INIT #endif #ifdef MDNS_IP6_SUPPORT #define
DNS_MQUERY_IPV6_GROUP_INIT IPADDR6_INIT_HOST(0xFF020000,0,0,0xFB) // ip_addr_t v6group =
DNS_MQUERY_IPV6_GROUP_INIT #endif*/
//#define MDNS_MULTICAST_PORT 5353
/*
This is NOT the TTL (Time-To-Live) for MDNS records, but the
subnet level distance MDNS records should travel.
1 sets the subnet distance to 'local', which is default for MDNS.
(Btw.: 255 would set it to 'as far as possible' -> internet)
However, RFC 3171 seems to force 255 instead
*/
#define MDNS_MULTICAST_TTL 255 /*1*/
/*
This is the MDNS record TTL
Host level records are set to 2min (120s)
service level records are set to 75min (4500s)
*/
#define MDNS_HOST_TTL 120
#define MDNS_SERVICE_TTL 4500
/*
Compressed labels are flagged by the two topmost bits of the length byte being set
*/
#define MDNS_DOMAIN_COMPRESS_MARK 0xC0
/*
Avoid endless recursion because of malformed compressed labels
*/
#define MDNS_DOMAIN_MAX_REDIRCTION 6
/*
Default service priority and weight in SRV answers
*/
#define MDNS_SRV_PRIORITY 0
#define MDNS_SRV_WEIGHT 0
/*
Delay between and number of probes for host and service domains
Delay between and number of announces for host and service domains
Delay between and number of service queries; the delay is multiplied by the resent number in
'_checkServiceQueryCache'
*/
#define MDNS_PROBE_DELAY 250
#define MDNS_PROBE_COUNT 3
#define MDNS_ANNOUNCE_DELAY 1000
#define MDNS_ANNOUNCE_COUNT 8
#define MDNS_DYNAMIC_QUERY_RESEND_COUNT 5
#define MDNS_DYNAMIC_QUERY_RESEND_DELAY 5000
/*
Force host domain to use only lowercase letters
*/
//#define MDNS_FORCE_LOWERCASE_HOSTNAME
/*
Enable/disable the usage of the F() macro in debug trace printf calls.
There needs to be an PGM compatible printf function to use this.
USE_PGM_PRINTF and F
*/
#define USE_PGM_PRINTF
#ifdef USE_PGM_PRINTF
#else
#ifdef F
#undef F
#endif
#define F(A) A
#endif
} // namespace MDNSImplementation
} // namespace esp8266
// Include the main header, so the submodlues only need to include this header
#include "LEAmDNS.h"
#endif // MDNS_PRIV_H
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+30
View File
@@ -0,0 +1,30 @@
/*
LEAmDNS_Priv.h
License (MIT license):
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 MDNS_LWIPDEFS_H
#define MDNS_LWIPDEFS_H
#include <lwip/prot/dns.h> // DNS_RRTYPE_xxx, DNS_MQUERY_PORT
#endif // MDNS_LWIPDEFS_H
+20
View File
@@ -0,0 +1,20 @@
#######################################
# Syntax Coloring Map For Ultrasound
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
LittleFS KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
format KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
+27
View File
@@ -0,0 +1,27 @@
#######################################
# Syntax Coloring Map For Ultrasound
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
MD5Builder KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
add KEYWORD2
addHexString KEYWORD2
addStream KEYWORD2
calculate KEYWORD2
getBytes KEYWORD2
getChars KEYWORD2
toString KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
+11
View File
@@ -0,0 +1,11 @@
name=MD5Builder
version=1.0.0
author=Earle F. Philhower, III <earlephilhower@yahoo.com>
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
sentence=Allows generating MD5 hashes of streams
paragraph=Allows generating MD5 hashes of streams
category=Data Processing
url=https://github.com/earlephilhower/arduino-pico
architectures=rp2040
dot_a_linkage=true
includes=MD5Builder.h
+117
View File
@@ -0,0 +1,117 @@
/*
MD5Builder - Simple MD5 hash calculations
Updated for the Pico by Earle F. Philhower, III
Modified from the ESP8266 version which is
Copyright (c) 2015 Hristo Gochkov. 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 <Arduino.h>
#include <MD5Builder.h>
#include <memory>
static uint8_t hex_char_to_byte(uint8_t c) {
return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) :
(c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) :
(c >= '0' && c <= '9') ? (c - (uint8_t)'0') : 0;
}
void MD5Builder::begin(void) {
memset(_buf, 0x00, 16);
br_md5_init(&_ctx);
}
void MD5Builder::add(const uint8_t * data, const uint16_t len) {
br_md5_update(&_ctx, data, len);
}
void MD5Builder::addHexString(const char * data) {
uint16_t i, len = strlen(data);
auto tmp = std::unique_ptr<uint8_t[]> {new (std::nothrow) uint8_t[len / 2]};
if (!tmp) {
return;
}
for (i = 0; i < len; i += 2) {
uint8_t high = hex_char_to_byte(data[i]);
uint8_t low = hex_char_to_byte(data[i + 1]);
tmp[i / 2] = (high & 0x0F) << 4 | (low & 0x0F);
}
add(tmp.get(), len / 2);
}
bool MD5Builder::addStream(Stream &stream, const size_t maxLen) {
const int buf_size = 512;
int maxLengthLeft = maxLen;
auto buf = std::unique_ptr<uint8_t[]> {new (std::nothrow) uint8_t[buf_size]};
if (!buf) {
return false;
}
int bytesAvailable = stream.available();
while ((bytesAvailable > 0) && (maxLengthLeft > 0)) {
// determine number of bytes to read
int readBytes = bytesAvailable;
if (readBytes > maxLengthLeft) {
readBytes = maxLengthLeft; // read only until max_len
}
if (readBytes > buf_size) {
readBytes = buf_size; // not read more the buffer can handle
}
// read data and check if we got something
int numBytesRead = stream.readBytes(buf.get(), readBytes);
if (numBytesRead < 1) {
return false;
}
// Update MD5 with buffer payload
br_md5_update(&_ctx, buf.get(), numBytesRead);
// update available number of bytes
maxLengthLeft -= numBytesRead;
bytesAvailable = stream.available();
}
return true;
}
void MD5Builder::calculate(void) {
br_md5_out(&_ctx, _buf);
}
void MD5Builder::getBytes(uint8_t * output) const {
memcpy(output, _buf, 16);
}
void MD5Builder::getChars(char * output) const {
for (uint8_t i = 0; i < 16; i++) {
sprintf(output + (i * 2), "%02x", _buf[i]);
}
}
String MD5Builder::toString(void) const {
char out[33];
getChars(out);
return String(out);
}
+59
View File
@@ -0,0 +1,59 @@
/*
MD5Builder - Simple MD5 hash calculations
Updated for the Pico by Earle F. Philhower, III
Modified from the ESP8266 version which is
Copyright (c) 2015 Hristo Gochkov. 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
#include <api/String.h>
#include <Stream.h>
#include <bearssl/bearssl_hash.h>
class MD5Builder {
private:
br_md5_context _ctx;
uint8_t _buf[16];
public:
void begin(void);
void add(const uint8_t * data, const uint16_t len);
void add(const char * data) {
add((const uint8_t*)data, strlen(data));
}
void add(char * data) {
add((const char*)data);
}
void add(const String& data) {
add(data.c_str());
}
void addHexString(const char * data);
void addHexString(char * data) {
addHexString((const char*)data);
}
void addHexString(const String& data) {
addHexString(data.c_str());
}
bool addStream(Stream & stream, const size_t maxLen);
void calculate(void);
void getBytes(uint8_t * output) const;
void getChars(char * output) const;
String toString(void) const;
};
@@ -0,0 +1,42 @@
// This example overwrites itself with a serial blinker sketch using OTA
// In general, you will get a file from the Internet, over a serial port, etc.
// and not include it in a header like we do here for simplicity.
//
// The blinker.BIN file was compressed with `gzip -9` and will be expanded
// during OTA
//
// You need to have at least 256K of filesystem configured in
// Tools->Flash Size
//
// Released to the public domain August 2022 by Earle F. Philhower, III
#include <PicoOTA.h>
#include <LittleFS.h>
#include "blink_100_1000.h"
void setup() {
Serial.begin(115200);
delay(5000);
Serial.printf("Writing OTA image of blinker...");
LittleFS.begin();
File f = LittleFS.open("blink.bin.gz", "w");
if (sizeof(blink_gz) != f.write(blink_gz, sizeof(blink_gz))) {
Serial.printf("Unable to write OTA binary. Is the filesystem size set?\n");
return;
}
f.close();
Serial.printf("done\n\n");
Serial.printf("Programming OTA commands...");
picoOTA.begin();
picoOTA.addFile("blink.bin.gz");
picoOTA.commit();
LittleFS.end();
Serial.printf("done\n\n");
Serial.printf("Rebooting in 5 seconds, should begin blinker instead of this app...\n");
delay(5000);
rp2040.reboot();
}
void loop() {
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,39 @@
// This example overwrites itself with a serial blinker sketch using OTA
// In general, you will get a file from the Internet, over a serial port, etc.
// and not include it in a header like we do here for simplicity.
//
// You need to have at least 256K of filesystem configured in
// Tools->Flash Size
//
// Released to the public domain August 2022 by Earle F. Philhower, III
#include <PicoOTA.h>
#include <LittleFS.h>
#include "blink_100_1000.h"
void setup() {
Serial.begin(115200);
delay(5000);
Serial.printf("Writing OTA image of blinker...");
LittleFS.begin();
File f = LittleFS.open("blink.bin", "w");
if (sizeof(blink) != f.write(blink, sizeof(blink))) {
Serial.printf("Unable to write OTA binary. Is the filesystem size set?\n");
return;
}
f.close();
Serial.printf("done\n\n");
Serial.printf("Programming OTA commands...");
picoOTA.begin();
picoOTA.addFile("blink.bin");
picoOTA.commit();
LittleFS.end();
Serial.printf("done\n\n");
Serial.printf("Rebooting in 5 seconds, should begin blinker instead of this app...\n");
delay(5000);
rp2040.reboot();
}
void loop() {
}
File diff suppressed because it is too large Load Diff
+21
View File
@@ -0,0 +1,21 @@
#######################################
# Syntax Coloring Map For Ultrasound
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
picoOTA KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
addFile KEYWORD1
commit KEYWORD1
#######################################
# Constants (LITERAL1)
#######################################

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