1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-08-07 00:04:36 +03:00

Merge branch 'master' into wifi_mesh_update_2.2

This commit is contained in:
aerlon
2019-09-17 20:32:41 +02:00
committed by GitHub
113 changed files with 2875 additions and 814 deletions

View File

@@ -13,8 +13,8 @@
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
// Fingerprint for demo URL, expires on June 2, 2019, needs to be updated well before this date
const uint8_t fingerprint[20] = {0x5A, 0xCF, 0xFE, 0xF0, 0xF1, 0xA6, 0xF4, 0x5F, 0xD2, 0x11, 0x11, 0xC6, 0x1D, 0x2F, 0x0E, 0xBC, 0x39, 0x8D, 0x50, 0xE0};
// Fingerprint for demo URL, expires on June 2, 2021, needs to be updated well before this date
const uint8_t fingerprint[20] = {0x40, 0xaf, 0x00, 0x6b, 0xec, 0x90, 0x22, 0x41, 0x8e, 0xa3, 0xad, 0xfa, 0x1a, 0xe8, 0x25, 0x41, 0x1d, 0x1a, 0x54, 0xb3};
ESP8266WiFiMulti WiFiMulti;

View File

@@ -225,6 +225,11 @@ bool HTTPClient::begin(String url, String httpsFingerprint)
return false;
}
_transportTraits = TransportTraitsPtr(new TLSTraits(httpsFingerprint));
if(!_transportTraits) {
DEBUG_HTTPCLIENT("[HTTP-Client][begin] could not create transport traits\n");
return false;
}
DEBUG_HTTPCLIENT("[HTTP-Client][begin] httpsFingerprint: %s\n", httpsFingerprint.c_str());
return true;
}
@@ -242,6 +247,11 @@ bool HTTPClient::begin(String url, const uint8_t httpsFingerprint[20])
return false;
}
_transportTraits = TransportTraitsPtr(new BearSSLTraits(httpsFingerprint));
if(!_transportTraits) {
DEBUG_HTTPCLIENT("[HTTP-Client][begin] could not create transport traits\n");
return false;
}
DEBUG_HTTPCLIENT("[HTTP-Client][begin] BearSSL-httpsFingerprint:");
for (size_t i=0; i < 20; i++) {
DEBUG_HTTPCLIENT(" %02x", httpsFingerprint[i]);
@@ -409,7 +419,7 @@ bool HTTPClient::begin(String host, uint16_t port, String uri, const uint8_t htt
*/
void HTTPClient::end(void)
{
disconnect();
disconnect(false);
clear();
_redirectCount = 0;
}
@@ -563,6 +573,7 @@ void HTTPClient::setRedirectLimit(uint16_t limit)
void HTTPClient::useHTTP10(bool useHTTP10)
{
_useHTTP10 = useHTTP10;
_reuse = !useHTTP10;
}
/**
@@ -980,7 +991,7 @@ int HTTPClient::writeToStream(Stream * stream)
return returnError(HTTPC_ERROR_ENCODING);
}
disconnect();
disconnect(true);
return ret;
}
@@ -996,7 +1007,7 @@ const String& HTTPClient::getString(void)
_payload.reset(new StreamString());
if(_size) {
if(_size > 0) {
// try to reserve needed memmory
if(!_payload->reserve((_size + 1))) {
DEBUG_HTTPCLIENT("[HTTP-Client][getString] not enough memory to reserve a string! need: %d\n", (_size + 1));
@@ -1139,7 +1150,11 @@ bool HTTPClient::hasHeader(const char* name)
bool HTTPClient::connect(void)
{
if(connected()) {
DEBUG_HTTPCLIENT("[HTTP-Client] connect. already connected, try reuse!\n");
if(_reuse) {
DEBUG_HTTPCLIENT("[HTTP-Client] connect: already connected, reusing connection\n");
} else {
DEBUG_HTTPCLIENT("[HTTP-Client] connect: already connected, try reuse!\n");
}
while(_client->available() > 0) {
_client->read();
}
@@ -1149,6 +1164,10 @@ bool HTTPClient::connect(void)
#if HTTPCLIENT_1_1_COMPATIBLE
if(!_client && _transportTraits) {
_tcpDeprecated = _transportTraits->create();
if(!_tcpDeprecated) {
DEBUG_HTTPCLIENT("[HTTP-Client] connect: could not create tcp\n");
return false;
}
_client = _tcpDeprecated.get();
}
#endif
@@ -1246,9 +1265,12 @@ int HTTPClient::handleHeaderResponse()
return HTTPC_ERROR_NOT_CONNECTED;
}
clear();
_canReuse = _reuse;
String transferEncoding;
_returnCode = -1;
_size = -1;
_transferEncoding = HTTPC_TE_IDENTITY;
unsigned long lastDataTime = millis();
@@ -1263,6 +1285,9 @@ int HTTPClient::handleHeaderResponse()
DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] RX: '%s'\n", headerLine.c_str());
if(headerLine.startsWith("HTTP/1.")) {
if(_canReuse) {
_canReuse = (headerLine[sizeof "HTTP/1." - 1] != '0');
}
_returnCode = headerLine.substring(9, headerLine.indexOf(' ', 9)).toInt();
} else if(headerLine.indexOf(':')) {
String headerName = headerLine.substring(0, headerLine.indexOf(':'));
@@ -1273,8 +1298,10 @@ int HTTPClient::handleHeaderResponse()
_size = headerValue.toInt();
}
if(headerName.equalsIgnoreCase("Connection")) {
_canReuse = headerValue.equalsIgnoreCase("keep-alive");
if(_canReuse && headerName.equalsIgnoreCase("Connection")) {
if(headerValue.indexOf("close") >= 0 && headerValue.indexOf("keep-alive") < 0) {
_canReuse = false;
}
}
if(headerName.equalsIgnoreCase("Transfer-Encoding")) {
@@ -1429,10 +1456,10 @@ int HTTPClient::writeToStreamDataBlock(Stream * stream, int size)
free(buff);
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] connection closed or file end (written: %d).\n", bytesWritten);
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] end of chunk or data (transferred: %d).\n", bytesWritten);
if((size > 0) && (size != bytesWritten)) {
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] bytesWritten %d and size %d mismatch!.\n", bytesWritten, size);
DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] transferred size %d and request size %d mismatch!.\n", bytesWritten, size);
return HTTPC_ERROR_STREAM_WRITE;
}

View File

@@ -235,7 +235,7 @@ protected:
/// request handling
String _host;
uint16_t _port = 0;
bool _reuse = false;
bool _reuse = true;
uint16_t _tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
bool _useHTTP10 = false;

View File

@@ -42,6 +42,7 @@ hostHeader KEYWORD2
#######################################
HTTP_GET LITERAL1
HTTP_HEAD LITERAL1
HTTP_POST LITERAL1
HTTP_ANY LITERAL1
CONTENT_LENGTH_UNKNOWN LITERAL1

View File

@@ -480,6 +480,7 @@ void ESP8266WebServerTemplate<ServerType>::send(int code, const String& content_
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::sendContent(const String& content) {
if (_currentMethod == HTTP_HEAD) return;
const char * footer = "\r\n";
size_t len = content.length();
if(_chunked) {
@@ -728,6 +729,7 @@ const String ESP8266WebServerTemplate<ServerType>::responseCodeToString(const in
case 415: return F("Unsupported Media Type");
case 416: return F("Requested range not satisfiable");
case 417: return F("Expectation Failed");
case 418: return F("I'm a teapot");
case 500: return F("Internal Server Error");
case 501: return F("Not Implemented");
case 502: return F("Bad Gateway");

View File

@@ -30,7 +30,7 @@
#include <FS.h>
#include "detail/mimetable.h"
enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS };
enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_HEAD, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS };
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END,
UPLOAD_FILE_ABORTED };
enum HTTPClientStatus { HC_NONE, HC_WAIT_READ, HC_WAIT_CLOSE };
@@ -194,10 +194,10 @@ protected:
std::unique_ptr<HTTPUpload> _currentUpload;
int _postArgsLen;
RequestArgument* _postArgs;
int _headerKeysCount;
RequestArgument* _currentHeaders;
size_t _contentLength;
String _responseHeaders;

View File

@@ -99,7 +99,9 @@ bool ESP8266WebServerTemplate<ServerType>::_parseRequest(ClientType& client) {
_chunked = false;
HTTPMethod method = HTTP_GET;
if (methodStr == F("POST")) {
if (methodStr == F("HEAD")) {
method = HTTP_HEAD;
} else if (methodStr == F("POST")) {
method = HTTP_POST;
} else if (methodStr == F("DELETE")) {
method = HTTP_DELETE;

View File

@@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python3
# This script pulls the list of Mozilla trusted certificate authorities
# from the web at the "mozurl" below, parses the file to grab the PEM
@@ -7,16 +7,18 @@
# and use them for your outgoing SSL connections.
#
# Script by Earle F. Philhower, III. Released to the public domain.
from __future__ import print_function
import csv
import os
import sys
from subprocess import Popen, PIPE, call
import urllib2
try:
# for Python 2.x
from urllib.request import urlopen
except:
from urllib2 import urlopen
try:
from StringIO import StringIO
except ImportError:
# for Python 3.x
except:
from io import StringIO
# Mozilla's URL for the CSV file with included PEM certs
@@ -25,9 +27,12 @@ mozurl = "https://ccadb-public.secure.force.com/mozilla/IncludedCACertificateRep
# Load the manes[] and pems[] array from the URL
names = []
pems = []
response = urllib2.urlopen(mozurl)
response = urlopen(mozurl)
csvData = response.read()
csvReader = csv.reader(StringIO(csvData))
if sys.version_info[0] > 2:
csvData = csvData.decode('utf-8')
csvFile = StringIO(csvData)
csvReader = csv.reader(csvFile)
for row in csvReader:
names.append(row[0]+":"+row[1]+":"+row[2])
pems.append(row[30])
@@ -46,10 +51,10 @@ idx = 0
for i in range(0, len(pems)):
certName = "data/ca_%03d.der" % (idx);
thisPem = pems[i].replace("'", "")
print names[i] + " -> " + certName
print(names[i] + " -> " + certName)
ssl = Popen(['openssl','x509','-inform','PEM','-outform','DER','-out', certName], shell = False, stdin = PIPE)
pipe = ssl.stdin
pipe.write(thisPem)
pipe.write(thisPem.encode('utf-8'))
pipe.close()
ssl.wait()
if os.path.exists(certName):

View File

@@ -0,0 +1,97 @@
// NAPT example released to public domain
#if LWIP_FEATURES && !LWIP_IPV6
#define HAVE_NETDUMP 0
#ifndef STASSID
#define STASSID "mynetwork"
#define STAPSK "mynetworkpassword"
#endif
#include <ESP8266WiFi.h>
#include <lwip/napt.h>
#include <lwip/dns.h>
#include <dhcpserver.h>
#define NAPT 1000
#define NAPT_PORT 10
#if HAVE_NETDUMP
#include <NetDump.h>
void dump(int netif_idx, const char* data, size_t len, int out, int success) {
(void)success;
Serial.print(out ? F("out ") : F(" in "));
Serial.printf("%d ", netif_idx);
// optional filter example: if (netDump_is_ARP(data))
{
netDump(Serial, data, len);
//netDumpHex(Serial, data, len);
}
}
#endif
void setup() {
Serial.begin(115200);
Serial.printf("\n\nNAPT Range extender\n");
Serial.printf("Heap on start: %d\n", ESP.getFreeHeap());
#if HAVE_NETDUMP
phy_capture = dump;
#endif
// first, connect to STA so we can get a proper local DNS server
WiFi.mode(WIFI_STA);
WiFi.begin(STASSID, STAPSK);
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(500);
}
Serial.printf("\nSTA: %s (dns: %s / %s)\n",
WiFi.localIP().toString().c_str(),
WiFi.dnsIP(0).toString().c_str(),
WiFi.dnsIP(1).toString().c_str());
// give DNS servers to AP side
dhcps_set_dns(0, WiFi.dnsIP(0));
dhcps_set_dns(1, WiFi.dnsIP(1));
WiFi.softAPConfig( // enable AP, with android-compatible google domain
IPAddress(172, 217, 28, 254),
IPAddress(172, 217, 28, 254),
IPAddress(255, 255, 255, 0));
WiFi.softAP(STASSID "extender", STAPSK);
Serial.printf("AP: %s\n", WiFi.softAPIP().toString().c_str());
Serial.printf("Heap before: %d\n", ESP.getFreeHeap());
err_t ret = ip_napt_init(NAPT, NAPT_PORT);
Serial.printf("ip_napt_init(%d,%d): ret=%d (OK=%d)\n", NAPT, NAPT_PORT, (int)ret, (int)ERR_OK);
if (ret == ERR_OK) {
ret = ip_napt_enable_no(SOFTAP_IF, 1);
Serial.printf("ip_napt_enable_no(SOFTAP_IF): ret=%d (OK=%d)\n", (int)ret, (int)ERR_OK);
if (ret == ERR_OK) {
Serial.printf("WiFi Network '%s' with same password is now NATed behind '%s'\n", STASSID "extender", STASSID);
}
}
Serial.printf("Heap after napt init: %d\n", ESP.getFreeHeap());
if (ret != ERR_OK) {
Serial.printf("NAPT initialization failed\n");
}
}
#else
void setup() {
Serial.begin(115200);
Serial.printf("\n\nNAPT not supported in this configuration\n");
}
#endif
void loop() {
}

View File

@@ -20,6 +20,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "BearSSLHelpers.h"
#include <memory>
#include <vector>
#include <bearssl/bearssl.h>
@@ -28,7 +29,10 @@
#include <string.h>
#include <Arduino.h>
#include <StackThunk.h>
#include "BearSSLHelpers.h"
#include <Updater_Signing.h>
#ifndef ARDUINO_SIGNING
#define ARDUINO_SIGNING 0
#endif
namespace brssl {
// Code here is pulled from brssl sources, with the copyright and license
@@ -901,3 +905,17 @@ make_stack_thunk(br_ssl_engine_sendrec_buf);
#endif
};
#if ARDUINO_SIGNING
namespace {
static BearSSL::PublicKey signingPubKey(signing_pubkey);
static BearSSL::HashSHA256 __signingHash;
static BearSSL::SigningVerifier __signingVerifier(&signingPubKey);
};
namespace esp8266 {
UpdaterHashClass& updaterSigningHash = __signingHash;
UpdaterVerifyClass& updaterSigningVerifier = __signingVerifier;
};
#endif

View File

@@ -26,7 +26,6 @@
#include <bearssl/bearssl.h>
#include <Updater.h>
// Internal opaque structures, not needed by user applications
namespace brssl {
class public_key;

View File

@@ -24,6 +24,7 @@
#include <list>
#include <string.h>
#include <coredecls.h>
#include "ESP8266WiFi.h"
#include "ESP8266WiFiGeneric.h"
@@ -38,12 +39,19 @@ extern "C" {
#include "lwip/opt.h"
#include "lwip/err.h"
#include "lwip/dns.h"
#include "lwip/dhcp.h"
#include "lwip/init.h" // LWIP_VERSION_
#if LWIP_VERSION_MAJOR == 1
#include "lwip/sntp.h"
#else
#include "lwip/apps/sntp.h"
#endif
}
#include "WiFiClient.h"
#include "WiFiUdp.h"
#include "debug.h"
#include "include/WiFiState.h"
extern "C" void esp_schedule();
extern "C" void esp_yield();
@@ -200,15 +208,15 @@ WiFiEventHandler ESP8266WiFiGenericClass::onSoftAPModeProbeRequestReceived(std::
return handler;
}
// WiFiEventHandler ESP8266WiFiGenericClass::onWiFiModeChange(std::function<void(const WiFiEventModeChange&)> f)
// {
// WiFiEventHandler handler = std::make_shared<WiFiEventHandlerOpaque>(WIFI_EVENT_MODE_CHANGE, [f](System_Event_t* e){
// WiFiEventModeChange& dst = *reinterpret_cast<WiFiEventModeChange*>(&e->event_info);
// f(dst);
// });
// sCbEventList.push_back(handler);
// return handler;
// }
WiFiEventHandler ESP8266WiFiGenericClass::onWiFiModeChange(std::function<void(const WiFiEventModeChange&)> f)
{
WiFiEventHandler handler = std::make_shared<WiFiEventHandlerOpaque>(WIFI_EVENT_MODE_CHANGE, [f](System_Event_t* e){
WiFiEventModeChange& dst = *reinterpret_cast<WiFiEventModeChange*>(&e->event_info);
f(dst);
});
sCbEventList.push_back(handler);
return handler;
}
/**
* callback for WiFi events
@@ -386,7 +394,29 @@ bool ESP8266WiFiGenericClass::getPersistent(){
* set new mode
* @param m WiFiMode_t
*/
bool ESP8266WiFiGenericClass::mode(WiFiMode_t m) {
bool ESP8266WiFiGenericClass::mode(WiFiMode_t m, WiFiState* state) {
if (m == WIFI_SHUTDOWN) {
return shutdown(0, state);
}
else if (m == WIFI_RESUME) {
return resumeFromShutdown(state);
}
else if (m & ~(WIFI_STA | WIFI_AP))
// any other bits than legacy disallowed
return false;
// m is now WIFI_STA, WIFI_AP or WIFI_AP_STA
if (state)
{
DEBUG_WIFI("core: state is useless without SHUTDOWN or RESUME\n");
}
if (wifi_fpm_get_sleep_type() != NONE_SLEEP_T) {
// wifi may have been put asleep by ESP8266WiFiGenericClass::preinitWiFiOff
wifi_fpm_do_wakeup();
wifi_fpm_close();
}
if(_persistent){
if(wifi_get_opmode() == (uint8) m && wifi_get_opmode_default() == (uint8) m){
return true;
@@ -396,12 +426,6 @@ bool ESP8266WiFiGenericClass::mode(WiFiMode_t m) {
}
bool ret = false;
if (m != WIFI_STA && m != WIFI_AP_STA)
// calls lwIP's dhcp_stop(),
// safe to call even if not started
wifi_station_dhcpc_stop();
ETS_UART_INTR_DISABLE();
if(_persistent) {
ret = wifi_set_opmode(m);
@@ -431,15 +455,13 @@ bool ESP8266WiFiGenericClass::enableSTA(bool enable) {
WiFiMode_t currentMode = getMode();
bool isEnabled = ((currentMode & WIFI_STA) != 0);
if(isEnabled != enable) {
if(enable) {
return mode((WiFiMode_t)(currentMode | WIFI_STA));
} else {
return mode((WiFiMode_t)(currentMode & (~WIFI_STA)));
}
} else {
if (isEnabled == enable)
return true;
}
if (enable)
return mode((WiFiMode_t)(currentMode | WIFI_STA));
return mode((WiFiMode_t)(currentMode & (~WIFI_STA)));
}
/**
@@ -472,16 +494,29 @@ bool ESP8266WiFiGenericClass::enableAP(bool enable){
bool ESP8266WiFiGenericClass::forceSleepBegin(uint32 sleepUs) {
_forceSleepLastMode = getMode();
if(!mode(WIFI_OFF)) {
DEBUG_WIFI("core: error with mode(WIFI_OFF)\n");
return false;
}
if(sleepUs == 0) {
if(sleepUs == 0 || sleepUs > 0xFFFFFFF) {
sleepUs = 0xFFFFFFF;
}
wifi_fpm_set_sleep_type(MODEM_SLEEP_T);
delay(0);
wifi_fpm_open();
return (wifi_fpm_do_sleep(sleepUs) == 0);
delay(0);
auto ret = wifi_fpm_do_sleep(sleepUs);
if (ret != 0)
{
DEBUG_WIFI("core: error %d with wifi_fpm_do_sleep: (-1=sleep status error, -2=force sleep not enabled)\n", ret);
return false;
}
// fpm_is_open() is always 1 here, with or without delay
// wifi_fpm_set_wakeup_cb(cb): callback is never called
// no power reduction without this delay
delay(10);
return true;
}
/**
@@ -489,8 +524,10 @@ bool ESP8266WiFiGenericClass::forceSleepBegin(uint32 sleepUs) {
* @return ok
*/
bool ESP8266WiFiGenericClass::forceSleepWake() {
wifi_fpm_do_wakeup();
wifi_fpm_close();
if (wifi_fpm_get_sleep_type() != NONE_SLEEP_T) {
wifi_fpm_do_wakeup();
wifi_fpm_close();
}
// restore last mode
if(mode(_forceSleepLastMode)) {
@@ -600,7 +637,142 @@ void wifi_dns_found_callback(const char *name, CONST ip_addr_t *ipaddr, void *ca
esp_schedule(); // resume the hostByName function
}
//meant to be called from user-defined preinit()
uint32_t ESP8266WiFiGenericClass::shutdownCRC (const WiFiState* state)
{
return state? crc32(&state->state, sizeof(state->state)): 0;
}
bool ESP8266WiFiGenericClass::shutdownValidCRC (const WiFiState* state)
{
return state && (crc32(&state->state, sizeof(state->state)) == state->crc);
}
bool ESP8266WiFiGenericClass::shutdown (uint32 sleepUs, WiFiState* state)
{
bool persistent = _persistent;
WiFiMode_t before_off_mode = getMode();
if ((before_off_mode & WIFI_STA) && state)
{
bool ret = wifi_get_ip_info(STATION_IF, &state->state.ip);
if (!ret)
{
DEBUG_WIFI("core: error with wifi_get_ip_info(STATION_IF)\n");
return false;
}
memset(state->state.fwconfig.bssid, 0xff, 6);
ret = wifi_station_get_config(&state->state.fwconfig);
if (!ret)
{
DEBUG_WIFI("core: error with wifi_station_get_config\n");
return false;
}
state->state.channel = wifi_get_channel();
}
// disable persistence in FW so in case of power failure
// it doesn't wake up in off mode.
// persistence state will be restored on WiFi resume.
WiFi.persistent(false);
if (!WiFi.forceSleepBegin(sleepUs))
{
// WIFI_OFF mode set by forceSleepBegin()
DEBUG_WIFI("core: error with forceSleepBegin()\n");
WiFi.mode(before_off_mode);
WiFi.persistent(persistent);
return false;
}
// WiFi is now in force-sleep mode
if (state)
{
// finish filling state and process crc
state->state.persistent = persistent;
state->state.mode = before_off_mode;
uint8_t i = 0;
for (auto& ntp: state->state.ntp)
{
#if LWIP_VERSION_MAJOR == 1
ntp = sntp_getserver(i++);
#else
ntp = *sntp_getserver(i++);
#endif
}
i = 0;
for (auto& dns: state->state.dns)
dns = WiFi.dnsIP(i++);
state->crc = shutdownCRC(state);
DEBUG_WIFI("core: state is saved\n");
}
return true;
}
bool ESP8266WiFiGenericClass::resumeFromShutdown (WiFiState* state)
{
if (wifi_fpm_get_sleep_type() != NONE_SLEEP_T) {
wifi_fpm_do_wakeup();
wifi_fpm_close();
}
if (!state || shutdownCRC(state) != state->crc)
{
DEBUG_WIFI("core: resume: no state or bad crc\n");
return false;
}
persistent(state->state.persistent);
if (!mode(state->state.mode))
{
DEBUG_WIFI("core: resume: can't set wifi mode to %d\n", state->state.mode);
return false;
}
if (state->state.mode & WIFI_STA)
{
IPAddress local(state->state.ip.ip);
if (local)
{
DEBUG_WIFI("core: resume: static address '%s'\n", local.toString().c_str());
WiFi.config(state->state.ip.ip, state->state.ip.gw, state->state.ip.netmask, state->state.dns[0], state->state.dns[1]);
uint8_t i = 0;
for (CONST auto& ntp: state->state.ntp)
{
IPAddress ip(ntp);
if (ip.isSet())
{
DEBUG_WIFI("core: resume: start SNTP, server='%s'\n", ip.toString().c_str());
sntp_setserver(i++, &ntp);
}
}
}
// state->state.fwconfig.bssid is not real bssid (it's what user may have provided when bssid_set==1)
if (WiFi.begin((const char*)state->state.fwconfig.ssid,
(const char*)state->state.fwconfig.password,
state->state.channel,
nullptr/*(const uint8_t*)state->state.fwconfig.bssid*/, // <- try with gw's mac address?
true) == WL_CONNECT_FAILED)
{
DEBUG_WIFI("core: resume: WiFi.begin failed\n");
return false;
}
}
if (state->state.mode & WIFI_AP)
{
DEBUG_WIFI("core: resume AP mode TODO\n");
return false;
}
// success, invalidate saved state
state->crc++;
return true;
}
//meant to be called from user-defined ::preinit()
void ESP8266WiFiGenericClass::preinitWiFiOff () {
// https://github.com/esp8266/Arduino/issues/2111#issuecomment-224251391
// WiFi.persistent(false);

View File

@@ -42,6 +42,8 @@ typedef std::shared_ptr<WiFiEventHandlerOpaque> WiFiEventHandler;
typedef void (*WiFiEventCb)(WiFiEvent_t);
struct WiFiState;
class ESP8266WiFiGenericClass {
// ----------------------------------------------------------------------------------------------
// -------------------------------------- Generic WiFi function ---------------------------------
@@ -62,7 +64,7 @@ class ESP8266WiFiGenericClass {
WiFiEventHandler onSoftAPModeStationConnected(std::function<void(const WiFiEventSoftAPModeStationConnected&)>);
WiFiEventHandler onSoftAPModeStationDisconnected(std::function<void(const WiFiEventSoftAPModeStationDisconnected&)>);
WiFiEventHandler onSoftAPModeProbeRequestReceived(std::function<void(const WiFiEventSoftAPModeProbeRequestReceived&)>);
// WiFiEventHandler onWiFiModeChange(std::function<void(const WiFiEventModeChange&)>);
WiFiEventHandler onWiFiModeChange(std::function<void(const WiFiEventModeChange&)>);
int32_t channel(void);
@@ -79,7 +81,7 @@ class ESP8266WiFiGenericClass {
void persistent(bool persistent);
bool mode(WiFiMode_t);
bool mode(WiFiMode_t, WiFiState* state = nullptr);
WiFiMode_t getMode();
bool enableSTA(bool enable);
@@ -88,6 +90,8 @@ class ESP8266WiFiGenericClass {
bool forceSleepBegin(uint32 sleepUs = 0);
bool forceSleepWake();
static uint32_t shutdownCRC (const WiFiState* state);
static bool shutdownValidCRC (const WiFiState* state);
static void preinitWiFiOff (); //meant to be called in user-defined preinit()
protected:
@@ -96,17 +100,22 @@ class ESP8266WiFiGenericClass {
static void _eventCallback(void *event);
// called by WiFi.mode(SHUTDOWN/RESTORE, state)
// - sleepUs is WiFi.forceSleepBegin() parameter, 0 = forever
// - saveState is the user's state to hold configuration on restore
bool shutdown (uint32 sleepUs = 0, WiFiState* stateSave = nullptr);
bool resumeFromShutdown (WiFiState* savedState = nullptr);
// ----------------------------------------------------------------------------------------------
// ------------------------------------ Generic Network function --------------------------------
// ----------------------------------------------------------------------------------------------
public:
int hostByName(const char* aHostname, IPAddress& aResult);
int hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms);
bool getPersistent();
protected:
protected:
friend class ESP8266WiFiSTAClass;
friend class ESP8266WiFiScanClass;
friend class ESP8266WiFiAPClass;

View File

@@ -369,18 +369,24 @@ bool ESP8266WiFiSTAClass::reconnect() {
* @return one value of wl_status_t enum
*/
bool ESP8266WiFiSTAClass::disconnect(bool wifioff) {
bool ret;
bool ret = false;
struct station_config conf;
*conf.ssid = 0;
*conf.password = 0;
// API Reference: wifi_station_disconnect() need to be called after system initializes and the ESP8266 Station mode is enabled.
if (WiFi.getMode() & WIFI_STA)
ret = wifi_station_disconnect();
else
ret = true;
ETS_UART_INTR_DISABLE();
if(WiFi._persistent) {
wifi_station_set_config(&conf);
} else {
wifi_station_set_config_current(&conf);
}
ret = wifi_station_disconnect();
ETS_UART_INTR_ENABLE();
if(wifioff) {

View File

@@ -34,7 +34,8 @@
typedef enum WiFiMode
{
WIFI_OFF = 0, WIFI_STA = 1, WIFI_AP = 2, WIFI_AP_STA = 3
WIFI_OFF = 0, WIFI_STA = 1, WIFI_AP = 2, WIFI_AP_STA = 3,
/* these two pseudo modes are experimental: */ WIFI_SHUTDOWN = 4, WIFI_RESUME = 8
} WiFiMode_t;
typedef enum WiFiPhyMode
@@ -58,9 +59,10 @@ typedef enum WiFiEvent
WIFI_EVENT_SOFTAPMODE_STACONNECTED,
WIFI_EVENT_SOFTAPMODE_STADISCONNECTED,
WIFI_EVENT_SOFTAPMODE_PROBEREQRECVED,
WIFI_EVENT_MODE_CHANGE,
WIFI_EVENT_SOFTAPMODE_DISTRIBUTE_STA_IP,
WIFI_EVENT_MAX,
WIFI_EVENT_ANY = WIFI_EVENT_MAX,
WIFI_EVENT_MODE_CHANGE
} WiFiEvent_t;
enum WiFiDisconnectReason

View File

@@ -32,6 +32,7 @@ extern "C" {
}
#include "debug.h"
#include "ESP8266WiFi.h"
#include "PolledTimeout.h"
#include "WiFiClient.h"
#include "WiFiClientSecureBearSSL.h"
#include "StackThunk.h"
@@ -437,12 +438,17 @@ int WiFiClientSecure::_run_until(unsigned target, bool blocking) {
DEBUG_BSSL("_run_until: Not connected\n");
return -1;
}
for (int no_work = 0; blocking || no_work < 2;) {
if (blocking) {
// Only for blocking operations can we afford to yield()
optimistic_yield(100);
esp8266::polledTimeout::oneShotMs loopTimeout(_timeout);
for (int no_work = 0; blocking || no_work < 2;) {
optimistic_yield(100);
if (loopTimeout) {
DEBUG_BSSL("_run_until: Timeout\n");
return -1;
}
int state;
state = br_ssl_engine_current_state(_eng);
if (state & BR_SSL_CLOSED) {
@@ -461,8 +467,19 @@ int WiFiClientSecure::_run_until(unsigned target, bool blocking) {
unsigned char *buf;
size_t len;
int wlen;
size_t availForWrite;
buf = br_ssl_engine_sendrec_buf(_eng, &len);
availForWrite = WiFiClient::availableForWrite();
if (!blocking && len > availForWrite) {
/*
writes on WiFiClient will block if len > availableForWrite()
this is needed to prevent available() calls from blocking
on dropped connections
*/
len = availForWrite;
}
wlen = WiFiClient::write(buf, len);
if (wlen <= 0) {
/*

View File

@@ -193,6 +193,9 @@ class WiFiClientSecure : public WiFiClient {
// AxTLS API deprecated section end
/////////////////////////////////////
protected:
bool _connectSSL(const char *hostName); // Do initial SSL handshake
private:
void _clear();
void _clearAuthenticationSettings();
@@ -243,7 +246,6 @@ class WiFiClientSecure : public WiFiClient {
size_t _recvapp_len;
bool _clientConnected(); // Is the underlying socket alive?
bool _connectSSL(const char *hostName); // Do initial SSL handshake
void _freeSSL();
int _run_until(unsigned target, bool blocking = true);
size_t _write(const uint8_t *buf, size_t size, bool pmem);

View File

@@ -128,14 +128,14 @@ public:
if (err != ERR_OK) {
return 0;
}
_connect_pending = 1;
_connect_pending = true;
_op_start_time = millis();
// Following delay will be interrupted by connect callback
for (decltype(_timeout_ms) i = 0; _connect_pending && i < _timeout_ms; i++) {
// Give scheduled functions a chance to run (e.g. Ethernet uses recurrent)
delay(1);
}
_connect_pending = 0;
}
_connect_pending = false;
if (!_pcb) {
DEBUGV(":cabrt\r\n");
return 0;
@@ -433,7 +433,9 @@ protected:
void _notify_error()
{
if (_connect_pending || _send_waiting) {
esp_schedule();
_send_waiting = false;
_connect_pending = false;
esp_schedule(); // break current delay()
}
}
@@ -464,8 +466,8 @@ protected:
// Give scheduled functions a chance to run (e.g. Ethernet uses recurrent)
delay(1);
}
_send_waiting = false;
} while(true);
_send_waiting = false;
if (_sync)
wait_until_sent();
@@ -534,7 +536,7 @@ protected:
{
if (_send_waiting) {
_send_waiting = false;
esp_schedule();
esp_schedule(); // break current delay()
}
}
@@ -608,9 +610,10 @@ protected:
(void) err;
(void) pcb;
assert(pcb == _pcb);
assert(_connect_pending);
_connect_pending = 0;
esp_schedule();
if (_connect_pending) {
_connect_pending = false;
esp_schedule(); // break current delay()
}
return ERR_OK;
}
@@ -659,7 +662,7 @@ private:
uint32_t _timeout_ms = 5000;
uint32_t _op_start_time = 0;
bool _send_waiting = false;
uint8_t _connect_pending = 0;
bool _connect_pending = false;
int8_t _refcnt;
ClientContext* _next;

View File

@@ -0,0 +1,23 @@
#ifndef WIFISTATE_H_
#define WIFISTATE_H_
#include <user_interface.h>
#include <ESP8266WiFiType.h>
struct WiFiState
{
uint32_t crc;
struct
{
station_config fwconfig;
ip_info ip;
ip_addr_t dns[2];
ip_addr_t ntp[2];
WiFiMode_t mode;
uint8_t channel;
bool persistent;
} state;
};
#endif // WIFISTATE_H_

View File

@@ -23,6 +23,7 @@
*/
#include <Schedule.h>
#include <AddrList.h>
#include "LEAmDNS_Priv.h"
@@ -59,11 +60,11 @@ MDNSResponder::MDNSResponder(void)
m_pServiceQueries(0),
m_fnServiceTxtCallback(0),
#ifdef ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE
m_bPassivModeEnabled(true) {
m_bPassivModeEnabled(true),
#else
m_bPassivModeEnabled(false) {
m_bPassivModeEnabled(false),
#endif
m_netif(nullptr) {
}
/*
@@ -95,20 +96,74 @@ bool MDNSResponder::begin(const char* p_pcHostname, const IPAddress& p_IPAddress
if (0 == m_pUDPContext) {
if (_setHostname(p_pcHostname)) {
m_IPAddress = p_IPAddress;
//// select interface
m_GotIPHandler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP& pEvent) {
(void) pEvent;
// Ensure that _restart() runs in USER context
schedule_function([this]() { MDNSResponder::_restart(); });
});
m_netif = nullptr;
IPAddress ipAddress = p_IPAddress;
m_DisconnectedHandler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected& pEvent) {
(void) pEvent;
// Ensure that _restart() runs in USER context
schedule_function([this]() { MDNSResponder::_restart(); });
if (!ipAddress.isSet()) {
IPAddress sta = WiFi.localIP();
IPAddress ap = WiFi.softAPIP();
if (!sta.isSet() && !ap.isSet()) {
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] internal interfaces (STA, AP) are not set (none was specified)\n")));
return false;
}
if (ap.isSet()) {
if (sta.isSet())
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] default interface AP selected over STA (none was specified)\n")));
else
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] default interface AP selected\n")));
ipAddress = ap;
} else {
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] default interface STA selected (none was specified)\n")));
ipAddress = sta;
}
// continue to ensure interface is UP
}
// check existence of this IP address in the interface list
bool found = false;
m_netif = nullptr;
for (auto a: addrList)
if (ipAddress == a.addr()) {
if (a.ifUp()) {
found = true;
m_netif = a.interface();
break;
}
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] found interface for IP '%s' but it is not UP\n"), ipAddress.toString().c_str()););
}
if (!found) {
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] interface defined by IP '%s' not found\n"), ipAddress.toString().c_str()););
return false;
}
//// done selecting the interface
if (m_netif->num == STATION_IF) {
m_GotIPHandler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP& pEvent) {
(void) pEvent;
// Ensure that _restart() runs in USER context
schedule_function([this]() { MDNSResponder::_restart(); });
});
m_DisconnectedHandler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected& pEvent) {
(void) pEvent;
// Ensure that _restart() runs in USER context
schedule_function([this]() { MDNSResponder::_restart(); });
});
}
bResult = _restart();
}
DEBUG_EX_ERR(if (!bResult) { DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] begin: FAILED for '%s'!\n"), (p_pcHostname ?: "-")); } );
@@ -642,7 +697,7 @@ uint32_t MDNSResponder::queryService(const char* p_pcService,
}
}
else {
DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService: INVALID input data!\n"), p_pcService, p_pcProtocol););
DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService: INVALID input data!\n")););
}
return u32Result;
}

View File

@@ -1148,7 +1148,7 @@ protected:
MDNSDynamicServiceTxtCallbackFunc m_fnServiceTxtCallback;
bool m_bPassivModeEnabled;
stcProbeInformation m_HostProbeInformation;
IPAddress m_IPAddress;
CONST netif* m_netif; // network interface to run on
/** CONTROL **/
/* MAINTENANCE */
@@ -1203,7 +1203,7 @@ protected:
uint16_t p_u16QueryType,
stcMDNSServiceQuery::stcAnswer* p_pKnownAnswers = 0);
const IPAddress& _getResponseMulticastInterface() const { return m_IPAddress; }
const IPAddress _getResponseMulticastInterface() const { return IPAddress(m_netif->ip_addr); }
uint8_t _replyMaskForHost(const stcMDNS_RRHeader& p_RRHeader,
bool* p_pbFullNameMatch = 0) const;

View File

@@ -22,7 +22,6 @@
*
*/
#include <arch/cc.h>
#include <sys/time.h>
#include <IPAddress.h>
#include <AddrList.h>
@@ -79,10 +78,10 @@ bool MDNSResponder::_process(bool p_bUserContext) {
}
}
else {
bResult = ((WiFi.isConnected() || // Either station is connected
WiFi.softAPgetStationNum()>0) && // Or AP has stations connected
(_updateProbeStatus()) && // Probing
(_checkServiceQueryCache())); // Service query cache check
bResult = (m_netif != nullptr) &&
(m_netif->flags & NETIF_FLAG_UP) && // network interface is up and running
_updateProbeStatus() && // Probing
_checkServiceQueryCache(); // Service query cache check
}
return bResult;
}
@@ -92,53 +91,10 @@ bool MDNSResponder::_process(bool p_bUserContext) {
*/
bool MDNSResponder::_restart(void) {
// check m_IPAddress
if (!m_IPAddress.isSet()) {
IPAddress sta = WiFi.localIP();
IPAddress ap = WiFi.softAPIP();
if (!sta.isSet() && !ap.isSet()) {
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] internal interfaces (STA, AP) are not set (none was specified)\n")));
return false;
}
if (sta.isSet()) {
if (ap.isSet())
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] default interface STA selected over AP (none was specified)\n")));
else
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] default interface STA selected\n")));
m_IPAddress = sta;
} else {
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] default interface AP selected (none was specified)\n")));
m_IPAddress = ap;
}
// continue to ensure interface is UP
}
// check existence of this IP address in the interface list
bool found = false;
for (auto a: addrList)
if (m_IPAddress == a.addr()) {
if (a.ifUp()) {
found = true;
break;
}
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] found interface for IP '%s' but it is not UP\n"), m_IPAddress.toString().c_str()););
}
if (!found) {
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] interface defined by IP '%s' not found\n"), m_IPAddress.toString().c_str()););
return false;
}
return ((_resetProbeStatus(true)) && // Stop and restart probing
(_allocUDPContext())); // Restart UDP
return ((m_netif != nullptr) &&
(m_netif->flags & NETIF_FLAG_UP) && // network interface is up and running
(_resetProbeStatus(true)) && // Stop and restart probing
(_allocUDPContext())); // Restart UDP
}
@@ -798,7 +754,7 @@ bool MDNSResponder::_processPTRAnswer(const MDNSResponder::stcMDNS_RRAnswerPTR*
if (p_pPTRAnswer->m_u32TTL) { // Received update message
pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); // Update TTL tag
DEBUG_EX_INFO(
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: Updated TTL(%lu) for "), p_pPTRAnswer->m_u32TTL);
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: Updated TTL(%d) for "), (int)p_pPTRAnswer->m_u32TTL);
_printRRDomain(pSQAnswer->m_ServiceDomain);
DEBUG_OUTPUT.printf_P(PSTR("\n"));
);
@@ -852,7 +808,7 @@ bool MDNSResponder::_processSRVAnswer(const MDNSResponder::stcMDNS_RRAnswerSRV*
if (p_pSRVAnswer->m_u32TTL) { // First or update message (TTL != 0)
pSQAnswer->m_TTLHostDomainAndPort.set(p_pSRVAnswer->m_u32TTL); // Update TTL tag
DEBUG_EX_INFO(
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processSRVAnswer: Updated TTL(%lu) for "), p_pSRVAnswer->m_u32TTL);
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processSRVAnswer: Updated TTL(%d) for "), (int)p_pSRVAnswer->m_u32TTL);
_printRRDomain(pSQAnswer->m_ServiceDomain);
DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n"));
);
@@ -905,7 +861,7 @@ bool MDNSResponder::_processTXTAnswer(const MDNSResponder::stcMDNS_RRAnswerTXT*
if (p_pTXTAnswer->m_u32TTL) { // First or update message
pSQAnswer->m_TTLTxts.set(p_pTXTAnswer->m_u32TTL); // Update TTL tag
DEBUG_EX_INFO(
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processTXTAnswer: Updated TTL(%lu) for "), p_pTXTAnswer->m_u32TTL);
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processTXTAnswer: Updated TTL(%d) for "), (int)p_pTXTAnswer->m_u32TTL);
_printRRDomain(pSQAnswer->m_ServiceDomain);
DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n"));
);
@@ -957,7 +913,7 @@ bool MDNSResponder::_processTXTAnswer(const MDNSResponder::stcMDNS_RRAnswerTXT*
if (p_pAAnswer->m_u32TTL) { // Valid TTL -> Update answers TTL
pIP4Address->m_TTL.set(p_pAAnswer->m_u32TTL);
DEBUG_EX_INFO(
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: Updated TTL(%lu) for "), p_pAAnswer->m_u32TTL);
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: Updated TTL(%d) for "), (int)p_pAAnswer->m_u32TTL);
_printRRDomain(pSQAnswer->m_ServiceDomain);
DEBUG_OUTPUT.printf_P(PSTR(" IP4Address (%s)\n"), pIP4Address->m_IPAddress.toString().c_str());
);
@@ -1124,7 +1080,7 @@ bool MDNSResponder::_updateProbeStatus(void) {
if (MDNS_ANNOUNCE_COUNT > m_HostProbeInformation.m_u8SentCount) {
m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY);
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing host (%lu).\n\n"), m_HostProbeInformation.m_u8SentCount););
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing host (%d).\n\n"), m_HostProbeInformation.m_u8SentCount););
}
else {
m_HostProbeInformation.m_Timeout.resetToNeverExpires();
@@ -1172,7 +1128,7 @@ bool MDNSResponder::_updateProbeStatus(void) {
if (MDNS_ANNOUNCE_COUNT > pService->m_ProbeInformation.m_u8SentCount) {
pService->m_ProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY);
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing service %s.%s.%s (%lu)\n\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_ProbeInformation.m_u8SentCount););
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing service %s.%s.%s (%d)\n\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_ProbeInformation.m_u8SentCount););
}
else {
pService->m_ProbeInformation.m_Timeout.resetToNeverExpires();

View File

@@ -170,7 +170,7 @@ namespace MDNSImplementation {
*/
bool MDNSResponder::_callProcess(void) {
DEBUG_EX_INFO(DEBUG_OUTPUT.printf("[MDNSResponder] _callProcess (%lu, triggered by: %s)\n", millis(), m_pUDPContext->getRemoteAddress().toString().c_str()););
DEBUG_EX_INFO(DEBUG_OUTPUT.printf("[MDNSResponder] _callProcess (%lu, triggered by: %s)\n", millis(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str()););
return _process(false);
}
@@ -199,7 +199,7 @@ bool MDNSResponder::_allocUDPContext(void) {
//TODO: set multicast address (lwip_joingroup() is IPv4 only at the time of writing)
multicast_addr.addr = DNS_MQUERY_IPV6_GROUP_INIT;
#endif
if (ERR_OK == igmp_joingroup(IP4_ADDR_ANY4, ip_2_ip4(&multicast_addr))) {
if (ERR_OK == igmp_joingroup(ip_2_ip4(&m_netif->ip_addr), ip_2_ip4(&multicast_addr))) {
m_pUDPContext = new UdpContext;
m_pUDPContext->ref();

View File

@@ -37,6 +37,9 @@ namespace MDNSImplementation {
#define ESP_8266_MDNS_INCLUDE
//#define DEBUG_ESP_MDNS_RESPONDER
#if !defined(DEBUG_ESP_MDNS_RESPONDER) && defined(DEBUG_ESP_MDNS)
#define DEBUG_ESP_MDNS_RESPONDER
#endif
#ifndef LWIP_OPEN_SRC
#define LWIP_OPEN_SRC

View File

@@ -212,7 +212,7 @@ void SPIClass::setFrequency(uint32_t freq) {
return;
}
const spiClk_t minFreqReg = { 0x7FFFF000 };
const spiClk_t minFreqReg = { 0x7FFFF020 };
uint32_t minFreq = ClkRegToFreq((spiClk_t*) &minFreqReg);
if(freq < minFreq) {
// use minimum possible clock

View File

@@ -0,0 +1,258 @@
// demonstrate the use of WiFi.mode(SHUTDOWN/RESUME)
// released to public domain
// current on wemos d1 mini (including: ldo, usbserial chip):
// ~85mA during normal operations
// ~30mA during wifi shutdown
// ~5mA during deepsleep
#ifndef STASSID
#define STASSID "mynetwork"
#define STAPSK "mynetworkpasswd"
#endif
#define WAIT_NTP 0 // define this to 1 for NTP check too
#include <ESP8266WiFi.h>
#include <coredecls.h> // crc32()
#include <include/WiFiState.h> // WiFiState structure details
enum state_e {
e_initial,
e_start_resume,
e_start_normal,
e_off_restart,
e_wait_connected,
e_wait_ntp,
e_shutdown,
e_wait_shutdown,
e_wait_off
};
static state_e step = e_initial; // step
static int wifi_timeout = 0; // wifi timeout counter
static bool time_is_set = false; // WAIT_NTP=1: wait for network - dhcp packet must have ntp server
// non volatile data
struct nv_s {
WiFiState wss; // core's wifi save state
uint32_t crc;
struct {
int rstcounter[7];
} data;
};
static nv_s* nv = (nv_s*)RTC_USER_MEM; // user non volatile area
#define SEP "###### "
#define EV "!!!!!! "
#define NFO "------ "
void resetUserCrc() {
nv->crc = crc32(&nv->data, sizeof(nv->data));
}
void printNv() {
Serial.printf(NFO "nfo1/2 wifi-nv-state: valid=%d, "
"persistent=%d, "
"mode=%d, "
"channel=%d, "
"ip=%s, "
"dns=%s, "
"ntp=%s\n",
WiFi.shutdownValidCRC(&nv->wss),
nv->wss.state.persistent,
nv->wss.state.mode,
nv->wss.state.channel,
IPAddress(&nv->wss.state.ip.ip).toString().c_str(),
IPAddress(&nv->wss.state.dns[0]).toString().c_str(),
IPAddress(&nv->wss.state.ntp[0]).toString().c_str());
Serial.printf(NFO "nfo2/2 rst reason counters: default:%d wdt:%d exception:%d softwdt:%d reset:%d deepsleep:%d extsys:%d\n",
nv->data.rstcounter[0],
nv->data.rstcounter[1],
nv->data.rstcounter[2],
nv->data.rstcounter[3],
nv->data.rstcounter[4],
nv->data.rstcounter[5],
nv->data.rstcounter[6]);
}
void timeset_cb() {
time_is_set = true;
static bool first = true;
if (first) {
first = false;
}
}
decltype(millis()) startup;
WiFiEventHandler evOff = WiFi.onWiFiModeChange([](const WiFiEventModeChange& event) {
Serial.printf(EV "mode changed event: ev:%d->%d getMode=%d\n", event.oldMode, event.newMode, wifi_get_opmode());
});
void preinit() {
ESP8266WiFiClass::preinitWiFiOff();
}
void setup() {
WiFi.persistent(false);
startup = millis();
Serial.begin(115200);
settimeofday_cb(timeset_cb);
// prepare non volatile user structure
if (crc32(&nv->data, sizeof(nv->data)) != nv->crc) {
memset(&nv->data, 0, sizeof(nv->data));
Serial.printf(SEP "reset NV user data\n");
}
// update reset reason
nv->data.rstcounter[system_get_rst_info()->reason]++;
// recalculate crc
resetUserCrc();
// nfo
printNv();
Serial.println("setup()");
}
#define TEST(x...) ({ auto v = x; Serial.printf(SEP "'%s': result = %d\n", #x, v); v; })
void loop() {
static int prev = 255;
if (step != prev) {
prev = step;
Serial.printf(NFO "step %d - wifi getMode=%d=%d heap=%d freeheap=%d\n",
prev,
WiFi.getMode(),
wifi_get_opmode(),
ESP.getFreeHeap(),
ESP.getFreeHeap());
printNv();
}
switch (step) {
case e_initial: {
if (WiFi.shutdownValidCRC(&nv->wss)) {
step = e_start_resume;
} else {
step = e_start_normal;
}
break;
}
case e_start_resume:
Serial.println(SEP "CRC valid => WIFI_RESUME");
startup = millis();
if (!TEST(WiFi.mode(WIFI_RESUME, &nv->wss))) {
Serial.printf(SEP "issue resuming WiFi\n");
step = e_off_restart;
} else {
Serial.printf(SEP "waiting for connected\\n");
step = e_wait_connected;
}
break;
case e_start_normal:
Serial.printf(SEP "CRC NOT valid, begin/WIFI_STA (current mode = %d)\n", wifi_get_opmode());
startup = millis();
if (!TEST(WiFi.mode(WIFI_STA)) || !TEST(WiFi.begin(STASSID, STAPSK))) {
Serial.printf(SEP "issue setting up STA\n");
step = e_off_restart;
} else {
Serial.printf(SEP "waiting for connected\n");
step = e_wait_connected;
}
break;
case e_wait_connected:
if (WiFi.status() == WL_CONNECTED) {
Serial.printf(SEP "connected! ---- startup time: %ld ms ----\n\n\n", millis() - startup);
wifi_timeout = 0;
if (WAIT_NTP) {
step = e_wait_ntp;
Serial.printf(SEP "wait for NTP\n");
} else {
step = e_shutdown;
}
} else if ((millis() - startup > 10000)) {
Serial.printf(SEP "connected TIMEOUT! status=%d\n", WiFi.status());
wifi_timeout++;
step = e_off_restart;
}
break;
case e_off_restart:
Serial.printf(SEP "OFF -> wait 2s\n");
(void)TEST(WiFi.mode(WIFI_OFF));
delay(2000); // test - mad wifi loop until :oom if delay not there - to verify
step = e_initial;
break;
case e_wait_ntp:
// check when NTP has set time
if (time_is_set) {
Serial.printf(SEP "NTP is set\n");
time_is_set = false;
step = e_shutdown;
}
break;
case e_shutdown: {
static int deepsleep = 0;
switch (++deepsleep) {
case 1: {
Serial.println(SEP "WIFI_OFF for 5s");
TEST(WiFi.mode(WIFI_OFF));
step = e_wait_off;
break;
}
case 2: // several loop on shutdown
case 3: // to check if it affects
case 4: { // reconnection duration
Serial.println(SEP "WIFI_SHUTDOWN for 5s");
TEST(WiFi.mode(WIFI_SHUTDOWN, &nv->wss));
step = e_wait_shutdown;
break;
}
default: {
Serial.println(SEP "DEEPSLEEP for 5s (bind GPIO16 <=> RST)");
TEST(WiFi.mode(WIFI_SHUTDOWN, &nv->wss));
Serial.flush();
ESP.deepSleep(5000000);
// will reboot, GPIO16 must be connected to reset
}
}
startup = millis();
break;
}
case e_wait_shutdown:
if (millis() - startup > 5000) {
step = e_start_resume;
}
break;
case e_wait_off:
if (millis() - startup > 5000) {
step = e_start_normal;
}
break;
}
}

View File

@@ -0,0 +1,159 @@
// show arduino_new benefits
// released to public domain
// result is below
class SomeClass {
public:
SomeClass(const String& s1 = emptyString, const String& s2 = emptyString) {
Serial.printf("SomeClass@%p(%s)(%s)\n", this, s1.c_str(), s2.c_str());
}
~SomeClass() {
Serial.printf("~ SomeClass @%p\n", this);
}
};
class oom {
private:
char large [65000];
public:
oom() {
Serial.printf("this constructor should not be called\n");
}
};
void setup() {
Serial.begin(115200);
Serial.printf("\n\narduino_new benefits\n\n");
delay(5000); // avoid too frequent bootloop
// arduino_new / arduino_newarray api
Serial.printf("\n----- arduino_new:\n");
auto an = arduino_new(SomeClass);
delete an;
Serial.printf("\n----- arduino_new with oom:\n");
auto anoom = arduino_new(oom);
Serial.printf("nullptr: %p\n", anoom);
delete anoom;
Serial.printf("\n----- arduino_new with constructor parameters:\n");
auto ancp = arduino_new(SomeClass, "param1", "param2");
delete ancp;
Serial.printf("\n----- arduino_newarray[2]\n");
auto ana2 = arduino_newarray(SomeClass, 2);
Serial.printf("@:%p s=%zd s(2)=%zd\n", ana2, sizeof(SomeClass), sizeof(SomeClass[2]));
Serial.printf("0: %p\n", &ana2[0]);
Serial.printf("1: %p\n", &ana2[1]);
delete [] ana2;
Serial.printf("\n----- arduino_newarray[2] (with constructor parameters)\n");
auto ana2cp = arduino_newarray(SomeClass, 2, "param1");
Serial.printf("@:%p s=%zd s(2)=%zd\n", ana2cp, sizeof(SomeClass), sizeof(SomeClass[2]));
Serial.printf("0: %p\n", &ana2cp[0]);
Serial.printf("1: %p\n", &ana2cp[1]);
delete [] ana2cp;
Serial.printf("\n----- arduino_newarray[100000]\n");
auto anaX = arduino_newarray(SomeClass, 100000);
Serial.printf("@:%p\n", anaX);
// standard c++ api for new and new[]
Serial.printf("\n----- new\n");
auto sn = new SomeClass;
delete sn;
Serial.printf("\n----- new with oom: (abort() with option 'Exceptions: Disabled (new can abort)'\n");
auto snoom = new oom;
Serial.printf("nullptr: %p\n", snoom);
delete snoom;
Serial.printf("\n----- new[2]\n");
auto sna2 = new SomeClass[2];
Serial.printf("@:%p s=%zd s(2)=%zd\n", sna2, sizeof(SomeClass), sizeof(SomeClass[2]));
Serial.printf("0: %p\n", &sna2[0]);
Serial.printf("1: %p\n", &sna2[1]);
delete [] sna2;
Serial.printf("\n----- new[10000] (badly fails with 'Exceptions: Legacy' or '...Disabled'\n");
auto snaX = new SomeClass[100000];
Serial.printf("@:%p\n", snaX);
}
void loop() {
}
//////////////////////////////
/*
Result with:
Exceptions: Legacy(new can return nullptr)
//////////////////////////////
arduino_new benefits
----- arduino_new:
SomeClass@0x3fff1864()()
~ SomeClass @0x3fff1864
----- arduino_new with oom:
nullptr: 0
----- arduino_new with constructor parameters:
SomeClass@0x3fff1864(param1)(param2)
~ SomeClass @0x3fff1864
----- arduino_newarray[2]
SomeClass@0x3fff1868()()
SomeClass@0x3fff1869()()
@: 0x3fff1868 s = 1 s(2) = 2
0: 0x3fff1868
1: 0x3fff1869
~ SomeClass @0x3fff1869
~ SomeClass @0x3fff1868
----- arduino_newarray[2](with constructor parameters)
SomeClass@0x3fff1868(param1)()
SomeClass@0x3fff1869(param1)()
@: 0x3fff1868 s = 1 s(2) = 2
0: 0x3fff1868
1: 0x3fff1869
~ SomeClass @0x3fff1869
~ SomeClass @0x3fff1868
----- arduino_newarray[100000]
@: 0
----- new
SomeClass@0x3fff1864()()
~ SomeClass @0x3fff1864
----- new with oom: (abort() with option 'Exceptions: Disabled (new can abort)'
this constructor should not be called
nullptr: 0
----- new[2]
SomeClass@0x3fff1868()()
SomeClass@0x3fff1869()()
@:0x3fff1868 s = 1 s(2) = 2
0: 0x3fff1868
1: 0x3fff1869
~ SomeClass @0x3fff1869
~ SomeClass @0x3fff1868
----- new[10000](badly fails with 'Exceptions: Legacy' or '...Disabled'
Exception(29):
epc1 = 0x402013de epc2 = 0x00000000 epc3 = 0x00000000 excvaddr = 0x00000000 depc = 0x00000000
>>> stack >>>
...
*/
/////////////////////////////