1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

Merge branch 'master' into wifi_mesh_update_2.2

This commit is contained in:
Develo 2020-04-17 09:39:09 -04:00 committed by GitHub
commit a24b8d23f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 705 additions and 162 deletions

View File

@ -48,19 +48,19 @@ Also known as latest git or master branch.
### Using PlatformIO ### Using PlatformIO
[PlatformIO](https://platformio.org?utm_source=github&utm_medium=arduino-esp8266) is an open source ecosystem for IoT [PlatformIO](https://platformio.org?utm_source=arduino-esp8266) is an open source ecosystem for IoT
development with a cross-platform build system, a library manager, and full support development with a cross-platform build system, a library manager, and full support
for Espressif (ESP8266) development. It works on the following popular host operating systems: macOS, Windows, for Espressif (ESP8266) development. It works on the following popular host operating systems: macOS, Windows,
Linux 32/64, and Linux ARM (like Raspberry Pi, BeagleBone, CubieBoard). Linux 32/64, and Linux ARM (like Raspberry Pi, BeagleBone, CubieBoard).
- [What is PlatformIO?](https://docs.platformio.org/en/latest/what-is-platformio.html?utm_source=github&utm_medium=arduino-esp8266) - [What is PlatformIO?](https://docs.platformio.org/en/latest/what-is-platformio.html?utm_source=arduino-esp8266)
- [PlatformIO IDE](https://platformio.org/platformio-ide?utm_source=github&utm_medium=arduino-esp8266) - [PlatformIO IDE](https://platformio.org/platformio-ide?utm_source=arduino-esp8266)
- [PlatformIO Core](https://docs.platformio.org/en/latest/core.html?utm_source=github&utm_medium=arduino-esp8266) (command line tool) - [PlatformIO Core](https://docs.platformio.org/en/latest/core.html?utm_source=arduino-esp8266) (command line tool)
- [Advanced usage](https://docs.platformio.org/en/latest/platforms/espressif8266.html?utm_source=github&utm_medium=arduino-esp8266) - - [Advanced usage](https://docs.platformio.org/en/latest/platforms/espressif8266.html?utm_source=arduino-esp8266) -
custom settings, uploading to SPIFFS, Over-the-Air (OTA), staging version custom settings, uploading to SPIFFS, Over-the-Air (OTA), staging version
- [Integration with Cloud and Standalone IDEs](https://docs.platformio.org/en/latest/ide.html?utm_source=github&utm_medium=arduino-esp8266) - - [Integration with Cloud and Standalone IDEs](https://docs.platformio.org/en/latest/ide.html?utm_source=arduino-esp8266) -
Cloud9, Codeanywhere, Eclipse Che (Codenvy), Atom, CLion, Eclipse, Emacs, NetBeans, Qt Creator, Sublime Text, VIM, Visual Studio, and VSCode Cloud9, Codeanywhere, Eclipse Che (Codenvy), Atom, CLion, Eclipse, Emacs, NetBeans, Qt Creator, Sublime Text, VIM, Visual Studio, and VSCode
- [Project Examples](https://docs.platformio.org/en/latest/platforms/espressif8266.html?utm_source=github&utm_medium=arduino-esp8266#examples) - [Project Examples](https://docs.platformio.org/en/latest/platforms/espressif8266.html?utm_source=arduino-esp8266#examples)
### Building with make ### Building with make

View File

@ -625,6 +625,63 @@ esp8285.menu.eesz.1M.build.flash_ld=eagle.flash.1m.ld
esp8285.menu.eesz.1M.build.spiffs_pagesize=256 esp8285.menu.eesz.1M.build.spiffs_pagesize=256
esp8285.menu.eesz.1M.upload.maximum_size=1023984 esp8285.menu.eesz.1M.upload.maximum_size=1023984
esp8285.menu.eesz.1M.build.rfcal_addr=0xFC000 esp8285.menu.eesz.1M.build.rfcal_addr=0xFC000
esp8285.menu.eesz.2M64=2MB (FS:64KB OTA:~992KB)
esp8285.menu.eesz.2M64.build.flash_size=2M
esp8285.menu.eesz.2M64.build.flash_size_bytes=0x200000
esp8285.menu.eesz.2M64.build.flash_ld=eagle.flash.2m64.ld
esp8285.menu.eesz.2M64.build.spiffs_pagesize=256
esp8285.menu.eesz.2M64.upload.maximum_size=1044464
esp8285.menu.eesz.2M64.build.rfcal_addr=0x1FC000
esp8285.menu.eesz.2M64.build.spiffs_start=0x1F0000
esp8285.menu.eesz.2M64.build.spiffs_end=0x1FB000
esp8285.menu.eesz.2M64.build.spiffs_blocksize=4096
esp8285.menu.eesz.2M128=2MB (FS:128KB OTA:~960KB)
esp8285.menu.eesz.2M128.build.flash_size=2M
esp8285.menu.eesz.2M128.build.flash_size_bytes=0x200000
esp8285.menu.eesz.2M128.build.flash_ld=eagle.flash.2m128.ld
esp8285.menu.eesz.2M128.build.spiffs_pagesize=256
esp8285.menu.eesz.2M128.upload.maximum_size=1044464
esp8285.menu.eesz.2M128.build.rfcal_addr=0x1FC000
esp8285.menu.eesz.2M128.build.spiffs_start=0x1E0000
esp8285.menu.eesz.2M128.build.spiffs_end=0x1FB000
esp8285.menu.eesz.2M128.build.spiffs_blocksize=4096
esp8285.menu.eesz.2M256=2MB (FS:256KB OTA:~896KB)
esp8285.menu.eesz.2M256.build.flash_size=2M
esp8285.menu.eesz.2M256.build.flash_size_bytes=0x200000
esp8285.menu.eesz.2M256.build.flash_ld=eagle.flash.2m256.ld
esp8285.menu.eesz.2M256.build.spiffs_pagesize=256
esp8285.menu.eesz.2M256.upload.maximum_size=1044464
esp8285.menu.eesz.2M256.build.rfcal_addr=0x1FC000
esp8285.menu.eesz.2M256.build.spiffs_start=0x1C0000
esp8285.menu.eesz.2M256.build.spiffs_end=0x1FB000
esp8285.menu.eesz.2M256.build.spiffs_blocksize=4096
esp8285.menu.eesz.2M512=2MB (FS:512KB OTA:~768KB)
esp8285.menu.eesz.2M512.build.flash_size=2M
esp8285.menu.eesz.2M512.build.flash_size_bytes=0x200000
esp8285.menu.eesz.2M512.build.flash_ld=eagle.flash.2m512.ld
esp8285.menu.eesz.2M512.build.spiffs_pagesize=256
esp8285.menu.eesz.2M512.upload.maximum_size=1044464
esp8285.menu.eesz.2M512.build.rfcal_addr=0x1FC000
esp8285.menu.eesz.2M512.build.spiffs_start=0x180000
esp8285.menu.eesz.2M512.build.spiffs_end=0x1FA000
esp8285.menu.eesz.2M512.build.spiffs_blocksize=8192
esp8285.menu.eesz.2M1M=2MB (FS:1MB OTA:~512KB)
esp8285.menu.eesz.2M1M.build.flash_size=2M
esp8285.menu.eesz.2M1M.build.flash_size_bytes=0x200000
esp8285.menu.eesz.2M1M.build.flash_ld=eagle.flash.2m1m.ld
esp8285.menu.eesz.2M1M.build.spiffs_pagesize=256
esp8285.menu.eesz.2M1M.upload.maximum_size=1044464
esp8285.menu.eesz.2M1M.build.rfcal_addr=0x1FC000
esp8285.menu.eesz.2M1M.build.spiffs_start=0x100000
esp8285.menu.eesz.2M1M.build.spiffs_end=0x1FA000
esp8285.menu.eesz.2M1M.build.spiffs_blocksize=8192
esp8285.menu.eesz.2M=2MB (FS:none OTA:~1019KB)
esp8285.menu.eesz.2M.build.flash_size=2M
esp8285.menu.eesz.2M.build.flash_size_bytes=0x200000
esp8285.menu.eesz.2M.build.flash_ld=eagle.flash.2m.ld
esp8285.menu.eesz.2M.build.spiffs_pagesize=256
esp8285.menu.eesz.2M.upload.maximum_size=1044464
esp8285.menu.eesz.2M.build.rfcal_addr=0x1FC000
esp8285.menu.led.2=2 esp8285.menu.led.2=2
esp8285.menu.led.2.build.led=-DLED_BUILTIN=2 esp8285.menu.led.2.build.led=-DLED_BUILTIN=2
esp8285.menu.led.0=0 esp8285.menu.led.0=0

View File

@ -193,9 +193,6 @@ bool EspClass::rtcUserMemoryWrite(uint32_t offset, uint32_t *data, size_t size)
} }
} }
extern "C" void __real_system_restart_local();
void EspClass::reset(void) void EspClass::reset(void)
{ {
__real_system_restart_local(); __real_system_restart_local();
@ -267,11 +264,12 @@ uint8_t EspClass::getBootMode(void)
return system_get_boot_mode(); return system_get_boot_mode();
} }
#ifndef F_CPU
uint8_t EspClass::getCpuFreqMHz(void) uint8_t EspClass::getCpuFreqMHz(void)
{ {
return system_get_cpu_freq(); return system_get_cpu_freq();
} }
#endif
uint32_t EspClass::getFlashChipId(void) uint32_t EspClass::getFlashChipId(void)
{ {

View File

@ -157,7 +157,14 @@ class EspClass {
uint8_t getBootVersion(); uint8_t getBootVersion();
uint8_t getBootMode(); uint8_t getBootMode();
#if defined(F_CPU) || defined(CORE_MOCK)
constexpr uint8_t getCpuFreqMHz() const
{
return clockCyclesPerMicrosecond();
}
#else
uint8_t getCpuFreqMHz(); uint8_t getCpuFreqMHz();
#endif
uint32_t getFlashChipId(); uint32_t getFlashChipId();
uint8_t getFlashChipVendorId(); uint8_t getFlashChipVendorId();
@ -201,6 +208,7 @@ class EspClass {
}; };
#ifndef CORE_MOCK #ifndef CORE_MOCK
uint32_t EspClass::getCycleCount() uint32_t EspClass::getCycleCount()
{ {
return esp_get_cycle_count(); return esp_get_cycle_count();

View File

@ -1,10 +1,11 @@
#include <Arduino.h> #include <Arduino.h>
#include <MD5Builder.h> #include <MD5Builder.h>
#include <memory>
uint8_t hex_char_to_byte(uint8_t c){ uint8_t hex_char_to_byte(uint8_t c) {
return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) : return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) :
(c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) : (c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) :
(c >= '0' && c<= '9') ? (c - (uint8_t)'0') : 0; (c >= '0' && c <= '9') ? (c - (uint8_t)'0') : 0;
} }
void MD5Builder::begin(void){ void MD5Builder::begin(void){
@ -18,25 +19,27 @@ void MD5Builder::add(const uint8_t * data, const uint16_t len){
void MD5Builder::addHexString(const char * data){ void MD5Builder::addHexString(const char * data){
uint16_t i, len = strlen(data); uint16_t i, len = strlen(data);
uint8_t * tmp = (uint8_t*)malloc(len/2); auto tmp = std::unique_ptr<uint8_t[]>{new(std::nothrow) uint8_t[len / 2]};
if(tmp == NULL) {
if (!tmp) {
return; return;
} }
for(i=0; i<len; i+=2) { for(i=0; i<len; i+=2) {
uint8_t high = hex_char_to_byte(data[i]); uint8_t high = hex_char_to_byte(data[i]);
uint8_t low = hex_char_to_byte(data[i+1]); uint8_t low = hex_char_to_byte(data[i+1]);
tmp[i/2] = (high & 0x0F) << 4 | (low & 0x0F); tmp[i/2] = (high & 0x0F) << 4 | (low & 0x0F);
} }
add(tmp, len/2); add(tmp.get(), len/2);
free(tmp);
} }
bool MD5Builder::addStream(Stream & stream, const size_t maxLen){ bool MD5Builder::addStream(Stream &stream, const size_t maxLen) {
const int buf_size = 512; const int buf_size = 512;
int maxLengthLeft = maxLen; int maxLengthLeft = maxLen;
uint8_t * buf = (uint8_t*) malloc(buf_size);
if(!buf) { auto buf = std::unique_ptr<uint8_t[]>{new(std::nothrow) uint8_t[buf_size]};
if (!buf) {
return false; return false;
} }
@ -45,21 +48,21 @@ bool MD5Builder::addStream(Stream & stream, const size_t maxLen){
// determine number of bytes to read // determine number of bytes to read
int readBytes = bytesAvailable; int readBytes = bytesAvailable;
if(readBytes > maxLengthLeft) { if (readBytes > maxLengthLeft){
readBytes = maxLengthLeft ; // read only until max_len readBytes = maxLengthLeft; // read only until max_len
} }
if(readBytes > buf_size) { if (readBytes > buf_size){
readBytes = buf_size; // not read more the buffer can handle readBytes = buf_size; // not read more the buffer can handle
} }
// read data and check if we got something // read data and check if we got something
int numBytesRead = stream.readBytes(buf, readBytes); int numBytesRead = stream.readBytes(buf.get(), readBytes);
if(numBytesRead< 1) { if (numBytesRead < 1) {
return false; return false;
} }
// Update MD5 with buffer payload // Update MD5 with buffer payload
MD5Update(&_ctx, buf, numBytesRead); MD5Update(&_ctx, buf.get(), numBytesRead);
yield(); // time for network streams yield(); // time for network streams
@ -67,7 +70,7 @@ bool MD5Builder::addStream(Stream & stream, const size_t maxLen){
maxLengthLeft -= numBytesRead; maxLengthLeft -= numBytesRead;
bytesAvailable = stream.available(); bytesAvailable = stream.available();
} }
free(buf);
return true; return true;
} }
@ -75,17 +78,17 @@ void MD5Builder::calculate(void){
MD5Final(_buf, &_ctx); MD5Final(_buf, &_ctx);
} }
void MD5Builder::getBytes(uint8_t * output){ void MD5Builder::getBytes(uint8_t * output) const {
memcpy(output, _buf, 16); memcpy(output, _buf, 16);
} }
void MD5Builder::getChars(char * output){ void MD5Builder::getChars(char * output) const {
for(uint8_t i = 0; i < 16; i++) { for (uint8_t i=0; i<16; i++){
sprintf(output + (i * 2), "%02x", _buf[i]); sprintf(output + (i * 2), "%02x", _buf[i]);
} }
} }
String MD5Builder::toString(void){ String MD5Builder::toString(void) const {
char out[33]; char out[33];
getChars(out); getChars(out);
return String(out); return String(out);

View File

@ -40,9 +40,9 @@ class MD5Builder {
void addHexString(const String& data){ addHexString(data.c_str()); } void addHexString(const String& data){ addHexString(data.c_str()); }
bool addStream(Stream & stream, const size_t maxLen); bool addStream(Stream & stream, const size_t maxLen);
void calculate(void); void calculate(void);
void getBytes(uint8_t * output); void getBytes(uint8_t * output) const;
void getChars(char * output); void getChars(char * output) const;
String toString(void); String toString(void) const;
}; };

View File

@ -76,7 +76,7 @@ struct TimeSourceCycles
using timeType = decltype(ESP.getCycleCount()); using timeType = decltype(ESP.getCycleCount());
static timeType time() {return ESP.getCycleCount();} static timeType time() {return ESP.getCycleCount();}
static constexpr timeType ticksPerSecond = F_CPU; // 80'000'000 or 160'000'000 Hz static constexpr timeType ticksPerSecond = ESP.getCpuFreqMHz() * 1000000UL; // 80'000'000 or 160'000'000 Hz
static constexpr timeType ticksPerSecondMax = 160000000; // 160MHz static constexpr timeType ticksPerSecondMax = 160000000; // 160MHz
}; };

View File

@ -26,6 +26,9 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include "pgmspace.h"
#include "debug.h"
#include "StackThunk.h" #include "StackThunk.h"
#include <ets_sys.h> #include <ets_sys.h>
@ -46,6 +49,11 @@ void stack_thunk_add_ref()
stack_thunk_refcnt++; stack_thunk_refcnt++;
if (stack_thunk_refcnt == 1) { if (stack_thunk_refcnt == 1) {
stack_thunk_ptr = (uint32_t *)malloc(_stackSize * sizeof(uint32_t)); stack_thunk_ptr = (uint32_t *)malloc(_stackSize * sizeof(uint32_t));
if (!stack_thunk_ptr) {
// This is a fatal error, stop the sketch
DEBUGV("Unable to allocate BearSSL stack\n");
abort();
}
stack_thunk_top = stack_thunk_ptr + _stackSize - 1; stack_thunk_top = stack_thunk_ptr + _stackSize - 1;
stack_thunk_save = NULL; stack_thunk_save = NULL;
stack_thunk_repaint(); stack_thunk_repaint();

View File

@ -22,6 +22,7 @@
*/ */
#include "Arduino.h" #include "Arduino.h"
#include "user_interface.h"
#include "core_esp8266_waveform.h" #include "core_esp8266_waveform.h"
// Which pins have a tone running on them? // Which pins have a tone running on them?
@ -35,10 +36,10 @@ static void _startTone(uint8_t _pin, uint32_t high, uint32_t low, unsigned long
pinMode(_pin, OUTPUT); pinMode(_pin, OUTPUT);
high = std::max(high, (uint32_t)100); high = std::max(high, (uint32_t)microsecondsToClockCycles(25)); // new 20KHz maximum tone frequency,
low = std::max(low, (uint32_t)100); low = std::max(low, (uint32_t)microsecondsToClockCycles(25)); // (25us high + 25us low period = 20KHz)
if (startWaveform(_pin, high, low, (uint32_t) duration * 1000)) { if (startWaveformCycles(_pin, high, low, microsecondsToClockCycles(duration * 1000))) {
_toneMap |= 1 << _pin; _toneMap |= 1 << _pin;
} }
} }
@ -48,7 +49,7 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) {
if (frequency == 0) { if (frequency == 0) {
noTone(_pin); noTone(_pin);
} else { } else {
uint32_t period = 1000000L / frequency; uint32_t period = (1000000L * system_get_cpu_freq()) / frequency;
uint32_t high = period / 2; uint32_t high = period / 2;
uint32_t low = period - high; uint32_t low = period - high;
_startTone(_pin, high, low, duration); _startTone(_pin, high, low, duration);
@ -62,7 +63,7 @@ void tone(uint8_t _pin, double frequency, unsigned long duration) {
if (frequency < 1.0) { // FP means no exact comparisons if (frequency < 1.0) { // FP means no exact comparisons
noTone(_pin); noTone(_pin);
} else { } else {
double period = 1000000.0 / frequency; double period = (1000000.0L * system_get_cpu_freq()) / frequency;
uint32_t high = (uint32_t)((period / 2.0) + 0.5); uint32_t high = (uint32_t)((period / 2.0) + 0.5);
uint32_t low = (uint32_t)(period + 0.5) - high; uint32_t low = (uint32_t)(period + 0.5) - high;
_startTone(_pin, high, low, duration); _startTone(_pin, high, low, duration);

View File

@ -1,6 +1,7 @@
#include "Updater.h" #include "Updater.h"
#include "eboot_command.h" #include "eboot_command.h"
#include <esp8266_peri.h> #include <esp8266_peri.h>
#include "StackThunk.h"
//#define DEBUG_UPDATER Serial //#define DEBUG_UPDATER Serial
@ -40,6 +41,14 @@ UpdaterClass::UpdaterClass()
{ {
#if ARDUINO_SIGNING #if ARDUINO_SIGNING
installSignature(&esp8266::updaterSigningHash, &esp8266::updaterSigningVerifier); installSignature(&esp8266::updaterSigningHash, &esp8266::updaterSigningVerifier);
stack_thunk_add_ref();
#endif
}
UpdaterClass::~UpdaterClass()
{
#if ARDUINO_SIGNING
stack_thunk_del_ref();
#endif #endif
} }
@ -199,6 +208,7 @@ bool UpdaterClass::end(bool evenIfRemaining){
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
DEBUG_UPDATER.println(F("no update")); DEBUG_UPDATER.println(F("no update"));
#endif #endif
_reset();
return false; return false;
} }
@ -206,7 +216,6 @@ bool UpdaterClass::end(bool evenIfRemaining){
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf_P(PSTR("premature end: res:%u, pos:%zu/%zu\n"), getError(), progress(), _size); DEBUG_UPDATER.printf_P(PSTR("premature end: res:%u, pos:%zu/%zu\n"), getError(), progress(), _size);
#endif #endif
_reset(); _reset();
return false; return false;
} }
@ -226,6 +235,7 @@ bool UpdaterClass::end(bool evenIfRemaining){
#endif #endif
if (sigLen != _verify->length()) { if (sigLen != _verify->length()) {
_setError(UPDATE_ERROR_SIGN); _setError(UPDATE_ERROR_SIGN);
_reset();
return false; return false;
} }
@ -251,6 +261,7 @@ bool UpdaterClass::end(bool evenIfRemaining){
uint8_t *sig = (uint8_t*)malloc(sigLen); uint8_t *sig = (uint8_t*)malloc(sigLen);
if (!sig) { if (!sig) {
_setError(UPDATE_ERROR_SIGN); _setError(UPDATE_ERROR_SIGN);
_reset();
return false; return false;
} }
ESP.flashRead(_startAddress + binSize, (uint32_t *)sig, sigLen); ESP.flashRead(_startAddress + binSize, (uint32_t *)sig, sigLen);
@ -262,9 +273,12 @@ bool UpdaterClass::end(bool evenIfRemaining){
DEBUG_UPDATER.printf("\n"); DEBUG_UPDATER.printf("\n");
#endif #endif
if (!_verify->verify(_hash, (void *)sig, sigLen)) { if (!_verify->verify(_hash, (void *)sig, sigLen)) {
free(sig);
_setError(UPDATE_ERROR_SIGN); _setError(UPDATE_ERROR_SIGN);
_reset();
return false; return false;
} }
free(sig);
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf_P(PSTR("[Updater] Signature matches\n")); DEBUG_UPDATER.printf_P(PSTR("[Updater] Signature matches\n"));
#endif #endif

View File

@ -53,6 +53,7 @@ class UpdaterClass {
typedef std::function<void(size_t, size_t)> THandlerFunction_Progress; typedef std::function<void(size_t, size_t)> THandlerFunction_Progress;
UpdaterClass(); UpdaterClass();
~UpdaterClass();
/* Optionally add a cryptographic signature verification hash and method */ /* Optionally add a cryptographic signature verification hash and method */
void installSignature(UpdaterHashClass *hash, UpdaterVerifyClass *verify) { _hash = hash; _verify = verify; } void installSignature(UpdaterHashClass *hash, UpdaterVerifyClass *verify) { _hash = hash; _verify = verify; }

View File

@ -81,14 +81,25 @@ void initVariant() __attribute__((weak));
void initVariant() { void initVariant() {
} }
void preloop_update_frequency() __attribute__((weak)); extern "C" void __preloop_update_frequency() {
void preloop_update_frequency() {
#if defined(F_CPU) && (F_CPU == 160000000L) #if defined(F_CPU) && (F_CPU == 160000000L)
REG_SET_BIT(0x3ff00014, BIT(0));
ets_update_cpu_frequency(160); ets_update_cpu_frequency(160);
CPU2X |= 1UL;
#elif defined(F_CPU)
ets_update_cpu_frequency(80);
CPU2X &= ~1UL;
#elif !defined(F_CPU)
if (system_get_cpu_freq() == 160) {
CPU2X |= 1UL;
}
else {
CPU2X &= ~1UL;
}
#endif #endif
} }
extern "C" void preloop_update_frequency() __attribute__((weak, alias("__preloop_update_frequency")));
extern "C" bool can_yield() { extern "C" bool can_yield() {
return cont_can_yield(g_pcont); return cont_can_yield(g_pcont);
} }

View File

@ -32,11 +32,10 @@
#include "pgmspace.h" #include "pgmspace.h"
#include "gdb_hooks.h" #include "gdb_hooks.h"
#include "StackThunk.h" #include "StackThunk.h"
#include "coredecls.h"
extern "C" { extern "C" {
extern void __real_system_restart_local();
// These will be pointers to PROGMEM const strings // These will be pointers to PROGMEM const strings
static const char* s_panic_file = 0; static const char* s_panic_file = 0;
static int s_panic_line = 0; static int s_panic_line = 0;

View File

@ -112,15 +112,19 @@ void setTimer1Callback(uint32_t (*fn)()) {
// waveform smoothly on next low->high transition. For immediate change, stopWaveform() // waveform smoothly on next low->high transition. For immediate change, stopWaveform()
// first, then it will immediately begin. // first, then it will immediately begin.
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS) { int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS) {
if ((pin > 16) || isFlashInterfacePin(pin)) { return startWaveformCycles(pin, microsecondsToClockCycles(timeHighUS), microsecondsToClockCycles(timeLowUS), microsecondsToClockCycles(runTimeUS));
}
int startWaveformCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles) {
if ((pin > 16) || isFlashInterfacePin(pin)) {
return false; return false;
} }
Waveform *wave = &waveform[pin]; Waveform *wave = &waveform[pin];
// Adjust to shave off some of the IRQ time, approximately // Adjust to shave off some of the IRQ time, approximately
wave->nextTimeHighCycles = microsecondsToClockCycles(timeHighUS); wave->nextTimeHighCycles = timeHighCycles;
wave->nextTimeLowCycles = microsecondsToClockCycles(timeLowUS); wave->nextTimeLowCycles = timeLowCycles;
wave->expiryCycle = runTimeUS ? GetCycleCount() + microsecondsToClockCycles(runTimeUS) : 0; wave->expiryCycle = runTimeCycles ? GetCycleCount() + runTimeCycles : 0;
if (runTimeUS && !wave->expiryCycle) { if (runTimeCycles && !wave->expiryCycle) {
wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it
} }

View File

@ -50,6 +50,8 @@ extern "C" {
// If runtimeUS > 0 then automatically stop it after that many usecs. // If runtimeUS > 0 then automatically stop it after that many usecs.
// Returns true or false on success or failure. // Returns true or false on success or failure.
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS); int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS);
// Same as above, but pass in CPU clock cycles instead of microseconds
int startWaveformCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles);
// Stop a waveform, if any, on the specified pin. // Stop a waveform, if any, on the specified pin.
// Returns true or false on success or failure. // Returns true or false on success or failure.
int stopWaveform(uint8_t pin); int stopWaveform(uint8_t pin);

View File

@ -235,21 +235,23 @@ extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode)
__attachInterruptFunctionalArg(pin, (voidFuncPtrArg)userFunc, 0, mode, false); __attachInterruptFunctionalArg(pin, (voidFuncPtrArg)userFunc, 0, mode, false);
} }
extern void __resetPins() {
for (int i = 0; i <= 16; ++i) {
if (!isFlashInterfacePin(i))
pinMode(i, INPUT);
}
}
extern void initPins() { extern void initPins() {
//Disable UART interrupts //Disable UART interrupts
system_set_os_print(0); system_set_os_print(0);
U0IE = 0; U0IE = 0;
U1IE = 0; U1IE = 0;
for (int i = 0; i <= 5; ++i) { resetPins();
pinMode(i, INPUT);
}
// pins 6-11 are used for the SPI flash interface
for (int i = 12; i <= 16; ++i) {
pinMode(i, INPUT);
}
} }
extern void resetPins() __attribute__ ((weak, alias("__resetPins")));
extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pinMode"))); extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pinMode")));
extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite"))); extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite")));
extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead"), nothrow)); extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead"), nothrow));

View File

@ -25,6 +25,7 @@
#include "core_esp8266_waveform.h" #include "core_esp8266_waveform.h"
extern "C" { extern "C" {
#include "user_interface.h"
static uint32_t analogMap = 0; static uint32_t analogMap = 0;
static int32_t analogScale = PWMRANGE; static int32_t analogScale = PWMRANGE;
@ -50,7 +51,7 @@ extern void __analogWrite(uint8_t pin, int val) {
if (pin > 16) { if (pin > 16) {
return; return;
} }
uint32_t analogPeriod = 1000000L / analogFreq; uint32_t analogPeriod = (1000000L * system_get_cpu_freq()) / analogFreq;
if (val < 0) { if (val < 0) {
val = 0; val = 0;
} else if (val > analogScale) { } else if (val > analogScale) {
@ -68,7 +69,7 @@ extern void __analogWrite(uint8_t pin, int val) {
stopWaveform(pin); stopWaveform(pin);
digitalWrite(pin, LOW); digitalWrite(pin, LOW);
} else { } else {
if (startWaveform(pin, high, low, 0)) { if (startWaveformCycles(pin, high, low, 0)) {
analogMap |= (1 << pin); analogMap |= (1 << pin);
} }
} }

View File

@ -21,6 +21,7 @@ void esp_schedule();
void tune_timeshift64 (uint64_t now_us); void tune_timeshift64 (uint64_t now_us);
void disable_extra4k_at_link_time (void) __attribute__((noinline)); void disable_extra4k_at_link_time (void) __attribute__((noinline));
bool sntp_set_timezone_in_seconds(int32_t timezone); bool sntp_set_timezone_in_seconds(int32_t timezone);
void __real_system_restart_local() __attribute__((noreturn));
uint32_t sqrt32 (uint32_t n); uint32_t sqrt32 (uint32_t n);
uint32_t crc32 (const void* data, size_t length, uint32_t crc = 0xffffffff); uint32_t crc32 (const void* data, size_t length, uint32_t crc = 0xffffffff);

View File

@ -37,6 +37,7 @@ extern "C" {
typedef void (*voidFuncPtr)(void); typedef void (*voidFuncPtr)(void);
void initPins(); void initPins();
void resetPins();
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"

View File

@ -230,3 +230,20 @@ Instructions - Other OS
cd hardware\esp8266com\esp8266 cd hardware\esp8266com\esp8266
git status git status
git pull git pull
Using PlatformIO
----------------
`PlatformIO <https://platformio.org?utm_source=arduino-esp8266>`__
is an open source ecosystem for IoT development with a cross-platform
build system, a library manager, and full support for Espressif
(ESP8266) development. It works on the following popular host operating
systems: macOS, Windows, Linux 32/64, and Linux ARM (like Raspberry Pi,
BeagleBone, CubieBoard).
- `What is PlatformIO? <https://docs.platformio.org/en/latest/what-is-platformio.html?utm_source=arduino-esp8266>`__
- `PlatformIO IDE <https://platformio.org/platformio-ide?utm_source=arduino-esp8266>`__
- `PlatformIO Core <https://docs.platformio.org/en/latest/core.html?utm_source=arduino-esp8266>`__ (command line tool)
- `Advanced usage <https://docs.platformio.org/en/latest/platforms/espressif8266.html?utm_source=arduino-esp8266>`__ - custom settings, uploading to SPIFFS, Over-the-Air (OTA), staging version
- `Integration with Cloud and Standalone IDEs <https://docs.platformio.org/en/latest/ide.html?utm_source=arduino-esp8266>`__ - Cloud9, Codeanywhere, Eclipse Che (Codenvy), Atom, CLion, Eclipse, Emacs, NetBeans, Qt Creator, Sublime Text, VIM, Visual Studio, and VSCode
- `Project Examples <https://docs.platformio.org/en/latest/platforms/espressif8266.html?utm_source=arduino-esp8266#examples>`__

View File

@ -328,9 +328,13 @@ void ArduinoOTAClass::_runUpdate() {
} }
if (Update.end()) { if (Update.end()) {
client.print("OK"); // Ensure last count packet has been sent out and not combined with the final OK
client.stop(); client.flush();
delay(1000); delay(1000);
client.print("OK");
client.flush();
delay(1000);
client.stop();
#ifdef OTA_DEBUG #ifdef OTA_DEBUG
OTA_DEBUG.printf("Update Success\n"); OTA_DEBUG.printf("Update Success\n");
#endif #endif

View File

@ -423,7 +423,6 @@ void HTTPClient::end(void)
{ {
disconnect(false); disconnect(false);
clear(); clear();
_redirectCount = 0;
} }
/** /**
@ -558,8 +557,17 @@ bool HTTPClient::setURL(const String& url)
/** /**
* set true to follow redirects. * set true to follow redirects.
* @param follow * @param follow
* @deprecated
*/ */
void HTTPClient::setFollowRedirects(bool follow) void HTTPClient::setFollowRedirects(bool follow)
{
_followRedirects = follow ? HTTPC_STRICT_FOLLOW_REDIRECTS : HTTPC_DISABLE_FOLLOW_REDIRECTS;
}
/**
* set redirect follow mode. See `followRedirects_t` enum for avaliable modes.
* @param follow
*/
void HTTPClient::setFollowRedirects(followRedirects_t follow)
{ {
_followRedirects = follow; _followRedirects = follow;
} }
@ -652,8 +660,9 @@ int HTTPClient::sendRequest(const char * type, const String& payload)
*/ */
int HTTPClient::sendRequest(const char * type, const uint8_t * payload, size_t size) int HTTPClient::sendRequest(const char * type, const uint8_t * payload, size_t size)
{ {
int code;
bool redirect = false; bool redirect = false;
int code = 0; uint16_t redirectCount = 0;
do { do {
// wipe out any existing headers from previous request // wipe out any existing headers from previous request
for(size_t i = 0; i < _headerKeysCount; i++) { for(size_t i = 0; i < _headerKeysCount; i++) {
@ -662,8 +671,7 @@ int HTTPClient::sendRequest(const char * type, const uint8_t * payload, size_t s
} }
} }
redirect = false; DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] type: '%s' redirCount: %d\n", type, redirectCount);
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] type: '%s' redirCount: %d\n", type, _redirectCount);
// connect to server // connect to server
if(!connect()) { if(!connect()) {
@ -687,9 +695,9 @@ int HTTPClient::sendRequest(const char * type, const uint8_t * payload, size_t s
int towrite = std::min((int)size, (int)HTTP_TCP_BUFFER_SIZE); int towrite = std::min((int)size, (int)HTTP_TCP_BUFFER_SIZE);
written = _client->write(p + bytesWritten, towrite); written = _client->write(p + bytesWritten, towrite);
if (written < 0) { if (written < 0) {
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
} else if (written == 0) { } else if (written == 0) {
return returnError(HTTPC_ERROR_CONNECTION_LOST); return returnError(HTTPC_ERROR_CONNECTION_LOST);
} }
bytesWritten += written; bytesWritten += written;
size -= written; size -= written;
@ -700,42 +708,67 @@ int HTTPClient::sendRequest(const char * type, const uint8_t * payload, size_t s
code = handleHeaderResponse(); code = handleHeaderResponse();
// //
// We can follow redirects for 301/302/307 for GET and HEAD requests and // Handle redirections as stated in RFC document:
// and we have not exceeded the redirect limit preventing an infinite
// redirect loop.
//
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html // https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
// //
if (_followRedirects && // Implementing HTTP_CODE_FOUND as redirection with GET method,
(_redirectCount < _redirectLimit) && // to follow most of existing user agent implementations.
(_location.length() > 0) && //
(code == 301 || code == 302 || code == 307) && redirect = false;
(!strcmp(type, "GET") || !strcmp(type, "HEAD")) if (
) { _followRedirects != HTTPC_DISABLE_FOLLOW_REDIRECTS &&
_redirectCount += 1; // increment the count for redirect. redirectCount < _redirectLimit &&
redirect = true; _location.length() > 0
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] following redirect:: '%s' redirCount: %d\n", _location.c_str(), _redirectCount); ) {
if (!setURL(_location)) { switch (code) {
// return the redirect instead of handling on failure of setURL() // redirecting using the same method
redirect = false; case HTTP_CODE_MOVED_PERMANENTLY:
case HTTP_CODE_TEMPORARY_REDIRECT: {
if (
// allow to force redirections on other methods
// (the RFC require user to accept the redirection)
_followRedirects == HTTPC_FORCE_FOLLOW_REDIRECTS ||
// allow GET and HEAD methods without force
!strcmp(type, "GET") ||
!strcmp(type, "HEAD")
) {
redirectCount += 1;
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] following redirect (the same method): '%s' redirCount: %d\n", _location.c_str(), redirectCount);
if (!setURL(_location)) {
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] failed setting URL for redirection\n");
// no redirection
break;
}
// redirect using the same request method and payload, diffrent URL
redirect = true;
}
break;
}
// redirecting with method dropped to GET or HEAD
// note: it does not need `HTTPC_FORCE_FOLLOW_REDIRECTS` for any method
case HTTP_CODE_FOUND:
case HTTP_CODE_SEE_OTHER: {
redirectCount += 1;
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] following redirect (dropped to GET/HEAD): '%s' redirCount: %d\n", _location.c_str(), redirectCount);
if (!setURL(_location)) {
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] failed setting URL for redirection\n");
// no redirection
break;
}
// redirect after changing method to GET/HEAD and dropping payload
type = "GET";
payload = nullptr;
size = 0;
redirect = true;
break;
}
default:
break;
} }
} }
} while (redirect); } while (redirect);
// handle 303 redirect for non GET/HEAD by changing to GET and requesting new url
if (_followRedirects &&
(_redirectCount < _redirectLimit) &&
(_location.length() > 0) &&
(code == 303) &&
strcmp(type, "GET") && strcmp(type, "HEAD")
) {
_redirectCount += 1;
if (setURL(_location)) {
code = sendRequest("GET");
}
}
// handle Server Response (Header) // handle Server Response (Header)
return returnError(code); return returnError(code);
} }

View File

@ -130,6 +130,23 @@ typedef enum {
HTTPC_TE_CHUNKED HTTPC_TE_CHUNKED
} transferEncoding_t; } 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;
#if HTTPCLIENT_1_1_COMPATIBLE #if HTTPCLIENT_1_1_COMPATIBLE
class TransportTraits; class TransportTraits;
typedef std::unique_ptr<TransportTraits> TransportTraitsPtr; typedef std::unique_ptr<TransportTraits> TransportTraitsPtr;
@ -173,8 +190,12 @@ public:
void setAuthorization(const char * user, const char * password); void setAuthorization(const char * user, const char * password);
void setAuthorization(const char * auth); void setAuthorization(const char * auth);
void setTimeout(uint16_t timeout); void setTimeout(uint16_t timeout);
void setFollowRedirects(bool follow);
// Redirections
void setFollowRedirects(bool follow) __attribute__ ((deprecated));
void setFollowRedirects(followRedirects_t follow);
void setRedirectLimit(uint16_t limit); // max redirects to follow for a single request void setRedirectLimit(uint16_t limit); // max redirects to follow for a single request
bool setURL(const String& url); // handy for handling redirects bool setURL(const String& url); // handy for handling redirects
void useHTTP10(bool usehttp10 = true); void useHTTP10(bool usehttp10 = true);
@ -252,8 +273,7 @@ protected:
int _returnCode = 0; int _returnCode = 0;
int _size = -1; int _size = -1;
bool _canReuse = false; bool _canReuse = false;
bool _followRedirects = false; followRedirects_t _followRedirects = HTTPC_DISABLE_FOLLOW_REDIRECTS;
uint16_t _redirectCount = 0;
uint16_t _redirectLimit = 10; uint16_t _redirectLimit = 10;
String _location; String _location;
transferEncoding_t _transferEncoding = HTTPC_TE_IDENTITY; transferEncoding_t _transferEncoding = HTTPC_TE_IDENTITY;

View File

@ -186,12 +186,27 @@ void handleFileList() {
Dir dir = filesystem->openDir(path); Dir dir = filesystem->openDir(path);
path.clear(); path.clear();
String output = "["; // use HTTP/1.1 Chunked response to avoid building a huge temporary string
if (!server.chunkedResponseModeStart(200, "text/json")) {
server.send(505, FPSTR("text/html"), FPSTR("HTTP1.1 required"));
return;
}
// use the same string for every line
String output;
output.reserve(64);
while (dir.next()) { while (dir.next()) {
File entry = dir.openFile("r");
if (output != "[") { if (output.length()) {
output += ','; // send string from previous iteration
// as an HTTP chunk
server.sendContent(output);
output = ',';
} else {
output = '[';
} }
File entry = dir.openFile("r");
bool isDir = false; bool isDir = false;
output += "{\"type\":\""; output += "{\"type\":\"";
output += (isDir) ? "dir" : "file"; output += (isDir) ? "dir" : "file";
@ -205,8 +220,10 @@ void handleFileList() {
entry.close(); entry.close();
} }
// send last string
output += "]"; output += "]";
server.send(200, "text/json", output); server.sendContent(output);
server.chunkedResponseFinalize();
} }
void setup(void) { void setup(void) {

View File

@ -149,18 +149,36 @@ public:
void sendContent(const char *content) { sendContent_P(content); } void sendContent(const char *content) { sendContent_P(content); }
void sendContent(const char *content, size_t size) { sendContent_P(content, size); } void sendContent(const char *content, size_t size) { sendContent_P(content, size); }
bool chunkedResponseModeStart_P (int code, PGM_P content_type) {
if (_currentVersion == 0)
// no chunk mode in HTTP/1.0
return false;
setContentLength(CONTENT_LENGTH_UNKNOWN);
send_P(code, content_type, "");
return true;
}
bool chunkedResponseModeStart (int code, const char* content_type) {
return chunkedResponseModeStart_P(code, content_type);
}
bool chunkedResponseModeStart (int code, const String& content_type) {
return chunkedResponseModeStart_P(code, content_type.c_str());
}
void chunkedResponseFinalize () {
sendContent(emptyString);
}
static String credentialHash(const String& username, const String& realm, const String& password); static String credentialHash(const String& username, const String& realm, const String& password);
static String urlDecode(const String& text); static String urlDecode(const String& text);
// Handle a GET request by sending a response header and stream file content to response body // Handle a GET request by sending a response header and stream file content to response body
template<typename T> template<typename T>
size_t streamFile(T &file, const String& contentType) { size_t streamFile(T &file, const String& contentType) {
return streamFile(file, contentType, HTTP_GET); return streamFile(file, contentType, HTTP_GET);
} }
// Implement GET and HEAD requests for files. // Implement GET and HEAD requests for files.
// Stream body on HTTP_GET but not on HTTP_HEAD requests. // Stream body on HTTP_GET but not on HTTP_HEAD requests.
template<typename T> template<typename T>
size_t streamFile(T &file, const String& contentType, HTTPMethod requestMethod) { size_t streamFile(T &file, const String& contentType, HTTPMethod requestMethod) {
size_t contentLength = 0; size_t contentLength = 0;

View File

@ -1,4 +1,3 @@
/* /*
arduino IPv6 example arduino IPv6 example
released to public domain released to public domain
@ -27,7 +26,8 @@
#define STAPSK "your-password" #define STAPSK "your-password"
#endif #endif
#define FQDN F("www.google.com") // with both IPv4 & IPv6 addresses #define FQDN F("www.google.com") // with both IPv4 & IPv6 addresses
#define FQDN2 F("www.yahoo.com") // with both IPv4 & IPv6 addresses
#define FQDN6 F("ipv6.google.com") // does not resolve in IPv4 #define FQDN6 F("ipv6.google.com") // does not resolve in IPv4
#define STATUSDELAY_MS 10000 #define STATUSDELAY_MS 10000
#define TCP_PORT 23 #define TCP_PORT 23
@ -50,6 +50,21 @@ void fqdn(Print& out, const String& fqdn) {
} }
} }
#if LWIP_IPV4 && LWIP_IPV6
void fqdn_rt(Print& out, const String& fqdn, DNSResolveType resolveType) {
out.print(F("resolving "));
out.print(fqdn);
out.print(F(": "));
IPAddress result;
if (WiFi.hostByName(fqdn.c_str(), result, 10000, resolveType)) {
result.printTo(out);
out.println();
} else {
out.println(F("timeout or not found"));
}
}
#endif
void status(Print& out) { void status(Print& out) {
out.println(F("------------------------------")); out.println(F("------------------------------"));
out.println(ESP.getFullVersion()); out.println(ESP.getFullVersion());
@ -85,7 +100,10 @@ void status(Print& out) {
// an example is provided with a fqdn which does not resolve with IPv4 // an example is provided with a fqdn which does not resolve with IPv4
fqdn(out, FQDN); fqdn(out, FQDN);
fqdn(out, FQDN6); fqdn(out, FQDN6);
#if LWIP_IPV4 && LWIP_IPV6
fqdn_rt(out, FQDN, DNSResolveType::DNS_AddrType_IPv4_IPv6); // IPv4 before IPv6
fqdn_rt(out, FQDN2, DNSResolveType::DNS_AddrType_IPv6_IPv4); // IPv6 before IPv4
#endif
out.println(F("------------------------------")); out.println(F("------------------------------"));
} }

View File

@ -26,6 +26,7 @@ PublicKey KEYWORD1
CertStoreSPIFFSBearSSL KEYWORD1 CertStoreSPIFFSBearSSL KEYWORD1
CertStoreSDBearSSL KEYWORD1 CertStoreSDBearSSL KEYWORD1
Session KEYWORD1 Session KEYWORD1
ESP8266WiFiGratuitous KEYWORD1
####################################### #######################################
@ -108,6 +109,9 @@ psk KEYWORD2
BSSID KEYWORD2 BSSID KEYWORD2
BSSIDstr KEYWORD2 BSSIDstr KEYWORD2
RSSI KEYWORD2 RSSI KEYWORD2
stationKeepAliveSetIntervalMs KEYWORD2
stationKeepAliveStop KEYWORD2
stationKeepAliveNow KEYWORD2
enableInsecureWEP KEYWORD2 enableInsecureWEP KEYWORD2
getListenInterval KEYWORD2 getListenInterval KEYWORD2
isSleepLevelMax KEYWORD2 isSleepLevelMax KEYWORD2

View File

@ -870,9 +870,9 @@ uint32_t SigningVerifier::length()
} }
} }
bool SigningVerifier::verify(UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) { // We need to use the 2nd stack to do a verification, so do the thunk
if (!_pubKey || !hash || !signature || signatureLen != length()) return false; // directly inside the class function for ease of use.
extern "C" bool SigningVerifier_verify(PublicKey *_pubKey, UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) {
if (_pubKey->isRSA()) { if (_pubKey->isRSA()) {
bool ret; bool ret;
unsigned char vrf[hash->len()]; unsigned char vrf[hash->len()];
@ -890,6 +890,20 @@ bool SigningVerifier::verify(UpdaterHashClass *hash, const void *signature, uint
} }
}; };
#if !CORE_MOCK
make_stack_thunk(SigningVerifier_verify);
extern "C" bool thunk_SigningVerifier_verify(PublicKey *_pubKey, UpdaterHashClass *hash, const void *signature, uint32_t signatureLen);
#endif
bool SigningVerifier::verify(UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) {
if (!_pubKey || !hash || !signature || signatureLen != length()) return false;
#if !CORE_MOCK
return thunk_SigningVerifier_verify(_pubKey, hash, signature, signatureLen);
#else
return SigningVerifier_verify(_pubKey, hash, signature, signatureLen);
#endif
}
#if !CORE_MOCK #if !CORE_MOCK
// Second stack thunked helpers // Second stack thunked helpers

View File

@ -608,7 +608,7 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul
int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms) int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms)
{ {
ip_addr_t addr; ip_addr_t addr;
aResult = static_cast<uint32_t>(0); aResult = static_cast<uint32_t>(INADDR_NONE);
if(aResult.fromString(aHostname)) { if(aResult.fromString(aHostname)) {
// Host name is a IP address use it! // Host name is a IP address use it!
@ -617,7 +617,11 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul
} }
DEBUG_WIFI_GENERIC("[hostByName] request IP for: %s\n", aHostname); DEBUG_WIFI_GENERIC("[hostByName] request IP for: %s\n", aHostname);
#if LWIP_IPV4 && LWIP_IPV6
err_t err = dns_gethostbyname_addrtype(aHostname, &addr, &wifi_dns_found_callback, &aResult,LWIP_DNS_ADDRTYPE_DEFAULT);
#else
err_t err = dns_gethostbyname(aHostname, &addr, &wifi_dns_found_callback, &aResult); err_t err = dns_gethostbyname(aHostname, &addr, &wifi_dns_found_callback, &aResult);
#endif
if(err == ERR_OK) { if(err == ERR_OK) {
aResult = IPAddress(&addr); aResult = IPAddress(&addr);
} else if(err == ERR_INPROGRESS) { } else if(err == ERR_INPROGRESS) {
@ -640,6 +644,57 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul
return (err == ERR_OK) ? 1 : 0; return (err == ERR_OK) ? 1 : 0;
} }
#if LWIP_IPV4 && LWIP_IPV6
int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms, DNSResolveType resolveType)
{
ip_addr_t addr;
err_t err;
aResult = static_cast<uint32_t>(INADDR_NONE);
if(aResult.fromString(aHostname)) {
// Host name is a IP address use it!
DEBUG_WIFI_GENERIC("[hostByName] Host: %s is a IP!\n", aHostname);
return 1;
}
DEBUG_WIFI_GENERIC("[hostByName] request IP for: %s\n", aHostname);
switch(resolveType)
{
// Use selected addrtype
case DNSResolveType::DNS_AddrType_IPv4:
case DNSResolveType::DNS_AddrType_IPv6:
case DNSResolveType::DNS_AddrType_IPv4_IPv6:
case DNSResolveType::DNS_AddrType_IPv6_IPv4:
err = dns_gethostbyname_addrtype(aHostname, &addr, &wifi_dns_found_callback, &aResult, (uint8_t) resolveType);
break;
default:
err = dns_gethostbyname_addrtype(aHostname, &addr, &wifi_dns_found_callback, &aResult, LWIP_DNS_ADDRTYPE_DEFAULT); // If illegal type, use default.
break;
}
if(err == ERR_OK) {
aResult = IPAddress(&addr);
} else if(err == ERR_INPROGRESS) {
_dns_lookup_pending = true;
delay(timeout_ms);
// will resume on timeout or when wifi_dns_found_callback fires
_dns_lookup_pending = false;
// will return here when dns_found_callback fires
if(aResult.isSet()) {
err = ERR_OK;
}
}
if(err != 0) {
DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, (int)err);
} else {
DEBUG_WIFI_GENERIC("[hostByName] Host: %s IP: %s\n", aHostname, aResult.toString().c_str());
}
return (err == ERR_OK) ? 1 : 0;
}
#endif
/** /**
* DNS callback * DNS callback
* @param name * @param name

View File

@ -42,6 +42,14 @@ typedef std::shared_ptr<WiFiEventHandlerOpaque> WiFiEventHandler;
typedef void (*WiFiEventCb)(WiFiEvent_t); typedef void (*WiFiEventCb)(WiFiEvent_t);
enum class DNSResolveType: uint8_t
{
DNS_AddrType_IPv4 = 0, // LWIP_DNS_ADDRTYPE_IPV4 = 0
DNS_AddrType_IPv6, // LWIP_DNS_ADDRTYPE_IPV6 = 1
DNS_AddrType_IPv4_IPv6, // LWIP_DNS_ADDRTYPE_IPV4_IPV6 = 2
DNS_AddrType_IPv6_IPv4 // LWIP_DNS_ADDRTYPE_IPV6_IPV4 = 3
};
struct WiFiState; struct WiFiState;
class ESP8266WiFiGenericClass { class ESP8266WiFiGenericClass {
@ -113,6 +121,9 @@ class ESP8266WiFiGenericClass {
public: public:
int hostByName(const char* aHostname, IPAddress& aResult); int hostByName(const char* aHostname, IPAddress& aResult);
int hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms); int hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms);
#if LWIP_IPV4 && LWIP_IPV6
int hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms, DNSResolveType resolveType);
#endif
bool getPersistent(); bool getPersistent();
protected: protected:

View File

@ -0,0 +1,95 @@
/*
ESP8266WiFiGratuitous.cpp - esp8266 Wifi support
copyright esp8266/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
*/
extern "C"
{
#include "lwip/init.h" // LWIP_VERSION_*
#if LWIP_VERSION_MAJOR == 1
#include "netif/wlan_lwip_if.h" // eagle_lwip_getif()
#include "netif/etharp.h" // gratuitous arp
#include "user_interface.h"
#else
#include "lwip/etharp.h" // gratuitous arp
#endif
} // extern "C"
#include <Schedule.h>
#include "ESP8266WiFiGratuitous.h"
namespace experimental
{
ETSTimer* ESP8266WiFiGratuitous::_timer = nullptr;
void ESP8266WiFiGratuitous::stationKeepAliveNow ()
{
for (netif* interface = netif_list; interface != nullptr; interface = interface->next)
if (
(interface->flags & NETIF_FLAG_LINK_UP)
&& (interface->flags & NETIF_FLAG_UP)
#if LWIP_VERSION_MAJOR == 1
&& interface == eagle_lwip_getif(STATION_IF) /* lwip1 does not set if->num properly */
&& (!ip_addr_isany(&interface->ip_addr))
#else
&& interface->num == STATION_IF
&& (!ip4_addr_isany_val(*netif_ip4_addr(interface)))
#endif
)
{
etharp_gratuitous(interface);
break;
}
}
void ESP8266WiFiGratuitous::scheduleItForNextYieldOnce (void*)
{
schedule_recurrent_function_us([]()
{
ESP8266WiFiGratuitous::stationKeepAliveNow();
return false;
}, 0);
}
bool ESP8266WiFiGratuitous::stationKeepAliveSetIntervalMs (uint32_t ms)
{
if (_timer)
{
os_timer_disarm(_timer);
free(_timer);
_timer = nullptr;
}
if (ms)
{
// send one now
stationKeepAliveNow();
_timer = (ETSTimer*)malloc(sizeof(ETSTimer));
if (_timer == nullptr)
return false;
os_timer_setfn(_timer, ESP8266WiFiGratuitous::scheduleItForNextYieldOnce, nullptr);
os_timer_arm(_timer, ms, true);
}
return true;
}
}; // experimental::

View File

@ -0,0 +1,54 @@
/*
ESP8266WiFiGratuitous.h - esp8266 Wifi support
copyright esp8266/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
*/
#ifndef ESP8266WIFIGRATUITOUS_H_
#define ESP8266WIFIGRATUITOUS_H_
#include <stdint.h> // uint32_t
#include <ets_sys.h> // ETSTimer
namespace experimental
{
class ESP8266WiFiGratuitous
{
public:
// disable(0) or enable/update automatic sending of Gratuitous ARP packets.
// A gratuitous ARP packet is immediately sent when calling this function, then
// based on a time interval in milliseconds, default = 1s
// return value: true when started, false otherwise
static bool stationKeepAliveSetIntervalMs (uint32_t ms = 1000);
// request for stopping arp gratuitous packets
static void stationKeepAliveStop () { (void)stationKeepAliveSetIntervalMs(0); }
// immediately send one gratuitous ARP from STA
static void stationKeepAliveNow ();
protected:
static void scheduleItForNextYieldOnce (void*);
static ETSTimer* _timer;
};
}; // experimental::
#endif // ESP8266WIFIGRATUITOUS_H_

View File

@ -89,7 +89,7 @@ static bool sta_config_equal(const station_config& lhs, const station_config& rh
return false; return false;
} }
} }
if(lhs.threshold.rssi != rhs.threshold.rssi) { if(lhs.threshold.rssi != rhs.threshold.rssi) {
return false; return false;
} }

View File

@ -41,8 +41,8 @@ class ESP8266WiFiSTAClass {
wl_status_t begin(const String& ssid, const String& passphrase = emptyString, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); wl_status_t begin(const String& ssid, const String& passphrase = emptyString, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true);
wl_status_t begin(); wl_status_t begin();
//The argument order for ESP is not the same as for Arduino. However, there is compatibility code under the hood //The argument order for ESP is not the same as for Arduino. However, there is compatibility code under the hood
//to detect Arduino arg order, and handle it correctly. Be aware that the Arduino default value handling doesn't //to detect Arduino arg order, and handle it correctly. Be aware that the Arduino default value handling doesn't
//work here (see Arduino docs for gway/subnet defaults). In other words: at least 3 args must always be given. //work here (see Arduino docs for gway/subnet defaults). In other words: at least 3 args must always be given.
bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000); bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000);

View File

@ -127,8 +127,14 @@ public:
} }
} }
int connect(CONST ip_addr_t* addr, uint16_t port) int connect(ip_addr_t* addr, uint16_t port)
{ {
#if LWIP_IPV6
// Set zone so that link local addresses use the default interface
if (IP_IS_V6(addr) && ip6_addr_lacks_zone(ip_2_ip6(addr), IP6_UNKNOWN)) {
ip6_addr_assign_zone(ip_2_ip6(addr), IP6_UNKNOWN, netif_default);
}
#endif
err_t err = tcp_connect(_pcb, addr, port, &ClientContext::_s_connected); err_t err = tcp_connect(_pcb, addr, port, &ClientContext::_s_connected);
if (err != ERR_OK) { if (err != ERR_OK) {
return 0; return 0;

View File

@ -114,6 +114,12 @@ public:
{ {
_pcb->remote_ip = addr; _pcb->remote_ip = addr;
_pcb->remote_port = port; _pcb->remote_port = port;
#if LWIP_IPV6
// Set zone so that link local addresses use the default interface
if (IP_IS_V6(&_pcb->remote_ip) && ip6_addr_lacks_zone(ip_2_ip6(&_pcb->remote_ip), IP6_UNKNOWN)) {
ip6_addr_assign_zone(ip_2_ip6(&_pcb->remote_ip), IP6_UNKNOWN, netif_default);
}
#endif
return true; return true;
} }

View File

@ -30,12 +30,12 @@ extern "C" uint32_t _FS_start;
extern "C" uint32_t _FS_end; extern "C" uint32_t _FS_end;
ESP8266HTTPUpdate::ESP8266HTTPUpdate(void) ESP8266HTTPUpdate::ESP8266HTTPUpdate(void)
: _httpClientTimeout(8000), _followRedirects(false), _ledPin(-1) : _httpClientTimeout(8000), _followRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS), _ledPin(-1)
{ {
} }
ESP8266HTTPUpdate::ESP8266HTTPUpdate(int httpClientTimeout) ESP8266HTTPUpdate::ESP8266HTTPUpdate(int httpClientTimeout)
: _httpClientTimeout(httpClientTimeout), _followRedirects(false), _ledPin(-1) : _httpClientTimeout(httpClientTimeout), _followRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS), _ledPin(-1)
{ {
} }

View File

@ -82,7 +82,20 @@ public:
_rebootOnUpdate = reboot; _rebootOnUpdate = reboot;
} }
void followRedirects(bool follow) /**
* 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 avaliable modes.
* @param follow
*/
void setFollowRedirects(followRedirects_t follow)
{ {
_followRedirects = follow; _followRedirects = follow;
} }
@ -160,7 +173,7 @@ protected:
bool _closeConnectionsOnUpdate = true; bool _closeConnectionsOnUpdate = true;
private: private:
int _httpClientTimeout; int _httpClientTimeout;
bool _followRedirects; followRedirects_t _followRedirects;
// Callbacks // Callbacks
HTTPUpdateStartCB _cbStart; HTTPUpdateStartCB _cbStart;

View File

@ -767,6 +767,12 @@ uint32_t MDNSResponder::queryService(const char* p_pcService,
const char* p_pcProtocol, const char* p_pcProtocol,
const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/)
{ {
if (0 == m_pUDPContext)
{
// safeguard against misuse
return 0;
}
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService '%s.%s'\n"), p_pcService, p_pcProtocol);); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService '%s.%s'\n"), p_pcService, p_pcProtocol););
uint32_t u32Result = 0; uint32_t u32Result = 0;

@ -1 +1 @@
Subproject commit 94b2388a4752f2b165371313f4d942daebff6eee Subproject commit 91ea6b1b1c34601565b23c96c4441f2d399a4f99

View File

@ -35,30 +35,42 @@ public:
typedef void (*callback_with_arg_t)(void*); typedef void (*callback_with_arg_t)(void*);
typedef std::function<void(void)> callback_function_t; typedef std::function<void(void)> callback_function_t;
// callback will be called at following loop() after ticker fires
void attach_scheduled(float seconds, callback_function_t callback) void attach_scheduled(float seconds, callback_function_t callback)
{ {
_callback_function = [callback]() { schedule_function(callback); }; _callback_function = [callback]() { schedule_function(callback); };
_attach_ms(1000UL * seconds, true); _attach_ms(1000UL * seconds, true);
} }
// callback will be called in SYS ctx when ticker fires
void attach(float seconds, callback_function_t callback) void attach(float seconds, callback_function_t callback)
{ {
_callback_function = std::move(callback); _callback_function = std::move(callback);
_attach_ms(1000UL * seconds, true); _attach_ms(1000UL * seconds, true);
} }
// callback will be called at following loop() after ticker fires
void attach_ms_scheduled(uint32_t milliseconds, callback_function_t callback) void attach_ms_scheduled(uint32_t milliseconds, callback_function_t callback)
{ {
_callback_function = [callback]() { schedule_function(callback); }; _callback_function = [callback]() { schedule_function(callback); };
_attach_ms(milliseconds, true); _attach_ms(milliseconds, true);
} }
// callback will be called at following yield() after ticker fires
void attach_ms_scheduled_accurate(uint32_t milliseconds, callback_function_t callback)
{
_callback_function = [callback]() { schedule_recurrent_function_us([callback]() { callback(); return false; }, 0); };
_attach_ms(milliseconds, true);
}
// callback will be called in SYS ctx when ticker fires
void attach_ms(uint32_t milliseconds, callback_function_t callback) void attach_ms(uint32_t milliseconds, callback_function_t callback)
{ {
_callback_function = std::move(callback); _callback_function = std::move(callback);
_attach_ms(milliseconds, true); _attach_ms(milliseconds, true);
} }
// callback will be called in SYS ctx when ticker fires
template<typename TArg> template<typename TArg>
void attach(float seconds, void (*callback)(TArg), TArg arg) void attach(float seconds, void (*callback)(TArg), TArg arg)
{ {
@ -66,6 +78,7 @@ public:
_attach_ms(1000UL * seconds, true, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg)); _attach_ms(1000UL * seconds, true, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
} }
// callback will be called in SYS ctx when ticker fires
template<typename TArg> template<typename TArg>
void attach_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg) void attach_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg)
{ {
@ -73,30 +86,35 @@ public:
_attach_ms(milliseconds, true, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg)); _attach_ms(milliseconds, true, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
} }
// callback will be called at following loop() after ticker fires
void once_scheduled(float seconds, callback_function_t callback) void once_scheduled(float seconds, callback_function_t callback)
{ {
_callback_function = [callback]() { schedule_function(callback); }; _callback_function = [callback]() { schedule_function(callback); };
_attach_ms(1000UL * seconds, false); _attach_ms(1000UL * seconds, false);
} }
// callback will be called in SYS ctx when ticker fires
void once(float seconds, callback_function_t callback) void once(float seconds, callback_function_t callback)
{ {
_callback_function = std::move(callback); _callback_function = std::move(callback);
_attach_ms(1000UL * seconds, false); _attach_ms(1000UL * seconds, false);
} }
// callback will be called at following loop() after ticker fires
void once_ms_scheduled(uint32_t milliseconds, callback_function_t callback) void once_ms_scheduled(uint32_t milliseconds, callback_function_t callback)
{ {
_callback_function = [callback]() { schedule_function(callback); }; _callback_function = [callback]() { schedule_function(callback); };
_attach_ms(milliseconds, false); _attach_ms(milliseconds, false);
} }
// callback will be called in SYS ctx when ticker fires
void once_ms(uint32_t milliseconds, callback_function_t callback) void once_ms(uint32_t milliseconds, callback_function_t callback)
{ {
_callback_function = std::move(callback); _callback_function = std::move(callback);
_attach_ms(milliseconds, false); _attach_ms(milliseconds, false);
} }
// callback will be called in SYS ctx when ticker fires
template<typename TArg> template<typename TArg>
void once(float seconds, void (*callback)(TArg), TArg arg) void once(float seconds, void (*callback)(TArg), TArg arg)
{ {
@ -104,6 +122,7 @@ public:
_attach_ms(1000UL * seconds, false, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg)); _attach_ms(1000UL * seconds, false, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
} }
// callback will be called in SYS ctx when ticker fires
template<typename TArg> template<typename TArg>
void once_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg) void once_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg)
{ {

View File

@ -134,7 +134,7 @@ void showTime() {
Serial.println((uint32_t)now); Serial.println((uint32_t)now);
// timezone and demo in the future // timezone and demo in the future
Serial.printf("timezone: %s\n", getenv("TZ")); Serial.printf("timezone: %s\n", getenv("TZ") ? : "(none)");
// human readable // human readable
Serial.print("ctime: "); Serial.print("ctime: ");

View File

@ -378,4 +378,4 @@
] ]
} }
] ]
} }

View File

@ -71,10 +71,10 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]")
http.end(); http.end();
} }
{ {
// 301 redirect with follow enabled // GET 301 redirect with strict RFC follow enabled
WiFiClient client; WiFiClient client;
HTTPClient http; HTTPClient http;
http.setFollowRedirects(true); http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
String uri = String("/redirect301?host=")+getenv("SERVER_IP"); String uri = String("/redirect301?host=")+getenv("SERVER_IP");
http.begin(client, getenv("SERVER_IP"), 8088, uri.c_str()); http.begin(client, getenv("SERVER_IP"), 8088, uri.c_str());
auto httpCode = http.GET(); auto httpCode = http.GET();
@ -83,7 +83,7 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]")
REQUIRE(payload == "redirect success"); REQUIRE(payload == "redirect success");
} }
{ {
// 301 redirect with follow disabled // GET 301 redirect with follow disabled
WiFiClient client; WiFiClient client;
HTTPClient http; HTTPClient http;
String uri = String("/redirect301?host=")+getenv("SERVER_IP"); String uri = String("/redirect301?host=")+getenv("SERVER_IP");
@ -92,10 +92,10 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]")
REQUIRE(httpCode == 301); REQUIRE(httpCode == 301);
} }
{ {
// 302 redirect with follow enabled // GET 302 redirect with strict RFC follow enabled
WiFiClient client; WiFiClient client;
HTTPClient http; HTTPClient http;
http.setFollowRedirects(true); http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
String uri = String("/redirect302?host=")+getenv("SERVER_IP"); String uri = String("/redirect302?host=")+getenv("SERVER_IP");
http.begin(client, getenv("SERVER_IP"), 8088, uri.c_str()); http.begin(client, getenv("SERVER_IP"), 8088, uri.c_str());
auto httpCode = http.GET(); auto httpCode = http.GET();
@ -104,7 +104,7 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]")
REQUIRE(payload == "redirect success"); REQUIRE(payload == "redirect success");
} }
{ {
// 302 redirect with follow disabled // GET 302 redirect with follow disabled
WiFiClient client; WiFiClient client;
HTTPClient http; HTTPClient http;
String uri = String("/redirect302?host=")+getenv("SERVER_IP"); String uri = String("/redirect302?host=")+getenv("SERVER_IP");
@ -113,10 +113,10 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]")
REQUIRE(httpCode == 302); REQUIRE(httpCode == 302);
} }
{ {
// 307 redirect with follow enabled // GET 307 redirect with strict RFC follow enabled
WiFiClient client; WiFiClient client;
HTTPClient http; HTTPClient http;
http.setFollowRedirects(true); http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
String uri = String("/redirect307?host=")+getenv("SERVER_IP"); String uri = String("/redirect307?host=")+getenv("SERVER_IP");
http.begin(client, getenv("SERVER_IP"), 8088, uri.c_str()); http.begin(client, getenv("SERVER_IP"), 8088, uri.c_str());
auto httpCode = http.GET(); auto httpCode = http.GET();
@ -125,7 +125,7 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]")
REQUIRE(payload == "redirect success"); REQUIRE(payload == "redirect success");
} }
{ {
// 307 redirect with follow disabled // GET 307 redirect with follow disabled
WiFiClient client; WiFiClient client;
HTTPClient http; HTTPClient http;
String uri = String("/redirect307?host=")+getenv("SERVER_IP"); String uri = String("/redirect307?host=")+getenv("SERVER_IP");
@ -134,10 +134,10 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]")
REQUIRE(httpCode == 307); REQUIRE(httpCode == 307);
} }
{ {
// 301 exceeding redirect limit // GET 301 exceeding redirect limit
WiFiClient client; WiFiClient client;
HTTPClient http; HTTPClient http;
http.setFollowRedirects(true); http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
http.setRedirectLimit(0); http.setRedirectLimit(0);
String uri = String("/redirect301?host=")+getenv("SERVER_IP"); String uri = String("/redirect301?host=")+getenv("SERVER_IP");
http.begin(client, getenv("SERVER_IP"), 8088, uri.c_str()); http.begin(client, getenv("SERVER_IP"), 8088, uri.c_str());
@ -145,20 +145,22 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]")
REQUIRE(httpCode == 301); REQUIRE(httpCode == 301);
} }
{ {
// POST 303 redirect with follow enabled // POST 303 redirect with strict RFC follow enabled
WiFiClient client; WiFiClient client;
HTTPClient http; HTTPClient http;
http.setFollowRedirects(true); http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
http.begin(client, getenv("SERVER_IP"), 8088, "/redirect303"); http.begin(client, getenv("SERVER_IP"), 8088, "/redirect303");
auto httpCode = http.POST(getenv("SERVER_IP")); auto httpCode = http.POST(getenv("SERVER_IP"));
REQUIRE(httpCode == HTTP_CODE_OK); REQUIRE(httpCode == HTTP_CODE_OK);
String payload = http.getString(); String payload = http.getString();
REQUIRE(payload == "redirect success"); REQUIRE(payload == "redirect success");
// TODO: need check for dropping: redirection should use GET method
} }
{ {
// POST 303 redirect with follow disabled // POST 303 redirect with follow disabled
WiFiClient client; WiFiClient client;
HTTPClient http; HTTPClient http;
http.setFollowRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS);
http.begin(client, getenv("SERVER_IP"), 8088, "/redirect303"); http.begin(client, getenv("SERVER_IP"), 8088, "/redirect303");
auto httpCode = http.POST(getenv("SERVER_IP")); auto httpCode = http.POST(getenv("SERVER_IP"));
REQUIRE(httpCode == 303); REQUIRE(httpCode == 303);
@ -167,6 +169,7 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]")
// 302 redirect with follow disabled // 302 redirect with follow disabled
WiFiClient client; WiFiClient client;
HTTPClient http; HTTPClient http;
http.setFollowRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS);
String uri = String("/redirect302?host=")+getenv("SERVER_IP"); String uri = String("/redirect302?host=")+getenv("SERVER_IP");
http.begin(client, getenv("SERVER_IP"), 8088, uri.c_str()); http.begin(client, getenv("SERVER_IP"), 8088, uri.c_str());
auto httpCode = http.GET(); auto httpCode = http.GET();

View File

@ -118,11 +118,6 @@ uint32_t EspClass::getFreeSketchSpace()
return 4 * 1024 * 1024; return 4 * 1024 * 1024;
} }
uint8_t EspClass::getCpuFreqMHz()
{
return F_CPU / 1000000;
}
const char *EspClass::getSdkVersion() const char *EspClass::getSdkVersion()
{ {
return "2.5.0"; return "2.5.0";

View File

@ -26,4 +26,11 @@ const ip_addr_t* sntp_getserver(u8_t)
return IP_ADDR_ANY; return IP_ADDR_ANY;
} }
err_t etharp_request(struct netif *netif, const ip4_addr_t *ipaddr)
{
(void)netif;
(void)ipaddr;
return ERR_OK;
}
} // extern "C" } // extern "C"

View File

@ -7,8 +7,8 @@ source "$TRAVIS_BUILD_DIR"/tests/common.sh
function install_platformio() function install_platformio()
{ {
pip3 install --user -U https://github.com/platformio/platformio/archive/develop.zip pip3 install --user -U https://github.com/platformio/platformio/archive/develop.zip
platformio platform install "https://github.com/platformio/platform-espressif8266.git#feature/stage" platformio platform install "https://github.com/platformio/platform-espressif8266.git"
sed -i 's/https:\/\/github\.com\/esp8266\/Arduino\.git/*/' ~/.platformio/platforms/espressif8266/platform.json python -c "import json; import os; fp=open(os.path.expanduser('~/.platformio/platforms/espressif8266/platform.json'), 'r+'); data=json.load(fp); data['packages']['framework-arduinoespressif8266']['version'] = '*'; fp.seek(0); fp.truncate(); json.dump(data, fp); fp.close()"
ln -sf $TRAVIS_BUILD_DIR ~/.platformio/packages/framework-arduinoespressif8266 ln -sf $TRAVIS_BUILD_DIR ~/.platformio/packages/framework-arduinoespressif8266
# Install dependencies: # Install dependencies:
# - esp8266/examples/ConfigFile # - esp8266/examples/ConfigFile

View File

@ -286,7 +286,7 @@ boards = collections.OrderedDict([
'crystalfreq_menu', 'crystalfreq_menu',
'flashmode_dout', 'flashmode_dout',
'flashfreq_40', 'flashfreq_40',
'1M', '1M', '2M',
'led', 'led',
], ],
'desc': [ 'ESP8285 (`datasheet <http://www.espressif.com/sites/default/files/0a-esp8285_datasheet_en_v1.0_20160422.pdf>`__) is a multi-chip package which contains ESP8266 and 1MB flash. All points related to bootstrapping resistors and recommended circuits listed above apply to ESP8285 as well.', 'desc': [ 'ESP8285 (`datasheet <http://www.espressif.com/sites/default/files/0a-esp8285_datasheet_en_v1.0_20160422.pdf>`__) is a multi-chip package which contains ESP8266 and 1MB flash. All points related to bootstrapping resistors and recommended circuits listed above apply to ESP8285 as well.',

View File

@ -132,7 +132,7 @@ def serve(remoteAddr, localAddr, remotePort, localPort, password, filename, comm
sys.stderr.write('FAIL\n') sys.stderr.write('FAIL\n')
logging.error('%s', data) logging.error('%s', data)
sock2.close() sock2.close()
sys.exit(1); sys.exit(1)
return 1 return 1
sys.stderr.write('OK\n') sys.stderr.write('OK\n')
else: else:
@ -172,7 +172,7 @@ def serve(remoteAddr, localAddr, remotePort, localPort, password, filename, comm
connection.sendall(chunk) connection.sendall(chunk)
if connection.recv(32).decode().find('O') >= 0: if connection.recv(32).decode().find('O') >= 0:
# connection will receive only digits or 'OK' # connection will receive only digits or 'OK'
received_ok = True; received_ok = True
except: except:
sys.stderr.write('\n') sys.stderr.write('\n')
logging.error('Error Uploading') logging.error('Error Uploading')
@ -188,19 +188,25 @@ def serve(remoteAddr, localAddr, remotePort, localPort, password, filename, comm
# the connection before receiving the 'O' of 'OK' # the connection before receiving the 'O' of 'OK'
try: try:
connection.settimeout(60) connection.settimeout(60)
while not received_ok: received_ok = False
if connection.recv(32).decode().find('O') >= 0: received_error = False
# connection will receive only digits or 'OK' while not (received_ok or received_error):
received_ok = True; reply = connection.recv(64).decode()
logging.info('Result: OK') # Look for either the "E" in ERROR or the "O" in OK response
# Check for "E" first, since both strings contain "O"
if reply.find('E') >= 0:
sys.stderr.write('\n')
logging.error('%s', reply)
received_error = True
elif reply.find('O') >= 0:
logging.info('Result: OK')
received_ok = True
connection.close() connection.close()
f.close() f.close()
sock.close() sock.close()
if (data != "OK"): if received_ok:
sys.stderr.write('\n') return 0
logging.error('%s', data) return 1
return 1;
return 0
except: except:
logging.error('No Result!') logging.error('No Result!')
connection.close() connection.close()

View File

@ -247,9 +247,12 @@ else:
# #
current_vtables = None current_vtables = None
fp_in_irom = ""
for d in flatten_cppdefines: for d in flatten_cppdefines:
if str(d).startswith("VTABLES_IN_"): if str(d).startswith("VTABLES_IN_"):
current_vtables = d current_vtables = d
if str(d) == "FP_IN_IROM":
fp_in_irom = "-DFP_IN_IROM"
if not current_vtables: if not current_vtables:
current_vtables = "VTABLES_IN_FLASH" current_vtables = "VTABLES_IN_FLASH"
env.Append(CPPDEFINES=[current_vtables]) env.Append(CPPDEFINES=[current_vtables])
@ -260,7 +263,7 @@ app_ld = env.Command(
join("$BUILD_DIR", "ld", "local.eagle.app.v6.common.ld"), join("$BUILD_DIR", "ld", "local.eagle.app.v6.common.ld"),
join(FRAMEWORK_DIR, "tools", "sdk", "ld", "eagle.app.v6.common.ld.h"), join(FRAMEWORK_DIR, "tools", "sdk", "ld", "eagle.app.v6.common.ld.h"),
env.VerboseAction( env.VerboseAction(
"$CC -CC -E -P -D%s $SOURCE -o $TARGET" % current_vtables, "$CC -CC -E -P -D%s %s $SOURCE -o $TARGET" % (current_vtables, fp_in_irom),
"Generating LD script $TARGET")) "Generating LD script $TARGET"))
env.Depends("$BUILD_DIR/$PROGNAME$PROGSUFFIX", app_ld) env.Depends("$BUILD_DIR/$PROGNAME$PROGSUFFIX", app_ld)

View File

@ -151,6 +151,14 @@ SECTIONS
*libc.a:(.literal .text .literal.* .text.*) *libc.a:(.literal .text .literal.* .text.*)
*libm.a:(.literal .text .literal.* .text.*) *libm.a:(.literal .text .literal.* .text.*)
#ifdef FP_IN_IROM
*libgcc.a:*f2.o(.literal .text)
*libgcc.a:*f3.o(.literal .text)
*libgcc.a:*fsi.o(.literal .text)
*libgcc.a:*fdi.o(.literal .text)
*libgcc.a:*ifs.o(.literal .text)
*libgcc.a:*idf.o(.literal .text)
#endif
*libgcc.a:_umoddi3.o(.literal .text) *libgcc.a:_umoddi3.o(.literal .text)
*libgcc.a:_udivdi3.o(.literal .text) *libgcc.a:_udivdi3.o(.literal .text)
*libstdc++.a:( .literal .text .literal.* .text.*) *libstdc++.a:( .literal .text .literal.* .text.*)