#130 facility data object, some code cleanup, comms protocol changed from 1.0.1 to 1.1.0

This commit is contained in:
Mikayla Fischler
2022-12-10 13:58:17 -05:00
parent 41913441d5
commit 03f0216d51
15 changed files with 635 additions and 283 deletions

View File

@@ -6,7 +6,7 @@ local util = require("scada-common.util")
local sounder = require("coordinator.sounder")
local CRDN_COMMANDS = comms.CRDN_COMMANDS
local UNIT_COMMANDS = comms.UNIT_COMMANDS
local ALARM_STATE = types.ALARM_STATE
@@ -22,19 +22,29 @@ local io = {}
function iocontrol.init(conf, comms)
io.facility = {
scram = false,
num_units = conf.num_units,
ps = psil.create()
num_units = conf.num_units, ---@type integer
ps = psil.create(),
induction_ps_tbl = {},
induction_data_tbl = {}
}
-- create induction tables (max 1 per unit, preferably 1 total)
for _ = 1, conf.num_units do
local data = {} ---@type imatrix_session_db
table.insert(io.facility.induction_ps_tbl, psil.create())
table.insert(io.facility.induction_data_tbl, data)
end
io.units = {}
for i = 1, conf.num_units do
local function ack(alarm)
comms.send_command(CRDN_COMMANDS.ACK_ALARM, i, alarm)
comms.send_command(UNIT_COMMANDS.ACK_ALARM, i, alarm)
log.debug(util.c("UNIT[", i, "]: ACK ALARM ", alarm))
end
local function reset(alarm)
comms.send_command(CRDN_COMMANDS.RESET_ALARM, i, alarm)
comms.send_command(UNIT_COMMANDS.RESET_ALARM, i, alarm)
log.debug(util.c("UNIT[", i, "]: RESET ALARM ", alarm))
end
@@ -107,33 +117,33 @@ function iocontrol.init(conf, comms)
function entry.start()
entry.control_state = true
comms.send_command(CRDN_COMMANDS.START, i)
comms.send_command(UNIT_COMMANDS.START, i)
log.debug(util.c("UNIT[", i, "]: START"))
end
function entry.scram()
entry.control_state = false
comms.send_command(CRDN_COMMANDS.SCRAM, i)
comms.send_command(UNIT_COMMANDS.SCRAM, i)
log.debug(util.c("UNIT[", i, "]: SCRAM"))
end
function entry.reset_rps()
comms.send_command(CRDN_COMMANDS.RESET_RPS, i)
comms.send_command(UNIT_COMMANDS.RESET_RPS, i)
log.debug(util.c("UNIT[", i, "]: RESET_RPS"))
end
function entry.ack_alarms()
comms.send_command(CRDN_COMMANDS.ACK_ALL_ALARMS, i)
comms.send_command(UNIT_COMMANDS.ACK_ALL_ALARMS, i)
log.debug(util.c("UNIT[", i, "]: ACK_ALL_ALARMS"))
end
function entry.set_burn(rate)
comms.send_command(CRDN_COMMANDS.SET_BURN, i, rate)
comms.send_command(UNIT_COMMANDS.SET_BURN, i, rate)
log.debug(util.c("UNIT[", i, "]: SET_BURN = ", rate))
end
function entry.set_waste(mode)
comms.send_command(CRDN_COMMANDS.SET_WASTE, i, mode)
comms.send_command(UNIT_COMMANDS.SET_WASTE, i, mode)
log.debug(util.c("UNIT[", i, "]: SET_WASTE = ", mode))
end
@@ -158,58 +168,173 @@ function iocontrol.init(conf, comms)
end
end
-- populate structure builds
-- populate facility structure builds
---@param build table
---@return boolean valid
function iocontrol.record_facility_builds(build)
if type(build) == "table" then
local fac = io.facility
-- induction matricies
if type(build.induction) == "table" then
for id, matrix in pairs(build.induction) do
if type(fac.induction_data_tbl[id]) == "table" then
fac.induction_data_tbl[id].formed = matrix[1] ---@type boolean
fac.induction_data_tbl[id].build = matrix[2] ---@type table
fac.induction_ps_tbl[id].publish("formed", matrix[1])
for key, val in pairs(fac.induction_data_tbl[id].build) do
fac.induction_ps_tbl[id].publish(key, val)
end
else
log.debug(util.c("iocontrol.record_facility_builds: invalid induction matrix id ", id))
end
end
end
else
log.error("facility builds not a table")
return false
end
return true
end
-- populate unit structure builds
---@param builds table
---@return boolean valid
function iocontrol.record_builds(builds)
if #builds ~= #io.units then
log.error("number of provided unit builds does not match expected number of units")
function iocontrol.record_unit_builds(builds)
-- note: if not all units and RTUs are connected, some will be nil
for id, build in pairs(builds) do
local unit = io.units[id] ---@type ioctl_entry
if type(build) ~= "table" then
log.error(util.c("corrupted unit builds provided, unit ", id, " not a table"))
return false
elseif type(unit) ~= "table" then
log.error(util.c("corrupted unit builds provided, invalid unit ", id))
return false
end
local log_header = util.c("iocontrol.record_unit_builds[unit ", id, "]: ")
-- reactor build
if type(build.reactor) == "table" then
unit.reactor_data.mek_struct = build.reactor
for key, val in pairs(unit.reactor_data.mek_struct) do
unit.reactor_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.reactor_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
-- 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))
end
end
end
end
return true
end
-- update facility status
---@param status table
---@return boolean valid
function iocontrol.update_facility_status(status)
local log_header = util.c("iocontrol.update_facility_status: ")
if type(status) ~= "table" then
log.debug(log_header .. "status not a table")
return false
else
-- note: if not all units and RTUs are connected, some will be nil
for i = 1, #builds do
local unit = io.units[i] ---@type ioctl_entry
local build = builds[i]
local fac = io.facility
-- reactor build
if type(build.reactor) == "table" then
unit.reactor_data.mek_struct = build.reactor
for key, val in pairs(unit.reactor_data.mek_struct) do
unit.reactor_ps.publish(key, val)
end
-- RTU statuses
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.reactor_ps.publish("size", { unit.reactor_data.mek_struct.length, unit.reactor_data.mek_struct.width })
end
end
local rtu_statuses = status[1]
-- boiler builds
if type(build.boilers) == "table" then
for id, boiler in pairs(build.boilers) do
unit.boiler_data_tbl[id].formed = boiler[1] ---@type boolean
unit.boiler_data_tbl[id].build = boiler[2] ---@type table
unit.boiler_ps_tbl[id].publish("formed", boiler[1])
for key, val in pairs(unit.boiler_data_tbl[id].build) do
unit.boiler_ps_tbl[id].publish(key, val)
if type(rtu_statuses) == "table" then
-- induction matricies statuses
if type(rtu_statuses.induction) == "table" then
for id = 1, #fac.induction_ps_tbl do
if rtu_statuses.induction[id] == nil then
-- disconnected
fac.induction_ps_tbl[id].publish("computed_status", 1)
end
end
end
-- turbine builds
if type(build.turbines) == "table" then
for id, turbine in pairs(build.turbines) do
unit.turbine_data_tbl[id].formed = turbine[1] ---@type boolean
unit.turbine_data_tbl[id].build = turbine[2] ---@type table
for id, matrix in pairs(rtu_statuses.induction) do
if type(fac.induction_data_tbl[id]) == "table" then
local rtu_faulted = matrix[1] ---@type boolean
fac.induction_data_tbl[id].formed = matrix[2] ---@type boolean
fac.induction_data_tbl[id].state = matrix[3] ---@type table
fac.induction_data_tbl[id].tanks = matrix[4] ---@type table
unit.turbine_ps_tbl[id].publish("formed", turbine[1])
local data = fac.induction_data_tbl[id] ---@type imatrix_session_db
for key, val in pairs(unit.turbine_data_tbl[id].build) do
unit.turbine_ps_tbl[id].publish(key, val)
fac.induction_ps_tbl[id].publish("formed", data.formed)
fac.induction_ps_tbl[id].publish("faulted", rtu_faulted)
if data.formed then
if rtu_faulted then
fac.induction_ps_tbl[id].publish("computed_status", 3) -- faulted
elseif data.tanks.energy_fill >= 0.99 then
fac.induction_ps_tbl[id].publish("computed_status", 6) -- full
elseif data.tanks.energy_fill <= 0.01 then
fac.induction_ps_tbl[id].publish("computed_status", 5) -- empty
else
fac.induction_ps_tbl[id].publish("computed_status", 4) -- on-line
end
else
fac.induction_ps_tbl[id].publish("computed_status", 2) -- not formed
end
for key, val in pairs(fac.induction_data_tbl[id].state) do
fac.induction_ps_tbl[id].publish(key, val)
end
for key, val in pairs(fac.induction_data_tbl[id].tanks) do
fac.induction_ps_tbl[id].publish(key, val)
end
else
log.debug(util.c(log_header, "invalid induction matrix id ", id))
end
end
else
log.debug(log_header .. "induction matrix list not a table")
end
end
end
@@ -220,16 +345,17 @@ end
-- update unit statuses
---@param statuses table
---@return boolean valid
function iocontrol.update_statuses(statuses)
function iocontrol.update_unit_statuses(statuses)
if type(statuses) ~= "table" then
log.debug("iocontrol.update_statuses: unit statuses not a table")
log.debug("iocontrol.update_unit_statuses: unit statuses not a table")
return false
elseif #statuses ~= #io.units then
log.debug("iocontrol.update_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
else
-- get all unit statuses
for i = 1, #statuses do
local log_header = util.c("iocontrol.update_statuses[unit ", i, "]: ")
local log_header = util.c("iocontrol.update_unit_statuses[unit ", i, "]: ")
local unit = io.units[i] ---@type ioctl_entry
local status = statuses[i]
@@ -264,18 +390,18 @@ function iocontrol.update_statuses(statuses)
unit.reactor_data.mek_status = mek_status ---@type mek_status
if unit.reactor_data.mek_status.status then
unit.reactor_ps.publish("computed_status", 3) -- running
unit.reactor_ps.publish("computed_status", 5) -- running
else
if unit.reactor_data.no_reactor then
unit.reactor_ps.publish("computed_status", 5) -- faulted
unit.reactor_ps.publish("computed_status", 3) -- faulted
elseif not unit.reactor_data.formed then
unit.reactor_ps.publish("computed_status", 6) -- multiblock not formed
unit.reactor_ps.publish("computed_status", 2) -- multiblock not formed
elseif unit.reactor_data.rps_status.force_dis then
unit.reactor_ps.publish("computed_status", 7) -- reactor force disabled
elseif unit.reactor_data.rps_tripped and unit.reactor_data.rps_trip_cause ~= "manual" then
unit.reactor_ps.publish("computed_status", 4) -- SCRAM
unit.reactor_ps.publish("computed_status", 6) -- SCRAM
else
unit.reactor_ps.publish("computed_status", 2) -- disabled
unit.reactor_ps.publish("computed_status", 4) -- disabled
end
end
@@ -307,7 +433,7 @@ function iocontrol.update_statuses(statuses)
if type(rtu_statuses) == "table" then
-- boiler statuses
if type(rtu_statuses.boilers) == "table" then
for id = 1, #unit.boiler_data_tbl do
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)
@@ -315,34 +441,38 @@ function iocontrol.update_statuses(statuses)
end
for id, boiler in pairs(rtu_statuses.boilers) do
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
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
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)
unit.boiler_ps_tbl[id].publish("formed", data.formed)
unit.boiler_ps_tbl[id].publish("faulted", rtu_faulted)
if data.formed then
if rtu_faulted then
unit.boiler_ps_tbl[id].publish("computed_status", 4) -- faulted
elseif data.state.boil_rate > 0 then
unit.boiler_ps_tbl[id].publish("computed_status", 3) -- active
if data.formed then
if rtu_faulted then
unit.boiler_ps_tbl[id].publish("computed_status", 3) -- faulted
elseif 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
unit.boiler_ps_tbl[id].publish("computed_status", 2) -- 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
else
unit.boiler_ps_tbl[id].publish("computed_status", 5) -- 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)
log.debug(util.c(log_header, "invalid boiler id ", id))
end
end
else
@@ -359,36 +489,40 @@ function iocontrol.update_statuses(statuses)
end
for id, turbine in pairs(rtu_statuses.turbines) do
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
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
local data = unit.turbine_data_tbl[id] ---@type turbinev_session_db
local data = unit.turbine_data_tbl[id] ---@type turbinev_session_db
unit.turbine_ps_tbl[id].publish("formed", data.formed)
unit.turbine_ps_tbl[id].publish("faulted", rtu_faulted)
unit.turbine_ps_tbl[id].publish("formed", data.formed)
unit.turbine_ps_tbl[id].publish("faulted", rtu_faulted)
if data.formed then
if data.tanks.energy_fill >= 0.99 then
unit.turbine_ps_tbl[id].publish("computed_status", 4) -- trip
elseif rtu_faulted then
unit.turbine_ps_tbl[id].publish("computed_status", 5) -- faulted
elseif data.state.flow_rate < 100 then
unit.turbine_ps_tbl[id].publish("computed_status", 2) -- idle
if data.formed then
if data.tanks.energy_fill >= 0.99 then
unit.turbine_ps_tbl[id].publish("computed_status", 6) -- trip
elseif rtu_faulted then
unit.turbine_ps_tbl[id].publish("computed_status", 3) -- faulted
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
unit.turbine_ps_tbl[id].publish("computed_status", 3) -- 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
else
unit.turbine_ps_tbl[id].publish("computed_status", 6) -- 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)
log.debug(util.c(log_header, "invalid turbine id ", id))
end
end
else