From 4fb39213f22542a0c536b79e1fb5c5d8d5d6ec07 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Tue, 1 Jul 2025 14:41:09 +0000 Subject: [PATCH 01/45] #401 supervisor support of pocket computer list app --- scada-common/comms.lua | 9 ++++---- supervisor/session/pocket.lua | 36 ++++++++++++++++++++++++++++++- supervisor/session/svsessions.lua | 11 +++++----- supervisor/startup.lua | 2 +- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/scada-common/comms.lua b/scada-common/comms.lua index 2f3ef71..18f2d48 100644 --- a/scada-common/comms.lua +++ b/scada-common/comms.lua @@ -17,7 +17,7 @@ local max_distance = nil local comms = {} -- protocol/data versions (protocol/data independent changes tracked by util.lua version) -comms.version = "3.0.7" +comms.version = "3.0.8" comms.api_version = "0.0.10" ---@enum PROTOCOL @@ -52,9 +52,10 @@ local MGMT_TYPE = { RTU_ADVERT = 3, -- RTU capability advertisement RTU_DEV_REMOUNT = 4, -- RTU multiblock possbily changed (formed, unformed) due to PPM remount RTU_TONE_ALARM = 5, -- instruct RTUs to play specified alarm tones - DIAG_TONE_GET = 6, -- diagnostic: get alarm tones - DIAG_TONE_SET = 7, -- diagnostic: set alarm tones - DIAG_ALARM_SET = 8 -- diagnostic: set alarm to simulate audio for + DIAG_TONE_GET = 6, -- (API) diagnostic: get alarm tones + DIAG_TONE_SET = 7, -- (API) diagnostic: set alarm tones + DIAG_ALARM_SET = 8, -- (API) diagnostic: set alarm to simulate audio for + INFO_LIST_CMP = 9 -- (API) info: list all computers on the network } ---@enum CRDN_TYPE diff --git a/supervisor/session/pocket.lua b/supervisor/session/pocket.lua index fc7098e..b229286 100644 --- a/supervisor/session/pocket.lua +++ b/supervisor/session/pocket.lua @@ -6,6 +6,7 @@ local databus = require("supervisor.databus") local pocket = {} +local DEV_TYPE = comms.DEVICE_TYPE local PROTOCOL = comms.PROTOCOL local MGMT_TYPE = comms.MGMT_TYPE @@ -34,9 +35,10 @@ local PERIODICS = { ---@param in_queue mqueue in message queue ---@param out_queue mqueue out message queue ---@param timeout number communications timeout +---@param sessions svsessions_list list of computer sessions, read-only ---@param facility facility facility data table ---@param fp_ok boolean if the front panel UI is running -function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, facility, fp_ok) +function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, sessions, facility, fp_ok) -- print a log message to the terminal as long as the UI isn't running local function println(message) if not fp_ok then util.println_ts(message) end end @@ -182,6 +184,38 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, end if not valid then _send_mgmt(MGMT_TYPE.DIAG_ALARM_SET, { false }) end + elseif pkt.type == MGMT_TYPE.INFO_LIST_CMP then + local read = databus.ps.get + +---@diagnostic disable-next-line: undefined-field + local devices = { { DEV_TYPE.SVR, os.getComputerID(), read("version"), 0 } } + + -- add the coordinator if connected + if read("crd_conn") then + table.insert(devices, { DEV_TYPE.CRD, read("crd_addr"), read("crd_fw"), databus.read("crd_rtt") }) + end + + -- add the PLCs if connected + for i = 1, #facility.get_units() do + local tag = "plc_" .. i + if read(tag .. "_conn") then + table.insert(devices, { DEV_TYPE.CRD, read(tag .. "_addr"), read(tag .. "_fw"), read(tag .. "_rtt") }) + end + end + + -- add connected RTUs + for i = 1, #sessions.rtu do + local s = sessions.rtu[i] + table.insert(devices, { DEV_TYPE.RTU, s.s_addr, s.version, read(s.instance.get_id() .. "_rtt") }) + end + + -- add connected pocket computers + for i = 1, #sessions.pdg do + local s = sessions.pdg[i] + table.insert(devices, { DEV_TYPE.PKT, s.s_addr, s.version, read(s.instance.get_id() .. "_rtt") }) + end + + _send_mgmt(MGMT_TYPE.INFO_LIST_CMP, devices) else log.debug(log_tag .. "handler received unsupported SCADA_MGMT packet type " .. pkt.type) end diff --git a/supervisor/session/svsessions.lua b/supervisor/session/svsessions.lua index 087fe19..cb37881 100644 --- a/supervisor/session/svsessions.lua +++ b/supervisor/session/svsessions.lua @@ -47,12 +47,13 @@ local self = { facility = nil, ---@type facility|nil plc_ini_reset = {}, -- lists of connected sessions + ---@class svsessions_list ---@diagnostic disable: missing-fields sessions = { - rtu = {}, ---@type rtu_session_struct - plc = {}, ---@type plc_session_struct - crd = {}, ---@type crd_session_struct - pdg = {} ---@type pdg_session_struct + rtu = {}, ---@type rtu_session_struct[] + plc = {}, ---@type plc_session_struct[] + crd = {}, ---@type crd_session_struct[] + pdg = {} ---@type pdg_session_struct[] }, ---@diagnostic enable: missing-fields -- next session IDs @@ -621,7 +622,7 @@ function svsessions.establish_pdg_session(source_addr, i_seq_num, version) local id = self.next_ids.pdg - pdg_s.instance = pocket.new_session(id, source_addr, i_seq_num, pdg_s.in_queue, pdg_s.out_queue, self.config.PKT_Timeout, self.facility, self.fp_ok) + pdg_s.instance = pocket.new_session(id, source_addr, i_seq_num, pdg_s.in_queue, pdg_s.out_queue, self.config.PKT_Timeout, self.sessions, self.facility, self.fp_ok) table.insert(self.sessions.pdg, pdg_s) local mt = { diff --git a/supervisor/startup.lua b/supervisor/startup.lua index 4a88018..fe49bec 100644 --- a/supervisor/startup.lua +++ b/supervisor/startup.lua @@ -23,7 +23,7 @@ local supervisor = require("supervisor.supervisor") local svsessions = require("supervisor.session.svsessions") -local SUPERVISOR_VERSION = "v1.7.0" +local SUPERVISOR_VERSION = "v1.7.1" local println = util.println local println_ts = util.println_ts From 0bfe767710af8c128106e576b95d3fd6bf39b7ef Mon Sep 17 00:00:00 2001 From: Mikayla Date: Fri, 1 Aug 2025 21:41:40 +0000 Subject: [PATCH 02/45] #401 pocket handling of computer data --- pocket/iocontrol.lua | 7 +++++-- pocket/iorx.lua | 46 ++++++++++++++++++++++++++++++++++++++++++++ pocket/pocket.lua | 5 +++++ pocket/startup.lua | 2 +- 4 files changed, 57 insertions(+), 3 deletions(-) diff --git a/pocket/iocontrol.lua b/pocket/iocontrol.lua index fe2955c..b559fb0 100644 --- a/pocket/iocontrol.lua +++ b/pocket/iocontrol.lua @@ -35,8 +35,8 @@ iocontrol.LINK_STATE = LINK_STATE ---@class pocket_ioctl local io = { - version = "unknown", - ps = psil.create() + version = "unknown", -- pocket version + ps = psil.create() -- pocket PSIL } local config = nil ---@type pkt_config @@ -91,6 +91,9 @@ function iocontrol.init_core(pkt_comms, nav, cfg) tone_indicators = {} ---@type IndicatorLight[] indicators to update from supervisor tone states } + -- computer list + io.diag.get_comps = function () comms.diag__get_computers() end + -- API access ---@class pocket_ioctl_api io.api = { diff --git a/pocket/iorx.lua b/pocket/iorx.lua index aea9699..ff72c7d 100644 --- a/pocket/iorx.lua +++ b/pocket/iorx.lua @@ -871,6 +871,52 @@ function iorx.record_radiation_data(data) fac.ps.publish("radiation_monitors", textutils.serialize(connected)) end +local comp_record = {} + +-- update the computers app with the network data from INFO_LIST_CMP +---@param data table +function iorx.record_network_data(data) + local ps = io.facility.ps + local connected = {} + + -- add/update connected computers + for i = 1, #data do + local entry = data[i] + local id = entry[2] + local pfx = "comp_" .. id + + connected[id] = true + + ps.publish(pfx .. "_type", entry[1]) + ps.publish(pfx .. "_addr", id) + ps.publish(pfx .. "_fw", entry[3]) + ps.publish(pfx .. "_rtt", entry[4]) + + if not comp_record[id] then + comp_record[id] = true + + -- trigger the app to create the new element + ps.publish("comp_connect", id) + end + end + + -- reset the published value + ps.publish("comp_connect", false) + + -- remove disconnected computers + for id, state in pairs(comp_record) do + if state and not connected[id] then + comp_record[id] = false + + -- trigger the app to delete the element + ps.publish("comp_disconnect", id) + end + end + + -- reset the published value + ps.publish("comp_disconnect", false) +end + return function (io_obj) io = io_obj return iorx diff --git a/pocket/pocket.lua b/pocket/pocket.lua index cfa435a..72ef137 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -558,6 +558,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 + -- supervisor get connected computers + function public.diag__get_computers() + if self.sv.linked then _send_sv(MGMT_TYPE.INFO_LIST_CMP, {}) 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 diff --git a/pocket/startup.lua b/pocket/startup.lua index b2f7874..3b53d2c 100644 --- a/pocket/startup.lua +++ b/pocket/startup.lua @@ -22,7 +22,7 @@ local pocket = require("pocket.pocket") local renderer = require("pocket.renderer") local threads = require("pocket.threads") -local POCKET_VERSION = "v0.13.5-beta" +local POCKET_VERSION = "v0.13.6-beta" local println = util.println local println_ts = util.println_ts From 1ce0bbfc65ecf7244e789ee3fe82d41c5604d69d Mon Sep 17 00:00:00 2001 From: Mikayla Date: Fri, 1 Aug 2025 21:43:19 +0000 Subject: [PATCH 03/45] #401 work on pocket computer list app --- pocket/pocket.lua | 7 +- pocket/ui/apps/comps.lua | 187 ++++++++++++++++++++++++++++++++++ pocket/ui/main.lua | 2 + pocket/ui/pages/home_page.lua | 5 +- 4 files changed, 196 insertions(+), 5 deletions(-) create mode 100644 pocket/ui/apps/comps.lua diff --git a/pocket/pocket.lua b/pocket/pocket.lua index 72ef137..4bbd051 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -99,9 +99,10 @@ local APP_ID = { RADMON = 10, -- diagnostic app pages ALARMS = 11, + COMPS = 12, -- other - DUMMY = 12, - NUM_APPS = 12 + DUMMY = 13, + NUM_APPS = 13 } pocket.APP_ID = APP_ID @@ -960,6 +961,8 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) else log.debug("supervisor SCADA diag alarm set packet length/type mismatch") end + elseif packet.type == MGMT_TYPE.INFO_LIST_CMP then + iocontrol.rx.record_network_data(packet.data) else _fail_type(packet) end elseif packet.type == MGMT_TYPE.ESTABLISH then -- connection with supervisor established diff --git a/pocket/ui/apps/comps.lua b/pocket/ui/apps/comps.lua new file mode 100644 index 0000000..8e0c595 --- /dev/null +++ b/pocket/ui/apps/comps.lua @@ -0,0 +1,187 @@ +-- +-- Computer List App +-- + +local util = require("scada-common.util") + +local iocontrol = require("pocket.iocontrol") +local pocket = require("pocket.pocket") + +local style = require("pocket.ui.style") + +local core = require("graphics.core") + +local Div = require("graphics.elements.Div") +local ListBox = require("graphics.elements.ListBox") +local MultiPane = require("graphics.elements.MultiPane") +local Rectangle = require("graphics.elements.Rectangle") +local TextBox = require("graphics.elements.TextBox") + +local WaitingAnim = require("graphics.elements.animations.Waiting") + +local RadIndicator = require("graphics.elements.indicators.RadIndicator") + +local ALIGN = core.ALIGN +local cpair = core.cpair +local border = core.border + +local APP_ID = pocket.APP_ID + +local label_fg_bg = style.label +local lu_col = style.label_unit_pair + +-- new computer list page view +---@param root Container parent +local function new_view(root) + local db = iocontrol.get_db() + + local frame = Div{parent=root,x=1,y=1} + + local app = db.nav.register_app(APP_ID.COMPS, frame, nil, true, false) + + 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 page_div = nil ---@type Div|nil + + -- load the app (create the elements) + local function load() + local f_ps = db.facility.ps + + page_div = Div{parent=main,y=2,width=main.get_width()} + + local panes = {} ---@type Div[] + + -- create all page divs + for _ = 1, 3 do + local div = Div{parent=page_div} + table.insert(panes, div) + end + + local last_update = 0 + -- refresh data callback, every 500ms it will re-send the query + local function update() + if util.time_ms() - last_update >= 500 then + db.diag.get_comps() + last_update = util.time_ms() + end + end + + -- create a new radiation monitor list + ---@param parent Container + ---@param ps psil + local function new_mon_list(parent, ps) + local mon_list = ListBox{parent=parent,y=6,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} + + local elem_list = {} ---@type graphics_element[] + + mon_list.register(ps, "radiation_monitors", function (data) + local ids = textutils.unserialize(data) + + -- delete any disconnected monitors + for id, elem in pairs(elem_list) do + if not util.table_contains(ids, id) then + elem.delete() + elem_list[id] = nil + end + end + + -- add newly connected monitors + for _, id in pairs(ids) do + if not elem_list[id] then + elem_list[id] = Div{parent=mon_list,height=5} + local mon_rect = Rectangle{parent=elem_list[id],height=4,x=2,width=20,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} + + TextBox{parent=mon_rect,text="Env. Detector "..id} + local mon_rad = RadIndicator{parent=mon_rect,x=2,label="",format="%13.3f",lu_colors=cpair(colors.gray,colors.gray),width=18} + mon_rad.register(ps, "radiation@" .. id, mon_rad.update) + end + end + end) + end + + --#region overview page + + local m_pane = panes[1] + local m_div = Div{parent=m_pane,x=2,width=main.get_width()-2} + + local main_page = app.new_page(nil, 1) + main_page.tasks = { update } + + TextBox{parent=m_div,y=1,text="Connected Computers",alignment=ALIGN.CENTER} + + TextBox{parent=m_div,y=3,text="Networked Computers",fg_bg=label_fg_bg} + local s_f_rad = RadIndicator{parent=m_div,label="",format="%17.3f",lu_colors=lu_col,width=21} + s_f_rad.register(f_ps, "radiation", s_f_rad.update) + + --#endregion + + --#region overview page + + local f_pane = panes[db.facility.num_units + 2] + local f_div = Div{parent=f_pane,width=main.get_width()} + + local fac_page = app.new_page(nil, db.facility.num_units + 2) + fac_page.tasks = { update } + + TextBox{parent=f_div,y=1,text="Facility Monitors",alignment=ALIGN.CENTER} + + TextBox{parent=f_div,x=2,y=3,text="Max Radiation",fg_bg=label_fg_bg} + local f_rad = RadIndicator{parent=f_div,x=2,label="",format="%17.3f",lu_colors=lu_col,width=21} + f_rad.register(f_ps, "radiation", f_rad.update) + + new_mon_list(f_div, f_ps) + + --#endregion + + -- setup multipane + local u_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes} + app.set_root_pane(u_pane) + + -- setup sidebar + + local list = { + { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home }, + { label = " \x1e ", color = core.cpair(colors.black, colors.blue), callback = stat_page.nav_to }, + { label = "FAC", color = core.cpair(colors.black, colors.yellow), callback = fac_page.nav_to } + } + + for i = 1, db.facility.num_units do + table.insert(list, { label = "U-" .. i, color = core.cpair(colors.black, colors.lightGray), callback = function () app.switcher(i) end }) + end + + app.set_sidebar(list) + + -- done, show the app + stat_page.nav_to() + 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/main.lua b/pocket/ui/main.lua index e033777..4ea44e1 100644 --- a/pocket/ui/main.lua +++ b/pocket/ui/main.lua @@ -7,6 +7,7 @@ local util = require("scada-common.util") local iocontrol = require("pocket.iocontrol") local pocket = require("pocket.pocket") +local comps_app = require("pocket.ui.apps.comps") 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") @@ -76,6 +77,7 @@ local function init(main) loader_app(page_div) sys_apps(page_div) diag_apps(page_div) + comps_app(page_div) dummy_app(page_div) -- verify all apps were created diff --git a/pocket/ui/pages/home_page.lua b/pocket/ui/pages/home_page.lua index 80fdd3f..900e6e8 100644 --- a/pocket/ui/pages/home_page.lua +++ b/pocket/ui/pages/home_page.lua @@ -59,9 +59,8 @@ local function new_view(root) TextBox{parent=apps_3,text="Diagnostic Apps",x=1,y=2,alignment=ALIGN.CENTER} - App{parent=apps_3,x=2,y=4,text="\x0f",title="Alarm",callback=function()open(APP_ID.ALARMS)end,app_fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=active_fg_bg} - App{parent=apps_3,x=9,y=4,text="@",title="Comps",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.orange),active_fg_bg=active_fg_bg} - App{parent=apps_3,x=16,y=4,text="R",title="RS Test",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.red),active_fg_bg=active_fg_bg} + App{parent=apps_3,x=2,y=4,text="\x0f",title="Alarm",callback=function()open(APP_ID.ALARMS)end,app_fg_bg=cpair(colors.black,colors.red),active_fg_bg=active_fg_bg} + App{parent=apps_3,x=9,y=4,text="@",title="Comps",callback=function()open(APP_ID.COMPS)end,app_fg_bg=cpair(colors.black,colors.orange),active_fg_bg=active_fg_bg} return main end From f4d4de659c5dc084482ebbfcc7ce3a529798f69d Mon Sep 17 00:00:00 2001 From: Mikayla Date: Tue, 5 Aug 2025 13:35:29 +0000 Subject: [PATCH 04/45] #401 supervisor and coordinator computer display --- pocket/iorx.lua | 42 ++++++++++++++++++++----- pocket/ui/apps/comps.lua | 68 +++++++++++++++++++++++++++++++++++++--- supervisor/databus.lua | 1 + 3 files changed, 98 insertions(+), 13 deletions(-) diff --git a/pocket/iorx.lua b/pocket/iorx.lua index ff72c7d..e503f6f 100644 --- a/pocket/iorx.lua +++ b/pocket/iorx.lua @@ -2,10 +2,13 @@ -- I/O Control's Data Receive (Rx) Handlers -- +local comms = require("scada-common.comms") local const = require("scada-common.constants") local types = require("scada-common.types") local util = require("scada-common.util") +local DEV_TYPE = comms.DEVICE_TYPE + local ALARM = types.ALARM local ALARM_STATE = types.ALARM_STATE @@ -878,28 +881,51 @@ local comp_record = {} function iorx.record_network_data(data) local ps = io.facility.ps local connected = {} + local crd_online = false + + ps.publish("comp_online", #data) -- add/update connected computers for i = 1, #data do local entry = data[i] + local type = entry[1] local id = entry[2] local pfx = "comp_" .. id connected[id] = true - ps.publish(pfx .. "_type", entry[1]) - ps.publish(pfx .. "_addr", id) - ps.publish(pfx .. "_fw", entry[3]) - ps.publish(pfx .. "_rtt", entry[4]) + if type == DEV_TYPE.SVR then + ps.publish("comp_svr_addr", id) + ps.publish("comp_svr_fw", entry[3]) + elseif type == DEV_TYPE.CRD then + crd_online = true + ps.publish("comp_crd_addr", id) + ps.publish("comp_crd_fw", entry[3]) + ps.publish("comp_crd_rtt", entry[4]) + else + ps.publish(pfx .. "_type", entry[1]) + ps.publish(pfx .. "_addr", id) + ps.publish(pfx .. "_fw", entry[3]) + ps.publish(pfx .. "_rtt", entry[4]) - if not comp_record[id] then - comp_record[id] = true + if not comp_record[id] then + comp_record[id] = true - -- trigger the app to create the new element - ps.publish("comp_connect", id) + -- trigger the app to create the new element + ps.publish("comp_connect", id) + end end end + -- handle the coordinator being online or not + -- no need to worry about the supervisor since this data is from the supervisor, so it has to be 'online' if received + ps.publish("comp_crd_online", crd_online) + if not crd_online then + ps.publish("comp_crd_addr", "---") + ps.publish("comp_crd_fw", "---") + ps.publish("comp_crd_rtt", "---") + end + -- reset the published value ps.publish("comp_connect", false) diff --git a/pocket/ui/apps/comps.lua b/pocket/ui/apps/comps.lua index 8e0c595..4b68d69 100644 --- a/pocket/ui/apps/comps.lua +++ b/pocket/ui/apps/comps.lua @@ -19,7 +19,7 @@ local TextBox = require("graphics.elements.TextBox") local WaitingAnim = require("graphics.elements.animations.Waiting") -local RadIndicator = require("graphics.elements.indicators.RadIndicator") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") local ALIGN = core.ALIGN local cpair = core.cpair @@ -30,6 +30,11 @@ local APP_ID = pocket.APP_ID local label_fg_bg = style.label local lu_col = style.label_unit_pair +-- nominal RTT is ping (0ms to 10ms usually) + 150ms for SV main loop tick +-- ensure in sync with supervisor databus file +local WARN_RTT = 300 -- 2x as long as expected w/ 0 ping +local HIGH_RTT = 500 -- 3.33x as long as expected w/ 0 ping + -- new computer list page view ---@param root Container parent local function new_view(root) @@ -107,7 +112,7 @@ local function new_view(root) end) end - --#region overview page + --#region main computer page local m_pane = panes[1] local m_div = Div{parent=m_pane,x=2,width=main.get_width()-2} @@ -117,9 +122,62 @@ local function new_view(root) TextBox{parent=m_div,y=1,text="Connected Computers",alignment=ALIGN.CENTER} - TextBox{parent=m_div,y=3,text="Networked Computers",fg_bg=label_fg_bg} - local s_f_rad = RadIndicator{parent=m_div,label="",format="%17.3f",lu_colors=lu_col,width=21} - s_f_rad.register(f_ps, "radiation", s_f_rad.update) + local conns = DataIndicator{parent=m_div,x=10,y=3,lu_colors=lu_col,label="Online",unit="",format="%3d",value=0,commas=true,width=21} + conns.register(f_ps, "comp_online", conns.update) + + local svr_div = Div{parent=m_div,y=5,height=5} + local svr_rect = Rectangle{parent=svr_div,height=5,x=2,width=21,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} + + TextBox{parent=svr_rect,text="Supervisor"} + TextBox{parent=svr_rect,x=12,y=1,width=6,text="Online",fg_bg=cpair(colors.green,colors._INHERIT)} + TextBox{parent=svr_rect,text="Computer ID",fg_bg=label_fg_bg} + TextBox{parent=svr_rect,text="Firmware",fg_bg=label_fg_bg} + local svr_addr = TextBox{parent=svr_rect,x=13,y=2,text="---"} + local svr_fw = TextBox{parent=svr_rect,x=13,y=3,text="---"} + + svr_addr.register(f_ps, "comp_svr_addr", svr_addr.set_value) + svr_fw.register(f_ps, "comp_svr_fw", svr_fw.set_value) + + local crd_div = Div{parent=m_div,y=5,height=5} + local crd_rect = Rectangle{parent=crd_div,height=6,x=2,width=21,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} + + TextBox{parent=crd_rect,text="Coordinator"} + local crd_online = TextBox{parent=svr_rect,x=12,y=1,width=7,text="Online",fg_bg=cpair(colors.green,colors._INHERIT)} + TextBox{parent=crd_rect,text="Computer ID",fg_bg=label_fg_bg} + TextBox{parent=crd_rect,text="Firmware",fg_bg=label_fg_bg} + TextBox{parent=crd_rect,text="Round-Trip Time",fg_bg=label_fg_bg} + local crd_addr = TextBox{parent=svr_rect,x=13,y=2,text="---"} + local crd_fw = TextBox{parent=svr_rect,x=13,y=3,text="---"} + local crd_rtt = TextBox{parent=svr_rect,x=13,y=3,text="---"} + + crd_addr.register(f_ps, "comp_crd_addr", crd_addr.set_value) + crd_fw.register(f_ps, "comp_crd_fw", crd_fw.set_value) + + crd_online.register(f_ps, "comp_crd_online", function (online) + if online then + crd_online.set_value("Online") + crd_online.recolor(colors.green) + else + crd_online.set_value("Off-line") + crd_online.recolor(colors.red) + end + end) + + crd_rtt.register(f_ps, "comp_crd_rtt", function (rtt) + crd_rtt.set_value(rtt) + + if type(rtt) ~= "number" then + crd_rtt.recolor(label_fg_bg.fgd) + else + if rtt > HIGH_RTT then + crd_rtt.recolor(colors.red) + elseif rtt > WARN_RTT then + crd_rtt.recolor(colors.yellow) + else + crd_rtt.recolor(colors.green) + end + end + end) --#endregion diff --git a/supervisor/databus.lua b/supervisor/databus.lua index f5daefb..eef99e7 100644 --- a/supervisor/databus.lua +++ b/supervisor/databus.lua @@ -8,6 +8,7 @@ local util = require("scada-common.util") local pgi = require("supervisor.panel.pgi") -- nominal RTT is ping (0ms to 10ms usually) + 150ms for SV main loop tick +-- ensure in sync with pocket computer list app local WARN_RTT = 300 -- 2x as long as expected w/ 0 ping local HIGH_RTT = 500 -- 3.33x as long as expected w/ 0 ping From f3eb6d0464535c5b6b56960f1fe6577b375865c5 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Wed, 6 Aug 2025 15:56:06 +0000 Subject: [PATCH 05/45] #401 PLC, RTU, PKT computer lists --- pocket/iorx.lua | 4 + pocket/ui/apps/comps.lua | 169 +++++++++++++++++++++------------- supervisor/session/pocket.lua | 2 +- 3 files changed, 112 insertions(+), 63 deletions(-) diff --git a/pocket/iorx.lua b/pocket/iorx.lua index e503f6f..3ea69c1 100644 --- a/pocket/iorx.lua +++ b/pocket/iorx.lua @@ -908,6 +908,10 @@ function iorx.record_network_data(data) ps.publish(pfx .. "_fw", entry[3]) ps.publish(pfx .. "_rtt", entry[4]) + if type == DEV_TYPE.PLC then + ps.publish(pfx .. "_unit", entry[5]) + end + if not comp_record[id] then comp_record[id] = true diff --git a/pocket/ui/apps/comps.lua b/pocket/ui/apps/comps.lua index 4b68d69..97d63f4 100644 --- a/pocket/ui/apps/comps.lua +++ b/pocket/ui/apps/comps.lua @@ -2,6 +2,7 @@ -- Computer List App -- +local comms = require("scada-common.comms") local util = require("scada-common.util") local iocontrol = require("pocket.iocontrol") @@ -21,6 +22,8 @@ local WaitingAnim = require("graphics.elements.animations.Waiting") local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local DEV_TYPE = comms.DEVICE_TYPE + local ALIGN = core.ALIGN local cpair = core.cpair local border = core.border @@ -65,7 +68,7 @@ local function new_view(root) local panes = {} ---@type Div[] -- create all page divs - for _ = 1, 3 do + for _ = 1, 4 do local div = Div{parent=page_div} table.insert(panes, div) end @@ -79,43 +82,36 @@ local function new_view(root) end end - -- create a new radiation monitor list - ---@param parent Container - ---@param ps psil - local function new_mon_list(parent, ps) - local mon_list = ListBox{parent=parent,y=6,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} + -- create indicators for the ID, firmware, and RTT + ---@param pfx string + ---@param rect Rectangle + local function create_common_indicators(pfx, rect) + TextBox{parent=rect,text="Computer ID",fg_bg=label_fg_bg} + TextBox{parent=rect,text="Firmware",fg_bg=label_fg_bg} + TextBox{parent=rect,text="Round-Trip Time",fg_bg=label_fg_bg} + local addr = TextBox{parent=rect,x=13,y=2,text="---"} + local fw = TextBox{parent=rect,x=13,y=3,text="---"} + local rtt = TextBox{parent=rect,x=13,y=3,text="---"} - local elem_list = {} ---@type graphics_element[] + addr.register(f_ps, pfx .. "_addr", addr.set_value) + fw.register(f_ps, pfx .. "_fw", fw.set_value) - mon_list.register(ps, "radiation_monitors", function (data) - local ids = textutils.unserialize(data) + rtt.register(f_ps, pfx.. "_rtt", function (value) + rtt.set_value(rtt) - -- delete any disconnected monitors - for id, elem in pairs(elem_list) do - if not util.table_contains(ids, id) then - elem.delete() - elem_list[id] = nil - end - end - - -- add newly connected monitors - for _, id in pairs(ids) do - if not elem_list[id] then - elem_list[id] = Div{parent=mon_list,height=5} - local mon_rect = Rectangle{parent=elem_list[id],height=4,x=2,width=20,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} - - TextBox{parent=mon_rect,text="Env. Detector "..id} - local mon_rad = RadIndicator{parent=mon_rect,x=2,label="",format="%13.3f",lu_colors=cpair(colors.gray,colors.gray),width=18} - mon_rad.register(ps, "radiation@" .. id, mon_rad.update) - end + if value > HIGH_RTT then + rtt.recolor(colors.red) + elseif value > WARN_RTT then + rtt.recolor(colors.yellow) + else + rtt.recolor(colors.green) end end) end --#region main computer page - local m_pane = panes[1] - local m_div = Div{parent=m_pane,x=2,width=main.get_width()-2} + local m_div = Div{parent=panes[1],x=2,width=main.get_width()-2} local main_page = app.new_page(nil, 1) main_page.tasks = { update } @@ -142,16 +138,9 @@ local function new_view(root) local crd_rect = Rectangle{parent=crd_div,height=6,x=2,width=21,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} TextBox{parent=crd_rect,text="Coordinator"} - local crd_online = TextBox{parent=svr_rect,x=12,y=1,width=7,text="Online",fg_bg=cpair(colors.green,colors._INHERIT)} - TextBox{parent=crd_rect,text="Computer ID",fg_bg=label_fg_bg} - TextBox{parent=crd_rect,text="Firmware",fg_bg=label_fg_bg} - TextBox{parent=crd_rect,text="Round-Trip Time",fg_bg=label_fg_bg} - local crd_addr = TextBox{parent=svr_rect,x=13,y=2,text="---"} - local crd_fw = TextBox{parent=svr_rect,x=13,y=3,text="---"} - local crd_rtt = TextBox{parent=svr_rect,x=13,y=3,text="---"} + local crd_online = TextBox{parent=crd_rect,x=12,y=1,width=7,text="Online",fg_bg=cpair(colors.green,colors._INHERIT)} - crd_addr.register(f_ps, "comp_crd_addr", crd_addr.set_value) - crd_fw.register(f_ps, "comp_crd_fw", crd_fw.set_value) + create_common_indicators("comp_crd", crd_rect) crd_online.register(f_ps, "comp_crd_online", function (online) if online then @@ -163,39 +152,95 @@ local function new_view(root) end end) - crd_rtt.register(f_ps, "comp_crd_rtt", function (rtt) - crd_rtt.set_value(rtt) + --#endregion - if type(rtt) ~= "number" then - crd_rtt.recolor(label_fg_bg.fgd) - else - if rtt > HIGH_RTT then - crd_rtt.recolor(colors.red) - elseif rtt > WARN_RTT then - crd_rtt.recolor(colors.yellow) - else - crd_rtt.recolor(colors.green) - end - end - end) + --#region PLC page + + local p_div = Div{parent=panes[2],width=main.get_width()} + + local plc_page = app.new_page(nil, 2) + plc_page.tasks = { update } + + TextBox{parent=p_div,y=1,text="PLC Devices",alignment=ALIGN.CENTER} + + local plc_list = ListBox{parent=p_div,y=6,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} + local plc_elems = {} ---@type graphics_element[] --#endregion - --#region overview page + --#region RTU page - local f_pane = panes[db.facility.num_units + 2] - local f_div = Div{parent=f_pane,width=main.get_width()} + local r_div = Div{parent=panes[2],width=main.get_width()} - local fac_page = app.new_page(nil, db.facility.num_units + 2) - fac_page.tasks = { update } + local rtu_page = app.new_page(nil, 3) + rtu_page.tasks = { update } - TextBox{parent=f_div,y=1,text="Facility Monitors",alignment=ALIGN.CENTER} + TextBox{parent=r_div,y=1,text="RTU Gateway Devices",alignment=ALIGN.CENTER} - TextBox{parent=f_div,x=2,y=3,text="Max Radiation",fg_bg=label_fg_bg} - local f_rad = RadIndicator{parent=f_div,x=2,label="",format="%17.3f",lu_colors=lu_col,width=21} - f_rad.register(f_ps, "radiation", f_rad.update) + local rtu_list = ListBox{parent=p_div,y=6,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} + local rtu_elems = {} ---@type graphics_element[] - new_mon_list(f_div, f_ps) + --#endregion + + --#region RTU page + + local pk_div = Div{parent=panes[2],width=main.get_width()} + + local pkt_page = app.new_page(nil, 4) + pkt_page.tasks = { update } + + TextBox{parent=pk_div,y=1,text="Pocket Devices",alignment=ALIGN.CENTER} + + local pkt_list = ListBox{parent=p_div,y=6,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} + local pkt_elems = {} ---@type graphics_element[] + + --#endregion + + --#region connect/disconnect management + + f_ps.subscribe("comp_connect", function (id) + local pfx = "comp_" .. id + local type = f_ps.get(pfx .. "_type") + + if type == DEV_TYPE.PLC then + plc_elems[id] = Div{parent=plc_list,height=5} + local rect = Rectangle{parent=plc_elems[id],height=6,x=2,width=20,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} + + local title = TextBox{parent=rect,text="PLC (Unit ?) @ "..id} + title.register(f_ps, pfx .. "_unit", function (unit) title.set_value("PLC (Unit " .. unit .. ") @ " .. id) end) + + create_common_indicators(pfx, rect) + elseif type == DEV_TYPE.RTU then + rtu_elems[id] = Div{parent=rtu_list,height=5} + local rect = Rectangle{parent=rtu_elems[id],height=6,x=2,width=20,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} + + TextBox{parent=rect,text="RTU Gateway @ "..id} + + create_common_indicators(pfx, rect) + elseif type == DEV_TYPE.PKT then + pkt_elems[id] = Div{parent=pkt_list,height=5} + local rect = Rectangle{parent=pkt_elems[id],height=6,x=2,width=20,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} + + TextBox{parent=rect,text="Pocket @ "..id} + + create_common_indicators(pfx, rect) + end + end) + + f_ps.subscribe("comp_disconnect", function (id) + local type = f_ps.get("comp_" ..id .. "_type") + + if type == DEV_TYPE.PLC then + if plc_elems[id] then plc_elems[id].delete() end + plc_elems[id] = nil + elseif type == DEV_TYPE.RTU then + if rtu_elems[id] then rtu_elems[id].delete() end + rtu_elems[id] = nil + elseif type == DEV_TYPE.PKT then + if pkt_elems[id] then pkt_elems[id].delete() end + pkt_elems[id] = nil + end + end) --#endregion diff --git a/supervisor/session/pocket.lua b/supervisor/session/pocket.lua index b229286..a47b1cf 100644 --- a/supervisor/session/pocket.lua +++ b/supervisor/session/pocket.lua @@ -199,7 +199,7 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, for i = 1, #facility.get_units() do local tag = "plc_" .. i if read(tag .. "_conn") then - table.insert(devices, { DEV_TYPE.CRD, read(tag .. "_addr"), read(tag .. "_fw"), read(tag .. "_rtt") }) + table.insert(devices, { DEV_TYPE.CRD, read(tag .. "_addr"), read(tag .. "_fw"), read(tag .. "_rtt"), i }) end end From e29a88eeeaad9b0256d4502d08b41345c4df8c82 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Wed, 6 Aug 2025 16:00:28 +0000 Subject: [PATCH 06/45] #401 sidebar updates --- pocket/ui/apps/comps.lua | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pocket/ui/apps/comps.lua b/pocket/ui/apps/comps.lua index 97d63f4..44585d7 100644 --- a/pocket/ui/apps/comps.lua +++ b/pocket/ui/apps/comps.lua @@ -252,18 +252,16 @@ local function new_view(root) local list = { { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home }, - { label = " \x1e ", color = core.cpair(colors.black, colors.blue), callback = stat_page.nav_to }, - { label = "FAC", color = core.cpair(colors.black, colors.yellow), callback = fac_page.nav_to } + { label = " \x1e ", color = core.cpair(colors.black, colors.blue), callback = main_page.nav_to }, + { label = "PLC", color = core.cpair(colors.black, colors.red), callback = plc_page.nav_to }, + { label = "RTU", color = core.cpair(colors.black, colors.orange), callback = rtu_page.nav_to }, + { label = "PKT", color = core.cpair(colors.black, colors.gray), callback = pkt_page.nav_to } } - for i = 1, db.facility.num_units do - table.insert(list, { label = "U-" .. i, color = core.cpair(colors.black, colors.lightGray), callback = function () app.switcher(i) end }) - end - app.set_sidebar(list) -- done, show the app - stat_page.nav_to() + main_page.nav_to() load_pane.set_value(2) end From fe783609489e560383806c14df07bca7f32a874f Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Wed, 13 Aug 2025 10:45:32 -0300 Subject: [PATCH 07/45] #401 working main page of computer list app --- graphics/core.lua | 2 +- graphics/elements/TextBox.lua | 7 +++ pocket/iorx.lua | 2 +- pocket/ui/apps/comps.lua | 82 ++++++++++++++++++++--------------- supervisor/session/pocket.lua | 16 +++---- 5 files changed, 64 insertions(+), 45 deletions(-) diff --git a/graphics/core.lua b/graphics/core.lua index 8f94b6f..48cfc01 100644 --- a/graphics/core.lua +++ b/graphics/core.lua @@ -7,7 +7,7 @@ local flasher = require("graphics.flasher") local core = {} -core.version = "2.4.7" +core.version = "2.4.8" core.flasher = flasher core.events = events diff --git a/graphics/elements/TextBox.lua b/graphics/elements/TextBox.lua index c91746d..3469d96 100644 --- a/graphics/elements/TextBox.lua +++ b/graphics/elements/TextBox.lua @@ -86,6 +86,13 @@ return function (args) e.redraw() end + -- change the foreground color of the text + ---@param c color + function e.recolor(c) + e.w_set_fgd(c) + e.redraw() + end + ---@class TextBox:graphics_element local TextBox, id = e.complete(true) diff --git a/pocket/iorx.lua b/pocket/iorx.lua index 3ea69c1..863e26f 100644 --- a/pocket/iorx.lua +++ b/pocket/iorx.lua @@ -879,7 +879,7 @@ local comp_record = {} -- update the computers app with the network data from INFO_LIST_CMP ---@param data table function iorx.record_network_data(data) - local ps = io.facility.ps + local ps = io.ps local connected = {} local crd_online = false diff --git a/pocket/ui/apps/comps.lua b/pocket/ui/apps/comps.lua index 44585d7..9fed26d 100644 --- a/pocket/ui/apps/comps.lua +++ b/pocket/ui/apps/comps.lua @@ -33,6 +33,8 @@ local APP_ID = pocket.APP_ID local label_fg_bg = style.label local lu_col = style.label_unit_pair +local box_label = cpair(colors.lightGray, colors.gray) + -- nominal RTT is ping (0ms to 10ms usually) + 150ms for SV main loop tick -- ensure in sync with supervisor databus file local WARN_RTT = 300 -- 2x as long as expected w/ 0 ping @@ -61,7 +63,7 @@ local function new_view(root) -- load the app (create the elements) local function load() - local f_ps = db.facility.ps + local ps = db.ps page_div = Div{parent=main,y=2,width=main.get_width()} @@ -86,20 +88,24 @@ local function new_view(root) ---@param pfx string ---@param rect Rectangle local function create_common_indicators(pfx, rect) - TextBox{parent=rect,text="Computer ID",fg_bg=label_fg_bg} - TextBox{parent=rect,text="Firmware",fg_bg=label_fg_bg} - TextBox{parent=rect,text="Round-Trip Time",fg_bg=label_fg_bg} - local addr = TextBox{parent=rect,x=13,y=2,text="---"} - local fw = TextBox{parent=rect,x=13,y=3,text="---"} - local rtt = TextBox{parent=rect,x=13,y=3,text="---"} + local first = TextBox{parent=rect,text="Computer",fg_bg=box_label} + TextBox{parent=rect,text="Firmware",fg_bg=box_label} + TextBox{parent=rect,text="RTT",fg_bg=box_label} - addr.register(f_ps, pfx .. "_addr", addr.set_value) - fw.register(f_ps, pfx .. "_fw", fw.set_value) + local y = first.get_y() + local addr = TextBox{parent=rect,x=10,y=y,text="---"} + local fw = TextBox{parent=rect,x=10,y=y+1,text="---"} + local rtt = TextBox{parent=rect,x=10,y=y+2,text="---"} - rtt.register(f_ps, pfx.. "_rtt", function (value) - rtt.set_value(rtt) + addr.register(ps, pfx .. "_addr", function (v) addr.set_value(util.strval(v)) end) + fw.register(ps, pfx .. "_fw", function (v) fw.set_value(util.strval(v)) end) - if value > HIGH_RTT then + rtt.register(ps, pfx .. "_rtt", function (value) + rtt.set_value(util.strval(value)) + + if value == "---" then + rtt.recolor(colors.white) + elseif value > HIGH_RTT then rtt.recolor(colors.red) elseif value > WARN_RTT then rtt.recolor(colors.yellow) @@ -118,37 +124,39 @@ local function new_view(root) TextBox{parent=m_div,y=1,text="Connected Computers",alignment=ALIGN.CENTER} - local conns = DataIndicator{parent=m_div,x=10,y=3,lu_colors=lu_col,label="Online",unit="",format="%3d",value=0,commas=true,width=21} - conns.register(f_ps, "comp_online", conns.update) + local conns = DataIndicator{parent=m_div,y=3,lu_colors=lu_col,label="Total Online",unit="",format="%8d",value=0,commas=true,width=21} + conns.register(ps, "comp_online", conns.update) - local svr_div = Div{parent=m_div,y=5,height=5} - local svr_rect = Rectangle{parent=svr_div,height=5,x=2,width=21,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} + local svr_div = Div{parent=m_div,y=4,height=6} + local svr_rect = Rectangle{parent=svr_div,height=6,width=22,border=border(1,colors.white,true),thin=true,fg_bg=cpair(colors.white,colors.gray)} TextBox{parent=svr_rect,text="Supervisor"} - TextBox{parent=svr_rect,x=12,y=1,width=6,text="Online",fg_bg=cpair(colors.green,colors._INHERIT)} - TextBox{parent=svr_rect,text="Computer ID",fg_bg=label_fg_bg} - TextBox{parent=svr_rect,text="Firmware",fg_bg=label_fg_bg} - local svr_addr = TextBox{parent=svr_rect,x=13,y=2,text="---"} - local svr_fw = TextBox{parent=svr_rect,x=13,y=3,text="---"} + TextBox{parent=svr_rect,text="Status",fg_bg=box_label} + TextBox{parent=svr_rect,x=10,y=2,text="Online",fg_bg=cpair(colors.green,colors._INHERIT)} + TextBox{parent=svr_rect,text="Computer",fg_bg=box_label} + TextBox{parent=svr_rect,text="Firmware",fg_bg=box_label} + local svr_addr = TextBox{parent=svr_rect,x=10,y=3,text="?"} + local svr_fw = TextBox{parent=svr_rect,x=10,y=4,text="?"} - svr_addr.register(f_ps, "comp_svr_addr", svr_addr.set_value) - svr_fw.register(f_ps, "comp_svr_fw", svr_fw.set_value) + svr_addr.register(ps, "comp_svr_addr", function (v) svr_addr.set_value(util.strval(v)) end) + svr_fw.register(ps, "comp_svr_fw", function (v) svr_fw.set_value(util.strval(v)) end) - local crd_div = Div{parent=m_div,y=5,height=5} - local crd_rect = Rectangle{parent=crd_div,height=6,x=2,width=21,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} + local crd_div = Div{parent=m_div,y=11,height=9} + local crd_rect = Rectangle{parent=crd_div,height=7,width=21,border=border(1,colors.white,true),thin=true,fg_bg=cpair(colors.white,colors.gray)} TextBox{parent=crd_rect,text="Coordinator"} - local crd_online = TextBox{parent=crd_rect,x=12,y=1,width=7,text="Online",fg_bg=cpair(colors.green,colors._INHERIT)} + TextBox{parent=crd_rect,text="Status",fg_bg=box_label} + local crd_online = TextBox{parent=crd_rect,x=10,y=2,width=8,text="Off-line",fg_bg=cpair(colors.red,colors._INHERIT)} create_common_indicators("comp_crd", crd_rect) - crd_online.register(f_ps, "comp_crd_online", function (online) + crd_online.register(ps, "comp_crd_online", function (online) if online then - crd_online.set_value("Online") crd_online.recolor(colors.green) + crd_online.set_value("Online") else - crd_online.set_value("Off-line") crd_online.recolor(colors.red) + crd_online.set_value("Off-line") end end) @@ -198,16 +206,18 @@ local function new_view(root) --#region connect/disconnect management - f_ps.subscribe("comp_connect", function (id) + ps.subscribe("comp_connect", function (id) + if id == false then return end + local pfx = "comp_" .. id - local type = f_ps.get(pfx .. "_type") + local type = ps.get(pfx .. "_type") if type == DEV_TYPE.PLC then plc_elems[id] = Div{parent=plc_list,height=5} local rect = Rectangle{parent=plc_elems[id],height=6,x=2,width=20,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} local title = TextBox{parent=rect,text="PLC (Unit ?) @ "..id} - title.register(f_ps, pfx .. "_unit", function (unit) title.set_value("PLC (Unit " .. unit .. ") @ " .. id) end) + title.register(ps, pfx .. "_unit", function (unit) title.set_value("PLC (Unit " .. unit .. ") @ " .. id) end) create_common_indicators(pfx, rect) elseif type == DEV_TYPE.RTU then @@ -227,8 +237,10 @@ local function new_view(root) end end) - f_ps.subscribe("comp_disconnect", function (id) - local type = f_ps.get("comp_" ..id .. "_type") + ps.subscribe("comp_disconnect", function (id) + if id == false then return end + + local type = ps.get("comp_" ..id .. "_type") if type == DEV_TYPE.PLC then if plc_elems[id] then plc_elems[id].delete() end @@ -252,7 +264,7 @@ local function new_view(root) local list = { { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home }, - { label = " \x1e ", color = core.cpair(colors.black, colors.blue), callback = main_page.nav_to }, + { label = " @ ", color = core.cpair(colors.black, colors.blue), callback = main_page.nav_to }, { label = "PLC", color = core.cpair(colors.black, colors.red), callback = plc_page.nav_to }, { label = "RTU", color = core.cpair(colors.black, colors.orange), callback = rtu_page.nav_to }, { label = "PKT", color = core.cpair(colors.black, colors.gray), callback = pkt_page.nav_to } diff --git a/supervisor/session/pocket.lua b/supervisor/session/pocket.lua index a47b1cf..e01d020 100644 --- a/supervisor/session/pocket.lua +++ b/supervisor/session/pocket.lua @@ -185,34 +185,34 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, if not valid then _send_mgmt(MGMT_TYPE.DIAG_ALARM_SET, { false }) end elseif pkt.type == MGMT_TYPE.INFO_LIST_CMP then - local read = databus.ps.get + local get = databus.ps.get ---@diagnostic disable-next-line: undefined-field - local devices = { { DEV_TYPE.SVR, os.getComputerID(), read("version"), 0 } } + local devices = { { DEV_TYPE.SVR, os.getComputerID(), get("version"), 0 } } -- add the coordinator if connected - if read("crd_conn") then - table.insert(devices, { DEV_TYPE.CRD, read("crd_addr"), read("crd_fw"), databus.read("crd_rtt") }) + if get("crd_conn") then + table.insert(devices, { DEV_TYPE.CRD, get("crd_addr"), get("crd_fw"), databus.read("crd_rtt") }) end -- add the PLCs if connected for i = 1, #facility.get_units() do local tag = "plc_" .. i - if read(tag .. "_conn") then - table.insert(devices, { DEV_TYPE.CRD, read(tag .. "_addr"), read(tag .. "_fw"), read(tag .. "_rtt"), i }) + if get(tag .. "_conn") then + table.insert(devices, { DEV_TYPE.CRD, get(tag .. "_addr"), get(tag .. "_fw"), get(tag .. "_rtt"), i }) end end -- add connected RTUs for i = 1, #sessions.rtu do local s = sessions.rtu[i] - table.insert(devices, { DEV_TYPE.RTU, s.s_addr, s.version, read(s.instance.get_id() .. "_rtt") }) + table.insert(devices, { DEV_TYPE.RTU, s.s_addr, s.version, get(s.instance.get_id() .. "_rtt") }) end -- add connected pocket computers for i = 1, #sessions.pdg do local s = sessions.pdg[i] - table.insert(devices, { DEV_TYPE.PKT, s.s_addr, s.version, read(s.instance.get_id() .. "_rtt") }) + table.insert(devices, { DEV_TYPE.PKT, s.s_addr, s.version, get(s.instance.get_id() .. "_rtt") }) end _send_mgmt(MGMT_TYPE.INFO_LIST_CMP, devices) From 170cba702c2436d361db8b51e26b4a1b20ca984e Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Wed, 13 Aug 2025 10:46:09 -0300 Subject: [PATCH 08/45] PSIL updates stored value before notifying subscribers --- scada-common/psil.lua | 4 ++-- scada-common/util.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scada-common/psil.lua b/scada-common/psil.lua index 82e99f6..b646d37 100644 --- a/scada-common/psil.lua +++ b/scada-common/psil.lua @@ -53,12 +53,12 @@ function psil.create() if ic[key] == nil then alloc(key) end if ic[key].value ~= value then + ic[key].value = value + for i = 1, #ic[key].subscribers do ic[key].subscribers[i].notify(value) end end - - ic[key].value = value end -- publish a toggled boolean value to a given key, passing it to all subscribers if it has changed
diff --git a/scada-common/util.lua b/scada-common/util.lua index 2a2f81a..8230fca 100644 --- a/scada-common/util.lua +++ b/scada-common/util.lua @@ -24,7 +24,7 @@ local t_pack = table.pack local util = {} -- scada-common version -util.version = "1.5.2" +util.version = "1.5.3" util.TICK_TIME_S = 0.05 util.TICK_TIME_MS = 50 From 9bb3f59496a74aa3a1a841441d4fd3ee48fe1bbd Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Wed, 13 Aug 2025 11:15:33 -0300 Subject: [PATCH 09/45] reworked pocket app loader --- pocket/iocontrol.lua | 3 ++- pocket/pocket.lua | 9 ++++++++- pocket/ui/apps/loader.lua | 21 +++++++++++++++++---- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/pocket/iocontrol.lua b/pocket/iocontrol.lua index b559fb0..aeb2cd7 100644 --- a/pocket/iocontrol.lua +++ b/pocket/iocontrol.lua @@ -36,7 +36,8 @@ iocontrol.LINK_STATE = LINK_STATE ---@class pocket_ioctl local io = { version = "unknown", -- pocket version - ps = psil.create() -- pocket PSIL + ps = psil.create(), -- pocket PSIL + loader_require = { sv = false, api = false } } local config = nil ---@type pkt_config diff --git a/pocket/pocket.lua b/pocket/pocket.lua index 4bbd051..5e227f3 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -278,7 +278,14 @@ function pocket.init_nav(smem) local app = self.apps[app_id] if app then - if app.requires_conn() and not smem.pkt_sys.pocket_comms.is_linked() then + local p_comms = smem.pkt_sys.pocket_comms + local req_sv, req_api = app.check_requires() + + if (req_sv and not p_comms.is_sv_linked()) or (req_api and not p_comms.is_api_linked()) then + -- report required connction(s) + iocontrol.get_db().loader_require = { sv = req_sv, api = req_api } + iocontrol.get_db().ps.toggle("loader_reqs") + -- bring up the app loader self.loader_return = app_id app_id = APP_ID.LOADER diff --git a/pocket/ui/apps/loader.lua b/pocket/ui/apps/loader.lua index 7a45a7a..533370c 100644 --- a/pocket/ui/apps/loader.lua +++ b/pocket/ui/apps/loader.lua @@ -32,16 +32,29 @@ local function create_pages(root) local root_pane = MultiPane{parent=main,x=1,y=1,panes={conn_sv_wait,conn_api_wait,main_pane}} - root_pane.register(db.ps, "link_state", function (state) - if state == LINK_STATE.UNLINKED or state == LINK_STATE.API_LINK_ONLY then + local function update() + local state = db.ps.get("link_state") + + if state == LINK_STATE.UNLINKED then root_pane.set_value(1) + elseif state == LINK_STATE.API_LINK_ONLY then + if not db.loader_require.sv then + root_pane.set_value(3) + db.nav.on_loader_connected() + else root_pane.set_value(1) end elseif state == LINK_STATE.SV_LINK_ONLY then - root_pane.set_value(2) + if not db.loader_require.api then + root_pane.set_value(3) + db.nav.on_loader_connected() + else root_pane.set_value(2) end else root_pane.set_value(3) db.nav.on_loader_connected() end - end) + end + + root_pane.register(db.ps, "link_state", update) + root_pane.register(db.ps, "loader_reqs", update) TextBox{parent=main_pane,text="Connected!",x=1,y=6,alignment=core.ALIGN.CENTER} end From a678b8dbe0f74756bea613e7f09feed638a8fc52 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Wed, 13 Aug 2025 11:17:30 -0300 Subject: [PATCH 10/45] #401 fix for supervisor coordinator RTT reporting --- supervisor/session/pocket.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/supervisor/session/pocket.lua b/supervisor/session/pocket.lua index e01d020..f82815e 100644 --- a/supervisor/session/pocket.lua +++ b/supervisor/session/pocket.lua @@ -192,7 +192,7 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, -- add the coordinator if connected if get("crd_conn") then - table.insert(devices, { DEV_TYPE.CRD, get("crd_addr"), get("crd_fw"), databus.read("crd_rtt") }) + table.insert(devices, { DEV_TYPE.CRD, get("crd_addr"), get("crd_fw"), get("crd_rtt") }) end -- add the PLCs if connected From 415cb712948f52cbe4bcdaa29902ad89c83674f8 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Wed, 13 Aug 2025 11:32:49 -0300 Subject: [PATCH 11/45] #401 working RTU and PKT computer lists --- pocket/iorx.lua | 3 +++ pocket/ui/apps/comps.lua | 35 +++++++++++++++++++---------------- supervisor/session/pocket.lua | 4 ++-- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/pocket/iorx.lua b/pocket/iorx.lua index 863e26f..cbb2c01 100644 --- a/pocket/iorx.lua +++ b/pocket/iorx.lua @@ -947,6 +947,9 @@ function iorx.record_network_data(data) ps.publish("comp_disconnect", false) end +-- clear the tracked connected computer record +function iorx.clear_comp_record() comp_record = {} end + return function (io_obj) io = io_obj return iorx diff --git a/pocket/ui/apps/comps.lua b/pocket/ui/apps/comps.lua index 9fed26d..06ac256 100644 --- a/pocket/ui/apps/comps.lua +++ b/pocket/ui/apps/comps.lua @@ -90,7 +90,7 @@ local function new_view(root) local function create_common_indicators(pfx, rect) local first = TextBox{parent=rect,text="Computer",fg_bg=box_label} TextBox{parent=rect,text="Firmware",fg_bg=box_label} - TextBox{parent=rect,text="RTT",fg_bg=box_label} + TextBox{parent=rect,text="RTT (ms)",fg_bg=box_label} local y = first.get_y() local addr = TextBox{parent=rect,x=10,y=y,text="---"} @@ -171,35 +171,35 @@ local function new_view(root) TextBox{parent=p_div,y=1,text="PLC Devices",alignment=ALIGN.CENTER} - local plc_list = ListBox{parent=p_div,y=6,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} + local plc_list = ListBox{parent=p_div,y=3,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} local plc_elems = {} ---@type graphics_element[] --#endregion --#region RTU page - local r_div = Div{parent=panes[2],width=main.get_width()} + local r_div = Div{parent=panes[3],width=main.get_width()} local rtu_page = app.new_page(nil, 3) rtu_page.tasks = { update } TextBox{parent=r_div,y=1,text="RTU Gateway Devices",alignment=ALIGN.CENTER} - local rtu_list = ListBox{parent=p_div,y=6,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} + local rtu_list = ListBox{parent=r_div,y=3,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} local rtu_elems = {} ---@type graphics_element[] --#endregion --#region RTU page - local pk_div = Div{parent=panes[2],width=main.get_width()} + local pk_div = Div{parent=panes[4],width=main.get_width()} local pkt_page = app.new_page(nil, 4) pkt_page.tasks = { update } TextBox{parent=pk_div,y=1,text="Pocket Devices",alignment=ALIGN.CENTER} - local pkt_list = ListBox{parent=p_div,y=6,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} + local pkt_list = ListBox{parent=pk_div,y=3,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} local pkt_elems = {} ---@type graphics_element[] --#endregion @@ -213,25 +213,25 @@ local function new_view(root) local type = ps.get(pfx .. "_type") if type == DEV_TYPE.PLC then - plc_elems[id] = Div{parent=plc_list,height=5} - local rect = Rectangle{parent=plc_elems[id],height=6,x=2,width=20,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} + plc_elems[id] = Div{parent=plc_list,height=8} + local rect = Rectangle{parent=plc_elems[id],height=6,x=2,width=20,border=border(1,colors.white,true),thin=true,fg_bg=cpair(colors.white,colors.gray)} - local title = TextBox{parent=rect,text="PLC (Unit ?) @ "..id} + local title = TextBox{parent=rect,text="PLC (Unit ?)"} title.register(ps, pfx .. "_unit", function (unit) title.set_value("PLC (Unit " .. unit .. ") @ " .. id) end) create_common_indicators(pfx, rect) elseif type == DEV_TYPE.RTU then - rtu_elems[id] = Div{parent=rtu_list,height=5} - local rect = Rectangle{parent=rtu_elems[id],height=6,x=2,width=20,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} + rtu_elems[id] = Div{parent=rtu_list,height=8} + local rect = Rectangle{parent=rtu_elems[id],height=6,x=2,width=20,border=border(1,colors.white,true),thin=true,fg_bg=cpair(colors.white,colors.gray)} - TextBox{parent=rect,text="RTU Gateway @ "..id} + TextBox{parent=rect,text="RTU Gateway"} create_common_indicators(pfx, rect) elseif type == DEV_TYPE.PKT then - pkt_elems[id] = Div{parent=pkt_list,height=5} - local rect = Rectangle{parent=pkt_elems[id],height=6,x=2,width=20,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} + pkt_elems[id] = Div{parent=pkt_list,height=8} + local rect = Rectangle{parent=pkt_elems[id],height=6,x=2,width=20,border=border(1,colors.white,true),thin=true,fg_bg=cpair(colors.white,colors.gray)} - TextBox{parent=rect,text="Pocket @ "..id} + TextBox{parent=rect,text="Pocket Computer"} create_common_indicators(pfx, rect) end @@ -267,7 +267,7 @@ local function new_view(root) { label = " @ ", color = core.cpair(colors.black, colors.blue), callback = main_page.nav_to }, { label = "PLC", color = core.cpair(colors.black, colors.red), callback = plc_page.nav_to }, { label = "RTU", color = core.cpair(colors.black, colors.orange), callback = rtu_page.nav_to }, - { label = "PKT", color = core.cpair(colors.black, colors.gray), callback = pkt_page.nav_to } + { label = "PKT", color = core.cpair(colors.black, colors.lightGray), callback = pkt_page.nav_to } } app.set_sidebar(list) @@ -289,6 +289,9 @@ local function new_view(root) -- show loading screen load_pane.set_value(1) + + -- clear the list of connected computers so that connections re-appear on reload of this app + iocontrol.rx.clear_comp_record() end app.set_load(load) diff --git a/supervisor/session/pocket.lua b/supervisor/session/pocket.lua index f82815e..e720862 100644 --- a/supervisor/session/pocket.lua +++ b/supervisor/session/pocket.lua @@ -206,13 +206,13 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, -- add connected RTUs for i = 1, #sessions.rtu do local s = sessions.rtu[i] - table.insert(devices, { DEV_TYPE.RTU, s.s_addr, s.version, get(s.instance.get_id() .. "_rtt") }) + table.insert(devices, { DEV_TYPE.RTU, s.s_addr, s.version, get("rtu_" .. s.instance.get_id() .. "_rtt") }) end -- add connected pocket computers for i = 1, #sessions.pdg do local s = sessions.pdg[i] - table.insert(devices, { DEV_TYPE.PKT, s.s_addr, s.version, get(s.instance.get_id() .. "_rtt") }) + table.insert(devices, { DEV_TYPE.PKT, s.s_addr, s.version, get("pdg_" .. s.instance.get_id() .. "_rtt") }) end _send_mgmt(MGMT_TYPE.INFO_LIST_CMP, devices) From 3b856655c3675c2cc918678a60ddc50ce45d7dfc Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Wed, 13 Aug 2025 11:46:26 -0300 Subject: [PATCH 12/45] #401 comment updates --- pocket/ui/apps/comps.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pocket/ui/apps/comps.lua b/pocket/ui/apps/comps.lua index 06ac256..914005b 100644 --- a/pocket/ui/apps/comps.lua +++ b/pocket/ui/apps/comps.lua @@ -176,7 +176,7 @@ local function new_view(root) --#endregion - --#region RTU page + --#region RTU gateway page local r_div = Div{parent=panes[3],width=main.get_width()} @@ -190,7 +190,7 @@ local function new_view(root) --#endregion - --#region RTU page + --#region pocket computer page local pk_div = Div{parent=panes[4],width=main.get_width()} From 691b781c523425b55ed52f9e02c4ad650d977c47 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Tue, 19 Aug 2025 18:42:48 -0400 Subject: [PATCH 13/45] #401 slowed polling rate for computer app --- pocket/ui/apps/comps.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pocket/ui/apps/comps.lua b/pocket/ui/apps/comps.lua index 914005b..63e885a 100644 --- a/pocket/ui/apps/comps.lua +++ b/pocket/ui/apps/comps.lua @@ -76,9 +76,9 @@ local function new_view(root) end local last_update = 0 - -- refresh data callback, every 500ms it will re-send the query + -- refresh data callback, every 1s it will re-send the query local function update() - if util.time_ms() - last_update >= 500 then + if util.time_ms() - last_update >= 1000 then db.diag.get_comps() last_update = util.time_ms() end From 4a1730ec47b43404d18180fb63b4b295fdc87489 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Tue, 19 Aug 2025 18:43:43 -0400 Subject: [PATCH 14/45] #401 cleanup and global RTT limit constants --- pocket/ui/apps/comps.lua | 39 +++++++++++++++++--------------------- scada-common/constants.lua | 6 ++++++ scada-common/util.lua | 2 +- supervisor/databus.lua | 26 +++++++++++-------------- 4 files changed, 35 insertions(+), 38 deletions(-) diff --git a/pocket/ui/apps/comps.lua b/pocket/ui/apps/comps.lua index 63e885a..cc1240e 100644 --- a/pocket/ui/apps/comps.lua +++ b/pocket/ui/apps/comps.lua @@ -2,23 +2,24 @@ -- Computer List App -- -local comms = require("scada-common.comms") -local util = require("scada-common.util") +local comms = require("scada-common.comms") +local const = require("scada-common.constants") +local util = require("scada-common.util") -local iocontrol = require("pocket.iocontrol") -local pocket = require("pocket.pocket") +local iocontrol = require("pocket.iocontrol") +local pocket = require("pocket.pocket") -local style = require("pocket.ui.style") +local style = require("pocket.ui.style") -local core = require("graphics.core") +local core = require("graphics.core") -local Div = require("graphics.elements.Div") -local ListBox = require("graphics.elements.ListBox") -local MultiPane = require("graphics.elements.MultiPane") -local Rectangle = require("graphics.elements.Rectangle") -local TextBox = require("graphics.elements.TextBox") +local Div = require("graphics.elements.Div") +local ListBox = require("graphics.elements.ListBox") +local MultiPane = require("graphics.elements.MultiPane") +local Rectangle = require("graphics.elements.Rectangle") +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") @@ -30,15 +31,9 @@ local border = core.border local APP_ID = pocket.APP_ID -local label_fg_bg = style.label -local lu_col = style.label_unit_pair +local lu_col = style.label_unit_pair -local box_label = cpair(colors.lightGray, colors.gray) - --- nominal RTT is ping (0ms to 10ms usually) + 150ms for SV main loop tick --- ensure in sync with supervisor databus file -local WARN_RTT = 300 -- 2x as long as expected w/ 0 ping -local HIGH_RTT = 500 -- 3.33x as long as expected w/ 0 ping +local box_label = cpair(colors.lightGray, colors.gray) -- new computer list page view ---@param root Container parent @@ -105,9 +100,9 @@ local function new_view(root) if value == "---" then rtt.recolor(colors.white) - elseif value > HIGH_RTT then + elseif value > const.HIGH_RTT then rtt.recolor(colors.red) - elseif value > WARN_RTT then + elseif value > const.WARN_RTT then rtt.recolor(colors.yellow) else rtt.recolor(colors.green) diff --git a/scada-common/constants.lua b/scada-common/constants.lua index 11a8929..02841e1 100644 --- a/scada-common/constants.lua +++ b/scada-common/constants.lua @@ -88,6 +88,7 @@ constants.FLOW_STABILITY_DELAY_MS = 10000 -- - background radiation 0.0000001 Sv/h (99.99 nSv/h) -- - "green tint" radiation 0.00001 Sv/h (10 uSv/h) -- - damaging radiation 0.00006 Sv/h (60 uSv/h) + constants.LOW_RADIATION = 0.00001 constants.HAZARD_RADIATION = 0.00006 constants.HIGH_RADIATION = 0.001 @@ -95,6 +96,11 @@ constants.VERY_HIGH_RADIATION = 0.1 constants.SEVERE_RADIATION = 8.0 constants.EXTREME_RADIATION = 100.0 +-- nominal RTT is ping (0ms to 10ms usually) + 150ms for SV main loop tick + +constants.WARN_RTT = 300 -- 2x as long as expected w/ 0 ping +constants.HIGH_RTT = 500 -- 3.33x as long as expected w/ 0 ping + --#endregion --#region Mekanism Configuration Constants diff --git a/scada-common/util.lua b/scada-common/util.lua index 8230fca..031eaa0 100644 --- a/scada-common/util.lua +++ b/scada-common/util.lua @@ -24,7 +24,7 @@ local t_pack = table.pack local util = {} -- scada-common version -util.version = "1.5.3" +util.version = "1.5.4" util.TICK_TIME_S = 0.05 util.TICK_TIME_MS = 50 diff --git a/supervisor/databus.lua b/supervisor/databus.lua index eef99e7..94d67d1 100644 --- a/supervisor/databus.lua +++ b/supervisor/databus.lua @@ -2,16 +2,12 @@ -- Data Bus - Central Communication Linking for Supervisor Front Panel -- -local psil = require("scada-common.psil") -local util = require("scada-common.util") +local const = require("scada-common.constants") +local psil = require("scada-common.psil") +local util = require("scada-common.util") local pgi = require("supervisor.panel.pgi") --- nominal RTT is ping (0ms to 10ms usually) + 150ms for SV main loop tick --- ensure in sync with pocket computer list app -local WARN_RTT = 300 -- 2x as long as expected w/ 0 ping -local HIGH_RTT = 500 -- 3.33x as long as expected w/ 0 ping - local databus = {} -- databus PSIL @@ -60,9 +56,9 @@ end function databus.tx_plc_rtt(reactor_id, rtt) databus.ps.publish("plc_" .. reactor_id .. "_rtt", rtt) - if rtt > HIGH_RTT then + if rtt > const.HIGH_RTT then databus.ps.publish("plc_" .. reactor_id .. "_rtt_color", colors.red) - elseif rtt > WARN_RTT then + elseif rtt > const.WARN_RTT then databus.ps.publish("plc_" .. reactor_id .. "_rtt_color", colors.yellow_hc) else databus.ps.publish("plc_" .. reactor_id .. "_rtt_color", colors.green_hc) @@ -91,9 +87,9 @@ end function databus.tx_rtu_rtt(session_id, rtt) databus.ps.publish("rtu_" .. session_id .. "_rtt", rtt) - if rtt > HIGH_RTT then + if rtt > const.HIGH_RTT then databus.ps.publish("rtu_" .. session_id .. "_rtt_color", colors.red) - elseif rtt > WARN_RTT then + elseif rtt > const.WARN_RTT then databus.ps.publish("rtu_" .. session_id .. "_rtt_color", colors.yellow_hc) else databus.ps.publish("rtu_" .. session_id .. "_rtt_color", colors.green_hc) @@ -130,9 +126,9 @@ end function databus.tx_crd_rtt(rtt) databus.ps.publish("crd_rtt", rtt) - if rtt > HIGH_RTT then + if rtt > const.HIGH_RTT then databus.ps.publish("crd_rtt_color", colors.red) - elseif rtt > WARN_RTT then + elseif rtt > const.WARN_RTT then databus.ps.publish("crd_rtt_color", colors.yellow_hc) else databus.ps.publish("crd_rtt_color", colors.green_hc) @@ -161,9 +157,9 @@ end function databus.tx_pdg_rtt(session_id, rtt) databus.ps.publish("pdg_" .. session_id .. "_rtt", rtt) - if rtt > HIGH_RTT then + if rtt > const.HIGH_RTT then databus.ps.publish("pdg_" .. session_id .. "_rtt_color", colors.red) - elseif rtt > WARN_RTT then + elseif rtt > const.WARN_RTT then databus.ps.publish("pdg_" .. session_id .. "_rtt_color", colors.yellow_hc) else databus.ps.publish("pdg_" .. session_id .. "_rtt_color", colors.green_hc) From 83e29abea7c5397ea2c324dd4f534d3cc999875e Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Tue, 19 Aug 2025 22:14:19 -0400 Subject: [PATCH 15/45] #401 bug fixes --- pocket/ui/apps/comps.lua | 10 +++++----- supervisor/session/pocket.lua | 12 +++++++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/pocket/ui/apps/comps.lua b/pocket/ui/apps/comps.lua index cc1240e..5450118 100644 --- a/pocket/ui/apps/comps.lua +++ b/pocket/ui/apps/comps.lua @@ -136,7 +136,7 @@ local function new_view(root) svr_addr.register(ps, "comp_svr_addr", function (v) svr_addr.set_value(util.strval(v)) end) svr_fw.register(ps, "comp_svr_fw", function (v) svr_fw.set_value(util.strval(v)) end) - local crd_div = Div{parent=m_div,y=11,height=9} + local crd_div = Div{parent=m_div,y=11,height=7} local crd_rect = Rectangle{parent=crd_div,height=7,width=21,border=border(1,colors.white,true),thin=true,fg_bg=cpair(colors.white,colors.gray)} TextBox{parent=crd_rect,text="Coordinator"} @@ -208,22 +208,22 @@ local function new_view(root) local type = ps.get(pfx .. "_type") if type == DEV_TYPE.PLC then - plc_elems[id] = Div{parent=plc_list,height=8} + plc_elems[id] = Div{parent=plc_list,height=7} local rect = Rectangle{parent=plc_elems[id],height=6,x=2,width=20,border=border(1,colors.white,true),thin=true,fg_bg=cpair(colors.white,colors.gray)} local title = TextBox{parent=rect,text="PLC (Unit ?)"} - title.register(ps, pfx .. "_unit", function (unit) title.set_value("PLC (Unit " .. unit .. ") @ " .. id) end) + title.register(ps, pfx .. "_unit", function (unit) title.set_value("PLC (Unit " .. unit .. ")") end) create_common_indicators(pfx, rect) elseif type == DEV_TYPE.RTU then - rtu_elems[id] = Div{parent=rtu_list,height=8} + rtu_elems[id] = Div{parent=rtu_list,height=7} local rect = Rectangle{parent=rtu_elems[id],height=6,x=2,width=20,border=border(1,colors.white,true),thin=true,fg_bg=cpair(colors.white,colors.gray)} TextBox{parent=rect,text="RTU Gateway"} create_common_indicators(pfx, rect) elseif type == DEV_TYPE.PKT then - pkt_elems[id] = Div{parent=pkt_list,height=8} + pkt_elems[id] = Div{parent=pkt_list,height=7} local rect = Rectangle{parent=pkt_elems[id],height=6,x=2,width=20,border=border(1,colors.white,true),thin=true,fg_bg=cpair(colors.white,colors.gray)} TextBox{parent=rect,text="Pocket Computer"} diff --git a/supervisor/session/pocket.lua b/supervisor/session/pocket.lua index e720862..7500110 100644 --- a/supervisor/session/pocket.lua +++ b/supervisor/session/pocket.lua @@ -2,6 +2,7 @@ local comms = require("scada-common.comms") local log = require("scada-common.log") local mqueue = require("scada-common.mqueue") local util = require("scada-common.util") + local databus = require("supervisor.databus") local pocket = {} @@ -198,8 +199,17 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, -- add the PLCs if connected for i = 1, #facility.get_units() do local tag = "plc_" .. i + + local addr = -1 + for _, s in ipairs(sessions.plc) do + if s.reactor == i then + addr = s.s_addr + break + end + end + if get(tag .. "_conn") then - table.insert(devices, { DEV_TYPE.CRD, get(tag .. "_addr"), get(tag .. "_fw"), get(tag .. "_rtt"), i }) + table.insert(devices, { DEV_TYPE.PLC, addr, get(tag .. "_fw"), get(tag .. "_rtt"), i }) end end From e3d0692dccaad16fb862ad96832998d6561478c6 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sun, 24 Aug 2025 18:46:07 -0400 Subject: [PATCH 16/45] #400 start of peripherals list app --- pocket/ui/apps/devices.lua | 0 scada-common/comms.lua | 3 ++- supervisor/session/pocket.lua | 40 +++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 pocket/ui/apps/devices.lua diff --git a/pocket/ui/apps/devices.lua b/pocket/ui/apps/devices.lua new file mode 100644 index 0000000..e69de29 diff --git a/scada-common/comms.lua b/scada-common/comms.lua index 18f2d48..8ce4bd8 100644 --- a/scada-common/comms.lua +++ b/scada-common/comms.lua @@ -55,7 +55,8 @@ local MGMT_TYPE = { DIAG_TONE_GET = 6, -- (API) diagnostic: get alarm tones DIAG_TONE_SET = 7, -- (API) diagnostic: set alarm tones DIAG_ALARM_SET = 8, -- (API) diagnostic: set alarm to simulate audio for - INFO_LIST_CMP = 9 -- (API) info: list all computers on the network + INFO_LIST_CMP = 9, -- (API) info: list all computers on the network + INFO_LIST_PERI = 10 -- (API) info: list all peripherals on the network } ---@enum CRDN_TYPE diff --git a/supervisor/session/pocket.lua b/supervisor/session/pocket.lua index 7500110..96ab138 100644 --- a/supervisor/session/pocket.lua +++ b/supervisor/session/pocket.lua @@ -226,6 +226,46 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, end _send_mgmt(MGMT_TYPE.INFO_LIST_CMP, devices) + elseif pkt.type == MGMT_TYPE.INFO_LIST_PERI then + local data = {} + + local fac = db.facility + local proc = process.get_control_states().process + + -- unit data + for i = 1, #db.units do + local u = db.units[i] + + data[i] = {} + + data[i].boilers = {} + for idx, blr in ipairs(u.boiler_data_tbl) do + data[i].boilers[idx] = {} + + if blr.formed ~= nil then + data[i].boilers[idx] = { blr.formed, blr.build.min_pos, blr.build.max_pos, blr.build.length, blr.build.width, blr.build.height } + end + end + + data[i].turbines = {} + for idx, trb in ipairs(u.turbine_data_tbl) do + data[i].turbines[idx] = {} + + if trb.formed ~= nil then + data[i].turbines[idx] = { trb.formed, trb.build.min_pos, trb.build.max_pos, trb.build.length, trb.build.width, trb.build.height } + end + end + + data[i].tanks = {} + for idx, trb in ipairs(u.tank_data_tbl) do + data[i].turbines[idx] = {} + + if trb.formed ~= nil then + data[i].turbines[idx] = { trb.formed, trb.build.min_pos, trb.build.max_pos, trb.build.length, trb.build.width, trb.build.height } + end + end + end + else log.debug(log_tag .. "handler received unsupported SCADA_MGMT packet type " .. pkt.type) end From 92113671ff8bc41859c6c90d1ec1fff1385a79f8 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sun, 24 Aug 2025 19:33:31 -0400 Subject: [PATCH 17/45] #403 front panel documentation complete --- pocket/ui/apps/guide.lua | 5 +-- pocket/ui/docs.lua | 70 ++++++++++++++++++++++++++-------------- 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index 2efb862..0d55633 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -213,15 +213,16 @@ local function new_view(root) PushButton{parent=fps,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} local fp_common_page = guide_section(sect_construct_data, fps_page, "Common Items", docs.fp.common, 100) - local fp_rplc_page = guide_section(sect_construct_data, fps_page, "Reactor PLC", docs.fp.r_plc, 180) + local fp_rplc_page = guide_section(sect_construct_data, fps_page, "Reactor PLC", docs.fp.r_plc, 190) local fp_rtu_page = guide_section(sect_construct_data, fps_page, "RTU Gateway", docs.fp.rtu_gw, 100) local fp_supervisor_page = guide_section(sect_construct_data, fps_page, "Supervisor", docs.fp.supervisor, 160) + local fp_coordinator_page = guide_section(sect_construct_data, fps_page, "Coordinator", docs.fp.coordinator, 80) PushButton{parent=fps,y=3,text="Common Items >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=fp_common_page.nav_to} PushButton{parent=fps,text="Reactor PLC >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=fp_rplc_page.nav_to} PushButton{parent=fps,text="RTU Gateway >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=fp_rtu_page.nav_to} PushButton{parent=fps,text="Supervisor >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=fp_supervisor_page.nav_to} - PushButton{parent=fps,text="Coordinator >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + PushButton{parent=fps,text="Coordinator >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=fp_coordinator_page.nav_to} TextBox{parent=gls,y=1,text="Glossary",alignment=ALIGN.CENTER} PushButton{parent=gls,x=3,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index f87b249..aedf7f3 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -67,7 +67,7 @@ docs.alarms = {} target = docs.alarms doc("ContainmentBreach", "Containment Breach", "Reactor disconnected or indicated unformed while being at or above 100% damage; explosion assumed.") doc("ContainmentRadiation", "Containment Radiation", "Environment detector(s) assigned to the unit have observed high levels of radiation.") -doc("ReactorLost", "Reactor Lost", "Reactor PLC has stopped communicating with the supervisor.") +doc("ReactorLost", "Reactor Lost", "Reactor PLC has stopped communicating with the Supervisor.") doc("CriticalDamage", "Damage Critical", "Reactor damage has reached or exceeded 100%, so it will explode at any moment.") doc("ReactorDamage", "Reactor Damage", "Reactor temperature causing increasing damage to the reactor casing.") doc("ReactorOverTemp", "Reactor Over Temp", "Reactor temperature is at or above maximum safe temperature, so it is now taking damage.") @@ -89,8 +89,8 @@ docs.annunc = { target = docs.annunc.unit.main_section sect("Unit Status") -doc("PLCOnline", "PLC Online", "Indicates if the fission reactor PLC is connected. If it isn't, check that your PLC is on and configured properly.") -doc("PLCHeartbeat", "PLC Heartbeat", "An indicator of status data being live. As status messages are received from the PLC, this light will turn on and off. If it gets stuck, the supervisor has stopped receiving data or a screen has frozen.") +doc("PLCOnline", "PLC Online", "Indicates if the fission Reactor PLC is connected. If it isn't, check that your PLC is on and configured properly.") +doc("PLCHeartbeat", "PLC Heartbeat", "An indicator of status data being live. As status messages are received from the PLC, this light will turn on and off. If it gets stuck, the Supervisor has stopped receiving data or a screen has frozen.") doc("RadiationMonitor", "Radiation Monitor", "On if at least one environment detector is connected and assigned to this unit.") doc("AutoControl", "Automatic Control", "On if the reactor is under the control of one of the automatic control modes.") sect("Safety Status") @@ -118,7 +118,7 @@ doc("high_temp", "Temperature High", "Indicates if the RPS tripped due to reachi doc("low_cool", "Coolant Level Low Low", "Indicates if the RPS tripped due to very low coolant levels that result in the temperature uncontrollably rising. Ensure that the cooling system can provide sufficient cooled coolant flow.") doc("no_fuel", "No Fuel", "Indicates if the RPS tripped due to no fuel being available. Check fuel input.") doc("fault", "PPM Fault", "Indicates if the RPS tripped due to a peripheral access fault. Something went wrong interfacing with the reactor, try restarting the PLC.") -doc("timeout", "Connection Timeout", "Indicates if the RPS tripped due to losing connection with the supervisory computer. Check that your PLC and supervisor remain chunk loaded.") +doc("timeout", "Connection Timeout", "Indicates if the RPS tripped due to losing connection with the supervisory computer. Check that your PLC and Supervisor remain chunk loaded.") doc("sys_fail", "System Failure", "Indicates if the RPS tripped due to the reactor not being formed. Ensure that the multi-block is formed.") target = docs.annunc.unit.rcs_section @@ -130,7 +130,7 @@ doc("SteamFeedMismatch", "Steam Feed Mismatch", "There is an above tolerance dif doc("MaxWaterReturnFeed", "Max Water Return Feed", "The turbines are condensing the max rate of water that they can per the structure build. If water return is insufficient, add more saturating condensers to your turbine(s).") doc("WaterLevelLow", "Water Level Low", "The water level in the boiler is low. A larger boiler water tank may help, or you can feed additional water into the boiler from elsewhere.") doc("HeatingRateLow", "Heating Rate Low", "The boiler is not hot enough to boil water, but it is receiving heated coolant. This is almost never a safety concern.") -doc("SteamDumpOpen", "Steam Relief Valve Open", "This turns yellow if the turbine is set to dumping excess and red if it is set to dumping [all]. 'Relief Valve' in this case is that setting allowing the venting of steam. You should never have this set to dumping [all]. Emergency coolant activation from the supervisor will automatically set it to dumping excess to ensure there is no backup of steam as water is added.") +doc("SteamDumpOpen", "Steam Relief Valve Open", "This turns yellow if the turbine is set to dumping excess and red if it is set to dumping [all]. 'Relief Valve' in this case is that setting allowing the venting of steam. You should never have this set to dumping [all]. Emergency coolant activation from the Supervisor will automatically set it to dumping excess to ensure there is no backup of steam as water is added.") doc("TurbineOverSpeed", "Turbine Over Speed", "The turbine is at steam capacity, but not tripped. You may need more turbines if they can't keep up.") doc("GeneratorTrip", "Generator Trip", "The turbine is no longer outputting power due to it having nowhere to go. Likely due to full power storage. This will lead to a Turbine Trip if not addressed.") doc("TurbineTrip", "Turbine Trip", "The turbine has reached its maximum power charge and has stopped rotating, and as a result stopped cooling steam to water. Ensure the turbine has somewhere to output power, as this is the most common cause of reactor meltdowns. However, the likelihood of a meltdown with this system in place is much lower, especially with emergency coolant helping during turbine trips.") @@ -155,7 +155,7 @@ doc("as_radiation", "Facility Radiation High", "Automatic SCRAM occurred due to doc("as_gen_fault", "Gen. Control Fault", "Automatic SCRAM occurred due to assigned units being degraded/no longer ready during generation mode. The system will automatically resume (starting with initial ramp) once the problem is resolved.") docs.fp = { - common = {}, r_plc = {}, rtu_gw = {}, supervisor = {} + common = {}, r_plc = {}, rtu_gw = {}, supervisor = {}, coordinator = {} } --comp id "This must never be the identical between devices, and that can only happen if you duplicate a computer (such as middle-click on it and place it elsewhere in creative mode)." @@ -165,17 +165,19 @@ sect("Core Status") doc("fp_status", "STATUS", "This is always lit, except on the Reactor PLC (see Reactor PLC section).") doc("fp_heartbeat", "HEARTBEAT", "This alternates between lit and unlit as the main loop on the device runs. If this freezes, something is wrong and the logs will indicate why.") sect("Hardware & Network") -doc("fp_modem", "MODEM", "This lights up if the wireless/ender modem is connected. In parentheses is the unique computer ID of this device, which will show up in places such as the supervisor's connection lists.") +doc("fp_modem", "MODEM", "This lights up if the wireless/ender modem is connected. In parentheses is the unique computer ID of this device, which will show up in places such as the Supervisor's connection lists.") doc("fp_modem", "NETWORK", "This is present when in standard color modes and indicates the network status using multiple colors.") list(DOC_LIST_TYPE.LED, { "not linked", "linked", "link denied", "bad comms version", "duplicate PLC" }, { colors.gray, colors.green, colors.red, colors.orange, colors.yellow }) text("You can fix \"bad comms version\" by ensuring all devices are up-to-date, as this indicates a communications protocol version mismatch. Note that yellow is Reactor PLC-specific, indicating duplicate unit IDs in use.") -doc("fp_nt_linked", "NT LINKED", "(color accessibility modes only)", "This indicates the device is linked to the supervisor.") -doc("fp_nt_version", "NT VERSION", "(color accessibility modes only)", "This indicates the communications versions of the supervisor and this device do not match. Make sure everything is up-to-date.") +doc("fp_nt_linked", "NT LINKED", "(color accessibility modes only)", "This indicates the device is linked to the Supervisor.") +doc("fp_nt_version", "NT VERSION", "(color accessibility modes only)", "This indicates the communications versions of the Supervisor and this device do not match. Make sure everything is up-to-date.") sect("Versions") doc("fp_fw", "FW", "Firmware application version of this device.") doc("fp_nt", "NT", "Network (comms) version this device has. These must match between devices in order for them to connect.") target = docs.fp.r_plc +sect("Overview") +text("Documentation for Reactor PLC-specific front panel items are below. Refer to 'Common Items' for the items not covered in this section.") sect("Core Status") doc("fp_status", "STATUS", "This is green once the PLC is initialized and OK (has all its peripherals) and red if something is wrong, in which case you should refer to the other indicator lights (REACTOR & MODEM).") sect("Hardware & Network") @@ -194,8 +196,8 @@ doc("fp_emer_cool", "EMER COOLANT", "This is only present if PLC-controlled emer doc("fp_rps_trip", "RPS TRIP", "Flashes when the RPS has SCRAM'd the reactor due to a safety trip.") sect("RPS Conditions") doc("fp_rps_man", "MANUAL", "The RPS was tripped manually (SCRAM by user, not via the Mekanism Reactor UI).") -doc("fp_rps_auto", "AUTOMATIC", "The RPS was tripped by the supervisor automatically.") -doc("fp_rps_to", "TIMEOUT", "The RPS tripped due to losing the supervisor connection.") +doc("fp_rps_auto", "AUTOMATIC", "The RPS was tripped by the Supervisor automatically.") +doc("fp_rps_to", "TIMEOUT", "The RPS tripped due to losing the Supervisor connection.") doc("fp_rps_pflt", "PLC FAULT", "The RPS tripped due to a peripheral error.") doc("fp_rps_rflt", "RCT FAULT", "The RPS tripped due to the reactor not being formed.") doc("fp_rps_temp", "HI DAMAGE", "The RPS tripped due to being >=" .. const.RPS_LIMITS.MAX_DAMAGE_PERCENT .. "% damaged.") @@ -206,6 +208,9 @@ doc("fp_rps_ccool", "LO CCOOLANT", "The RPS tripped due to having low levels of doc("fp_rps_ccool", "HI HCOOLANT", "The RPS tripped due to having high levels of heated coolant (>" .. (const.RPS_LIMITS.MAX_HEATED_COLLANT_FILL * 100) .. "%).") target = docs.fp.rtu_gw +sect("Overview") +text("Documentation for RTU Gateway-specific front panel items are below. Refer to 'Common Items' for the items not covered in this section.") +doc("fp_rtu_spkr", "SPEAKERS", "This is the count of speaker peripherals connected to this RTU Gateway.") sect("Co-Routine States") doc("fp_rtu_rt_main", "RT MAIN", "This indicates if the device's main loop co-routine is running.") doc("fp_rtu_rt_comms", "RT COMMS", "This indicates if the communications handler co-routine is running.") @@ -218,30 +223,45 @@ doc("fp_rtu_rt", "Device Assignment", "In each RTU entry row, the device identif target = docs.fp.supervisor sect("Round Trip Times") -doc("fp_sv_fw", "RTT", "Each connection has a round trip time, or RTT. Since the supervisor updates at a rate of 150ms, RTTs from ~150ms to ~300ms are typical. Higher RTTs indicate lag, and if they end up in the thousands there will be performance problems.") +doc("fp_sv_rtt", "RTT", "Each connection has a round trip time, or RTT. Since the Supervisor updates at a rate of 150ms, RTTs from ~150ms to ~300ms are typical. Higher RTTs indicate lag, and if they end up in the thousands there will be performance problems.") list(DOC_LIST_TYPE.BULLET, { "green: <=300ms", "yellow: <=500ms ", "red: >500ms" }) sect("SVR Tab") -text("This tab includes information about the supervisor, covered by 'Common Items'.") +text("This tab includes information about the Supervisor, covered by 'Common Items'.") sect("PLC Tab") text("This tab lists the expected PLC connections based on the number of configured units. Status information about each connection is shown when linked.") -doc("fp_sv_link", "LINK", "This indicates if the reactor PLC is linked.") -doc("fp_sv_p_cmpid", "PLC Computer ID", "This shows the computer ID of the reactor PLC, or --- if disconnected.") -doc("fp_sv_p_fw", "PLC FW", "This shows the firmware version of the reactor PLC.") +doc("fp_sv_link", "LINK", "This indicates if the Reactor PLC is linked.") +doc("fp_sv_p_cmpid", "PLC Computer ID", "This shows the computer ID of the Reactor PLC, or --- if disconnected.") +doc("fp_sv_p_fw", "PLC FW", "This shows the firmware version of the Reactor PLC.") sect("RTU Tab") -text("As RTU gateways connect to the supervisor, they will show up here along with some information.") -doc("fp_sv_r_cmpid", "RTU Computer ID", "At the start of the entry is an @ sign followed by the computer ID of the RTU gateway.") -doc("fp_sv_r_units", "UNITS", "This is a count of the number of RTUs configured on the RTU gateway (each line on the RTU gateway's front panel).") -doc("fp_sv_r_fw", "RTU FW", "This shows the firmware version of the RTU gateway.") +text("As RTU gateways connect to the Supervisor, they will show up here along with some information.") +doc("fp_sv_r_cmpid", "RTU Computer ID", "At the start of the entry is an @ sign followed by the computer ID of the RTU Gateway.") +doc("fp_sv_r_units", "UNITS", "This is a count of the number of RTUs configured on the RTU Gateway (each line on the RTU Gateway's front panel).") +doc("fp_sv_r_fw", "RTU FW", "This shows the firmware version of the RTU Gateway.") sect("PKT Tab") -text("As pocket computers connect to the supervisor, they will show up here along with some information. The properties listed are the same as with RTU gateways (except for UNITS), so they will not be further described here.") +text("As pocket computers connect to the Supervisor, they will show up here along with some information. The properties listed are the same as with RTU gateways (except for UNITS), so they will not be further described here.") sect("DEV Tab") text("If nothing is connected, this will list all the expected RTU devices that aren't found. This page should be blank if everything is connected and configured correctly. If not, it will list certain types of detectable problems.") doc("fp_sv_d_miss", "MISSING", "These items list missing devices, with the details that should be used in the RTU's configuration.") -doc("fp_sv_d_oor", "BAD INDEX", "If you have a configuration entry that has an index outside of the maximum number of devices configured on the supervisor, this will show up indicating what entry is incorrect. For example, if you specified a unit has 2 turbines and a #3 connected, it would show up here as out of range.") +doc("fp_sv_d_oor", "BAD INDEX", "If you have a configuration entry that has an index outside of the maximum number of devices configured on the Supervisor, this will show up indicating what entry is incorrect. For example, if you specified a unit has 2 turbines and a #3 connected, it would show up here as out of range.") doc("fp_sv_d_dupe", "DUPLICATE", "If a device tries to connect that is configured the same as another, it will be rejected and show up here. If you try to connect two #1 turbines for a unit, that would fail and one would appear here.") sect("INF Tab") text("This tab gives information about the other tabs, along with extra details on the DEV tab.") +target = docs.fp.coordinator +sect("Round Trip Times") +doc("fp_crd_rtt", "RTT", "Each connection has a round trip time, or RTT. Since the Coordinator updates at a rate of 500ms, RTTs ~500ms - ~1000ms are typical. Higher RTTs indicate lag, which results in performance problems.") +list(DOC_LIST_TYPE.BULLET, { "green: <=1000ms", "yellow: <=1500ms ", "red: >1500ms" }) +sect("CRD Tab") +text("This tab includes information about the Coordinator, partially covered by 'Common Items'.") +doc("fp_crd_spkr", "SPEAKER", "This indicates if the speaker is connected.") +doc("fp_crd_rt_main", "RT MAIN", "This indicates that the device's main loop co-routine is running.") +doc("fp_crd_rt_render", "RT RENDER", "This indicates that the Coordinator graphics renderer co-routine is running.") +doc("fp_crd_mon_main", "MAIN MONITOR", "The connection status of the main display monitor.") +doc("fp_crd_mon_flow", "FLOW MONITOR", "The connection status of the coolant and waste flow display monitor.") +doc("fp_crd_mon_unit", "UNIT X MONITOR", "The connection status of the monitor associated with a given unit.") +sect("API Tab") +text("This tab lists connected pocket computers. Refer to the Supervisor PKT tab documentation for details on fields.") + docs.glossary = { abbvs = {}, terms = {} } @@ -249,8 +269,8 @@ docs.glossary = { target = docs.glossary.abbvs doc("G_ACK", "ACK", "Alarm ACKnowledge. Pressing this acknowledges that you understand an alarm occurred and would like to stop the audio tone(s).") doc("G_Auto", "Auto", "Automatic.") -doc("G_CRD", "CRD", "Coordinator. Abbreviation for the coordinator computer.") -doc("G_DBG", "DBG", "Debug. Abbreviation for the debugging sessions from pocket computers found on the supervisor's front panel.") +doc("G_CRD", "CRD", "Coordinator. Abbreviation for the Coordinator computer.") +doc("G_DBG", "DBG", "Debug. Abbreviation for the debugging sessions from pocket computers found on the Supervisor's front panel.") doc("G_FP", "FP", "Front Panel. See Terminology.") doc("G_Hi", "Hi", "High.") doc("G_Lo", "Lo", "Low.") @@ -260,7 +280,7 @@ doc("G_PLC", "PLC", "Programmable Logic Controller. A device that not only repor doc("G_PPM", "PPM", "Protected Peripheral Manager. This is an abstraction layer created for this project that prevents peripheral calls from crashing applications.") doc("G_RCP", "RCP", "Reactor Coolant Pump. This is from real-world terminology with water-cooled (boiling water and pressurized water) reactors, but in this system it just reflects to the functioning of reactor coolant flow. See the annunciator page on it for more information.") doc("G_RCS", "RCS", "Reactor Cooling System. The combination of all machines used to cool the reactor (turbines, boilers, dynamic tanks).") -doc("G_RPS", "RPS", "Reactor Protection System. A component of the reactor PLC responsible for keeping the reactor safe.") +doc("G_RPS", "RPS", "Reactor Protection System. A component of the Reactor PLC responsible for keeping the reactor safe.") doc("G_RTU", "RT", "co-RouTine. This is used to identify the status of core Lua co-routines on front panels.") doc("G_RTU", "RTU", "Remote Terminal Unit. Provides monitoring to and basic output from a SCADA system, interfacing with various types of devices/interfaces.") doc("G_SCADA", "SCADA", "Supervisory Control and Data Acquisition. A control systems architecture used in a wide variety process control applications.") From d0401fe51f7db044c30d714c546c3cc8db51e04a Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Mon, 1 Sep 2025 16:37:21 -0400 Subject: [PATCH 18/45] #403 main display documentation --- pocket/ui/apps/guide.lua | 25 ++++++++--- pocket/ui/docs.lua | 69 +++++++++++++++++++++++++++++-- pocket/ui/pages/guide_section.lua | 17 +++++++- 3 files changed, 100 insertions(+), 11 deletions(-) diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index 0d55633..f482622 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -187,27 +187,40 @@ local function new_view(root) local annunc_div = Div{parent=page_div,x=2} table.insert(panes, annunc_div) + local coord_page = app.new_page(uis_page, #panes + 1) + local coord_div = Div{parent=page_div,x=2} + table.insert(panes, coord_div) + local alarms_page = guide_section(sect_construct_data, uis_page, "Alarms", docs.alarms, 100) PushButton{parent=uis,y=3,text="Alarms >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=alarms_page.nav_to} PushButton{parent=uis,text="Annunciators >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=annunc_page.nav_to} + PushButton{parent=uis,text="Coordinator UI >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=coord_page.nav_to} PushButton{parent=uis,text="Pocket UI >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() - PushButton{parent=uis,text="Coordinator UI >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() TextBox{parent=annunc_div,y=1,text="Annunciators",alignment=ALIGN.CENTER} PushButton{parent=annunc_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=uis_page.nav_to} + local fac_annunc_page = guide_section(sect_construct_data, annunc_page, "Facility", docs.annunc.facility.main_section, 110) local unit_gen_page = guide_section(sect_construct_data, annunc_page, "Unit General", docs.annunc.unit.main_section, 170) local unit_rps_page = guide_section(sect_construct_data, annunc_page, "Unit RPS", docs.annunc.unit.rps_section, 100) local unit_rcs_page = guide_section(sect_construct_data, annunc_page, "Unit RCS", docs.annunc.unit.rcs_section, 170) - local fac_annunc_page = guide_section(sect_construct_data, annunc_page, "Facility", docs.annunc.facility.main_section, 110) - - PushButton{parent=annunc_div,y=3,text="Unit General >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=unit_gen_page.nav_to} + PushButton{parent=annunc_div,y=3,text="Facility General >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=fac_annunc_page.nav_to} + PushButton{parent=annunc_div,text="Unit General >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=unit_gen_page.nav_to} PushButton{parent=annunc_div,text="Unit RPS >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=unit_rps_page.nav_to} PushButton{parent=annunc_div,text="Unit RCS >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=unit_rcs_page.nav_to} - PushButton{parent=annunc_div,text="Facility General >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=fac_annunc_page.nav_to} - PushButton{parent=annunc_div,text="Waste & Valves >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + + TextBox{parent=coord_div,y=1,text="Coordinator UI",alignment=ALIGN.CENTER} + PushButton{parent=coord_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=uis_page.nav_to} + + local main_disp_page = guide_section(sect_construct_data, coord_page, "Main Display", docs.c_ui.main, 300) + local flow_disp_page = guide_section(sect_construct_data, coord_page, "Flow Display", docs.annunc.unit.rps_section, 100) + local unit_disp_page = guide_section(sect_construct_data, coord_page, "Unit Display", docs.annunc.unit.rcs_section, 170) + + PushButton{parent=coord_div,y=3,text="Main Display >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_disp_page.nav_to} + PushButton{parent=coord_div,text="Flow Display >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=flow_disp_page.nav_to} + PushButton{parent=coord_div,text="Unit Display >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=unit_disp_page.nav_to} TextBox{parent=fps,y=1,text="Front Panels",alignment=ALIGN.CENTER} PushButton{parent=fps,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index aedf7f3..7cc8814 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -7,7 +7,9 @@ local DOC_ITEM_TYPE = { SECTION = 1, SUBSECTION = 2, TEXT = 3, - LIST = 4 + NOTE = 4, + TIP = 5, + LIST = 6 } ---@enum DOC_LIST_TYPE @@ -51,6 +53,18 @@ local function text(body) table.insert(target, item) end +local function note(body) + ---@class pocket_doc_note + local item = { type = DOC_ITEM_TYPE.NOTE, text = body } + table.insert(target, item) +end + +local function tip(body) + ---@class pocket_doc_tip + local item = { type = DOC_ITEM_TYPE.TIP, text = body } + table.insert(target, item) +end + ---@param type DOC_LIST_TYPE ---@param items table ---@param colors table|nil colors for indicators or nil for normal lists @@ -60,7 +74,7 @@ local function list(type, items, colors) table.insert(target, list_def) end --- important to note in the future: The PLC should always be in a chunk with the reactor to ensure it can protect it on chunk load if you do not keep it all chunk loaded +--- @todo important to note in the future: The PLC should always be in a chunk with the reactor to ensure it can protect it on chunk load if you do not keep it all chunk loaded docs.alarms = {} @@ -154,11 +168,59 @@ doc("as_crit_alarm", "Unit Critical Alarm", "Automatic SCRAM occurred due to cri doc("as_radiation", "Facility Radiation High", "Automatic SCRAM occurred due to high facility radiation levels.") doc("as_gen_fault", "Gen. Control Fault", "Automatic SCRAM occurred due to assigned units being degraded/no longer ready during generation mode. The system will automatically resume (starting with initial ramp) once the problem is resolved.") +docs.c_ui = { + main = {}, flow = {}, unit = {} +} + +target = docs.c_ui.main +sect("Facility Diagram") +text("The facility overview diagram is made up of unit diagrams showing the reactor, boiler(s) if present, and turbine(s). This includes values of various key statistics such as temperatures along with bars showing the fill percentage of the tanks in each multiblock.") +text("Boilers are shown under the reactor, listed in order of index (#1 then #2 below). Turbines are shown to the right, also listed in order of index (indexes are per unit and set in the RTU Gateway configuration).") +text("Pipe connections are visualized with color-coded lines, which are primarily to indicate connections, as not all facilities may use pipes.") +note("If a component you have is not showing up, ensure the Supervisor is configured for your actual cooling configuration.") +sect("Facility Status") +note("The annunciator here is described in Operator UIs > Annunciators.") +doc("ui_fac_scram", "FAC SCRAM", "This SCRAMs all units in the facility.") +doc("ui_fac_ack", "ACK \x13", "This acknowledges (mutes) all alarms for all units in the facility.") +doc("ui_fac_rad", "Radiation", "The facility radiation, which is the maximum of all connected facility radiation monitors (excludes unit monitors).") +doc("ui_fac_linked", "Linked RTUs", "The number of RTU Gateways connected.") +sect("Automatic Control") +text("This interface is used for managing automatic facility control, which only applies to units set via the unit display to be under auto control. This includes setpoints, status, configuration, and control.") +doc("ui_fac_auto_bt", "Burn Target", "When set to Combined Burn Rate mode, assigned units will ramp up to meet this combined target.") +doc("ui_fac_auto_ct", "Charge Target", "When set to Charge Level mode, assigned units will run to reach and maintain this induction matrix charge level.") +doc("ui_fac_auto_gt", "Gen. Target", "When set to Generation Rate mode, assigned units will run to reach and maintain this continous power output, using the induction matrix input rate.") +doc("ui_fac_save", "SAVE", "This saves your configuration without starting control.") +doc("ui_fac_start", "START", "This starts the configured automatic control.") +tip("START also includes the SAVE operation.") +doc("ui_fac_stop", "STOP", "This terminates automatic control, stopping assigned units.") +text("There are four automatic control modes, detailed further in System Usage > Automatic Control") +doc("ui_fac_auto_mmb", "Monitored Max Burn", "This runs all assigned units at the maximum configured rate.") +doc("ui_fac_auto_cbr", "Combined Burn Rate", "This runs assigned units to meet the target combined rate.") +doc("ui_fac_auto_cl", "Charge Level", "This runs assigned units to maintain an induction matrix charge level.") +doc("ui_fac_auto_gr", "Generation Rate", "This runs assigned units to meet a target induction matrix power input rate.") +doc("ui_fac_auto_lim", "Unit Limit", "Each unit can have a limit set that auto control will never exceed.") +doc("ui_fac_unit_ready", "Unit Status Ready", "A unit is only ready for auto control if all multiblocks are formed, online with data received, and there is no RPS trip.") +doc("ui_fac_unit_degraded", "Unit Status Degraded", "A unit is degraded if the reactor, boiler(s), and/or turbine(s) are faulted or not connected.") +sect("Waste Control") +text("Above unit statuses are the unit waste statuses, showing which are set to the auto waste mode and the actual current waste production of that unit.") +text("The facility automatic waste control interface is surrounded by a brown border and lets you configure that system, starting with the requested waste product.") +doc("ui_fac_waste_pu_fall_act", "Fallback Active", "When the system is falling back to plutonium production while SNAs cannot keep up.") +doc("ui_fac_waste_sps_lc_act", "SPS Disabled LC", "When the system is falling back to polonium production to prevent draining all power with the SPS while the induction matrix charge has dropped below 10% and not yet reached 15%.") +doc("ui_fac_waste_pu_fall", "Pu Fallback", "Switch from Po or Antimatter when the SNAs can't keep up (like at night).") +doc("ui_fac_waste_sps_lc", "Low Charge SPS", "Continue running antimatter production even at low induction matrix charge levels (<10%).") +sect("Induction Matrix") +text("The induction matrix statistics are shown at the bottom right, including fill bars for the FILL, I (input rate), and O (output rate).") +text("Averages are computed by the system while other data is directly from the device.") +doc("ui_fac_im_charge", "Charging", "Charge is increasing (more input than output).") +doc("ui_fac_im_charge", "Discharging", "Charge is draining (more output than input).") +doc("ui_fac_im_charge", "Max I/O Rate", "The induction providers are at their maximum rate.") +doc("ui_fac_eta", "ETA", "The ETA is based off a longer average so it may take a minute to stabilize, but will give a rough estimate of time to charge/discharge.") + docs.fp = { common = {}, r_plc = {}, rtu_gw = {}, supervisor = {}, coordinator = {} } ---comp id "This must never be the identical between devices, and that can only happen if you duplicate a computer (such as middle-click on it and place it elsewhere in creative mode)." +--- @todo comp id "This must never be the identical between devices, and that can only happen if you duplicate a computer (such as middle-click on it and place it elsewhere in creative mode)." target = docs.fp.common sect("Core Status") @@ -270,7 +332,6 @@ target = docs.glossary.abbvs doc("G_ACK", "ACK", "Alarm ACKnowledge. Pressing this acknowledges that you understand an alarm occurred and would like to stop the audio tone(s).") doc("G_Auto", "Auto", "Automatic.") doc("G_CRD", "CRD", "Coordinator. Abbreviation for the Coordinator computer.") -doc("G_DBG", "DBG", "Debug. Abbreviation for the debugging sessions from pocket computers found on the Supervisor's front panel.") doc("G_FP", "FP", "Front Panel. See Terminology.") doc("G_Hi", "Hi", "High.") doc("G_Lo", "Lo", "Low.") diff --git a/pocket/ui/pages/guide_section.lua b/pocket/ui/pages/guide_section.lua index 76ceaf6..03c5cf7 100644 --- a/pocket/ui/pages/guide_section.lua +++ b/pocket/ui/pages/guide_section.lua @@ -49,7 +49,7 @@ return function (data, base_page, title, items, scroll_height) local page_end for i = 1, #items do - local item = items[i] ---@type pocket_doc_sect|pocket_doc_subsect|pocket_doc_text|pocket_doc_list + local item = items[i] ---@type pocket_doc_sect|pocket_doc_subsect|pocket_doc_text|pocket_doc_note|pocket_doc_tip|pocket_doc_list if item.type == DOC_TYPE.SECTION then ---@cast item pocket_doc_sect @@ -73,6 +73,8 @@ return function (data, base_page, title, items, scroll_height) local _ = Div{parent=name_list,height=1} end + table.insert(search_db, { string.lower(item.name), item.name, title, view }) + local name_title = Div{parent=name_list,height=1} TextBox{parent=name_title,x=1,text=title_text,fg_bg=cpair(colors.lightGray,colors.black)} PushButton{parent=name_title,x=title_offs,y=1,text=item.name,alignment=ALIGN.LEFT,fg_bg=cpair(colors.green,colors.black),active_fg_bg=btn_active,callback=view} @@ -108,6 +110,19 @@ return function (data, base_page, title, items, scroll_height) TextBox{parent=def_list,text=item.text} + page_end = Div{parent=def_list,height=1,can_focus=true} + elseif item.type == DOC_TYPE.NOTE then + ---@cast item pocket_doc_note + + TextBox{parent=def_list,text=item.text,fg_bg=cpair(colors.gray,colors._INHERIT)} + + page_end = Div{parent=def_list,height=1,can_focus=true} + elseif item.type == DOC_TYPE.TIP then + ---@cast item pocket_doc_tip + + TextBox{parent=def_list,text="TIP!",fg_bg=cpair(colors.orange,colors._INHERIT)} + TextBox{parent=def_list,text=item.text} + page_end = Div{parent=def_list,height=1,can_focus=true} elseif item.type == DOC_TYPE.LIST then ---@cast item pocket_doc_list From 017deec06e367c25f268eb0811352b1743755d3b Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Mon, 1 Sep 2025 17:05:31 -0400 Subject: [PATCH 19/45] #403 unit display documentation --- pocket/ui/apps/guide.lua | 4 ++-- pocket/ui/docs.lua | 28 +++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index f482622..8571de2 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -215,8 +215,8 @@ local function new_view(root) PushButton{parent=coord_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=uis_page.nav_to} local main_disp_page = guide_section(sect_construct_data, coord_page, "Main Display", docs.c_ui.main, 300) - local flow_disp_page = guide_section(sect_construct_data, coord_page, "Flow Display", docs.annunc.unit.rps_section, 100) - local unit_disp_page = guide_section(sect_construct_data, coord_page, "Unit Display", docs.annunc.unit.rcs_section, 170) + local flow_disp_page = guide_section(sect_construct_data, coord_page, "Flow Display", docs.c_ui.flow, 300) + local unit_disp_page = guide_section(sect_construct_data, coord_page, "Unit Display", docs.c_ui.unit, 150) PushButton{parent=coord_div,y=3,text="Main Display >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_disp_page.nav_to} PushButton{parent=coord_div,text="Flow Display >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=flow_disp_page.nav_to} diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index 7cc8814..5b10e66 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -182,7 +182,7 @@ sect("Facility Status") note("The annunciator here is described in Operator UIs > Annunciators.") doc("ui_fac_scram", "FAC SCRAM", "This SCRAMs all units in the facility.") doc("ui_fac_ack", "ACK \x13", "This acknowledges (mutes) all alarms for all units in the facility.") -doc("ui_fac_rad", "Radiation", "The facility radiation, which is the maximum of all connected facility radiation monitors (excludes unit monitors).") +doc("ui_fac_rad", "Radiation", "The facility radiation, which is the current maximum of all connected facility radiation monitors (excludes unit monitors).") doc("ui_fac_linked", "Linked RTUs", "The number of RTU Gateways connected.") sect("Automatic Control") text("This interface is used for managing automatic facility control, which only applies to units set via the unit display to be under auto control. This includes setpoints, status, configuration, and control.") @@ -216,6 +216,32 @@ doc("ui_fac_im_charge", "Discharging", "Charge is draining (more output than inp doc("ui_fac_im_charge", "Max I/O Rate", "The induction providers are at their maximum rate.") doc("ui_fac_eta", "ETA", "The ETA is based off a longer average so it may take a minute to stabilize, but will give a rough estimate of time to charge/discharge.") +target = docs.c_ui.flow +sect("Flow Diagram") +text("TBD") + +target = docs.c_ui.unit +sect("Data Display") +text("The unit monitor contains extensive data information, including annunciator and alarm displays described in the associated sections in the Operator UIs section.") +doc("ui_unit_core", "Core Map", "A core map diagram is shown at the top right, colored by core temperature. The layout is based off of the multiblock dimensions.") +list(DOC_LIST_TYPE.BULLET, { "Gray <= 300\xb0C", "Blue <= 350\xb0C", "Green < 600\xb0C", "Yellow < 100\xb0C", "Orange < 1200\xb0C", "Red < 1300\xb0C", "Pink >= 1300\xb0C" }) +text("Internal tanks (fuel, cooled coolant, heated coolant, and waste) are displayed below the core map, labeled F, C, H, and W, respectively.") +doc("ui_unit_rad", "Radiation", "The unit radiation, which is the current maximum of all connected radiation monitors assigned to this unit.") +text("Multiple other data values are shown but should be self-explanatory.") +sect("Controls") +text("A set of buttons and the burn rate input are used for manual reactor control. When in auto mode, unavailable controls are disabled. The burn rate is only applied after SET is pressed.") +doc("ui_unit_start", "START", "This starts the reactor at the requested burn rate.") +doc("ui_unit_scram", "SCRAM", "This SCRAMs the reactor.") +doc("ui_unit_ack", "ACK \x13", "This acknowledges alarms on this unit.") +doc("ui_unit_reset", "RESET", "This resets the RPS for this unit.") +sect("Auto Control") +text("To put this unit under auto control, select an option other than Manual. You must press SET to apply this, but cannot change this while auto control is active. The priorities available are described in System Usage > Automatic Control.") +doc("ui_unit_prio", "Prio. Group", "This displays the unit's auto control priority group.") +doc("ui_unit_ready", "READY", "This indicates if the unit is ready for auto control. A unit is only ready for auto control if all multiblocks are formed, online with data received, and there is no RPS trip.") +doc("ui_unit_standby", "STANDBY", "This indicates if the unit is set to auto control and that is active, but the auto control does not currently need this reactor to run at the moment, so it is idle.") +sect("Waste Processing") +text("The unit's waste output configuration can be set via these buttons. Auto will put this unit under control of the facility waste control, otherwise the system will always command the requested option for this unit.") + docs.fp = { common = {}, r_plc = {}, rtu_gw = {}, supervisor = {}, coordinator = {} } From 6db6a7d7b7d2e5bd0ad6b414344ebc1a20546f3a Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Mon, 1 Sep 2025 17:54:21 -0400 Subject: [PATCH 20/45] #403 flow display documentation --- pocket/ui/apps/guide.lua | 3 +-- pocket/ui/docs.lua | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index 8571de2..7fc69ed 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -196,7 +196,6 @@ local function new_view(root) PushButton{parent=uis,y=3,text="Alarms >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=alarms_page.nav_to} PushButton{parent=uis,text="Annunciators >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=annunc_page.nav_to} PushButton{parent=uis,text="Coordinator UI >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=coord_page.nav_to} - PushButton{parent=uis,text="Pocket UI >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() TextBox{parent=annunc_div,y=1,text="Annunciators",alignment=ALIGN.CENTER} PushButton{parent=annunc_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=uis_page.nav_to} @@ -215,7 +214,7 @@ local function new_view(root) PushButton{parent=coord_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=uis_page.nav_to} local main_disp_page = guide_section(sect_construct_data, coord_page, "Main Display", docs.c_ui.main, 300) - local flow_disp_page = guide_section(sect_construct_data, coord_page, "Flow Display", docs.c_ui.flow, 300) + local flow_disp_page = guide_section(sect_construct_data, coord_page, "Flow Display", docs.c_ui.flow, 210) local unit_disp_page = guide_section(sect_construct_data, coord_page, "Unit Display", docs.c_ui.unit, 150) PushButton{parent=coord_div,y=3,text="Main Display >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_disp_page.nav_to} diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index 5b10e66..11d778b 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -218,7 +218,39 @@ doc("ui_fac_eta", "ETA", "The ETA is based off a longer average so it may take a target = docs.c_ui.flow sect("Flow Diagram") -text("TBD") +text("The coolant and waste flow monitor is one large P&ID (process and instrumentation diagram) showing an overview of those flows.") +text("Color-coded pipes are used to show the connections, and valve symbols \x10\x11 are used to show valves (redstone controlled pipes).") +doc("ui_flow_rates", "Flow Rates", "Flow rates are always shown below their respective pipes and sourced from devices when possible. The waste flow is based on the reactor burn rate, then everything downstream of the SNAs are based on the SNA production rate.") +doc("ui_flow_valves", "Standard Valves", "Valve naming (PV00-XX) is based on P&ID naming conventions. These count up across the whole facility, and use tags at the end to add clarity.") +note("The indicator next to the label turns on when the associated redstone RTU is connected.") +list(DOC_LIST_TYPE.BULLET, { "PU: Plutonium", "PO: Polonium", "PL: Po Pellets", "AM: Antimatter", "EMC: Emer. Coolant", "AUX: Aux. Coolant" }) +doc("ui_flow_valve_open", "OPEN", "This indicates if the respective valve is commanded open.") +doc("ui_flow_prv", "PRVs", "Pressure Relief Valves (PRVs) are used to show the turbine steam dumping states of each turbine.") +list(DOC_LIST_TYPE.LED, { "Not Dumping", "Dumping Excess", "Dumping" }, { colors.gray, colors.yellow, colors.red }) +sect("SNAs") +text("Solar Neutron Activators are shown on the flow diagram as a combined block due to the large variable count supported.") +tip("SNAs consume 10x the waste as they procuce in antimatter, so take that into account before connecting too many SNAs.") +doc("ui_flow_sna_act", "ACTIVE", "The SNAs have a non-zero total flow.") +doc("ui_flow_sna_cnt", "CNT", "The count of SNAs assigned to the unit.") +doc("ui_flow_sna_peak_o", "PEAK\x1a", "The combined theoretical peak output the SNAs can achive under full sunlight.") +doc("ui_flow_sna_max_o", "MAX \x1a", "The current combined maximum output rate of the SNAs (based on current sunlight).") +doc("ui_flow_sna_max_i", "\x1aMAX", "The computed combined maximum input rate (10x the output rate).") +doc("ui_flow_sna_in", "\x1aIN", "The current input rate into the SNAs.") +sect("Dynamic Tanks") +text("Dynamic tanks configured for the system are listed to the left. The title may start with U for unit tanks or F for facility tanks.") +text("The fill information and water level are shown below the status label.") +doc("ui_flow_dyn_fill", "FILL", "If filling is enabled by the tank mode (via Mekanism UI).") +doc("ui_flow_dyn_empty", "EMPTY", "If emptying is enabled by the tank mode (via Mekanism UI).") +sect("SPS") +doc("ui_flow_sps_in", "Input Rate", "The rate of polonium into the SPS.") +doc("ui_flow_sps_prod", "Production Rate", "The rate of antimatter produced by the SPS.") +sect("Statistics") +text("The sum of all unit's waste rate statistics are shown under the SPS block. These are combined current rates, not long-term sums.") +doc("ui_flow_stat_raw", "RAW WASTE", "The combined rate of raw waste generated by the reactors before processing.") +doc("ui_flow_stat_proc", "PROC. WASTE", "The combined rates of different waste product production. Pu is plutonium, Po is polonium, and PoPl is polonium pellets. Antimatter is shown in the SPS block.") +doc("ui_flow_stat_spent", "SPENT WASTE", "The combined rate of spent waste generated after processing.") +sect("Other Blocks") +text("Other blocks, such as CENTRIFUGE, correspond to devices that are not intended to be connected and/or serve as labels.") target = docs.c_ui.unit sect("Data Display") From dc191278361538f4f6b59b1d652ee445e5a3dc10 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Mon, 1 Sep 2025 18:18:51 -0400 Subject: [PATCH 21/45] #403 guide loading detailed info --- pocket/ui/apps/guide.lua | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index 7fc69ed..fb536bf 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -47,8 +47,16 @@ local function new_view(root) 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.cyan,colors._INHERIT)} + TextBox{parent=load_div,y=12,text="Loading...",alignment=ALIGN.CENTER} + local load_text_1 = TextBox{parent=load_div,y=14,text="",alignment=ALIGN.CENTER,fg_bg=cpair(colors.lightGray,colors._INHERIT)} + local load_text_2 = TextBox{parent=load_div,y=15,text="",alignment=ALIGN.CENTER,fg_bg=cpair(colors.lightGray,colors._INHERIT)} + + -- give more detailed information so the user doesn't give up + local function load_text(a, b) + if a then load_text_1.set_value(a) end + load_text_2.set_value(b or "") + end local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}} @@ -171,6 +179,8 @@ local function new_view(root) util.nop() + load_text("System Usage") + TextBox{parent=use,y=1,text="System Usage",alignment=ALIGN.CENTER} PushButton{parent=use,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} @@ -180,6 +190,8 @@ local function new_view(root) PushButton{parent=use,text="Automatic Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() PushButton{parent=use,text="Waste Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + load_text("Operator UIs") + TextBox{parent=uis,y=1,text="Operator UIs",alignment=ALIGN.CENTER} PushButton{parent=uis,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} @@ -191,12 +203,16 @@ local function new_view(root) local coord_div = Div{parent=page_div,x=2} table.insert(panes, coord_div) + load_text(false, "Alarms") + local alarms_page = guide_section(sect_construct_data, uis_page, "Alarms", docs.alarms, 100) PushButton{parent=uis,y=3,text="Alarms >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=alarms_page.nav_to} PushButton{parent=uis,text="Annunciators >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=annunc_page.nav_to} PushButton{parent=uis,text="Coordinator UI >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=coord_page.nav_to} + load_text(false, "Annunciators") + TextBox{parent=annunc_div,y=1,text="Annunciators",alignment=ALIGN.CENTER} PushButton{parent=annunc_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=uis_page.nav_to} @@ -210,24 +226,36 @@ local function new_view(root) PushButton{parent=annunc_div,text="Unit RPS >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=unit_rps_page.nav_to} PushButton{parent=annunc_div,text="Unit RCS >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=unit_rcs_page.nav_to} + load_text(false, "Coordinator UI") + TextBox{parent=coord_div,y=1,text="Coordinator UI",alignment=ALIGN.CENTER} PushButton{parent=coord_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=uis_page.nav_to} + load_text(false, "Main Display") local main_disp_page = guide_section(sect_construct_data, coord_page, "Main Display", docs.c_ui.main, 300) + load_text(false, "Flow Display") local flow_disp_page = guide_section(sect_construct_data, coord_page, "Flow Display", docs.c_ui.flow, 210) + load_text(false, "Unit Display") local unit_disp_page = guide_section(sect_construct_data, coord_page, "Unit Display", docs.c_ui.unit, 150) PushButton{parent=coord_div,y=3,text="Main Display >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_disp_page.nav_to} PushButton{parent=coord_div,text="Flow Display >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=flow_disp_page.nav_to} PushButton{parent=coord_div,text="Unit Display >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=unit_disp_page.nav_to} + load_text(false, "Front Panels") + TextBox{parent=fps,y=1,text="Front Panels",alignment=ALIGN.CENTER} PushButton{parent=fps,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} + load_text("Front Panels", "Common Items") local fp_common_page = guide_section(sect_construct_data, fps_page, "Common Items", docs.fp.common, 100) + load_text(false, "Reactor PLC") local fp_rplc_page = guide_section(sect_construct_data, fps_page, "Reactor PLC", docs.fp.r_plc, 190) + load_text(false, "RTU Gateway") local fp_rtu_page = guide_section(sect_construct_data, fps_page, "RTU Gateway", docs.fp.rtu_gw, 100) + load_text(false, "Supervisor") local fp_supervisor_page = guide_section(sect_construct_data, fps_page, "Supervisor", docs.fp.supervisor, 160) + load_text(false, "Coordinator") local fp_coordinator_page = guide_section(sect_construct_data, fps_page, "Coordinator", docs.fp.coordinator, 80) PushButton{parent=fps,y=3,text="Common Items >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=fp_common_page.nav_to} @@ -236,6 +264,8 @@ local function new_view(root) PushButton{parent=fps,text="Supervisor >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=fp_supervisor_page.nav_to} PushButton{parent=fps,text="Coordinator >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=fp_coordinator_page.nav_to} + load_text("Glossary") + TextBox{parent=gls,y=1,text="Glossary",alignment=ALIGN.CENTER} PushButton{parent=gls,x=3,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} @@ -245,6 +275,8 @@ local function new_view(root) PushButton{parent=gls,y=3,text="Abbreviations >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=gls_abbv_page.nav_to} PushButton{parent=gls,text="Terminology >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=gls_term_page.nav_to} + load_text("Links") + TextBox{parent=lnk,y=1,text="Wiki and Discord",alignment=ALIGN.CENTER} PushButton{parent=lnk,x=1,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} From 7d0bbafd6cd6592249b7d9c1927d0dad5a7aaee5 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Mon, 1 Sep 2025 19:09:49 -0400 Subject: [PATCH 22/45] #403 manual control guide --- pocket/ui/apps/guide.lua | 17 ++++++++++------ pocket/ui/docs.lua | 43 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index fb536bf..0ba5bb4 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -112,6 +112,8 @@ local function new_view(root) PushButton{parent=home,text="Glossary >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=gls_page.nav_to} PushButton{parent=home,y=10,text="Wiki and Discord >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=lnk_page.nav_to} + load_text("Search") + TextBox{parent=search,y=1,text="Search",alignment=ALIGN.CENTER} local query_field = TextField{parent=search,x=1,y=3,width=18,fg_bg=cpair(colors.white,colors.gray)} @@ -184,9 +186,12 @@ local function new_view(root) TextBox{parent=use,y=1,text="System Usage",alignment=ALIGN.CENTER} PushButton{parent=use,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} + load_text(false, "Manual Control") + local man_ctrl_page = guide_section(sect_construct_data, use_page, "Manual Control", docs.usage.manual, 100) + PushButton{parent=use,y=3,text="Configuring Devices >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() PushButton{parent=use,text="Connecting Devices >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() - PushButton{parent=use,text="Manual Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + PushButton{parent=use,text="Manual Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=man_ctrl_page.nav_to} PushButton{parent=use,text="Automatic Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() PushButton{parent=use,text="Waste Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() @@ -235,19 +240,19 @@ local function new_view(root) local main_disp_page = guide_section(sect_construct_data, coord_page, "Main Display", docs.c_ui.main, 300) load_text(false, "Flow Display") local flow_disp_page = guide_section(sect_construct_data, coord_page, "Flow Display", docs.c_ui.flow, 210) - load_text(false, "Unit Display") - local unit_disp_page = guide_section(sect_construct_data, coord_page, "Unit Display", docs.c_ui.unit, 150) + load_text(false, "Unit Displays") + local unit_disp_page = guide_section(sect_construct_data, coord_page, "Unit Displays", docs.c_ui.unit, 150) PushButton{parent=coord_div,y=3,text="Main Display >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_disp_page.nav_to} PushButton{parent=coord_div,text="Flow Display >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=flow_disp_page.nav_to} - PushButton{parent=coord_div,text="Unit Display >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=unit_disp_page.nav_to} + PushButton{parent=coord_div,text="Unit Displays >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=unit_disp_page.nav_to} - load_text(false, "Front Panels") + load_text("Front Panels") TextBox{parent=fps,y=1,text="Front Panels",alignment=ALIGN.CENTER} PushButton{parent=fps,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} - load_text("Front Panels", "Common Items") + load_text(false, "Common Items") local fp_common_page = guide_section(sect_construct_data, fps_page, "Common Items", docs.fp.common, 100) load_text(false, "Reactor PLC") local fp_rplc_page = guide_section(sect_construct_data, fps_page, "Reactor PLC", docs.fp.r_plc, 190) diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index 11d778b..6c40fc7 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -76,6 +76,29 @@ end --- @todo important to note in the future: The PLC should always be in a chunk with the reactor to ensure it can protect it on chunk load if you do not keep it all chunk loaded +--#region System Usage + +docs.usage = { + manual = {} +} + +target = docs.usage.manual +sect("Overview") +text("Manual reactor control still includes safety checks and monitoring, but the burn rate is not automatically controlled.") +text("A unit is under manual control when the AUTO CTRL option Manual is selected on the unit display.") +note("Specific UIs will not be discussed here. If you need help with the UI, refer to Operator UIs > Coordinator UI > Unit Displays.") +sect("Manual Control") +text("The unit display on the Coordinator is used to run manual control. You may also start/stop and set the burn rate via the Mekanism UI on the Fission Reactor.") +tip("If some controls are grayed out on the unit display, that operation isn't currently available, such as due to the reactor being already started or being under auto control.") +text("Manual control is started by the START button and runs at the commanded burn rate next to it, which can be modified before starting or after having started by selecting a value then pressing SET.") +text("The reactor can be stopped via SCRAM, then the RPS needs to be reset via RESET.") + +--#endregion + +--#region Operator UIs + +--#region Alarms + docs.alarms = {} target = docs.alarms @@ -92,6 +115,10 @@ doc("RPSTransient", "RPS Transient", "Reactor protection system was activated.") doc("RCSTransient", "RCS Transient", "Something is wrong with the reactor coolant system, check RCS indicators for details.") doc("TurbineTripAlarm", "Turbine Trip", "A turbine stopped rotating, likely due to having full energy storage. This will prevent cooling, so it needs to be resolved before using that unit.") +--#endregion + +--#region Annunciators + docs.annunc = { unit = { main_section = {}, rps_section = {}, rcs_section = {} @@ -168,6 +195,10 @@ doc("as_crit_alarm", "Unit Critical Alarm", "Automatic SCRAM occurred due to cri doc("as_radiation", "Facility Radiation High", "Automatic SCRAM occurred due to high facility radiation levels.") doc("as_gen_fault", "Gen. Control Fault", "Automatic SCRAM occurred due to assigned units being degraded/no longer ready during generation mode. The system will automatically resume (starting with initial ramp) once the problem is resolved.") +--#endregion + +--#region Coordinator UI + docs.c_ui = { main = {}, flow = {}, unit = {} } @@ -274,6 +305,12 @@ doc("ui_unit_standby", "STANDBY", "This indicates if the unit is set to auto con sect("Waste Processing") text("The unit's waste output configuration can be set via these buttons. Auto will put this unit under control of the facility waste control, otherwise the system will always command the requested option for this unit.") +--#endregion + +--#endregion + +--#region Front Panels + docs.fp = { common = {}, r_plc = {}, rtu_gw = {}, supervisor = {}, coordinator = {} } @@ -382,6 +419,10 @@ doc("fp_crd_mon_unit", "UNIT X MONITOR", "The connection status of the monitor a sect("API Tab") text("This tab lists connected pocket computers. Refer to the Supervisor PKT tab documentation for details on fields.") +--#endregion + +--#region Glossary + docs.glossary = { abbvs = {}, terms = {} } @@ -421,4 +462,6 @@ doc("G_Tripped", "Tripped", "An alarm condition has been met, and is still met." doc("G_Tripping", "Tripping", "Alarm condition(s) is/are met, but has/have not reached the minimum time before the condition(s) is/are deemed a problem.") doc("G_TurbineTrip", "Turbine Trip", "The turbine stopped, which prevents heated coolant from being cooled. In Mekanism, this would occur when a turbine cannot generate any more energy due to filling its buffer and having no output with any remaining energy capacity.") +--#endregion + return docs From 2cee1ea8953d354557b8d1055190d2c15a6de92a Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Mon, 1 Sep 2025 23:06:13 -0400 Subject: [PATCH 23/45] #403 start of auto and waste control docs --- pocket/ui/apps/guide.lua | 8 ++++++-- pocket/ui/docs.lua | 13 ++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index 0ba5bb4..7bdd5a8 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -188,12 +188,16 @@ local function new_view(root) load_text(false, "Manual Control") local man_ctrl_page = guide_section(sect_construct_data, use_page, "Manual Control", docs.usage.manual, 100) + load_text(false, "Auto Control") + local auto_ctrl_page = guide_section(sect_construct_data, use_page, "Auto Control", docs.usage.auto, 200) + load_text(false, "Waste Control") + local waste_ctrl_page = guide_section(sect_construct_data, use_page, "Waste Control", docs.usage.waste, 100) PushButton{parent=use,y=3,text="Configuring Devices >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() PushButton{parent=use,text="Connecting Devices >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() PushButton{parent=use,text="Manual Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=man_ctrl_page.nav_to} - PushButton{parent=use,text="Automatic Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() - PushButton{parent=use,text="Waste Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + PushButton{parent=use,text="Automatic Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=auto_ctrl_page.nav_to} + PushButton{parent=use,text="Waste Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=waste_ctrl_page.nav_to} load_text("Operator UIs") diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index 6c40fc7..830b7d5 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -79,7 +79,7 @@ end --#region System Usage docs.usage = { - manual = {} + manual = {}, auto = {}, waste = {} } target = docs.usage.manual @@ -93,6 +93,17 @@ tip("If some controls are grayed out on the unit display, that operation isn't c text("Manual control is started by the START button and runs at the commanded burn rate next to it, which can be modified before starting or after having started by selecting a value then pressing SET.") text("The reactor can be stopped via SCRAM, then the RPS needs to be reset via RESET.") +target = docs.usage.auto +sect("Overview") +text("TBD") + +target = docs.usage.waste +sect("Overview") +text("When 'valves' are connected for routing waste, this system can manage which waste product(s) are made. The flow monitor shows the diagram of how valves are meant to be connected.") +text("There are three waste products, listed below with the colors generally associated with them.") +list(DOC_LIST_TYPE.LED, { "Pu - Plutonium", "Po - Polonium", "AM - Antimatter" }, { colors.cyan, colors.green, colors.purple }) +note("The Po and Pu colors are swapped in older versions of Mekanism.") + --#endregion --#region Operator UIs From 4bc5af46ab156885058df4285ff772ea9803eb9c Mon Sep 17 00:00:00 2001 From: Mikayla Date: Tue, 2 Sep 2025 14:17:43 +0000 Subject: [PATCH 24/45] #403 spelling fixes --- pocket/ui/docs.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index 830b7d5..f017632 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -150,7 +150,7 @@ doc("ReactorSCRAM", "Reactor SCRAM", "On if the reactor protection system is hol doc("ManualReactorSCRAM", "Manual Reactor SCRAM", "On if the operator (you) initiated a SCRAM.") doc("AutoReactorSCRAM", "Auto Reactor SCRAM", "On if the automatic control system initiated a SCRAM. The main view screen annunciator will have an indication as to why.") doc("RadiationWarning", "Radiation Warning", "On if radiation levels are above normal. There is likely a leak somewhere, so that should be identified and fixed. Hazmat suit recommended.") -doc("RCPTrip", "RCP Trip", "Reactor coolant pump tripped. This is a technical concept not directly mapping to Mekansim. Here, it indicates if there is either high heated coolant or low cooled coolant that caused an RPS trip. Check the coolant system if this occurs.") +doc("RCPTrip", "RCP Trip", "Reactor coolant pump tripped. This is a technical concept not directly mapping to Mekanism. Here, it indicates if there is either high heated coolant or low cooled coolant that caused an RPS trip. Check the coolant system if this occurs.") doc("RCSFlowLow", "RCS Flow Low", "Indicates if the reactor coolant system flow is low. This is observed when the cooled coolant level in the reactor is dropping. This can occur while a turbine spins up, but if it persists, check that the cooling system is operating properly. This can occur with smaller boilers or when using pipes and not having enough.") doc("CoolantLevelLow", "Coolant Level Low", "On if the reactor coolant level is lower than it should be. Check the coolant system.") doc("ReactorTempHigh", "Reactor Temp. High", "On if the reactor temperature is above expected maximum operating temperature. This is not yet damaging, but should be attended to. Check coolant system.") @@ -230,7 +230,7 @@ sect("Automatic Control") text("This interface is used for managing automatic facility control, which only applies to units set via the unit display to be under auto control. This includes setpoints, status, configuration, and control.") doc("ui_fac_auto_bt", "Burn Target", "When set to Combined Burn Rate mode, assigned units will ramp up to meet this combined target.") doc("ui_fac_auto_ct", "Charge Target", "When set to Charge Level mode, assigned units will run to reach and maintain this induction matrix charge level.") -doc("ui_fac_auto_gt", "Gen. Target", "When set to Generation Rate mode, assigned units will run to reach and maintain this continous power output, using the induction matrix input rate.") +doc("ui_fac_auto_gt", "Gen. Target", "When set to Generation Rate mode, assigned units will run to reach and maintain this continuous power output, using the induction matrix input rate.") doc("ui_fac_save", "SAVE", "This saves your configuration without starting control.") doc("ui_fac_start", "START", "This starts the configured automatic control.") tip("START also includes the SAVE operation.") @@ -271,10 +271,10 @@ doc("ui_flow_prv", "PRVs", "Pressure Relief Valves (PRVs) are used to show the t list(DOC_LIST_TYPE.LED, { "Not Dumping", "Dumping Excess", "Dumping" }, { colors.gray, colors.yellow, colors.red }) sect("SNAs") text("Solar Neutron Activators are shown on the flow diagram as a combined block due to the large variable count supported.") -tip("SNAs consume 10x the waste as they procuce in antimatter, so take that into account before connecting too many SNAs.") +tip("SNAs consume 10x the waste as they produce in antimatter, so take that into account before connecting too many SNAs.") doc("ui_flow_sna_act", "ACTIVE", "The SNAs have a non-zero total flow.") doc("ui_flow_sna_cnt", "CNT", "The count of SNAs assigned to the unit.") -doc("ui_flow_sna_peak_o", "PEAK\x1a", "The combined theoretical peak output the SNAs can achive under full sunlight.") +doc("ui_flow_sna_peak_o", "PEAK\x1a", "The combined theoretical peak output the SNAs can achieve under full sunlight.") doc("ui_flow_sna_max_o", "MAX \x1a", "The current combined maximum output rate of the SNAs (based on current sunlight).") doc("ui_flow_sna_max_i", "\x1aMAX", "The computed combined maximum input rate (10x the output rate).") doc("ui_flow_sna_in", "\x1aIN", "The current input rate into the SNAs.") From 28150042ccd014c0c6e8c09aeef37c68371cb08f Mon Sep 17 00:00:00 2001 From: Mikayla Date: Tue, 2 Sep 2025 15:38:43 +0000 Subject: [PATCH 25/45] #403 waste control usage documentation --- pocket/ui/docs.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index f017632..f2a159e 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -103,6 +103,16 @@ text("When 'valves' are connected for routing waste, this system can manage whic text("There are three waste products, listed below with the colors generally associated with them.") list(DOC_LIST_TYPE.LED, { "Pu - Plutonium", "Po - Polonium", "AM - Antimatter" }, { colors.cyan, colors.green, colors.purple }) note("The Po and Pu colors are swapped in older versions of Mekanism.") +sect("Unit Waste") +text("Units can be set to specific waste products via buttons at the bottom right of a unit display.") +note("Refer to Operator UIs > Coordinator UI > Unit Displays for details.") +text("If a 'Auto' is selected instead of a waste product, that unit's waste will be processed per the facility waste control.") +sect("Facility Waste") +text("Facility waste control adds additional functionality to waste processing through automatic control.") +text("The waste control interface on the main display lets you set a target waste type along with options that can change that based on circumstances.") +note("Refer to Operator UIs > Coordinator UI > Main Display for information on the display and control interface.") +doc("usage_waste_fallback", "Pu Fallback", "This option switches facility waste control to plutonium when the SNAs cannot keep up, such as at night.") +doc("usage_waste_sps_lc", "Low Charge SPS", "This option prevents the facility waste control from stopping antimatter production at low induction matrix charge (< 10%, resumes after reaching 15%).") --#endregion From eb95f2331d5f23593651c133169e538f90ef8720 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Tue, 2 Sep 2025 14:33:10 -0400 Subject: [PATCH 26/45] #403 waste control doc updates --- pocket/ui/docs.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index f2a159e..8512b68 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -106,13 +106,15 @@ note("The Po and Pu colors are swapped in older versions of Mekanism.") sect("Unit Waste") text("Units can be set to specific waste products via buttons at the bottom right of a unit display.") note("Refer to Operator UIs > Coordinator UI > Unit Displays for details.") -text("If a 'Auto' is selected instead of a waste product, that unit's waste will be processed per the facility waste control.") +text("If 'Auto' is selected instead of a waste product, that unit's waste will be processed per the facility waste control.") sect("Facility Waste") text("Facility waste control adds additional functionality to waste processing through automatic control.") text("The waste control interface on the main display lets you set a target waste type along with options that can change that based on circumstances.") note("Refer to Operator UIs > Coordinator UI > Main Display for information on the display and control interface.") doc("usage_waste_fallback", "Pu Fallback", "This option switches facility waste control to plutonium when the SNAs cannot keep up, such as at night.") doc("usage_waste_sps_lc", "Low Charge SPS", "This option prevents the facility waste control from stopping antimatter production at low induction matrix charge (< 10%, resumes after reaching 15%).") +text("With that option enabled, antimatter production will continue. With it disabled, it will switch to polonium if set to antimatter while charge is low.") +note("Pu Fallback takes priority and will switch to plutonium when appropriate regardless of the Low Charge SPS setting.") --#endregion From d0276e149b94b004a2bb79756dcb3e4e26df9952 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Fri, 12 Sep 2025 01:22:27 +0000 Subject: [PATCH 27/45] #400 revert changes --- pocket/ui/apps/devices.lua | 0 scada-common/comms.lua | 3 +-- supervisor/session/pocket.lua | 40 ----------------------------------- 3 files changed, 1 insertion(+), 42 deletions(-) delete mode 100644 pocket/ui/apps/devices.lua diff --git a/pocket/ui/apps/devices.lua b/pocket/ui/apps/devices.lua deleted file mode 100644 index e69de29..0000000 diff --git a/scada-common/comms.lua b/scada-common/comms.lua index 8ce4bd8..18f2d48 100644 --- a/scada-common/comms.lua +++ b/scada-common/comms.lua @@ -55,8 +55,7 @@ local MGMT_TYPE = { DIAG_TONE_GET = 6, -- (API) diagnostic: get alarm tones DIAG_TONE_SET = 7, -- (API) diagnostic: set alarm tones DIAG_ALARM_SET = 8, -- (API) diagnostic: set alarm to simulate audio for - INFO_LIST_CMP = 9, -- (API) info: list all computers on the network - INFO_LIST_PERI = 10 -- (API) info: list all peripherals on the network + INFO_LIST_CMP = 9 -- (API) info: list all computers on the network } ---@enum CRDN_TYPE diff --git a/supervisor/session/pocket.lua b/supervisor/session/pocket.lua index 96ab138..7500110 100644 --- a/supervisor/session/pocket.lua +++ b/supervisor/session/pocket.lua @@ -226,46 +226,6 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, end _send_mgmt(MGMT_TYPE.INFO_LIST_CMP, devices) - elseif pkt.type == MGMT_TYPE.INFO_LIST_PERI then - local data = {} - - local fac = db.facility - local proc = process.get_control_states().process - - -- unit data - for i = 1, #db.units do - local u = db.units[i] - - data[i] = {} - - data[i].boilers = {} - for idx, blr in ipairs(u.boiler_data_tbl) do - data[i].boilers[idx] = {} - - if blr.formed ~= nil then - data[i].boilers[idx] = { blr.formed, blr.build.min_pos, blr.build.max_pos, blr.build.length, blr.build.width, blr.build.height } - end - end - - data[i].turbines = {} - for idx, trb in ipairs(u.turbine_data_tbl) do - data[i].turbines[idx] = {} - - if trb.formed ~= nil then - data[i].turbines[idx] = { trb.formed, trb.build.min_pos, trb.build.max_pos, trb.build.length, trb.build.width, trb.build.height } - end - end - - data[i].tanks = {} - for idx, trb in ipairs(u.tank_data_tbl) do - data[i].turbines[idx] = {} - - if trb.formed ~= nil then - data[i].turbines[idx] = { trb.formed, trb.build.min_pos, trb.build.max_pos, trb.build.length, trb.build.width, trb.build.height } - end - end - end - else log.debug(log_tag .. "handler received unsupported SCADA_MGMT packet type " .. pkt.type) end From aba79e88cf5e0d782e3f5ba09c38b91e04a7a235 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Thu, 11 Sep 2025 22:28:58 -0400 Subject: [PATCH 28/45] #403 auto control usage guide --- pocket/ui/apps/guide.lua | 2 +- pocket/ui/docs.lua | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index 7bdd5a8..ae56f40 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -191,7 +191,7 @@ local function new_view(root) load_text(false, "Auto Control") local auto_ctrl_page = guide_section(sect_construct_data, use_page, "Auto Control", docs.usage.auto, 200) load_text(false, "Waste Control") - local waste_ctrl_page = guide_section(sect_construct_data, use_page, "Waste Control", docs.usage.waste, 100) + local waste_ctrl_page = guide_section(sect_construct_data, use_page, "Waste Control", docs.usage.waste, 120) PushButton{parent=use,y=3,text="Configuring Devices >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() PushButton{parent=use,text="Connecting Devices >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index 8512b68..f513b3b 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -95,7 +95,30 @@ text("The reactor can be stopped via SCRAM, then the RPS needs to be reset via R target = docs.usage.auto sect("Overview") -text("TBD") +text("A main feature of this system is automatic reactor control that supports various managed control modes.") +tip("You should first review the Main Display and Unit Display documentation under Operator UIs > Coordinator before proceeding if you are not familiar with the interfaces.") +sect("Configuration") +note("Configurations cannot be modified while auto control is active.") +doc("usage_auto_assign", "Unit Assignments", "Auto control only applies to units set to a mode other than Manual. To prefer certain units or only use the minimum number necessary, priority groups are used to split up the required burn rate.") +text("Primary units will be used first, followed by secondary, etc. If multiple are assigned to a group, burn rate will be assigned evenly between them.") +text("The next priority group will only be used once the previous one cannot keep up with the total required burn rate for auto control at that moment.") +doc("usage_auto_setpoints", "Setpoints", "Three setpoint spinner inputs are available for the three setpoint-based auto control modes. The system will do its best to meet the requested value, with the current value listed below the input.") +doc("usage_auto_limits", "Unit Limits", "Each unit can be limited to a maximum auto control burn rate to prevent exceeding any safe levels that you know of.") +doc("usage_auto_states", "Unit States", "Any assigned units must be shown as Ready and not Degraded to use auto control. See Operator UIs > Coordinator > Main Display for more.") +sect("Operation Modes") +text("Four auto control modes are available that function based on configurations set on the main display. All modes except Monitored Max Burn will try to only use the primary group until it can't keep up, then the secondary, etc.") +note("No units will be set to a burn rate higher than their limit.") +doc("usage_op_mon_max", "Monitored Max Burn", "This mode runs all units assigned to auto control at their unit limit burn rate regardless of priority group.") +doc("usage_op_com_rate", "Combined Burn Rate", "Assigned units will be commanded to meet the Burn Target setpoint.") +doc("usage_op_chg_level", "Charge Level", "Assigned units will be commanded to bring the induction matrix up to the requested Charge Target.") +doc("usage_op_gen_rate", "Generation Rate", "Assigned units will be commanded to maintain the requested Generation Target.") +note("The rate used is the input rate into the induction matrix, so using other power generation sources may disrupt this control mode.") +sect("Start and Stop") +text("A text box is used to indicate the system status. It will also provide information of why the system has paused control or failed to start.") +text("You cannot start auto control until all assigned units have all their devices connected and functional and the reactor's RPS is not tripped.") +doc("usage_op_save", "SAVE", "SAVE will save the configuration without starting control.") +doc("usage_op_start", "START", "START will attempt to start auto control, which includes first saving the configuration.") +doc("usage_op_stop", "STOP", "STOP will stop all reactors assigned to automatic control.") target = docs.usage.waste sect("Overview") From df9f1195e3d9bb6adf9b0e4ef183862655b25396 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Thu, 11 Sep 2025 22:30:39 -0400 Subject: [PATCH 29/45] #403 fixed scroll bar sticking around sometimes --- pocket/ui/apps/guide.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index ae56f40..6174fa1 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -79,7 +79,7 @@ local function new_view(root) app.set_sidebar(list) page_div = Div{parent=main,y=2} - local p_width = page_div.get_width() - 2 + local p_width = page_div.get_width() - 1 local main_page = app.new_page(nil, 1) local search_page = app.new_page(main_page, 2) From 59f99f70a4ac956e6ccf797a6d759062ca9984a5 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Thu, 11 Sep 2025 23:39:06 -0400 Subject: [PATCH 30/45] #403 basic connections guide --- pocket/ui/apps/guide.lua | 8 ++++++-- pocket/ui/docs.lua | 33 ++++++++++++++++++++++++++++++- pocket/ui/pages/guide_section.lua | 4 ++-- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index 6174fa1..e707392 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -186,6 +186,10 @@ local function new_view(root) TextBox{parent=use,y=1,text="System Usage",alignment=ALIGN.CENTER} PushButton{parent=use,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} + load_text(false, "Connecting Devices") + local conn_dev_page = guide_section(sect_construct_data, use_page, "Connecting Devs", docs.usage.conn, 110) + load_text(false, "Configuring Devices") + local config_dev_page = guide_section(sect_construct_data, use_page, "Configuring Devs", docs.usage.config, 100) load_text(false, "Manual Control") local man_ctrl_page = guide_section(sect_construct_data, use_page, "Manual Control", docs.usage.manual, 100) load_text(false, "Auto Control") @@ -193,8 +197,8 @@ local function new_view(root) load_text(false, "Waste Control") local waste_ctrl_page = guide_section(sect_construct_data, use_page, "Waste Control", docs.usage.waste, 120) - PushButton{parent=use,y=3,text="Configuring Devices >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() - PushButton{parent=use,text="Connecting Devices >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + PushButton{parent=use,y=3,text="Connecting Devices >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=conn_dev_page.nav_to} + PushButton{parent=use,text="Configuring Devices >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=config_dev_page.nav_to} PushButton{parent=use,text="Manual Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=man_ctrl_page.nav_to} PushButton{parent=use,text="Automatic Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=auto_ctrl_page.nav_to} PushButton{parent=use,text="Waste Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=waste_ctrl_page.nav_to} diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index f513b3b..dc268fa 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -79,9 +79,40 @@ end --#region System Usage docs.usage = { - manual = {}, auto = {}, waste = {} + config = {}, conn = {}, manual = {}, auto = {}, waste = {} } +target = docs.usage.conn +sect("Overview") +tip("For the best setup experience, see the Wiki on GitHub or the YouTube channel! This app does not contain all information.") +text("Mekanism devices are connected to ComputerCraft computers that form the SCADA control system.") +sect("Mekanism Conns") +text("Multiblocks and single block devices are both connected directly to a computer by touching it or via wired modems.") +doc("usage_conn_mb", "Multiblocks", "For multiblocks, a logic adapter is used if it exists for that multiblock, otherwise a valve or port block is used.") +text("A wired modem is only connected to the block when you right click it and it gets a red border and you see a message in the chat with the peripheral name.") +tip("Do not connect all peripherals in the system on the same network cable, since Reactor PLCs will grab the first reactor they find and you may accidentally duplicate RTUs.") +sect("Computer Conns") +tip("It helps to be familiar with how ComputerCraft manages peripherals before using this system, though it is not necessary.") +doc("usage_conn_network", "Network", "All computers in the system communicate with each other via wireless or ender modems. Ender modems are preferred due to the unlimited range.") +text("Five different network channels are used and must have the same value for each name across all devices.") +text("For example, the supervisor channel SVR_CHANNEL must be set to the same channel for all devices in your system. Two different named channels should not share the same value (such as SVR_CHANNEL vs CRD_CHANNEL).") +doc("usage_conn_peri", "Peripherals", "ComputerCraft peripherals like monitors and speakers need to touch the computer or be connected via wired modems.") + +target = docs.usage.config +sect("Overview") +tip("For the best setup experience, see the Wiki on GitHub or the YouTube channel! This app does not contain all information.") +text("All devices have a configurator program you can launch by running the 'configure' command.") +sect("Reactor PLC") +text("") +sect("RTU Gateway") +text("") +sect("Supervisor") +text("") +sect("Coordinator") +text("") +sect("Pocket") +text("") + target = docs.usage.manual sect("Overview") text("Manual reactor control still includes safety checks and monitoring, but the burn rate is not automatically controlled.") diff --git a/pocket/ui/pages/guide_section.lua b/pocket/ui/pages/guide_section.lua index 03c5cf7..a3ea333 100644 --- a/pocket/ui/pages/guide_section.lua +++ b/pocket/ui/pages/guide_section.lua @@ -34,13 +34,13 @@ return function (data, base_page, title, items, scroll_height) local section_div = Div{parent=page_div,x=2} table.insert(panes, section_div) TextBox{parent=section_div,y=1,text=title,alignment=ALIGN.CENTER} - PushButton{parent=section_div,x=3,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=base_page.nav_to} + PushButton{parent=section_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=base_page.nav_to} local view_page = app.new_page(section_page, #panes + 1) local section_view_div = Div{parent=page_div,x=2} table.insert(panes, section_view_div) TextBox{parent=section_view_div,y=1,text=title,alignment=ALIGN.CENTER} - PushButton{parent=section_view_div,x=3,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=section_page.nav_to} + PushButton{parent=section_view_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=section_page.nav_to} local name_list = ListBox{parent=section_div,x=1,y=3,scroll_height=60,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} local def_list = ListBox{parent=section_view_div,x=1,y=3,scroll_height=scroll_height,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} From 4f7285573fcacf491e1bbbbdc2ec25b6ab6cec20 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Fri, 12 Sep 2025 00:00:01 -0400 Subject: [PATCH 31/45] #403 work on configuration guide --- pocket/ui/apps/guide.lua | 2 +- pocket/ui/docs.lua | 28 ++++++++++++++++++++++------ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index e707392..0487c3f 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -189,7 +189,7 @@ local function new_view(root) load_text(false, "Connecting Devices") local conn_dev_page = guide_section(sect_construct_data, use_page, "Connecting Devs", docs.usage.conn, 110) load_text(false, "Configuring Devices") - local config_dev_page = guide_section(sect_construct_data, use_page, "Configuring Devs", docs.usage.config, 100) + local config_dev_page = guide_section(sect_construct_data, use_page, "Configuring Devs", docs.usage.config, 200) load_text(false, "Manual Control") local man_ctrl_page = guide_section(sect_construct_data, use_page, "Manual Control", docs.usage.manual, 100) load_text(false, "Auto Control") diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index dc268fa..fc0f8b5 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -79,7 +79,7 @@ end --#region System Usage docs.usage = { - config = {}, conn = {}, manual = {}, auto = {}, waste = {} + conn = {}, config = {}, manual = {}, auto = {}, waste = {} } target = docs.usage.conn @@ -102,16 +102,32 @@ target = docs.usage.config sect("Overview") tip("For the best setup experience, see the Wiki on GitHub or the YouTube channel! This app does not contain all information.") text("All devices have a configurator program you can launch by running the 'configure' command.") +sect("Networking") +text("TBD") +doc("usage_cfg_chan", "Channels", "TBD") +doc("usage_cfg_to", "Conn Timeout", "TBD") +doc("usage_cfg_tr", "Trusted Range", "TBD") +doc("usage_cfg_auth", "Authentication", "TBD") +sect("Logging") +text("Logs are automatically saved to a log.txt file in the root of the computer. You can change the path to it, if it contains verbose debug messages, and if it is appended to or overwritten each time the program runs.") +text("If you intend to be able to share logs, you should leave it to append.") +doc("usage_cfg_log_upload", "Sharing Logs", "To share logs, you would run 'pastebin put log.txt' where your log file is then share the code.") sect("Reactor PLC") -text("") +text("The Reactor PLC must be connected to a single fission reactor that it will manage. Use the configurator to choose if you would like it to operate as networked or not.") +doc("usage_cfg_plc_nonet", "Non-Networked", "This lets you use this device as an advanced standalone safety system rather than a basic redstone breaker for easier safety protection.") +doc("usage_cfg_plc_net", "Networked", "This is the most commonly used mode. The Reactor PLC will require a connection to the Supervisor to operate and will allow usage through that for more advanced functionality.") +doc("usage_cfg_plc_unit", "Unit ID", "When networked, you can set any unit ID ranging from 1 to 4. Multiple Reactor PLCs cannot share the same unit ID.") sect("RTU Gateway") -text("") +text("The RTU Gateway allows connecting multiple RTU interfaces to the SCADA system. These interfaces may be external peripherals or redstone.") +text("All devices except for fission reactors must be connected via an RTU Gateway.") sect("Supervisor") -text("") +text("TBD") sect("Coordinator") -text("") +text("TBD") sect("Pocket") -text("") +text("TBD") +sect("Self-Check") +text("Most application configurators provide a self-check function that will check the validity of your configuration and the network connection. You should run this if you are having issues with that device.") target = docs.usage.manual sect("Overview") From 9e020b28522f94f5162ed7b1860a95dd9a79ad8d Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Fri, 12 Sep 2025 19:24:29 -0400 Subject: [PATCH 32/45] #403 remaining documentation --- pocket/ui/apps/guide.lua | 2 +- pocket/ui/docs.lua | 26 ++++++++++++++++++-------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index 0487c3f..8265937 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -189,7 +189,7 @@ local function new_view(root) load_text(false, "Connecting Devices") local conn_dev_page = guide_section(sect_construct_data, use_page, "Connecting Devs", docs.usage.conn, 110) load_text(false, "Configuring Devices") - local config_dev_page = guide_section(sect_construct_data, use_page, "Configuring Devs", docs.usage.config, 200) + local config_dev_page = guide_section(sect_construct_data, use_page, "Configuring Devs", docs.usage.config, 350) load_text(false, "Manual Control") local man_ctrl_page = guide_section(sect_construct_data, use_page, "Manual Control", docs.usage.manual, 100) load_text(false, "Auto Control") diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index fc0f8b5..809d2d5 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -103,11 +103,10 @@ sect("Overview") tip("For the best setup experience, see the Wiki on GitHub or the YouTube channel! This app does not contain all information.") text("All devices have a configurator program you can launch by running the 'configure' command.") sect("Networking") -text("TBD") -doc("usage_cfg_chan", "Channels", "TBD") -doc("usage_cfg_to", "Conn Timeout", "TBD") -doc("usage_cfg_tr", "Trusted Range", "TBD") -doc("usage_cfg_auth", "Authentication", "TBD") +doc("usage_cfg_chan", "Channels", "Channels are used for the computer to computer communication, described in the connection guide section. Channels with the same name must have the same value across all devices in your system and channels with different names cannot overlap.") +doc("usage_cfg_to", "Conn Timeout", "After this period of time the device will close the connection assuming the other device is unresponsive.") +doc("usage_cfg_tr", "Trusted Range", "Devices further than this block distance away will have any network traffic rejected by this device.") +doc("usage_cfg_auth", "Authentication", "To provide a level of security, you can enable facility-wide authentication by setting keys, which must be the same (and set) on all your devices. This adds computation time to each network transmission so you should only do this if you need it on multiplayer.") sect("Logging") text("Logs are automatically saved to a log.txt file in the root of the computer. You can change the path to it, if it contains verbose debug messages, and if it is appended to or overwritten each time the program runs.") text("If you intend to be able to share logs, you should leave it to append.") @@ -121,13 +120,24 @@ sect("RTU Gateway") text("The RTU Gateway allows connecting multiple RTU interfaces to the SCADA system. These interfaces may be external peripherals or redstone.") text("All devices except for fission reactors must be connected via an RTU Gateway.") sect("Supervisor") -text("TBD") +text("The Supervisor configuration is core to the entire system. If you change things about the system, such as the cooling devices or reactor count, it must be updated here.") +text("This configuration contains many settings that are detailed better in the configurator so they will not be covered here.") +doc("usage_cfg_sv_tanks", "Dynamic Tanks", "Dynamic tanks can be used to provide emergency coolant (and/or auxiliary coolant) to the system. Many layouts are supported by using a mix of facility tanks (connect to 1+ units) and unit tanks (connect to only one unit).") +doc("usage_cfg_sv_aux", "Auxiliary Coolant", "This coolant is enabled at the start of reactors to prevent water levels from dropping in the reactor or boiler while the turbine ramps up. This can be connected to a dynamic tank, a sink, or any other water supply.") sect("Coordinator") -text("TBD") +text("The Coordinator configuration is mainly focused around setting up your displays. This is best to do last after everything else. See the wiki on the GitHub for details on monitor sizing.") +tip("When changing the unit count on the Supervisor, you must also update it on the Coordinator.") +doc("usage_cfg_crd_main", "Main Monitor", "The main monitor contains the main interface and overview. It is always 8 block wide with varying height depending on how many units you have.") +doc("usage_cfg_crd_flow", "Flow Monitor", "The flow monitor contains the waste and coolant flow diagram. It is always 8 block wide with varying height depending on how many units you have.") +doc("usage_cfg_crd_unit", "Unit Monitor", "You need one unit monitor per reactor, and it is always a 4x4 monitor.") +text("Monitors can be connected by direct contact or via wired modems.") +text("Various unit and color options are available to customize the display to your liking. Using energy scales other than RF can impact the precision of your power-related auto control setpoints as RF is always used internally.") sect("Pocket") -text("TBD") +text("You're already here, so not much to mention!") sect("Self-Check") text("Most application configurators provide a self-check function that will check the validity of your configuration and the network connection. You should run this if you are having issues with that device.") +sect("Config Changes") +text("When an update adds or removes or otherwise modifies configuration requirements, you will be warned that you need to re-configure. You will not lose any prior data as updates will preserve configurations, you just need to step through the instructions again to add or change any new data.") target = docs.usage.manual sect("Overview") From 03923850375fed2a8b97ac4f106cff721f4616a6 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Fri, 12 Sep 2025 19:45:15 -0400 Subject: [PATCH 33/45] #622 reinforced induction matrix support --- rtu/config/check.lua | 2 +- rtu/config/peripherals.lua | 14 +++++++------- rtu/startup.lua | 4 ++-- rtu/threads.lua | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/rtu/config/check.lua b/rtu/config/check.lua index fbc7c4c..2956560 100644 --- a/rtu/config/check.lua +++ b/rtu/config/check.lua @@ -200,7 +200,7 @@ local function self_check() else valid = true - if p_type ~= nil and not (p_type == "inductionPort" or p_type == "spsPort") then + if p_type ~= nil and not (p_type == "inductionPort" or p_type == "reinforcedInductionPort" or p_type == "spsPort") then self.self_check_msg("> check " .. entry.name .. " valid...", false, "unrecognized device type") end end diff --git a/rtu/config/peripherals.lua b/rtu/config/peripherals.lua index cbb3a06..1723b02 100644 --- a/rtu/config/peripherals.lua +++ b/rtu/config/peripherals.lua @@ -43,7 +43,7 @@ local self = { local peripherals = {} -local RTU_DEV_TYPES = { "boilerValve", "turbineValve", "dynamicValve", "inductionPort", "spsPort", "solarNeutronActivator", "environmentDetector", "environment_detector" } +local RTU_DEV_TYPES = { "boilerValve", "turbineValve", "dynamicValve", "inductionPort", "reinforcedInductionPort", "spsPort", "solarNeutronActivator", "environmentDetector", "environment_detector" } local NEEDS_UNIT = { "boilerValve", "turbineValve", "dynamicValve", "solarNeutronActivator", "environmentDetector", "environment_detector" } -- create the peripherals configuration view @@ -171,8 +171,8 @@ function peripherals.create(tool_ctl, main_pane, cfg_sys, peri_cfg, style) self.p_assign_btn.redraw() if self.p_assign_btn.get_value() == 1 then self.p_unit.disable() else self.p_unit.enable() end self.p_desc.set_value("You can connect more than one environment detector for a particular unit or the facility. In that case, the maximum radiation reading from those assigned to that particular unit or the facility will be used for alarms and display.") - elseif type == "inductionPort" or type == "spsPort" then - local dev = tri(type == "inductionPort", "induction matrix", "SPS") + elseif type == "inductionPort" or type == "reinforcedInductionPort" or type == "spsPort" then + local dev = tri(type == "inductionPort" or type == "reinforcedInductionPort", "induction matrix", "SPS") self.p_idx.hide(true) self.p_unit.hide(true) self.p_prompt.set_value("This is the " .. dev .. " for the facility.") @@ -212,10 +212,10 @@ function peripherals.create(tool_ctl, main_pane, cfg_sys, peri_cfg, style) tool_ctl.update_peri_list() - TextBox{parent=peri_c_3,x=1,y=1,height=4,text="This feature is intended for advanced users. If you are clicking this just because your device is not shown, follow the connection instructions in 'I don't see my device!'."} - TextBox{parent=peri_c_3,x=1,y=6,height=4,text="Peripheral Name"} - local p_name = TextField{parent=peri_c_3,x=1,y=7,width=49,height=1,max_len=128,fg_bg=bw_fg_bg} - local p_type = Radio2D{parent=peri_c_3,x=1,y=9,rows=4,columns=2,default=1,options=RTU_DEV_TYPES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.purple} + TextBox{parent=peri_c_3,x=1,y=1,height=4,text="This feature is intended for advanced users. If you just can't see your device, click 'I don't see my device!' instead."} + TextBox{parent=peri_c_3,x=1,y=5,height=4,text="Peripheral Name"} + local p_name = TextField{parent=peri_c_3,x=1,y=6,width=49,height=1,max_len=128,fg_bg=bw_fg_bg} + local p_type = Radio2D{parent=peri_c_3,x=1,y=8,rows=5,columns=2,default=1,options=RTU_DEV_TYPES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.purple} local man_p_err = TextBox{parent=peri_c_3,x=8,y=14,width=35,text="Please enter a peripheral name.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} man_p_err.hide(true) diff --git a/rtu/startup.lua b/rtu/startup.lua index d7cfe97..f052ff2 100644 --- a/rtu/startup.lua +++ b/rtu/startup.lua @@ -440,8 +440,8 @@ local function main() println_ts(util.c("sys_config> failed to check if '", name, "' is formed")) log.warning(util.c("sys_config> failed to check if '", name, "' is a formed dynamic tank multiblock")) end - elseif type == "inductionPort" then - -- induction matrix multiblock + elseif type == "inductionPort" or type == "reinforcedInductionPort" then + -- induction matrix multiblock (reinforced or normal) if not validate_assign(true) then return false end rtu_type = RTU_UNIT_TYPE.IMATRIX diff --git a/rtu/threads.lua b/rtu/threads.lua index ac875aa..54dc388 100644 --- a/rtu/threads.lua +++ b/rtu/threads.lua @@ -74,7 +74,7 @@ local function handle_unit_mount(smem, println_ts, iface, type, device, unit) end unit.type = RTU_UNIT_TYPE.DYNAMIC_VALVE - elseif type == "inductionPort" then + elseif type == "inductionPort" or type == "reinforcedInductionPort" then -- induction matrix multiblock if unit.reactor ~= 0 then fail(util.c("induction matrix '", unit.name, "' cannot init, not assigned to facility")) end From 384ebb461fe65fd84cfd47b79b9aecc57678c846 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Fri, 12 Sep 2025 19:50:43 -0400 Subject: [PATCH 34/45] #622 comment change and version increment --- rtu/startup.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtu/startup.lua b/rtu/startup.lua index f052ff2..c085221 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.12.2" +local RTU_VERSION = "v1.12.3" local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE local RTU_HW_STATE = databus.RTU_HW_STATE @@ -441,7 +441,7 @@ local function main() log.warning(util.c("sys_config> failed to check if '", name, "' is a formed dynamic tank multiblock")) end elseif type == "inductionPort" or type == "reinforcedInductionPort" then - -- induction matrix multiblock (reinforced or normal) + -- induction matrix multiblock (normal or reinforced) if not validate_assign(true) then return false end rtu_type = RTU_UNIT_TYPE.IMATRIX From a2ec418d537917f0b1d464e0fa9ce7db892cf86a Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Fri, 12 Sep 2025 19:52:58 -0400 Subject: [PATCH 35/45] luacheck fix --- pocket/ui/apps/guide.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index 8265937..88bf082 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -62,7 +62,6 @@ local function new_view(root) local btn_fg_bg = cpair(colors.cyan, colors.black) local btn_active = cpair(colors.white, colors.black) - local btn_disable = cpair(colors.gray, colors.black) app.set_sidebar({{ label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home }}) From 16f62bc32a9cab06f2784a4faeef98c40317265a Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Fri, 12 Sep 2025 19:54:51 -0400 Subject: [PATCH 36/45] pocket version update --- pocket/startup.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pocket/startup.lua b/pocket/startup.lua index 3b53d2c..d8d7890 100644 --- a/pocket/startup.lua +++ b/pocket/startup.lua @@ -22,7 +22,7 @@ local pocket = require("pocket.pocket") local renderer = require("pocket.renderer") local threads = require("pocket.threads") -local POCKET_VERSION = "v0.13.6-beta" +local POCKET_VERSION = "v1.0.0" local println = util.println local println_ts = util.println_ts From 61f1af7f4e4ca08737a0a638d5fca189f7e079b5 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Fri, 12 Sep 2025 20:20:11 -0400 Subject: [PATCH 37/45] #403 resolved todos in documentation --- pocket/ui/docs.lua | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index 809d2d5..44219ea 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -74,8 +74,6 @@ local function list(type, items, colors) table.insert(target, list_def) end ---- @todo important to note in the future: The PLC should always be in a chunk with the reactor to ensure it can protect it on chunk load if you do not keep it all chunk loaded - --#region System Usage docs.usage = { @@ -103,6 +101,7 @@ sect("Overview") tip("For the best setup experience, see the Wiki on GitHub or the YouTube channel! This app does not contain all information.") text("All devices have a configurator program you can launch by running the 'configure' command.") sect("Networking") +doc("usage_cfg_id", "Computer ID", "A computer ID must NEVER be the identical between devices, which can only happen if you duplicate a computer (such as if you middle-click on it and place it again in creative mode).") doc("usage_cfg_chan", "Channels", "Channels are used for the computer to computer communication, described in the connection guide section. Channels with the same name must have the same value across all devices in your system and channels with different names cannot overlap.") doc("usage_cfg_to", "Conn Timeout", "After this period of time the device will close the connection assuming the other device is unresponsive.") doc("usage_cfg_tr", "Trusted Range", "Devices further than this block distance away will have any network traffic rejected by this device.") @@ -113,6 +112,7 @@ text("If you intend to be able to share logs, you should leave it to append.") doc("usage_cfg_log_upload", "Sharing Logs", "To share logs, you would run 'pastebin put log.txt' where your log file is then share the code.") sect("Reactor PLC") text("The Reactor PLC must be connected to a single fission reactor that it will manage. Use the configurator to choose if you would like it to operate as networked or not.") +tip("The Reactor PLC should always be in a chunk with the reactor to ensure it can protect it on server start and/or chunk load.") doc("usage_cfg_plc_nonet", "Non-Networked", "This lets you use this device as an advanced standalone safety system rather than a basic redstone breaker for easier safety protection.") doc("usage_cfg_plc_net", "Networked", "This is the most commonly used mode. The Reactor PLC will require a connection to the Supervisor to operate and will allow usage through that for more advanced functionality.") doc("usage_cfg_plc_unit", "Unit ID", "When networked, you can set any unit ID ranging from 1 to 4. Multiple Reactor PLCs cannot share the same unit ID.") @@ -418,8 +418,6 @@ docs.fp = { common = {}, r_plc = {}, rtu_gw = {}, supervisor = {}, coordinator = {} } ---- @todo comp id "This must never be the identical between devices, and that can only happen if you duplicate a computer (such as middle-click on it and place it elsewhere in creative mode)." - target = docs.fp.common sect("Core Status") doc("fp_status", "STATUS", "This is always lit, except on the Reactor PLC (see Reactor PLC section).") From 55685fb6a60695a53787ac7a3a1b91dc94cb16a0 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Fri, 12 Sep 2025 20:24:42 -0400 Subject: [PATCH 38/45] #629 home page cleanup --- pocket/ui/pages/home_page.lua | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/pocket/ui/pages/home_page.lua b/pocket/ui/pages/home_page.lua index 900e6e8..2af6f8a 100644 --- a/pocket/ui/pages/home_page.lua +++ b/pocket/ui/pages/home_page.lua @@ -29,9 +29,8 @@ local function new_view(root) local apps_1 = Div{parent=main,x=1,y=1,height=15} local apps_2 = Div{parent=main,x=1,y=1,height=15} - local apps_3 = Div{parent=main,x=1,y=1,height=15} - local panes = { apps_1, apps_2, apps_3 } + local panes = { apps_1, apps_2 } local app_pane = AppMultiPane{parent=main,x=1,y=1,height=18,panes=panes,active_color=colors.lightGray,nav_colors=cpair(colors.lightGray,colors.gray),scroll_nav=true,drag_nav=true,callback=app.switcher} @@ -54,13 +53,9 @@ local function new_view(root) App{parent=apps_1,x=16,y=7,text="\xb6",title="Guide",callback=function()open(APP_ID.GUIDE)end,app_fg_bg=cpair(colors.black,colors.cyan),active_fg_bg=active_fg_bg} App{parent=apps_1,x=2,y=12,text="?",title="About",callback=function()open(APP_ID.ABOUT)end,app_fg_bg=cpair(colors.black,colors.white),active_fg_bg=active_fg_bg} - App{parent=apps_2,x=2,y=2,text="\x08",title="Devices",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.lightGray),active_fg_bg=active_fg_bg} - App{parent=apps_2,x=9,y=2,text="\x1e",title="Rad",callback=function()open(APP_ID.RADMON)end,app_fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=active_fg_bg} - - TextBox{parent=apps_3,text="Diagnostic Apps",x=1,y=2,alignment=ALIGN.CENTER} - - App{parent=apps_3,x=2,y=4,text="\x0f",title="Alarm",callback=function()open(APP_ID.ALARMS)end,app_fg_bg=cpair(colors.black,colors.red),active_fg_bg=active_fg_bg} - App{parent=apps_3,x=9,y=4,text="@",title="Comps",callback=function()open(APP_ID.COMPS)end,app_fg_bg=cpair(colors.black,colors.orange),active_fg_bg=active_fg_bg} + App{parent=apps_2,x=2,y=2,text="\x0f",title="Alarm",callback=function()open(APP_ID.ALARMS)end,app_fg_bg=cpair(colors.black,colors.red),active_fg_bg=active_fg_bg} + App{parent=apps_2,x=9,y=2,text="@",title="Comps",callback=function()open(APP_ID.COMPS)end,app_fg_bg=cpair(colors.black,colors.orange),active_fg_bg=active_fg_bg} + App{parent=apps_2,x=16,y=2,text="\x1e",title="Rad",callback=function()open(APP_ID.RADMON)end,app_fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=active_fg_bg} return main end From afc89ac7278ef7bfe276a960257179854c50e24e Mon Sep 17 00:00:00 2001 From: Mikayla Date: Sat, 13 Sep 2025 00:55:15 +0000 Subject: [PATCH 39/45] #629 code cleanup --- pocket/iocontrol.lua | 1 - pocket/iorx.lua | 1 - pocket/pocket.lua | 9 ++++----- pocket/ui/apps/comps.lua | 1 - pocket/ui/apps/dummy_app.lua | 29 ----------------------------- pocket/ui/apps/facility.lua | 2 +- pocket/ui/apps/guide.lua | 5 ----- pocket/ui/apps/process.lua | 4 ++-- pocket/ui/apps/unit.lua | 3 --- pocket/ui/docs.lua | 4 ++++ pocket/ui/main.lua | 2 -- pocket/ui/pages/dynamic_tank.lua | 6 +++++- pocket/ui/pages/facility_matrix.lua | 4 ++++ pocket/ui/pages/facility_sps.lua | 4 ++++ pocket/ui/pages/guide_section.lua | 6 +++++- pocket/ui/pages/home_page.lua | 2 -- pocket/ui/pages/unit_boiler.lua | 6 +++++- pocket/ui/pages/unit_reactor.lua | 6 +++++- pocket/ui/pages/unit_turbine.lua | 4 ++++ 19 files changed, 43 insertions(+), 56 deletions(-) delete mode 100644 pocket/ui/apps/dummy_app.lua diff --git a/pocket/iocontrol.lua b/pocket/iocontrol.lua index aeb2cd7..a710413 100644 --- a/pocket/iocontrol.lua +++ b/pocket/iocontrol.lua @@ -17,7 +17,6 @@ local ENERGY_UNITS = types.ENERGY_SCALE_UNITS local TEMP_SCALE = types.TEMP_SCALE local TEMP_UNITS = types.TEMP_SCALE_UNITS ----@todo nominal trip time is ping (0ms to 10ms usually) local WARN_TT = 40 local HIGH_TT = 80 diff --git a/pocket/iorx.lua b/pocket/iorx.lua index cbb2c01..bfcc1f9 100644 --- a/pocket/iorx.lua +++ b/pocket/iorx.lua @@ -60,7 +60,6 @@ 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 diff --git a/pocket/pocket.lua b/pocket/pocket.lua index 5e227f3..128ad1c 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -88,7 +88,7 @@ local APP_ID = { -- core UI ROOT = 1, LOADER = 2, - -- main app pages + -- main apps UNITS = 3, FACILITY = 4, CONTROL = 5, @@ -97,12 +97,11 @@ local APP_ID = { GUIDE = 8, ABOUT = 9, RADMON = 10, - -- diagnostic app pages + -- diagnostic apps ALARMS = 11, COMPS = 12, - -- other - DUMMY = 13, - NUM_APPS = 13 + -- count + NUM_APPS = 12 } pocket.APP_ID = APP_ID diff --git a/pocket/ui/apps/comps.lua b/pocket/ui/apps/comps.lua index 5450118..91a9558 100644 --- a/pocket/ui/apps/comps.lua +++ b/pocket/ui/apps/comps.lua @@ -32,7 +32,6 @@ local border = core.border local APP_ID = pocket.APP_ID local lu_col = style.label_unit_pair - local box_label = cpair(colors.lightGray, colors.gray) -- new computer list page view diff --git a/pocket/ui/apps/dummy_app.lua b/pocket/ui/apps/dummy_app.lua deleted file mode 100644 index a564761..0000000 --- a/pocket/ui/apps/dummy_app.lua +++ /dev/null @@ -1,29 +0,0 @@ --- --- Placeholder App --- - -local iocontrol = require("pocket.iocontrol") -local pocket = require("pocket.pocket") - -local core = require("graphics.core") - -local Div = require("graphics.elements.Div") -local TextBox = require("graphics.elements.TextBox") - -local APP_ID = pocket.APP_ID - --- create placeholder app page ----@param root Container parent -local function create_pages(root) - local db = iocontrol.get_db() - - local main = Div{parent=root,x=1,y=1} - - db.nav.register_app(APP_ID.DUMMY, main).new_page(nil, function () end) - - TextBox{parent=main,text="This app is not implemented yet.",x=1,y=2,alignment=core.ALIGN.CENTER} - - TextBox{parent=main,text=" pretend something cool is here \x03",x=1,y=10,alignment=core.ALIGN.CENTER,fg_bg=core.cpair(colors.gray,colors.black)} -end - -return create_pages diff --git a/pocket/ui/apps/facility.lua b/pocket/ui/apps/facility.lua index 65b25e3..9763982 100644 --- a/pocket/ui/apps/facility.lua +++ b/pocket/ui/apps/facility.lua @@ -41,7 +41,7 @@ local grn_ind_s = style.icon_states.grn_ind_s -- new unit page view ---@param root Container parent local function new_view(root) - local db = iocontrol.get_db() + local db = iocontrol.get_db() local frame = Div{parent=root,x=1,y=1} diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index 88bf082..5e627f3 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -9,7 +9,6 @@ local iocontrol = require("pocket.iocontrol") local pocket = require("pocket.pocket") local docs = require("pocket.ui.docs") --- local style = require("pocket.ui.style") local guide_section = require("pocket.ui.pages.guide_section") @@ -31,10 +30,6 @@ 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 - -- new system guide view ---@param root Container parent local function new_view(root) diff --git a/pocket/ui/apps/process.lua b/pocket/ui/apps/process.lua index 6f04d60..ed03d71 100644 --- a/pocket/ui/apps/process.lua +++ b/pocket/ui/apps/process.lua @@ -194,7 +194,7 @@ local function new_view(root) TextBox{parent=c_div,y=1,text="Process Control",alignment=ALIGN.CENTER} - local u_stat = Rectangle{parent=c_div,border=border(1,colors.gray,true),thin=true,width=21,height=5,x=1,y=3,fg_bg=cpair(colors.black,colors.lightGray)} + local u_stat = Rectangle{parent=c_div,border=border(1,colors.gray,true),thin=true,width=21,height=5,x=1,y=3,fg_bg=cpair(colors.black,colors.lightGray)} local stat_line_1 = TextBox{parent=u_stat,x=1,y=1,text="UNKNOWN",alignment=ALIGN.CENTER} local stat_line_2 = TextBox{parent=u_stat,x=1,y=2,text="awaiting data...",height=2,alignment=ALIGN.CENTER,trim_whitespace=true,fg_bg=cpair(colors.gray,colors.lightGray)} @@ -210,7 +210,7 @@ local function new_view(root) end local start = HazardButton{parent=c_div,x=2,y=9,text="START",accent=colors.lightBlue,callback=_start_auto,timeout=3,fg_bg=hzd_fg_bg,dis_colors=dis_colors} - local stop = HazardButton{parent=c_div,x=13,y=9,text="STOP",accent=colors.red,callback=process.process_stop,timeout=3,fg_bg=hzd_fg_bg,dis_colors=dis_colors} + local stop = HazardButton{parent=c_div,x=13,y=9,text="STOP",accent=colors.red,callback=process.process_stop,timeout=3,fg_bg=hzd_fg_bg,dis_colors=dis_colors} db.facility.start_ack = start.on_response db.facility.stop_ack = stop.on_response diff --git a/pocket/ui/apps/unit.lua b/pocket/ui/apps/unit.lua index 304608e..6213f6b 100644 --- a/pocket/ui/apps/unit.lua +++ b/pocket/ui/apps/unit.lua @@ -312,8 +312,6 @@ local function new_view(root) c_emg.register(u_ps, "EmergencyCoolant", c_emg.update) c_mwrf.register(u_ps, "MaxWaterReturnFeed", c_mwrf.update) - -- rcs_div.line_break() - -- TextBox{parent=rcs_div,text="Mismatches",alignment=ALIGN.CENTER,fg_bg=label} local c_cfm = IconIndicator{parent=rcs_div,label="Coolant Feed",states=yel_ind_s} local c_brm = IconIndicator{parent=rcs_div,label="Boil Rate",states=yel_ind_s} local c_sfm = IconIndicator{parent=rcs_div,label="Steam Feed",states=yel_ind_s} @@ -323,7 +321,6 @@ local function new_view(root) c_sfm.register(u_ps, "SteamFeedMismatch", c_sfm.update) rcs_div.line_break() - -- TextBox{parent=rcs_div,text="Aggregate Checks",alignment=ALIGN.CENTER,fg_bg=label} if unit.num_boilers > 0 then local wll = IconIndicator{parent=rcs_div,label="Boiler Water Lo",states=red_ind_s} diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index 44219ea..ec395a7 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -1,3 +1,7 @@ +-- +-- All the text documentation used in the Guide app is defined in this file. +-- + local const = require("scada-common.constants") local docs = {} diff --git a/pocket/ui/main.lua b/pocket/ui/main.lua index 4ea44e1..83a6d9c 100644 --- a/pocket/ui/main.lua +++ b/pocket/ui/main.lua @@ -10,7 +10,6 @@ local pocket = require("pocket.pocket") local comps_app = require("pocket.ui.apps.comps") 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") @@ -78,7 +77,6 @@ local function init(main) sys_apps(page_div) diag_apps(page_div) comps_app(page_div) - dummy_app(page_div) -- verify all apps were created assert(util.table_len(db.nav.get_containers()) == APP_ID.NUM_APPS, "app IDs were not sequential or some apps weren't registered") diff --git a/pocket/ui/pages/dynamic_tank.lua b/pocket/ui/pages/dynamic_tank.lua index 17221a6..6604dfd 100644 --- a/pocket/ui/pages/dynamic_tank.lua +++ b/pocket/ui/pages/dynamic_tank.lua @@ -1,3 +1,7 @@ +-- +-- Dynamic Tank View +-- + local types = require("scada-common.types") local util = require("scada-common.util") @@ -16,7 +20,7 @@ local IconIndicator = require("graphics.elements.indicators.IconIndicator") local StateIndicator = require("graphics.elements.indicators.StateIndicator") local CONTAINER_MODE = types.CONTAINER_MODE -local COOLANT_TYPE = types.COOLANT_TYPE +local COOLANT_TYPE = types.COOLANT_TYPE local ALIGN = core.ALIGN local cpair = core.cpair diff --git a/pocket/ui/pages/facility_matrix.lua b/pocket/ui/pages/facility_matrix.lua index 77640b1..1d3c362 100644 --- a/pocket/ui/pages/facility_matrix.lua +++ b/pocket/ui/pages/facility_matrix.lua @@ -1,3 +1,7 @@ +-- +-- Induction Matrix View +-- + local iocontrol = require("pocket.iocontrol") local style = require("pocket.ui.style") diff --git a/pocket/ui/pages/facility_sps.lua b/pocket/ui/pages/facility_sps.lua index 1de23ca..2de3863 100644 --- a/pocket/ui/pages/facility_sps.lua +++ b/pocket/ui/pages/facility_sps.lua @@ -1,3 +1,7 @@ +-- +-- SPS View +-- + local iocontrol = require("pocket.iocontrol") local style = require("pocket.ui.style") diff --git a/pocket/ui/pages/guide_section.lua b/pocket/ui/pages/guide_section.lua index a3ea333..9bb1df2 100644 --- a/pocket/ui/pages/guide_section.lua +++ b/pocket/ui/pages/guide_section.lua @@ -1,3 +1,7 @@ +-- +-- A Guide App Subsection +-- + local log = require("scada-common.log") local util = require("scada-common.util") @@ -17,7 +21,7 @@ local LED = require("graphics.elements.indicators.LED") local ALIGN = core.ALIGN local cpair = core.cpair -local DOC_TYPE = docs.DOC_ITEM_TYPE +local DOC_TYPE = docs.DOC_ITEM_TYPE local LIST_TYPE = docs.DOC_LIST_TYPE -- new guide documentation section diff --git a/pocket/ui/pages/home_page.lua b/pocket/ui/pages/home_page.lua index 2af6f8a..bb962d5 100644 --- a/pocket/ui/pages/home_page.lua +++ b/pocket/ui/pages/home_page.lua @@ -9,11 +9,9 @@ local core = require("graphics.core") local AppMultiPane = require("graphics.elements.AppMultiPane") local Div = require("graphics.elements.Div") -local TextBox = require("graphics.elements.TextBox") local App = require("graphics.elements.controls.App") -local ALIGN = core.ALIGN local cpair = core.cpair local APP_ID = pocket.APP_ID diff --git a/pocket/ui/pages/unit_boiler.lua b/pocket/ui/pages/unit_boiler.lua index 1790268..344451c 100644 --- a/pocket/ui/pages/unit_boiler.lua +++ b/pocket/ui/pages/unit_boiler.lua @@ -1,3 +1,7 @@ +-- +-- Unit Boiler View +-- + local types = require("scada-common.types") local util = require("scada-common.util") @@ -13,8 +17,8 @@ local TextBox = require("graphics.elements.TextBox") local PushButton = require("graphics.elements.controls.PushButton") local DataIndicator = require("graphics.elements.indicators.DataIndicator") -local StateIndicator = require("graphics.elements.indicators.StateIndicator") local IconIndicator = require("graphics.elements.indicators.IconIndicator") +local StateIndicator = require("graphics.elements.indicators.StateIndicator") local VerticalBar = require("graphics.elements.indicators.VerticalBar") local ALIGN = core.ALIGN diff --git a/pocket/ui/pages/unit_reactor.lua b/pocket/ui/pages/unit_reactor.lua index a3333f5..30a8e36 100644 --- a/pocket/ui/pages/unit_reactor.lua +++ b/pocket/ui/pages/unit_reactor.lua @@ -1,3 +1,7 @@ +-- +-- Unit Reactor View +-- + local types = require("scada-common.types") local util = require("scada-common.util") @@ -13,8 +17,8 @@ local TextBox = require("graphics.elements.TextBox") local PushButton = require("graphics.elements.controls.PushButton") local DataIndicator = require("graphics.elements.indicators.DataIndicator") -local StateIndicator = require("graphics.elements.indicators.StateIndicator") local IconIndicator = require("graphics.elements.indicators.IconIndicator") +local StateIndicator = require("graphics.elements.indicators.StateIndicator") local VerticalBar = require("graphics.elements.indicators.VerticalBar") local ALIGN = core.ALIGN diff --git a/pocket/ui/pages/unit_turbine.lua b/pocket/ui/pages/unit_turbine.lua index 94541ad..9e9a79e 100644 --- a/pocket/ui/pages/unit_turbine.lua +++ b/pocket/ui/pages/unit_turbine.lua @@ -1,3 +1,7 @@ +-- +-- Unit Turbine View +-- + local util = require("scada-common.util") local iocontrol = require("pocket.iocontrol") From a1bb5ce50b6b8d543933cbaa8882a4f716e82e5f Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Fri, 12 Sep 2025 21:46:02 -0400 Subject: [PATCH 40/45] #629 rework of alarm testing app and other cleanup --- pocket/iocontrol.lua | 6 +- pocket/pocket.lua | 13 +- pocket/ui/apps/{sys_apps.lua => about.lua} | 32 ++-- pocket/ui/apps/alarm.lua | 171 +++++++++++++++++++++ pocket/ui/apps/diag_apps.lua | 118 -------------- pocket/ui/main.lua | 8 +- 6 files changed, 198 insertions(+), 150 deletions(-) rename pocket/ui/apps/{sys_apps.lua => about.lua} (85%) create mode 100644 pocket/ui/apps/alarm.lua delete mode 100644 pocket/ui/apps/diag_apps.lua diff --git a/pocket/iocontrol.lua b/pocket/iocontrol.lua index a710413..df3fd41 100644 --- a/pocket/iocontrol.lua +++ b/pocket/iocontrol.lua @@ -85,10 +85,8 @@ function iocontrol.init_core(pkt_comms, nav, cfg) get_tone_states = function () comms.diag__get_alarm_tones() end, - ready_warn = nil, ---@type TextBox - tone_buttons = {}, ---@type SwitchButton[] - alarm_buttons = {}, ---@type Checkbox[] - tone_indicators = {} ---@type IndicatorLight[] indicators to update from supervisor tone states + tone_buttons = {}, ---@type SwitchButton[] + alarm_buttons = {} ---@type Checkbox[] } -- computer list diff --git a/pocket/pocket.lua b/pocket/pocket.lua index 128ad1c..133e26d 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -676,6 +676,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) ---@param packet mgmt_frame|crdn_frame|nil function public.handle_packet(packet) local diag = iocontrol.get_db().diag + local ps = iocontrol.get_db().ps if packet ~= nil then local l_chan = packet.scada_frame.local_channel() @@ -927,23 +928,23 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) elseif packet.type == MGMT_TYPE.DIAG_TONE_GET then if _check_length(packet, 8) then for i = 1, #packet.data do - diag.tone_test.tone_indicators[i].update(packet.data[i] == true) + ps.publish("alarm_tone_" .. i, packet.data[i] == true) end end elseif packet.type == MGMT_TYPE.DIAG_TONE_SET then if packet.length == 1 and packet.data[1] == false then - diag.tone_test.ready_warn.set_value("testing denied") + ps.publish("alarm_ready_warn", "testing denied") log.debug("supervisor SCADA diag tone set failed") elseif packet.length == 2 and type(packet.data[2]) == "table" then local ready = packet.data[1] local states = packet.data[2] - diag.tone_test.ready_warn.set_value(util.trinary(ready, "", "system not idle")) + ps.publish("alarm_ready_warn", util.trinary(ready, "", "system not idle")) for i = 1, #states do if diag.tone_test.tone_buttons[i] ~= nil then diag.tone_test.tone_buttons[i].set_value(states[i] == true) - diag.tone_test.tone_indicators[i].update(states[i] == true) + ps.publish("alarm_tone_" .. i, states[i] == true) end end else @@ -951,13 +952,13 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) end elseif packet.type == MGMT_TYPE.DIAG_ALARM_SET then if packet.length == 1 and packet.data[1] == false then - diag.tone_test.ready_warn.set_value("testing denied") + ps.publish("alarm_ready_warn", "testing denied") log.debug("supervisor SCADA diag alarm set failed") elseif packet.length == 2 and type(packet.data[2]) == "table" then local ready = packet.data[1] local states = packet.data[2] - diag.tone_test.ready_warn.set_value(util.trinary(ready, "", "system not idle")) + ps.publish("alarm_ready_warn", 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/apps/sys_apps.lua b/pocket/ui/apps/about.lua similarity index 85% rename from pocket/ui/apps/sys_apps.lua rename to pocket/ui/apps/about.lua index d797caf..08facc5 100644 --- a/pocket/ui/apps/sys_apps.lua +++ b/pocket/ui/apps/about.lua @@ -1,5 +1,5 @@ -- --- System Apps +-- About Page -- local comms = require("scada-common.comms") @@ -24,25 +24,21 @@ local cpair = core.cpair local APP_ID = pocket.APP_ID --- create system app pages +-- create about page view ---@param root Container parent local function create_pages(root) local db = iocontrol.get_db() - ---------------- - -- About Page -- - ---------------- + local frame = Div{parent=root,x=1,y=1} - local about_root = Div{parent=root,x=1,y=1} + local app = db.nav.register_app(APP_ID.ABOUT, frame) - local about_app = db.nav.register_app(APP_ID.ABOUT, about_root) + local about_page = app.new_page(nil, 1) + local nt_page = app.new_page(about_page, 2) + local fw_page = app.new_page(about_page, 3) + local hw_page = app.new_page(about_page, 4) - local about_page = about_app.new_page(nil, 1) - local nt_page = about_app.new_page(about_page, 2) - local fw_page = about_app.new_page(about_page, 3) - local hw_page = about_app.new_page(about_page, 4) - - local about = Div{parent=about_root,x=1,y=2} + local about = Div{parent=frame,x=1,y=2} TextBox{parent=about,y=1,text="System Information",alignment=ALIGN.CENTER} @@ -58,7 +54,7 @@ local function create_pages(root) local config = pocket.config - local nt_div = Div{parent=about_root,x=1,y=2} + local nt_div = Div{parent=frame,x=1,y=2} TextBox{parent=nt_div,y=1,text="Network Details",alignment=ALIGN.CENTER} PushButton{parent=nt_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=about_page.nav_to} @@ -87,7 +83,7 @@ local function create_pages(root) --#region Firmware Versions - local fw_div = Div{parent=about_root,x=1,y=2} + local fw_div = Div{parent=frame,x=1,y=2} TextBox{parent=fw_div,y=1,text="Firmware Versions",alignment=ALIGN.CENTER} PushButton{parent=fw_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=about_page.nav_to} @@ -123,7 +119,7 @@ local function create_pages(root) --#region Host Versions - local hw_div = Div{parent=about_root,x=1,y=2} + local hw_div = Div{parent=frame,x=1,y=2} TextBox{parent=hw_div,y=1,text="Host Versions",alignment=ALIGN.CENTER} PushButton{parent=hw_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=about_page.nav_to} @@ -138,9 +134,9 @@ local function create_pages(root) --#endregion - local root_pane = MultiPane{parent=about_root,x=1,y=1,panes={about,nt_div,fw_div,hw_div}} + local root_pane = MultiPane{parent=frame,x=1,y=1,panes={about,nt_div,fw_div,hw_div}} - about_app.set_root_pane(root_pane) + app.set_root_pane(root_pane) end return create_pages diff --git a/pocket/ui/apps/alarm.lua b/pocket/ui/apps/alarm.lua new file mode 100644 index 0000000..68c69a5 --- /dev/null +++ b/pocket/ui/apps/alarm.lua @@ -0,0 +1,171 @@ +-- +-- Alarm Test App +-- + +local iocontrol = require("pocket.iocontrol") +local pocket = require("pocket.pocket") + +local core = require("graphics.core") + +local Div = require("graphics.elements.Div") +local MultiPane = require("graphics.elements.MultiPane") +local TextBox = require("graphics.elements.TextBox") + +local IndicatorLight = require("graphics.elements.indicators.IndicatorLight") + +local Checkbox = require("graphics.elements.controls.Checkbox") +local PushButton = require("graphics.elements.controls.PushButton") +local SwitchButton = require("graphics.elements.controls.SwitchButton") + +local ALIGN = core.ALIGN +local cpair = core.cpair + +local APP_ID = pocket.APP_ID + +local c_wht_gray = cpair(colors.white, colors.gray) +local c_red_gray = cpair(colors.red, colors.gray) +local c_yel_gray = cpair(colors.yellow, colors.gray) +local c_blue_gray = cpair(colors.blue, colors.gray) + +-- create alarm test page view +---@param root Container parent +local function new_view(root) + local db = iocontrol.get_db() + local ps = db.ps + local ttest = db.diag.tone_test + + local frame = Div{parent=root,x=1,y=1} + + local app = db.nav.register_app(APP_ID.ALARMS, frame, nil, true) + + local main = Div{parent=frame,x=1,y=1} + local page_div = Div{parent=main,y=2,width=main.get_width()} + + --#region alarm testing + + local alarm_page = app.new_page(nil, 1) + alarm_page.tasks = { db.diag.tone_test.get_tone_states } + + local alarms_div = Div{parent=page_div} + + TextBox{parent=alarms_div,text="Alarm Sounder Tests",alignment=ALIGN.CENTER} + + local alarm_ready_warn = TextBox{parent=alarms_div,y=2,text="",alignment=ALIGN.CENTER,fg_bg=cpair(colors.yellow,colors.black)} + alarm_ready_warn.register(ps, "alarm_ready_warn", alarm_ready_warn.set_value) + + local alarm_page_states = Div{parent=alarms_div,x=2,y=3,height=5,width=8} + + TextBox{parent=alarm_page_states,text="States",alignment=ALIGN.CENTER} + local ta_1 = IndicatorLight{parent=alarm_page_states,label="1",colors=c_blue_gray} + local ta_2 = IndicatorLight{parent=alarm_page_states,label="2",colors=c_blue_gray} + local ta_3 = IndicatorLight{parent=alarm_page_states,label="3",colors=c_blue_gray} + local ta_4 = IndicatorLight{parent=alarm_page_states,label="4",colors=c_blue_gray} + local ta_5 = IndicatorLight{parent=alarm_page_states,x=6,y=2,label="5",colors=c_blue_gray} + local ta_6 = IndicatorLight{parent=alarm_page_states,x=6,label="6",colors=c_blue_gray} + local ta_7 = IndicatorLight{parent=alarm_page_states,x=6,label="7",colors=c_blue_gray} + local ta_8 = IndicatorLight{parent=alarm_page_states,x=6,label="8",colors=c_blue_gray} + + local ta = { ta_1, ta_2, ta_3, ta_4, ta_5, ta_6, ta_7, ta_8 } + + for i = 1, #ta do + ta[i].register(ps, "alarm_tone_" .. i, ta[i].update) + end + + local alarms = Div{parent=alarms_div,x=11,y=3,height=15,fg_bg=cpair(colors.lightGray,colors.black)} + + TextBox{parent=alarms,text="Alarms (\x13)",alignment=ALIGN.CENTER,fg_bg=alarms_div.get_fg_bg()} + + local alarm_btns = {} + alarm_btns[1] = Checkbox{parent=alarms,label="BREACH",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_breach} + alarm_btns[2] = Checkbox{parent=alarms,label="RADIATION",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_rad} + alarm_btns[3] = Checkbox{parent=alarms,label="RCT LOST",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_lost} + alarm_btns[4] = Checkbox{parent=alarms,label="CRIT DAMAGE",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_crit} + alarm_btns[5] = Checkbox{parent=alarms,label="DAMAGE",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_dmg} + alarm_btns[6] = Checkbox{parent=alarms,label="OVER TEMP",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_overtemp} + alarm_btns[7] = Checkbox{parent=alarms,label="HIGH TEMP",min_width=15,box_fg_bg=c_yel_gray,callback=ttest.test_hightemp} + alarm_btns[8] = Checkbox{parent=alarms,label="WASTE LEAK",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_wasteleak} + alarm_btns[9] = Checkbox{parent=alarms,label="WASTE HIGH",min_width=15,box_fg_bg=c_yel_gray,callback=ttest.test_highwaste} + alarm_btns[10] = Checkbox{parent=alarms,label="RPS TRANS",min_width=15,box_fg_bg=c_yel_gray,callback=ttest.test_rps} + alarm_btns[11] = Checkbox{parent=alarms,label="RCS TRANS",min_width=15,box_fg_bg=c_yel_gray,callback=ttest.test_rcs} + alarm_btns[12] = Checkbox{parent=alarms,label="TURBINE TRP",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_turbinet} + + ttest.alarm_buttons = alarm_btns + + local function stop_all_alarms() + for i = 1, #alarm_btns do alarm_btns[i].set_value(false) end + ttest.stop_alarms() + end + + PushButton{parent=alarms,x=3,y=15,text="STOP \x13",min_width=8,fg_bg=cpair(colors.black,colors.red),active_fg_bg=c_wht_gray,callback=stop_all_alarms} + + --#endregion + + --#region direct tone testing + + local tones_page = app.new_page(nil, 2) + tones_page.tasks = { db.diag.tone_test.get_tone_states } + + local tones_div = Div{parent=page_div} + + TextBox{parent=tones_div,text="Alarm Sounder Tests",alignment=ALIGN.CENTER} + + local tone_ready_warn = TextBox{parent=tones_div,y=2,text="",alignment=ALIGN.CENTER,fg_bg=cpair(colors.yellow,colors.black)} + tone_ready_warn.register(ps, "alarm_ready_warn", tone_ready_warn.set_value) + + local tone_page_states = Div{parent=tones_div,x=3,y=3,height=5,width=8} + + TextBox{parent=tone_page_states,text="States",alignment=ALIGN.CENTER} + local tt_1 = IndicatorLight{parent=tone_page_states,label="1",colors=c_blue_gray} + local tt_2 = IndicatorLight{parent=tone_page_states,label="2",colors=c_blue_gray} + local tt_3 = IndicatorLight{parent=tone_page_states,label="3",colors=c_blue_gray} + local tt_4 = IndicatorLight{parent=tone_page_states,label="4",colors=c_blue_gray} + local tt_5 = IndicatorLight{parent=tone_page_states,x=6,y=2,label="5",colors=c_blue_gray} + local tt_6 = IndicatorLight{parent=tone_page_states,x=6,label="6",colors=c_blue_gray} + local tt_7 = IndicatorLight{parent=tone_page_states,x=6,label="7",colors=c_blue_gray} + local tt_8 = IndicatorLight{parent=tone_page_states,x=6,label="8",colors=c_blue_gray} + + local tt = { tt_1, tt_2, tt_3, tt_4, tt_5, tt_6, tt_7, tt_8 } + + for i = 1, #tt do + tt[i].register(ps, "alarm_tone_" .. i, tt[i].update) + end + + local tones = Div{parent=tones_div,x=14,y=3,height=10,width=8,fg_bg=cpair(colors.black,colors.yellow)} + + TextBox{parent=tones,text="Tones",alignment=ALIGN.CENTER,fg_bg=tones_div.get_fg_bg()} + + local test_btns = {} + test_btns[1] = SwitchButton{parent=tones,text="TEST 1",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_1} + test_btns[2] = SwitchButton{parent=tones,text="TEST 2",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_2} + test_btns[3] = SwitchButton{parent=tones,text="TEST 3",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_3} + test_btns[4] = SwitchButton{parent=tones,text="TEST 4",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_4} + test_btns[5] = SwitchButton{parent=tones,text="TEST 5",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_5} + test_btns[6] = SwitchButton{parent=tones,text="TEST 6",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_6} + test_btns[7] = SwitchButton{parent=tones,text="TEST 7",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_7} + test_btns[8] = SwitchButton{parent=tones,text="TEST 8",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_8} + + ttest.tone_buttons = test_btns + + local function stop_all_tones() + for i = 1, #test_btns do test_btns[i].set_value(false) end + ttest.stop_tones() + end + + PushButton{parent=tones,text="STOP",min_width=8,active_fg_bg=c_wht_gray,fg_bg=cpair(colors.black,colors.red),callback=stop_all_tones} + + --#endregion + + -- setup multipane + local u_pane = MultiPane{parent=page_div,x=1,y=1,panes={alarms_div,tones_div}} + app.set_root_pane(u_pane) + + local list = { + { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home }, + { label = " \x13 ", color = core.cpair(colors.black, colors.red), callback = function () app.switcher(1) end }, + { label = " \x0f ", color = core.cpair(colors.black, colors.yellow), callback = function () app.switcher(2) end } + } + + app.set_sidebar(list) +end + +return new_view diff --git a/pocket/ui/apps/diag_apps.lua b/pocket/ui/apps/diag_apps.lua deleted file mode 100644 index ba2bed3..0000000 --- a/pocket/ui/apps/diag_apps.lua +++ /dev/null @@ -1,118 +0,0 @@ --- --- Diagnostic Apps --- - -local iocontrol = require("pocket.iocontrol") -local pocket = require("pocket.pocket") - -local core = require("graphics.core") - -local Div = require("graphics.elements.Div") -local TextBox = require("graphics.elements.TextBox") - -local IndicatorLight = require("graphics.elements.indicators.IndicatorLight") - -local Checkbox = require("graphics.elements.controls.Checkbox") -local PushButton = require("graphics.elements.controls.PushButton") -local SwitchButton = require("graphics.elements.controls.SwitchButton") - -local ALIGN = core.ALIGN -local cpair = core.cpair - -local APP_ID = pocket.APP_ID - --- create diagnostic app pages ----@param root Container parent -local function create_pages(root) - local db = iocontrol.get_db() - - ------------------------ - -- Alarm Testing Page -- - ------------------------ - - local alarm_test = Div{parent=root,x=1,y=1} - - local alarm_app = db.nav.register_app(APP_ID.ALARMS, alarm_test, nil, true) - - local page = alarm_app.new_page(nil, function () end) - page.tasks = { db.diag.tone_test.get_tone_states } - - local ttest = db.diag.tone_test - - local c_wht_gray = cpair(colors.white, colors.gray) - local c_red_gray = cpair(colors.red, colors.gray) - local c_yel_gray = cpair(colors.yellow, colors.gray) - local c_blue_gray = cpair(colors.blue, colors.gray) - - local audio = Div{parent=alarm_test,x=1,y=1} - - TextBox{parent=audio,y=1,text="Alarm Sounder Tests",alignment=ALIGN.CENTER} - - ttest.ready_warn = TextBox{parent=audio,y=2,text="",alignment=ALIGN.CENTER,fg_bg=cpair(colors.yellow,colors.black)} - - local tones = Div{parent=audio,x=2,y=3,height=10,width=8,fg_bg=cpair(colors.black,colors.yellow)} - - TextBox{parent=tones,text="Tones",alignment=ALIGN.CENTER,fg_bg=audio.get_fg_bg()} - - local test_btns = {} - test_btns[1] = SwitchButton{parent=tones,text="TEST 1",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_1} - test_btns[2] = SwitchButton{parent=tones,text="TEST 2",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_2} - test_btns[3] = SwitchButton{parent=tones,text="TEST 3",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_3} - test_btns[4] = SwitchButton{parent=tones,text="TEST 4",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_4} - test_btns[5] = SwitchButton{parent=tones,text="TEST 5",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_5} - test_btns[6] = SwitchButton{parent=tones,text="TEST 6",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_6} - test_btns[7] = SwitchButton{parent=tones,text="TEST 7",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_7} - test_btns[8] = SwitchButton{parent=tones,text="TEST 8",min_width=8,active_fg_bg=c_wht_gray,callback=ttest.test_8} - - ttest.tone_buttons = test_btns - - local function stop_all_tones() - for i = 1, #test_btns do test_btns[i].set_value(false) end - ttest.stop_tones() - end - - PushButton{parent=tones,text="STOP",min_width=8,active_fg_bg=c_wht_gray,fg_bg=cpair(colors.black,colors.red),callback=stop_all_tones} - - local alarms = Div{parent=audio,x=11,y=3,height=15,fg_bg=cpair(colors.lightGray,colors.black)} - - TextBox{parent=alarms,text="Alarms (\x13)",alignment=ALIGN.CENTER,fg_bg=audio.get_fg_bg()} - - local alarm_btns = {} - alarm_btns[1] = Checkbox{parent=alarms,label="BREACH",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_breach} - alarm_btns[2] = Checkbox{parent=alarms,label="RADIATION",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_rad} - alarm_btns[3] = Checkbox{parent=alarms,label="RCT LOST",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_lost} - alarm_btns[4] = Checkbox{parent=alarms,label="CRIT DAMAGE",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_crit} - alarm_btns[5] = Checkbox{parent=alarms,label="DAMAGE",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_dmg} - alarm_btns[6] = Checkbox{parent=alarms,label="OVER TEMP",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_overtemp} - alarm_btns[7] = Checkbox{parent=alarms,label="HIGH TEMP",min_width=15,box_fg_bg=c_yel_gray,callback=ttest.test_hightemp} - alarm_btns[8] = Checkbox{parent=alarms,label="WASTE LEAK",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_wasteleak} - alarm_btns[9] = Checkbox{parent=alarms,label="WASTE HIGH",min_width=15,box_fg_bg=c_yel_gray,callback=ttest.test_highwaste} - alarm_btns[10] = Checkbox{parent=alarms,label="RPS TRANS",min_width=15,box_fg_bg=c_yel_gray,callback=ttest.test_rps} - alarm_btns[11] = Checkbox{parent=alarms,label="RCS TRANS",min_width=15,box_fg_bg=c_yel_gray,callback=ttest.test_rcs} - alarm_btns[12] = Checkbox{parent=alarms,label="TURBINE TRP",min_width=15,box_fg_bg=c_red_gray,callback=ttest.test_turbinet} - - ttest.alarm_buttons = alarm_btns - - local function stop_all_alarms() - for i = 1, #alarm_btns do alarm_btns[i].set_value(false) end - ttest.stop_alarms() - end - - PushButton{parent=alarms,x=3,y=15,text="STOP \x13",min_width=8,fg_bg=cpair(colors.black,colors.red),active_fg_bg=c_wht_gray,callback=stop_all_alarms} - - local states = Div{parent=audio,x=2,y=14,height=5,width=8} - - TextBox{parent=states,text="States",alignment=ALIGN.CENTER} - local t_1 = IndicatorLight{parent=states,label="1",colors=c_blue_gray} - local t_2 = IndicatorLight{parent=states,label="2",colors=c_blue_gray} - local t_3 = IndicatorLight{parent=states,label="3",colors=c_blue_gray} - local t_4 = IndicatorLight{parent=states,label="4",colors=c_blue_gray} - local t_5 = IndicatorLight{parent=states,x=6,y=2,label="5",colors=c_blue_gray} - local t_6 = IndicatorLight{parent=states,x=6,label="6",colors=c_blue_gray} - local t_7 = IndicatorLight{parent=states,x=6,label="7",colors=c_blue_gray} - local t_8 = IndicatorLight{parent=states,x=6,label="8",colors=c_blue_gray} - - ttest.tone_indicators = { t_1, t_2, t_3, t_4, t_5, t_6, t_7, t_8 } -end - -return create_pages diff --git a/pocket/ui/main.lua b/pocket/ui/main.lua index 83a6d9c..92e576e 100644 --- a/pocket/ui/main.lua +++ b/pocket/ui/main.lua @@ -7,15 +7,15 @@ local util = require("scada-common.util") local iocontrol = require("pocket.iocontrol") local pocket = require("pocket.pocket") +local alarm_app = require("pocket.ui.apps.alarm") local comps_app = require("pocket.ui.apps.comps") local control_app = require("pocket.ui.apps.control") -local diag_apps = require("pocket.ui.apps.diag_apps") 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") local rad_app = require("pocket.ui.apps.radiation") -local sys_apps = require("pocket.ui.apps.sys_apps") +local about_app = require("pocket.ui.apps.about") local unit_app = require("pocket.ui.apps.unit") local waste_app = require("pocket.ui.apps.waste") @@ -74,8 +74,8 @@ local function init(main) guide_app(page_div) rad_app(page_div) loader_app(page_div) - sys_apps(page_div) - diag_apps(page_div) + about_app(page_div) + alarm_app(page_div) comps_app(page_div) -- verify all apps were created From 6ad63aedebf52569bcefcb519ff71dea80f9d1b8 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Fri, 12 Sep 2025 21:49:08 -0400 Subject: [PATCH 41/45] include reordering --- pocket/ui/main.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pocket/ui/main.lua b/pocket/ui/main.lua index 92e576e..001b314 100644 --- a/pocket/ui/main.lua +++ b/pocket/ui/main.lua @@ -7,6 +7,7 @@ local util = require("scada-common.util") local iocontrol = require("pocket.iocontrol") local pocket = require("pocket.pocket") +local about_app = require("pocket.ui.apps.about") local alarm_app = require("pocket.ui.apps.alarm") local comps_app = require("pocket.ui.apps.comps") local control_app = require("pocket.ui.apps.control") @@ -15,7 +16,6 @@ local guide_app = require("pocket.ui.apps.guide") local loader_app = require("pocket.ui.apps.loader") local process_app = require("pocket.ui.apps.process") local rad_app = require("pocket.ui.apps.radiation") -local about_app = require("pocket.ui.apps.about") local unit_app = require("pocket.ui.apps.unit") local waste_app = require("pocket.ui.apps.waste") From e7a859438e580c6fdc825785369f5637c79fd775 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Fri, 12 Sep 2025 21:54:58 -0400 Subject: [PATCH 42/45] added additional terms to glossary --- pocket/ui/apps/guide.lua | 2 +- pocket/ui/docs.lua | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index 5e627f3..0e97295 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -277,7 +277,7 @@ local function new_view(root) PushButton{parent=gls,x=3,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} local gls_abbv_page = guide_section(sect_construct_data, gls_page, "Abbreviations", docs.glossary.abbvs, 140) - local gls_term_page = guide_section(sect_construct_data, gls_page, "Terminology", docs.glossary.terms, 100) + local gls_term_page = guide_section(sect_construct_data, gls_page, "Terminology", docs.glossary.terms, 120) PushButton{parent=gls,y=3,text="Abbreviations >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=gls_abbv_page.nav_to} PushButton{parent=gls,text="Terminology >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=gls_term_page.nav_to} diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index ec395a7..ee98b5a 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -554,6 +554,8 @@ doc("G_UI", "UI", "User Interface.") target = docs.glossary.terms doc("G_AssignedUnit", "Assigned Unit", "A unit that is assigned to an automatic control group (not assigned to Manual).") +doc("G_AuxCoolant", "Auxiliary Coolant", "A separate water input to the reactor or boiler to supplement return water from a turbine during initial ramp-up.") +doc("G_EmerCoolant", "Emergency Coolant", "A dynamic tank or other water supply used when a reactor or boiler does not have enough water to stop a runaway reactor overheat.") doc("G_Fault", "Fault", "Something has gone wrong and/or failed to function.") doc("G_FrontPanel", "Front Panel", "A basic interface on the front of a device for viewing and sometimes modifying its state. This is what you see when looking at a computer running one of the SCADA applications.") doc("G_HighHigh", "High High", "Very High.") From 20f949a9dd5b0e4428594ffae1793d29ca2c8cc1 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 13 Sep 2025 15:50:25 -0400 Subject: [PATCH 43/45] fixed pocket main thread crash on nil current page, added info page to alarm test app --- pocket/pocket.lua | 4 ++-- pocket/startup.lua | 2 +- pocket/threads.lua | 6 ++++-- pocket/ui/apps/alarm.lua | 17 +++++++++++++++-- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/pocket/pocket.lua b/pocket/pocket.lua index 133e26d..3119e85 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -150,7 +150,7 @@ function pocket.init_nav(smem) ---@class pocket_app local app = { loaded = false, - cur_page = nil, ---@type nav_tree_page + cur_page = nil, ---@type nav_tree_page|nil pane = pane, paned_pages = {}, ---@type nav_tree_page[] sidebar_items = {} ---@type sidebar_entry[] @@ -348,7 +348,7 @@ function pocket.init_nav(smem) function nav.get_containers() return self.containers end -- get the currently active page - ---@return nav_tree_page + ---@return nav_tree_page|nil function nav.get_current_page() return self.apps[self.cur_app].get_current_page() end diff --git a/pocket/startup.lua b/pocket/startup.lua index d8d7890..cbd6803 100644 --- a/pocket/startup.lua +++ b/pocket/startup.lua @@ -22,7 +22,7 @@ local pocket = require("pocket.pocket") local renderer = require("pocket.renderer") local threads = require("pocket.threads") -local POCKET_VERSION = "v1.0.0" +local POCKET_VERSION = "v1.0.1" local println = util.println local println_ts = util.println_ts diff --git a/pocket/threads.lua b/pocket/threads.lua index e5d0ea7..120c8dd 100644 --- a/pocket/threads.lua +++ b/pocket/threads.lua @@ -58,8 +58,10 @@ function threads.thread__main(smem) pocket_comms.link_update() -- update any tasks for the active page - local page_tasks = nav.get_current_page().tasks - for i = 1, #page_tasks do page_tasks[i]() end + if nav.get_current_page() then + local page_tasks = nav.get_current_page().tasks + for i = 1, #page_tasks do page_tasks[i]() end + end loop_clock.start() elseif sv_wd.is_timer(param1) then diff --git a/pocket/ui/apps/alarm.lua b/pocket/ui/apps/alarm.lua index 68c69a5..a6dc573 100644 --- a/pocket/ui/apps/alarm.lua +++ b/pocket/ui/apps/alarm.lua @@ -155,14 +155,27 @@ local function new_view(root) --#endregion + --#region info page + + app.new_page(nil, 3) + + local info_div = Div{parent=page_div} + + TextBox{parent=info_div,x=2,y=1,text="This app provides tools to test alarm sounds by alarm and by tone (1-8)."} + TextBox{parent=info_div,x=2,y=6,text="The system must be idle (all units stopped with no alarms active) for testing to run."} + TextBox{parent=info_div,x=2,y=12,text="Currently, testing will be denied unless you have a Facility Authentication Key set (this will change in the future)."} + + --#endregion + -- setup multipane - local u_pane = MultiPane{parent=page_div,x=1,y=1,panes={alarms_div,tones_div}} + local u_pane = MultiPane{parent=page_div,x=1,y=1,panes={alarms_div,tones_div,info_div}} app.set_root_pane(u_pane) local list = { { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home }, { label = " \x13 ", color = core.cpair(colors.black, colors.red), callback = function () app.switcher(1) end }, - { label = " \x0f ", color = core.cpair(colors.black, colors.yellow), callback = function () app.switcher(2) end } + { label = " \x0f ", color = core.cpair(colors.black, colors.yellow), callback = function () app.switcher(2) end }, + { label = " ? ", color = core.cpair(colors.black, colors.blue), callback = function () app.switcher(3) end } } app.set_sidebar(list) From ff68eeae1a65b0441afb3a26fb154e7c96643213 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 13 Sep 2025 16:04:45 -0400 Subject: [PATCH 44/45] #629 removed unused render commands --- pocket/pocket.lua | 2 -- pocket/startup.lua | 2 +- pocket/threads.lua | 3 --- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/pocket/pocket.lua b/pocket/pocket.lua index 3119e85..e7e6ed8 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -17,8 +17,6 @@ local LINK_STATE = iocontrol.LINK_STATE local pocket = {} local MQ__RENDER_CMD = { - UNLOAD_SV_APPS = 1, - UNLOAD_API_APPS = 2 } local MQ__RENDER_DATA = { diff --git a/pocket/startup.lua b/pocket/startup.lua index cbd6803..6b48922 100644 --- a/pocket/startup.lua +++ b/pocket/startup.lua @@ -22,7 +22,7 @@ local pocket = require("pocket.pocket") local renderer = require("pocket.renderer") local threads = require("pocket.threads") -local POCKET_VERSION = "v1.0.1" +local POCKET_VERSION = "v1.0.2" local println = util.println local println_ts = util.println_ts diff --git a/pocket/threads.lua b/pocket/threads.lua index 120c8dd..c9219bc 100644 --- a/pocket/threads.lua +++ b/pocket/threads.lua @@ -159,9 +159,6 @@ function threads.thread__render(smem) if msg ~= nil then if msg.qtype == mqueue.TYPE.COMMAND then -- received a command - if msg.message == MQ__RENDER_CMD.UNLOAD_SV_APPS then - elseif msg.message == MQ__RENDER_CMD.UNLOAD_API_APPS then - end elseif msg.qtype == mqueue.TYPE.DATA then -- received data local cmd = msg.message ---@type queue_data From f7fe9754fe973eb8d34cc681a91faadb8e1aecff Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 13 Sep 2025 16:07:12 -0400 Subject: [PATCH 45/45] #629 luacheck fix for remaining unused variables --- pocket/pocket.lua | 4 ---- pocket/startup.lua | 2 +- pocket/threads.lua | 1 - 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/pocket/pocket.lua b/pocket/pocket.lua index e7e6ed8..56614b7 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -16,14 +16,10 @@ local LINK_STATE = iocontrol.LINK_STATE local pocket = {} -local MQ__RENDER_CMD = { -} - local MQ__RENDER_DATA = { LOAD_APP = 1 } -pocket.MQ__RENDER_CMD = MQ__RENDER_CMD pocket.MQ__RENDER_DATA = MQ__RENDER_DATA ---@type pkt_config diff --git a/pocket/startup.lua b/pocket/startup.lua index 6b48922..7272ab8 100644 --- a/pocket/startup.lua +++ b/pocket/startup.lua @@ -22,7 +22,7 @@ local pocket = require("pocket.pocket") local renderer = require("pocket.renderer") local threads = require("pocket.threads") -local POCKET_VERSION = "v1.0.2" +local POCKET_VERSION = "v1.0.3" local println = util.println local println_ts = util.println_ts diff --git a/pocket/threads.lua b/pocket/threads.lua index c9219bc..50c0e05 100644 --- a/pocket/threads.lua +++ b/pocket/threads.lua @@ -14,7 +14,6 @@ local threads = {} local MAIN_CLOCK = 0.5 -- (2Hz, 10 ticks) local RENDER_SLEEP = 100 -- (100ms, 2 ticks) -local MQ__RENDER_CMD = pocket.MQ__RENDER_CMD local MQ__RENDER_DATA = pocket.MQ__RENDER_DATA -- main thread