cc-mek-scada/scada-common/util.lua

285 lines
6.6 KiB
Lua
Raw Normal View History

2022-05-10 21:06:27 +00:00
--
-- Utility Functions
--
---@class util
local util = {}
2022-05-31 19:55:40 +00:00
-- OPERATORS --
-- trinary operator
---@param cond boolean condition
---@param a any return if true
---@param b any return if false
---@return any value
2022-05-31 20:09:06 +00:00
function util.trinary(cond, a, b)
2022-05-31 19:55:40 +00:00
if cond then return a else return b end
end
-- PRINT --
2022-04-05 21:28:19 +00:00
-- print
---@param message any
2022-05-31 20:09:06 +00:00
function util.print(message)
term.write(tostring(message))
2022-04-05 21:28:19 +00:00
end
-- print line
---@param message any
2022-05-31 20:09:06 +00:00
function util.println(message)
print(tostring(message))
2022-04-05 21:28:19 +00:00
end
2022-01-13 15:11:42 +00:00
-- timestamped print
---@param message any
2022-05-31 20:09:06 +00:00
function util.print_ts(message)
term.write(os.date("[%H:%M:%S] ") .. tostring(message))
2022-01-13 15:11:42 +00:00
end
2022-04-05 21:28:19 +00:00
-- timestamped print line
---@param message any
2022-05-31 20:09:06 +00:00
function util.println_ts(message)
print(os.date("[%H:%M:%S] ") .. tostring(message))
end
-- STRING TOOLS --
-- get a value as a string
---@param val any
---@return string
2022-05-31 20:09:06 +00:00
function util.strval(val)
local t = type(val)
if t == "table" or t == "function" then
return "[" .. tostring(val) .. "]"
else
return tostring(val)
end
end
-- concatenation with built-in to string
---@vararg any
---@return string
2022-05-31 20:09:06 +00:00
function util.concat(...)
local str = ""
for _, v in ipairs(arg) do
str = str .. util.strval(v)
end
return str
end
2022-05-31 19:55:40 +00:00
-- alias
util.c = util.concat
-- sprintf implementation
---@param format string
---@vararg any
2022-05-31 20:09:06 +00:00
function util.sprintf(format, ...)
return string.format(format, table.unpack(arg))
2022-04-05 21:28:19 +00:00
end
2022-05-31 19:55:40 +00:00
-- MATH --
-- round a number to an integer
---@return integer rounded
2022-05-31 20:09:06 +00:00
function util.round(x)
2022-05-31 19:55:40 +00:00
return math.floor(x + 0.5)
end
-- TIME --
2022-05-10 21:06:27 +00:00
-- current time
---@return integer milliseconds
2022-05-31 20:09:06 +00:00
function util.time_ms()
---@diagnostic disable-next-line: undefined-field
return os.epoch('local')
end
2022-05-10 21:06:27 +00:00
-- current time
---@return number seconds
2022-05-31 20:09:06 +00:00
function util.time_s()
---@diagnostic disable-next-line: undefined-field
return os.epoch('local') / 1000.0
end
2022-05-10 21:06:27 +00:00
-- current time
---@return integer milliseconds
2022-05-31 20:09:06 +00:00
function util.time()
return util.time_ms()
end
-- PARALLELIZATION --
-- protected sleep call so we still are in charge of catching termination
2022-05-10 21:06:27 +00:00
---@param t integer seconds
--- EVENT_CONSUMER: this function consumes events
2022-05-31 20:09:06 +00:00
function util.psleep(t)
---@diagnostic disable-next-line: undefined-field
pcall(os.sleep, t)
end
2022-05-10 21:06:27 +00:00
-- no-op to provide a brief pause (1 tick) to yield
---
--- EVENT_CONSUMER: this function consumes events
2022-05-31 20:09:06 +00:00
function util.nop()
util.psleep(0.05)
end
-- attempt to maintain a minimum loop timing (duration of execution)
2022-05-10 21:06:27 +00:00
---@param target_timing integer minimum amount of milliseconds to wait for
---@param last_update integer millisecond time of last update
---@return integer time_now
2022-05-10 15:35:52 +00:00
-- EVENT_CONSUMER: this function consumes events
2022-05-31 20:09:06 +00:00
function util.adaptive_delay(target_timing, last_update)
local sleep_for = target_timing - (util.time() - last_update)
-- only if >50ms since worker loops already yield 0.05s
if sleep_for >= 50 then
util.psleep(sleep_for / 1000.0)
end
return util.time()
end
2022-05-16 21:11:46 +00:00
-- TABLE UTILITIES --
-- delete elements from a table if the passed function returns false when passed a table element
--
-- put briefly: deletes elements that return false, keeps elements that return true
---@param t table table to remove elements from
---@param f function should return false to delete an element when passed the element: f(elem) = true|false
---@param on_delete? function optional function to execute on deletion, passed the table element to be deleted as the parameter
2022-05-31 20:09:06 +00:00
function util.filter_table(t, f, on_delete)
2022-05-16 21:11:46 +00:00
local move_to = 1
for i = 1, #t do
local element = t[i]
if element ~= nil then
if f(element) then
if t[move_to] == nil then
t[move_to] = element
t[i] = nil
end
move_to = move_to + 1
else
if on_delete then on_delete(element) end
t[i] = nil
end
end
end
end
2022-05-18 18:30:48 +00:00
-- check if a table contains the provided element
---@param t table table to check
---@param element any element to check for
2022-05-31 20:09:06 +00:00
function util.table_contains(t, element)
2022-05-18 18:30:48 +00:00
for i = 1, #t do
if t[i] == element then return true end
end
return false
end
2022-05-10 21:06:27 +00:00
-- MEKANISM POWER --
-- function util.kFE(fe) return fe / 1000.0 end
-- function util.MFE(fe) return fe / 1000000.0 end
-- function util.GFE(fe) return fe / 1000000000.0 end
-- function util.TFE(fe) return fe / 1000000000000.0 end
2022-05-10 21:06:27 +00:00
-- -- FLOATING POINT PRINTS --
-- local function fractional_1s(number)
-- return number == math.round(number)
-- end
-- local function fractional_10ths(number)
-- number = number * 10
-- return number == math.round(number)
-- end
-- local function fractional_100ths(number)
-- number = number * 100
-- return number == math.round(number)
-- end
-- function util.power_format(fe)
2022-05-10 21:06:27 +00:00
-- if fe < 1000 then
-- return string.format("%.2f FE", fe)
-- elseif fe < 1000000 then
-- return string.format("%.3f kFE", kFE(fe))
-- end
-- end
-- WATCHDOG --
2022-04-05 21:28:19 +00:00
2022-01-13 15:11:42 +00:00
-- ComputerCraft OS Timer based Watchdog
2022-05-10 17:06:13 +00:00
---@param timeout number timeout duration
---
--- triggers a timer event if not fed within 'timeout' seconds
2022-05-31 20:09:06 +00:00
function util.new_watchdog(timeout)
2022-05-10 17:06:13 +00:00
---@diagnostic disable-next-line: undefined-field
local start_timer = os.startTimer
2022-05-10 17:06:13 +00:00
---@diagnostic disable-next-line: undefined-field
local cancel_timer = os.cancelTimer
2022-05-10 15:35:52 +00:00
local self = {
2022-05-10 17:06:13 +00:00
timeout = timeout,
wd_timer = start_timer(timeout)
2022-01-13 15:11:42 +00:00
}
2022-05-10 17:06:13 +00:00
---@class watchdog
local public = {}
---@param timer number timer event timer ID
2022-05-31 20:09:06 +00:00
function public.is_timer(timer)
2022-05-10 17:06:13 +00:00
return self.wd_timer == timer
2022-01-13 15:11:42 +00:00
end
2022-05-10 15:35:52 +00:00
2022-05-10 17:06:13 +00:00
-- satiate the beast
2022-05-31 20:09:06 +00:00
function public.feed()
2022-05-10 17:06:13 +00:00
if self.wd_timer ~= nil then
cancel_timer(self.wd_timer)
2022-01-13 15:11:42 +00:00
end
2022-05-10 17:06:13 +00:00
self.wd_timer = start_timer(self.timeout)
2022-01-13 15:11:42 +00:00
end
2022-05-10 17:06:13 +00:00
-- cancel the watchdog
2022-05-31 20:09:06 +00:00
function public.cancel()
2022-05-10 17:06:13 +00:00
if self.wd_timer ~= nil then
cancel_timer(self.wd_timer)
2022-05-02 15:44:10 +00:00
end
end
2022-05-10 17:06:13 +00:00
return public
end
-- LOOP CLOCK --
-- ComputerCraft OS Timer based Loop Clock
---@param period number clock period
---
--- fires a timer event at the specified period, does not start at construct time
2022-05-31 20:09:06 +00:00
function util.new_clock(period)
2022-05-10 17:06:13 +00:00
---@diagnostic disable-next-line: undefined-field
local start_timer = os.startTimer
local self = {
period = period,
timer = nil
2022-01-13 15:11:42 +00:00
}
2022-05-10 17:06:13 +00:00
---@class clock
local public = {}
---@param timer number timer event timer ID
2022-05-31 20:09:06 +00:00
function public.is_clock(timer)
2022-05-10 17:06:13 +00:00
return self.timer == timer
end
-- start the clock
2022-05-31 20:09:06 +00:00
function public.start()
2022-05-10 17:06:13 +00:00
self.timer = start_timer(self.period)
end
return public
2022-01-13 15:11:42 +00:00
end
return util