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:
commit
a24b8d23f0
14
README.md
14
README.md
@ -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
|
||||||
|
|
||||||
|
57
boards.txt
57
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.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
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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();
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#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)) :
|
||||||
@ -18,23 +19,25 @@ 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);
|
|
||||||
|
auto buf = std::unique_ptr<uint8_t[]>{new(std::nothrow) uint8_t[buf_size]};
|
||||||
|
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
return false;
|
return false;
|
||||||
@ -53,13 +56,13 @@ bool MD5Builder::addStream(Stream & stream, const size_t maxLen){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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);
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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; }
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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) {
|
||||||
|
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)) {
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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));
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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"
|
||||||
|
@ -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>`__
|
||||||
|
@ -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
|
||||||
|
@ -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()) {
|
||||||
@ -700,41 +708,66 @@ 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) &&
|
|
||||||
(!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;
|
redirect = false;
|
||||||
}
|
if (
|
||||||
}
|
_followRedirects != HTTPC_DISABLE_FOLLOW_REDIRECTS &&
|
||||||
|
redirectCount < _redirectLimit &&
|
||||||
} while (redirect);
|
_location.length() > 0
|
||||||
|
|
||||||
// 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;
|
switch (code) {
|
||||||
if (setURL(_location)) {
|
// redirecting using the same method
|
||||||
code = sendRequest("GET");
|
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 Server Response (Header)
|
// handle Server Response (Header)
|
||||||
return returnError(code);
|
return returnError(code);
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
while (dir.next()) {
|
if (!server.chunkedResponseModeStart(200, "text/json")) {
|
||||||
File entry = dir.openFile("r");
|
server.send(505, FPSTR("text/html"), FPSTR("HTTP1.1 required"));
|
||||||
if (output != "[") {
|
return;
|
||||||
output += ',';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// use the same string for every line
|
||||||
|
String output;
|
||||||
|
output.reserve(64);
|
||||||
|
while (dir.next()) {
|
||||||
|
|
||||||
|
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;
|
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) {
|
||||||
|
@ -149,6 +149,24 @@ 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);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
arduino IPv6 example
|
arduino IPv6 example
|
||||||
released to public domain
|
released to public domain
|
||||||
@ -28,6 +27,7 @@
|
|||||||
#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("------------------------------"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
95
libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.cpp
Normal file
95
libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.cpp
Normal 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::
|
54
libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.h
Normal file
54
libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.h
Normal 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_
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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: ");
|
||||||
|
@ -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();
|
||||||
|
@ -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";
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
|
@ -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.',
|
||||||
|
@ -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()
|
||||||
|
# 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')
|
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')
|
|
||||||
logging.error('%s', data)
|
|
||||||
return 1;
|
|
||||||
return 0
|
return 0
|
||||||
|
return 1
|
||||||
except:
|
except:
|
||||||
logging.error('No Result!')
|
logging.error('No Result!')
|
||||||
connection.close()
|
connection.close()
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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.*)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user