#131 start of unit status text, added updating coordinator waste processing option on reconnect
This commit is contained in:
@@ -39,7 +39,7 @@ function iocontrol.init(conf, comms)
|
||||
|
||||
---@class ioctl_entry
|
||||
local entry = {
|
||||
unit_id = i, ---@type integer
|
||||
unit_id = i, ---@type integer
|
||||
initialized = false,
|
||||
|
||||
num_boilers = 0,
|
||||
@@ -53,15 +53,15 @@ function iocontrol.init(conf, comms)
|
||||
scram = function () end,
|
||||
reset_rps = function () end,
|
||||
ack_alarms = function () end,
|
||||
set_burn = function (rate) end, ---@param rate number
|
||||
set_waste = function (mode) end, ---@param mode integer
|
||||
set_burn = function (rate) end, ---@param rate number
|
||||
set_waste = function (mode) end, ---@param mode integer
|
||||
|
||||
start_ack = function (success) end, ---@param success boolean
|
||||
scram_ack = function (success) end, ---@param success boolean
|
||||
reset_rps_ack = function (success) end, ---@param success boolean
|
||||
ack_alarms_ack = function (success) end,---@param success boolean
|
||||
set_burn_ack = function (success) end, ---@param success boolean
|
||||
set_waste_ack = function (success) end, ---@param success boolean
|
||||
start_ack = function (success) end, ---@param success boolean
|
||||
scram_ack = function (success) end, ---@param success boolean
|
||||
reset_rps_ack = function (success) end, ---@param success boolean
|
||||
ack_alarms_ack = function (success) end, ---@param success boolean
|
||||
set_burn_ack = function (success) end, ---@param success boolean
|
||||
set_waste_ack = function (success) end, ---@param success boolean
|
||||
|
||||
alarm_callbacks = {
|
||||
c_breach = { ack = function () ack(1) end, reset = function () reset(1) end },
|
||||
@@ -95,7 +95,7 @@ function iocontrol.init(conf, comms)
|
||||
},
|
||||
|
||||
reactor_ps = psil.create(),
|
||||
reactor_data = {}, ---@type reactor_db
|
||||
reactor_data = {}, ---@type reactor_db
|
||||
|
||||
boiler_ps_tbl = {},
|
||||
boiler_data_tbl = {},
|
||||
@@ -221,18 +221,19 @@ end
|
||||
---@return boolean valid
|
||||
function iocontrol.update_statuses(statuses)
|
||||
if type(statuses) ~= "table" then
|
||||
log.debug("unit statuses not a table")
|
||||
log.debug("iocontrol.update_statuses: unit statuses not a table")
|
||||
return false
|
||||
elseif #statuses ~= #io.units then
|
||||
log.debug("number of provided unit statuses does not match expected number of units")
|
||||
log.debug("iocontrol.update_statuses: number of provided unit statuses does not match expected number of units")
|
||||
return false
|
||||
else
|
||||
for i = 1, #statuses do
|
||||
local log_header = util.c("iocontrol.update_statuses[unit ", i, "]: ")
|
||||
local unit = io.units[i] ---@type ioctl_entry
|
||||
local status = statuses[i]
|
||||
|
||||
if type(status) ~= "table" or #status ~= 4 then
|
||||
log.debug("invalid status entry in unit statuses (not a table or invalid length)")
|
||||
if type(status) ~= "table" or #status ~= 5 then
|
||||
log.debug(log_header .. "invalid status entry in unit statuses (not a table or invalid length)")
|
||||
return false
|
||||
end
|
||||
|
||||
@@ -255,7 +256,7 @@ function iocontrol.update_statuses(statuses)
|
||||
unit.reactor_data.no_reactor = gen_status[5]
|
||||
unit.reactor_data.formed = gen_status[6]
|
||||
else
|
||||
log.debug("reactor general status length mismatch")
|
||||
log.debug(log_header .. "reactor general status length mismatch")
|
||||
end
|
||||
|
||||
unit.reactor_data.rps_status = rps_status ---@type rps_status
|
||||
@@ -295,75 +296,16 @@ function iocontrol.update_statuses(statuses)
|
||||
end
|
||||
end
|
||||
else
|
||||
log.debug("reactor status length mismatch")
|
||||
end
|
||||
|
||||
-- annunciator
|
||||
|
||||
local annunciator = status[2] ---@type annunciator
|
||||
|
||||
for key, val in pairs(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.reactor_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("unrecognized table found in annunciator list, this is a bug", true)
|
||||
else
|
||||
-- non-table fields
|
||||
unit.reactor_ps.publish(key, val)
|
||||
end
|
||||
end
|
||||
|
||||
-- alarms
|
||||
|
||||
local alarm_states = status[3]
|
||||
|
||||
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.reactor_ps.publish("ALM" .. id, 2)
|
||||
elseif state == types.ALARM_STATE.RING_BACK then
|
||||
unit.reactor_ps.publish("ALM" .. id, 3)
|
||||
else
|
||||
unit.reactor_ps.publish("ALM" .. id, 1)
|
||||
end
|
||||
end
|
||||
else
|
||||
log.debug("alarm states not a table")
|
||||
return false
|
||||
log.debug(log_header .. "reactor status length mismatch")
|
||||
end
|
||||
|
||||
-- RTU statuses
|
||||
|
||||
local rtu_statuses = status[4]
|
||||
local rtu_statuses = status[2]
|
||||
|
||||
if type(rtu_statuses) == "table" then
|
||||
-- boiler statuses
|
||||
if type(rtu_statuses.boilers) == "table" then
|
||||
-- boiler statuses
|
||||
|
||||
for id = 1, #unit.boiler_data_tbl do
|
||||
if rtu_statuses.boilers[i] == nil then
|
||||
-- disconnected
|
||||
@@ -403,12 +345,11 @@ function iocontrol.update_statuses(statuses)
|
||||
end
|
||||
end
|
||||
else
|
||||
log.debug("boiler list not a table")
|
||||
log.debug(log_header .. "boiler list not a table")
|
||||
end
|
||||
|
||||
-- turbine statuses
|
||||
if type(rtu_statuses.turbines) == "table" then
|
||||
-- turbine statuses
|
||||
|
||||
for id = 1, #unit.turbine_ps_tbl do
|
||||
if rtu_statuses.turbines[i] == nil then
|
||||
-- disconnected
|
||||
@@ -450,11 +391,84 @@ function iocontrol.update_statuses(statuses)
|
||||
end
|
||||
end
|
||||
else
|
||||
log.debug("turbine list not a table")
|
||||
log.debug(log_header .. "turbine list not a table")
|
||||
return false
|
||||
end
|
||||
else
|
||||
log.debug("rtu list not a table")
|
||||
log.debug(log_header .. "rtu list not a table")
|
||||
end
|
||||
|
||||
-- annunciator
|
||||
|
||||
local annunciator = status[3] ---@type annunciator
|
||||
|
||||
for key, val in pairs(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.reactor_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.reactor_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.reactor_ps.publish("Alarm_" .. id, 2)
|
||||
elseif state == types.ALARM_STATE.RING_BACK then
|
||||
unit.reactor_ps.publish("Alarm_" .. id, 3)
|
||||
else
|
||||
unit.reactor_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 == 3 then
|
||||
unit.reactor_ps.publish("U_StatusLine1", unit_state[1])
|
||||
unit.reactor_ps.publish("U_StatusLine2", unit_state[2])
|
||||
unit.reactor_ps.publish("U_WasteMode", unit_state[3])
|
||||
else
|
||||
log.debug(log_header .. "unit state length mismatch")
|
||||
end
|
||||
else
|
||||
log.debug(log_header .. "unit state not a table")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ local coordinator = require("coordinator.coordinator")
|
||||
local renderer = require("coordinator.renderer")
|
||||
local sounder = require("coordinator.sounder")
|
||||
|
||||
local COORDINATOR_VERSION = "beta-v0.7.4"
|
||||
local COORDINATOR_VERSION = "beta-v0.7.5"
|
||||
|
||||
local print = util.print
|
||||
local println = util.println
|
||||
|
||||
@@ -308,8 +308,8 @@ local function init(parent, id)
|
||||
local set_burn = function () unit.set_burn(burn_rate.get_value()) end
|
||||
PushButton{parent=burn_control,x=14,y=2,text="SET",min_width=5,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=set_burn}
|
||||
|
||||
r_ps.subscribe("burn_rate", function (v) burn_rate.set_value(v) end)
|
||||
r_ps.subscribe("max_burn", function (v) burn_rate.set_max(v) end)
|
||||
r_ps.subscribe("burn_rate", burn_rate.set_value)
|
||||
r_ps.subscribe("max_burn", burn_rate.set_max)
|
||||
|
||||
local dis_colors = cpair(colors.white, colors.lightGray)
|
||||
|
||||
@@ -334,18 +334,24 @@ local function init(parent, id)
|
||||
r_ps.subscribe("rps_tripped", start_button_en_check)
|
||||
r_ps.subscribe("rps_tripped", function (active) if active then reset.enable() else reset.disable() end end)
|
||||
|
||||
TextBox{parent=main,x=2,y=30,text="Idle",width=29,height=1,alignment=TEXT_ALIGN.CENTER,fg_bg=cpair(colors.gray, colors.white)}
|
||||
local stat_line_1 = DataIndicator{parent=main,x=2,y=30,label="",format="%s",value="",width=29,height=1,alignment=TEXT_ALIGN.CENTER,fg_bg=cpair(colors.gray, colors.white)}
|
||||
local stat_line_2 = DataIndicator{parent=main,x=2,y=31,label="",format="%s",value="",width=29,height=1,alignment=TEXT_ALIGN.CENTER,fg_bg=cpair(colors.gray, colors.white)}
|
||||
|
||||
r_ps.subscribe("U_StatusLine1", stat_line_1.update)
|
||||
r_ps.subscribe("U_StatusLine2", stat_line_2.update)
|
||||
|
||||
local waste_sel = Div{parent=main,x=2,y=50,width=29,height=2,fg_bg=cpair(colors.black, colors.white)}
|
||||
|
||||
MultiButton{parent=waste_sel,x=1,y=1,options=waste_opts,callback=unit.set_waste,min_width=6,fg_bg=cpair(colors.black, colors.white)}
|
||||
local waste_mode = MultiButton{parent=waste_sel,x=1,y=1,options=waste_opts,callback=unit.set_waste,min_width=6,fg_bg=cpair(colors.black, colors.white)}
|
||||
TextBox{parent=waste_sel,text="Waste Processing",alignment=TEXT_ALIGN.CENTER,x=1,y=1,height=1}
|
||||
|
||||
r_ps.subscribe("U_WasteMode", waste_mode.set_value)
|
||||
|
||||
----------------------
|
||||
-- alarm management --
|
||||
----------------------
|
||||
|
||||
local alarm_panel = Div{parent=main,x=2,y=32,width=29,height=16,fg_bg=cpair(colors.black,colors.white)}
|
||||
local alarm_panel = Div{parent=main,x=2,y=33,width=29,height=16,fg_bg=cpair(colors.black,colors.white)}
|
||||
|
||||
local a_brc = AlarmLight{parent=alarm_panel,x=6,y=2,label="Containment Breach",c1=colors.gray,c2=colors.red,c3=colors.green,flash=true,period=period.BLINK_250_MS}
|
||||
local a_rad = AlarmLight{parent=alarm_panel,x=6,label="Containment Radiation",c1=colors.gray,c2=colors.red,c3=colors.green,flash=true,period=period.BLINK_250_MS}
|
||||
@@ -362,20 +368,20 @@ local function init(parent, id)
|
||||
local a_clt = AlarmLight{parent=alarm_panel,x=6,label="RCS Transient",c1=colors.gray,c2=colors.yellow,c3=colors.green,flash=true,period=period.BLINK_500_MS}
|
||||
local a_tbt = AlarmLight{parent=alarm_panel,x=6,label="Turbine Trip",c1=colors.gray,c2=colors.red,c3=colors.green,flash=true,period=period.BLINK_250_MS}
|
||||
|
||||
r_ps.subscribe("ALM1", a_brc.update)
|
||||
r_ps.subscribe("ALM2", a_rad.update)
|
||||
r_ps.subscribe("ALM4", a_dmg.update)
|
||||
r_ps.subscribe("Alarm_1", a_brc.update)
|
||||
r_ps.subscribe("Alarm_2", a_rad.update)
|
||||
r_ps.subscribe("Alarm_4", a_dmg.update)
|
||||
|
||||
r_ps.subscribe("ALM3", a_rcl.update)
|
||||
r_ps.subscribe("ALM5", a_rcd.update)
|
||||
r_ps.subscribe("ALM6", a_rot.update)
|
||||
r_ps.subscribe("ALM7", a_rht.update)
|
||||
r_ps.subscribe("ALM8", a_rwl.update)
|
||||
r_ps.subscribe("ALM9", a_rwh.update)
|
||||
r_ps.subscribe("Alarm_3", a_rcl.update)
|
||||
r_ps.subscribe("Alarm_5", a_rcd.update)
|
||||
r_ps.subscribe("Alarm_6", a_rot.update)
|
||||
r_ps.subscribe("Alarm_7", a_rht.update)
|
||||
r_ps.subscribe("Alarm_8", a_rwl.update)
|
||||
r_ps.subscribe("Alarm_9", a_rwh.update)
|
||||
|
||||
r_ps.subscribe("ALM10", a_rps.update)
|
||||
r_ps.subscribe("ALM11", a_clt.update)
|
||||
r_ps.subscribe("ALM12", a_tbt.update)
|
||||
r_ps.subscribe("Alarm_10", a_rps.update)
|
||||
r_ps.subscribe("Alarm_11", a_clt.update)
|
||||
r_ps.subscribe("Alarm_12", a_tbt.update)
|
||||
|
||||
-- ack's and resets
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
local iocontrol = require("coordinator.iocontrol")
|
||||
local sounder = require("coordinator.sounder")
|
||||
local util = require("scada-common.util")
|
||||
|
||||
local style = require("coordinator.ui.style")
|
||||
|
||||
@@ -28,32 +29,46 @@ local function init(monitor)
|
||||
local main = DisplayBox{window=monitor,fg_bg=style.root}
|
||||
|
||||
-- window header message
|
||||
TextBox{parent=main,text="Nuclear Generation Facility SCADA Coordinator",alignment=TEXT_ALIGN.CENTER,height=1,fg_bg=style.header}
|
||||
local header = TextBox{parent=main,text="Nuclear Generation Facility SCADA Coordinator",alignment=TEXT_ALIGN.CENTER,height=1,fg_bg=style.header}
|
||||
|
||||
local db = iocontrol.get_db()
|
||||
|
||||
local uo_1, uo_2, uo_3, uo_4 ---@type graphics_element
|
||||
|
||||
local cnc_y_start = 3
|
||||
|
||||
-- unit overviews
|
||||
if db.facility.num_units >= 1 then uo_1 = unit_overview(main, 2, 3, db.units[1]) end
|
||||
if db.facility.num_units >= 2 then uo_2 = unit_overview(main, 84, 3, db.units[2]) end
|
||||
if db.facility.num_units >= 1 then
|
||||
uo_1 = unit_overview(main, 2, 3, db.units[1])
|
||||
cnc_y_start = cnc_y_start + uo_1.height() + 1
|
||||
end
|
||||
|
||||
if db.facility.num_units >= 2 then
|
||||
uo_2 = unit_overview(main, 84, 3, db.units[2])
|
||||
end
|
||||
|
||||
if db.facility.num_units >= 3 then
|
||||
-- base offset 3, spacing 1, max height of units 1 and 2
|
||||
local row_2_offset = 3 + 1 + math.max(uo_1.height(), uo_2.height())
|
||||
|
||||
uo_3 = unit_overview(main, 2, row_2_offset, db.units[3])
|
||||
if db.facility.num_units == 4 then uo_4 = unit_overview(main, 84, row_2_offset, db.units[4]) end
|
||||
cnc_y_start = cnc_y_start + uo_3.height() + 1
|
||||
|
||||
if db.facility.num_units == 4 then
|
||||
uo_4 = unit_overview(main, 84, row_2_offset, db.units[4])
|
||||
end
|
||||
end
|
||||
|
||||
-- command & control
|
||||
|
||||
TextBox{parent=main,y=cnc_y_start,text=util.strrep("\x8c", header.width()),alignment=TEXT_ALIGN.CENTER,height=1,fg_bg=style.header}
|
||||
|
||||
-- testing
|
||||
---@fixme remove test code
|
||||
|
||||
ColorMap{parent=main,x=2,y=(main.height()-1)}
|
||||
|
||||
PushButton{parent=main,x=2,y=(main.height()-20),text="TEST 1",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_1}
|
||||
PushButton{parent=main,x=2,y=(cnc_y_start+2),text="TEST 1",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_1}
|
||||
PushButton{parent=main,x=2,text="TEST 2",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_2}
|
||||
PushButton{parent=main,x=2,text="TEST 3",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_3}
|
||||
PushButton{parent=main,x=2,text="TEST 4",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_4}
|
||||
@@ -64,7 +79,7 @@ local function init(monitor)
|
||||
PushButton{parent=main,x=2,text="STOP",min_width=8,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.stop}
|
||||
PushButton{parent=main,x=2,text="PSCALE",min_width=8,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_power_scale}
|
||||
|
||||
SwitchButton{parent=main,x=12,y=(main.height()-20),text="CONTAINMENT BREACH",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_breach}
|
||||
SwitchButton{parent=main,x=12,y=(cnc_y_start+2),text="CONTAINMENT BREACH",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_breach}
|
||||
SwitchButton{parent=main,x=12,text="CONTAINMENT RADIATION",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_rad}
|
||||
SwitchButton{parent=main,x=12,text="REACTOR LOST",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_lost}
|
||||
SwitchButton{parent=main,x=12,text="CRITICAL DAMAGE",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_crit}
|
||||
|
||||
@@ -2,15 +2,11 @@
|
||||
-- Reactor Unit SCADA Coordinator GUI
|
||||
--
|
||||
|
||||
local tcallbackdsp = require("scada-common.tcallbackdsp")
|
||||
local style = require("coordinator.ui.style")
|
||||
|
||||
local iocontrol = require("coordinator.iocontrol")
|
||||
local unit_detail = require("coordinator.ui.components.unit_detail")
|
||||
|
||||
local style = require("coordinator.ui.style")
|
||||
|
||||
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
|
||||
---@param monitor table
|
||||
|
||||
Reference in New Issue
Block a user