Merge pull request #585 from MikaylaFischler/479-sodium-emergency-coolant

479 Sodium Emergency Coolant
This commit is contained in:
Mikayla 2024-12-20 20:47:36 -05:00 committed by GitHub
commit fd414a814c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 495 additions and 191 deletions

View File

@ -231,7 +231,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
TextBox{parent=fac_c_2,x=1,y=1,height=3,text="Please enter the number of reactors you have, also referred to as reactor units or 'units' for short. A maximum of 4 is currently supported."} TextBox{parent=fac_c_2,x=1,y=1,height=3,text="Please enter the number of reactors you have, also referred to as reactor units or 'units' for short. A maximum of 4 is currently supported."}
tool_ctl.num_units = NumberField{parent=fac_c_2,x=1,y=5,width=5,max_chars=2,default=ini_cfg.UnitCount,min=1,max=4,fg_bg=bw_fg_bg} tool_ctl.num_units = NumberField{parent=fac_c_2,x=1,y=5,width=5,max_chars=2,default=ini_cfg.UnitCount,min=1,max=4,fg_bg=bw_fg_bg}
TextBox{parent=fac_c_2,x=7,y=5,text="reactors"} TextBox{parent=fac_c_2,x=7,y=5,text="reactors"}
TextBox{parent=fac_c_2,x=1,y=7,height=3,text="This will decide how many monitors you need. If this does not match the supervisor's number of reactor units, the coordinator will not connect.",fg_bg=g_lg_fg_bg} TextBox{parent=fac_c_2,x=1,y=7,height=3,text="This will decide how many monitors you need. If this does not match the supervisor's number of reactor units, the coordinator will not connect.",fg_bg=cpair(colors.yellow,colors._INHERIT)}
TextBox{parent=fac_c_2,x=1,y=10,height=3,text="Since you skipped supervisor sync, the main monitor minimum height can't be determined precisely. It is marked with * on the next page.",fg_bg=g_lg_fg_bg} TextBox{parent=fac_c_2,x=1,y=10,height=3,text="Since you skipped supervisor sync, the main monitor minimum height can't be determined precisely. It is marked with * on the next page.",fg_bg=g_lg_fg_bg}
local nu_error = TextBox{parent=fac_c_2,x=8,y=14,width=35,text="Please set the number of reactors.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local nu_error = TextBox{parent=fac_c_2,x=8,y=14,width=35,text="Please set the number of reactors.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}

View File

@ -88,6 +88,8 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale)
tank_mode = conf.cooling.fac_tank_mode, tank_mode = conf.cooling.fac_tank_mode,
tank_defs = conf.cooling.fac_tank_defs, tank_defs = conf.cooling.fac_tank_defs,
tank_list = conf.cooling.fac_tank_list, tank_list = conf.cooling.fac_tank_list,
tank_conns = conf.cooling.fac_tank_conns,
tank_fluid_types = conf.cooling.tank_fluid_types,
all_sys_ok = false, all_sys_ok = false,
rtu_count = 0, rtu_count = 0,
@ -116,7 +118,7 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale)
radiation = types.new_zero_radiation_reading(), radiation = types.new_zero_radiation_reading(),
save_cfg_ack = nil, ---@type fun(success: boolean) save_cfg_ack = nil, ---@type fun(success: boolean)
---@type { [TONE]: boolean } ---@type { [TONE]: boolean }
alarm_tones = { false, false, false, false, false, false, false, false }, alarm_tones = { false, false, false, false, false, false, false, false },

View File

@ -19,7 +19,7 @@ local renderer = require("coordinator.renderer")
local sounder = require("coordinator.sounder") local sounder = require("coordinator.sounder")
local threads = require("coordinator.threads") local threads = require("coordinator.threads")
local COORDINATOR_VERSION = "v1.5.17" local COORDINATOR_VERSION = "v1.6.0"
local CHUNK_LOAD_DELAY_S = 30.0 local CHUNK_LOAD_DELAY_S = 30.0

View File

@ -2,8 +2,11 @@
-- Basic Unit Flow Overview -- Basic Unit Flow Overview
-- --
local types = require("scada-common.types")
local util = require("scada-common.util") local util = require("scada-common.util")
local iocontrol = require("coordinator.iocontrol")
local style = require("coordinator.ui.style") local style = require("coordinator.ui.style")
local core = require("graphics.core") local core = require("graphics.core")
@ -19,6 +22,8 @@ local DataIndicator = require("graphics.elements.indicators.DataIndicator")
local IndicatorLight = require("graphics.elements.indicators.IndicatorLight") local IndicatorLight = require("graphics.elements.indicators.IndicatorLight")
local TriIndicatorLight = require("graphics.elements.indicators.TriIndicatorLight") local TriIndicatorLight = require("graphics.elements.indicators.TriIndicatorLight")
local COOLANT_TYPE = types.COOLANT_TYPE
local ALIGN = core.ALIGN local ALIGN = core.ALIGN
local sprintf = util.sprintf local sprintf = util.sprintf
@ -35,8 +40,8 @@ local lg_gray = style.lg_gray
---@param x integer top left x ---@param x integer top left x
---@param y integer top left y ---@param y integer top left y
---@param wide boolean whether to render wide version ---@param wide boolean whether to render wide version
---@param unit ioctl_unit unit database entry ---@param unit_id integer unit index
local function make(parent, x, y, wide, unit) local function make(parent, x, y, wide, unit_id)
local s_field = style.theme.field_box local s_field = style.theme.field_box
local text_c = style.text_colors local text_c = style.text_colors
@ -48,6 +53,12 @@ local function make(parent, x, y, wide, unit)
local height = 16 local height = 16
local facility = iocontrol.get_db().facility
local unit = iocontrol.get_db().units[unit_id]
local tank_conns = facility.tank_conns
local tank_types = facility.tank_fluid_types
local v_start = 1 + ((unit.unit_id - 1) * 5) local v_start = 1 + ((unit.unit_id - 1) * 5)
local prv_start = 1 + ((unit.unit_id - 1) * 3) local prv_start = 1 + ((unit.unit_id - 1) * 3)
local v_fields = { "pu", "po", "pl", "am" } local v_fields = { "pu", "po", "pl", "am" }
@ -80,21 +91,22 @@ local function make(parent, x, y, wide, unit)
local rc_pipes = {} local rc_pipes = {}
local emc_x = 42 -- emergency coolant connection x point
if unit.num_boilers > 0 then if unit.num_boilers > 0 then
table.insert(rc_pipes, pipe(0, 1, _wide(28, 19), 1, colors.lightBlue, true)) table.insert(rc_pipes, pipe(0, 1, _wide(28, 19), 1, colors.lightBlue, true))
table.insert(rc_pipes, pipe(0, 3, _wide(28, 19), 3, colors.orange, true)) table.insert(rc_pipes, pipe(0, 3, _wide(28, 19), 3, colors.orange, true))
table.insert(rc_pipes, pipe(_wide(46 ,39), 1, _wide(72,58), 1, colors.blue, true)) table.insert(rc_pipes, pipe(_wide(46 ,39), 1, _wide(72,58), 1, colors.blue, true))
table.insert(rc_pipes, pipe(_wide(46,39), 3, _wide(72,58), 3, colors.white, true)) table.insert(rc_pipes, pipe(_wide(46,39), 3, _wide(72,58), 3, colors.white, true))
else else
emc_x = 3
table.insert(rc_pipes, pipe(0, 1, _wide(72,58), 1, colors.blue, true)) table.insert(rc_pipes, pipe(0, 1, _wide(72,58), 1, colors.blue, true))
table.insert(rc_pipes, pipe(0, 3, _wide(72,58), 3, colors.white, true)) table.insert(rc_pipes, pipe(0, 3, _wide(72,58), 3, colors.white, true))
end end
if unit.has_tank then if unit.has_tank then
table.insert(rc_pipes, pipe(emc_x, 1, emc_x, 0, colors.blue, true, true)) local is_water = tank_types[tank_conns[unit_id]] == COOLANT_TYPE.WATER
-- emergency coolant connection x point
local emc_x = util.trinary(is_water and (unit.num_boilers > 0), 42, 3)
table.insert(rc_pipes, pipe(emc_x, 1, emc_x, 0, util.trinary(is_water, colors.blue, colors.lightBlue), true, true))
end end
local prv_yo = math.max(3 - unit.num_turbines, 0) local prv_yo = math.max(3 - unit.num_turbines, 0)

View File

@ -24,6 +24,7 @@ local IndicatorLight = require("graphics.elements.indicators.IndicatorLight")
local StateIndicator = require("graphics.elements.indicators.StateIndicator") local StateIndicator = require("graphics.elements.indicators.StateIndicator")
local CONTAINER_MODE = types.CONTAINER_MODE local CONTAINER_MODE = types.CONTAINER_MODE
local COOLANT_TYPE = types.COOLANT_TYPE
local ALIGN = core.ALIGN local ALIGN = core.ALIGN
@ -45,8 +46,10 @@ local function init(main)
local facility = iocontrol.get_db().facility local facility = iocontrol.get_db().facility
local units = iocontrol.get_db().units local units = iocontrol.get_db().units
local tank_defs = facility.tank_defs local tank_defs = facility.tank_defs
local tank_list = facility.tank_list local tank_conns = facility.tank_conns
local tank_list = facility.tank_list
local tank_types = facility.tank_fluid_types
-- window header message -- window header message
local header = TextBox{parent=main,y=1,text="Facility Coolant and Waste Flow Monitor",alignment=ALIGN.CENTER,fg_bg=style.theme.header} local header = TextBox{parent=main,y=1,text="Facility Coolant and Waste Flow Monitor",alignment=ALIGN.CENTER,fg_bg=style.theme.header}
@ -56,12 +59,16 @@ local function init(main)
datetime.register(facility.ps, "date_time", datetime.set_value) datetime.register(facility.ps, "date_time", datetime.set_value)
local po_pipes = {} local po_pipes = {}
local water_pipes = {} local emcool_pipes = {}
-- get the y offset for this unit index -- get the y offset for this unit index
---@param idx integer unit index ---@param idx integer unit index
local function y_ofs(idx) return ((idx - 1) * 20) end local function y_ofs(idx) return ((idx - 1) * 20) end
-- get the coolant color
---@param idx integer tank index
local function c_clr(idx) return util.trinary(tank_types[tank_conns[idx]] == COOLANT_TYPE.WATER, colors.blue, colors.lightBlue) end
-- determinte facility tank start/end from the definitions list -- determinte facility tank start/end from the definitions list
---@param start_idx integer start index of table iteration ---@param start_idx integer start index of table iteration
---@param end_idx integer end index of table iteration ---@param end_idx integer end index of table iteration
@ -81,11 +88,13 @@ local function init(main)
for i = 1, facility.num_units do for i = 1, facility.num_units do
if units[i].has_tank then if units[i].has_tank then
local y = y_ofs(i) local y = y_ofs(i)
table.insert(water_pipes, pipe(2, y, 2, y + 3, colors.blue, true)) local color = c_clr(i)
table.insert(water_pipes, pipe(2, y, 21, y, colors.blue, true))
local x = util.trinary(units[i].num_boilers == 0, 45, 84) table.insert(emcool_pipes, pipe(2, y, 2, y + 3, color, true))
table.insert(water_pipes, pipe(21, y, x, y + 2, colors.blue, true, true)) table.insert(emcool_pipes, pipe(2, y, 21, y, color, true))
local x = util.trinary((tank_types[tank_conns[i]] == COOLANT_TYPE.SODIUM) or (units[i].num_boilers == 0), 45, 84)
table.insert(emcool_pipes, pipe(21, y, x, y + 2, color, true, true))
end end
end end
else else
@ -93,16 +102,17 @@ local function init(main)
for i = 1, #tank_defs do for i = 1, #tank_defs do
if tank_defs[i] > 0 then if tank_defs[i] > 0 then
local y = y_ofs(i) local y = y_ofs(i)
local color = c_clr(i)
if tank_defs[i] == 2 then if tank_defs[i] == 2 then
table.insert(water_pipes, pipe(1, y, 21, y, colors.blue, true)) table.insert(emcool_pipes, pipe(1, y, 21, y, color, true))
else else
table.insert(water_pipes, pipe(2, y, 2, y + 3, colors.blue, true)) table.insert(emcool_pipes, pipe(2, y, 2, y + 3, color, true))
table.insert(water_pipes, pipe(2, y, 21, y, colors.blue, true)) table.insert(emcool_pipes, pipe(2, y, 21, y, color, true))
end end
local x = util.trinary(units[i].num_boilers == 0, 45, 84) local x = util.trinary((tank_types[tank_conns[i]] == COOLANT_TYPE.SODIUM) or (units[i].num_boilers == 0), 45, 84)
table.insert(water_pipes, pipe(21, y, x, y + 2, colors.blue, true, true)) table.insert(emcool_pipes, pipe(21, y, x, y + 2, color, true, true))
end end
end end
@ -112,13 +122,14 @@ local function init(main)
for i = 1, #tank_defs do for i = 1, #tank_defs do
local y = y_ofs(i) local y = y_ofs(i)
if i == first_fdef then if i == first_fdef then
table.insert(water_pipes, pipe(0, y, 1, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y, 1, y + 5, c_clr(i), true))
elseif i > first_fdef then elseif i > first_fdef then
if i == last_fdef then if i == last_fdef then
table.insert(water_pipes, pipe(0, y - 14, 0, y, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y - 14, 0, y, c_clr(first_fdef), true))
elseif i < last_fdef then elseif i < last_fdef then
table.insert(water_pipes, pipe(0, y - 14, 0, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y - 14, 0, y + 5, c_clr(first_fdef), true))
end end
end end
end end
@ -128,17 +139,19 @@ local function init(main)
for i = 1, #tank_defs do for i = 1, #tank_defs do
local y = y_ofs(i) local y = y_ofs(i)
local color = c_clr(first_fdef)
if i == 4 then if i == 4 then
if tank_defs[i] == 2 then if tank_defs[i] == 2 then
table.insert(water_pipes, pipe(0, y, 1, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y, 1, y + 5, c_clr(i), true))
end end
elseif i == first_fdef then elseif i == first_fdef then
table.insert(water_pipes, pipe(0, y, 1, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true))
elseif i > first_fdef then elseif i > first_fdef then
if i == last_fdef then if i == last_fdef then
table.insert(water_pipes, pipe(0, y - 14, 0, y, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y - 14, 0, y, color, true))
elseif i < last_fdef then elseif i < last_fdef then
table.insert(water_pipes, pipe(0, y - 14, 0, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y - 14, 0, y + 5, color, true))
end end
end end
end end
@ -147,12 +160,12 @@ local function init(main)
for _, a in pairs({ 1, 3 }) do for _, a in pairs({ 1, 3 }) do
local b = a + 1 local b = a + 1
if tank_defs[a] == 2 then if tank_defs[a] == 2 then
table.insert(water_pipes, pipe(0, y_ofs(a), 1, y_ofs(a) + 6, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y_ofs(a), 1, y_ofs(a) + 6, c_clr(a), true))
if tank_defs[b] == 2 then if tank_defs[b] == 2 then
table.insert(water_pipes, pipe(0, y_ofs(b) - 13, 1, y_ofs(b), colors.blue, true)) table.insert(emcool_pipes, pipe(0, y_ofs(b) - 13, 1, y_ofs(b), c_clr(a), true))
end end
elseif tank_defs[b] == 2 then elseif tank_defs[b] == 2 then
table.insert(water_pipes, pipe(0, y_ofs(b), 1, y_ofs(b) + 6, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y_ofs(b), 1, y_ofs(b) + 6, c_clr(b), true))
end end
end end
elseif facility.tank_mode == 4 then elseif facility.tank_mode == 4 then
@ -161,17 +174,19 @@ local function init(main)
for i = 1, #tank_defs do for i = 1, #tank_defs do
local y = y_ofs(i) local y = y_ofs(i)
local color = c_clr(first_fdef)
if i == 1 then if i == 1 then
if tank_defs[i] == 2 then if tank_defs[i] == 2 then
table.insert(water_pipes, pipe(0, y, 1, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y, 1, y + 5, c_clr(i), true))
end end
elseif i == first_fdef then elseif i == first_fdef then
table.insert(water_pipes, pipe(0, y, 1, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true))
elseif i > first_fdef then elseif i > first_fdef then
if i == last_fdef then if i == last_fdef then
table.insert(water_pipes, pipe(0, y - 14, 0, y, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y - 14, 0, y, color, true))
elseif i < last_fdef then elseif i < last_fdef then
table.insert(water_pipes, pipe(0, y - 14, 0, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y - 14, 0, y + 5, color, true))
end end
end end
end end
@ -181,17 +196,19 @@ local function init(main)
for i = 1, #tank_defs do for i = 1, #tank_defs do
local y = y_ofs(i) local y = y_ofs(i)
local color = c_clr(first_fdef)
if i == 3 or i == 4 then if i == 3 or i == 4 then
if tank_defs[i] == 2 then if tank_defs[i] == 2 then
table.insert(water_pipes, pipe(0, y, 1, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y, 1, y + 5, c_clr(i), true))
end end
elseif i == first_fdef then elseif i == first_fdef then
table.insert(water_pipes, pipe(0, y, 1, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true))
elseif i > first_fdef then elseif i > first_fdef then
if i == last_fdef then if i == last_fdef then
table.insert(water_pipes, pipe(0, y - 14, 0, y, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y - 14, 0, y, color, true))
elseif i < last_fdef then elseif i < last_fdef then
table.insert(water_pipes, pipe(0, y - 14, 0, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y - 14, 0, y + 5, color, true))
end end
end end
end end
@ -201,17 +218,19 @@ local function init(main)
for i = 1, #tank_defs do for i = 1, #tank_defs do
local y = y_ofs(i) local y = y_ofs(i)
local color = c_clr(first_fdef)
if i == 1 or i == 4 then if i == 1 or i == 4 then
if tank_defs[i] == 2 then if tank_defs[i] == 2 then
table.insert(water_pipes, pipe(0, y, 1, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y, 1, y + 5, c_clr(i), true))
end end
elseif i == first_fdef then elseif i == first_fdef then
table.insert(water_pipes, pipe(0, y, 1, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true))
elseif i > first_fdef then elseif i > first_fdef then
if i == last_fdef then if i == last_fdef then
table.insert(water_pipes, pipe(0, y - 14, 0, y, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y - 14, 0, y, color, true))
elseif i < last_fdef then elseif i < last_fdef then
table.insert(water_pipes, pipe(0, y - 14, 0, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y - 14, 0, y + 5, color, true))
end end
end end
end end
@ -221,17 +240,19 @@ local function init(main)
for i = 1, #tank_defs do for i = 1, #tank_defs do
local y = y_ofs(i) local y = y_ofs(i)
local color = c_clr(first_fdef)
if i == 1 or i == 2 then if i == 1 or i == 2 then
if tank_defs[i] == 2 then if tank_defs[i] == 2 then
table.insert(water_pipes, pipe(0, y, 1, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y, 1, y + 5, c_clr(i), true))
end end
elseif i == first_fdef then elseif i == first_fdef then
table.insert(water_pipes, pipe(0, y, 1, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true))
elseif i > first_fdef then elseif i > first_fdef then
if i == last_fdef then if i == last_fdef then
table.insert(water_pipes, pipe(0, y - 14, 0, y, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y - 14, 0, y, color, true))
elseif i < last_fdef then elseif i < last_fdef then
table.insert(water_pipes, pipe(0, y - 14, 0, y + 5, colors.blue, true)) table.insert(emcool_pipes, pipe(0, y - 14, 0, y + 5, color, true))
end end
end end
end end
@ -239,14 +260,14 @@ local function init(main)
end end
local flow_x = 3 local flow_x = 3
if #water_pipes > 0 then if #emcool_pipes > 0 then
flow_x = 25 flow_x = 25
PipeNetwork{parent=main,x=2,y=3,pipes=water_pipes,bg=style.theme.bg} PipeNetwork{parent=main,x=2,y=3,pipes=emcool_pipes,bg=style.theme.bg}
end end
for i = 1, facility.num_units do for i = 1, facility.num_units do
local y_offset = y_ofs(i) local y_offset = y_ofs(i)
unit_flow(main, flow_x, 5 + y_offset, #water_pipes == 0, units[i]) unit_flow(main, flow_x, 5 + y_offset, #emcool_pipes == 0, i)
table.insert(po_pipes, pipe(0, 3 + y_offset, 4, 0, colors.cyan, true, true)) table.insert(po_pipes, pipe(0, 3 + y_offset, 4, 0, colors.cyan, true, true))
util.nop() util.nop()
end end
@ -301,8 +322,10 @@ local function init(main)
local tank_pcnt = DataIndicator{parent=tank_box,x=10,y=3,label="",format="%5.2f",value=100,unit="%",lu_colors=lu_col,width=8,fg_bg=text_col} local tank_pcnt = DataIndicator{parent=tank_box,x=10,y=3,label="",format="%5.2f",value=100,unit="%",lu_colors=lu_col,width=8,fg_bg=text_col}
local tank_amnt = DataIndicator{parent=tank_box,x=2,label="",format="%13d",value=0,commas=true,unit="mB",lu_colors=lu_col,width=16,fg_bg=s_field} local tank_amnt = DataIndicator{parent=tank_box,x=2,label="",format="%13d",value=0,commas=true,unit="mB",lu_colors=lu_col,width=16,fg_bg=s_field}
TextBox{parent=tank_box,x=2,y=6,text="Water Level",width=11,fg_bg=style.label} local is_water = tank_types[i] == COOLANT_TYPE.WATER
local level = HorizontalBar{parent=tank_box,x=2,y=7,bar_fg_bg=cpair(colors.blue,colors.gray),height=1,width=16}
TextBox{parent=tank_box,x=2,y=6,text=util.trinary(is_water,"Water","Sodium").." Level",width=12,fg_bg=style.label}
local level = HorizontalBar{parent=tank_box,x=2,y=7,bar_fg_bg=cpair(util.trinary(is_water,colors.blue,colors.lightBlue),colors.gray),height=1,width=16}
TextBox{parent=tank_box,x=2,y=9,text="In/Out Mode",width=11,fg_bg=style.label} TextBox{parent=tank_box,x=2,y=9,text="In/Out Mode",width=11,fg_bg=style.label}
local can_fill = IndicatorLight{parent=tank_box,x=2,y=10,label="FILL",colors=style.ind_wht} local can_fill = IndicatorLight{parent=tank_box,x=2,y=10,label="FILL",colors=style.ind_wht}

View File

@ -138,6 +138,9 @@ function iocontrol.init_fac(conf)
num_units = conf.num_units, num_units = conf.num_units,
tank_mode = conf.cooling.fac_tank_mode, tank_mode = conf.cooling.fac_tank_mode,
tank_defs = conf.cooling.fac_tank_defs, tank_defs = conf.cooling.fac_tank_defs,
tank_list = conf.cooling.fac_tank_list,
tank_conns = conf.cooling.fac_tank_conns,
tank_fluid_types = conf.cooling.tank_fluid_types,
all_sys_ok = false, all_sys_ok = false,
rtu_count = 0, rtu_count = 0,

View File

@ -20,7 +20,7 @@ local pocket = require("pocket.pocket")
local renderer = require("pocket.renderer") local renderer = require("pocket.renderer")
local threads = require("pocket.threads") local threads = require("pocket.threads")
local POCKET_VERSION = "v0.12.11-alpha" local POCKET_VERSION = "v0.12.12-alpha"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts

View File

@ -372,7 +372,7 @@ local function new_view(root)
if #unit.tank_data_tbl > 0 then if #unit.tank_data_tbl > 0 then
local tank_pane = Div{parent=page_div} local tank_pane = Div{parent=page_div}
nav_links[i].d_tank = dyn_tank(app, u_page, panes, tank_pane, unit.tank_ps_tbl[1], update) nav_links[i].d_tank = dyn_tank(app, u_page, panes, tank_pane, i, unit.tank_ps_tbl[1], update)
end end
--#endregion --#endregion

View File

@ -1,4 +1,7 @@
local types = require("scada-common.types") local types = require("scada-common.types")
local util = require("scada-common.util")
local iocontrol = require("pocket.iocontrol")
local style = require("pocket.ui.style") local style = require("pocket.ui.style")
@ -13,6 +16,7 @@ local IconIndicator = require("graphics.elements.indicators.IconIndicator")
local StateIndicator = require("graphics.elements.indicators.StateIndicator") local StateIndicator = require("graphics.elements.indicators.StateIndicator")
local CONTAINER_MODE = types.CONTAINER_MODE local CONTAINER_MODE = types.CONTAINER_MODE
local COOLANT_TYPE = types.COOLANT_TYPE
local cpair = core.cpair local cpair = core.cpair
@ -30,9 +34,12 @@ local mode_ind_s = {
---@param page nav_tree_page ---@param page nav_tree_page
---@param panes Div[] ---@param panes Div[]
---@param tank_pane Div ---@param tank_pane Div
---@param tank_id integer global facility tank ID (as used for tank list, etc)
---@param ps psil ---@param ps psil
---@param update function ---@param update function
return function (app, page, panes, tank_pane, ps, update) return function (app, page, panes, tank_pane, tank_id, ps, update)
local fac = iocontrol.get_db().facility
local tank_div = Div{parent=tank_pane,x=2,width=tank_pane.get_width()-2} local tank_div = Div{parent=tank_pane,x=2,width=tank_pane.get_width()-2}
table.insert(panes, tank_div) table.insert(panes, tank_div)
@ -47,8 +54,10 @@ return function (app, page, panes, tank_pane, ps, update)
local tank_pcnt = DataIndicator{parent=tank_div,x=14,y=3,label="",format="%5.2f",value=100,unit="%",lu_colors=lu_col,width=8,fg_bg=text_fg} local tank_pcnt = DataIndicator{parent=tank_div,x=14,y=3,label="",format="%5.2f",value=100,unit="%",lu_colors=lu_col,width=8,fg_bg=text_fg}
local tank_amnt = DataIndicator{parent=tank_div,label="",format="%18d",value=0,commas=true,unit="mB",lu_colors=lu_col,width=21,fg_bg=text_fg} local tank_amnt = DataIndicator{parent=tank_div,label="",format="%18d",value=0,commas=true,unit="mB",lu_colors=lu_col,width=21,fg_bg=text_fg}
TextBox{parent=tank_div,y=6,text="Fluid Level",width=11,fg_bg=label} local is_water = fac.tank_fluid_types[tank_id] == COOLANT_TYPE.WATER
local level = HorizontalBar{parent=tank_div,y=7,bar_fg_bg=cpair(colors.blue,colors.gray),height=1,width=21}
TextBox{parent=tank_div,y=6,text=util.trinary(is_water,"Water","Sodium").." Level",width=12,fg_bg=label}
local level = HorizontalBar{parent=tank_div,y=7,bar_fg_bg=cpair(util.trinary(is_water,colors.blue,colors.lightBlue),colors.gray),height=1,width=21}
TextBox{parent=tank_div,y=9,text="Tank Fill Mode",width=14,fg_bg=label} TextBox{parent=tank_div,y=9,text="Tank Fill Mode",width=14,fg_bg=label}
local can_fill = IconIndicator{parent=tank_div,y=10,label="Fill",states=mode_ind_s} local can_fill = IconIndicator{parent=tank_div,y=10,label="Fill",states=mode_ind_s}

View File

@ -418,6 +418,12 @@ types.AUTO_GROUP_NAMES = {
"Backup" "Backup"
} }
---@enum COOLANT_TYPE
types.COOLANT_TYPE = {
WATER = 1,
SODIUM = 2
}
---@enum WASTE_MODE ---@enum WASTE_MODE
types.WASTE_MODE = { types.WASTE_MODE = {
AUTO = 1, AUTO = 1,

View File

@ -24,7 +24,7 @@ local t_pack = table.pack
local util = {} local util = {}
-- scada-common version -- scada-common version
util.version = "1.4.9" util.version = "1.4.10"
util.TICK_TIME_S = 0.05 util.TICK_TIME_S = 0.05
util.TICK_TIME_MS = 50 util.TICK_TIME_MS = 50

View File

@ -18,12 +18,148 @@ local tri = util.trinary
local cpair = core.cpair local cpair = core.cpair
local self = { local self = {
vis_ftanks = {}, ---@type { line: Div, pipe_conn?: TextBox, pipe_chain?: TextBox, pipe_direct?: TextBox, label?: TextBox }[] tank_fluid_opts = {}, ---@type Radio2D[]
vis_utanks = {} ---@type { line: Div, label: TextBox }[]
vis_draw = nil, ---@type function
draw_fluid_ops = nil, ---@type function
vis_ftanks = {}, ---@type { line: Div, pipe_conn?: TextBox, pipe_chain?: TextBox, pipe_direct?: TextBox, label?: TextBox }[]
vis_utanks = {} ---@type { line: Div, label: TextBox }[]
} }
local facility = {} local facility = {}
-- generate the tank list and tank connections tables
---@param mode integer facility tank mode
---@param defs table facility tank definitions
---@return table tank_list, table tank_conns
function facility.generate_tank_list_and_conns(mode, defs)
local tank_mode = mode
local tank_defs = defs
local tank_list = { table.unpack(tank_defs) }
local tank_conns = { table.unpack(tank_defs) }
local function calc_fdef(start_idx, end_idx)
local first = 4
for i = start_idx, end_idx do
if tank_defs[i] == 2 then
if i < first then first = i end
end
end
return first
end
-- set units using their own tanks as connected to their respective unit tank
for i = 1, #tank_defs do
if tank_defs[i] == 1 then tank_conns[i] = i end
end
if tank_mode == 1 then
-- (1) 1 total facility tank (A A A A)
local first_fdef = calc_fdef(1, #tank_defs)
for i = 1, #tank_defs do
if (i >= first_fdef) and (tank_defs[i] == 2) then
tank_conns[i] = first_fdef
if i > first_fdef then tank_list[i] = 0 end
end
end
elseif tank_mode == 2 then
-- (2) 2 total facility tanks (A A A B)
local first_fdef = calc_fdef(1, math.min(3, #tank_defs))
for i = 1, #tank_defs do
if (i >= first_fdef) and (tank_defs[i] == 2) then
if i == 4 then
tank_conns[i] = 4
else
tank_conns[i] = first_fdef
if i > first_fdef then tank_list[i] = 0 end
end
end
end
elseif tank_mode == 3 then
-- (3) 2 total facility tanks (A A B B)
for _, a in pairs({ 1, 3 }) do
local b = a + 1
if tank_defs[a] == 2 then
tank_conns[a] = a
elseif tank_defs[b] == 2 then
tank_conns[b] = b
end
if (tank_defs[a] == 2) and (tank_defs[b] == 2) then
tank_list[b] = 0
tank_conns[b] = a
end
end
elseif tank_mode == 4 then
-- (4) 2 total facility tanks (A B B B)
local first_fdef = calc_fdef(2, #tank_defs)
for i = 1, #tank_defs do
if tank_defs[i] == 2 then
if i == 1 then
tank_conns[i] = 1
elseif i >= first_fdef then
tank_conns[i] = first_fdef
if i > first_fdef then tank_list[i] = 0 end
end
end
end
elseif tank_mode == 5 then
-- (5) 3 total facility tanks (A A B C)
local first_fdef = calc_fdef(1, math.min(2, #tank_defs))
for i = 1, #tank_defs do
if (i >= first_fdef) and (tank_defs[i] == 2) then
if i == 3 or i == 4 then
tank_conns[i] = i
elseif i >= first_fdef then
tank_conns[i] = first_fdef
if i > first_fdef then tank_list[i] = 0 end
end
end
end
elseif tank_mode == 6 then
-- (6) 3 total facility tanks (A B B C)
local first_fdef = calc_fdef(2, math.min(3, #tank_defs))
for i = 1, #tank_defs do
if tank_defs[i] == 2 then
if i == 1 or i == 4 then
tank_conns[i] = i
elseif i >= first_fdef then
tank_conns[i] = first_fdef
if i > first_fdef then tank_list[i] = 0 end
end
end
end
elseif tank_mode == 7 then
-- (7) 3 total facility tanks (A B C C)
local first_fdef = calc_fdef(3, #tank_defs)
for i = 1, #tank_defs do
if tank_defs[i] == 2 then
if i == 1 or i == 2 then
tank_conns[i] = i
elseif i >= first_fdef then
tank_conns[i] = first_fdef
if i > first_fdef then tank_list[i] = 0 end
end
end
end
elseif tank_mode == 8 then
-- (8) 4 total facility tanks (A B C D)
for i = 1, #tank_defs do
if tank_defs[i] == 2 then tank_conns[i] = i end
end
end
return tank_list, tank_conns
end
-- create the facility configuration view -- create the facility configuration view
---@param tool_ctl _svr_cfg_tool_ctl ---@param tool_ctl _svr_cfg_tool_ctl
---@param main_pane MultiPane ---@param main_pane MultiPane
@ -48,14 +184,18 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
local fac_c_5 = Div{parent=fac_cfg,x=2,y=4,width=49} local fac_c_5 = Div{parent=fac_cfg,x=2,y=4,width=49}
local fac_c_6 = Div{parent=fac_cfg,x=2,y=4,width=49} local fac_c_6 = Div{parent=fac_cfg,x=2,y=4,width=49}
local fac_c_7 = Div{parent=fac_cfg,x=2,y=4,width=49} local fac_c_7 = Div{parent=fac_cfg,x=2,y=4,width=49}
local fac_c_8 = Div{parent=fac_cfg,x=2,y=4,width=49}
local fac_pane = MultiPane{parent=fac_cfg,x=1,y=4,panes={fac_c_1,fac_c_2,fac_c_3,fac_c_4,fac_c_5,fac_c_6,fac_c_7}} local fac_pane = MultiPane{parent=fac_cfg,x=1,y=4,panes={fac_c_1,fac_c_2,fac_c_3,fac_c_4,fac_c_5,fac_c_6,fac_c_7, fac_c_8}}
TextBox{parent=fac_cfg,x=1,y=2,text=" Facility Configuration",fg_bg=cpair(colors.black,colors.yellow)} TextBox{parent=fac_cfg,x=1,y=2,text=" Facility Configuration",fg_bg=cpair(colors.black,colors.yellow)}
--#region Unit Count
TextBox{parent=fac_c_1,x=1,y=1,height=3,text="Please enter the number of reactors you have, also referred to as reactor units or 'units' for short. A maximum of 4 is currently supported."} TextBox{parent=fac_c_1,x=1,y=1,height=3,text="Please enter the number of reactors you have, also referred to as reactor units or 'units' for short. A maximum of 4 is currently supported."}
tool_ctl.num_units = NumberField{parent=fac_c_1,x=1,y=5,width=5,max_chars=2,default=ini_cfg.UnitCount,min=1,max=4,fg_bg=bw_fg_bg} tool_ctl.num_units = NumberField{parent=fac_c_1,x=1,y=5,width=5,max_chars=2,default=ini_cfg.UnitCount,min=1,max=4,fg_bg=bw_fg_bg}
TextBox{parent=fac_c_1,x=7,y=5,text="reactors"} TextBox{parent=fac_c_1,x=7,y=5,text="reactors"}
TextBox{parent=fac_c_1,x=1,y=7,height=3,text="If you already configured your coordinator, make sure you update the coordinator's configured unit count.",fg_bg=cpair(colors.yellow,colors._INHERIT)}
local nu_error = TextBox{parent=fac_c_1,x=8,y=14,width=35,text="Please set the number of reactors.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local nu_error = TextBox{parent=fac_c_1,x=8,y=14,width=35,text="Please set the number of reactors.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@ -77,6 +217,9 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
PushButton{parent=fac_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_1,x=44,y=14,text="Next \x1a",callback=submit_num_units,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_1,x=44,y=14,text="Next \x1a",callback=submit_num_units,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
--#region Cooling Configuration
TextBox{parent=fac_c_2,x=1,y=1,height=4,text="Please provide the reactor cooling configuration below. This includes the number of turbines, boilers, and if that reactor has a connection to a dynamic tank for emergency coolant."} TextBox{parent=fac_c_2,x=1,y=1,height=4,text="Please provide the reactor cooling configuration below. This includes the number of turbines, boilers, and if that reactor has a connection to a dynamic tank for emergency coolant."}
TextBox{parent=fac_c_2,x=1,y=6,text="UNIT TURBINES BOILERS HAS TANK CONNECTION?",fg_bg=g_lg_fg_bg} TextBox{parent=fac_c_2,x=1,y=6,text="UNIT TURBINES BOILERS HAS TANK CONNECTION?",fg_bg=g_lg_fg_bg}
@ -149,6 +292,9 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
PushButton{parent=fac_c_2,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_2,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_2,x=44,y=14,text="Next \x1a",callback=submit_cooling,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_2,x=44,y=14,text="Next \x1a",callback=submit_cooling,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
--#region Facility Tanks Option
TextBox{parent=fac_c_3,x=1,y=1,height=6,text="You have set one or more of your units to use dynamic tanks for emergency coolant. You have two paths for configuration. The first is to assign dynamic tanks to reactor units; one tank per reactor, only connected to that reactor. RTU configurations must also assign it as such."} TextBox{parent=fac_c_3,x=1,y=1,height=6,text="You have set one or more of your units to use dynamic tanks for emergency coolant. You have two paths for configuration. The first is to assign dynamic tanks to reactor units; one tank per reactor, only connected to that reactor. RTU configurations must also assign it as such."}
TextBox{parent=fac_c_3,x=1,y=8,height=3,text="Alternatively, you can configure them as facility tanks to connect to multiple reactor units. These can intermingle with unit-specific tanks."} TextBox{parent=fac_c_3,x=1,y=8,height=3,text="Alternatively, you can configure them as facility tanks to connect to multiple reactor units. These can intermingle with unit-specific tanks."}
@ -161,6 +307,16 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
else else
tmp_cfg.FacilityTankMode = 0 tmp_cfg.FacilityTankMode = 0
tmp_cfg.FacilityTankDefs = {} tmp_cfg.FacilityTankDefs = {}
-- on facility tank mode 0, setup tank defs to match unit tank option
for i = 1, tmp_cfg.UnitCount do
tmp_cfg.FacilityTankDefs[i] = tri(tmp_cfg.CoolingConfig[i].TankConnection, 1, 0)
end
tmp_cfg.FacilityTankList, tmp_cfg.FacilityTankConns = facility.generate_tank_list_and_conns(tmp_cfg.FacilityTankMode, tmp_cfg.FacilityTankDefs)
self.draw_fluid_ops()
fac_pane.set_value(7) fac_pane.set_value(7)
end end
end end
@ -168,6 +324,9 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
PushButton{parent=fac_c_3,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_3,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_3,x=44,y=14,text="Next \x1a",callback=submit_en_fac_tank,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_3,x=44,y=14,text="Next \x1a",callback=submit_en_fac_tank,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
--#region Facility Tank Connections
TextBox{parent=fac_c_4,x=1,y=1,height=4,text="Please set unit connections to dynamic tanks, selecting at least one facility tank. The layout for facility tanks will be configured next."} TextBox{parent=fac_c_4,x=1,y=1,height=4,text="Please set unit connections to dynamic tanks, selecting at least one facility tank. The layout for facility tanks will be configured next."}
for i = 1, 4 do for i = 1, 4 do
@ -220,7 +379,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
self.vis_utanks[i].line.hide(true) self.vis_utanks[i].line.hide(true)
end end
tool_ctl.vis_draw(tmp_cfg.FacilityTankMode) self.vis_draw(tmp_cfg.FacilityTankMode)
if any_fac then if any_fac then
tank_err.hide(true) tank_err.hide(true)
@ -231,6 +390,9 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
PushButton{parent=fac_c_4,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_4,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_4,x=44,y=14,text="Next \x1a",callback=submit_tank_defs,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_4,x=44,y=14,text="Next \x1a",callback=submit_tank_defs,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
--#region Facility Tank Mode
TextBox{parent=fac_c_5,x=1,y=1,text="Please select your dynamic tank layout."} TextBox{parent=fac_c_5,x=1,y=1,text="Please select your dynamic tank layout."}
TextBox{parent=fac_c_5,x=12,y=3,text="Facility Tanks Unit Tanks",fg_bg=g_lg_fg_bg} TextBox{parent=fac_c_5,x=12,y=3,text="Facility Tanks Unit Tanks",fg_bg=g_lg_fg_bg}
@ -269,7 +431,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
-- draw the pipe visualization -- draw the pipe visualization
---@param mode integer pipe mode ---@param mode integer pipe mode
function tool_ctl.vis_draw(mode) function self.vis_draw(mode)
-- is a facility tank connected to this unit -- is a facility tank connected to this unit
---@param i integer unit 1 - 4 ---@param i integer unit 1 - 4
---@return boolean connected ---@return boolean connected
@ -391,7 +553,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
local function change_mode(mode) local function change_mode(mode)
tmp_cfg.FacilityTankMode = mode tmp_cfg.FacilityTankMode = mode
tool_ctl.vis_draw(mode) self.vis_draw(mode)
end end
local tank_modes = { "Mode 1", "Mode 2", "Mode 3", "Mode 4", "Mode 5", "Mode 6", "Mode 7", "Mode 8" } local tank_modes = { "Mode 1", "Mode 2", "Mode 3", "Mode 4", "Mode 5", "Mode 6", "Mode 7", "Mode 8" }
@ -399,24 +561,127 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
--#endregion --#endregion
local function next_from_tank_mode()
-- determine tank list and connections
tmp_cfg.FacilityTankList, tmp_cfg.FacilityTankConns = facility.generate_tank_list_and_conns(tmp_cfg.FacilityTankMode, tmp_cfg.FacilityTankDefs)
self.draw_fluid_ops()
fac_pane.set_value(7)
end
PushButton{parent=fac_c_5,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_5,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_5,x=44,y=14,text="Next \x1a",callback=function()fac_pane.set_value(7)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_5,x=44,y=14,text="Next \x1a",callback=next_from_tank_mode,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_5,x=8,y=14,min_width=7,text="About",callback=function()fac_pane.set_value(6)end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_5,x=8,y=14,min_width=7,text="About",callback=function()fac_pane.set_value(6)end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg}
--#endregion
--#region Facility Tank Mode About
TextBox{parent=fac_c_6,height=3,text="This visualization tool shows the pipe connections required for a particular dynamic tank configuration you have selected."} TextBox{parent=fac_c_6,height=3,text="This visualization tool shows the pipe connections required for a particular dynamic tank configuration you have selected."}
TextBox{parent=fac_c_6,y=5,height=4,text="Examples: A U2 tank should be configured on an RTU as the dynamic tank for unit #2. An F3 tank should be configured on an RTU as the #3 dynamic tank for the facility."} TextBox{parent=fac_c_6,y=5,height=4,text="Examples: A U2 tank should be configured on an RTU as the dynamic tank for unit #2. An F3 tank should be configured on an RTU as the #3 dynamic tank for the facility."}
TextBox{parent=fac_c_6,y=10,height=3,text="Some modes may look the same if you are not using 4 total reactor units. The wiki has details. Modes that look the same will function the same.",fg_bg=g_lg_fg_bg} TextBox{parent=fac_c_6,y=10,height=3,text="Some modes may look the same if you are not using 4 total reactor units. The wiki has details. Modes that look the same will function the same.",fg_bg=g_lg_fg_bg}
PushButton{parent=fac_c_6,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(5)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_6,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(5)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=fac_c_7,height=6,text="Charge control provides automatic control to maintain an induction matrix charge level. In order to have smoother control, reactors that were activated will be held on at 0.01 mB/t for a short period before allowing them to turn off. This minimizes overshooting the charge target."} --#endregion
TextBox{parent=fac_c_7,y=8,height=3,text="You can extend this to a full minute to minimize reactors flickering on/off, but there may be more overshoot of the target."} --#region Dynamic Tank Fluid Types
local ext_idling = Checkbox{parent=fac_c_7,x=1,y=12,label="Enable Extended Idling",default=ini_cfg.ExtChargeIdling,box_fg_bg=cpair(colors.yellow,colors.black)} TextBox{parent=fac_c_7,height=3,text="Specify each tank's coolant type, for display use only. Water is the only option if one or more of the connected units is water cooled."}
local tank_fluid_list = Div{parent=fac_c_7,x=1,y=5,height=8}
function self.draw_fluid_ops()
tank_fluid_list.remove_all()
local tank_list = tmp_cfg.FacilityTankList
local tank_conns = tmp_cfg.FacilityTankConns
local next_f = 1
for i = 1, #tank_list do
local type = tmp_cfg.TankFluidTypes[i]
if type == 0 then type = 1 end
self.tank_fluid_opts[i] = nil
if tank_list[i] == 1 then
local row = Div{parent=tank_fluid_list,height=2}
TextBox{parent=row,width=11,text="Unit Tank "..i}
TextBox{parent=row,text="Connected to: Unit "..i,fg_bg=cpair(colors.gray,colors.lightGray)}
local tank_fluid = Radio2D{parent=row,x=34,y=1,rows=1,columns=2,default=type,options={"Water","Sodium"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.yellow,disable_color=colors.gray,disable_fg_bg=g_lg_fg_bg}
if tmp_cfg.CoolingConfig[i].BoilerCount == 0 then
tank_fluid.set_value(1)
tank_fluid.disable()
end
self.tank_fluid_opts[i] = tank_fluid
elseif tank_list[i] == 2 then
local row = Div{parent=tank_fluid_list,height=2}
TextBox{parent=row,width=15,text="Facility Tank "..next_f}
local conns = ""
local any_bwr = false
for u = 1, #tank_conns do
if tank_conns[u] == i then
conns = conns .. tri(conns == "", "", ", ") .. "Unit " .. u
any_bwr = any_bwr or (tmp_cfg.CoolingConfig[u].BoilerCount == 0)
end
end
TextBox{parent=row,text="Connected to: "..conns,fg_bg=cpair(colors.gray,colors.lightGray)}
local tank_fluid = Radio2D{parent=row,x=34,y=1,rows=1,columns=2,default=type,options={"Water","Sodium"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.yellow,disable_color=colors.gray,disable_fg_bg=g_lg_fg_bg}
if any_bwr then
tank_fluid.set_value(1)
tank_fluid.disable()
end
self.tank_fluid_opts[i] = tank_fluid
next_f = next_f + 1
end
end
end
local function back_from_fluids()
fac_pane.set_value(tri(tmp_cfg.FacilityTankMode == 0, 3, 5))
end
local function submit_tank_fluids()
tmp_cfg.TankFluidTypes = {}
for i = 1, #tmp_cfg.FacilityTankList do
if self.tank_fluid_opts[i] ~= nil then
tmp_cfg.TankFluidTypes[i] = self.tank_fluid_opts[i].get_value()
else
tmp_cfg.TankFluidTypes[i] = 0
end
end
fac_pane.set_value(8)
end
PushButton{parent=fac_c_7,x=1,y=14,text="\x1b Back",callback=back_from_fluids,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_7,x=44,y=14,text="Next \x1a",callback=submit_tank_fluids,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
--#region Extended Idling
TextBox{parent=fac_c_8,height=6,text="Charge control provides automatic control to maintain an induction matrix charge level. In order to have smoother control, reactors that were activated will be held on at 0.01 mB/t for a short period before allowing them to turn off. This minimizes overshooting the charge target."}
TextBox{parent=fac_c_8,y=8,height=3,text="You can extend this to a full minute to minimize reactors flickering on/off, but there may be more overshoot of the target."}
local ext_idling = Checkbox{parent=fac_c_8,x=1,y=12,label="Enable Extended Idling",default=ini_cfg.ExtChargeIdling,box_fg_bg=cpair(colors.yellow,colors.black)}
local function back_from_idling() local function back_from_idling()
fac_pane.set_value(tri(tmp_cfg.FacilityTankMode == 0, 3, 5)) fac_pane.set_value(tri(tmp_cfg.FacilityTankMode == 0, 3, 7))
end end
local function submit_idling() local function submit_idling()
@ -424,8 +689,10 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
main_pane.set_value(3) main_pane.set_value(3)
end end
PushButton{parent=fac_c_7,x=1,y=14,text="\x1b Back",callback=back_from_idling,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_8,x=1,y=14,text="\x1b Back",callback=back_from_idling,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_7,x=44,y=14,text="Next \x1a",callback=submit_idling,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_8,x=44,y=14,text="Next \x1a",callback=submit_idling,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
--#endregion --#endregion

View File

@ -1,6 +1,9 @@
local log = require("scada-common.log") local log = require("scada-common.log")
local types = require("scada-common.types")
local util = require("scada-common.util") local util = require("scada-common.util")
local facility = require("supervisor.config.facility")
local core = require("graphics.core") local core = require("graphics.core")
local themes = require("graphics.themes") local themes = require("graphics.themes")
@ -508,8 +511,15 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
else else
tmp_cfg.FacilityTankMode = 0 tmp_cfg.FacilityTankMode = 0
tmp_cfg.FacilityTankDefs = {} tmp_cfg.FacilityTankDefs = {}
-- on facility tank mode 0, setup tank defs to match unit tank option
for i = 1, tmp_cfg.UnitCount do
tmp_cfg.FacilityTankDefs[i] = tri(tmp_cfg.CoolingConfig[i].TankConnection, 1, 0)
end
end end
tmp_cfg.FacilityTankList, tmp_cfg.FacilityTankConns = facility.generate_tank_list_and_conns(tmp_cfg.FacilityTankMode, tmp_cfg.FacilityTankDefs)
tmp_cfg.SVR_Channel = config.SVR_CHANNEL tmp_cfg.SVR_Channel = config.SVR_CHANNEL
tmp_cfg.PLC_Channel = config.PLC_CHANNEL tmp_cfg.PLC_Channel = config.PLC_CHANNEL
tmp_cfg.RTU_Channel = config.RTU_CHANNEL tmp_cfg.RTU_Channel = config.RTU_CHANNEL
@ -557,6 +567,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
local val_max_w = (inner_width - label_w) + 1 local val_max_w = (inner_width - label_w) + 1
local raw = cfg[f[1]] local raw = cfg[f[1]]
local val = util.strval(raw) local val = util.strval(raw)
local skip = false
if f[1] == "AuthKey" then val = string.rep("*", string.len(val)) if f[1] == "AuthKey" then val = string.rep("*", string.len(val))
elseif f[1] == "LogMode" then val = tri(raw == log.MODE.APPEND, "append", "replace") elseif f[1] == "LogMode" then val = tri(raw == log.MODE.APPEND, "append", "replace")
@ -579,43 +590,88 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
if val == "" then val = "no facility tanks" end if val == "" then val = "no facility tanks" end
elseif f[1] == "FacilityTankMode" and raw == 0 then val = "0 (n/a, unit mode)" elseif f[1] == "FacilityTankMode" and raw == 0 then val = "0 (n/a, unit mode)"
elseif f[1] == "FacilityTankDefs" and type(cfg.FacilityTankDefs) == "table" then elseif f[1] == "FacilityTankDefs" and type(cfg.FacilityTankDefs) == "table" then
local tank_name_list = { table.unpack(cfg.FacilityTankList) } ---@type (string|integer)[]
local next_f = 1
val = "" val = ""
for idx = 1, #tank_name_list do
if tank_name_list[idx] == 1 then
tank_name_list[idx] = "U" .. idx
elseif tank_name_list[idx] == 2 then
tank_name_list[idx] = "F" .. next_f
next_f = next_f + 1
end
end
for idx = 1, #cfg.FacilityTankDefs do for idx = 1, #cfg.FacilityTankDefs do
local t_mode = "not connected to a tank" local t_mode = "not connected to a tank"
if cfg.FacilityTankDefs[idx] == 1 then if cfg.FacilityTankDefs[idx] == 1 then
t_mode = "connected to its unit tank" t_mode = "connected to its unit tank (" .. tank_name_list[cfg.FacilityTankConns[idx]] .. ")"
elseif cfg.FacilityTankDefs[idx] == 2 then elseif cfg.FacilityTankDefs[idx] == 2 then
t_mode = "connected to a facility tank" t_mode = "connected to facility tank " .. tank_name_list[cfg.FacilityTankConns[idx]]
end end
val = val .. tri(idx == 1, "", "\n") .. util.sprintf(" \x07 unit %d - %s", idx, t_mode) val = val .. tri(idx == 1, "", "\n") .. util.sprintf(" \x07 unit %d - %s", idx, t_mode)
end end
if val == "" then val = "no facility tanks" end if val == "" then val = "no facility tanks" end
elseif f[1] == "FacilityTankList" or f[1] == "FacilityTankConns" then
-- hide these since this info is available in the FacilityTankDefs list (connections) and TankFluidTypes list (list of tanks)
skip = true
elseif f[1] == "TankFluidTypes" and type(cfg.TankFluidTypes) == "table" and type(cfg.FacilityTankList) == "table" then
local tank_list = cfg.FacilityTankList
local next_f = 1
val = ""
for idx = 1, #tank_list do
local prefix = "?"
local fluid = "water"
local type = cfg.TankFluidTypes[idx]
if tank_list[idx] > 0 then
if tank_list[idx] == 1 then
prefix = "U" .. idx
elseif tank_list[idx] == 2 then
prefix = "F" .. next_f
next_f = next_f + 1
end
if type == types.COOLANT_TYPE.SODIUM then
fluid = "sodium"
end
val = val .. tri(val == "", "", "\n") .. util.sprintf(" \x07 tank %s - %s", prefix, fluid)
end
end
if val == "" then val = "no emergency coolant tanks" end
end end
if val == "nil" then val = "<not set>" end if not skip then
if val == "nil" then val = "<not set>" end
local c = tri(alternate, g_lg_fg_bg, cpair(colors.gray,colors.white)) local c = tri(alternate, g_lg_fg_bg, cpair(colors.gray,colors.white))
alternate = not alternate alternate = not alternate
if string.len(val) > val_max_w then if string.len(val) > val_max_w then
local lines = util.strwrap(val, inner_width) local lines = util.strwrap(val, inner_width)
height = #lines + 1 height = #lines + 1
end
local line = Div{parent=setting_list,height=height,fg_bg=c}
TextBox{parent=line,text=f[2],width=string.len(f[2]),fg_bg=cpair(colors.black,line.get_fg_bg().bkg)}
local textbox
if height > 1 then
textbox = TextBox{parent=line,x=1,y=2,text=val,height=height-1}
else
textbox = TextBox{parent=line,x=label_w+1,y=1,text=val,alignment=RIGHT}
end
if f[1] == "AuthKey" then self.auth_key_textbox = textbox end
end end
local line = Div{parent=setting_list,height=height,fg_bg=c}
TextBox{parent=line,text=f[2],width=string.len(f[2]),fg_bg=cpair(colors.black,line.get_fg_bg().bkg)}
local textbox
if height > 1 then
textbox = TextBox{parent=line,x=1,y=2,text=val,height=height-1}
else
textbox = TextBox{parent=line,x=label_w+1,y=1,text=val,alignment=RIGHT}
end
if f[1] == "AuthKey" then self.auth_key_textbox = textbox end
end end
end end

View File

@ -30,7 +30,8 @@ local CENTER = core.ALIGN.CENTER
-- changes to the config data/format to let the user know -- changes to the config data/format to let the user know
local changes = { local changes = {
{ "v1.2.12", { "Added front panel UI theme", "Added color accessibility modes" } }, { "v1.2.12", { "Added front panel UI theme", "Added color accessibility modes" } },
{ "v1.3.2", { "Added standard with black off state color mode", "Added blue indicator color modes" } } { "v1.3.2", { "Added standard with black off state color mode", "Added blue indicator color modes" } },
{ "v1.6.0", { "Added sodium emergency coolant option" } }
} }
---@class svr_configurator ---@class svr_configurator
@ -78,8 +79,11 @@ local tool_ctl = {
local tmp_cfg = { local tmp_cfg = {
UnitCount = 1, UnitCount = 1,
CoolingConfig = {}, ---@type { TurbineCount: integer, BoilerCount: integer, TankConnection: boolean }[] CoolingConfig = {}, ---@type { TurbineCount: integer, BoilerCount: integer, TankConnection: boolean }[]
FacilityTankMode = 0, FacilityTankMode = 0, -- dynamic tank emergency coolant layout
FacilityTankDefs = {}, ---@type integer[] FacilityTankDefs = {}, ---@type integer[] each unit's tank connection target (0 = disconnected, 1 = unit, 2 = facility)
FacilityTankList = {}, ---@type integer[] list of tanks by slot (0 = none or covered by an above tank, 1 = unit tank, 2 = facility tank)
FacilityTankConns = {}, ---@type integer[] map of unit tank connections (indicies are units, values are tank indicies in the tank list)
TankFluidTypes = {}, ---@type integer[] which type of fluid each tank in the tank list should be containing
ExtChargeIdling = false, ExtChargeIdling = false,
SVR_Channel = nil, ---@type integer SVR_Channel = nil, ---@type integer
PLC_Channel = nil, ---@type integer PLC_Channel = nil, ---@type integer
@ -110,6 +114,9 @@ local fields = {
{ "CoolingConfig", "Cooling Configuration", {} }, { "CoolingConfig", "Cooling Configuration", {} },
{ "FacilityTankMode", "Facility Tank Mode", 0 }, { "FacilityTankMode", "Facility Tank Mode", 0 },
{ "FacilityTankDefs", "Facility Tank Definitions", {} }, { "FacilityTankDefs", "Facility Tank Definitions", {} },
{ "FacilityTankList", "Facility Tank List", {} }, -- hidden
{ "FacilityTankConns", "Facility Tank Connections", {} }, -- hidden
{ "TankFluidTypes", "Tank Fluid Types", {} },
{ "ExtChargeIdling", "Extended Charge Idling", false }, { "ExtChargeIdling", "Extended Charge Idling", false },
{ "SVR_Channel", "SVR Channel", 16240 }, { "SVR_Channel", "SVR Channel", 16240 },
{ "PLC_Channel", "PLC Channel", 16241 }, { "PLC_Channel", "PLC Channel", 16241 },
@ -176,7 +183,7 @@ local function config_view(display)
TextBox{parent=main_page,x=2,y=2,height=2,text="Welcome to the Supervisor configurator! Please select one of the following options."} TextBox{parent=main_page,x=2,y=2,height=2,text="Welcome to the Supervisor configurator! Please select one of the following options."}
if tool_ctl.ask_config then if tool_ctl.ask_config then
TextBox{parent=main_page,x=2,y=y_start,height=4,width=49,text="Notice: This device had no valid config so the configurator has been automatically started. If you previously had a valid config, you may want to check the Change Log to see what changed.",fg_bg=cpair(colors.red,colors.lightGray)} TextBox{parent=main_page,x=2,y=y_start,height=4,width=49,text="Notice: This device is not configured for this version of the supervisor. If you previously had a valid config, it's not lost. You may want to check the Change Log to see what changed.",fg_bg=cpair(colors.red,colors.lightGray)}
y_start = y_start + 5 y_start = y_start + 5
end end
@ -275,6 +282,10 @@ function configurator.configure(ask_config)
load_settings(settings_cfg, true) load_settings(settings_cfg, true)
tool_ctl.has_config = load_settings(ini_cfg) tool_ctl.has_config = load_settings(ini_cfg)
-- these need to be initialized as they are used before being set
tmp_cfg.FacilityTankMode = ini_cfg.FacilityTankMode
tmp_cfg.TankFluidTypes = { table.unpack(ini_cfg.TankFluidTypes) }
reset_term() reset_term()
-- set overridden colors -- set overridden colors

View File

@ -51,7 +51,9 @@ function facility.new(config)
r_cool = config.CoolingConfig, r_cool = config.CoolingConfig,
fac_tank_mode = config.FacilityTankMode, fac_tank_mode = config.FacilityTankMode,
fac_tank_defs = config.FacilityTankDefs, fac_tank_defs = config.FacilityTankDefs,
fac_tank_list = {} ---@type integer[] fac_tank_list = config.FacilityTankList,
fac_tank_conns = config.FacilityTankConns,
tank_fluid_types = config.TankFluidTypes
}, },
-- rtus -- rtus
rtu_gw_conn_count = 0, rtu_gw_conn_count = 0,
@ -147,99 +149,6 @@ function facility.new(config)
table.insert(self.test_tone_states, false) table.insert(self.test_tone_states, false)
end end
--#region decode tank configuration
local cool_conf = self.cooling_conf
-- determine tank information
if cool_conf.fac_tank_mode == 0 then
cool_conf.fac_tank_defs = {}
-- on facility tank mode 0, setup tank defs to match unit tank option
for i = 1, config.UnitCount do
cool_conf.fac_tank_defs[i] = util.trinary(cool_conf.r_cool[i].TankConnection, 1, 0)
end
cool_conf.fac_tank_list = { table.unpack(cool_conf.fac_tank_defs) }
else
-- decode the layout of tanks from the connections definitions
local tank_mode = cool_conf.fac_tank_mode
local tank_defs = cool_conf.fac_tank_defs
local tank_list = { table.unpack(tank_defs) }
local function calc_fdef(start_idx, end_idx)
local first = 4
for i = start_idx, end_idx do
if tank_defs[i] == 2 then
if i < first then first = i end
end
end
return first
end
if tank_mode == 1 then
-- (1) 1 total facility tank (A A A A)
local first_fdef = calc_fdef(1, #tank_defs)
for i = 1, #tank_defs do
if i > first_fdef and tank_defs[i] == 2 then
tank_list[i] = 0
end
end
elseif tank_mode == 2 then
-- (2) 2 total facility tanks (A A A B)
local first_fdef = calc_fdef(1, math.min(3, #tank_defs))
for i = 1, #tank_defs do
if (i ~= 4) and (i > first_fdef) and (tank_defs[i] == 2) then
tank_list[i] = 0
end
end
elseif tank_mode == 3 then
-- (3) 2 total facility tanks (A A B B)
for _, a in pairs({ 1, 3 }) do
local b = a + 1
if (tank_defs[a] == 2) and (tank_defs[b] == 2) then
tank_list[b] = 0
end
end
elseif tank_mode == 4 then
-- (4) 2 total facility tanks (A B B B)
local first_fdef = calc_fdef(2, #tank_defs)
for i = 1, #tank_defs do
if (i ~= 1) and (i > first_fdef) and (tank_defs[i] == 2) then
tank_list[i] = 0
end
end
elseif tank_mode == 5 then
-- (5) 3 total facility tanks (A A B C)
local first_fdef = calc_fdef(1, math.min(2, #tank_defs))
for i = 1, #tank_defs do
if (not (i == 3 or i == 4)) and (i > first_fdef) and (tank_defs[i] == 2) then
tank_list[i] = 0
end
end
elseif tank_mode == 6 then
-- (6) 3 total facility tanks (A B B C)
local first_fdef = calc_fdef(2, math.min(3, #tank_defs))
for i = 1, #tank_defs do
if (not (i == 1 or i == 4)) and (i > first_fdef) and (tank_defs[i] == 2) then
tank_list[i] = 0
end
end
elseif tank_mode == 7 then
-- (7) 3 total facility tanks (A B C C)
local first_fdef = calc_fdef(3, #tank_defs)
for i = 1, #tank_defs do
if (not (i == 1 or i == 2)) and (i > first_fdef) and (tank_defs[i] == 2) then
tank_list[i] = 0
end
end
end
cool_conf.fac_tank_list = tank_list
end
--#endregion
-- PUBLIC FUNCTIONS -- -- PUBLIC FUNCTIONS --
---@class facility ---@class facility

View File

@ -22,7 +22,7 @@ local supervisor = require("supervisor.supervisor")
local svsessions = require("supervisor.session.svsessions") local svsessions = require("supervisor.session.svsessions")
local SUPERVISOR_VERSION = "v1.5.18" local SUPERVISOR_VERSION = "v1.6.0"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts

View File

@ -27,6 +27,9 @@ function supervisor.load_config()
config.CoolingConfig = settings.get("CoolingConfig") config.CoolingConfig = settings.get("CoolingConfig")
config.FacilityTankMode = settings.get("FacilityTankMode") config.FacilityTankMode = settings.get("FacilityTankMode")
config.FacilityTankDefs = settings.get("FacilityTankDefs") config.FacilityTankDefs = settings.get("FacilityTankDefs")
config.FacilityTankList = settings.get("FacilityTankList")
config.FacilityTankConns = settings.get("FacilityTankConns")
config.TankFluidTypes = settings.get("TankFluidTypes")
config.ExtChargeIdling = settings.get("ExtChargeIdling") config.ExtChargeIdling = settings.get("ExtChargeIdling")
config.SVR_Channel = settings.get("SVR_Channel") config.SVR_Channel = settings.get("SVR_Channel")
@ -56,8 +59,11 @@ function supervisor.load_config()
cfv.assert_range(config.UnitCount, 1, 4) cfv.assert_range(config.UnitCount, 1, 4)
cfv.assert_type_table(config.CoolingConfig) cfv.assert_type_table(config.CoolingConfig)
cfv.assert_type_table(config.FacilityTankDefs)
cfv.assert_type_int(config.FacilityTankMode) cfv.assert_type_int(config.FacilityTankMode)
cfv.assert_type_table(config.FacilityTankDefs)
cfv.assert_type_table(config.FacilityTankList)
cfv.assert_type_table(config.FacilityTankConns)
cfv.assert_type_table(config.TankFluidTypes)
cfv.assert_range(config.FacilityTankMode, 0, 8) cfv.assert_range(config.FacilityTankMode, 0, 8)
cfv.assert_type_bool(config.ExtChargeIdling) cfv.assert_type_bool(config.ExtChargeIdling)