diff --git a/cores/esp8266/Arduino.h b/cores/esp8266/Arduino.h index f82b3aea9..a4e00ec73 100644 --- a/cores/esp8266/Arduino.h +++ b/cores/esp8266/Arduino.h @@ -282,6 +282,13 @@ void configTime(int timezone, int daylightOffset_sec, const char* server1, void configTime(const char* tz, const char* server1, const char* server2 = nullptr, const char* server3 = nullptr); +// esp32 api compatibility +inline void configTzTime(const char* tz, const char* server1, + const char* server2 = nullptr, const char* server3 = nullptr) +{ + configTime(tz, server1, server2, server3); +} + #endif // __cplusplus #include "pins_arduino.h" diff --git a/cores/esp8266/Print.cpp b/cores/esp8266/Print.cpp index a1add0578..d93293ee8 100644 --- a/cores/esp8266/Print.cpp +++ b/cores/esp8266/Print.cpp @@ -268,47 +268,6 @@ size_t Print::printNumber(unsigned long n, uint8_t base) { } size_t Print::printFloat(double number, uint8_t digits) { - size_t n = 0; - - if(isnan(number)) - return print("nan"); - if(isinf(number)) - return print("inf"); - if(number > 4294967040.0) - return print("ovf"); // constant determined empirically - if(number < -4294967040.0) - return print("ovf"); // constant determined empirically - - // Handle negative numbers - if(number < 0.0) { - n += print('-'); - number = -number; - } - - // Round correctly so that print(1.999, 2) prints as "2.00" - double rounding = 0.5; - for(uint8_t i = 0; i < digits; ++i) - rounding /= 10.0; - - number += rounding; - - // Extract the integer part of the number and print it - unsigned long int_part = (unsigned long) number; - double remainder = number - (double) int_part; - n += print(int_part); - - // Print the decimal point, but only if there are digits beyond - if(digits > 0) { - n += print("."); - } - - // Extract digits from the remainder one at a time - while(digits-- > 0) { - remainder *= 10.0; - int toPrint = int(remainder); - n += print(toPrint); - remainder -= toPrint; - } - - return n; + char buf[40]; + return write(dtostrf(number, 0, digits, buf)); } diff --git a/cores/esp8266/Print.h b/cores/esp8266/Print.h index e620f14ad..e43883b39 100644 --- a/cores/esp8266/Print.h +++ b/cores/esp8266/Print.h @@ -26,6 +26,8 @@ #include "WString.h" #include "Printable.h" +#include "stdlib_noniso.h" + #define DEC 10 #define HEX 16 #define OCT 8 diff --git a/cores/esp8266/StackThunk.cpp b/cores/esp8266/StackThunk.cpp index 89294d390..541cd440f 100644 --- a/cores/esp8266/StackThunk.cpp +++ b/cores/esp8266/StackThunk.cpp @@ -111,14 +111,14 @@ uint32_t stack_thunk_get_max_usage() /* Print the stack from the first used 16-byte chunk to the top, decodable by the exception decoder */ void stack_thunk_dump_stack() { - uint32_t *pos = stack_thunk_top; - while (pos < stack_thunk_ptr) { + uint32_t *pos = stack_thunk_ptr; + while (pos < stack_thunk_top) { if ((pos[0] != _stackPaint) || (pos[1] != _stackPaint) || (pos[2] != _stackPaint) || (pos[3] != _stackPaint)) break; pos += 4; } ets_printf(">>>stack>>>\n"); - while (pos < stack_thunk_ptr) { + while (pos < stack_thunk_top) { ets_printf("%08x: %08x %08x %08x %08x\n", (int32_t)pos, pos[0], pos[1], pos[2], pos[3]); pos += 4; } diff --git a/cores/esp8266/WMath.cpp b/cores/esp8266/WMath.cpp index 1f0c8d7db..2cc20b9f5 100644 --- a/cores/esp8266/WMath.cpp +++ b/cores/esp8266/WMath.cpp @@ -70,11 +70,11 @@ long secureRandom(long howsmall, long howbig) { } long map(long x, long in_min, long in_max, long out_min, long out_max) { - long divisor = (in_max - in_min); - if(divisor == 0){ - return -1; //AVR returns -1, SAM returns 0 - } - return (x - in_min) * (out_max - out_min) / divisor + out_min; + const long dividend = out_max - out_min; + const long divisor = in_max - in_min; + const long delta = x - in_min; + + return (delta * dividend + (divisor / 2)) / divisor + out_min; } unsigned int makeWord(unsigned int w) { diff --git a/cores/esp8266/core_esp8266_noniso.cpp b/cores/esp8266/core_esp8266_noniso.cpp index b39edbb28..2d1fb7160 100644 --- a/cores/esp8266/core_esp8266_noniso.cpp +++ b/cores/esp8266/core_esp8266_noniso.cpp @@ -22,6 +22,7 @@ */ +#include #include #include #include @@ -40,75 +41,9 @@ char* ultoa(unsigned long value, char* result, int base) { } char * dtostrf(double number, signed char width, unsigned char prec, char *s) { - bool negative = false; - - if (isnan(number)) { - strcpy(s, "nan"); - return s; - } - if (isinf(number)) { - strcpy(s, "inf"); - return s; - } - - char* out = s; - - int fillme = width; // how many cells to fill for the integer part - if (prec > 0) { - fillme -= (prec+1); - } - - // Handle negative numbers - if (number < 0.0) { - negative = true; - fillme--; - number = -number; - } - - // Round correctly so that print(1.999, 2) prints as "2.00" - // I optimized out most of the divisions - double rounding = 2.0; - for (uint8_t i = 0; i < prec; ++i) - rounding *= 10.0; - rounding = 1.0 / rounding; - - number += rounding; - - // Figure out how big our number really is - double tenpow = 1.0; - int digitcount = 1; - while (number >= 10.0 * tenpow) { - tenpow *= 10.0; - digitcount++; - } - - number /= tenpow; - fillme -= digitcount; - - // Pad unused cells with spaces - while (fillme-- > 0) { - *out++ = ' '; - } - - // Handle negative sign - if (negative) *out++ = '-'; - - // Print the digits, and if necessary, the decimal point - digitcount += prec; - int8_t digit = 0; - while (digitcount-- > 0) { - digit = (int8_t)number; - if (digit > 9) digit = 9; // insurance - *out++ = (char)('0' | digit); - if ((digitcount == prec) && (prec > 0)) { - *out++ = '.'; - } - number -= digit; - number *= 10.0; - } - - // make sure the string is terminated - *out = 0; + char fmt[32]; + sprintf(fmt, "%%%d.%df", width, prec); + sprintf(s, fmt, number); return s; } diff --git a/cores/esp8266/core_esp8266_postmortem.cpp b/cores/esp8266/core_esp8266_postmortem.cpp index 0486ee573..84aad50a0 100644 --- a/cores/esp8266/core_esp8266_postmortem.cpp +++ b/cores/esp8266/core_esp8266_postmortem.cpp @@ -89,7 +89,7 @@ static void ets_printf_P(const char *str, ...) { vsnprintf(destStr, sizeof(destStr), str, argPtr); va_end(argPtr); while (*c) { - ets_putc(*(c++)); + ets_uart_putc1(*(c++)); } } @@ -147,10 +147,10 @@ void __wrap_system_restart_local() { // (determined empirically, might break) uint32_t offset = 0; if (rst_info.reason == REASON_SOFT_WDT_RST) { - offset = 0x1b0; + offset = 0x1a0; } else if (rst_info.reason == REASON_EXCEPTION_RST) { - offset = 0x1a0; + offset = 0x190; } else if (rst_info.reason == REASON_WDT_RST) { offset = 0x10; diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h index a3ce60c39..86ba43711 100644 --- a/cores/esp8266/coredecls.h +++ b/cores/esp8266/coredecls.h @@ -13,12 +13,14 @@ extern "C" { #include // g_pcont declaration extern bool timeshift64_is_set; +extern uint32_t sntp_real_timestamp; bool can_yield(); void esp_yield(); void esp_schedule(); void tune_timeshift64 (uint64_t now_us); void disable_extra4k_at_link_time (void) __attribute__((noinline)); +bool sntp_set_timezone_in_seconds(int32_t timezone); uint32_t sqrt32 (uint32_t n); uint32_t crc32 (const void* data, size_t length, uint32_t crc = 0xffffffff); diff --git a/cores/esp8266/sntp-lwip2.cpp b/cores/esp8266/sntp-lwip2.cpp index 9750a40da..cc3d8e853 100644 --- a/cores/esp8266/sntp-lwip2.cpp +++ b/cores/esp8266/sntp-lwip2.cpp @@ -1,7 +1,7 @@ /* * sntp-lwip2.c - ESP8266-specific functions for SNTP and lwIP-v2 * Copyright (c) 2015 Espressif (license is tools/sdk/lwip/src/core/sntp.c's) - * Redistribution and use in source and binary forms, with or without modification, + * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, @@ -10,17 +10,17 @@ * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * derived from this software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include "coredecls.h" @@ -65,11 +66,11 @@ extern "C" { static const char stod14[] PROGMEM = "settimeofday() can't set time!\n"; bool sntp_set_timezone(sint8 timezone); -bool sntp_set_timezone_in_seconds(sint32 timezone) +bool sntp_set_timezone_in_seconds(int32_t timezone) { - return sntp_set_timezone((sint8)(timezone/(60*60))); //TODO: move this to the same file as sntp_set_timezone() in lwip1.4, and implement correctly over there. + return sntp_set_timezone((sint8)(timezone/(60*60))); //TODO: move this to the same file as sntp_set_timezone() in lwip1.4, and implement correctly over there. } - + void sntp_set_daylight(int daylight); int settimeofday(const struct timeval* tv, const struct timezone* tz) @@ -87,7 +88,7 @@ int settimeofday(const struct timeval* tv, const struct timezone* tz) // reset time subsystem timeshift64_is_set = false; - + return -1; } return 0; @@ -99,372 +100,31 @@ int settimeofday(const struct timeval* tv, const struct timezone* tz) #include -static uint32 realtime_stamp = 0; -static uint16 dst = 0; -static sint32 time_zone = 8 * (60 * 60); // espressif HQ's default timezone +uint32_t sntp_real_timestamp = 0; LOCAL os_timer_t sntp_timer; -/*****************************************/ -#define SECSPERMIN 60L -#define MINSPERHOUR 60L -#define HOURSPERDAY 24L -#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) -#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY) -#define DAYSPERWEEK 7 -#define MONSPERYEAR 12 - -#define YEAR_BASE 1900 -#define EPOCH_YEAR 1970 -#define EPOCH_WDAY 4 -#define EPOCH_YEARS_SINCE_LEAP 2 -#define EPOCH_YEARS_SINCE_CENTURY 70 -#define EPOCH_YEARS_SINCE_LEAP_CENTURY 370 - -#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) - -int __tznorth; -int __tzyear; -char reult[100]; -static const int mon_lengths[2][12] = { - {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, - {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} -} ; - -static const int year_lengths[2] = { - 365, - 366 -} ; - -struct tm res_buf; - -__tzrule_type sntp__tzrule[2]; -struct tm * -sntp_mktm_r(const time_t * tim_p ,struct tm *res ,int is_gmtime) -{ - long days, rem; - time_t lcltime; - int y; - int yleap; - const int *ip; - - /* base decision about std/dst time on current time */ - lcltime = *tim_p; - - days = ((long)lcltime) / SECSPERDAY; - rem = ((long)lcltime) % SECSPERDAY; - while (rem < 0) - { - rem += SECSPERDAY; - --days; - } - while (rem >= SECSPERDAY) - { - rem -= SECSPERDAY; - ++days; - } - - /* compute hour, min, and sec */ - res->tm_hour = (int) (rem / SECSPERHOUR); - rem %= SECSPERHOUR; - res->tm_min = (int) (rem / SECSPERMIN); - res->tm_sec = (int) (rem % SECSPERMIN); - - /* compute day of week */ - if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0) - res->tm_wday += DAYSPERWEEK; - - /* compute year & day of year */ - y = EPOCH_YEAR; - if (days >= 0) - { - for (;;) - { - yleap = isleap(y); - if (days < year_lengths[yleap]) - break; - y++; - days -= year_lengths[yleap]; - } - } - else - { - do - { - --y; - yleap = isleap(y); - days += year_lengths[yleap]; - } while (days < 0); - } - - res->tm_year = y - YEAR_BASE; - res->tm_yday = days; - ip = mon_lengths[yleap]; - for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon) - days -= ip[res->tm_mon]; - res->tm_mday = days + 1; - - if (!is_gmtime) - { - int offset; - int hours, mins, secs; - -// TZ_LOCK; -// if (_daylight) -// { -// if (y == __tzyear || __tzcalc_limits (y)) -// res->tm_isdst = (__tznorth -// ? (*tim_p >= __tzrule[0].change && *tim_p < __tzrule[1].change) -// : (*tim_p >= __tzrule[0].change || *tim_p < __tzrule[1].change)); -// else -// res->tm_isdst = -1; -// } -// else - res->tm_isdst = -1; - - offset = (res->tm_isdst == 1 ? sntp__tzrule[1].offset : sntp__tzrule[0].offset); - - hours = offset / SECSPERHOUR; - offset = offset % SECSPERHOUR; - - mins = offset / SECSPERMIN; - secs = offset % SECSPERMIN; - - res->tm_sec -= secs; - res->tm_min -= mins; - res->tm_hour -= hours; - - if (res->tm_sec >= SECSPERMIN) - { - res->tm_min += 1; - res->tm_sec -= SECSPERMIN; - } - else if (res->tm_sec < 0) - { - res->tm_min -= 1; - res->tm_sec += SECSPERMIN; - } - if (res->tm_min >= MINSPERHOUR) - { - res->tm_hour += 1; - res->tm_min -= MINSPERHOUR; - } - else if (res->tm_min < 0) - { - res->tm_hour -= 1; - res->tm_min += MINSPERHOUR; - } - if (res->tm_hour >= HOURSPERDAY) - { - ++res->tm_yday; - ++res->tm_wday; - if (res->tm_wday > 6) - res->tm_wday = 0; - ++res->tm_mday; - res->tm_hour -= HOURSPERDAY; - if (res->tm_mday > ip[res->tm_mon]) - { - res->tm_mday -= ip[res->tm_mon]; - res->tm_mon += 1; - if (res->tm_mon == 12) - { - res->tm_mon = 0; - res->tm_year += 1; - res->tm_yday = 0; - } - } - } - else if (res->tm_hour < 0) - { - res->tm_yday -= 1; - res->tm_wday -= 1; - if (res->tm_wday < 0) - res->tm_wday = 6; - res->tm_mday -= 1; - res->tm_hour += 24; - if (res->tm_mday == 0) - { - res->tm_mon -= 1; - if (res->tm_mon < 0) - { - res->tm_mon = 11; - res->tm_year -= 1; - res->tm_yday = 365 + isleap(res->tm_year); - } - res->tm_mday = ip[res->tm_mon]; - } - } -// TZ_UNLOCK; - } - else - res->tm_isdst = 0; -// os_printf("res %d %d %d %d %d\n",res->tm_year,res->tm_mon,res->tm_mday,res->tm_yday,res->tm_hour); - return (res); -} -struct tm * -sntp_localtime_r(const time_t * tim_p , - struct tm *res) -{ - return sntp_mktm_r (tim_p, res, 0); -} - -struct tm * -sntp_localtime(const time_t * tim_p) -{ - return sntp_localtime_r (tim_p, &res_buf); -} - -int sntp__tzcalc_limits(int year) -{ - int days, year_days, years; - int i, j; - - if (year < EPOCH_YEAR) - return 0; - - __tzyear = year; - - years = (year - EPOCH_YEAR); - - year_days = years * 365 + - (years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 - (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 + - (years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400; - - for (i = 0; i < 2; ++i) - { - if (sntp__tzrule[i].ch == 'J') - days = year_days + sntp__tzrule[i].d + (isleap(year) && sntp__tzrule[i].d >= 60); - else if (sntp__tzrule[i].ch == 'D') - days = year_days + sntp__tzrule[i].d; - else - { - int yleap = isleap(year); - int m_day, m_wday, wday_diff; - const int *ip = mon_lengths[yleap]; - - days = year_days; - - for (j = 1; j < sntp__tzrule[i].m; ++j) - days += ip[j-1]; - - m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK; - - wday_diff = sntp__tzrule[i].d - m_wday; - if (wday_diff < 0) - wday_diff += DAYSPERWEEK; - m_day = (sntp__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff; - - while (m_day >= ip[j-1]) - m_day -= DAYSPERWEEK; - - days += m_day; - } - - /* store the change-over time in GMT form by adding offset */ - sntp__tzrule[i].change = days * SECSPERDAY + sntp__tzrule[i].s + sntp__tzrule[i].offset; - } - - __tznorth = (sntp__tzrule[0].change < sntp__tzrule[1].change); - - return 1; -} - -char* sntp_asctime_r(struct tm *tim_p ,char *result) -{ - static const char day_name[7][4] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" - }; - static const char mon_name[12][4] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - os_sprintf (result, "%s %s %02d %02d:%02d:%02d %02d\n", - day_name[tim_p->tm_wday], - mon_name[tim_p->tm_mon], - tim_p->tm_mday, tim_p->tm_hour, tim_p->tm_min, - tim_p->tm_sec, 1900 + tim_p->tm_year); - return result; -} - -char* sntp_asctime(struct tm *tim_p) -{ - return sntp_asctime_r (tim_p, reult); -} - -uint32 ICACHE_RAM_ATTR sntp_get_current_timestamp(void) -{ - return realtime_stamp; -} - -char* sntp_get_real_time(time_t t) -{ - return sntp_asctime(sntp_localtime (&t)); -} - -/* Returns the set timezone in seconds. If the timezone was set as seconds, the fractional part is floored. */ -sint32 sntp_get_timezone_in_seconds(void) -{ - return time_zone; -} - -/* Returns the set timezone in hours. If the timezone was set as seconds, the fractional part is floored. */ -sint8 sntp_get_timezone(void) -{ - return (sint8)(time_zone / (60 * 60)); -} - -/* Sets the timezone in hours. Internally, the timezone is converted to seconds. */ -bool sntp_set_timezone_in_seconds(sint32 timezone) -{ - if(timezone >= (-11 * (60 * 60)) || timezone <= (13 * (60 * 60))) { - time_zone = timezone; - return true; - } - return false; -} - -/* Sets the timezone in hours. Internally, the timezone is converted to seconds. */ -bool sntp_set_timezone(sint8 timezone) -{ - return sntp_set_timezone_in_seconds((sint32)timezone * 60 * 60); -} - - -void sntp_set_daylight(int daylight) -{ - dst = daylight; -} - void ICACHE_RAM_ATTR sntp_time_inc (void) { - realtime_stamp++; -} - -static void sntp_set_system_time (uint32_t t) -{ - realtime_stamp = t + time_zone + dst; - os_timer_disarm(&sntp_timer); - os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntp_time_inc, NULL); - os_timer_arm(&sntp_timer, 1000, 1); + sntp_real_timestamp++; } int settimeofday(const struct timeval* tv, const struct timezone* tz) { - if (tz) /*before*/ - { - sntp_set_timezone_in_seconds(tz->tz_minuteswest * 60); - // apparently tz->tz_dsttime is a bitfield and should not be further used (cf man) - sntp_set_daylight(0); - } - if (tv) /*after*/ - { - // reset time subsystem - tune_timeshift64(tv->tv_sec * 1000000ULL + tv->tv_usec); + if (tz || !tv) + // tz is obsolete (cf. man settimeofday) + return EINVAL; - sntp_set_system_time(tv->tv_sec); + // reset time subsystem + tune_timeshift64(tv->tv_sec * 1000000ULL + tv->tv_usec); + + sntp_real_timestamp = tv->tv_sec; + os_timer_disarm(&sntp_timer); + os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntp_time_inc, NULL); + os_timer_arm(&sntp_timer, 1000, 1); + + if (_settimeofday_cb) + schedule_recurrent_function_us([](){ _settimeofday_cb(); return false; }, 0); - if (_settimeofday_cb) - schedule_recurrent_function_us([](){ _settimeofday_cb(); return false; }, 0); - } return 0; } diff --git a/cores/esp8266/sntp-lwip2.h b/cores/esp8266/sntp-lwip2.h index 5ae697754..bcda54f9a 100644 --- a/cores/esp8266/sntp-lwip2.h +++ b/cores/esp8266/sntp-lwip2.h @@ -1,10 +1,6 @@ #ifndef __sntp_lwip2_h__ #define __sntp_lwip2_h__ -extern "C" { - -bool sntp_set_timezone_in_seconds(sint32 timezone); - -} +#include #endif diff --git a/cores/esp8266/time.cpp b/cores/esp8266/time.cpp index 33fb91752..a5788ebcf 100644 --- a/cores/esp8266/time.cpp +++ b/cores/esp8266/time.cpp @@ -23,6 +23,8 @@ #include "sntp.h" #include "coredecls.h" +#include // configTime() + #include "sntp-lwip2.h" extern "C" { @@ -71,14 +73,27 @@ int clock_gettime(clockid_t unused, struct timespec *tp) return 0; } +#if LWIP_VERSION_MAJOR == 1 +// hack for espressif time management included in patched lwIP-1.4 +#define sntp_real_timestamp sntp_get_current_timestamp() +#endif + +#if LWIP_VERSION_MAJOR == 2 +// backport api +bool sntp_set_timezone_in_seconds (int32_t timezone_sec) +{ + configTime(timezone_sec, 0, sntp_getservername(0), sntp_getservername(1), sntp_getservername(2)); + return true; +} +#endif + time_t time(time_t * t) { - time_t seconds = sntp_get_current_timestamp(); if (t) { - *t = seconds; + *t = sntp_real_timestamp; } - return seconds; + return sntp_real_timestamp; } int _gettimeofday_r(struct _reent* unused, struct timeval *tp, void *tzp) @@ -88,7 +103,7 @@ int _gettimeofday_r(struct _reent* unused, struct timeval *tp, void *tzp) if (tp) { if (!timeshift64_is_set) - tune_timeshift64(sntp_get_current_timestamp() * 1000000ULL); + tune_timeshift64(sntp_real_timestamp * 1000000ULL); uint64_t currentTime_us = timeshift64 + micros64(); tp->tv_sec = currentTime_us / 1000000ULL; tp->tv_usec = currentTime_us % 1000000ULL; @@ -100,15 +115,21 @@ int _gettimeofday_r(struct _reent* unused, struct timeval *tp, void *tzp) void configTime(int timezone_sec, int daylightOffset_sec, const char* server1, const char* server2, const char* server3) { - sntp_stop(); + char tzstr [64]; - setServer(0, server1); - setServer(1, server2); - setServer(2, server3); + // There is no way to tell when DST starts or stop with this API + // So DST is always integrated in TZ + // The other API should be preferred - sntp_set_timezone_in_seconds(timezone_sec); - sntp_set_daylight(daylightOffset_sec); - sntp_init(); + int tzs = daylightOffset_sec + timezone_sec; + int tzh = tzs / 3600; + tzs -= tzh * 3600; + int tzm = tzs / 60; + tzs -= tzm * 60; + + // man tzset: + snprintf(tzstr, sizeof tzstr, "ESPUSER<%+d:%02d:%02d>", tzh, tzm, tzs); + return configTime(tzstr, server1, server2, server3); } void configTime(const char* tz, const char* server1, const char* server2, const char* server3) @@ -118,11 +139,9 @@ void configTime(const char* tz, const char* server1, const char* server2, const setServer(0, server1); setServer(1, server2); setServer(2, server3); - char tzram[strlen_P(tz) + 1]; memcpy_P(tzram, tz, sizeof(tzram)); setenv("TZ", tzram, 1/*overwrite*/); - sntp_set_timezone_in_seconds(0); tzset(); sntp_init(); diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index b29f159a3..1c44f7833 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -110,7 +110,9 @@ public: // Append whatever follows this URI in request to get the file path. path += requestUri.substring(_baseUriLength); - if (!_fs.exists(path) && path.endsWith(".htm") && _fs.exists(path + "l")) { + // If neither nor .gz exist, and is a file.htm, try it with file.html instead + // For the normal case this will give a search order of index.htm, index.htm.gz, index.html, index.html.gz + if (!_fs.exists(path) && !_fs.exists(path + ".gz") && path.endsWith(".htm")) { path += "l"; } } diff --git a/libraries/ESP8266WiFi/src/WiFiServer.cpp b/libraries/ESP8266WiFi/src/WiFiServer.cpp index 494bf61dd..2ba5c6c97 100644 --- a/libraries/ESP8266WiFi/src/WiFiServer.cpp +++ b/libraries/ESP8266WiFi/src/WiFiServer.cpp @@ -35,12 +35,17 @@ extern "C" { #include "lwip/opt.h" #include "lwip/tcp.h" #include "lwip/inet.h" +#include "lwip/init.h" // LWIP_VERSION_ #include +#ifndef MAX_PENDING_CLIENTS_PER_PORT +#define MAX_PENDING_CLIENTS_PER_PORT 5 +#endif + WiFiServer::WiFiServer(const IPAddress& addr, uint16_t port) : _port(port) , _addr(addr) -, _pcb(nullptr) +, _listen_pcb(nullptr) , _unclaimed(nullptr) , _discarded(nullptr) { @@ -49,7 +54,7 @@ WiFiServer::WiFiServer(const IPAddress& addr, uint16_t port) WiFiServer::WiFiServer(uint16_t port) : _port(port) , _addr(IP_ANY_TYPE) -, _pcb(nullptr) +, _listen_pcb(nullptr) , _unclaimed(nullptr) , _discarded(nullptr) { @@ -60,9 +65,14 @@ void WiFiServer::begin() { } void WiFiServer::begin(uint16_t port) { + return begin(port, MAX_PENDING_CLIENTS_PER_PORT); +} + +void WiFiServer::begin(uint16_t port, uint8_t backlog) { close(); + if (!backlog) + return; _port = port; - err_t err; tcp_pcb* pcb = tcp_new(); if (!pcb) return; @@ -70,20 +80,23 @@ void WiFiServer::begin(uint16_t port) { pcb->so_options |= SOF_REUSEADDR; // (IPAddress _addr) operator-converted to (const ip_addr_t*) - err = tcp_bind(pcb, _addr, _port); - - if (err != ERR_OK) { + if (tcp_bind(pcb, _addr, _port) != ERR_OK) { tcp_close(pcb); return; } +#if LWIP_VERSION_MAJOR == 1 tcp_pcb* listen_pcb = tcp_listen(pcb); +#else + tcp_pcb* listen_pcb = tcp_listen_with_backlog(pcb, backlog); +#endif + if (!listen_pcb) { tcp_close(pcb); return; } - _pcb = listen_pcb; - _port = _pcb->local_port; + _listen_pcb = listen_pcb; + _port = _listen_pcb->local_port; tcp_accept(listen_pcb, &WiFiServer::_s_accept); tcp_arg(listen_pcb, (void*) this); } @@ -111,6 +124,10 @@ WiFiClient WiFiServer::available(byte* status) { (void) status; if (_unclaimed) { WiFiClient result(_unclaimed); +#if LWIP_VERSION_MAJOR != 1 + _unclaimed->acceptPCB(); + tcp_backlog_accepted(_unclaimed->getPCB()); +#endif _unclaimed = _unclaimed->next(); result.setNoDelay(getNoDelay()); DEBUGV("WS:av\r\n"); @@ -122,9 +139,9 @@ WiFiClient WiFiServer::available(byte* status) { } uint8_t WiFiServer::status() { - if (!_pcb) + if (!_listen_pcb) return CLOSED; - return _pcb->state; + return _listen_pcb->state; } uint16_t WiFiServer::port() const { @@ -132,11 +149,11 @@ uint16_t WiFiServer::port() const { } void WiFiServer::close() { - if (!_pcb) { + if (!_listen_pcb) { return; } - tcp_close(_pcb); - _pcb = nullptr; + tcp_close(_listen_pcb); + _listen_pcb = nullptr; } void WiFiServer::stop() { @@ -169,9 +186,36 @@ T* slist_append_tail(T* head, T* item) { long WiFiServer::_accept(tcp_pcb* apcb, long err) { (void) err; DEBUGV("WS:ac\r\n"); + +#if LWIP_VERSION_MAJOR == 1 + ClientContext* client = new ClientContext(apcb, &WiFiServer::_s_discard, this); + tcp_accepted(_listen_pcb); + +#else + + // backlog doc: + // http://lwip.100.n7.nabble.com/Problem-re-opening-listening-pbc-tt32484.html#a32494 + // https://www.nongnu.org/lwip/2_1_x/group__tcp__raw.html#gaeff14f321d1eecd0431611f382fcd338 + + // lwip-v2: Tell ClientContext to not accept yet the connection (final 'false' below) + ClientContext* client = new ClientContext(apcb, &WiFiServer::_s_discard, this, false); + // increase lwIP's backlog + tcp_backlog_delayed(apcb); + + // Optimization Path: + // when lwip-v1.4 is not allowed anymore, + // - _accept() should not create ClientContext anymore + // - apcb should be stored into some sort of linked list (->_unclaimed) + // (the linked list would store tcp_pcb* instead of ClientContext*) + // (TCP_PCB_EXTARGS might be used for that (lwIP's struct tcp_pcb)) + // - on available(), get the pcb back and create the ClientContext + // (this is not done today for better source readability with lwip-1.4 around) + +#endif + _unclaimed = slist_append_tail(_unclaimed, client); - tcp_accepted(_pcb); + return ERR_OK; } diff --git a/libraries/ESP8266WiFi/src/WiFiServer.h b/libraries/ESP8266WiFi/src/WiFiServer.h index 7a4a3246d..9df758bf0 100644 --- a/libraries/ESP8266WiFi/src/WiFiServer.h +++ b/libraries/ESP8266WiFi/src/WiFiServer.h @@ -31,6 +31,37 @@ extern "C" { #include "Server.h" #include "IPAddress.h" +// lwIP-v2 backlog facility allows to keep memory safe by limiting the +// maximum number of incoming *pending clients*. Default number of possibly +// simultaneously pending clients is defined in WiFiServer.cpp +// (MAX_PENDING_CLIENTS_PER_PORT=5). User can overide it at runtime from +// sketch: +// WiFiServer::begin(port, max-simultaneous-pending-clients); +// +// An "incoming pending" client is a new incoming TCP connection trying to +// reach the TCP server. It is "pending" until lwIP acknowledges it and +// "accepted / no more pending" when user calls WiFiServer::available(). +// +// Before the backlog feature or with lwIP-v1.4, there was no pending +// connections: They were immediately accepted and filling RAM. +// +// Several pending clients can appear during the time when one client is +// served by a long not-async service like ESP8266WebServer. During that +// time WiFiServer::available() cannot be called. +// +// Note: This *does not limit* the number of *simultaneously accepted +// clients*. Such limit management is left to the user. +// +// Thus, when the maximum number of pending connections is reached, new +// connections are delayed. +// By "delayed", it is meant that WiFiServer(lwIP) will not answer to the +// SYN packet until there is room for a new one: The TCP server on that port +// will be mute. The TCP client will regularly try to connect until success +// or a timeout occurs (72s on windows). +// +// When user calls WiFiServer::available(), the tcp server stops muting and +// answers to newcomers (until the "backlog" pending list is full again). + class ClientContext; class WiFiClient; @@ -39,7 +70,7 @@ class WiFiServer : public Server { protected: uint16_t _port; IPAddress _addr; - tcp_pcb* _pcb; + tcp_pcb* _listen_pcb; ClientContext* _unclaimed; ClientContext* _discarded; @@ -53,6 +84,7 @@ public: bool hasClient(); void begin(); void begin(uint16_t port); + void begin(uint16_t port, uint8_t backlog); void setNoDelay(bool nodelay); bool getNoDelay(); virtual size_t write(uint8_t); diff --git a/libraries/ESP8266WiFi/src/include/ClientContext.h b/libraries/ESP8266WiFi/src/include/ClientContext.h index 806fc5e39..4afe647a2 100644 --- a/libraries/ESP8266WiFi/src/include/ClientContext.h +++ b/libraries/ESP8266WiFi/src/include/ClientContext.h @@ -36,16 +36,27 @@ bool getDefaultPrivateGlobalSyncValue (); class ClientContext { public: - ClientContext(tcp_pcb* pcb, discard_cb_t discard_cb, void* discard_cb_arg) : + ClientContext(tcp_pcb* pcb, discard_cb_t discard_cb, void* discard_cb_arg, bool acceptNow = true) : _pcb(pcb), _rx_buf(0), _rx_buf_offset(0), _discard_cb(discard_cb), _discard_cb_arg(discard_cb_arg), _refcnt(0), _next(0), _sync(::getDefaultPrivateGlobalSyncValue()) { - tcp_setprio(pcb, TCP_PRIO_MIN); - tcp_arg(pcb, this); - tcp_recv(pcb, &_s_recv); - tcp_sent(pcb, &_s_acked); - tcp_err(pcb, &_s_error); - tcp_poll(pcb, &_s_poll, 1); + if (acceptNow) + acceptPCB(); + } + + tcp_pcb* getPCB () + { + return _pcb; + } + + void acceptPCB() + { + tcp_setprio(_pcb, TCP_PRIO_MIN); + tcp_arg(_pcb, this); + tcp_recv(_pcb, &_s_recv); + tcp_sent(_pcb, &_s_acked); + tcp_err(_pcb, &_s_error); + tcp_poll(_pcb, &_s_poll, 1); // keep-alive not enabled by default //keepAlive(); diff --git a/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino b/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino index c526b6670..33cd14603 100644 --- a/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino +++ b/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino @@ -134,13 +134,14 @@ void showTime() { Serial.println((uint32_t)now); // timezone and demo in the future - Serial.printf("timezone: %s\n", MYTZ); + Serial.printf("timezone: %s\n", getenv("TZ")); // human readable Serial.print("ctime: "); Serial.print(ctime(&now)); #if LWIP_VERSION_MAJOR > 1 + // LwIP v2 is able to list more details about the currently configured SNTP servers for (int i = 0; i < SNTP_MAX_SERVERS; i++) { IPAddress sntp = *sntp_getserver(i); @@ -203,8 +204,7 @@ void setup() { // it will be used until NTP server will send us real current time time_t rtc = RTC_UTC_TEST; timeval tv = { rtc, 0 }; - timezone tz = { 0, 0 }; - settimeofday(&tv, &tz); + settimeofday(&tv, nullptr); // install callback - called when settimeofday is called (by SNTP or us) // once enabled (by DHCP), SNTP is updated every hour @@ -212,8 +212,18 @@ void setup() { // NTP servers may be overriden by your DHCP server for a more local one // (see below) + + // ----> Here is the ONLY ONE LINE needed in your sketch + configTime(MYTZ, "pool.ntp.org"); + // Here is the ONLY ONE LINE needed in your sketch <---- + // pick a value from TZ.h (search for this file in your filesystem) for MYTZ + + // former configTime is still valid, here is the call for 7 hours to the west + // with an enabled 30mn DST + //configTime(7 * 3600, 3600 / 2, "pool.ntp.org"); + // OPTIONAL: disable obtaining SNTP servers from DHCP //sntp_servermode_dhcp(0); // 0: disable obtaining SNTP servers from DHCP (enabled by default) diff --git a/package/build_boards_manager_package.sh b/package/build_boards_manager_package.sh index ff63547b9..372fa2c63 100755 --- a/package/build_boards_manager_package.sh +++ b/package/build_boards_manager_package.sh @@ -1,13 +1,13 @@ #!/bin/bash -# #set -x ver=`git describe --tag` visiblever=$ver -if [ "$ver" = 0.0.1 ]; then +# match 0.0.* +if [ "${ver%.*}" = 0.0 ]; then - git tag -d 0.0.1 + git tag -d ${ver} ver=`git describe --tag HEAD` plain_ver=$ver @@ -167,8 +167,21 @@ curl -L -o $old_json "https://github.com/esp8266/Arduino/releases/download/${bas new_json=package_esp8266com_index.json set +e -# Merge the old and new, then drop any obsolete package versions -python3 ../../merge_packages.py $new_json $old_json | python3 ../../drop_versions.py - tools 1.20.0-26-gb404fb9 >tmp && mv tmp $new_json && rm $old_json +# Merge the old and new +python3 ../../merge_packages.py $new_json $old_json > tmp + +# additional json to merge (for experimental releases) +echo "Additional json package files: ${MOREJSONPACKAGES}" +for json in ${MOREJSONPACKAGES}; do + if [ ! -z "$json" -a -r "$json" ]; then + echo "- merging $json" + python3 ../../merge_packages.py tmp $json > tmp2 + mv tmp2 tmp + fi +done + +# drop any obsolete package versions +python3 ../../drop_versions.py - tools 1.20.0-26-gb404fb9 < tmp > tmp2 && mv tmp2 $new_json && rm $old_json tmp # Verify the JSON file can be read, fail if it's not OK set -e diff --git a/tests/host/common/MockWiFiServer.cpp b/tests/host/common/MockWiFiServer.cpp index 6b8b7e83c..132ca5e88 100644 --- a/tests/host/common/MockWiFiServer.cpp +++ b/tests/host/common/MockWiFiServer.cpp @@ -59,7 +59,7 @@ WiFiClient WiFiServer::available (uint8_t* status) { (void)status; if (hasClient()) - return WiFiClient(new ClientContext(serverAccept(pcb2int(_pcb)))); + return WiFiClient(new ClientContext(serverAccept(pcb2int(_listen_pcb)))); return WiFiClient(); } diff --git a/tests/host/common/MockWiFiServerSocket.cpp b/tests/host/common/MockWiFiServerSocket.cpp index c791577d0..f56b9f424 100644 --- a/tests/host/common/MockWiFiServerSocket.cpp +++ b/tests/host/common/MockWiFiServerSocket.cpp @@ -60,6 +60,13 @@ int serverAccept (int srvsock) void WiFiServer::begin (uint16_t port) { + return begin(port, !0); +} + +void WiFiServer::begin (uint16_t port, uint8_t backlog) +{ + if (!backlog) + return; _port = port; return begin(); } @@ -109,13 +116,13 @@ void WiFiServer::begin () // store int into pointer - _pcb = int2pcb(sock); + _listen_pcb = int2pcb(sock); } bool WiFiServer::hasClient () { struct pollfd p; - p.fd = pcb2int(_pcb); + p.fd = pcb2int(_listen_pcb); p.events = POLLIN; return poll(&p, 1, 0) && p.revents == POLLIN; } @@ -134,7 +141,7 @@ size_t WiFiServer::write (const uint8_t *buf, size_t size) void WiFiServer::close () { - if (pcb2int(_pcb) >= 0) - ::close(pcb2int(_pcb)); - _pcb = int2pcb(-1); + if (pcb2int(_listen_pcb) >= 0) + ::close(pcb2int(_listen_pcb)); + _listen_pcb = int2pcb(-1); } diff --git a/tools/platformio-build.py b/tools/platformio-build.py index 7efcfb90e..c595497cb 100644 --- a/tools/platformio-build.py +++ b/tools/platformio-build.py @@ -264,6 +264,9 @@ app_ld = env.Command( "Generating LD script $TARGET")) env.Depends("$BUILD_DIR/$PROGNAME$PROGSUFFIX", app_ld) +if not env.BoardConfig().get("build.ldscript", ""): + env.Replace(LDSCRIPT_PATH=env.BoardConfig().get("build.arduino.ldscript", "")) + # # Dynamic core_version.h for staging builds # diff --git a/tools/sdk/lib/liblwip2-1460-feat.a b/tools/sdk/lib/liblwip2-1460-feat.a index 4dc84bf8b..a4d969e50 100644 Binary files a/tools/sdk/lib/liblwip2-1460-feat.a and b/tools/sdk/lib/liblwip2-1460-feat.a differ diff --git a/tools/sdk/lib/liblwip2-1460.a b/tools/sdk/lib/liblwip2-1460.a index 95c171203..a733ace32 100644 Binary files a/tools/sdk/lib/liblwip2-1460.a and b/tools/sdk/lib/liblwip2-1460.a differ diff --git a/tools/sdk/lib/liblwip2-536-feat.a b/tools/sdk/lib/liblwip2-536-feat.a index 6de957e3e..b077ff0a7 100644 Binary files a/tools/sdk/lib/liblwip2-536-feat.a and b/tools/sdk/lib/liblwip2-536-feat.a differ diff --git a/tools/sdk/lib/liblwip2-536.a b/tools/sdk/lib/liblwip2-536.a index 04b92dc84..93d6c9957 100644 Binary files a/tools/sdk/lib/liblwip2-536.a and b/tools/sdk/lib/liblwip2-536.a differ diff --git a/tools/sdk/lib/liblwip6-1460-feat.a b/tools/sdk/lib/liblwip6-1460-feat.a index 3256c5f9b..f278e75f9 100644 Binary files a/tools/sdk/lib/liblwip6-1460-feat.a and b/tools/sdk/lib/liblwip6-1460-feat.a differ diff --git a/tools/sdk/lib/liblwip6-536-feat.a b/tools/sdk/lib/liblwip6-536-feat.a index 4c8fea615..56968ba78 100644 Binary files a/tools/sdk/lib/liblwip6-536-feat.a and b/tools/sdk/lib/liblwip6-536-feat.a differ diff --git a/tools/sdk/lwip2/builder b/tools/sdk/lwip2/builder index 354887a25..b543b1f1f 160000 --- a/tools/sdk/lwip2/builder +++ b/tools/sdk/lwip2/builder @@ -1 +1 @@ -Subproject commit 354887a25f83064dc0c795e11704190845812713 +Subproject commit b543b1f1f4aff4787693da71b6ea91ca23e9b01f diff --git a/tools/sdk/lwip2/include/lwip-git-hash.h b/tools/sdk/lwip2/include/lwip-git-hash.h index 42aca1818..0fb03f0df 100644 --- a/tools/sdk/lwip2/include/lwip-git-hash.h +++ b/tools/sdk/lwip2/include/lwip-git-hash.h @@ -1,5 +1,5 @@ // generated by makefiles/make-lwip2-hash #ifndef LWIP_HASH_H #define LWIP_HASH_H -#define LWIP_HASH_STR "STABLE-2_1_2_RELEASE/glue:1.2-16-ge23a07e" +#define LWIP_HASH_STR "STABLE-2_1_2_RELEASE/glue:1.2-29-gb543b1f" #endif // LWIP_HASH_H diff --git a/tools/sdk/lwip2/include/lwipopts.h b/tools/sdk/lwip2/include/lwipopts.h index e2ae90030..6ee039f7c 100644 --- a/tools/sdk/lwip2/include/lwipopts.h +++ b/tools/sdk/lwip2/include/lwipopts.h @@ -1402,7 +1402,7 @@ * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. */ #if !defined TCP_LISTEN_BACKLOG || defined __DOXYGEN__ -#define TCP_LISTEN_BACKLOG 0 +#define TCP_LISTEN_BACKLOG LWIP_FEATURES // 0 #endif /** @@ -2278,6 +2278,12 @@ * @ingroup lwip_opts_infrastructure * @{ */ +/** + * LWIP_CHKSUM_ALGORITHM==3: Checksum algorithm fastest for ESP8266 + */ +#if !defined LWIP_CHKSUM_ALGORITHM || defined __DOXYGEN__ +#define LWIP_CHKSUM_ALGORITHM 3 // 2 +#endif /** * LWIP_CHECKSUM_CTRL_PER_NETIF==1: Checksum generation/check can be enabled/disabled * per netif. @@ -3573,7 +3579,7 @@ extern "C" { #define SNTP_SUPPRESS_DELAY_CHECK 1 #define SNTP_UPDATE_DELAY_DEFAULT 3600000 // update delay defined by a default weak function #define SNTP_UPDATE_DELAY sntp_update_delay_MS_rfc_not_less_than_15000() -extern uint32_t SNTP_UPDATE_DELAY; +uint32_t SNTP_UPDATE_DELAY; #if LWIP_FEATURES // esp8266/arduino/lwip-1.4 had 3 possible SNTP servers (constant was harcoded) @@ -3591,7 +3597,7 @@ extern uint32_t SNTP_UPDATE_DELAY; #define SNTP_STARTUP_DELAY 1 // enable startup delay #define SNTP_STARTUP_DELAY_FUNC_DEFAULT 0 // to 0 by default via a default weak function #define SNTP_STARTUP_DELAY_FUNC sntp_startup_delay_MS_rfc_not_less_than_60000() -extern uint32_t SNTP_STARTUP_DELAY_FUNC; +uint32_t SNTP_STARTUP_DELAY_FUNC; /* -------------------------------------------------- @@ -3611,7 +3617,7 @@ struct netif; #error LWIP_ERR_T definition should come from lwip1.4 from espressif #endif //#define LWIP_ERR_T s8 -LWIP_ERR_T lwip_unhandled_packet (struct pbuf* pbuf, struct netif* netif) __attribute__((weak)); +LWIP_ERR_T lwip_unhandled_packet (struct pbuf* pbuf, struct netif* netif); /* --------------------------------------------------