From 3c688bfafa9e97e7994f5a3389314f7cb4e33799 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Tue, 10 May 2022 17:06:27 -0400 Subject: [PATCH] #47 scada-common doc comments --- scada-common/alarm.lua | 23 +++-- scada-common/comms.lua | 222 ++++++++++++++++++++-------------------- scada-common/log.lua | 14 +++ scada-common/mqueue.lua | 59 ++++++----- scada-common/ppm.lua | 40 ++++++-- scada-common/rsio.lua | 23 ++++- scada-common/types.lua | 5 + scada-common/util.lua | 53 +++++++++- 8 files changed, 288 insertions(+), 151 deletions(-) diff --git a/scada-common/alarm.lua b/scada-common/alarm.lua index 7c39bc4..2fcaa19 100644 --- a/scada-common/alarm.lua +++ b/scada-common/alarm.lua @@ -1,7 +1,9 @@ local util = require("scada-common.util") +---@class alarm local alarm = {} +---@alias SEVERITY integer SEVERITY = { INFO = 0, -- basic info message WARNING = 1, -- warning about some abnormal state @@ -13,6 +15,8 @@ SEVERITY = { alarm.SEVERITY = SEVERITY +-- severity integer to string +---@param severity SEVERITY alarm.severity_to_string = function (severity) if severity == SEVERITY.INFO then return "INFO" @@ -31,6 +35,10 @@ alarm.severity_to_string = function (severity) end end +-- create a new scada alarm entry +---@param severity SEVERITY +---@param device string +---@param message string alarm.scada_alarm = function (severity, device, message) local self = { time = util.time(), @@ -40,11 +48,17 @@ alarm.scada_alarm = function (severity, device, message) message = message } - local format = function () + ---@class scada_alarm + local public = {} + + -- format the alarm as a string + ---@return string message + public.format = function () return self.ts_string .. " [" .. alarm.severity_to_string(self.severity) .. "] (" .. self.device ") >> " .. self.message end - local properties = function () + -- get alarm properties + public.properties = function () return { time = self.time, severity = self.severity, @@ -53,10 +67,7 @@ alarm.scada_alarm = function (severity, device, message) } end - return { - format = format, - properties = properties - } + return public end return alarm diff --git a/scada-common/comms.lua b/scada-common/comms.lua index 5a84fbc..9eebb2d 100644 --- a/scada-common/comms.lua +++ b/scada-common/comms.lua @@ -5,11 +5,13 @@ local log = require("scada-common.log") local types = require("scada-common.types") +---@class comms local comms = {} local rtu_t = types.rtu_t local insert = table.insert +---@alias PROTOCOLS integer local PROTOCOLS = { MODBUS_TCP = 0, -- our "MODBUS TCP"-esque protocol RPLC = 1, -- reactor PLC protocol @@ -18,6 +20,7 @@ local PROTOCOLS = { COORD_API = 4 -- data/control packets for pocket computers to/from coordinators } +---@alias RPLC_TYPES integer local RPLC_TYPES = { LINK_REQ = 0, -- linking requests STATUS = 1, -- reactor/system status @@ -30,12 +33,14 @@ local RPLC_TYPES = { RPS_RESET = 8 -- clear RPS trip (if in bad state, will trip immediately) } +---@alias RPLC_LINKING integer local RPLC_LINKING = { ALLOW = 0, -- link approved DENY = 1, -- link denied COLLISION = 2 -- link denied due to existing active link } +---@alias SCADA_MGMT_TYPES integer local SCADA_MGMT_TYPES = { KEEP_ALIVE = 0, -- keep alive packet w/ RTT CLOSE = 1, -- close a connection @@ -43,6 +48,7 @@ local SCADA_MGMT_TYPES = { REMOTE_LINKED = 3 -- remote device linked } +---@alias RTU_ADVERT_TYPES integer local RTU_ADVERT_TYPES = { REDSTONE = 0, -- redstone I/O BOILER = 1, -- boiler @@ -71,8 +77,14 @@ comms.scada_packet = function () payload = nil } + ---@class scada_packet + local public = {} + -- make a SCADA packet - local make = function (seq_num, protocol, payload) + ---@param seq_num integer + ---@param protocol PROTOCOLS + ---@param payload table + public.make = function (seq_num, protocol, payload) self.valid = true self.seq_num = seq_num self.protocol = protocol @@ -82,7 +94,12 @@ comms.scada_packet = function () end -- parse in a modem message as a SCADA packet - local receive = function (side, sender, reply_to, message, distance) + ---@param side string + ---@param sender integer + ---@param reply_to integer + ---@param message any + ---@param distance integer + public.receive = function (side, sender, reply_to, message, distance) self.modem_msg_in = { iface = side, s_port = sender, @@ -108,40 +125,23 @@ comms.scada_packet = function () -- public accessors -- - local modem_event = function () return self.modem_msg_in end - local raw_sendable = function () return self.raw end + public.modem_event = function () return self.modem_msg_in end + public.raw_sendable = function () return self.raw end - local local_port = function () return self.modem_msg_in.s_port end - local remote_port = function () return self.modem_msg_in.r_port end + public.local_port = function () return self.modem_msg_in.s_port end + public.remote_port = function () return self.modem_msg_in.r_port end - local is_valid = function () return self.valid end + public.is_valid = function () return self.valid end - local seq_num = function () return self.seq_num end - local protocol = function () return self.protocol end - local length = function () return self.length end - local data = function () return self.payload end + public.seq_num = function () return self.seq_num end + public.protocol = function () return self.protocol end + public.length = function () return self.length end + public.data = function () return self.payload end - return { - -- construct - make = make, - receive = receive, - -- raw access - modem_event = modem_event, - raw_sendable = raw_sendable, - -- ports - local_port = local_port, - remote_port = remote_port, - -- well-formed - is_valid = is_valid, - -- packet properties - seq_num = seq_num, - protocol = protocol, - length = length, - data = data - } + return public end --- MODBUS packet +-- MODBUS packet -- modeled after MODBUS TCP packet comms.modbus_packet = function () local self = { @@ -154,8 +154,15 @@ comms.modbus_packet = function () data = nil } + ---@class modbus_packet + local public = {} + -- make a MODBUS packet - local make = function (txn_id, unit_id, func_code, data) + ---@param txn_id integer + ---@param unit_id integer + ---@param func_code MODBUS_FCODE + ---@param data table + public.make = function (txn_id, unit_id, func_code, data) self.txn_id = txn_id self.length = #data self.unit_id = unit_id @@ -170,18 +177,20 @@ comms.modbus_packet = function () end -- decode a MODBUS packet from a SCADA frame - local decode = function (frame) + ---@param frame scada_packet + ---@return boolean success + public.decode = function (frame) if frame then self.frame = frame if frame.protocol() == PROTOCOLS.MODBUS_TCP then local size_ok = frame.length() >= 3 - + if size_ok then local data = frame.data() - make(data[1], data[2], data[3], { table.unpack(data, 4, #data) }) + public.make(data[1], data[2], data[3], { table.unpack(data, 4, #data) }) end - + return size_ok else log.debug("attempted MODBUS_TCP parse of incorrect protocol " .. frame.protocol(), true) @@ -194,10 +203,10 @@ comms.modbus_packet = function () end -- get raw to send - local raw_sendable = function () return self.raw end + public.raw_sendable = function () return self.raw end -- get this packet - local get = function () + public.get = function () return { scada_frame = self.frame, txn_id = self.txn_id, @@ -208,15 +217,7 @@ comms.modbus_packet = function () } end - return { - -- construct - make = make, - decode = decode, - -- raw access - raw_sendable = raw_sendable, - -- formatted access - get = get - } + return public end -- reactor PLC packet @@ -230,10 +231,12 @@ comms.rplc_packet = function () body = nil } + ---@class rplc_packet + local public = {} + -- check that type is known local _rplc_type_valid = function () - return self.type == RPLC_TYPES.KEEP_ALIVE or - self.type == RPLC_TYPES.LINK_REQ or + return self.type == RPLC_TYPES.LINK_REQ or self.type == RPLC_TYPES.STATUS or self.type == RPLC_TYPES.MEK_STRUCT or self.type == RPLC_TYPES.MEK_BURN_RATE or @@ -245,7 +248,10 @@ comms.rplc_packet = function () end -- make an RPLC packet - local make = function (id, packet_type, data) + ---@param id integer + ---@param packet_type RPLC_TYPES + ---@param data table + public.make = function (id, packet_type, data) -- packet accessor properties self.id = id self.type = packet_type @@ -260,7 +266,9 @@ comms.rplc_packet = function () end -- decode an RPLC packet from a SCADA frame - local decode = function (frame) + ---@param frame scada_packet + ---@return boolean success + public.decode = function (frame) if frame then self.frame = frame @@ -269,7 +277,7 @@ comms.rplc_packet = function () if ok then local data = frame.data() - make(data[1], data[2], { table.unpack(data, 3, #data) }) + public.make(data[1], data[2], { table.unpack(data, 3, #data) }) ok = _rplc_type_valid() end @@ -285,10 +293,10 @@ comms.rplc_packet = function () end -- get raw to send - local raw_sendable = function () return self.raw end + public.raw_sendable = function () return self.raw end -- get this packet - local get = function () + public.get = function () return { scada_frame = self.frame, id = self.id, @@ -298,15 +306,7 @@ comms.rplc_packet = function () } end - return { - -- construct - make = make, - decode = decode, - -- raw access - raw_sendable = raw_sendable, - -- formatted access - get = get - } + return public end -- SCADA management packet @@ -319,17 +319,21 @@ comms.mgmt_packet = function () data = nil } + ---@class mgmt_packet + local public = {} + -- check that type is known local _scada_type_valid = function () - return self.type == SCADA_MGMT_TYPES.PING or + return self.type == SCADA_MGMT_TYPES.KEEP_ALIVE or self.type == SCADA_MGMT_TYPES.CLOSE or self.type == SCADA_MGMT_TYPES.REMOTE_LINKED or - self.type == SCADA_MGMT_TYPES.RTU_ADVERT or - self.type == SCADA_MGMT_TYPES.RTU_HEARTBEAT + self.type == SCADA_MGMT_TYPES.RTU_ADVERT end -- make a SCADA management packet - local make = function (packet_type, data) + ---@param packet_type SCADA_MGMT_TYPES + ---@param data table + public.make = function (packet_type, data) -- packet accessor properties self.type = packet_type self.length = #data @@ -343,19 +347,21 @@ comms.mgmt_packet = function () end -- decode a SCADA management packet from a SCADA frame - local decode = function (frame) + ---@param frame scada_packet + ---@return boolean success + public.decode = function (frame) if frame then self.frame = frame if frame.protocol() == PROTOCOLS.SCADA_MGMT then local ok = frame.length() >= 1 - + if ok then local data = frame.data() - make(data[1], { table.unpack(data, 2, #data) }) + public.make(data[1], { table.unpack(data, 2, #data) }) ok = _scada_type_valid() end - + return ok else log.debug("attempted SCADA_MGMT parse of incorrect protocol " .. frame.protocol(), true) @@ -368,10 +374,10 @@ comms.mgmt_packet = function () end -- get raw to send - local raw_sendable = function () return self.raw end + public.raw_sendable = function () return self.raw end -- get this packet - local get = function () + public.get = function () return { scada_frame = self.frame, type = self.type, @@ -380,15 +386,7 @@ comms.mgmt_packet = function () } end - return { - -- construct - make = make, - decode = decode, - -- raw access - raw_sendable = raw_sendable, - -- formatted access - get = get - } + return public end -- SCADA coordinator packet @@ -402,13 +400,18 @@ comms.coord_packet = function () data = nil } + ---@class coord_packet + local public = {} + local _coord_type_valid = function () -- @todo return false end -- make a coordinator packet - local make = function (packet_type, data) + ---@param packet_type any + ---@param data table + public.make = function (packet_type, data) -- packet accessor properties self.type = packet_type self.length = #data @@ -422,7 +425,9 @@ comms.coord_packet = function () end -- decode a coordinator packet from a SCADA frame - local decode = function (frame) + ---@param frame scada_packet + ---@return boolean success + public.decode = function (frame) if frame then self.frame = frame @@ -431,7 +436,7 @@ comms.coord_packet = function () if ok then local data = frame.data() - make(data[1], { table.unpack(data, 2, #data) }) + public.make(data[1], { table.unpack(data, 2, #data) }) ok = _coord_type_valid() end @@ -447,10 +452,10 @@ comms.coord_packet = function () end -- get raw to send - local raw_sendable = function () return self.raw end + public.raw_sendable = function () return self.raw end -- get this packet - local get = function () + public.get = function () return { scada_frame = self.frame, type = self.type, @@ -459,15 +464,7 @@ comms.coord_packet = function () } end - return { - -- construct - make = make, - decode = decode, - -- raw access - raw_sendable = raw_sendable, - -- formatted access - get = get - } + return public end -- coordinator API (CAPI) packet @@ -481,13 +478,18 @@ comms.capi_packet = function () data = nil } + ---@class capi_packet + local public = {} + local _coord_type_valid = function () -- @todo return false end - -- make a coordinator packet - local make = function (packet_type, data) + -- make a coordinator API packet + ---@param packet_type any + ---@param data table + public.make = function (packet_type, data) -- packet accessor properties self.type = packet_type self.length = #data @@ -500,8 +502,10 @@ comms.capi_packet = function () end end - -- decode a coordinator packet from a SCADA frame - local decode = function (frame) + -- decode a coordinator API packet from a SCADA frame + ---@param frame scada_packet + ---@return boolean success + public.decode = function (frame) if frame then self.frame = frame @@ -510,7 +514,7 @@ comms.capi_packet = function () if ok then local data = frame.data() - make(data[1], { table.unpack(data, 2, #data) }) + public.make(data[1], { table.unpack(data, 2, #data) }) ok = _coord_type_valid() end @@ -526,10 +530,10 @@ comms.capi_packet = function () end -- get raw to send - local raw_sendable = function () return self.raw end + public.raw_sendable = function () return self.raw end -- get this packet - local get = function () + public.get = function () return { scada_frame = self.frame, type = self.type, @@ -538,18 +542,12 @@ comms.capi_packet = function () } end - return { - -- construct - make = make, - decode = decode, - -- raw access - raw_sendable = raw_sendable, - -- formatted access - get = get - } + return public end -- convert rtu_t to RTU advertisement type +---@param type rtu_t +---@return RTU_ADVERT_TYPES|nil comms.rtu_t_to_advert_type = function (type) if type == rtu_t.redstone then return RTU_ADVERT_TYPES.REDSTONE @@ -571,6 +569,8 @@ comms.rtu_t_to_advert_type = function (type) end -- convert RTU advertisement type to rtu_t +---@param atype RTU_ADVERT_TYPES +---@return rtu_t|nil comms.advert_type_to_rtu_t = function (atype) if atype == RTU_ADVERT_TYPES.REDSTONE then return rtu_t.redstone diff --git a/scada-common/log.lua b/scada-common/log.lua index e841b23..71e4495 100644 --- a/scada-common/log.lua +++ b/scada-common/log.lua @@ -4,8 +4,10 @@ local util = require("scada-common.util") -- File System Logger -- +---@class log local log = {} +---@alias MODE integer local MODE = { APPEND = 0, NEW = 1 @@ -13,6 +15,7 @@ local MODE = { log.MODE = MODE +-- whether to log debug messages or not local LOG_DEBUG = true local _log_sys = { @@ -21,9 +24,12 @@ local _log_sys = { file = nil } +---@type function local free_space = fs.getFreeSpace -- initialize logger +---@param path string file path +---@param write_mode MODE log.init = function (path, write_mode) _log_sys.path = path _log_sys.mode = write_mode @@ -36,6 +42,7 @@ log.init = function (path, write_mode) end -- private log write function +---@param msg string local _log = function (msg) local time_stamp = os.date("[%c] ") local stamped = time_stamp .. msg @@ -70,6 +77,8 @@ local _log = function (msg) end -- log debug messages +---@param msg string message +---@param trace? boolean include file trace log.debug = function (msg, trace) if LOG_DEBUG then local dbg_info = "" @@ -90,16 +99,20 @@ log.debug = function (msg, trace) end -- log info messages +---@param msg string message log.info = function (msg) _log("[INF] " .. msg) end -- log warning messages +---@param msg string message log.warning = function (msg) _log("[WRN] " .. msg) end -- log error messages +---@param msg string message +---@param trace? boolean include file trace log.error = function (msg, trace) local dbg_info = "" @@ -118,6 +131,7 @@ log.error = function (msg, trace) end -- log fatal errors +---@param msg string message log.fatal = function (msg) _log("[FTL] " .. msg) end diff --git a/scada-common/mqueue.lua b/scada-common/mqueue.lua index d1ac5c1..db97df4 100644 --- a/scada-common/mqueue.lua +++ b/scada-common/mqueue.lua @@ -4,6 +4,7 @@ local mqueue = {} +---@alias TYPE integer local TYPE = { COMMAND = 0, DATA = 1, @@ -12,41 +13,61 @@ local TYPE = { mqueue.TYPE = TYPE +-- create a new message queue mqueue.new = function () local queue = {} local insert = table.insert local remove = table.remove - local length = function () - return #queue - end + ---@class queue_item + local queue_item = { + qtype = 0, ---@type TYPE + message = 0 ---@type any + } - local empty = function () - return #queue == 0 - end + ---@class mqueue + local public = {} - local ready = function () - return #queue ~= 0 - end + -- get queue length + public.length = function () return #queue end + -- check if queue is empty + ---@return boolean is_empty + public.empty = function () return #queue == 0 end + + -- check if queue has contents + public.ready = function () return #queue ~= 0 end + + -- push a new item onto the queue + ---@param qtype TYPE + ---@param message string local _push = function (qtype, message) insert(queue, { qtype = qtype, message = message }) end - local push_command = function (message) + -- push a command onto the queue + ---@param message any + public.push_command = function (message) _push(TYPE.COMMAND, message) end - local push_data = function (key, value) + -- push data onto the queue + ---@param key any + ---@param value any + public.push_data = function (key, value) _push(TYPE.DATA, { key = key, val = value }) end - local push_packet = function (message) - _push(TYPE.PACKET, message) + -- push a packet onto the queue + ---@param packet scada_packet|modbus_packet|rplc_packet|coord_packet|capi_packet + public.push_packet = function (packet) + _push(TYPE.PACKET, packet) end - local pop = function () + -- get an item off the queue + ---@return queue_item|nil + public.pop = function () if #queue > 0 then return remove(queue, 1) else @@ -54,15 +75,7 @@ mqueue.new = function () end end - return { - length = length, - empty = empty, - ready = ready, - push_packet = push_packet, - push_data = push_data, - push_command = push_command, - pop = pop - } + return public end return mqueue diff --git a/scada-common/ppm.lua b/scada-common/ppm.lua index e834946..c5026ea 100644 --- a/scada-common/ppm.lua +++ b/scada-common/ppm.lua @@ -4,9 +4,10 @@ local log = require("scada-common.log") -- Protected Peripheral Manager -- +---@class ppm local ppm = {} -local ACCESS_FAULT = nil +local ACCESS_FAULT = nil ---@type nil ppm.ACCESS_FAULT = ACCESS_FAULT @@ -22,9 +23,12 @@ local _ppm_sys = { mute = false } --- wrap peripheral calls with lua protected call --- we don't want a disconnect to crash a program --- also provides peripheral-specific fault checks (auto-clear fault defaults to true) +-- wrap peripheral calls with lua protected call as we don't want a disconnect to crash a program +--- +---also provides peripheral-specific fault checks (auto-clear fault defaults to true) +--- +---assumes iface is a valid peripheral +---@param iface string CC peripheral interface local peri_init = function (iface) local self = { faulted = false, @@ -150,6 +154,8 @@ ppm.mount_all = function () end -- mount a particular device +---@param iface string CC peripheral interface +---@return string|nil type, table|nil device ppm.mount = function (iface) local ifaces = peripheral.getNames() local pm_dev = nil @@ -171,33 +177,44 @@ ppm.mount = function (iface) end -- handle peripheral_detach event +---@param iface string CC peripheral interface +---@return string|nil type, table|nil device ppm.handle_unmount = function (iface) + local pm_dev = nil + local pm_type = nil + -- what got disconnected? local lost_dev = _ppm_sys.mounts[iface] if lost_dev then - local type = lost_dev.type - log.warning("PPM: lost device " .. type .. " mounted to " .. iface) + pm_type = lost_dev.type + pm_dev = lost_dev.dev + + log.warning("PPM: lost device " .. pm_type .. " mounted to " .. iface) else log.error("PPM: lost device unknown to the PPM mounted to " .. iface) end - return lost_dev + return pm_type, pm_dev end -- GENERAL ACCESSORS -- -- list all available peripherals +---@return table names ppm.list_avail = function () return peripheral.getNames() end -- list mounted peripherals +---@return table mounts ppm.list_mounts = function () return _ppm_sys.mounts end -- get a mounted peripheral by side/interface +---@param iface string CC peripheral interface +---@return table|nil device function table ppm.get_periph = function (iface) if _ppm_sys.mounts[iface] then return _ppm_sys.mounts[iface].dev @@ -205,6 +222,8 @@ ppm.get_periph = function (iface) end -- get a mounted peripheral type by side/interface +---@param iface string CC peripheral interface +---@return string|nil type ppm.get_type = function (iface) if _ppm_sys.mounts[iface] then return _ppm_sys.mounts[iface].type @@ -212,6 +231,8 @@ ppm.get_type = function (iface) end -- get all mounted peripherals by type +---@param name string type name +---@return table devices device function tables ppm.get_all_devices = function (name) local devices = {} @@ -225,6 +246,8 @@ ppm.get_all_devices = function (name) end -- get a mounted peripheral by type (if multiple, returns the first) +---@param name string type name +---@return table|nil device function table ppm.get_device = function (name) local device = nil @@ -241,11 +264,13 @@ end -- SPECIFIC DEVICE ACCESSORS -- -- get the fission reactor (if multiple, returns the first) +---@return table|nil reactor function table ppm.get_fission_reactor = function () return ppm.get_device("fissionReactor") end -- get the wireless modem (if multiple, returns the first) +---@return table|nil modem function table ppm.get_wireless_modem = function () local w_modem = nil @@ -260,6 +285,7 @@ ppm.get_wireless_modem = function () end -- list all connected monitors +---@return table monitors ppm.list_monitors = function () return ppm.get_all_devices("monitor") end diff --git a/scada-common/rsio.lua b/scada-common/rsio.lua index d5a3d5a..d71d777 100644 --- a/scada-common/rsio.lua +++ b/scada-common/rsio.lua @@ -8,16 +8,19 @@ local rsio = {} -- RS I/O CONSTANTS -- ---------------------- +---@alias IO_LVL integer local IO_LVL = { LOW = 0, HIGH = 1 } +---@alias IO_DIR integer local IO_DIR = { IN = 0, OUT = 1 } +---@alias IO_MODE integer local IO_MODE = { DIGITAL_OUT = 0, DIGITAL_IN = 1, @@ -25,6 +28,7 @@ local IO_MODE = { ANALOG_IN = 3 } +---@alias RS_IO integer local RS_IO = { -- digital inputs -- @@ -73,6 +77,7 @@ rsio.IO = RS_IO ----------------------- -- channel to string +---@param channel RS_IO rsio.to_string = function (channel) local names = { "F_SCRAM", @@ -155,6 +160,8 @@ local RS_DIO_MAP = { } -- get the mode of a channel +---@param channel RS_IO +---@return IO_MODE rsio.get_io_mode = function (channel) local modes = { IO_MODE.DIGITAL_IN, -- F_SCRAM @@ -194,11 +201,15 @@ end local RS_SIDES = rs.getSides() -- check if a channel is valid +---@param channel RS_IO +---@return boolean valid rsio.is_valid_channel = function (channel) - return channel ~= nil and channel > 0 and channel <= RS_IO.A_T_FLOW_RATE + return (channel ~= nil) and (channel > 0) and (channel <= RS_IO.A_T_FLOW_RATE) end -- check if a side is valid +---@param side string +---@return boolean valid rsio.is_valid_side = function (side) if side ~= nil then for i = 0, #RS_SIDES do @@ -209,6 +220,8 @@ rsio.is_valid_side = function (side) end -- check if a color is a valid single color +---@param color integer +---@return boolean valid rsio.is_color = function (color) return (color > 0) and (_B_AND(color, (color - 1)) == 0); end @@ -218,6 +231,8 @@ end ----------------- -- get digital IO level reading +---@param rs_value boolean +---@return IO_LVL rsio.digital_read = function (rs_value) if rs_value then return IO_LVL.HIGH @@ -227,6 +242,9 @@ rsio.digital_read = function (rs_value) end -- returns the level corresponding to active +---@param channel RS_IO +---@param active boolean +---@return IO_LVL rsio.digital_write = function (channel, active) if channel < RS_IO.WASTE_PO or channel > RS_IO.R_PLC_TIMEOUT then return IO_LVL.LOW @@ -236,6 +254,9 @@ rsio.digital_write = function (channel, active) end -- returns true if the level corresponds to active +---@param channel RS_IO +---@param level IO_LVL +---@return boolean rsio.digital_is_active = function (channel, level) if channel > RS_IO.R_ENABLE or channel > RS_IO.R_PLC_TIMEOUT then return false diff --git a/scada-common/types.lua b/scada-common/types.lua index 5bd747e..372b1d3 100644 --- a/scada-common/types.lua +++ b/scada-common/types.lua @@ -2,8 +2,10 @@ -- Global Types -- +---@class types local types = {} +---@alias rtu_t string types.rtu_t = { redstone = "redstone", boiler = "boiler", @@ -14,6 +16,7 @@ types.rtu_t = { induction_matrix = "induction_matrix" } +---@alias rps_status_t string types.rps_status_t = { ok = "ok", dmg_crit = "dmg_crit", @@ -30,6 +33,7 @@ types.rps_status_t = { -- MODBUS -- modbus function codes +---@alias MODBUS_FCODE integer types.MODBUS_FCODE = { READ_COILS = 0x01, READ_DISCRETE_INPUTS = 0x02, @@ -43,6 +47,7 @@ types.MODBUS_FCODE = { } -- modbus exception codes +---@alias MODBUS_EXCODE integer types.MODBUS_EXCODE = { ILLEGAL_FUNCTION = 0x01, ILLEGAL_DATA_ADDR = 0x02, diff --git a/scada-common/util.lua b/scada-common/util.lua index 77ad4c9..8dffd40 100644 --- a/scada-common/util.lua +++ b/scada-common/util.lua @@ -1,3 +1,8 @@ +-- +-- Utility Functions +-- + +---@class util local util = {} -- PRINT -- @@ -24,16 +29,22 @@ end -- TIME -- +-- current time +---@return integer milliseconds util.time_ms = function () ---@diagnostic disable-next-line: undefined-field return os.epoch('local') end +-- current time +---@return integer seconds util.time_s = function () ---@diagnostic disable-next-line: undefined-field return os.epoch('local') / 1000 end +-- current time +---@return integer milliseconds util.time = function () return util.time_ms() end @@ -41,19 +52,24 @@ end -- PARALLELIZATION -- -- protected sleep call so we still are in charge of catching termination --- EVENT_CONSUMER: this function consumes events +---@param t integer seconds +--- EVENT_CONSUMER: this function consumes events util.psleep = function (t) ---@diagnostic disable-next-line: undefined-field pcall(os.sleep, t) end --- no-op to provide a brief pause (and a yield) --- EVENT_CONSUMER: this function consumes events +-- no-op to provide a brief pause (1 tick) to yield +--- +--- EVENT_CONSUMER: this function consumes events util.nop = function () util.psleep(0.05) end -- attempt to maintain a minimum loop timing (duration of execution) +---@param target_timing integer minimum amount of milliseconds to wait for +---@param last_update integer millisecond time of last update +---@return integer time_now -- EVENT_CONSUMER: this function consumes events util.adaptive_delay = function (target_timing, last_update) local sleep_for = target_timing - (util.time() - last_update) @@ -64,6 +80,37 @@ util.adaptive_delay = function (target_timing, last_update) return util.time() end +-- MEKANISM POWER -- + +-- function kFE(fe) return fe / 1000 end +-- function MFE(fe) return fe / 1000000 end +-- function GFE(fe) return fe / 1000000000 end +-- function TFE(fe) return fe / 1000000000000 end + +-- -- 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 power_format(fe) +-- if fe < 1000 then +-- return string.format("%.2f FE", fe) +-- elseif fe < 1000000 then +-- return string.format("%.3f kFE", kFE(fe)) +-- end +-- end + -- WATCHDOG -- -- ComputerCraft OS Timer based Watchdog