mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-22 18:26:30 +00:00
Berry 'tasmota.defer()' (#22976)
This commit is contained in:
parent
5a6b219971
commit
ff5b4956c8
@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
|
||||
### Added
|
||||
- Formatter `%_U` for `ext_snprintf_P()` to print uint64_t variable as decimal equivalent to `%llu`
|
||||
- Support for RC-switch decoding of 64-bit received data
|
||||
- Berry `tasmota.defer()`
|
||||
|
||||
### Breaking Changed
|
||||
|
||||
|
@ -86,6 +86,7 @@ class be_class_tasmota (scope: global, name: Tasmota) {
|
||||
_fl, var // list of active fast-loop object (faster than drivers)
|
||||
_rules, var // list of active rules
|
||||
_timers, var // list of active timers
|
||||
_defer, var // list of deferred functions to be called at next millisecond
|
||||
_crons, var // list of active crons
|
||||
_ccmd, var // list of active Tasmota commands implemented in Berry
|
||||
_drivers, var // list of active drivers
|
||||
@ -173,6 +174,8 @@ class be_class_tasmota (scope: global, name: Tasmota) {
|
||||
exec_rules, closure(class_Tasmota_exec_rules_closure)
|
||||
exec_tele, closure(class_Tasmota_exec_tele_closure)
|
||||
set_timer, closure(class_Tasmota_set_timer_closure)
|
||||
run_timers, closure(class_Tasmota_run_timers_closure)
|
||||
defer, closure(class_Tasmota_defer_closure)
|
||||
run_deferred, closure(class_Tasmota_run_deferred_closure)
|
||||
remove_timer, closure(class_Tasmota_remove_timer_closure)
|
||||
add_cmd, closure(class_Tasmota_add_cmd_closure)
|
||||
|
@ -9,6 +9,7 @@ class Tasmota
|
||||
var _fl # list of fast_loop registered closures
|
||||
var _rules
|
||||
var _timers # holds both timers and cron
|
||||
var _defer # holds functions to be called at next millisecond
|
||||
var _crons
|
||||
var _ccmd
|
||||
var _drivers
|
||||
@ -273,13 +274,39 @@ class Tasmota
|
||||
def set_timer(delay,f,id)
|
||||
self.check_not_method(f)
|
||||
if self._timers == nil
|
||||
self._timers=[]
|
||||
self._timers = []
|
||||
end
|
||||
self._timers.push(Trigger(self.millis(delay),f,id))
|
||||
end
|
||||
|
||||
# run every 50ms tick
|
||||
# special version to push a function that will be called immediately after
|
||||
def defer(f)
|
||||
if self._defer == nil
|
||||
self._defer = []
|
||||
end
|
||||
self._defer.push(f)
|
||||
tasmota.global.deferred_ready = 1
|
||||
end
|
||||
|
||||
# run any immediate function
|
||||
def run_deferred()
|
||||
if self._defer
|
||||
var sz = size(self._defer) # make sure to run only those present at first, and not those inserted in between
|
||||
while sz > 0
|
||||
var f = self._defer[0]
|
||||
self._defer.remove(0)
|
||||
sz -= 1
|
||||
f()
|
||||
end
|
||||
if size(self._defer) == 0
|
||||
tasmota.global.deferred_ready = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# run every 50ms tick
|
||||
def run_timers()
|
||||
self.run_deferred() # run immediate functions first
|
||||
if self._timers
|
||||
var i=0
|
||||
while i < self._timers.size()
|
||||
@ -699,7 +726,7 @@ class Tasmota
|
||||
def event(event_type, cmd, idx, payload, raw)
|
||||
import introspect
|
||||
if event_type=='every_50ms'
|
||||
self.run_deferred()
|
||||
self.run_timers()
|
||||
end #- first run deferred events -#
|
||||
|
||||
if event_type=='every_250ms'
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -383,6 +383,7 @@ struct TasmotaGlobal_t {
|
||||
#endif // PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED
|
||||
|
||||
#ifdef USE_BERRY
|
||||
bool berry_deferred_ready = false; // is there an deferred Berry function to be called at next millisecond
|
||||
bool berry_fast_loop_enabled = false; // is Berry fast loop enabled, i.e. control is passed at each loop iteration
|
||||
#endif // USE_BERRY
|
||||
} TasmotaGlobal = { 0 };
|
||||
|
@ -33,10 +33,11 @@ extern "C" {
|
||||
|
||||
extern const be_ctypes_structure_t be_tasmota_global_struct = {
|
||||
sizeof(TasmotaGlobal), /* size in bytes */
|
||||
11, /* number of elements */
|
||||
12, /* number of elements */
|
||||
nullptr,
|
||||
(const be_ctypes_structure_item_t[11]) {
|
||||
(const be_ctypes_structure_item_t[12]) {
|
||||
// Warning: fields below need to be in alphabetical order
|
||||
{ "deferred_ready", offsetof(TasmotaGlobal_t, berry_deferred_ready), 0, 0, ctypes_u8, 0 },
|
||||
{ "devices_present", offsetof(TasmotaGlobal_t, devices_present), 0, 0, ctypes_u8, 0 },
|
||||
{ "energy_driver", offsetof(TasmotaGlobal_t, energy_driver), 0, 0, ctypes_u8, 0 },
|
||||
{ "fast_loop_enabled", offsetof(TasmotaGlobal_t, berry_fast_loop_enabled), 0, 0, ctypes_u8, 0 },
|
||||
|
@ -176,6 +176,26 @@ int32_t callBerryEventDispatcher(const char *type, const char *cmd, int32_t idx,
|
||||
return ret;
|
||||
}
|
||||
|
||||
// simple wrapper to call `tasmota.<method_name>()`
|
||||
static void callBerryTasmotaFunc(const char * method_name) {
|
||||
bvm *vm = berry.vm;
|
||||
if (be_getglobal(vm, "tasmota")) {
|
||||
if (be_getmethod(vm, -1, method_name)) {
|
||||
be_pushvalue(vm, -2); // add instance as first arg
|
||||
BrTimeoutStart();
|
||||
int32_t ret = be_pcall(vm, 1);
|
||||
if (ret != 0) {
|
||||
be_error_pop_all(berry.vm); // clear Berry stack
|
||||
}
|
||||
BrTimeoutReset();
|
||||
be_pop(vm, 1);
|
||||
}
|
||||
be_pop(vm, 1); // remove method
|
||||
}
|
||||
be_pop(vm, 1); // remove instance object
|
||||
be_pop(vm, be_top(vm)); // clean
|
||||
}
|
||||
|
||||
// Simplified version of event loop. Just call `tasmota.fast_loop()`
|
||||
// `every_5ms` is a flag to wait at least 5ms between calss to `tasmota.fast_loop()`
|
||||
void callBerryFastLoop(bool every_5ms) {
|
||||
@ -191,21 +211,13 @@ void callBerryFastLoop(bool every_5ms) {
|
||||
fast_loop_last_call = now;
|
||||
|
||||
// TODO - can we make this dereferencing once for all?
|
||||
if (be_getglobal(vm, "tasmota")) {
|
||||
if (be_getmethod(vm, -1, "fast_loop")) {
|
||||
be_pushvalue(vm, -2); // add instance as first arg
|
||||
BrTimeoutStart();
|
||||
int32_t ret = be_pcall(vm, 1);
|
||||
if (ret != 0) {
|
||||
be_error_pop_all(berry.vm); // clear Berry stack
|
||||
}
|
||||
BrTimeoutReset();
|
||||
be_pop(vm, 1);
|
||||
}
|
||||
be_pop(vm, 1); // remove method
|
||||
}
|
||||
be_pop(vm, 1); // remove instance object
|
||||
be_pop(vm, be_top(vm)); // clean
|
||||
callBerryTasmotaFunc("fast_loop");
|
||||
}
|
||||
|
||||
// call `tasmota.run_immediate()`
|
||||
void callBerryRunDeferred(void) {
|
||||
if (nullptr == berry.vm) { return; }
|
||||
callBerryTasmotaFunc("run_deferred");
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
@ -888,6 +900,9 @@ bool Xdrv52(uint32_t function)
|
||||
|
||||
switch (function) {
|
||||
case FUNC_SLEEP_LOOP:
|
||||
if (TasmotaGlobal.berry_deferred_ready) { // there are immediate functions registered, call them first
|
||||
callBerryRunDeferred(); // call `tasmota.run_immediate()`
|
||||
}
|
||||
if (TasmotaGlobal.berry_fast_loop_enabled) { // call only if enabled at global level
|
||||
callBerryFastLoop(true); // call `tasmota.fast_loop()` optimized for minimal performance impact
|
||||
}
|
||||
@ -914,6 +929,9 @@ bool Xdrv52(uint32_t function)
|
||||
}
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
if (TasmotaGlobal.berry_deferred_ready) { // there are immediate functions registered, call them first
|
||||
callBerryRunDeferred(); // call `tasmota.run_immediate()`
|
||||
}
|
||||
if (TasmotaGlobal.berry_fast_loop_enabled) { // call only if enabled at global level
|
||||
callBerryFastLoop(false); // call `tasmota.fast_loop()` optimized for minimal performance impact
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user