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

delay / esp_delay: transparently manage recurrent scheduled functions #8802

Merged
merged 10 commits into from
Jan 14, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Prev Previous commit
Next Next commit
simplify api
  • Loading branch information
d-a-v committed Jan 14, 2023
commit 0c8f70554db985b5ff12297f7e6bc31b3fb8331e
19 changes: 8 additions & 11 deletions cores/esp8266/Schedule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,19 +151,16 @@ void update_recurrent_grain ()
// round to the upper millis
recurrent_max_grain_mS = recurrent_max_grain_uS <= 1000? 1: (recurrent_max_grain_uS + 999) / 1000;
}
if (recurrent_max_grain_mS == 0)
// no recurrent function, set grain to max
recurrent_max_grain_mS = std::numeric_limits<decltype(recurrent_max_grain_mS)>::max();
}

#if 1
static uint32_t last_grain = 0;
if (recurrent_max_grain_mS != last_grain)
{
::printf("grain4rsf: %u -> %u\n", last_grain, recurrent_max_grain_mS);
last_grain = recurrent_max_grain_mS;
}
#ifdef DEBUG_ESP_CORE
static uint32_t last_grain = 0;
if (recurrent_max_grain_mS != last_grain)
{
::printf(":rsf %u->%u\n", last_grain, recurrent_max_grain_mS);
last_grain = recurrent_max_grain_mS;
}
#endif
}
}

void run_scheduled_functions()
Expand Down
24 changes: 11 additions & 13 deletions cores/esp8266/core_esp8266_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,24 +162,22 @@ extern "C" void __esp_delay(unsigned long ms) {

extern "C" void esp_delay(unsigned long ms) __attribute__((weak, alias("__esp_delay")));

bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, uint32_t intvl_ms) {
bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms) {
uint32_t expired = millis() - start_ms;
if (expired >= timeout_ms) {
return true;
return true; // expired
}

if (intvl_ms == 0)
{
// run_recurrent_scheduled_functions() is called from esp_delay()->esp_suspend()
// intvl_ms is set according to recurrent schedule functions
// intervals based on their respective requirements
if (recurrent_max_grain_mS == 0)
update_recurrent_grain();
intvl_ms = recurrent_max_grain_mS;
}
// possibly recompute recurrent scheduled function common timing grain
update_recurrent_grain();

// update intvl_ms according to this grain
uint32_t ms = compute_gcd(intvl_ms, recurrent_max_grain_mS);

// recurrent scheduled functions will be called from esp_delay()->esp_suspend()
esp_delay(ms? std::min((timeout_ms - expired), ms): (timeout_ms - expired));
d-a-v marked this conversation as resolved.
Show resolved Hide resolved

esp_delay(std::min((timeout_ms - expired), intvl_ms));
return false;
return false; // expiration must be checked again
}

extern "C" void __yield() {
Expand Down
1 change: 1 addition & 0 deletions cores/esp8266/core_esp8266_wiring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static uint32_t micros_overflow_count = 0;

void __delay(unsigned long ms) {
// use API letting recurrent scheduled functions run in background
// but stay blocked in delay until ms is expired
esp_delay(ms, [](){ return true; });
}

Expand Down
16 changes: 9 additions & 7 deletions cores/esp8266/coredecls.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ inline void esp_suspend(T&& blocked) {
// Try to delay until timeout_ms has expired since start_ms.
// Returns true if timeout_ms has completely expired on entry.
// Otherwise returns false after delaying for the relative
// remainder of timeout_ms, or an absolute intvl_ms, whichever is shorter.
// remainder of timeout_ms, or an absolute intvl_ms, whichever is shorter
// and possibly amended by recurrent scheduled fuctions timing grain.
// The delay may be asynchronously cancelled, before that timeout is reached.
// intvl_ms==0 will adapt to recurrent scheduled functions and run them accordingly
bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, uint32_t intvl_ms);
bool esp_try_delay(const uint32_t start_ms, const uint32_t timeout_ms, const uint32_t intvl_ms);

// This overload of esp_delay() delays for a duration of at most timeout_ms milliseconds.
// Whenever it is resumed, as well as every intvl_ms millisconds, it performs
// the blocked callback, and if that returns true, it keeps delaying for the remainder
// of the original timeout_ms period.
// Whenever it is resumed, as well as at most every intvl_ms millisconds and depending on
// recurrent scheduled functions, it performs the blocked callback, and if that returns true,
// it keeps delaying for the remainder of the original timeout_ms period.
template <typename T>
inline void esp_delay(const uint32_t timeout_ms, T&& blocked, const uint32_t intvl_ms) {
const auto start_ms = millis();
Expand All @@ -73,9 +73,11 @@ inline void esp_delay(const uint32_t timeout_ms, T&& blocked, const uint32_t int
// it keeps delaying for the remainder of the original timeout_ms period.
template <typename T>
inline void esp_delay(const uint32_t timeout_ms, T&& blocked) {
esp_delay(timeout_ms, std::forward<T>(blocked), 0);
esp_delay(timeout_ms, std::forward<T>(blocked), timeout_ms);
}

// Greatest Common Divisor Euclidian algorithm
// one entry may be 0, the other is returned
template <typename T>
auto compute_gcd (T a, T b)
{
Expand Down
13 changes: 5 additions & 8 deletions libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -451,9 +451,9 @@ bool ESP8266WiFiGenericClass::mode(WiFiMode_t m) {
//tasks to wait correctly.
constexpr unsigned int timeoutValue = 1000; //1 second
if(can_yield()) {
// 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);
// The final argument, intvl_ms, to esp_delay determines at least
// how frequently wifi_get_opmode() is checked
d-a-v marked this conversation as resolved.
Show resolved Hide resolved
esp_delay(timeoutValue, [m]() { return wifi_get_opmode() != m; }, 100);

//if at this point mode still hasn't been reached, give up
if(wifi_get_opmode() != (uint8) m) {
Expand Down Expand Up @@ -642,11 +642,8 @@ static int hostByNameImpl(const char* aHostname, IPAddress& aResult, uint32_t ti
// We need to wait for c/b to fire *or* we exit on our own timeout
// (which also requires us to notify the c/b that it is supposed to delete the pending obj)
case ERR_INPROGRESS:
// Re-check every 10ms, we expect this to happen fast
esp_delay(timeout_ms,
[&]() {
return !pending->done;
});
// esp_delay will be interrupted by found callback
mcspr marked this conversation as resolved.
Show resolved Hide resolved
esp_delay(timeout_ms, [&]() { return !pending->done; });

if (pending->done) {
if ((pending->addr).isSet()) {
Expand Down
4 changes: 2 additions & 2 deletions libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ static wl_status_t waitWiFiConnect(uint32_t connectTimeoutMs)
[&status]() {
status = WiFi.status();
return status != WL_CONNECTED && status != WL_CONNECT_FAILED;
}, 0);
}, 100);

// Check status
if (status == WL_CONNECTED) {
Expand Down Expand Up @@ -242,7 +242,7 @@ int8_t ESP8266WiFiMulti::startScan()
[&scanResult]() {
scanResult = WiFi.scanComplete();
return scanResult < 0;
}, 0);
}, 100);
// Check for scan timeout which may occur when scan does not report completion
if (scanResult < 0) {
DEBUG_WIFI_MULTI("[WIFIM] Scan timeout\n");
Expand Down
6 changes: 2 additions & 4 deletions libraries/ESP8266WiFi/src/include/ClientContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,7 @@ class ClientContext
_connect_pending = true;
_op_start_time = millis();
// 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);
esp_delay(_timeout_ms, [this]() { return this->_connect_pending; });
_connect_pending = false;
if (!_pcb) {
DEBUGV(":cabrt\r\n");
Expand Down Expand Up @@ -485,8 +484,7 @@ class ClientContext

_send_waiting = true;
// 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);
esp_delay(_timeout_ms, [this]() { return this->_send_waiting; });
_send_waiting = false;
} while(true);

Expand Down