diff --git a/README.md b/README.md index 2b198c63b..776a7550d 100644 --- a/README.md +++ b/README.md @@ -48,19 +48,19 @@ Also known as latest git or master branch. ### 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 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=github&utm_medium=arduino-esp8266) -- [PlatformIO IDE](https://platformio.org/platformio-ide?utm_source=github&utm_medium=arduino-esp8266) -- [PlatformIO Core](https://docs.platformio.org/en/latest/core.html?utm_source=github&utm_medium=arduino-esp8266) (command line tool) -- [Advanced usage](https://docs.platformio.org/en/latest/platforms/espressif8266.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=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=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 -- [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 diff --git a/boards.txt b/boards.txt index bcbf48813..9499d2354 100644 --- a/boards.txt +++ b/boards.txt @@ -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.upload.maximum_size=1023984 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.build.led=-DLED_BUILTIN=2 esp8285.menu.led.0=0 diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp index a0e525f2b..db29ec599 100644 --- a/cores/esp8266/Esp.cpp +++ b/cores/esp8266/Esp.cpp @@ -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) { __real_system_restart_local(); @@ -267,11 +264,12 @@ uint8_t EspClass::getBootMode(void) return system_get_boot_mode(); } +#ifndef F_CPU uint8_t EspClass::getCpuFreqMHz(void) { return system_get_cpu_freq(); } - +#endif uint32_t EspClass::getFlashChipId(void) { diff --git a/cores/esp8266/Esp.h b/cores/esp8266/Esp.h index f4529c839..01327747e 100644 --- a/cores/esp8266/Esp.h +++ b/cores/esp8266/Esp.h @@ -157,7 +157,14 @@ class EspClass { uint8_t getBootVersion(); uint8_t getBootMode(); +#if defined(F_CPU) || defined(CORE_MOCK) + constexpr uint8_t getCpuFreqMHz() const + { + return clockCyclesPerMicrosecond(); + } +#else uint8_t getCpuFreqMHz(); +#endif uint32_t getFlashChipId(); uint8_t getFlashChipVendorId(); @@ -201,6 +208,7 @@ class EspClass { }; #ifndef CORE_MOCK + uint32_t EspClass::getCycleCount() { return esp_get_cycle_count(); diff --git a/cores/esp8266/MD5Builder.cpp b/cores/esp8266/MD5Builder.cpp index b32693ed7..3d068b949 100644 --- a/cores/esp8266/MD5Builder.cpp +++ b/cores/esp8266/MD5Builder.cpp @@ -1,10 +1,11 @@ #include #include +#include -uint8_t hex_char_to_byte(uint8_t c){ - return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) : - (c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) : - (c >= '0' && c<= '9') ? (c - (uint8_t)'0') : 0; +uint8_t hex_char_to_byte(uint8_t c) { + return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) : + (c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) : + (c >= '0' && c <= '9') ? (c - (uint8_t)'0') : 0; } void MD5Builder::begin(void){ @@ -18,25 +19,27 @@ void MD5Builder::add(const uint8_t * data, const uint16_t len){ void MD5Builder::addHexString(const char * data){ uint16_t i, len = strlen(data); - uint8_t * tmp = (uint8_t*)malloc(len/2); - if(tmp == NULL) { + auto tmp = std::unique_ptr{new(std::nothrow) uint8_t[len / 2]}; + + if (!tmp) { return; } + for(i=0; i{new(std::nothrow) uint8_t[buf_size]}; + + if (!buf) { return false; } @@ -45,21 +48,21 @@ bool MD5Builder::addStream(Stream & stream, const size_t maxLen){ // determine number of bytes to read int readBytes = bytesAvailable; - if(readBytes > maxLengthLeft) { - readBytes = maxLengthLeft ; // read only until max_len + if (readBytes > maxLengthLeft){ + 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 } // read data and check if we got something - int numBytesRead = stream.readBytes(buf, readBytes); - if(numBytesRead< 1) { + int numBytesRead = stream.readBytes(buf.get(), readBytes); + if (numBytesRead < 1) { return false; } // Update MD5 with buffer payload - MD5Update(&_ctx, buf, numBytesRead); + MD5Update(&_ctx, buf.get(), numBytesRead); yield(); // time for network streams @@ -67,7 +70,7 @@ bool MD5Builder::addStream(Stream & stream, const size_t maxLen){ maxLengthLeft -= numBytesRead; bytesAvailable = stream.available(); } - free(buf); + return true; } @@ -75,17 +78,17 @@ void MD5Builder::calculate(void){ MD5Final(_buf, &_ctx); } -void MD5Builder::getBytes(uint8_t * output){ +void MD5Builder::getBytes(uint8_t * output) const { memcpy(output, _buf, 16); } -void MD5Builder::getChars(char * output){ - for(uint8_t i = 0; i < 16; i++) { +void MD5Builder::getChars(char * output) const { + for (uint8_t i=0; i<16; i++){ sprintf(output + (i * 2), "%02x", _buf[i]); } } -String MD5Builder::toString(void){ +String MD5Builder::toString(void) const { char out[33]; getChars(out); return String(out); diff --git a/cores/esp8266/MD5Builder.h b/cores/esp8266/MD5Builder.h index 6c6d560a0..c3fbce573 100644 --- a/cores/esp8266/MD5Builder.h +++ b/cores/esp8266/MD5Builder.h @@ -40,9 +40,9 @@ class MD5Builder { void addHexString(const String& data){ addHexString(data.c_str()); } bool addStream(Stream & stream, const size_t maxLen); void calculate(void); - void getBytes(uint8_t * output); - void getChars(char * output); - String toString(void); + void getBytes(uint8_t * output) const; + void getChars(char * output) const; + String toString(void) const; }; diff --git a/cores/esp8266/PolledTimeout.h b/cores/esp8266/PolledTimeout.h index fe9c9ca4b..715564a8e 100644 --- a/cores/esp8266/PolledTimeout.h +++ b/cores/esp8266/PolledTimeout.h @@ -76,7 +76,7 @@ struct TimeSourceCycles using timeType = decltype(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 }; diff --git a/cores/esp8266/StackThunk.cpp b/cores/esp8266/StackThunk.cpp index 541cd440f..4b708bcc6 100644 --- a/cores/esp8266/StackThunk.cpp +++ b/cores/esp8266/StackThunk.cpp @@ -26,6 +26,9 @@ #include #include +#include +#include "pgmspace.h" +#include "debug.h" #include "StackThunk.h" #include @@ -46,6 +49,11 @@ void stack_thunk_add_ref() stack_thunk_refcnt++; if (stack_thunk_refcnt == 1) { 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_save = NULL; stack_thunk_repaint(); diff --git a/cores/esp8266/Tone.cpp b/cores/esp8266/Tone.cpp index 35a5a4151..ff895f153 100644 --- a/cores/esp8266/Tone.cpp +++ b/cores/esp8266/Tone.cpp @@ -22,6 +22,7 @@ */ #include "Arduino.h" +#include "user_interface.h" #include "core_esp8266_waveform.h" // 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); - high = std::max(high, (uint32_t)100); - low = std::max(low, (uint32_t)100); + high = std::max(high, (uint32_t)microsecondsToClockCycles(25)); // new 20KHz maximum tone frequency, + 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; } } @@ -48,7 +49,7 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) { if (frequency == 0) { noTone(_pin); } else { - uint32_t period = 1000000L / frequency; + uint32_t period = (1000000L * system_get_cpu_freq()) / frequency; uint32_t high = period / 2; uint32_t low = period - high; _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 noTone(_pin); } 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 low = (uint32_t)(period + 0.5) - high; _startTone(_pin, high, low, duration); diff --git a/cores/esp8266/Updater.cpp b/cores/esp8266/Updater.cpp index 70d16a55e..351a57746 100644 --- a/cores/esp8266/Updater.cpp +++ b/cores/esp8266/Updater.cpp @@ -1,6 +1,7 @@ #include "Updater.h" #include "eboot_command.h" #include +#include "StackThunk.h" //#define DEBUG_UPDATER Serial @@ -40,6 +41,14 @@ UpdaterClass::UpdaterClass() { #if ARDUINO_SIGNING installSignature(&esp8266::updaterSigningHash, &esp8266::updaterSigningVerifier); + stack_thunk_add_ref(); +#endif +} + +UpdaterClass::~UpdaterClass() +{ +#if ARDUINO_SIGNING + stack_thunk_del_ref(); #endif } @@ -199,6 +208,7 @@ bool UpdaterClass::end(bool evenIfRemaining){ #ifdef DEBUG_UPDATER DEBUG_UPDATER.println(F("no update")); #endif + _reset(); return false; } @@ -206,7 +216,6 @@ bool UpdaterClass::end(bool evenIfRemaining){ #ifdef DEBUG_UPDATER DEBUG_UPDATER.printf_P(PSTR("premature end: res:%u, pos:%zu/%zu\n"), getError(), progress(), _size); #endif - _reset(); return false; } @@ -226,6 +235,7 @@ bool UpdaterClass::end(bool evenIfRemaining){ #endif if (sigLen != _verify->length()) { _setError(UPDATE_ERROR_SIGN); + _reset(); return false; } @@ -251,6 +261,7 @@ bool UpdaterClass::end(bool evenIfRemaining){ uint8_t *sig = (uint8_t*)malloc(sigLen); if (!sig) { _setError(UPDATE_ERROR_SIGN); + _reset(); return false; } ESP.flashRead(_startAddress + binSize, (uint32_t *)sig, sigLen); @@ -262,9 +273,12 @@ bool UpdaterClass::end(bool evenIfRemaining){ DEBUG_UPDATER.printf("\n"); #endif if (!_verify->verify(_hash, (void *)sig, sigLen)) { + free(sig); _setError(UPDATE_ERROR_SIGN); + _reset(); return false; } + free(sig); #ifdef DEBUG_UPDATER DEBUG_UPDATER.printf_P(PSTR("[Updater] Signature matches\n")); #endif diff --git a/cores/esp8266/Updater.h b/cores/esp8266/Updater.h index d47c61333..f51edc5b7 100644 --- a/cores/esp8266/Updater.h +++ b/cores/esp8266/Updater.h @@ -53,6 +53,7 @@ class UpdaterClass { typedef std::function THandlerFunction_Progress; UpdaterClass(); + ~UpdaterClass(); /* Optionally add a cryptographic signature verification hash and method */ void installSignature(UpdaterHashClass *hash, UpdaterVerifyClass *verify) { _hash = hash; _verify = verify; } diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index a95c4b2c1..0ec4f1f3b 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -81,14 +81,25 @@ void initVariant() __attribute__((weak)); void initVariant() { } -void preloop_update_frequency() __attribute__((weak)); -void preloop_update_frequency() { +extern "C" void __preloop_update_frequency() { #if defined(F_CPU) && (F_CPU == 160000000L) - REG_SET_BIT(0x3ff00014, BIT(0)); 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 } +extern "C" void preloop_update_frequency() __attribute__((weak, alias("__preloop_update_frequency"))); + extern "C" bool can_yield() { return cont_can_yield(g_pcont); } diff --git a/cores/esp8266/core_esp8266_postmortem.cpp b/cores/esp8266/core_esp8266_postmortem.cpp index 84aad50a0..2af579883 100644 --- a/cores/esp8266/core_esp8266_postmortem.cpp +++ b/cores/esp8266/core_esp8266_postmortem.cpp @@ -32,11 +32,10 @@ #include "pgmspace.h" #include "gdb_hooks.h" #include "StackThunk.h" +#include "coredecls.h" extern "C" { -extern void __real_system_restart_local(); - // These will be pointers to PROGMEM const strings static const char* s_panic_file = 0; static int s_panic_line = 0; diff --git a/cores/esp8266/core_esp8266_waveform.cpp b/cores/esp8266/core_esp8266_waveform.cpp index 59fce8695..e3924cf08 100644 --- a/cores/esp8266/core_esp8266_waveform.cpp +++ b/cores/esp8266/core_esp8266_waveform.cpp @@ -112,15 +112,19 @@ void setTimer1Callback(uint32_t (*fn)()) { // waveform smoothly on next low->high transition. For immediate change, stopWaveform() // first, then it will immediately begin. 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; } Waveform *wave = &waveform[pin]; // Adjust to shave off some of the IRQ time, approximately - wave->nextTimeHighCycles = microsecondsToClockCycles(timeHighUS); - wave->nextTimeLowCycles = microsecondsToClockCycles(timeLowUS); - wave->expiryCycle = runTimeUS ? GetCycleCount() + microsecondsToClockCycles(runTimeUS) : 0; - if (runTimeUS && !wave->expiryCycle) { + wave->nextTimeHighCycles = timeHighCycles; + wave->nextTimeLowCycles = timeLowCycles; + wave->expiryCycle = runTimeCycles ? GetCycleCount() + runTimeCycles : 0; + if (runTimeCycles && !wave->expiryCycle) { wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it } diff --git a/cores/esp8266/core_esp8266_waveform.h b/cores/esp8266/core_esp8266_waveform.h index 24ce91fb3..9a5f2ce37 100644 --- a/cores/esp8266/core_esp8266_waveform.h +++ b/cores/esp8266/core_esp8266_waveform.h @@ -50,6 +50,8 @@ extern "C" { // If runtimeUS > 0 then automatically stop it after that many usecs. // Returns true or false on success or failure. 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. // Returns true or false on success or failure. int stopWaveform(uint8_t pin); diff --git a/cores/esp8266/core_esp8266_wiring_digital.cpp b/cores/esp8266/core_esp8266_wiring_digital.cpp index 47eeebf86..ab6ed5dee 100644 --- a/cores/esp8266/core_esp8266_wiring_digital.cpp +++ b/cores/esp8266/core_esp8266_wiring_digital.cpp @@ -235,21 +235,23 @@ extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode) __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() { //Disable UART interrupts system_set_os_print(0); U0IE = 0; U1IE = 0; - for (int i = 0; i <= 5; ++i) { - pinMode(i, INPUT); - } - // pins 6-11 are used for the SPI flash interface - for (int i = 12; i <= 16; ++i) { - pinMode(i, INPUT); - } + resetPins(); } +extern void resetPins() __attribute__ ((weak, alias("__resetPins"))); 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 int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead"), nothrow)); diff --git a/cores/esp8266/core_esp8266_wiring_pwm.cpp b/cores/esp8266/core_esp8266_wiring_pwm.cpp index 5a3481bbd..b15b95f82 100644 --- a/cores/esp8266/core_esp8266_wiring_pwm.cpp +++ b/cores/esp8266/core_esp8266_wiring_pwm.cpp @@ -25,6 +25,7 @@ #include "core_esp8266_waveform.h" extern "C" { +#include "user_interface.h" static uint32_t analogMap = 0; static int32_t analogScale = PWMRANGE; @@ -50,7 +51,7 @@ extern void __analogWrite(uint8_t pin, int val) { if (pin > 16) { return; } - uint32_t analogPeriod = 1000000L / analogFreq; + uint32_t analogPeriod = (1000000L * system_get_cpu_freq()) / analogFreq; if (val < 0) { val = 0; } else if (val > analogScale) { @@ -68,7 +69,7 @@ extern void __analogWrite(uint8_t pin, int val) { stopWaveform(pin); digitalWrite(pin, LOW); } else { - if (startWaveform(pin, high, low, 0)) { + if (startWaveformCycles(pin, high, low, 0)) { analogMap |= (1 << pin); } } diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h index 86ba43711..aa37cb06b 100644 --- a/cores/esp8266/coredecls.h +++ b/cores/esp8266/coredecls.h @@ -21,6 +21,7 @@ void esp_schedule(); void tune_timeshift64 (uint64_t now_us); void disable_extra4k_at_link_time (void) __attribute__((noinline)); bool sntp_set_timezone_in_seconds(int32_t timezone); +void __real_system_restart_local() __attribute__((noreturn)); uint32_t sqrt32 (uint32_t n); uint32_t crc32 (const void* data, size_t length, uint32_t crc = 0xffffffff); diff --git a/cores/esp8266/wiring_private.h b/cores/esp8266/wiring_private.h index 2c53565a6..cb52f0539 100644 --- a/cores/esp8266/wiring_private.h +++ b/cores/esp8266/wiring_private.h @@ -37,6 +37,7 @@ extern "C" { typedef void (*voidFuncPtr)(void); void initPins(); +void resetPins(); #ifdef __cplusplus } // extern "C" diff --git a/doc/installing.rst b/doc/installing.rst index ca9e3f449..515fc891f 100644 --- a/doc/installing.rst +++ b/doc/installing.rst @@ -230,3 +230,20 @@ Instructions - Other OS cd hardware\esp8266com\esp8266 git status git pull + +Using PlatformIO +---------------- + +`PlatformIO `__ +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? `__ +- `PlatformIO IDE `__ +- `PlatformIO Core `__ (command line tool) +- `Advanced usage `__ - custom settings, uploading to SPIFFS, Over-the-Air (OTA), staging version +- `Integration with Cloud and Standalone IDEs `__ - Cloud9, Codeanywhere, Eclipse Che (Codenvy), Atom, CLion, Eclipse, Emacs, NetBeans, Qt Creator, Sublime Text, VIM, Visual Studio, and VSCode +- `Project Examples `__ diff --git a/libraries/ArduinoOTA/ArduinoOTA.cpp b/libraries/ArduinoOTA/ArduinoOTA.cpp index 0b0789474..64e8397a2 100644 --- a/libraries/ArduinoOTA/ArduinoOTA.cpp +++ b/libraries/ArduinoOTA/ArduinoOTA.cpp @@ -328,9 +328,13 @@ void ArduinoOTAClass::_runUpdate() { } if (Update.end()) { - client.print("OK"); - client.stop(); + // Ensure last count packet has been sent out and not combined with the final OK + client.flush(); delay(1000); + client.print("OK"); + client.flush(); + delay(1000); + client.stop(); #ifdef OTA_DEBUG OTA_DEBUG.printf("Update Success\n"); #endif diff --git a/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp b/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp index ff46822c3..5212dcf3e 100644 --- a/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp +++ b/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp @@ -423,7 +423,6 @@ void HTTPClient::end(void) { disconnect(false); clear(); - _redirectCount = 0; } /** @@ -558,8 +557,17 @@ bool HTTPClient::setURL(const String& url) /** * set true to follow redirects. * @param follow + * @deprecated */ 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; } @@ -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 code; bool redirect = false; - int code = 0; + uint16_t redirectCount = 0; do { // wipe out any existing headers from previous request 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 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); written = _client->write(p + bytesWritten, towrite); if (written < 0) { - return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); + return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); } else if (written == 0) { - return returnError(HTTPC_ERROR_CONNECTION_LOST); + return returnError(HTTPC_ERROR_CONNECTION_LOST); } bytesWritten += written; size -= written; @@ -700,42 +708,67 @@ int HTTPClient::sendRequest(const char * type, const uint8_t * payload, size_t s code = handleHeaderResponse(); // - // We can follow redirects for 301/302/307 for GET and HEAD requests and - // and we have not exceeded the redirect limit preventing an infinite - // redirect loop. - // + // Handle redirections as stated in RFC document: // https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html // - if (_followRedirects && - (_redirectCount < _redirectLimit) && - (_location.length() > 0) && - (code == 301 || code == 302 || code == 307) && - (!strcmp(type, "GET") || !strcmp(type, "HEAD")) - ) { - _redirectCount += 1; // increment the count for redirect. - redirect = true; - DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] following redirect:: '%s' redirCount: %d\n", _location.c_str(), _redirectCount); - if (!setURL(_location)) { - // return the redirect instead of handling on failure of setURL() - redirect = false; + // Implementing HTTP_CODE_FOUND as redirection with GET method, + // to follow most of existing user agent implementations. + // + redirect = false; + if ( + _followRedirects != HTTPC_DISABLE_FOLLOW_REDIRECTS && + redirectCount < _redirectLimit && + _location.length() > 0 + ) { + switch (code) { + // redirecting using the same method + 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); - // 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) return returnError(code); } diff --git a/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.h b/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.h index 1d7548f0f..1ab26c8de 100644 --- a/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.h +++ b/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.h @@ -130,6 +130,23 @@ typedef enum { HTTPC_TE_CHUNKED } transferEncoding_t; +/** + * redirection follow mode. + * + `HTTPC_DISABLE_FOLLOW_REDIRECTS` - no redirection will be followed. + * + `HTTPC_STRICT_FOLLOW_REDIRECTS` - strict RFC2616, only requests using + * GET or HEAD methods will be redirected (using the same method), + * since the RFC requires end-user confirmation in other cases. + * + `HTTPC_FORCE_FOLLOW_REDIRECTS` - all redirections will be followed, + * regardless of a used method. New request will use the same method, + * and they will include the same body data and the same headers. + * In the sense of the RFC, it's just like every redirection is confirmed. + */ +typedef enum { + HTTPC_DISABLE_FOLLOW_REDIRECTS, + HTTPC_STRICT_FOLLOW_REDIRECTS, + HTTPC_FORCE_FOLLOW_REDIRECTS +} followRedirects_t; + #if HTTPCLIENT_1_1_COMPATIBLE class TransportTraits; typedef std::unique_ptr TransportTraitsPtr; @@ -173,8 +190,12 @@ public: void setAuthorization(const char * user, const char * password); void setAuthorization(const char * auth); 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 + bool setURL(const String& url); // handy for handling redirects void useHTTP10(bool usehttp10 = true); @@ -252,8 +273,7 @@ protected: int _returnCode = 0; int _size = -1; bool _canReuse = false; - bool _followRedirects = false; - uint16_t _redirectCount = 0; + followRedirects_t _followRedirects = HTTPC_DISABLE_FOLLOW_REDIRECTS; uint16_t _redirectLimit = 10; String _location; transferEncoding_t _transferEncoding = HTTPC_TE_IDENTITY; diff --git a/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino b/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino index fb5847d4b..bd25fad58 100644 --- a/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino +++ b/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino @@ -186,12 +186,27 @@ void handleFileList() { Dir dir = filesystem->openDir(path); 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()) { - File entry = dir.openFile("r"); - if (output != "[") { - output += ','; + + if (output.length()) { + // send string from previous iteration + // as an HTTP chunk + server.sendContent(output); + output = ','; + } else { + output = '['; } + + File entry = dir.openFile("r"); bool isDir = false; output += "{\"type\":\""; output += (isDir) ? "dir" : "file"; @@ -205,8 +220,10 @@ void handleFileList() { entry.close(); } + // send last string output += "]"; - server.send(200, "text/json", output); + server.sendContent(output); + server.chunkedResponseFinalize(); } void setup(void) { diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index eefcba2ba..9e999acad 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -149,18 +149,36 @@ public: void sendContent(const char *content) { sendContent_P(content); } 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 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 size_t streamFile(T &file, const String& contentType) { return streamFile(file, contentType, HTTP_GET); } // 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 size_t streamFile(T &file, const String& contentType, HTTPMethod requestMethod) { size_t contentLength = 0; diff --git a/libraries/ESP8266WiFi/examples/IPv6/IPv6.ino b/libraries/ESP8266WiFi/examples/IPv6/IPv6.ino index 1c7b1c081..48bd5a449 100644 --- a/libraries/ESP8266WiFi/examples/IPv6/IPv6.ino +++ b/libraries/ESP8266WiFi/examples/IPv6/IPv6.ino @@ -1,4 +1,3 @@ - /* arduino IPv6 example released to public domain @@ -27,7 +26,8 @@ #define STAPSK "your-password" #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 STATUSDELAY_MS 10000 #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) { out.println(F("------------------------------")); 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 fqdn(out, FQDN); 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("------------------------------")); } diff --git a/libraries/ESP8266WiFi/keywords.txt b/libraries/ESP8266WiFi/keywords.txt index b24bfc598..16eea2422 100644 --- a/libraries/ESP8266WiFi/keywords.txt +++ b/libraries/ESP8266WiFi/keywords.txt @@ -26,6 +26,7 @@ PublicKey KEYWORD1 CertStoreSPIFFSBearSSL KEYWORD1 CertStoreSDBearSSL KEYWORD1 Session KEYWORD1 +ESP8266WiFiGratuitous KEYWORD1 ####################################### @@ -108,6 +109,9 @@ psk KEYWORD2 BSSID KEYWORD2 BSSIDstr KEYWORD2 RSSI KEYWORD2 +stationKeepAliveSetIntervalMs KEYWORD2 +stationKeepAliveStop KEYWORD2 +stationKeepAliveNow KEYWORD2 enableInsecureWEP KEYWORD2 getListenInterval KEYWORD2 isSleepLevelMax KEYWORD2 diff --git a/libraries/ESP8266WiFi/src/BearSSLHelpers.cpp b/libraries/ESP8266WiFi/src/BearSSLHelpers.cpp index ffce2b00e..f96254779 100644 --- a/libraries/ESP8266WiFi/src/BearSSLHelpers.cpp +++ b/libraries/ESP8266WiFi/src/BearSSLHelpers.cpp @@ -870,9 +870,9 @@ uint32_t SigningVerifier::length() } } -bool SigningVerifier::verify(UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) { - if (!_pubKey || !hash || !signature || signatureLen != length()) return false; - +// We need to use the 2nd stack to do a verification, so do the thunk +// 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()) { bool ret; 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 // Second stack thunked helpers diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp index 4b2eb54ce..41d771fb6 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp @@ -608,7 +608,7 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms) { ip_addr_t addr; - aResult = static_cast(0); + aResult = static_cast(INADDR_NONE); if(aResult.fromString(aHostname)) { // 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); +#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); +#endif if(err == ERR_OK) { aResult = IPAddress(&addr); } else if(err == ERR_INPROGRESS) { @@ -640,6 +644,57 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul 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(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 * @param name diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h index 1f5ec5c99..b5f307aed 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h @@ -42,6 +42,14 @@ typedef std::shared_ptr WiFiEventHandler; 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; class ESP8266WiFiGenericClass { @@ -113,6 +121,9 @@ class ESP8266WiFiGenericClass { public: int hostByName(const char* aHostname, IPAddress& aResult); 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(); protected: diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.cpp new file mode 100644 index 000000000..1ba3f862b --- /dev/null +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.cpp @@ -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 + +#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:: diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.h b/libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.h new file mode 100644 index 000000000..d86426cd8 --- /dev/null +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.h @@ -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 // uint32_t +#include // 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_ diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp index 8f52942b7..26fb4b9d3 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp @@ -89,7 +89,7 @@ static bool sta_config_equal(const station_config& lhs, const station_config& rh return false; } } - + if(lhs.threshold.rssi != rhs.threshold.rssi) { return false; } diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.h b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.h index 696ff1b39..cf38e1254 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.h +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.h @@ -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(); - //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 + //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 //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); diff --git a/libraries/ESP8266WiFi/src/include/ClientContext.h b/libraries/ESP8266WiFi/src/include/ClientContext.h index 6ce97115f..8095e402a 100644 --- a/libraries/ESP8266WiFi/src/include/ClientContext.h +++ b/libraries/ESP8266WiFi/src/include/ClientContext.h @@ -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); if (err != ERR_OK) { return 0; diff --git a/libraries/ESP8266WiFi/src/include/UdpContext.h b/libraries/ESP8266WiFi/src/include/UdpContext.h index 8534c61f1..a81384b2a 100644 --- a/libraries/ESP8266WiFi/src/include/UdpContext.h +++ b/libraries/ESP8266WiFi/src/include/UdpContext.h @@ -114,6 +114,12 @@ public: { _pcb->remote_ip = addr; _pcb->remote_port = port; +#if LWIP_IPV6 + // Set zone so that link local addresses use the default interface + if (IP_IS_V6(&_pcb->remote_ip) && ip6_addr_lacks_zone(ip_2_ip6(&_pcb->remote_ip), IP6_UNKNOWN)) { + ip6_addr_assign_zone(ip_2_ip6(&_pcb->remote_ip), IP6_UNKNOWN, netif_default); + } +#endif return true; } diff --git a/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.cpp b/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.cpp index 9d56718c1..a7fe1934d 100755 --- a/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.cpp +++ b/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.cpp @@ -30,12 +30,12 @@ extern "C" uint32_t _FS_start; extern "C" uint32_t _FS_end; ESP8266HTTPUpdate::ESP8266HTTPUpdate(void) - : _httpClientTimeout(8000), _followRedirects(false), _ledPin(-1) + : _httpClientTimeout(8000), _followRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS), _ledPin(-1) { } ESP8266HTTPUpdate::ESP8266HTTPUpdate(int httpClientTimeout) - : _httpClientTimeout(httpClientTimeout), _followRedirects(false), _ledPin(-1) + : _httpClientTimeout(httpClientTimeout), _followRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS), _ledPin(-1) { } diff --git a/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.h b/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.h index 8d06def9d..ddbd307ad 100755 --- a/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.h +++ b/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.h @@ -82,7 +82,20 @@ public: _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; } @@ -160,7 +173,7 @@ protected: bool _closeConnectionsOnUpdate = true; private: int _httpClientTimeout; - bool _followRedirects; + followRedirects_t _followRedirects; // Callbacks HTTPUpdateStartCB _cbStart; diff --git a/libraries/ESP8266mDNS/src/LEAmDNS.cpp b/libraries/ESP8266mDNS/src/LEAmDNS.cpp index 628432411..87ff5167f 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS.cpp @@ -767,6 +767,12 @@ uint32_t MDNSResponder::queryService(const char* p_pcService, const char* p_pcProtocol, 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);); uint32_t u32Result = 0; diff --git a/libraries/SoftwareSerial b/libraries/SoftwareSerial index 94b2388a4..91ea6b1b1 160000 --- a/libraries/SoftwareSerial +++ b/libraries/SoftwareSerial @@ -1 +1 @@ -Subproject commit 94b2388a4752f2b165371313f4d942daebff6eee +Subproject commit 91ea6b1b1c34601565b23c96c4441f2d399a4f99 diff --git a/libraries/Ticker/src/Ticker.h b/libraries/Ticker/src/Ticker.h index 436a68ce8..07ce33c62 100644 --- a/libraries/Ticker/src/Ticker.h +++ b/libraries/Ticker/src/Ticker.h @@ -35,30 +35,42 @@ public: typedef void (*callback_with_arg_t)(void*); typedef std::function callback_function_t; + // callback will be called at following loop() after ticker fires void attach_scheduled(float seconds, callback_function_t callback) { _callback_function = [callback]() { schedule_function(callback); }; _attach_ms(1000UL * seconds, true); } + // callback will be called in SYS ctx when ticker fires void attach(float seconds, callback_function_t callback) { _callback_function = std::move(callback); _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) { _callback_function = [callback]() { schedule_function(callback); }; _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) { _callback_function = std::move(callback); _attach_ms(milliseconds, true); } + // callback will be called in SYS ctx when ticker fires template void attach(float seconds, void (*callback)(TArg), TArg arg) { @@ -66,6 +78,7 @@ public: _attach_ms(1000UL * seconds, true, reinterpret_cast(callback), reinterpret_cast(arg)); } + // callback will be called in SYS ctx when ticker fires template void attach_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg) { @@ -73,30 +86,35 @@ public: _attach_ms(milliseconds, true, reinterpret_cast(callback), reinterpret_cast(arg)); } + // callback will be called at following loop() after ticker fires void once_scheduled(float seconds, callback_function_t callback) { _callback_function = [callback]() { schedule_function(callback); }; _attach_ms(1000UL * seconds, false); } + // callback will be called in SYS ctx when ticker fires void once(float seconds, callback_function_t callback) { _callback_function = std::move(callback); _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) { _callback_function = [callback]() { schedule_function(callback); }; _attach_ms(milliseconds, false); } + // callback will be called in SYS ctx when ticker fires void once_ms(uint32_t milliseconds, callback_function_t callback) { _callback_function = std::move(callback); _attach_ms(milliseconds, false); } + // callback will be called in SYS ctx when ticker fires template void once(float seconds, void (*callback)(TArg), TArg arg) { @@ -104,6 +122,7 @@ public: _attach_ms(1000UL * seconds, false, reinterpret_cast(callback), reinterpret_cast(arg)); } + // callback will be called in SYS ctx when ticker fires template void once_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg) { diff --git a/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino b/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino index 33cd14603..3a16efb61 100644 --- a/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino +++ b/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino @@ -134,7 +134,7 @@ void showTime() { Serial.println((uint32_t)now); // timezone and demo in the future - Serial.printf("timezone: %s\n", getenv("TZ")); + Serial.printf("timezone: %s\n", getenv("TZ") ? : "(none)"); // human readable Serial.print("ctime: "); diff --git a/package/package_esp8266com_index.template.json b/package/package_esp8266com_index.template.json index 86a9570bf..97a05e2bb 100644 --- a/package/package_esp8266com_index.template.json +++ b/package/package_esp8266com_index.template.json @@ -378,4 +378,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/tests/device/test_sw_http_client/test_sw_http_client.ino b/tests/device/test_sw_http_client/test_sw_http_client.ino index 6de2314fa..3e60bf974 100644 --- a/tests/device/test_sw_http_client/test_sw_http_client.ino +++ b/tests/device/test_sw_http_client/test_sw_http_client.ino @@ -71,10 +71,10 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]") http.end(); } { - // 301 redirect with follow enabled + // GET 301 redirect with strict RFC follow enabled WiFiClient client; HTTPClient http; - http.setFollowRedirects(true); + http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); String uri = String("/redirect301?host=")+getenv("SERVER_IP"); http.begin(client, getenv("SERVER_IP"), 8088, uri.c_str()); auto httpCode = http.GET(); @@ -83,7 +83,7 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]") REQUIRE(payload == "redirect success"); } { - // 301 redirect with follow disabled + // GET 301 redirect with follow disabled WiFiClient client; HTTPClient http; String uri = String("/redirect301?host=")+getenv("SERVER_IP"); @@ -92,10 +92,10 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]") REQUIRE(httpCode == 301); } { - // 302 redirect with follow enabled + // GET 302 redirect with strict RFC follow enabled WiFiClient client; HTTPClient http; - http.setFollowRedirects(true); + http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); String uri = String("/redirect302?host=")+getenv("SERVER_IP"); http.begin(client, getenv("SERVER_IP"), 8088, uri.c_str()); auto httpCode = http.GET(); @@ -104,7 +104,7 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]") REQUIRE(payload == "redirect success"); } { - // 302 redirect with follow disabled + // GET 302 redirect with follow disabled WiFiClient client; HTTPClient http; String uri = String("/redirect302?host=")+getenv("SERVER_IP"); @@ -113,10 +113,10 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]") REQUIRE(httpCode == 302); } { - // 307 redirect with follow enabled + // GET 307 redirect with strict RFC follow enabled WiFiClient client; HTTPClient http; - http.setFollowRedirects(true); + http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); String uri = String("/redirect307?host=")+getenv("SERVER_IP"); http.begin(client, getenv("SERVER_IP"), 8088, uri.c_str()); auto httpCode = http.GET(); @@ -125,7 +125,7 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]") REQUIRE(payload == "redirect success"); } { - // 307 redirect with follow disabled + // GET 307 redirect with follow disabled WiFiClient client; HTTPClient http; String uri = String("/redirect307?host=")+getenv("SERVER_IP"); @@ -134,10 +134,10 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]") REQUIRE(httpCode == 307); } { - // 301 exceeding redirect limit + // GET 301 exceeding redirect limit WiFiClient client; HTTPClient http; - http.setFollowRedirects(true); + http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); http.setRedirectLimit(0); String uri = String("/redirect301?host=")+getenv("SERVER_IP"); http.begin(client, getenv("SERVER_IP"), 8088, uri.c_str()); @@ -145,20 +145,22 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]") REQUIRE(httpCode == 301); } { - // POST 303 redirect with follow enabled + // POST 303 redirect with strict RFC follow enabled WiFiClient client; HTTPClient http; - http.setFollowRedirects(true); + http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); http.begin(client, getenv("SERVER_IP"), 8088, "/redirect303"); auto httpCode = http.POST(getenv("SERVER_IP")); REQUIRE(httpCode == HTTP_CODE_OK); String payload = http.getString(); REQUIRE(payload == "redirect success"); + // TODO: need check for dropping: redirection should use GET method } { // POST 303 redirect with follow disabled WiFiClient client; HTTPClient http; + http.setFollowRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS); http.begin(client, getenv("SERVER_IP"), 8088, "/redirect303"); auto httpCode = http.POST(getenv("SERVER_IP")); REQUIRE(httpCode == 303); @@ -167,6 +169,7 @@ TEST_CASE("HTTP GET & POST requests", "[HTTPClient]") // 302 redirect with follow disabled WiFiClient client; HTTPClient http; + http.setFollowRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS); String uri = String("/redirect302?host=")+getenv("SERVER_IP"); http.begin(client, getenv("SERVER_IP"), 8088, uri.c_str()); auto httpCode = http.GET(); diff --git a/tests/host/common/MockEsp.cpp b/tests/host/common/MockEsp.cpp index c5ca502ed..0854bdcd7 100644 --- a/tests/host/common/MockEsp.cpp +++ b/tests/host/common/MockEsp.cpp @@ -118,11 +118,6 @@ uint32_t EspClass::getFreeSketchSpace() return 4 * 1024 * 1024; } -uint8_t EspClass::getCpuFreqMHz() -{ - return F_CPU / 1000000; -} - const char *EspClass::getSdkVersion() { return "2.5.0"; diff --git a/tests/host/common/MocklwIP.cpp b/tests/host/common/MocklwIP.cpp index bc5ae6ebc..f114572c1 100644 --- a/tests/host/common/MocklwIP.cpp +++ b/tests/host/common/MocklwIP.cpp @@ -26,4 +26,11 @@ const ip_addr_t* sntp_getserver(u8_t) 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" diff --git a/tests/platformio.sh b/tests/platformio.sh index 4f1cbbb78..e2d24859d 100755 --- a/tests/platformio.sh +++ b/tests/platformio.sh @@ -7,8 +7,8 @@ source "$TRAVIS_BUILD_DIR"/tests/common.sh function install_platformio() { pip3 install --user -U https://github.com/platformio/platformio/archive/develop.zip - platformio platform install "https://github.com/platformio/platform-espressif8266.git#feature/stage" - sed -i 's/https:\/\/github\.com\/esp8266\/Arduino\.git/*/' ~/.platformio/platforms/espressif8266/platform.json + platformio platform install "https://github.com/platformio/platform-espressif8266.git" + 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 # Install dependencies: # - esp8266/examples/ConfigFile diff --git a/tools/boards.txt.py b/tools/boards.txt.py index ff582896d..d33cbe1fc 100755 --- a/tools/boards.txt.py +++ b/tools/boards.txt.py @@ -286,7 +286,7 @@ boards = collections.OrderedDict([ 'crystalfreq_menu', 'flashmode_dout', 'flashfreq_40', - '1M', + '1M', '2M', 'led', ], 'desc': [ 'ESP8285 (`datasheet `__) 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.', diff --git a/tools/espota.py b/tools/espota.py index 373020a91..d6b5a8086 100755 --- a/tools/espota.py +++ b/tools/espota.py @@ -132,7 +132,7 @@ def serve(remoteAddr, localAddr, remotePort, localPort, password, filename, comm sys.stderr.write('FAIL\n') logging.error('%s', data) sock2.close() - sys.exit(1); + sys.exit(1) return 1 sys.stderr.write('OK\n') else: @@ -172,7 +172,7 @@ def serve(remoteAddr, localAddr, remotePort, localPort, password, filename, comm connection.sendall(chunk) if connection.recv(32).decode().find('O') >= 0: # connection will receive only digits or 'OK' - received_ok = True; + received_ok = True except: sys.stderr.write('\n') 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' try: connection.settimeout(60) - while not received_ok: - if connection.recv(32).decode().find('O') >= 0: - # connection will receive only digits or 'OK' - received_ok = True; - logging.info('Result: OK') + received_ok = False + received_error = False + while not (received_ok or received_error): + reply = connection.recv(64).decode() + # 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() f.close() sock.close() - if (data != "OK"): - sys.stderr.write('\n') - logging.error('%s', data) - return 1; - return 0 + if received_ok: + return 0 + return 1 except: logging.error('No Result!') connection.close() diff --git a/tools/platformio-build.py b/tools/platformio-build.py index c595497cb..33ba5380f 100644 --- a/tools/platformio-build.py +++ b/tools/platformio-build.py @@ -247,9 +247,12 @@ else: # current_vtables = None +fp_in_irom = "" for d in flatten_cppdefines: if str(d).startswith("VTABLES_IN_"): current_vtables = d + if str(d) == "FP_IN_IROM": + fp_in_irom = "-DFP_IN_IROM" if not current_vtables: current_vtables = "VTABLES_IN_FLASH" env.Append(CPPDEFINES=[current_vtables]) @@ -260,7 +263,7 @@ app_ld = env.Command( join("$BUILD_DIR", "ld", "local.eagle.app.v6.common.ld"), join(FRAMEWORK_DIR, "tools", "sdk", "ld", "eagle.app.v6.common.ld.h"), 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")) env.Depends("$BUILD_DIR/$PROGNAME$PROGSUFFIX", app_ld) diff --git a/tools/sdk/ld/eagle.app.v6.common.ld.h b/tools/sdk/ld/eagle.app.v6.common.ld.h index 383154e49..b7ba38e12 100644 --- a/tools/sdk/ld/eagle.app.v6.common.ld.h +++ b/tools/sdk/ld/eagle.app.v6.common.ld.h @@ -151,6 +151,14 @@ SECTIONS *libc.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:_udivdi3.o(.literal .text) *libstdc++.a:( .literal .text .literal.* .text.*)