2022-06-08 18:47:45 +00:00
|
|
|
--
|
|
|
|
-- Timer Callback Dispatcher
|
|
|
|
--
|
|
|
|
|
2022-10-21 19:15:56 +00:00
|
|
|
local log = require("scada-common.log")
|
|
|
|
local util = require("scada-common.util")
|
|
|
|
|
2022-06-08 18:47:45 +00:00
|
|
|
local tcallbackdsp = {}
|
|
|
|
|
|
|
|
local registry = {}
|
|
|
|
|
|
|
|
-- request a function to be called after the specified time
|
|
|
|
---@param time number seconds
|
|
|
|
---@param f function callback function
|
|
|
|
function tcallbackdsp.dispatch(time, f)
|
2022-10-23 05:41:02 +00:00
|
|
|
local timer = util.start_timer(time)
|
|
|
|
registry[timer] = {
|
|
|
|
callback = f,
|
|
|
|
duration = time,
|
|
|
|
expiry = time + util.time_s()
|
|
|
|
}
|
2022-06-08 18:47:45 +00:00
|
|
|
end
|
|
|
|
|
2022-10-21 19:15:56 +00:00
|
|
|
-- request a function to be called after the specified time, aborting any registered instances of that function reference
|
|
|
|
---@param time number seconds
|
|
|
|
---@param f function callback function
|
|
|
|
function tcallbackdsp.dispatch_unique(time, f)
|
2022-11-06 23:41:52 +00:00
|
|
|
-- cancel if already registered
|
2022-10-21 19:15:56 +00:00
|
|
|
for timer, entry in pairs(registry) do
|
|
|
|
if entry.callback == f then
|
|
|
|
-- found an instance of this function reference, abort it
|
2022-10-23 16:21:17 +00:00
|
|
|
log.debug(util.c("TCD: aborting duplicate timer callback [timer: ", timer, ", ", f, "]"))
|
2022-10-21 19:15:56 +00:00
|
|
|
|
|
|
|
-- cancel event and remove from registry (even if it fires it won't call)
|
2022-10-23 05:41:02 +00:00
|
|
|
util.cancel_timer(timer)
|
2022-10-21 19:15:56 +00:00
|
|
|
registry[timer] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-10-23 05:41:02 +00:00
|
|
|
local timer = util.start_timer(time)
|
|
|
|
registry[timer] = {
|
|
|
|
callback = f,
|
|
|
|
duration = time,
|
|
|
|
expiry = time + util.time_s()
|
|
|
|
}
|
2022-10-21 19:15:56 +00:00
|
|
|
end
|
|
|
|
|
2022-11-06 23:41:52 +00:00
|
|
|
-- abort a requested callback
|
|
|
|
---@param f function callback function
|
|
|
|
function tcallbackdsp.abort(f)
|
|
|
|
for timer, entry in pairs(registry) do
|
|
|
|
if entry.callback == f then
|
|
|
|
-- cancel event and remove from registry (even if it fires it won't call)
|
|
|
|
util.cancel_timer(timer)
|
|
|
|
registry[timer] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-06-08 18:47:45 +00:00
|
|
|
-- lookup a timer event and execute the callback if found
|
|
|
|
---@param event integer timer event timer ID
|
|
|
|
function tcallbackdsp.handle(event)
|
|
|
|
if registry[event] ~= nil then
|
2022-10-23 05:41:02 +00:00
|
|
|
local callback = registry[event].callback
|
|
|
|
-- clear first so that dispatch_unique call from inside callback won't throw a debug message
|
2022-06-08 18:47:45 +00:00
|
|
|
registry[event] = nil
|
2022-10-23 05:41:02 +00:00
|
|
|
callback()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-02-21 15:31:05 +00:00
|
|
|
-- identify any overdo callbacks<br>
|
2022-10-23 05:41:02 +00:00
|
|
|
-- prints to log debug output
|
|
|
|
function tcallbackdsp.diagnostics()
|
|
|
|
for timer, entry in pairs(registry) do
|
2022-10-23 16:21:17 +00:00
|
|
|
if entry.expiry < util.time_s() then
|
2022-10-23 05:41:02 +00:00
|
|
|
local overtime = util.time_s() - entry.expiry
|
|
|
|
log.debug(util.c("TCD: unserviced timer ", timer, " for callback ", entry.callback, " is at least ", overtime, "s late"))
|
2022-10-23 16:21:17 +00:00
|
|
|
else
|
|
|
|
local time = entry.expiry - util.time_s()
|
|
|
|
log.debug(util.c("TCD: pending timer ", timer, " for callback ", entry.callback, " (call after ", entry.duration, "s, expires ", time, ")"))
|
2022-10-23 05:41:02 +00:00
|
|
|
end
|
2022-06-08 18:47:45 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return tcallbackdsp
|