From ba4a5aa85ea5c28f10ea5b89c2093407e54a02a1 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Sat, 4 Jan 2025 15:33:37 +0000 Subject: [PATCH 01/29] #557 work on facility app --- pocket/iocontrol.lua | 8 ++ pocket/pocket.lua | 17 +-- pocket/ui/apps/facility.lua | 241 ++++++++++++++++++++++++++++++++++ pocket/ui/pages/home_page.lua | 2 +- 4 files changed, 259 insertions(+), 9 deletions(-) create mode 100644 pocket/ui/apps/facility.lua diff --git a/pocket/iocontrol.lua b/pocket/iocontrol.lua index e606b07..75c3b5d 100644 --- a/pocket/iocontrol.lua +++ b/pocket/iocontrol.lua @@ -192,6 +192,14 @@ function iocontrol.init_fac(conf) table.insert(io.facility.sps_ps_tbl, psil.create()) table.insert(io.facility.sps_data_tbl, {}) + -- create facility tank tables + for i = 1, #io.facility.tank_list do + if io.facility.tank_list[i] == 2 then + table.insert(io.facility.tank_ps_tbl, psil.create()) + table.insert(io.facility.tank_data_tbl, {}) + end + end + -- create unit data structures io.units = {} ---@type pioctl_unit[] for i = 1, conf.num_units do diff --git a/pocket/pocket.lua b/pocket/pocket.lua index 8233c78..d022ec1 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -88,16 +88,17 @@ local APP_ID = { LOADER = 2, -- main app pages UNITS = 3, - CONTROL = 4, - PROCESS = 5, - WASTE = 6, - GUIDE = 7, - ABOUT = 8, + FACILITY = 4, + CONTROL = 5, + PROCESS = 6, + WASTE = 7, + GUIDE = 8, + ABOUT = 9, -- diagnostic app pages - ALARMS = 9, + ALARMS = 10, -- other - DUMMY = 10, - NUM_APPS = 10 + DUMMY = 11, + NUM_APPS = 11 } pocket.APP_ID = APP_ID diff --git a/pocket/ui/apps/facility.lua b/pocket/ui/apps/facility.lua new file mode 100644 index 0000000..352119c --- /dev/null +++ b/pocket/ui/apps/facility.lua @@ -0,0 +1,241 @@ +-- +-- Facility Overview App +-- + +local util = require("scada-common.util") + +local iocontrol = require("pocket.iocontrol") +local pocket = require("pocket.pocket") + +local style = require("pocket.ui.style") + +local dyn_tank = require("pocket.ui.pages.dynamic_tank") + +local core = require("graphics.core") + +local Div = require("graphics.elements.Div") +local ListBox = require("graphics.elements.ListBox") +local MultiPane = require("graphics.elements.MultiPane") +local TextBox = require("graphics.elements.TextBox") + +local WaitingAnim = require("graphics.elements.animations.Waiting") + +local PushButton = require("graphics.elements.controls.PushButton") + +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local IconIndicator = require("graphics.elements.indicators.IconIndicator") + +local ALIGN = core.ALIGN +local cpair = core.cpair + +local APP_ID = pocket.APP_ID + +-- local label = style.label +local lu_col = style.label_unit_pair +local text_fg = style.text_fg +local basic_states = style.icon_states.basic_states +local mode_states = style.icon_states.mode_states +local red_ind_s = style.icon_states.red_ind_s +local yel_ind_s = style.icon_states.yel_ind_s + +-- new unit page view +---@param root Container parent +local function new_view(root) + local db = iocontrol.get_db() + local fac = db.facility + + local frame = Div{parent=root,x=1,y=1} + + local app = db.nav.register_app(APP_ID.FACILITY, frame, nil, false, true) + + local load_div = Div{parent=frame,x=1,y=1} + local main = Div{parent=frame,x=1,y=1} + + TextBox{parent=load_div,y=12,text="Loading...",alignment=ALIGN.CENTER} + WaitingAnim{parent=load_div,x=math.floor(main.get_width()/2)-1,y=8,fg_bg=cpair(colors.orange,colors._INHERIT)} + + local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}} + + app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } }) + + local btn_fg_bg = cpair(colors.orange, colors.black) + local btn_active = cpair(colors.white, colors.black) + + local tank_pages = {} + local page_div = nil ---@type Div|nil + + -- load the app (create the elements) + local function load() + page_div = Div{parent=main,y=2,width=main.get_width()} + + local panes = {} ---@type Div[] + + -- refresh data callback, every 500ms it will re-send the query + local last_update = 0 + local function update() + if util.time_ms() - last_update >= 500 then + -- db.api.get_fac() + last_update = util.time_ms() + end + end + + for i = 1, db.facility.num_units do + local u_pane = panes[i] + local u_div = Div{parent=u_pane,x=2,width=main.get_width()-2} + local unit = db.units[i] + local u_ps = unit.unit_ps + + --#region Main Unit Overview + + local f_page = app.new_page(nil, i) + f_page.tasks = { update } + + TextBox{parent=u_div,y=1,text="Reactor Unit #"..i,alignment=ALIGN.CENTER} + PushButton{parent=u_div,x=1,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()prev(i)end} + PushButton{parent=u_div,x=21,y=1,text=">",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()next(i)end} + + local type = util.trinary(unit.num_boilers > 0, "Sodium Cooled Reactor", "Boiling Water Reactor") + TextBox{parent=u_div,y=3,text=type,alignment=ALIGN.CENTER,fg_bg=cpair(colors.gray,colors.black)} + + local rate = DataIndicator{parent=u_div,y=5,lu_colors=lu_col,label="Burn",unit="mB/t",format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg} + local temp = DataIndicator{parent=u_div,lu_colors=lu_col,label="Temp",unit=db.temp_label,format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg} + + local ctrl = IconIndicator{parent=u_div,x=1,y=8,label="Control State",states=mode_states} + + rate.register(u_ps, "act_burn_rate", rate.update) + temp.register(u_ps, "temp", function (t) temp.update(db.temp_convert(t)) end) + ctrl.register(u_ps, "U_ControlStatus", ctrl.update) + + u_div.line_break() + + local rct = IconIndicator{parent=u_div,x=1,label="Fission Reactor",states=basic_states} + local rps = IconIndicator{parent=u_div,x=1,label="Protection System",states=basic_states} + + rct.register(u_ps, "U_ReactorStatus", rct.update) + rps.register(u_ps, "U_RPS", rps.update) + + u_div.line_break() + + local rcs = IconIndicator{parent=u_div,x=1,label="Coolant System",states=basic_states} + rcs.register(u_ps, "U_RCS", rcs.update) + + for b = 1, unit.num_boilers do + local blr = IconIndicator{parent=u_div,x=1,label="Boiler "..b,states=basic_states} + blr.register(unit.boiler_ps_tbl[b], "BoilerStatus", blr.update) + end + + for t = 1, unit.num_turbines do + local tbn = IconIndicator{parent=u_div,x=1,label="Turbine "..t,states=basic_states} + tbn.register(unit.turbine_ps_tbl[t], "TurbineStatus", tbn.update) + end + + --#endregion + + util.nop() + + --#region RPS Tab + + local rps_pane = Div{parent=page_div} + local rps_div = Div{parent=rps_pane,x=2,width=main.get_width()-2} + table.insert(panes, rps_div) + + local rps_page = app.new_page(f_page, #panes) + rps_page.tasks = { update } + nav_links[i].rps = rps_page.nav_to + + TextBox{parent=rps_div,y=1,text="Protection System",alignment=ALIGN.CENTER} + + local r_trip = IconIndicator{parent=rps_div,y=3,label="RPS Trip",states=basic_states} + r_trip.register(u_ps, "U_RPS", r_trip.update) + + local r_mscrm = IconIndicator{parent=rps_div,y=5,label="Manual SCRAM",states=red_ind_s} + local r_ascrm = IconIndicator{parent=rps_div,label="Automatic SCRAM",states=red_ind_s} + local rps_tmo = IconIndicator{parent=rps_div,label="Timeout",states=yel_ind_s} + local rps_flt = IconIndicator{parent=rps_div,label="PPM Fault",states=yel_ind_s} + local rps_sfl = IconIndicator{parent=rps_div,label="Not Formed",states=red_ind_s} + + r_mscrm.register(u_ps, "manual", r_mscrm.update) + r_ascrm.register(u_ps, "automatic", r_ascrm.update) + rps_tmo.register(u_ps, "timeout", rps_tmo.update) + rps_flt.register(u_ps, "fault", rps_flt.update) + rps_sfl.register(u_ps, "sys_fail", rps_sfl.update) + + rps_div.line_break() + local rps_dmg = IconIndicator{parent=rps_div,label="Reactor Damage Hi",states=red_ind_s} + local rps_tmp = IconIndicator{parent=rps_div,label="Temp. Critical",states=red_ind_s} + local rps_nof = IconIndicator{parent=rps_div,label="Fuel Level Lo",states=yel_ind_s} + local rps_exw = IconIndicator{parent=rps_div,label="Waste Level Hi",states=yel_ind_s} + local rps_loc = IconIndicator{parent=rps_div,label="Coolant Lo Lo",states=yel_ind_s} + local rps_exh = IconIndicator{parent=rps_div,label="Heated Coolant Hi",states=yel_ind_s} + + rps_dmg.register(u_ps, "high_dmg", rps_dmg.update) + rps_tmp.register(u_ps, "high_temp", rps_tmp.update) + rps_nof.register(u_ps, "no_fuel", rps_nof.update) + rps_exw.register(u_ps, "ex_waste", rps_exw.update) + rps_loc.register(u_ps, "low_cool", rps_loc.update) + rps_exh.register(u_ps, "ex_hcool", rps_exh.update) + + --#endregion + + --#region Dynamic Tank Tabs + + local next_tank = 1 + + for id = 1, #fac.tank_list do + if fac.tank_list[id] == 2 then + local tank_pane = Div{parent=page_div} + tank_pages[next_tank] = dyn_tank(app, f_page, panes, tank_pane, id, fac.tank_ps_tbl[next_tank], update) + next_tank = next_tank + 1 + end + end + + --#endregion + + util.nop() + end + + -- setup multipane + local f_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes} + app.set_root_pane(f_pane) + + -- setup sidebar + + local list = { + { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home }, + { label = "FAC", color = core.cpair(colors.black, colors.orange), callback = f_annunc.nav_to }, + { label = "MTX", color = core.cpair(colors.black, colors.white), callback = mtx_page.nav_to }, + { label = "SPS", color = core.cpair(colors.black, colors.purple), callback = sps_page.nav_to }, + { label = "TNK", tall = true, color = core.cpair(colors.white, colors.gray), callback = tank_page.nav_to } + } + + for i = 1, #fac.tank_data_tbl do + table.insert(list, { label = "F-" .. i, color = core.cpair(colors.black, colors.lightGray), callback = tank_pages[i] }) + end + + app.set_sidebar(list) + + -- done, show the app + load_pane.set_value(2) + end + + -- delete the elements and switch back to the loading screen + local function unload() + if page_div then + page_div.delete() + page_div = nil + end + + app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } }) + app.delete_pages() + + -- show loading screen + load_pane.set_value(1) + end + + app.set_load(load) + app.set_unload(unload) + + return main +end + +return new_view diff --git a/pocket/ui/pages/home_page.lua b/pocket/ui/pages/home_page.lua index 345c9ce..ada6e92 100644 --- a/pocket/ui/pages/home_page.lua +++ b/pocket/ui/pages/home_page.lua @@ -46,7 +46,7 @@ local function new_view(root) local active_fg_bg = cpair(colors.white,colors.gray) App{parent=apps_1,x=2,y=2,text="U",title="Units",callback=function()open(APP_ID.UNITS)end,app_fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=active_fg_bg} - App{parent=apps_1,x=9,y=2,text="F",title="Facil",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.orange),active_fg_bg=active_fg_bg} + App{parent=apps_1,x=9,y=2,text="F",title="Facil",callback=function()open(APP_ID.FACILITY)end,app_fg_bg=cpair(colors.black,colors.orange),active_fg_bg=active_fg_bg} App{parent=apps_1,x=16,y=2,text="\x15",title="Control",callback=function()open(APP_ID.CONTROL)end,app_fg_bg=cpair(colors.black,colors.green),active_fg_bg=active_fg_bg} App{parent=apps_1,x=2,y=7,text="\x17",title="Process",callback=function()open(APP_ID.PROCESS)end,app_fg_bg=cpair(colors.black,colors.purple),active_fg_bg=active_fg_bg} App{parent=apps_1,x=9,y=7,text="\x7f",title="Waste",callback=function()open(APP_ID.WASTE)end,app_fg_bg=cpair(colors.black,colors.brown),active_fg_bg=active_fg_bg} From c6a5d487e0b3aa67c112d8c3f688965452cb5dba Mon Sep 17 00:00:00 2001 From: Mikayla Date: Sat, 4 Jan 2025 15:33:57 +0000 Subject: [PATCH 02/29] comment updates and refactors --- pocket/ui/apps/control.lua | 2 +- pocket/ui/apps/process.lua | 2 +- pocket/ui/apps/unit.lua | 2 +- pocket/ui/apps/waste.lua | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pocket/ui/apps/control.lua b/pocket/ui/apps/control.lua index 57cabc8..6732c93 100644 --- a/pocket/ui/apps/control.lua +++ b/pocket/ui/apps/control.lua @@ -1,5 +1,5 @@ -- --- Unit Control Page +-- Facility & Unit Control App -- local types = require("scada-common.types") diff --git a/pocket/ui/apps/process.lua b/pocket/ui/apps/process.lua index 593e74c..6f04d60 100644 --- a/pocket/ui/apps/process.lua +++ b/pocket/ui/apps/process.lua @@ -1,5 +1,5 @@ -- --- Process Control Page +-- Process Control App -- local types = require("scada-common.types") diff --git a/pocket/ui/apps/unit.lua b/pocket/ui/apps/unit.lua index 2f916d3..8e7a995 100644 --- a/pocket/ui/apps/unit.lua +++ b/pocket/ui/apps/unit.lua @@ -1,5 +1,5 @@ -- --- Unit Overview Page +-- Unit Overview App -- local util = require("scada-common.util") diff --git a/pocket/ui/apps/waste.lua b/pocket/ui/apps/waste.lua index 24e62ae..7d79b50 100644 --- a/pocket/ui/apps/waste.lua +++ b/pocket/ui/apps/waste.lua @@ -1,5 +1,5 @@ -- --- Waste Control Page +-- Waste Control App -- local util = require("scada-common.util") @@ -264,8 +264,8 @@ local function new_view(root) --#endregion -- setup multipane - local u_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes} - app.set_root_pane(u_pane) + local w_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes} + app.set_root_pane(w_pane) -- setup sidebar From 01c5d62f381c6dbb1e25b3d70e8855476ced281c Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sun, 5 Jan 2025 14:39:16 -0500 Subject: [PATCH 03/29] #557 skeleton of facility app with some pages --- pocket/ui/apps/facility.lua | 175 +++++++++++++++---------------- pocket/ui/pages/dynamic_tank.lua | 2 +- 2 files changed, 86 insertions(+), 91 deletions(-) diff --git a/pocket/ui/apps/facility.lua b/pocket/ui/apps/facility.lua index 352119c..238d0ab 100644 --- a/pocket/ui/apps/facility.lua +++ b/pocket/ui/apps/facility.lua @@ -18,25 +18,27 @@ local ListBox = require("graphics.elements.ListBox") local MultiPane = require("graphics.elements.MultiPane") local TextBox = require("graphics.elements.TextBox") -local WaitingAnim = require("graphics.elements.animations.Waiting") +local WaitingAnim = require("graphics.elements.animations.Waiting") -local PushButton = require("graphics.elements.controls.PushButton") - -local DataIndicator = require("graphics.elements.indicators.DataIndicator") -local IconIndicator = require("graphics.elements.indicators.IconIndicator") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local IconIndicator = require("graphics.elements.indicators.IconIndicator") +local StateIndicator = require("graphics.elements.indicators.StateIndicator") local ALIGN = core.ALIGN local cpair = core.cpair local APP_ID = pocket.APP_ID --- local label = style.label -local lu_col = style.label_unit_pair local text_fg = style.text_fg +local label_fg_bg = style.label +local lu_col = style.label_unit_pair + local basic_states = style.icon_states.basic_states local mode_states = style.icon_states.mode_states local red_ind_s = style.icon_states.red_ind_s local yel_ind_s = style.icon_states.yel_ind_s +local grn_ind_s = style.icon_states.grn_ind_s +local wht_ind_s = style.icon_states.wht_ind_s -- new unit page view ---@param root Container parent @@ -66,6 +68,8 @@ local function new_view(root) -- load the app (create the elements) local function load() + local f_ps = fac.ps + page_div = Div{parent=main,y=2,width=main.get_width()} local panes = {} ---@type Div[] @@ -79,121 +83,112 @@ local function new_view(root) end end - for i = 1, db.facility.num_units do - local u_pane = panes[i] - local u_div = Div{parent=u_pane,x=2,width=main.get_width()-2} - local unit = db.units[i] - local u_ps = unit.unit_ps + --#region facility annunciator - --#region Main Unit Overview + local a_pane = Div{parent=page_div} + local a_div = Div{parent=a_pane,x=2,width=main.get_width()-2} + table.insert(panes, a_pane) - local f_page = app.new_page(nil, i) - f_page.tasks = { update } + local f_annunc = app.new_page(nil, #panes) + f_annunc.tasks = { update } - TextBox{parent=u_div,y=1,text="Reactor Unit #"..i,alignment=ALIGN.CENTER} - PushButton{parent=u_div,x=1,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()prev(i)end} - PushButton{parent=u_div,x=21,y=1,text=">",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()next(i)end} + TextBox{parent=a_div,y=1,text="Annunciator",alignment=ALIGN.CENTER} - local type = util.trinary(unit.num_boilers > 0, "Sodium Cooled Reactor", "Boiling Water Reactor") - TextBox{parent=u_div,y=3,text=type,alignment=ALIGN.CENTER,fg_bg=cpair(colors.gray,colors.black)} + local all_ok = IconIndicator{parent=a_div,y=3,label="Unit Systems Online",states=grn_ind_s} + local ind_mat = IconIndicator{parent=a_div,label="Induction Matrix",states=grn_ind_s} + local sps = IconIndicator{parent=a_div,label="SPS Connected",states=grn_ind_s} - local rate = DataIndicator{parent=u_div,y=5,lu_colors=lu_col,label="Burn",unit="mB/t",format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg} - local temp = DataIndicator{parent=u_div,lu_colors=lu_col,label="Temp",unit=db.temp_label,format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg} + all_ok.register(f_ps, "all_sys_ok", all_ok.update) + ind_mat.register(fac.induction_ps_tbl[1], "computed_status", function (status) ind_mat.update(status > 1) end) + sps.register(fac.sps_ps_tbl[1], "computed_status", function (status) sps.update(status > 1) end) - local ctrl = IconIndicator{parent=u_div,x=1,y=8,label="Control State",states=mode_states} + a_div.line_break() - rate.register(u_ps, "act_burn_rate", rate.update) - temp.register(u_ps, "temp", function (t) temp.update(db.temp_convert(t)) end) - ctrl.register(u_ps, "U_ControlStatus", ctrl.update) + local auto_ready = IconIndicator{parent=a_div,label="Configured Units Ready",states=grn_ind_s} + local auto_act = IconIndicator{parent=a_div,label="Process Active",states=grn_ind_s} + local auto_ramp = IconIndicator{parent=a_div,label="Process Ramping",states=wht_ind_s} + local auto_sat = IconIndicator{parent=a_div,label="Min/Max Burn Rate",states=yel_ind_s} - u_div.line_break() + auto_ready.register(f_ps, "auto_ready", auto_ready.update) + auto_act.register(f_ps, "auto_active", auto_act.update) + auto_ramp.register(f_ps, "auto_ramping", auto_ramp.update) + auto_sat.register(f_ps, "auto_saturated", auto_sat.update) - local rct = IconIndicator{parent=u_div,x=1,label="Fission Reactor",states=basic_states} - local rps = IconIndicator{parent=u_div,x=1,label="Protection System",states=basic_states} + a_div.line_break() - rct.register(u_ps, "U_ReactorStatus", rct.update) - rps.register(u_ps, "U_RPS", rps.update) + local auto_scram = IconIndicator{parent=a_div,label="Automatic SCRAM",states=red_ind_s} + local matrix_flt = IconIndicator{parent=a_div,label="Induction Matrix Fault",states=yel_ind_s} + local matrix_fill = IconIndicator{parent=a_div,label="Matrix Charge High",states=red_ind_s} + local unit_crit = IconIndicator{parent=a_div,label="Unit Critical Alarm",states=red_ind_s} + local fac_rad_h = IconIndicator{parent=a_div,label="Facility Radiation High",states=red_ind_s} + local gen_fault = IconIndicator{parent=a_div,label="Gen. Control Fault",states=yel_ind_s} - u_div.line_break() + auto_scram.register(f_ps, "auto_scram", auto_scram.update) + matrix_flt.register(f_ps, "as_matrix_fault", matrix_flt.update) + matrix_fill.register(f_ps, "as_matrix_fill", matrix_fill.update) + unit_crit.register(f_ps, "as_crit_alarm", unit_crit.update) + fac_rad_h.register(f_ps, "as_radiation", fac_rad_h.update) + gen_fault.register(f_ps, "as_gen_fault", gen_fault.update) - local rcs = IconIndicator{parent=u_div,x=1,label="Coolant System",states=basic_states} - rcs.register(u_ps, "U_RCS", rcs.update) + --#endregion - for b = 1, unit.num_boilers do - local blr = IconIndicator{parent=u_div,x=1,label="Boiler "..b,states=basic_states} - blr.register(unit.boiler_ps_tbl[b], "BoilerStatus", blr.update) - end + --#region induction matrix - for t = 1, unit.num_turbines do - local tbn = IconIndicator{parent=u_div,x=1,label="Turbine "..t,states=basic_states} - tbn.register(unit.turbine_ps_tbl[t], "TurbineStatus", tbn.update) - end + local m_pane = Div{parent=page_div} + local m_div = Div{parent=m_pane,x=2,width=main.get_width()-2} + table.insert(panes, m_pane) - --#endregion + local mtx_page = app.new_page(nil, #panes) + mtx_page.tasks = { update } - util.nop() + TextBox{parent=m_div,y=1,text="Induction Matrix",alignment=ALIGN.CENTER} - --#region RPS Tab + --#endregion - local rps_pane = Div{parent=page_div} - local rps_div = Div{parent=rps_pane,x=2,width=main.get_width()-2} - table.insert(panes, rps_div) + --#region SPS page - local rps_page = app.new_page(f_page, #panes) - rps_page.tasks = { update } - nav_links[i].rps = rps_page.nav_to + local s_pane = Div{parent=page_div} + local s_div = Div{parent=s_pane,x=2,width=main.get_width()-2} + table.insert(panes, s_pane) - TextBox{parent=rps_div,y=1,text="Protection System",alignment=ALIGN.CENTER} + local sps_page = app.new_page(nil, #panes) + sps_page.tasks = { update } - local r_trip = IconIndicator{parent=rps_div,y=3,label="RPS Trip",states=basic_states} - r_trip.register(u_ps, "U_RPS", r_trip.update) + TextBox{parent=s_div,y=1,text="Facility SPS",alignment=ALIGN.CENTER} - local r_mscrm = IconIndicator{parent=rps_div,y=5,label="Manual SCRAM",states=red_ind_s} - local r_ascrm = IconIndicator{parent=rps_div,label="Automatic SCRAM",states=red_ind_s} - local rps_tmo = IconIndicator{parent=rps_div,label="Timeout",states=yel_ind_s} - local rps_flt = IconIndicator{parent=rps_div,label="PPM Fault",states=yel_ind_s} - local rps_sfl = IconIndicator{parent=rps_div,label="Not Formed",states=red_ind_s} + local sps_status = StateIndicator{parent=s_div,x=5,y=3,states=style.sps.states,value=1,min_width=12} - r_mscrm.register(u_ps, "manual", r_mscrm.update) - r_ascrm.register(u_ps, "automatic", r_ascrm.update) - rps_tmo.register(u_ps, "timeout", rps_tmo.update) - rps_flt.register(u_ps, "fault", rps_flt.update) - rps_sfl.register(u_ps, "sys_fail", rps_sfl.update) + sps_status.register(f_ps, "sps_computed_status", sps_status.update) - rps_div.line_break() - local rps_dmg = IconIndicator{parent=rps_div,label="Reactor Damage Hi",states=red_ind_s} - local rps_tmp = IconIndicator{parent=rps_div,label="Temp. Critical",states=red_ind_s} - local rps_nof = IconIndicator{parent=rps_div,label="Fuel Level Lo",states=yel_ind_s} - local rps_exw = IconIndicator{parent=rps_div,label="Waste Level Hi",states=yel_ind_s} - local rps_loc = IconIndicator{parent=rps_div,label="Coolant Lo Lo",states=yel_ind_s} - local rps_exh = IconIndicator{parent=rps_div,label="Heated Coolant Hi",states=yel_ind_s} + TextBox{parent=s_div,y=5,text="Input Rate",width=10,fg_bg=label_fg_bg} + local sps_in = DataIndicator{parent=s_div,label="",format="%16.2f",value=0,unit="mB/t",lu_colors=lu_col,width=21,fg_bg=text_fg} - rps_dmg.register(u_ps, "high_dmg", rps_dmg.update) - rps_tmp.register(u_ps, "high_temp", rps_tmp.update) - rps_nof.register(u_ps, "no_fuel", rps_nof.update) - rps_exw.register(u_ps, "ex_waste", rps_exw.update) - rps_loc.register(u_ps, "low_cool", rps_loc.update) - rps_exh.register(u_ps, "ex_hcool", rps_exh.update) + sps_in.register(f_ps, "po_am_rate", sps_in.update) - --#endregion + TextBox{parent=s_div,y=8,text="Production Rate",width=15,fg_bg=label_fg_bg} + local sps_rate = DataIndicator{parent=s_div,label="",format="%16d",value=0,unit="\xb5B/t",lu_colors=lu_col,width=21,fg_bg=text_fg} - --#region Dynamic Tank Tabs + sps_rate.register(f_ps, "sps_process_rate", function (r) sps_rate.update(r * 1000) end) - local next_tank = 1 + --#endregion - for id = 1, #fac.tank_list do - if fac.tank_list[id] == 2 then - local tank_pane = Div{parent=page_div} - tank_pages[next_tank] = dyn_tank(app, f_page, panes, tank_pane, id, fac.tank_ps_tbl[next_tank], update) - next_tank = next_tank + 1 - end - end + --#region facility tank pages - --#endregion + local t_pane = Div{parent=page_div} + local t_div = Div{parent=t_pane,x=2,width=main.get_width()-2} + table.insert(panes, t_pane) - util.nop() + local tank_page = app.new_page(nil, #panes) + tank_page.tasks = { update } + + TextBox{parent=t_div,y=1,text="Facility Tanks",alignment=ALIGN.CENTER} + + for i = 1, fac.tank_data_tbl do + tank_pages[i] = dyn_tank(app, nil, panes, Div{parent=page_div}, i, fac.tank_ps_tbl[i], update) end + --#endregion + -- setup multipane local f_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes} app.set_root_pane(f_pane) @@ -209,7 +204,7 @@ local function new_view(root) } for i = 1, #fac.tank_data_tbl do - table.insert(list, { label = "F-" .. i, color = core.cpair(colors.black, colors.lightGray), callback = tank_pages[i] }) + table.insert(list, { label = "F-" .. i, color = core.cpair(colors.black, colors.lightGray), callback = tank_pages[i].nav_to }) end app.set_sidebar(list) diff --git a/pocket/ui/pages/dynamic_tank.lua b/pocket/ui/pages/dynamic_tank.lua index 356f7e6..d9303fa 100644 --- a/pocket/ui/pages/dynamic_tank.lua +++ b/pocket/ui/pages/dynamic_tank.lua @@ -31,7 +31,7 @@ local mode_ind_s = { -- create a dynamic tank view for the unit or facility app ---@param app pocket_app ----@param page nav_tree_page +---@param page nav_tree_page|nil parent page, if applicable ---@param panes Div[] ---@param tank_pane Div ---@param tank_id integer global facility tank ID (as used for tank list, etc) From 1dece587b2d25b7eebd475e72f80ed6ccd2e692a Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sun, 5 Jan 2025 14:40:36 -0500 Subject: [PATCH 04/29] cleanup --- pocket/ui/apps/unit.lua | 3 +-- pocket/ui/apps/waste.lua | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/pocket/ui/apps/unit.lua b/pocket/ui/apps/unit.lua index 8e7a995..304608e 100644 --- a/pocket/ui/apps/unit.lua +++ b/pocket/ui/apps/unit.lua @@ -33,9 +33,8 @@ local cpair = core.cpair local APP_ID = pocket.APP_ID --- local label = style.label -local lu_col = style.label_unit_pair local text_fg = style.text_fg +local lu_col = style.label_unit_pair local basic_states = style.icon_states.basic_states local mode_states = style.icon_states.mode_states local red_ind_s = style.icon_states.red_ind_s diff --git a/pocket/ui/apps/waste.lua b/pocket/ui/apps/waste.lua index 7d79b50..0be7dde 100644 --- a/pocket/ui/apps/waste.lua +++ b/pocket/ui/apps/waste.lua @@ -33,9 +33,7 @@ local APP_ID = pocket.APP_ID local label_fg_bg = style.label local text_fg = style.text_fg - local lu_col = style.label_unit_pair - local yel_ind_s = style.icon_states.yel_ind_s local wht_ind_s = style.icon_states.wht_ind_s From ae85cfc57957e3bc8d927135678d080950ab3885 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sun, 5 Jan 2025 15:05:01 -0500 Subject: [PATCH 05/29] #557 start of induction matrix and sps pages --- pocket/iorx.lua | 4 ++ pocket/ui/pages/facility_matrix.lua | 59 +++++++++++++++++++++++++++++ pocket/ui/pages/facility_sps.lua | 0 3 files changed, 63 insertions(+) create mode 100644 pocket/ui/pages/facility_matrix.lua create mode 100644 pocket/ui/pages/facility_sps.lua diff --git a/pocket/iorx.lua b/pocket/iorx.lua index 0aac073..528c2f4 100644 --- a/pocket/iorx.lua +++ b/pocket/iorx.lua @@ -651,6 +651,10 @@ function iorx.record_waste_data(data) fac.ps.publish("sps_process_rate", f_data[9]) end +function iorx.record_fac_detail_data(data) + +end + return function (io_obj) io = io_obj return iorx diff --git a/pocket/ui/pages/facility_matrix.lua b/pocket/ui/pages/facility_matrix.lua new file mode 100644 index 0000000..57301e6 --- /dev/null +++ b/pocket/ui/pages/facility_matrix.lua @@ -0,0 +1,59 @@ +local types = require("scada-common.types") +local util = require("scada-common.util") + +local iocontrol = require("pocket.iocontrol") + +local style = require("pocket.ui.style") + +local core = require("graphics.core") + +local Div = require("graphics.elements.Div") +local TextBox = require("graphics.elements.TextBox") + +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local HorizontalBar = require("graphics.elements.indicators.HorizontalBar") +local IconIndicator = require("graphics.elements.indicators.IconIndicator") +local StateIndicator = require("graphics.elements.indicators.StateIndicator") + +local cpair = core.cpair + +local label = style.label +local lu_col = style.label_unit_pair +local text_fg = style.text_fg + +local mode_ind_s = { + { color = cpair(colors.black, colors.lightGray), symbol = "-" }, + { color = cpair(colors.black, colors.white), symbol = "+" } +} + +-- create an induction matrix view for the facility app +---@param app pocket_app +---@param page nav_tree_page|nil parent page, if applicable +---@param panes Div[] +---@param tank_pane Div +---@param ps psil +---@param update function +return function (app, page, panes, tank_pane, ps, update) + local fac = iocontrol.get_db().facility + + local mtx_div = Div{parent=tank_pane,x=2,width=tank_pane.get_width()-2} + table.insert(panes, mtx_div) + + local matrix_page = app.new_page(page, #panes) + matrix_page.tasks = { update } + + TextBox{parent=mtx_div,y=1,text="I Matrix",width=9} + local status = StateIndicator{parent=mtx_div,x=10,y=1,states=style.imatrix.states,value=1,min_width=12} + status.register(ps, "InductionMatrixStateStatus", status.update) + + TextBox{parent=mtx_div,y=3,text="Fill",width=10,fg_bg=label} + local chg_pcnt = DataIndicator{parent=mtx_div,x=14,y=3,label="",format="%5.2f",value=100,unit="%",lu_colors=lu_col,width=8,fg_bg=text_fg} + local chg_amnt = DataIndicator{parent=mtx_div,label="",format="%18d",value=0,commas=true,unit="mB",lu_colors=lu_col,width=21,fg_bg=text_fg} + + TextBox{parent=mtx_div,y=6,text="Charge Level",width=12,fg_bg=label} + local level = HorizontalBar{parent=mtx_div,y=7,bar_fg_bg=cpair(colors.green,colors.gray),height=1,width=21} + + level.register(ps, "fill", level.update) + + return matrix_page.nav_to +end diff --git a/pocket/ui/pages/facility_sps.lua b/pocket/ui/pages/facility_sps.lua new file mode 100644 index 0000000..e69de29 From 071df9e431199ff5ee2acbf754ba748881150879 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sun, 5 Jan 2025 15:08:41 -0500 Subject: [PATCH 06/29] #557 include matrix page --- pocket/ui/apps/facility.lua | 18 ++++++------------ pocket/ui/pages/facility_matrix.lua | 5 ++--- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/pocket/ui/apps/facility.lua b/pocket/ui/apps/facility.lua index 238d0ab..6abd78b 100644 --- a/pocket/ui/apps/facility.lua +++ b/pocket/ui/apps/facility.lua @@ -10,6 +10,7 @@ local pocket = require("pocket.pocket") local style = require("pocket.ui.style") local dyn_tank = require("pocket.ui.pages.dynamic_tank") +local induction_mtx = require("pocket.ui.pages.facility_matrix") local core = require("graphics.core") @@ -63,7 +64,7 @@ local function new_view(root) local btn_fg_bg = cpair(colors.orange, colors.black) local btn_active = cpair(colors.white, colors.black) - local tank_pages = {} + local tank_page_navs = {} local page_div = nil ---@type Div|nil -- load the app (create the elements) @@ -134,14 +135,7 @@ local function new_view(root) --#region induction matrix - local m_pane = Div{parent=page_div} - local m_div = Div{parent=m_pane,x=2,width=main.get_width()-2} - table.insert(panes, m_pane) - - local mtx_page = app.new_page(nil, #panes) - mtx_page.tasks = { update } - - TextBox{parent=m_div,y=1,text="Induction Matrix",alignment=ALIGN.CENTER} + local mtx_page_nav = induction_mtx(app, panes, Div{parent=page_div}, fac.induction_ps_tbl[1], update) --#endregion @@ -184,7 +178,7 @@ local function new_view(root) TextBox{parent=t_div,y=1,text="Facility Tanks",alignment=ALIGN.CENTER} for i = 1, fac.tank_data_tbl do - tank_pages[i] = dyn_tank(app, nil, panes, Div{parent=page_div}, i, fac.tank_ps_tbl[i], update) + tank_page_navs[i] = dyn_tank(app, nil, panes, Div{parent=page_div}, i, fac.tank_ps_tbl[i], update) end --#endregion @@ -198,13 +192,13 @@ local function new_view(root) local list = { { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home }, { label = "FAC", color = core.cpair(colors.black, colors.orange), callback = f_annunc.nav_to }, - { label = "MTX", color = core.cpair(colors.black, colors.white), callback = mtx_page.nav_to }, + { label = "MTX", color = core.cpair(colors.black, colors.white), callback = mtx_page_nav }, { label = "SPS", color = core.cpair(colors.black, colors.purple), callback = sps_page.nav_to }, { label = "TNK", tall = true, color = core.cpair(colors.white, colors.gray), callback = tank_page.nav_to } } for i = 1, #fac.tank_data_tbl do - table.insert(list, { label = "F-" .. i, color = core.cpair(colors.black, colors.lightGray), callback = tank_pages[i].nav_to }) + table.insert(list, { label = "F-" .. i, color = core.cpair(colors.black, colors.lightGray), callback = tank_page_navs[i] }) end app.set_sidebar(list) diff --git a/pocket/ui/pages/facility_matrix.lua b/pocket/ui/pages/facility_matrix.lua index 57301e6..6f16986 100644 --- a/pocket/ui/pages/facility_matrix.lua +++ b/pocket/ui/pages/facility_matrix.lua @@ -28,18 +28,17 @@ local mode_ind_s = { -- create an induction matrix view for the facility app ---@param app pocket_app ----@param page nav_tree_page|nil parent page, if applicable ---@param panes Div[] ---@param tank_pane Div ---@param ps psil ---@param update function -return function (app, page, panes, tank_pane, ps, update) +return function (app, panes, tank_pane, ps, update) local fac = iocontrol.get_db().facility local mtx_div = Div{parent=tank_pane,x=2,width=tank_pane.get_width()-2} table.insert(panes, mtx_div) - local matrix_page = app.new_page(page, #panes) + local matrix_page = app.new_page(nil, #panes) matrix_page.tasks = { update } TextBox{parent=mtx_div,y=1,text="I Matrix",width=9} From 872082b970612721bd10f7e2c3a35e8d18de2c2f Mon Sep 17 00:00:00 2001 From: Mikayla Date: Tue, 7 Jan 2025 23:21:29 +0000 Subject: [PATCH 07/29] #557 sps page --- pocket/ui/apps/facility.lua | 56 ++++--------------- pocket/ui/pages/facility_sps.lua | 95 ++++++++++++++++++++++++++++++++ scada-common/comms.lua | 15 ++--- 3 files changed, 115 insertions(+), 51 deletions(-) diff --git a/pocket/ui/apps/facility.lua b/pocket/ui/apps/facility.lua index 6abd78b..baf948d 100644 --- a/pocket/ui/apps/facility.lua +++ b/pocket/ui/apps/facility.lua @@ -10,6 +10,7 @@ local pocket = require("pocket.pocket") local style = require("pocket.ui.style") local dyn_tank = require("pocket.ui.pages.dynamic_tank") +local facility_sps = require("pocket.ui.pages.facility_sps") local induction_mtx = require("pocket.ui.pages.facility_matrix") local core = require("graphics.core") @@ -95,34 +96,22 @@ local function new_view(root) TextBox{parent=a_div,y=1,text="Annunciator",alignment=ALIGN.CENTER} - local all_ok = IconIndicator{parent=a_div,y=3,label="Unit Systems Online",states=grn_ind_s} + local all_ok = IconIndicator{parent=a_div,y=3,label="Units Online",states=grn_ind_s} local ind_mat = IconIndicator{parent=a_div,label="Induction Matrix",states=grn_ind_s} local sps = IconIndicator{parent=a_div,label="SPS Connected",states=grn_ind_s} all_ok.register(f_ps, "all_sys_ok", all_ok.update) - ind_mat.register(fac.induction_ps_tbl[1], "computed_status", function (status) ind_mat.update(status > 1) end) - sps.register(fac.sps_ps_tbl[1], "computed_status", function (status) sps.update(status > 1) end) - - a_div.line_break() - - local auto_ready = IconIndicator{parent=a_div,label="Configured Units Ready",states=grn_ind_s} - local auto_act = IconIndicator{parent=a_div,label="Process Active",states=grn_ind_s} - local auto_ramp = IconIndicator{parent=a_div,label="Process Ramping",states=wht_ind_s} - local auto_sat = IconIndicator{parent=a_div,label="Min/Max Burn Rate",states=yel_ind_s} - - auto_ready.register(f_ps, "auto_ready", auto_ready.update) - auto_act.register(f_ps, "auto_active", auto_act.update) - auto_ramp.register(f_ps, "auto_ramping", auto_ramp.update) - auto_sat.register(f_ps, "auto_saturated", auto_sat.update) + -- ind_mat.register(fac.induction_ps_tbl[1], "computed_status", function (status) ind_mat.update(status > 1) end) + -- sps.register(fac.sps_ps_tbl[1], "computed_status", function (status) sps.update(status > 1) end) a_div.line_break() local auto_scram = IconIndicator{parent=a_div,label="Automatic SCRAM",states=red_ind_s} - local matrix_flt = IconIndicator{parent=a_div,label="Induction Matrix Fault",states=yel_ind_s} - local matrix_fill = IconIndicator{parent=a_div,label="Matrix Charge High",states=red_ind_s} - local unit_crit = IconIndicator{parent=a_div,label="Unit Critical Alarm",states=red_ind_s} - local fac_rad_h = IconIndicator{parent=a_div,label="Facility Radiation High",states=red_ind_s} - local gen_fault = IconIndicator{parent=a_div,label="Gen. Control Fault",states=yel_ind_s} + local matrix_flt = IconIndicator{parent=a_div,label="Ind. Matrix Fault",states=yel_ind_s} + local matrix_fill = IconIndicator{parent=a_div,label="Matrix Charge Hi",states=red_ind_s} + local unit_crit = IconIndicator{parent=a_div,label="Unit Crit. Alarm",states=red_ind_s} + local fac_rad_h = IconIndicator{parent=a_div,label="FAC Radiation Hi",states=red_ind_s} + local gen_fault = IconIndicator{parent=a_div,label="Gen Control Fault",states=yel_ind_s} auto_scram.register(f_ps, "auto_scram", auto_scram.update) matrix_flt.register(f_ps, "as_matrix_fault", matrix_flt.update) @@ -139,30 +128,9 @@ local function new_view(root) --#endregion - --#region SPS page + --#region SPS - local s_pane = Div{parent=page_div} - local s_div = Div{parent=s_pane,x=2,width=main.get_width()-2} - table.insert(panes, s_pane) - - local sps_page = app.new_page(nil, #panes) - sps_page.tasks = { update } - - TextBox{parent=s_div,y=1,text="Facility SPS",alignment=ALIGN.CENTER} - - local sps_status = StateIndicator{parent=s_div,x=5,y=3,states=style.sps.states,value=1,min_width=12} - - sps_status.register(f_ps, "sps_computed_status", sps_status.update) - - TextBox{parent=s_div,y=5,text="Input Rate",width=10,fg_bg=label_fg_bg} - local sps_in = DataIndicator{parent=s_div,label="",format="%16.2f",value=0,unit="mB/t",lu_colors=lu_col,width=21,fg_bg=text_fg} - - sps_in.register(f_ps, "po_am_rate", sps_in.update) - - TextBox{parent=s_div,y=8,text="Production Rate",width=15,fg_bg=label_fg_bg} - local sps_rate = DataIndicator{parent=s_div,label="",format="%16d",value=0,unit="\xb5B/t",lu_colors=lu_col,width=21,fg_bg=text_fg} - - sps_rate.register(f_ps, "sps_process_rate", function (r) sps_rate.update(r * 1000) end) + local sps_page_nav = facility_sps(app, panes, Div{parent=page_div}, fac.sps_ps_tbl[1], update) --#endregion @@ -193,7 +161,7 @@ local function new_view(root) { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home }, { label = "FAC", color = core.cpair(colors.black, colors.orange), callback = f_annunc.nav_to }, { label = "MTX", color = core.cpair(colors.black, colors.white), callback = mtx_page_nav }, - { label = "SPS", color = core.cpair(colors.black, colors.purple), callback = sps_page.nav_to }, + { label = "SPS", color = core.cpair(colors.black, colors.purple), callback = sps_page_nav }, { label = "TNK", tall = true, color = core.cpair(colors.white, colors.gray), callback = tank_page.nav_to } } diff --git a/pocket/ui/pages/facility_sps.lua b/pocket/ui/pages/facility_sps.lua index e69de29..456adc1 100644 --- a/pocket/ui/pages/facility_sps.lua +++ b/pocket/ui/pages/facility_sps.lua @@ -0,0 +1,95 @@ +local iocontrol = require("pocket.iocontrol") + +local style = require("pocket.ui.style") + +local core = require("graphics.core") + +local Div = require("graphics.elements.Div") +local TextBox = require("graphics.elements.TextBox") + +local PushButton = require("graphics.elements.controls.PushButton") + +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local HorizontalBar = require("graphics.elements.indicators.HorizontalBar") +local PowerIndicator = require("graphics.elements.indicators.PowerIndicator") +local StateIndicator = require("graphics.elements.indicators.StateIndicator") + +local ALIGN = core.ALIGN +local cpair = core.cpair + +local label = style.label +local lu_col = style.label_unit_pair +local text_fg = style.text_fg + +-- create an SPS view in the facility app +---@param app pocket_app +---@param panes Div[] +---@param sps_pane Div +---@param ps psil +---@param update function +return function (app, panes, sps_pane, ps, update) + local db = iocontrol.get_db() + + local sps_div = Div{parent=sps_pane,x=2,width=sps_pane.get_width()-2} + table.insert(panes, sps_div) + + local sps_page = app.new_page(nil, #panes) + sps_page.tasks = { update } + + TextBox{parent=sps_div,y=1,text="Facility SPS",alignment=ALIGN.CENTER} + local status = StateIndicator{parent=sps_div,x=5,y=3,states=style.sps.states,value=1,min_width=12} + status.register(ps, "sps_computed_status", status.update) + + TextBox{parent=sps_div,text="Polonium",x=1,y=5,fg_bg=label} + local po_bar = HorizontalBar{parent=sps_div,x=1,y=6,fg_bg=cpair(colors.cyan,colors.gray)} + TextBox{parent=sps_div,text="Antimatter",x=1,y=5,fg_bg=label} + local am_bar = HorizontalBar{parent=sps_div,x=1,y=6,fg_bg=cpair(colors.purple,colors.gray)} + TextBox{parent=sps_div,text="Energy Storage",x=21,y=8,fg_bg=label} + local energy_bar = HorizontalBar{parent=sps_div,x=1,y=9,fg_bg=cpair(colors.green,colors.gray)} + + po_bar.register(ps, "input_fill", po_bar.update) + am_bar.register(ps, "output_fill", am_bar.update) + energy_bar.register(ps, "energy_fill", energy_bar.update) + + TextBox{parent=sps_div,text="Input Rate",x=3,y=11,width=17,fg_bg=label} + local input_rate = DataIndicator{parent=sps_div,x=3,y=12,lu_colors=lu_col,label="",unit="mB/t",format="%11.0f",value=0,commas=true,width=17,fg_bg=text_fg} + TextBox{parent=sps_div,text="Production",x=3,y=14,width=17,fg_bg=label} + local proc_rate = DataIndicator{parent=sps_div,x=3,y=15,lu_colors=lu_col,label="",unit="\xb5B/t",format="%11d",value=0,width=17,fg_bg=text_fg} + + proc_rate.register(ps, "process_rate", function (r) proc_rate.update(r * 1000) end) + input_rate.register(db.facility.ps, "po_am_rate", input_rate.update) + + local sps_ext_div = Div{parent=sps_pane,x=2,width=sps_pane.get_width()-2} + table.insert(panes, sps_ext_div) + + local sps_ext_page = app.new_page(sps_page, #panes) + sps_ext_page.tasks = { update } + + PushButton{parent=sps_div,x=9,y=18,text="MORE",min_width=6,fg_bg=cpair(colors.lightGray,colors.gray),active_fg_bg=cpair(colors.gray,colors.lightGray),callback=sps_ext_page.nav_to} + PushButton{parent=sps_ext_div,x=9,y=18,text="BACK",min_width=6,fg_bg=cpair(colors.lightGray,colors.gray),active_fg_bg=cpair(colors.gray,colors.lightGray),callback=sps_page.nav_to} + + TextBox{parent=sps_ext_div,y=1,text="More SPS Info",alignment=ALIGN.CENTER} + + TextBox{parent=sps_ext_div,text="Polonium Tank",x=1,y=3,width=10,fg_bg=label} + local input_p = DataIndicator{parent=sps_ext_div,x=14,y=3,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} + local input_amnt = DataIndicator{parent=sps_ext_div,x=1,y=4,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg} + + input_p.register(ps, "input_fill", function (x) input_p.update(x * 100) end) + input_amnt.register(ps, "input", function (x) input_amnt.update(x.amount) end) + + TextBox{parent=sps_ext_div,text="Antimatter Tank",x=1,y=6,width=10,fg_bg=label} + local output_p = DataIndicator{parent=sps_ext_div,x=14,y=6,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} + local output_amnt = DataIndicator{parent=sps_ext_div,x=1,y=7,lu_colors=lu_col,label="",unit="mB",format="%18.3f",value=0,commas=true,width=21,fg_bg=text_fg} + + output_p.register(ps, "output_fill", function (x) output_p.update(x * 100) end) + output_amnt.register(ps, "output", function (x) output_amnt.update(x.amount) end) + + TextBox{parent=sps_ext_div,text="Energy Fill",x=1,y=8,width=12,fg_bg=label} + local energy_p = DataIndicator{parent=sps_ext_div,x=14,y=8,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} + local energy_amnt = PowerIndicator{parent=sps_ext_div,x=1,y=9,lu_colors=lu_col,label="",unit=db.energy_label,format="%17.4f",value=0,width=21,fg_bg=text_fg} + + energy_p.register(ps, "energy_fill", function (x) energy_p.update(x * 100) end) + energy_amnt.register(ps, "energy", function (val) energy_amnt.update(db.energy_convert(val)) end) + + return sps_page.nav_to +end diff --git a/scada-common/comms.lua b/scada-common/comms.lua index a3e40a8..a8d0014 100644 --- a/scada-common/comms.lua +++ b/scada-common/comms.lua @@ -17,8 +17,8 @@ local max_distance = nil local comms = {} -- protocol/data versions (protocol/data independent changes tracked by util.lua version) -comms.version = "3.0.3" -comms.api_version = "0.0.8" +comms.version = "3.0.4" +comms.api_version = "0.0.9" ---@enum PROTOCOL local PROTOCOL = { @@ -66,11 +66,12 @@ local CRDN_TYPE = { UNIT_BUILDS = 4, -- build of each reactor unit (reactor + RTUs) UNIT_STATUSES = 5, -- state of each of the reactor units UNIT_CMD = 6, -- command a reactor unit - API_GET_FAC = 7, -- API: get all the facility data - API_GET_UNIT = 8, -- API: get reactor unit data - API_GET_CTRL = 9, -- API: get data for the control app - API_GET_PROC = 10, -- API: get data for the process app - API_GET_WASTE = 11 -- API: get data for the waste app + API_GET_FAC = 7, -- API: get the facility general data + API_GET_FAC_DTL = 8, -- API: get (detailed) data for the facility app + API_GET_UNIT = 9, -- API: get reactor unit data + API_GET_CTRL = 10, -- API: get data for the control app + API_GET_PROC = 11, -- API: get data for the process app + API_GET_WASTE = 12 -- API: get data for the waste app } ---@enum ESTABLISH_ACK From 4cb6f9ca0fa7b03caf45d88f38078358d2596dd7 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Tue, 7 Jan 2025 23:21:48 +0000 Subject: [PATCH 08/29] #557 work on message data --- coordinator/session/pocket.lua | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/coordinator/session/pocket.lua b/coordinator/session/pocket.lua index c8b77de..4bd78ed 100644 --- a/coordinator/session/pocket.lua +++ b/coordinator/session/pocket.lua @@ -260,11 +260,33 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout) { fac.auto_ready, fac.auto_active, fac.auto_ramping, fac.auto_saturated }, { fac.auto_current_waste_product, fac.auto_pu_fallback_active }, util.table_len(fac.tank_data_tbl), - fac.induction_data_tbl[1] ~= nil, - fac.sps_data_tbl[1] ~= nil, + fac.induction_data_tbl[1] ~= nil, ---@fixme this means nothing + fac.sps_data_tbl[1] ~= nil ---@fixme this means nothing } _send(CRDN_TYPE.API_GET_FAC, data) + elseif pkt.type == CRDN_TYPE.API_GET_FAC_DTL then + local fac = db.facility + + local tank_statuses = {} + + for i = 1, #fac.tank_ps_tbl do table.insert(tank_statuses, fac.tank_ps_tbl[i].get("computed_status")) end + + local data = { + fac.all_sys_ok, + fac.rtu_count, + { fac.auto_current_waste_product, fac.auto_pu_fallback_active }, + fac.auto_scram, + fac.ascram_status, + tank_statuses, + fac.tank_data_tbl, + fac.induction_ps_tbl[1].get("computed_status") or types.IMATRIX_STATE.OFFLINE, + fac.induction_data_tbl[1], + fac.sps_ps_tbl[1].get("computed_status") or types.SPS_STATE.OFFLINE, + fac.sps_data_tbl[1] + } + + _send(CRDN_TYPE.API_GET_FAC_DTL, data) elseif pkt.type == CRDN_TYPE.API_GET_UNIT then if pkt.length == 1 and type(pkt.data[1]) == "number" then local u = db.units[pkt.data[1]] From 1190fe2dd5df2b33a67419fe209cfa21d3f03279 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Wed, 8 Jan 2025 19:04:38 -0500 Subject: [PATCH 09/29] #559 discard modbus messages if busy --- rtu/rtu.lua | 12 +++++------- rtu/startup.lua | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/rtu/rtu.lua b/rtu/rtu.lua index 06178ad..2fce541 100644 --- a/rtu/rtu.lua +++ b/rtu/rtu.lua @@ -481,16 +481,14 @@ function rtu.comms(version, nic, conn_watchdog) -- check validity then pass off to unit comms thread return_code, reply = unit.modbus_io.check_request(packet) if return_code then - -- check if there are more than 3 active transactions - -- still queue the packet, but this may indicate a problem + -- check if there are more than 3 active transactions, which will be treated as busy if unit.pkt_queue.length() > 3 then reply = modbus.reply__srv_device_busy(packet) - log.debug("queueing new request with " .. unit.pkt_queue.length() .. - " transactions already in the queue" .. unit_dbg_tag) + log.warning("device busy, discarding new request" .. unit_dbg_tag) + else + -- queue the command if not busy + unit.pkt_queue.push_packet(packet) end - - -- always queue the command even if busy - unit.pkt_queue.push_packet(packet) else log.warning("cannot perform requested MODBUS operation" .. unit_dbg_tag) end diff --git a/rtu/startup.lua b/rtu/startup.lua index f43996c..c957ac9 100644 --- a/rtu/startup.lua +++ b/rtu/startup.lua @@ -31,7 +31,7 @@ local sna_rtu = require("rtu.dev.sna_rtu") local sps_rtu = require("rtu.dev.sps_rtu") local turbinev_rtu = require("rtu.dev.turbinev_rtu") -local RTU_VERSION = "v1.10.21" +local RTU_VERSION = "v1.11.0" local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE local RTU_HW_STATE = databus.RTU_HW_STATE From cd4caf0163ab8dc20bbdfaefcbeb32633faf3c47 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Wed, 8 Jan 2025 19:07:53 -0500 Subject: [PATCH 10/29] #559 supervisor updates to handle busy errors --- supervisor/session/rtu/boilerv.lua | 50 +++++++------- supervisor/session/rtu/dynamicv.lua | 90 +++++++++++++++++-------- supervisor/session/rtu/envd.lua | 12 ++-- supervisor/session/rtu/imatrix.lua | 50 +++++++------- supervisor/session/rtu/sna.lua | 38 +++++------ supervisor/session/rtu/sps.lua | 50 +++++++------- supervisor/session/rtu/turbinev.lua | 90 +++++++++++++++++-------- supervisor/session/rtu/unit_session.lua | 30 ++++++--- supervisor/startup.lua | 2 +- 9 files changed, 239 insertions(+), 173 deletions(-) diff --git a/supervisor/session/rtu/boilerv.lua b/supervisor/session/rtu/boilerv.lua index a1a1a99..11b5e39 100644 --- a/supervisor/session/rtu/boilerv.lua +++ b/supervisor/session/rtu/boilerv.lua @@ -105,27 +105,39 @@ function boilerv.new(session_id, unit_id, advert, out_queue) -- PRIVATE FUNCTIONS -- -- query if the multiblock is formed - local function _request_formed() + ---@param time_now integer + local function _request_formed(time_now) -- read discrete input 1 (start = 1, count = 1) - self.session.send_request(TXN_TYPES.FORMED, MODBUS_FCODE.READ_DISCRETE_INPUTS, { 1, 1 }) + if self.session.send_request(TXN_TYPES.FORMED, MODBUS_FCODE.READ_DISCRETE_INPUTS, { 1, 1 }) ~= false then + self.periodics.next_formed_req = time_now + PERIODICS.FORMED + end end -- query the build of the device - local function _request_build() + ---@param time_now integer + local function _request_build(time_now) -- read input registers 1 through 12 (start = 1, count = 12) - self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 12 }) + if self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 12 }) ~= false then + self.periodics.next_build_req = time_now + PERIODICS.BUILD + end end -- query the state of the device - local function _request_state() + ---@param time_now integer + local function _request_state(time_now) -- read input registers 13 through 15 (start = 13, count = 3) - self.session.send_request(TXN_TYPES.STATE, MODBUS_FCODE.READ_INPUT_REGS, { 13, 3 }) + if self.session.send_request(TXN_TYPES.STATE, MODBUS_FCODE.READ_INPUT_REGS, { 13, 3 }) ~= false then + self.periodics.next_state_req = time_now + PERIODICS.STATE + end end -- query the tanks of the device - local function _request_tanks() + ---@param time_now integer + local function _request_tanks(time_now) -- read input registers 16 through 27 (start = 16, count = 12) - self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 16, 12 }) + if self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 16, 12 }) ~= false then + self.periodics.next_tanks_req = time_now + PERIODICS.TANKS + end end -- PUBLIC FUNCTIONS -- @@ -210,26 +222,12 @@ function boilerv.new(session_id, unit_id, advert, out_queue) -- update this runner ---@param time_now integer milliseconds function public.update(time_now) - if self.periodics.next_formed_req <= time_now then - _request_formed() - self.periodics.next_formed_req = time_now + PERIODICS.FORMED - end + if self.periodics.next_formed_req <= time_now then _request_formed(time_now) end if self.db.formed then - if not self.has_build and self.periodics.next_build_req <= time_now then - _request_build() - self.periodics.next_build_req = time_now + PERIODICS.BUILD - end - - if self.periodics.next_state_req <= time_now then - _request_state() - self.periodics.next_state_req = time_now + PERIODICS.STATE - end - - if self.periodics.next_tanks_req <= time_now then - _request_tanks() - self.periodics.next_tanks_req = time_now + PERIODICS.TANKS - end + if not self.has_build and self.periodics.next_build_req <= time_now then _request_build(time_now) end + if self.periodics.next_state_req <= time_now then _request_state(time_now) end + if self.periodics.next_tanks_req <= time_now then _request_tanks(time_now) end end self.session.post_update() diff --git a/supervisor/session/rtu/dynamicv.lua b/supervisor/session/rtu/dynamicv.lua index 0c06d7b..16ba84b 100644 --- a/supervisor/session/rtu/dynamicv.lua +++ b/supervisor/session/rtu/dynamicv.lua @@ -42,6 +42,8 @@ local PERIODICS = { TANKS = 500 } +local WRITE_BUSY_WAIT = 1000 + -- create a new dynamicv rtu session runner ---@nodiscard ---@param session_id integer RTU gateway session ID @@ -63,6 +65,8 @@ function dynamicv.new(session_id, unit_id, advert, out_queue) local self = { session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS), has_build = false, + mode_cmd = nil, ---@type container_mode|nil + resend_mode = false, periodics = { next_formed_req = 0, next_build_req = 0, @@ -101,45 +105,77 @@ function dynamicv.new(session_id, unit_id, advert, out_queue) -- increment the container mode local function _inc_cont_mode() + -- set mode command + if self.mode_cmd == "BOTH" then self.mode_cmd = "FILL" + elseif self.mode_cmd == "FILL" then self.mode_cmd = "EMPTY" + elseif self.mode_cmd == "EMPTY" then self.mode_cmd = "BOTH" + end + -- write coil 1 with unused value 0 - self.session.send_request(TXN_TYPES.INC_CONT, MODBUS_FCODE.WRITE_SINGLE_COIL, { 1, 0 }) + if self.session.send_request(TXN_TYPES.INC_CONT, MODBUS_FCODE.WRITE_SINGLE_COIL, { 1, 0 }, WRITE_BUSY_WAIT) == false then + self.resend_mode = true + end end -- decrement the container mode local function _dec_cont_mode() + -- set mode command + if self.mode_cmd == "BOTH" then self.mode_cmd = "EMPTY" + elseif self.mode_cmd == "EMPTY" then self.mode_cmd = "FILL" + elseif self.mode_cmd == "FILL" then self.mode_cmd = "BOTH" + end + -- write coil 2 with unused value 0 - self.session.send_request(TXN_TYPES.DEC_CONT, MODBUS_FCODE.WRITE_SINGLE_COIL, { 2, 0 }) + if self.session.send_request(TXN_TYPES.DEC_CONT, MODBUS_FCODE.WRITE_SINGLE_COIL, { 2, 0 , WRITE_BUSY_WAIT}) == false then + self.resend_mode = false + end end -- set the container mode ---@param mode container_mode local function _set_cont_mode(mode) + self.mode_cmd = mode + -- write holding register 1 - self.session.send_request(TXN_TYPES.SET_CONT, MODBUS_FCODE.WRITE_SINGLE_HOLD_REG, { 1, mode }) + if self.session.send_request(TXN_TYPES.SET_CONT, MODBUS_FCODE.WRITE_SINGLE_HOLD_REG, { 1, mode }, WRITE_BUSY_WAIT) == false then + self.resend_mode = false + end end -- query if the multiblock is formed - local function _request_formed() + ---@param time_now integer + local function _request_formed(time_now) -- read discrete input 1 (start = 1, count = 1) - self.session.send_request(TXN_TYPES.FORMED, MODBUS_FCODE.READ_DISCRETE_INPUTS, { 1, 1 }) + if self.session.send_request(TXN_TYPES.FORMED, MODBUS_FCODE.READ_DISCRETE_INPUTS, { 1, 1 }) ~= false then + self.periodics.next_formed_req = time_now + PERIODICS.FORMED + end end -- query the build of the device - local function _request_build() + ---@param time_now integer + local function _request_build(time_now) -- read input registers 1 through 7 (start = 1, count = 7) - self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 7 }) + if self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 7 }) ~= false then + self.periodics.next_build_req = time_now + PERIODICS.BUILD + end end -- query the state of the device - local function _request_state() + ---@param time_now integer + local function _request_state(time_now) -- read holding register 1 (start = 1, count = 1) - self.session.send_request(TXN_TYPES.STATE, MODBUS_FCODE.READ_MUL_HOLD_REGS, { 1, 1 }) + if self.session.send_request(TXN_TYPES.STATE, MODBUS_FCODE.READ_MUL_HOLD_REGS, { 1, 1 }) ~= false then + self.periodics.next_state_req = time_now + PERIODICS.STATE + end end -- query the tanks of the device - local function _request_tanks() + ---@param time_now integer + local function _request_tanks(time_now) -- read input registers 8 through 9 (start = 8, count = 2) - self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 8, 2 }) + if self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 8, 2 }) ~= false then + self.periodics.next_tanks_req = time_now + PERIODICS.TANKS + end end -- PUBLIC FUNCTIONS -- @@ -182,6 +218,10 @@ function dynamicv.new(session_id, unit_id, advert, out_queue) if m_pkt.length == 1 then self.db.state.last_update = util.time_ms() self.db.state.container_mode = m_pkt.data[1] + + if self.mode_cmd == nil then + self.mode_cmd = self.db.state.container_mode + end else log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")") end @@ -247,30 +287,22 @@ function dynamicv.new(session_id, unit_id, advert, out_queue) end end + -- try to resend mode if needed + if self.resend_mode then + self.resend_mode = false + _set_cont_mode(self.mode_cmd) + end + time_now = util.time() -- handle periodics - if self.periodics.next_formed_req <= time_now then - _request_formed() - self.periodics.next_formed_req = time_now + PERIODICS.FORMED - end + if self.periodics.next_formed_req <= time_now then _request_formed(time_now) end if self.db.formed then - if not self.has_build and self.periodics.next_build_req <= time_now then - _request_build() - self.periodics.next_build_req = time_now + PERIODICS.BUILD - end - - if self.periodics.next_state_req <= time_now then - _request_state() - self.periodics.next_state_req = time_now + PERIODICS.STATE - end - - if self.periodics.next_tanks_req <= time_now then - _request_tanks() - self.periodics.next_tanks_req = time_now + PERIODICS.TANKS - end + if not self.has_build and self.periodics.next_build_req <= time_now then _request_build(time_now) end + if self.periodics.next_state_req <= time_now then _request_state(time_now) end + if self.periodics.next_tanks_req <= time_now then _request_tanks(time_now) end end self.session.post_update() diff --git a/supervisor/session/rtu/envd.lua b/supervisor/session/rtu/envd.lua index 269975a..ef36fad 100644 --- a/supervisor/session/rtu/envd.lua +++ b/supervisor/session/rtu/envd.lua @@ -58,9 +58,12 @@ function envd.new(session_id, unit_id, advert, out_queue) -- PRIVATE FUNCTIONS -- -- query the radiation readings of the device - local function _request_radiation() + ---@param time_now integer + local function _request_radiation(time_now) -- read input registers 1 and 2 (start = 1, count = 2) - self.session.send_request(TXN_TYPES.RAD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 2 }) + if self.session.send_request(TXN_TYPES.RAD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 2 }) ~= false then + self.periodics.next_rad_req = time_now + PERIODICS.RAD + end end -- PUBLIC FUNCTIONS -- @@ -90,10 +93,7 @@ function envd.new(session_id, unit_id, advert, out_queue) -- update this runner ---@param time_now integer milliseconds function public.update(time_now) - if self.periodics.next_rad_req <= time_now then - _request_radiation() - self.periodics.next_rad_req = time_now + PERIODICS.RAD - end + if self.periodics.next_rad_req <= time_now then _request_radiation(time_now) end self.session.post_update() end diff --git a/supervisor/session/rtu/imatrix.lua b/supervisor/session/rtu/imatrix.lua index aa7a984..5fea7aa 100644 --- a/supervisor/session/rtu/imatrix.lua +++ b/supervisor/session/rtu/imatrix.lua @@ -89,27 +89,39 @@ function imatrix.new(session_id, unit_id, advert, out_queue) -- PRIVATE FUNCTIONS -- -- query if the multiblock is formed - local function _request_formed() + ---@param time_now integer + local function _request_formed(time_now) -- read discrete input 1 (start = 1, count = 1) - self.session.send_request(TXN_TYPES.FORMED, MODBUS_FCODE.READ_DISCRETE_INPUTS, { 1, 1 }) + if self.session.send_request(TXN_TYPES.FORMED, MODBUS_FCODE.READ_DISCRETE_INPUTS, { 1, 1 }) ~= false then + self.periodics.next_formed_req = time_now + PERIODICS.FORMED + end end -- query the build of the device - local function _request_build() + ---@param time_now integer + local function _request_build(time_now) -- read input registers 1 through 9 (start = 1, count = 9) - self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 9 }) + if self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 9 }) ~= false then + self.periodics.next_build_req = time_now + PERIODICS.BUILD + end end -- query the state of the device - local function _request_state() + ---@param time_now integer + local function _request_state(time_now) -- read input register 10 through 11 (start = 10, count = 2) - self.session.send_request(TXN_TYPES.STATE, MODBUS_FCODE.READ_INPUT_REGS, { 10, 2 }) + if self.session.send_request(TXN_TYPES.STATE, MODBUS_FCODE.READ_INPUT_REGS, { 10, 2 }) ~= false then + self.periodics.next_state_req = time_now + PERIODICS.STATE + end end -- query the tanks of the device - local function _request_tanks() + ---@param time_now integer + local function _request_tanks(time_now) -- read input registers 12 through 15 (start = 12, count = 3) - self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 12, 3 }) + if self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 12, 3 }) ~= false then + self.periodics.next_tanks_req = time_now + PERIODICS.TANKS + end end -- PUBLIC FUNCTIONS -- @@ -181,26 +193,12 @@ function imatrix.new(session_id, unit_id, advert, out_queue) -- update this runner ---@param time_now integer milliseconds function public.update(time_now) - if self.periodics.next_formed_req <= time_now then - _request_formed() - self.periodics.next_formed_req = time_now + PERIODICS.FORMED - end + if self.periodics.next_formed_req <= time_now then _request_formed(time_now) end if self.db.formed then - if not self.has_build and self.periodics.next_build_req <= time_now then - _request_build() - self.periodics.next_build_req = time_now + PERIODICS.BUILD - end - - if self.periodics.next_state_req <= time_now then - _request_state() - self.periodics.next_state_req = time_now + PERIODICS.STATE - end - - if self.periodics.next_tanks_req <= time_now then - _request_tanks() - self.periodics.next_tanks_req = time_now + PERIODICS.TANKS - end + if not self.has_build and self.periodics.next_build_req <= time_now then _request_build(time_now) end + if self.periodics.next_state_req <= time_now then _request_state(time_now) end + if self.periodics.next_tanks_req <= time_now then _request_tanks(time_now) end end self.session.post_update() diff --git a/supervisor/session/rtu/sna.lua b/supervisor/session/rtu/sna.lua index 7e0fc34..f46fa5c 100644 --- a/supervisor/session/rtu/sna.lua +++ b/supervisor/session/rtu/sna.lua @@ -80,21 +80,30 @@ function sna.new(session_id, unit_id, advert, out_queue) -- PRIVATE FUNCTIONS -- -- query the build of the device - local function _request_build() + ---@param time_now integer + local function _request_build(time_now) -- read input registers 1 through 2 (start = 1, count = 2) - self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 2 }) + if self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 2 }) ~= false then + self.periodics.next_build_req = time_now + PERIODICS.BUILD + end end -- query the state of the device - local function _request_state() + ---@param time_now integer + local function _request_state(time_now) -- read input registers 3 through 4 (start = 3, count = 2) - self.session.send_request(TXN_TYPES.STATE, MODBUS_FCODE.READ_INPUT_REGS, { 3, 2 }) + if self.session.send_request(TXN_TYPES.STATE, MODBUS_FCODE.READ_INPUT_REGS, { 3, 2 }) ~= false then + self.periodics.next_state_req = time_now + PERIODICS.STATE + end end -- query the tanks of the device - local function _request_tanks() + ---@param time_now integer + local function _request_tanks(time_now) -- read input registers 5 through 10 (start = 5, count = 6) - self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 5, 6 }) + if self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 5, 6 }) ~= false then + self.periodics.next_tanks_req = time_now + PERIODICS.TANKS + end end -- PUBLIC FUNCTIONS -- @@ -152,20 +161,9 @@ function sna.new(session_id, unit_id, advert, out_queue) -- update this runner ---@param time_now integer milliseconds function public.update(time_now) - if not self.has_build and self.periodics.next_build_req <= time_now then - _request_build() - self.periodics.next_build_req = time_now + PERIODICS.BUILD - end - - if self.periodics.next_state_req <= time_now then - _request_state() - self.periodics.next_state_req = time_now + PERIODICS.STATE - end - - if self.periodics.next_tanks_req <= time_now then - _request_tanks() - self.periodics.next_tanks_req = time_now + PERIODICS.TANKS - end + if not self.has_build and self.periodics.next_build_req <= time_now then _request_build(time_now) end + if self.periodics.next_state_req <= time_now then _request_state(time_now) end + if self.periodics.next_tanks_req <= time_now then _request_tanks(time_now) end self.session.post_update() end diff --git a/supervisor/session/rtu/sps.lua b/supervisor/session/rtu/sps.lua index 1dacd61..2096821 100644 --- a/supervisor/session/rtu/sps.lua +++ b/supervisor/session/rtu/sps.lua @@ -94,27 +94,39 @@ function sps.new(session_id, unit_id, advert, out_queue) -- PRIVATE FUNCTIONS -- -- query if the multiblock is formed - local function _request_formed() + ---@param time_now integer + local function _request_formed(time_now) -- read discrete input 1 (start = 1, count = 1) - self.session.send_request(TXN_TYPES.FORMED, MODBUS_FCODE.READ_DISCRETE_INPUTS, { 1, 1 }) + if self.session.send_request(TXN_TYPES.FORMED, MODBUS_FCODE.READ_DISCRETE_INPUTS, { 1, 1 }) ~= false then + self.periodics.next_formed_req = time_now + PERIODICS.FORMED + end end -- query the build of the device - local function _request_build() + ---@param time_now integer + local function _request_build(time_now) -- read input registers 1 through 9 (start = 1, count = 9) - self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 9 }) + if self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 9 }) ~= false then + self.periodics.next_build_req = time_now + PERIODICS.BUILD + end end -- query the state of the device - local function _request_state() + ---@param time_now integer + local function _request_state(time_now) -- read input register 10 (start = 10, count = 1) - self.session.send_request(TXN_TYPES.STATE, MODBUS_FCODE.READ_INPUT_REGS, { 10, 1 }) + if self.session.send_request(TXN_TYPES.STATE, MODBUS_FCODE.READ_INPUT_REGS, { 10, 1 }) ~= false then + self.periodics.next_state_req = time_now + PERIODICS.STATE + end end -- query the tanks of the device - local function _request_tanks() + ---@param time_now integer + local function _request_tanks(time_now) -- read input registers 11 through 19 (start = 11, count = 9) - self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 11, 9 }) + if self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 11, 9 }) ~= false then + self.periodics.next_tanks_req = time_now + PERIODICS.TANKS + end end -- PUBLIC FUNCTIONS -- @@ -191,26 +203,12 @@ function sps.new(session_id, unit_id, advert, out_queue) -- update this runner ---@param time_now integer milliseconds function public.update(time_now) - if self.periodics.next_formed_req <= time_now then - _request_formed() - self.periodics.next_formed_req = time_now + PERIODICS.FORMED - end + if self.periodics.next_formed_req <= time_now then _request_formed(time_now) end if self.db.formed then - if not self.has_build and self.periodics.next_build_req <= time_now then - _request_build() - self.periodics.next_build_req = time_now + PERIODICS.BUILD - end - - if self.periodics.next_state_req <= time_now then - _request_state() - self.periodics.next_state_req = time_now + PERIODICS.STATE - end - - if self.periodics.next_tanks_req <= time_now then - _request_tanks() - self.periodics.next_tanks_req = time_now + PERIODICS.TANKS - end + if not self.has_build and self.periodics.next_build_req <= time_now then _request_build(time_now) end + if self.periodics.next_state_req <= time_now then _request_state(time_now) end + if self.periodics.next_tanks_req <= time_now then _request_tanks(time_now) end end self.session.post_update() diff --git a/supervisor/session/rtu/turbinev.lua b/supervisor/session/rtu/turbinev.lua index 3581884..7023021 100644 --- a/supervisor/session/rtu/turbinev.lua +++ b/supervisor/session/rtu/turbinev.lua @@ -42,6 +42,8 @@ local PERIODICS = { TANKS = 1000 } +local WRITE_BUSY_WAIT = 1000 + -- create a new turbinev rtu session runner ---@nodiscard ---@param session_id integer RTU gateway session ID @@ -63,6 +65,8 @@ function turbinev.new(session_id, unit_id, advert, out_queue) local self = { session = unit_session.new(session_id, unit_id, advert, out_queue, log_tag, TXN_TAGS), has_build = false, + mode_cmd = nil, ---@type dumping_mode|nil + resend_mode = false, periodics = { next_formed_req = 0, next_build_req = 0, @@ -116,45 +120,77 @@ function turbinev.new(session_id, unit_id, advert, out_queue) -- increment the dumping mode local function _inc_dump_mode() + -- set mode command + if self.mode_cmd == "IDLE" then self.mode_cmd = "DUMPING_EXCESS" + elseif self.mode_cmd == "DUMPING_EXCESS" then self.mode_cmd = "DUMPING" + elseif self.mode_cmd == "DUMPING" then self.mode_cmd = "IDLE" + end + -- write coil 1 with unused value 0 - self.session.send_request(TXN_TYPES.INC_DUMP, MODBUS_FCODE.WRITE_SINGLE_COIL, { 1, 0 }) + if self.session.send_request(TXN_TYPES.INC_DUMP, MODBUS_FCODE.WRITE_SINGLE_COIL, { 1, 0 }, WRITE_BUSY_WAIT) == false then + self.resend_mode = true + end end -- decrement the dumping mode local function _dec_dump_mode() + -- set mode command + if self.mode_cmd == "IDLE" then self.mode_cmd = "DUMPING" + elseif self.mode_cmd == "DUMPING_EXCESS" then self.mode_cmd = "IDLE" + elseif self.mode_cmd == "DUMPING" then self.mode_cmd = "DUMPING_EXCESS" + end + -- write coil 2 with unused value 0 - self.session.send_request(TXN_TYPES.DEC_DUMP, MODBUS_FCODE.WRITE_SINGLE_COIL, { 2, 0 }) + if self.session.send_request(TXN_TYPES.DEC_DUMP, MODBUS_FCODE.WRITE_SINGLE_COIL, { 2, 0 }, WRITE_BUSY_WAIT) == false then + self.resend_mode = true + end end -- set the dumping mode ---@param mode dumping_mode local function _set_dump_mode(mode) + self.mode_cmd = mode + -- write holding register 1 - self.session.send_request(TXN_TYPES.SET_DUMP, MODBUS_FCODE.WRITE_SINGLE_HOLD_REG, { 1, mode }) + if self.session.send_request(TXN_TYPES.SET_DUMP, MODBUS_FCODE.WRITE_SINGLE_HOLD_REG, { 1, mode }, WRITE_BUSY_WAIT) == false then + self.resend_mode = true + end end -- query if the multiblock is formed - local function _request_formed() + ---@param time_now integer + local function _request_formed(time_now) -- read discrete input 1 (start = 1, count = 1) - self.session.send_request(TXN_TYPES.FORMED, MODBUS_FCODE.READ_DISCRETE_INPUTS, { 1, 1 }) + if self.session.send_request(TXN_TYPES.FORMED, MODBUS_FCODE.READ_DISCRETE_INPUTS, { 1, 1 }) ~= false then + self.periodics.next_formed_req = time_now + PERIODICS.FORMED + end end -- query the build of the device - local function _request_build() + ---@param time_now integer + local function _request_build(time_now) -- read input registers 1 through 15 (start = 1, count = 15) - self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 15 }) + if self.session.send_request(TXN_TYPES.BUILD, MODBUS_FCODE.READ_INPUT_REGS, { 1, 15 }) ~= false then + self.periodics.next_build_req = time_now + PERIODICS.BUILD + end end -- query the state of the device - local function _request_state() + ---@param time_now integer + local function _request_state(time_now) -- read input registers 16 through 19 (start = 16, count = 4) - self.session.send_request(TXN_TYPES.STATE, MODBUS_FCODE.READ_INPUT_REGS, { 16, 4 }) + if self.session.send_request(TXN_TYPES.STATE, MODBUS_FCODE.READ_INPUT_REGS, { 16, 4 }) ~= false then + self.periodics.next_state_req = time_now + PERIODICS.STATE + end end -- query the tanks of the device - local function _request_tanks() + ---@param time_now integer + local function _request_tanks(time_now) -- read input registers 20 through 25 (start = 20, count = 6) - self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 20, 6 }) + if self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 20, 6 }) ~= false then + self.periodic.next_tanks_req = time_now + PERIODICS.TANKS + end end -- PUBLIC FUNCTIONS -- @@ -208,6 +244,10 @@ function turbinev.new(session_id, unit_id, advert, out_queue) self.db.state.prod_rate = m_pkt.data[2] self.db.state.steam_input_rate = m_pkt.data[3] self.db.state.dumping_mode = m_pkt.data[4] + + if self.mode_cmd == nil then + self.mode_cmd = self.db.state.dumping_mode + end else log.debug(log_tag .. "MODBUS transaction reply length mismatch (" .. TXN_TAGS[txn_type] .. ")") end @@ -277,30 +317,22 @@ function turbinev.new(session_id, unit_id, advert, out_queue) end end + -- try to resend mode if needed + if self.resend_mode then + self.resend_mode = false + _set_dump_mode(self.mode_cmd) + end + time_now = util.time() -- handle periodics - if self.periodics.next_formed_req <= time_now then - _request_formed() - self.periodics.next_formed_req = time_now + PERIODICS.FORMED - end + if self.periodics.next_formed_req <= time_now then _request_formed(time_now) end if self.db.formed then - if not self.has_build and self.periodics.next_build_req <= time_now then - _request_build() - self.periodics.next_build_req = time_now + PERIODICS.BUILD - end - - if self.periodics.next_state_req <= time_now then - _request_state() - self.periodics.next_state_req = time_now + PERIODICS.STATE - end - - if self.periodics.next_tanks_req <= time_now then - _request_tanks() - self.periodics.next_tanks_req = time_now + PERIODICS.TANKS - end + if not self.has_build and self.periodics.next_build_req <= time_now then _request_build(time_now) end + if self.periodics.next_state_req <= time_now then _request_state(time_now) end + if self.periodics.next_tanks_req <= time_now then _request_tanks(time_now) end end self.session.post_update() diff --git a/supervisor/session/rtu/unit_session.lua b/supervisor/session/rtu/unit_session.lua index 632890b..8c51ccb 100644 --- a/supervisor/session/rtu/unit_session.lua +++ b/supervisor/session/rtu/unit_session.lua @@ -22,6 +22,8 @@ local RTU_US_DATA = { unit_session.RTU_US_CMDS = RTU_US_CMDS unit_session.RTU_US_DATA = RTU_US_DATA +local DEFAULT_BUSY_WAIT = 3000 + -- create a new unit session runner ---@nodiscard ---@param session_id integer RTU gateway session ID @@ -36,7 +38,8 @@ function unit_session.new(session_id, unit_id, advert, out_queue, log_tag, txn_t reactor = advert.reactor, transaction_controller = txnctrl.new(), connected = true, - device_fail = false + device_fail = false, + last_busy = 0 } ---@class _unit_session @@ -53,14 +56,21 @@ function unit_session.new(session_id, unit_id, advert, out_queue, log_tag, txn_t ---@param txn_type integer transaction type ---@param f_code MODBUS_FCODE function code ---@param register_param (number|string)[] register range or register and values - ---@return integer txn_id transaction ID of this transaction - function protected.send_request(txn_type, f_code, register_param) - local m_pkt = comms.modbus_packet() - local txn_id = self.transaction_controller.create(txn_type) + ---@param busy_wait integer|nil milliseconds to wait (>0), or uses the default + ---@return integer|false txn_id transaction ID of this transaction or false if not sent due to being busy + function protected.send_request(txn_type, f_code, register_param, busy_wait) + local txn_id = false ---@type integer|false - m_pkt.make(txn_id, unit_id, f_code, register_param) + busy_wait = busy_wait or DEFAULT_BUSY_WAIT - out_queue.push_packet(m_pkt) + if (util.time_ms() - self.last_busy) >= busy_wait then + local m_pkt = comms.modbus_packet() + txn_id = self.transaction_controller.create(txn_type) + + m_pkt.make(txn_id, unit_id, f_code, register_param) + + out_queue.push_packet(m_pkt) + end return txn_id end @@ -99,9 +109,9 @@ function unit_session.new(session_id, unit_id, advert, out_queue, log_tag, txn_t -- will have to wait on reply, renew the transaction self.transaction_controller.renew(m_pkt.txn_id, txn_type) elseif ex == MODBUS_EXCODE.SERVER_DEVICE_BUSY then - -- will have to wait on reply, renew the transaction - self.transaction_controller.renew(m_pkt.txn_id, txn_type) - log.debug(log_tag .. "MODBUS: device busy" .. txn_tag) + -- will have to try again later + self.last_busy = util.time_ms() + log.warning(log_tag .. "MODBUS: device busy" .. txn_tag) elseif ex == MODBUS_EXCODE.NEG_ACKNOWLEDGE then -- general failure log.error(log_tag .. "MODBUS: negative acknowledge (bad request)" .. txn_tag) diff --git a/supervisor/startup.lua b/supervisor/startup.lua index 870792e..32651da 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.6.1" +local SUPERVISOR_VERSION = "v1.6.2" local println = util.println local println_ts = util.println_ts From fb221a566c69a1a93d29eea72f28c99867ba7fa5 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Thu, 9 Jan 2025 00:14:28 +0000 Subject: [PATCH 11/29] #557 facility app bug fix --- pocket/ui/apps/facility.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pocket/ui/apps/facility.lua b/pocket/ui/apps/facility.lua index baf948d..18ba4b4 100644 --- a/pocket/ui/apps/facility.lua +++ b/pocket/ui/apps/facility.lua @@ -46,7 +46,6 @@ local wht_ind_s = style.icon_states.wht_ind_s ---@param root Container parent local function new_view(root) local db = iocontrol.get_db() - local fac = db.facility local frame = Div{parent=root,x=1,y=1} @@ -70,6 +69,7 @@ local function new_view(root) -- load the app (create the elements) local function load() + local fac = db.facility local f_ps = fac.ps page_div = Div{parent=main,y=2,width=main.get_width()} From eabb065d1712f005e5f4a1adc43009d40e680732 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Thu, 9 Jan 2025 00:14:49 +0000 Subject: [PATCH 12/29] #557 ui cleanup on sps page --- pocket/ui/pages/facility_sps.lua | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pocket/ui/pages/facility_sps.lua b/pocket/ui/pages/facility_sps.lua index 456adc1..337b852 100644 --- a/pocket/ui/pages/facility_sps.lua +++ b/pocket/ui/pages/facility_sps.lua @@ -42,19 +42,19 @@ return function (app, panes, sps_pane, ps, update) TextBox{parent=sps_div,text="Polonium",x=1,y=5,fg_bg=label} local po_bar = HorizontalBar{parent=sps_div,x=1,y=6,fg_bg=cpair(colors.cyan,colors.gray)} - TextBox{parent=sps_div,text="Antimatter",x=1,y=5,fg_bg=label} - local am_bar = HorizontalBar{parent=sps_div,x=1,y=6,fg_bg=cpair(colors.purple,colors.gray)} - TextBox{parent=sps_div,text="Energy Storage",x=21,y=8,fg_bg=label} - local energy_bar = HorizontalBar{parent=sps_div,x=1,y=9,fg_bg=cpair(colors.green,colors.gray)} + TextBox{parent=sps_div,text="Antimatter",x=1,y=8,fg_bg=label} + local am_bar = HorizontalBar{parent=sps_div,x=1,y=9,fg_bg=cpair(colors.purple,colors.gray)} + TextBox{parent=sps_div,text="Energy Storage",x=21,y=11,fg_bg=label} + local energy_bar = HorizontalBar{parent=sps_div,x=1,y=12,fg_bg=cpair(colors.green,colors.gray)} po_bar.register(ps, "input_fill", po_bar.update) am_bar.register(ps, "output_fill", am_bar.update) energy_bar.register(ps, "energy_fill", energy_bar.update) - TextBox{parent=sps_div,text="Input Rate",x=3,y=11,width=17,fg_bg=label} - local input_rate = DataIndicator{parent=sps_div,x=3,y=12,lu_colors=lu_col,label="",unit="mB/t",format="%11.0f",value=0,commas=true,width=17,fg_bg=text_fg} - TextBox{parent=sps_div,text="Production",x=3,y=14,width=17,fg_bg=label} - local proc_rate = DataIndicator{parent=sps_div,x=3,y=15,lu_colors=lu_col,label="",unit="\xb5B/t",format="%11d",value=0,width=17,fg_bg=text_fg} + TextBox{parent=sps_div,text="Input Rate",x=3,y=14,width=17,fg_bg=label} + local input_rate = DataIndicator{parent=sps_div,x=3,y=15,lu_colors=lu_col,label="",unit="mB/t",format="%11.0f",value=0,commas=true,width=17,fg_bg=text_fg} + TextBox{parent=sps_div,text="Production",x=3,y=17,width=17,fg_bg=label} + local proc_rate = DataIndicator{parent=sps_div,x=3,y=18,lu_colors=lu_col,label="",unit="\xb5B/t",format="%11d",value=0,width=17,fg_bg=text_fg} proc_rate.register(ps, "process_rate", function (r) proc_rate.update(r * 1000) end) input_rate.register(db.facility.ps, "po_am_rate", input_rate.update) @@ -70,21 +70,21 @@ return function (app, panes, sps_pane, ps, update) TextBox{parent=sps_ext_div,y=1,text="More SPS Info",alignment=ALIGN.CENTER} - TextBox{parent=sps_ext_div,text="Polonium Tank",x=1,y=3,width=10,fg_bg=label} + TextBox{parent=sps_ext_div,text="Polonium Tank",x=1,y=3,width=13,fg_bg=label} local input_p = DataIndicator{parent=sps_ext_div,x=14,y=3,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} local input_amnt = DataIndicator{parent=sps_ext_div,x=1,y=4,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg} input_p.register(ps, "input_fill", function (x) input_p.update(x * 100) end) input_amnt.register(ps, "input", function (x) input_amnt.update(x.amount) end) - TextBox{parent=sps_ext_div,text="Antimatter Tank",x=1,y=6,width=10,fg_bg=label} + TextBox{parent=sps_ext_div,text="Antimatter Tank",x=1,y=6,width=15,fg_bg=label} local output_p = DataIndicator{parent=sps_ext_div,x=14,y=6,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} local output_amnt = DataIndicator{parent=sps_ext_div,x=1,y=7,lu_colors=lu_col,label="",unit="mB",format="%18.3f",value=0,commas=true,width=21,fg_bg=text_fg} output_p.register(ps, "output_fill", function (x) output_p.update(x * 100) end) output_amnt.register(ps, "output", function (x) output_amnt.update(x.amount) end) - TextBox{parent=sps_ext_div,text="Energy Fill",x=1,y=8,width=12,fg_bg=label} + TextBox{parent=sps_ext_div,text="Energy Fill",x=1,y=8,width=11,fg_bg=label} local energy_p = DataIndicator{parent=sps_ext_div,x=14,y=8,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} local energy_amnt = PowerIndicator{parent=sps_ext_div,x=1,y=9,lu_colors=lu_col,label="",unit=db.energy_label,format="%17.4f",value=0,width=21,fg_bg=text_fg} From 2fdc9feea7ed8e1e1b7c95a52f11b194ee4a3870 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Thu, 9 Jan 2025 00:15:12 +0000 Subject: [PATCH 13/29] #557 work on induction matrix page --- pocket/ui/pages/facility_matrix.lua | 39 +++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/pocket/ui/pages/facility_matrix.lua b/pocket/ui/pages/facility_matrix.lua index 6f16986..7287457 100644 --- a/pocket/ui/pages/facility_matrix.lua +++ b/pocket/ui/pages/facility_matrix.lua @@ -13,6 +13,7 @@ local TextBox = require("graphics.elements.TextBox") local DataIndicator = require("graphics.elements.indicators.DataIndicator") local HorizontalBar = require("graphics.elements.indicators.HorizontalBar") local IconIndicator = require("graphics.elements.indicators.IconIndicator") +local PowerIndicator = require("graphics.elements.indicators.PowerIndicator") local StateIndicator = require("graphics.elements.indicators.StateIndicator") local cpair = core.cpair @@ -33,7 +34,8 @@ local mode_ind_s = { ---@param ps psil ---@param update function return function (app, panes, tank_pane, ps, update) - local fac = iocontrol.get_db().facility + local db = iocontrol.get_db() + local fac = db.facility local mtx_div = Div{parent=tank_pane,x=2,width=tank_pane.get_width()-2} table.insert(panes, mtx_div) @@ -45,14 +47,37 @@ return function (app, panes, tank_pane, ps, update) local status = StateIndicator{parent=mtx_div,x=10,y=1,states=style.imatrix.states,value=1,min_width=12} status.register(ps, "InductionMatrixStateStatus", status.update) - TextBox{parent=mtx_div,y=3,text="Fill",width=10,fg_bg=label} - local chg_pcnt = DataIndicator{parent=mtx_div,x=14,y=3,label="",format="%5.2f",value=100,unit="%",lu_colors=lu_col,width=8,fg_bg=text_fg} - local chg_amnt = DataIndicator{parent=mtx_div,label="",format="%18d",value=0,commas=true,unit="mB",lu_colors=lu_col,width=21,fg_bg=text_fg} + TextBox{parent=mtx_div,text="Charge",x=1,y=5,fg_bg=label} + local chg_bar = HorizontalBar{parent=mtx_div,x=1,y=6,fg_bg=cpair(colors.green,colors.gray)} + TextBox{parent=mtx_div,text="Input",x=1,y=7,fg_bg=label} + local in_bar = HorizontalBar{parent=mtx_div,x=1,y=8,fg_bg=cpair(colors.blue,colors.gray)} + TextBox{parent=mtx_div,text="Output",x=21,y=9,fg_bg=label} + local out_bar = HorizontalBar{parent=mtx_div,x=1,y=10,fg_bg=cpair(colors.red,colors.gray)} - TextBox{parent=mtx_div,y=6,text="Charge Level",width=12,fg_bg=label} - local level = HorizontalBar{parent=mtx_div,y=7,bar_fg_bg=cpair(colors.green,colors.gray),height=1,width=21} + local function calc_saturation(val) + local data = fac.induction_data_tbl[1] + if (type(data.build) == "table") and (type(data.build.transfer_cap) == "number") and (data.build.transfer_cap > 0) then + return val / data.build.transfer_cap + else return 0 end + end - level.register(ps, "fill", level.update) + chg_bar.register(ps, "energy_fill", chg_bar.update) + in_bar.register(ps, "last_input", function (val) in_bar.update(calc_saturation(val)) end) + out_bar.register(ps, "last_output", function (val) out_bar.update(calc_saturation(val)) end) + + local energy = PowerIndicator{parent=mtx_div,x=1,y=12,lu_colors=lu_col,label="Chg: ",unit=db.energy_label,format="%8.2f",value=0,width=22,fg_bg=text_fg} + local avg_chg = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg:",unit=db.energy_label,format="%8.2f",value=0,width=22,fg_bg=text_fg} + local input = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="In: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} + local avg_in = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg:",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} + local output = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="Out: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} + local avg_out = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg:",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} + + energy.register(ps, "energy", function (val) energy.update(db.energy_convert(val)) end) + avg_chg.register(fac.ps, "avg_charge", avg_chg.update) + input.register(ps, "last_input", function (val) input.update(db.energy_convert(val)) end) + avg_in.register(fac.ps, "avg_inflow", avg_in.update) + output.register(ps, "last_output", function (val) output.update(db.energy_convert(val)) end) + avg_out.register(fac.ps, "avg_outflow", avg_out.update) return matrix_page.nav_to end From fb139949f8c38aea3e2355146b81704a4d5ffe2f Mon Sep 17 00:00:00 2001 From: Mikayla Date: Thu, 9 Jan 2025 00:17:00 +0000 Subject: [PATCH 14/29] fix to induction matrix transfer bars not rescaling with capacity changes --- coordinator/startup.lua | 2 +- coordinator/ui/components/imatrix.lua | 4 ++-- coordinator/ui/layout/main_view.lua | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/coordinator/startup.lua b/coordinator/startup.lua index 6fb924b..1ba0a81 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.6.2" +local COORDINATOR_VERSION = "v1.6.3" local CHUNK_LOAD_DELAY_S = 30.0 diff --git a/coordinator/ui/components/imatrix.lua b/coordinator/ui/components/imatrix.lua index 186f7bd..1f053a8 100644 --- a/coordinator/ui/components/imatrix.lua +++ b/coordinator/ui/components/imatrix.lua @@ -25,10 +25,9 @@ local ALIGN = core.ALIGN ---@param root Container parent ---@param x integer top left x ---@param y integer top left y ----@param data imatrix_session_db matrix data ---@param ps psil ps interface ---@param id number? matrix ID -local function new_view(root, x, y, data, ps, id) +local function new_view(root, x, y, ps, id) local label_fg = style.theme.label_fg local text_fg = style.theme.text_fg local lu_col = style.lu_colors @@ -94,6 +93,7 @@ local function new_view(root, x, y, data, ps, id) TextBox{parent=rect,text="FILL I/O",x=2,y=20,width=8,fg_bg=label_fg} local function calc_saturation(val) + local data = db.facility.induction_data_tbl[id or 1] if (type(data.build) == "table") and (type(data.build.transfer_cap) == "number") and (data.build.transfer_cap > 0) then return val / data.build.transfer_cap else return 0 end diff --git a/coordinator/ui/layout/main_view.lua b/coordinator/ui/layout/main_view.lua index ebc9cc3..b1369d1 100644 --- a/coordinator/ui/layout/main_view.lua +++ b/coordinator/ui/layout/main_view.lua @@ -88,7 +88,7 @@ local function init(main) util.nop() - imatrix(main, 131, cnc_bottom_align_start, facility.induction_data_tbl[1], facility.induction_ps_tbl[1]) + imatrix(main, 131, cnc_bottom_align_start, facility.induction_ps_tbl[1]) end return init From d05abf6e00fa5d94b8d15946547b99ba2c7155e9 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Wed, 8 Jan 2025 21:54:45 -0500 Subject: [PATCH 15/29] #557 facility app and sps page fixes --- pocket/ui/apps/facility.lua | 2 +- pocket/ui/main.lua | 2 ++ pocket/ui/pages/facility_sps.lua | 32 ++++++++++++++++---------------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/pocket/ui/apps/facility.lua b/pocket/ui/apps/facility.lua index 18ba4b4..076eba3 100644 --- a/pocket/ui/apps/facility.lua +++ b/pocket/ui/apps/facility.lua @@ -145,7 +145,7 @@ local function new_view(root) TextBox{parent=t_div,y=1,text="Facility Tanks",alignment=ALIGN.CENTER} - for i = 1, fac.tank_data_tbl do + for i = 1, #fac.tank_data_tbl do tank_page_navs[i] = dyn_tank(app, nil, panes, Div{parent=page_div}, i, fac.tank_ps_tbl[i], update) end diff --git a/pocket/ui/main.lua b/pocket/ui/main.lua index 99b6ab3..6a70737 100644 --- a/pocket/ui/main.lua +++ b/pocket/ui/main.lua @@ -10,6 +10,7 @@ local pocket = require("pocket.pocket") local control_app = require("pocket.ui.apps.control") local diag_apps = require("pocket.ui.apps.diag_apps") local dummy_app = require("pocket.ui.apps.dummy_app") +local facil_app = require("pocket.ui.apps.facility") local guide_app = require("pocket.ui.apps.guide") local loader_app = require("pocket.ui.apps.loader") local process_app = require("pocket.ui.apps.process") @@ -65,6 +66,7 @@ local function init(main) -- create all the apps & pages home_page(page_div) unit_app(page_div) + facil_app(page_div) control_app(page_div) process_app(page_div) waste_app(page_div) diff --git a/pocket/ui/pages/facility_sps.lua b/pocket/ui/pages/facility_sps.lua index 337b852..3e3e25d 100644 --- a/pocket/ui/pages/facility_sps.lua +++ b/pocket/ui/pages/facility_sps.lua @@ -40,21 +40,21 @@ return function (app, panes, sps_pane, ps, update) local status = StateIndicator{parent=sps_div,x=5,y=3,states=style.sps.states,value=1,min_width=12} status.register(ps, "sps_computed_status", status.update) - TextBox{parent=sps_div,text="Polonium",x=1,y=5,fg_bg=label} - local po_bar = HorizontalBar{parent=sps_div,x=1,y=6,fg_bg=cpair(colors.cyan,colors.gray)} - TextBox{parent=sps_div,text="Antimatter",x=1,y=8,fg_bg=label} - local am_bar = HorizontalBar{parent=sps_div,x=1,y=9,fg_bg=cpair(colors.purple,colors.gray)} - TextBox{parent=sps_div,text="Energy Storage",x=21,y=11,fg_bg=label} - local energy_bar = HorizontalBar{parent=sps_div,x=1,y=12,fg_bg=cpair(colors.green,colors.gray)} + TextBox{parent=sps_div,text="Po",y=5,fg_bg=label} + local po_bar = HorizontalBar{parent=sps_div,x=4,y=5,fg_bg=cpair(colors.cyan,colors.gray),height=1} + TextBox{parent=sps_div,text="AM",y=7,fg_bg=label} + local am_bar = HorizontalBar{parent=sps_div,x=4,y=7,fg_bg=cpair(colors.purple,colors.gray),height=1} + TextBox{parent=sps_div,text="En",y=9,fg_bg=label} + local energy_bar = HorizontalBar{parent=sps_div,x=4,y=9,fg_bg=cpair(colors.green,colors.gray),height=1} po_bar.register(ps, "input_fill", po_bar.update) am_bar.register(ps, "output_fill", am_bar.update) energy_bar.register(ps, "energy_fill", energy_bar.update) - TextBox{parent=sps_div,text="Input Rate",x=3,y=14,width=17,fg_bg=label} - local input_rate = DataIndicator{parent=sps_div,x=3,y=15,lu_colors=lu_col,label="",unit="mB/t",format="%11.0f",value=0,commas=true,width=17,fg_bg=text_fg} - TextBox{parent=sps_div,text="Production",x=3,y=17,width=17,fg_bg=label} - local proc_rate = DataIndicator{parent=sps_div,x=3,y=18,lu_colors=lu_col,label="",unit="\xb5B/t",format="%11d",value=0,width=17,fg_bg=text_fg} + TextBox{parent=sps_div,y=11,text="Input Rate",width=10,fg_bg=label} + local input_rate = DataIndicator{parent=sps_div,label="",format="%16.2f",value=0,unit="mB/t",lu_colors=lu_col,width=21,fg_bg=text_fg} + TextBox{parent=sps_div,y=14,text="Production Rate",width=15,fg_bg=label} + local proc_rate = DataIndicator{parent=sps_div,label="",format="%16d",value=0,unit="\xb5B/t",lu_colors=lu_col,width=21,fg_bg=text_fg} proc_rate.register(ps, "process_rate", function (r) proc_rate.update(r * 1000) end) input_rate.register(db.facility.ps, "po_am_rate", input_rate.update) @@ -70,23 +70,23 @@ return function (app, panes, sps_pane, ps, update) TextBox{parent=sps_ext_div,y=1,text="More SPS Info",alignment=ALIGN.CENTER} - TextBox{parent=sps_ext_div,text="Polonium Tank",x=1,y=3,width=13,fg_bg=label} + TextBox{parent=sps_ext_div,text="Polonium",x=1,y=3,width=13,fg_bg=label} local input_p = DataIndicator{parent=sps_ext_div,x=14,y=3,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} local input_amnt = DataIndicator{parent=sps_ext_div,x=1,y=4,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg} input_p.register(ps, "input_fill", function (x) input_p.update(x * 100) end) input_amnt.register(ps, "input", function (x) input_amnt.update(x.amount) end) - TextBox{parent=sps_ext_div,text="Antimatter Tank",x=1,y=6,width=15,fg_bg=label} + TextBox{parent=sps_ext_div,text="Antimatter",x=1,y=6,width=15,fg_bg=label} local output_p = DataIndicator{parent=sps_ext_div,x=14,y=6,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} - local output_amnt = DataIndicator{parent=sps_ext_div,x=1,y=7,lu_colors=lu_col,label="",unit="mB",format="%18.3f",value=0,commas=true,width=21,fg_bg=text_fg} + local output_amnt = DataIndicator{parent=sps_ext_div,x=1,y=7,lu_colors=lu_col,label="",unit="\xb5B",format="%18.3f",value=0,commas=true,width=21,fg_bg=text_fg} output_p.register(ps, "output_fill", function (x) output_p.update(x * 100) end) output_amnt.register(ps, "output", function (x) output_amnt.update(x.amount) end) - TextBox{parent=sps_ext_div,text="Energy Fill",x=1,y=8,width=11,fg_bg=label} - local energy_p = DataIndicator{parent=sps_ext_div,x=14,y=8,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} - local energy_amnt = PowerIndicator{parent=sps_ext_div,x=1,y=9,lu_colors=lu_col,label="",unit=db.energy_label,format="%17.4f",value=0,width=21,fg_bg=text_fg} + TextBox{parent=sps_ext_div,text="Energy Fill",x=1,y=9,width=11,fg_bg=label} + local energy_p = DataIndicator{parent=sps_ext_div,x=14,y=9,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} + local energy_amnt = PowerIndicator{parent=sps_ext_div,x=1,y=10,lu_colors=lu_col,label="",unit=db.energy_label,format="%17.4f",value=0,width=21,fg_bg=text_fg} energy_p.register(ps, "energy_fill", function (x) energy_p.update(x * 100) end) energy_amnt.register(ps, "energy", function (val) energy_amnt.update(db.energy_convert(val)) end) From cbc004a6c7d15fb748d216ebbc9387e91bf51c9c Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Wed, 8 Jan 2025 22:49:05 -0500 Subject: [PATCH 16/29] #557 induction matrix page updates --- pocket/ui/pages/facility_matrix.lua | 48 +++++++++++++++++++---------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/pocket/ui/pages/facility_matrix.lua b/pocket/ui/pages/facility_matrix.lua index 7287457..1a1f42c 100644 --- a/pocket/ui/pages/facility_matrix.lua +++ b/pocket/ui/pages/facility_matrix.lua @@ -10,12 +10,15 @@ local core = require("graphics.core") local Div = require("graphics.elements.Div") local TextBox = require("graphics.elements.TextBox") +local PushButton = require("graphics.elements.controls.PushButton") + local DataIndicator = require("graphics.elements.indicators.DataIndicator") local HorizontalBar = require("graphics.elements.indicators.HorizontalBar") local IconIndicator = require("graphics.elements.indicators.IconIndicator") local PowerIndicator = require("graphics.elements.indicators.PowerIndicator") local StateIndicator = require("graphics.elements.indicators.StateIndicator") +local ALIGN = core.ALIGN local cpair = core.cpair local label = style.label @@ -30,29 +33,29 @@ local mode_ind_s = { -- create an induction matrix view for the facility app ---@param app pocket_app ---@param panes Div[] ----@param tank_pane Div +---@param matrix_pane Div ---@param ps psil ---@param update function -return function (app, panes, tank_pane, ps, update) +return function (app, panes, matrix_pane, ps, update) local db = iocontrol.get_db() local fac = db.facility - local mtx_div = Div{parent=tank_pane,x=2,width=tank_pane.get_width()-2} + local mtx_div = Div{parent=matrix_pane,x=2,width=matrix_pane.get_width()-2} table.insert(panes, mtx_div) local matrix_page = app.new_page(nil, #panes) matrix_page.tasks = { update } - TextBox{parent=mtx_div,y=1,text="I Matrix",width=9} - local status = StateIndicator{parent=mtx_div,x=10,y=1,states=style.imatrix.states,value=1,min_width=12} + TextBox{parent=mtx_div,y=1,text="Induction Matrix",alignment=ALIGN.CENTER} + local status = StateIndicator{parent=mtx_div,x=5,y=3,states=style.imatrix.states,value=1,min_width=12} status.register(ps, "InductionMatrixStateStatus", status.update) - TextBox{parent=mtx_div,text="Charge",x=1,y=5,fg_bg=label} - local chg_bar = HorizontalBar{parent=mtx_div,x=1,y=6,fg_bg=cpair(colors.green,colors.gray)} - TextBox{parent=mtx_div,text="Input",x=1,y=7,fg_bg=label} - local in_bar = HorizontalBar{parent=mtx_div,x=1,y=8,fg_bg=cpair(colors.blue,colors.gray)} - TextBox{parent=mtx_div,text="Output",x=21,y=9,fg_bg=label} - local out_bar = HorizontalBar{parent=mtx_div,x=1,y=10,fg_bg=cpair(colors.red,colors.gray)} + TextBox{parent=mtx_div,text="Chg",y=5,fg_bg=label} + local chg_bar = HorizontalBar{parent=mtx_div,x=5,y=5,height=1,fg_bg=cpair(colors.green,colors.gray)} + TextBox{parent=mtx_div,text="In",y=7,fg_bg=label} + local in_bar = HorizontalBar{parent=mtx_div,x=5,y=7,height=1,fg_bg=cpair(colors.blue,colors.gray)} + TextBox{parent=mtx_div,text="Out",y=9,fg_bg=label} + local out_bar = HorizontalBar{parent=mtx_div,x=5,y=9,height=1,fg_bg=cpair(colors.red,colors.gray)} local function calc_saturation(val) local data = fac.induction_data_tbl[1] @@ -65,12 +68,12 @@ return function (app, panes, tank_pane, ps, update) in_bar.register(ps, "last_input", function (val) in_bar.update(calc_saturation(val)) end) out_bar.register(ps, "last_output", function (val) out_bar.update(calc_saturation(val)) end) - local energy = PowerIndicator{parent=mtx_div,x=1,y=12,lu_colors=lu_col,label="Chg: ",unit=db.energy_label,format="%8.2f",value=0,width=22,fg_bg=text_fg} - local avg_chg = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg:",unit=db.energy_label,format="%8.2f",value=0,width=22,fg_bg=text_fg} - local input = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="In: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} - local avg_in = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg:",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} - local output = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="Out: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} - local avg_out = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg:",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} + local energy = PowerIndicator{parent=mtx_div,x=1,y=11,lu_colors=lu_col,label="Chg: ",unit=db.energy_label,format="%8.2f",value=0,width=22,fg_bg=text_fg} + local avg_chg = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg: ",unit=db.energy_label,format="%8.2f",value=0,width=22,fg_bg=text_fg} + local input = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="In: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} + local avg_in = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} + local output = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="Out: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} + local avg_out = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} energy.register(ps, "energy", function (val) energy.update(db.energy_convert(val)) end) avg_chg.register(fac.ps, "avg_charge", avg_chg.update) @@ -79,5 +82,16 @@ return function (app, panes, tank_pane, ps, update) output.register(ps, "last_output", function (val) output.update(db.energy_convert(val)) end) avg_out.register(fac.ps, "avg_outflow", avg_out.update) + local mtx_ext_div = Div{parent=matrix_pane,x=2,width=matrix_pane.get_width()-2} + table.insert(panes, mtx_ext_div) + + local mtx_ext_page = app.new_page(matrix_page, #panes) + mtx_ext_page.tasks = { update } + + PushButton{parent=mtx_div,x=9,y=18,text="MORE",min_width=6,fg_bg=cpair(colors.lightGray,colors.gray),active_fg_bg=cpair(colors.gray,colors.lightGray),callback=mtx_ext_page.nav_to} + PushButton{parent=mtx_ext_div,x=9,y=18,text="BACK",min_width=6,fg_bg=cpair(colors.lightGray,colors.gray),active_fg_bg=cpair(colors.gray,colors.lightGray),callback=matrix_page.nav_to} + + TextBox{parent=mtx_ext_div,y=1,text="More Matrix Info",alignment=ALIGN.CENTER} + return matrix_page.nav_to end From 78b0e1bf24c9f8be4f21fc5cf12e02e18fd37f0f Mon Sep 17 00:00:00 2001 From: Mikayla Date: Thu, 9 Jan 2025 23:50:47 +0000 Subject: [PATCH 17/29] #557 facility app and induction matrix updates --- pocket/ui/apps/facility.lua | 63 +++++++++++++++++++++++++++-- pocket/ui/pages/facility_matrix.lua | 54 ++++++++++++++++++++----- 2 files changed, 105 insertions(+), 12 deletions(-) diff --git a/pocket/ui/apps/facility.lua b/pocket/ui/apps/facility.lua index 076eba3..039c39b 100644 --- a/pocket/ui/apps/facility.lua +++ b/pocket/ui/apps/facility.lua @@ -85,14 +85,70 @@ local function new_view(root) end end + --#region facility overview + + local f_pane = Div{parent=page_div} + local f_div = Div{parent=f_pane,x=2,width=main.get_width()-2} + table.insert(panes, f_pane) + + local fac_page = app.new_page(nil, #panes) + fac_page.tasks = { update } + + TextBox{parent=f_div,y=1,text="Facility",alignment=ALIGN.CENTER} + + local eta = TextBox{parent=f_div,x=1,y=17,text="ETA Unknown",alignment=ALIGN.CENTER,fg_bg=cpair(colors.white,colors.gray)} + + eta.register(fac.induction_ps_tbl[1], "eta_ms", function (eta_ms) + local str, pre = "", util.trinary(eta_ms >= 0, "Full in ", "Empty in ") + + local seconds = math.abs(eta_ms) / 1000 + local minutes = seconds / 60 + local hours = minutes / 60 + local days = hours / 24 + + if math.abs(eta_ms) < 1000 or (eta_ms ~= eta_ms) then + -- really small or NaN + str = "No ETA" + elseif days < 1000 then + days = math.floor(days) + hours = math.floor(hours % 24) + minutes = math.floor(minutes % 60) + seconds = math.floor(seconds % 60) + + if days > 0 then + str = days .. "d" + elseif hours > 0 then + str = hours .. "h " .. minutes .. "m" + elseif minutes > 0 then + str = minutes .. "m " .. seconds .. "s" + elseif seconds > 0 then + str = seconds .. "s" + end + + str = pre .. str + else + local years = math.floor(days / 365.25) + + if years <= 99999999 then + str = pre .. years .. "y" + else + str = pre .. "eras" + end + end + + eta.set_value(str) + end) + + --#endregion + --#region facility annunciator local a_pane = Div{parent=page_div} local a_div = Div{parent=a_pane,x=2,width=main.get_width()-2} table.insert(panes, a_pane) - local f_annunc = app.new_page(nil, #panes) - f_annunc.tasks = { update } + local annunc_page = app.new_page(nil, #panes) + annunc_page.tasks = { update } TextBox{parent=a_div,y=1,text="Annunciator",alignment=ALIGN.CENTER} @@ -159,7 +215,8 @@ local function new_view(root) local list = { { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home }, - { label = "FAC", color = core.cpair(colors.black, colors.orange), callback = f_annunc.nav_to }, + { label = "FAC", color = core.cpair(colors.black, colors.orange), callback = fac_page.nav_to }, + { label = "ANN", color = core.cpair(colors.black, colors.yellow), callback = annunc_page.nav_to }, { label = "MTX", color = core.cpair(colors.black, colors.white), callback = mtx_page_nav }, { label = "SPS", color = core.cpair(colors.black, colors.purple), callback = sps_page_nav }, { label = "TNK", tall = true, color = core.cpair(colors.white, colors.gray), callback = tank_page.nav_to } diff --git a/pocket/ui/pages/facility_matrix.lua b/pocket/ui/pages/facility_matrix.lua index 1a1f42c..0eeb8a5 100644 --- a/pocket/ui/pages/facility_matrix.lua +++ b/pocket/ui/pages/facility_matrix.lua @@ -25,6 +25,13 @@ local label = style.label local lu_col = style.label_unit_pair local text_fg = style.text_fg +local basic_states = style.icon_states.basic_states +local mode_states = style.icon_states.mode_states +local red_ind_s = style.icon_states.red_ind_s +local yel_ind_s = style.icon_states.yel_ind_s +local grn_ind_s = style.icon_states.grn_ind_s +local wht_ind_s = style.icon_states.wht_ind_s + local mode_ind_s = { { color = cpair(colors.black, colors.lightGray), symbol = "-" }, { color = cpair(colors.black, colors.white), symbol = "+" } @@ -68,19 +75,19 @@ return function (app, panes, matrix_pane, ps, update) in_bar.register(ps, "last_input", function (val) in_bar.update(calc_saturation(val)) end) out_bar.register(ps, "last_output", function (val) out_bar.update(calc_saturation(val)) end) - local energy = PowerIndicator{parent=mtx_div,x=1,y=11,lu_colors=lu_col,label="Chg: ",unit=db.energy_label,format="%8.2f",value=0,width=22,fg_bg=text_fg} - local avg_chg = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg: ",unit=db.energy_label,format="%8.2f",value=0,width=22,fg_bg=text_fg} - local input = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="In: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} - local avg_in = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} - local output = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="Out: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} - local avg_out = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=22,fg_bg=text_fg} + local energy = PowerIndicator{parent=mtx_div,x=1,y=11,lu_colors=lu_col,label="Chg: ",unit=db.energy_label,format="%8.2f",value=0,width=21,fg_bg=text_fg} + local avg_chg = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg: ",unit=db.energy_label,format="%8.2f",value=0,width=21,fg_bg=text_fg} + local input = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="In: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=21,fg_bg=text_fg} + local avg_in = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=21,fg_bg=text_fg} + local output = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="Out: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=21,fg_bg=text_fg} + local avg_out = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=21,fg_bg=text_fg} energy.register(ps, "energy", function (val) energy.update(db.energy_convert(val)) end) - avg_chg.register(fac.ps, "avg_charge", avg_chg.update) + avg_chg.register(ps, "avg_charge", avg_chg.update) input.register(ps, "last_input", function (val) input.update(db.energy_convert(val)) end) - avg_in.register(fac.ps, "avg_inflow", avg_in.update) + avg_in.register(ps, "avg_inflow", avg_in.update) output.register(ps, "last_output", function (val) output.update(db.energy_convert(val)) end) - avg_out.register(fac.ps, "avg_outflow", avg_out.update) + avg_out.register(ps, "avg_outflow", avg_out.update) local mtx_ext_div = Div{parent=matrix_pane,x=2,width=matrix_pane.get_width()-2} table.insert(panes, mtx_ext_div) @@ -93,5 +100,34 @@ return function (app, panes, matrix_pane, ps, update) TextBox{parent=mtx_ext_div,y=1,text="More Matrix Info",alignment=ALIGN.CENTER} + local chging = IconIndicator{parent=mtx_ext_div,y=3,label="Charging",states=wht_ind_s} + local dischg = IconIndicator{parent=mtx_ext_div,y=4,label="Discharging",states=wht_ind_s} + + TextBox{parent=mtx_ext_div,text="Energy Fill",x=1,y=6,width=13,fg_bg=label} + local fill = DataIndicator{parent=mtx_ext_div,x=14,y=6,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} + + chging.register(ps, "is_charging", chging.update) + dischg.register(ps, "is_discharging", dischg.update) + fill.register(ps, "energy_fill", function (x) fill.update(x * 100) end) + + local max_io = IconIndicator{parent=mtx_ext_div,y=8,label="Max I/O Rate",states=yel_ind_s} + + TextBox{parent=mtx_ext_div,text="Input Util.",x=1,y=10,width=13,fg_bg=label} + local in_util = DataIndicator{parent=mtx_ext_div,x=14,y=10,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} + TextBox{parent=mtx_ext_div,text="Output Util.",x=1,y=11,width=13,fg_bg=label} + local out_util = DataIndicator{parent=mtx_ext_div,x=14,y=11,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} + + max_io.register(ps, "at_max_io", max_io.update) + in_util.register(ps, "last_input", function (x) in_util.update(calc_saturation(x) * 100) end) + out_util.register(ps, "last_output", function (x) out_util.update(calc_saturation(x) * 100) end) + + TextBox{parent=mtx_ext_div,text="Capacity",x=1,y=13,width=13,fg_bg=label} + local capacity = PowerIndicator{parent=mtx_ext_div,y=14,lu_colors=lu_col,label="",unit=db.energy_label,format="%8.2f",value=0,width=21,fg_bg=text_fg} + TextBox{parent=mtx_ext_div,text="Maximum In/Out Rate",x=1,y=15,width=13,fg_bg=label} + local trans_cap = PowerIndicator{parent=mtx_ext_div,y=16,lu_colors=lu_col,label="",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=21,fg_bg=text_fg} + + capacity.register(ps, "max_energy", function (val) capacity.update(db.energy_convert(val)) end) + trans_cap.register(ps, "transfer_cap", function (val) trans_cap.update(db.energy_convert(val)) end) + return matrix_page.nav_to end From eb197e7fddaa48cd9b2817e8fa934db27d02bad5 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Thu, 9 Jan 2025 23:51:02 +0000 Subject: [PATCH 18/29] updated dynamic tank page to indicate which tank it is --- pocket/ui/pages/dynamic_tank.lua | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/pocket/ui/pages/dynamic_tank.lua b/pocket/ui/pages/dynamic_tank.lua index d9303fa..c0719d0 100644 --- a/pocket/ui/pages/dynamic_tank.lua +++ b/pocket/ui/pages/dynamic_tank.lua @@ -18,6 +18,7 @@ local StateIndicator = require("graphics.elements.indicators.StateIndicator") local CONTAINER_MODE = types.CONTAINER_MODE local COOLANT_TYPE = types.COOLANT_TYPE +local ALIGN = core.ALIGN local cpair = core.cpair local label = style.label @@ -46,22 +47,35 @@ return function (app, page, panes, tank_pane, tank_id, ps, update) local tank_page = app.new_page(page, #panes) tank_page.tasks = { update } - TextBox{parent=tank_div,y=1,text="Dyn Tank",width=9} - local status = StateIndicator{parent=tank_div,x=10,y=1,states=style.dtank.states,value=1,min_width=12} + local tank_assign = "" + local f_tank_count = 0 + + for i = 1, #fac.tank_list do + local is_fac = fac.tank_list[i] == 2 + if is_fac then f_tank_count = f_tank_count + 1 end + + if i == tank_id then + tank_assign = util.trinary(is_fac, "F-" .. f_tank_count, "U-" .. i) + break + end + end + + TextBox{parent=tank_div,y=1,text="Dynamic Tank "..tank_assign,alignment=ALIGN.CENTER} + local status = StateIndicator{parent=tank_div,x=5,y=3,states=style.dtank.states,value=1,min_width=12} status.register(ps, "DynamicTankStateStatus", status.update) - TextBox{parent=tank_div,y=3,text="Fill",width=10,fg_bg=label} - 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} + TextBox{parent=tank_div,y=5,text="Fill",width=10,fg_bg=label} + local tank_pcnt = DataIndicator{parent=tank_div,x=14,y=5,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 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.lightBlue),colors.gray),height=1,width=21} + TextBox{parent=tank_div,y=8,text=util.trinary(is_water,"Water","Sodium").." Level",width=12,fg_bg=label} + local level = HorizontalBar{parent=tank_div,y=9,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} - local can_empty = IconIndicator{parent=tank_div,y=11,label="Empty",states=mode_ind_s} + TextBox{parent=tank_div,y=1,text="Tank Fill Mode",width=14,fg_bg=label} + local can_fill = IconIndicator{parent=tank_div,y=12,label="Fill",states=mode_ind_s} + local can_empty = IconIndicator{parent=tank_div,y=13,label="Empty",states=mode_ind_s} local function _can_fill(mode) can_fill.update((mode == CONTAINER_MODE.BOTH) or (mode == CONTAINER_MODE.FILL)) From 4a4234c8c8fd9adb9bbba0cc8a70f524ee3ab743 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Fri, 10 Jan 2025 22:52:27 -0500 Subject: [PATCH 19/29] #557 ui improvements --- pocket/ui/pages/dynamic_tank.lua | 2 +- pocket/ui/pages/facility_matrix.lua | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pocket/ui/pages/dynamic_tank.lua b/pocket/ui/pages/dynamic_tank.lua index c0719d0..17221a6 100644 --- a/pocket/ui/pages/dynamic_tank.lua +++ b/pocket/ui/pages/dynamic_tank.lua @@ -73,7 +73,7 @@ return function (app, page, panes, tank_pane, tank_id, ps, update) TextBox{parent=tank_div,y=8,text=util.trinary(is_water,"Water","Sodium").." Level",width=12,fg_bg=label} local level = HorizontalBar{parent=tank_div,y=9,bar_fg_bg=cpair(util.trinary(is_water,colors.blue,colors.lightBlue),colors.gray),height=1,width=21} - TextBox{parent=tank_div,y=1,text="Tank Fill Mode",width=14,fg_bg=label} + TextBox{parent=tank_div,y=11,text="Tank Fill Mode",width=14,fg_bg=label} local can_fill = IconIndicator{parent=tank_div,y=12,label="Fill",states=mode_ind_s} local can_empty = IconIndicator{parent=tank_div,y=13,label="Empty",states=mode_ind_s} diff --git a/pocket/ui/pages/facility_matrix.lua b/pocket/ui/pages/facility_matrix.lua index 0eeb8a5..a66f2a9 100644 --- a/pocket/ui/pages/facility_matrix.lua +++ b/pocket/ui/pages/facility_matrix.lua @@ -121,10 +121,10 @@ return function (app, panes, matrix_pane, ps, update) in_util.register(ps, "last_input", function (x) in_util.update(calc_saturation(x) * 100) end) out_util.register(ps, "last_output", function (x) out_util.update(calc_saturation(x) * 100) end) - TextBox{parent=mtx_ext_div,text="Capacity",x=1,y=13,width=13,fg_bg=label} - local capacity = PowerIndicator{parent=mtx_ext_div,y=14,lu_colors=lu_col,label="",unit=db.energy_label,format="%8.2f",value=0,width=21,fg_bg=text_fg} - TextBox{parent=mtx_ext_div,text="Maximum In/Out Rate",x=1,y=15,width=13,fg_bg=label} - local trans_cap = PowerIndicator{parent=mtx_ext_div,y=16,lu_colors=lu_col,label="",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=21,fg_bg=text_fg} + TextBox{parent=mtx_ext_div,text="Capacity ("..db.energy_label..")",x=1,y=13,fg_bg=label} + local capacity = DataIndicator{parent=mtx_ext_div,y=14,lu_colors=lu_col,label="",unit="",format="%21d",value=1000000000000,width=21,fg_bg=text_fg} + TextBox{parent=mtx_ext_div,text="Max In/Out ("..db.energy_label.."/t)",x=1,y=15,fg_bg=label} + local trans_cap = DataIndicator{parent=mtx_ext_div,y=16,lu_colors=lu_col,label="",unit="",format="%21d",rate=true,value=0,width=21,fg_bg=text_fg} capacity.register(ps, "max_energy", function (val) capacity.update(db.energy_convert(val)) end) trans_cap.register(ps, "transfer_cap", function (val) trans_cap.update(db.energy_convert(val)) end) From 2d83de8b8851ae3dc02673374a153b78bf2c24a3 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 11 Jan 2025 11:57:06 -0500 Subject: [PATCH 20/29] moved ETA string generation to icontrol --- coordinator/iocontrol.lua | 44 +++++++++++++++++++++++++++ coordinator/ui/components/imatrix.lua | 41 +------------------------ pocket/ui/apps/facility.lua | 41 +------------------------ 3 files changed, 46 insertions(+), 80 deletions(-) diff --git a/coordinator/iocontrol.lua b/coordinator/iocontrol.lua index 07479e0..95a3e6f 100644 --- a/coordinator/iocontrol.lua +++ b/coordinator/iocontrol.lua @@ -495,6 +495,49 @@ end --#region Statuses +-- generate the text string for the induction matrix charge/discharge ETA +---@param eta_ms number eta in milliseconds +local function gen_eta_text(eta_ms) + local str, pre = "", util.trinary(eta_ms >= 0, "Full in ", "Empty in ") + + local seconds = math.abs(eta_ms) / 1000 + local minutes = seconds / 60 + local hours = minutes / 60 + local days = hours / 24 + + if math.abs(eta_ms) < 1000 or (eta_ms ~= eta_ms) then + -- really small or NaN + str = "No ETA" + elseif days < 1000 then + days = math.floor(days) + hours = math.floor(hours % 24) + minutes = math.floor(minutes % 60) + seconds = math.floor(seconds % 60) + + if days > 0 then + str = days .. "d" + elseif hours > 0 then + str = hours .. "h " .. minutes .. "m" + elseif minutes > 0 then + str = minutes .. "m " .. seconds .. "s" + elseif seconds > 0 then + str = seconds .. "s" + end + + str = pre .. str + else + local years = math.floor(days / 365.25) + + if years <= 99999999 then + str = pre .. years .. "y" + else + str = pre .. "eras" + end + end + + return str +end + -- record and publish multiblock status data ---@param entry any ---@param data imatrix_session_db|sps_session_db|dynamicv_session_db|turbinev_session_db|boilerv_session_db @@ -616,6 +659,7 @@ function iocontrol.update_facility_status(status) ps.publish("avg_inflow", in_f) ps.publish("avg_outflow", out_f) ps.publish("eta_ms", eta) + ps.publish("eta_string", gen_eta_text(eta or 0)) ps.publish("is_charging", in_f > out_f) ps.publish("is_discharging", out_f > in_f) diff --git a/coordinator/ui/components/imatrix.lua b/coordinator/ui/components/imatrix.lua index 1f053a8..c6fd21d 100644 --- a/coordinator/ui/components/imatrix.lua +++ b/coordinator/ui/components/imatrix.lua @@ -105,46 +105,7 @@ local function new_view(root, x, y, ps, id) local eta = TextBox{parent=rect,x=11,y=20,width=20,text="ETA Unknown",alignment=ALIGN.CENTER,fg_bg=style.theme.field_box} - eta.register(ps, "eta_ms", function (eta_ms) - local str, pre = "", util.trinary(eta_ms >= 0, "Full in ", "Empty in ") - - local seconds = math.abs(eta_ms) / 1000 - local minutes = seconds / 60 - local hours = minutes / 60 - local days = hours / 24 - - if math.abs(eta_ms) < 1000 or (eta_ms ~= eta_ms) then - -- really small or NaN - str = "No ETA" - elseif days < 1000 then - days = math.floor(days) - hours = math.floor(hours % 24) - minutes = math.floor(minutes % 60) - seconds = math.floor(seconds % 60) - - if days > 0 then - str = days .. "d" - elseif hours > 0 then - str = hours .. "h " .. minutes .. "m" - elseif minutes > 0 then - str = minutes .. "m " .. seconds .. "s" - elseif seconds > 0 then - str = seconds .. "s" - end - - str = pre .. str - else - local years = math.floor(days / 365.25) - - if years <= 99999999 then - str = pre .. years .. "y" - else - str = pre .. "eras" - end - end - - eta.set_value(str) - end) + eta.register(ps, "eta_string", eta.set_value) end return new_view diff --git a/pocket/ui/apps/facility.lua b/pocket/ui/apps/facility.lua index 039c39b..8e338da 100644 --- a/pocket/ui/apps/facility.lua +++ b/pocket/ui/apps/facility.lua @@ -98,46 +98,7 @@ local function new_view(root) local eta = TextBox{parent=f_div,x=1,y=17,text="ETA Unknown",alignment=ALIGN.CENTER,fg_bg=cpair(colors.white,colors.gray)} - eta.register(fac.induction_ps_tbl[1], "eta_ms", function (eta_ms) - local str, pre = "", util.trinary(eta_ms >= 0, "Full in ", "Empty in ") - - local seconds = math.abs(eta_ms) / 1000 - local minutes = seconds / 60 - local hours = minutes / 60 - local days = hours / 24 - - if math.abs(eta_ms) < 1000 or (eta_ms ~= eta_ms) then - -- really small or NaN - str = "No ETA" - elseif days < 1000 then - days = math.floor(days) - hours = math.floor(hours % 24) - minutes = math.floor(minutes % 60) - seconds = math.floor(seconds % 60) - - if days > 0 then - str = days .. "d" - elseif hours > 0 then - str = hours .. "h " .. minutes .. "m" - elseif minutes > 0 then - str = minutes .. "m " .. seconds .. "s" - elseif seconds > 0 then - str = seconds .. "s" - end - - str = pre .. str - else - local years = math.floor(days / 365.25) - - if years <= 99999999 then - str = pre .. years .. "y" - else - str = pre .. "eras" - end - end - - eta.set_value(str) - end) + eta.register(fac.induction_ps_tbl[1], "eta_string", eta.set_value) --#endregion From 1c57fc1fe39c9d6b662012d27bd4099b186c2d52 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 11 Jan 2025 11:57:28 -0500 Subject: [PATCH 21/29] #557 work on facility app --- pocket/ui/apps/facility.lua | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pocket/ui/apps/facility.lua b/pocket/ui/apps/facility.lua index 8e338da..d468085 100644 --- a/pocket/ui/apps/facility.lua +++ b/pocket/ui/apps/facility.lua @@ -87,9 +87,9 @@ local function new_view(root) --#region facility overview - local f_pane = Div{parent=page_div} - local f_div = Div{parent=f_pane,x=2,width=main.get_width()-2} - table.insert(panes, f_pane) + local main_pane = Div{parent=page_div} + local f_div = Div{parent=main_pane,x=2,width=main.get_width()-2} + table.insert(panes, main_pane) local fac_page = app.new_page(nil, #panes) fac_page.tasks = { update } @@ -162,8 +162,18 @@ local function new_view(root) TextBox{parent=t_div,y=1,text="Facility Tanks",alignment=ALIGN.CENTER} + -- for i = 1, #fac.tank_list do + -- if fac.tank_list[i] == 2 then + -- table.insert(io.facility.tank_ps_tbl, psil.create()) + -- table.insert(io.facility.tank_data_tbl, {}) + -- end + -- end + for i = 1, #fac.tank_data_tbl do tank_page_navs[i] = dyn_tank(app, nil, panes, Div{parent=page_div}, i, fac.tank_ps_tbl[i], update) + + t_div.line_break() + TextBox{parent=t_div,y=1,text="Facility Tank ",alignment=ALIGN.CENTER} end --#endregion From 767b54c3e62cab1f7fc30b102486656fee64c262 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Wed, 15 Jan 2025 22:49:55 +0000 Subject: [PATCH 22/29] #557 facility tank overview page --- pocket/ui/apps/facility.lua | 42 ++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/pocket/ui/apps/facility.lua b/pocket/ui/apps/facility.lua index d468085..549b2a2 100644 --- a/pocket/ui/apps/facility.lua +++ b/pocket/ui/apps/facility.lua @@ -162,18 +162,40 @@ local function new_view(root) TextBox{parent=t_div,y=1,text="Facility Tanks",alignment=ALIGN.CENTER} - -- for i = 1, #fac.tank_list do - -- if fac.tank_list[i] == 2 then - -- table.insert(io.facility.tank_ps_tbl, psil.create()) - -- table.insert(io.facility.tank_data_tbl, {}) - -- end - -- end + t_div.line_break() - for i = 1, #fac.tank_data_tbl do - tank_page_navs[i] = dyn_tank(app, nil, panes, Div{parent=page_div}, i, fac.tank_ps_tbl[i], update) + local f_tank_id = 1 + for t = 1, #fac.tank_list do + if fac.tank_list[t] == 1 then + t_div.line_break() - t_div.line_break() - TextBox{parent=t_div,y=1,text="Facility Tank ",alignment=ALIGN.CENTER} + local tank = IconIndicator{parent=t_div,x=1,label="Unit Tank "..t.." (U-"..t..")",states=basic_states} + tank.register(db.units[t].tank_ps_tbl[1], "DynamicTankStatus", tank.update) + + TextBox{parent=t_div,text="Unit "..t,fg_bg=label_fg_bg} + elseif fac.tank_list[t] == 2 then + tank_page_navs[f_tank_id] = dyn_tank(app, nil, panes, Div{parent=page_div}, t, fac.tank_ps_tbl[f_tank_id], update) + + t_div.line_break() + + local tank = IconIndicator{parent=t_div,x=1,label="Facility Tank "..f_tank_id.." (F-"..f_tank_id..")",states=basic_states} + tank.register(fac.tank_ps_tbl[f_tank_id], "DynamicTankStatus", tank.update) + + local connections + for i = 1, #fac.tank_conns do + if fac.tank_conns[i] == t then + if connections then + connections = "Unit " .. i + else + connections = connections .. ", Unit " .. i + end + end + end + + TextBox{parent=t_div,text=connections,fg_bg=label_fg_bg} + + f_tank_id = f_tank_id + 1 + end end --#endregion From 127c878794e2442d4b47499d39154ee5f811e219 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Mon, 20 Jan 2025 12:21:51 -0500 Subject: [PATCH 23/29] #557 facility app ui design complete --- pocket/ui/apps/facility.lua | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/pocket/ui/apps/facility.lua b/pocket/ui/apps/facility.lua index 549b2a2..0b38c07 100644 --- a/pocket/ui/apps/facility.lua +++ b/pocket/ui/apps/facility.lua @@ -96,10 +96,21 @@ local function new_view(root) TextBox{parent=f_div,y=1,text="Facility",alignment=ALIGN.CENTER} - local eta = TextBox{parent=f_div,x=1,y=17,text="ETA Unknown",alignment=ALIGN.CENTER,fg_bg=cpair(colors.white,colors.gray)} + TextBox{parent=f_div,y=3,text="Induction Matrix",alignment=ALIGN.CENTER} + local eta = TextBox{parent=f_div,x=1,y=5,text="ETA Unknown",alignment=ALIGN.CENTER,fg_bg=cpair(colors.white,colors.gray)} eta.register(fac.induction_ps_tbl[1], "eta_string", eta.set_value) + TextBox{parent=f_div,y=7,text="Unit Statuses",alignment=ALIGN.CENTER} + + f_div.line_break() + + for i = 1, fac.num_units do + local ctrl = IconIndicator{parent=f_div,label="U"..i.." Control State",states=mode_states} + ctrl.register(db.units[i].unit_ps, "U_ControlStatus", ctrl.update) + f_div.line_break(); + end + --#endregion --#region facility annunciator @@ -162,8 +173,6 @@ local function new_view(root) TextBox{parent=t_div,y=1,text="Facility Tanks",alignment=ALIGN.CENTER} - t_div.line_break() - local f_tank_id = 1 for t = 1, #fac.tank_list do if fac.tank_list[t] == 1 then @@ -172,27 +181,27 @@ local function new_view(root) local tank = IconIndicator{parent=t_div,x=1,label="Unit Tank "..t.." (U-"..t..")",states=basic_states} tank.register(db.units[t].tank_ps_tbl[1], "DynamicTankStatus", tank.update) - TextBox{parent=t_div,text="Unit "..t,fg_bg=label_fg_bg} + TextBox{parent=t_div,x=5,text="\x07 Unit "..t,fg_bg=label_fg_bg} elseif fac.tank_list[t] == 2 then tank_page_navs[f_tank_id] = dyn_tank(app, nil, panes, Div{parent=page_div}, t, fac.tank_ps_tbl[f_tank_id], update) t_div.line_break() - local tank = IconIndicator{parent=t_div,x=1,label="Facility Tank "..f_tank_id.." (F-"..f_tank_id..")",states=basic_states} + local tank = IconIndicator{parent=t_div,x=1,label="Fac. Tank "..f_tank_id.." (F-"..f_tank_id..")",states=basic_states} tank.register(fac.tank_ps_tbl[f_tank_id], "DynamicTankStatus", tank.update) - local connections + local connections = "" for i = 1, #fac.tank_conns do if fac.tank_conns[i] == t then - if connections then - connections = "Unit " .. i + if connections ~= "" then + connections = connections .. "\n\x07 Unit " .. i else - connections = connections .. ", Unit " .. i + connections = "\x07 Unit " .. i end end end - TextBox{parent=t_div,text=connections,fg_bg=label_fg_bg} + TextBox{parent=t_div,x=5,text=connections,fg_bg=label_fg_bg} f_tank_id = f_tank_id + 1 end @@ -208,11 +217,11 @@ local function new_view(root) local list = { { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home }, - { label = "FAC", color = core.cpair(colors.black, colors.orange), callback = fac_page.nav_to }, + { label = "FAC", tall = true, color = core.cpair(colors.black, colors.orange), callback = fac_page.nav_to }, { label = "ANN", color = core.cpair(colors.black, colors.yellow), callback = annunc_page.nav_to }, { label = "MTX", color = core.cpair(colors.black, colors.white), callback = mtx_page_nav }, { label = "SPS", color = core.cpair(colors.black, colors.purple), callback = sps_page_nav }, - { label = "TNK", tall = true, color = core.cpair(colors.white, colors.gray), callback = tank_page.nav_to } + { label = "TNK", tall = true, color = core.cpair(colors.black, colors.blue), callback = tank_page.nav_to } } for i = 1, #fac.tank_data_tbl do From baba2e1411181f4c781d0fc2660962318ce89bea Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Mon, 20 Jan 2025 15:38:53 -0500 Subject: [PATCH 24/29] #557 facility app data and fixes --- coordinator/session/pocket.lua | 28 ++++- pocket/iocontrol.lua | 1 + pocket/iorx.lua | 168 +++++++++++++++++++++++++++- pocket/pocket.lua | 9 ++ pocket/ui/apps/facility.lua | 27 +++-- pocket/ui/apps/waste.lua | 2 +- pocket/ui/pages/facility_matrix.lua | 30 ++--- pocket/ui/pages/facility_sps.lua | 17 +-- 8 files changed, 229 insertions(+), 53 deletions(-) diff --git a/coordinator/session/pocket.lua b/coordinator/session/pocket.lua index 4bd78ed..6a901ac 100644 --- a/coordinator/session/pocket.lua +++ b/coordinator/session/pocket.lua @@ -266,24 +266,46 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout) _send(CRDN_TYPE.API_GET_FAC, data) elseif pkt.type == CRDN_TYPE.API_GET_FAC_DTL then - local fac = db.facility + local units = {} local tank_statuses = {} + for i = 1, #db.units do + local u = db.units[i] + + units[i] = { u.connected, u.annunciator, u.reactor_data, u.tank_data_tbl } + + for t = 1, #u.tank_ps_tbl do table.insert(tank_statuses, u.tank_ps_tbl[t].get("computed_status")) end + end + + local fac = db.facility + for i = 1, #fac.tank_ps_tbl do table.insert(tank_statuses, fac.tank_ps_tbl[i].get("computed_status")) end + local mtx_sps = fac.induction_ps_tbl[1] + local matrix_data = { + mtx_sps.get("eta_string"), + mtx_sps.get("avg_charge"), + mtx_sps.get("avg_inflow"), + mtx_sps.get("avg_outflow"), + mtx_sps.get("is_charging"), + mtx_sps.get("is_discharging"), + mtx_sps.get("at_max_io") + } + local data = { fac.all_sys_ok, fac.rtu_count, - { fac.auto_current_waste_product, fac.auto_pu_fallback_active }, fac.auto_scram, fac.ascram_status, tank_statuses, fac.tank_data_tbl, fac.induction_ps_tbl[1].get("computed_status") or types.IMATRIX_STATE.OFFLINE, fac.induction_data_tbl[1], + matrix_data, fac.sps_ps_tbl[1].get("computed_status") or types.SPS_STATE.OFFLINE, - fac.sps_data_tbl[1] + fac.sps_data_tbl[1], + units } _send(CRDN_TYPE.API_GET_FAC_DTL, data) diff --git a/pocket/iocontrol.lua b/pocket/iocontrol.lua index 75c3b5d..5378329 100644 --- a/pocket/iocontrol.lua +++ b/pocket/iocontrol.lua @@ -94,6 +94,7 @@ function iocontrol.init_core(pkt_comms, nav, cfg) -- API access ---@class pocket_ioctl_api io.api = { + get_fac = function () comms.api__get_facility() end, get_unit = function (unit) comms.api__get_unit(unit) end, get_ctrl = function () comms.api__get_control() end, get_proc = function () comms.api__get_process() end, diff --git a/pocket/iorx.lua b/pocket/iorx.lua index 528c2f4..76fcd9b 100644 --- a/pocket/iorx.lua +++ b/pocket/iorx.lua @@ -12,6 +12,8 @@ local ALARM_STATE = types.ALARM_STATE local BLR_STATE = types.BOILER_STATE local TRB_STATE = types.TURBINE_STATE local TNK_STATE = types.TANK_STATE +local MTX_STATE = types.IMATRIX_STATE +local SPS_STATE = types.SPS_STATE local io ---@type pocket_ioctl local iorx = {} ---@class iorx @@ -55,6 +57,11 @@ local function _record_multiblock_status(faulted, data, ps) ps.publish("formed", data.formed) ps.publish("faulted", faulted) + ---@todo revisit this + if data.build then + for key, val in pairs(data.build) do ps.publish(key, val) end + end + for key, val in pairs(data.state) do ps.publish(key, val) end for key, val in pairs(data.tanks) do ps.publish(key, val) end end @@ -647,12 +654,169 @@ function iorx.record_waste_data(data) fac.ps.publish("po_am_rate", fac.waste_stats[5]) fac.ps.publish("spent_waste_rate", fac.waste_stats[6]) - fac.ps.publish("sps_computed_status", f_data[8]) + fac.sps_ps_tbl[1].publish("SPSStateStatus", f_data[8]) fac.ps.publish("sps_process_rate", f_data[9]) end -function iorx.record_fac_detail_data(data) +-- update facility app with facility and unit data from API_GET_FAC_DTL +---@param data table +function iorx.record_fac_detail_data(data) + local fac = io.facility + + local tank_statuses = data[5] + local next_t_stat = 1 + + -- annunciator + + fac.all_sys_ok = data[1] + fac.rtu_count = data[2] + fac.auto_scram = data[3] + fac.ascram_status = data[4] + + fac.ps.publish("all_sys_ok", fac.all_sys_ok) + fac.ps.publish("rtu_count", fac.rtu_count) + fac.ps.publish("auto_scram", fac.auto_scram) + fac.ps.publish("as_matrix_fault", fac.ascram_status.matrix_fault) + fac.ps.publish("as_matrix_fill", fac.ascram_status.matrix_fill) + fac.ps.publish("as_crit_alarm", fac.ascram_status.crit_alarm) + fac.ps.publish("as_radiation", fac.ascram_status.radiation) + fac.ps.publish("as_gen_fault", fac.ascram_status.gen_fault) + + -- unit data + + local units = data[12] + + for i = 1, io.facility.num_units do + local unit = io.units[i] + local u_rx = units[i] + + unit.connected = u_rx[1] + unit.annunciator = u_rx[2] + unit.reactor_data = u_rx[3] + + local control_status = 1 + if unit.connected then + if unit.reactor_data.rps_tripped then control_status = 2 end + if unit.reactor_data.mek_status.status then + control_status = util.trinary(unit.annunciator.AutoControl, 4, 3) + end + end + + unit.unit_ps.publish("U_ControlStatus", control_status) + + unit.tank_data_tbl = u_rx[4] + + for id = 1, #unit.tank_data_tbl do + local tank = unit.tank_data_tbl[id] + local ps = unit.tank_ps_tbl[id] + local c_stat = tank_statuses[next_t_stat] + + local tank_status = 1 + + if c_stat ~= TNK_STATE.OFFLINE then + if c_stat == TNK_STATE.FAULT then + tank_status = 3 + elseif tank.formed then + tank_status = 4 + else + tank_status = 2 + end + end + + ps.publish("DynamicTankStatus", tank_status) + ps.publish("DynamicTankStateStatus", c_stat) + + next_t_stat = next_t_stat + 1 + end + end + + -- facility dynamic tank data + + fac.tank_data_tbl = data[6] + + for id = 1, #fac.tank_data_tbl do + local tank = fac.tank_data_tbl[id] + local ps = fac.tank_ps_tbl[id] + local c_stat = tank_statuses[next_t_stat] + + local tank_status = 1 + + if c_stat ~= TNK_STATE.OFFLINE then + if c_stat == TNK_STATE.FAULT then + tank_status = 3 + elseif tank.formed then + tank_status = 4 + else + tank_status = 2 + end + + _record_multiblock_status(c_stat == TNK_STATE.FAULT, tank, ps) + end + + ps.publish("DynamicTankStatus", tank_status) + ps.publish("DynamicTankStateStatus", c_stat) + + next_t_stat = next_t_stat + 1 + end + + -- induction matrix data + + fac.induction_data_tbl[1] = data[8] + + local matrix = fac.induction_data_tbl[1] + local m_ps = fac.induction_ps_tbl[1] + local m_stat = data[7] + + local mtx_status = 1 + + if m_stat ~= MTX_STATE.OFFLINE then + if m_stat == MTX_STATE.FAULT then + mtx_status = 3 + elseif matrix.formed then + mtx_status = 4 + else + mtx_status = 2 + end + + _record_multiblock_status(m_stat == MTX_STATE.FAULT, matrix, m_ps) + end + + m_ps.publish("InductionMatrixStatus", mtx_status) + m_ps.publish("InductionMatrixStateStatus", m_stat) + + m_ps.publish("eta_string", data[9][1]) + m_ps.publish("avg_charge", data[9][2]) + m_ps.publish("avg_inflow", data[9][3]) + m_ps.publish("avg_outflow", data[9][4]) + m_ps.publish("is_charging", data[9][5]) + m_ps.publish("is_discharging", data[9][6]) + m_ps.publish("at_max_io", data[9][7]) + + -- sps data + + fac.sps_data_tbl[1] = data[11] + + local sps = fac.sps_data_tbl[1] + local s_ps = fac.sps_ps_tbl[1] + local s_stat = data[10] + + local sps_status = 1 + + if s_stat ~= SPS_STATE.OFFLINE then + if s_stat == SPS_STATE.FAULT then + sps_status = 3 + elseif sps.formed then + sps_status = 4 + else + sps_status = 2 + end + + _record_multiblock_status(s_stat == SPS_STATE.FAULT, sps, s_ps) + end + + s_ps.publish("SPSStatus", sps_status) + s_ps.publish("SPSStateStatus", s_stat) end return function (io_obj) diff --git a/pocket/pocket.lua b/pocket/pocket.lua index d022ec1..511190c 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -554,6 +554,11 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) if self.sv.linked then _send_sv(MGMT_TYPE.DIAG_ALARM_SET, { id, state }) end end + -- coordinator get facility app data + function public.api__get_facility() + if self.api.linked then _send_api(CRDN_TYPE.API_GET_FAC_DTL, {}) end + end + -- coordinator get unit data function public.api__get_unit(unit) if self.api.linked then _send_api(CRDN_TYPE.API_GET_UNIT, { unit }) end @@ -730,6 +735,10 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) if _check_length(packet, 11) then iocontrol.rx.record_facility_data(packet.data) end + elseif packet.type == CRDN_TYPE.API_GET_FAC_DTL then + if _check_length(packet, 12) then + iocontrol.rx.record_fac_detail_data(packet.data) + end elseif packet.type == CRDN_TYPE.API_GET_UNIT then if _check_length(packet, 12) and type(packet.data[1]) == "number" and iocontrol.get_db().units[packet.data[1]] then iocontrol.rx.record_unit_data(packet.data) diff --git a/pocket/ui/apps/facility.lua b/pocket/ui/apps/facility.lua index 0b38c07..df86348 100644 --- a/pocket/ui/apps/facility.lua +++ b/pocket/ui/apps/facility.lua @@ -31,7 +31,6 @@ local cpair = core.cpair local APP_ID = pocket.APP_ID -local text_fg = style.text_fg local label_fg_bg = style.label local lu_col = style.label_unit_pair @@ -40,7 +39,6 @@ local mode_states = style.icon_states.mode_states local red_ind_s = style.icon_states.red_ind_s local yel_ind_s = style.icon_states.yel_ind_s local grn_ind_s = style.icon_states.grn_ind_s -local wht_ind_s = style.icon_states.wht_ind_s -- new unit page view ---@param root Container parent @@ -61,9 +59,6 @@ local function new_view(root) app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } }) - local btn_fg_bg = cpair(colors.orange, colors.black) - local btn_active = cpair(colors.white, colors.black) - local tank_page_navs = {} local page_div = nil ---@type Div|nil @@ -80,7 +75,7 @@ local function new_view(root) local last_update = 0 local function update() if util.time_ms() - last_update >= 500 then - -- db.api.get_fac() + db.api.get_fac() last_update = util.time_ms() end end @@ -96,19 +91,27 @@ local function new_view(root) TextBox{parent=f_div,y=1,text="Facility",alignment=ALIGN.CENTER} - TextBox{parent=f_div,y=3,text="Induction Matrix",alignment=ALIGN.CENTER} + local mtx_state = IconIndicator{parent=f_div,y=3,label="Matrix Status",states=basic_states} + local sps_state = IconIndicator{parent=f_div,label="SPS Status",states=basic_states} + mtx_state.register(fac.induction_ps_tbl[1], "InductionMatrixStatus", mtx_state.update) + sps_state.register(fac.sps_ps_tbl[1], "SPSStatus", sps_state.update) - local eta = TextBox{parent=f_div,x=1,y=5,text="ETA Unknown",alignment=ALIGN.CENTER,fg_bg=cpair(colors.white,colors.gray)} + TextBox{parent=f_div,y=6,text="RTU Gateways",fg_bg=label_fg_bg} + local rtu_count = DataIndicator{parent=f_div,x=19,y=6,label="",format="%3d",value=0,lu_colors=lu_col,width=3} + rtu_count.register(f_ps, "rtu_count", rtu_count.update) + + TextBox{parent=f_div,y=8,text="Induction Matrix",alignment=ALIGN.CENTER} + + local eta = TextBox{parent=f_div,x=1,y=10,text="ETA Unknown",alignment=ALIGN.CENTER,fg_bg=cpair(colors.white,colors.gray)} eta.register(fac.induction_ps_tbl[1], "eta_string", eta.set_value) - TextBox{parent=f_div,y=7,text="Unit Statuses",alignment=ALIGN.CENTER} + TextBox{parent=f_div,y=12,text="Unit Statuses",alignment=ALIGN.CENTER} f_div.line_break() for i = 1, fac.num_units do local ctrl = IconIndicator{parent=f_div,label="U"..i.." Control State",states=mode_states} ctrl.register(db.units[i].unit_ps, "U_ControlStatus", ctrl.update) - f_div.line_break(); end --#endregion @@ -129,8 +132,8 @@ local function new_view(root) local sps = IconIndicator{parent=a_div,label="SPS Connected",states=grn_ind_s} all_ok.register(f_ps, "all_sys_ok", all_ok.update) - -- ind_mat.register(fac.induction_ps_tbl[1], "computed_status", function (status) ind_mat.update(status > 1) end) - -- sps.register(fac.sps_ps_tbl[1], "computed_status", function (status) sps.update(status > 1) end) + ind_mat.register(fac.induction_ps_tbl[1], "InductionMatrixStateStatus", function (status) ind_mat.update(status > 1) end) + sps.register(fac.sps_ps_tbl[1], "SPSStateStatus", function (status) sps.update(status > 1) end) a_div.line_break() diff --git a/pocket/ui/apps/waste.lua b/pocket/ui/apps/waste.lua index 0be7dde..8037d82 100644 --- a/pocket/ui/apps/waste.lua +++ b/pocket/ui/apps/waste.lua @@ -247,7 +247,7 @@ local function new_view(root) local sps_status = StateIndicator{parent=s_div,x=5,y=3,states=style.sps.states,value=1,min_width=12} - sps_status.register(f_ps, "sps_computed_status", sps_status.update) + sps_status.register(db.facility.sps_ps_tbl[1], "SPSStateStatus", sps_status.update) TextBox{parent=s_div,y=5,text="Input Rate",width=10,fg_bg=label_fg_bg} local sps_in = DataIndicator{parent=s_div,label="",format="%16.2f",value=0,unit="mB/t",lu_colors=lu_col,width=21,fg_bg=text_fg} diff --git a/pocket/ui/pages/facility_matrix.lua b/pocket/ui/pages/facility_matrix.lua index a66f2a9..77640b1 100644 --- a/pocket/ui/pages/facility_matrix.lua +++ b/pocket/ui/pages/facility_matrix.lua @@ -1,6 +1,3 @@ -local types = require("scada-common.types") -local util = require("scada-common.util") - local iocontrol = require("pocket.iocontrol") local style = require("pocket.ui.style") @@ -25,17 +22,8 @@ local label = style.label local lu_col = style.label_unit_pair local text_fg = style.text_fg -local basic_states = style.icon_states.basic_states -local mode_states = style.icon_states.mode_states -local red_ind_s = style.icon_states.red_ind_s -local yel_ind_s = style.icon_states.yel_ind_s -local grn_ind_s = style.icon_states.grn_ind_s -local wht_ind_s = style.icon_states.wht_ind_s - -local mode_ind_s = { - { color = cpair(colors.black, colors.lightGray), symbol = "-" }, - { color = cpair(colors.black, colors.white), symbol = "+" } -} +local yel_ind_s = style.icon_states.yel_ind_s +local wht_ind_s = style.icon_states.wht_ind_s -- create an induction matrix view for the facility app ---@param app pocket_app @@ -75,12 +63,12 @@ return function (app, panes, matrix_pane, ps, update) in_bar.register(ps, "last_input", function (val) in_bar.update(calc_saturation(val)) end) out_bar.register(ps, "last_output", function (val) out_bar.update(calc_saturation(val)) end) - local energy = PowerIndicator{parent=mtx_div,x=1,y=11,lu_colors=lu_col,label="Chg: ",unit=db.energy_label,format="%8.2f",value=0,width=21,fg_bg=text_fg} - local avg_chg = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg: ",unit=db.energy_label,format="%8.2f",value=0,width=21,fg_bg=text_fg} - local input = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="In: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=21,fg_bg=text_fg} - local avg_in = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=21,fg_bg=text_fg} - local output = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="Out: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=21,fg_bg=text_fg} - local avg_out = PowerIndicator{parent=mtx_div,x=1,lu_colors=lu_col,label="\xb7Avg: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=21,fg_bg=text_fg} + local energy = PowerIndicator{parent=mtx_div,y=11,lu_colors=lu_col,label="Chg: ",unit=db.energy_label,format="%8.2f",value=0,width=21,fg_bg=text_fg} + local avg_chg = PowerIndicator{parent=mtx_div,lu_colors=lu_col,label="\xb7Avg: ",unit=db.energy_label,format="%8.2f",value=0,width=21,fg_bg=text_fg} + local input = PowerIndicator{parent=mtx_div,lu_colors=lu_col,label="In: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=21,fg_bg=text_fg} + local avg_in = PowerIndicator{parent=mtx_div,lu_colors=lu_col,label="\xb7Avg: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=21,fg_bg=text_fg} + local output = PowerIndicator{parent=mtx_div,lu_colors=lu_col,label="Out: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=21,fg_bg=text_fg} + local avg_out = PowerIndicator{parent=mtx_div,lu_colors=lu_col,label="\xb7Avg: ",unit=db.energy_label,format="%8.2f",rate=true,value=0,width=21,fg_bg=text_fg} energy.register(ps, "energy", function (val) energy.update(db.energy_convert(val)) end) avg_chg.register(ps, "avg_charge", avg_chg.update) @@ -122,7 +110,7 @@ return function (app, panes, matrix_pane, ps, update) out_util.register(ps, "last_output", function (x) out_util.update(calc_saturation(x) * 100) end) TextBox{parent=mtx_ext_div,text="Capacity ("..db.energy_label..")",x=1,y=13,fg_bg=label} - local capacity = DataIndicator{parent=mtx_ext_div,y=14,lu_colors=lu_col,label="",unit="",format="%21d",value=1000000000000,width=21,fg_bg=text_fg} + local capacity = DataIndicator{parent=mtx_ext_div,y=14,lu_colors=lu_col,label="",unit="",format="%21d",value=0,width=21,fg_bg=text_fg} TextBox{parent=mtx_ext_div,text="Max In/Out ("..db.energy_label.."/t)",x=1,y=15,fg_bg=label} local trans_cap = DataIndicator{parent=mtx_ext_div,y=16,lu_colors=lu_col,label="",unit="",format="%21d",rate=true,value=0,width=21,fg_bg=text_fg} diff --git a/pocket/ui/pages/facility_sps.lua b/pocket/ui/pages/facility_sps.lua index 3e3e25d..1de23ca 100644 --- a/pocket/ui/pages/facility_sps.lua +++ b/pocket/ui/pages/facility_sps.lua @@ -11,7 +11,6 @@ local PushButton = require("graphics.elements.controls.PushButton") local DataIndicator = require("graphics.elements.indicators.DataIndicator") local HorizontalBar = require("graphics.elements.indicators.HorizontalBar") -local PowerIndicator = require("graphics.elements.indicators.PowerIndicator") local StateIndicator = require("graphics.elements.indicators.StateIndicator") local ALIGN = core.ALIGN @@ -38,22 +37,19 @@ return function (app, panes, sps_pane, ps, update) TextBox{parent=sps_div,y=1,text="Facility SPS",alignment=ALIGN.CENTER} local status = StateIndicator{parent=sps_div,x=5,y=3,states=style.sps.states,value=1,min_width=12} - status.register(ps, "sps_computed_status", status.update) + status.register(ps, "SPSStateStatus", status.update) TextBox{parent=sps_div,text="Po",y=5,fg_bg=label} local po_bar = HorizontalBar{parent=sps_div,x=4,y=5,fg_bg=cpair(colors.cyan,colors.gray),height=1} TextBox{parent=sps_div,text="AM",y=7,fg_bg=label} local am_bar = HorizontalBar{parent=sps_div,x=4,y=7,fg_bg=cpair(colors.purple,colors.gray),height=1} - TextBox{parent=sps_div,text="En",y=9,fg_bg=label} - local energy_bar = HorizontalBar{parent=sps_div,x=4,y=9,fg_bg=cpair(colors.green,colors.gray),height=1} po_bar.register(ps, "input_fill", po_bar.update) am_bar.register(ps, "output_fill", am_bar.update) - energy_bar.register(ps, "energy_fill", energy_bar.update) - TextBox{parent=sps_div,y=11,text="Input Rate",width=10,fg_bg=label} + TextBox{parent=sps_div,y=9,text="Input Rate",width=10,fg_bg=label} local input_rate = DataIndicator{parent=sps_div,label="",format="%16.2f",value=0,unit="mB/t",lu_colors=lu_col,width=21,fg_bg=text_fg} - TextBox{parent=sps_div,y=14,text="Production Rate",width=15,fg_bg=label} + TextBox{parent=sps_div,y=12,text="Production Rate",width=15,fg_bg=label} local proc_rate = DataIndicator{parent=sps_div,label="",format="%16d",value=0,unit="\xb5B/t",lu_colors=lu_col,width=21,fg_bg=text_fg} proc_rate.register(ps, "process_rate", function (r) proc_rate.update(r * 1000) end) @@ -84,12 +80,5 @@ return function (app, panes, sps_pane, ps, update) output_p.register(ps, "output_fill", function (x) output_p.update(x * 100) end) output_amnt.register(ps, "output", function (x) output_amnt.update(x.amount) end) - TextBox{parent=sps_ext_div,text="Energy Fill",x=1,y=9,width=11,fg_bg=label} - local energy_p = DataIndicator{parent=sps_ext_div,x=14,y=9,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} - local energy_amnt = PowerIndicator{parent=sps_ext_div,x=1,y=10,lu_colors=lu_col,label="",unit=db.energy_label,format="%17.4f",value=0,width=21,fg_bg=text_fg} - - energy_p.register(ps, "energy_fill", function (x) energy_p.update(x * 100) end) - energy_amnt.register(ps, "energy", function (val) energy_amnt.update(db.energy_convert(val)) end) - return sps_page.nav_to end From afd6800be65249aa13883436674da4da40f67c14 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Mon, 20 Jan 2025 15:40:00 -0500 Subject: [PATCH 25/29] updated pocket version --- pocket/startup.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pocket/startup.lua b/pocket/startup.lua index b4e1a9b..636c6ef 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.13-alpha" +local POCKET_VERSION = "v0.13.0-beta" local println = util.println local println_ts = util.println_ts From fbebc2a02127dee264ca93305d5eea3b68df79b7 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Mon, 20 Jan 2025 16:24:18 -0500 Subject: [PATCH 26/29] prep for beta --- pocket/pocket.lua | 4 ++-- pocket/ui/main.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pocket/pocket.lua b/pocket/pocket.lua index 511190c..7bfe669 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -913,7 +913,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) local ready = packet.data[1] local states = packet.data[2] - diag.tone_test.ready_warn.set_value(util.trinary(ready, "", "system not ready")) + diag.tone_test.ready_warn.set_value(util.trinary(ready, "", "system not idle")) for i = 1, #states do if diag.tone_test.tone_buttons[i] ~= nil then @@ -932,7 +932,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) local ready = packet.data[1] local states = packet.data[2] - diag.tone_test.ready_warn.set_value(util.trinary(ready, "", "system not ready")) + diag.tone_test.ready_warn.set_value(util.trinary(ready, "", "system not idle")) for i = 1, #states do if diag.tone_test.alarm_buttons[i] ~= nil then diff --git a/pocket/ui/main.lua b/pocket/ui/main.lua index 6a70737..588cf0b 100644 --- a/pocket/ui/main.lua +++ b/pocket/ui/main.lua @@ -46,7 +46,7 @@ local function init(main) local db = iocontrol.get_db() -- window header message and connection status - TextBox{parent=main,y=1,text="EARLY ACCESS ALPHA S C ",fg_bg=style.header} + TextBox{parent=main,y=1,text=" S C ",fg_bg=style.header} local svr_conn = SignalBar{parent=main,y=1,x=22,compact=true,colors_low_med=cpair(colors.red,colors.yellow),disconnect_color=colors.lightGray,fg_bg=cpair(colors.green,colors.gray)} local crd_conn = SignalBar{parent=main,y=1,x=26,compact=true,colors_low_med=cpair(colors.red,colors.yellow),disconnect_color=colors.lightGray,fg_bg=cpair(colors.green,colors.gray)} From 3767c0f8d917ca14e6c75a2c586dfb878fe4a827 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Mon, 20 Jan 2025 16:26:41 -0500 Subject: [PATCH 27/29] luacheck fixes and coordinator version bump --- coordinator/startup.lua | 2 +- pocket/ui/apps/facility.lua | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/coordinator/startup.lua b/coordinator/startup.lua index 1ba0a81..d3413e3 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.6.3" +local COORDINATOR_VERSION = "v1.6.4" local CHUNK_LOAD_DELAY_S = 30.0 diff --git a/pocket/ui/apps/facility.lua b/pocket/ui/apps/facility.lua index df86348..65b25e3 100644 --- a/pocket/ui/apps/facility.lua +++ b/pocket/ui/apps/facility.lua @@ -16,15 +16,13 @@ local induction_mtx = require("pocket.ui.pages.facility_matrix") local core = require("graphics.core") local Div = require("graphics.elements.Div") -local ListBox = require("graphics.elements.ListBox") local MultiPane = require("graphics.elements.MultiPane") local TextBox = require("graphics.elements.TextBox") -local WaitingAnim = require("graphics.elements.animations.Waiting") +local WaitingAnim = require("graphics.elements.animations.Waiting") -local DataIndicator = require("graphics.elements.indicators.DataIndicator") -local IconIndicator = require("graphics.elements.indicators.IconIndicator") -local StateIndicator = require("graphics.elements.indicators.StateIndicator") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local IconIndicator = require("graphics.elements.indicators.IconIndicator") local ALIGN = core.ALIGN local cpair = core.cpair From c859c229640e7bd92e3c632ca9c4a35ed0d651b9 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Mon, 20 Jan 2025 17:01:49 -0500 Subject: [PATCH 28/29] cleanup --- coordinator/session/pocket.lua | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/coordinator/session/pocket.lua b/coordinator/session/pocket.lua index 6a901ac..a12870a 100644 --- a/coordinator/session/pocket.lua +++ b/coordinator/session/pocket.lua @@ -266,23 +266,20 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout) _send(CRDN_TYPE.API_GET_FAC, data) elseif pkt.type == CRDN_TYPE.API_GET_FAC_DTL then - local units = {} + local fac = db.facility + local mtx_sps = fac.induction_ps_tbl[1] + local units = {} local tank_statuses = {} for i = 1, #db.units do local u = db.units[i] - units[i] = { u.connected, u.annunciator, u.reactor_data, u.tank_data_tbl } - for t = 1, #u.tank_ps_tbl do table.insert(tank_statuses, u.tank_ps_tbl[t].get("computed_status")) end end - local fac = db.facility - for i = 1, #fac.tank_ps_tbl do table.insert(tank_statuses, fac.tank_ps_tbl[i].get("computed_status")) end - local mtx_sps = fac.induction_ps_tbl[1] local matrix_data = { mtx_sps.get("eta_string"), mtx_sps.get("avg_charge"), From 869e67710fdcca89838eca178bfce607747196fb Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sun, 26 Jan 2025 14:49:44 -0500 Subject: [PATCH 29/29] #559 supervisor bugfix --- supervisor/session/rtu/turbinev.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/supervisor/session/rtu/turbinev.lua b/supervisor/session/rtu/turbinev.lua index 7023021..fa9fb6a 100644 --- a/supervisor/session/rtu/turbinev.lua +++ b/supervisor/session/rtu/turbinev.lua @@ -189,7 +189,7 @@ function turbinev.new(session_id, unit_id, advert, out_queue) local function _request_tanks(time_now) -- read input registers 20 through 25 (start = 20, count = 6) if self.session.send_request(TXN_TYPES.TANKS, MODBUS_FCODE.READ_INPUT_REGS, { 20, 6 }) ~= false then - self.periodic.next_tanks_req = time_now + PERIODICS.TANKS + self.periodics.next_tanks_req = time_now + PERIODICS.TANKS end end