mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#47 scada-common doc comments
This commit is contained in:
parent
6e1ece8183
commit
3c688bfafa
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user