mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#118 coordinator code cleanup
This commit is contained in:
parent
79494f0587
commit
4340518ecf
@ -4,13 +4,17 @@ local apisessions = {}
|
|||||||
function apisessions.handle_packet(packet)
|
function apisessions.handle_packet(packet)
|
||||||
end
|
end
|
||||||
|
|
||||||
function apisessions.check_all_watchdogs()
|
-- attempt to identify which session's watchdog timer fired
|
||||||
end
|
---@param timer_event number
|
||||||
|
function apisessions.check_all_watchdogs(timer_event)
|
||||||
function apisessions.close_all()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- delete all closed sessions
|
||||||
function apisessions.free_all_closed()
|
function apisessions.free_all_closed()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- close all open connections
|
||||||
|
function apisessions.close_all()
|
||||||
|
end
|
||||||
|
|
||||||
return apisessions
|
return apisessions
|
||||||
|
@ -25,6 +25,7 @@ local FAC_COMMAND = comms.FAC_COMMAND
|
|||||||
local coordinator = {}
|
local coordinator = {}
|
||||||
|
|
||||||
-- request the user to select a monitor
|
-- request the user to select a monitor
|
||||||
|
---@nodiscard
|
||||||
---@param names table available monitors
|
---@param names table available monitors
|
||||||
---@return boolean|string|nil
|
---@return boolean|string|nil
|
||||||
local function ask_monitor(names)
|
local function ask_monitor(names)
|
||||||
@ -64,9 +65,11 @@ function coordinator.configure_monitors(num_units)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- we need a certain number of monitors (1 per unit + 1 primary display)
|
-- we need a certain number of monitors (1 per unit + 1 primary display)
|
||||||
if #names < num_units + 1 then
|
local num_displays_needed = num_units + 1
|
||||||
println("not enough monitors connected (need " .. num_units + 1 .. ")")
|
if #names < num_displays_needed then
|
||||||
log.warning("insufficient monitors present (need " .. num_units + 1 .. ")")
|
local message = "not enough monitors connected (need " .. num_displays_needed .. ")"
|
||||||
|
println(message)
|
||||||
|
log.warning(message)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -125,7 +128,6 @@ function coordinator.configure_monitors(num_units)
|
|||||||
else
|
else
|
||||||
-- make sure all displays are connected
|
-- make sure all displays are connected
|
||||||
for i = 1, num_units do
|
for i = 1, num_units do
|
||||||
---@diagnostic disable-next-line: need-check-nil
|
|
||||||
local display = unit_displays[i]
|
local display = unit_displays[i]
|
||||||
|
|
||||||
if not util.table_contains(names, display) then
|
if not util.table_contains(names, display) then
|
||||||
@ -183,14 +185,19 @@ function coordinator.log_sys(message) log_dmesg(message, "SYSTEM") end
|
|||||||
function coordinator.log_boot(message) log_dmesg(message, "BOOT") end
|
function coordinator.log_boot(message) log_dmesg(message, "BOOT") end
|
||||||
function coordinator.log_comms(message) log_dmesg(message, "COMMS") end
|
function coordinator.log_comms(message) log_dmesg(message, "COMMS") end
|
||||||
|
|
||||||
|
-- log a message for communications connecting, providing access to progress indication control functions
|
||||||
|
---@nodiscard
|
||||||
---@param message string
|
---@param message string
|
||||||
---@return function update, function done
|
---@return function update, function done
|
||||||
function coordinator.log_comms_connecting(message)
|
function coordinator.log_comms_connecting(message)
|
||||||
---@diagnostic disable-next-line: return-type-mismatch
|
local update, done = log_dmesg(message, "COMMS", true)
|
||||||
return log_dmesg(message, "COMMS", true)
|
---@cast update function
|
||||||
|
---@cast done function
|
||||||
|
return update, done
|
||||||
end
|
end
|
||||||
|
|
||||||
-- coordinator communications
|
-- coordinator communications
|
||||||
|
---@nodiscard
|
||||||
---@param version string coordinator version
|
---@param version string coordinator version
|
||||||
---@param modem table modem device
|
---@param modem table modem device
|
||||||
---@param sv_port integer port of configured supervisor
|
---@param sv_port integer port of configured supervisor
|
||||||
@ -203,23 +210,19 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
sv_linked = false,
|
sv_linked = false,
|
||||||
sv_seq_num = 0,
|
sv_seq_num = 0,
|
||||||
sv_r_seq_num = nil,
|
sv_r_seq_num = nil,
|
||||||
modem = modem,
|
|
||||||
connected = false,
|
connected = false,
|
||||||
last_est_ack = ESTABLISH_ACK.ALLOW
|
last_est_ack = ESTABLISH_ACK.ALLOW
|
||||||
}
|
}
|
||||||
|
|
||||||
---@class coord_comms
|
|
||||||
local public = {}
|
|
||||||
|
|
||||||
comms.set_trusted_range(range)
|
comms.set_trusted_range(range)
|
||||||
|
|
||||||
-- PRIVATE FUNCTIONS --
|
-- PRIVATE FUNCTIONS --
|
||||||
|
|
||||||
-- configure modem channels
|
-- configure modem channels
|
||||||
local function _conf_channels()
|
local function _conf_channels()
|
||||||
self.modem.closeAll()
|
modem.closeAll()
|
||||||
self.modem.open(sv_listen)
|
modem.open(sv_listen)
|
||||||
self.modem.open(api_listen)
|
modem.open(api_listen)
|
||||||
end
|
end
|
||||||
|
|
||||||
_conf_channels()
|
_conf_channels()
|
||||||
@ -242,7 +245,7 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
pkt.make(msg_type, msg)
|
pkt.make(msg_type, msg)
|
||||||
s_pkt.make(self.sv_seq_num, protocol, pkt.raw_sendable())
|
s_pkt.make(self.sv_seq_num, protocol, pkt.raw_sendable())
|
||||||
|
|
||||||
self.modem.transmit(sv_port, sv_listen, s_pkt.raw_sendable())
|
modem.transmit(sv_port, sv_listen, s_pkt.raw_sendable())
|
||||||
self.sv_seq_num = self.sv_seq_num + 1
|
self.sv_seq_num = self.sv_seq_num + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -259,11 +262,13 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
|
|
||||||
-- PUBLIC FUNCTIONS --
|
-- PUBLIC FUNCTIONS --
|
||||||
|
|
||||||
|
---@class coord_comms
|
||||||
|
local public = {}
|
||||||
|
|
||||||
-- reconnect a newly connected modem
|
-- reconnect a newly connected modem
|
||||||
---@param modem table
|
---@param new_modem table
|
||||||
---@diagnostic disable-next-line: redefined-local
|
function public.reconnect_modem(new_modem)
|
||||||
function public.reconnect_modem(modem)
|
modem = new_modem
|
||||||
self.modem = modem
|
|
||||||
_conf_channels()
|
_conf_channels()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -275,6 +280,7 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- attempt to connect to the subervisor
|
-- attempt to connect to the subervisor
|
||||||
|
---@nodiscard
|
||||||
---@param timeout_s number timeout in seconds
|
---@param timeout_s number timeout in seconds
|
||||||
---@param tick_dmesg_waiting function callback to tick dmesg waiting
|
---@param tick_dmesg_waiting function callback to tick dmesg waiting
|
||||||
---@param task_done function callback to show done on dmesg
|
---@param task_done function callback to show done on dmesg
|
||||||
@ -400,7 +406,7 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
|
|
||||||
if l_port == api_listen then
|
if l_port == api_listen then
|
||||||
if protocol == PROTOCOL.COORD_API then
|
if protocol == PROTOCOL.COORD_API then
|
||||||
---@diagnostic disable-next-line: param-type-mismatch
|
---@cast packet capi_frame
|
||||||
apisessions.handle_packet(packet)
|
apisessions.handle_packet(packet)
|
||||||
else
|
else
|
||||||
log.debug("illegal packet type " .. protocol .. " on api listening channel", true)
|
log.debug("illegal packet type " .. protocol .. " on api listening channel", true)
|
||||||
@ -421,6 +427,7 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
|
|
||||||
-- handle packet
|
-- handle packet
|
||||||
if protocol == PROTOCOL.SCADA_CRDN then
|
if protocol == PROTOCOL.SCADA_CRDN then
|
||||||
|
---@cast packet crdn_frame
|
||||||
if self.sv_linked then
|
if self.sv_linked then
|
||||||
if packet.type == SCADA_CRDN_TYPE.INITIAL_BUILDS then
|
if packet.type == SCADA_CRDN_TYPE.INITIAL_BUILDS then
|
||||||
if packet.length == 2 then
|
if packet.length == 2 then
|
||||||
@ -432,7 +439,7 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
-- acknowledge receipt of builds
|
-- acknowledge receipt of builds
|
||||||
_send_sv(PROTOCOL.SCADA_CRDN, SCADA_CRDN_TYPE.INITIAL_BUILDS, {})
|
_send_sv(PROTOCOL.SCADA_CRDN, SCADA_CRDN_TYPE.INITIAL_BUILDS, {})
|
||||||
else
|
else
|
||||||
log.error("received invalid INITIAL_BUILDS packet")
|
log.debug("received invalid INITIAL_BUILDS packet")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.debug("INITIAL_BUILDS packet length mismatch")
|
log.debug("INITIAL_BUILDS packet length mismatch")
|
||||||
@ -444,7 +451,7 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
-- acknowledge receipt of builds
|
-- acknowledge receipt of builds
|
||||||
_send_sv(PROTOCOL.SCADA_CRDN, SCADA_CRDN_TYPE.FAC_BUILDS, {})
|
_send_sv(PROTOCOL.SCADA_CRDN, SCADA_CRDN_TYPE.FAC_BUILDS, {})
|
||||||
else
|
else
|
||||||
log.error("received invalid FAC_BUILDS packet")
|
log.debug("received invalid FAC_BUILDS packet")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.debug("FAC_BUILDS packet length mismatch")
|
log.debug("FAC_BUILDS packet length mismatch")
|
||||||
@ -452,7 +459,7 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
elseif packet.type == SCADA_CRDN_TYPE.FAC_STATUS then
|
elseif packet.type == SCADA_CRDN_TYPE.FAC_STATUS then
|
||||||
-- update facility status
|
-- update facility status
|
||||||
if not iocontrol.update_facility_status(packet.data) then
|
if not iocontrol.update_facility_status(packet.data) then
|
||||||
log.error("received invalid FAC_STATUS packet")
|
log.debug("received invalid FAC_STATUS packet")
|
||||||
end
|
end
|
||||||
elseif packet.type == SCADA_CRDN_TYPE.FAC_CMD then
|
elseif packet.type == SCADA_CRDN_TYPE.FAC_CMD then
|
||||||
-- facility command acknowledgement
|
-- facility command acknowledgement
|
||||||
@ -485,7 +492,7 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
-- acknowledge receipt of builds
|
-- acknowledge receipt of builds
|
||||||
_send_sv(PROTOCOL.SCADA_CRDN, SCADA_CRDN_TYPE.UNIT_BUILDS, {})
|
_send_sv(PROTOCOL.SCADA_CRDN, SCADA_CRDN_TYPE.UNIT_BUILDS, {})
|
||||||
else
|
else
|
||||||
log.error("received invalid UNIT_BUILDS packet")
|
log.debug("received invalid UNIT_BUILDS packet")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.debug("UNIT_BUILDS packet length mismatch")
|
log.debug("UNIT_BUILDS packet length mismatch")
|
||||||
@ -518,7 +525,7 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
elseif cmd == UNIT_COMMAND.ACK_ALL_ALARMS then
|
elseif cmd == UNIT_COMMAND.ACK_ALL_ALARMS then
|
||||||
unit.ack_alarms_ack(ack)
|
unit.ack_alarms_ack(ack)
|
||||||
elseif cmd == UNIT_COMMAND.SET_GROUP then
|
elseif cmd == UNIT_COMMAND.SET_GROUP then
|
||||||
---@todo how is this going to be handled?
|
-- UI will be updated to display current group if changed successfully
|
||||||
else
|
else
|
||||||
log.debug(util.c("received unit command ack with unknown command ", cmd))
|
log.debug(util.c("received unit command ack with unknown command ", cmd))
|
||||||
end
|
end
|
||||||
@ -535,6 +542,7 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
log.debug("discarding SCADA_CRDN packet before linked")
|
log.debug("discarding SCADA_CRDN packet before linked")
|
||||||
end
|
end
|
||||||
elseif protocol == PROTOCOL.SCADA_MGMT then
|
elseif protocol == PROTOCOL.SCADA_MGMT then
|
||||||
|
---@cast packet mgmt_frame
|
||||||
if packet.type == SCADA_MGMT_TYPE.ESTABLISH then
|
if packet.type == SCADA_MGMT_TYPE.ESTABLISH then
|
||||||
-- connection with supervisor established
|
-- connection with supervisor established
|
||||||
if packet.length == 2 then
|
if packet.length == 2 then
|
||||||
@ -562,10 +570,10 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
|
|
||||||
self.sv_linked = true
|
self.sv_linked = true
|
||||||
else
|
else
|
||||||
log.error("invalid supervisor configuration definitions received, establish failed")
|
log.debug("invalid supervisor configuration definitions received, establish failed")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.error("invalid supervisor configuration table received, establish failed")
|
log.debug("invalid supervisor configuration table received, establish failed")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.debug("SCADA_MGMT establish packet reply (len = 2) unsupported")
|
log.debug("SCADA_MGMT establish packet reply (len = 2) unsupported")
|
||||||
@ -577,11 +585,11 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
|
|
||||||
if est_ack == ESTABLISH_ACK.DENY then
|
if est_ack == ESTABLISH_ACK.DENY then
|
||||||
if self.last_est_ack ~= est_ack then
|
if self.last_est_ack ~= est_ack then
|
||||||
log.debug("supervisor connection denied")
|
log.info("supervisor connection denied")
|
||||||
end
|
end
|
||||||
elseif est_ack == ESTABLISH_ACK.COLLISION then
|
elseif est_ack == ESTABLISH_ACK.COLLISION then
|
||||||
if self.last_est_ack ~= est_ack then
|
if self.last_est_ack ~= est_ack then
|
||||||
log.debug("supervisor connection denied due to collision")
|
log.info("supervisor connection denied due to collision")
|
||||||
end
|
end
|
||||||
elseif est_ack == ESTABLISH_ACK.BAD_VERSION then
|
elseif est_ack == ESTABLISH_ACK.BAD_VERSION then
|
||||||
if self.last_est_ack ~= est_ack then
|
if self.last_est_ack ~= est_ack then
|
||||||
@ -619,9 +627,9 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
sv_watchdog.cancel()
|
sv_watchdog.cancel()
|
||||||
self.sv_linked = false
|
self.sv_linked = false
|
||||||
println_ts("server connection closed by remote host")
|
println_ts("server connection closed by remote host")
|
||||||
log.warning("server connection closed by remote host")
|
log.info("server connection closed by remote host")
|
||||||
else
|
else
|
||||||
log.warning("received unknown SCADA_MGMT packet type " .. packet.type)
|
log.debug("received unknown SCADA_MGMT packet type " .. packet.type)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.debug("discarding non-link SCADA_MGMT packet before linked")
|
log.debug("discarding non-link SCADA_MGMT packet before linked")
|
||||||
@ -636,6 +644,7 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- check if the coordinator is still linked to the supervisor
|
-- check if the coordinator is still linked to the supervisor
|
||||||
|
---@nodiscard
|
||||||
function public.is_linked() return self.sv_linked end
|
function public.is_linked() return self.sv_linked end
|
||||||
|
|
||||||
return public
|
return public
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
--
|
||||||
|
-- I/O Control for Supervisor/Coordinator Integration
|
||||||
|
--
|
||||||
|
|
||||||
local log = require("scada-common.log")
|
local log = require("scada-common.log")
|
||||||
local psil = require("scada-common.psil")
|
local psil = require("scada-common.psil")
|
||||||
local types = require("scada-common.types")
|
local types = require("scada-common.types")
|
||||||
@ -16,7 +20,6 @@ local io = {}
|
|||||||
-- initialize the coordinator IO controller
|
-- initialize the coordinator IO controller
|
||||||
---@param conf facility_conf configuration
|
---@param conf facility_conf configuration
|
||||||
---@param comms coord_comms comms reference
|
---@param comms coord_comms comms reference
|
||||||
---@diagnostic disable-next-line: redefined-local
|
|
||||||
function iocontrol.init(conf, comms)
|
function iocontrol.init(conf, comms)
|
||||||
---@class ioctl_facility
|
---@class ioctl_facility
|
||||||
io.facility = {
|
io.facility = {
|
||||||
@ -41,11 +44,11 @@ function iocontrol.init(conf, comms)
|
|||||||
|
|
||||||
radiation = types.new_zero_radiation_reading(),
|
radiation = types.new_zero_radiation_reading(),
|
||||||
|
|
||||||
save_cfg_ack = function (success) end, ---@param success boolean
|
save_cfg_ack = function (success) end, ---@param success boolean
|
||||||
start_ack = function (success) end, ---@param success boolean
|
start_ack = function (success) end, ---@param success boolean
|
||||||
stop_ack = function (success) end, ---@param success boolean
|
stop_ack = function (success) end, ---@param success boolean
|
||||||
scram_ack = function (success) end, ---@param success boolean
|
scram_ack = function (success) end, ---@param success boolean
|
||||||
ack_alarms_ack = function (success) end, ---@param success boolean
|
ack_alarms_ack = function (success) end, ---@param success boolean
|
||||||
|
|
||||||
ps = psil.create(),
|
ps = psil.create(),
|
||||||
|
|
||||||
@ -56,7 +59,7 @@ function iocontrol.init(conf, comms)
|
|||||||
env_d_data = {}
|
env_d_data = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
-- create induction tables (max 1 per unit, preferably 1 total)
|
-- create induction tables (currently only 1 is supported)
|
||||||
for _ = 1, conf.num_units do
|
for _ = 1, conf.num_units do
|
||||||
local data = {} ---@type imatrix_session_db
|
local data = {} ---@type imatrix_session_db
|
||||||
table.insert(io.facility.induction_ps_tbl, psil.create())
|
table.insert(io.facility.induction_ps_tbl, psil.create())
|
||||||
@ -170,6 +173,8 @@ end
|
|||||||
---@param build table
|
---@param build table
|
||||||
---@return boolean valid
|
---@return boolean valid
|
||||||
function iocontrol.record_facility_builds(build)
|
function iocontrol.record_facility_builds(build)
|
||||||
|
local valid = true
|
||||||
|
|
||||||
if type(build) == "table" then
|
if type(build) == "table" then
|
||||||
local fac = io.facility
|
local fac = io.facility
|
||||||
|
|
||||||
@ -187,96 +192,103 @@ function iocontrol.record_facility_builds(build)
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.debug(util.c("iocontrol.record_facility_builds: invalid induction matrix id ", id))
|
log.debug(util.c("iocontrol.record_facility_builds: invalid induction matrix id ", id))
|
||||||
|
valid = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.error("facility builds not a table")
|
log.debug("facility builds not a table")
|
||||||
return false
|
valid = false
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return valid
|
||||||
end
|
end
|
||||||
|
|
||||||
-- populate unit structure builds
|
-- populate unit structure builds
|
||||||
---@param builds table
|
---@param builds table
|
||||||
---@return boolean valid
|
---@return boolean valid
|
||||||
function iocontrol.record_unit_builds(builds)
|
function iocontrol.record_unit_builds(builds)
|
||||||
|
local valid = true
|
||||||
|
|
||||||
-- note: if not all units and RTUs are connected, some will be nil
|
-- note: if not all units and RTUs are connected, some will be nil
|
||||||
for id, build in pairs(builds) do
|
for id, build in pairs(builds) do
|
||||||
local unit = io.units[id] ---@type ioctl_unit
|
local unit = io.units[id] ---@type ioctl_unit
|
||||||
|
|
||||||
|
local log_header = util.c("iocontrol.record_unit_builds[UNIT ", id, "]: ")
|
||||||
|
|
||||||
if type(build) ~= "table" then
|
if type(build) ~= "table" then
|
||||||
log.error(util.c("corrupted unit builds provided, unit ", id, " not a table"))
|
log.debug(log_header .. "build not a table")
|
||||||
return false
|
valid = false
|
||||||
elseif type(unit) ~= "table" then
|
elseif type(unit) ~= "table" then
|
||||||
log.error(util.c("corrupted unit builds provided, invalid unit ", id))
|
log.debug(log_header .. "invalid unit id")
|
||||||
return false
|
valid = false
|
||||||
end
|
else
|
||||||
|
-- reactor build
|
||||||
|
if type(build.reactor) == "table" then
|
||||||
|
unit.reactor_data.mek_struct = build.reactor ---@type mek_struct
|
||||||
|
for key, val in pairs(unit.reactor_data.mek_struct) do
|
||||||
|
unit.unit_ps.publish(key, val)
|
||||||
|
end
|
||||||
|
|
||||||
local log_header = util.c("iocontrol.record_unit_builds[unit ", id, "]: ")
|
if (type(unit.reactor_data.mek_struct.length) == "number") and (unit.reactor_data.mek_struct.length ~= 0) and
|
||||||
|
(type(unit.reactor_data.mek_struct.width) == "number") and (unit.reactor_data.mek_struct.width ~= 0) then
|
||||||
-- reactor build
|
unit.unit_ps.publish("size", { unit.reactor_data.mek_struct.length, unit.reactor_data.mek_struct.width })
|
||||||
if type(build.reactor) == "table" then
|
|
||||||
unit.reactor_data.mek_struct = build.reactor ---@type mek_struct
|
|
||||||
for key, val in pairs(unit.reactor_data.mek_struct) do
|
|
||||||
unit.unit_ps.publish(key, val)
|
|
||||||
end
|
|
||||||
|
|
||||||
if (type(unit.reactor_data.mek_struct.length) == "number") and (unit.reactor_data.mek_struct.length ~= 0) and
|
|
||||||
(type(unit.reactor_data.mek_struct.width) == "number") and (unit.reactor_data.mek_struct.width ~= 0) then
|
|
||||||
unit.unit_ps.publish("size", { unit.reactor_data.mek_struct.length, unit.reactor_data.mek_struct.width })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- boiler builds
|
|
||||||
if type(build.boilers) == "table" then
|
|
||||||
for b_id, boiler in pairs(build.boilers) do
|
|
||||||
if type(unit.boiler_data_tbl[b_id]) == "table" then
|
|
||||||
unit.boiler_data_tbl[b_id].formed = boiler[1] ---@type boolean
|
|
||||||
unit.boiler_data_tbl[b_id].build = boiler[2] ---@type table
|
|
||||||
|
|
||||||
unit.boiler_ps_tbl[b_id].publish("formed", boiler[1])
|
|
||||||
|
|
||||||
for key, val in pairs(unit.boiler_data_tbl[b_id].build) do
|
|
||||||
unit.boiler_ps_tbl[b_id].publish(key, val)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
log.debug(util.c(log_header, "invalid boiler id ", b_id))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
-- turbine builds
|
-- boiler builds
|
||||||
if type(build.turbines) == "table" then
|
if type(build.boilers) == "table" then
|
||||||
for t_id, turbine in pairs(build.turbines) do
|
for b_id, boiler in pairs(build.boilers) do
|
||||||
if type(unit.turbine_data_tbl[t_id]) == "table" then
|
if type(unit.boiler_data_tbl[b_id]) == "table" then
|
||||||
unit.turbine_data_tbl[t_id].formed = turbine[1] ---@type boolean
|
unit.boiler_data_tbl[b_id].formed = boiler[1] ---@type boolean
|
||||||
unit.turbine_data_tbl[t_id].build = turbine[2] ---@type table
|
unit.boiler_data_tbl[b_id].build = boiler[2] ---@type table
|
||||||
|
|
||||||
unit.turbine_ps_tbl[t_id].publish("formed", turbine[1])
|
unit.boiler_ps_tbl[b_id].publish("formed", boiler[1])
|
||||||
|
|
||||||
for key, val in pairs(unit.turbine_data_tbl[t_id].build) do
|
for key, val in pairs(unit.boiler_data_tbl[b_id].build) do
|
||||||
unit.turbine_ps_tbl[t_id].publish(key, val)
|
unit.boiler_ps_tbl[b_id].publish(key, val)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug(util.c(log_header, "invalid boiler id ", b_id))
|
||||||
|
valid = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- turbine builds
|
||||||
|
if type(build.turbines) == "table" then
|
||||||
|
for t_id, turbine in pairs(build.turbines) do
|
||||||
|
if type(unit.turbine_data_tbl[t_id]) == "table" then
|
||||||
|
unit.turbine_data_tbl[t_id].formed = turbine[1] ---@type boolean
|
||||||
|
unit.turbine_data_tbl[t_id].build = turbine[2] ---@type table
|
||||||
|
|
||||||
|
unit.turbine_ps_tbl[t_id].publish("formed", turbine[1])
|
||||||
|
|
||||||
|
for key, val in pairs(unit.turbine_data_tbl[t_id].build) do
|
||||||
|
unit.turbine_ps_tbl[t_id].publish(key, val)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug(util.c(log_header, "invalid turbine id ", t_id))
|
||||||
|
valid = false
|
||||||
end
|
end
|
||||||
else
|
|
||||||
log.debug(util.c(log_header, "invalid turbine id ", t_id))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return valid
|
||||||
end
|
end
|
||||||
|
|
||||||
-- update facility status
|
-- update facility status
|
||||||
---@param status table
|
---@param status table
|
||||||
---@return boolean valid
|
---@return boolean valid
|
||||||
function iocontrol.update_facility_status(status)
|
function iocontrol.update_facility_status(status)
|
||||||
|
local valid = true
|
||||||
local log_header = util.c("iocontrol.update_facility_status: ")
|
local log_header = util.c("iocontrol.update_facility_status: ")
|
||||||
|
|
||||||
if type(status) ~= "table" then
|
if type(status) ~= "table" then
|
||||||
log.debug(log_header .. "status not a table")
|
log.debug(util.c(log_header, "status not a table"))
|
||||||
return false
|
valid = false
|
||||||
else
|
else
|
||||||
local fac = io.facility
|
local fac = io.facility
|
||||||
|
|
||||||
@ -284,10 +296,17 @@ function iocontrol.update_facility_status(status)
|
|||||||
|
|
||||||
local ctl_status = status[1]
|
local ctl_status = status[1]
|
||||||
|
|
||||||
if type(ctl_status) == "table" and (#ctl_status == 14) then
|
if type(ctl_status) == "table" and #ctl_status == 14 then
|
||||||
fac.all_sys_ok = ctl_status[1]
|
fac.all_sys_ok = ctl_status[1]
|
||||||
fac.auto_ready = ctl_status[2]
|
fac.auto_ready = ctl_status[2]
|
||||||
fac.auto_active = ctl_status[3] > 0
|
|
||||||
|
if type(ctl_status[3]) == "number" then
|
||||||
|
fac.auto_active = ctl_status[3] > 1
|
||||||
|
else
|
||||||
|
fac.auto_active = false
|
||||||
|
valid = false
|
||||||
|
end
|
||||||
|
|
||||||
fac.auto_ramping = ctl_status[4]
|
fac.auto_ramping = ctl_status[4]
|
||||||
fac.auto_saturated = ctl_status[5]
|
fac.auto_saturated = ctl_status[5]
|
||||||
|
|
||||||
@ -327,6 +346,7 @@ function iocontrol.update_facility_status(status)
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.debug(log_header .. "control status not a table or length mismatch")
|
log.debug(log_header .. "control status not a table or length mismatch")
|
||||||
|
valid = false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- RTU statuses
|
-- RTU statuses
|
||||||
@ -334,10 +354,10 @@ function iocontrol.update_facility_status(status)
|
|||||||
local rtu_statuses = status[2]
|
local rtu_statuses = status[2]
|
||||||
|
|
||||||
fac.rtu_count = 0
|
fac.rtu_count = 0
|
||||||
|
|
||||||
if type(rtu_statuses) == "table" then
|
if type(rtu_statuses) == "table" then
|
||||||
-- connected RTU count
|
-- connected RTU count
|
||||||
fac.rtu_count = rtu_statuses.count
|
fac.rtu_count = rtu_statuses.count
|
||||||
fac.ps.publish("rtu_count", fac.rtu_count)
|
|
||||||
|
|
||||||
-- power statistics
|
-- power statistics
|
||||||
if type(rtu_statuses.power) == "table" then
|
if type(rtu_statuses.power) == "table" then
|
||||||
@ -346,6 +366,7 @@ function iocontrol.update_facility_status(status)
|
|||||||
fac.induction_ps_tbl[1].publish("avg_outflow", rtu_statuses.power[3])
|
fac.induction_ps_tbl[1].publish("avg_outflow", rtu_statuses.power[3])
|
||||||
else
|
else
|
||||||
log.debug(log_header .. "power statistics list not a table")
|
log.debug(log_header .. "power statistics list not a table")
|
||||||
|
valid = false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- induction matricies statuses
|
-- induction matricies statuses
|
||||||
@ -371,16 +392,16 @@ function iocontrol.update_facility_status(status)
|
|||||||
|
|
||||||
if data.formed then
|
if data.formed then
|
||||||
if rtu_faulted then
|
if rtu_faulted then
|
||||||
fac.induction_ps_tbl[id].publish("computed_status", 3) -- faulted
|
fac.induction_ps_tbl[id].publish("computed_status", 3) -- faulted
|
||||||
elseif data.tanks.energy_fill >= 0.99 then
|
elseif data.tanks.energy_fill >= 0.99 then
|
||||||
fac.induction_ps_tbl[id].publish("computed_status", 6) -- full
|
fac.induction_ps_tbl[id].publish("computed_status", 6) -- full
|
||||||
elseif data.tanks.energy_fill <= 0.01 then
|
elseif data.tanks.energy_fill <= 0.01 then
|
||||||
fac.induction_ps_tbl[id].publish("computed_status", 5) -- empty
|
fac.induction_ps_tbl[id].publish("computed_status", 5) -- empty
|
||||||
else
|
else
|
||||||
fac.induction_ps_tbl[id].publish("computed_status", 4) -- on-line
|
fac.induction_ps_tbl[id].publish("computed_status", 4) -- on-line
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
fac.induction_ps_tbl[id].publish("computed_status", 2) -- not formed
|
fac.induction_ps_tbl[id].publish("computed_status", 2) -- not formed
|
||||||
end
|
end
|
||||||
|
|
||||||
for key, val in pairs(fac.induction_data_tbl[id].state) do
|
for key, val in pairs(fac.induction_data_tbl[id].state) do
|
||||||
@ -396,6 +417,7 @@ function iocontrol.update_facility_status(status)
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.debug(log_header .. "induction matrix list not a table")
|
log.debug(log_header .. "induction matrix list not a table")
|
||||||
|
valid = false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- environment detector status
|
-- environment detector status
|
||||||
@ -413,313 +435,324 @@ function iocontrol.update_facility_status(status)
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.debug(log_header .. "radiation monitor list not a table")
|
log.debug(log_header .. "radiation monitor list not a table")
|
||||||
return false
|
valid = false
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.debug(log_header .. "rtu statuses not a table")
|
log.debug(log_header .. "rtu statuses not a table")
|
||||||
|
valid = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
fac.ps.publish("rtu_count", fac.rtu_count)
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return valid
|
||||||
end
|
end
|
||||||
|
|
||||||
-- update unit statuses
|
-- update unit statuses
|
||||||
---@param statuses table
|
---@param statuses table
|
||||||
---@return boolean valid
|
---@return boolean valid
|
||||||
function iocontrol.update_unit_statuses(statuses)
|
function iocontrol.update_unit_statuses(statuses)
|
||||||
|
local valid = true
|
||||||
|
|
||||||
if type(statuses) ~= "table" then
|
if type(statuses) ~= "table" then
|
||||||
log.debug("iocontrol.update_unit_statuses: unit statuses not a table")
|
log.debug("iocontrol.update_unit_statuses: unit statuses not a table")
|
||||||
return false
|
valid = false
|
||||||
elseif #statuses ~= #io.units then
|
elseif #statuses ~= #io.units then
|
||||||
log.debug("iocontrol.update_unit_statuses: number of provided unit statuses does not match expected number of units")
|
log.debug("iocontrol.update_unit_statuses: number of provided unit statuses does not match expected number of units")
|
||||||
return false
|
valid = false
|
||||||
else
|
else
|
||||||
local burn_rate_sum = 0.0
|
local burn_rate_sum = 0.0
|
||||||
|
|
||||||
-- get all unit statuses
|
-- get all unit statuses
|
||||||
for i = 1, #statuses do
|
for i = 1, #statuses do
|
||||||
local log_header = util.c("iocontrol.update_unit_statuses[unit ", i, "]: ")
|
local log_header = util.c("iocontrol.update_unit_statuses[unit ", i, "]: ")
|
||||||
|
|
||||||
local unit = io.units[i] ---@type ioctl_unit
|
local unit = io.units[i] ---@type ioctl_unit
|
||||||
local status = statuses[i]
|
local status = statuses[i]
|
||||||
|
|
||||||
if type(status) ~= "table" or #status ~= 5 then
|
if type(status) ~= "table" or #status ~= 5 then
|
||||||
log.debug(log_header .. "invalid status entry in unit statuses (not a table or invalid length)")
|
log.debug(log_header .. "invalid status entry in unit statuses (not a table or invalid length)")
|
||||||
return false
|
valid = false
|
||||||
end
|
|
||||||
|
|
||||||
-- reactor PLC status
|
|
||||||
|
|
||||||
local reactor_status = status[1]
|
|
||||||
|
|
||||||
if type(reactor_status) ~= "table" then
|
|
||||||
reactor_status = {}
|
|
||||||
log.debug(log_header .. "reactor status not a table")
|
|
||||||
end
|
|
||||||
|
|
||||||
if #reactor_status == 0 then
|
|
||||||
unit.unit_ps.publish("computed_status", 1) -- disconnected
|
|
||||||
elseif #reactor_status == 3 then
|
|
||||||
local mek_status = reactor_status[1]
|
|
||||||
local rps_status = reactor_status[2]
|
|
||||||
local gen_status = reactor_status[3]
|
|
||||||
|
|
||||||
if #gen_status == 6 then
|
|
||||||
unit.reactor_data.last_status_update = gen_status[1]
|
|
||||||
unit.reactor_data.control_state = gen_status[2]
|
|
||||||
unit.reactor_data.rps_tripped = gen_status[3]
|
|
||||||
unit.reactor_data.rps_trip_cause = gen_status[4]
|
|
||||||
unit.reactor_data.no_reactor = gen_status[5]
|
|
||||||
unit.reactor_data.formed = gen_status[6]
|
|
||||||
else
|
|
||||||
log.debug(log_header .. "reactor general status length mismatch")
|
|
||||||
end
|
|
||||||
|
|
||||||
unit.reactor_data.rps_status = rps_status ---@type rps_status
|
|
||||||
unit.reactor_data.mek_status = mek_status ---@type mek_status
|
|
||||||
|
|
||||||
-- if status hasn't been received, mek_status = {}
|
|
||||||
if type(unit.reactor_data.mek_status.act_burn_rate) == "number" then
|
|
||||||
burn_rate_sum = burn_rate_sum + unit.reactor_data.mek_status.act_burn_rate
|
|
||||||
end
|
|
||||||
|
|
||||||
if unit.reactor_data.mek_status.status then
|
|
||||||
unit.unit_ps.publish("computed_status", 5) -- running
|
|
||||||
else
|
|
||||||
if unit.reactor_data.no_reactor then
|
|
||||||
unit.unit_ps.publish("computed_status", 3) -- faulted
|
|
||||||
elseif not unit.reactor_data.formed then
|
|
||||||
unit.unit_ps.publish("computed_status", 2) -- multiblock not formed
|
|
||||||
elseif unit.reactor_data.rps_status.force_dis then
|
|
||||||
unit.unit_ps.publish("computed_status", 7) -- reactor force disabled
|
|
||||||
elseif unit.reactor_data.rps_tripped and unit.reactor_data.rps_trip_cause ~= "manual" then
|
|
||||||
unit.unit_ps.publish("computed_status", 6) -- SCRAM
|
|
||||||
else
|
|
||||||
unit.unit_ps.publish("computed_status", 4) -- disabled
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for key, val in pairs(unit.reactor_data) do
|
|
||||||
if key ~= "rps_status" and key ~= "mek_struct" and key ~= "mek_status" then
|
|
||||||
unit.unit_ps.publish(key, val)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if type(unit.reactor_data.rps_status) == "table" then
|
|
||||||
for key, val in pairs(unit.reactor_data.rps_status) do
|
|
||||||
unit.unit_ps.publish(key, val)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if type(unit.reactor_data.mek_status) == "table" then
|
|
||||||
for key, val in pairs(unit.reactor_data.mek_status) do
|
|
||||||
unit.unit_ps.publish(key, val)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
log.debug(log_header .. "reactor status length mismatch")
|
-- reactor PLC status
|
||||||
end
|
local reactor_status = status[1]
|
||||||
|
|
||||||
-- RTU statuses
|
if type(reactor_status) ~= "table" then
|
||||||
|
reactor_status = {}
|
||||||
|
log.debug(log_header .. "reactor status not a table")
|
||||||
|
end
|
||||||
|
|
||||||
local rtu_statuses = status[2]
|
if #reactor_status == 0 then
|
||||||
|
unit.unit_ps.publish("computed_status", 1) -- disconnected
|
||||||
|
elseif #reactor_status == 3 then
|
||||||
|
local mek_status = reactor_status[1]
|
||||||
|
local rps_status = reactor_status[2]
|
||||||
|
local gen_status = reactor_status[3]
|
||||||
|
|
||||||
if type(rtu_statuses) == "table" then
|
if #gen_status == 6 then
|
||||||
-- boiler statuses
|
unit.reactor_data.last_status_update = gen_status[1]
|
||||||
if type(rtu_statuses.boilers) == "table" then
|
unit.reactor_data.control_state = gen_status[2]
|
||||||
for id = 1, #unit.boiler_ps_tbl do
|
unit.reactor_data.rps_tripped = gen_status[3]
|
||||||
if rtu_statuses.boilers[i] == nil then
|
unit.reactor_data.rps_trip_cause = gen_status[4]
|
||||||
-- disconnected
|
unit.reactor_data.no_reactor = gen_status[5]
|
||||||
unit.boiler_ps_tbl[id].publish("computed_status", 1)
|
unit.reactor_data.formed = gen_status[6]
|
||||||
|
else
|
||||||
|
log.debug(log_header .. "reactor general status length mismatch")
|
||||||
|
end
|
||||||
|
|
||||||
|
unit.reactor_data.rps_status = rps_status ---@type rps_status
|
||||||
|
unit.reactor_data.mek_status = mek_status ---@type mek_status
|
||||||
|
|
||||||
|
-- if status hasn't been received, mek_status = {}
|
||||||
|
if type(unit.reactor_data.mek_status.act_burn_rate) == "number" then
|
||||||
|
burn_rate_sum = burn_rate_sum + unit.reactor_data.mek_status.act_burn_rate
|
||||||
|
end
|
||||||
|
|
||||||
|
if unit.reactor_data.mek_status.status then
|
||||||
|
unit.unit_ps.publish("computed_status", 5) -- running
|
||||||
|
else
|
||||||
|
if unit.reactor_data.no_reactor then
|
||||||
|
unit.unit_ps.publish("computed_status", 3) -- faulted
|
||||||
|
elseif not unit.reactor_data.formed then
|
||||||
|
unit.unit_ps.publish("computed_status", 2) -- multiblock not formed
|
||||||
|
elseif unit.reactor_data.rps_status.force_dis then
|
||||||
|
unit.unit_ps.publish("computed_status", 7) -- reactor force disabled
|
||||||
|
elseif unit.reactor_data.rps_tripped and unit.reactor_data.rps_trip_cause ~= "manual" then
|
||||||
|
unit.unit_ps.publish("computed_status", 6) -- SCRAM
|
||||||
|
else
|
||||||
|
unit.unit_ps.publish("computed_status", 4) -- disabled
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for id, boiler in pairs(rtu_statuses.boilers) do
|
for key, val in pairs(unit.reactor_data) do
|
||||||
if type(unit.boiler_data_tbl[id]) == "table" then
|
if key ~= "rps_status" and key ~= "mek_struct" and key ~= "mek_status" then
|
||||||
local rtu_faulted = boiler[1] ---@type boolean
|
unit.unit_ps.publish(key, val)
|
||||||
unit.boiler_data_tbl[id].formed = boiler[2] ---@type boolean
|
end
|
||||||
unit.boiler_data_tbl[id].state = boiler[3] ---@type table
|
end
|
||||||
unit.boiler_data_tbl[id].tanks = boiler[4] ---@type table
|
|
||||||
|
|
||||||
local data = unit.boiler_data_tbl[id] ---@type boilerv_session_db
|
if type(unit.reactor_data.rps_status) == "table" then
|
||||||
|
for key, val in pairs(unit.reactor_data.rps_status) do
|
||||||
|
unit.unit_ps.publish(key, val)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
unit.boiler_ps_tbl[id].publish("formed", data.formed)
|
if type(unit.reactor_data.mek_status) == "table" then
|
||||||
unit.boiler_ps_tbl[id].publish("faulted", rtu_faulted)
|
for key, val in pairs(unit.reactor_data.mek_status) do
|
||||||
|
unit.unit_ps.publish(key, val)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug(log_header .. "reactor status length mismatch")
|
||||||
|
valid = false
|
||||||
|
end
|
||||||
|
|
||||||
if rtu_faulted then
|
-- RTU statuses
|
||||||
unit.boiler_ps_tbl[id].publish("computed_status", 3) -- faulted
|
local rtu_statuses = status[2]
|
||||||
elseif data.formed then
|
|
||||||
if data.state.boil_rate > 0 then
|
if type(rtu_statuses) == "table" then
|
||||||
unit.boiler_ps_tbl[id].publish("computed_status", 5) -- active
|
-- boiler statuses
|
||||||
|
if type(rtu_statuses.boilers) == "table" then
|
||||||
|
for id = 1, #unit.boiler_ps_tbl do
|
||||||
|
if rtu_statuses.boilers[i] == nil then
|
||||||
|
-- disconnected
|
||||||
|
unit.boiler_ps_tbl[id].publish("computed_status", 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for id, boiler in pairs(rtu_statuses.boilers) do
|
||||||
|
if type(unit.boiler_data_tbl[id]) == "table" then
|
||||||
|
local rtu_faulted = boiler[1] ---@type boolean
|
||||||
|
unit.boiler_data_tbl[id].formed = boiler[2] ---@type boolean
|
||||||
|
unit.boiler_data_tbl[id].state = boiler[3] ---@type table
|
||||||
|
unit.boiler_data_tbl[id].tanks = boiler[4] ---@type table
|
||||||
|
|
||||||
|
local data = unit.boiler_data_tbl[id] ---@type boilerv_session_db
|
||||||
|
|
||||||
|
unit.boiler_ps_tbl[id].publish("formed", data.formed)
|
||||||
|
unit.boiler_ps_tbl[id].publish("faulted", rtu_faulted)
|
||||||
|
|
||||||
|
if rtu_faulted then
|
||||||
|
unit.boiler_ps_tbl[id].publish("computed_status", 3) -- faulted
|
||||||
|
elseif data.formed then
|
||||||
|
if data.state.boil_rate > 0 then
|
||||||
|
unit.boiler_ps_tbl[id].publish("computed_status", 5) -- active
|
||||||
|
else
|
||||||
|
unit.boiler_ps_tbl[id].publish("computed_status", 4) -- idle
|
||||||
|
end
|
||||||
else
|
else
|
||||||
unit.boiler_ps_tbl[id].publish("computed_status", 4) -- idle
|
unit.boiler_ps_tbl[id].publish("computed_status", 2) -- not formed
|
||||||
|
end
|
||||||
|
|
||||||
|
for key, val in pairs(unit.boiler_data_tbl[id].state) do
|
||||||
|
unit.boiler_ps_tbl[id].publish(key, val)
|
||||||
|
end
|
||||||
|
|
||||||
|
for key, val in pairs(unit.boiler_data_tbl[id].tanks) do
|
||||||
|
unit.boiler_ps_tbl[id].publish(key, val)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
unit.boiler_ps_tbl[id].publish("computed_status", 2) -- not formed
|
log.debug(util.c(log_header, "invalid boiler id ", id))
|
||||||
|
valid = false
|
||||||
end
|
end
|
||||||
|
|
||||||
for key, val in pairs(unit.boiler_data_tbl[id].state) do
|
|
||||||
unit.boiler_ps_tbl[id].publish(key, val)
|
|
||||||
end
|
|
||||||
|
|
||||||
for key, val in pairs(unit.boiler_data_tbl[id].tanks) do
|
|
||||||
unit.boiler_ps_tbl[id].publish(key, val)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
log.debug(util.c(log_header, "invalid boiler id ", id))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
log.debug(log_header .. "boiler list not a table")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- turbine statuses
|
|
||||||
if type(rtu_statuses.turbines) == "table" then
|
|
||||||
for id = 1, #unit.turbine_ps_tbl do
|
|
||||||
if rtu_statuses.turbines[i] == nil then
|
|
||||||
-- disconnected
|
|
||||||
unit.turbine_ps_tbl[id].publish("computed_status", 1)
|
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
log.debug(log_header .. "boiler list not a table")
|
||||||
|
valid = false
|
||||||
end
|
end
|
||||||
|
|
||||||
for id, turbine in pairs(rtu_statuses.turbines) do
|
-- turbine statuses
|
||||||
if type(unit.turbine_data_tbl[id]) == "table" then
|
if type(rtu_statuses.turbines) == "table" then
|
||||||
local rtu_faulted = turbine[1] ---@type boolean
|
for id = 1, #unit.turbine_ps_tbl do
|
||||||
unit.turbine_data_tbl[id].formed = turbine[2] ---@type boolean
|
if rtu_statuses.turbines[i] == nil then
|
||||||
unit.turbine_data_tbl[id].state = turbine[3] ---@type table
|
-- disconnected
|
||||||
unit.turbine_data_tbl[id].tanks = turbine[4] ---@type table
|
unit.turbine_ps_tbl[id].publish("computed_status", 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local data = unit.turbine_data_tbl[id] ---@type turbinev_session_db
|
for id, turbine in pairs(rtu_statuses.turbines) do
|
||||||
|
if type(unit.turbine_data_tbl[id]) == "table" then
|
||||||
|
local rtu_faulted = turbine[1] ---@type boolean
|
||||||
|
unit.turbine_data_tbl[id].formed = turbine[2] ---@type boolean
|
||||||
|
unit.turbine_data_tbl[id].state = turbine[3] ---@type table
|
||||||
|
unit.turbine_data_tbl[id].tanks = turbine[4] ---@type table
|
||||||
|
|
||||||
unit.turbine_ps_tbl[id].publish("formed", data.formed)
|
local data = unit.turbine_data_tbl[id] ---@type turbinev_session_db
|
||||||
unit.turbine_ps_tbl[id].publish("faulted", rtu_faulted)
|
|
||||||
|
|
||||||
if rtu_faulted then
|
unit.turbine_ps_tbl[id].publish("formed", data.formed)
|
||||||
unit.turbine_ps_tbl[id].publish("computed_status", 3) -- faulted
|
unit.turbine_ps_tbl[id].publish("faulted", rtu_faulted)
|
||||||
elseif data.formed then
|
|
||||||
if data.tanks.energy_fill >= 0.99 then
|
if rtu_faulted then
|
||||||
unit.turbine_ps_tbl[id].publish("computed_status", 6) -- trip
|
unit.turbine_ps_tbl[id].publish("computed_status", 3) -- faulted
|
||||||
elseif data.state.flow_rate < 100 then
|
elseif data.formed then
|
||||||
unit.turbine_ps_tbl[id].publish("computed_status", 4) -- idle
|
if data.tanks.energy_fill >= 0.99 then
|
||||||
|
unit.turbine_ps_tbl[id].publish("computed_status", 6) -- trip
|
||||||
|
elseif data.state.flow_rate < 100 then
|
||||||
|
unit.turbine_ps_tbl[id].publish("computed_status", 4) -- idle
|
||||||
|
else
|
||||||
|
unit.turbine_ps_tbl[id].publish("computed_status", 5) -- active
|
||||||
|
end
|
||||||
else
|
else
|
||||||
unit.turbine_ps_tbl[id].publish("computed_status", 5) -- active
|
unit.turbine_ps_tbl[id].publish("computed_status", 2) -- not formed
|
||||||
|
end
|
||||||
|
|
||||||
|
for key, val in pairs(unit.turbine_data_tbl[id].state) do
|
||||||
|
unit.turbine_ps_tbl[id].publish(key, val)
|
||||||
|
end
|
||||||
|
|
||||||
|
for key, val in pairs(unit.turbine_data_tbl[id].tanks) do
|
||||||
|
unit.turbine_ps_tbl[id].publish(key, val)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
unit.turbine_ps_tbl[id].publish("computed_status", 2) -- not formed
|
log.debug(util.c(log_header, "invalid turbine id ", id))
|
||||||
|
valid = false
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug(log_header .. "turbine list not a table")
|
||||||
|
valid = false
|
||||||
|
end
|
||||||
|
|
||||||
for key, val in pairs(unit.turbine_data_tbl[id].state) do
|
-- environment detector status
|
||||||
unit.turbine_ps_tbl[id].publish(key, val)
|
if type(rtu_statuses.rad_mon) == "table" then
|
||||||
end
|
if #rtu_statuses.rad_mon > 0 then
|
||||||
|
local rad_mon = rtu_statuses.rad_mon[1]
|
||||||
|
local rtu_faulted = rad_mon[1] ---@type boolean
|
||||||
|
unit.radiation = rad_mon[2] ---@type number
|
||||||
|
|
||||||
for key, val in pairs(unit.turbine_data_tbl[id].tanks) do
|
unit.unit_ps.publish("radiation", unit.radiation)
|
||||||
unit.turbine_ps_tbl[id].publish(key, val)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
log.debug(util.c(log_header, "invalid turbine id ", id))
|
unit.radiation = types.new_zero_radiation_reading()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug(log_header .. "radiation monitor list not a table")
|
||||||
|
valid = false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.debug(log_header .. "rtu list not a table")
|
||||||
|
valid = false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- annunciator
|
||||||
|
unit.annunciator = status[3]
|
||||||
|
|
||||||
|
if type(unit.annunciator) ~= "table" then
|
||||||
|
unit.annunciator = {}
|
||||||
|
log.debug(log_header .. "annunciator state not a table")
|
||||||
|
valid = false
|
||||||
|
end
|
||||||
|
|
||||||
|
for key, val in pairs(unit.annunciator) do
|
||||||
|
if key == "TurbineTrip" then
|
||||||
|
-- split up turbine trip table for all turbines and a general OR combination
|
||||||
|
local trips = val
|
||||||
|
local any = false
|
||||||
|
|
||||||
|
for id = 1, #trips do
|
||||||
|
any = any or trips[id]
|
||||||
|
unit.turbine_ps_tbl[id].publish(key, trips[id])
|
||||||
|
end
|
||||||
|
|
||||||
|
unit.unit_ps.publish("TurbineTrip", any)
|
||||||
|
elseif key == "BoilerOnline" or key == "HeatingRateLow" or key == "WaterLevelLow" then
|
||||||
|
-- split up array for all boilers
|
||||||
|
for id = 1, #val do
|
||||||
|
unit.boiler_ps_tbl[id].publish(key, val[id])
|
||||||
|
end
|
||||||
|
elseif key == "TurbineOnline" or key == "SteamDumpOpen" or key == "TurbineOverSpeed" then
|
||||||
|
-- split up array for all turbines
|
||||||
|
for id = 1, #val do
|
||||||
|
unit.turbine_ps_tbl[id].publish(key, val[id])
|
||||||
|
end
|
||||||
|
elseif type(val) == "table" then
|
||||||
|
-- we missed one of the tables?
|
||||||
|
log.debug(log_header .. "unrecognized table found in annunciator list, this is a bug")
|
||||||
|
valid = false
|
||||||
|
else
|
||||||
|
-- non-table fields
|
||||||
|
unit.unit_ps.publish(key, val)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- alarms
|
||||||
|
local alarm_states = status[4]
|
||||||
|
|
||||||
|
if type(alarm_states) == "table" then
|
||||||
|
for id = 1, #alarm_states do
|
||||||
|
local state = alarm_states[id]
|
||||||
|
|
||||||
|
unit.alarms[id] = state
|
||||||
|
|
||||||
|
if state == types.ALARM_STATE.TRIPPED or state == types.ALARM_STATE.ACKED then
|
||||||
|
unit.unit_ps.publish("Alarm_" .. id, 2)
|
||||||
|
elseif state == types.ALARM_STATE.RING_BACK then
|
||||||
|
unit.unit_ps.publish("Alarm_" .. id, 3)
|
||||||
|
else
|
||||||
|
unit.unit_ps.publish("Alarm_" .. id, 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.debug(log_header .. "turbine list not a table")
|
log.debug(log_header .. "alarm states not a table")
|
||||||
return false
|
valid = false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- environment detector status
|
-- unit state fields
|
||||||
if type(rtu_statuses.rad_mon) == "table" then
|
local unit_state = status[5]
|
||||||
if #rtu_statuses.rad_mon > 0 then
|
|
||||||
local rad_mon = rtu_statuses.rad_mon[1]
|
|
||||||
local rtu_faulted = rad_mon[1] ---@type boolean
|
|
||||||
unit.radiation = rad_mon[2] ---@type number
|
|
||||||
|
|
||||||
unit.unit_ps.publish("radiation", unit.radiation)
|
if type(unit_state) == "table" then
|
||||||
|
if #unit_state == 5 then
|
||||||
|
unit.unit_ps.publish("U_StatusLine1", unit_state[1])
|
||||||
|
unit.unit_ps.publish("U_StatusLine2", unit_state[2])
|
||||||
|
unit.unit_ps.publish("U_WasteMode", unit_state[3])
|
||||||
|
unit.unit_ps.publish("U_AutoReady", unit_state[4])
|
||||||
|
unit.unit_ps.publish("U_AutoDegraded", unit_state[5])
|
||||||
else
|
else
|
||||||
unit.radiation = types.new_zero_radiation_reading()
|
log.debug(log_header .. "unit state length mismatch")
|
||||||
|
valid = false
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
log.debug(log_header .. "radiation monitor list not a table")
|
log.debug(log_header .. "unit state not a table")
|
||||||
return false
|
valid = false
|
||||||
end
|
end
|
||||||
else
|
|
||||||
log.debug(log_header .. "rtu list not a table")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- annunciator
|
|
||||||
|
|
||||||
unit.annunciator = status[3]
|
|
||||||
|
|
||||||
if type(unit.annunciator) ~= "table" then
|
|
||||||
unit.annunciator = {}
|
|
||||||
log.debug(log_header .. "annunciator state not a table")
|
|
||||||
end
|
|
||||||
|
|
||||||
for key, val in pairs(unit.annunciator) do
|
|
||||||
if key == "TurbineTrip" then
|
|
||||||
-- split up turbine trip table for all turbines and a general OR combination
|
|
||||||
local trips = val
|
|
||||||
local any = false
|
|
||||||
|
|
||||||
for id = 1, #trips do
|
|
||||||
any = any or trips[id]
|
|
||||||
unit.turbine_ps_tbl[id].publish(key, trips[id])
|
|
||||||
end
|
|
||||||
|
|
||||||
unit.unit_ps.publish("TurbineTrip", any)
|
|
||||||
elseif key == "BoilerOnline" or key == "HeatingRateLow" or key == "WaterLevelLow" then
|
|
||||||
-- split up array for all boilers
|
|
||||||
for id = 1, #val do
|
|
||||||
unit.boiler_ps_tbl[id].publish(key, val[id])
|
|
||||||
end
|
|
||||||
elseif key == "TurbineOnline" or key == "SteamDumpOpen" or key == "TurbineOverSpeed" then
|
|
||||||
-- split up array for all turbines
|
|
||||||
for id = 1, #val do
|
|
||||||
unit.turbine_ps_tbl[id].publish(key, val[id])
|
|
||||||
end
|
|
||||||
elseif type(val) == "table" then
|
|
||||||
-- we missed one of the tables?
|
|
||||||
log.error(log_header .. "unrecognized table found in annunciator list, this is a bug", true)
|
|
||||||
else
|
|
||||||
-- non-table fields
|
|
||||||
unit.unit_ps.publish(key, val)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- alarms
|
|
||||||
|
|
||||||
local alarm_states = status[4]
|
|
||||||
|
|
||||||
if type(alarm_states) == "table" then
|
|
||||||
for id = 1, #alarm_states do
|
|
||||||
local state = alarm_states[id]
|
|
||||||
|
|
||||||
unit.alarms[id] = state
|
|
||||||
|
|
||||||
if state == types.ALARM_STATE.TRIPPED or state == types.ALARM_STATE.ACKED then
|
|
||||||
unit.unit_ps.publish("Alarm_" .. id, 2)
|
|
||||||
elseif state == types.ALARM_STATE.RING_BACK then
|
|
||||||
unit.unit_ps.publish("Alarm_" .. id, 3)
|
|
||||||
else
|
|
||||||
unit.unit_ps.publish("Alarm_" .. id, 1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
log.debug(log_header .. "alarm states not a table")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- unit state fields
|
|
||||||
|
|
||||||
local unit_state = status[5]
|
|
||||||
|
|
||||||
if type(unit_state) == "table" then
|
|
||||||
if #unit_state == 5 then
|
|
||||||
unit.unit_ps.publish("U_StatusLine1", unit_state[1])
|
|
||||||
unit.unit_ps.publish("U_StatusLine2", unit_state[2])
|
|
||||||
unit.unit_ps.publish("U_WasteMode", unit_state[3])
|
|
||||||
unit.unit_ps.publish("U_AutoReady", unit_state[4])
|
|
||||||
unit.unit_ps.publish("U_AutoDegraded", unit_state[5])
|
|
||||||
else
|
|
||||||
log.debug(log_header .. "unit state length mismatch")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
log.debug(log_header .. "unit state not a table")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -729,7 +762,7 @@ function iocontrol.update_unit_statuses(statuses)
|
|||||||
sounder.eval(io.units)
|
sounder.eval(io.units)
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return valid
|
||||||
end
|
end
|
||||||
|
|
||||||
-- get the IO controller database
|
-- get the IO controller database
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
--
|
||||||
|
-- Process Control Management
|
||||||
|
--
|
||||||
|
|
||||||
local comms = require("scada-common.comms")
|
local comms = require("scada-common.comms")
|
||||||
local log = require("scada-common.log")
|
local log = require("scada-common.log")
|
||||||
@ -30,11 +33,11 @@ local self = {
|
|||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
-- initialize the process controller
|
-- initialize the process controller
|
||||||
---@param iocontrol ioctl
|
---@param iocontrol ioctl iocontrl system
|
||||||
---@diagnostic disable-next-line: redefined-local
|
---@param coord_comms coord_comms coordinator communications
|
||||||
function process.init(iocontrol, comms)
|
function process.init(iocontrol, coord_comms)
|
||||||
self.io = iocontrol
|
self.io = iocontrol
|
||||||
self.comms = comms
|
self.comms = coord_comms
|
||||||
|
|
||||||
for i = 1, self.io.facility.num_units do
|
for i = 1, self.io.facility.num_units do
|
||||||
self.config.limits[i] = 0.1
|
self.config.limits[i] = 0.1
|
||||||
@ -91,13 +94,13 @@ end
|
|||||||
-- facility SCRAM command
|
-- facility SCRAM command
|
||||||
function process.fac_scram()
|
function process.fac_scram()
|
||||||
self.comms.send_fac_command(FAC_COMMAND.SCRAM_ALL)
|
self.comms.send_fac_command(FAC_COMMAND.SCRAM_ALL)
|
||||||
log.debug("FAC: SCRAM ALL")
|
log.debug("PROCESS: FAC SCRAM ALL")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- facility alarm acknowledge command
|
-- facility alarm acknowledge command
|
||||||
function process.fac_ack_alarms()
|
function process.fac_ack_alarms()
|
||||||
self.comms.send_fac_command(FAC_COMMAND.ACK_ALL_ALARMS)
|
self.comms.send_fac_command(FAC_COMMAND.ACK_ALL_ALARMS)
|
||||||
log.debug("FAC: ACK ALL ALARMS")
|
log.debug("PROCESS: FAC ACK ALL ALARMS")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- start reactor
|
-- start reactor
|
||||||
@ -105,7 +108,7 @@ end
|
|||||||
function process.start(id)
|
function process.start(id)
|
||||||
self.io.units[id].control_state = true
|
self.io.units[id].control_state = true
|
||||||
self.comms.send_unit_command(UNIT_COMMAND.START, id)
|
self.comms.send_unit_command(UNIT_COMMAND.START, id)
|
||||||
log.debug(util.c("UNIT[", id, "]: START"))
|
log.debug(util.c("PROCESS: UNIT[", id, "] START"))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- SCRAM reactor
|
-- SCRAM reactor
|
||||||
@ -113,14 +116,14 @@ end
|
|||||||
function process.scram(id)
|
function process.scram(id)
|
||||||
self.io.units[id].control_state = false
|
self.io.units[id].control_state = false
|
||||||
self.comms.send_unit_command(UNIT_COMMAND.SCRAM, id)
|
self.comms.send_unit_command(UNIT_COMMAND.SCRAM, id)
|
||||||
log.debug(util.c("UNIT[", id, "]: SCRAM"))
|
log.debug(util.c("PROCESS: UNIT[", id, "] SCRAM"))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- reset reactor protection system
|
-- reset reactor protection system
|
||||||
---@param id integer unit ID
|
---@param id integer unit ID
|
||||||
function process.reset_rps(id)
|
function process.reset_rps(id)
|
||||||
self.comms.send_unit_command(UNIT_COMMAND.RESET_RPS, id)
|
self.comms.send_unit_command(UNIT_COMMAND.RESET_RPS, id)
|
||||||
log.debug(util.c("UNIT[", id, "]: RESET RPS"))
|
log.debug(util.c("PROCESS: UNIT[", id, "] RESET RPS"))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- set burn rate
|
-- set burn rate
|
||||||
@ -128,7 +131,7 @@ end
|
|||||||
---@param rate number burn rate
|
---@param rate number burn rate
|
||||||
function process.set_rate(id, rate)
|
function process.set_rate(id, rate)
|
||||||
self.comms.send_unit_command(UNIT_COMMAND.SET_BURN, id, rate)
|
self.comms.send_unit_command(UNIT_COMMAND.SET_BURN, id, rate)
|
||||||
log.debug(util.c("UNIT[", id, "]: SET BURN = ", rate))
|
log.debug(util.c("PROCESS: UNIT[", id, "] SET BURN ", rate))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- set waste mode
|
-- set waste mode
|
||||||
@ -139,13 +142,11 @@ function process.set_waste(id, mode)
|
|||||||
self.io.units[id].unit_ps.publish("U_WasteMode", mode)
|
self.io.units[id].unit_ps.publish("U_WasteMode", mode)
|
||||||
|
|
||||||
self.comms.send_unit_command(UNIT_COMMAND.SET_WASTE, id, mode)
|
self.comms.send_unit_command(UNIT_COMMAND.SET_WASTE, id, mode)
|
||||||
log.debug(util.c("UNIT[", id, "]: SET WASTE = ", mode))
|
log.debug(util.c("PROCESS: UNIT[", id, "] SET WASTE ", mode))
|
||||||
|
|
||||||
local waste_mode = settings.get("WASTE_MODES") ---@type table|nil
|
local waste_mode = settings.get("WASTE_MODES") ---@type table|nil
|
||||||
|
|
||||||
if type(waste_mode) ~= "table" then
|
if type(waste_mode) ~= "table" then waste_mode = {} end
|
||||||
waste_mode = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
waste_mode[id] = mode
|
waste_mode[id] = mode
|
||||||
|
|
||||||
@ -160,7 +161,7 @@ end
|
|||||||
---@param id integer unit ID
|
---@param id integer unit ID
|
||||||
function process.ack_all_alarms(id)
|
function process.ack_all_alarms(id)
|
||||||
self.comms.send_unit_command(UNIT_COMMAND.ACK_ALL_ALARMS, id)
|
self.comms.send_unit_command(UNIT_COMMAND.ACK_ALL_ALARMS, id)
|
||||||
log.debug(util.c("UNIT[", id, "]: ACK ALL ALARMS"))
|
log.debug(util.c("PROCESS: UNIT[", id, "] ACK ALL ALARMS"))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- acknowledge an alarm
|
-- acknowledge an alarm
|
||||||
@ -168,7 +169,7 @@ end
|
|||||||
---@param alarm integer alarm ID
|
---@param alarm integer alarm ID
|
||||||
function process.ack_alarm(id, alarm)
|
function process.ack_alarm(id, alarm)
|
||||||
self.comms.send_unit_command(UNIT_COMMAND.ACK_ALARM, id, alarm)
|
self.comms.send_unit_command(UNIT_COMMAND.ACK_ALARM, id, alarm)
|
||||||
log.debug(util.c("UNIT[", id, "]: ACK ALARM ", alarm))
|
log.debug(util.c("PROCESS: UNIT[", id, "] ACK ALARM ", alarm))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- reset an alarm
|
-- reset an alarm
|
||||||
@ -176,7 +177,7 @@ end
|
|||||||
---@param alarm integer alarm ID
|
---@param alarm integer alarm ID
|
||||||
function process.reset_alarm(id, alarm)
|
function process.reset_alarm(id, alarm)
|
||||||
self.comms.send_unit_command(UNIT_COMMAND.RESET_ALARM, id, alarm)
|
self.comms.send_unit_command(UNIT_COMMAND.RESET_ALARM, id, alarm)
|
||||||
log.debug(util.c("UNIT[", id, "]: RESET ALARM ", alarm))
|
log.debug(util.c("PROCESS: UNIT[", id, "] RESET ALARM ", alarm))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- assign a unit to a group
|
-- assign a unit to a group
|
||||||
@ -184,13 +185,11 @@ end
|
|||||||
---@param group_id integer|0 group ID or 0 for independent
|
---@param group_id integer|0 group ID or 0 for independent
|
||||||
function process.set_group(unit_id, group_id)
|
function process.set_group(unit_id, group_id)
|
||||||
self.comms.send_unit_command(UNIT_COMMAND.SET_GROUP, unit_id, group_id)
|
self.comms.send_unit_command(UNIT_COMMAND.SET_GROUP, unit_id, group_id)
|
||||||
log.debug(util.c("UNIT[", unit_id, "]: SET GROUP ", group_id))
|
log.debug(util.c("PROCESS: UNIT[", unit_id, "] SET GROUP ", group_id))
|
||||||
|
|
||||||
local prio_groups = settings.get("PRIORITY_GROUPS") ---@type table|nil
|
local prio_groups = settings.get("PRIORITY_GROUPS") ---@type table|nil
|
||||||
|
|
||||||
if type(prio_groups) ~= "table" then
|
if type(prio_groups) ~= "table" then prio_groups = {} end
|
||||||
prio_groups = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
prio_groups[unit_id] = group_id
|
prio_groups[unit_id] = group_id
|
||||||
|
|
||||||
@ -208,13 +207,13 @@ end
|
|||||||
-- stop automatic process control
|
-- stop automatic process control
|
||||||
function process.stop_auto()
|
function process.stop_auto()
|
||||||
self.comms.send_fac_command(FAC_COMMAND.STOP)
|
self.comms.send_fac_command(FAC_COMMAND.STOP)
|
||||||
log.debug("FAC: STOP AUTO")
|
log.debug("PROCESS: STOP AUTO CTL")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- start automatic process control
|
-- start automatic process control
|
||||||
function process.start_auto()
|
function process.start_auto()
|
||||||
self.comms.send_auto_start(self.config)
|
self.comms.send_auto_start(self.config)
|
||||||
log.debug("FAC: START AUTO")
|
log.debug("PROCESS: START AUTO CTL")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- save process control settings
|
-- save process control settings
|
||||||
@ -246,8 +245,6 @@ function process.save(mode, burn_target, charge_target, gen_target, limits)
|
|||||||
log.warning("process.save(): failed to save coordinator settings file")
|
log.warning("process.save(): failed to save coordinator settings file")
|
||||||
end
|
end
|
||||||
|
|
||||||
log.debug("saved = " .. util.strval(saved))
|
|
||||||
|
|
||||||
self.io.facility.save_cfg_ack(saved)
|
self.io.facility.save_cfg_ack(saved)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -273,18 +270,4 @@ function process.start_ack_handle(response)
|
|||||||
self.io.facility.start_ack(ack)
|
self.io.facility.start_ack(ack)
|
||||||
end
|
end
|
||||||
|
|
||||||
--------------------------
|
|
||||||
-- SUPERVISOR RESPONSES --
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
-- acknowledgement from the supervisor to assign a unit to a group
|
|
||||||
function process.sv_assign(unit_id, group_id)
|
|
||||||
self.io.units[unit_id].group = group_id
|
|
||||||
end
|
|
||||||
|
|
||||||
-- acknowledgement from the supervisor to assign a unit a burn rate limit
|
|
||||||
function process.sv_limit(unit_id, limit)
|
|
||||||
self.io.units[unit_id].limit = limit
|
|
||||||
end
|
|
||||||
|
|
||||||
return process
|
return process
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
--
|
||||||
|
-- Graphics Rendering Control
|
||||||
|
--
|
||||||
|
|
||||||
local log = require("scada-common.log")
|
local log = require("scada-common.log")
|
||||||
local util = require("scada-common.util")
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
@ -56,6 +60,7 @@ function renderer.set_displays(monitors)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- check if the renderer is configured to use a given monitor peripheral
|
-- check if the renderer is configured to use a given monitor peripheral
|
||||||
|
---@nodiscard
|
||||||
---@param periph table peripheral
|
---@param periph table peripheral
|
||||||
---@return boolean is_used
|
---@return boolean is_used
|
||||||
function renderer.is_monitor_used(periph)
|
function renderer.is_monitor_used(periph)
|
||||||
@ -87,6 +92,7 @@ function renderer.reset(recolor)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- check main display width
|
-- check main display width
|
||||||
|
---@nodiscard
|
||||||
---@return boolean width_okay
|
---@return boolean width_okay
|
||||||
function renderer.validate_main_display_width()
|
function renderer.validate_main_display_width()
|
||||||
local w, _ = engine.monitors.primary.getSize()
|
local w, _ = engine.monitors.primary.getSize()
|
||||||
@ -94,6 +100,7 @@ function renderer.validate_main_display_width()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- check display sizes
|
-- check display sizes
|
||||||
|
---@nodiscard
|
||||||
---@return boolean valid all unit display dimensions OK
|
---@return boolean valid all unit display dimensions OK
|
||||||
function renderer.validate_unit_display_sizes()
|
function renderer.validate_unit_display_sizes()
|
||||||
local valid = true
|
local valid = true
|
||||||
@ -101,7 +108,7 @@ function renderer.validate_unit_display_sizes()
|
|||||||
for id, monitor in pairs(engine.monitors.unit_displays) do
|
for id, monitor in pairs(engine.monitors.unit_displays) do
|
||||||
local w, h = monitor.getSize()
|
local w, h = monitor.getSize()
|
||||||
if w ~= 79 or h ~= 52 then
|
if w ~= 79 or h ~= 52 then
|
||||||
log.warning(util.c("unit ", id, " display resolution not 79 wide by 52 tall: ", w, ", ", h))
|
log.warning(util.c("RENDERER: unit ", id, " display resolution not 79 wide by 52 tall: ", w, ", ", h))
|
||||||
valid = false
|
valid = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -171,6 +178,7 @@ function renderer.close_ui()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- is the UI ready?
|
-- is the UI ready?
|
||||||
|
---@nodiscard
|
||||||
---@return boolean ready
|
---@return boolean ready
|
||||||
function renderer.ui_ready() return engine.ui_ready end
|
function renderer.ui_ready() return engine.ui_ready end
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ local sounder = {}
|
|||||||
|
|
||||||
local _2_PI = 2 * math.pi -- 2 whole pies, hope you're hungry
|
local _2_PI = 2 * math.pi -- 2 whole pies, hope you're hungry
|
||||||
local _DRATE = 48000 -- 48kHz audio
|
local _DRATE = 48000 -- 48kHz audio
|
||||||
local _MAX_VAL = 127/2 -- max signed integer in this 8-bit audio
|
local _MAX_VAL = 127 / 2 -- max signed integer in this 8-bit audio
|
||||||
local _MAX_SAMPLES = 0x20000 -- 128 * 1024 samples
|
local _MAX_SAMPLES = 0x20000 -- 128 * 1024 samples
|
||||||
local _05s_SAMPLES = 24000 -- half a second worth of samples
|
local _05s_SAMPLES = 24000 -- half a second worth of samples
|
||||||
|
|
||||||
@ -26,7 +26,8 @@ local alarm_ctl = {
|
|||||||
playing = false,
|
playing = false,
|
||||||
num_active = 0,
|
num_active = 0,
|
||||||
next_block = 1,
|
next_block = 1,
|
||||||
quad_buffer = { {}, {}, {}, {} } -- split audio up into 0.5s samples so specific components can be ended quicker
|
-- split audio up into 0.5s samples so specific components can be ended quicker
|
||||||
|
quad_buffer = { {}, {}, {}, {} }
|
||||||
}
|
}
|
||||||
|
|
||||||
-- sounds modeled after https://www.e2s.com/references-and-guidelines/listen-and-download-alarm-tones
|
-- sounds modeled after https://www.e2s.com/references-and-guidelines/listen-and-download-alarm-tones
|
||||||
@ -52,6 +53,7 @@ local TONES = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
-- calculate how many samples are in the given number of milliseconds
|
-- calculate how many samples are in the given number of milliseconds
|
||||||
|
---@nodiscard
|
||||||
---@param ms integer milliseconds
|
---@param ms integer milliseconds
|
||||||
---@return integer samples
|
---@return integer samples
|
||||||
local function ms_to_samples(ms) return math.floor(ms * 48) end
|
local function ms_to_samples(ms) return math.floor(ms * 48) end
|
||||||
@ -224,6 +226,7 @@ end
|
|||||||
--#endregion
|
--#endregion
|
||||||
|
|
||||||
-- hard audio limiter
|
-- hard audio limiter
|
||||||
|
---@nodiscard
|
||||||
---@param output number output level
|
---@param output number output level
|
||||||
---@return number limited -128.0 to 127.0
|
---@return number limited -128.0 to 127.0
|
||||||
local function limit(output)
|
local function limit(output)
|
||||||
@ -454,7 +457,7 @@ function sounder.test_power_scale()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
log.debug("power rescale test took " .. (util.time_ms() - start) .. "ms")
|
log.debug("SOUNDER: power rescale test took " .. (util.time_ms() - start) .. "ms")
|
||||||
end
|
end
|
||||||
|
|
||||||
--#endregion
|
--#endregion
|
||||||
|
@ -19,7 +19,7 @@ local iocontrol = require("coordinator.iocontrol")
|
|||||||
local renderer = require("coordinator.renderer")
|
local renderer = require("coordinator.renderer")
|
||||||
local sounder = require("coordinator.sounder")
|
local sounder = require("coordinator.sounder")
|
||||||
|
|
||||||
local COORDINATOR_VERSION = "beta-v0.10.1"
|
local COORDINATOR_VERSION = "v0.11.0"
|
||||||
|
|
||||||
local print = util.print
|
local print = util.print
|
||||||
local println = util.println
|
local println = util.println
|
||||||
@ -81,7 +81,7 @@ local function main()
|
|||||||
-- setup monitors
|
-- setup monitors
|
||||||
local configured, monitors = coordinator.configure_monitors(config.NUM_UNITS)
|
local configured, monitors = coordinator.configure_monitors(config.NUM_UNITS)
|
||||||
if not configured or monitors == nil then
|
if not configured or monitors == nil then
|
||||||
println("boot> monitor setup failed")
|
println("startup> monitor setup failed")
|
||||||
log.fatal("monitor configuration failed")
|
log.fatal("monitor configuration failed")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -91,11 +91,11 @@ local function main()
|
|||||||
renderer.reset(config.RECOLOR)
|
renderer.reset(config.RECOLOR)
|
||||||
|
|
||||||
if not renderer.validate_main_display_width() then
|
if not renderer.validate_main_display_width() then
|
||||||
println("boot> main display must be 8 blocks wide")
|
println("startup> main display must be 8 blocks wide")
|
||||||
log.fatal("main display not wide enough")
|
log.fatal("main display not wide enough")
|
||||||
return
|
return
|
||||||
elseif not renderer.validate_unit_display_sizes() then
|
elseif not renderer.validate_unit_display_sizes() then
|
||||||
println("boot> one or more unit display dimensions incorrect; they must be 4x4 blocks")
|
println("startup> one or more unit display dimensions incorrect; they must be 4x4 blocks")
|
||||||
log.fatal("unit display dimensions incorrect")
|
log.fatal("unit display dimensions incorrect")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -116,7 +116,7 @@ local function main()
|
|||||||
local speaker = ppm.get_device("speaker")
|
local speaker = ppm.get_device("speaker")
|
||||||
if speaker == nil then
|
if speaker == nil then
|
||||||
log_boot("annunciator alarm speaker not found")
|
log_boot("annunciator alarm speaker not found")
|
||||||
println("boot> speaker not found")
|
println("startup> speaker not found")
|
||||||
log.fatal("no annunciator alarm speaker found")
|
log.fatal("no annunciator alarm speaker found")
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
@ -135,7 +135,7 @@ local function main()
|
|||||||
local modem = ppm.get_wireless_modem()
|
local modem = ppm.get_wireless_modem()
|
||||||
if modem == nil then
|
if modem == nil then
|
||||||
log_comms("wireless modem not found")
|
log_comms("wireless modem not found")
|
||||||
println("boot> wireless modem not found")
|
println("startup> wireless modem not found")
|
||||||
log.fatal("no wireless modem on startup")
|
log.fatal("no wireless modem on startup")
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
@ -145,12 +145,12 @@ local function main()
|
|||||||
-- create connection watchdog
|
-- create connection watchdog
|
||||||
local conn_watchdog = util.new_watchdog(config.COMMS_TIMEOUT)
|
local conn_watchdog = util.new_watchdog(config.COMMS_TIMEOUT)
|
||||||
conn_watchdog.cancel()
|
conn_watchdog.cancel()
|
||||||
log.debug("boot> conn watchdog created")
|
log.debug("startup> conn watchdog created")
|
||||||
|
|
||||||
-- start comms, open all channels
|
-- start comms, open all channels
|
||||||
local coord_comms = coordinator.comms(COORDINATOR_VERSION, modem, config.SCADA_SV_PORT, config.SCADA_SV_LISTEN,
|
local coord_comms = coordinator.comms(COORDINATOR_VERSION, modem, config.SCADA_SV_PORT, config.SCADA_SV_LISTEN,
|
||||||
config.SCADA_API_LISTEN, config.TRUSTED_RANGE, conn_watchdog)
|
config.SCADA_API_LISTEN, config.TRUSTED_RANGE, conn_watchdog)
|
||||||
log.debug("boot> comms init")
|
log.debug("startup> comms init")
|
||||||
log_comms("comms initialized")
|
log_comms("comms initialized")
|
||||||
|
|
||||||
-- base loop clock (2Hz, 10 ticks)
|
-- base loop clock (2Hz, 10 ticks)
|
||||||
@ -176,7 +176,7 @@ local function main()
|
|||||||
end
|
end
|
||||||
|
|
||||||
if not init_connect_sv() then
|
if not init_connect_sv() then
|
||||||
println("boot> failed to connect to supervisor")
|
println("startup> failed to connect to supervisor")
|
||||||
log_sys("system shutdown")
|
log_sys("system shutdown")
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
@ -199,7 +199,7 @@ local function main()
|
|||||||
renderer.close_ui()
|
renderer.close_ui()
|
||||||
log_graphics(util.c("UI crashed: ", message))
|
log_graphics(util.c("UI crashed: ", message))
|
||||||
println_ts("UI crashed")
|
println_ts("UI crashed")
|
||||||
log.fatal(util.c("ui crashed with error ", message))
|
log.fatal(util.c("GUI crashed with error ", message))
|
||||||
else
|
else
|
||||||
log_graphics("first UI draw took " .. (util.time_ms() - draw_start) .. "ms")
|
log_graphics("first UI draw took " .. (util.time_ms() - draw_start) .. "ms")
|
||||||
|
|
||||||
@ -223,7 +223,7 @@ local function main()
|
|||||||
if ui_ok then
|
if ui_ok then
|
||||||
-- start connection watchdog
|
-- start connection watchdog
|
||||||
conn_watchdog.feed()
|
conn_watchdog.feed()
|
||||||
log.debug("boot> conn watchdog started")
|
log.debug("startup> conn watchdog started")
|
||||||
|
|
||||||
log_sys("system started successfully")
|
log_sys("system started successfully")
|
||||||
end
|
end
|
||||||
@ -243,7 +243,6 @@ local function main()
|
|||||||
no_modem = true
|
no_modem = true
|
||||||
log_sys("comms modem disconnected")
|
log_sys("comms modem disconnected")
|
||||||
println_ts("wireless modem disconnected!")
|
println_ts("wireless modem disconnected!")
|
||||||
log.error("comms modem disconnected!")
|
|
||||||
|
|
||||||
-- close out UI
|
-- close out UI
|
||||||
renderer.close_ui()
|
renderer.close_ui()
|
||||||
@ -252,20 +251,21 @@ local function main()
|
|||||||
log_sys("awaiting comms modem reconnect...")
|
log_sys("awaiting comms modem reconnect...")
|
||||||
else
|
else
|
||||||
log_sys("non-comms modem disconnected")
|
log_sys("non-comms modem disconnected")
|
||||||
log.warning("non-comms modem disconnected")
|
|
||||||
end
|
end
|
||||||
elseif type == "monitor" then
|
elseif type == "monitor" then
|
||||||
if renderer.is_monitor_used(device) then
|
if renderer.is_monitor_used(device) then
|
||||||
-- "halt and catch fire" style handling
|
-- "halt and catch fire" style handling
|
||||||
println_ts("lost a configured monitor, system will now exit")
|
local msg = "lost a configured monitor, system will now exit"
|
||||||
log_sys("lost a configured monitor, system will now exit")
|
println_ts(msg)
|
||||||
|
log_sys(msg)
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
log_sys("lost unused monitor, ignoring")
|
log_sys("lost unused monitor, ignoring")
|
||||||
end
|
end
|
||||||
elseif type == "speaker" then
|
elseif type == "speaker" then
|
||||||
println_ts("lost alarm sounder speaker")
|
local msg = "lost alarm sounder speaker"
|
||||||
log_sys("lost alarm sounder speaker")
|
println_ts(msg)
|
||||||
|
log_sys(msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif event == "peripheral" then
|
elseif event == "peripheral" then
|
||||||
@ -291,8 +291,9 @@ local function main()
|
|||||||
elseif type == "monitor" then
|
elseif type == "monitor" then
|
||||||
-- not supported, system will exit on loss of in-use monitors
|
-- not supported, system will exit on loss of in-use monitors
|
||||||
elseif type == "speaker" then
|
elseif type == "speaker" then
|
||||||
println_ts("alarm sounder speaker reconnected")
|
local msg = "alarm sounder speaker reconnected"
|
||||||
log_sys("alarm sounder speaker reconnected")
|
println_ts(msg)
|
||||||
|
log_sys(msg)
|
||||||
sounder.reconnect(device)
|
sounder.reconnect(device)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -301,7 +302,7 @@ local function main()
|
|||||||
-- main loop tick
|
-- main loop tick
|
||||||
|
|
||||||
-- free any closed sessions
|
-- free any closed sessions
|
||||||
--apisessions.free_all_closed()
|
apisessions.free_all_closed()
|
||||||
|
|
||||||
-- update date and time string for main display
|
-- update date and time string for main display
|
||||||
iocontrol.get_db().facility.ps.publish("date_time", os.date(date_format))
|
iocontrol.get_db().facility.ps.publish("date_time", os.date(date_format))
|
||||||
@ -326,7 +327,7 @@ local function main()
|
|||||||
-- a non-clock/main watchdog timer event
|
-- a non-clock/main watchdog timer event
|
||||||
|
|
||||||
--check API watchdogs
|
--check API watchdogs
|
||||||
--apisessions.check_all_watchdogs(param1)
|
apisessions.check_all_watchdogs(param1)
|
||||||
|
|
||||||
-- notify timer callback dispatcher
|
-- notify timer callback dispatcher
|
||||||
tcallbackdsp.handle(param1)
|
tcallbackdsp.handle(param1)
|
||||||
|
@ -13,6 +13,7 @@ local cpair = core.graphics.cpair
|
|||||||
local border = core.graphics.border
|
local border = core.graphics.border
|
||||||
|
|
||||||
-- new boiler view
|
-- new boiler view
|
||||||
|
---@nodiscard
|
||||||
---@param root graphics_element parent
|
---@param root graphics_element parent
|
||||||
---@param x integer top left x
|
---@param x integer top left x
|
||||||
---@param y integer top left y
|
---@param y integer top left y
|
||||||
|
@ -19,6 +19,7 @@ local border = core.graphics.border
|
|||||||
local TEXT_ALIGN = core.graphics.TEXT_ALIGN
|
local TEXT_ALIGN = core.graphics.TEXT_ALIGN
|
||||||
|
|
||||||
-- new induction matrix view
|
-- new induction matrix view
|
||||||
|
---@nodiscard
|
||||||
---@param root graphics_element parent
|
---@param root graphics_element parent
|
||||||
---@param x integer top left x
|
---@param x integer top left x
|
||||||
---@param y integer top left y
|
---@param y integer top left y
|
||||||
|
@ -16,11 +16,8 @@ local DataIndicator = require("graphics.elements.indicators.data")
|
|||||||
local IndicatorLight = require("graphics.elements.indicators.light")
|
local IndicatorLight = require("graphics.elements.indicators.light")
|
||||||
local RadIndicator = require("graphics.elements.indicators.rad")
|
local RadIndicator = require("graphics.elements.indicators.rad")
|
||||||
local TriIndicatorLight = require("graphics.elements.indicators.trilight")
|
local TriIndicatorLight = require("graphics.elements.indicators.trilight")
|
||||||
local VerticalBar = require("graphics.elements.indicators.vbar")
|
|
||||||
|
|
||||||
local HazardButton = require("graphics.elements.controls.hazard_button")
|
local HazardButton = require("graphics.elements.controls.hazard_button")
|
||||||
local MultiButton = require("graphics.elements.controls.multi_button")
|
|
||||||
local PushButton = require("graphics.elements.controls.push_button")
|
|
||||||
local RadioButton = require("graphics.elements.controls.radio_button")
|
local RadioButton = require("graphics.elements.controls.radio_button")
|
||||||
local SpinboxNumeric = require("graphics.elements.controls.spinbox_numeric")
|
local SpinboxNumeric = require("graphics.elements.controls.spinbox_numeric")
|
||||||
|
|
||||||
@ -32,6 +29,7 @@ local border = core.graphics.border
|
|||||||
local period = core.flasher.PERIOD
|
local period = core.flasher.PERIOD
|
||||||
|
|
||||||
-- new process control view
|
-- new process control view
|
||||||
|
---@nodiscard
|
||||||
---@param root graphics_element parent
|
---@param root graphics_element parent
|
||||||
---@param x integer top left x
|
---@param x integer top left x
|
||||||
---@param y integer top left y
|
---@param y integer top left y
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
local types = require("scada-common.types")
|
||||||
|
|
||||||
local style = require("coordinator.ui.style")
|
local style = require("coordinator.ui.style")
|
||||||
|
|
||||||
local core = require("graphics.core")
|
local core = require("graphics.core")
|
||||||
@ -13,6 +15,7 @@ local cpair = core.graphics.cpair
|
|||||||
local border = core.graphics.border
|
local border = core.graphics.border
|
||||||
|
|
||||||
-- create new reactor view
|
-- create new reactor view
|
||||||
|
---@nodiscard
|
||||||
---@param root graphics_element parent
|
---@param root graphics_element parent
|
||||||
---@param x integer top left x
|
---@param x integer top left x
|
||||||
---@param y integer top left y
|
---@param y integer top left y
|
||||||
@ -47,7 +50,7 @@ local function new_view(root, x, y, data, ps)
|
|||||||
local waste = HorizontalBar{parent=reactor_fills,x=8,y=5,show_percent=true,bar_fg_bg=cpair(colors.brown,colors.gray),height=1,width=14}
|
local waste = HorizontalBar{parent=reactor_fills,x=8,y=5,show_percent=true,bar_fg_bg=cpair(colors.brown,colors.gray),height=1,width=14}
|
||||||
|
|
||||||
ps.subscribe("ccool_type", function (type)
|
ps.subscribe("ccool_type", function (type)
|
||||||
if type == "mekanism:sodium" then
|
if type == types.FLUID.SODIUM then
|
||||||
ccool.recolor(cpair(colors.lightBlue, colors.gray))
|
ccool.recolor(cpair(colors.lightBlue, colors.gray))
|
||||||
else
|
else
|
||||||
ccool.recolor(cpair(colors.blue, colors.gray))
|
ccool.recolor(cpair(colors.blue, colors.gray))
|
||||||
@ -55,7 +58,7 @@ local function new_view(root, x, y, data, ps)
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
ps.subscribe("hcool_type", function (type)
|
ps.subscribe("hcool_type", function (type)
|
||||||
if type == "mekanism:superheated_sodium" then
|
if type == types.FLUID.SUPERHEATED_SODIUM then
|
||||||
hcool.recolor(cpair(colors.orange, colors.gray))
|
hcool.recolor(cpair(colors.orange, colors.gray))
|
||||||
else
|
else
|
||||||
hcool.recolor(cpair(colors.white, colors.gray))
|
hcool.recolor(cpair(colors.white, colors.gray))
|
||||||
|
@ -15,6 +15,7 @@ local cpair = core.graphics.cpair
|
|||||||
local border = core.graphics.border
|
local border = core.graphics.border
|
||||||
|
|
||||||
-- new turbine view
|
-- new turbine view
|
||||||
|
---@nodiscard
|
||||||
---@param root graphics_element parent
|
---@param root graphics_element parent
|
||||||
---@param x integer top left x
|
---@param x integer top left x
|
||||||
---@param y integer top left y
|
---@param y integer top left y
|
||||||
|
@ -57,6 +57,7 @@ local waste_opts = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
-- create a unit view
|
-- create a unit view
|
||||||
|
---@nodiscard
|
||||||
---@param parent graphics_element parent
|
---@param parent graphics_element parent
|
||||||
---@param id integer
|
---@param id integer
|
||||||
local function init(parent, id)
|
local function init(parent, id)
|
||||||
@ -237,13 +238,13 @@ local function init(parent, id)
|
|||||||
local rcs_annunc = Div{parent=rcs,width=27,height=22,x=2,y=1}
|
local rcs_annunc = Div{parent=rcs,width=27,height=22,x=2,y=1}
|
||||||
local rcs_tags = Div{parent=rcs,width=2,height=13,x=29,y=9}
|
local rcs_tags = Div{parent=rcs,width=2,height=13,x=29,y=9}
|
||||||
|
|
||||||
local c_flt = IndicatorLight{parent=rcs_annunc,label="RCS Hardware Fault",colors=cpair(colors.yellow,colors.gray)}
|
local c_flt = IndicatorLight{parent=rcs_annunc,label="RCS Hardware Fault",colors=cpair(colors.yellow,colors.gray)}
|
||||||
local c_emg = TriIndicatorLight{parent=rcs_annunc,label="Emergency Coolant",c1=colors.gray,c2=colors.white,c3=colors.yellow}
|
local c_emg = TriIndicatorLight{parent=rcs_annunc,label="Emergency Coolant",c1=colors.gray,c2=colors.white,c3=colors.yellow}
|
||||||
local c_cfm = IndicatorLight{parent=rcs_annunc,label="Coolant Feed Mismatch",colors=cpair(colors.yellow,colors.gray)}
|
local c_cfm = IndicatorLight{parent=rcs_annunc,label="Coolant Feed Mismatch",colors=cpair(colors.yellow,colors.gray)}
|
||||||
local c_brm = IndicatorLight{parent=rcs_annunc,label="Boil Rate Mismatch",colors=cpair(colors.yellow,colors.gray)}
|
local c_brm = IndicatorLight{parent=rcs_annunc,label="Boil Rate Mismatch",colors=cpair(colors.yellow,colors.gray)}
|
||||||
local c_sfm = IndicatorLight{parent=rcs_annunc,label="Steam Feed Mismatch",colors=cpair(colors.yellow,colors.gray)}
|
local c_sfm = IndicatorLight{parent=rcs_annunc,label="Steam Feed Mismatch",colors=cpair(colors.yellow,colors.gray)}
|
||||||
local c_mwrf = IndicatorLight{parent=rcs_annunc,label="Max Water Return Feed",colors=cpair(colors.yellow,colors.gray)}
|
local c_mwrf = IndicatorLight{parent=rcs_annunc,label="Max Water Return Feed",colors=cpair(colors.yellow,colors.gray)}
|
||||||
local c_tbnt = IndicatorLight{parent=rcs_annunc,label="Turbine Trip",colors=cpair(colors.red,colors.gray),flash=true,period=period.BLINK_250_MS}
|
local c_tbnt = IndicatorLight{parent=rcs_annunc,label="Turbine Trip",colors=cpair(colors.red,colors.gray),flash=true,period=period.BLINK_250_MS}
|
||||||
|
|
||||||
u_ps.subscribe("RCSFault", c_flt.update)
|
u_ps.subscribe("RCSFault", c_flt.update)
|
||||||
u_ps.subscribe("EmergencyCoolant", c_emg.update)
|
u_ps.subscribe("EmergencyCoolant", c_emg.update)
|
||||||
|
@ -19,6 +19,7 @@ local TEXT_ALIGN = core.graphics.TEXT_ALIGN
|
|||||||
local pipe = core.graphics.pipe
|
local pipe = core.graphics.pipe
|
||||||
|
|
||||||
-- make a new unit overview window
|
-- make a new unit overview window
|
||||||
|
---@nodiscard
|
||||||
---@param parent graphics_element parent
|
---@param parent graphics_element parent
|
||||||
---@param x integer top left x
|
---@param x integer top left x
|
||||||
---@param y integer top left y
|
---@param y integer top left y
|
||||||
@ -51,7 +52,7 @@ local function make(parent, x, y, unit)
|
|||||||
-- REACTOR --
|
-- REACTOR --
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
reactor_view(root, 1, 3, unit.reactor_data, unit.unit_ps)
|
local _ = reactor_view(root, 1, 3, unit.reactor_data, unit.unit_ps)
|
||||||
|
|
||||||
if num_boilers > 0 then
|
if num_boilers > 0 then
|
||||||
local coolant_pipes = {}
|
local coolant_pipes = {}
|
||||||
@ -101,16 +102,16 @@ local function make(parent, x, y, unit)
|
|||||||
local steam_pipes_b = {}
|
local steam_pipes_b = {}
|
||||||
|
|
||||||
if no_boilers then
|
if no_boilers then
|
||||||
table.insert(steam_pipes_b, pipe(0, 1, 3, 1, colors.white)) -- steam to turbine 1
|
table.insert(steam_pipes_b, pipe(0, 1, 3, 1, colors.white)) -- steam to turbine 1
|
||||||
table.insert(steam_pipes_b, pipe(0, 2, 3, 2, colors.blue)) -- water to turbine 1
|
table.insert(steam_pipes_b, pipe(0, 2, 3, 2, colors.blue)) -- water to turbine 1
|
||||||
|
|
||||||
if num_turbines >= 2 then
|
if num_turbines >= 2 then
|
||||||
table.insert(steam_pipes_b, pipe(1, 2, 3, 9, colors.white)) -- steam to turbine 2
|
table.insert(steam_pipes_b, pipe(1, 2, 3, 9, colors.white)) -- steam to turbine 2
|
||||||
table.insert(steam_pipes_b, pipe(2, 3, 3, 10, colors.blue)) -- water to turbine 2
|
table.insert(steam_pipes_b, pipe(2, 3, 3, 10, colors.blue)) -- water to turbine 2
|
||||||
end
|
end
|
||||||
|
|
||||||
if num_turbines >= 3 then
|
if num_turbines >= 3 then
|
||||||
table.insert(steam_pipes_b, pipe(1, 9, 3, 17, colors.white)) -- steam boiler 1 to turbine 1 junction end
|
table.insert(steam_pipes_b, pipe(1, 9, 3, 17, colors.white)) -- steam boiler 1 to turbine 1 junction end
|
||||||
table.insert(steam_pipes_b, pipe(2, 10, 3, 18, colors.blue)) -- water boiler 1 to turbine 1 junction start
|
table.insert(steam_pipes_b, pipe(2, 10, 3, 18, colors.blue)) -- water boiler 1 to turbine 1 junction start
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
--
|
--
|
||||||
-- Reactor Unit SCADA Coordinator GUI
|
-- Reactor Unit Waiting Spinner
|
||||||
--
|
--
|
||||||
|
|
||||||
local style = require("coordinator.ui.style")
|
local style = require("coordinator.ui.style")
|
||||||
@ -16,6 +16,7 @@ local TEXT_ALIGN = core.graphics.TEXT_ALIGN
|
|||||||
local cpair = core.graphics.cpair
|
local cpair = core.graphics.cpair
|
||||||
|
|
||||||
-- create a unit waiting view
|
-- create a unit waiting view
|
||||||
|
---@nodiscard
|
||||||
---@param parent graphics_element parent
|
---@param parent graphics_element parent
|
||||||
---@param y integer y offset
|
---@param y integer y offset
|
||||||
local function init(parent, y)
|
local function init(parent, y)
|
||||||
|
@ -3,13 +3,11 @@ local completion = require("cc.completion")
|
|||||||
local util = require("scada-common.util")
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
local print = util.print
|
local print = util.print
|
||||||
local println = util.println
|
|
||||||
local print_ts = util.print_ts
|
|
||||||
local println_ts = util.println_ts
|
|
||||||
|
|
||||||
local dialog = {}
|
local dialog = {}
|
||||||
|
|
||||||
-- ask the user yes or no
|
-- ask the user yes or no
|
||||||
|
---@nodiscard
|
||||||
---@param question string
|
---@param question string
|
||||||
---@param default boolean
|
---@param default boolean
|
||||||
---@return boolean|nil
|
---@return boolean|nil
|
||||||
@ -36,6 +34,7 @@ function dialog.ask_y_n(question, default)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- ask the user for an input within a set of options
|
-- ask the user for an input within a set of options
|
||||||
|
---@nodiscard
|
||||||
---@param options table
|
---@param options table
|
||||||
---@param cancel string
|
---@param cancel string
|
||||||
---@return boolean|string|nil
|
---@return boolean|string|nil
|
||||||
|
@ -30,6 +30,7 @@ local TEXT_ALIGN = core.graphics.TEXT_ALIGN
|
|||||||
local cpair = core.graphics.cpair
|
local cpair = core.graphics.cpair
|
||||||
|
|
||||||
-- create new main view
|
-- create new main view
|
||||||
|
---@nodiscard
|
||||||
---@param monitor table main viewscreen
|
---@param monitor table main viewscreen
|
||||||
local function init(monitor)
|
local function init(monitor)
|
||||||
local facility = iocontrol.get_db().facility
|
local facility = iocontrol.get_db().facility
|
||||||
@ -77,7 +78,7 @@ local function init(monitor)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- command & control
|
-- command & control
|
||||||
|
|
||||||
cnc_y_start = cnc_y_start
|
cnc_y_start = cnc_y_start
|
||||||
|
|
||||||
@ -90,7 +91,7 @@ local function init(monitor)
|
|||||||
|
|
||||||
cnc_bottom_align_start = cnc_bottom_align_start + 2
|
cnc_bottom_align_start = cnc_bottom_align_start + 2
|
||||||
|
|
||||||
local process = process_ctl(main, 2, cnc_bottom_align_start)
|
local _ = process_ctl(main, 2, cnc_bottom_align_start)
|
||||||
|
|
||||||
-- testing
|
-- testing
|
||||||
---@fixme remove test code
|
---@fixme remove test code
|
||||||
@ -123,7 +124,7 @@ local function init(monitor)
|
|||||||
SwitchButton{parent=audio,x=1,text="RCS TRANSIENT",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_rcs}
|
SwitchButton{parent=audio,x=1,text="RCS TRANSIENT",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_rcs}
|
||||||
SwitchButton{parent=audio,x=1,text="TURBINE TRIP",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_turbinet}
|
SwitchButton{parent=audio,x=1,text="TURBINE TRIP",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_turbinet}
|
||||||
|
|
||||||
local imatrix_1 = imatrix(main, 131, cnc_bottom_align_start, facility.induction_data_tbl[1], facility.induction_ps_tbl[1])
|
local _ = imatrix(main, 131, cnc_bottom_align_start, facility.induction_data_tbl[1], facility.induction_ps_tbl[1])
|
||||||
|
|
||||||
return main
|
return main
|
||||||
end
|
end
|
||||||
|
@ -9,12 +9,13 @@ local unit_detail = require("coordinator.ui.components.unit_detail")
|
|||||||
local DisplayBox = require("graphics.elements.displaybox")
|
local DisplayBox = require("graphics.elements.displaybox")
|
||||||
|
|
||||||
-- create a unit view
|
-- create a unit view
|
||||||
|
---@nodiscard
|
||||||
---@param monitor table
|
---@param monitor table
|
||||||
---@param id integer
|
---@param id integer
|
||||||
local function init(monitor, id)
|
local function init(monitor, id)
|
||||||
local main = DisplayBox{window=monitor,fg_bg=style.root}
|
local main = DisplayBox{window=monitor,fg_bg=style.root}
|
||||||
|
|
||||||
unit_detail(main, id)
|
local _ = unit_detail(main, id)
|
||||||
|
|
||||||
return main
|
return main
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user