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
Next Next commit
wip
  • Loading branch information
d-a-v committed Jan 10, 2023
commit bde2c4c5d33d68059cf7d7818a3907a07024b63e
27 changes: 27 additions & 0 deletions cores/esp8266/Schedule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ static scheduled_fn_t* sLast = nullptr;
static scheduled_fn_t* sUnused = nullptr;
static int sCount = 0;

uint32_t recurrent_max_grain_mS = 0;
d-a-v marked this conversation as resolved.
Show resolved Hide resolved

typedef std::function<bool(void)> mRecFuncT;
struct recurrent_fn_t
{
Expand Down Expand Up @@ -130,9 +132,31 @@ bool schedule_recurrent_function_us(const std::function<bool(void)>& fn,
}
rLast = item;

// grain needs to be recomputed
recurrent_max_grain_mS = 0;

return true;
}

void update_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 = compute_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;
}
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();
}
}

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

delete(to_ditch);

// grain needs to be recomputed
recurrent_max_grain_mS = 0;
}
else
{
Expand Down
7 changes: 7 additions & 0 deletions cores/esp8266/Schedule.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@
// scheduled function happen more often: every yield() (vs every loop()),
// and time resolution is microsecond (vs millisecond). Details are below.

// recurrent_max_grain_mS is used by delay() to let a chance to all
// recurrent functions to accomplish their duty per their timing
// requirement.
// When it is 0, update_recurrent_grain() can be called to recalculate it
extern uint32_t recurrent_max_grain_mS;
void update_recurrent_grain ();
d-a-v marked this conversation as resolved.
Show resolved Hide resolved

// scheduled functions called once:
//
// * internal queue is FIFO.
Expand Down
12 changes: 11 additions & 1 deletion cores/esp8266/core_esp8266_wiring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,17 @@ static uint32_t micros_overflow_count = 0;
#define REPEAT 1

void __delay(unsigned long ms) {
esp_delay(ms);

// default "userland" delay() will call recurrent scheduled functions
// based on best effort according to their respective requirements

if (recurrent_max_grain_mS == 0)
update_recurrent_grain();
const auto start_ms = millis();
do
{
run_scheduled_recurrent_functions();
} while (!esp_try_delay(start_ms, ms, recurrent_max_grain_mS));
}

void delay(unsigned long ms) __attribute__ ((weak, alias("__delay")));
Expand Down
17 changes: 13 additions & 4 deletions cores/esp8266/coredecls.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

#ifndef __COREDECLS_H
#define __COREDECLS_H
#pragma once

#include "core_esp8266_features.h"

Expand Down Expand Up @@ -76,6 +75,16 @@ inline void esp_delay(const uint32_t timeout_ms, T&& blocked) {
esp_delay(timeout_ms, std::forward<T>(blocked), timeout_ms);
}

#endif // __cplusplus
template <typename T>
auto compute_gcd (T a, T b)
{
while (b)
{
auto t = b;
b = a % b;
a = t;
}
return a;
}

#endif // __COREDECLS_H
#endif // __cplusplus