Compare commits

...
18 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
71 changed files with 4882 additions and 67 deletions
+2 -2
View File
@@ -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
+3 -1
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;
+4 -1
View File
@@ -314,7 +314,10 @@ public:
}
void reboot() {
watchdog_reboot(0, 0, 100);
watchdog_reboot(0, 0, 10);
while (1) {
continue;
}
}
inline void restart() {
+2 -2
View File
@@ -1,5 +1,5 @@
#pragma once
#define ARDUINO_PICO_MAJOR 2
#define ARDUINO_PICO_MINOR 4
#define ARDUINO_PICO_REVISION 0
#define ARDUINO_PICO_VERSION_STR "2.4.0"
#define ARDUINO_PICO_REVISION 1
#define ARDUINO_PICO_VERSION_STR "2.4.1"
@@ -36,7 +36,6 @@
#define CYW43_WL_GPIO_LED_PIN 0
#endif
volatile bool __inLWIP = false;
// note same code
+2 -2
View File
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
# built documents.
#
# The short X.Y version.
version = u'2.4.0'
version = u'2.4.1'
# The full version, including alpha/beta/rc tags.
release = u'2.4.0'
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.
+2
View File
@@ -50,6 +50,8 @@ 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>
+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
-------------------------------------
+1 -1
View File
@@ -233,7 +233,7 @@ A firmware file is uploaded via any method (Ethernet, WiFi, serial ZModem, etc.)
The ROM layout consists of:
... code:
.. code:: cpp
[boot2.S] [OTA Bootloader] [0-pad] [OTA partition table] [Main sketch] [LittleFS filesystem] [EEPROM]
+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.
+2
View File
@@ -2,6 +2,8 @@
# Syntax Coloring Map
#######################################
Arduino KEYWORD3 RESERVED_WORD
#######################################
# Datatypes (KEYWORD1)
#######################################
+13 -9
View File
@@ -243,6 +243,19 @@ void ArduinoOTAClass::_onRx() {
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");
@@ -261,15 +274,6 @@ void ArduinoOTAClass::_runUpdate() {
_state = OTA_IDLE;
return;
}
if (!LittleFS.begin()) {
_udp_ota->append("ERR: ", 5);
_udp_ota->append("nofilesystem", 6);
_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);
+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;
}
@@ -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
+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
+1 -1
View File
@@ -1100,7 +1100,7 @@ protected:
};
public:
uint16_t m_u16ID; // Query ID (used only in lagacy queries)
uint16_t m_u16ID; // Query ID (used only in legacy queries)
stcMDNS_RRQuestion* m_pQuestions; // A list of queries
uint8_t m_u8HostReplyMask; // Flags for reply components/answers
bool m_bLegacyQuery; // Flag: Legacy query
+1 -1
View File
@@ -1980,7 +1980,7 @@ uint8_t MDNSResponder::_replyMaskForHost(const MDNSResponder::stcMDNS_RRHeader&
#ifdef MDNS_IP6_SUPPORT
// TODO
#endif
} // Address qeuest
} // Address quest
stcMDNS_RRDomain hostDomain;
if ((_buildDomainForHost(m_pcHostname, hostDomain))
+6 -2
View File
@@ -32,8 +32,12 @@
class SDClass {
public:
boolean begin(uint8_t csPin, uint32_t cfg = SPI_HALF_SPEED) {
SDFS.setConfig(SDFSConfig(csPin, cfg));
boolean begin(uint8_t csPin, HardwareSPI &spi) {
SDFS.setConfig(SDFSConfig(csPin, SPI_HALF_SPEED, spi));
return (boolean)SDFS.begin();
}
boolean begin(uint8_t csPin, uint32_t cfg = SPI_HALF_SPEED, HardwareSPI &spi = SPI) {
SDFS.setConfig(SDFSConfig(csPin, cfg, spi));
return (boolean)SDFS.begin();
}
+10 -4
View File
@@ -45,7 +45,7 @@ class SDFSConfig : public FSConfig {
public:
static constexpr uint32_t FSId = 0x53444653;
SDFSConfig(uint8_t csPin = 4, uint32_t spi = SD_SCK_MHZ(10)) : FSConfig(FSId, false), _csPin(csPin), _part(0), _spiSettings(spi) { }
SDFSConfig(uint8_t csPin = 4, uint32_t spi = SD_SCK_MHZ(10), HardwareSPI &port = SPI) : FSConfig(FSId, false), _csPin(csPin), _part(0), _spiSettings(spi), _spi(&port) { }
SDFSConfig setAutoFormat(bool val = true) {
_autoFormat = val;
@@ -55,10 +55,14 @@ public:
_csPin = pin;
return *this;
}
SDFSConfig setSPI(uint32_t spi) {
SDFSConfig setSPISpeed(uint32_t spi) {
_spiSettings = spi;
return *this;
}
SDFSConfig setSPI(HardwareSPI &spi) {
_spi = &spi;
return true;
}
SDFSConfig setPart(uint8_t part) {
_part = part;
return *this;
@@ -68,6 +72,7 @@ public:
uint8_t _csPin;
uint8_t _part;
uint32_t _spiSettings;
HardwareSPI *_spi;
};
class SDFSImpl : public FSImpl {
@@ -146,10 +151,11 @@ public:
if (_mounted) {
return true;
}
_mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings);
SdSpiConfig ssc(_cfg._csPin, SHARED_SPI, _cfg._spiSettings, _cfg._spi);
_mounted = _fs.begin(ssc);
if (!_mounted && _cfg._autoFormat) {
format();
_mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings);
_mounted = _fs.begin(ssc);
}
FsDateTime::setCallback(dateTimeCB);
return _mounted;
+20 -15
View File
@@ -25,8 +25,6 @@
#include <hardware/flash.h>
#include <PicoOTA.h>
#define DEBUG_UPDATER Serial
#include <Updater_Signing.h>
#ifndef ARDUINO_SIGNING
#define ARDUINO_SIGNING 0
@@ -200,7 +198,7 @@ bool UpdaterClass::end(bool evenIfRemaining) {
int binSize = _size;
if (expectedSigLen > 0) {
_size -= (sigLen + sizeof(uint32_t) /* The siglen word */);
binSize -= (sigLen + sizeof(uint32_t) /* The siglen word */);
}
_hash->begin();
#ifdef DEBUG_UPDATER
@@ -414,30 +412,37 @@ void UpdaterClass::_setError(int error) {
}
void UpdaterClass::printError(Print &out) {
out.printf_P(PSTR("ERROR[%u]: "), _error);
String err;
err = "ERROR[";
err += _error;
err += "]: ";
if (_error == UPDATE_ERROR_OK) {
out.println(F("No Error"));
err += "No Error";
} else if (_error == UPDATE_ERROR_WRITE) {
out.println(F("Flash Write Failed"));
err += "Flash Write Failed";
} else if (_error == UPDATE_ERROR_ERASE) {
out.println(F("Flash Erase Failed"));
err += "Flash Erase Failed";
} else if (_error == UPDATE_ERROR_READ) {
out.println(F("Flash Read Failed"));
err += "Flash Read Failed";
} else if (_error == UPDATE_ERROR_SPACE) {
out.println(F("Not Enough Space"));
err += "Not Enough Space";
} else if (_error == UPDATE_ERROR_SIZE) {
out.println(F("Bad Size Given"));
err += "Bad Size Given";
} else if (_error == UPDATE_ERROR_STREAM) {
out.println(F("Stream Read Timeout"));
err += "Stream Read Timeout";
} else if (_error == UPDATE_ERROR_NO_DATA) {
out.println(F("No data supplied"));
err += "No data supplied";
} else if (_error == UPDATE_ERROR_MD5) {
out.printf_P(PSTR("MD5 Failed: expected:%s, calculated:%s\n"), _target_md5.c_str(), _md5.toString().c_str());
err += "MD5 Failed: expected:";
err += _target_md5.c_str();
err += " calculated:";
err += _md5.toString();
} else if (_error == UPDATE_ERROR_SIGN) {
out.println(F("Signature verification failed"));
err += "Signature verification failed";
} else {
out.println(F("UNKNOWN"));
err += "UNKNOWN";
}
out.println(err.c_str());
}
UpdaterClass Update;
@@ -16,6 +16,8 @@ const char* password = STAPSK;
const char* host = "djxmmx.net";
const uint16_t port = 17;
WiFiMulti multi;
void setup() {
Serial.begin(115200);
@@ -26,11 +28,12 @@ void setup() {
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
multi.addAP(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
if (multi.run() != WL_CONNECTED) {
Serial.println("Unable to connect to network, rebooting in 10 seconds...");
delay(10000);
rp2040.reboot();
}
Serial.println("");
+22
View File
@@ -13,6 +13,7 @@ WiFiClient KEYWORD1
WiFiSSLClient KEYWORD1
WiFiServer KEYWORD1
WiFiUDP KEYWORD1
WiFiMulti KEYWORD1
NTP KEYWORD1
@@ -48,6 +49,7 @@ parsePacket KEYWORD2
remoteIP KEYWORD2
remotePort KEYWORD2
mode KEYWORD2
addAP KEYWORD2
beginAP KEYWORD2
beginEnterprise KEYWORD2
@@ -61,6 +63,26 @@ beginMulticast KEYWORD2
setTimeout KEYWORD2
waitSet 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)
+2 -1
View File
@@ -29,7 +29,8 @@
#include <string.h>
#include <Arduino.h>
#include "StackThunk.h"
//#include <Updater_Signing.h>
#include <Updater_Signing.h>
#ifndef ARDUINO_SIGNING
#define ARDUINO_SIGNING 0
#endif
+2
View File
@@ -12,4 +12,6 @@
#include "WiFiServerSecure.h"
#include "WiFiUdp.h"
#include "WiFiMulti.h"
#include "WiFiNTP.h"
+6 -1
View File
@@ -96,6 +96,8 @@ int WiFiClass::begin(const char* ssid, const char *passphrase) {
if (!_wifi.begin()) {
return WL_IDLE_STATUS;
}
// Enable CYW43 event debugging (make sure Debug Port is set)
//cyw43_state.trace_flags = 0xffff;
while (!_calledESP && ((millis() - start < (uint32_t)2 * _timeout)) && !connected()) {
delay(10);
}
@@ -152,7 +154,7 @@ uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase) {
#endif
bool WiFiClass::connected() {
return (_apMode && _wifiHWInitted) || (_wifi.connected() && localIP().isSet());
return (_apMode && _wifiHWInitted) || (_wifi.connected() && localIP().isSet() && (cyw43_wifi_link_status(&cyw43_state, _apMode ? 1 : 0) == CYW43_LINK_JOIN));
}
/* Change Ip configuration settings disabling the dhcp client
@@ -223,6 +225,9 @@ void WiFiClass::setDNS(IPAddress dns_server1, IPAddress dns_server2) {
void WiFiClass::setHostname(const char* name) {
_wifi.setHostname(name);
}
const char *WiFiClass::getHostname() {
return _wifi.getHostname();
}
/*
Disconnect from the network
+59
View File
@@ -91,6 +91,57 @@ public:
uint8_t beginAP(const char *ssid, const char* passphrase);
uint8_t beginAP(const char *ssid, const char* passphrase, uint8_t channel);
// ESP8266 compatible calls
bool softAP(const char* ssid, const char* psk = NULL, int channel = 1, int ssid_hidden = 0, int max_connection = 4) {
(void) ssid_hidden;
(void) max_connection;
return beginAP(ssid, psk, channel) == WL_CONNECTED;
}
bool softAP(const String& ssid, const String& psk = "", int channel = 1, int ssid_hidden = 0, int max_connection = 4) {
(void) ssid_hidden;
(void) max_connection;
if (psk != "") {
return beginAP(ssid.c_str(), psk.c_str(), channel) == WL_CONNECTED;
} else {
return beginAP(ssid.c_str(), channel) == WL_CONNECTED;
}
}
bool softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet) {
config(local_ip, local_ip, gateway, subnet);
return true;
}
bool softAPdisconnect(bool wifioff = false) {
(void) wifioff;
end();
return true;
}
uint8_t softAPgetStationNum();
IPAddress softAPIP() {
return localIP();
}
uint8_t* softAPmacAddress(uint8_t* mac) {
return macAddress(mac);
}
String softAPmacAddress(void) {
uint8_t mac[8];
macAddress(mac);
char buff[32];
sprintf(buff, "%02x:%02x:%02x:%02x:%02x:%02x", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
return String(buff);
}
String softAPSSID() {
return String(SSID());
}
// TODO - EAP is not supported by the driver. Maybe some way of user-level wap-supplicant in the future?
//uint8_t beginEnterprise(const char* ssid, const char* username, const char* password);
//uint8_t beginEnterprise(const char* ssid, const char* username, const char* password, const char* identity);
@@ -147,6 +198,7 @@ public:
*/
void setHostname(const char* name);
const char *getHostname();
/*
Disconnect from the network
@@ -163,6 +215,13 @@ public:
return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
*/
uint8_t* macAddress(uint8_t* mac);
String macAddress(void) {
uint8_t mac[8];
macAddress(mac);
char buff[32];
sprintf(buff, "%02x:%02x:%02x:%02x:%02x:%02x", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
return String(buff);
}
/*
Get the interface IP address.
-1
View File
@@ -23,7 +23,6 @@
#pragma once
#include <memory>
#include "WiFi.h"
#include "Print.h"
#include "Client.h"
#include "IPAddress.h"
@@ -1224,7 +1224,7 @@ bool WiFiClientSecureCtx::_connectSSL(const char* hostName) {
_x509_insecure = nullptr;
_x509_knownkey = nullptr;
// reduce timeout after successful handshake to fail fast if server stop accepting our data for whathever reason
// reduce timeout after successful handshake to fail fast if server stop accepting our data for whatever reason
if (ret) {
_timeout = 5000;
}
+106
View File
@@ -0,0 +1,106 @@
/*
WiFiMulti.cpp - Choose best RSSI and connect
Copyright (c) 2022 Earle F. Philhower, III
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified by Ivan Grokhotkov, January 2015 - esp8266 support
*/
#include "WiFi.h"
#include <string.h>
#include <algorithm>
WiFiMulti::WiFiMulti() {
}
WiFiMulti::~WiFiMulti() {
while (!_list.empty()) {
struct _AP ap = _list.front();
_list.pop_front();
free(ap.ssid);
free(ap.pass);
}
}
bool WiFiMulti::addAP(const char *ssid, const char *pass) {
struct _AP ap;
if (!ssid) {
return false;
}
ap.ssid = strdup(ssid);
if (!ap.ssid) {
return false;
}
if (pass) {
ap.pass = strdup(pass);
if (!ap.pass) {
free(ap.ssid);
return false;
}
} else {
ap.pass = nullptr;
}
DEBUGV("[WIFIMULTI] Adding: '%s' %s' to list\n", ap.ssid, ap.pass);
_list.push_front(ap);
return true;
}
uint8_t WiFiMulti::run(uint32_t to) {
// If we're already connected, don't re-scan/etc.
if (WiFi.status() == WL_CONNECTED) {
return WL_CONNECTED;
}
int cnt = WiFi.scanNetworks();
if (!cnt) {
return WL_DISCONNECTED;
}
// Find the highest RSSI network in our list. Probably more efficient searches, but the list
// of APs will have < 5 in > 99% of the cases so it's a don't care.
int maxRSSID = -999;
std::list<struct _AP>::iterator hit;
bool found = false;
for (int i = 0; i < cnt; i++) {
if (WiFi.RSSI(i) > maxRSSID) {
for (auto j = _list.begin(); j != _list.end(); j++) {
DEBUGV("[WIFIMULTI] Checking for '%s' at %d\n", WiFi.SSID(i), WiFi.RSSI(i));
if (!strcmp(j->ssid, WiFi.SSID(i))) {
hit = j;
maxRSSID = WiFi.RSSI(i);
found = true;
}
}
}
}
if (!found) {
return WL_DISCONNECTED;
}
// Connect!
DEBUGV("[WIFIMULTI] Connecting to '%s' and '%s'\n", hit->ssid, hit->pass);
uint32_t start = millis();
if (hit->pass) {
WiFi.begin(hit->ssid, hit->pass);
} else {
WiFi.begin(hit->ssid);
}
while (!WiFi.connected() && (millis() - start < to)) {
delay(5);
}
return WiFi.status();
}
+43
View File
@@ -0,0 +1,43 @@
/*
WiFiMulti.h - Choose best RSSI and connect
Copyright (c) 2022 Earle F. Philhower, III
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified by Ivan Grokhotkov, January 2015 - esp8266 support
*/
#pragma once
#include <list>
#include <stdint.h>
#include "wl_definitions.h"
class WiFiMulti {
public:
WiFiMulti();
~WiFiMulti();
bool addAP(const char *ssid, const char *pass = NULL);
uint8_t run(uint32_t to = 10000);
private:
struct _AP {
char *ssid;
char *pass;
};
std::list<struct _AP> _list;
};
+3 -2
View File
@@ -63,7 +63,7 @@
#define PORT_DHCP_SERVER (67)
#define PORT_DHCP_CLIENT (68)
#define DEFAULT_DNS MAKE_IP4(8, 8, 8, 8)
//#define DEFAULT_DNS MAKE_IP4(8, 8, 8, 8)
#define DEFAULT_LEASE_TIME_S (24 * 60 * 60) // in seconds
#define MAC_LEN (6)
@@ -276,9 +276,10 @@ static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p,
opt_write_n(&opt, DHCP_OPT_SERVER_ID, 4, ip_2_ip4(&d->ip));
opt_write_n(&opt, DHCP_OPT_SUBNET_MASK, 4, ip_2_ip4(&d->nm));
opt_write_n(&opt, DHCP_OPT_ROUTER, 4, ip_2_ip4(&d->ip)); // aka gateway; can have multiple addresses
opt_write_u32(&opt, DHCP_OPT_DNS, DEFAULT_DNS); // can have multiple addresses
opt_write_n(&opt, DHCP_OPT_DNS, 4, ip_2_ip4(&d->ip)); // can have multiple addresses
opt_write_u32(&opt, DHCP_OPT_IP_LEASE_TIME, DEFAULT_LEASE_TIME_S);
*opt++ = DHCP_OPT_END;
dhcp_socket_sendto(&d->udp, &dhcp_msg, opt - (uint8_t *)&dhcp_msg, 0xffffffff, PORT_DHCP_CLIENT);
ignore_request:
+1 -1
View File
@@ -43,7 +43,7 @@ extern "C" {
#define WL_IPV4_LENGTH 4
// Maximum size of a SSID list
#define WL_NETWORKS_LIST_MAXNUM 10
// Maxmium number of socket
// Maximum number of socket
#define WIFI_MAX_SOCK_NUM 10
// Socket not available constant
#define SOCK_NOT_AVAIL 255
@@ -26,6 +26,18 @@ extern "C" {
#include "pico/cyw43_arch.h"
#include <Arduino.h>
// From cyw43_ctrl.c
#define WIFI_JOIN_STATE_KIND_MASK (0x000f)
#define WIFI_JOIN_STATE_ACTIVE (0x0001)
#define WIFI_JOIN_STATE_FAIL (0x0002)
#define WIFI_JOIN_STATE_NONET (0x0003)
#define WIFI_JOIN_STATE_BADAUTH (0x0004)
#define WIFI_JOIN_STATE_AUTH (0x0200)
#define WIFI_JOIN_STATE_LINK (0x0400)
#define WIFI_JOIN_STATE_KEYED (0x0800)
#define WIFI_JOIN_STATE_ALL (0x0e01)
netif *CYW43::_netif = nullptr;
CYW43::CYW43(int8_t cs, arduino::SPIClass& spi, int8_t intrpin) {
@@ -124,6 +136,7 @@ extern "C" void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
if (CYW43::_netif) {
netif_set_link_down(CYW43::_netif);
}
self->wifi_join_state &= ~WIFI_JOIN_STATE_ACTIVE;
}
extern "C" int cyw43_tcpip_link_status(cyw43_t *self, int itf) {
@@ -1,5 +1,5 @@
/* Simple sketch to do something on a BOOTSEL press */
/* Releaed into the public domain */
/* Released into the public domain */
void setup() {
Serial.begin(115200);
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "framework-arduinopico",
"version": "1.20400.0",
"version": "1.20401.0",
"description": "Arduino Wiring-based Framework (RPi Pico RP2040)",
"keywords": [
"framework",
+2 -2
View File
@@ -20,7 +20,7 @@
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
name=Raspberry Pi RP2040 Boards
version=2.4.0
version=2.4.1
runtime.tools.pqt-gcc.path={runtime.platform.path}/system/arm-none-eabi
runtime.tools.pqt-python3.path={runtime.platform.path}/system/python3
@@ -110,7 +110,7 @@ recipe.hooks.sketch.prebuild.pattern="{runtime.tools.pqt-python3.path}/python3"
recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} {build.usbpid} {build.usbpwr} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {build.debug_port} {build.debug_level} {build.flags.optimize} {includes} "{source_file}" -o "{object_file}"
## Compile c++ files
recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} {build.usbpid} {build.usbpwr} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {build.debug_port} {build.debug_level} {build.flags.optimize} {includes} "{source_file}" -o "{object_file}"
recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" -I "{build.path}/core" {compiler.cpp.flags} {build.usbpid} {build.usbpwr} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {build.debug_port} {build.debug_level} {build.flags.optimize} {includes} "{source_file}" -o "{object_file}"
## Compile S files
recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} {build.usbpid} {build.usbpwr} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.debug_port} {build.debug_level} {includes} "{source_file}" -o "{object_file}"
+1 -1
View File
@@ -7,7 +7,7 @@ for dir in ./cores/rp2040 ./libraries/EEPROM ./libraries/I2S \
./libraries/WiFi ./libraries/lwIP_Ethernet ./libraries/lwIP_CYW43 \
./libraries/FreeRTOS/src ./libraries/LEAmDNS ./libraries/MD5Builder \
./libraries/PicoOTA ./libraries/SDFS ./libraries/ArduinoOTA \
./libraries/Updater; do
./libraries/Updater ./libraries/HTTPClient ./libraries/HTTPUpdate; do
find $dir -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" \) -a \! -path '*api*' -exec astyle --suffix=none --options=./tests/astyle_core.conf \{\} \;
find $dir -type f -name "*.ino" -exec astyle --suffix=none --options=./tests/astyle_examples.conf \{\} \;
done
+1 -3
View File
@@ -65,9 +65,7 @@ def compile(tmp_dir, sketch, cache, tools_dir, hardware_dir, ide_path, f, args):
'dbgport={dbgport},' \
'dbglvl={dbglvl},' \
'usbstack={usbstack}'.format(**vars(args))
if "/WiFi" in sketch:
fqbn = fqbn.replace("rpipico", "rpipicow")
if "/ArduinoOTA" in sketch:
if ("/WiFi" in sketch) or ("/ArduinoOTA" in sketch) or ("/HTTPClient" in sketch) or ('/HTTPUpdate' in sketch):
fqbn = fqbn.replace("rpipico", "rpipicow")
cmd += [fqbn]
cmd += ['-built-in-libraries', ide_path + '/libraries']