mirror of
https://github.com/esp8266/Arduino.git
synced 2025-07-18 23:03:34 +03:00
Implement esp_yield() as a replacement for delay(0)
esp_yield() now also calls esp_schedule(), original esp_yield() function renamed to esp_suspend(). Don't use delay(0) in the Core internals, libraries and examples. Use yield() when the code is supposed to be called from CONT, use esp_yield() when the code can be called from either CONT or SYS. Clean-up esp_yield() and esp_schedule() declarations across the code and use coredecls.h instead. Implement helper functions for libraries that were previously using esp_yield(), esp_schedule() and esp_delay() directly to wait for certain SYS context tasks to complete. Correctly use esp_delay() for timeouts, make sure scheduled functions have a chance to run (e.g. LwIP_Ethernet uses recurrent) Related issues: - #6107 - discussion about the esp_yield() and esp_delay() usage in ClientContext - #6212 - discussion about replacing delay() with a blocking loop - #6680 - pull request introducing LwIP-based Ethernet - #7146 - discussion that originated UART code changes - #7969 - proposal to remove delay(0) from the example code - #8291 - discussion related to the run_scheduled_recurrent_functions() usage in LwIP Ethernet - #8317 - yieldUntil() implementation, similar to the esp_delay() overload with a timeout and a 0 interval
This commit is contained in:
@ -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) {
|
||||
@ -518,9 +513,9 @@ bool ESP8266WiFiGenericClass::forceSleepBegin(uint32 sleepUs) {
|
||||
}
|
||||
|
||||
wifi_fpm_set_sleep_type(MODEM_SLEEP_T);
|
||||
delay(0);
|
||||
esp_yield();
|
||||
wifi_fpm_open();
|
||||
delay(0);
|
||||
esp_yield();
|
||||
auto ret = wifi_fpm_do_sleep(sleepUs);
|
||||
if (ret != 0)
|
||||
{
|
||||
@ -621,22 +616,24 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
if(err != 0) {
|
||||
DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, (int)err);
|
||||
} else {
|
||||
if(err == ERR_OK) {
|
||||
DEBUG_WIFI_GENERIC("[hostByName] Host: %s IP: %s\n", aHostname, aResult.toString().c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
return (err == ERR_OK) ? 1 : 0;
|
||||
|
||||
DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %s (%d)!\n", aHostname, lwip_strerr(err), (int)err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
@ -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()) {
|
||||
@ -680,13 +677,13 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul
|
||||
}
|
||||
}
|
||||
|
||||
if(err != 0) {
|
||||
DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, (int)err);
|
||||
} else {
|
||||
if(err == ERR_OK) {
|
||||
DEBUG_WIFI_GENERIC("[hostByName] Host: %s IP: %s\n", aHostname, aResult.toString().c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
return (err == ERR_OK) ? 1 : 0;
|
||||
DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, (int)err);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -705,7 +702,8 @@ void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *ca
|
||||
if(ipaddr) {
|
||||
(*reinterpret_cast<IPAddress*>(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)
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include "PolledTimeout.h"
|
||||
#include "ESP8266WiFiMulti.h"
|
||||
#include <coredecls.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -82,37 +83,29 @@ static void printWiFiStatus(wl_status_t status)
|
||||
*/
|
||||
static wl_status_t waitWiFiConnect(uint32_t connectTimeoutMs)
|
||||
{
|
||||
wl_status_t status;
|
||||
wl_status_t status = WL_CONNECT_FAILED;
|
||||
// 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);
|
||||
// Check status
|
||||
if (status == WL_CONNECTED) {
|
||||
// Connected, print WiFi status
|
||||
printWiFiStatus(status);
|
||||
|
||||
// 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);
|
||||
|
||||
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 +235,19 @@ 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();
|
||||
@ -535,7 +523,7 @@ void ESP8266WiFiMulti::printWiFiScan()
|
||||
rssi,
|
||||
(encryptionType == ENC_TYPE_NONE) ? ' ' : '*',
|
||||
ssid.c_str());
|
||||
delay(0);
|
||||
esp_yield();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include "PolledTimeout.h"
|
||||
#include "LwipIntf.h"
|
||||
|
||||
#include <coredecls.h>
|
||||
|
||||
#include "c_types.h"
|
||||
#include "ets_sys.h"
|
||||
#include "os_type.h"
|
||||
@ -44,9 +46,6 @@ extern "C" {
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
extern "C" void esp_schedule();
|
||||
extern "C" void esp_yield();
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------- Private functions ------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
|
@ -36,9 +36,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
extern "C" void esp_schedule();
|
||||
extern "C" void esp_yield();
|
||||
#include <coredecls.h>
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------- Private functions ------------------------------------------------
|
||||
@ -94,11 +92,13 @@ int8_t ESP8266WiFiScanClass::scanNetworks(bool async, bool show_hidden, uint8 ch
|
||||
ESP8266WiFiScanClass::_scanStarted = true;
|
||||
|
||||
if(ESP8266WiFiScanClass::_scanAsync) {
|
||||
delay(0); // time for the OS to trigger the scan
|
||||
esp_yield(); // time for the OS to trigger the scan
|
||||
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);
|
||||
|
@ -44,7 +44,6 @@ extern "C" {
|
||||
#include "lwip/netif.h"
|
||||
#include <include/ClientContext.h>
|
||||
#include "c_types.h"
|
||||
#include "coredecls.h"
|
||||
#include <mmu_iram.h>
|
||||
#include <umm_malloc/umm_malloc.h>
|
||||
#include <umm_malloc/umm_heap_select.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 <assert.h>
|
||||
#include <esp_priv.h>
|
||||
#include <coredecls.h>
|
||||
|
||||
bool getDefaultPrivateGlobalSyncValue ();
|
||||
|
||||
@ -145,11 +143,9 @@ public:
|
||||
}
|
||||
_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");
|
||||
@ -352,7 +348,7 @@ public:
|
||||
last_sent = millis();
|
||||
}
|
||||
|
||||
delay(0); // from sys or os context
|
||||
esp_yield(); // from sys or os context
|
||||
|
||||
if ((state() != ESTABLISHED) || (sndbuf == TCP_SND_BUF)) {
|
||||
// peer has closed or all bytes are sent and acked
|
||||
@ -458,9 +454,10 @@ protected:
|
||||
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 @@ protected:
|
||||
}
|
||||
|
||||
_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 @@ protected:
|
||||
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 @@ protected:
|
||||
(void) pcb;
|
||||
assert(pcb == _pcb);
|
||||
if (_connect_pending) {
|
||||
// resume connect
|
||||
_connect_pending = false;
|
||||
esp_schedule(); // break delay in connect
|
||||
esp_schedule();
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
class UdpContext;
|
||||
|
||||
extern "C" {
|
||||
void esp_yield();
|
||||
void esp_suspend();
|
||||
void esp_schedule();
|
||||
#include <assert.h>
|
||||
}
|
||||
@ -177,7 +177,7 @@ public:
|
||||
}
|
||||
|
||||
// warning: handler is called from tcp stack context
|
||||
// esp_yield and non-reentrant functions which depend on it will fail
|
||||
// esp_suspend and non-reentrant functions which depend on it will fail
|
||||
void onRx(rxhandler_t handler) {
|
||||
_on_rx = handler;
|
||||
}
|
||||
@ -411,7 +411,7 @@ public:
|
||||
err_t err;
|
||||
esp8266::polledTimeout::oneShotFastMs timeout(timeoutMs);
|
||||
while (((err = trySend(addr, port, /* keep buffer on error */true)) != ERR_OK) && !timeout)
|
||||
delay(0);
|
||||
esp_yield();
|
||||
if (err != ERR_OK)
|
||||
cancelBuffer(); // get rid of buffer kept on error after timeout
|
||||
return err == ERR_OK;
|
||||
|
Reference in New Issue
Block a user