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

Merge pull request #7 from esp8266/esp8266

pull master
This commit is contained in:
Me No Dev
2015-10-08 03:42:34 +03:00
28 changed files with 890 additions and 285 deletions

View File

@ -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;
} }

View File

@ -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();
} }

View File

@ -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') {

View File

@ -1,9 +1,9 @@
/* /*
timer.c - Timer1 library for esp8266 timer.c - Timer1 library for esp8266
Copyright (c) 2015 Hristo Gochkov. All rights reserved. Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment. This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
@ -29,13 +29,13 @@
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) {
// 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
uint32_t savedPS = xt_rsil(15); // stop other interrupts uint32_t savedPS = xt_rsil(15); // stop other interrupts
timer1_user_cb(); timer1_user_cb();
xt_wsr_ps(savedPS); xt_wsr_ps(savedPS);
} }
@ -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();
} }

View File

@ -1,9 +1,9 @@
/* /*
pwm.c - analogWrite implementation for esp8266 pwm.c - analogWrite implementation for esp8266
Copyright (c) 2015 Hristo Gochkov. All rights reserved. Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment. This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
@ -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];

View File

@ -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;
@ -486,8 +486,8 @@ size_t ICACHE_FLASH_ATTR strlcpy(char* dst, const char* src, size_t size) {
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software * 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement: * must display the following acknowledgement:
* This product includes software developed by the University of * This product includes software developed by the University of
* California, Berkeley and its contributors. * California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors * 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software * may be used to endorse or promote products derived from this software
* without specific prior written permission. * without specific prior written permission.
@ -505,134 +505,134 @@ 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;
unsigned long cutoff; unsigned long cutoff;
int neg = 0, any, cutlim; int neg = 0, any, cutlim;
/* /*
* Skip white space and pick up leading +/- sign if any. * Skip white space and pick up leading +/- sign if any.
* If base is 0, allow 0x for hex and 0 for octal, else * If base is 0, allow 0x for hex and 0 for octal, else
* assume decimal; if base is already 16, allow 0x. * assume decimal; if base is already 16, allow 0x.
*/ */
do { do {
c = *s++; c = *s++;
} while (isspace(c)); } while (isspace(c));
if (c == '-') { if (c == '-') {
neg = 1; neg = 1;
c = *s++; c = *s++;
} else if (c == '+') } else if (c == '+')
c = *s++; c = *s++;
if ((base == 0 || base == 16) && if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) { c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1]; c = s[1];
s += 2; s += 2;
base = 16; base = 16;
} }
if (base == 0) if (base == 0)
base = c == '0' ? 8 : 10; base = c == '0' ? 8 : 10;
/* /*
* Compute the cutoff value between legal numbers and illegal * Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the * numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if * base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that * followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the limit * is equal to this value may be valid or not; the limit
* between valid and invalid numbers is then based on the last * between valid and invalid numbers is then based on the last
* digit. For instance, if the range for longs is * digit. For instance, if the range for longs is
* [-2147483648..2147483647] and the input base is 10, * [-2147483648..2147483647] and the input base is 10,
* cutoff will be set to 214748364 and cutlim to either * cutoff will be set to 214748364 and cutlim to either
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
* a value > 214748364, or equal but the next digit is > 7 (or 8), * a value > 214748364, or equal but the next digit is > 7 (or 8),
* the number is too big, and we will return a range error. * the number is too big, and we will return a range error.
* *
* Set any if any `digits' consumed; make it negative to indicate * Set any if any `digits' consumed; make it negative to indicate
* overflow. * overflow.
*/ */
cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
cutlim = cutoff % (unsigned long)base; cutlim = cutoff % (unsigned long)base;
cutoff /= (unsigned long)base; cutoff /= (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) { for (acc = 0, any = 0;; c = *s++) {
if (isdigit(c)) if (isdigit(c))
c -= '0'; c -= '0';
else if (isalpha(c)) else if (isalpha(c))
c -= isupper(c) ? 'A' - 10 : 'a' - 10; c -= isupper(c) ? 'A' - 10 : 'a' - 10;
else else
break; break;
if (c >= base) if (c >= base)
break; break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1; any = -1;
else { else {
any = 1; any = 1;
acc *= base; acc *= base;
acc += c; acc += c;
} }
} }
if (any < 0) { if (any < 0) {
acc = neg ? LONG_MIN : LONG_MAX; acc = neg ? LONG_MIN : LONG_MAX;
errno = ERANGE; errno = ERANGE;
} else if (neg) } else if (neg)
acc = -acc; acc = -acc;
if (endptr != 0) if (endptr != 0)
*endptr = (char *) (any ? (char *)s - 1 : nptr); *endptr = (char *) (any ? (char *)s - 1 : nptr);
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;
int c; int c;
unsigned long cutoff; unsigned long cutoff;
int neg = 0, any, cutlim; int neg = 0, any, cutlim;
/* /*
* See strtol for comments as to the logic used. * See strtol for comments as to the logic used.
*/ */
do { do {
c = *s++; c = *s++;
} while (isspace(c)); } while (isspace(c));
if (c == '-') { if (c == '-') {
neg = 1; neg = 1;
c = *s++; c = *s++;
} else if (c == '+') } else if (c == '+')
c = *s++; c = *s++;
if ((base == 0 || base == 16) && if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) { c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1]; c = s[1];
s += 2; s += 2;
base = 16; base = 16;
} }
if (base == 0) if (base == 0)
base = c == '0' ? 8 : 10; base = c == '0' ? 8 : 10;
cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
cutlim = (unsigned long)ULONG_MAX % (unsigned long)base; cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) { for (acc = 0, any = 0;; c = *s++) {
if (isdigit(c)) if (isdigit(c))
c -= '0'; c -= '0';
else if (isalpha(c)) else if (isalpha(c))
c -= isupper(c) ? 'A' - 10 : 'a' - 10; c -= isupper(c) ? 'A' - 10 : 'a' - 10;
else else
break; break;
if (c >= base) if (c >= base)
break; break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1; any = -1;
else { else {
any = 1; any = 1;
acc *= base; acc *= base;
acc += c; acc += c;
} }
} }
if (any < 0) { if (any < 0) {
acc = ULONG_MAX; acc = ULONG_MAX;
errno = ERANGE; errno = ERANGE;
} else if (neg) } else if (neg)
acc = -acc; acc = -acc;
if (endptr != 0) if (endptr != 0)
*endptr = (char *) (any ? (char *)s - 1 : nptr); *endptr = (char *) (any ? (char *)s - 1 : nptr);
return (acc); return (acc);
} }

View File

@ -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>");

View File

@ -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);
}

View File

@ -0,0 +1,20 @@
#######################################
# Syntax Coloring Map For HTTPUpdateServer
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
ESP8266HTTPUpdateServer KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
setup KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View 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

View File

@ -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();
});
}

View File

@ -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

View File

@ -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

View File

@ -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;
} }

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View 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

View File

@ -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)

View File

@ -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

View File

@ -51,7 +51,7 @@ public:
protected: protected:
int _connectSSL(); int _connectSSL();
SSLContext* _ssl; SSLContext* _ssl = nullptr;
}; };
#endif //wificlientsecure_h #endif //wificlientsecure_h

View 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>.

View 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

View 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 *) &regs)[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(&regs.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);
}
}

View File

@ -0,0 +1,6 @@
#ifndef GDBSTUB_H
#define GDBSTUB_H
// this header is intentionally left blank
#endif //GDBSTUB_H

View File

@ -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

View File

@ -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

View File

@ -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)