From 4501cb783f0e7e2757efbfbb7584151460874549 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Thu, 19 Dec 2024 00:58:53 +0000 Subject: [PATCH 1/7] #479 sodium emergency coolant --- coordinator/iocontrol.lua | 4 +- coordinator/startup.lua | 2 +- coordinator/ui/layout/flow_view.lua | 108 ++++++----- pocket/iocontrol.lua | 3 + pocket/startup.lua | 2 +- pocket/ui/apps/unit.lua | 2 +- pocket/ui/pages/dynamic_tank.lua | 15 +- scada-common/types.lua | 6 + supervisor/config/facility.lua | 272 ++++++++++++++++++++++++++-- supervisor/configure.lua | 12 +- supervisor/facility.lua | 97 +--------- supervisor/startup.lua | 2 +- supervisor/supervisor.lua | 4 +- 13 files changed, 368 insertions(+), 161 deletions(-) diff --git a/coordinator/iocontrol.lua b/coordinator/iocontrol.lua index f7dde3d..07479e0 100644 --- a/coordinator/iocontrol.lua +++ b/coordinator/iocontrol.lua @@ -88,6 +88,8 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale) tank_mode = conf.cooling.fac_tank_mode, 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, rtu_count = 0, @@ -116,7 +118,7 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale) 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 } alarm_tones = { false, false, false, false, false, false, false, false }, diff --git a/coordinator/startup.lua b/coordinator/startup.lua index 8f7f1a6..25b48d4 100644 --- a/coordinator/startup.lua +++ b/coordinator/startup.lua @@ -19,7 +19,7 @@ local renderer = require("coordinator.renderer") local sounder = require("coordinator.sounder") local threads = require("coordinator.threads") -local COORDINATOR_VERSION = "v1.5.17" +local COORDINATOR_VERSION = "v1.6.0" local CHUNK_LOAD_DELAY_S = 30.0 diff --git a/coordinator/ui/layout/flow_view.lua b/coordinator/ui/layout/flow_view.lua index b002f24..8a552a2 100644 --- a/coordinator/ui/layout/flow_view.lua +++ b/coordinator/ui/layout/flow_view.lua @@ -24,6 +24,7 @@ local IndicatorLight = require("graphics.elements.indicators.IndicatorLight") local StateIndicator = require("graphics.elements.indicators.StateIndicator") local CONTAINER_MODE = types.CONTAINER_MODE +local COOLANT_TYPE = types.COOLANT_TYPE local ALIGN = core.ALIGN @@ -45,8 +46,10 @@ local function init(main) local facility = iocontrol.get_db().facility local units = iocontrol.get_db().units - local tank_defs = facility.tank_defs - local tank_list = facility.tank_list + local tank_defs = facility.tank_defs + local tank_conns = facility.tank_conns + local tank_list = facility.tank_list + local tank_types = facility.tank_fluid_types -- 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} @@ -56,12 +59,16 @@ local function init(main) datetime.register(facility.ps, "date_time", datetime.set_value) local po_pipes = {} - local water_pipes = {} + local emcool_pipes = {} -- get the y offset for this unit index ---@param idx integer unit index 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.cyan) end + -- determinte facility tank start/end from the definitions list ---@param start_idx integer start 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 if units[i].has_tank then local y = y_ofs(i) - table.insert(water_pipes, pipe(2, y, 2, y + 3, colors.blue, true)) - table.insert(water_pipes, pipe(2, y, 21, y, colors.blue, true)) + local color = c_clr(i) - local x = util.trinary(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(2, y, 2, y + 3, color, true)) + table.insert(emcool_pipes, pipe(2, y, 21, y, color, true)) + + local x = util.trinary(tank_types[tank_conns[i]] == COOLANT_TYPE.WATER, 45, 84) + table.insert(emcool_pipes, pipe(21, y, x, y + 2, color, true, true)) end end else @@ -93,16 +102,17 @@ local function init(main) for i = 1, #tank_defs do if tank_defs[i] > 0 then local y = y_ofs(i) + local color = c_clr(i) 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 - table.insert(water_pipes, pipe(2, y, 2, y + 3, colors.blue, true)) - table.insert(water_pipes, pipe(2, y, 21, y, colors.blue, true)) + table.insert(emcool_pipes, pipe(2, y, 2, y + 3, color, true)) + table.insert(emcool_pipes, pipe(2, y, 21, y, color, true)) end - local x = util.trinary(units[i].num_boilers == 0, 45, 84) - table.insert(water_pipes, pipe(21, y, x, y + 2, colors.blue, true, 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 @@ -112,13 +122,15 @@ local function init(main) for i = 1, #tank_defs do local y = y_ofs(i) + local color = c_clr(i) + 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, color, true)) elseif i > first_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 - 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 @@ -128,17 +140,19 @@ local function init(main) for i = 1, #tank_defs do local y = y_ofs(i) + local color = c_clr(i) + if i == 4 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, color, true)) end 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 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 - 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 @@ -147,12 +161,12 @@ local function init(main) for _, a in pairs({ 1, 3 }) do local b = a + 1 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 - 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(b), true)) end 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 elseif facility.tank_mode == 4 then @@ -161,17 +175,19 @@ local function init(main) for i = 1, #tank_defs do local y = y_ofs(i) + local color = c_clr(i) + if i == 1 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, color, true)) end 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 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 - 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 @@ -181,17 +197,19 @@ local function init(main) for i = 1, #tank_defs do local y = y_ofs(i) + local color = c_clr(i) + if i == 3 or i == 4 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, color, true)) end 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 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 - 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 @@ -201,17 +219,19 @@ local function init(main) for i = 1, #tank_defs do local y = y_ofs(i) + local color = c_clr(i) + if i == 1 or i == 4 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, color, true)) end 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 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 - 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 @@ -221,17 +241,19 @@ local function init(main) for i = 1, #tank_defs do local y = y_ofs(i) + local color = c_clr(i) + if i == 1 or 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, color, true)) end 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 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 - 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 @@ -239,14 +261,14 @@ local function init(main) end local flow_x = 3 - if #water_pipes > 0 then + if #emcool_pipes > 0 then 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 for i = 1, facility.num_units do 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, units[i]) table.insert(po_pipes, pipe(0, 3 + y_offset, 4, 0, colors.cyan, true, true)) util.nop() end @@ -301,8 +323,8 @@ 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_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 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(tank_types[i]==COOLANT_TYPE.WATER,"Water","Sodium").." Level",width=11,fg_bg=style.label} + local level = HorizontalBar{parent=tank_box,x=2,y=7,bar_fg_bg=cpair(util.trinary(tank_types[i]==COOLANT_TYPE.WATER,colors.blue,colors.cyan),colors.gray),height=1,width=16} 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} diff --git a/pocket/iocontrol.lua b/pocket/iocontrol.lua index b860aa4..e606b07 100644 --- a/pocket/iocontrol.lua +++ b/pocket/iocontrol.lua @@ -138,6 +138,9 @@ function iocontrol.init_fac(conf) num_units = conf.num_units, tank_mode = conf.cooling.fac_tank_mode, 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, rtu_count = 0, diff --git a/pocket/startup.lua b/pocket/startup.lua index 0058904..4782325 100644 --- a/pocket/startup.lua +++ b/pocket/startup.lua @@ -20,7 +20,7 @@ local pocket = require("pocket.pocket") local renderer = require("pocket.renderer") 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_ts = util.println_ts diff --git a/pocket/ui/apps/unit.lua b/pocket/ui/apps/unit.lua index 8335ff1..2f916d3 100644 --- a/pocket/ui/apps/unit.lua +++ b/pocket/ui/apps/unit.lua @@ -372,7 +372,7 @@ local function new_view(root) if #unit.tank_data_tbl > 0 then 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 --#endregion diff --git a/pocket/ui/pages/dynamic_tank.lua b/pocket/ui/pages/dynamic_tank.lua index bfc89de..06b4614 100644 --- a/pocket/ui/pages/dynamic_tank.lua +++ b/pocket/ui/pages/dynamic_tank.lua @@ -1,4 +1,7 @@ local types = require("scada-common.types") +local util = require("scada-common.util") + +local iocontrol = require("pocket.iocontrol") 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 CONTAINER_MODE = types.CONTAINER_MODE +local COOLANT_TYPE = types.COOLANT_TYPE local cpair = core.cpair @@ -30,9 +34,12 @@ local mode_ind_s = { ---@param page nav_tree_page ---@param panes Div[] ---@param tank_pane Div +---@param tank_id integer global facility tank ID (as used for tank list, etc) ---@param ps psil ---@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} 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_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 level = HorizontalBar{parent=tank_div,y=7,bar_fg_bg=cpair(colors.blue,colors.gray),height=1,width=21} + local is_water = fac.tank_fluid_types[tank_id] == COOLANT_TYPE.WATER + + TextBox{parent=tank_div,y=6,text=util.trinary(is_water,"Water","Sodium").." Level",width=11,fg_bg=label} + local level = HorizontalBar{parent=tank_div,y=7,bar_fg_bg=cpair(util.trinary(is_water,colors.blue,colors.cyan),colors.gray),height=1,width=21} 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} diff --git a/scada-common/types.lua b/scada-common/types.lua index 19392fe..92402b8 100644 --- a/scada-common/types.lua +++ b/scada-common/types.lua @@ -418,6 +418,12 @@ types.AUTO_GROUP_NAMES = { "Backup" } +---@enum COOLANT_TYPE +types.COOLANT_TYPE = { + WATER = 0, + SODIUM = 1 +} + ---@enum WASTE_MODE types.WASTE_MODE = { AUTO = 1, diff --git a/supervisor/config/facility.lua b/supervisor/config/facility.lua index 84c9c51..b8b4a18 100644 --- a/supervisor/config/facility.lua +++ b/supervisor/config/facility.lua @@ -18,8 +18,13 @@ local tri = util.trinary local cpair = core.cpair local self = { - vis_ftanks = {}, ---@type { line: Div, pipe_conn?: TextBox, pipe_chain?: TextBox, pipe_direct?: TextBox, label?: TextBox }[] - vis_utanks = {} ---@type { line: Div, label: TextBox }[] + tank_fluid_opts = {}, ---@type Radio2D[] + + 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 = {} @@ -48,11 +53,14 @@ 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_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_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)} + --#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."} 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"} @@ -77,6 +85,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=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=6,text="UNIT TURBINES BOILERS HAS TANK CONNECTION?",fg_bg=g_lg_fg_bg} @@ -149,6 +160,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=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=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 +175,14 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) else tmp_cfg.FacilityTankMode = 0 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] = util.trinary(tmp_cfg.CoolingConfig[i].TankConnection, 1, 0) + end + + tmp_cfg.FacilityTankList = { table.unpack(tmp_cfg.FacilityTankDefs) } + fac_pane.set_value(7) end end @@ -168,6 +190,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=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."} for i = 1, 4 do @@ -220,7 +245,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) self.vis_utanks[i].line.hide(true) end - tool_ctl.vis_draw(tmp_cfg.FacilityTankMode) + self.vis_draw(tmp_cfg.FacilityTankMode) if any_fac then tank_err.hide(true) @@ -231,6 +256,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=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=12,y=3,text="Facility Tanks Unit Tanks",fg_bg=g_lg_fg_bg} @@ -269,7 +297,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) -- draw the pipe visualization ---@param mode integer pipe mode - function tool_ctl.vis_draw(mode) + function self.vis_draw(mode) -- is a facility tank connected to this unit ---@param i integer unit 1 - 4 ---@return boolean connected @@ -391,7 +419,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) local function change_mode(mode) tmp_cfg.FacilityTankMode = mode - tool_ctl.vis_draw(mode) + self.vis_draw(mode) end local tank_modes = { "Mode 1", "Mode 2", "Mode 3", "Mode 4", "Mode 5", "Mode 6", "Mode 7", "Mode 8" } @@ -399,24 +427,244 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) --#endregion + local function next_from_tank_mode() + -- determine tank list and connections + + local tank_mode = tmp_cfg.FacilityTankMode + local tank_defs = tmp_cfg.FacilityTankDefs + 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 + + tmp_cfg.FacilityTankList = tank_list + tmp_cfg.FacilityTankConns = tank_conns + + 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=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} + --#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,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} 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."} - 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."} + --#endregion + --#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 the type of coolant each tank will contain. This only affects visualizations, not operation. You cannot set Sodium if one or more of the connected reactors 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 + 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} + + local tank_fluid = Radio2D{parent=row,x=15,y=1,rows=1,columns=2,default=ini_cfg.TankFluidTypes[i],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 = "Connected to: " + local any_bwr = false + + for u = 1, #tank_conns do + if tank_conns[u] == i then + conns = conns .. "Unit " .. u .. " " + any_bwr = any_bwr or (tmp_cfg.CoolingConfig[u].BoilerCount == 0) + end + end + + TextBox{parent=row,text=conns} + + local tank_fluid = Radio2D{parent=row,x=15,y=1,rows=1,columns=2,default=ini_cfg.TankFluidTypes[i],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 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=function()fac_pane.set_value(5)end,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() - fac_pane.set_value(tri(tmp_cfg.FacilityTankMode == 0, 3, 5)) + fac_pane.set_value(tri(tmp_cfg.FacilityTankMode == 0, 3, 7)) end local function submit_idling() @@ -429,6 +677,8 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) --#endregion + --#endregion + return fac_pane end diff --git a/supervisor/configure.lua b/supervisor/configure.lua index 0b1b558..f4e71f2 100644 --- a/supervisor/configure.lua +++ b/supervisor/configure.lua @@ -30,7 +30,8 @@ local CENTER = core.ALIGN.CENTER -- changes to the config data/format to let the user know local changes = { { "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 @@ -78,8 +79,11 @@ local tool_ctl = { local tmp_cfg = { UnitCount = 1, CoolingConfig = {}, ---@type { TurbineCount: integer, BoilerCount: integer, TankConnection: boolean }[] - FacilityTankMode = 0, - FacilityTankDefs = {}, ---@type integer[] + FacilityTankMode = 0, -- dynamic tank emergency coolant layout + 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, SVR_Channel = nil, ---@type integer PLC_Channel = nil, ---@type integer @@ -176,7 +180,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."} 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, you may want to check the Change Log to see what changed.",fg_bg=cpair(colors.red,colors.lightGray)} y_start = y_start + 5 end diff --git a/supervisor/facility.lua b/supervisor/facility.lua index 604771a..e47842f 100644 --- a/supervisor/facility.lua +++ b/supervisor/facility.lua @@ -51,7 +51,9 @@ function facility.new(config) r_cool = config.CoolingConfig, fac_tank_mode = config.FacilityTankMode, 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 rtu_gw_conn_count = 0, @@ -147,99 +149,6 @@ function facility.new(config) table.insert(self.test_tone_states, false) 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 -- ---@class facility diff --git a/supervisor/startup.lua b/supervisor/startup.lua index 85a229e..c401dea 100644 --- a/supervisor/startup.lua +++ b/supervisor/startup.lua @@ -22,7 +22,7 @@ local supervisor = require("supervisor.supervisor") local svsessions = require("supervisor.session.svsessions") -local SUPERVISOR_VERSION = "v1.5.18" +local SUPERVISOR_VERSION = "v1.6.0" local println = util.println local println_ts = util.println_ts diff --git a/supervisor/supervisor.lua b/supervisor/supervisor.lua index 98cdc78..afc2bb5 100644 --- a/supervisor/supervisor.lua +++ b/supervisor/supervisor.lua @@ -27,6 +27,7 @@ function supervisor.load_config() config.CoolingConfig = settings.get("CoolingConfig") config.FacilityTankMode = settings.get("FacilityTankMode") config.FacilityTankDefs = settings.get("FacilityTankDefs") + config.TankFluidTypes = settings.get("TankFluidTypes") config.ExtChargeIdling = settings.get("ExtChargeIdling") config.SVR_Channel = settings.get("SVR_Channel") @@ -56,8 +57,9 @@ function supervisor.load_config() cfv.assert_range(config.UnitCount, 1, 4) cfv.assert_type_table(config.CoolingConfig) - cfv.assert_type_table(config.FacilityTankDefs) cfv.assert_type_int(config.FacilityTankMode) + cfv.assert_type_table(config.FacilityTankDefs) + cfv.assert_type_table(config.TankFluidTypes) cfv.assert_range(config.FacilityTankMode, 0, 8) cfv.assert_type_bool(config.ExtChargeIdling) From bc4228d4eb8b93b38bf2f06b33cb5d2e12dd943d Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Wed, 18 Dec 2024 21:47:16 -0500 Subject: [PATCH 2/7] #479 WIP sodium emergency coolant fixes --- coordinator/ui/components/unit_flow.lua | 25 +- coordinator/ui/layout/flow_view.lua | 14 +- scada-common/types.lua | 4 +- scada-common/util.lua | 2 +- supervisor/config/facility.lua | 291 +++++++++++++----------- supervisor/config/system.lua | 57 +++-- supervisor/configure.lua | 5 +- supervisor/supervisor.lua | 4 + 8 files changed, 230 insertions(+), 172 deletions(-) diff --git a/coordinator/ui/components/unit_flow.lua b/coordinator/ui/components/unit_flow.lua index 27e4d0d..f0813f7 100644 --- a/coordinator/ui/components/unit_flow.lua +++ b/coordinator/ui/components/unit_flow.lua @@ -2,8 +2,11 @@ -- Basic Unit Flow Overview -- +local types = require("scada-common.types") local util = require("scada-common.util") +local iocontrol = require("coordinator.iocontrol") + local style = require("coordinator.ui.style") local core = require("graphics.core") @@ -19,6 +22,8 @@ local DataIndicator = require("graphics.elements.indicators.DataIndicator") local IndicatorLight = require("graphics.elements.indicators.IndicatorLight") local TriIndicatorLight = require("graphics.elements.indicators.TriIndicatorLight") +local COOLANT_TYPE = types.COOLANT_TYPE + local ALIGN = core.ALIGN local sprintf = util.sprintf @@ -35,8 +40,8 @@ local lg_gray = style.lg_gray ---@param x integer top left x ---@param y integer top left y ---@param wide boolean whether to render wide version ----@param unit ioctl_unit unit database entry -local function make(parent, x, y, wide, unit) +---@param unit_id integer unit index +local function make(parent, x, y, wide, unit_id) local s_field = style.theme.field_box local text_c = style.text_colors @@ -48,6 +53,13 @@ local function make(parent, x, y, wide, unit) local height = 16 + local facility = iocontrol.get_db().facility + local unit = iocontrol.get_db().units[unit_id] + + local tank_defs = facility.tank_defs + local tank_conns = facility.tank_conns + local tank_types = facility.tank_fluid_types + local v_start = 1 + ((unit.unit_id - 1) * 5) local prv_start = 1 + ((unit.unit_id - 1) * 3) local v_fields = { "pu", "po", "pl", "am" } @@ -80,21 +92,22 @@ local function make(parent, x, y, wide, unit) local rc_pipes = {} - local emc_x = 42 -- emergency coolant connection x point - 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, 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), 3, _wide(72,58), 3, colors.white, true)) else - emc_x = 3 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)) end 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 local prv_yo = math.max(3 - unit.num_turbines, 0) diff --git a/coordinator/ui/layout/flow_view.lua b/coordinator/ui/layout/flow_view.lua index 8a552a2..bf90a9c 100644 --- a/coordinator/ui/layout/flow_view.lua +++ b/coordinator/ui/layout/flow_view.lua @@ -67,7 +67,7 @@ local function init(main) -- 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.cyan) end + 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 ---@param start_idx integer start index of table iteration @@ -128,9 +128,9 @@ local function init(main) table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true)) elseif i > first_fdef then if i == last_fdef then - table.insert(emcool_pipes, pipe(0, y - 14, 0, y, color, true)) + table.insert(emcool_pipes, pipe(0, y - 14, 0, y, c_clr(first_fdef), true)) elseif i < last_fdef then - table.insert(emcool_pipes, pipe(0, y - 14, 0, y + 5, color, true)) + table.insert(emcool_pipes, pipe(0, y - 14, 0, y + 5, c_clr(first_fdef), true)) end end end @@ -268,7 +268,7 @@ local function init(main) for i = 1, facility.num_units do local y_offset = y_ofs(i) - unit_flow(main, flow_x, 5 + y_offset, #emcool_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)) util.nop() end @@ -323,8 +323,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_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=util.trinary(tank_types[i]==COOLANT_TYPE.WATER,"Water","Sodium").." Level",width=11,fg_bg=style.label} - local level = HorizontalBar{parent=tank_box,x=2,y=7,bar_fg_bg=cpair(util.trinary(tank_types[i]==COOLANT_TYPE.WATER,colors.blue,colors.cyan),colors.gray),height=1,width=16} + local is_water = tank_types[i] == COOLANT_TYPE.WATER + + 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} local can_fill = IndicatorLight{parent=tank_box,x=2,y=10,label="FILL",colors=style.ind_wht} diff --git a/scada-common/types.lua b/scada-common/types.lua index 92402b8..0d562a6 100644 --- a/scada-common/types.lua +++ b/scada-common/types.lua @@ -420,8 +420,8 @@ types.AUTO_GROUP_NAMES = { ---@enum COOLANT_TYPE types.COOLANT_TYPE = { - WATER = 0, - SODIUM = 1 + WATER = 1, + SODIUM = 2 } ---@enum WASTE_MODE diff --git a/scada-common/util.lua b/scada-common/util.lua index 3023a49..96c1ec8 100644 --- a/scada-common/util.lua +++ b/scada-common/util.lua @@ -24,7 +24,7 @@ local t_pack = table.pack local util = {} -- scada-common version -util.version = "1.4.7" +util.version = "1.4.8" util.TICK_TIME_S = 0.05 util.TICK_TIME_MS = 50 diff --git a/supervisor/config/facility.lua b/supervisor/config/facility.lua index b8b4a18..7e64f97 100644 --- a/supervisor/config/facility.lua +++ b/supervisor/config/facility.lua @@ -29,6 +29,138 @@ local self = { 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 +---@return table tank_conns +local function 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 ---@param tool_ctl _svr_cfg_tool_ctl ---@param main_pane MultiPane @@ -178,10 +310,12 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) -- on facility tank mode 0, setup tank defs to match unit tank option for i = 1, tmp_cfg.UnitCount do - tmp_cfg.FacilityTankDefs[i] = util.trinary(tmp_cfg.CoolingConfig[i].TankConnection, 1, 0) + tmp_cfg.FacilityTankDefs[i] = tri(tmp_cfg.CoolingConfig[i].TankConnection, 1, 0) end - tmp_cfg.FacilityTankList = { table.unpack(tmp_cfg.FacilityTankDefs) } + tmp_cfg.FacilityTankList, tmp_cfg.FacilityTankConns = generate_tank_list_and_conns(tmp_cfg.FacilityTankMode, tmp_cfg.FacilityTankDefs) + + self.draw_fluid_ops() fac_pane.set_value(7) end @@ -429,132 +563,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) local function next_from_tank_mode() -- determine tank list and connections - - local tank_mode = tmp_cfg.FacilityTankMode - local tank_defs = tmp_cfg.FacilityTankDefs - 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 - - tmp_cfg.FacilityTankList = tank_list - tmp_cfg.FacilityTankConns = tank_conns + tmp_cfg.FacilityTankList, tmp_cfg.FacilityTankConns = generate_tank_list_and_conns(tmp_cfg.FacilityTankMode, tmp_cfg.FacilityTankDefs) self.draw_fluid_ops() @@ -578,7 +587,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) --#endregion --#region Dynamic Tank Fluid Types - TextBox{parent=fac_c_7,height=3,text="Specify the type of coolant each tank will contain. This only affects visualizations, not operation. You cannot set Sodium if one or more of the connected reactors is water cooled."} + TextBox{parent=fac_c_7,height=3,text="Specify the type of coolant each tank will contain, 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} @@ -591,15 +600,17 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) local next_f = 1 for i = 1, #tank_list do + local type = tmp_cfg.TankFluidTypes[i] + 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} + TextBox{parent=row,text="Connected to: Unit "..i,fg_bg=cpair(colors.gray,colors.lightGray)} - local tank_fluid = Radio2D{parent=row,x=15,y=1,rows=1,columns=2,default=ini_cfg.TankFluidTypes[i],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} + 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) @@ -612,19 +623,19 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) TextBox{parent=row,width=15,text="Facility Tank "..next_f} - local conns = "Connected to: " + local conns = "" local any_bwr = false for u = 1, #tank_conns do if tank_conns[u] == i then - conns = conns .. "Unit " .. u .. " " + conns = conns .. tri(conns == "", "", ", ") .. "Unit " .. u any_bwr = any_bwr or (tmp_cfg.CoolingConfig[u].BoilerCount == 0) end end - TextBox{parent=row,text=conns} + TextBox{parent=row,text="Connected to: "..conns,fg_bg=cpair(colors.gray,colors.lightGray)} - local tank_fluid = Radio2D{parent=row,x=15,y=1,rows=1,columns=2,default=ini_cfg.TankFluidTypes[i],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} + 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) @@ -638,6 +649,10 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) 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 = {} @@ -652,7 +667,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) fac_pane.set_value(8) end - PushButton{parent=fac_c_7,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_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 @@ -672,8 +687,8 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) main_pane.set_value(3) 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_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=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=44,y=14,text="Next \x1a",callback=submit_idling,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} --#endregion diff --git a/supervisor/config/system.lua b/supervisor/config/system.lua index 9e0b0c7..cb5bacd 100644 --- a/supervisor/config/system.lua +++ b/supervisor/config/system.lua @@ -557,6 +557,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 raw = cfg[f[1]] local val = util.strval(raw) + local skip = false if f[1] == "AuthKey" then val = string.rep("*", string.len(val)) elseif f[1] == "LogMode" then val = tri(raw == log.MODE.APPEND, "append", "replace") @@ -593,29 +594,49 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit end if val == "" then val = "no facility tanks" end + elseif f[1] == "FacilityTankList" or f[1] == "FacilityTankConns" then + -- hide + skip = true + elseif f[1] == "TankFluidTypes" and type(cfg.TankFluidTypes) == "table" and type(cfg.FacilityTankDefs) == "table" then + val = "" + + for idx = 1, #cfg.FacilityTankDefs do + local t_mode = "not connected to a tank" + if cfg.FacilityTankDefs[idx] == 1 then + t_mode = "connected to its unit tank" + elseif cfg.FacilityTankDefs[idx] == 2 then + t_mode = "connected to a facility tank" + end + + val = val .. tri(idx == 1, "", "\n") .. util.sprintf(" \x07 unit %d - %s", idx, t_mode) + end + + if val == "" then val = "no emergency coolant tanks" end end - if val == "nil" then val = "" end + if not skip then + if val == "nil" then val = "" end - local c = tri(alternate, g_lg_fg_bg, cpair(colors.gray,colors.white)) - alternate = not alternate + local c = tri(alternate, g_lg_fg_bg, cpair(colors.gray,colors.white)) + alternate = not alternate - if string.len(val) > val_max_w then - local lines = util.strwrap(val, inner_width) - height = #lines + 1 + if string.len(val) > val_max_w then + local lines = util.strwrap(val, inner_width) + 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 - - 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 diff --git a/supervisor/configure.lua b/supervisor/configure.lua index f4e71f2..73acd96 100644 --- a/supervisor/configure.lua +++ b/supervisor/configure.lua @@ -114,6 +114,9 @@ local fields = { { "CoolingConfig", "Cooling Configuration", {} }, { "FacilityTankMode", "Facility Tank Mode", 0 }, { "FacilityTankDefs", "Facility Tank Definitions", {} }, + { "FacilityTankList", "Facility Tank List", {} }, -- hidden + { "FacilityTankConns", "Facility Tank Connections", {} }, -- hidden + { "TankFluidTypes", "Tank Fluid Types", {} }, { "ExtChargeIdling", "Extended Charge Idling", false }, { "SVR_Channel", "SVR Channel", 16240 }, { "PLC_Channel", "PLC Channel", 16241 }, @@ -180,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."} if tool_ctl.ask_config then - 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, 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 end diff --git a/supervisor/supervisor.lua b/supervisor/supervisor.lua index afc2bb5..fe7b011 100644 --- a/supervisor/supervisor.lua +++ b/supervisor/supervisor.lua @@ -27,6 +27,8 @@ function supervisor.load_config() config.CoolingConfig = settings.get("CoolingConfig") config.FacilityTankMode = settings.get("FacilityTankMode") 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") @@ -59,6 +61,8 @@ function supervisor.load_config() cfv.assert_type_table(config.CoolingConfig) 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) From ffd4bae2d5b0598ca3f989ec03e922f269a64914 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Fri, 20 Dec 2024 00:57:25 +0000 Subject: [PATCH 3/7] #479 work on sodium emergency coolant config and ui --- coordinator/ui/components/unit_flow.lua | 1 - coordinator/ui/layout/flow_view.lua | 9 ++-- supervisor/config/facility.lua | 6 +-- supervisor/config/system.lua | 59 ++++++++++++++++++++----- 4 files changed, 54 insertions(+), 21 deletions(-) diff --git a/coordinator/ui/components/unit_flow.lua b/coordinator/ui/components/unit_flow.lua index f0813f7..2c1ed35 100644 --- a/coordinator/ui/components/unit_flow.lua +++ b/coordinator/ui/components/unit_flow.lua @@ -56,7 +56,6 @@ local function make(parent, x, y, wide, unit_id) local facility = iocontrol.get_db().facility local unit = iocontrol.get_db().units[unit_id] - local tank_defs = facility.tank_defs local tank_conns = facility.tank_conns local tank_types = facility.tank_fluid_types diff --git a/coordinator/ui/layout/flow_view.lua b/coordinator/ui/layout/flow_view.lua index bf90a9c..75972e9 100644 --- a/coordinator/ui/layout/flow_view.lua +++ b/coordinator/ui/layout/flow_view.lua @@ -122,10 +122,9 @@ local function init(main) for i = 1, #tank_defs do local y = y_ofs(i) - local color = c_clr(i) if i == first_fdef then - table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true)) + table.insert(emcool_pipes, pipe(0, y, 1, y + 5, c_clr(i), true)) elseif i > first_fdef then if i == last_fdef then table.insert(emcool_pipes, pipe(0, y - 14, 0, y, c_clr(first_fdef), true)) @@ -140,11 +139,11 @@ local function init(main) for i = 1, #tank_defs do local y = y_ofs(i) - local color = c_clr(i) + local color = c_clr(first_fdef) if i == 4 then if tank_defs[i] == 2 then - table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true)) + table.insert(emcool_pipes, pipe(0, y, 1, y + 5, c_clr(i), true)) end elseif i == first_fdef then table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true)) @@ -163,7 +162,7 @@ local function init(main) if tank_defs[a] == 2 then table.insert(emcool_pipes, pipe(0, y_ofs(a), 1, y_ofs(a) + 6, c_clr(a), true)) if tank_defs[b] == 2 then - table.insert(emcool_pipes, pipe(0, y_ofs(b) - 13, 1, y_ofs(b), c_clr(b), true)) + table.insert(emcool_pipes, pipe(0, y_ofs(b) - 13, 1, y_ofs(b), c_clr(a), true)) end elseif tank_defs[b] == 2 then table.insert(emcool_pipes, pipe(0, y_ofs(b), 1, y_ofs(b) + 6, c_clr(b), true)) diff --git a/supervisor/config/facility.lua b/supervisor/config/facility.lua index 7e64f97..225c758 100644 --- a/supervisor/config/facility.lua +++ b/supervisor/config/facility.lua @@ -34,7 +34,7 @@ local facility = {} ---@param defs table facility tank definitions ---@return table tank_list ---@return table tank_conns -local function generate_tank_list_and_conns(mode, defs) +function facility.generate_tank_list_and_conns(mode, defs) local tank_mode = mode local tank_defs = defs local tank_list = { table.unpack(tank_defs) } @@ -313,7 +313,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) tmp_cfg.FacilityTankDefs[i] = tri(tmp_cfg.CoolingConfig[i].TankConnection, 1, 0) end - tmp_cfg.FacilityTankList, tmp_cfg.FacilityTankConns = generate_tank_list_and_conns(tmp_cfg.FacilityTankMode, tmp_cfg.FacilityTankDefs) + tmp_cfg.FacilityTankList, tmp_cfg.FacilityTankConns = facility.generate_tank_list_and_conns(tmp_cfg.FacilityTankMode, tmp_cfg.FacilityTankDefs) self.draw_fluid_ops() @@ -563,7 +563,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) local function next_from_tank_mode() -- determine tank list and connections - tmp_cfg.FacilityTankList, tmp_cfg.FacilityTankConns = generate_tank_list_and_conns(tmp_cfg.FacilityTankMode, tmp_cfg.FacilityTankDefs) + tmp_cfg.FacilityTankList, tmp_cfg.FacilityTankConns = facility.generate_tank_list_and_conns(tmp_cfg.FacilityTankMode, tmp_cfg.FacilityTankDefs) self.draw_fluid_ops() diff --git a/supervisor/config/system.lua b/supervisor/config/system.lua index cb5bacd..7518210 100644 --- a/supervisor/config/system.lua +++ b/supervisor/config/system.lua @@ -1,6 +1,9 @@ local log = require("scada-common.log") +local types = require("scada-common.types") local util = require("scada-common.util") +local facility = require("supervisor.config.facility") + local core = require("graphics.core") local themes = require("graphics.themes") @@ -508,8 +511,15 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit else tmp_cfg.FacilityTankMode = 0 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 + 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.PLC_Channel = config.PLC_CHANNEL tmp_cfg.RTU_Channel = config.RTU_CHANNEL @@ -580,14 +590,26 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit 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] == "FacilityTankDefs" and type(cfg.FacilityTankDefs) == "table" then + local tank_name_list = { table.unpack(cfg.FacilityTankList) } ---@type (string|integer)[] + local next_f = 1 + val = "" + for idx = 1, #tank_name_list do + if tank_name_list[i] == 1 then + tank_name_list[i] = "U" .. idx + elseif tank_name_list[i] == 2 then + tank_name_list[i] = "F" .. next_f + next_f = next_f + 1 + end + end + for idx = 1, #cfg.FacilityTankDefs do local t_mode = "not connected to a tank" 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[i]] .. ")" elseif cfg.FacilityTankDefs[idx] == 2 then - t_mode = "connected to a facility tank" + t_mode = "connected to facility tank " .. tank_name_list[cfg.FacilityTankConns[i]] end val = val .. tri(idx == 1, "", "\n") .. util.sprintf(" \x07 unit %d - %s", idx, t_mode) @@ -595,20 +617,33 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit if val == "" then val = "no facility tanks" end elseif f[1] == "FacilityTankList" or f[1] == "FacilityTankConns" then - -- hide + -- 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.FacilityTankDefs) == "table" then + 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, #cfg.FacilityTankDefs do - local t_mode = "not connected to a tank" - if cfg.FacilityTankDefs[idx] == 1 then - t_mode = "connected to its unit tank" - elseif cfg.FacilityTankDefs[idx] == 2 then - t_mode = "connected to a facility tank" - end + for idx = 1, #tank_list do + local prefix = "?" + local fluid = "water" + local type = tmp_cfg.TankFluidTypes[idx] - val = val .. tri(idx == 1, "", "\n") .. util.sprintf(" \x07 unit %d - %s", idx, t_mode) + if tank_list[i] > 0 then + if tank_list[i] == 1 then + prefix = "U" .. idx + elseif tank_list[i] == 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 From feabed6a1ed0871c739a96dc0b543aa268ef4f42 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Thu, 19 Dec 2024 20:10:57 -0500 Subject: [PATCH 4/7] #479 fixed configurator tank summary --- supervisor/config/system.lua | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/supervisor/config/system.lua b/supervisor/config/system.lua index 7518210..71483f9 100644 --- a/supervisor/config/system.lua +++ b/supervisor/config/system.lua @@ -596,10 +596,10 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit val = "" for idx = 1, #tank_name_list do - if tank_name_list[i] == 1 then - tank_name_list[i] = "U" .. idx - elseif tank_name_list[i] == 2 then - tank_name_list[i] = "F" .. next_f + 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 @@ -607,9 +607,9 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit for idx = 1, #cfg.FacilityTankDefs do local t_mode = "not connected to a tank" if cfg.FacilityTankDefs[idx] == 1 then - t_mode = "connected to its unit tank (" .. tank_name_list[cfg.FacilityTankConns[i]] .. ")" + t_mode = "connected to its unit tank (" .. tank_name_list[cfg.FacilityTankConns[idx]] .. ")" elseif cfg.FacilityTankDefs[idx] == 2 then - t_mode = "connected to facility tank " .. tank_name_list[cfg.FacilityTankConns[i]] + t_mode = "connected to facility tank " .. tank_name_list[cfg.FacilityTankConns[idx]] end val = val .. tri(idx == 1, "", "\n") .. util.sprintf(" \x07 unit %d - %s", idx, t_mode) @@ -628,12 +628,12 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit for idx = 1, #tank_list do local prefix = "?" local fluid = "water" - local type = tmp_cfg.TankFluidTypes[idx] + local type = cfg.TankFluidTypes[idx] - if tank_list[i] > 0 then - if tank_list[i] == 1 then + if tank_list[idx] > 0 then + if tank_list[idx] == 1 then prefix = "U" .. idx - elseif tank_list[i] == 2 then + elseif tank_list[idx] == 2 then prefix = "F" .. next_f next_f = next_f + 1 end From 3f42adea5baf8f8fd33a94067ae208390430e310 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Fri, 20 Dec 2024 12:42:45 -0500 Subject: [PATCH 5/7] #479 fixes and emphasis on needing to keep supervisor and coordinator unit counts in sync --- coordinator/config/facility.lua | 2 +- coordinator/ui/layout/flow_view.lua | 18 +++++++++--------- pocket/ui/pages/dynamic_tank.lua | 2 +- supervisor/config/facility.lua | 5 ++++- supervisor/configure.lua | 4 ++++ 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/coordinator/config/facility.lua b/coordinator/config/facility.lua index 00f8c99..423eb19 100644 --- a/coordinator/config/facility.lua +++ b/coordinator/config/facility.lua @@ -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."} 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=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} 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} diff --git a/coordinator/ui/layout/flow_view.lua b/coordinator/ui/layout/flow_view.lua index 75972e9..7b89212 100644 --- a/coordinator/ui/layout/flow_view.lua +++ b/coordinator/ui/layout/flow_view.lua @@ -93,7 +93,7 @@ local function init(main) table.insert(emcool_pipes, pipe(2, y, 2, y + 3, color, true)) table.insert(emcool_pipes, pipe(2, y, 21, y, color, true)) - local x = util.trinary(tank_types[tank_conns[i]] == COOLANT_TYPE.WATER, 45, 84) + 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 @@ -174,11 +174,11 @@ local function init(main) for i = 1, #tank_defs do local y = y_ofs(i) - local color = c_clr(i) + local color = c_clr(first_fdef) if i == 1 then if tank_defs[i] == 2 then - table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true)) + table.insert(emcool_pipes, pipe(0, y, 1, y + 5, c_clr(i), true)) end elseif i == first_fdef then table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true)) @@ -196,11 +196,11 @@ local function init(main) for i = 1, #tank_defs do local y = y_ofs(i) - local color = c_clr(i) + local color = c_clr(first_fdef) if i == 3 or i == 4 then if tank_defs[i] == 2 then - table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true)) + table.insert(emcool_pipes, pipe(0, y, 1, y + 5, c_clr(i), true)) end elseif i == first_fdef then table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true)) @@ -218,11 +218,11 @@ local function init(main) for i = 1, #tank_defs do local y = y_ofs(i) - local color = c_clr(i) + local color = c_clr(first_fdef) if i == 1 or i == 4 then if tank_defs[i] == 2 then - table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true)) + table.insert(emcool_pipes, pipe(0, y, 1, y + 5, c_clr(i), true)) end elseif i == first_fdef then table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true)) @@ -240,11 +240,11 @@ local function init(main) for i = 1, #tank_defs do local y = y_ofs(i) - local color = c_clr(i) + local color = c_clr(first_fdef) if i == 1 or i == 2 then if tank_defs[i] == 2 then - table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true)) + table.insert(emcool_pipes, pipe(0, y, 1, y + 5, c_clr(i), true)) end elseif i == first_fdef then table.insert(emcool_pipes, pipe(0, y, 1, y + 5, color, true)) diff --git a/pocket/ui/pages/dynamic_tank.lua b/pocket/ui/pages/dynamic_tank.lua index 06b4614..4999967 100644 --- a/pocket/ui/pages/dynamic_tank.lua +++ b/pocket/ui/pages/dynamic_tank.lua @@ -56,7 +56,7 @@ return function (app, page, panes, tank_pane, tank_id, ps, update) local is_water = fac.tank_fluid_types[tank_id] == COOLANT_TYPE.WATER - TextBox{parent=tank_div,y=6,text=util.trinary(is_water,"Water","Sodium").." Level",width=11,fg_bg=label} + 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.cyan),colors.gray),height=1,width=21} TextBox{parent=tank_div,y=9,text="Tank Fill Mode",width=14,fg_bg=label} diff --git a/supervisor/config/facility.lua b/supervisor/config/facility.lua index 225c758..c00ef9b 100644 --- a/supervisor/config/facility.lua +++ b/supervisor/config/facility.lua @@ -196,6 +196,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) 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} 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} @@ -587,7 +588,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) --#endregion --#region Dynamic Tank Fluid Types - TextBox{parent=fac_c_7,height=3,text="Specify the type of coolant each tank will contain, for display use only. Water is the only option if one or more of the connected units is water cooled."} + 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} @@ -602,6 +603,8 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style) 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 diff --git a/supervisor/configure.lua b/supervisor/configure.lua index 73acd96..6e760bd 100644 --- a/supervisor/configure.lua +++ b/supervisor/configure.lua @@ -282,6 +282,10 @@ function configurator.configure(ask_config) load_settings(settings_cfg, true) 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() -- set overridden colors From de3fa163c586d96bd57ae21c3a3717e675e56cf3 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Fri, 20 Dec 2024 17:20:56 -0500 Subject: [PATCH 6/7] #479 fixed dynamic tank fill color in pocket --- pocket/ui/pages/dynamic_tank.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pocket/ui/pages/dynamic_tank.lua b/pocket/ui/pages/dynamic_tank.lua index 4999967..356f7e6 100644 --- a/pocket/ui/pages/dynamic_tank.lua +++ b/pocket/ui/pages/dynamic_tank.lua @@ -57,7 +57,7 @@ return function (app, page, panes, tank_pane, tank_id, ps, update) local is_water = fac.tank_fluid_types[tank_id] == COOLANT_TYPE.WATER 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.cyan),colors.gray),height=1,width=21} + 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} local can_fill = IconIndicator{parent=tank_div,y=10,label="Fill",states=mode_ind_s} From c487b22fe1d354a06230e3e9281fddb1e6c2a69f Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Fri, 20 Dec 2024 20:45:57 -0500 Subject: [PATCH 7/7] cleanup --- supervisor/config/facility.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/supervisor/config/facility.lua b/supervisor/config/facility.lua index c00ef9b..13e238c 100644 --- a/supervisor/config/facility.lua +++ b/supervisor/config/facility.lua @@ -32,8 +32,7 @@ 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 ----@return table tank_conns +---@return table tank_list, table tank_conns function facility.generate_tank_list_and_conns(mode, defs) local tank_mode = mode local tank_defs = defs