mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#162 #168 status indicator for emergency coolant, display number of connected RTUs, added RCS hardware fault and radiation warning indicators
This commit is contained in:
parent
199ce53f52
commit
2babd67198
@ -23,7 +23,9 @@ local io = {}
|
||||
function iocontrol.init(conf, comms)
|
||||
---@class ioctl_facility
|
||||
io.facility = {
|
||||
num_units = conf.num_units, ---@type integer
|
||||
all_sys_ok = false,
|
||||
rtu_count = 0,
|
||||
|
||||
auto_ready = false,
|
||||
auto_active = false,
|
||||
@ -42,8 +44,6 @@ function iocontrol.init(conf, comms)
|
||||
|
||||
radiation = types.new_zero_radiation_reading(),
|
||||
|
||||
num_units = conf.num_units, ---@type integer
|
||||
|
||||
save_cfg_ack = function (success) end, ---@param success boolean
|
||||
start_ack = function (success) end, ---@param success boolean
|
||||
stop_ack = function (success) end, ---@param success boolean
|
||||
@ -336,7 +336,12 @@ function iocontrol.update_facility_status(status)
|
||||
|
||||
local rtu_statuses = status[2]
|
||||
|
||||
fac.rtu_count = 0
|
||||
if type(rtu_statuses) == "table" then
|
||||
-- connected RTU count
|
||||
fac.rtu_count = rtu_statuses.count
|
||||
fac.ps.publish("rtu_count", fac.rtu_count)
|
||||
|
||||
-- power statistics
|
||||
if type(rtu_statuses.power) == "table" then
|
||||
fac.induction_ps_tbl[1].publish("avg_charge", rtu_statuses.power[1])
|
||||
@ -406,13 +411,15 @@ function iocontrol.update_facility_status(status)
|
||||
fac.ps.publish("rad_computed_status", util.trinary(rtu_faulted, 2, 3))
|
||||
fac.ps.publish("radiation", fac.radiation)
|
||||
else
|
||||
fac.radiation = { radiation = 0, unit = "nSv" }
|
||||
fac.radiation = types.new_zero_radiation_reading()
|
||||
fac.ps.publish("rad_computed_status", 1)
|
||||
end
|
||||
else
|
||||
log.debug(log_header .. "radiation monitor list not a table")
|
||||
return false
|
||||
end
|
||||
else
|
||||
log.debug(log_header .. "rtu statuses not a table")
|
||||
end
|
||||
end
|
||||
|
||||
@ -626,11 +633,9 @@ function iocontrol.update_unit_statuses(statuses)
|
||||
local rtu_faulted = rad_mon[1] ---@type boolean
|
||||
unit.radiation = rad_mon[2] ---@type number
|
||||
|
||||
unit.unit_ps.publish("rad_computed_status", util.trinary(rtu_faulted, 2, 3))
|
||||
unit.unit_ps.publish("radiation", unit.radiation)
|
||||
else
|
||||
unit.radiation = { radiation = 0, unit = "nSv" }
|
||||
unit.unit_ps.publish("rad_computed_status", 1)
|
||||
unit.radiation = types.new_zero_radiation_reading()
|
||||
end
|
||||
else
|
||||
log.debug(log_header .. "radiation monitor list not a table")
|
||||
|
@ -19,7 +19,7 @@ local iocontrol = require("coordinator.iocontrol")
|
||||
local renderer = require("coordinator.renderer")
|
||||
local sounder = require("coordinator.sounder")
|
||||
|
||||
local COORDINATOR_VERSION = "beta-v0.9.12"
|
||||
local COORDINATOR_VERSION = "beta-v0.9.13"
|
||||
|
||||
local print = util.print
|
||||
local println = util.println
|
||||
|
@ -90,10 +90,14 @@ local function new_view(root, x, y)
|
||||
facility.ps.subscribe("as_radiation", fac_rad_h.update)
|
||||
facility.ps.subscribe("as_gen_fault", gen_fault.update)
|
||||
|
||||
TextBox{parent=main,y=23,text="Radiation",height=1,width=21,fg_bg=style.label}
|
||||
TextBox{parent=main,y=23,text="Radiation",height=1,width=13,fg_bg=style.label}
|
||||
local radiation = RadIndicator{parent=main,label="",format="%9.3f",lu_colors=lu_cpair,width=13,fg_bg=bw_fg_bg}
|
||||
facility.ps.subscribe("radiation", radiation.update)
|
||||
|
||||
TextBox{parent=main,x=15,y=23,text="Linked RTUs",height=1,width=11,fg_bg=style.label}
|
||||
local rtu_count = DataIndicator{parent=main,x=15,y=24,label="",format="%11d",value=0,lu_colors=lu_cpair,width=11,fg_bg=bw_fg_bg}
|
||||
facility.ps.subscribe("rtu_count", rtu_count.update)
|
||||
|
||||
---------------------
|
||||
-- process control --
|
||||
---------------------
|
||||
|
@ -157,28 +157,29 @@ local function init(parent, id)
|
||||
|
||||
local annunciator = Div{parent=main,width=23,height=18,x=22,y=3}
|
||||
|
||||
-- connectivity/basic state
|
||||
-- connectivity
|
||||
local plc_online = IndicatorLight{parent=annunciator,label="PLC Online",colors=cpair(colors.green,colors.red)}
|
||||
local plc_hbeat = IndicatorLight{parent=annunciator,label="PLC Heartbeat",colors=cpair(colors.white,colors.gray)}
|
||||
local r_active = IndicatorLight{parent=annunciator,label="Active",colors=cpair(colors.green,colors.gray)}
|
||||
local r_auto = IndicatorLight{parent=annunciator,label="Automatic Control",colors=cpair(colors.blue,colors.gray)}
|
||||
|
||||
annunciator.line_break()
|
||||
|
||||
local rad_mon = TriIndicatorLight{parent=annunciator,label="Radiation Monitor",c1=colors.gray,c2=colors.yellow,c3=colors.green}
|
||||
|
||||
u_ps.subscribe("PLCOnline", plc_online.update)
|
||||
u_ps.subscribe("PLCHeartbeat", plc_hbeat.update)
|
||||
u_ps.subscribe("status", r_active.update)
|
||||
u_ps.subscribe("AutoControl", r_auto.update)
|
||||
u_ps.subscribe("rad_computed_status", rad_mon.update)
|
||||
u_ps.subscribe("RadiationMonitor", rad_mon.update)
|
||||
|
||||
annunciator.line_break()
|
||||
|
||||
-- non-RPS reactor annunciator panel
|
||||
-- operating state
|
||||
local r_active = IndicatorLight{parent=annunciator,label="Active",colors=cpair(colors.green,colors.gray)}
|
||||
local r_auto = IndicatorLight{parent=annunciator,label="Automatic Control",colors=cpair(colors.white,colors.gray)}
|
||||
|
||||
u_ps.subscribe("status", r_active.update)
|
||||
u_ps.subscribe("AutoControl", r_auto.update)
|
||||
|
||||
-- main unit transient/warning annunciator panel
|
||||
local r_scram = IndicatorLight{parent=annunciator,label="Reactor SCRAM",colors=cpair(colors.red,colors.gray)}
|
||||
local r_mscrm = IndicatorLight{parent=annunciator,label="Manual Reactor SCRAM",colors=cpair(colors.red,colors.gray)}
|
||||
local r_ascrm = IndicatorLight{parent=annunciator,label="Auto Reactor SCRAM",colors=cpair(colors.red,colors.gray)}
|
||||
local rad_wrn = IndicatorLight{parent=annunciator,label="Radiation Warning",colors=cpair(colors.yellow,colors.gray)}
|
||||
local r_rtrip = IndicatorLight{parent=annunciator,label="RCP Trip",colors=cpair(colors.red,colors.gray)}
|
||||
local r_cflow = IndicatorLight{parent=annunciator,label="RCS Flow Low",colors=cpair(colors.yellow,colors.gray)}
|
||||
local r_clow = IndicatorLight{parent=annunciator,label="Coolant Level Low",colors=cpair(colors.yellow,colors.gray)}
|
||||
@ -191,6 +192,7 @@ local function init(parent, id)
|
||||
u_ps.subscribe("ReactorSCRAM", r_scram.update)
|
||||
u_ps.subscribe("ManualReactorSCRAM", r_mscrm.update)
|
||||
u_ps.subscribe("AutoReactorSCRAM", r_ascrm.update)
|
||||
u_ps.subscribe("RadiationWarning", rad_wrn.update)
|
||||
u_ps.subscribe("RCPTrip", r_rtrip.update)
|
||||
u_ps.subscribe("RCSFlowLow", r_cflow.update)
|
||||
u_ps.subscribe("CoolantLevelLow", r_clow.update)
|
||||
@ -233,14 +235,18 @@ local function init(parent, id)
|
||||
TextBox{parent=main,text="REACTOR COOLANT SYSTEM",fg_bg=cpair(colors.black,colors.blue),alignment=TEXT_ALIGN.CENTER,width=33,height=1,x=46,y=22}
|
||||
local rcs = Rectangle{parent=main,border=border(1,colors.blue,true),thin=true,width=33,height=24,x=46,y=23}
|
||||
local rcs_annunc = Div{parent=rcs,width=27,height=22,x=2,y=1}
|
||||
local rcs_tags = Div{parent=rcs,width=2,height=22,x=29,y=1}
|
||||
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_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_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_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}
|
||||
|
||||
u_ps.subscribe("RCSFault", c_flt.update)
|
||||
u_ps.subscribe("EmergencyCoolant", c_emg.update)
|
||||
u_ps.subscribe("CoolantFeedMismatch", c_cfm.update)
|
||||
u_ps.subscribe("BoilRateMismatch", c_brm.update)
|
||||
u_ps.subscribe("SteamFeedMismatch", c_sfm.update)
|
||||
@ -252,7 +258,7 @@ local function init(parent, id)
|
||||
-- boiler annunciator panel(s)
|
||||
|
||||
if unit.num_boilers > 0 then
|
||||
TextBox{parent=rcs_tags,x=1,y=7,text="B1",width=2,height=1,fg_bg=bw_fg_bg}
|
||||
TextBox{parent=rcs_tags,x=1,text="B1",width=2,height=1,fg_bg=bw_fg_bg}
|
||||
local b1_wll = IndicatorLight{parent=rcs_annunc,label="Water Level Low",colors=cpair(colors.red,colors.gray)}
|
||||
b_ps[1].subscribe("WasterLevelLow", b1_wll.update)
|
||||
|
||||
@ -273,7 +279,7 @@ local function init(parent, id)
|
||||
-- turbine annunciator panels
|
||||
|
||||
if unit.num_boilers == 0 then
|
||||
TextBox{parent=rcs_tags,y=7,text="T1",width=2,height=1,fg_bg=bw_fg_bg}
|
||||
TextBox{parent=rcs_tags,text="T1",width=2,height=1,fg_bg=bw_fg_bg}
|
||||
else
|
||||
rcs_tags.line_break()
|
||||
rcs_annunc.line_break()
|
||||
@ -292,9 +298,6 @@ local function init(parent, id)
|
||||
t_ps[1].subscribe("TurbineTrip", t1_trp.update)
|
||||
|
||||
if unit.num_turbines > 1 then
|
||||
rcs_tags.line_break()
|
||||
rcs_annunc.line_break()
|
||||
|
||||
TextBox{parent=rcs_tags,text="T2",width=2,height=1,fg_bg=bw_fg_bg}
|
||||
local t2_sdo = TriIndicatorLight{parent=rcs_annunc,label="Steam Relief Valve Open",c1=colors.gray,c2=colors.yellow,c3=colors.red}
|
||||
t_ps[2].subscribe("SteamDumpOpen", function (val) t2_sdo.update(val + 1) end)
|
||||
@ -309,9 +312,6 @@ local function init(parent, id)
|
||||
end
|
||||
|
||||
if unit.num_turbines > 2 then
|
||||
rcs_tags.line_break()
|
||||
rcs_annunc.line_break()
|
||||
|
||||
TextBox{parent=rcs_tags,text="T3",width=2,height=1,fg_bg=bw_fg_bg}
|
||||
local t3_sdo = TriIndicatorLight{parent=rcs_annunc,label="Steam Relief Valve Open",c1=colors.gray,c2=colors.yellow,c3=colors.red}
|
||||
t_ps[3].subscribe("SteamDumpOpen", function (val) t3_sdo.update(val + 1) end)
|
||||
|
@ -1,5 +1,6 @@
|
||||
-- Radiation Indicator Graphics Element
|
||||
|
||||
local types = require("scada-common.types")
|
||||
local util = require("scada-common.util")
|
||||
|
||||
local element = require("graphics.element")
|
||||
@ -80,7 +81,7 @@ local function rad(args)
|
||||
function e.set_value(val) e.on_update(val) end
|
||||
|
||||
-- initial value draw
|
||||
e.on_update({ radiation = 0, unit = "nSv" })
|
||||
e.on_update(types.new_zero_radiation_reading())
|
||||
|
||||
return e.get()
|
||||
end
|
||||
|
@ -14,7 +14,7 @@ util.TICK_TIME_MS = 50
|
||||
--#region
|
||||
|
||||
-- trinary operator
|
||||
---@param cond boolean condition
|
||||
---@param cond boolean|nil condition
|
||||
---@param a any return if true
|
||||
---@param b any return if false
|
||||
---@return any value
|
||||
|
@ -60,6 +60,7 @@ function facility.new(num_reactors, cooling_conf)
|
||||
envd = {},
|
||||
status_text = { "START UP", "initializing..." },
|
||||
all_sys_ok = false,
|
||||
rtu_conn_count = 0,
|
||||
-- process control
|
||||
units_ready = false,
|
||||
mode = PROCESS.INACTIVE,
|
||||
@ -224,6 +225,12 @@ function facility.new(num_reactors, cooling_conf)
|
||||
|
||||
-- UPDATE --
|
||||
|
||||
-- supervisor sessions reporting the list of active RTU sessions
|
||||
---@param rtu_sessions table session list of all connected RTUs
|
||||
function public.report_rtus(rtu_sessions)
|
||||
self.rtu_conn_count = #rtu_sessions
|
||||
end
|
||||
|
||||
-- update (iterate) the facility management
|
||||
function public.update()
|
||||
-- unlink RTU unit sessions if they are closed
|
||||
@ -801,6 +808,9 @@ function facility.new(num_reactors, cooling_conf)
|
||||
function public.get_rtu_statuses()
|
||||
local status = {}
|
||||
|
||||
-- total count of all connected RTUs in the facility
|
||||
status.count = self.rtu_conn_count
|
||||
|
||||
-- power averages from induction matricies
|
||||
status.power = {
|
||||
self.avg_charge.compute(),
|
||||
|
@ -144,7 +144,7 @@ end
|
||||
---@param sessions table
|
||||
local function _close(sessions)
|
||||
for i = 1, #sessions do
|
||||
local session = sessions[i] ---@type plc_session_struct
|
||||
local session = sessions[i] ---@type plc_session_struct|rtu_session_struct
|
||||
if session.open then
|
||||
_shutdown(session)
|
||||
end
|
||||
@ -156,7 +156,7 @@ end
|
||||
---@param timer_event number
|
||||
local function _check_watchdogs(sessions, timer_event)
|
||||
for i = 1, #sessions do
|
||||
local session = sessions[i] ---@type plc_session_struct
|
||||
local session = sessions[i] ---@type plc_session_struct|rtu_session_struct
|
||||
if session.open then
|
||||
local triggered = session.instance.check_wd(timer_event)
|
||||
if triggered then
|
||||
@ -400,6 +400,9 @@ function svsessions.iterate_all()
|
||||
-- iterate coordinator sessions
|
||||
_iterate(self.coord_sessions)
|
||||
|
||||
-- report RTU sessions to facility
|
||||
self.facility.report_rtus(self.rtu_sessions)
|
||||
|
||||
-- iterate facility
|
||||
self.facility.update()
|
||||
|
||||
|
@ -163,10 +163,12 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
||||
-- reactor
|
||||
PLCOnline = false,
|
||||
PLCHeartbeat = false, -- alternate true/false to blink, each time there is a keep_alive
|
||||
RadiationMonitor = 1,
|
||||
AutoControl = false,
|
||||
ReactorSCRAM = false,
|
||||
ManualReactorSCRAM = false,
|
||||
AutoReactorSCRAM = false,
|
||||
RadiationWarning = false,
|
||||
RCPTrip = false,
|
||||
RCSFlowLow = false,
|
||||
CoolantLevelLow = false,
|
||||
@ -175,16 +177,19 @@ function unit.new(for_reactor, num_boilers, num_turbines)
|
||||
FuelInputRateLow = false,
|
||||
WasteLineOcclusion = false,
|
||||
HighStartupRate = false,
|
||||
-- boiler
|
||||
-- cooling
|
||||
RCSFault = false,
|
||||
EmergencyCoolant = 1,
|
||||
CoolantFeedMismatch = false,
|
||||
BoilRateMismatch = false,
|
||||
SteamFeedMismatch = false,
|
||||
MaxWaterReturnFeed = false,
|
||||
-- boilers
|
||||
BoilerOnline = {},
|
||||
HeatingRateLow = {},
|
||||
WaterLevelLow = {},
|
||||
BoilRateMismatch = false,
|
||||
CoolantFeedMismatch = false,
|
||||
-- turbine
|
||||
-- turbines
|
||||
TurbineOnline = {},
|
||||
SteamFeedMismatch = false,
|
||||
MaxWaterReturnFeed = false,
|
||||
SteamDumpOpen = {},
|
||||
TurbineOverSpeed = {},
|
||||
TurbineTrip = {}
|
||||
|
@ -1,4 +1,5 @@
|
||||
local log = require("scada-common.log")
|
||||
local rsio = require("scada-common.rsio")
|
||||
local types = require("scada-common.types")
|
||||
local util = require("scada-common.util")
|
||||
|
||||
@ -7,6 +8,8 @@ local ALARM_STATE = types.ALARM_STATE
|
||||
local TRI_FAIL = types.TRI_FAIL
|
||||
local DUMPING_MODE = types.DUMPING_MODE
|
||||
|
||||
local IO = rsio.IO
|
||||
|
||||
local aistate_string = {
|
||||
"INACTIVE",
|
||||
"TRIPPING",
|
||||
@ -19,6 +22,7 @@ local aistate_string = {
|
||||
-- background radiation 0.0000001 Sv/h (99.99 nSv/h)
|
||||
-- "green tint" radiation 0.00001 Sv/h (10 uSv/h)
|
||||
-- damaging radiation 0.00006 Sv/h (60 uSv/h)
|
||||
local RADIATION_ALERT_LEVEL = 0.00001 -- 10 uSv/h
|
||||
local RADIATION_ALARM_LEVEL = 0.00005 -- 50 uSv/h, not yet damaging but this isn't good
|
||||
|
||||
---@class unit_logic_extension
|
||||
@ -33,6 +37,8 @@ function logic.update_annunciator(self)
|
||||
local num_boilers = self.num_boilers
|
||||
local num_turbines = self.num_turbines
|
||||
|
||||
self.db.annunciator.RCSFault = false
|
||||
|
||||
-- variables for boiler, or reactor if no boilers used
|
||||
local total_boil_rate = 0.0
|
||||
|
||||
@ -114,6 +120,29 @@ function logic.update_annunciator(self)
|
||||
self.plc_cache.ok = false
|
||||
end
|
||||
|
||||
---------------
|
||||
-- MISC RTUs --
|
||||
---------------
|
||||
|
||||
self.db.annunciator.RadiationMonitor = 1
|
||||
self.db.annunciator.RadiationWarning = false
|
||||
for i = 1, #self.envd do
|
||||
local envd = self.envd[i] ---@type unit_session
|
||||
self.db.annunciator.RadiationMonitor = util.trinary(envd.is_faulted(), 2, 3)
|
||||
self.db.annunciator.RadiationWarning = envd.get_db().radiation_raw > RADIATION_ALERT_LEVEL
|
||||
break
|
||||
end
|
||||
|
||||
self.db.annunciator.EmergencyCoolant = 1
|
||||
for i = 1, #self.redstone do
|
||||
local db = self.redstone[i].get_db() ---@type redstone_session_db
|
||||
local io = db.io[IO.U_EMER_COOL] ---@type rs_db_dig_io|nil
|
||||
if io ~= nil then
|
||||
self.db.annunciator.EmergencyCoolant = util.trinary(io.read(), 3, 2)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-------------
|
||||
-- BOILERS --
|
||||
-------------
|
||||
@ -133,6 +162,8 @@ function logic.update_annunciator(self)
|
||||
local session = self.boilers[i] ---@type unit_session
|
||||
local boiler = session.get_db() ---@type boilerv_session_db
|
||||
|
||||
self.db.annunciator.RCSFault = self.db.annunciator.RCSFault or (not boiler.formed) or session.is_faulted()
|
||||
|
||||
-- update ready state
|
||||
-- - must be formed
|
||||
-- - must have received build, state, and tanks at least once
|
||||
@ -225,6 +256,8 @@ function logic.update_annunciator(self)
|
||||
local session = self.turbines[i] ---@type unit_session
|
||||
local turbine = session.get_db() ---@type turbinev_session_db
|
||||
|
||||
self.db.annunciator.RCSFault = self.db.annunciator.RCSFault or (not turbine.formed) or session.is_faulted()
|
||||
|
||||
-- update ready state
|
||||
-- - must be formed
|
||||
-- - must have received build, state, and tanks at least once
|
||||
|
@ -14,7 +14,7 @@ local svsessions = require("supervisor.session.svsessions")
|
||||
local config = require("supervisor.config")
|
||||
local supervisor = require("supervisor.supervisor")
|
||||
|
||||
local SUPERVISOR_VERSION = "beta-v0.11.7"
|
||||
local SUPERVISOR_VERSION = "beta-v0.11.8"
|
||||
|
||||
local print = util.print
|
||||
local println = util.println
|
||||
|
Loading…
Reference in New Issue
Block a user