Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

delay / esp_delay: transparently manage recurrent scheduled functions#8802

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
d-a-v merged 10 commits intoesp8266:masterfromd-a-v:autosplitdelay
Jan 14, 2023
Merged
Show file tree
Hide file tree
Changes fromall commits
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
35 changes: 35 additions & 0 deletionscores/esp8266/Schedule.cpp
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,7 @@
*/

#include<assert.h>
#include<numeric>

#include"Schedule.h"
#include"PolledTimeout.h"
Expand All@@ -34,6 +35,7 @@ static scheduled_fn_t* sFirst = nullptr;
staticscheduled_fn_t*sLast =nullptr;
staticscheduled_fn_t*sUnused =nullptr;
staticintsCount =0;
staticuint32_t recurrent_max_grain_mS =0;

typedef std::function<bool(void)>mRecFuncT;
structrecurrent_fn_t
Expand DownExpand Up@@ -130,9 +132,39 @@ bool schedule_recurrent_function_us(const std::function<bool(void)>& fn,
}
rLast = item;

// grain needs to be recomputed
recurrent_max_grain_mS =0;

returntrue;
}

uint32_tcompute_scheduled_recurrent_grain ()
{
if (recurrent_max_grain_mS ==0)
{
if (rFirst)
{
uint32_t recurrent_max_grain_uS = rFirst->callNow.getTimeout();
for (auto it = rFirst->mNext; it; it = it->mNext)
recurrent_max_grain_uS =std::gcd(recurrent_max_grain_uS, it->callNow.getTimeout());
if (recurrent_max_grain_uS)
// round to the upper millis
recurrent_max_grain_mS = recurrent_max_grain_uS <=1000?1: (recurrent_max_grain_uS +999) /1000;
}

#ifdef DEBUG_ESP_CORE
staticuint32_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
}

return recurrent_max_grain_mS;
}

voidrun_scheduled_functions()
{
// prevent scheduling of new functions during this run
Expand DownExpand Up@@ -226,6 +258,9 @@ void run_scheduled_recurrent_functions()
}

delete(to_ditch);

// grain needs to be recomputed
recurrent_max_grain_mS =0;
}
else
{
Expand Down
5 changes: 5 additions & 0 deletionscores/esp8266/Schedule.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,11 @@
// scheduled function happen more often: every yield() (vs every loop()),
// and time resolution is microsecond (vs millisecond). Details are below.

// compute_scheduled_recurrent_grain() is used by delay() to give a chance to
// all recurrent functions to run per their timing requirement.

uint32_tcompute_scheduled_recurrent_grain ();

// scheduled functions called once:
//
// * internal queue is FIFO.
Expand Down
17 changes: 14 additions & 3 deletionscores/esp8266/core_esp8266_main.cpp
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,9 @@

//This may be used to change user task stack size:
//#define CONT_STACKSIZE 4096

#include <numeric>

#include <Arduino.h>
#include "Schedule.h"
extern "C" {
Expand DownExpand Up@@ -165,10 +168,18 @@ extern "C" void esp_delay(unsigned long ms) __attribute__((weak, alias("__esp_de
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
}
esp_delay(std::min((timeout_ms - expired), intvl_ms));
return false;

// compute greatest chunked delay with respect to scheduled recurrent functions
uint32_t grain_ms = std::gcd(intvl_ms, compute_scheduled_recurrent_grain());

// recurrent scheduled functions will be called from esp_delay()->esp_suspend()
esp_delay(grain_ms > 0 ?
std::min((timeout_ms - expired), grain_ms):
(timeout_ms - expired));

return false; // expiration must be checked again
}

extern "C" void __yield() {
Expand Down
4 changes: 3 additions & 1 deletioncores/esp8266/core_esp8266_wiring.cpp
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,7 +34,9 @@ static uint32_t micros_overflow_count = 0;
#defineREPEAT1

void__delay(unsignedlong ms) {
esp_delay(ms);
// Use API letting recurrent scheduled functions run in background
// but stay blocked in delay until ms is expired.
esp_delay(ms, [](){returntrue; });
}

voiddelay(unsignedlong ms) __attribute__ ((weak, alias("__delay")));
Expand Down
14 changes: 6 additions & 8 deletionscores/esp8266/coredecls.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@

#ifndef __COREDECLS_H
#define__COREDECLS_H
#pragma once

#include"core_esp8266_features.h"

Expand DownExpand Up@@ -55,14 +54,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 functions timing grain.
// The delay may be asynchronously cancelled, before that timeout is reached.
boolesp_try_delay(constuint32_t start_ms,constuint32_t timeout_ms,constuint32_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 asat mostevery intvl_ms millisconds and depending on
//recurrent scheduled functions, it performsthe blocked callback, and if that returns true,
//it keeps delaying for the remainderof the original timeout_ms period.
template<typename T>
inlinevoidesp_delay(constuint32_t timeout_ms, T&& blocked,constuint32_t intvl_ms) {
constauto start_ms =millis();
Expand All@@ -79,5 +79,3 @@ inline void esp_delay(const uint32_t timeout_ms, T&& blocked) {
}

#endif// __cplusplus

#endif// __COREDECLS_H
12 changes: 4 additions & 8 deletionslibraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -451,9 +451,8 @@ bool ESP8266WiFiGenericClass::mode(WiFiMode_t m) {
//tasks to wait correctly.
constexprunsignedint 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]() {returnwifi_get_opmode() != m; },5);
// check opmode every 100ms or give up after timeout
esp_delay(timeoutValue, [m]() {returnwifi_get_opmode() != m; },100);

//if at this point mode still hasn't been reached, give up
if(wifi_get_opmode() != (uint8) m) {
Expand DownExpand Up@@ -642,11 +641,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;
},10);
// sleep until dns_found_callback is called or timeout is reached
esp_delay(timeout_ms, [&]() {return !pending->done; });

if (pending->done) {
if ((pending->addr).isSet()) {
Expand Down
11 changes: 5 additions & 6 deletionslibraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -84,13 +84,13 @@ static void printWiFiStatus(wl_status_t status)
staticwl_status_twaitWiFiConnect(uint32_t connectTimeoutMs)
{
wl_status_t status = WL_CONNECT_FAILED;
//The final argument, intvl_ms,toesp_delay influences how frequently
//the scheduled recurrent functions (Schedule.h) are probed.
//Wait for WiFitoconnect
//stop waiting upon status checked every 100ms or when timeout is reached
esp_delay(connectTimeoutMs,
[&status]() {
status = WiFi.status();
return status != WL_CONNECTED && status != WL_CONNECT_FAILED;
},0);
},100);

// Check status
if (status == WL_CONNECTED) {
Expand DownExpand Up@@ -236,13 +236,12 @@ int8_t ESP8266WiFiMulti::startScan()
WiFi.scanNetworks(true);

// Wait for WiFi scan change or timeout
// The final argument, intvl_ms, to esp_delay influences how frequently
// the scheduled recurrent functions (Schedule.h) are probed.
// stop waiting upon status checked every 100ms or when timeout is reached
esp_delay(WIFI_SCAN_TIMEOUT_MS,
[&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 deletionslibraries/ESP8266WiFi/src/include/ClientContext.h
View file
Open in desktop
Original file line numberDiff line numberDiff 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]() {returnthis->_connect_pending; },1);
esp_delay(_timeout_ms, [this]() {returnthis->_connect_pending; });
_connect_pending =false;
if (!_pcb) {
DEBUGV(":cabrt\r\n");
Expand DownExpand 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]() {returnthis->_send_waiting; },1);
esp_delay(_timeout_ms, [this]() {returnthis->_send_waiting; });
_send_waiting =false;
}while(true);

Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp