diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index b052718d51..4d259f3688 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -80,6 +80,10 @@ const char* core_release = #else NULL; #endif + +static os_timer_t delay_timer; +#define ONCE 0 +#define REPEAT 1 } // extern "C" void initVariant() __attribute__((weak)); @@ -128,6 +132,38 @@ extern "C" IRAM_ATTR void esp_schedule() { ets_post(LOOP_TASK_PRIORITY, 0, 0); } +void delay_end(void* arg) { + (void)arg; + esp_schedule(); +} + +extern "C" void __esp_delay(unsigned long ms) { + if (ms) { + os_timer_setfn(&delay_timer, (os_timer_func_t*)&delay_end, 0); + os_timer_arm(&delay_timer, ms, ONCE); + } + else { + esp_schedule(); + } + esp_yield(); + if (ms) { + os_timer_disarm(&delay_timer); + } +} + +extern "C" void esp_delay(unsigned long ms) __attribute__((weak, alias("__esp_delay"))); + +using IsBlockedCB = std::function; + +void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked, const uint32_t intvl_ms) { + const auto start = millis(); + decltype(millis()) expired; + while ((expired = millis() - start) < timeout_ms && blocked()) { + auto remaining = timeout_ms - expired; + esp_delay(remaining <= intvl_ms ? remaining : intvl_ms); + } +} + extern "C" void __yield() { if (can_yield()) { esp_schedule(); @@ -215,8 +251,8 @@ static void loop_task(os_event_t *events) { panic(); } } -extern "C" { +extern "C" { struct object { long placeholder[ 10 ]; }; void __register_frame_info (const void *begin, struct object *ob); extern char __eh_frame[]; @@ -253,7 +289,6 @@ static void __unhandled_exception_cpp() } #endif } - } void init_done() { diff --git a/cores/esp8266/core_esp8266_wiring.cpp b/cores/esp8266/core_esp8266_wiring.cpp index b956cebe43..8e2351d618 100644 --- a/cores/esp8266/core_esp8266_wiring.cpp +++ b/cores/esp8266/core_esp8266_wiring.cpp @@ -23,37 +23,20 @@ #include "ets_sys.h" #include "osapi.h" #include "user_interface.h" -#include "cont.h" +#include "coredecls.h" extern "C" { extern void ets_delay_us(uint32_t us); -extern void esp_schedule(); -extern void esp_yield(); -static os_timer_t delay_timer; static os_timer_t micros_overflow_timer; static uint32_t micros_at_last_overflow_tick = 0; static uint32_t micros_overflow_count = 0; #define ONCE 0 #define REPEAT 1 -void delay_end(void* arg) { - (void) arg; - esp_schedule(); -} - void __delay(unsigned long ms) { - if(ms) { - os_timer_setfn(&delay_timer, (os_timer_func_t*) &delay_end, 0); - os_timer_arm(&delay_timer, ms, ONCE); - } else { - esp_schedule(); - } - esp_yield(); - if(ms) { - os_timer_disarm(&delay_timer); - } + esp_delay(ms); } void delay(unsigned long ms) __attribute__ ((weak, alias("__delay"))); diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h index b9c771df77..c4ef04a292 100644 --- a/cores/esp8266/coredecls.h +++ b/cores/esp8266/coredecls.h @@ -14,6 +14,7 @@ extern "C" { bool can_yield(); void esp_yield(); +void esp_delay(unsigned long ms); void esp_schedule(); void tune_timeshift64 (uint64_t now_us); void disable_extra4k_at_link_time (void) __attribute__((noinline)); @@ -32,9 +33,28 @@ uint32_t crc32 (const void* data, size_t length, uint32_t crc = 0xffffffff); using BoolCB = std::function; using TrivialCB = std::function; +void settimeofday_cb (BoolCB&& cb); void settimeofday_cb (const BoolCB& cb); void settimeofday_cb (const TrivialCB& cb); +using IsBlockedCB = std::function; + +inline void esp_suspend() { + esp_yield(); +} + +inline void esp_suspend(const IsBlockedCB& blocked) { + do { + esp_suspend(); + } while (blocked()); +} + +void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked, const uint32_t intvl_ms); + +inline void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked) { + esp_delay(timeout_ms, blocked, timeout_ms); +} + #endif // __cplusplus #endif // __COREDECLS_H diff --git a/cores/esp8266/time.cpp b/cores/esp8266/time.cpp index b9489c330f..8e997c72d5 100644 --- a/cores/esp8266/time.cpp +++ b/cores/esp8266/time.cpp @@ -214,6 +214,11 @@ void settimeofday_cb (const TrivialCB& cb) _settimeofday_cb = [cb](bool sntp) { (void)sntp; cb(); }; } +void settimeofday_cb (BoolCB&& cb) +{ + _settimeofday_cb = std::move(cb); +} + void settimeofday_cb (const BoolCB& cb) { _settimeofday_cb = cb; diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp index 19da592c76..6b0b9ba754 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp @@ -49,10 +49,6 @@ extern "C" { #include "debug.h" #include "include/WiFiState.h" -extern "C" void esp_schedule(); -extern "C" void esp_yield(); - - // ----------------------------------------------------------------------------------------------------------------------- // ------------------------------------------------- Generic WiFi function ----------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------- @@ -438,10 +434,9 @@ bool ESP8266WiFiGenericClass::mode(WiFiMode_t m) { //tasks to wait correctly. constexpr unsigned int timeoutValue = 1000; //1 second if(can_yield()) { - using oneShot = esp8266::polledTimeout::oneShotFastMs; - oneShot timeout(timeoutValue); - while(wifi_get_opmode() != (uint8) m && !timeout) - delay(5); + // The final argument, intvl_ms, to esp_delay influences how frequently + // the scheduled recurrent functions (Schedule.h) are probed. + esp_delay(timeoutValue, [m]() { return wifi_get_opmode() != m; }, 5); //if at this point mode still hasn't been reached, give up if(wifi_get_opmode() != (uint8) m) { @@ -621,10 +616,12 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul aResult = IPAddress(&addr); } else if(err == ERR_INPROGRESS) { _dns_lookup_pending = true; - delay(timeout_ms); - // will resume on timeout or when wifi_dns_found_callback fires + // Will resume on timeout or when wifi_dns_found_callback fires. + // The final argument, intvl_ms, to esp_delay influences how frequently + // the scheduled recurrent functions (Schedule.h) are probed; here, to allow + // the ethernet driver perform work. + esp_delay(timeout_ms, []() { return _dns_lookup_pending; }, 1); _dns_lookup_pending = false; - // will return here when dns_found_callback fires if(aResult.isSet()) { err = ERR_OK; } @@ -671,8 +668,8 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul aResult = IPAddress(&addr); } else if(err == ERR_INPROGRESS) { _dns_lookup_pending = true; - delay(timeout_ms); // will resume on timeout or when wifi_dns_found_callback fires + esp_delay(timeout_ms, []() { return _dns_lookup_pending; }); _dns_lookup_pending = false; // will return here when dns_found_callback fires if(aResult.isSet()) { @@ -705,7 +702,8 @@ void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *ca if(ipaddr) { (*reinterpret_cast(callback_arg)) = IPAddress(ipaddr); } - esp_schedule(); // break delay in hostByName + _dns_lookup_pending = false; // resume hostByName + esp_schedule(); } uint32_t ESP8266WiFiGenericClass::shutdownCRC (const WiFiState& state) diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp index 8d74f687cb..5bfa13a430 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp @@ -27,6 +27,7 @@ #include "ESP8266WiFiMulti.h" #include #include +#include /** * @brief Print WiFi status @@ -83,36 +84,25 @@ static void printWiFiStatus(wl_status_t status) static wl_status_t waitWiFiConnect(uint32_t connectTimeoutMs) { wl_status_t status; + // The final argument, intvl_ms, to esp_delay influences how frequently + // the scheduled recurrent functions (Schedule.h) are probed. + esp_delay(connectTimeoutMs, + [&status]() { status = WiFi.status(); return status != WL_CONNECTED && status != WL_CONNECT_FAILED; }, 0); - // Set WiFi connect timeout - using esp8266::polledTimeout::oneShotMs; - oneShotMs connectTimeout(connectTimeoutMs); - - // Wait for WiFi status change or timeout - do { - // Refresh watchdog - delay(0); - - // Get WiFi status - status = WiFi.status(); - - // Check status - if (status == WL_CONNECTED) { - // Connected, print WiFi status - printWiFiStatus(status); - - // Return WiFi status - return status; - } else if (status == WL_CONNECT_FAILED) { - DEBUG_WIFI_MULTI("[WIFIM] Connect failed\n"); - - // Return WiFi connect failed - return WL_CONNECT_FAILED; - } - } while (!connectTimeout); + // Check status + if (status == WL_CONNECTED) { + // Connected, print WiFi status + printWiFiStatus(status); - DEBUG_WIFI_MULTI("[WIFIM] Connect timeout\n"); + // Return WiFi status + return status; + } else if (status == WL_CONNECT_FAILED) { + DEBUG_WIFI_MULTI("[WIFIM] Connect failed\n"); + } else { + DEBUG_WIFI_MULTI("[WIFIM] Connect timeout\n"); + } + // Return WiFi connect failed return WL_CONNECT_FAILED; } @@ -242,24 +232,16 @@ int8_t ESP8266WiFiMulti::startScan() // Start wifi scan in async mode WiFi.scanNetworks(true); - // Set WiFi scan timeout - using esp8266::polledTimeout::oneShotMs; - oneShotMs scanTimeout(WIFI_SCAN_TIMEOUT_MS); - // Wait for WiFi scan change or timeout - do { - // Refresh watchdog - delay(0); - - // Check scan timeout which may occur when scan does not report completion - if (scanTimeout) { - DEBUG_WIFI_MULTI("[WIFIM] Scan timeout\n"); - return WIFI_SCAN_FAILED; - } - - // Get scan result - scanResult = WiFi.scanComplete(); - } while (scanResult < 0); + // The final argument, intvl_ms, to esp_delay influences how frequently + // the scheduled recurrent functions (Schedule.h) are probed. + esp_delay(WIFI_SCAN_TIMEOUT_MS, + [&scanResult]() { scanResult = WiFi.scanComplete(); return scanResult < 0; }, 0); + // Check for scan timeout which may occur when scan does not report completion + if (scanResult < 0) { + DEBUG_WIFI_MULTI("[WIFIM] Scan timeout\n"); + return WIFI_SCAN_FAILED; + } // Print WiFi scan result printWiFiScan(); diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp index 99d27ba7a3..b93c77da9c 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp @@ -30,6 +30,8 @@ static void wifi_wps_status_cb(wps_cb_status status); +static bool _wps_config_pending = false; + /** * WPS config * so far only WPS_TYPE_PBC is supported (SDK 1.2.0) @@ -70,8 +72,9 @@ bool ESP8266WiFiSTAClass::beginWPSConfig(void) { return false; } - esp_yield(); + _wps_config_pending = true; // will resume when wifi_wps_status_cb fires + esp_suspend([]() { return _wps_config_pending; }); return true; } @@ -107,5 +110,6 @@ void wifi_wps_status_cb(wps_cb_status status) { } // TODO user function to get status - esp_schedule(); // resume beginWPSConfig + _wps_config_pending = false; // resume beginWPSConfig + esp_schedule(); } diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp index dd910295dd..9b59a90461 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp @@ -44,9 +44,6 @@ extern "C" { #include "debug.h" -extern "C" void esp_schedule(); -extern "C" void esp_yield(); - // ----------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------- Private functions ------------------------------------------------ // ----------------------------------------------------------------------------------------------------------------------- diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp index 65878a3d5b..37de0df1c6 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp @@ -36,9 +36,7 @@ extern "C" { } #include "debug.h" - -extern "C" void esp_schedule(); -extern "C" void esp_yield(); +#include // ----------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------- Private functions ------------------------------------------------ @@ -98,7 +96,9 @@ int8_t ESP8266WiFiScanClass::scanNetworks(bool async, bool show_hidden, uint8 ch return WIFI_SCAN_RUNNING; } - esp_yield(); // will resume when _scanDone fires + // will resume when _scanDone fires + esp_suspend([]() { return !ESP8266WiFiScanClass::_scanComplete && ESP8266WiFiScanClass::_scanStarted; }); + return ESP8266WiFiScanClass::_scanCount; } else { return WIFI_SCAN_FAILED; @@ -322,7 +322,7 @@ void ESP8266WiFiScanClass::_scanDone(void* result, int status) { ESP8266WiFiScanClass::_scanStarted = false; ESP8266WiFiScanClass::_scanComplete = true; - if(!ESP8266WiFiScanClass::_scanAsync) { + if (!ESP8266WiFiScanClass::_scanAsync) { esp_schedule(); // resume scanNetworks } else if (ESP8266WiFiScanClass::_onComplete) { ESP8266WiFiScanClass::_onComplete(ESP8266WiFiScanClass::_scanCount); diff --git a/libraries/ESP8266WiFi/src/include/ClientContext.h b/libraries/ESP8266WiFi/src/include/ClientContext.h index a994b5cb1d..6707677da5 100644 --- a/libraries/ESP8266WiFi/src/include/ClientContext.h +++ b/libraries/ESP8266WiFi/src/include/ClientContext.h @@ -26,11 +26,9 @@ class WiFiClient; typedef void (*discard_cb_t)(void*, ClientContext*); -extern "C" void esp_yield(); -extern "C" void esp_schedule(); - #include #include +#include bool getDefaultPrivateGlobalSyncValue (); @@ -145,11 +143,9 @@ class ClientContext } _connect_pending = true; _op_start_time = millis(); - for (decltype(_timeout_ms) i = 0; _connect_pending && i < _timeout_ms; i++) { - // Give scheduled functions a chance to run (e.g. Ethernet uses recurrent) - delay(1); - // will resume on timeout or when _connected or _notify_error fires - } + // will resume on timeout or when _connected or _notify_error fires + // give scheduled functions a chance to run (e.g. Ethernet uses recurrent) + esp_delay(_timeout_ms, [this]() { return this->_connect_pending; }, 1); _connect_pending = false; if (!_pcb) { DEBUGV(":cabrt\r\n"); @@ -458,9 +454,10 @@ class ClientContext void _notify_error() { if (_connect_pending || _send_waiting) { + // resume connect or _write_from_source _send_waiting = false; _connect_pending = false; - esp_schedule(); // break delay in connect or _write_from_source + esp_schedule(); } } @@ -487,11 +484,9 @@ class ClientContext } _send_waiting = true; - for (decltype(_timeout_ms) i = 0; _send_waiting && i < _timeout_ms; i++) { - // Give scheduled functions a chance to run (e.g. Ethernet uses recurrent) - delay(1); - // will resume on timeout or when _write_some_from_cb or _notify_error fires - } + // will resume on timeout or when _write_some_from_cb or _notify_error fires + // give scheduled functions a chance to run (e.g. Ethernet uses recurrent) + esp_delay(_timeout_ms, [this]() { return this->_send_waiting; }, 1); _send_waiting = false; } while(true); @@ -561,8 +556,9 @@ class ClientContext void _write_some_from_cb() { if (_send_waiting) { + // resume _write_from_source _send_waiting = false; - esp_schedule(); // break delay in _write_from_source + esp_schedule(); } } @@ -649,8 +645,9 @@ class ClientContext (void) pcb; assert(pcb == _pcb); if (_connect_pending) { + // resume connect _connect_pending = false; - esp_schedule(); // break delay in connect + esp_schedule(); } return ERR_OK; } diff --git a/tests/host/common/Arduino.cpp b/tests/host/common/Arduino.cpp index 780c4adc14..1e9758e63d 100644 --- a/tests/host/common/Arduino.cpp +++ b/tests/host/common/Arduino.cpp @@ -15,6 +15,7 @@ #include #include "Arduino.h" +#include #include @@ -57,6 +58,33 @@ extern "C" void esp_yield() { } +extern "C" void esp_delay (unsigned long ms) +{ + usleep(ms * 1000); +} + +using IsBlockedCB = std::function; + +inline void esp_suspend() { + esp_yield(); +} + +inline void esp_suspend(const IsBlockedCB& blocked) { + (void)blocked; +} + +void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked, const uint32_t intvl_ms) +{ + (void)blocked; + (void)intvl_ms; + usleep(timeout_ms * 1000); +} + +inline void esp_delay(const uint32_t timeout_ms, const IsBlockedCB& blocked) +{ + (void)blocked; + usleep(timeout_ms * 1000); +} extern "C" void __panic_func(const char* file, int line, const char* func) { (void)file; @@ -67,7 +95,7 @@ extern "C" void __panic_func(const char* file, int line, const char* func) { extern "C" void delay(unsigned long ms) { - usleep(ms * 1000); + esp_delay(ms); } extern "C" void delayMicroseconds(unsigned int us)