diff --git a/scada-common/audio.lua b/scada-common/audio.lua index 019b510..e1a6958 100644 --- a/scada-common/audio.lua +++ b/scada-common/audio.lua @@ -6,10 +6,10 @@ -- note: max samples = 0x20000 (128 * 1024 samples) -local _2_PI = 2 * math.pi -- 2 whole pies, hope you're hungry -local _DRATE = 48000 -- 48kHz audio -local _MAX_VAL = 127 / 2 -- max signed integer in this 8-bit audio -local _05s_SAMPLES = 24000 -- half a second worth of samples +local _2_PI = 2 * math.pi -- 2 whole pies, hope you're hungry +local _DRATE = 48000 -- 48kHz audio data rate +local _MAX_VAL = 127 / 2 -- max signed integer in this 8-bit audio +local _05s_SAMPLES = 24000 -- half a second worth of samples ---@class audio local audio = {} @@ -28,6 +28,7 @@ local TONE = { audio.TONE = TONE +---@type integer[][][] local tone_data = { { {}, {}, {}, {} }, -- 340Hz @ 2Hz Intermittent { {}, {}, {}, {} }, -- 544Hz 100mS / 440Hz 400mS Alternating @@ -214,7 +215,14 @@ end -- generate all 8 tone sequences function audio.generate_tones() - gen_tone_1(); gen_tone_2(); gen_tone_3(); gen_tone_4(); gen_tone_5(); gen_tone_6(); gen_tone_7(); gen_tone_8() + gen_tone_1() + gen_tone_2() + gen_tone_3() + gen_tone_4() + gen_tone_5() + gen_tone_6() + gen_tone_7() + gen_tone_8() end -- hard audio limiter @@ -226,7 +234,7 @@ local function limit(output) end -- clear output buffer ----@param buffer table quad buffer +---@param buffer integer[][] quad buffer local function clear(buffer) for i = 1, 4 do for s = 1, _05s_SAMPLES do buffer[i][s] = 0 end @@ -239,7 +247,7 @@ function audio.new_stream() any_active = false, need_recompute = false, next_block = 1, - -- split audio up into 0.5s samples, so specific components can be ended quicker + ---@type integer[][] split audio up into 0.5s samples, so specific components can be ended quicker quad_buffer = { {}, {}, {}, {} }, -- all tone enable states tone_active = { false, false, false, false, false, false, false, false } @@ -263,14 +271,17 @@ function audio.new_stream() -- check if a tone is active ---@param index TONE tone index function public.is_active(index) - if self.tone_active[index] then return self.tone_active[index] end - return false + return self.tone_active[index] or false end -- set all tones inactive, reset next block, and clear output buffer function public.stop() - for i = 1, #self.tone_active do self.tone_active[i] = false end + for i = 1, #self.tone_active do + self.tone_active[i] = false + end + self.next_block = 1 + clear(self.quad_buffer) end @@ -287,9 +298,11 @@ function audio.new_stream() for id = 1, #tone_data do if self.tone_active[id] then self.any_active = true + for i = 1, 4 do local buffer = self.quad_buffer[i] local values = tone_data[id][i] + for s = 1, _05s_SAMPLES do self.quad_buffer[i][s] = limit(buffer[s] + values[s]) end end end @@ -305,8 +318,13 @@ function audio.new_stream() -- get the next audio block function public.get_next_block() local block = self.quad_buffer[self.next_block] + self.next_block = self.next_block + 1 - if self.next_block > 4 then self.next_block = 1 end + + if self.next_block > 4 then + self.next_block = 1 + end + return block end diff --git a/scada-common/comms.lua b/scada-common/comms.lua index 6a82228..6f12fb2 100644 --- a/scada-common/comms.lua +++ b/scada-common/comms.lua @@ -405,7 +405,7 @@ function comms.modbus_packet() self.raw = { self.txn_id, self.unit_id, self.func_code } for i = 1, self.length do insert(self.raw, data[i]) end else - log.error("comms.modbus_packet.make(): data not table") + log.error("comms.modbus_packet.make(): data not a table") end end @@ -491,7 +491,7 @@ function comms.rplc_packet() self.raw = { self.id, self.type } for i = 1, #data do insert(self.raw, data[i]) end else - log.error("comms.rplc_packet.make(): data not table") + log.error("comms.rplc_packet.make(): data not a table") end end @@ -573,7 +573,7 @@ function comms.mgmt_packet() self.raw = { self.type } for i = 1, #data do insert(self.raw, data[i]) end else - log.error("comms.mgmt_packet.make(): data not table") + log.error("comms.mgmt_packet.make(): data not a table") end end @@ -652,7 +652,7 @@ function comms.crdn_packet() self.raw = { self.type } for i = 1, #data do insert(self.raw, data[i]) end else - log.error("comms.crdn_packet.make(): data not table") + log.error("comms.crdn_packet.make(): data not a table") end end diff --git a/scada-common/log.lua b/scada-common/log.lua index f876eaa..c416d9c 100644 --- a/scada-common/log.lua +++ b/scada-common/log.lua @@ -7,7 +7,7 @@ local util = require("scada-common.util") ---@class logger local log = {} ----@alias MODE integer +---@enum MODE local MODE = { APPEND = 0, NEW = 1 } log.MODE = MODE @@ -18,7 +18,7 @@ local logger = { mode = MODE.APPEND, debug = false, file = nil, ---@type table|nil - dmesg_out = nil, + dmesg_out = nil, ---@type table|nil dmesg_restore_coord = { 1, 1 }, dmesg_scroll_count = 0 } @@ -37,7 +37,7 @@ local function _log(msg) local out_of_space = false local time_stamp = os.date("[%c] ") - local stamped = time_stamp .. util.strval(msg) + local stamped = util.c(time_stamp, msg) -- attempt to write log local status, result = pcall(function () @@ -291,7 +291,7 @@ function log.dmesg_working(msg, tag, tag_color) end -- log debug messages ----@param msg string message +---@param msg any message ---@param trace? boolean include file trace function log.debug(msg, trace) if logger.debug then @@ -302,30 +302,30 @@ function log.debug(msg, trace) local name = "" if info.name ~= nil then - name = ":" .. info.name .. "():" + name = util.c(":", info.name, "():") end - dbg_info = info.short_src .. ":" .. name .. info.currentline .. " > " + dbg_info = util.c(info.short_src, ":", name, info.currentline, " > ") end - _log("[DBG] " .. dbg_info .. util.strval(msg)) + _log(util.c("[DBG] ", dbg_info, msg)) end end -- log info messages ----@param msg string message +---@param msg any message function log.info(msg) - _log("[INF] " .. util.strval(msg)) + _log(util.c("[INF] ", msg)) end -- log warning messages ----@param msg string message +---@param msg any message function log.warning(msg) - _log("[WRN] " .. util.strval(msg)) + _log(util.c("[WRN] ", msg)) end -- log error messages ----@param msg string message +---@param msg any message ---@param trace? boolean include file trace function log.error(msg, trace) local dbg_info = "" @@ -335,19 +335,19 @@ function log.error(msg, trace) local name = "" if info.name ~= nil then - name = ":" .. info.name .. "():" + name = util.c(":", info.name, "():") end - dbg_info = info.short_src .. ":" .. name .. info.currentline .. " > " + dbg_info = util.c(info.short_src, ":", name, info.currentline, " > ") end - _log("[ERR] " .. dbg_info .. util.strval(msg)) + _log(util.c("[ERR] ", dbg_info, msg)) end -- log fatal errors ----@param msg string message +---@param msg any message function log.fatal(msg) - _log("[FTL] " .. util.strval(msg)) + _log(util.c("[FTL] ", msg)) end return log diff --git a/scada-common/mqueue.lua b/scada-common/mqueue.lua index fc60a1e..db09509 100644 --- a/scada-common/mqueue.lua +++ b/scada-common/mqueue.lua @@ -27,6 +27,7 @@ local remove = table.remove -- create a new message queue ---@nodiscard function mqueue.new() + ---@type queue_item[] local queue = {} ---@class mqueue diff --git a/scada-common/network.lua b/scada-common/network.lua index c34a1d5..0c6e751 100644 --- a/scada-common/network.lua +++ b/scada-common/network.lua @@ -85,18 +85,15 @@ function network.nic(modem) } ---@class nic - ---@field open function - ---@field isOpen function - ---@field close function - ---@field closeAll function - ---@field isWireless function - ---@field getNameLocal function - ---@field getNamesRemote function - ---@field isPresentRemote function - ---@field getTypeRemote function - ---@field hasTypeRemote function - ---@field getMethodsRemote function - ---@field callRemote function + ---@field isOpen fun(channel: integer) : boolean check if a channel is open + ---@field isWireless fun() : boolean determine if this is a wired or wireless modem + ---@field getNamesRemote fun() : string[] list all remote peripherals on the wired network + ---@field isPresentRemote fun(name: string) : boolean determine if a peripheral is available on this wired network + ---@field getTypeRemote fun(name: string) : string|nil get the type of a peripheral is available on this wired network + ---@field hasTypeRemote fun(name: string, type: string) : boolean|nil check a peripheral is of a particular type + ---@field getMethodsRemote fun(name: string) : string[] get all available methods for the remote peripheral with the given name + ---@field callRemote fun(remoteName: string, method: string, ...) : table call a method on a peripheral on this wired network + ---@field getNameLocal fun() : string|nil returns the network name of the current computer, if the modem is on local public = {} -- check if this NIC has a connected modem diff --git a/scada-common/ppm.lua b/scada-common/ppm.lua index e6a95e8..83f1308 100644 --- a/scada-common/ppm.lua +++ b/scada-common/ppm.lua @@ -23,7 +23,7 @@ ppm.VIRTUAL_DEVICE_TYPE = VIRTUAL_DEVICE_TYPE local REPORT_FREQUENCY = 20 -- log every 20 faults per function local ppm_sys = { - mounts = {}, + mounts = {}, ---@type { [string]: ppm_entry } next_vid = 0, auto_cf = false, faulted = false, @@ -40,10 +40,10 @@ local function peri_init(iface) local self = { faulted = false, last_fault = "", - fault_counts = {}, + fault_counts = {}, ---@type { [string]: integer } auto_cf = true, - type = VIRTUAL_DEVICE_TYPE, - device = {} + type = VIRTUAL_DEVICE_TYPE, ---@type string + device = {} ---@type { [string]: function } } if iface ~= "__virtual__" then @@ -181,7 +181,7 @@ local function peri_init(iface) setmetatable(self.device, mt) ---@class ppm_entry - local entry = { type = self.type, dev = self.device } + local entry = { type = self.type, dev = self.device } return entry end @@ -284,10 +284,10 @@ end ---@param device table device table function ppm.unmount(device) if device then - for side, data in pairs(ppm_sys.mounts) do + for iface, data in pairs(ppm_sys.mounts) do if data.dev == device then - log.warning(util.c("PPM: manually unmounted ", data.type, " mounted to ", side)) - ppm_sys.mounts[side] = nil + log.warning(util.c("PPM: manually unmounted ", data.type, " mounted to ", iface)) + ppm_sys.mounts[iface] = nil break end end @@ -352,8 +352,8 @@ end ---@return string|nil iface CC peripheral interface function ppm.get_iface(device) if device then - for side, data in pairs(ppm_sys.mounts) do - if data.dev == device then return side end + for iface, data in pairs(ppm_sys.mounts) do + if data.dev == device then return iface end end end diff --git a/scada-common/psil.lua b/scada-common/psil.lua index 09686bf..f3d810a 100644 --- a/scada-common/psil.lua +++ b/scada-common/psil.lua @@ -6,9 +6,10 @@ local util = require("scada-common.util") local psil = {} --- instantiate a new PSI layer +-- instantiate a new interconnect layer ---@nodiscard function psil.create() + ---@type { [string]: { subscribers: { notify: fun(param: any) }[], value: any } } interconnect table local ic = {} -- allocate a new interconnect field diff --git a/scada-common/rsio.lua b/scada-common/rsio.lua index fb3a50a..b88180a 100644 --- a/scada-common/rsio.lua +++ b/scada-common/rsio.lua @@ -113,10 +113,13 @@ assert(#dup_chk == rsio.NUM_PORTS, "port list malformed") local IO = IO_PORT -- list of all port names +---@type string[] local PORT_NAMES = {} + for k, v in pairs(IO) do PORT_NAMES[v] = k end -- list of all port I/O modes +---@type { [IO_PORT]: IO_MODE } local MODES = { [IO.F_SCRAM] = IO_MODE.DIGITAL_IN, [IO.F_ACK] = IO_MODE.DIGITAL_IN, @@ -233,6 +236,7 @@ end --#region Generic Checks +---@type string[] local RS_SIDES = rs.getSides() -- check if a port is valid diff --git a/scada-common/tcd.lua b/scada-common/tcd.lua index a3c920f..f11c2d8 100644 --- a/scada-common/tcd.lua +++ b/scada-common/tcd.lua @@ -7,6 +7,7 @@ local util = require("scada-common.util") local tcd = {} +---@type { callback: function, duration: number, expiry: number }[] local registry = {} -- request a function to be called after the specified time diff --git a/scada-common/util.lua b/scada-common/util.lua index 36a73fc..6176b63 100644 --- a/scada-common/util.lua +++ b/scada-common/util.lua @@ -24,7 +24,7 @@ local t_pack = table.pack local util = {} -- scada-common version -util.version = "1.4.4" +util.version = "1.4.5" util.TICK_TIME_S = 0.05 util.TICK_TIME_MS = 50 @@ -33,9 +33,9 @@ util.TICK_TIME_MS = 50 -- trinary operator ---@nodiscard ----@param cond boolean|nil condition ----@param a any return if true ----@param b any return if false +---@param cond any condition +---@param a any return if evaluated as true +---@param b any return if false or nil ---@return any value function util.trinary(cond, a, b) if cond then return a else return b end @@ -84,7 +84,7 @@ end -- does not behave exactly like C's strtok ---@param str string string to tokenize ---@param sep string separator to tokenize by ----@return table token_list +---@return string[] token_list function util.strtok(str, sep) local list = {} for part in string.gmatch(str, "([^" .. sep .. "]+)") do t_insert(list, part) end @@ -123,7 +123,7 @@ end ---@nodiscard ---@param str string ---@param limit integer line limit, must be greater than 0 ----@return table lines +---@return string[] lines function util.strwrap(str, limit) assert(limit > 0, "util.strwrap() limit not greater than 0") return cc_strings.wrap(str, limit) @@ -343,8 +343,9 @@ end -- 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 +---@generic Type +---@param t Type[] table to remove elements from +---@param f fun(t_elem: Type) : boolean should return false to delete an element when passed the element ---@param on_delete? function optional function to execute on deletion, passed the table element to be deleted as the parameter function util.filter_table(t, f, on_delete) local move_to = 1 @@ -366,9 +367,10 @@ function util.filter_table(t, f, on_delete) end -- check if a table contains the provided element +---@generic Type ---@nodiscard ----@param t table table to check ----@param element any element to check for +---@param t Type[] table to check +---@param element Type element to check for function util.table_contains(t, element) for i = 1, #t do if t[i] == element then return true end