mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#118 cleanup started of scada-common
This commit is contained in:
parent
e2d2a0f1dc
commit
34cac6a8b8
@ -173,7 +173,6 @@ local function main()
|
||||
log.debug("init> running without networking")
|
||||
end
|
||||
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
util.push_event("clock_start")
|
||||
|
||||
println("boot> completed")
|
||||
|
@ -266,7 +266,6 @@ function threads.thread__main(smem, init)
|
||||
-- this thread cannot be slept because it will miss events (namely "terminate" otherwise)
|
||||
if not plc_state.shutdown then
|
||||
log.info("main thread restarting now...")
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
util.push_event("clock_start")
|
||||
end
|
||||
end
|
||||
|
@ -16,7 +16,7 @@ local max_distance = nil
|
||||
|
||||
comms.version = "1.4.0"
|
||||
|
||||
---@alias PROTOCOLS integer
|
||||
---@enum PROTOCOLS
|
||||
local PROTOCOLS = {
|
||||
MODBUS_TCP = 0, -- our "MODBUS TCP"-esque protocol
|
||||
RPLC = 1, -- reactor PLC protocol
|
||||
@ -25,7 +25,7 @@ local PROTOCOLS = {
|
||||
COORD_API = 4 -- data/control packets for pocket computers to/from coordinators
|
||||
}
|
||||
|
||||
---@alias RPLC_TYPES integer
|
||||
---@enum RPLC_TYPES
|
||||
local RPLC_TYPES = {
|
||||
STATUS = 0, -- reactor/system status
|
||||
MEK_STRUCT = 1, -- mekanism build structure
|
||||
@ -40,7 +40,7 @@ local RPLC_TYPES = {
|
||||
AUTO_BURN_RATE = 10 -- set an automatic burn rate, PLC will respond with status, enable toggle speed limited
|
||||
}
|
||||
|
||||
---@alias SCADA_MGMT_TYPES integer
|
||||
---@enum SCADA_MGMT_TYPES
|
||||
local SCADA_MGMT_TYPES = {
|
||||
ESTABLISH = 0, -- establish new connection
|
||||
KEEP_ALIVE = 1, -- keep alive packet w/ RTT
|
||||
@ -49,7 +49,7 @@ local SCADA_MGMT_TYPES = {
|
||||
RTU_DEV_REMOUNT = 4 -- RTU multiblock possbily changed (formed, unformed) due to PPM remount
|
||||
}
|
||||
|
||||
---@alias SCADA_CRDN_TYPES integer
|
||||
---@enum SCADA_CRDN_TYPES
|
||||
local SCADA_CRDN_TYPES = {
|
||||
INITIAL_BUILDS = 0, -- initial, complete builds packet to the coordinator
|
||||
FAC_BUILDS = 1, -- facility RTU builds
|
||||
@ -60,12 +60,11 @@ local SCADA_CRDN_TYPES = {
|
||||
UNIT_CMD = 6 -- command a reactor unit
|
||||
}
|
||||
|
||||
---@alias CAPI_TYPES integer
|
||||
---@enum CAPI_TYPES
|
||||
local CAPI_TYPES = {
|
||||
ESTABLISH = 0 -- initial greeting
|
||||
}
|
||||
|
||||
---@alias ESTABLISH_ACK integer
|
||||
---@enum ESTABLISH_ACK
|
||||
local ESTABLISH_ACK = {
|
||||
ALLOW = 0, -- link approved
|
||||
DENY = 1, -- link denied
|
||||
@ -73,7 +72,7 @@ local ESTABLISH_ACK = {
|
||||
BAD_VERSION = 3 -- link denied due to comms version mismatch
|
||||
}
|
||||
|
||||
---@alias DEVICE_TYPES integer
|
||||
---@enum DEVICE_TYPES
|
||||
local DEVICE_TYPES = {
|
||||
PLC = 0, -- PLC device type for establish
|
||||
RTU = 1, -- RTU device type for establish
|
||||
@ -81,7 +80,7 @@ local DEVICE_TYPES = {
|
||||
CRDN = 3 -- coordinator device type for establish
|
||||
}
|
||||
|
||||
---@alias RTU_UNIT_TYPES integer
|
||||
---@enum RTU_UNIT_TYPES
|
||||
local RTU_UNIT_TYPES = {
|
||||
REDSTONE = 0, -- redstone I/O
|
||||
BOILER_VALVE = 1, -- boiler mekanism 10.1+
|
||||
@ -92,7 +91,7 @@ local RTU_UNIT_TYPES = {
|
||||
ENV_DETECTOR = 6 -- environment detector
|
||||
}
|
||||
|
||||
---@alias PLC_AUTO_ACK integer
|
||||
---@enum PLC_AUTO_ACK
|
||||
local PLC_AUTO_ACK = {
|
||||
FAIL = 0, -- failed to set burn rate/burn rate invalid
|
||||
DIRECT_SET_OK = 1, -- successfully set burn rate
|
||||
@ -100,7 +99,7 @@ local PLC_AUTO_ACK = {
|
||||
ZERO_DIS_OK = 3 -- successfully disabled reactor with < 0.01 burn rate
|
||||
}
|
||||
|
||||
---@alias FAC_COMMANDS integer
|
||||
---@enum FAC_COMMANDS
|
||||
local FAC_COMMANDS = {
|
||||
SCRAM_ALL = 0, -- SCRAM all reactors
|
||||
STOP = 1, -- stop automatic control
|
||||
@ -108,7 +107,7 @@ local FAC_COMMANDS = {
|
||||
ACK_ALL_ALARMS = 3 -- acknowledge all alarms on all units
|
||||
}
|
||||
|
||||
---@alias UNIT_COMMANDS integer
|
||||
---@enum UNIT_COMMANDS
|
||||
local UNIT_COMMANDS = {
|
||||
SCRAM = 0, -- SCRAM the reactor
|
||||
START = 1, -- start the reactor
|
||||
@ -152,6 +151,7 @@ function comms.set_trusted_range(distance)
|
||||
end
|
||||
|
||||
-- generic SCADA packet object
|
||||
---@nodiscard
|
||||
function comms.scada_packet()
|
||||
local self = {
|
||||
modem_msg_in = nil,
|
||||
@ -180,11 +180,12 @@ function comms.scada_packet()
|
||||
end
|
||||
|
||||
-- parse in a modem message as a SCADA packet
|
||||
---@param side string
|
||||
---@param sender integer
|
||||
---@param reply_to integer
|
||||
---@param message any
|
||||
---@param distance integer
|
||||
---@param side string modem side
|
||||
---@param sender integer sender port
|
||||
---@param reply_to integer reply port
|
||||
---@param message any message body
|
||||
---@param distance integer transmission distance
|
||||
---@return boolean valid valid message received
|
||||
function public.receive(side, sender, reply_to, message, distance)
|
||||
self.modem_msg_in = {
|
||||
iface = side,
|
||||
@ -223,24 +224,34 @@ function comms.scada_packet()
|
||||
|
||||
-- public accessors --
|
||||
|
||||
---@nodiscard
|
||||
function public.modem_event() return self.modem_msg_in end
|
||||
---@nodiscard
|
||||
function public.raw_sendable() return self.raw end
|
||||
|
||||
---@nodiscard
|
||||
function public.local_port() return self.modem_msg_in.s_port end
|
||||
---@nodiscard
|
||||
function public.remote_port() return self.modem_msg_in.r_port end
|
||||
|
||||
---@nodiscard
|
||||
function public.is_valid() return self.valid end
|
||||
|
||||
---@nodiscard
|
||||
function public.seq_num() return self.seq_num end
|
||||
---@nodiscard
|
||||
function public.protocol() return self.protocol end
|
||||
---@nodiscard
|
||||
function public.length() return self.length end
|
||||
---@nodiscard
|
||||
function public.data() return self.payload end
|
||||
|
||||
return public
|
||||
end
|
||||
|
||||
-- MODBUS packet
|
||||
-- MODBUS packet<br>
|
||||
-- modeled after MODBUS TCP packet
|
||||
---@nodiscard
|
||||
function comms.modbus_packet()
|
||||
local self = {
|
||||
frame = nil,
|
||||
@ -309,9 +320,11 @@ function comms.modbus_packet()
|
||||
end
|
||||
|
||||
-- get raw to send
|
||||
---@nodiscard
|
||||
function public.raw_sendable() return self.raw end
|
||||
|
||||
-- get this packet as a frame with an immutable relation to this object
|
||||
---@nodiscard
|
||||
function public.get()
|
||||
---@class modbus_frame
|
||||
local frame = {
|
||||
@ -330,6 +343,7 @@ function comms.modbus_packet()
|
||||
end
|
||||
|
||||
-- reactor PLC packet
|
||||
---@nodiscard
|
||||
function comms.rplc_packet()
|
||||
local self = {
|
||||
frame = nil,
|
||||
@ -410,9 +424,11 @@ function comms.rplc_packet()
|
||||
end
|
||||
|
||||
-- get raw to send
|
||||
---@nodiscard
|
||||
function public.raw_sendable() return self.raw end
|
||||
|
||||
-- get this packet as a frame with an immutable relation to this object
|
||||
---@nodiscard
|
||||
function public.get()
|
||||
---@class rplc_frame
|
||||
local frame = {
|
||||
@ -430,6 +446,7 @@ function comms.rplc_packet()
|
||||
end
|
||||
|
||||
-- SCADA management packet
|
||||
---@nodiscard
|
||||
function comms.mgmt_packet()
|
||||
local self = {
|
||||
frame = nil,
|
||||
@ -500,9 +517,11 @@ function comms.mgmt_packet()
|
||||
end
|
||||
|
||||
-- get raw to send
|
||||
---@nodiscard
|
||||
function public.raw_sendable() return self.raw end
|
||||
|
||||
-- get this packet as a frame with an immutable relation to this object
|
||||
---@nodiscard
|
||||
function public.get()
|
||||
---@class mgmt_frame
|
||||
local frame = {
|
||||
@ -519,6 +538,7 @@ function comms.mgmt_packet()
|
||||
end
|
||||
|
||||
-- SCADA coordinator packet
|
||||
---@nodiscard
|
||||
function comms.crdn_packet()
|
||||
local self = {
|
||||
frame = nil,
|
||||
@ -532,6 +552,7 @@ function comms.crdn_packet()
|
||||
local public = {}
|
||||
|
||||
-- check that type is known
|
||||
---@nodiscard
|
||||
local function _crdn_type_valid()
|
||||
return self.type == SCADA_CRDN_TYPES.INITIAL_BUILDS or
|
||||
self.type == SCADA_CRDN_TYPES.FAC_BUILDS or
|
||||
@ -590,9 +611,11 @@ function comms.crdn_packet()
|
||||
end
|
||||
|
||||
-- get raw to send
|
||||
---@nodiscard
|
||||
function public.raw_sendable() return self.raw end
|
||||
|
||||
-- get this packet as a frame with an immutable relation to this object
|
||||
---@nodiscard
|
||||
function public.get()
|
||||
---@class crdn_frame
|
||||
local frame = {
|
||||
@ -609,7 +632,8 @@ function comms.crdn_packet()
|
||||
end
|
||||
|
||||
-- coordinator API (CAPI) packet
|
||||
-- @todo
|
||||
---@todo implement for pocket access
|
||||
---@nodiscard
|
||||
function comms.capi_packet()
|
||||
local self = {
|
||||
frame = nil,
|
||||
@ -623,7 +647,7 @@ function comms.capi_packet()
|
||||
local public = {}
|
||||
|
||||
local function _capi_type_valid()
|
||||
-- @todo
|
||||
---@todo
|
||||
return false
|
||||
end
|
||||
|
||||
@ -675,9 +699,11 @@ function comms.capi_packet()
|
||||
end
|
||||
|
||||
-- get raw to send
|
||||
---@nodiscard
|
||||
function public.raw_sendable() return self.raw end
|
||||
|
||||
-- get this packet as a frame with an immutable relation to this object
|
||||
---@nodiscard
|
||||
function public.get()
|
||||
---@class capi_frame
|
||||
local frame = {
|
||||
@ -694,6 +720,7 @@ function comms.capi_packet()
|
||||
end
|
||||
|
||||
-- convert rtu_t to RTU unit type
|
||||
---@nodiscard
|
||||
---@param type rtu_t
|
||||
---@return RTU_UNIT_TYPES|nil
|
||||
function comms.rtu_t_to_unit_type(type)
|
||||
@ -717,6 +744,7 @@ function comms.rtu_t_to_unit_type(type)
|
||||
end
|
||||
|
||||
-- convert RTU unit type to rtu_t
|
||||
---@nodiscard
|
||||
---@param utype RTU_UNIT_TYPES
|
||||
---@return rtu_t|nil
|
||||
function comms.advert_type_to_rtu_t(utype)
|
||||
|
@ -70,6 +70,7 @@ function crypto.init(password, server_port)
|
||||
end
|
||||
|
||||
-- encrypt plaintext
|
||||
---@nodiscard
|
||||
---@param plaintext string
|
||||
---@return table initial_value, string ciphertext
|
||||
function crypto.encrypt(plaintext)
|
||||
@ -113,6 +114,7 @@ function crypto.encrypt(plaintext)
|
||||
end
|
||||
|
||||
-- decrypt ciphertext
|
||||
---@nodiscard
|
||||
---@param iv string CTR initial value
|
||||
---@param ciphertext string ciphertext hex
|
||||
---@return string plaintext
|
||||
@ -135,6 +137,7 @@ function crypto.decrypt(iv, ciphertext)
|
||||
end
|
||||
|
||||
-- generate HMAC of message
|
||||
---@nodiscard
|
||||
---@param message_hex string initial value concatenated with ciphertext
|
||||
function crypto.hmac(message_hex)
|
||||
local start = util.time()
|
||||
@ -201,11 +204,12 @@ function crypto.secure_modem(modem)
|
||||
end
|
||||
|
||||
-- parse in a modem message as a network packet
|
||||
---@param side string
|
||||
---@param sender integer
|
||||
---@param reply_to integer
|
||||
---@nodiscard
|
||||
---@param side string modem side
|
||||
---@param sender integer sender port
|
||||
---@param reply_to integer reply port
|
||||
---@param message any encrypted packet sent with secure_modem.transmit
|
||||
---@param distance integer
|
||||
---@param distance integer transmission distance
|
||||
---@return string side, integer sender, integer reply_to, any plaintext_message, integer distance
|
||||
function public.receive(side, sender, reply_to, message, distance)
|
||||
local body = ""
|
||||
|
@ -18,7 +18,7 @@ log.MODE = MODE
|
||||
-- whether to log debug messages or not
|
||||
local LOG_DEBUG = true
|
||||
|
||||
local _log_sys = {
|
||||
local log_sys = {
|
||||
path = "/log.txt",
|
||||
mode = MODE.APPEND,
|
||||
file = nil,
|
||||
@ -33,27 +33,25 @@ local free_space = fs.getFreeSpace
|
||||
---@param write_mode MODE
|
||||
---@param dmesg_redirect? table terminal/window to direct dmesg to
|
||||
function log.init(path, write_mode, dmesg_redirect)
|
||||
_log_sys.path = path
|
||||
_log_sys.mode = write_mode
|
||||
log_sys.path = path
|
||||
log_sys.mode = write_mode
|
||||
|
||||
if _log_sys.mode == MODE.APPEND then
|
||||
_log_sys.file = fs.open(path, "a")
|
||||
if log_sys.mode == MODE.APPEND then
|
||||
log_sys.file = fs.open(path, "a")
|
||||
else
|
||||
_log_sys.file = fs.open(path, "w")
|
||||
log_sys.file = fs.open(path, "w")
|
||||
end
|
||||
|
||||
if dmesg_redirect then
|
||||
_log_sys.dmesg_out = dmesg_redirect
|
||||
log_sys.dmesg_out = dmesg_redirect
|
||||
else
|
||||
_log_sys.dmesg_out = term.current()
|
||||
log_sys.dmesg_out = term.current()
|
||||
end
|
||||
end
|
||||
|
||||
-- direct dmesg output to a monitor/window
|
||||
---@param window table window or terminal reference
|
||||
function log.direct_dmesg(window)
|
||||
_log_sys.dmesg_out = window
|
||||
end
|
||||
function log.direct_dmesg(window) log_sys.dmesg_out = window end
|
||||
|
||||
-- private log write function
|
||||
---@param msg string
|
||||
@ -64,8 +62,8 @@ local function _log(msg)
|
||||
|
||||
-- attempt to write log
|
||||
local status, result = pcall(function ()
|
||||
_log_sys.file.writeLine(stamped)
|
||||
_log_sys.file.flush()
|
||||
log_sys.file.writeLine(stamped)
|
||||
log_sys.file.flush()
|
||||
end)
|
||||
|
||||
-- if we don't have space, we need to create a new log file
|
||||
@ -80,18 +78,18 @@ local function _log(msg)
|
||||
end
|
||||
end
|
||||
|
||||
if out_of_space or (free_space(_log_sys.path) < 100) then
|
||||
if out_of_space or (free_space(log_sys.path) < 100) then
|
||||
-- delete the old log file before opening a new one
|
||||
_log_sys.file.close()
|
||||
fs.delete(_log_sys.path)
|
||||
log_sys.file.close()
|
||||
fs.delete(log_sys.path)
|
||||
|
||||
-- re-init logger and pass dmesg_out so that it doesn't change
|
||||
log.init(_log_sys.path, _log_sys.mode, _log_sys.dmesg_out)
|
||||
log.init(log_sys.path, log_sys.mode, log_sys.dmesg_out)
|
||||
|
||||
-- leave a message
|
||||
_log_sys.file.writeLine(time_stamp .. "recycled log file")
|
||||
_log_sys.file.writeLine(stamped)
|
||||
_log_sys.file.flush()
|
||||
log_sys.file.writeLine(time_stamp .. "recycled log file")
|
||||
log_sys.file.writeLine(stamped)
|
||||
log_sys.file.flush()
|
||||
end
|
||||
end
|
||||
|
||||
@ -109,7 +107,7 @@ function log.dmesg(msg, tag, tag_color)
|
||||
tag = util.strval(tag)
|
||||
|
||||
local t_stamp = string.format("%12.2f", os.clock())
|
||||
local out = _log_sys.dmesg_out
|
||||
local out = log_sys.dmesg_out
|
||||
|
||||
if out ~= nil then
|
||||
local out_w, out_h = out.getSize()
|
||||
@ -197,6 +195,7 @@ function log.dmesg(msg, tag, tag_color)
|
||||
end
|
||||
|
||||
-- print a dmesg message, but then show remaining seconds instead of timestamp
|
||||
---@nodiscard
|
||||
---@param msg string message
|
||||
---@param tag? string log tag
|
||||
---@param tag_color? integer log tag color
|
||||
@ -204,7 +203,7 @@ end
|
||||
function log.dmesg_working(msg, tag, tag_color)
|
||||
local ts_coord = log.dmesg(msg, tag, tag_color)
|
||||
|
||||
local out = _log_sys.dmesg_out
|
||||
local out = log_sys.dmesg_out
|
||||
local width = (ts_coord.x2 - ts_coord.x1) + 1
|
||||
|
||||
if out ~= nil then
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
local mqueue = {}
|
||||
|
||||
---@alias MQ_TYPE integer
|
||||
---@enum MQ_TYPE
|
||||
local TYPE = {
|
||||
COMMAND = 0,
|
||||
DATA = 1,
|
||||
@ -14,6 +14,7 @@ local TYPE = {
|
||||
mqueue.TYPE = TYPE
|
||||
|
||||
-- create a new message queue
|
||||
---@nodiscard
|
||||
function mqueue.new()
|
||||
local queue = {}
|
||||
|
||||
@ -35,10 +36,13 @@ function mqueue.new()
|
||||
function public.length() return #queue end
|
||||
|
||||
-- check if queue is empty
|
||||
---@nodiscard
|
||||
---@return boolean is_empty
|
||||
function public.empty() return #queue == 0 end
|
||||
|
||||
-- check if queue has contents
|
||||
---@nodiscard
|
||||
---@return boolean has_contents
|
||||
function public.ready() return #queue ~= 0 end
|
||||
|
||||
-- push a new item onto the queue
|
||||
@ -68,6 +72,7 @@ function mqueue.new()
|
||||
end
|
||||
|
||||
-- get an item off the queue
|
||||
---@nodiscard
|
||||
---@return queue_item|nil
|
||||
function public.pop()
|
||||
if #queue > 0 then
|
||||
|
@ -24,7 +24,7 @@ ppm.VIRTUAL_DEVICE_TYPE = VIRTUAL_DEVICE_TYPE
|
||||
|
||||
local REPORT_FREQUENCY = 20 -- log every 20 faults per function
|
||||
|
||||
local _ppm_sys = {
|
||||
local ppm_sys = {
|
||||
mounts = {},
|
||||
next_vid = 0,
|
||||
auto_cf = false,
|
||||
@ -34,11 +34,9 @@ local _ppm_sys = {
|
||||
mute = false
|
||||
}
|
||||
|
||||
-- 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
|
||||
-- wrap peripheral calls with lua protected call as we don't want a disconnect to crash a program<br>
|
||||
-- also provides peripheral-specific fault checks (auto-clear fault defaults to true)<br>
|
||||
-- assumes iface is a valid peripheral
|
||||
---@param iface string CC peripheral interface
|
||||
local function peri_init(iface)
|
||||
local self = {
|
||||
@ -68,7 +66,7 @@ local function peri_init(iface)
|
||||
if status then
|
||||
-- auto fault clear
|
||||
if self.auto_cf then self.faulted = false end
|
||||
if _ppm_sys.auto_cf then _ppm_sys.faulted = false end
|
||||
if ppm_sys.auto_cf then ppm_sys.faulted = false end
|
||||
|
||||
self.fault_counts[key] = 0
|
||||
|
||||
@ -80,10 +78,10 @@ local function peri_init(iface)
|
||||
self.faulted = true
|
||||
self.last_fault = result
|
||||
|
||||
_ppm_sys.faulted = true
|
||||
_ppm_sys.last_fault = result
|
||||
ppm_sys.faulted = true
|
||||
ppm_sys.last_fault = result
|
||||
|
||||
if not _ppm_sys.mute and (self.fault_counts[key] % REPORT_FREQUENCY == 0) then
|
||||
if not ppm_sys.mute and (self.fault_counts[key] % REPORT_FREQUENCY == 0) then
|
||||
local count_str = ""
|
||||
if self.fault_counts[key] > 0 then
|
||||
count_str = " [" .. self.fault_counts[key] .. " total faults]"
|
||||
@ -95,7 +93,7 @@ local function peri_init(iface)
|
||||
self.fault_counts[key] = self.fault_counts[key] + 1
|
||||
|
||||
if result == "Terminated" then
|
||||
_ppm_sys.terminate = true
|
||||
ppm_sys.terminate = true
|
||||
end
|
||||
|
||||
return ACCESS_FAULT
|
||||
@ -136,10 +134,10 @@ local function peri_init(iface)
|
||||
self.faulted = true
|
||||
self.last_fault = UNDEFINED_FIELD
|
||||
|
||||
_ppm_sys.faulted = true
|
||||
_ppm_sys.last_fault = UNDEFINED_FIELD
|
||||
ppm_sys.faulted = true
|
||||
ppm_sys.last_fault = UNDEFINED_FIELD
|
||||
|
||||
if not _ppm_sys.mute and (self.fault_counts[key] % REPORT_FREQUENCY == 0) then
|
||||
if not ppm_sys.mute and (self.fault_counts[key] % REPORT_FREQUENCY == 0) then
|
||||
local count_str = ""
|
||||
if self.fault_counts[key] > 0 then
|
||||
count_str = " [" .. self.fault_counts[key] .. " total calls]"
|
||||
@ -169,48 +167,35 @@ end
|
||||
-- REPORTING --
|
||||
|
||||
-- silence error prints
|
||||
function ppm.disable_reporting()
|
||||
_ppm_sys.mute = true
|
||||
end
|
||||
function ppm.disable_reporting() ppm_sys.mute = true end
|
||||
|
||||
-- allow error prints
|
||||
function ppm.enable_reporting()
|
||||
_ppm_sys.mute = false
|
||||
end
|
||||
function ppm.enable_reporting() ppm_sys.mute = false end
|
||||
|
||||
-- FAULT MEMORY --
|
||||
|
||||
-- enable automatically clearing fault flag
|
||||
function ppm.enable_afc()
|
||||
_ppm_sys.auto_cf = true
|
||||
end
|
||||
function ppm.enable_afc() ppm_sys.auto_cf = true end
|
||||
|
||||
-- disable automatically clearing fault flag
|
||||
function ppm.disable_afc()
|
||||
_ppm_sys.auto_cf = false
|
||||
end
|
||||
function ppm.disable_afc() ppm_sys.auto_cf = false end
|
||||
|
||||
-- clear fault flag
|
||||
function ppm.clear_fault()
|
||||
_ppm_sys.faulted = false
|
||||
end
|
||||
function ppm.clear_fault() ppm_sys.faulted = false end
|
||||
|
||||
-- check fault flag
|
||||
function ppm.is_faulted()
|
||||
return _ppm_sys.faulted
|
||||
end
|
||||
---@nodiscard
|
||||
function ppm.is_faulted() return ppm_sys.faulted end
|
||||
|
||||
-- get the last fault message
|
||||
function ppm.get_last_fault()
|
||||
return _ppm_sys.last_fault
|
||||
end
|
||||
---@nodiscard
|
||||
function ppm.get_last_fault() return ppm_sys.last_fault end
|
||||
|
||||
-- TERMINATION --
|
||||
|
||||
-- if a caught error was a termination request
|
||||
function ppm.should_terminate()
|
||||
return _ppm_sys.terminate
|
||||
end
|
||||
---@nodiscard
|
||||
function ppm.should_terminate() return ppm_sys.terminate end
|
||||
|
||||
-- MOUNTING --
|
||||
|
||||
@ -218,12 +203,12 @@ end
|
||||
function ppm.mount_all()
|
||||
local ifaces = peripheral.getNames()
|
||||
|
||||
_ppm_sys.mounts = {}
|
||||
ppm_sys.mounts = {}
|
||||
|
||||
for i = 1, #ifaces do
|
||||
_ppm_sys.mounts[ifaces[i]] = peri_init(ifaces[i])
|
||||
ppm_sys.mounts[ifaces[i]] = peri_init(ifaces[i])
|
||||
|
||||
log.info(util.c("PPM: found a ", _ppm_sys.mounts[ifaces[i]].type, " (", ifaces[i], ")"))
|
||||
log.info(util.c("PPM: found a ", ppm_sys.mounts[ifaces[i]].type, " (", ifaces[i], ")"))
|
||||
end
|
||||
|
||||
if #ifaces == 0 then
|
||||
@ -232,6 +217,7 @@ function ppm.mount_all()
|
||||
end
|
||||
|
||||
-- mount a particular device
|
||||
---@nodiscard
|
||||
---@param iface string CC peripheral interface
|
||||
---@return string|nil type, table|nil device
|
||||
function ppm.mount(iface)
|
||||
@ -241,10 +227,10 @@ function ppm.mount(iface)
|
||||
|
||||
for i = 1, #ifaces do
|
||||
if iface == ifaces[i] then
|
||||
_ppm_sys.mounts[iface] = peri_init(iface)
|
||||
ppm_sys.mounts[iface] = peri_init(iface)
|
||||
|
||||
pm_type = _ppm_sys.mounts[iface].type
|
||||
pm_dev = _ppm_sys.mounts[iface].dev
|
||||
pm_type = ppm_sys.mounts[iface].type
|
||||
pm_dev = ppm_sys.mounts[iface].dev
|
||||
|
||||
log.info(util.c("PPM: mount(", iface, ") -> found a ", pm_type))
|
||||
break
|
||||
@ -255,26 +241,27 @@ function ppm.mount(iface)
|
||||
end
|
||||
|
||||
-- mount a virtual, placeholder device (specifically designed for RTU startup with missing devices)
|
||||
---@nodiscard
|
||||
---@return string type, table device
|
||||
function ppm.mount_virtual()
|
||||
local iface = "ppm_vdev_" .. _ppm_sys.next_vid
|
||||
local iface = "ppm_vdev_" .. ppm_sys.next_vid
|
||||
|
||||
_ppm_sys.mounts[iface] = peri_init("__virtual__")
|
||||
_ppm_sys.next_vid = _ppm_sys.next_vid + 1
|
||||
ppm_sys.mounts[iface] = peri_init("__virtual__")
|
||||
ppm_sys.next_vid = ppm_sys.next_vid + 1
|
||||
|
||||
log.info(util.c("PPM: mount_virtual() -> allocated new virtual device ", iface))
|
||||
|
||||
return _ppm_sys.mounts[iface].type, _ppm_sys.mounts[iface].dev
|
||||
return ppm_sys.mounts[iface].type, ppm_sys.mounts[iface].dev
|
||||
end
|
||||
|
||||
-- manually unmount a peripheral from the PPM
|
||||
---@param device table device table
|
||||
function ppm.unmount(device)
|
||||
if device then
|
||||
for side, data in pairs(_ppm_sys.mounts) do
|
||||
for side, 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
|
||||
ppm_sys.mounts[side] = nil
|
||||
break
|
||||
end
|
||||
end
|
||||
@ -282,6 +269,7 @@ function ppm.unmount(device)
|
||||
end
|
||||
|
||||
-- handle peripheral_detach event
|
||||
---@nodiscard
|
||||
---@param iface string CC peripheral interface
|
||||
---@return string|nil type, table|nil device
|
||||
function ppm.handle_unmount(iface)
|
||||
@ -289,7 +277,7 @@ function ppm.handle_unmount(iface)
|
||||
local pm_type = nil
|
||||
|
||||
-- what got disconnected?
|
||||
local lost_dev = _ppm_sys.mounts[iface]
|
||||
local lost_dev = ppm_sys.mounts[iface]
|
||||
|
||||
if lost_dev then
|
||||
pm_type = lost_dev.type
|
||||
@ -300,7 +288,7 @@ function ppm.handle_unmount(iface)
|
||||
log.error(util.c("PPM: lost device unknown to the PPM mounted to ", iface))
|
||||
end
|
||||
|
||||
_ppm_sys.mounts[iface] = nil
|
||||
ppm_sys.mounts[iface] = nil
|
||||
|
||||
return pm_type, pm_dev
|
||||
end
|
||||
@ -308,23 +296,26 @@ end
|
||||
-- GENERAL ACCESSORS --
|
||||
|
||||
-- list all available peripherals
|
||||
---@nodiscard
|
||||
---@return table names
|
||||
function ppm.list_avail()
|
||||
return peripheral.getNames()
|
||||
end
|
||||
|
||||
-- list mounted peripherals
|
||||
---@nodiscard
|
||||
---@return table mounts
|
||||
function ppm.list_mounts()
|
||||
return _ppm_sys.mounts
|
||||
return ppm_sys.mounts
|
||||
end
|
||||
|
||||
-- get a mounted peripheral side/interface by device table
|
||||
---@nodiscard
|
||||
---@param device table device table
|
||||
---@return string|nil iface CC peripheral interface
|
||||
function ppm.get_iface(device)
|
||||
if device then
|
||||
for side, data in pairs(_ppm_sys.mounts) do
|
||||
for side, data in pairs(ppm_sys.mounts) do
|
||||
if data.dev == device then return side end
|
||||
end
|
||||
end
|
||||
@ -333,30 +324,33 @@ function ppm.get_iface(device)
|
||||
end
|
||||
|
||||
-- get a mounted peripheral by side/interface
|
||||
---@nodiscard
|
||||
---@param iface string CC peripheral interface
|
||||
---@return table|nil device function table
|
||||
function ppm.get_periph(iface)
|
||||
if _ppm_sys.mounts[iface] then
|
||||
return _ppm_sys.mounts[iface].dev
|
||||
if ppm_sys.mounts[iface] then
|
||||
return ppm_sys.mounts[iface].dev
|
||||
else return nil end
|
||||
end
|
||||
|
||||
-- get a mounted peripheral type by side/interface
|
||||
---@nodiscard
|
||||
---@param iface string CC peripheral interface
|
||||
---@return string|nil type
|
||||
function ppm.get_type(iface)
|
||||
if _ppm_sys.mounts[iface] then
|
||||
return _ppm_sys.mounts[iface].type
|
||||
if ppm_sys.mounts[iface] then
|
||||
return ppm_sys.mounts[iface].type
|
||||
else return nil end
|
||||
end
|
||||
|
||||
-- get all mounted peripherals by type
|
||||
---@nodiscard
|
||||
---@param name string type name
|
||||
---@return table devices device function tables
|
||||
function ppm.get_all_devices(name)
|
||||
local devices = {}
|
||||
|
||||
for _, data in pairs(_ppm_sys.mounts) do
|
||||
for _, data in pairs(ppm_sys.mounts) do
|
||||
if data.type == name then
|
||||
table.insert(devices, data.dev)
|
||||
end
|
||||
@ -366,12 +360,13 @@ function ppm.get_all_devices(name)
|
||||
end
|
||||
|
||||
-- get a mounted peripheral by type (if multiple, returns the first)
|
||||
---@nodiscard
|
||||
---@param name string type name
|
||||
---@return table|nil device function table
|
||||
function ppm.get_device(name)
|
||||
local device = nil
|
||||
|
||||
for side, data in pairs(_ppm_sys.mounts) do
|
||||
for _, data in pairs(ppm_sys.mounts) do
|
||||
if data.type == name then
|
||||
device = data.dev
|
||||
break
|
||||
@ -384,20 +379,21 @@ end
|
||||
-- SPECIFIC DEVICE ACCESSORS --
|
||||
|
||||
-- get the fission reactor (if multiple, returns the first)
|
||||
---@nodiscard
|
||||
---@return table|nil reactor function table
|
||||
function ppm.get_fission_reactor()
|
||||
return ppm.get_device("fissionReactorLogicAdapter")
|
||||
end
|
||||
|
||||
-- get the wireless modem (if multiple, returns the first)
|
||||
--
|
||||
-- get the wireless modem (if multiple, returns the first)<br>
|
||||
-- if this is in a CraftOS emulated environment, wired modems will be used instead
|
||||
---@nodiscard
|
||||
---@return table|nil modem function table
|
||||
function ppm.get_wireless_modem()
|
||||
local w_modem = nil
|
||||
local emulated_env = periphemu ~= nil
|
||||
|
||||
for _, device in pairs(_ppm_sys.mounts) do
|
||||
for _, device in pairs(ppm_sys.mounts) do
|
||||
if device.type == "modem" and (emulated_env or device.dev.isWireless()) then
|
||||
w_modem = device.dev
|
||||
break
|
||||
@ -408,11 +404,12 @@ function ppm.get_wireless_modem()
|
||||
end
|
||||
|
||||
-- list all connected monitors
|
||||
---@nodiscard
|
||||
---@return table monitors
|
||||
function ppm.get_monitor_list()
|
||||
local list = {}
|
||||
|
||||
for iface, device in pairs(_ppm_sys.mounts) do
|
||||
for iface, device in pairs(ppm_sys.mounts) do
|
||||
if device.type == "monitor" then
|
||||
list[iface] = device
|
||||
end
|
||||
|
@ -5,6 +5,7 @@
|
||||
local psil = {}
|
||||
|
||||
-- instantiate a new PSI layer
|
||||
---@nodiscard
|
||||
function psil.create()
|
||||
local self = {
|
||||
ic = {}
|
||||
@ -19,8 +20,7 @@ function psil.create()
|
||||
---@class psil
|
||||
local public = {}
|
||||
|
||||
-- subscribe to a data object in the interconnect
|
||||
--
|
||||
-- subscribe to a data object in the interconnect<br>
|
||||
-- will call func() right away if a value is already avaliable
|
||||
---@param key string data key
|
||||
---@param func function function to call on change
|
||||
|
@ -89,6 +89,7 @@ rsio.IO = IO_PORT
|
||||
-----------------------
|
||||
|
||||
-- port to string
|
||||
---@nodiscard
|
||||
---@param port IO_PORT
|
||||
function rsio.to_string(port)
|
||||
local names = {
|
||||
@ -194,6 +195,7 @@ local RS_DIO_MAP = {
|
||||
}
|
||||
|
||||
-- get the mode of a port
|
||||
---@nodiscard
|
||||
---@param port IO_PORT
|
||||
---@return IO_MODE
|
||||
function rsio.get_io_mode(port)
|
||||
@ -239,6 +241,7 @@ end
|
||||
local RS_SIDES = rs.getSides()
|
||||
|
||||
-- check if a port is valid
|
||||
---@nodiscard
|
||||
---@param port IO_PORT
|
||||
---@return boolean valid
|
||||
function rsio.is_valid_port(port)
|
||||
@ -246,6 +249,7 @@ function rsio.is_valid_port(port)
|
||||
end
|
||||
|
||||
-- check if a side is valid
|
||||
---@nodiscard
|
||||
---@param side string
|
||||
---@return boolean valid
|
||||
function rsio.is_valid_side(side)
|
||||
@ -258,6 +262,7 @@ function rsio.is_valid_side(side)
|
||||
end
|
||||
|
||||
-- check if a color is a valid single color
|
||||
---@nodiscard
|
||||
---@param color integer
|
||||
---@return boolean valid
|
||||
function rsio.is_color(color)
|
||||
@ -269,22 +274,25 @@ end
|
||||
-----------------
|
||||
|
||||
-- get digital I/O level reading from a redstone boolean input value
|
||||
---@param rs_value boolean
|
||||
---@nodiscard
|
||||
---@param rs_value boolean raw value from redstone
|
||||
---@return IO_LVL
|
||||
function rsio.digital_read(rs_value)
|
||||
if rs_value then return IO_LVL.HIGH else return IO_LVL.LOW end
|
||||
end
|
||||
|
||||
-- get redstone boolean output value corresponding to a digital I/O level
|
||||
---@param level IO_LVL
|
||||
---@nodiscard
|
||||
---@param level IO_LVL logic level
|
||||
---@return boolean
|
||||
function rsio.digital_write(level)
|
||||
return level == IO_LVL.HIGH
|
||||
end
|
||||
|
||||
-- returns the level corresponding to active
|
||||
---@param port IO_PORT
|
||||
---@param active boolean
|
||||
---@nodiscard
|
||||
---@param port IO_PORT port (to determine active high/low)
|
||||
---@param active boolean state to convert to logic level
|
||||
---@return IO_LVL|false
|
||||
function rsio.digital_write_active(port, active)
|
||||
if (not util.is_int(port)) or (port < IO_PORT.F_ALARM) or (port > IO_PORT.U_EMER_COOL) then
|
||||
@ -295,9 +303,10 @@ function rsio.digital_write_active(port, active)
|
||||
end
|
||||
|
||||
-- returns true if the level corresponds to active
|
||||
---@param port IO_PORT
|
||||
---@param level IO_LVL
|
||||
---@return boolean|nil
|
||||
---@nodiscard
|
||||
---@param port IO_PORT port (to determine active low/high)
|
||||
---@param level IO_LVL logic level
|
||||
---@return boolean|nil state true for active, false for inactive, or nil if invalid port or level provided
|
||||
function rsio.digital_is_active(port, level)
|
||||
if not util.is_int(port) then
|
||||
return nil
|
||||
@ -313,6 +322,7 @@ end
|
||||
----------------
|
||||
|
||||
-- read an analog value scaled from min to max
|
||||
---@nodiscard
|
||||
---@param rs_value number redstone reading (0 to 15)
|
||||
---@param min number minimum of range
|
||||
---@param max number maximum of range
|
||||
@ -323,6 +333,7 @@ function rsio.analog_read(rs_value, min, max)
|
||||
end
|
||||
|
||||
-- write an analog value from the provided scale range
|
||||
---@nodiscard
|
||||
---@param value number value to write (from min to max range)
|
||||
---@param min number minimum of range
|
||||
---@param max number maximum of range
|
||||
|
@ -19,8 +19,6 @@ function tcallbackdsp.dispatch(time, f)
|
||||
duration = time,
|
||||
expiry = time + util.time_s()
|
||||
}
|
||||
|
||||
-- log.debug(util.c("TCD: queued callback for ", f, " [timer: ", timer, "]"))
|
||||
end
|
||||
|
||||
-- request a function to be called after the specified time, aborting any registered instances of that function reference
|
||||
@ -45,8 +43,6 @@ function tcallbackdsp.dispatch_unique(time, f)
|
||||
duration = time,
|
||||
expiry = time + util.time_s()
|
||||
}
|
||||
|
||||
-- log.debug(util.c("TCD: queued callback for ", f, " [timer: ", timer, "]"))
|
||||
end
|
||||
|
||||
-- abort a requested callback
|
||||
@ -72,8 +68,7 @@ function tcallbackdsp.handle(event)
|
||||
end
|
||||
end
|
||||
|
||||
-- identify any overdo callbacks
|
||||
--
|
||||
-- identify any overdo callbacks<br>
|
||||
-- prints to log debug output
|
||||
function tcallbackdsp.diagnostics()
|
||||
for timer, entry in pairs(registry) do
|
||||
|
@ -12,12 +12,14 @@ local types = {}
|
||||
---@field amount integer
|
||||
|
||||
-- create a new tank fluid
|
||||
---@nodiscard
|
||||
---@param n string name
|
||||
---@param a integer amount
|
||||
---@return radiation_reading
|
||||
function types.new_tank_fluid(n, a) return { name = n, amount = a } end
|
||||
|
||||
-- create a new empty tank fluid
|
||||
---@nodiscard
|
||||
---@return tank_fluid
|
||||
function types.new_empty_gas() return { type = "mekanism:empty_gas", amount = 0 } end
|
||||
|
||||
@ -26,12 +28,14 @@ function types.new_empty_gas() return { type = "mekanism:empty_gas", amount = 0
|
||||
---@field unit string
|
||||
|
||||
-- create a new radiation reading
|
||||
---@nodiscard
|
||||
---@param r number radiaiton level
|
||||
---@param u string radiation unit
|
||||
---@return radiation_reading
|
||||
function types.new_radiation_reading(r, u) return { radiation = r, unit = u } end
|
||||
|
||||
-- create a new zeroed radiation reading
|
||||
---@nodiscard
|
||||
---@return radiation_reading
|
||||
function types.new_zero_radiation_reading() return { radiation = 0, unit = "nSv" } end
|
||||
|
||||
@ -41,6 +45,7 @@ function types.new_zero_radiation_reading() return { radiation = 0, unit = "nSv"
|
||||
---@field z integer
|
||||
|
||||
-- create a new coordinate
|
||||
---@nodiscard
|
||||
---@param x integer
|
||||
---@param y integer
|
||||
---@param z integer
|
||||
@ -48,11 +53,12 @@ function types.new_zero_radiation_reading() return { radiation = 0, unit = "nSv"
|
||||
function types.new_coordinate(x, y, z) return { x = x, y = y, z = z } end
|
||||
|
||||
-- create a new zero coordinate
|
||||
---@nodiscard
|
||||
---@return coordinate
|
||||
function types.new_zero_coordinate() return { x = 0, y = 0, z = 0 } end
|
||||
|
||||
---@class rtu_advertisement
|
||||
---@field type integer
|
||||
---@field type RTU_UNIT_TYPES
|
||||
---@field index integer
|
||||
---@field reactor integer
|
||||
---@field rsio table|nil
|
||||
@ -62,15 +68,16 @@ function types.new_zero_coordinate() return { x = 0, y = 0, z = 0 } end
|
||||
---@alias color integer
|
||||
|
||||
-- ENUMERATION TYPES --
|
||||
--#region
|
||||
|
||||
---@alias TRI_FAIL integer
|
||||
---@enum TRI_FAIL
|
||||
types.TRI_FAIL = {
|
||||
OK = 0,
|
||||
PARTIAL = 1,
|
||||
FULL = 2
|
||||
}
|
||||
|
||||
---@alias PROCESS integer
|
||||
---@enum PROCESS
|
||||
types.PROCESS = {
|
||||
INACTIVE = 0,
|
||||
MAX_BURN = 1,
|
||||
@ -93,7 +100,7 @@ types.PROCESS_NAMES = {
|
||||
"GEN_RATE_FAULT_IDLE"
|
||||
}
|
||||
|
||||
---@alias WASTE_MODE integer
|
||||
---@enum WASTE_MODE
|
||||
types.WASTE_MODE = {
|
||||
AUTO = 1,
|
||||
PLUTONIUM = 2,
|
||||
@ -101,7 +108,7 @@ types.WASTE_MODE = {
|
||||
ANTI_MATTER = 4
|
||||
}
|
||||
|
||||
---@alias ALARM integer
|
||||
---@enum ALARM
|
||||
types.ALARM = {
|
||||
ContainmentBreach = 1,
|
||||
ContainmentRadiation = 2,
|
||||
@ -117,7 +124,7 @@ types.ALARM = {
|
||||
TurbineTrip = 12
|
||||
}
|
||||
|
||||
types.alarm_string = {
|
||||
types.ALARM_NAMES = {
|
||||
"ContainmentBreach",
|
||||
"ContainmentRadiation",
|
||||
"ReactorLost",
|
||||
@ -132,7 +139,7 @@ types.alarm_string = {
|
||||
"TurbineTrip"
|
||||
}
|
||||
|
||||
---@alias ALARM_PRIORITY integer
|
||||
---@enum ALARM_PRIORITY
|
||||
types.ALARM_PRIORITY = {
|
||||
CRITICAL = 0,
|
||||
EMERGENCY = 1,
|
||||
@ -140,30 +147,14 @@ types.ALARM_PRIORITY = {
|
||||
TIMELY = 3
|
||||
}
|
||||
|
||||
types.alarm_prio_string = {
|
||||
types.ALARM_PRIORITY_NAMES = {
|
||||
"CRITICAL",
|
||||
"EMERGENCY",
|
||||
"URGENT",
|
||||
"TIMELY"
|
||||
}
|
||||
|
||||
-- map alarms to alarm priority
|
||||
types.ALARM_PRIO_MAP = {
|
||||
types.ALARM_PRIORITY.CRITICAL,
|
||||
types.ALARM_PRIORITY.CRITICAL,
|
||||
types.ALARM_PRIORITY.URGENT,
|
||||
types.ALARM_PRIORITY.CRITICAL,
|
||||
types.ALARM_PRIORITY.EMERGENCY,
|
||||
types.ALARM_PRIORITY.EMERGENCY,
|
||||
types.ALARM_PRIORITY.TIMELY,
|
||||
types.ALARM_PRIORITY.EMERGENCY,
|
||||
types.ALARM_PRIORITY.TIMELY,
|
||||
types.ALARM_PRIORITY.URGENT,
|
||||
types.ALARM_PRIORITY.TIMELY,
|
||||
types.ALARM_PRIORITY.URGENT
|
||||
}
|
||||
|
||||
---@alias ALARM_STATE integer
|
||||
---@enum ALARM_STATE
|
||||
types.ALARM_STATE = {
|
||||
INACTIVE = 0,
|
||||
TRIPPED = 1,
|
||||
@ -171,7 +162,10 @@ types.ALARM_STATE = {
|
||||
RING_BACK = 3
|
||||
}
|
||||
|
||||
--#endregion
|
||||
|
||||
-- STRING TYPES --
|
||||
--#region
|
||||
|
||||
---@alias os_event
|
||||
---| "alarm"
|
||||
@ -206,21 +200,7 @@ types.ALARM_STATE = {
|
||||
---| "websocket_failure"
|
||||
---| "websocket_message"
|
||||
---| "websocket_success"
|
||||
|
||||
---@alias rps_trip_cause
|
||||
---| "ok"
|
||||
---| "dmg_crit"
|
||||
---| "high_temp"
|
||||
---| "no_coolant"
|
||||
---| "full_waste"
|
||||
---| "heated_coolant_backup"
|
||||
---| "no_fuel"
|
||||
---| "fault"
|
||||
---| "timeout"
|
||||
---| "manual"
|
||||
---| "automatic"
|
||||
---| "sys_fail"
|
||||
---| "force_disabled"
|
||||
---| "clock_start" custom, added for reactor PLC
|
||||
|
||||
---@alias fluid
|
||||
---| "mekanism:empty_gas"
|
||||
@ -246,6 +226,21 @@ types.rtu_t = {
|
||||
env_detector = "environment_detector"
|
||||
}
|
||||
|
||||
---@alias rps_trip_cause
|
||||
---| "ok"
|
||||
---| "dmg_crit"
|
||||
---| "high_temp"
|
||||
---| "no_coolant"
|
||||
---| "full_waste"
|
||||
---| "heated_coolant_backup"
|
||||
---| "no_fuel"
|
||||
---| "fault"
|
||||
---| "timeout"
|
||||
---| "manual"
|
||||
---| "automatic"
|
||||
---| "sys_fail"
|
||||
---| "force_disabled"
|
||||
|
||||
---@alias rps_status_t rps_trip_cause
|
||||
types.rps_status_t = {
|
||||
ok = "ok",
|
||||
@ -263,18 +258,24 @@ types.rps_status_t = {
|
||||
force_disabled = "force_disabled"
|
||||
}
|
||||
|
||||
-- turbine steam dumping modes
|
||||
---@alias DUMPING_MODE string
|
||||
---@alias DUMPING_MODE
|
||||
---| "IDLE"
|
||||
---| "DUMPING"
|
||||
---| "DUMPING_EXCESS"
|
||||
|
||||
types.DUMPING_MODE = {
|
||||
IDLE = "IDLE",
|
||||
DUMPING = "DUMPING",
|
||||
DUMPING_EXCESS = "DUMPING_EXCESS"
|
||||
}
|
||||
|
||||
-- MODBUS
|
||||
--#endregion
|
||||
|
||||
-- modbus function codes
|
||||
---@alias MODBUS_FCODE integer
|
||||
-- MODBUS --
|
||||
--#region
|
||||
|
||||
-- MODBUS function codes
|
||||
---@enum MODBUS_FCODE
|
||||
types.MODBUS_FCODE = {
|
||||
READ_COILS = 0x01,
|
||||
READ_DISCRETE_INPUTS = 0x02,
|
||||
@ -287,8 +288,8 @@ types.MODBUS_FCODE = {
|
||||
ERROR_FLAG = 0x80
|
||||
}
|
||||
|
||||
-- modbus exception codes
|
||||
---@alias MODBUS_EXCODE integer
|
||||
-- MODBUS exception codes
|
||||
---@enum MODBUS_EXCODE
|
||||
types.MODBUS_EXCODE = {
|
||||
ILLEGAL_FUNCTION = 0x01,
|
||||
ILLEGAL_DATA_ADDR = 0x02,
|
||||
@ -302,4 +303,6 @@ types.MODBUS_EXCODE = {
|
||||
GATEWAY_TARGET_TIMEOUT = 0x0B
|
||||
}
|
||||
|
||||
--#endregion
|
||||
|
||||
return types
|
||||
|
@ -14,6 +14,7 @@ util.TICK_TIME_MS = 50
|
||||
--#region
|
||||
|
||||
-- trinary operator
|
||||
---@nodiscard
|
||||
---@param cond boolean|nil condition
|
||||
---@param a any return if true
|
||||
---@param b any return if false
|
||||
@ -57,6 +58,7 @@ end
|
||||
--#region
|
||||
|
||||
-- get a value as a string
|
||||
---@nodiscard
|
||||
---@param val any
|
||||
---@return string
|
||||
function util.strval(val)
|
||||
@ -69,6 +71,7 @@ function util.strval(val)
|
||||
end
|
||||
|
||||
-- repeat a string n times
|
||||
---@nodiscard
|
||||
---@param str string
|
||||
---@param n integer
|
||||
---@return string
|
||||
@ -81,6 +84,7 @@ function util.strrep(str, n)
|
||||
end
|
||||
|
||||
-- repeat a space n times
|
||||
---@nodiscard
|
||||
---@param n integer
|
||||
---@return string
|
||||
function util.spaces(n)
|
||||
@ -88,6 +92,7 @@ function util.spaces(n)
|
||||
end
|
||||
|
||||
-- pad text to a minimum width
|
||||
---@nodiscard
|
||||
---@param str string text
|
||||
---@param n integer minimum width
|
||||
---@return string
|
||||
@ -100,6 +105,7 @@ function util.pad(str, n)
|
||||
end
|
||||
|
||||
-- wrap a string into a table of lines, supporting single dash splits
|
||||
---@nodiscard
|
||||
---@param str string
|
||||
---@param limit integer line limit
|
||||
---@return table lines
|
||||
@ -147,13 +153,12 @@ function util.strwrap(str, limit)
|
||||
end
|
||||
|
||||
-- concatenation with built-in to string
|
||||
---@nodiscard
|
||||
---@vararg any
|
||||
---@return string
|
||||
function util.concat(...)
|
||||
local str = ""
|
||||
for _, v in ipairs(arg) do
|
||||
str = str .. util.strval(v)
|
||||
end
|
||||
for _, v in ipairs(arg) do str = str .. util.strval(v) end
|
||||
return str
|
||||
end
|
||||
|
||||
@ -161,15 +166,16 @@ end
|
||||
util.c = util.concat
|
||||
|
||||
-- sprintf implementation
|
||||
---@nodiscard
|
||||
---@param format string
|
||||
---@vararg any
|
||||
function util.sprintf(format, ...)
|
||||
return string.format(format, table.unpack(arg))
|
||||
end
|
||||
|
||||
-- format a number string with commas as the thousands separator
|
||||
--
|
||||
-- format a number string with commas as the thousands separator<br>
|
||||
-- subtracts from spaces at the start if present for each comma used
|
||||
---@nodiscard
|
||||
---@param num string number string
|
||||
---@return string
|
||||
function util.comma_format(num)
|
||||
@ -196,6 +202,7 @@ end
|
||||
--#region
|
||||
|
||||
-- is a value an integer
|
||||
---@nodiscard
|
||||
---@param x any value
|
||||
---@return boolean is_integer if the number is an integer
|
||||
function util.is_int(x)
|
||||
@ -203,6 +210,7 @@ function util.is_int(x)
|
||||
end
|
||||
|
||||
-- get the sign of a number
|
||||
---@nodiscard
|
||||
---@param x number value
|
||||
---@return integer sign (-1 for < 0, 1 otherwise)
|
||||
function util.sign(x)
|
||||
@ -210,12 +218,14 @@ function util.sign(x)
|
||||
end
|
||||
|
||||
-- round a number to an integer
|
||||
---@nodiscard
|
||||
---@return integer rounded
|
||||
function util.round(x)
|
||||
return math.floor(x + 0.5)
|
||||
end
|
||||
|
||||
-- get a new moving average object
|
||||
---@nodiscard
|
||||
---@param length integer history length
|
||||
---@param default number value to fill history with for first call to compute()
|
||||
function util.mov_avg(length, default)
|
||||
@ -249,6 +259,7 @@ function util.mov_avg(length, default)
|
||||
end
|
||||
|
||||
-- compute the moving average
|
||||
---@nodiscard
|
||||
---@return number average
|
||||
function public.compute()
|
||||
local sum = 0
|
||||
@ -264,6 +275,7 @@ end
|
||||
-- TIME --
|
||||
|
||||
-- current time
|
||||
---@nodiscard
|
||||
---@return integer milliseconds
|
||||
function util.time_ms()
|
||||
---@diagnostic disable-next-line: undefined-field
|
||||
@ -271,6 +283,7 @@ function util.time_ms()
|
||||
end
|
||||
|
||||
-- current time
|
||||
---@nodiscard
|
||||
---@return number seconds
|
||||
function util.time_s()
|
||||
---@diagnostic disable-next-line: undefined-field
|
||||
@ -278,10 +291,9 @@ function util.time_s()
|
||||
end
|
||||
|
||||
-- current time
|
||||
---@nodiscard
|
||||
---@return integer milliseconds
|
||||
function util.time()
|
||||
return util.time_ms()
|
||||
end
|
||||
function util.time() return util.time_ms() end
|
||||
|
||||
--#endregion
|
||||
|
||||
@ -289,6 +301,7 @@ end
|
||||
--#region
|
||||
|
||||
-- OS pull event raw wrapper with types
|
||||
---@nodiscard
|
||||
---@param target_event? string event to wait for
|
||||
---@return os_event event, any param1, any param2, any param3, any param4, any param5
|
||||
function util.pull_event(target_event)
|
||||
@ -309,6 +322,7 @@ function util.push_event(event, param1, param2, param3, param4, param5)
|
||||
end
|
||||
|
||||
-- start an OS timer
|
||||
---@nodiscard
|
||||
---@param t number timer duration in seconds
|
||||
---@return integer timer ID
|
||||
function util.start_timer(t)
|
||||
@ -336,14 +350,12 @@ function util.psleep(t)
|
||||
pcall(os.sleep, t)
|
||||
end
|
||||
|
||||
-- no-op to provide a brief pause (1 tick) to yield
|
||||
---
|
||||
-- no-op to provide a brief pause (1 tick) to yield<br>
|
||||
--- EVENT_CONSUMER: this function consumes events
|
||||
function util.nop()
|
||||
util.psleep(0.05)
|
||||
end
|
||||
function util.nop() util.psleep(0.05) end
|
||||
|
||||
-- attempt to maintain a minimum loop timing (duration of execution)
|
||||
---@nodiscard
|
||||
---@param target_timing integer minimum amount of milliseconds to wait for
|
||||
---@param last_update integer millisecond time of last update
|
||||
---@return integer time_now
|
||||
@ -351,9 +363,7 @@ end
|
||||
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
|
||||
if sleep_for >= 50 then util.psleep(sleep_for / 1000.0) end
|
||||
return util.time()
|
||||
end
|
||||
|
||||
@ -362,8 +372,7 @@ end
|
||||
-- TABLE UTILITIES --
|
||||
--#region
|
||||
|
||||
-- delete elements from a table if the passed function returns false when passed a table element
|
||||
--
|
||||
-- delete elements from a table if the passed function returns false when passed a table element<br>
|
||||
-- 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
|
||||
@ -388,6 +397,7 @@ function util.filter_table(t, f, on_delete)
|
||||
end
|
||||
|
||||
-- check if a table contains the provided element
|
||||
---@nodiscard
|
||||
---@param t table table to check
|
||||
---@param element any element to check for
|
||||
function util.table_contains(t, element)
|
||||
@ -404,11 +414,13 @@ end
|
||||
--#region
|
||||
|
||||
-- convert Joules to FE
|
||||
---@nodiscard
|
||||
---@param J number Joules
|
||||
---@return number FE Forge Energy
|
||||
function util.joules_to_fe(J) return (J * 0.4) end
|
||||
|
||||
-- convert FE to Joules
|
||||
---@nodiscard
|
||||
---@param FE number Forge Energy
|
||||
---@return number J Joules
|
||||
function util.fe_to_joules(FE) return (FE * 2.5) end
|
||||
@ -418,10 +430,11 @@ local function MFE(fe) return fe / 1000000.0 end
|
||||
local function GFE(fe) return fe / 1000000000.0 end
|
||||
local function TFE(fe) return fe / 1000000000000.0 end
|
||||
local function PFE(fe) return fe / 1000000000000000.0 end
|
||||
local function EFE(fe) return fe / 1000000000000000000.0 end -- if you accomplish this please touch grass
|
||||
local function ZFE(fe) return fe / 1000000000000000000000.0 end -- please stop
|
||||
local function EFE(fe) return fe / 1000000000000000000.0 end -- if you accomplish this please touch grass
|
||||
local function ZFE(fe) return fe / 1000000000000000000000.0 end -- please stop
|
||||
|
||||
-- format a power value into XXX.XX UNIT format (FE, kFE, MFE, GFE, TFE, PFE, EFE, ZFE)
|
||||
---@nodiscard
|
||||
---@param fe number forge energy value
|
||||
---@param combine_label? boolean if a label should be included in the string itself
|
||||
---@param format? string format override
|
||||
@ -430,9 +443,7 @@ function util.power_format(fe, combine_label, format)
|
||||
local unit
|
||||
local value
|
||||
|
||||
if type(format) ~= "string" then
|
||||
format = "%.2f"
|
||||
end
|
||||
if type(format) ~= "string" then format = "%.2f" end
|
||||
|
||||
if fe < 1000.0 then
|
||||
unit = "FE"
|
||||
@ -474,10 +485,10 @@ end
|
||||
|
||||
-- WATCHDOG --
|
||||
|
||||
-- ComputerCraft OS Timer based Watchdog
|
||||
-- OS timer based watchdog<br>
|
||||
-- triggers a timer event if not fed within 'timeout' seconds
|
||||
---@nodiscard
|
||||
---@param timeout number timeout duration
|
||||
---
|
||||
--- triggers a timer event if not fed within 'timeout' seconds
|
||||
function util.new_watchdog(timeout)
|
||||
local self = {
|
||||
timeout = timeout,
|
||||
@ -487,10 +498,10 @@ function util.new_watchdog(timeout)
|
||||
---@class watchdog
|
||||
local public = {}
|
||||
|
||||
-- check if a timer is this watchdog
|
||||
---@nodiscard
|
||||
---@param timer number timer event timer ID
|
||||
function public.is_timer(timer)
|
||||
return self.wd_timer == timer
|
||||
end
|
||||
function public.is_timer(timer) return self.wd_timer == timer end
|
||||
|
||||
-- satiate the beast
|
||||
function public.feed()
|
||||
@ -512,10 +523,10 @@ end
|
||||
|
||||
-- LOOP CLOCK --
|
||||
|
||||
-- ComputerCraft OS Timer based Loop Clock
|
||||
-- OS timer based loop clock<br>
|
||||
-- fires a timer event at the specified period, does not start at construct time
|
||||
---@nodiscard
|
||||
---@param period number clock period
|
||||
---
|
||||
--- fires a timer event at the specified period, does not start at construct time
|
||||
function util.new_clock(period)
|
||||
local self = {
|
||||
period = period,
|
||||
@ -525,24 +536,22 @@ function util.new_clock(period)
|
||||
---@class clock
|
||||
local public = {}
|
||||
|
||||
-- check if a timer is this clock
|
||||
---@nodiscard
|
||||
---@param timer number timer event timer ID
|
||||
function public.is_clock(timer)
|
||||
return self.timer == timer
|
||||
end
|
||||
function public.is_clock(timer) return self.timer == timer end
|
||||
|
||||
-- start the clock
|
||||
function public.start()
|
||||
self.timer = util.start_timer(self.period)
|
||||
end
|
||||
function public.start() self.timer = util.start_timer(self.period) end
|
||||
|
||||
return public
|
||||
end
|
||||
|
||||
-- FIELD VALIDATOR --
|
||||
|
||||
-- create a new type validator
|
||||
--
|
||||
-- create a new type validator<br>
|
||||
-- can execute sequential checks and check valid() to see if it is still valid
|
||||
---@nodiscard
|
||||
function util.new_validator()
|
||||
local valid = true
|
||||
|
||||
@ -565,6 +574,8 @@ function util.new_validator()
|
||||
|
||||
function public.assert_port(port) valid = valid and type(port) == "number" and port >= 0 and port <= 65535 end
|
||||
|
||||
-- check if all assertions passed successfully
|
||||
---@nodiscard
|
||||
function public.valid() return valid end
|
||||
|
||||
return public
|
||||
|
@ -367,8 +367,8 @@ local function _update_alarm_state(self, tripped, alarm)
|
||||
else
|
||||
alarm.state = AISTATE.TRIPPED
|
||||
self.db.alarm_states[alarm.id] = ALARM_STATE.TRIPPED
|
||||
log.info(util.c("UNIT ", self.r_id, " ALARM ", alarm.id, " (", types.alarm_string[alarm.id], "): TRIPPED [PRIORITY ",
|
||||
types.alarm_prio_string[alarm.tier + 1],"]"))
|
||||
log.info(util.c("UNIT ", self.r_id, " ALARM ", alarm.id, " (", types.ALARM_NAMES[alarm.id], "): TRIPPED [PRIORITY ",
|
||||
types.ALARM_PRIORITY_NAMES[alarm.tier + 1],"]"))
|
||||
end
|
||||
else
|
||||
alarm.trip_time = util.time_ms()
|
||||
@ -381,8 +381,8 @@ local function _update_alarm_state(self, tripped, alarm)
|
||||
if elapsed > (alarm.hold_time * 1000) then
|
||||
alarm.state = AISTATE.TRIPPED
|
||||
self.db.alarm_states[alarm.id] = ALARM_STATE.TRIPPED
|
||||
log.info(util.c("UNIT ", self.r_id, " ALARM ", alarm.id, " (", types.alarm_string[alarm.id], "): TRIPPED [PRIORITY ",
|
||||
types.alarm_prio_string[alarm.tier + 1],"]"))
|
||||
log.info(util.c("UNIT ", self.r_id, " ALARM ", alarm.id, " (", types.ALARM_NAMES[alarm.id], "): TRIPPED [PRIORITY ",
|
||||
types.ALARM_PRIORITY_NAMES[alarm.tier + 1],"]"))
|
||||
end
|
||||
elseif int_state == AISTATE.RING_BACK_TRIPPING then
|
||||
alarm.trip_time = 0
|
||||
@ -432,7 +432,7 @@ local function _update_alarm_state(self, tripped, alarm)
|
||||
-- check for state change
|
||||
if alarm.state ~= int_state then
|
||||
local change_str = util.c(aistate_string[int_state + 1], " -> ", aistate_string[alarm.state + 1])
|
||||
log.debug(util.c("UNIT ", self.r_id, " ALARM ", alarm.id, " (", types.alarm_string[alarm.id], "): ", change_str))
|
||||
log.debug(util.c("UNIT ", self.r_id, " ALARM ", alarm.id, " (", types.ALARM_NAMES[alarm.id], "): ", change_str))
|
||||
end
|
||||
end
|
||||
|
||||
@ -530,8 +530,8 @@ function logic.update_auto_safety(public, self)
|
||||
for _, alarm in pairs(self.alarms) do
|
||||
if alarm.tier <= PRIO.URGENT and (alarm.state == AISTATE.TRIPPED or alarm.state == AISTATE.ACKED) then
|
||||
if not self.auto_was_alarmed then
|
||||
log.info(util.c("UNIT ", self.r_id, " AUTO SCRAM due to ALARM ", alarm.id, " (", types.alarm_string[alarm.id], ") [PRIORITY ",
|
||||
types.alarm_prio_string[alarm.tier + 1],"]"))
|
||||
log.info(util.c("UNIT ", self.r_id, " AUTO SCRAM due to ALARM ", alarm.id, " (", types.ALARM_NAMES[alarm.id], ") [PRIORITY ",
|
||||
types.ALARM_PRIORITY_NAMES[alarm.tier + 1],"]"))
|
||||
end
|
||||
|
||||
alarmed = true
|
||||
|
Loading…
Reference in New Issue
Block a user