Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shimmable suspend-CONT API for async esp_yield() / esp_schedule() "stop the Arduino world" metaphor #6782

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
896344d
Fix async esp_yield() / esp_schedule() "stop the Arduino world" metaphor
dok-net Nov 15, 2019
dbdc041
Cleanup obsoleted externals.
dok-net Nov 15, 2019
1bd1f25
WIP: Revert removal of esp_schedule, prepares for reintroducing preem…
dok-net Nov 16, 2019
a66ec75
WIP: implement infinite suspension of CONT to SYS (pending esp_schedu…
dok-net Nov 16, 2019
8e41ff3
Re-implement preemptible (esp_schedule) delay of CONT by esp_delay i…
dok-net Nov 16, 2019
c2edd9d
Add host mockup for esp_delay
dok-net Nov 16, 2019
62a39a3
Facilitating reuse of the pattern, implement CONT suspend and delay a…
dok-net Nov 18, 2019
49563a1
Memory footprint optimization by inlining
dok-net Nov 18, 2019
85dbad6
Fixing host mockups for esp_delay, esp_yield
dok-net Nov 18, 2019
d12245e
Suppress unused argument warning.
dok-net Nov 18, 2019
2f2b0bd
Identified another candidate for esp_delay refactoring.
dok-net Nov 18, 2019
b4d1a07
Replace std::function by Delegate in esp_yield/esp_delay callback fun…
dok-net Dec 30, 2020
b54f63e
Delegate now uses function declaration syntax in template type specif…
dok-net Nov 29, 2019
8da7ec3
Use terse function notation - match std::function, the optional 1st a…
dok-net Nov 29, 2019
358f942
Fix for host target
dok-net Dec 2, 2019
ea5648b
Avoid Delegate anti-pattern (std::function with capture where C-style…
dok-net Mar 5, 2020
5011f88
Rename new esp_yield(...) with blocking predicate argument to more de…
dok-net Mar 10, 2020
df1460f
revert to std::function from Delegate to make easier to accept PR
dok-net Jan 9, 2021
7417970
Refactor ESP8266WiFiMulti to use esp_delay. Optimisation opportunity:…
dok-net Jan 23, 2021
6ac4ea4
Adapt logic to feed scheduled recurrent functions in hostByName from …
dok-net Jul 20, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions cores/esp8266/core_esp8266_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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<bool()>;

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();
Expand Down Expand Up @@ -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[];
Expand Down Expand Up @@ -253,7 +289,6 @@ static void __unhandled_exception_cpp()
}
#endif
}

}

void init_done() {
Expand Down
21 changes: 2 additions & 19 deletions cores/esp8266/core_esp8266_wiring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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")));
Expand Down
20 changes: 20 additions & 0 deletions cores/esp8266/coredecls.h
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -32,9 +33,28 @@ uint32_t crc32 (const void* data, size_t length, uint32_t crc = 0xffffffff);
using BoolCB = std::function<void(bool)>;
using TrivialCB = std::function<void()>;

void settimeofday_cb (BoolCB&& cb);
void settimeofday_cb (const BoolCB& cb);
void settimeofday_cb (const TrivialCB& cb);

using IsBlockedCB = std::function<bool()>;

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
5 changes: 5 additions & 0 deletions cores/esp8266/time.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
24 changes: 11 additions & 13 deletions libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 -----------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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()) {
Expand Down Expand Up @@ -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)
Expand Down
70 changes: 26 additions & 44 deletions libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "ESP8266WiFiMulti.h"
#include <limits.h>
#include <string.h>
#include <coredecls.h>

/**
* @brief Print WiFi status
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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();
Expand Down
8 changes: 6 additions & 2 deletions libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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();
}
3 changes: 0 additions & 3 deletions libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ extern "C" {

#include "debug.h"

extern "C" void esp_schedule();
extern "C" void esp_yield();

// -----------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------- Private functions ------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
Expand Down
10 changes: 5 additions & 5 deletions libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ extern "C" {
}

#include "debug.h"

extern "C" void esp_schedule();
extern "C" void esp_yield();
#include <coredecls.h>

// -----------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------- Private functions ------------------------------------------------
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
Loading