mirror of
https://github.com/esp8266/Arduino.git
synced 2025-05-06 18:19:16 +03:00
commit
212e189e59
@ -25,20 +25,20 @@
|
|||||||
|
|
||||||
#define CONT_STACKGUARD 0xfeefeffe
|
#define CONT_STACKGUARD 0xfeefeffe
|
||||||
|
|
||||||
void cont_init(cont_t* cont) {
|
void ICACHE_RAM_ATTR cont_init(cont_t* cont) {
|
||||||
cont->stack_guard1 = CONT_STACKGUARD;
|
cont->stack_guard1 = CONT_STACKGUARD;
|
||||||
cont->stack_guard2 = CONT_STACKGUARD;
|
cont->stack_guard2 = CONT_STACKGUARD;
|
||||||
cont->stack_end = cont->stack + (sizeof(cont->stack) / 4);
|
cont->stack_end = cont->stack + (sizeof(cont->stack) / 4);
|
||||||
cont->struct_start = (unsigned*) cont;
|
cont->struct_start = (unsigned*) cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cont_check(cont_t* cont) {
|
int ICACHE_RAM_ATTR cont_check(cont_t* cont) {
|
||||||
if(cont->stack_guard1 != CONT_STACKGUARD || cont->stack_guard2 != CONT_STACKGUARD) return 1;
|
if(cont->stack_guard1 != CONT_STACKGUARD || cont->stack_guard2 != CONT_STACKGUARD) return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cont_can_yield(cont_t* cont) {
|
bool ICACHE_RAM_ATTR cont_can_yield(cont_t* cont) {
|
||||||
return !ETS_INTR_WITHINISR() &&
|
return !ETS_INTR_WITHINISR() &&
|
||||||
cont->pc_ret != 0 && cont->pc_yield == 0;
|
cont->pc_ret != 0 && cont->pc_yield == 0;
|
||||||
}
|
}
|
||||||
|
@ -129,8 +129,12 @@ static void do_global_ctors(void) {
|
|||||||
(*p)();
|
(*p)();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" void __gdb_init() {}
|
||||||
|
extern "C" void gdb_init(void) __attribute__ ((weak, alias("__gdb_init")));
|
||||||
|
|
||||||
void init_done() {
|
void init_done() {
|
||||||
system_set_os_print(1);
|
system_set_os_print(1);
|
||||||
|
gdb_init();
|
||||||
do_global_ctors();
|
do_global_ctors();
|
||||||
esp_schedule();
|
esp_schedule();
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ extern void __real_system_restart_local();
|
|||||||
extern cont_t g_cont;
|
extern cont_t g_cont;
|
||||||
|
|
||||||
|
|
||||||
static void uart_write_char_d(char c);
|
void uart_write_char_d(char c);
|
||||||
static void uart0_write_char_d(char c);
|
static void uart0_write_char_d(char c);
|
||||||
static void uart1_write_char_d(char c);
|
static void uart1_write_char_d(char c);
|
||||||
static void print_stack(uint32_t start, uint32_t end);
|
static void print_stack(uint32_t start, uint32_t end);
|
||||||
@ -133,8 +133,8 @@ void uart_write_char_d(char c) {
|
|||||||
uart1_write_char_d(c);
|
uart1_write_char_d(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void uart0_write_char_d(char c) {
|
static void uart0_write_char_d(char c) {
|
||||||
while (((USS(0) >> USTXC) & 0xff) >= 0x7e) { }
|
while (((USS(0) >> USTXC) & 0xff)) { }
|
||||||
|
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
USF(0) = '\r';
|
USF(0) = '\r';
|
||||||
@ -142,7 +142,7 @@ void uart0_write_char_d(char c) {
|
|||||||
USF(0) = c;
|
USF(0) = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void uart1_write_char_d(char c) {
|
static void uart1_write_char_d(char c) {
|
||||||
while (((USS(1) >> USTXC) & 0xff) >= 0x7e) { }
|
while (((USS(1) >> USTXC) & 0xff) >= 0x7e) { }
|
||||||
|
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
static volatile timercallback timer1_user_cb = NULL;
|
static volatile timercallback timer1_user_cb = NULL;
|
||||||
|
|
||||||
void timer1_isr_handler(void *para){
|
void ICACHE_RAM_ATTR timer1_isr_handler(void *para){
|
||||||
if ((T1C & ((1 << TCAR) | (1 << TCIT))) == 0) TEIE &= ~TEIE1;//edge int disable
|
if ((T1C & ((1 << TCAR) | (1 << TCIT))) == 0) TEIE &= ~TEIE1;//edge int disable
|
||||||
T1I = 0;
|
T1I = 0;
|
||||||
if (timer1_user_cb) {
|
if (timer1_user_cb) {
|
||||||
@ -61,7 +61,7 @@ void timer1_enable(uint8_t divider, uint8_t int_type, uint8_t reload){
|
|||||||
T1I = 0;
|
T1I = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer1_write(uint32_t ticks){
|
void ICACHE_RAM_ATTR timer1_write(uint32_t ticks){
|
||||||
T1L = ((ticks)& 0x7FFFFF);
|
T1L = ((ticks)& 0x7FFFFF);
|
||||||
if ((T1C & (1 << TCIT)) == 0) TEIE |= TEIE1;//edge int enable
|
if ((T1C & (1 << TCIT)) == 0) TEIE |= TEIE1;//edge int enable
|
||||||
}
|
}
|
||||||
@ -76,7 +76,7 @@ void timer1_disable(){
|
|||||||
|
|
||||||
static volatile timercallback timer0_user_cb = NULL;
|
static volatile timercallback timer0_user_cb = NULL;
|
||||||
|
|
||||||
void timer0_isr_handler(void* para){
|
void ICACHE_RAM_ATTR timer0_isr_handler(void* para){
|
||||||
if (timer0_user_cb) {
|
if (timer0_user_cb) {
|
||||||
// to make ISR compatible to Arduino AVR model where interrupts are disabled
|
// to make ISR compatible to Arduino AVR model where interrupts are disabled
|
||||||
// we disable them before we call the client ISR
|
// we disable them before we call the client ISR
|
||||||
@ -99,6 +99,3 @@ void timer0_detachInterrupt() {
|
|||||||
timer0_user_cb = NULL;
|
timer0_user_cb = NULL;
|
||||||
ETS_CCOMPARE0_DISABLE();
|
ETS_CCOMPARE0_DISABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ void prep_pwm_steps(){
|
|||||||
ETS_FRC1_INTR_ENABLE();
|
ETS_FRC1_INTR_ENABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pwm_timer_isr(){
|
void ICACHE_RAM_ATTR pwm_timer_isr(){
|
||||||
static uint8_t current_step = 0;
|
static uint8_t current_step = 0;
|
||||||
static uint8_t stepcount = 0;
|
static uint8_t stepcount = 0;
|
||||||
static uint16_t steps[17];
|
static uint16_t steps[17];
|
||||||
|
@ -39,25 +39,25 @@
|
|||||||
#include "user_interface.h"
|
#include "user_interface.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
void* malloc(size_t size) {
|
void* ICACHE_RAM_ATTR malloc(size_t size) {
|
||||||
size = ((size + 3) & ~((size_t)0x3));
|
size = ((size + 3) & ~((size_t)0x3));
|
||||||
return os_malloc(size);
|
return os_malloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void free(void* ptr) {
|
void ICACHE_RAM_ATTR free(void* ptr) {
|
||||||
os_free(ptr);
|
os_free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* realloc(void* ptr, size_t size) {
|
void* ICACHE_RAM_ATTR realloc(void* ptr, size_t size) {
|
||||||
size = ((size + 3) & ~((size_t)0x3));
|
size = ((size + 3) & ~((size_t)0x3));
|
||||||
return os_realloc(ptr, size);
|
return os_realloc(ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int puts(const char * str) {
|
int ICACHE_RAM_ATTR puts(const char * str) {
|
||||||
return os_printf("%s", str);
|
return os_printf("%s", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
int printf(const char* format, ...) {
|
int ICACHE_RAM_ATTR printf(const char* format, ...) {
|
||||||
int ret;
|
int ret;
|
||||||
va_list arglist;
|
va_list arglist;
|
||||||
va_start(arglist, format);
|
va_start(arglist, format);
|
||||||
@ -66,7 +66,7 @@ int printf(const char* format, ...) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sprintf(char* buffer, const char* format, ...) {
|
int ICACHE_RAM_ATTR sprintf(char* buffer, const char* format, ...) {
|
||||||
int ret;
|
int ret;
|
||||||
va_list arglist;
|
va_list arglist;
|
||||||
va_start(arglist, format);
|
va_start(arglist, format);
|
||||||
@ -75,7 +75,7 @@ int sprintf(char* buffer, const char* format, ...) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snprintf(char* buffer, size_t size, const char* format, ...) {
|
int ICACHE_RAM_ATTR snprintf(char* buffer, size_t size, const char* format, ...) {
|
||||||
int ret;
|
int ret;
|
||||||
va_list arglist;
|
va_list arglist;
|
||||||
va_start(arglist, format);
|
va_start(arglist, format);
|
||||||
@ -84,22 +84,22 @@ int snprintf(char* buffer, size_t size, const char* format, ...) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vprintf(const char * format, va_list arg) {
|
int ICACHE_RAM_ATTR vprintf(const char * format, va_list arg) {
|
||||||
return ets_vprintf(format, arg);
|
return ets_vprintf(format, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int vsnprintf(char * buffer, size_t size, const char * format, va_list arg) {
|
int ICACHE_RAM_ATTR vsnprintf(char * buffer, size_t size, const char * format, va_list arg) {
|
||||||
return ets_vsnprintf(buffer, size, format, arg);
|
return ets_vsnprintf(buffer, size, format, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ICACHE_FLASH_ATTR strnlen(const char *s, size_t len) {
|
size_t strnlen(const char *s, size_t len) {
|
||||||
// there is no ets_strnlen
|
// there is no ets_strnlen
|
||||||
const char *cp;
|
const char *cp;
|
||||||
for (cp = s; len != 0 && *cp != '\0'; cp++, len--);
|
for (cp = s; len != 0 && *cp != '\0'; cp++, len--);
|
||||||
return (size_t)(cp - s);
|
return (size_t)(cp - s);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* ICACHE_FLASH_ATTR strchr(const char * str, int character) {
|
char* strchr(const char * str, int character) {
|
||||||
while(1) {
|
while(1) {
|
||||||
if(*str == 0x00) {
|
if(*str == 0x00) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -111,7 +111,7 @@ char* ICACHE_FLASH_ATTR strchr(const char * str, int character) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char * ICACHE_FLASH_ATTR strrchr(const char * str, int character) {
|
char* strrchr(const char * str, int character) {
|
||||||
char * ret = NULL;
|
char * ret = NULL;
|
||||||
while(1) {
|
while(1) {
|
||||||
if(*str == 0x00) {
|
if(*str == 0x00) {
|
||||||
@ -124,11 +124,11 @@ char * ICACHE_FLASH_ATTR strrchr(const char * str, int character) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char* ICACHE_FLASH_ATTR strcat(char * dest, const char * src) {
|
char* strcat(char * dest, const char * src) {
|
||||||
return strncat(dest, src, strlen(src));
|
return strncat(dest, src, strlen(src));
|
||||||
}
|
}
|
||||||
|
|
||||||
char* ICACHE_FLASH_ATTR strncat(char * dest, const char * src, size_t n) {
|
char* strncat(char * dest, const char * src, size_t n) {
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t offset = strlen(dest);
|
size_t offset = strlen(dest);
|
||||||
for(i = 0; i < n && src[i]; i++) {
|
for(i = 0; i < n && src[i]; i++) {
|
||||||
@ -138,7 +138,7 @@ char* ICACHE_FLASH_ATTR strncat(char * dest, const char * src, size_t n) {
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* ICACHE_FLASH_ATTR strtok_r(char* s, const char* delim, char** last) {
|
char* strtok_r(char* s, const char* delim, char** last) {
|
||||||
const char* spanp;
|
const char* spanp;
|
||||||
char* tok;
|
char* tok;
|
||||||
char c;
|
char c;
|
||||||
@ -193,13 +193,13 @@ cont:
|
|||||||
// NOTREACHED EVER
|
// NOTREACHED EVER
|
||||||
}
|
}
|
||||||
|
|
||||||
char* ICACHE_FLASH_ATTR strtok(char* s, const char* delim) {
|
char* strtok(char* s, const char* delim) {
|
||||||
static char* last;
|
static char* last;
|
||||||
|
|
||||||
return (strtok_r(s, delim, &last));
|
return (strtok_r(s, delim, &last));
|
||||||
}
|
}
|
||||||
|
|
||||||
int ICACHE_FLASH_ATTR strcasecmp(const char * str1, const char * str2) {
|
int strcasecmp(const char * str1, const char * str2) {
|
||||||
int d = 0;
|
int d = 0;
|
||||||
while(1) {
|
while(1) {
|
||||||
int c1 = tolower(*str1++);
|
int c1 = tolower(*str1++);
|
||||||
@ -211,7 +211,7 @@ int ICACHE_FLASH_ATTR strcasecmp(const char * str1, const char * str2) {
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* ICACHE_FLASH_ATTR strdup(const char *str) {
|
char* strdup(const char *str) {
|
||||||
size_t len = strlen(str) + 1;
|
size_t len = strlen(str) + 1;
|
||||||
char *cstr = malloc(len);
|
char *cstr = malloc(len);
|
||||||
if(cstr) {
|
if(cstr) {
|
||||||
@ -222,7 +222,7 @@ char* ICACHE_FLASH_ATTR strdup(const char *str) {
|
|||||||
|
|
||||||
// based on Source:
|
// based on Source:
|
||||||
// https://github.com/anakod/Sming/blob/master/Sming/system/stringconversion.cpp#L93
|
// https://github.com/anakod/Sming/blob/master/Sming/system/stringconversion.cpp#L93
|
||||||
double ICACHE_FLASH_ATTR strtod(const char* str, char** endptr) {
|
double strtod(const char* str, char** endptr) {
|
||||||
double result = 0.0;
|
double result = 0.0;
|
||||||
double factor = 1.0;
|
double factor = 1.0;
|
||||||
bool decimals = false;
|
bool decimals = false;
|
||||||
@ -388,7 +388,7 @@ int isblank(int c) {
|
|||||||
|
|
||||||
static int errno_var = 0;
|
static int errno_var = 0;
|
||||||
|
|
||||||
int* ICACHE_FLASH_ATTR __errno(void) {
|
int* __errno(void) {
|
||||||
// DEBUGV("__errno is called last error: %d (not current)\n", errno_var);
|
// DEBUGV("__errno is called last error: %d (not current)\n", errno_var);
|
||||||
return &errno_var;
|
return &errno_var;
|
||||||
}
|
}
|
||||||
@ -440,7 +440,7 @@ time_t mktime(struct tm *timp) {
|
|||||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
size_t ICACHE_FLASH_ATTR strlcpy(char* dst, const char* src, size_t size) {
|
size_t strlcpy(char* dst, const char* src, size_t size) {
|
||||||
const char *s = src;
|
const char *s = src;
|
||||||
size_t n = size;
|
size_t n = size;
|
||||||
|
|
||||||
@ -505,7 +505,7 @@ size_t ICACHE_FLASH_ATTR strlcpy(char* dst, const char* src, size_t size) {
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
long ICACHE_FLASH_ATTR strtol(const char *nptr, char **endptr, int base) {
|
long strtol(const char *nptr, char **endptr, int base) {
|
||||||
const unsigned char *s = (const unsigned char *)nptr;
|
const unsigned char *s = (const unsigned char *)nptr;
|
||||||
unsigned long acc;
|
unsigned long acc;
|
||||||
int c;
|
int c;
|
||||||
@ -581,7 +581,7 @@ long ICACHE_FLASH_ATTR strtol(const char *nptr, char **endptr, int base) {
|
|||||||
return (acc);
|
return (acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long ICACHE_FLASH_ATTR strtoul(const char *nptr, char **endptr, int base)
|
unsigned long strtoul(const char *nptr, char **endptr, int base)
|
||||||
{
|
{
|
||||||
const unsigned char *s = (const unsigned char *)nptr;
|
const unsigned char *s = (const unsigned char *)nptr;
|
||||||
unsigned long acc;
|
unsigned long acc;
|
||||||
|
@ -73,7 +73,7 @@ void handleWifi() {
|
|||||||
Serial.println("scan done");
|
Serial.println("scan done");
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
server.sendContent(String() + "\r\n<tr><td>SSID " + String(WiFi.SSID(i)) + String((WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":" *") + " (" + WiFi.RSSI(i) + ")</td></tr>");
|
server.sendContent(String() + "\r\n<tr><td>SSID " + WiFi.SSID(i) + String((WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":" *") + " (" + WiFi.RSSI(i) + ")</td></tr>");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
server.sendContent(String() + "<tr><td>No WLAN found</td></tr>");
|
server.sendContent(String() + "<tr><td>No WLAN found</td></tr>");
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
To upload through terminal you can use: curl -F "image=@firmware.bin" esp8266-webupdate.local/update
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <WiFiClient.h>
|
||||||
|
#include <ESP8266WebServer.h>
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
|
#include <ESP8266HTTPUpdateServer.h>
|
||||||
|
|
||||||
|
const char* host = "esp8266-webupdate";
|
||||||
|
const char* ssid = "........";
|
||||||
|
const char* password = "........";
|
||||||
|
|
||||||
|
ESP8266WebServer httpServer(80);
|
||||||
|
ESP8266HTTPUpdateServer httpUpdater;
|
||||||
|
|
||||||
|
void setup(void){
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println();
|
||||||
|
Serial.println("Booting Sketch...");
|
||||||
|
WiFi.mode(WIFI_AP_STA);
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
|
||||||
|
while(WiFi.waitForConnectResult() != WL_CONNECTED){
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
Serial.println("WiFi failed, retrying.");
|
||||||
|
}
|
||||||
|
|
||||||
|
MDNS.begin(host);
|
||||||
|
|
||||||
|
httpUpdater.setup(&httpServer);
|
||||||
|
httpServer.begin();
|
||||||
|
|
||||||
|
MDNS.addService("http", "tcp", 80);
|
||||||
|
Serial.printf("HTTPUpdateServer ready! Open http://%s.local/update in your browser\n", host);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(void){
|
||||||
|
httpServer.handleClient();
|
||||||
|
delay(1);
|
||||||
|
}
|
20
libraries/ESP8266HTTPUpdateServer/keywords.txt
Normal file
20
libraries/ESP8266HTTPUpdateServer/keywords.txt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#######################################
|
||||||
|
# Syntax Coloring Map For HTTPUpdateServer
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Datatypes (KEYWORD1)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
ESP8266HTTPUpdateServer KEYWORD1
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Methods and Functions (KEYWORD2)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
begin KEYWORD2
|
||||||
|
setup KEYWORD2
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Constants (LITERAL1)
|
||||||
|
#######################################
|
9
libraries/ESP8266HTTPUpdateServer/library.properties
Normal file
9
libraries/ESP8266HTTPUpdateServer/library.properties
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
name=ESP8266HTTPUpdateServer
|
||||||
|
version=1.0
|
||||||
|
author=Ivan Grokhotkov, Miguel Ángel Ajo
|
||||||
|
maintainer=Ivan Grokhtkov <ivan@esp8266.com>
|
||||||
|
sentence=Simple HTTP Update server based on the ESP8266WebServer
|
||||||
|
paragraph=The library accepts HTTP post requests to the /update url, and updates the ESP8266 firmware.
|
||||||
|
category=Communication
|
||||||
|
url=
|
||||||
|
architectures=esp8266
|
@ -0,0 +1,75 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <WiFiClient.h>
|
||||||
|
#include <WiFiServer.h>
|
||||||
|
#include <ESP8266WebServer.h>
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
#include "ESP8266HTTPUpdateServer.h"
|
||||||
|
|
||||||
|
|
||||||
|
const char* ESP8266HTTPUpdateServer::_serverIndex =
|
||||||
|
R"(<html><body><form method='POST' action='/update' enctype='multipart/form-data'>
|
||||||
|
<input type='file' name='update'>
|
||||||
|
<input type='submit' value='Update'>
|
||||||
|
</form>
|
||||||
|
</body></html>)";
|
||||||
|
|
||||||
|
ESP8266HTTPUpdateServer::ESP8266HTTPUpdateServer(bool serial_debug)
|
||||||
|
{
|
||||||
|
_serial_output = serial_debug;
|
||||||
|
_server = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server)
|
||||||
|
{
|
||||||
|
_server = server;
|
||||||
|
|
||||||
|
// handler for the /update form page
|
||||||
|
_server->on("/update", HTTP_GET, [&](){
|
||||||
|
_server->sendHeader("Connection", "close");
|
||||||
|
_server->sendHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
_server->send(200, "text/html", _serverIndex);
|
||||||
|
});
|
||||||
|
|
||||||
|
// handler for the /update form POST (once file upload finishes)
|
||||||
|
_server->on("/update", HTTP_POST, [&](){
|
||||||
|
_server->sendHeader("Connection", "close");
|
||||||
|
_server->sendHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
_server->send(200, "text/plain", (Update.hasError())?"FAIL":"OK");
|
||||||
|
ESP.restart();
|
||||||
|
});
|
||||||
|
|
||||||
|
// handler for the file upload, get's the sketch bytes, and writes
|
||||||
|
// them through the Update object.
|
||||||
|
_server->onFileUpload([&](){
|
||||||
|
if(_server->uri() != "/update") return;
|
||||||
|
HTTPUpload& upload = _server->upload();
|
||||||
|
if(upload.status == UPLOAD_FILE_START){
|
||||||
|
if (_serial_output)
|
||||||
|
Serial.setDebugOutput(true);
|
||||||
|
WiFiUDP::stopAll();
|
||||||
|
if (_serial_output)
|
||||||
|
Serial.printf("Update: %s\n", upload.filename.c_str());
|
||||||
|
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
|
||||||
|
if(!Update.begin(maxSketchSpace)){//start with max available size
|
||||||
|
if (_serial_output) Update.printError(Serial);
|
||||||
|
}
|
||||||
|
} else if(upload.status == UPLOAD_FILE_WRITE){
|
||||||
|
if (_serial_output) Serial.printf(".");
|
||||||
|
if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){
|
||||||
|
if (_serial_output) Update.printError(Serial);
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if(upload.status == UPLOAD_FILE_END){
|
||||||
|
if(Update.end(true)){ //true to set the size to the current progress
|
||||||
|
if (_serial_output) Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
|
||||||
|
} else {
|
||||||
|
if (_serial_output) Update.printError(Serial);
|
||||||
|
}
|
||||||
|
if (_serial_output) Serial.setDebugOutput(false);
|
||||||
|
} else if(upload.status == UPLOAD_FILE_ABORTED){
|
||||||
|
Update.end();
|
||||||
|
if (_serial_output) Serial.println("Update was aborted");
|
||||||
|
}
|
||||||
|
yield();
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef __HTTP_UPDATE_SERVER_H
|
||||||
|
#define __HTTP_UPDATE_SERVER_H
|
||||||
|
|
||||||
|
class ESP8266WebServer;
|
||||||
|
|
||||||
|
class ESP8266HTTPUpdateServer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
bool _serial_output;
|
||||||
|
ESP8266WebServer *_server;
|
||||||
|
static const char *_serverIndex;
|
||||||
|
public:
|
||||||
|
ESP8266HTTPUpdateServer(bool serial_debug=false);
|
||||||
|
void setup(ESP8266WebServer *server=NULL);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -16,6 +16,7 @@ HTTPMethod KEYWORD1
|
|||||||
begin KEYWORD2
|
begin KEYWORD2
|
||||||
handleClient KEYWORD2
|
handleClient KEYWORD2
|
||||||
on KEYWORD2
|
on KEYWORD2
|
||||||
|
addHandler KEYWORD2
|
||||||
uri KEYWORD2
|
uri KEYWORD2
|
||||||
method KEYWORD2
|
method KEYWORD2
|
||||||
client KEYWORD2
|
client KEYWORD2
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
#include "WiFiClient.h"
|
#include "WiFiClient.h"
|
||||||
#include "ESP8266WebServer.h"
|
#include "ESP8266WebServer.h"
|
||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
#include "detail/RequestHandler.h"
|
#include "detail/RequestHandlersImpl.h"
|
||||||
// #define DEBUG
|
// #define DEBUG
|
||||||
#define DEBUG_OUTPUT Serial
|
#define DEBUG_OUTPUT Serial
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ ESP8266WebServer::~ESP8266WebServer() {
|
|||||||
return;
|
return;
|
||||||
RequestHandler* handler = _firstHandler;
|
RequestHandler* handler = _firstHandler;
|
||||||
while (handler) {
|
while (handler) {
|
||||||
RequestHandler* next = handler->next;
|
RequestHandler* next = handler->next();
|
||||||
delete handler;
|
delete handler;
|
||||||
handler = next;
|
handler = next;
|
||||||
}
|
}
|
||||||
@ -63,13 +63,17 @@ void ESP8266WebServer::on(const char* uri, HTTPMethod method, ESP8266WebServer::
|
|||||||
_addRequestHandler(new FunctionRequestHandler(fn, uri, method));
|
_addRequestHandler(new FunctionRequestHandler(fn, uri, method));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ESP8266WebServer::addHandler(RequestHandler* handler) {
|
||||||
|
_addRequestHandler(handler);
|
||||||
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::_addRequestHandler(RequestHandler* handler) {
|
void ESP8266WebServer::_addRequestHandler(RequestHandler* handler) {
|
||||||
if (!_lastHandler) {
|
if (!_lastHandler) {
|
||||||
_firstHandler = handler;
|
_firstHandler = handler;
|
||||||
_lastHandler = handler;
|
_lastHandler = handler;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_lastHandler->next = handler;
|
_lastHandler->next(handler);
|
||||||
_lastHandler = handler;
|
_lastHandler = handler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -293,7 +297,7 @@ void ESP8266WebServer::onNotFound(THandlerFunction fn) {
|
|||||||
|
|
||||||
void ESP8266WebServer::_handleRequest() {
|
void ESP8266WebServer::_handleRequest() {
|
||||||
RequestHandler* handler;
|
RequestHandler* handler;
|
||||||
for (handler = _firstHandler; handler; handler = handler->next) {
|
for (handler = _firstHandler; handler; handler = handler->next()) {
|
||||||
if (handler->handle(*this, _currentMethod, _currentUri))
|
if (handler->handle(*this, _currentMethod, _currentUri))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,8 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS };
|
enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS };
|
||||||
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END };
|
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END,
|
||||||
|
UPLOAD_FILE_ABORTED };
|
||||||
|
|
||||||
#define HTTP_DOWNLOAD_UNIT_SIZE 1460
|
#define HTTP_DOWNLOAD_UNIT_SIZE 1460
|
||||||
#define HTTP_UPLOAD_BUFLEN 2048
|
#define HTTP_UPLOAD_BUFLEN 2048
|
||||||
@ -37,7 +38,9 @@ enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END };
|
|||||||
#define CONTENT_LENGTH_UNKNOWN ((size_t) -1)
|
#define CONTENT_LENGTH_UNKNOWN ((size_t) -1)
|
||||||
#define CONTENT_LENGTH_NOT_SET ((size_t) -2)
|
#define CONTENT_LENGTH_NOT_SET ((size_t) -2)
|
||||||
|
|
||||||
class RequestHandler;
|
class ESP8266WebServer;
|
||||||
|
|
||||||
|
#include "detail/RequestHandler.h"
|
||||||
|
|
||||||
namespace fs {
|
namespace fs {
|
||||||
class FS;
|
class FS;
|
||||||
@ -65,6 +68,7 @@ public:
|
|||||||
typedef std::function<void(void)> THandlerFunction;
|
typedef std::function<void(void)> THandlerFunction;
|
||||||
void on(const char* uri, THandlerFunction handler);
|
void on(const char* uri, THandlerFunction handler);
|
||||||
void on(const char* uri, HTTPMethod method, THandlerFunction fn);
|
void on(const char* uri, HTTPMethod method, THandlerFunction fn);
|
||||||
|
void addHandler(RequestHandler* handler);
|
||||||
void serveStatic(const char* uri, fs::FS& fs, const char* path);
|
void serveStatic(const char* uri, fs::FS& fs, const char* path);
|
||||||
void onNotFound(THandlerFunction fn); //called when handler is not assigned
|
void onNotFound(THandlerFunction fn); //called when handler is not assigned
|
||||||
void onFileUpload(THandlerFunction fn); //handle file uploads
|
void onFileUpload(THandlerFunction fn); //handle file uploads
|
||||||
@ -116,6 +120,7 @@ protected:
|
|||||||
void _parseArguments(String data);
|
void _parseArguments(String data);
|
||||||
static const char* _responseCodeToString(int code);
|
static const char* _responseCodeToString(int code);
|
||||||
bool _parseForm(WiFiClient& client, String boundary, uint32_t len);
|
bool _parseForm(WiFiClient& client, String boundary, uint32_t len);
|
||||||
|
bool _parseFormUploadAborted();
|
||||||
void _uploadWriteByte(uint8_t b);
|
void _uploadWriteByte(uint8_t b);
|
||||||
uint8_t _uploadReadByte(WiFiClient& client);
|
uint8_t _uploadReadByte(WiFiClient& client);
|
||||||
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
|
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
|
||||||
|
@ -274,7 +274,7 @@ void ESP8266WebServer::_uploadWriteByte(uint8_t b){
|
|||||||
uint8_t ESP8266WebServer::_uploadReadByte(WiFiClient& client){
|
uint8_t ESP8266WebServer::_uploadReadByte(WiFiClient& client){
|
||||||
int res = client.read();
|
int res = client.read();
|
||||||
if(res == -1){
|
if(res == -1){
|
||||||
while(!client.available())
|
while(!client.available() && client.connected())
|
||||||
yield();
|
yield();
|
||||||
res = client.read();
|
res = client.read();
|
||||||
}
|
}
|
||||||
@ -387,13 +387,16 @@ bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t
|
|||||||
uint8_t argByte = _uploadReadByte(client);
|
uint8_t argByte = _uploadReadByte(client);
|
||||||
readfile:
|
readfile:
|
||||||
while(argByte != 0x0D){
|
while(argByte != 0x0D){
|
||||||
|
if (!client.connected()) return _parseFormUploadAborted();
|
||||||
_uploadWriteByte(argByte);
|
_uploadWriteByte(argByte);
|
||||||
argByte = _uploadReadByte(client);
|
argByte = _uploadReadByte(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
argByte = _uploadReadByte(client);
|
argByte = _uploadReadByte(client);
|
||||||
|
if (!client.connected()) return _parseFormUploadAborted();
|
||||||
if (argByte == 0x0A){
|
if (argByte == 0x0A){
|
||||||
argByte = _uploadReadByte(client);
|
argByte = _uploadReadByte(client);
|
||||||
|
if (!client.connected()) return _parseFormUploadAborted();
|
||||||
if ((char)argByte != '-'){
|
if ((char)argByte != '-'){
|
||||||
//continue reading the file
|
//continue reading the file
|
||||||
_uploadWriteByte(0x0D);
|
_uploadWriteByte(0x0D);
|
||||||
@ -401,6 +404,7 @@ readfile:
|
|||||||
goto readfile;
|
goto readfile;
|
||||||
} else {
|
} else {
|
||||||
argByte = _uploadReadByte(client);
|
argByte = _uploadReadByte(client);
|
||||||
|
if (!client.connected()) return _parseFormUploadAborted();
|
||||||
if ((char)argByte != '-'){
|
if ((char)argByte != '-'){
|
||||||
//continue reading the file
|
//continue reading the file
|
||||||
_uploadWriteByte(0x0D);
|
_uploadWriteByte(0x0D);
|
||||||
@ -481,3 +485,9 @@ readfile:
|
|||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ESP8266WebServer::_parseFormUploadAborted(){
|
||||||
|
_currentUpload.status = UPLOAD_FILE_ABORTED;
|
||||||
|
if (_fileUploadHandler) _fileUploadHandler();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -3,109 +3,13 @@
|
|||||||
|
|
||||||
class RequestHandler {
|
class RequestHandler {
|
||||||
public:
|
public:
|
||||||
RequestHandler(const char* uri, HTTPMethod method)
|
virtual bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) { return false; }
|
||||||
: _uri(uri)
|
|
||||||
, _method(method)
|
|
||||||
, next(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) = 0;
|
RequestHandler* next() { return _next; }
|
||||||
|
void next(RequestHandler* r) { _next = r; }
|
||||||
|
|
||||||
RequestHandler* next;
|
private:
|
||||||
|
RequestHandler* _next = nullptr;
|
||||||
protected:
|
|
||||||
String _uri;
|
|
||||||
HTTPMethod _method;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class FunctionRequestHandler : public RequestHandler {
|
|
||||||
typedef RequestHandler base;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FunctionRequestHandler(ESP8266WebServer::THandlerFunction fn, const char* uri, HTTPMethod method)
|
|
||||||
: _fn(fn)
|
|
||||||
, base(uri, method)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override {
|
|
||||||
if (_method != HTTP_ANY && _method != requestMethod)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (requestUri != _uri)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
_fn();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
ESP8266WebServer::THandlerFunction _fn;
|
|
||||||
};
|
|
||||||
|
|
||||||
class StaticRequestHandler : public RequestHandler {
|
|
||||||
typedef RequestHandler base;
|
|
||||||
|
|
||||||
public:
|
|
||||||
StaticRequestHandler(FS& fs, const char* path, const char* uri)
|
|
||||||
: _fs(fs)
|
|
||||||
, base(uri, HTTP_GET)
|
|
||||||
, _path(path)
|
|
||||||
{
|
|
||||||
_isFile = fs.exists(path);
|
|
||||||
DEBUGV("StaticRequestHandler: path=%s uri=%s isFile=%d\r\n", path, uri, _isFile);
|
|
||||||
_baseUriLength = _uri.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override {
|
|
||||||
if (requestMethod != _method)
|
|
||||||
return false;
|
|
||||||
DEBUGV("StaticRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), _uri.c_str());
|
|
||||||
if (!requestUri.startsWith(_uri))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
String path(_path);
|
|
||||||
if (!_isFile) {
|
|
||||||
// Base URI doesn't point to a file. Append whatever follows this
|
|
||||||
// URI in request to get the file path.
|
|
||||||
path += requestUri.substring(_baseUriLength);
|
|
||||||
}
|
|
||||||
else if (requestUri != _uri) {
|
|
||||||
// Base URI points to a file but request doesn't match this URI exactly
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
DEBUGV("StaticRequestHandler::handle: path=%s, isFile=%d\r\n", path.c_str(), _isFile);
|
|
||||||
File f = _fs.open(path, "r");
|
|
||||||
if (!f)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
server.streamFile(f, getContentType(path));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String getContentType(const String& path) {
|
|
||||||
if (path.endsWith(".html")) return "text/html";
|
|
||||||
else if (path.endsWith(".htm")) return "text/html";
|
|
||||||
else if (path.endsWith(".css")) return "text/css";
|
|
||||||
else if (path.endsWith(".txt")) return "text/plain";
|
|
||||||
else if (path.endsWith(".js")) return "application/javascript";
|
|
||||||
else if (path.endsWith(".png")) return "image/png";
|
|
||||||
else if (path.endsWith(".gif")) return "image/gif";
|
|
||||||
else if (path.endsWith(".jpg")) return "image/jpeg";
|
|
||||||
else if (path.endsWith(".ico")) return "image/x-icon";
|
|
||||||
else if (path.endsWith(".xml")) return "text/xml";
|
|
||||||
else if (path.endsWith(".pdf")) return "application/pdf";
|
|
||||||
else if (path.endsWith(".zip")) return "application/zip";
|
|
||||||
return "text/plain";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
FS _fs;
|
|
||||||
String _path;
|
|
||||||
bool _isFile;
|
|
||||||
size_t _baseUriLength;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //REQUESTHANDLER_H
|
#endif //REQUESTHANDLER_H
|
||||||
|
95
libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h
Normal file
95
libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#ifndef REQUESTHANDLERSIMPL_H
|
||||||
|
#define REQUESTHANDLERSIMPL_H
|
||||||
|
|
||||||
|
#include "RequestHandler.h"
|
||||||
|
|
||||||
|
class FunctionRequestHandler : public RequestHandler {
|
||||||
|
public:
|
||||||
|
FunctionRequestHandler(ESP8266WebServer::THandlerFunction fn, const char* uri, HTTPMethod method)
|
||||||
|
: _fn(fn)
|
||||||
|
, _uri(uri)
|
||||||
|
, _method(method)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override {
|
||||||
|
if (_method != HTTP_ANY && _method != requestMethod)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (requestUri != _uri)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_fn();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
String _uri;
|
||||||
|
HTTPMethod _method;
|
||||||
|
ESP8266WebServer::THandlerFunction _fn;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StaticRequestHandler : public RequestHandler {
|
||||||
|
public:
|
||||||
|
StaticRequestHandler(FS& fs, const char* path, const char* uri)
|
||||||
|
: _fs(fs)
|
||||||
|
, _uri(uri)
|
||||||
|
, _path(path)
|
||||||
|
{
|
||||||
|
_isFile = fs.exists(path);
|
||||||
|
DEBUGV("StaticRequestHandler: path=%s uri=%s isFile=%d\r\n", path, uri, _isFile);
|
||||||
|
_baseUriLength = _uri.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override {
|
||||||
|
if (requestMethod != HTTP_GET)
|
||||||
|
return false;
|
||||||
|
DEBUGV("StaticRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), _uri.c_str());
|
||||||
|
if (!requestUri.startsWith(_uri))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
String path(_path);
|
||||||
|
if (!_isFile) {
|
||||||
|
// Base URI doesn't point to a file. Append whatever follows this
|
||||||
|
// URI in request to get the file path.
|
||||||
|
path += requestUri.substring(_baseUriLength);
|
||||||
|
}
|
||||||
|
else if (requestUri != _uri) {
|
||||||
|
// Base URI points to a file but request doesn't match this URI exactly
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DEBUGV("StaticRequestHandler::handle: path=%s, isFile=%d\r\n", path.c_str(), _isFile);
|
||||||
|
File f = _fs.open(path, "r");
|
||||||
|
if (!f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
server.streamFile(f, getContentType(path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getContentType(const String& path) {
|
||||||
|
if (path.endsWith(".html")) return "text/html";
|
||||||
|
else if (path.endsWith(".htm")) return "text/html";
|
||||||
|
else if (path.endsWith(".css")) return "text/css";
|
||||||
|
else if (path.endsWith(".txt")) return "text/plain";
|
||||||
|
else if (path.endsWith(".js")) return "application/javascript";
|
||||||
|
else if (path.endsWith(".png")) return "image/png";
|
||||||
|
else if (path.endsWith(".gif")) return "image/gif";
|
||||||
|
else if (path.endsWith(".jpg")) return "image/jpeg";
|
||||||
|
else if (path.endsWith(".ico")) return "image/x-icon";
|
||||||
|
else if (path.endsWith(".xml")) return "text/xml";
|
||||||
|
else if (path.endsWith(".pdf")) return "application/pdf";
|
||||||
|
else if (path.endsWith(".zip")) return "application/zip";
|
||||||
|
return "text/plain";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
FS _fs;
|
||||||
|
String _uri;
|
||||||
|
String _path;
|
||||||
|
bool _isFile;
|
||||||
|
size_t _baseUriLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //REQUESTHANDLERSIMPL_H
|
@ -536,13 +536,13 @@ void * ESP8266WiFiClass::_getScanInfoByIndex(int i)
|
|||||||
return reinterpret_cast<bss_info*>(ESP8266WiFiClass::_scanResult) + i;
|
return reinterpret_cast<bss_info*>(ESP8266WiFiClass::_scanResult) + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ESP8266WiFiClass::SSID(uint8_t i)
|
String ESP8266WiFiClass::SSID(uint8_t i)
|
||||||
{
|
{
|
||||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||||
if (!it)
|
if (!it)
|
||||||
return 0;
|
return "";
|
||||||
|
|
||||||
return reinterpret_cast<const char*>(it->ssid);
|
return String(reinterpret_cast<const char*>(it->ssid));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t * ESP8266WiFiClass::BSSID(uint8_t i)
|
uint8_t * ESP8266WiFiClass::BSSID(uint8_t i)
|
||||||
|
@ -239,7 +239,7 @@ public:
|
|||||||
*
|
*
|
||||||
* return: ssid string of the specified item on the networks scanned list
|
* return: ssid string of the specified item on the networks scanned list
|
||||||
*/
|
*/
|
||||||
const char* SSID(uint8_t networkItem);
|
String SSID(uint8_t networkItem);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the encryption type of the networks discovered during the scanNetworks
|
* Return the encryption type of the networks discovered during the scanNetworks
|
||||||
|
@ -51,7 +51,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
int _connectSSL();
|
int _connectSSL();
|
||||||
|
|
||||||
SSLContext* _ssl;
|
SSLContext* _ssl = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //wificlientsecure_h
|
#endif //wificlientsecure_h
|
||||||
|
49
libraries/GDBStub/README.md
Normal file
49
libraries/GDBStub/README.md
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
## Using GDB stub
|
||||||
|
|
||||||
|
- Add `#include <GDBStub.h>` to the sketch
|
||||||
|
- Upload the sketch
|
||||||
|
- Redirect serial port to TCP port:
|
||||||
|
```
|
||||||
|
tcp_serial_redirect.py -p /dev/tty.SLAB_USBtoUART -b 115200 --spy -P 9980 --rts=0 --dtr=0
|
||||||
|
```
|
||||||
|
Change port and baud rate as necessary. This command requires python and pyserial.
|
||||||
|
- Observe serial output:
|
||||||
|
```
|
||||||
|
nc localhost 9980
|
||||||
|
```
|
||||||
|
- When crash happens, `Trap %d: pc=%p va=%p` line will appear in serial output.
|
||||||
|
- Close nc and start gdb:
|
||||||
|
```
|
||||||
|
xtensa-lx106-elf-gdb /path/to/Sketch.cpp.elf -ex "target remote :9980"
|
||||||
|
```
|
||||||
|
- Use gdb to inspect program state at the point of an exception.
|
||||||
|
|
||||||
|
## Tips and tricks
|
||||||
|
|
||||||
|
- To halt the target when software WDT fires, add
|
||||||
|
```
|
||||||
|
((int*)0) = 0;
|
||||||
|
```
|
||||||
|
at the top of `__wrap_system_restart_local` in core_esp8266_postmortem.c.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
GDB Server stub by Marko Mikulicic was taken from Cesanta's smart.js
|
||||||
|
|
||||||
|
https://github.com/cesanta/smart.js
|
||||||
|
|
||||||
|
Copyright (c) 2013-2014 Cesanta Software Limited
|
||||||
|
All rights reserved
|
||||||
|
|
||||||
|
This software is dual-licensed: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License version 2 as
|
||||||
|
published by the Free Software Foundation. For the terms of this
|
||||||
|
license, see <http://www.gnu.org/licenses>.
|
||||||
|
|
||||||
|
You are free to use this software under the terms of the GNU General
|
||||||
|
Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||||
|
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
Alternatively, you can license this software under a commercial
|
||||||
|
license, as set out in <https://www.cesanta.com/license>.
|
9
libraries/GDBStub/library.properties
Normal file
9
libraries/GDBStub/library.properties
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
name=GDBStub
|
||||||
|
version=0.1
|
||||||
|
author=Marko Mikulicic (Cesanta)
|
||||||
|
maintainer=Ivan Grokhotkov <ivan@esp8266.com>
|
||||||
|
sentence=GDB server stub from Cesanta's Smart.js
|
||||||
|
paragraph=GDB server stub helps debug crashes when JTAG isn't an option.
|
||||||
|
category=Uncategorized
|
||||||
|
url=https://github.com/cesanta/smart.js
|
||||||
|
architectures=esp8266
|
355
libraries/GDBStub/src/GDBStub.c
Normal file
355
libraries/GDBStub/src/GDBStub.c
Normal file
@ -0,0 +1,355 @@
|
|||||||
|
/* GDB Server stub by Marko Mikulicic (Cesanta)
|
||||||
|
|
||||||
|
Copyright (c) 2013-2014 Cesanta Software Limited
|
||||||
|
All rights reserved
|
||||||
|
|
||||||
|
This software is dual-licensed: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License version 2 as
|
||||||
|
published by the Free Software Foundation. For the terms of this
|
||||||
|
license, see <http://www.gnu.org/licenses>.
|
||||||
|
|
||||||
|
You are free to use this software under the terms of the GNU General
|
||||||
|
Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||||
|
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
Alternatively, you can license this software under a commercial
|
||||||
|
license, as set out in <https://www.cesanta.com/license>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ets_sys.h"
|
||||||
|
#include "user_interface.h"
|
||||||
|
#include "esp8266_peri.h"
|
||||||
|
|
||||||
|
#include "xtensa/corebits.h"
|
||||||
|
#include "xtensa/specreg.h"
|
||||||
|
|
||||||
|
#define __stringify_1(x...) #x
|
||||||
|
#define __stringify(x...) __stringify_1(x)
|
||||||
|
#define RSR(sr) \
|
||||||
|
({ \
|
||||||
|
uint32_t r; \
|
||||||
|
asm volatile("rsr %0,"__stringify(sr) : "=a"(r)); \
|
||||||
|
r; \
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the saved registers begin at a fixed position in the xtos
|
||||||
|
* low-level exception handler. I don't know if 0x100 it's just an
|
||||||
|
* artifact of the actual xtos build ESP8266EX is using (although this nice
|
||||||
|
* round number looks deliberate). The exception handler is burned on rom
|
||||||
|
* so it should work on future SDK updates, but not necessarily on future
|
||||||
|
* revisions of the chip.
|
||||||
|
*/
|
||||||
|
#define V7_GDB_SP_OFFSET 0x100
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Addresses in this range are guaranteed to be readable without faulting.
|
||||||
|
* Contains ranges that are unmapped but innocuous.
|
||||||
|
*
|
||||||
|
* Putative ESP8266 memory map at:
|
||||||
|
* https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map
|
||||||
|
*/
|
||||||
|
#define ESP_LOWER_VALID_ADDRESS 0x20000000
|
||||||
|
#define ESP_UPPER_VALID_ADDRESS 0x60000000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constructed by xtos.
|
||||||
|
*
|
||||||
|
* There is a UserFrame structure in
|
||||||
|
* ./esp_iot_rtos_sdk/extra_include/xtensa/xtruntime-frames.h
|
||||||
|
*/
|
||||||
|
struct xtos_saved_regs {
|
||||||
|
uint32_t pc; /* instruction causing the trap */
|
||||||
|
uint32_t ps;
|
||||||
|
uint32_t sar;
|
||||||
|
uint32_t vpri; /* current xtos virtual priority */
|
||||||
|
uint32_t a0; /* when __XTENSA_CALL0_ABI__ is true */
|
||||||
|
uint32_t a[16]; /* a2 - a15 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register file in the format lx106 gdb port expects it.
|
||||||
|
*
|
||||||
|
* Inspired by gdb/regformats/reg-xtensa.dat from
|
||||||
|
* https://github.com/jcmvbkbc/crosstool-NG/blob/lx106-g%2B%2B/overlays/xtensa_lx106.tar
|
||||||
|
*/
|
||||||
|
struct regfile {
|
||||||
|
uint32_t a[16];
|
||||||
|
uint32_t pc;
|
||||||
|
uint32_t sar;
|
||||||
|
uint32_t litbase;
|
||||||
|
uint32_t sr176;
|
||||||
|
uint32_t sr208;
|
||||||
|
uint32_t ps;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define printf ets_printf
|
||||||
|
extern void uart_write_char_d(char c);
|
||||||
|
|
||||||
|
/* TODO(mkm): not sure if gdb guarantees lowercase hex digits */
|
||||||
|
#define fromhex(c) \
|
||||||
|
(((c) &0x40) ? ((c) &0x20 ? (c) - 'a' + 10 : (c) - 'A' + 10) : (c) - '0')
|
||||||
|
#define hexdigit(n) (((n) < 10) ? '0' + (n) : 'a' + ((n) -10))
|
||||||
|
|
||||||
|
static struct regfile regs = {0};
|
||||||
|
static uint8_t gdb_send_checksum;
|
||||||
|
|
||||||
|
int gdb_read_uart() {
|
||||||
|
static char buf[512];
|
||||||
|
static char pos = 0;
|
||||||
|
|
||||||
|
if (pos == 0) {
|
||||||
|
size_t rx_count;
|
||||||
|
while ((rx_count = (USS(0) >> USRXC) & 0xff)>0 && pos < sizeof(buf)) {
|
||||||
|
buf[pos++] = U0F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pos == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return buf[--pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t read_unaligned_byte(uint8_t *addr) {
|
||||||
|
uint32_t *base = (uint32_t *) ((uintptr_t) addr & ~0x3);
|
||||||
|
uint32_t word;
|
||||||
|
|
||||||
|
word = *base;
|
||||||
|
return (uint8_t)(word >> 8 * ((uintptr_t) addr & 0x3));
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_nack() {
|
||||||
|
printf("-");
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_ack() {
|
||||||
|
printf("+");
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_begin_packet() {
|
||||||
|
printf("$");
|
||||||
|
gdb_send_checksum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_end_packet() {
|
||||||
|
printf("#%c%c", hexdigit(gdb_send_checksum >> 4),
|
||||||
|
hexdigit(gdb_send_checksum & 0xF));
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_putchar(char ch) {
|
||||||
|
gdb_send_checksum += (uint8_t) ch;
|
||||||
|
printf("%c", ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* output a string while computing the checksum */
|
||||||
|
void gdb_putstr(char *str) {
|
||||||
|
while (*str) gdb_putchar(*str++);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_putbyte(uint8_t val) {
|
||||||
|
gdb_putchar(hexdigit(val >> 4));
|
||||||
|
gdb_putchar(hexdigit(val & 0xF));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 32-bit integer in native byte order */
|
||||||
|
void gdb_putint(uint32_t val) {
|
||||||
|
int i;
|
||||||
|
uint8_t *v = (uint8_t *) &val;
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
gdb_putbyte(v[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send a gdb packet with checksum */
|
||||||
|
void gdb_send_packet(char *str) {
|
||||||
|
gdb_begin_packet();
|
||||||
|
gdb_putstr(str);
|
||||||
|
gdb_end_packet();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t gdb_read_unaligned(uint8_t *addr) {
|
||||||
|
if (addr < (uint8_t *) ESP_LOWER_VALID_ADDRESS ||
|
||||||
|
addr >= (uint8_t *) ESP_UPPER_VALID_ADDRESS) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return read_unaligned_byte(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handles the GDB server protocol.
|
||||||
|
* We currently support only the simple command set.
|
||||||
|
*
|
||||||
|
* Data is exchanged in packets like `$Cxxxxx#cc`
|
||||||
|
* where `C` is a single letter command name, `xxxx` is some data payload,
|
||||||
|
* and `cc` is a two digit hex checksum of the packet body.
|
||||||
|
* Replies follow the same structure except that they lack the command symbol.
|
||||||
|
*
|
||||||
|
* For a more complete description of the protocol, see
|
||||||
|
* https://sourceware.org/gdb/current/onlinedocs/gdb/Remote-Protocol.html
|
||||||
|
*/
|
||||||
|
void gdb_handle_char(int ch) {
|
||||||
|
static enum {
|
||||||
|
GDB_JUNK,
|
||||||
|
GDB_DATA,
|
||||||
|
GDB_CHECKSUM,
|
||||||
|
GDB_CHECKSUM2
|
||||||
|
} state = GDB_JUNK;
|
||||||
|
static char data[128];
|
||||||
|
static int pos = 0;
|
||||||
|
static uint8_t checksum;
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case GDB_JUNK:
|
||||||
|
if (ch == '$') {
|
||||||
|
checksum = 0;
|
||||||
|
state = GDB_DATA;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GDB_DATA:
|
||||||
|
if (ch == '#') {
|
||||||
|
state = GDB_CHECKSUM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* ignore too long commands, by acking and sending empty response */
|
||||||
|
if (pos > sizeof(data)) {
|
||||||
|
state = GDB_JUNK;
|
||||||
|
gdb_ack();
|
||||||
|
gdb_send_packet("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
checksum += (uint8_t) ch;
|
||||||
|
data[pos++] = ch;
|
||||||
|
break;
|
||||||
|
case GDB_CHECKSUM:
|
||||||
|
if (fromhex(ch) != (checksum >> 4)) {
|
||||||
|
gdb_nack();
|
||||||
|
state = GDB_JUNK;
|
||||||
|
} else {
|
||||||
|
state = GDB_CHECKSUM2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GDB_CHECKSUM2:
|
||||||
|
state = GDB_JUNK;
|
||||||
|
if (fromhex(ch) != (checksum & 0xF)) {
|
||||||
|
gdb_nack();
|
||||||
|
pos = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gdb_ack();
|
||||||
|
|
||||||
|
/* process commands */
|
||||||
|
switch (data[0]) {
|
||||||
|
case '?':
|
||||||
|
/* stop status */
|
||||||
|
gdb_send_packet("S09"); /* TRAP */
|
||||||
|
break;
|
||||||
|
case 'm': {
|
||||||
|
/* read memory */
|
||||||
|
int i;
|
||||||
|
uint32_t addr = 0;
|
||||||
|
uint32_t num = 0;
|
||||||
|
for (i = 1; i < pos && data[i] != ','; i++) {
|
||||||
|
addr <<= 4;
|
||||||
|
addr |= fromhex(data[i]);
|
||||||
|
}
|
||||||
|
for (i++; i < pos; i++) {
|
||||||
|
num <<= 4;
|
||||||
|
num |= fromhex(data[i]); /* should be decimal */
|
||||||
|
}
|
||||||
|
gdb_begin_packet();
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
gdb_putbyte(gdb_read_unaligned(((uint8_t *) addr) + i));
|
||||||
|
}
|
||||||
|
gdb_end_packet();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'g': {
|
||||||
|
/* dump registers */
|
||||||
|
int i;
|
||||||
|
gdb_begin_packet();
|
||||||
|
for (i = 0; i < sizeof(regs); i++) {
|
||||||
|
gdb_putbyte(((uint8_t *) ®s)[i]);
|
||||||
|
}
|
||||||
|
gdb_end_packet();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
gdb_send_packet("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The user should detach and let gdb do the talkin' */
|
||||||
|
void gdb_server() {
|
||||||
|
printf("waiting for gdb\n");
|
||||||
|
/*
|
||||||
|
* polling since we cannot wait for interrupts inside
|
||||||
|
* an interrupt handler of unknown level.
|
||||||
|
*
|
||||||
|
* Interrupts disabled so that the user (or v7 prompt)
|
||||||
|
* uart interrupt handler doesn't interfere.
|
||||||
|
*/
|
||||||
|
xthal_set_intenable(0);
|
||||||
|
for (;;) {
|
||||||
|
int ch = gdb_read_uart();
|
||||||
|
if (ch != -1) gdb_handle_char(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* xtos low level exception handler (in rom)
|
||||||
|
* populates an xtos_regs structure with (most) registers
|
||||||
|
* present at the time of the exception and passes it to the
|
||||||
|
* high-level handler.
|
||||||
|
*
|
||||||
|
* Note that the a1 (sp) register is clobbered (bug? necessity?),
|
||||||
|
* however the original stack pointer can be inferred from the address
|
||||||
|
* of the saved registers area, since the exception handler uses the same
|
||||||
|
* user stack. This might be different in other execution modes on the
|
||||||
|
* quite variegated xtensa platform family, but that's how it works on ESP8266.
|
||||||
|
*/
|
||||||
|
void ICACHE_RAM_ATTR gdb_exception_handler(struct xtos_saved_regs *frame) {
|
||||||
|
ESP8266_REG(0x900) &= 0x7e; // Disable WDT
|
||||||
|
int i;
|
||||||
|
uint32_t cause = RSR(EXCCAUSE);
|
||||||
|
uint32_t vaddr = RSR(EXCVADDR);
|
||||||
|
memcpy(®s.a[2], frame->a, sizeof(frame->a));
|
||||||
|
|
||||||
|
regs.a[0] = frame->a0;
|
||||||
|
regs.a[1] = (uint32_t) frame + V7_GDB_SP_OFFSET;
|
||||||
|
regs.pc = frame->pc;
|
||||||
|
regs.sar = frame->sar;
|
||||||
|
regs.ps = frame->ps;
|
||||||
|
regs.litbase = RSR(LITBASE);
|
||||||
|
|
||||||
|
U0IE = 0;
|
||||||
|
ets_install_putc1(&uart_write_char_d);
|
||||||
|
|
||||||
|
printf("\nTrap %d: pc=%p va=%p\n", cause, frame->pc, vaddr);
|
||||||
|
gdb_server();
|
||||||
|
|
||||||
|
_ResetVector();
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_init() {
|
||||||
|
char causes[] = {EXCCAUSE_ILLEGAL, EXCCAUSE_INSTR_ERROR,
|
||||||
|
EXCCAUSE_LOAD_STORE_ERROR, EXCCAUSE_DIVIDE_BY_ZERO,
|
||||||
|
EXCCAUSE_UNALIGNED, EXCCAUSE_INSTR_PROHIBITED,
|
||||||
|
EXCCAUSE_LOAD_PROHIBITED, EXCCAUSE_STORE_PROHIBITED};
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < (int) sizeof(causes); i++) {
|
||||||
|
_xtos_set_exception_handler(causes[i], gdb_exception_handler);
|
||||||
|
}
|
||||||
|
}
|
6
libraries/GDBStub/src/GDBStub.h
Normal file
6
libraries/GDBStub/src/GDBStub.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef GDBSTUB_H
|
||||||
|
#define GDBSTUB_H
|
||||||
|
|
||||||
|
// this header is intentionally left blank
|
||||||
|
|
||||||
|
#endif //GDBSTUB_H
|
@ -16,18 +16,18 @@ compiler.sdk.path={runtime.platform.path}/tools/sdk
|
|||||||
compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ "-I{compiler.sdk.path}/include"
|
compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ "-I{compiler.sdk.path}/include"
|
||||||
|
|
||||||
compiler.c.cmd=xtensa-lx106-elf-gcc
|
compiler.c.cmd=xtensa-lx106-elf-gcc
|
||||||
compiler.c.flags=-c -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99
|
compiler.c.flags=-c -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99 -ffunction-sections -fdata-sections
|
||||||
|
|
||||||
compiler.S.cmd=xtensa-lx106-elf-gcc
|
compiler.S.cmd=xtensa-lx106-elf-gcc
|
||||||
compiler.S.flags=-c -g -x assembler-with-cpp -MMD
|
compiler.S.flags=-c -g -x assembler-with-cpp -MMD
|
||||||
|
|
||||||
compiler.c.elf.flags=-g -Os -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-T{build.flash_ld}" -Wl,-wrap,system_restart_local -Wl,-wrap,register_chipv6_phy
|
compiler.c.elf.flags=-g -Os -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-T{build.flash_ld}" -Wl,--gc-sections -Wl,-wrap,system_restart_local -Wl,-wrap,register_chipv6_phy
|
||||||
|
|
||||||
compiler.c.elf.cmd=xtensa-lx106-elf-gcc
|
compiler.c.elf.cmd=xtensa-lx106-elf-gcc
|
||||||
compiler.c.elf.libs=-lm -lgcc -lhal -lphy -lnet80211 -llwip -lwpa -lmain -lpp -lsmartconfig -lwps -lcrypto -laxtls
|
compiler.c.elf.libs=-lm -lgcc -lhal -lphy -lnet80211 -llwip -lwpa -lmain -lpp -lsmartconfig -lwps -lcrypto -laxtls
|
||||||
|
|
||||||
compiler.cpp.cmd=xtensa-lx106-elf-g++
|
compiler.cpp.cmd=xtensa-lx106-elf-g++
|
||||||
compiler.cpp.flags=-c -Os -g -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -falign-functions=4 -std=c++11 -MMD
|
compiler.cpp.flags=-c -Os -g -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -falign-functions=4 -std=c++11 -MMD -ffunction-sections -fdata-sections
|
||||||
|
|
||||||
compiler.as.cmd=xtensa-lx106-elf-as
|
compiler.as.cmd=xtensa-lx106-elf-as
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ typedef enum {
|
|||||||
|
|
||||||
#ifdef ICACHE_FLASH
|
#ifdef ICACHE_FLASH
|
||||||
#define ICACHE_FLASH_ATTR __attribute__((section(".irom0.text")))
|
#define ICACHE_FLASH_ATTR __attribute__((section(".irom0.text")))
|
||||||
#define ICACHE_RAM_ATTR __attribute__((section(".text")))
|
#define ICACHE_RAM_ATTR __attribute__((section(".iram.text")))
|
||||||
#define ICACHE_RODATA_ATTR __attribute__((section(".irom.text")))
|
#define ICACHE_RODATA_ATTR __attribute__((section(".irom.text")))
|
||||||
#else
|
#else
|
||||||
#define ICACHE_FLASH_ATTR
|
#define ICACHE_FLASH_ATTR
|
||||||
|
@ -150,12 +150,11 @@ SECTIONS
|
|||||||
.irom0.text : ALIGN(4)
|
.irom0.text : ALIGN(4)
|
||||||
{
|
{
|
||||||
_irom0_text_start = ABSOLUTE(.);
|
_irom0_text_start = ABSOLUTE(.);
|
||||||
*core_esp8266_*.o(.literal*, .text*)
|
*.c.o(.literal*, .text*)
|
||||||
*spiffs*.o(.literal*, .text*)
|
|
||||||
*.cpp.o(.literal*, .text*)
|
*.cpp.o(.literal*, .text*)
|
||||||
*libm.a:(.literal .text .literal.* .text.*)
|
*libm.a:(.literal .text .literal.* .text.*)
|
||||||
*libsmartconfig.a:(.literal .text .literal.* .text.*)
|
*libsmartconfig.a:(.literal .text .literal.* .text.*)
|
||||||
*(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
|
*(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text .irom.text.*)
|
||||||
_irom0_text_end = ABSOLUTE(.);
|
_irom0_text_end = ABSOLUTE(.);
|
||||||
_flash_code_end = ABSOLUTE(.);
|
_flash_code_end = ABSOLUTE(.);
|
||||||
} >irom0_0_seg :irom0_0_phdr
|
} >irom0_0_seg :irom0_0_phdr
|
||||||
@ -192,6 +191,8 @@ SECTIONS
|
|||||||
*(.init.literal)
|
*(.init.literal)
|
||||||
*(.init)
|
*(.init)
|
||||||
*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
|
*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
|
||||||
|
*.cpp.o(.iram.text)
|
||||||
|
*.c.o(.iram.text)
|
||||||
*(.fini.literal)
|
*(.fini.literal)
|
||||||
*(.fini)
|
*(.fini)
|
||||||
*(.gnu.version)
|
*(.gnu.version)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user