From 43b44cc425c28fd85dd8d3919166d4d4c298c8f9 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Wed, 24 Apr 2024 21:11:41 +0000 Subject: [PATCH 01/44] #465 first pass at minifier --- .gitignore | 2 +- safemin.py | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 safemin.py diff --git a/.gitignore b/.gitignore index 0688a640..de579c07 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -_notes/ +_*/ /*program.sh \ No newline at end of file diff --git a/safemin.py b/safemin.py new file mode 100644 index 00000000..4f354a24 --- /dev/null +++ b/safemin.py @@ -0,0 +1,72 @@ +import os +import re + +# minify files in a directory +def min_files(path): + start_sum, end_sum = 0, 0 + + for (root, _, files) in os.walk(path): + os.makedirs('_minified/' + root, exist_ok=True) + + for f in files: + start, end = minify(root + "/" + f) + + start_sum = start_sum + start + end_sum = end_sum + end + + delta = start_sum - end_sum + + print(f"> done with '{path}': shrunk from {start_sum} bytes to {end_sum} bytes (saved {delta} bytes, or {(100*delta/start_sum):.2f}%)") + + return list + +# minify a file +def minify(path: str): + size_start = os.stat(path).st_size + + f = open(path, "r") + contents = f.read() + f.close() + + if re.search(r'--+\[+', contents) != None: + # absolutely not dealing with lua multiline comments + # - there are more important things to do + # - this minification is intended to be 100% safe, so working with multiline comments is asking for trouble + # - the project doesn't use them as of writing this (except in test/), and it might as well stay that way + raise Exception(f"no multiline comments allowed! (offending file: {path})") + + if re.search(r'\\$', contents, flags=re.MULTILINE) != None: + # '\' allows for multiline strings, which would require reverting to processing syntax line by line to support them + raise Exception(f"no escaping newlines! (offending file: {path})") + + # drop the comments + # -> whitespace before '--' and anything after that, which includes '---' comments + minified = re.sub(r'\s*--+(?!.*[\'"]).*', '', contents) + + # drop leading whitespace on each line + minified = re.sub(r'^ +', '', minified, flags=re.MULTILINE) + + # drop blank lines + while minified != re.sub(r'\n\n', '\n', minified): + minified = re.sub(r'\n\n', '\n', minified) + + # write the minified file + f_min = open(f"_minified/{path}", "w") + f_min.write(minified) + f_min.close() + + size_end = os.stat(f"_minified/{path}").st_size + + print(f">> shrunk '{path}' from {size_start} bytes to {size_end} bytes (saved {size_start-size_end} bytes)") + + return size_start, size_end + +# minify applications and libraries +dirs = [ 'scada-common', 'graphics', 'lockbox', 'reactor-plc', 'rtu', 'supervisor', 'coordinator', 'pocket' ] +for _, d in enumerate(dirs): + min_files(d) + +# minify root files +minify("startup.lua") +minify("initenv.lua") +minify("configure.lua") From 4a7028f401e38b41f7f115964e666ed2fb6b38de Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Thu, 27 Jun 2024 19:57:43 -0400 Subject: [PATCH 02/44] #497 instantly launch pocket program, block network dependent apps until connected --- pocket/iocontrol.lua | 6 ++-- pocket/pocket.lua | 46 +++++++++++++++++++------ pocket/startup.lua | 2 +- pocket/ui/apps/diag_apps.lua | 2 +- pocket/ui/apps/loader.lua | 49 +++++++++++++++++++++++++++ pocket/ui/components/conn_waiting.lua | 6 ++-- pocket/ui/main.lua | 30 +++------------- 7 files changed, 95 insertions(+), 46 deletions(-) create mode 100644 pocket/ui/apps/loader.lua diff --git a/pocket/iocontrol.lua b/pocket/iocontrol.lua index da9c0d7b..38e642e6 100644 --- a/pocket/iocontrol.lua +++ b/pocket/iocontrol.lua @@ -342,10 +342,8 @@ function iocontrol.report_link_state(state, sv_addr, api_addr) io.ps.publish("crd_conn_quality", 0) end - if state == LINK_STATE.LINKED then - io.ps.publish("sv_addr", sv_addr) - io.ps.publish("api_addr", api_addr) - end + if sv_addr then io.ps.publish("sv_addr", sv_addr) end + if api_addr then io.ps.publish("api_addr", api_addr) end end -- determine supervisor connection quality (trip time) diff --git a/pocket/pocket.lua b/pocket/pocket.lua index 0afc0683..e73c3b12 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -78,15 +78,16 @@ end ---@enum POCKET_APP_ID local APP_ID = { ROOT = 1, + LOADER = 2, -- main app pages - UNITS = 2, - GUIDE = 3, - ABOUT = 4, + UNITS = 3, + GUIDE = 4, + ABOUT = 5, -- diag app page - ALARMS = 5, + ALARMS = 6, -- other - DUMMY = 6, - NUM_APPS = 6 + DUMMY = 7, + NUM_APPS = 7 } pocket.APP_ID = APP_ID @@ -98,9 +99,9 @@ pocket.APP_ID = APP_ID ---@field switcher function|nil function to switch between children ---@field tasks table tasks to run while viewing this page --- allocate the page navigation system ----@param render_queue mqueue -function pocket.init_nav(render_queue) +-- initialize the page navigation system +---@param smem pkt_shared_memory +function pocket.init_nav(smem) local self = { pane = nil, ---@type graphics_element sidebar = nil, ---@type graphics_element @@ -108,6 +109,7 @@ function pocket.init_nav(render_queue) containers = {}, help_map = {}, help_return = nil, + loader_return = nil, cur_app = APP_ID.ROOT } @@ -143,10 +145,13 @@ function pocket.init_nav(render_queue) app.load = function () app.loaded = true end app.unload = function () app.loaded = false end - -- check which connections this requires + -- check which connections this requires (for unload) ---@return boolean requires_sv, boolean requires_api function app.check_requires() return require_sv or false, require_api or false end + -- check if any connection is required (for load) + function app.requires_conn() return require_sv or require_api or false end + -- delayed set of the pane if it wasn't ready at the start ---@param root_pane graphics_element multipane function app.set_root_pane(root_pane) @@ -254,7 +259,14 @@ function pocket.init_nav(render_queue) local app = self.apps[app_id] ---@type pocket_app if app then - if not app.loaded then render_queue.push_data(MQ__RENDER_DATA.LOAD_APP, app_id) end + if app.requires_conn() and not smem.pkt_sys.pocket_comms.is_linked() then + -- bring up the app loader + self.loader_return = app_id + app_id = APP_ID.LOADER + app = self.apps[app_id] + else self.loader_return = nil end + + if not app.loaded then smem.q.mq_render.push_data(MQ__RENDER_DATA.LOAD_APP, app_id) end self.cur_app = app_id self.pane.set_value(app_id) @@ -267,6 +279,14 @@ function pocket.init_nav(render_queue) end end + -- open the app that was blocked on connecting + function nav.on_loader_connected() + if self.loader_return then + nav.open_app(self.loader_return) + end + end + + -- load a given app ---@param app_id POCKET_APP_ID function nav.load_app(app_id) @@ -844,6 +864,10 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) ---@nodiscard function public.is_api_linked() return self.api.linked end + -- check if we are still linked with the supervisor and coordinator + ---@nodiscard + function public.is_linked() return self.sv.linked and self.api.linked end + return public end diff --git a/pocket/startup.lua b/pocket/startup.lua index b56da4fb..a80a4ca4 100644 --- a/pocket/startup.lua +++ b/pocket/startup.lua @@ -123,7 +123,7 @@ local function main() -- setup system ---------------------------------------- - smem_sys.nav = pocket.init_nav(__shared_memory.q.mq_render) + smem_sys.nav = pocket.init_nav(__shared_memory) -- message authentication init if type(config.AuthKey) == "string" and string.len(config.AuthKey) > 0 then diff --git a/pocket/ui/apps/diag_apps.lua b/pocket/ui/apps/diag_apps.lua index be63e952..27ef837f 100644 --- a/pocket/ui/apps/diag_apps.lua +++ b/pocket/ui/apps/diag_apps.lua @@ -32,7 +32,7 @@ local function create_pages(root) local alarm_test = Div{parent=root,x=1,y=1} - local alarm_app = db.nav.register_app(APP_ID.ALARMS, alarm_test) + 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 } diff --git a/pocket/ui/apps/loader.lua b/pocket/ui/apps/loader.lua new file mode 100644 index 00000000..8ea72f06 --- /dev/null +++ b/pocket/ui/apps/loader.lua @@ -0,0 +1,49 @@ +-- +-- Loading Screen App +-- + +local iocontrol = require("pocket.iocontrol") +local pocket = require("pocket.pocket") + +local conn_waiting = require("pocket.ui.components.conn_waiting") + +local core = require("graphics.core") + +local Div = require("graphics.elements.div") +local MultiPane = require("graphics.elements.multipane") +local TextBox = require("graphics.elements.textbox") + +local APP_ID = pocket.APP_ID + +local LINK_STATE = iocontrol.LINK_STATE + +-- create the connecting to SV & API page +---@param root graphics_element 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.LOADER, main).new_page(nil, function () end) + + local conn_sv_wait = conn_waiting(main, 6, false) + local conn_api_wait = conn_waiting(main, 6, true) + local main_pane = Div{parent=main,x=1,y=2} + + 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 + root_pane.set_value(1) + elseif state == LINK_STATE.SV_LINK_ONLY then + root_pane.set_value(2) + else + root_pane.set_value(3) + db.nav.on_loader_connected() + end + end) + + TextBox{parent=main_pane,text="Connected!",x=1,y=6,alignment=core.ALIGN.CENTER} +end + +return create_pages diff --git a/pocket/ui/components/conn_waiting.lua b/pocket/ui/components/conn_waiting.lua index 9cbe1b3c..6b696504 100644 --- a/pocket/ui/components/conn_waiting.lua +++ b/pocket/ui/components/conn_waiting.lua @@ -23,16 +23,16 @@ local function init(parent, y, is_api) local root = Div{parent=parent,x=1,y=1} -- bounding box div - local box = Div{parent=root,x=1,y=y,height=5} + local box = Div{parent=root,x=1,y=y,height=6} local waiting_x = math.floor(parent.get_width() / 2) - 1 if is_api then WaitingAnim{parent=box,x=waiting_x,y=1,fg_bg=cpair(colors.blue,style.root.bkg)} - TextBox{parent=box,text="Connecting to API",alignment=ALIGN.CENTER,y=5,height=1,fg_bg=cpair(colors.white,style.root.bkg)} + TextBox{parent=box,text="Connecting to API",alignment=ALIGN.CENTER,y=5,fg_bg=cpair(colors.white,style.root.bkg)} else WaitingAnim{parent=box,x=waiting_x,y=1,fg_bg=cpair(colors.green,style.root.bkg)} - TextBox{parent=box,text="Connecting to Supervisor",alignment=ALIGN.CENTER,y=5,height=1,fg_bg=cpair(colors.white,style.root.bkg)} + TextBox{parent=box,text="Connecting to Supervisor",alignment=ALIGN.CENTER,y=5,fg_bg=cpair(colors.white,style.root.bkg)} end return root diff --git a/pocket/ui/main.lua b/pocket/ui/main.lua index 40b11043..524a67c3 100644 --- a/pocket/ui/main.lua +++ b/pocket/ui/main.lua @@ -10,11 +10,10 @@ local pocket = require("pocket.pocket") local diag_apps = require("pocket.ui.apps.diag_apps") local dummy_app = require("pocket.ui.apps.dummy_app") local guide_app = require("pocket.ui.apps.guide") +local loader_app = require("pocket.ui.apps.loader") local sys_apps = require("pocket.ui.apps.sys_apps") local unit_app = require("pocket.ui.apps.unit") -local conn_waiting = require("pocket.ui.components.conn_waiting") - local home_page = require("pocket.ui.pages.home_page") local style = require("pocket.ui.style") @@ -33,8 +32,6 @@ local SignalBar = require("graphics.elements.indicators.signal") local ALIGN = core.ALIGN local cpair = core.cpair -local LINK_STATE = iocontrol.LINK_STATE - local APP_ID = pocket.APP_ID -- create new main view @@ -42,6 +39,8 @@ local APP_ID = pocket.APP_ID local function init(main) local db = iocontrol.get_db() + local main_pane = Div{parent=main,x=1,y=2} + -- window header message TextBox{parent=main,y=1,text="EARLY ACCESS ALPHA S C ",alignment=ALIGN.LEFT,height=1,fg_bg=style.header} local svr_conn = SignalBar{parent=main,y=1,x=22,compact=true,colors_low_med=cpair(colors.red,colors.yellow),disconnect_color=colors.lightGray,fg_bg=cpair(colors.green,colors.gray)} @@ -50,28 +49,6 @@ local function init(main) db.ps.subscribe("svr_conn_quality", svr_conn.set_value) db.ps.subscribe("crd_conn_quality", crd_conn.set_value) - --#region root panel panes (connection screens + main screen) - - local root_pane_div = Div{parent=main,x=1,y=2} - - local conn_sv_wait = conn_waiting(root_pane_div, 6, false) - local conn_api_wait = conn_waiting(root_pane_div, 6, true) - local main_pane = Div{parent=main,x=1,y=2} - - local root_pane = MultiPane{parent=root_pane_div,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 - root_pane.set_value(1) - elseif state == LINK_STATE.SV_LINK_ONLY then - root_pane.set_value(2) - else - root_pane.set_value(3) - end - end) - - --#endregion - --#region main page panel panes & sidebar local page_div = Div{parent=main_pane,x=4,y=1} @@ -80,6 +57,7 @@ local function init(main) unit_app(page_div) guide_app(page_div) + loader_app(page_div) sys_apps(page_div) diag_apps(page_div) dummy_app(page_div) From fc42049aa02e409bc2496085d44117c639634f5d Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Thu, 27 Jun 2024 19:57:55 -0400 Subject: [PATCH 03/44] removed deprecated high temp constant --- scada-common/constants.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/scada-common/constants.lua b/scada-common/constants.lua index b2755b95..0472a6cd 100644 --- a/scada-common/constants.lua +++ b/scada-common/constants.lua @@ -52,7 +52,6 @@ local alarms = {} -- unit alarms -alarms.HIGH_TEMP = 1150 -- temp >= 1150K alarms.HIGH_WASTE = 0.85 -- fill > 85% alarms.HIGH_RADIATION = 0.00005 -- 50 uSv/h, not yet damaging but this isn't good From 2bc20ec312e04273bc6a20f95289591a9913cff5 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Thu, 27 Jun 2024 20:01:53 -0400 Subject: [PATCH 04/44] cleanup --- pocket/pocket.lua | 1 - pocket/ui/main.lua | 9 +++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/pocket/pocket.lua b/pocket/pocket.lua index e73c3b12..5e6798e2 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -286,7 +286,6 @@ function pocket.init_nav(smem) end end - -- load a given app ---@param app_id POCKET_APP_ID function nav.load_app(app_id) diff --git a/pocket/ui/main.lua b/pocket/ui/main.lua index 524a67c3..4a33327a 100644 --- a/pocket/ui/main.lua +++ b/pocket/ui/main.lua @@ -41,7 +41,7 @@ local function init(main) local main_pane = Div{parent=main,x=1,y=2} - -- window header message + -- window header message and connection status TextBox{parent=main,y=1,text="EARLY ACCESS ALPHA S C ",alignment=ALIGN.LEFT,height=1,fg_bg=style.header} local svr_conn = SignalBar{parent=main,y=1,x=22,compact=true,colors_low_med=cpair(colors.red,colors.yellow),disconnect_color=colors.lightGray,fg_bg=cpair(colors.green,colors.gray)} local crd_conn = SignalBar{parent=main,y=1,x=26,compact=true,colors_low_med=cpair(colors.red,colors.yellow),disconnect_color=colors.lightGray,fg_bg=cpair(colors.green,colors.gray)} @@ -49,12 +49,10 @@ local function init(main) db.ps.subscribe("svr_conn_quality", svr_conn.set_value) db.ps.subscribe("crd_conn_quality", crd_conn.set_value) - --#region main page panel panes & sidebar - local page_div = Div{parent=main_pane,x=4,y=1} + -- create all the apps & pages home_page(page_div) - unit_app(page_div) guide_app(page_div) loader_app(page_div) @@ -62,6 +60,7 @@ local function init(main) diag_apps(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") db.nav.set_pane(MultiPane{parent=page_div,x=1,y=1,panes=db.nav.get_containers()}) @@ -70,8 +69,6 @@ local function init(main) PushButton{parent=main_pane,x=1,y=19,text="\x1b",min_width=3,fg_bg=cpair(colors.white,colors.gray),active_fg_bg=cpair(colors.gray,colors.black),callback=db.nav.nav_up} db.nav.open_app(APP_ID.ROOT) - - --#endregion end return init From 897a3ed22d9f336641c071c9f7b97faae4c9f3cd Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Thu, 27 Jun 2024 21:03:53 -0400 Subject: [PATCH 05/44] #502 much needed refresh and cleanup of PLC struct and status packet handling --- reactor-plc/plc.lua | 52 ++++++------- reactor-plc/startup.lua | 2 +- supervisor/session/plc.lua | 148 +++++++++++++++++++------------------ supervisor/startup.lua | 2 +- 4 files changed, 100 insertions(+), 104 deletions(-) diff --git a/reactor-plc/plc.lua b/reactor-plc/plc.lua index 2fb869af..e3a25783 100644 --- a/reactor-plc/plc.lua +++ b/reactor-plc/plc.lua @@ -571,33 +571,17 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog) self.seq_num = self.seq_num + 1 end - -- variable reactor status information, excluding heating rate + -- dynamic reactor status information, excluding heating rate ---@return table data_table, boolean faulted - local function _reactor_status() + local function _get_reactor_status() local fuel = nil local waste = nil local coolant = nil local hcoolant = nil - local data_table = { - false, -- getStatus - 0, -- getBurnRate - 0, -- getActualBurnRate - 0, -- getTemperature - 0, -- getDamagePercent - 0, -- getBoilEfficiency - 0, -- getEnvironmentalLoss - 0, -- fuel_amnt - 0, -- getFuelFilledPercentage - 0, -- waste_amnt - 0, -- getWasteFilledPercentage - "", -- coolant_name - 0, -- coolant_amnt - 0, -- getCoolantFilledPercentage - "", -- hcoolant_name - 0, -- hcoolant_amnt - 0 -- getHeatedCoolantFilledPercentage - } + local data_table = {} + + reactor.__p_disable_afc() local tasks = { function () data_table[1] = reactor.getStatus() end, @@ -637,30 +621,32 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog) data_table[16] = hcoolant.amount end + reactor.__p_enable_afc() + return data_table, reactor.__p_is_faulted() end -- update the status cache if changed ---@return boolean changed local function _update_status_cache() - local status, faulted = _reactor_status() + local status, faulted = _get_reactor_status() local changed = false - if self.status_cache ~= nil then - if not faulted then + if not faulted then + if self.status_cache ~= nil then for i = 1, #status do if status[i] ~= self.status_cache[i] then changed = true break end end + else + changed = true end - else - changed = true - end - if changed and not faulted then - self.status_cache = status + if changed then + self.status_cache = status + end end return changed @@ -679,9 +665,11 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog) _send(msg_type, { status }) end - -- send structure properties (these should not change, server will cache these) + -- send static structure properties, cached by server local function _send_struct() - local mek_data = { false, 0, 0, 0, types.new_zero_coordinate(), types.new_zero_coordinate(), 0, 0, 0, 0, 0, 0, 0, 0 } + local mek_data = {} + + reactor.__p_disable_afc() local tasks = { function () mek_data[1] = reactor.getLength() end, @@ -705,6 +693,8 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog) _send(RPLC_TYPE.MEK_STRUCT, mek_data) self.resend_build = false end + + reactor.__p_enable_afc() end -- PUBLIC FUNCTIONS -- diff --git a/reactor-plc/startup.lua b/reactor-plc/startup.lua index 1b8b2d63..fc925366 100644 --- a/reactor-plc/startup.lua +++ b/reactor-plc/startup.lua @@ -18,7 +18,7 @@ local plc = require("reactor-plc.plc") local renderer = require("reactor-plc.renderer") local threads = require("reactor-plc.threads") -local R_PLC_VERSION = "v1.7.11" +local R_PLC_VERSION = "v1.7.12" local println = util.println local println_ts = util.println_ts diff --git a/supervisor/session/plc.lua b/supervisor/session/plc.lua index a4a82712..29565546 100644 --- a/supervisor/session/plc.lua +++ b/supervisor/session/plc.lua @@ -209,52 +209,89 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f -- copy in the reactor status ---@param mek_data table local function _copy_status(mek_data) + local stat = self.sDB.mek_status + local struct = self.sDB.mek_struct + -- copy status information - self.sDB.mek_status.status = mek_data[1] - self.sDB.mek_status.burn_rate = mek_data[2] - self.sDB.mek_status.act_burn_rate = mek_data[3] - self.sDB.mek_status.temp = mek_data[4] - self.sDB.mek_status.damage = mek_data[5] - self.sDB.mek_status.boil_eff = mek_data[6] - self.sDB.mek_status.env_loss = mek_data[7] + stat.status = mek_data[1] + stat.burn_rate = mek_data[2] + stat.act_burn_rate = mek_data[3] + stat.temp = mek_data[4] + stat.damage = mek_data[5] + stat.boil_eff = mek_data[6] + stat.env_loss = mek_data[7] -- copy container information - self.sDB.mek_status.fuel = mek_data[8] - self.sDB.mek_status.fuel_fill = mek_data[9] - self.sDB.mek_status.waste = mek_data[10] - self.sDB.mek_status.waste_fill = mek_data[11] - self.sDB.mek_status.ccool_type = mek_data[12] - self.sDB.mek_status.ccool_amnt = mek_data[13] - self.sDB.mek_status.ccool_fill = mek_data[14] - self.sDB.mek_status.hcool_type = mek_data[15] - self.sDB.mek_status.hcool_amnt = mek_data[16] - self.sDB.mek_status.hcool_fill = mek_data[17] + stat.fuel = mek_data[8] + stat.fuel_fill = mek_data[9] + stat.waste = mek_data[10] + stat.waste_fill = mek_data[11] + stat.ccool_type = mek_data[12] + stat.ccool_amnt = mek_data[13] + stat.ccool_fill = mek_data[14] + stat.hcool_type = mek_data[15] + stat.hcool_amnt = mek_data[16] + stat.hcool_fill = mek_data[17] -- update computable fields if we have our structure if self.received_struct then - self.sDB.mek_status.fuel_need = self.sDB.mek_struct.fuel_cap - self.sDB.mek_status.fuel_fill - self.sDB.mek_status.waste_need = self.sDB.mek_struct.waste_cap - self.sDB.mek_status.waste_fill - self.sDB.mek_status.cool_need = self.sDB.mek_struct.ccool_cap - self.sDB.mek_status.ccool_fill - self.sDB.mek_status.hcool_need = self.sDB.mek_struct.hcool_cap - self.sDB.mek_status.hcool_fill + stat.fuel_need = struct.fuel_cap - stat.fuel_fill + stat.waste_need = struct.waste_cap - stat.waste_fill + stat.cool_need = struct.ccool_cap - stat.ccool_fill + stat.hcool_need = struct.hcool_cap - stat.hcool_fill end end -- copy in the reactor structure ---@param mek_data table local function _copy_struct(mek_data) - self.sDB.mek_struct.length = mek_data[1] - self.sDB.mek_struct.width = mek_data[2] - self.sDB.mek_struct.height = mek_data[3] - self.sDB.mek_struct.min_pos = mek_data[4] - self.sDB.mek_struct.max_pos = mek_data[5] - self.sDB.mek_struct.heat_cap = mek_data[6] - self.sDB.mek_struct.fuel_asm = mek_data[7] - self.sDB.mek_struct.fuel_sa = mek_data[8] - self.sDB.mek_struct.fuel_cap = mek_data[9] - self.sDB.mek_struct.waste_cap = mek_data[10] - self.sDB.mek_struct.ccool_cap = mek_data[11] - self.sDB.mek_struct.hcool_cap = mek_data[12] - self.sDB.mek_struct.max_burn = mek_data[13] + local struct = self.sDB.mek_struct + + struct.length = mek_data[1] + struct.width = mek_data[2] + struct.height = mek_data[3] + struct.min_pos = mek_data[4] + struct.max_pos = mek_data[5] + struct.heat_cap = mek_data[6] + struct.fuel_asm = mek_data[7] + struct.fuel_sa = mek_data[8] + struct.fuel_cap = mek_data[9] + struct.waste_cap = mek_data[10] + struct.ccool_cap = mek_data[11] + struct.hcool_cap = mek_data[12] + struct.max_burn = mek_data[13] + end + + -- handle a reactor status packet + ---@param pkt rplc_frame + local function _handle_status(pkt) + local valid = (type(pkt.data[1]) == "number") and (type(pkt.data[2]) == "boolean") and + (type(pkt.data[3]) == "boolean") and (type(pkt.data[4]) == "boolean") and + (type(pkt.data[5]) == "number") + + if valid then + self.sDB.last_status_update = pkt.data[1] + self.sDB.control_state = pkt.data[2] + self.sDB.no_reactor = pkt.data[3] + self.sDB.formed = pkt.data[4] + self.sDB.auto_ack_token = pkt.data[5] + + if (not self.sDB.no_reactor) and self.sDB.formed and (type(pkt.data[6]) == "number") then + self.sDB.mek_status.heating_rate = pkt.data[6] or 0.0 + + -- attempt to read mek_data table + if type(pkt.data[7]) == "table" then + if #pkt.data[7] == 17 then + _copy_status(pkt.data[7]) + self.received_status_cache = true + else + log.error(log_header .. "RPLC status packet reactor data length mismatch") + end + end + end + else + log.debug(log_header .. "RPLC status packet invalid") + end end -- mark this PLC session as closed, stop watchdog @@ -334,48 +371,17 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f if pkt.type == RPLC_TYPE.STATUS then -- status packet received, update data if pkt.length >= 5 then - if (type(pkt.data[1]) == "number") and (type(pkt.data[2]) == "boolean") and (type(pkt.data[3]) == "boolean") and - (type(pkt.data[4]) == "boolean") and (type(pkt.data[5]) == "number") then - self.sDB.last_status_update = pkt.data[1] - self.sDB.control_state = pkt.data[2] - self.sDB.no_reactor = pkt.data[3] - self.sDB.formed = pkt.data[4] - self.sDB.auto_ack_token = pkt.data[5] - - if (not self.sDB.no_reactor) and self.sDB.formed and (type(pkt.data[6]) == "number") then - self.sDB.mek_status.heating_rate = pkt.data[6] or 0.0 - - -- attempt to read mek_data table - if type(pkt.data[7]) == "table" then - local status = pcall(_copy_status, pkt.data[7]) - if status then - -- copied in status data OK - self.received_status_cache = true - else - -- error copying status data - log.error(log_header .. "failed to parse status packet data") - end - end - end - else - log.debug(log_header .. "RPLC status packet invalid") - end + _handle_status(pkt) else log.debug(log_header .. "RPLC status packet length mismatch") end elseif pkt.type == RPLC_TYPE.MEK_STRUCT then -- received reactor structure, record it - if pkt.length == 14 then - local status = pcall(_copy_struct, pkt.data) - if status then - -- copied in structure data OK - _compute_op_temps() - self.received_struct = true - out_queue.push_data(svqtypes.SV_Q_DATA.PLC_BUILD_CHANGED, reactor_id) - else - -- error copying structure data - log.error(log_header .. "failed to parse struct packet data") - end + if pkt.length == 13 then + _copy_struct(pkt.data) + _compute_op_temps() + self.received_struct = true + out_queue.push_data(svqtypes.SV_Q_DATA.PLC_BUILD_CHANGED, reactor_id) else log.debug(log_header .. "RPLC struct packet length mismatch") end diff --git a/supervisor/startup.lua b/supervisor/startup.lua index 89c38d8a..47c8122a 100644 --- a/supervisor/startup.lua +++ b/supervisor/startup.lua @@ -21,7 +21,7 @@ local supervisor = require("supervisor.supervisor") local svsessions = require("supervisor.session.svsessions") -local SUPERVISOR_VERSION = "v1.3.12" +local SUPERVISOR_VERSION = "v1.3.13" local println = util.println local println_ts = util.println_ts From 4cdbe3b07f5ec07599dbf5c09b586f0119ce6226 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Thu, 27 Jun 2024 21:05:53 -0400 Subject: [PATCH 06/44] some more cleanup --- supervisor/session/plc.lua | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/supervisor/session/plc.lua b/supervisor/session/plc.lua index 29565546..75ceb696 100644 --- a/supervisor/session/plc.lua +++ b/supervisor/session/plc.lua @@ -190,20 +190,23 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f -- copy in the RPS status ---@param rps_status table local function _copy_rps_status(rps_status) - self.sDB.rps_tripped = rps_status[1] - self.sDB.rps_trip_cause = rps_status[2] - self.sDB.rps_status.high_dmg = rps_status[3] - self.sDB.rps_status.high_temp = rps_status[4] - self.sDB.rps_status.low_cool = rps_status[5] - self.sDB.rps_status.ex_waste = rps_status[6] - self.sDB.rps_status.ex_hcool = rps_status[7] - self.sDB.rps_status.no_fuel = rps_status[8] - self.sDB.rps_status.fault = rps_status[9] - self.sDB.rps_status.timeout = rps_status[10] - self.sDB.rps_status.manual = rps_status[11] - self.sDB.rps_status.automatic = rps_status[12] - self.sDB.rps_status.sys_fail = rps_status[13] - self.sDB.rps_status.force_dis = rps_status[14] + local rps = self.sDB.rps_status + + self.sDB.rps_tripped = rps_status[1] + self.sDB.rps_trip_cause = rps_status[2] + + rps.high_dmg = rps_status[3] + rps.high_temp = rps_status[4] + rps.low_cool = rps_status[5] + rps.ex_waste = rps_status[6] + rps.ex_hcool = rps_status[7] + rps.no_fuel = rps_status[8] + rps.fault = rps_status[9] + rps.timeout = rps_status[10] + rps.manual = rps_status[11] + rps.automatic = rps_status[12] + rps.sys_fail = rps_status[13] + rps.force_dis = rps_status[14] end -- copy in the reactor status From d2bc4f6bc06e171753b125c0bd317ddd9e3a2976 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Sat, 29 Jun 2024 02:27:55 +0000 Subject: [PATCH 07/44] #488 HMAC acceleration and seq_num changes --- coordinator/coordinator.lua | 16 +- coordinator/session/apisessions.lua | 9 +- coordinator/session/pocket.lua | 14 +- coordinator/startup.lua | 2 +- pocket/pocket.lua | 26 +- pocket/startup.lua | 2 +- reactor-plc/plc.lua | 15 +- reactor-plc/startup.lua | 2 +- rtu/rtu.lua | 13 +- rtu/startup.lua | 2 +- scada-common/comms.lua | 17 +- scada-common/network.lua | 19 +- supervisor/session/coordinator.lua | 14 +- supervisor/session/plc.lua | 14 +- supervisor/session/pocket.lua | 14 +- supervisor/session/rtu.lua | 14 +- supervisor/session/svsessions.lua | 42 +-- supervisor/startup.lua | 4 +- supervisor/supervisor.lua | 451 ++++++++++++++-------------- 19 files changed, 330 insertions(+), 360 deletions(-) diff --git a/coordinator/coordinator.lua b/coordinator/coordinator.lua index f6a20188..9e98a33c 100644 --- a/coordinator/coordinator.lua +++ b/coordinator/coordinator.lua @@ -232,8 +232,7 @@ function coordinator.comms(version, nic, sv_watchdog) local self = { sv_linked = false, sv_addr = comms.BROADCAST, - sv_seq_num = 0, - sv_r_seq_num = nil, + sv_seq_num = util.time_ms() * 10, -- unique per peer, restarting will not re-use seq nums due to message rate sv_config_err = false, last_est_ack = ESTABLISH_ACK.ALLOW, last_api_est_acks = {}, @@ -370,7 +369,6 @@ function coordinator.comms(version, nic, sv_watchdog) sv_watchdog.cancel() self.sv_addr = comms.BROADCAST self.sv_linked = false - self.sv_r_seq_num = nil iocontrol.fp_link_state(types.PANEL_LINK_STATE.DISCONNECTED) _send_sv(PROTOCOL.SCADA_MGMT, MGMT_TYPE.CLOSE, {}) end @@ -492,7 +490,7 @@ function coordinator.comms(version, nic, sv_watchdog) _send_api_establish_ack(packet.scada_frame, ESTABLISH_ACK.BAD_API_VERSION) elseif dev_type == DEVICE_TYPE.PKT then -- pocket linking request - local id = apisessions.establish_session(src_addr, firmware_v) + local id = apisessions.establish_session(src_addr, packet.scada_frame.seq_num() + 1, firmware_v) coordinator.log_comms(util.c("API_ESTABLISH: pocket (", firmware_v, ") [@", src_addr, "] connected with session ID ", id)) local conf = iocontrol.get_db().facility.conf @@ -514,16 +512,14 @@ function coordinator.comms(version, nic, sv_watchdog) end elseif r_chan == config.SVR_Channel then -- check sequence number - if self.sv_r_seq_num == nil then - self.sv_r_seq_num = packet.scada_frame.seq_num() - elseif self.sv_linked and ((self.sv_r_seq_num + 1) ~= packet.scada_frame.seq_num()) then - log.warning("sequence out-of-order: last = " .. self.sv_r_seq_num .. ", new = " .. packet.scada_frame.seq_num()) + if self.sv_seq_num ~= packet.scada_frame.seq_num() then + log.warning("sequence out-of-order: last = " .. self.sv_seq_num .. ", new = " .. packet.scada_frame.seq_num()) return false elseif self.sv_linked and src_addr ~= self.sv_addr then log.debug("received packet from unknown computer " .. src_addr .. " while linked; channel in use by another system?") return false else - self.sv_r_seq_num = packet.scada_frame.seq_num() + self.sv_seq_num = packet.scada_frame.seq_num() + 1 end -- feed watchdog on valid sequence number @@ -675,7 +671,6 @@ function coordinator.comms(version, nic, sv_watchdog) sv_watchdog.cancel() self.sv_addr = comms.BROADCAST self.sv_linked = false - self.sv_r_seq_num = nil iocontrol.fp_link_state(types.PANEL_LINK_STATE.DISCONNECTED) log.info("server connection closed by remote host") else @@ -706,7 +701,6 @@ function coordinator.comms(version, nic, sv_watchdog) self.sv_addr = src_addr self.sv_linked = true - self.sv_r_seq_num = nil self.sv_config_err = false iocontrol.fp_link_state(types.PANEL_LINK_STATE.LINKED) diff --git a/coordinator/session/apisessions.lua b/coordinator/session/apisessions.lua index 516b91be..4daa45d6 100644 --- a/coordinator/session/apisessions.lua +++ b/coordinator/session/apisessions.lua @@ -89,10 +89,11 @@ end -- establish a new API session ---@nodiscard ----@param source_addr integer ----@param version string +---@param source_addr integer pocket computer ID +---@param i_seq_num integer initial sequence number to use next +---@param version string pocket version ---@return integer session_id -function apisessions.establish_session(source_addr, version) +function apisessions.establish_session(source_addr, i_seq_num, version) ---@class pkt_session_struct local pkt_s = { open = true, @@ -105,7 +106,7 @@ function apisessions.establish_session(source_addr, version) local id = self.next_id - pkt_s.instance = pocket.new_session(id, source_addr, pkt_s.in_queue, pkt_s.out_queue, self.config.API_Timeout) + pkt_s.instance = pocket.new_session(id, source_addr, i_seq_num, pkt_s.in_queue, pkt_s.out_queue, self.config.API_Timeout) table.insert(self.sessions, pkt_s) local mt = { diff --git a/coordinator/session/pocket.lua b/coordinator/session/pocket.lua index cd03fc11..f2f59e41 100644 --- a/coordinator/session/pocket.lua +++ b/coordinator/session/pocket.lua @@ -32,16 +32,16 @@ local PERIODICS = { ---@nodiscard ---@param id integer session ID ---@param s_addr integer device source address +---@param i_seq_num integer initial sequence number ---@param in_queue mqueue in message queue ---@param out_queue mqueue out message queue ---@param timeout number communications timeout -function pocket.new_session(id, s_addr, in_queue, out_queue, timeout) +function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout) local log_header = "pkt_session(" .. id .. "): " local self = { -- connection properties - seq_num = 0, - r_seq_num = nil, + seq_num = i_seq_num, connected = true, conn_watchdog = util.new_watchdog(timeout), last_rtt = 0, @@ -104,13 +104,11 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout) ---@param pkt mgmt_frame|crdn_frame local function _handle_packet(pkt) -- check sequence number - if self.r_seq_num == nil then - self.r_seq_num = pkt.scada_frame.seq_num() - elseif (self.r_seq_num + 1) ~= pkt.scada_frame.seq_num() then - log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num()) + if self.seq_num ~= pkt.scada_frame.seq_num() then + log.warning(log_header .. "sequence out-of-order: last = " .. self.seq_num .. ", new = " .. pkt.scada_frame.seq_num()) return else - self.r_seq_num = pkt.scada_frame.seq_num() + self.seq_num = pkt.scada_frame.seq_num() + 1 end -- feed watchdog diff --git a/coordinator/startup.lua b/coordinator/startup.lua index f152bc86..9e20631c 100644 --- a/coordinator/startup.lua +++ b/coordinator/startup.lua @@ -19,7 +19,7 @@ local renderer = require("coordinator.renderer") local sounder = require("coordinator.sounder") local threads = require("coordinator.threads") -local COORDINATOR_VERSION = "v1.4.7" +local COORDINATOR_VERSION = "v1.5.0" local CHUNK_LOAD_DELAY_S = 30.0 diff --git a/pocket/pocket.lua b/pocket/pocket.lua index 5e6798e2..fb4f41ab 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -370,15 +370,13 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) sv = { linked = false, addr = comms.BROADCAST, - seq_num = 0, - r_seq_num = nil, ---@type nil|integer + seq_num = util.time_ms() * 10, -- unique per peer, restarting will not re-use seq nums due to message rate last_est_ack = ESTABLISH_ACK.ALLOW }, api = { linked = false, addr = comms.BROADCAST, - seq_num = 0, - r_seq_num = nil, ---@type nil|integer + seq_num = util.time_ms() * 10, -- unique per peer, restarting will not re-use seq nums due to message rate last_est_ack = ESTABLISH_ACK.ALLOW }, establish_delay_counter = 0 @@ -466,7 +464,6 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) sv_watchdog.cancel() nav.unload_sv() self.sv.linked = false - self.sv.r_seq_num = nil self.sv.addr = comms.BROADCAST _send_sv(MGMT_TYPE.CLOSE, {}) end @@ -476,7 +473,6 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) api_watchdog.cancel() nav.unload_api() self.api.linked = false - self.api.r_seq_num = nil self.api.addr = comms.BROADCAST _send_crd(MGMT_TYPE.CLOSE, {}) end @@ -603,17 +599,15 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) log.debug("received packet on unconfigured channel " .. l_chan, true) elseif r_chan == config.CRD_Channel then -- check sequence number - if self.api.r_seq_num == nil then - self.api.r_seq_num = packet.scada_frame.seq_num() - elseif self.connected and ((self.api.r_seq_num + 1) ~= packet.scada_frame.seq_num()) then - log.warning("sequence out-of-order (API): last = " .. self.api.r_seq_num .. ", new = " .. packet.scada_frame.seq_num()) + if self.api.seq_num ~= packet.scada_frame.seq_num() then + log.warning("sequence out-of-order (API): last = " .. self.api.seq_num .. ", new = " .. packet.scada_frame.seq_num()) return elseif self.api.linked and (src_addr ~= self.api.addr) then log.debug("received packet from unknown computer " .. src_addr .. " while linked (API expected " .. self.api.addr .. "); channel in use by another system?") return else - self.api.r_seq_num = packet.scada_frame.seq_num() + self.api.seq_num = packet.scada_frame.seq_num() + 1 end -- feed watchdog on valid sequence number @@ -658,7 +652,6 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) api_watchdog.cancel() nav.unload_api() self.api.linked = false - self.api.r_seq_num = nil self.api.addr = comms.BROADCAST log.info("coordinator server connection closed by remote host") else _fail_type(packet) end @@ -723,17 +716,15 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) end elseif r_chan == config.SVR_Channel then -- check sequence number - if self.sv.r_seq_num == nil then - self.sv.r_seq_num = packet.scada_frame.seq_num() - elseif self.connected and ((self.sv.r_seq_num + 1) ~= packet.scada_frame.seq_num()) then - log.warning("sequence out-of-order (SVR): last = " .. self.sv.r_seq_num .. ", new = " .. packet.scada_frame.seq_num()) + if self.sv.seq_num ~= packet.scada_frame.seq_num() then + log.warning("sequence out-of-order (SVR): last = " .. self.sv.seq_num .. ", new = " .. packet.scada_frame.seq_num()) return elseif self.sv.linked and (src_addr ~= self.sv.addr) then log.debug("received packet from unknown computer " .. src_addr .. " while linked (SVR expected " .. self.sv.addr .. "); channel in use by another system?") return else - self.sv.r_seq_num = packet.scada_frame.seq_num() + self.sv.seq_num = packet.scada_frame.seq_num() + 1 end -- feed watchdog on valid sequence number @@ -764,7 +755,6 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) sv_watchdog.cancel() nav.unload_sv() self.sv.linked = false - self.sv.r_seq_num = nil self.sv.addr = comms.BROADCAST log.info("supervisor server connection closed by remote host") elseif packet.type == MGMT_TYPE.DIAG_TONE_GET then diff --git a/pocket/startup.lua b/pocket/startup.lua index a80a4ca4..2701efb8 100644 --- a/pocket/startup.lua +++ b/pocket/startup.lua @@ -20,7 +20,7 @@ local pocket = require("pocket.pocket") local renderer = require("pocket.renderer") local threads = require("pocket.threads") -local POCKET_VERSION = "v0.10.0-alpha" +local POCKET_VERSION = "v0.11.0-alpha" local println = util.println local println_ts = util.println_ts diff --git a/reactor-plc/plc.lua b/reactor-plc/plc.lua index 2fb869af..df116cf3 100644 --- a/reactor-plc/plc.lua +++ b/reactor-plc/plc.lua @@ -524,8 +524,7 @@ end function plc.comms(version, nic, reactor, rps, conn_watchdog) local self = { sv_addr = comms.BROADCAST, - seq_num = 0, - r_seq_num = nil, + seq_num = util.time_ms() * 10, -- unique per peer, restarting will not re-use seq nums due to message rate scrammed = false, linked = false, last_est_ack = ESTABLISH_ACK.ALLOW, @@ -725,7 +724,6 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog) function public.unlink() self.sv_addr = comms.BROADCAST self.linked = false - self.r_seq_num = nil self.status_cache = nil databus.tx_link_state(types.PANEL_LINK_STATE.DISCONNECTED) end @@ -834,17 +832,15 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog) -- handle packets now that we have prints setup if l_chan == config.PLC_Channel then -- check sequence number - if self.r_seq_num == nil then - self.r_seq_num = packet.scada_frame.seq_num() - elseif self.linked and ((self.r_seq_num + 1) ~= packet.scada_frame.seq_num()) then - log.warning("sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. packet.scada_frame.seq_num()) + if self.seq_num ~= packet.scada_frame.seq_num() then + log.warning("sequence out-of-order: last = " .. self.seq_num .. ", new = " .. packet.scada_frame.seq_num()) return elseif self.linked and (src_addr ~= self.sv_addr) then log.debug("received packet from unknown computer " .. src_addr .. " while linked (expected " .. self.sv_addr .. "); channel in use by another system?") return else - self.r_seq_num = packet.scada_frame.seq_num() + self.seq_num = packet.scada_frame.seq_num() + 1 end -- feed the watchdog first so it doesn't uhh...eat our packets :) @@ -1030,10 +1026,9 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog) println_ts("linked!") log.info("supervisor establish request approved, linked to SV (CID#" .. src_addr .. ")") - -- link + reset remote sequence number and cache + -- link + reset cache self.sv_addr = src_addr self.linked = true - self.r_seq_num = nil self.status_cache = nil if plc_state.reactor_formed then _send_struct() end diff --git a/reactor-plc/startup.lua b/reactor-plc/startup.lua index 1b8b2d63..6f6a27b7 100644 --- a/reactor-plc/startup.lua +++ b/reactor-plc/startup.lua @@ -18,7 +18,7 @@ local plc = require("reactor-plc.plc") local renderer = require("reactor-plc.renderer") local threads = require("reactor-plc.threads") -local R_PLC_VERSION = "v1.7.11" +local R_PLC_VERSION = "v1.8.0" local println = util.println local println_ts = util.println_ts diff --git a/rtu/rtu.lua b/rtu/rtu.lua index 71cea405..0278f428 100644 --- a/rtu/rtu.lua +++ b/rtu/rtu.lua @@ -284,8 +284,7 @@ end function rtu.comms(version, nic, conn_watchdog) local self = { sv_addr = comms.BROADCAST, - seq_num = 0, - r_seq_num = nil, + seq_num = util.time_ms() * 10, -- unique per peer, restarting will not re-use seq nums due to message rate txn_id = 0, last_est_ack = ESTABLISH_ACK.ALLOW } @@ -363,7 +362,6 @@ function rtu.comms(version, nic, conn_watchdog) function public.unlink(rtu_state) rtu_state.linked = false self.sv_addr = comms.BROADCAST - self.r_seq_num = nil databus.tx_link_state(types.PANEL_LINK_STATE.DISCONNECTED) end @@ -441,17 +439,15 @@ function rtu.comms(version, nic, conn_watchdog) if l_chan == config.RTU_Channel then -- check sequence number - if self.r_seq_num == nil then - self.r_seq_num = packet.scada_frame.seq_num() - elseif rtu_state.linked and ((self.r_seq_num + 1) ~= packet.scada_frame.seq_num()) then - log.warning("sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. packet.scada_frame.seq_num()) + if self.seq_num ~= packet.scada_frame.seq_num() then + log.warning("sequence out-of-order: last = " .. self.seq_num .. ", new = " .. packet.scada_frame.seq_num()) return elseif rtu_state.linked and (src_addr ~= self.sv_addr) then log.debug("received packet from unknown computer " .. src_addr .. " while linked (expected " .. self.sv_addr .. "); channel in use by another system?") return else - self.r_seq_num = packet.scada_frame.seq_num() + self.seq_num = packet.scada_frame.seq_num() + 1 end -- feed watchdog on valid sequence number @@ -556,7 +552,6 @@ function rtu.comms(version, nic, conn_watchdog) -- establish allowed rtu_state.linked = true self.sv_addr = packet.scada_frame.src_addr() - self.r_seq_num = nil println_ts("supervisor connection established") log.info("supervisor connection established") else diff --git a/rtu/startup.lua b/rtu/startup.lua index ae2e72bd..00f27c7f 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.9.6" +local RTU_VERSION = "v1.10.0" local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE diff --git a/scada-common/comms.lua b/scada-common/comms.lua index 3e65ed61..e31c60b2 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 = "2.5.2" +comms.version = "3.0.0" comms.api_version = "0.0.3" ---@enum PROTOCOL @@ -240,6 +240,8 @@ function comms.scada_packet() ---@nodiscard function public.modem_event() return self.modem_msg_in end ---@nodiscard + function public.raw_header() return { self.src_addr, self.dest_addr, self.seq_num, self.protocol } end + ---@nodiscard function public.raw_sendable() return self.raw end ---@nodiscard @@ -278,7 +280,7 @@ function comms.authd_packet() src_addr = comms.BROADCAST, dest_addr = comms.BROADCAST, mac = "", - payload = "" + payload = nil } ---@class authd_packet @@ -286,14 +288,13 @@ function comms.authd_packet() -- make an authenticated SCADA packet ---@param s_packet scada_packet scada packet to authenticate - ---@param mac function message authentication function + ---@param mac function message authentication hash function function public.make(s_packet, mac) self.valid = true self.src_addr = s_packet.src_addr() self.dest_addr = s_packet.dest_addr() - self.payload = textutils.serialize(s_packet.raw_sendable(), { allow_repetitions = true, compact = true }) - self.mac = mac(self.payload) - self.raw = { self.src_addr, self.dest_addr, self.mac, self.payload } + self.mac = mac(textutils.serialize(s_packet.raw_header(), { allow_repetitions = true, compact = true })) + self.raw = { self.src_addr, self.dest_addr, self.mac, s_packet.data() } end -- parse in a modem message as an authenticated SCADA packet @@ -330,14 +331,14 @@ function comms.authd_packet() self.src_addr = nil self.dest_addr = nil self.mac = "" - self.payload = "" + self.payload = {} end -- check if this packet is destined for this device local is_destination = (self.dest_addr == comms.BROADCAST) or (self.dest_addr == COMPUTER_ID) self.valid = is_destination and type(self.src_addr) == "number" and type(self.dest_addr) == "number" and - type(self.mac) == "string" and type(self.payload) == "string" + type(self.mac) == "string" and type(self.payload) == "table" end end diff --git a/scada-common/network.lua b/scada-common/network.lua index bdaf5c32..4dce34ec 100644 --- a/scada-common/network.lua +++ b/scada-common/network.lua @@ -114,7 +114,7 @@ function network.nic(modem) modem.open(channel) end - -- link all public functions except for transmit + -- link all public functions except for transmit, open, and close for key, func in pairs(modem) do if key ~= "transmit" and key ~= "open" and key ~= "close" and key ~= "closeAll" then public[key] = func end end @@ -184,7 +184,7 @@ function network.nic(modem) ---@cast tx_packet authd_packet tx_packet.make(packet, compute_hmac) - -- log.debug("crypto.modem.transmit: data processing took " .. (util.time_ms() - start) .. "ms") + -- log.debug("network.modem.transmit: data processing took " .. (util.time_ms() - start) .. "ms") end modem.transmit(dest_channel, local_channel, tx_packet.raw_sendable()) @@ -211,17 +211,18 @@ function network.nic(modem) a_packet.receive(side, sender, reply_to, message, distance) if a_packet.is_valid() then + s_packet.receive(side, sender, reply_to, a_packet.data(), distance) + + if s_packet.is_valid() then -- local start = util.time_ms() - local packet_hmac = a_packet.mac() - local msg = a_packet.data() - local computed_hmac = compute_hmac(msg) + local computed_hmac = compute_hmac(textutils.serialize(s_packet.raw_header(), { allow_repetitions = true, compact = true })) - if packet_hmac == computed_hmac then - -- log.debug("crypto.modem.receive: HMAC verified in " .. (util.time_ms() - start) .. "ms") - s_packet.receive(side, sender, reply_to, textutils.unserialize(msg), distance) + if a_packet.mac() == computed_hmac then + -- log.debug("network.modem.receive: HMAC verified in " .. (util.time_ms() - start) .. "ms") s_packet.stamp_authenticated() else - -- log.debug("crypto.modem.receive: HMAC failed verification in " .. (util.time_ms() - start) .. "ms") + -- log.debug("network.modem.receive: HMAC failed verification in " .. (util.time_ms() - start) .. "ms") + end end end else diff --git a/supervisor/session/coordinator.lua b/supervisor/session/coordinator.lua index 9c9284fb..f4496500 100644 --- a/supervisor/session/coordinator.lua +++ b/supervisor/session/coordinator.lua @@ -43,12 +43,13 @@ local PERIODICS = { ---@nodiscard ---@param id integer session ID ---@param s_addr integer device source address +---@param i_seq_num integer initial sequence number ---@param in_queue mqueue in message queue ---@param out_queue mqueue out message queue ---@param timeout number communications timeout ---@param facility facility facility data table ---@param fp_ok boolean if the front panel UI is running -function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facility, fp_ok) +function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, 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 @@ -57,8 +58,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil local self = { units = facility.get_units(), -- connection properties - seq_num = 0, - r_seq_num = nil, + seq_num = i_seq_num, connected = true, conn_watchdog = util.new_watchdog(timeout), establish_time = util.time_s(), @@ -182,13 +182,11 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil ---@param pkt mgmt_frame|crdn_frame local function _handle_packet(pkt) -- check sequence number - if self.r_seq_num == nil then - self.r_seq_num = pkt.scada_frame.seq_num() - elseif (self.r_seq_num + 1) ~= pkt.scada_frame.seq_num() then - log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num()) + if self.seq_num ~= pkt.scada_frame.seq_num() then + log.warning(log_header .. "sequence out-of-order: last = " .. self.seq_num .. ", new = " .. pkt.scada_frame.seq_num()) return else - self.r_seq_num = pkt.scada_frame.seq_num() + self.seq_num = pkt.scada_frame.seq_num() + 1 end -- feed watchdog diff --git a/supervisor/session/plc.lua b/supervisor/session/plc.lua index a4a82712..63293e4a 100644 --- a/supervisor/session/plc.lua +++ b/supervisor/session/plc.lua @@ -48,12 +48,13 @@ local PERIODICS = { ---@nodiscard ---@param id integer session ID ---@param s_addr integer device source address +---@param i_seq_num integer initial sequence number ---@param reactor_id integer reactor ID ---@param in_queue mqueue in message queue ---@param out_queue mqueue out message queue ---@param timeout number communications timeout ---@param fp_ok boolean if the front panel UI is running -function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, fp_ok) +function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue, timeout, 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 @@ -66,8 +67,7 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f ramping_rate = false, auto_lock = false, -- connection properties - seq_num = 0, - r_seq_num = nil, + seq_num = i_seq_num, connected = true, received_struct = false, received_status_cache = false, @@ -309,13 +309,11 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f ---@param pkt mgmt_frame|rplc_frame local function _handle_packet(pkt) -- check sequence number - if self.r_seq_num == nil then - self.r_seq_num = pkt.scada_frame.seq_num() - elseif (self.r_seq_num + 1) ~= pkt.scada_frame.seq_num() then - log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num()) + if self.seq_num ~= pkt.scada_frame.seq_num() then + log.warning(log_header .. "sequence out-of-order: last = " .. self.seq_num .. ", new = " .. pkt.scada_frame.seq_num()) return else - self.r_seq_num = pkt.scada_frame.seq_num() + self.seq_num = pkt.scada_frame.seq_num() + 1 end -- process packet diff --git a/supervisor/session/pocket.lua b/supervisor/session/pocket.lua index 48756eab..145add24 100644 --- a/supervisor/session/pocket.lua +++ b/supervisor/session/pocket.lua @@ -30,12 +30,13 @@ local PERIODICS = { ---@nodiscard ---@param id integer session ID ---@param s_addr integer device source address +---@param i_seq_num integer initial sequence number ---@param in_queue mqueue in message queue ---@param out_queue mqueue out message queue ---@param timeout number communications timeout ---@param facility facility facility data table ---@param fp_ok boolean if the front panel UI is running -function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility, fp_ok) +function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, 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 @@ -43,8 +44,7 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility, local self = { -- connection properties - seq_num = 0, - r_seq_num = nil, + seq_num = i_seq_num, connected = true, conn_watchdog = util.new_watchdog(timeout), last_rtt = 0, @@ -93,13 +93,11 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility, ---@param pkt mgmt_frame local function _handle_packet(pkt) -- check sequence number - if self.r_seq_num == nil then - self.r_seq_num = pkt.scada_frame.seq_num() - elseif (self.r_seq_num + 1) ~= pkt.scada_frame.seq_num() then - log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num()) + if self.seq_num ~= pkt.scada_frame.seq_num() then + log.warning(log_header .. "sequence out-of-order: last = " .. self.seq_num .. ", new = " .. pkt.scada_frame.seq_num()) return else - self.r_seq_num = pkt.scada_frame.seq_num() + self.seq_num = pkt.scada_frame.seq_num() + 1 end -- feed watchdog diff --git a/supervisor/session/rtu.lua b/supervisor/session/rtu.lua index 6bebb876..789e6493 100644 --- a/supervisor/session/rtu.lua +++ b/supervisor/session/rtu.lua @@ -34,13 +34,14 @@ local PERIODICS = { ---@nodiscard ---@param id integer session ID ---@param s_addr integer device source address +---@param i_seq_num integer initial sequence number ---@param in_queue mqueue in message queue ---@param out_queue mqueue out message queue ---@param timeout number communications timeout ---@param advertisement table RTU device advertisement ---@param facility facility facility data table ---@param fp_ok boolean if the front panel UI is running -function rtu.new_session(id, s_addr, in_queue, out_queue, timeout, advertisement, facility, fp_ok) +function rtu.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, advertisement, 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 @@ -51,8 +52,7 @@ function rtu.new_session(id, s_addr, in_queue, out_queue, timeout, advertisement advert = advertisement, fac_units = facility.get_units(), -- connection properties - seq_num = 0, - r_seq_num = nil, + seq_num = i_seq_num, connected = true, conn_watchdog = util.new_watchdog(timeout), last_rtt = 0, @@ -240,13 +240,11 @@ function rtu.new_session(id, s_addr, in_queue, out_queue, timeout, advertisement ---@param pkt modbus_frame|mgmt_frame local function _handle_packet(pkt) -- check sequence number - if self.r_seq_num == nil then - self.r_seq_num = pkt.scada_frame.seq_num() - elseif (self.r_seq_num + 1) ~= pkt.scada_frame.seq_num() then - log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num()) + if self.seq_num ~= pkt.scada_frame.seq_num() then + log.warning(log_header .. "sequence out-of-order: last = " .. self.seq_num .. ", new = " .. pkt.scada_frame.seq_num()) return else - self.r_seq_num = pkt.scada_frame.seq_num() + self.seq_num = pkt.scada_frame.seq_num() + 1 end -- feed watchdog diff --git a/supervisor/session/svsessions.lua b/supervisor/session/svsessions.lua index 7300162b..c7c24fc5 100644 --- a/supervisor/session/svsessions.lua +++ b/supervisor/session/svsessions.lua @@ -273,11 +273,12 @@ end -- establish a new PLC session ---@nodiscard ----@param source_addr integer ----@param for_reactor integer ----@param version string +---@param source_addr integer PLC computer ID +---@param i_seq_num integer initial sequence number to use next +---@param for_reactor integer unit ID +---@param version string PLC version ---@return integer|false session_id -function svsessions.establish_plc_session(source_addr, for_reactor, version) +function svsessions.establish_plc_session(source_addr, i_seq_num, for_reactor, version) if svsessions.get_reactor_session(for_reactor) == nil and for_reactor >= 1 and for_reactor <= self.config.UnitCount then ---@class plc_session_struct local plc_s = { @@ -294,7 +295,7 @@ function svsessions.establish_plc_session(source_addr, for_reactor, version) local id = self.next_ids.plc - plc_s.instance = plc.new_session(id, source_addr, for_reactor, plc_s.in_queue, plc_s.out_queue, self.config.PLC_Timeout, self.fp_ok) + plc_s.instance = plc.new_session(id, source_addr, i_seq_num, for_reactor, plc_s.in_queue, plc_s.out_queue, self.config.PLC_Timeout, self.fp_ok) table.insert(self.sessions.plc, plc_s) local units = self.facility.get_units() @@ -320,13 +321,14 @@ function svsessions.establish_plc_session(source_addr, for_reactor, version) end end --- establish a new RTU session +-- establish a new RTU gateway session ---@nodiscard ----@param source_addr integer ----@param advertisement table ----@param version string +---@param source_addr integer RTU gateway computer ID +---@param i_seq_num integer initial sequence number to use next +---@param advertisement table RTU capability advertisement +---@param version string RTU gateway version ---@return integer session_id -function svsessions.establish_rtu_session(source_addr, advertisement, version) +function svsessions.establish_rtu_session(source_addr, i_seq_num, advertisement, version) ---@class rtu_session_struct local rtu_s = { s_type = "rtu", @@ -341,7 +343,7 @@ function svsessions.establish_rtu_session(source_addr, advertisement, version) local id = self.next_ids.rtu - rtu_s.instance = rtu.new_session(id, source_addr, rtu_s.in_queue, rtu_s.out_queue, self.config.RTU_Timeout, advertisement, self.facility, self.fp_ok) + rtu_s.instance = rtu.new_session(id, source_addr, i_seq_num, rtu_s.in_queue, rtu_s.out_queue, self.config.RTU_Timeout, advertisement, self.facility, self.fp_ok) table.insert(self.sessions.rtu, rtu_s) local mt = { @@ -362,10 +364,11 @@ end -- establish a new coordinator session ---@nodiscard ----@param source_addr integer ----@param version string +---@param source_addr integer coordinator computer ID +---@param i_seq_num integer initial sequence number to use next +---@param version string coordinator version ---@return integer|false session_id -function svsessions.establish_crd_session(source_addr, version) +function svsessions.establish_crd_session(source_addr, i_seq_num, version) if svsessions.get_crd_session() == nil then ---@class crd_session_struct local crd_s = { @@ -381,7 +384,7 @@ function svsessions.establish_crd_session(source_addr, version) local id = self.next_ids.crd - crd_s.instance = coordinator.new_session(id, source_addr, crd_s.in_queue, crd_s.out_queue, self.config.CRD_Timeout, self.facility, self.fp_ok) + crd_s.instance = coordinator.new_session(id, source_addr, i_seq_num, crd_s.in_queue, crd_s.out_queue, self.config.CRD_Timeout, self.facility, self.fp_ok) table.insert(self.sessions.crd, crd_s) local mt = { @@ -406,10 +409,11 @@ end -- establish a new pocket diagnostics session ---@nodiscard ----@param source_addr integer ----@param version string +---@param source_addr integer pocket computer ID +---@param i_seq_num integer initial sequence number to use next +---@param version string pocket version ---@return integer|false session_id -function svsessions.establish_pdg_session(source_addr, version) +function svsessions.establish_pdg_session(source_addr, i_seq_num, version) ---@class pdg_session_struct local pdg_s = { s_type = "pkt", @@ -424,7 +428,7 @@ function svsessions.establish_pdg_session(source_addr, version) local id = self.next_ids.pdg - pdg_s.instance = pocket.new_session(id, source_addr, 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.facility, self.fp_ok) table.insert(self.sessions.pdg, pdg_s) local mt = { diff --git a/supervisor/startup.lua b/supervisor/startup.lua index 89c38d8a..edc60f17 100644 --- a/supervisor/startup.lua +++ b/supervisor/startup.lua @@ -21,7 +21,7 @@ local supervisor = require("supervisor.supervisor") local svsessions = require("supervisor.session.svsessions") -local SUPERVISOR_VERSION = "v1.3.12" +local SUPERVISOR_VERSION = "v1.4.0" local println = util.println local println_ts = util.println_ts @@ -214,7 +214,7 @@ local function main() elseif event == "modem_message" then -- got a packet local packet = superv_comms.parse_packet(param1, param2, param3, param4, param5) - superv_comms.handle_packet(packet) + if packet then superv_comms.handle_packet(packet) end elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" or event == "double_click" then -- handle a mouse event diff --git a/supervisor/supervisor.lua b/supervisor/supervisor.lua index 1d79e72c..2d69b7cc 100644 --- a/supervisor/supervisor.lua +++ b/supervisor/supervisor.lua @@ -191,283 +191,282 @@ function supervisor.comms(_version, nic, fp_ok) end -- handle a packet - ---@param packet modbus_frame|rplc_frame|mgmt_frame|crdn_frame|nil + ---@param packet modbus_frame|rplc_frame|mgmt_frame|crdn_frame function public.handle_packet(packet) - if packet ~= nil then - local l_chan = packet.scada_frame.local_channel() - local r_chan = packet.scada_frame.remote_channel() - local src_addr = packet.scada_frame.src_addr() - local protocol = packet.scada_frame.protocol() - - if l_chan ~= config.SVR_Channel then - log.debug("received packet on unconfigured channel " .. l_chan, true) - elseif r_chan == config.PLC_Channel then - -- look for an associated session - local session = svsessions.find_plc_session(src_addr) - - if protocol == PROTOCOL.RPLC then - ---@cast packet rplc_frame - -- reactor PLC packet - if session ~= nil then - -- pass the packet onto the session handler - session.in_queue.push_packet(packet) - else - -- any other packet should be session related, discard it - log.debug("discarding RPLC packet without a known session") - end - elseif protocol == PROTOCOL.SCADA_MGMT then - ---@cast packet mgmt_frame - -- SCADA management packet - if session ~= nil then - -- pass the packet onto the session handler - session.in_queue.push_packet(packet) - elseif packet.type == MGMT_TYPE.ESTABLISH then - -- establish a new session - local last_ack = self.last_est_acks[src_addr] - - -- validate packet and continue - if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then - local comms_v = packet.data[1] - local firmware_v = packet.data[2] - local dev_type = packet.data[3] - - if comms_v ~= comms.version then - if last_ack ~= ESTABLISH_ACK.BAD_VERSION then - log.info(util.c("dropping PLC establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")")) - end + local l_chan = packet.scada_frame.local_channel() + local r_chan = packet.scada_frame.remote_channel() + local src_addr = packet.scada_frame.src_addr() + local protocol = packet.scada_frame.protocol() + local i_seq_num = packet.scada_frame.seq_num() + 1 + + if l_chan ~= config.SVR_Channel then + log.debug("received packet on unconfigured channel " .. l_chan, true) + elseif r_chan == config.PLC_Channel then + -- look for an associated session + local session = svsessions.find_plc_session(src_addr) + + if protocol == PROTOCOL.RPLC then + ---@cast packet rplc_frame + -- reactor PLC packet + if session ~= nil then + -- pass the packet onto the session handler + session.in_queue.push_packet(packet) + else + -- any other packet should be session related, discard it + log.debug("discarding RPLC packet without a known session") + end + elseif protocol == PROTOCOL.SCADA_MGMT then + ---@cast packet mgmt_frame + -- SCADA management packet + if session ~= nil then + -- pass the packet onto the session handler + session.in_queue.push_packet(packet) + elseif packet.type == MGMT_TYPE.ESTABLISH then + -- establish a new session + local last_ack = self.last_est_acks[src_addr] + + -- validate packet and continue + if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then + local comms_v = packet.data[1] + local firmware_v = packet.data[2] + local dev_type = packet.data[3] + + if comms_v ~= comms.version then + if last_ack ~= ESTABLISH_ACK.BAD_VERSION then + log.info(util.c("dropping PLC establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")")) + end + + _send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION) + elseif dev_type == DEVICE_TYPE.PLC then + -- PLC linking request + if packet.length == 4 and type(packet.data[4]) == "number" then + local reactor_id = packet.data[4] + local plc_id = svsessions.establish_plc_session(src_addr, i_seq_num, reactor_id, firmware_v) - _send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION) - elseif dev_type == DEVICE_TYPE.PLC then - -- PLC linking request - if packet.length == 4 and type(packet.data[4]) == "number" then - local reactor_id = packet.data[4] - local plc_id = svsessions.establish_plc_session(src_addr, reactor_id, firmware_v) - - if plc_id == false then - -- reactor already has a PLC assigned - if last_ack ~= ESTABLISH_ACK.COLLISION then - log.warning(util.c("PLC_ESTABLISH: assignment collision with reactor ", reactor_id)) - end - - _send_establish(packet.scada_frame, ESTABLISH_ACK.COLLISION) - else - -- got an ID; assigned to a reactor successfully - println(util.c("PLC (", firmware_v, ") [@", src_addr, "] \xbb reactor ", reactor_id, " connected")) - log.info(util.c("PLC_ESTABLISH: PLC (", firmware_v, ") [@", src_addr, "] reactor unit ", reactor_id, " PLC connected with session ID ", plc_id)) - _send_establish(packet.scada_frame, ESTABLISH_ACK.ALLOW) + if plc_id == false then + -- reactor already has a PLC assigned + if last_ack ~= ESTABLISH_ACK.COLLISION then + log.warning(util.c("PLC_ESTABLISH: assignment collision with reactor ", reactor_id)) end + + _send_establish(packet.scada_frame, ESTABLISH_ACK.COLLISION) else - log.debug("PLC_ESTABLISH: packet length mismatch/bad parameter type") - _send_establish(packet.scada_frame, ESTABLISH_ACK.DENY) + -- got an ID; assigned to a reactor successfully + println(util.c("PLC (", firmware_v, ") [@", src_addr, "] \xbb reactor ", reactor_id, " connected")) + log.info(util.c("PLC_ESTABLISH: PLC (", firmware_v, ") [@", src_addr, "] reactor unit ", reactor_id, " PLC connected with session ID ", plc_id)) + _send_establish(packet.scada_frame, ESTABLISH_ACK.ALLOW) end else - log.debug(util.c("illegal establish packet for device ", dev_type, " on PLC channel")) + log.debug("PLC_ESTABLISH: packet length mismatch/bad parameter type") _send_establish(packet.scada_frame, ESTABLISH_ACK.DENY) end else - log.debug("invalid establish packet (on PLC channel)") + log.debug(util.c("illegal establish packet for device ", dev_type, " on PLC channel")) _send_establish(packet.scada_frame, ESTABLISH_ACK.DENY) end else - -- any other packet should be session related, discard it - log.debug(util.c("discarding PLC SCADA_MGMT packet without a known session from computer ", src_addr)) + log.debug("invalid establish packet (on PLC channel)") + _send_establish(packet.scada_frame, ESTABLISH_ACK.DENY) end else - log.debug(util.c("illegal packet type ", protocol, " on PLC channel")) + -- any other packet should be session related, discard it + log.debug(util.c("discarding PLC SCADA_MGMT packet without a known session from computer ", src_addr)) end - elseif r_chan == config.RTU_Channel then - -- look for an associated session - local session = svsessions.find_rtu_session(src_addr) - - if protocol == PROTOCOL.MODBUS_TCP then - ---@cast packet modbus_frame - -- MODBUS response - if session ~= nil then - -- pass the packet onto the session handler - session.in_queue.push_packet(packet) - else - -- any other packet should be session related, discard it - log.debug("discarding MODBUS_TCP packet without a known session") - end - elseif protocol == PROTOCOL.SCADA_MGMT then - ---@cast packet mgmt_frame - -- SCADA management packet - if session ~= nil then - -- pass the packet onto the session handler - session.in_queue.push_packet(packet) - elseif packet.type == MGMT_TYPE.ESTABLISH then - -- establish a new session - local last_ack = self.last_est_acks[src_addr] - - -- validate packet and continue - if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then - local comms_v = packet.data[1] - local firmware_v = packet.data[2] - local dev_type = packet.data[3] - - if comms_v ~= comms.version then - if last_ack ~= ESTABLISH_ACK.BAD_VERSION then - log.info(util.c("dropping RTU establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")")) - end + else + log.debug(util.c("illegal packet type ", protocol, " on PLC channel")) + end + elseif r_chan == config.RTU_Channel then + -- look for an associated session + local session = svsessions.find_rtu_session(src_addr) + + if protocol == PROTOCOL.MODBUS_TCP then + ---@cast packet modbus_frame + -- MODBUS response + if session ~= nil then + -- pass the packet onto the session handler + session.in_queue.push_packet(packet) + else + -- any other packet should be session related, discard it + log.debug("discarding MODBUS_TCP packet without a known session") + end + elseif protocol == PROTOCOL.SCADA_MGMT then + ---@cast packet mgmt_frame + -- SCADA management packet + if session ~= nil then + -- pass the packet onto the session handler + session.in_queue.push_packet(packet) + elseif packet.type == MGMT_TYPE.ESTABLISH then + -- establish a new session + local last_ack = self.last_est_acks[src_addr] + + -- validate packet and continue + if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then + local comms_v = packet.data[1] + local firmware_v = packet.data[2] + local dev_type = packet.data[3] + + if comms_v ~= comms.version then + if last_ack ~= ESTABLISH_ACK.BAD_VERSION then + log.info(util.c("dropping RTU establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")")) + end - _send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION) - elseif dev_type == DEVICE_TYPE.RTU then - if packet.length == 4 then - -- this is an RTU advertisement for a new session - local rtu_advert = packet.data[4] - local s_id = svsessions.establish_rtu_session(src_addr, rtu_advert, firmware_v) + _send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION) + elseif dev_type == DEVICE_TYPE.RTU then + if packet.length == 4 then + -- this is an RTU advertisement for a new session + local rtu_advert = packet.data[4] + local s_id = svsessions.establish_rtu_session(src_addr, i_seq_num, rtu_advert, firmware_v) - println(util.c("RTU (", firmware_v, ") [@", src_addr, "] \xbb connected")) - log.info(util.c("RTU_ESTABLISH: RTU (",firmware_v, ") [@", src_addr, "] connected with session ID ", s_id)) - _send_establish(packet.scada_frame, ESTABLISH_ACK.ALLOW) - else - log.debug("RTU_ESTABLISH: packet length mismatch") - _send_establish(packet.scada_frame, ESTABLISH_ACK.DENY) - end + println(util.c("RTU (", firmware_v, ") [@", src_addr, "] \xbb connected")) + log.info(util.c("RTU_ESTABLISH: RTU (",firmware_v, ") [@", src_addr, "] connected with session ID ", s_id)) + _send_establish(packet.scada_frame, ESTABLISH_ACK.ALLOW) else - log.debug(util.c("illegal establish packet for device ", dev_type, " on RTU channel")) + log.debug("RTU_ESTABLISH: packet length mismatch") _send_establish(packet.scada_frame, ESTABLISH_ACK.DENY) end else - log.debug("invalid establish packet (on RTU channel)") + log.debug(util.c("illegal establish packet for device ", dev_type, " on RTU channel")) _send_establish(packet.scada_frame, ESTABLISH_ACK.DENY) end else - -- any other packet should be session related, discard it - log.debug(util.c("discarding RTU SCADA_MGMT packet without a known session from computer ", src_addr)) + log.debug("invalid establish packet (on RTU channel)") + _send_establish(packet.scada_frame, ESTABLISH_ACK.DENY) end else - log.debug(util.c("illegal packet type ", protocol, " on RTU channel")) + -- any other packet should be session related, discard it + log.debug(util.c("discarding RTU SCADA_MGMT packet without a known session from computer ", src_addr)) end - elseif r_chan == config.CRD_Channel then - -- look for an associated session - local session = svsessions.find_crd_session(src_addr) - - if protocol == PROTOCOL.SCADA_MGMT then - ---@cast packet mgmt_frame - -- SCADA management packet - if session ~= nil then - -- pass the packet onto the session handler - session.in_queue.push_packet(packet) - elseif packet.type == MGMT_TYPE.ESTABLISH then - -- establish a new session - local last_ack = self.last_est_acks[src_addr] - - -- validate packet and continue - if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then - local comms_v = packet.data[1] - local firmware_v = packet.data[2] - local dev_type = packet.data[3] - - if comms_v ~= comms.version then - if last_ack ~= ESTABLISH_ACK.BAD_VERSION then - log.info(util.c("dropping coordinator establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")")) - end - - _send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION) - elseif dev_type == DEVICE_TYPE.CRD then - -- this is an attempt to establish a new coordinator session - local s_id = svsessions.establish_crd_session(src_addr, firmware_v) + else + log.debug(util.c("illegal packet type ", protocol, " on RTU channel")) + end + elseif r_chan == config.CRD_Channel then + -- look for an associated session + local session = svsessions.find_crd_session(src_addr) + + if protocol == PROTOCOL.SCADA_MGMT then + ---@cast packet mgmt_frame + -- SCADA management packet + if session ~= nil then + -- pass the packet onto the session handler + session.in_queue.push_packet(packet) + elseif packet.type == MGMT_TYPE.ESTABLISH then + -- establish a new session + local last_ack = self.last_est_acks[src_addr] + + -- validate packet and continue + if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then + local comms_v = packet.data[1] + local firmware_v = packet.data[2] + local dev_type = packet.data[3] + + if comms_v ~= comms.version then + if last_ack ~= ESTABLISH_ACK.BAD_VERSION then + log.info(util.c("dropping coordinator establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")")) + end - if s_id ~= false then - println(util.c("CRD (", firmware_v, ") [@", src_addr, "] \xbb connected")) - log.info(util.c("CRD_ESTABLISH: coordinator (", firmware_v, ") [@", src_addr, "] connected with session ID ", s_id)) + _send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION) + elseif dev_type == DEVICE_TYPE.CRD then + -- this is an attempt to establish a new coordinator session + local s_id = svsessions.establish_crd_session(src_addr, i_seq_num, firmware_v) - _send_establish(packet.scada_frame, ESTABLISH_ACK.ALLOW, { config.UnitCount, cooling_conf }) - else - if last_ack ~= ESTABLISH_ACK.COLLISION then - log.info("CRD_ESTABLISH: denied new coordinator [@" .. src_addr .. "] due to already being connected to another coordinator") - end + if s_id ~= false then + println(util.c("CRD (", firmware_v, ") [@", src_addr, "] \xbb connected")) + log.info(util.c("CRD_ESTABLISH: coordinator (", firmware_v, ") [@", src_addr, "] connected with session ID ", s_id)) - _send_establish(packet.scada_frame, ESTABLISH_ACK.COLLISION) - end + _send_establish(packet.scada_frame, ESTABLISH_ACK.ALLOW, { config.UnitCount, cooling_conf }) else - log.debug(util.c("illegal establish packet for device ", dev_type, " on coordinator channel")) - _send_establish(packet.scada_frame, ESTABLISH_ACK.DENY) + if last_ack ~= ESTABLISH_ACK.COLLISION then + log.info("CRD_ESTABLISH: denied new coordinator [@" .. src_addr .. "] due to already being connected to another coordinator") + end + + _send_establish(packet.scada_frame, ESTABLISH_ACK.COLLISION) end else - log.debug("CRD_ESTABLISH: establish packet length mismatch") + log.debug(util.c("illegal establish packet for device ", dev_type, " on coordinator channel")) _send_establish(packet.scada_frame, ESTABLISH_ACK.DENY) end else - -- any other packet should be session related, discard it - log.debug(util.c("discarding coordinator SCADA_MGMT packet without a known session from computer ", src_addr)) - end - elseif protocol == PROTOCOL.SCADA_CRDN then - ---@cast packet crdn_frame - -- coordinator packet - if session ~= nil then - -- pass the packet onto the session handler - session.in_queue.push_packet(packet) - else - -- any other packet should be session related, discard it - log.debug(util.c("discarding coordinator SCADA_CRDN packet without a known session from computer ", src_addr)) + log.debug("CRD_ESTABLISH: establish packet length mismatch") + _send_establish(packet.scada_frame, ESTABLISH_ACK.DENY) end else - log.debug(util.c("illegal packet type ", protocol, " on coordinator channel")) + -- any other packet should be session related, discard it + log.debug(util.c("discarding coordinator SCADA_MGMT packet without a known session from computer ", src_addr)) end - elseif r_chan == config.PKT_Channel then - -- look for an associated session - local session = svsessions.find_pdg_session(src_addr) - - if protocol == PROTOCOL.SCADA_MGMT then - ---@cast packet mgmt_frame - -- SCADA management packet - if session ~= nil then - -- pass the packet onto the session handler - session.in_queue.push_packet(packet) - elseif packet.type == MGMT_TYPE.ESTABLISH then - -- establish a new session - local last_ack = self.last_est_acks[src_addr] - - -- validate packet and continue - if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then - local comms_v = packet.data[1] - local firmware_v = packet.data[2] - local dev_type = packet.data[3] - - if comms_v ~= comms.version then - if last_ack ~= ESTABLISH_ACK.BAD_VERSION then - log.info(util.c("dropping PDG establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")")) - end + elseif protocol == PROTOCOL.SCADA_CRDN then + ---@cast packet crdn_frame + -- coordinator packet + if session ~= nil then + -- pass the packet onto the session handler + session.in_queue.push_packet(packet) + else + -- any other packet should be session related, discard it + log.debug(util.c("discarding coordinator SCADA_CRDN packet without a known session from computer ", src_addr)) + end + else + log.debug(util.c("illegal packet type ", protocol, " on coordinator channel")) + end + elseif r_chan == config.PKT_Channel then + -- look for an associated session + local session = svsessions.find_pdg_session(src_addr) + + if protocol == PROTOCOL.SCADA_MGMT then + ---@cast packet mgmt_frame + -- SCADA management packet + if session ~= nil then + -- pass the packet onto the session handler + session.in_queue.push_packet(packet) + elseif packet.type == MGMT_TYPE.ESTABLISH then + -- establish a new session + local last_ack = self.last_est_acks[src_addr] + + -- validate packet and continue + if packet.length >= 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then + local comms_v = packet.data[1] + local firmware_v = packet.data[2] + local dev_type = packet.data[3] + + if comms_v ~= comms.version then + if last_ack ~= ESTABLISH_ACK.BAD_VERSION then + log.info(util.c("dropping PDG establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")")) + end - _send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION) - elseif dev_type == DEVICE_TYPE.PKT then - -- this is an attempt to establish a new pocket diagnostic session - local s_id = svsessions.establish_pdg_session(src_addr, firmware_v) + _send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION) + elseif dev_type == DEVICE_TYPE.PKT then + -- this is an attempt to establish a new pocket diagnostic session + local s_id = svsessions.establish_pdg_session(src_addr, i_seq_num, firmware_v) - println(util.c("PKT (", firmware_v, ") [@", src_addr, "] \xbb connected")) - log.info(util.c("PDG_ESTABLISH: pocket (", firmware_v, ") [@", src_addr, "] connected with session ID ", s_id)) + println(util.c("PKT (", firmware_v, ") [@", src_addr, "] \xbb connected")) + log.info(util.c("PDG_ESTABLISH: pocket (", firmware_v, ") [@", src_addr, "] connected with session ID ", s_id)) - _send_establish(packet.scada_frame, ESTABLISH_ACK.ALLOW) - else - log.debug(util.c("illegal establish packet for device ", dev_type, " on pocket channel")) - _send_establish(packet.scada_frame, ESTABLISH_ACK.DENY) - end + _send_establish(packet.scada_frame, ESTABLISH_ACK.ALLOW) else - log.debug("PDG_ESTABLISH: establish packet length mismatch") + log.debug(util.c("illegal establish packet for device ", dev_type, " on pocket channel")) _send_establish(packet.scada_frame, ESTABLISH_ACK.DENY) end else - -- any other packet should be session related, discard it - log.debug(util.c("discarding pocket SCADA_MGMT packet without a known session from computer ", src_addr)) - end - elseif protocol == PROTOCOL.SCADA_CRDN then - ---@cast packet crdn_frame - -- coordinator packet - if session ~= nil then - -- pass the packet onto the session handler - session.in_queue.push_packet(packet) - else - -- any other packet should be session related, discard it - log.debug(util.c("discarding pocket SCADA_CRDN packet without a known session from computer ", src_addr)) + log.debug("PDG_ESTABLISH: establish packet length mismatch") + _send_establish(packet.scada_frame, ESTABLISH_ACK.DENY) end else - log.debug(util.c("illegal packet type ", protocol, " on pocket channel")) + -- any other packet should be session related, discard it + log.debug(util.c("discarding pocket SCADA_MGMT packet without a known session from computer ", src_addr)) + end + elseif protocol == PROTOCOL.SCADA_CRDN then + ---@cast packet crdn_frame + -- coordinator packet + if session ~= nil then + -- pass the packet onto the session handler + session.in_queue.push_packet(packet) + else + -- any other packet should be session related, discard it + log.debug(util.c("discarding pocket SCADA_CRDN packet without a known session from computer ", src_addr)) end else - log.debug("received packet for unknown channel " .. r_chan, true) + log.debug(util.c("illegal packet type ", protocol, " on pocket channel")) end + else + log.debug("received packet for unknown channel " .. r_chan, true) end end From bc76c01aa56375185f9355e62fe3c2370b6b6fe0 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 12:18:55 -0400 Subject: [PATCH 08/44] #504 fixed reactor idle status on pocket display --- pocket/iocontrol.lua | 5 ++++- pocket/startup.lua | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pocket/iocontrol.lua b/pocket/iocontrol.lua index 38e642e6..de69dd37 100644 --- a/pocket/iocontrol.lua +++ b/pocket/iocontrol.lua @@ -523,7 +523,10 @@ function iocontrol.record_unit_data(data) reactor_state = 6 -- SCRAM rps_status = 2 end - else rps_status = 4 end + else + rps_status = 4 + reactor_state = 4 + end -- update reactor/control status if unit.reactor_data.mek_status.status then diff --git a/pocket/startup.lua b/pocket/startup.lua index a80a4ca4..7e5a7425 100644 --- a/pocket/startup.lua +++ b/pocket/startup.lua @@ -20,7 +20,7 @@ local pocket = require("pocket.pocket") local renderer = require("pocket.renderer") local threads = require("pocket.threads") -local POCKET_VERSION = "v0.10.0-alpha" +local POCKET_VERSION = "v0.10.1-alpha" local println = util.println local println_ts = util.println_ts From a15cbadd32d9fe2887d95733b67d862802b7fb5a Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 12:29:28 -0400 Subject: [PATCH 09/44] #497 initial loading screen --- pocket/startup.lua | 2 +- pocket/ui/main.lua | 51 ++++++++++++++++++++++++++++------------------ 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/pocket/startup.lua b/pocket/startup.lua index 7e5a7425..530bdef2 100644 --- a/pocket/startup.lua +++ b/pocket/startup.lua @@ -20,7 +20,7 @@ local pocket = require("pocket.pocket") local renderer = require("pocket.renderer") local threads = require("pocket.threads") -local POCKET_VERSION = "v0.10.1-alpha" +local POCKET_VERSION = "v0.10.2-alpha" local println = util.println local println_ts = util.println_ts diff --git a/pocket/ui/main.lua b/pocket/ui/main.lua index 4a33327a..6da1d7b5 100644 --- a/pocket/ui/main.lua +++ b/pocket/ui/main.lua @@ -2,32 +2,34 @@ -- Pocket GUI Root -- -local util = require("scada-common.util") +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 diag_apps = require("pocket.ui.apps.diag_apps") -local dummy_app = require("pocket.ui.apps.dummy_app") -local guide_app = require("pocket.ui.apps.guide") -local loader_app = require("pocket.ui.apps.loader") -local sys_apps = require("pocket.ui.apps.sys_apps") -local unit_app = require("pocket.ui.apps.unit") +local diag_apps = require("pocket.ui.apps.diag_apps") +local dummy_app = require("pocket.ui.apps.dummy_app") +local guide_app = require("pocket.ui.apps.guide") +local loader_app = require("pocket.ui.apps.loader") +local sys_apps = require("pocket.ui.apps.sys_apps") +local unit_app = require("pocket.ui.apps.unit") -local home_page = require("pocket.ui.pages.home_page") +local home_page = require("pocket.ui.pages.home_page") -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 MultiPane = require("graphics.elements.multipane") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.div") +local MultiPane = require("graphics.elements.multipane") +local TextBox = require("graphics.elements.textbox") -local PushButton = require("graphics.elements.controls.push_button") -local Sidebar = require("graphics.elements.controls.sidebar") +local WaitingAnim = require("graphics.elements.animations.waiting") -local SignalBar = require("graphics.elements.indicators.signal") +local PushButton = require("graphics.elements.controls.push_button") +local Sidebar = require("graphics.elements.controls.sidebar") + +local SignalBar = require("graphics.elements.indicators.signal") local ALIGN = core.ALIGN local cpair = core.cpair @@ -39,8 +41,6 @@ local APP_ID = pocket.APP_ID local function init(main) local db = iocontrol.get_db() - local main_pane = Div{parent=main,x=1,y=2} - -- window header message and connection status TextBox{parent=main,y=1,text="EARLY ACCESS ALPHA S C ",alignment=ALIGN.LEFT,height=1,fg_bg=style.header} local svr_conn = SignalBar{parent=main,y=1,x=22,compact=true,colors_low_med=cpair(colors.red,colors.yellow),disconnect_color=colors.lightGray,fg_bg=cpair(colors.green,colors.gray)} @@ -49,6 +49,14 @@ local function init(main) db.ps.subscribe("svr_conn_quality", svr_conn.set_value) db.ps.subscribe("crd_conn_quality", crd_conn.set_value) + local start_pane = Div{parent=main,x=1,y=2} + local main_pane = Div{parent=main,x=1,y=2} + + WaitingAnim{parent=start_pane,x=12,y=7,fg_bg=cpair(colors.lightBlue,style.root.bkg)} + TextBox{parent=start_pane,y=11,text="starting up...",alignment=ALIGN.CENTER,fg_bg=cpair(colors.lightGray,style.root.bkg)} + + local root_pane = MultiPane{parent=main,x=1,y=2,panes={start_pane,main_pane}} + local page_div = Div{parent=main_pane,x=4,y=1} -- create all the apps & pages @@ -69,6 +77,9 @@ local function init(main) PushButton{parent=main_pane,x=1,y=19,text="\x1b",min_width=3,fg_bg=cpair(colors.white,colors.gray),active_fg_bg=cpair(colors.gray,colors.black),callback=db.nav.nav_up} db.nav.open_app(APP_ID.ROOT) + + -- done with initial render, lets go! + root_pane.set_value(2) end return init From 55dc203cdd713ad21ca42bc27dfd2e2d9a28fca4 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 12:47:56 -0400 Subject: [PATCH 10/44] increment reactor plc version to 1.8.0 --- reactor-plc/startup.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactor-plc/startup.lua b/reactor-plc/startup.lua index fc925366..6f6a27b7 100644 --- a/reactor-plc/startup.lua +++ b/reactor-plc/startup.lua @@ -18,7 +18,7 @@ local plc = require("reactor-plc.plc") local renderer = require("reactor-plc.renderer") local threads = require("reactor-plc.threads") -local R_PLC_VERSION = "v1.7.12" +local R_PLC_VERSION = "v1.8.0" local println = util.println local println_ts = util.println_ts From 2de30ef06448e8f81af7bdacba4bcf86c79ebc05 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 14:10:58 -0400 Subject: [PATCH 11/44] #488 fixes to sequence number changes and auth packet data --- coordinator/coordinator.lua | 13 +++++++++---- coordinator/session/pocket.lua | 9 +++++---- pocket/pocket.lua | 22 ++++++++++++++++------ reactor-plc/plc.lua | 10 +++++++--- rtu/rtu.lua | 10 +++++++--- scada-common/comms.lua | 2 +- scada-common/network.lua | 10 +++++----- supervisor/session/coordinator.lua | 9 +++++---- supervisor/session/plc.lua | 9 +++++---- supervisor/session/pocket.lua | 9 +++++---- supervisor/session/rtu.lua | 9 +++++---- supervisor/session/svsessions.lua | 8 ++++---- supervisor/supervisor.lua | 2 +- 13 files changed, 75 insertions(+), 47 deletions(-) diff --git a/coordinator/coordinator.lua b/coordinator/coordinator.lua index 9e98a33c..27543eca 100644 --- a/coordinator/coordinator.lua +++ b/coordinator/coordinator.lua @@ -233,6 +233,7 @@ function coordinator.comms(version, nic, sv_watchdog) sv_linked = false, sv_addr = comms.BROADCAST, sv_seq_num = util.time_ms() * 10, -- unique per peer, restarting will not re-use seq nums due to message rate + sv_r_seq_num = nil, ---@type nil|integer sv_config_err = false, last_est_ack = ESTABLISH_ACK.ALLOW, last_api_est_acks = {}, @@ -369,6 +370,7 @@ function coordinator.comms(version, nic, sv_watchdog) sv_watchdog.cancel() self.sv_addr = comms.BROADCAST self.sv_linked = false + self.sv_r_seq_num = nil iocontrol.fp_link_state(types.PANEL_LINK_STATE.DISCONNECTED) _send_sv(PROTOCOL.SCADA_MGMT, MGMT_TYPE.CLOSE, {}) end @@ -490,7 +492,7 @@ function coordinator.comms(version, nic, sv_watchdog) _send_api_establish_ack(packet.scada_frame, ESTABLISH_ACK.BAD_API_VERSION) elseif dev_type == DEVICE_TYPE.PKT then -- pocket linking request - local id = apisessions.establish_session(src_addr, packet.scada_frame.seq_num() + 1, firmware_v) + local id = apisessions.establish_session(src_addr, packet.scada_frame.seq_num(), firmware_v) coordinator.log_comms(util.c("API_ESTABLISH: pocket (", firmware_v, ") [@", src_addr, "] connected with session ID ", id)) local conf = iocontrol.get_db().facility.conf @@ -512,14 +514,16 @@ function coordinator.comms(version, nic, sv_watchdog) end elseif r_chan == config.SVR_Channel then -- check sequence number - if self.sv_seq_num ~= packet.scada_frame.seq_num() then - log.warning("sequence out-of-order: last = " .. self.sv_seq_num .. ", new = " .. packet.scada_frame.seq_num()) + if self.sv_r_seq_num == nil then + self.sv_r_seq_num = packet.scada_frame.seq_num() + 1 + elseif self.sv_r_seq_num ~= packet.scada_frame.seq_num() then + log.warning("sequence out-of-order: last = " .. self.sv_r_seq_num .. ", new = " .. packet.scada_frame.seq_num()) return false elseif self.sv_linked and src_addr ~= self.sv_addr then log.debug("received packet from unknown computer " .. src_addr .. " while linked; channel in use by another system?") return false else - self.sv_seq_num = packet.scada_frame.seq_num() + 1 + self.sv_r_seq_num = packet.scada_frame.seq_num() + 1 end -- feed watchdog on valid sequence number @@ -671,6 +675,7 @@ function coordinator.comms(version, nic, sv_watchdog) sv_watchdog.cancel() self.sv_addr = comms.BROADCAST self.sv_linked = false + self.sv_r_seq_num = nil iocontrol.fp_link_state(types.PANEL_LINK_STATE.DISCONNECTED) log.info("server connection closed by remote host") else diff --git a/coordinator/session/pocket.lua b/coordinator/session/pocket.lua index f2f59e41..c554c645 100644 --- a/coordinator/session/pocket.lua +++ b/coordinator/session/pocket.lua @@ -41,7 +41,8 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout) local self = { -- connection properties - seq_num = i_seq_num, + seq_num = i_seq_num + 2, -- next after the establish approval was sent + r_seq_num = i_seq_num + 1, connected = true, conn_watchdog = util.new_watchdog(timeout), last_rtt = 0, @@ -104,11 +105,11 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout) ---@param pkt mgmt_frame|crdn_frame local function _handle_packet(pkt) -- check sequence number - if self.seq_num ~= pkt.scada_frame.seq_num() then - log.warning(log_header .. "sequence out-of-order: last = " .. self.seq_num .. ", new = " .. pkt.scada_frame.seq_num()) + if self.r_seq_num ~= pkt.scada_frame.seq_num() then + log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num()) return else - self.seq_num = pkt.scada_frame.seq_num() + 1 + self.r_seq_num = pkt.scada_frame.seq_num() + 1 end -- feed watchdog diff --git a/pocket/pocket.lua b/pocket/pocket.lua index fb4f41ab..82b87b54 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -371,12 +371,14 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) linked = false, addr = comms.BROADCAST, seq_num = util.time_ms() * 10, -- unique per peer, restarting will not re-use seq nums due to message rate + r_seq_num = nil, ---@type nil|integer last_est_ack = ESTABLISH_ACK.ALLOW }, api = { linked = false, addr = comms.BROADCAST, seq_num = util.time_ms() * 10, -- unique per peer, restarting will not re-use seq nums due to message rate + r_seq_num = nil, ---@type nil|integer last_est_ack = ESTABLISH_ACK.ALLOW }, establish_delay_counter = 0 @@ -465,6 +467,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) nav.unload_sv() self.sv.linked = false self.sv.addr = comms.BROADCAST + self.sv.r_seq_num = nil _send_sv(MGMT_TYPE.CLOSE, {}) end @@ -474,6 +477,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) nav.unload_api() self.api.linked = false self.api.addr = comms.BROADCAST + self.api.r_seq_num = nil _send_crd(MGMT_TYPE.CLOSE, {}) end @@ -599,15 +603,17 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) log.debug("received packet on unconfigured channel " .. l_chan, true) elseif r_chan == config.CRD_Channel then -- check sequence number - if self.api.seq_num ~= packet.scada_frame.seq_num() then - log.warning("sequence out-of-order (API): last = " .. self.api.seq_num .. ", new = " .. packet.scada_frame.seq_num()) + if self.api.r_seq_num == nil then + self.api.r_seq_num = packet.scada_frame.seq_num() + 1 + elseif self.api.r_seq_num ~= packet.scada_frame.seq_num() then + log.warning("sequence out-of-order (API): last = " .. self.api.r_seq_num .. ", new = " .. packet.scada_frame.seq_num()) return elseif self.api.linked and (src_addr ~= self.api.addr) then log.debug("received packet from unknown computer " .. src_addr .. " while linked (API expected " .. self.api.addr .. "); channel in use by another system?") return else - self.api.seq_num = packet.scada_frame.seq_num() + 1 + self.api.r_seq_num = packet.scada_frame.seq_num() + 1 end -- feed watchdog on valid sequence number @@ -653,6 +659,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) nav.unload_api() self.api.linked = false self.api.addr = comms.BROADCAST + self.api.r_seq_num = nil log.info("coordinator server connection closed by remote host") else _fail_type(packet) end elseif packet.type == MGMT_TYPE.ESTABLISH then @@ -716,15 +723,17 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) end elseif r_chan == config.SVR_Channel then -- check sequence number - if self.sv.seq_num ~= packet.scada_frame.seq_num() then - log.warning("sequence out-of-order (SVR): last = " .. self.sv.seq_num .. ", new = " .. packet.scada_frame.seq_num()) + if self.sv.r_seq_num == nil then + self.sv.r_seq_num = packet.scada_frame.seq_num() + 1 + elseif self.sv.r_seq_num ~= packet.scada_frame.seq_num() then + log.warning("sequence out-of-order (SVR): last = " .. self.sv.r_seq_num .. ", new = " .. packet.scada_frame.seq_num()) return elseif self.sv.linked and (src_addr ~= self.sv.addr) then log.debug("received packet from unknown computer " .. src_addr .. " while linked (SVR expected " .. self.sv.addr .. "); channel in use by another system?") return else - self.sv.seq_num = packet.scada_frame.seq_num() + 1 + self.sv.r_seq_num = packet.scada_frame.seq_num() + 1 end -- feed watchdog on valid sequence number @@ -756,6 +765,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) nav.unload_sv() self.sv.linked = false self.sv.addr = comms.BROADCAST + self.sv.r_seq_num = nil log.info("supervisor server connection closed by remote host") elseif packet.type == MGMT_TYPE.DIAG_TONE_GET then if _check_length(packet, 8) then diff --git a/reactor-plc/plc.lua b/reactor-plc/plc.lua index 3eead7e0..3a61e377 100644 --- a/reactor-plc/plc.lua +++ b/reactor-plc/plc.lua @@ -525,6 +525,7 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog) local self = { sv_addr = comms.BROADCAST, seq_num = util.time_ms() * 10, -- unique per peer, restarting will not re-use seq nums due to message rate + r_seq_num = nil, ---@type nil|integer scrammed = false, linked = false, last_est_ack = ESTABLISH_ACK.ALLOW, @@ -715,6 +716,7 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog) self.sv_addr = comms.BROADCAST self.linked = false self.status_cache = nil + self.r_seq_num = nil databus.tx_link_state(types.PANEL_LINK_STATE.DISCONNECTED) end @@ -822,15 +824,17 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog) -- handle packets now that we have prints setup if l_chan == config.PLC_Channel then -- check sequence number - if self.seq_num ~= packet.scada_frame.seq_num() then - log.warning("sequence out-of-order: last = " .. self.seq_num .. ", new = " .. packet.scada_frame.seq_num()) + if self.r_seq_num == nil then + self.r_seq_num = packet.scada_frame.seq_num() + 1 + elseif self.r_seq_num ~= packet.scada_frame.seq_num() then + log.warning("sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. packet.scada_frame.seq_num()) return elseif self.linked and (src_addr ~= self.sv_addr) then log.debug("received packet from unknown computer " .. src_addr .. " while linked (expected " .. self.sv_addr .. "); channel in use by another system?") return else - self.seq_num = packet.scada_frame.seq_num() + 1 + self.r_seq_num = packet.scada_frame.seq_num() + 1 end -- feed the watchdog first so it doesn't uhh...eat our packets :) diff --git a/rtu/rtu.lua b/rtu/rtu.lua index 0278f428..231c261e 100644 --- a/rtu/rtu.lua +++ b/rtu/rtu.lua @@ -285,6 +285,7 @@ function rtu.comms(version, nic, conn_watchdog) local self = { sv_addr = comms.BROADCAST, seq_num = util.time_ms() * 10, -- unique per peer, restarting will not re-use seq nums due to message rate + r_seq_num = nil, ---@type nil|integer txn_id = 0, last_est_ack = ESTABLISH_ACK.ALLOW } @@ -362,6 +363,7 @@ function rtu.comms(version, nic, conn_watchdog) function public.unlink(rtu_state) rtu_state.linked = false self.sv_addr = comms.BROADCAST + self.r_seq_num = nil databus.tx_link_state(types.PANEL_LINK_STATE.DISCONNECTED) end @@ -439,15 +441,17 @@ function rtu.comms(version, nic, conn_watchdog) if l_chan == config.RTU_Channel then -- check sequence number - if self.seq_num ~= packet.scada_frame.seq_num() then - log.warning("sequence out-of-order: last = " .. self.seq_num .. ", new = " .. packet.scada_frame.seq_num()) + if self.r_seq_num == nil then + self.r_seq_num = packet.scada_frame.seq_num() + 1 + elseif self.r_seq_num ~= packet.scada_frame.seq_num() then + log.warning("sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. packet.scada_frame.seq_num()) return elseif rtu_state.linked and (src_addr ~= self.sv_addr) then log.debug("received packet from unknown computer " .. src_addr .. " while linked (expected " .. self.sv_addr .. "); channel in use by another system?") return else - self.seq_num = packet.scada_frame.seq_num() + 1 + self.r_seq_num = packet.scada_frame.seq_num() + 1 end -- feed watchdog on valid sequence number diff --git a/scada-common/comms.lua b/scada-common/comms.lua index e31c60b2..bfedd2cd 100644 --- a/scada-common/comms.lua +++ b/scada-common/comms.lua @@ -294,7 +294,7 @@ function comms.authd_packet() self.src_addr = s_packet.src_addr() self.dest_addr = s_packet.dest_addr() self.mac = mac(textutils.serialize(s_packet.raw_header(), { allow_repetitions = true, compact = true })) - self.raw = { self.src_addr, self.dest_addr, self.mac, s_packet.data() } + self.raw = { self.src_addr, self.dest_addr, self.mac, s_packet.raw_sendable() } end -- parse in a modem message as an authenticated SCADA packet diff --git a/scada-common/network.lua b/scada-common/network.lua index 4dce34ec..c34a1d50 100644 --- a/scada-common/network.lua +++ b/scada-common/network.lua @@ -80,7 +80,7 @@ end ---@param modem table modem to use function network.nic(modem) local self = { - connected = true, -- used to avoid costly MAC calculations if modem isn't even present + connected = true, -- used to avoid costly MAC calculations if modem isn't even present channels = {} } @@ -175,7 +175,7 @@ function network.nic(modem) ---@param packet scada_packet packet function public.transmit(dest_channel, local_channel, packet) if self.connected then - local tx_packet = packet ---@type authd_packet|scada_packet + local tx_packet = packet ---@type authd_packet|scada_packet if c_eng.hmac ~= nil then -- local start = util.time_ms() @@ -214,13 +214,13 @@ function network.nic(modem) s_packet.receive(side, sender, reply_to, a_packet.data(), distance) if s_packet.is_valid() then - -- local start = util.time_ms() + -- local start = util.time_ms() local computed_hmac = compute_hmac(textutils.serialize(s_packet.raw_header(), { allow_repetitions = true, compact = true })) if a_packet.mac() == computed_hmac then -- log.debug("network.modem.receive: HMAC verified in " .. (util.time_ms() - start) .. "ms") - s_packet.stamp_authenticated() - else + s_packet.stamp_authenticated() + else -- log.debug("network.modem.receive: HMAC failed verification in " .. (util.time_ms() - start) .. "ms") end end diff --git a/supervisor/session/coordinator.lua b/supervisor/session/coordinator.lua index f4496500..a135a44d 100644 --- a/supervisor/session/coordinator.lua +++ b/supervisor/session/coordinator.lua @@ -58,7 +58,8 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim local self = { units = facility.get_units(), -- connection properties - seq_num = i_seq_num, + seq_num = i_seq_num + 2, -- next after the establish approval was sent + r_seq_num = i_seq_num + 1, connected = true, conn_watchdog = util.new_watchdog(timeout), establish_time = util.time_s(), @@ -182,11 +183,11 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim ---@param pkt mgmt_frame|crdn_frame local function _handle_packet(pkt) -- check sequence number - if self.seq_num ~= pkt.scada_frame.seq_num() then - log.warning(log_header .. "sequence out-of-order: last = " .. self.seq_num .. ", new = " .. pkt.scada_frame.seq_num()) + if self.r_seq_num ~= pkt.scada_frame.seq_num() then + log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num()) return else - self.seq_num = pkt.scada_frame.seq_num() + 1 + self.r_seq_num = pkt.scada_frame.seq_num() + 1 end -- feed watchdog diff --git a/supervisor/session/plc.lua b/supervisor/session/plc.lua index fb5ca1b3..4aad6d3e 100644 --- a/supervisor/session/plc.lua +++ b/supervisor/session/plc.lua @@ -67,7 +67,8 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue, ramping_rate = false, auto_lock = false, -- connection properties - seq_num = i_seq_num, + seq_num = i_seq_num + 2, -- next after the establish approval was sent + r_seq_num = i_seq_num + 1, connected = true, received_struct = false, received_status_cache = false, @@ -349,11 +350,11 @@ function plc.new_session(id, s_addr, i_seq_num, reactor_id, in_queue, out_queue, ---@param pkt mgmt_frame|rplc_frame local function _handle_packet(pkt) -- check sequence number - if self.seq_num ~= pkt.scada_frame.seq_num() then - log.warning(log_header .. "sequence out-of-order: last = " .. self.seq_num .. ", new = " .. pkt.scada_frame.seq_num()) + if self.r_seq_num ~= pkt.scada_frame.seq_num() then + log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num()) return else - self.seq_num = pkt.scada_frame.seq_num() + 1 + self.r_seq_num = pkt.scada_frame.seq_num() + 1 end -- process packet diff --git a/supervisor/session/pocket.lua b/supervisor/session/pocket.lua index 145add24..94a44676 100644 --- a/supervisor/session/pocket.lua +++ b/supervisor/session/pocket.lua @@ -44,7 +44,8 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, local self = { -- connection properties - seq_num = i_seq_num, + seq_num = i_seq_num + 2, -- next after the establish approval was sent + r_seq_num = i_seq_num + 1, connected = true, conn_watchdog = util.new_watchdog(timeout), last_rtt = 0, @@ -93,11 +94,11 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, ---@param pkt mgmt_frame local function _handle_packet(pkt) -- check sequence number - if self.seq_num ~= pkt.scada_frame.seq_num() then - log.warning(log_header .. "sequence out-of-order: last = " .. self.seq_num .. ", new = " .. pkt.scada_frame.seq_num()) + if self.r_seq_num ~= pkt.scada_frame.seq_num() then + log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num()) return else - self.seq_num = pkt.scada_frame.seq_num() + 1 + self.r_seq_num = pkt.scada_frame.seq_num() + 1 end -- feed watchdog diff --git a/supervisor/session/rtu.lua b/supervisor/session/rtu.lua index 789e6493..756ee011 100644 --- a/supervisor/session/rtu.lua +++ b/supervisor/session/rtu.lua @@ -52,7 +52,8 @@ function rtu.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, ad advert = advertisement, fac_units = facility.get_units(), -- connection properties - seq_num = i_seq_num, + seq_num = i_seq_num + 2, -- next after the establish approval was sent + r_seq_num = i_seq_num + 1, connected = true, conn_watchdog = util.new_watchdog(timeout), last_rtt = 0, @@ -240,11 +241,11 @@ function rtu.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, ad ---@param pkt modbus_frame|mgmt_frame local function _handle_packet(pkt) -- check sequence number - if self.seq_num ~= pkt.scada_frame.seq_num() then - log.warning(log_header .. "sequence out-of-order: last = " .. self.seq_num .. ", new = " .. pkt.scada_frame.seq_num()) + if self.r_seq_num ~= pkt.scada_frame.seq_num() then + log.warning(log_header .. "sequence out-of-order: last = " .. self.r_seq_num .. ", new = " .. pkt.scada_frame.seq_num()) return else - self.seq_num = pkt.scada_frame.seq_num() + 1 + self.r_seq_num = pkt.scada_frame.seq_num() + 1 end -- feed watchdog diff --git a/supervisor/session/svsessions.lua b/supervisor/session/svsessions.lua index c7c24fc5..002dd569 100644 --- a/supervisor/session/svsessions.lua +++ b/supervisor/session/svsessions.lua @@ -274,7 +274,7 @@ end -- establish a new PLC session ---@nodiscard ---@param source_addr integer PLC computer ID ----@param i_seq_num integer initial sequence number to use next +---@param i_seq_num integer initial (most recent) sequence number ---@param for_reactor integer unit ID ---@param version string PLC version ---@return integer|false session_id @@ -324,7 +324,7 @@ end -- establish a new RTU gateway session ---@nodiscard ---@param source_addr integer RTU gateway computer ID ----@param i_seq_num integer initial sequence number to use next +---@param i_seq_num integer initial (most recent) sequence number ---@param advertisement table RTU capability advertisement ---@param version string RTU gateway version ---@return integer session_id @@ -365,7 +365,7 @@ end -- establish a new coordinator session ---@nodiscard ---@param source_addr integer coordinator computer ID ----@param i_seq_num integer initial sequence number to use next +---@param i_seq_num integer initial (most recent) sequence number ---@param version string coordinator version ---@return integer|false session_id function svsessions.establish_crd_session(source_addr, i_seq_num, version) @@ -410,7 +410,7 @@ end -- establish a new pocket diagnostics session ---@nodiscard ---@param source_addr integer pocket computer ID ----@param i_seq_num integer initial sequence number to use next +---@param i_seq_num integer initial (most recent) sequence number ---@param version string pocket version ---@return integer|false session_id function svsessions.establish_pdg_session(source_addr, i_seq_num, version) diff --git a/supervisor/supervisor.lua b/supervisor/supervisor.lua index 2d69b7cc..69a98f54 100644 --- a/supervisor/supervisor.lua +++ b/supervisor/supervisor.lua @@ -197,7 +197,7 @@ function supervisor.comms(_version, nic, fp_ok) local r_chan = packet.scada_frame.remote_channel() local src_addr = packet.scada_frame.src_addr() local protocol = packet.scada_frame.protocol() - local i_seq_num = packet.scada_frame.seq_num() + 1 + local i_seq_num = packet.scada_frame.seq_num() if l_chan ~= config.SVR_Channel then log.debug("received packet on unconfigured channel " .. l_chan, true) From aebb9f42be4e818df5b59ce0ca670f9ab9bf9547 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Sat, 29 Jun 2024 18:29:49 +0000 Subject: [PATCH 12/44] #506 work on off-line installer generation script --- bundle.py | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 bundle.py diff --git a/bundle.py b/bundle.py new file mode 100644 index 00000000..fc6e83ba --- /dev/null +++ b/bundle.py @@ -0,0 +1,76 @@ +import base64 +import json +import os +import sys + +def encode_recursive(path): + list = {} + + for item in os.listdir(path): + item_path = path + '/' + item + + if os.path.isfile(item_path): + handle = open(item_path, 'r') + list[item] = base64.b64encode(bytes(handle.read(), 'UTF-8')).decode('ASCII') + handle.close() + else: + list[item] = encode_recursive(item_path) + + return list + +def encode_files(files): + list = {} + + for item in files: + item_path = './' + item + + handle = open(item_path, 'r') + list[item] = base64.b64encode(bytes(handle.read(), 'UTF-8')).decode('ASCII') + handle.close() + + return list + +manifest = { + "files" : { + # common files + "system" : encode_files([ "initenv.lua", "startup.lua", "configure.lua", "LICENSE" ]), + "common" : encode_recursive("./scada-common"), + "graphics" : encode_recursive("./graphics"), + "lockbox" : encode_recursive("./lockbox"), + # platform files + "reactor-plc" : encode_recursive("./reactor-plc"), + "rtu" : encode_recursive("./rtu"), + "supervisor" : encode_recursive("./supervisor"), + "coordinator" : encode_recursive("./coordinator"), + "pocket" : encode_recursive("./pocket"), + }, + "depends" : { + "reactor-plc" : [ "reactor-plc", "system", "common", "graphics", "lockbox" ], + "rtu" : [ "rtu", "system", "common", "graphics", "lockbox" ], + "supervisor" : [ "supervisor", "system", "common", "graphics", "lockbox" ], + "coordinator" : [ "coordinator", "system", "common", "graphics", "lockbox" ], + "pocket" : [ "pocket", "system", "common", "graphics", "lockbox" ] + } +} + +def write_items(body, items, indent): + indent_str = " " * indent + for key, value in items.items(): + if isinstance(value, str): + body = body + f"{indent_str}['{key}'] = \"{value}\",\n" + else: + body = body + f"{indent_str}['{key}'] = {{\n" + body = write_items(body, value, indent + 4) + body = body + f"{indent_str}}},\n" + + return body + + +for app in [ "reactor-plc", "rtu", "supervisor", "coordinator", "pocket" ]: + f = open("_" + app + ".lua", "w") + body = "local application = {\n" + for depend in manifest["depends"][app]: + body = body + write_items("", { f"{depend}": manifest["files"][depend] }, 4) + body = body + "}\n\n" + f.write(body) + f.close() From 8e14fa1591a8ab9aefc1a141c90e86910abc1e49 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Sat, 29 Jun 2024 18:30:32 +0000 Subject: [PATCH 13/44] disable a diagnostic message in ccmsi --- ccmsi.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/ccmsi.lua b/ccmsi.lua index cc4a5d02..86f2094d 100644 --- a/ccmsi.lua +++ b/ccmsi.lua @@ -138,6 +138,7 @@ local function gen_tree(manifest) for i = 1, #list do local split = {} +---@diagnostic disable-next-line: discard-returns string.gsub(list[i], "([^/]+)", function(c) split[#split + 1] = c end) if #split == 1 then table.insert(tree, list[i]) else table.insert(tree, _tree_add(tree, split)) end From f2937b47e9c41cf1f8906b13567c9292bbb91db7 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 14:49:26 -0400 Subject: [PATCH 14/44] cleanup --- coordinator/session/apisessions.lua | 2 +- reactor-plc/plc.lua | 2 +- scada-common/comms.lua | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coordinator/session/apisessions.lua b/coordinator/session/apisessions.lua index 4daa45d6..5c4a38a7 100644 --- a/coordinator/session/apisessions.lua +++ b/coordinator/session/apisessions.lua @@ -90,7 +90,7 @@ end -- establish a new API session ---@nodiscard ---@param source_addr integer pocket computer ID ----@param i_seq_num integer initial sequence number to use next +---@param i_seq_num integer initial (most recent) sequence number ---@param version string pocket version ---@return integer session_id function apisessions.establish_session(source_addr, i_seq_num, version) diff --git a/reactor-plc/plc.lua b/reactor-plc/plc.lua index 3a61e377..c89974f3 100644 --- a/reactor-plc/plc.lua +++ b/reactor-plc/plc.lua @@ -715,8 +715,8 @@ function plc.comms(version, nic, reactor, rps, conn_watchdog) function public.unlink() self.sv_addr = comms.BROADCAST self.linked = false - self.status_cache = nil self.r_seq_num = nil + self.status_cache = nil databus.tx_link_state(types.PANEL_LINK_STATE.DISCONNECTED) end diff --git a/scada-common/comms.lua b/scada-common/comms.lua index bfedd2cd..fa6f6ffd 100644 --- a/scada-common/comms.lua +++ b/scada-common/comms.lua @@ -280,7 +280,7 @@ function comms.authd_packet() src_addr = comms.BROADCAST, dest_addr = comms.BROADCAST, mac = "", - payload = nil + payload = {} } ---@class authd_packet From c05a45c29aeefbb39245a35c06f2ba42db4b0c76 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 14:51:15 -0400 Subject: [PATCH 15/44] more cleanup --- pocket/pocket.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pocket/pocket.lua b/pocket/pocket.lua index 82b87b54..fab08277 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -466,8 +466,8 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) sv_watchdog.cancel() nav.unload_sv() self.sv.linked = false - self.sv.addr = comms.BROADCAST self.sv.r_seq_num = nil + self.sv.addr = comms.BROADCAST _send_sv(MGMT_TYPE.CLOSE, {}) end @@ -476,8 +476,8 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) api_watchdog.cancel() nav.unload_api() self.api.linked = false - self.api.addr = comms.BROADCAST self.api.r_seq_num = nil + self.api.addr = comms.BROADCAST _send_crd(MGMT_TYPE.CLOSE, {}) end @@ -658,8 +658,8 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) api_watchdog.cancel() nav.unload_api() self.api.linked = false - self.api.addr = comms.BROADCAST self.api.r_seq_num = nil + self.api.addr = comms.BROADCAST log.info("coordinator server connection closed by remote host") else _fail_type(packet) end elseif packet.type == MGMT_TYPE.ESTABLISH then @@ -764,8 +764,8 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav) sv_watchdog.cancel() nav.unload_sv() self.sv.linked = false - self.sv.addr = comms.BROADCAST self.sv.r_seq_num = nil + self.sv.addr = comms.BROADCAST log.info("supervisor server connection closed by remote host") elseif packet.type == MGMT_TYPE.DIAG_TONE_GET then if _check_length(packet, 8) then From 4f48ba8abce57283cf35b432298517f3ddb25ca0 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Sat, 29 Jun 2024 18:59:39 +0000 Subject: [PATCH 16/44] #403 work on guide docs --- pocket/ui/apps/guide.lua | 3 ++- pocket/ui/docs.lua | 25 ++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index b1748058..824b18e3 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -188,11 +188,12 @@ local function new_view(root) 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.unit.fac_section, 100) 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,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,dis_fg_bg=btn_disable,callback=function()end}.disable() + 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=fps,y=1,text="Front Panels",height=1,alignment=ALIGN.CENTER} diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index 40507a1f..9ebab56a 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -28,7 +28,7 @@ doc("TurbineTripAlarm", "Turbine Trip", "A turbine stopped rotating, likely due docs.annunc = { unit = { - main_section = {}, rps_section = {}, rcs_section = {} + main_section = {}, rps_section = {}, rcs_section = {}, fac_section = {} } } @@ -78,15 +78,35 @@ doc("TurbineOverSpeed", "Turbine Over Speed", "The turbine is at steam capacity, 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.") +target = docs.annunc.unit.fac_section +doc("?", "Unit Systems Online", "All unit systems (reactors, boilers, and turbines) are connected.") +doc("?", "Radiation Monitor", "At least one facility radiation monitor is connected") +doc("?", "Induction Matrix", "The induction matrix is connected.") +doc("?", "SPS Connected", "Indicates if the super-critical phase shifter is connected.") +doc("?", "Configured Units Ready", "All units assigned to automatic control are ready to run automatic control.") +doc("?", "Process Active", "Automatic process control is active.") +doc("?", "Process Ramping", "Automatic process control is performing an initial ramp-up of the reactors for later PID control (generation and charge mode).") +doc("?", "Min/Max Burn Rate", "Auto control has either commanded 0 mB/t or the maximum total burn rate available (from assigned units).") +doc("?", "Automatic SCRAM", "Automatic control system SCRAM'ed the assigned reactors due to a safety hazard, shown by the below indicators.") +doc("?", "Matrix Disconnected", "Automatic SCRAM occurred due to loss of induction matrix connection.") +doc("?", "Matrix Charge High", "Automatic SCRAM occurred due to induction matrix charge exceeding acceptable limit.") +doc("?", "Unit Critical Alarm", "Automatic SCRAM occurred due to critical level unit alarm(s).") +doc("?", "Facility Radiation High", "Automatic SCRAM occurred due to high facility radiation levels.") +doc("?", "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.glossary = { abbvs = {}, terms = {} } 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.") +doc("G_PID", "PID", "A Proportional Integral Derivitave closed-loop controller.") doc("G_PKT", "PKT", "Pocket. Abbreviation for the pocket computer.") doc("G_PLC", "PLC", "Programmable Logic Controller. A device that not only reports data and controls outputs, but can also make decisions on its own.") doc("G_PPM", "PPM", "Protected Peripheral Manager. This is an abstraction layer created for this project that prevents peripheral calls from crashing applications.") @@ -99,8 +119,11 @@ doc("G_SVR", "SVR", "Supervisor. Abbreviation for the supervisory computer.") 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_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.") +doc("G_LowLow", "Low Low", "Very Low.") doc("G_Nominal", "Nominal", "Normal operation. Everything operating as intended.") doc("G_Ringback", "Ringback", "An indication that an alarm had gone off but is no longer having its trip condition(s) met. This is to make you are aware that it occurred.") doc("G_SCRAM", "SCRAM", "[Emergency] shut-down of a reactor by stopping the fission. In Mekanism and here, it isn't always for an emergency.") From a4add9370c538061803d704986f7708425196f9e Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 15:08:11 -0400 Subject: [PATCH 17/44] RTU modem init consistency and cleanup --- coordinator/startup.lua | 6 +++--- rtu/startup.lua | 36 +++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/coordinator/startup.lua b/coordinator/startup.lua index 9e20631c..1960e583 100644 --- a/coordinator/startup.lua +++ b/coordinator/startup.lua @@ -19,7 +19,7 @@ local renderer = require("coordinator.renderer") local sounder = require("coordinator.sounder") local threads = require("coordinator.threads") -local COORDINATOR_VERSION = "v1.5.0" +local COORDINATOR_VERSION = "v1.5.1" local CHUNK_LOAD_DELAY_S = 30.0 @@ -151,8 +151,8 @@ local function main() -- core coordinator devices crd_dev = { - speaker = ppm.get_device("speaker"), - modem = ppm.get_wireless_modem() + modem = ppm.get_wireless_modem(), + speaker = ppm.get_device("speaker") }, -- system objects diff --git a/rtu/startup.lua b/rtu/startup.lua index 00f27c7f..c5000ea5 100644 --- a/rtu/startup.lua +++ b/rtu/startup.lua @@ -31,7 +31,7 @@ local sna_rtu = require("rtu.dev.sna_rtu") local sps_rtu = require("rtu.dev.sps_rtu") local turbinev_rtu = require("rtu.dev.turbinev_rtu") -local RTU_VERSION = "v1.10.0" +local RTU_VERSION = "v1.10.1" local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE @@ -93,14 +93,6 @@ local function main() network.init_mac(config.AuthKey) end - -- get modem - local modem = ppm.get_wireless_modem() - if modem == nil then - println("boot> wireless modem not found") - log.fatal("no wireless modem on startup") - return - end - -- generate alarm tones audio.generate_tones() @@ -116,14 +108,15 @@ local function main() -- RTU gateway devices (not RTU units) rtu_dev = { + modem = ppm.get_wireless_modem(), sounders = {} }, -- system objects rtu_sys = { - nic = network.nic(modem), - rtu_comms = nil, ---@type rtu_comms - conn_watchdog = nil, ---@type watchdog + nic = nil, ---@type nic + rtu_comms = nil, ---@type rtu_comms + conn_watchdog = nil, ---@type watchdog units = {} }, @@ -134,8 +127,9 @@ local function main() } local smem_sys = __shared_memory.rtu_sys + local smem_dev = __shared_memory.rtu_dev - databus.tx_hw_modem(true) + local rtu_state = __shared_memory.rtu_state ---------------------------------------- -- interpret config and init units @@ -501,8 +495,6 @@ local function main() -- start system ---------------------------------------- - local rtu_state = __shared_memory.rtu_state - log.debug("boot> running sys_config()") if sys_config() then @@ -517,23 +509,33 @@ local function main() log.info("startup> running in headless mode without front panel") end + -- check modem + if smem_dev.modem == nil then + println("startup> wireless modem not found") + log.fatal("no wireless modem on startup") + return + end + + databus.tx_hw_modem(true) + -- find and setup all speakers local speakers = ppm.get_all_devices("speaker") for _, s in pairs(speakers) do local sounder = rtu.init_sounder(s) - table.insert(__shared_memory.rtu_dev.sounders, sounder) + table.insert(smem_dev.sounders, sounder) log.debug(util.c("startup> added speaker, attached as ", sounder.name)) end - databus.tx_hw_spkr_count(#__shared_memory.rtu_dev.sounders) + databus.tx_hw_spkr_count(#smem_dev.sounders) -- start connection watchdog smem_sys.conn_watchdog = util.new_watchdog(config.ConnTimeout) log.debug("startup> conn watchdog started") -- setup comms + smem_sys.nic = network.nic(smem_dev.modem) smem_sys.rtu_comms = rtu.comms(RTU_VERSION, smem_sys.nic, smem_sys.conn_watchdog) log.debug("startup> comms init") From e868fd33973a51c8aee221545e3dbd6816ef2074 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 15:11:16 -0400 Subject: [PATCH 18/44] cleanup of bootloader --- startup.lua | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/startup.lua b/startup.lua index 811f5103..662d9892 100644 --- a/startup.lua +++ b/startup.lua @@ -1,35 +1,31 @@ -local util = require("scada-common.util") +local BOOTLOADER_VERSION = "1.1" -local println = util.println - -local BOOTLOADER_VERSION = "1.0" - -println("SCADA BOOTLOADER V" .. BOOTLOADER_VERSION) -println("BOOT> SCANNING FOR APPLICATIONS...") +print("SCADA BOOTLOADER V" .. BOOTLOADER_VERSION) +print("BOOT> SCANNING FOR APPLICATIONS...") local exit_code if fs.exists("reactor-plc/startup.lua") then - println("BOOT> EXEC REACTOR PLC STARTUP") + print("BOOT> EXEC REACTOR PLC STARTUP") exit_code = shell.execute("reactor-plc/startup") elseif fs.exists("rtu/startup.lua") then - println("BOOT> EXEC RTU STARTUP") + print("BOOT> EXEC RTU STARTUP") exit_code = shell.execute("rtu/startup") elseif fs.exists("supervisor/startup.lua") then - println("BOOT> EXEC SUPERVISOR STARTUP") + print("BOOT> EXEC SUPERVISOR STARTUP") exit_code = shell.execute("supervisor/startup") elseif fs.exists("coordinator/startup.lua") then - println("BOOT> EXEC COORDINATOR STARTUP") + print("BOOT> EXEC COORDINATOR STARTUP") exit_code = shell.execute("coordinator/startup") elseif fs.exists("pocket/startup.lua") then - println("BOOT> EXEC POCKET STARTUP") + print("BOOT> EXEC POCKET STARTUP") exit_code = shell.execute("pocket/startup") else - println("BOOT> NO SCADA STARTUP FOUND") - println("BOOT> EXIT") + print("BOOT> NO SCADA STARTUP FOUND") + print("BOOT> EXIT") return false end -if not exit_code then println("BOOT> APPLICATION CRASHED") end +if not exit_code then print("BOOT> APPLICATION CRASHED") end return exit_code From 0b2f7b13a12a23beea07b8a3e6d7eb4f981f6215 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 15:14:43 -0400 Subject: [PATCH 19/44] moved build scripts to new build directory --- .github/workflows/manifest.yml | 4 ++-- imgen.py => build/imgen.py | 6 +++++- safemin.py => build/safemin.py | 0 3 files changed, 7 insertions(+), 3 deletions(-) rename imgen.py => build/imgen.py (97%) rename safemin.py => build/safemin.py (100%) diff --git a/.github/workflows/manifest.yml b/.github/workflows/manifest.yml index efafe3d5..565363b5 100644 --- a/.github/workflows/manifest.yml +++ b/.github/workflows/manifest.yml @@ -46,7 +46,7 @@ jobs: - name: Generate manifest and shields for main branch id: manifest-main if: ${{ (success() || failure()) && steps.checkout-main.outcome == 'success' }} - run: python imgen.py shields + run: python ./build/imgen.py shields - name: Save main's manifest if: ${{ (success() || failure()) && steps.manifest-main.outcome == 'success' }} run: mv install_manifest.json deploy/manifests/main @@ -61,7 +61,7 @@ jobs: - name: Generate manifest for devel id: manifest-devel if: ${{ (success() || failure()) && steps.checkout-devel.outcome == 'success' }} - run: python imgen.py + run: python ./build/imgen.py - name: Save devel's manifest if: ${{ (success() || failure()) && steps.manifest-devel.outcome == 'success' }} run: mv install_manifest.json deploy/manifests/devel diff --git a/imgen.py b/build/imgen.py similarity index 97% rename from imgen.py rename to build/imgen.py index a854b1f4..265f7863 100644 --- a/imgen.py +++ b/build/imgen.py @@ -44,9 +44,11 @@ def get_version(path, is_lib = False): # generate installation manifest object def make_manifest(size): + os.chdir('./_minified') + manifest = { "versions" : { - "installer" : get_version("./ccmsi.lua"), + "installer" : get_version("../ccmsi.lua"), "bootloader" : get_version("./startup.lua"), "common" : get_version("./scada-common/util.lua", True), "comms" : get_version("./scada-common/comms.lua", True), @@ -95,6 +97,8 @@ def make_manifest(size): } } + os.chdir('../') + return manifest # write initial manifest with placeholder size diff --git a/safemin.py b/build/safemin.py similarity index 100% rename from safemin.py rename to build/safemin.py From f83eecf2e2454b8522dc49872e029fb862984453 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 15:28:16 -0400 Subject: [PATCH 20/44] script to package zips for installation without internet but with filesystem upload access --- build/package_zip.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100755 build/package_zip.sh diff --git a/build/package_zip.sh b/build/package_zip.sh new file mode 100755 index 00000000..9288a051 --- /dev/null +++ b/build/package_zip.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# Create zips to attach to GitHub releases. +# These can be extracted onto a computer and will include all files CCMSI would otherwise install. + +tag=$(git describe --tags) +apps=(coordinator pocket reactor-plc rtu supervisor) + +for app in "${apps[@]}" do + mkdir ${tag}_${app} + cp -R $app scada-common graphics lockbox configure.lua initenv.lua startup.lua LICENSE ${tag}_${app} + zip -r ${tag}_${app}.zip ${tag}_${app} + rm -R ${tag}_${app} +done From b0259581738ce73a5f161c7c82bcbf90d65cf11d Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 15:41:04 -0400 Subject: [PATCH 21/44] comments in minifier --- build/safemin.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build/safemin.py b/build/safemin.py index 4f354a24..b1b710cb 100644 --- a/build/safemin.py +++ b/build/safemin.py @@ -34,12 +34,13 @@ def minify(path: str): # - this minification is intended to be 100% safe, so working with multiline comments is asking for trouble # - the project doesn't use them as of writing this (except in test/), and it might as well stay that way raise Exception(f"no multiline comments allowed! (offending file: {path})") - + if re.search(r'\\$', contents, flags=re.MULTILINE) != None: # '\' allows for multiline strings, which would require reverting to processing syntax line by line to support them raise Exception(f"no escaping newlines! (offending file: {path})") - # drop the comments + # drop the comments, unless the line has quotes, because quotes are scary + # (quotes are scary since we could actually be inside a string: "-- ..." shouldn't get deleted) # -> whitespace before '--' and anything after that, which includes '---' comments minified = re.sub(r'\s*--+(?!.*[\'"]).*', '', contents) From 8e0e4df3ebf9f8badc732c774fcedf90aeec5a70 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 15:52:34 -0400 Subject: [PATCH 22/44] rename package zip script --- build/{package_zip.sh => package.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename build/{package_zip.sh => package.sh} (100%) diff --git a/build/package_zip.sh b/build/package.sh similarity index 100% rename from build/package_zip.sh rename to build/package.sh From a1b571d7c09a2884f181a8461c6d204d37c72770 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 15:52:47 -0400 Subject: [PATCH 23/44] copy over LICENSE to minified output directory --- build/safemin.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/safemin.py b/build/safemin.py index b1b710cb..25761599 100644 --- a/build/safemin.py +++ b/build/safemin.py @@ -71,3 +71,10 @@ def minify(path: str): minify("startup.lua") minify("initenv.lua") minify("configure.lua") + +# copy in license for build usage +lic1 = open("LICENSE", "r") +lic2 = open("_minified/LICENSE", "w") +lic2.write(lic1.read()) +lic1.close() +lic2.close() From df8c71f12e34de721ed79c4521cdc34bf2bc3641 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 16:02:25 -0400 Subject: [PATCH 24/44] #506 use minified files for off-line installer --- bundle.py => build/bundle.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) rename bundle.py => build/bundle.py (72%) diff --git a/bundle.py b/build/bundle.py similarity index 72% rename from bundle.py rename to build/bundle.py index fc6e83ba..8cc2af19 100644 --- a/bundle.py +++ b/build/bundle.py @@ -3,6 +3,9 @@ import os import sys +path_prefix = "./_minified/" + +# recursively encode files with base64 def encode_recursive(path): list = {} @@ -18,11 +21,12 @@ def encode_recursive(path): return list +# encode listed files with base64 def encode_files(files): list = {} for item in files: - item_path = './' + item + item_path = path_prefix + './' + item handle = open(item_path, 'r') list[item] = base64.b64encode(bytes(handle.read(), 'UTF-8')).decode('ASCII') @@ -30,19 +34,20 @@ def encode_files(files): return list +# file manifest (reflects imgen.py) manifest = { "files" : { # common files "system" : encode_files([ "initenv.lua", "startup.lua", "configure.lua", "LICENSE" ]), - "common" : encode_recursive("./scada-common"), - "graphics" : encode_recursive("./graphics"), - "lockbox" : encode_recursive("./lockbox"), + "common" : encode_recursive(path_prefix + "./scada-common"), + "graphics" : encode_recursive(path_prefix + "./graphics"), + "lockbox" : encode_recursive(path_prefix + "./lockbox"), # platform files - "reactor-plc" : encode_recursive("./reactor-plc"), - "rtu" : encode_recursive("./rtu"), - "supervisor" : encode_recursive("./supervisor"), - "coordinator" : encode_recursive("./coordinator"), - "pocket" : encode_recursive("./pocket"), + "reactor-plc" : encode_recursive(path_prefix + "./reactor-plc"), + "rtu" : encode_recursive(path_prefix + "./rtu"), + "supervisor" : encode_recursive(path_prefix + "./supervisor"), + "coordinator" : encode_recursive(path_prefix + "./coordinator"), + "pocket" : encode_recursive(path_prefix + "./pocket"), }, "depends" : { "reactor-plc" : [ "reactor-plc", "system", "common", "graphics", "lockbox" ], @@ -53,6 +58,7 @@ def encode_files(files): } } +# write the application installation items as Lua tables def write_items(body, items, indent): indent_str = " " * indent for key, value in items.items(): @@ -66,6 +72,7 @@ def write_items(body, items, indent): return body + for app in [ "reactor-plc", "rtu", "supervisor", "coordinator", "pocket" ]: f = open("_" + app + ".lua", "w") body = "local application = {\n" From 270aeb13ca71f15319d8a0b7841d75bfb1d18c1c Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 22:38:11 -0400 Subject: [PATCH 25/44] removed config.lua from luacheck --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 975bb733..9caba854 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -26,4 +26,4 @@ jobs: # --no-max-line-length = Disable warnings for long line lengths # --exclude-files ... = Exclude lockbox library (external) and config files # --globals ... = Override all globals overridden in .vscode/settings.json AND 'os' since CraftOS 'os' differs from Lua's 'os' - args: . --no-max-line-length -i 121 512 542 --exclude-files ./lockbox/* ./*/config.lua --globals os _HOST bit colors fs http keys parallel periphemu peripheral read rs settings shell term textutils window + args: . --no-max-line-length -i 121 512 542 --exclude-files ./lockbox/* --globals os _HOST bit colors fs http keys parallel periphemu peripheral read rs settings shell term textutils window From 89e84f9711e320f5fd6d0430676902160a31d8a3 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 22:39:58 -0400 Subject: [PATCH 26/44] #194 ccmsi updates around log handling --- ccmsi.lua | 67 +++++++++++++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/ccmsi.lua b/ccmsi.lua index 86f2094d..76210dac 100644 --- a/ccmsi.lua +++ b/ccmsi.lua @@ -18,7 +18,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. local function println(message) print(tostring(message)) end local function print(message) term.write(tostring(message)) end -local CCMSI_VERSION = "v1.14" +local CCMSI_VERSION = "v1.15" local install_dir = "/.install-cache" local manifest_path = "https://mikaylafischler.github.io/cc-mek-scada/manifests/" @@ -121,7 +121,7 @@ local function write_install_manifest(manifest, dependencies) end -- recursively build a tree out of the file manifest -local function gen_tree(manifest) +local function gen_tree(manifest, log) local function _tree_add(tree, split) if #split > 1 then local name = table.remove(split, 1) @@ -131,7 +131,7 @@ local function gen_tree(manifest) return nil end - local list, tree = {}, {} + local list, tree = { log }, {} -- make a list of each and every file for _, files in pairs(manifest.files) do for i = 1, #files do table.insert(list, files[i]) end end @@ -160,7 +160,7 @@ local function _clean_dir(dir, tree) if fs.isDir(path) then _clean_dir(path, tree[val]) if #fs.list(path) == 0 then fs.delete(path);println("deleted "..path) end - elseif (not _in_array(val, tree)) and (val ~= "config.lua" ) then + elseif (not _in_array(val, tree)) and (val ~= "config.lua" ) then ---@todo delete on full release fs.delete(path) println("deleted "..path) end @@ -169,11 +169,15 @@ end -- go through app/common directories to delete unused files local function clean(manifest) - local tree = gen_tree(manifest) + local log = nil + if fs.exists(app..".settings") and settings.load(app..".settings") then + log = settings.get("LogPath") + end + + local tree = gen_tree(manifest, log) table.insert(tree, "install_manifest.json") table.insert(tree, "ccmsi.lua") - table.insert(tree, "log.txt") ---@fixme fix after migration to settings files? local ls = fs.list("/") for _, val in pairs(ls) do @@ -535,35 +539,6 @@ elseif mode == "uninstall" then table.insert(dependencies, app) - -- delete log file - local log_deleted = false - local settings_file = app..".settings" - local legacy_config_file = app.."/config.lua" - - lgray() - if fs.exists(legacy_config_file) then - log_deleted = pcall(function () - local config = require(app..".config") - if fs.exists(config.LOG_PATH) then - fs.delete(config.LOG_PATH) - println("deleted log file "..config.LOG_PATH) - end - end) - elseif fs.exists(settings_file) and settings.load(settings_file) then - local log = settings.get("LogPath") - if log ~= nil and fs.exists(log) then - log_deleted = true - fs.delete(log) - println("deleted log file "..log) - end - end - - if not log_deleted then - red();println("Failed to delete log file.") - white();println("press any key to continue...") - any_key();lgray() - end - -- delete all installed files for _, dependency in pairs(dependencies) do local files = file_list[dependency] @@ -583,8 +558,26 @@ elseif mode == "uninstall" then end end - if fs.exists(legacy_config_file) then - fs.delete(legacy_config_file);println("deleted "..legacy_config_file) + -- delete log file + local log_deleted = false + local settings_file = app..".settings" + + lgray() + if fs.exists(settings_file) and settings.load(settings_file) then + local log = settings.get("LogPath") + if log ~= nil then + log_deleted = true + if fs.exists(log) then + fs.delete(log) + println("deleted log file "..log) + end + end + end + + if not log_deleted then + red();println("Failed to delete log file.") + white();println("press any key to continue...") + any_key();lgray() end if fs.exists(settings_file) then From 63c990a3cf245e9d379dc679932eb54487f08f5e Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 22:44:12 -0400 Subject: [PATCH 27/44] #506 two-file bundled offline installer generation --- build/_offline.lua | 114 +++++++++++++++++++++ build/bundle.py | 161 +++++++++++++++++++++++++++--- build/ccmsim.lua | 240 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 500 insertions(+), 15 deletions(-) create mode 100644 build/_offline.lua create mode 100644 build/ccmsim.lua diff --git a/build/_offline.lua b/build/_offline.lua new file mode 100644 index 00000000..883170ed --- /dev/null +++ b/build/_offline.lua @@ -0,0 +1,114 @@ +---@diagnostic disable: undefined-global + +local b64_lookup = { + ['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4, ['F'] = 5, ['G'] = 6, ['H'] = 7, ['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15, ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24, ['Z'] = 25, + ['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33, ['i'] = 34, ['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39, ['o'] = 40, ['p'] = 41, ['q'] = 42, ['r'] = 43, ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47, ['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51, + ['0'] = 52, ['1'] = 53, ['2'] = 54, ['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59, ['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63 +} + +local BYTE = 0xFF +local CHAR = string.char +local BOR = bit.bor ---@type function +local BAND = bit.band ---@type function +local LSHFT = bit.blshift ---@type function +local RSHFT = bit.blogic_rshift ---@type function + +-- decode a base64 string +---@param input string +local function b64_decode(input) +---@diagnostic disable-next-line: undefined-field + local t_start = os.epoch("local") + + local decoded = {} + + local c_idx, idx = 1, 1 + + for _ = 1, input:len() / 4 do + local block = input:sub(idx, idx + 4) + local word = 0x0 + + -- build the 24-bit sequence from the 4 characters + for i = 1, 4 do + local num = b64_lookup[block:sub(i, i)] + + if num then + word = BOR(word, LSHFT(b64_lookup[block:sub(i, i)], (4 - i) * 6)) + end + end + + -- decode the 24-bit sequence as 8 bytes + for i = 1, 3 do + local char = BAND(BYTE, RSHFT(word, (3 - i) * 8)) + + if char ~= 0 then + decoded[c_idx] = CHAR(char) + c_idx = c_idx + 1 + end + end + + idx = idx + 4 + end + +---@diagnostic disable-next-line: undefined-field + local elapsed = (os.epoch("local") - t_start) + local decoded_str = table.concat(decoded) + + return decoded_str, elapsed +end + +-- write files recursively from base64 encodings in a table +---@param files table +---@param path string +local function write_files(files, path) + fs.makeDir(path) + + for k, v in pairs(files) do + if type(v) == "table" then + if k == "system" then + -- write system files to root + write_files(v, "/") + else + -- descend into directories + write_files(v, path .. "/" .. k .. "/") + end + +---@diagnostic disable-next-line: undefined-field + os.sleep(0.05) + else + local handle = fs.open(path .. k, "w") + local text, time = b64_decode(v) + + print("decoded '" .. k .. "' in " .. time .. "ms") + + handle.write(text) + handle.close() + end + end +end + +local function write_install() + local handle = fs.open("install_manifest.json", "w") + handle.write(b64_decode(install_manifest)) + handle.close() + + handle = fs.open("ccmsim.lua", "w") + handle.write(b64_decode(ccmsi_offline)) + handle.close() +end + +lgray() + +-- write both app and dependency files +write_files(app_files, "/") +write_files(dep_files, "/") + +-- write a install manifest and offline installer +write_install() + +green() +print("Done!") +white() +print("Use can use the freshly installed 'ccmsim' program to manage your off-line installation.") +lgray() +print("You do not need to run it now though, your system is all ready to start! Launch with 'startup'.") +white() diff --git a/build/bundle.py b/build/bundle.py index 8cc2af19..f45f2abd 100644 --- a/build/bundle.py +++ b/build/bundle.py @@ -1,10 +1,24 @@ import base64 import json import os +import subprocess import sys path_prefix = "./_minified/" +# get git build info +build = subprocess.check_output(["git", "describe", "--tags"]).strip().decode("utf-8") + +# list files in a directory +def list_files(path): + list = [] + + for (root, dirs, files) in os.walk(path): + for f in files: + list.append((root[2:] + "/" + f).replace('\\','/')) + + return list + # recursively encode files with base64 def encode_recursive(path): list = {} @@ -34,12 +48,46 @@ def encode_files(files): return list +# get the version of an application at the provided path +def get_version(path, is_lib = False): + ver = "" + string = ".version = \"" + + if not is_lib: + string = "_VERSION = \"" + + f = open(path, "r") + + for line in f: + pos = line.find(string) + if pos >= 0: + ver = line[(pos + len(string)):(len(line) - 2)] + break + + f.close() + + return ver + # file manifest (reflects imgen.py) manifest = { + "common_versions" : { + "bootloader" : get_version("./startup.lua"), + "common" : get_version("./scada-common/util.lua", True), + "comms" : get_version("./scada-common/comms.lua", True), + "graphics" : get_version("./graphics/core.lua", True), + "lockbox" : get_version("./lockbox/init.lua", True), + }, + "app_versions" : { + "reactor-plc" : get_version("./reactor-plc/startup.lua"), + "rtu" : get_version("./rtu/startup.lua"), + "supervisor" : get_version("./supervisor/startup.lua"), + "coordinator" : get_version("./coordinator/startup.lua"), + "pocket" : get_version("./pocket/startup.lua") + }, "files" : { # common files "system" : encode_files([ "initenv.lua", "startup.lua", "configure.lua", "LICENSE" ]), - "common" : encode_recursive(path_prefix + "./scada-common"), + "scada-common" : encode_recursive(path_prefix + "./scada-common"), "graphics" : encode_recursive(path_prefix + "./graphics"), "lockbox" : encode_recursive(path_prefix + "./lockbox"), # platform files @@ -49,13 +97,20 @@ def encode_files(files): "coordinator" : encode_recursive(path_prefix + "./coordinator"), "pocket" : encode_recursive(path_prefix + "./pocket"), }, - "depends" : { - "reactor-plc" : [ "reactor-plc", "system", "common", "graphics", "lockbox" ], - "rtu" : [ "rtu", "system", "common", "graphics", "lockbox" ], - "supervisor" : [ "supervisor", "system", "common", "graphics", "lockbox" ], - "coordinator" : [ "coordinator", "system", "common", "graphics", "lockbox" ], - "pocket" : [ "pocket", "system", "common", "graphics", "lockbox" ] - } + "install_files" : { + # common files + "system" : [ "initenv.lua", "startup.lua", "configure.lua", "LICENSE" ], + "scada-common" : list_files("./scada-common"), + "graphics" : list_files("./graphics"), + "lockbox" : list_files("./lockbox"), + # platform files + "reactor-plc" : list_files("./reactor-plc"), + "rtu" : list_files("./rtu"), + "supervisor" : list_files("./supervisor"), + "coordinator" : list_files("./coordinator"), + "pocket" : list_files("./pocket"), + }, + "depends" : [ "system", "scada-common", "graphics", "lockbox" ], } # write the application installation items as Lua tables @@ -71,13 +126,89 @@ def write_items(body, items, indent): return body +# create output directory +if not os.path.exists("./BUNDLE"): + os.makedirs("./BUNDLE") + +# get offline installer +ccmsim_file = open("./build/ccmsim.lua", "r") +ccmsim_script = ccmsim_file.read() +ccmsim_file.close() + +# create dependency bundled file +dep_file = "common_" + build + ".lua" +f_d = open("./BUNDLE/" + dep_file, "w") + +body_b = "local dep_files = {\n" +for depend in manifest["depends"]: + body_b = body_b + write_items("", { f"{depend}": manifest["files"][depend] }, 4) +body_b = body_b + "}\n" +body_b = body_b + f""" +if select("#", ...) == 0 then + term.setTextColor(colors.red) + print("You must run the other file you should have uploaded (it has the app in its name).") + term.setTextColor(colors.white) +end + +return dep_files +""" + +f_d.write(body_b) +f_d.close() + +# application bundled files for app in [ "reactor-plc", "rtu", "supervisor", "coordinator", "pocket" ]: - f = open("_" + app + ".lua", "w") - body = "local application = {\n" - for depend in manifest["depends"][app]: - body = body + write_items("", { f"{depend}": manifest["files"][depend] }, 4) - body = body + "}\n\n" - f.write(body) - f.close() + app_file = app + "_" + build + ".lua" + + f_script = open("./build/_offline.lua", "r") + script = f_script.read() + f_script.close() + + f_a = open("./BUNDLE/" + app_file, "w") + + body_a = "local app_files = {\n" + + body_a = body_a + write_items("", { f"{app}": manifest["files"][app] }, 4) + "}\n" + + versions = manifest["common_versions"].copy() + versions[app] = manifest["app_versions"][app] + + depends = manifest["depends"].copy() + depends.append(app) + + install_manifest = json.dumps({ "versions" : versions, "files" : manifest["install_files"], "depends" : depends }) + + body_a = body_a + f""" +-- install manifest JSON and offline installer +local install_manifest = "{base64.b64encode(bytes(install_manifest, 'UTF-8')).decode('ASCII')}" +local ccmsi_offline = "{base64.b64encode(bytes(ccmsim_script, 'UTF-8')).decode('ASCII')}" + +local function red() term.setTextColor(colors.red) end +local function green() term.setTextColor(colors.green) end +local function white() term.setTextColor(colors.white) end +local function lgray() term.setTextColor(colors.lightGray) end + +if not fs.exists("{dep_file}") then + red() + print("Missing '{dep_file}'! Please upload it, then run this file again.") + white() + return +end + +-- rename the dependency file +fs.move("{dep_file}", "install_depends.lua") + +-- load the other file +local dep_files = require("install_depends") + +-- delete the uploaded files to free up space to actually install +fs.delete("{app_file}") +fs.delete("install_depends.lua") + +-- get started installing +{script}""" + + f_a.write(body_a) + f_a.close() diff --git a/build/ccmsim.lua b/build/ccmsim.lua new file mode 100644 index 00000000..8dc11cee --- /dev/null +++ b/build/ccmsim.lua @@ -0,0 +1,240 @@ +local function println(message) print(tostring(message)) end +local function print(message) term.write(tostring(message)) end + +local opts = { ... } +local mode, app + +local function red() term.setTextColor(colors.red) end +local function orange() term.setTextColor(colors.orange) end +local function yellow() term.setTextColor(colors.yellow) end +local function green() term.setTextColor(colors.green) end +local function blue() term.setTextColor(colors.blue) end +local function white() term.setTextColor(colors.white) end +local function lgray() term.setTextColor(colors.lightGray) end + +-- get command line option in list +local function get_opt(opt, options) + for _, v in pairs(options) do if opt == v then return v end end + return nil +end + +-- wait for any key to be pressed +---@diagnostic disable-next-line: undefined-field +local function any_key() os.pullEvent("key_up") end + +-- ask the user yes or no +local function ask_y_n(question, default) + print(question) + if default == true then print(" (Y/n)? ") else print(" (y/N)? ") end + local response = read();any_key() + if response == "" then return default + elseif response == "Y" or response == "y" then return true + elseif response == "N" or response == "n" then return false + else return nil end +end + +-- read the local manifest file +local function read_local_manifest() + local local_ok = false + local local_manifest = {} + local imfile = fs.open("install_manifest.json", "r") + if imfile ~= nil then + local_ok, local_manifest = pcall(function () return textutils.unserializeJSON(imfile.readAll()) end) + imfile.close() + end + return local_ok, local_manifest +end + +-- recursively build a tree out of the file manifest +local function gen_tree(manifest, log) + local function _tree_add(tree, split) + if #split > 1 then + local name = table.remove(split, 1) + if tree[name] == nil then tree[name] = {} end + table.insert(tree[name], _tree_add(tree[name], split)) + else return split[1] end + return nil + end + + local list, tree = { log }, {} + + -- make a list of each and every file + for _, files in pairs(manifest.files) do for i = 1, #files do table.insert(list, files[i]) end end + + for i = 1, #list do + local split = {} +---@diagnostic disable-next-line: discard-returns + string.gsub(list[i], "([^/]+)", function(c) split[#split + 1] = c end) + if #split == 1 then table.insert(tree, list[i]) + else table.insert(tree, _tree_add(tree, split)) end + end + + return tree +end + +local function _in_array(val, array) + for _, v in pairs(array) do if v == val then return true end end + return false +end + +local function _clean_dir(dir, tree) + if tree == nil then tree = {} end + local ls = fs.list(dir) + for _, val in pairs(ls) do + local path = dir.."/"..val + if fs.isDir(path) then + _clean_dir(path, tree[val]) + if #fs.list(path) == 0 then fs.delete(path);println("deleted "..path) end + elseif (not _in_array(val, tree)) and (val ~= "config.lua" ) then + fs.delete(path) + println("deleted "..path) + end + end +end + +-- go through app/common directories to delete unused files +local function clean(manifest) + local log = nil + if fs.exists(app..".settings") and settings.load(app..".settings") then + log = settings.get("LogPath") + if log:sub(1, 1) == "/" then log = log:sub(2) end + end + + local tree = gen_tree(manifest, log) + + table.insert(tree, "install_manifest.json") + table.insert(tree, "ccmsim.lua") + + local ls = fs.list("/") + for _, val in pairs(ls) do + if fs.isDriveRoot(val) then + yellow();println("skipped mount '"..val.."'") + elseif fs.isDir(val) then + if tree[val] ~= nil then lgray();_clean_dir("/"..val, tree[val]) + else white(); if ask_y_n("delete the unused directory '"..val.."'") then lgray();_clean_dir("/"..val) end end + if #fs.list(val) == 0 then fs.delete(val);lgray();println("deleted empty directory '"..val.."'") end + elseif not _in_array(val, tree) and (string.find(val, ".settings") == nil) then + white();if ask_y_n("delete the unused file '"..val.."'") then fs.delete(val);lgray();println("deleted "..val) end + end + end + + white() +end + +-- get and validate command line options + +println("-- CC Mekanism SCADA Install Manager (Off-Line) --") + +if #opts == 0 or opts[1] == "help" then + println("usage: ccmsim ") + println("") + lgray() + println(" check - check your installed versions") + println(" update-rm - delete everything except the config,") + println(" so that you can upload files for a") + println(" new two-file/off-line update") + println(" uninstall - delete all app files and config") + return +else + mode = get_opt(opts[1], { "check", "update-rm", "uninstall" }) + if mode == nil then + red();println("Unrecognized mode.");white() + return + end +end + +-- run selected mode + +if mode == "check" then + local local_ok, manifest = read_local_manifest() + if not local_ok then + yellow();println("failed to load local installation information");white() + end + + -- list all versions + for key, value in pairs(manifest.versions) do + term.setTextColor(colors.purple) + print(string.format("%-14s", "["..key.."]")) + blue();println(value);white() + end +elseif mode == "update-rm" or mode == "uninstall" then + local ok, manifest = read_local_manifest() + if not ok then + red();println("Error parsing local installation manifest.");white() + return + end + + app = manifest.depends[#manifest.depends] + + if mode == "uninstall" then + orange();println("Uninstalling all app files...") + else + orange();println("Deleting all app files except for configuration...") + end + + -- ask for confirmation + if not ask_y_n("Continue", false) then return end + + -- delete unused files first + clean(manifest) + + local file_list = manifest.files + local dependencies = manifest.depends + + -- delete all installed files + for _, dependency in pairs(dependencies) do + local files = file_list[dependency] + for _, file in pairs(files) do + if fs.exists(file) then fs.delete(file);println("deleted "..file) end + end + + local folder = files[1] + while true do + local dir = fs.getDir(folder) + if dir == "" or dir == ".." then break else folder = dir end + end + + if fs.isDir(folder) then + fs.delete(folder) + println("deleted directory "..folder) + end + end + + -- delete log file + local log_deleted = false + local settings_file = app..".settings" + + lgray() + if fs.exists(settings_file) and settings.load(settings_file) then + local log = settings.get("LogPath") + if log ~= nil then + log_deleted = true + if fs.exists(log) then + fs.delete(log) + println("deleted log file "..log) + end + end + end + + if not log_deleted then + red();println("Failed to delete log file.") + white();println("press any key to continue...") + any_key();lgray() + end + + if mode == "uninstall" then + if fs.exists(settings_file) then + fs.delete(settings_file);println("deleted "..settings_file) + end + + fs.delete("install_manifest.json") + println("deleted install_manifest.json") + + fs.delete("ccmsim.lua") + println("deleted ccmsim.lua") + end + + green();println("Done!") +end + +white() From c5fb299f551574687baee1ecd193805a8a8aa0cc Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 23:38:51 -0400 Subject: [PATCH 28/44] message rewording, fixed colors on deletions --- build/_offline.lua | 4 ++-- build/ccmsim.lua | 6 ++---- ccmsi.lua | 6 ++---- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/build/_offline.lua b/build/_offline.lua index 883170ed..59cd53ca 100644 --- a/build/_offline.lua +++ b/build/_offline.lua @@ -108,7 +108,7 @@ write_install() green() print("Done!") white() -print("Use can use the freshly installed 'ccmsim' program to manage your off-line installation.") +print("All files have been installed. The app can be started with 'startup' and configured with 'configure'.") lgray() -print("You do not need to run it now though, your system is all ready to start! Launch with 'startup'.") +print("Hint: You can use 'ccmsim' to manage your off-line installation.") white() diff --git a/build/ccmsim.lua b/build/ccmsim.lua index 8dc11cee..a265076e 100644 --- a/build/ccmsim.lua +++ b/build/ccmsim.lua @@ -182,6 +182,7 @@ elseif mode == "update-rm" or mode == "uninstall" then local dependencies = manifest.depends -- delete all installed files + lgray() for _, dependency in pairs(dependencies) do local files = file_list[dependency] for _, file in pairs(files) do @@ -204,7 +205,6 @@ elseif mode == "update-rm" or mode == "uninstall" then local log_deleted = false local settings_file = app..".settings" - lgray() if fs.exists(settings_file) and settings.load(settings_file) then local log = settings.get("LogPath") if log ~= nil then @@ -217,9 +217,7 @@ elseif mode == "update-rm" or mode == "uninstall" then end if not log_deleted then - red();println("Failed to delete log file.") - white();println("press any key to continue...") - any_key();lgray() + red();println("Failed to delete log file (it may not exist).");lgray() end if mode == "uninstall" then diff --git a/ccmsi.lua b/ccmsi.lua index 76210dac..b056a9fc 100644 --- a/ccmsi.lua +++ b/ccmsi.lua @@ -540,6 +540,7 @@ elseif mode == "uninstall" then table.insert(dependencies, app) -- delete all installed files + lgray() for _, dependency in pairs(dependencies) do local files = file_list[dependency] for _, file in pairs(files) do @@ -562,7 +563,6 @@ elseif mode == "uninstall" then local log_deleted = false local settings_file = app..".settings" - lgray() if fs.exists(settings_file) and settings.load(settings_file) then local log = settings.get("LogPath") if log ~= nil then @@ -575,9 +575,7 @@ elseif mode == "uninstall" then end if not log_deleted then - red();println("Failed to delete log file.") - white();println("press any key to continue...") - any_key();lgray() + red();println("Failed to delete log file (it may not exist).");lgray() end if fs.exists(settings_file) then From ec1b56b853ad01b582023fba839c3c16235db60d Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 23:42:22 -0400 Subject: [PATCH 29/44] disable luacheck on offline script --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 9caba854..6828526d 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -26,4 +26,4 @@ jobs: # --no-max-line-length = Disable warnings for long line lengths # --exclude-files ... = Exclude lockbox library (external) and config files # --globals ... = Override all globals overridden in .vscode/settings.json AND 'os' since CraftOS 'os' differs from Lua's 'os' - args: . --no-max-line-length -i 121 512 542 --exclude-files ./lockbox/* --globals os _HOST bit colors fs http keys parallel periphemu peripheral read rs settings shell term textutils window + args: . --no-max-line-length -i 121 512 542 --exclude-files ./lockbox/* ./build/_offline.lua --globals os _HOST bit colors fs http keys parallel periphemu peripheral read rs settings shell term textutils window From 72a480e4758bf8bef4359da499ae2e27d201eff2 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 23:49:33 -0400 Subject: [PATCH 30/44] luacheck the offline script but with an ignore --- .github/workflows/check.yml | 2 +- build/_offline.lua | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 6828526d..9caba854 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -26,4 +26,4 @@ jobs: # --no-max-line-length = Disable warnings for long line lengths # --exclude-files ... = Exclude lockbox library (external) and config files # --globals ... = Override all globals overridden in .vscode/settings.json AND 'os' since CraftOS 'os' differs from Lua's 'os' - args: . --no-max-line-length -i 121 512 542 --exclude-files ./lockbox/* ./build/_offline.lua --globals os _HOST bit colors fs http keys parallel periphemu peripheral read rs settings shell term textutils window + args: . --no-max-line-length -i 121 512 542 --exclude-files ./lockbox/* --globals os _HOST bit colors fs http keys parallel periphemu peripheral read rs settings shell term textutils window diff --git a/build/_offline.lua b/build/_offline.lua index 59cd53ca..9c67c5c3 100644 --- a/build/_offline.lua +++ b/build/_offline.lua @@ -1,4 +1,5 @@ ---@diagnostic disable: undefined-global +-- luacheck: ignore install_manifest, ccmsi_offline, app_files, dep_files, lgray, green, white local b64_lookup = { ['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4, ['F'] = 5, ['G'] = 6, ['H'] = 7, ['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15, ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24, ['Z'] = 25, From f13f03fddc2b8f802ccc5772d77a101b68eeb8fc Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 23:51:32 -0400 Subject: [PATCH 31/44] luacheck fix --- build/_offline.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/_offline.lua b/build/_offline.lua index 9c67c5c3..9d057abd 100644 --- a/build/_offline.lua +++ b/build/_offline.lua @@ -1,5 +1,5 @@ ---@diagnostic disable: undefined-global --- luacheck: ignore install_manifest, ccmsi_offline, app_files, dep_files, lgray, green, white +-- luacheck: globals install_manifest, ccmsi_offline, app_files, dep_files, lgray, green, white local b64_lookup = { ['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4, ['F'] = 5, ['G'] = 6, ['H'] = 7, ['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15, ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24, ['Z'] = 25, From ea1bcbf81c0efdd0e8571d9facaf458f71cc6dad Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 23:52:34 -0400 Subject: [PATCH 32/44] luacheck fix 2 --- build/_offline.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/_offline.lua b/build/_offline.lua index 9d057abd..7f6a9671 100644 --- a/build/_offline.lua +++ b/build/_offline.lua @@ -1,5 +1,5 @@ ---@diagnostic disable: undefined-global --- luacheck: globals install_manifest, ccmsi_offline, app_files, dep_files, lgray, green, white +-- luacheck: push ignore install_manifest ccmsi_offline app_files dep_files lgray green white local b64_lookup = { ['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4, ['F'] = 5, ['G'] = 6, ['H'] = 7, ['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15, ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24, ['Z'] = 25, From e69cbc8633a00b7e83b17c24fa448397f36d1157 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 29 Jun 2024 23:53:37 -0400 Subject: [PATCH 33/44] luacheck fix 3 who could see this coming --- build/_offline.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/_offline.lua b/build/_offline.lua index 7f6a9671..b8deeb43 100644 --- a/build/_offline.lua +++ b/build/_offline.lua @@ -113,3 +113,5 @@ print("All files have been installed. The app can be started with 'startup' and lgray() print("Hint: You can use 'ccmsim' to manage your off-line installation.") white() + +--luacheck: pop From c93cd4d0bd3f9a81851d04453c1d33871e2a023e Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sun, 30 Jun 2024 00:01:00 -0400 Subject: [PATCH 34/44] remove UTF-8 copyright symbol --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 7578961f..d7dcef6a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright © 2022 - 2024 Mikayla Fischler +Copyright 2022 - 2024 Mikayla Fischler Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 375e969161f32cdbac155771c37f952201eae78b Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sun, 30 Jun 2024 12:33:52 -0400 Subject: [PATCH 35/44] cleanup --- build/_offline.lua | 3 ++- build/bundle.py | 4 ++-- build/ccmsim.lua | 3 +-- build/imgen.py | 6 +----- ccmsi.lua | 3 +-- 5 files changed, 7 insertions(+), 12 deletions(-) diff --git a/build/_offline.lua b/build/_offline.lua index b8deeb43..52b119c8 100644 --- a/build/_offline.lua +++ b/build/_offline.lua @@ -87,6 +87,7 @@ local function write_files(files, path) end end +-- write installation manifiest and offline install manager local function write_install() local handle = fs.open("install_manifest.json", "w") handle.write(b64_decode(install_manifest)) @@ -103,7 +104,7 @@ lgray() write_files(app_files, "/") write_files(dep_files, "/") --- write a install manifest and offline installer +-- write an install manifest and the offline installer write_install() green() diff --git a/build/bundle.py b/build/bundle.py index f45f2abd..38940448 100644 --- a/build/bundle.py +++ b/build/bundle.py @@ -7,7 +7,7 @@ path_prefix = "./_minified/" # get git build info -build = subprocess.check_output(["git", "describe", "--tags"]).strip().decode("utf-8") +build = subprocess.check_output(["git", "describe", "--tags"]).strip().decode('UTF-8') # list files in a directory def list_files(path): @@ -110,7 +110,7 @@ def get_version(path, is_lib = False): "coordinator" : list_files("./coordinator"), "pocket" : list_files("./pocket"), }, - "depends" : [ "system", "scada-common", "graphics", "lockbox" ], + "depends" : [ "system", "scada-common", "graphics", "lockbox" ] } # write the application installation items as Lua tables diff --git a/build/ccmsim.lua b/build/ccmsim.lua index a265076e..d311a7cf 100644 --- a/build/ccmsim.lua +++ b/build/ccmsim.lua @@ -132,7 +132,7 @@ if #opts == 0 or opts[1] == "help" then println(" check - check your installed versions") println(" update-rm - delete everything except the config,") println(" so that you can upload files for a") - println(" new two-file/off-line update") + println(" new two-file off-line update") println(" uninstall - delete all app files and config") return else @@ -144,7 +144,6 @@ else end -- run selected mode - if mode == "check" then local local_ok, manifest = read_local_manifest() if not local_ok then diff --git a/build/imgen.py b/build/imgen.py index 265f7863..a854b1f4 100644 --- a/build/imgen.py +++ b/build/imgen.py @@ -44,11 +44,9 @@ def get_version(path, is_lib = False): # generate installation manifest object def make_manifest(size): - os.chdir('./_minified') - manifest = { "versions" : { - "installer" : get_version("../ccmsi.lua"), + "installer" : get_version("./ccmsi.lua"), "bootloader" : get_version("./startup.lua"), "common" : get_version("./scada-common/util.lua", True), "comms" : get_version("./scada-common/comms.lua", True), @@ -97,8 +95,6 @@ def make_manifest(size): } } - os.chdir('../') - return manifest # write initial manifest with placeholder size diff --git a/ccmsi.lua b/ccmsi.lua index b056a9fc..bc911123 100644 --- a/ccmsi.lua +++ b/ccmsi.lua @@ -160,7 +160,7 @@ local function _clean_dir(dir, tree) if fs.isDir(path) then _clean_dir(path, tree[val]) if #fs.list(path) == 0 then fs.delete(path);println("deleted "..path) end - elseif (not _in_array(val, tree)) and (val ~= "config.lua" ) then ---@todo delete on full release + elseif (not _in_array(val, tree)) and (val ~= "config.lua" ) then ---@todo remove config.lua on full release fs.delete(path) println("deleted "..path) end @@ -249,7 +249,6 @@ else end -- run selected mode - if mode == "check" then local ok, manifest = get_remote_manifest() if not ok then return end From 8a409f031382a70f5936823814231c915c41879b Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sun, 30 Jun 2024 12:36:22 -0400 Subject: [PATCH 36/44] manifest build fix --- .github/workflows/manifest.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/manifest.yml b/.github/workflows/manifest.yml index 565363b5..2e5c5f83 100644 --- a/.github/workflows/manifest.yml +++ b/.github/workflows/manifest.yml @@ -46,7 +46,7 @@ jobs: - name: Generate manifest and shields for main branch id: manifest-main if: ${{ (success() || failure()) && steps.checkout-main.outcome == 'success' }} - run: python ./build/imgen.py shields + run: python build/imgen.py shields - name: Save main's manifest if: ${{ (success() || failure()) && steps.manifest-main.outcome == 'success' }} run: mv install_manifest.json deploy/manifests/main @@ -61,7 +61,7 @@ jobs: - name: Generate manifest for devel id: manifest-devel if: ${{ (success() || failure()) && steps.checkout-devel.outcome == 'success' }} - run: python ./build/imgen.py + run: python build/imgen.py - name: Save devel's manifest if: ${{ (success() || failure()) && steps.manifest-devel.outcome == 'success' }} run: mv install_manifest.json deploy/manifests/devel From f1c4f8c00ab1ec23a702a86a0bb430fa18dfa693 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sun, 30 Jun 2024 12:40:23 -0400 Subject: [PATCH 37/44] keep main on old file path for now --- .github/workflows/manifest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/manifest.yml b/.github/workflows/manifest.yml index 2e5c5f83..a3b67a56 100644 --- a/.github/workflows/manifest.yml +++ b/.github/workflows/manifest.yml @@ -46,7 +46,7 @@ jobs: - name: Generate manifest and shields for main branch id: manifest-main if: ${{ (success() || failure()) && steps.checkout-main.outcome == 'success' }} - run: python build/imgen.py shields + run: python imgen.py shields - name: Save main's manifest if: ${{ (success() || failure()) && steps.manifest-main.outcome == 'success' }} run: mv install_manifest.json deploy/manifests/main From 9614407c3758609888e8d5d2ce2c6c00cd6f905c Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sun, 30 Jun 2024 13:55:13 -0400 Subject: [PATCH 38/44] #500 removed now redundant height=1 from TextBox elements --- coordinator/configure.lua | 118 +++++++++--------- coordinator/ui/components/boiler.lua | 8 +- coordinator/ui/components/imatrix.lua | 8 +- coordinator/ui/components/pkt_entry.lua | 14 +-- coordinator/ui/components/process_ctl.lua | 16 +-- coordinator/ui/components/reactor.lua | 8 +- coordinator/ui/components/turbine.lua | 4 +- coordinator/ui/components/unit_detail.lua | 80 ++++++------- coordinator/ui/components/unit_flow.lua | 24 ++-- coordinator/ui/components/unit_overview.lua | 2 +- coordinator/ui/layout/flow_view.lua | 30 ++--- coordinator/ui/layout/front_panel.lua | 8 +- coordinator/ui/layout/main_view.lua | 6 +- pocket/configure.lua | 52 ++++---- pocket/ui/apps/diag_apps.lua | 10 +- pocket/ui/apps/guide.lua | 16 +-- pocket/ui/apps/sys_apps.lua | 54 ++++----- pocket/ui/apps/unit.lua | 20 ++-- pocket/ui/main.lua | 2 +- pocket/ui/pages/guide_section.lua | 4 +- pocket/ui/pages/home_page.lua | 2 +- pocket/ui/pages/unit_boiler.lua | 26 ++-- pocket/ui/pages/unit_reactor.lua | 32 ++--- pocket/ui/pages/unit_turbine.lua | 20 ++-- reactor-plc/configure.lua | 66 +++++----- reactor-plc/panel/front_panel.lua | 8 +- rtu/configure.lua | 126 ++++++++++---------- rtu/panel/front_panel.lua | 16 +-- supervisor/configure.lua | 106 ++++++++-------- supervisor/panel/components/pdg_entry.lua | 14 +-- supervisor/panel/components/rtu_entry.lua | 16 +-- supervisor/panel/front_panel.lua | 36 +++--- 32 files changed, 476 insertions(+), 476 deletions(-) diff --git a/coordinator/configure.lua b/coordinator/configure.lua index f57f11e0..b16a43dc 100644 --- a/coordinator/configure.lua +++ b/coordinator/configure.lua @@ -305,7 +305,7 @@ local function config_view(display) ---@diagnostic disable-next-line: undefined-field local function exit() os.queueEvent("terminate") end - TextBox{parent=display,y=1,text="Coordinator Configurator",alignment=CENTER,height=1,fg_bg=style.header} + TextBox{parent=display,y=1,text="Coordinator Configurator",alignment=CENTER,fg_bg=style.header} local root_pane_div = Div{parent=display,x=1,y=2} @@ -377,24 +377,24 @@ local function config_view(display) local net_pane = MultiPane{parent=net_cfg,x=1,y=4,panes={net_c_1,net_c_2,net_c_3,net_c_4}} - TextBox{parent=net_cfg,x=1,y=2,height=1,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)} + TextBox{parent=net_cfg,x=1,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)} - TextBox{parent=net_c_1,x=1,y=1,height=1,text="Please set the network channels below."} + TextBox{parent=net_c_1,x=1,y=1,text="Please set the network channels below."} TextBox{parent=net_c_1,x=1,y=3,height=4,text="Each of the 5 uniquely named channels, including the 3 below, must be the same for each device in this SCADA network. For multiplayer servers, it is recommended to not use the default channels.",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_1,x=1,y=8,height=1,width=18,text="Supervisor Channel"} + TextBox{parent=net_c_1,x=1,y=8,width=18,text="Supervisor Channel"} local svr_chan = NumberField{parent=net_c_1,x=21,y=8,width=7,default=ini_cfg.SVR_Channel,min=1,max=65535,fg_bg=bw_fg_bg} TextBox{parent=net_c_1,x=29,y=8,height=4,text="[SVR_CHANNEL]",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_1,x=1,y=10,height=1,width=19,text="Coordinator Channel"} + TextBox{parent=net_c_1,x=1,y=10,width=19,text="Coordinator Channel"} local crd_chan = NumberField{parent=net_c_1,x=21,y=10,width=7,default=ini_cfg.CRD_Channel,min=1,max=65535,fg_bg=bw_fg_bg} TextBox{parent=net_c_1,x=29,y=10,height=4,text="[CRD_CHANNEL]",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_1,x=1,y=12,height=1,width=14,text="Pocket Channel"} + TextBox{parent=net_c_1,x=1,y=12,width=14,text="Pocket Channel"} local pkt_chan = NumberField{parent=net_c_1,x=21,y=12,width=7,default=ini_cfg.PKT_Channel,min=1,max=65535,fg_bg=bw_fg_bg} TextBox{parent=net_c_1,x=29,y=12,height=4,text="[PKT_CHANNEL]",fg_bg=g_lg_fg_bg} - local chan_err = TextBox{parent=net_c_1,x=8,y=14,height=1,width=35,text="Please set all channels.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local chan_err = TextBox{parent=net_c_1,x=8,y=14,width=35,text="Please set all channels.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_channels() local svr_c, crd_c, pkt_c = tonumber(svr_chan.get_value()), tonumber(crd_chan.get_value()), tonumber(pkt_chan.get_value()) @@ -408,18 +408,18 @@ local function config_view(display) PushButton{parent=net_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=net_c_1,x=44,y=14,text="Next \x1a",callback=submit_channels,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - TextBox{parent=net_c_2,x=1,y=1,height=1,text="Please set the connection timeouts below."} + TextBox{parent=net_c_2,x=1,y=1,text="Please set the connection timeouts below."} TextBox{parent=net_c_2,x=1,y=3,height=4,text="You generally should not need to modify these. On slow servers, you can try to increase this to make the system wait longer before assuming a disconnection. The default for all is 5 seconds.",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_2,x=1,y=8,height=1,width=19,text="Supervisor Timeout"} + TextBox{parent=net_c_2,x=1,y=8,width=19,text="Supervisor Timeout"} local svr_timeout = NumberField{parent=net_c_2,x=20,y=8,width=7,default=ini_cfg.SVR_Timeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg} - TextBox{parent=net_c_2,x=1,y=10,height=1,width=14,text="Pocket Timeout"} + TextBox{parent=net_c_2,x=1,y=10,width=14,text="Pocket Timeout"} local api_timeout = NumberField{parent=net_c_2,x=20,y=10,width=7,default=ini_cfg.API_Timeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg} TextBox{parent=net_c_2,x=28,y=8,height=4,width=7,text="seconds\n\nseconds",fg_bg=g_lg_fg_bg} - local ct_err = TextBox{parent=net_c_2,x=8,y=14,height=1,width=35,text="Please set all connection timeouts.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local ct_err = TextBox{parent=net_c_2,x=8,y=14,width=35,text="Please set all connection timeouts.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_timeouts() local svr_cto, api_cto = tonumber(svr_timeout.get_value()), tonumber(api_timeout.get_value()) @@ -433,13 +433,13 @@ local function config_view(display) PushButton{parent=net_c_2,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=net_c_2,x=44,y=14,text="Next \x1a",callback=submit_timeouts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - TextBox{parent=net_c_3,x=1,y=1,height=1,text="Please set the trusted range below."} + TextBox{parent=net_c_3,x=1,y=1,text="Please set the trusted range below."} TextBox{parent=net_c_3,x=1,y=3,height=3,text="Setting this to a value larger than 0 prevents connections with devices that many meters (blocks) away in any direction.",fg_bg=g_lg_fg_bg} TextBox{parent=net_c_3,x=1,y=7,height=2,text="This is optional. You can disable this functionality by setting the value to 0.",fg_bg=g_lg_fg_bg} local range = NumberField{parent=net_c_3,x=1,y=10,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg} - local tr_err = TextBox{parent=net_c_3,x=8,y=14,height=1,width=35,text="Please set the trusted range.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local tr_err = TextBox{parent=net_c_3,x=8,y=14,width=35,text="Please set the trusted range.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_tr() local range_val = tonumber(range.get_value()) @@ -457,7 +457,7 @@ local function config_view(display) TextBox{parent=net_c_4,x=1,y=1,height=2,text="Optionally, set the facility authentication key below. Do NOT use one of your passwords."} TextBox{parent=net_c_4,x=1,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for security on multiplayer servers. All devices on the same network MUST use the same key if any device has a key. This does result in some extra compution (can slow things down).",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_4,x=1,y=11,height=1,text="Facility Auth Key"} + TextBox{parent=net_c_4,x=1,y=11,text="Facility Auth Key"} local key, _, censor = TextField{parent=net_c_4,x=1,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg} local function censor_key(enable) censor(util.trinary(enable, "*", nil)) end @@ -467,7 +467,7 @@ local function config_view(display) hide_key.set_value(true) censor_key(true) - local key_err = TextBox{parent=net_c_4,x=8,y=14,height=1,width=35,text="Key must be at least 8 characters.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local key_err = TextBox{parent=net_c_4,x=8,y=14,width=35,text="Key must be at least 8 characters.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_auth() local v = key.get_value() @@ -505,12 +505,12 @@ local function config_view(display) local fac_pane = MultiPane{parent=mon_cfg,x=1,y=4,panes={fac_c_1,fac_c_2,fac_c_3}} - TextBox{parent=fac_cfg,x=1,y=2,height=1,text=" Facility Configuration",fg_bg=cpair(colors.black,colors.yellow)} + TextBox{parent=fac_cfg,x=1,y=2,text=" Facility Configuration",fg_bg=cpair(colors.black,colors.yellow)} TextBox{parent=fac_c_1,x=1,y=1,height=4,text="This tool can attempt to connect to your supervisor computer. This would load facility information in order to get the unit count and aid monitor setup."} TextBox{parent=fac_c_1,x=1,y=6,height=2,text="The supervisor startup app must be running and fully configured on your supervisor computer."} - tool_ctl.sv_conn_status = TextBox{parent=fac_c_1,x=11,y=9,height=1,text=""} + tool_ctl.sv_conn_status = TextBox{parent=fac_c_1,x=11,y=9,text=""} tool_ctl.sv_conn_detail = TextBox{parent=fac_c_1,x=1,y=11,height=2,text=""} tool_ctl.sv_conn_button = PushButton{parent=fac_c_1,x=1,y=9,text="Connect",min_width=9,callback=function()tool_ctl.sv_connect()end,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg,dis_fg_bg=dis_fg_bg} @@ -534,11 +534,11 @@ local function config_view(display) TextBox{parent=fac_c_2,x=1,y=1,height=3,text="Please enter the number of reactors you have, also referred to as reactor units or 'units' for short. A maximum of 4 is currently supported."} local num_units = NumberField{parent=fac_c_2,x=1,y=5,width=5,max_chars=2,default=ini_cfg.UnitCount,min=1,max=4,fg_bg=bw_fg_bg} - TextBox{parent=fac_c_2,x=7,y=5,height=1,text="reactors"} + TextBox{parent=fac_c_2,x=7,y=5,text="reactors"} TextBox{parent=fac_c_2,x=1,y=7,height=3,text="This will decide how many monitors you need. If this does not match the supervisor's number of reactor units, the coordinator will not connect.",fg_bg=g_lg_fg_bg} TextBox{parent=fac_c_2,x=1,y=10,height=3,text="Since you skipped supervisor sync, the main monitor minimum height can't be determined precisely. It is marked with * on the next page.",fg_bg=g_lg_fg_bg} - local nu_error = TextBox{parent=fac_c_2,x=8,y=14,height=1,width=35,text="Please set the number of reactors.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local nu_error = TextBox{parent=fac_c_2,x=8,y=14,width=35,text="Please set the number of reactors.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_num_units() local count = tonumber(num_units.get_value()) @@ -571,7 +571,7 @@ local function config_view(display) local mon_pane = MultiPane{parent=mon_cfg,x=1,y=4,panes={mon_c_1,mon_c_2,mon_c_3,mon_c_4}} - TextBox{parent=mon_cfg,x=1,y=2,height=1,text=" Monitor Configuration",fg_bg=cpair(colors.black,colors.blue)} + TextBox{parent=mon_cfg,x=1,y=2,text=" Monitor Configuration",fg_bg=cpair(colors.black,colors.blue)} TextBox{parent=mon_c_1,x=1,y=1,height=5,text="Your configuration requires the following monitors. The main and flow monitors' heights are dependent on your unit count and cooling setup. If you manually entered the unit count, a * will be shown on potentially inaccurate calculations."} local mon_reqs = ListBox{parent=mon_c_1,x=1,y=7,height=6,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} @@ -592,7 +592,7 @@ local function config_view(display) local mon_list = ListBox{parent=mon_c_2,x=1,y=6,height=7,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} - local assign_err = TextBox{parent=mon_c_2,x=8,y=14,height=1,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local assign_err = TextBox{parent=mon_c_2,x=8,y=14,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_monitors() if tmp_cfg.MainDisplay == nil then @@ -652,13 +652,13 @@ local function config_view(display) if value == "0" or value == nil then mon_unit.set_value(0) end end - TextBox{parent=mon_c_3,x=1,y=6,width=10,height=1,text="Assignment"} + TextBox{parent=mon_c_3,x=1,y=6,width=10,text="Assignment"} local mon_assign = RadioButton{parent=mon_c_3,x=1,y=7,default=1,options={"Main Monitor","Flow Monitor","Unit Monitor"},callback=on_assign_mon,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.blue} - mon_unit_l = TextBox{parent=mon_c_3,x=18,y=6,width=7,height=1,text="Unit ID"} + mon_unit_l = TextBox{parent=mon_c_3,x=18,y=6,width=7,text="Unit ID"} mon_unit = NumberField{parent=mon_c_3,x=18,y=7,width=10,max_chars=2,min=1,max=4,fg_bg=bw_fg_bg} - local mon_u_err = TextBox{parent=mon_c_3,x=8,y=14,height=1,width=35,text="Please provide a unit ID.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local mon_u_err = TextBox{parent=mon_c_3,x=8,y=14,width=35,text="Please provide a unit ID.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} -- purge all assignments for a given monitor ---@param iface string @@ -720,7 +720,7 @@ local function config_view(display) local spkr_c = Div{parent=spkr_cfg,x=2,y=4,width=49} - TextBox{parent=spkr_cfg,x=1,y=2,height=1,text=" Speaker Configuration",fg_bg=cpair(colors.black,colors.cyan)} + TextBox{parent=spkr_cfg,x=1,y=2,text=" Speaker Configuration",fg_bg=cpair(colors.black,colors.cyan)} TextBox{parent=spkr_c,x=1,y=1,height=2,text="The coordinator uses a speaker to play alarm sounds."} TextBox{parent=spkr_c,x=1,y=4,height=3,text="You can change the speaker audio volume from the default. The range is 0.0 to 3.0, where 1.0 is standard volume."} @@ -729,7 +729,7 @@ local function config_view(display) TextBox{parent=spkr_c,x=1,y=10,height=3,text="Note: alarm sine waves are at half scale so that multiple will be required to reach full scale.",fg_bg=g_lg_fg_bg} - local s_vol_err = TextBox{parent=spkr_c,x=8,y=14,height=1,width=35,text="Please set a volume.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local s_vol_err = TextBox{parent=spkr_c,x=8,y=14,width=35,text="Please set a volume.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_vol() local vol = tonumber(s_vol.get_value()) @@ -749,14 +749,14 @@ local function config_view(display) local crd_c_1 = Div{parent=crd_cfg,x=2,y=4,width=49} - TextBox{parent=crd_cfg,x=1,y=2,height=1,text=" Coordinator UI Configuration",fg_bg=cpair(colors.black,colors.lime)} + TextBox{parent=crd_cfg,x=1,y=2,text=" Coordinator UI Configuration",fg_bg=cpair(colors.black,colors.lime)} TextBox{parent=crd_c_1,x=1,y=1,height=3,text="Configure the UI interface options below if you wish to customize formats."} - TextBox{parent=crd_c_1,x=1,y=4,height=1,text="Clock Time Format"} + TextBox{parent=crd_c_1,x=1,y=4,text="Clock Time Format"} local clock_fmt = RadioButton{parent=crd_c_1,x=1,y=5,default=util.trinary(ini_cfg.Time24Hour,1,2),options={"24-Hour","12-Hour"},callback=function()end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.lime} - TextBox{parent=crd_c_1,x=1,y=8,height=1,text="Temperature Scale"} + TextBox{parent=crd_c_1,x=1,y=8,text="Temperature Scale"} local temp_scale = RadioButton{parent=crd_c_1,x=1,y=9,default=ini_cfg.TempScale,options=types.TEMP_SCALE_NAMES,callback=function()end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.lime} local function submit_ui_opts() @@ -774,20 +774,20 @@ local function config_view(display) local log_c_1 = Div{parent=log_cfg,x=2,y=4,width=49} - TextBox{parent=log_cfg,x=1,y=2,height=1,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)} + TextBox{parent=log_cfg,x=1,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)} - TextBox{parent=log_c_1,x=1,y=1,height=1,text="Please configure logging below."} + TextBox{parent=log_c_1,x=1,y=1,text="Please configure logging below."} - TextBox{parent=log_c_1,x=1,y=3,height=1,text="Log File Mode"} + TextBox{parent=log_c_1,x=1,y=3,text="Log File Mode"} local mode = RadioButton{parent=log_c_1,x=1,y=4,default=ini_cfg.LogMode+1,options={"Append on Startup","Replace on Startup"},callback=function()end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.pink} - TextBox{parent=log_c_1,x=1,y=7,height=1,text="Log File Path"} + TextBox{parent=log_c_1,x=1,y=7,text="Log File Path"} local path = TextField{parent=log_c_1,x=1,y=8,width=49,height=1,value=ini_cfg.LogPath,max_len=128,fg_bg=bw_fg_bg} local en_dbg = CheckBox{parent=log_c_1,x=1,y=10,default=ini_cfg.LogDebug,label="Enable Logging Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)} TextBox{parent=log_c_1,x=3,y=11,height=2,text="This results in much larger log files. It is best to only use this when there is a problem.",fg_bg=g_lg_fg_bg} - local path_err = TextBox{parent=log_c_1,x=8,y=14,height=1,width=35,text="Please provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local path_err = TextBox{parent=log_c_1,x=8,y=14,width=35,text="Please provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_log() if path.get_value() ~= "" then @@ -815,20 +815,20 @@ local function config_view(display) local clr_pane = MultiPane{parent=clr_cfg,x=1,y=4,panes={clr_c_1,clr_c_2,clr_c_3,clr_c_4}} - TextBox{parent=clr_cfg,x=1,y=2,height=1,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)} + TextBox{parent=clr_cfg,x=1,y=2,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)} TextBox{parent=clr_c_1,x=1,y=1,height=2,text="Here you can select the color themes for the different UI displays."} TextBox{parent=clr_c_1,x=1,y=4,height=2,text="Click 'Accessibility' below to access colorblind assistive options.",fg_bg=g_lg_fg_bg} - TextBox{parent=clr_c_1,x=1,y=7,height=1,text="Main UI Theme"} + TextBox{parent=clr_c_1,x=1,y=7,text="Main UI Theme"} local main_theme = RadioButton{parent=clr_c_1,x=1,y=8,default=ini_cfg.MainTheme,options=themes.UI_THEME_NAMES,callback=function()end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta} - TextBox{parent=clr_c_1,x=18,y=7,height=1,text="Front Panel Theme"} + TextBox{parent=clr_c_1,x=18,y=7,text="Front Panel Theme"} local fp_theme = RadioButton{parent=clr_c_1,x=18,y=8,default=ini_cfg.FrontPanelTheme,options=themes.FP_THEME_NAMES,callback=function()end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta} TextBox{parent=clr_c_2,x=1,y=1,height=6,text="This system uses color heavily to distinguish ok and not, with some indicators using many colors. By selecting a mode below, indicators will change as shown. For non-standard modes, indicators with more than two colors will be split up."} - TextBox{parent=clr_c_2,x=21,y=7,height=1,text="Preview"} + TextBox{parent=clr_c_2,x=21,y=7,text="Preview"} local _ = IndLight{parent=clr_c_2,x=21,y=8,label="Good",colors=cpair(colors.black,colors.green)} _ = IndLight{parent=clr_c_2,x=21,y=9,label="Warning",colors=cpair(colors.black,colors.yellow)} _ = IndLight{parent=clr_c_2,x=21,y=10,label="Bad",colors=cpair(colors.black,colors.red)} @@ -855,7 +855,7 @@ local function config_view(display) end end - TextBox{parent=clr_c_2,x=1,y=7,height=1,width=10,text="Color Mode"} + TextBox{parent=clr_c_2,x=1,y=7,width=10,text="Color Mode"} local c_mode = RadioButton{parent=clr_c_2,x=1,y=8,default=ini_cfg.ColorMode,options=themes.COLOR_MODE_NAMES,callback=recolor,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta} TextBox{parent=clr_c_2,x=21,y=13,height=2,width=18,text="Note: exact color varies by theme.",fg_bg=g_lg_fg_bg} @@ -911,7 +911,7 @@ local function config_view(display) clr_pane.set_value(1) end - TextBox{parent=clr_c_3,x=1,y=1,height=1,text="Settings saved!"} + TextBox{parent=clr_c_3,x=1,y=1,text="Settings saved!"} PushButton{parent=clr_c_3,x=1,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)} PushButton{parent=clr_c_3,x=44,y=14,min_width=6,text="Home",callback=c_go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} @@ -930,7 +930,7 @@ local function config_view(display) local sum_pane = MultiPane{parent=summary,x=1,y=4,panes={sum_c_1,sum_c_2,sum_c_3,sum_c_4}} - TextBox{parent=summary,x=1,y=2,height=1,text=" Summary",fg_bg=cpair(colors.black,colors.green)} + TextBox{parent=summary,x=1,y=2,text=" Summary",fg_bg=cpair(colors.black,colors.green)} local setting_list = ListBox{parent=sum_c_1,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} @@ -998,7 +998,7 @@ local function config_view(display) tool_ctl.show_key_btn = PushButton{parent=sum_c_1,x=8,y=14,min_width=17,text="Unhide Auth Key",callback=function()tool_ctl.show_auth_key()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=dis_fg_bg} tool_ctl.settings_apply = PushButton{parent=sum_c_1,x=43,y=14,min_width=7,text="Apply",callback=save_and_continue,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg} - TextBox{parent=sum_c_2,x=1,y=1,height=1,text="Settings saved!"} + TextBox{parent=sum_c_2,x=1,y=1,text="Settings saved!"} local function go_home() main_pane.set_value(1) @@ -1033,15 +1033,15 @@ local function config_view(display) local cl = Div{parent=changelog,x=2,y=4,width=49} - TextBox{parent=changelog,x=1,y=2,height=1,text=" Config Change Log",fg_bg=bw_fg_bg} + TextBox{parent=changelog,x=1,y=2,text=" Config Change Log",fg_bg=bw_fg_bg} local c_log = ListBox{parent=cl,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} for _, change in ipairs(changes) do - TextBox{parent=c_log,text=change[1],height=1,fg_bg=bw_fg_bg} + TextBox{parent=c_log,text=change[1],fg_bg=bw_fg_bg} for _, v in ipairs(change[2]) do local e = Div{parent=c_log,height=#util.strwrap(v,46)} - TextBox{parent=e,y=1,x=1,text="- ",height=1,fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=e,y=1,x=1,text="- ",fg_bg=cpair(colors.gray,colors.white)} TextBox{parent=e,y=1,x=3,text=v,height=e.get_height(),fg_bg=cpair(colors.gray,colors.white)} end end @@ -1137,12 +1137,12 @@ local function config_view(display) fac_config_list.remove_all() local str = util.sprintf("Facility has %d reactor unit%s:", #conf, util.trinary(#conf==1,"","s")) - TextBox{parent=fac_config_list,height=1,text=str,fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=fac_config_list,text=str,fg_bg=cpair(colors.gray,colors.white)} for i = 1, #conf do local num_b, num_t = conf[i][1], conf[i][2] str = util.sprintf("\x07 Unit %d has %d boiler%s and %d turbine%s", i, num_b, util.trinary(num_b == 1, "", "s"), num_t, util.trinary(num_t == 1, "", "s")) - TextBox{parent=fac_config_list,height=1,text=str,fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=fac_config_list,text=str,fg_bg=cpair(colors.gray,colors.white)} end end @@ -1178,13 +1178,13 @@ local function config_view(display) mon_reqs.remove_all() - TextBox{parent=mon_reqs,x=1,y=1,height=1,text="\x1a "..tmp_cfg.UnitCount.." Unit View Monitor"..util.trinary(plural,"s","")} - TextBox{parent=mon_reqs,x=1,y=1,height=1,text=" "..util.trinary(plural,"each ","").."must be 4 blocks wide by 4 tall",fg_bg=cpair(colors.gray,colors.white)} - TextBox{parent=mon_reqs,x=1,y=1,height=1,text="\x1a 1 Main View Monitor"} - TextBox{parent=mon_reqs,x=1,y=1,height=1,text=" must be 8 blocks wide by "..m_at_least..tool_ctl.main_mon_h..asterisk.." tall",fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=mon_reqs,x=1,y=1,text="\x1a "..tmp_cfg.UnitCount.." Unit View Monitor"..util.trinary(plural,"s","")} + TextBox{parent=mon_reqs,x=1,y=1,text=" "..util.trinary(plural,"each ","").."must be 4 blocks wide by 4 tall",fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=mon_reqs,x=1,y=1,text="\x1a 1 Main View Monitor"} + TextBox{parent=mon_reqs,x=1,y=1,text=" must be 8 blocks wide by "..m_at_least..tool_ctl.main_mon_h..asterisk.." tall",fg_bg=cpair(colors.gray,colors.white)} if not tmp_cfg.DisableFlowView then - TextBox{parent=mon_reqs,x=1,y=1,height=1,text="\x1a 1 Flow View Monitor"} - TextBox{parent=mon_reqs,x=1,y=1,height=1,text=" must be 8 blocks wide by "..f_at_least..tool_ctl.flow_mon_h.." tall",fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=mon_reqs,x=1,y=1,text="\x1a 1 Flow View Monitor"} + TextBox{parent=mon_reqs,x=1,y=1,text=" must be 8 blocks wide by "..f_at_least..tool_ctl.flow_mon_h.." tall",fg_bg=cpair(colors.gray,colors.white)} end end @@ -1286,8 +1286,8 @@ local function config_view(display) local line = Div{parent=mon_list,x=1,y=1,height=1} - TextBox{parent=line,x=1,y=1,width=6,height=1,text=assignment,fg_bg=cpair(util.trinary(assignment=="Unused",colors.red,colors.blue),colors.white)} - TextBox{parent=line,x=8,y=1,height=1,text=iface} + TextBox{parent=line,x=1,y=1,width=6,text=assignment,fg_bg=cpair(util.trinary(assignment=="Unused",colors.red,colors.blue),colors.white)} + TextBox{parent=line,x=8,y=1,text=iface} local w, h = ppm.monitor_block_size(dev.getSize()) @@ -1296,7 +1296,7 @@ local function config_view(display) tool_ctl.gen_mon_list() end - TextBox{parent=line,x=33,y=1,width=4,height=1,text=w.."x"..h,fg_bg=cpair(colors.black,colors.white)} + TextBox{parent=line,x=33,y=1,width=4,text=w.."x"..h,fg_bg=cpair(colors.black,colors.white)} PushButton{parent=line,x=37,y=1,min_width=5,height=1,text="SET",callback=function()tool_ctl.edit_monitor(iface,device)end,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg} local unset = PushButton{parent=line,x=42,y=1,min_width=7,height=1,text="UNSET",callback=unset_mon,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg,dis_fg_bg=cpair(colors.black,colors.gray)} @@ -1315,15 +1315,15 @@ local function config_view(display) for i = 1, #dc_list do local line = Div{parent=mon_list,x=1,y=1,height=1} - TextBox{parent=line,x=1,y=1,width=6,height=1,text=dc_list[i][1],fg_bg=cpair(colors.blue,colors.white)} - TextBox{parent=line,x=8,y=1,height=1,text="disconnected",fg_bg=cpair(colors.red,colors.white)} + TextBox{parent=line,x=1,y=1,width=6,text=dc_list[i][1],fg_bg=cpair(colors.blue,colors.white)} + TextBox{parent=line,x=8,y=1,text="disconnected",fg_bg=cpair(colors.red,colors.white)} local function unset_mon() purge_assignments(dc_list[i][2]) tool_ctl.gen_mon_list() end - TextBox{parent=line,x=33,y=1,width=4,height=1,text="?x?",fg_bg=cpair(colors.black,colors.white)} + TextBox{parent=line,x=33,y=1,width=4,text="?x?",fg_bg=cpair(colors.black,colors.white)} PushButton{parent=line,x=37,y=1,min_width=5,height=1,text="SET",callback=function()end,dis_fg_bg=cpair(colors.black,colors.gray)}.disable() PushButton{parent=line,x=42,y=1,min_width=7,height=1,text="UNSET",callback=unset_mon,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg,dis_fg_bg=cpair(colors.black,colors.gray)} end diff --git a/coordinator/ui/components/boiler.lua b/coordinator/ui/components/boiler.lua index 0b7843f4..72eef552 100644 --- a/coordinator/ui/components/boiler.lua +++ b/coordinator/ui/components/boiler.lua @@ -35,10 +35,10 @@ local function new_view(root, x, y, ps) temp.register(ps, "temperature", function (t) temp.update(db.temp_convert(t)) end) boil_r.register(ps, "boil_rate", boil_r.update) - TextBox{parent=boiler,text="H",x=2,y=5,height=1,width=1,fg_bg=text_fg} - TextBox{parent=boiler,text="W",x=3,y=5,height=1,width=1,fg_bg=text_fg} - TextBox{parent=boiler,text="S",x=27,y=5,height=1,width=1,fg_bg=text_fg} - TextBox{parent=boiler,text="C",x=28,y=5,height=1,width=1,fg_bg=text_fg} + TextBox{parent=boiler,text="H",x=2,y=5,width=1,fg_bg=text_fg} + TextBox{parent=boiler,text="W",x=3,y=5,width=1,fg_bg=text_fg} + TextBox{parent=boiler,text="S",x=27,y=5,width=1,fg_bg=text_fg} + TextBox{parent=boiler,text="C",x=28,y=5,width=1,fg_bg=text_fg} local hcool = VerticalBar{parent=boiler,x=2,y=1,fg_bg=cpair(colors.orange,colors.gray),height=4,width=1} local water = VerticalBar{parent=boiler,x=3,y=1,fg_bg=cpair(colors.blue,colors.gray),height=4,width=1} diff --git a/coordinator/ui/components/imatrix.lua b/coordinator/ui/components/imatrix.lua index b116e3da..c5a1e557 100644 --- a/coordinator/ui/components/imatrix.lua +++ b/coordinator/ui/components/imatrix.lua @@ -42,8 +42,8 @@ local function new_view(root, x, y, data, ps, id) -- black has low contrast with dark gray, so if background is black use white instead local cutout_fg_bg = cpair(util.trinary(style.theme.bg == colors.black, colors.white, style.theme.bg), colors.gray) - TextBox{parent=matrix,text=" ",width=33,height=1,x=1,y=1,fg_bg=cutout_fg_bg} - TextBox{parent=matrix,text=title,alignment=ALIGN.CENTER,width=33,height=1,x=1,y=2,fg_bg=cutout_fg_bg} + TextBox{parent=matrix,text=" ",width=33,x=1,y=1,fg_bg=cutout_fg_bg} + TextBox{parent=matrix,text=title,alignment=ALIGN.CENTER,width=33,x=1,y=2,fg_bg=cutout_fg_bg} local rect = Rectangle{parent=matrix,border=border(1,colors.gray,true),width=33,height=22,x=1,y=3} @@ -87,7 +87,7 @@ local function new_view(root, x, y, data, ps, id) local in_cap = VerticalBar{parent=rect,x=7,y=12,fg_bg=cpair(colors.red,colors.gray),height=7,width=1} local out_cap = VerticalBar{parent=rect,x=9,y=12,fg_bg=cpair(colors.blue,colors.gray),height=7,width=1} - TextBox{parent=rect,text="FILL I/O",x=2,y=20,height=1,width=8,fg_bg=label_fg} + TextBox{parent=rect,text="FILL I/O",x=2,y=20,width=8,fg_bg=label_fg} local function calc_saturation(val) if (type(data.build) == "table") and (type(data.build.transfer_cap) == "number") and (data.build.transfer_cap > 0) then @@ -99,7 +99,7 @@ local function new_view(root, x, y, data, ps, id) in_cap.register(ps, "last_input", function (val) in_cap.update(calc_saturation(val)) end) out_cap.register(ps, "last_output", function (val) out_cap.update(calc_saturation(val)) end) - local eta = TextBox{parent=rect,x=11,y=20,width=20,height=1,text="ETA Unknown",alignment=ALIGN.CENTER,fg_bg=style.theme.field_box} + local eta = TextBox{parent=rect,x=11,y=20,width=20,text="ETA Unknown",alignment=ALIGN.CENTER,fg_bg=style.theme.field_box} eta.register(ps, "eta_ms", function (eta_ms) local str, pre = "", util.trinary(eta_ms >= 0, "Full in ", "Empty in ") diff --git a/coordinator/ui/components/pkt_entry.lua b/coordinator/ui/components/pkt_entry.lua index 760f4063..e377e2e4 100644 --- a/coordinator/ui/components/pkt_entry.lua +++ b/coordinator/ui/components/pkt_entry.lua @@ -34,18 +34,18 @@ local function init(parent, id) local ps_prefix = "pkt_" .. id .. "_" - TextBox{parent=entry,x=1,y=1,text="",width=8,height=1,fg_bg=s_hi_box} - local pkt_addr = TextBox{parent=entry,x=1,y=2,text="@ C ??",alignment=ALIGN.CENTER,width=8,height=1,fg_bg=s_hi_box,nav_active=cpair(colors.gray,colors.black)} - TextBox{parent=entry,x=1,y=3,text="",width=8,height=1,fg_bg=s_hi_box} + TextBox{parent=entry,x=1,y=1,text="",width=8,fg_bg=s_hi_box} + local pkt_addr = TextBox{parent=entry,x=1,y=2,text="@ C ??",alignment=ALIGN.CENTER,width=8,fg_bg=s_hi_box,nav_active=cpair(colors.gray,colors.black)} + TextBox{parent=entry,x=1,y=3,text="",width=8,fg_bg=s_hi_box} pkt_addr.register(ps, ps_prefix .. "addr", pkt_addr.set_value) - TextBox{parent=entry,x=10,y=2,text="FW:",width=3,height=1} - local pkt_fw_v = TextBox{parent=entry,x=14,y=2,text=" ------- ",width=20,height=1,fg_bg=label_fg} + TextBox{parent=entry,x=10,y=2,text="FW:",width=3} + local pkt_fw_v = TextBox{parent=entry,x=14,y=2,text=" ------- ",width=20,fg_bg=label_fg} pkt_fw_v.register(ps, ps_prefix .. "fw", pkt_fw_v.set_value) - TextBox{parent=entry,x=35,y=2,text="RTT:",width=4,height=1} + TextBox{parent=entry,x=35,y=2,text="RTT:",width=4} local pkt_rtt = DataIndicator{parent=entry,x=40,y=2,label="",unit="",format="%5d",value=0,width=5,fg_bg=label_fg} - TextBox{parent=entry,x=46,y=2,text="ms",width=4,height=1,fg_bg=label_fg} + TextBox{parent=entry,x=46,y=2,text="ms",width=4,fg_bg=label_fg} pkt_rtt.register(ps, ps_prefix .. "rtt", pkt_rtt.update) pkt_rtt.register(ps, ps_prefix .. "rtt_color", pkt_rtt.recolor) diff --git a/coordinator/ui/components/process_ctl.lua b/coordinator/ui/components/process_ctl.lua index 6435de77..eea09e4b 100644 --- a/coordinator/ui/components/process_ctl.lua +++ b/coordinator/ui/components/process_ctl.lua @@ -105,11 +105,11 @@ local function new_view(root, x, y) fac_rad_h.register(facility.ps, "as_radiation", fac_rad_h.update) gen_fault.register(facility.ps, "as_gen_fault", gen_fault.update) - TextBox{parent=main,y=23,text="Radiation",height=1,width=13,fg_bg=style.label} + TextBox{parent=main,y=23,text="Radiation",width=13,fg_bg=style.label} local radiation = RadIndicator{parent=main,label="",format="%9.3f",lu_colors=lu_cpair,width=13,fg_bg=s_field} radiation.register(facility.ps, "radiation", radiation.update) - TextBox{parent=main,x=15,y=23,text="Linked RTUs",height=1,width=11,fg_bg=style.label} + TextBox{parent=main,x=15,y=23,text="Linked RTUs",width=11,fg_bg=style.label} local rtu_count = DataIndicator{parent=main,x=15,y=24,label="",format="%11d",value=0,lu_colors=lu_cpair,width=11,fg_bg=s_field} rtu_count.register(facility.ps, "rtu_count", rtu_count.update) @@ -190,7 +190,7 @@ local function new_view(root, x, y) local lim_ctl = Div{parent=limit_div,x=9,y=_y,width=14,height=3,fg_bg=s_hi_box} local lim = SpinboxNumeric{parent=lim_ctl,x=2,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,arrow_fg_bg=arrow_fg_bg,arrow_disable=style.theme.disabled,fg_bg=lim_fg_bg} - TextBox{parent=lim_ctl,x=9,y=2,text="mB/t",width=4,height=1,fg_bg=label_fg} + TextBox{parent=lim_ctl,x=9,y=2,text="mB/t",width=4,fg_bg=label_fg} local cur_burn = DataIndicator{parent=limit_div,x=9,y=_y+3,label="",format="%7.1f",value=0,unit="mB/t",commas=false,lu_colors=cpair(cur_lu,cur_lu),width=14,fg_bg=cur_fg_bg} @@ -249,8 +249,8 @@ local function new_view(root, x, y) mode.register(facility.ps, "process_mode", mode.set_value) local u_stat = Rectangle{parent=proc,border=border(1,colors.gray,true),thin=true,width=31,height=4,x=1,y=16,fg_bg=bw_fg_bg} - local stat_line_1 = TextBox{parent=u_stat,x=1,y=1,text="UNKNOWN",width=31,height=1,alignment=ALIGN.CENTER,fg_bg=bw_fg_bg} - local stat_line_2 = TextBox{parent=u_stat,x=1,y=2,text="awaiting data...",width=31,height=1,alignment=ALIGN.CENTER,fg_bg=cpair(colors.gray,colors.white)} + local stat_line_1 = TextBox{parent=u_stat,x=1,y=1,text="UNKNOWN",width=31,alignment=ALIGN.CENTER,fg_bg=bw_fg_bg} + local stat_line_2 = TextBox{parent=u_stat,x=1,y=2,text="awaiting data...",width=31,alignment=ALIGN.CENTER,fg_bg=cpair(colors.gray,colors.white)} stat_line_1.register(facility.ps, "status_line_1", stat_line_1.set_value) stat_line_2.register(facility.ps, "status_line_2", stat_line_2.set_value) @@ -320,7 +320,7 @@ local function new_view(root, x, y) for i = 1, facility.num_units do local unit = units[i] ---@type ioctl_unit - TextBox{parent=waste_status,y=i,text="U"..i.." Waste",width=8,height=1} + TextBox{parent=waste_status,y=i,text="U"..i.." Waste",width=8} local a_waste = IndicatorLight{parent=waste_status,x=10,y=i,label="Auto",colors=ind_wht} local waste_m = StateIndicator{parent=waste_status,x=17,y=i,states=style.waste.states_abbrv,value=1,min_width=6} @@ -332,8 +332,8 @@ local function new_view(root, x, y) local cutout_fg_bg = cpair(style.theme.bg, colors.brown) - TextBox{parent=waste_sel,text=" ",width=21,height=1,x=1,y=1,fg_bg=cutout_fg_bg} - TextBox{parent=waste_sel,text="WASTE PRODUCTION",alignment=ALIGN.CENTER,width=21,height=1,x=1,y=2,fg_bg=cutout_fg_bg} + TextBox{parent=waste_sel,text=" ",width=21,x=1,y=1,fg_bg=cutout_fg_bg} + TextBox{parent=waste_sel,text="WASTE PRODUCTION",alignment=ALIGN.CENTER,width=21,x=1,y=2,fg_bg=cutout_fg_bg} local rect = Rectangle{parent=waste_sel,border=border(1,colors.brown,true),width=21,height=22,x=1,y=3} local status = StateIndicator{parent=rect,x=2,y=1,states=style.waste.states,value=1,min_width=17} diff --git a/coordinator/ui/components/reactor.lua b/coordinator/ui/components/reactor.lua index 8e6005d5..2319f762 100644 --- a/coordinator/ui/components/reactor.lua +++ b/coordinator/ui/components/reactor.lua @@ -41,10 +41,10 @@ local function new_view(root, x, y, ps) local reactor_fills = Rectangle{parent=root,border=border(1, colors.gray, true),width=24,height=7,x=(x + 29),y=y} - TextBox{parent=reactor_fills,text="FUEL",x=2,y=1,height=1,fg_bg=text_fg} - TextBox{parent=reactor_fills,text="COOL",x=2,y=2,height=1,fg_bg=text_fg} - TextBox{parent=reactor_fills,text="HCOOL",x=2,y=4,height=1,fg_bg=text_fg} - TextBox{parent=reactor_fills,text="WASTE",x=2,y=5,height=1,fg_bg=text_fg} + TextBox{parent=reactor_fills,text="FUEL",x=2,y=1,fg_bg=text_fg} + TextBox{parent=reactor_fills,text="COOL",x=2,y=2,fg_bg=text_fg} + TextBox{parent=reactor_fills,text="HCOOL",x=2,y=4,fg_bg=text_fg} + TextBox{parent=reactor_fills,text="WASTE",x=2,y=5,fg_bg=text_fg} local fuel = HorizontalBar{parent=reactor_fills,x=8,y=1,show_percent=true,bar_fg_bg=cpair(style.theme.fuel_color,colors.gray),height=1,width=14} local ccool = HorizontalBar{parent=reactor_fills,x=8,y=2,show_percent=true,bar_fg_bg=cpair(colors.blue,colors.gray),height=1,width=14} diff --git a/coordinator/ui/components/turbine.lua b/coordinator/ui/components/turbine.lua index 75cbabd1..179e82d7 100644 --- a/coordinator/ui/components/turbine.lua +++ b/coordinator/ui/components/turbine.lua @@ -37,8 +37,8 @@ local function new_view(root, x, y, ps) local steam = VerticalBar{parent=turbine,x=2,y=1,fg_bg=cpair(colors.white,colors.gray),height=4,width=1} local energy = VerticalBar{parent=turbine,x=3,y=1,fg_bg=cpair(colors.green,colors.gray),height=4,width=1} - TextBox{parent=turbine,text="S",x=2,y=5,height=1,width=1,fg_bg=text_fg} - TextBox{parent=turbine,text="E",x=3,y=5,height=1,width=1,fg_bg=text_fg} + TextBox{parent=turbine,text="S",x=2,y=5,width=1,fg_bg=text_fg} + TextBox{parent=turbine,text="E",x=3,y=5,width=1,fg_bg=text_fg} steam.register(ps, "steam_fill", steam.update) energy.register(ps, "energy_fill", energy.update) diff --git a/coordinator/ui/components/unit_detail.lua b/coordinator/ui/components/unit_detail.lua index 2c26b985..479c099e 100644 --- a/coordinator/ui/components/unit_detail.lua +++ b/coordinator/ui/components/unit_detail.lua @@ -71,7 +71,7 @@ local function init(parent, id) local b_ps = unit.boiler_ps_tbl local t_ps = unit.turbine_ps_tbl - TextBox{parent=main,text="Reactor Unit #" .. id,alignment=ALIGN.CENTER,height=1,fg_bg=style.theme.header} + TextBox{parent=main,text="Reactor Unit #" .. id,alignment=ALIGN.CENTER,fg_bg=style.theme.header} ----------------------------- -- main stats and core map -- @@ -81,20 +81,20 @@ local function init(parent, id) core_map.register(u_ps, "temp", core_map.update) core_map.register(u_ps, "size", function (s) core_map.resize(s[1], s[2]) end) - TextBox{parent=main,x=12,y=22,text="Heating Rate",height=1,width=12,fg_bg=style.label} + TextBox{parent=main,x=12,y=22,text="Heating Rate",width=12,fg_bg=style.label} local heating_r = DataIndicator{parent=main,x=12,label="",format="%14.0f",value=0,unit="mB/t",commas=true,lu_colors=lu_cpair,width=19,fg_bg=s_field} heating_r.register(u_ps, "heating_rate", heating_r.update) - TextBox{parent=main,x=12,y=25,text="Commanded Burn Rate",height=1,width=19,fg_bg=style.label} + TextBox{parent=main,x=12,y=25,text="Commanded Burn Rate",width=19,fg_bg=style.label} local burn_r = DataIndicator{parent=main,x=12,label="",format="%14.2f",value=0,unit="mB/t",lu_colors=lu_cpair,width=19,fg_bg=s_field} burn_r.register(u_ps, "burn_rate", burn_r.update) - TextBox{parent=main,text="F",x=2,y=22,width=1,height=1,fg_bg=style.label} - TextBox{parent=main,text="C",x=4,y=22,width=1,height=1,fg_bg=style.label} - TextBox{parent=main,text="\x1a",x=6,y=24,width=1,height=1,fg_bg=style.label} - TextBox{parent=main,text="\x1a",x=6,y=25,width=1,height=1,fg_bg=style.label} - TextBox{parent=main,text="H",x=8,y=22,width=1,height=1,fg_bg=style.label} - TextBox{parent=main,text="W",x=10,y=22,width=1,height=1,fg_bg=style.label} + TextBox{parent=main,text="F",x=2,y=22,width=1,fg_bg=style.label} + TextBox{parent=main,text="C",x=4,y=22,width=1,fg_bg=style.label} + TextBox{parent=main,text="\x1a",x=6,y=24,width=1,fg_bg=style.label} + TextBox{parent=main,text="\x1a",x=6,y=25,width=1,fg_bg=style.label} + TextBox{parent=main,text="H",x=8,y=22,width=1,fg_bg=style.label} + TextBox{parent=main,text="W",x=10,y=22,width=1,fg_bg=style.label} local fuel = VerticalBar{parent=main,x=2,y=23,fg_bg=cpair(style.theme.fuel_color,colors.gray),height=4,width=1} local ccool = VerticalBar{parent=main,x=4,y=23,fg_bg=cpair(colors.blue,colors.gray),height=4,width=1} @@ -122,20 +122,20 @@ local function init(parent, id) end end) - TextBox{parent=main,x=32,y=22,text="Core Temp",height=1,width=9,fg_bg=style.label} + TextBox{parent=main,x=32,y=22,text="Core Temp",width=9,fg_bg=style.label} local fmt = util.trinary(string.len(db.temp_label) == 2, "%10.2f", "%11.2f") local core_temp = DataIndicator{parent=main,x=32,label="",format=fmt,value=0,commas=true,unit=db.temp_label,lu_colors=lu_cpair,width=13,fg_bg=s_field} core_temp.register(u_ps, "temp", function (t) core_temp.update(db.temp_convert(t)) end) - TextBox{parent=main,x=32,y=25,text="Burn Rate",height=1,width=9,fg_bg=style.label} + TextBox{parent=main,x=32,y=25,text="Burn Rate",width=9,fg_bg=style.label} local act_burn_r = DataIndicator{parent=main,x=32,label="",format="%8.2f",value=0,unit="mB/t",lu_colors=lu_cpair,width=13,fg_bg=s_field} act_burn_r.register(u_ps, "act_burn_rate", act_burn_r.update) - TextBox{parent=main,x=32,y=28,text="Damage",height=1,width=6,fg_bg=style.label} + TextBox{parent=main,x=32,y=28,text="Damage",width=6,fg_bg=style.label} local damage_p = DataIndicator{parent=main,x=32,label="",format="%11.0f",value=0,unit="%",lu_colors=lu_cpair,width=13,fg_bg=s_field} damage_p.register(u_ps, "damage", damage_p.update) - TextBox{parent=main,x=32,y=31,text="Radiation",height=1,width=21,fg_bg=style.label} + TextBox{parent=main,x=32,y=31,text="Radiation",width=21,fg_bg=style.label} local radiation = RadIndicator{parent=main,x=32,label="",format="%9.3f",lu_colors=lu_cpair,width=13,fg_bg=s_field} radiation.register(u_ps, "radiation", radiation.update) @@ -144,8 +144,8 @@ local function init(parent, id) ------------------- local u_stat = Rectangle{parent=main,border=border(1,colors.gray,true),thin=true,width=33,height=4,x=46,y=3,fg_bg=bw_fg_bg} - local stat_line_1 = TextBox{parent=u_stat,x=1,y=1,text="UNKNOWN",width=33,height=1,alignment=ALIGN.CENTER,fg_bg=bw_fg_bg} - local stat_line_2 = TextBox{parent=u_stat,x=1,y=2,text="awaiting data...",width=33,height=1,alignment=ALIGN.CENTER,fg_bg=gry_wht} + local stat_line_1 = TextBox{parent=u_stat,x=1,y=1,text="UNKNOWN",width=33,alignment=ALIGN.CENTER,fg_bg=bw_fg_bg} + local stat_line_2 = TextBox{parent=u_stat,x=1,y=2,text="awaiting data...",width=33,alignment=ALIGN.CENTER,fg_bg=gry_wht} stat_line_1.register(u_ps, "U_StatusLine1", stat_line_1.set_value) stat_line_2.register(u_ps, "U_StatusLine2", stat_line_2.set_value) @@ -205,7 +205,7 @@ local function init(parent, id) -- RPS annunciator panel - TextBox{parent=main,text="REACTOR PROTECTION SYSTEM",fg_bg=cpair(colors.black,colors.cyan),alignment=ALIGN.CENTER,width=33,height=1,x=46,y=8} + TextBox{parent=main,text="REACTOR PROTECTION SYSTEM",fg_bg=cpair(colors.black,colors.cyan),alignment=ALIGN.CENTER,width=33,x=46,y=8} local rps = Rectangle{parent=main,border=border(1,colors.cyan,true),thin=true,width=33,height=12,x=46,y=9} local rps_annunc = Div{parent=rps,width=31,height=10,x=2,y=1} @@ -233,7 +233,7 @@ local function init(parent, id) -- cooling annunciator panel - TextBox{parent=main,text="REACTOR COOLANT SYSTEM",fg_bg=cpair(colors.black,colors.blue),alignment=ALIGN.CENTER,width=33,height=1,x=46,y=22} + TextBox{parent=main,text="REACTOR COOLANT SYSTEM",fg_bg=cpair(colors.black,colors.blue),alignment=ALIGN.CENTER,width=33,x=46,y=22} local rcs = Rectangle{parent=main,border=border(1,colors.blue,true),thin=true,width=33,height=24,x=46,y=23} local rcs_annunc = Div{parent=rcs,width=27,height=22,x=3,y=1} local rcs_tags = Div{parent=rcs,width=2,height=16,x=1,y=7} @@ -265,11 +265,11 @@ local function init(parent, id) if unit.num_boilers > 0 then if available_space > 0 then _add_space() end - TextBox{parent=rcs_tags,x=1,text="B1",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,x=1,text="B1",width=2,fg_bg=hc_text} local b1_wll = IndicatorLight{parent=rcs_annunc,label="Water Level Low",colors=ind_red} b1_wll.register(b_ps[1], "WaterLevelLow", b1_wll.update) - TextBox{parent=rcs_tags,text="B1",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,text="B1",width=2,fg_bg=hc_text} local b1_hr = IndicatorLight{parent=rcs_annunc,label="Heating Rate Low",colors=ind_yel} b1_hr.register(b_ps[1], "HeatingRateLow", b1_hr.update) end @@ -281,11 +281,11 @@ local function init(parent, id) _add_space() end - TextBox{parent=rcs_tags,text="B2",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,text="B2",width=2,fg_bg=hc_text} local b2_wll = IndicatorLight{parent=rcs_annunc,label="Water Level Low",colors=ind_red} b2_wll.register(b_ps[2], "WaterLevelLow", b2_wll.update) - TextBox{parent=rcs_tags,text="B2",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,text="B2",width=2,fg_bg=hc_text} local b2_hr = IndicatorLight{parent=rcs_annunc,label="Heating Rate Low",colors=ind_yel} b2_hr.register(b_ps[2], "HeatingRateLow", b2_hr.update) end @@ -294,19 +294,19 @@ local function init(parent, id) if available_space > 1 then _add_space() end - TextBox{parent=rcs_tags,text="T1",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,text="T1",width=2,fg_bg=hc_text} local t1_sdo = TriIndicatorLight{parent=rcs_annunc,label="Steam Relief Valve Open",c1=ind_bkg,c2=ind_yel.fgd,c3=ind_red.fgd} t1_sdo.register(t_ps[1], "SteamDumpOpen", t1_sdo.update) - TextBox{parent=rcs_tags,text="T1",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,text="T1",width=2,fg_bg=hc_text} local t1_tos = IndicatorLight{parent=rcs_annunc,label="Turbine Over Speed",colors=ind_red} t1_tos.register(t_ps[1], "TurbineOverSpeed", t1_tos.update) - TextBox{parent=rcs_tags,text="T1",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,text="T1",width=2,fg_bg=hc_text} local t1_gtrp = IndicatorLight{parent=rcs_annunc,label="Generator Trip",colors=ind_yel,flash=true,period=period.BLINK_250_MS} t1_gtrp.register(t_ps[1], "GeneratorTrip", t1_gtrp.update) - TextBox{parent=rcs_tags,text="T1",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,text="T1",width=2,fg_bg=hc_text} local t1_trp = IndicatorLight{parent=rcs_annunc,label="Turbine Trip",colors=ind_red,flash=true,period=period.BLINK_250_MS} t1_trp.register(t_ps[1], "TurbineTrip", t1_trp.update) @@ -315,19 +315,19 @@ local function init(parent, id) _add_space() end - TextBox{parent=rcs_tags,text="T2",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,text="T2",width=2,fg_bg=hc_text} local t2_sdo = TriIndicatorLight{parent=rcs_annunc,label="Steam Relief Valve Open",c1=ind_bkg,c2=ind_yel.fgd,c3=ind_red.fgd} t2_sdo.register(t_ps[2], "SteamDumpOpen", t2_sdo.update) - TextBox{parent=rcs_tags,text="T2",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,text="T2",width=2,fg_bg=hc_text} local t2_tos = IndicatorLight{parent=rcs_annunc,label="Turbine Over Speed",colors=ind_red} t2_tos.register(t_ps[2], "TurbineOverSpeed", t2_tos.update) - TextBox{parent=rcs_tags,text="T2",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,text="T2",width=2,fg_bg=hc_text} local t2_gtrp = IndicatorLight{parent=rcs_annunc,label="Generator Trip",colors=ind_yel,flash=true,period=period.BLINK_250_MS} t2_gtrp.register(t_ps[2], "GeneratorTrip", t2_gtrp.update) - TextBox{parent=rcs_tags,text="T2",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,text="T2",width=2,fg_bg=hc_text} local t2_trp = IndicatorLight{parent=rcs_annunc,label="Turbine Trip",colors=ind_red,flash=true,period=period.BLINK_250_MS} t2_trp.register(t_ps[2], "TurbineTrip", t2_trp.update) end @@ -335,19 +335,19 @@ local function init(parent, id) if unit.num_turbines > 2 then if available_space > 3 then _add_space() end - TextBox{parent=rcs_tags,text="T3",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,text="T3",width=2,fg_bg=hc_text} local t3_sdo = TriIndicatorLight{parent=rcs_annunc,label="Steam Relief Valve Open",c1=ind_bkg,c2=ind_yel.fgd,c3=ind_red.fgd} t3_sdo.register(t_ps[3], "SteamDumpOpen", t3_sdo.update) - TextBox{parent=rcs_tags,text="T3",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,text="T3",width=2,fg_bg=hc_text} local t3_tos = IndicatorLight{parent=rcs_annunc,label="Turbine Over Speed",colors=ind_red} t3_tos.register(t_ps[3], "TurbineOverSpeed", t3_tos.update) - TextBox{parent=rcs_tags,text="T3",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,text="T3",width=2,fg_bg=hc_text} local t3_gtrp = IndicatorLight{parent=rcs_annunc,label="Generator Trip",colors=ind_yel,flash=true,period=period.BLINK_250_MS} t3_gtrp.register(t_ps[3], "GeneratorTrip", t3_gtrp.update) - TextBox{parent=rcs_tags,text="T3",width=2,height=1,fg_bg=hc_text} + TextBox{parent=rcs_tags,text="T3",width=2,fg_bg=hc_text} local t3_trp = IndicatorLight{parent=rcs_annunc,label="Turbine Trip",colors=ind_red,flash=true,period=period.BLINK_250_MS} t3_trp.register(t_ps[3], "TurbineTrip", t3_trp.update) end @@ -394,7 +394,7 @@ local function init(parent, id) reset.register(u_ps, "rps_tripped", function (active) if active then reset.enable() else reset.disable() end end) - TextBox{parent=main,text="WASTE PROCESSING",fg_bg=cpair(colors.black,colors.brown),alignment=ALIGN.CENTER,width=33,height=1,x=46,y=48} + TextBox{parent=main,text="WASTE PROCESSING",fg_bg=cpair(colors.black,colors.brown),alignment=ALIGN.CENTER,width=33,x=46,y=48} local waste_proc = Rectangle{parent=main,border=border(1,colors.brown,true),thin=true,width=33,height=3,x=46,y=49} local waste_div = Div{parent=waste_proc,x=2,y=1,width=31,height=1} @@ -474,15 +474,15 @@ local function init(parent, id) -- color tags - TextBox{parent=alarm_panel,x=5,y=13,text="\x95",width=1,height=1,fg_bg=cpair(s_hi_bright.bkg,colors.cyan)} - TextBox{parent=alarm_panel,x=5,text="\x95",width=1,height=1,fg_bg=cpair(s_hi_bright.bkg,colors.blue)} - TextBox{parent=alarm_panel,x=5,text="\x95",width=1,height=1,fg_bg=cpair(s_hi_bright.bkg,colors.blue)} + TextBox{parent=alarm_panel,x=5,y=13,text="\x95",width=1,fg_bg=cpair(s_hi_bright.bkg,colors.cyan)} + TextBox{parent=alarm_panel,x=5,text="\x95",width=1,fg_bg=cpair(s_hi_bright.bkg,colors.blue)} + TextBox{parent=alarm_panel,x=5,text="\x95",width=1,fg_bg=cpair(s_hi_bright.bkg,colors.blue)} -------------------------------- -- automatic control settings -- -------------------------------- - TextBox{parent=main,text="AUTO CTRL",fg_bg=cpair(colors.black,colors.purple),alignment=ALIGN.CENTER,width=13,height=1,x=32,y=36} + TextBox{parent=main,text="AUTO CTRL",fg_bg=cpair(colors.black,colors.purple),alignment=ALIGN.CENTER,width=13,x=32,y=36} local auto_ctl = Rectangle{parent=main,border=border(1,colors.purple,true),thin=true,width=13,height=15,x=32,y=37} local auto_div = Div{parent=auto_ctl,width=13,height=15,x=1,y=1} @@ -499,8 +499,8 @@ local function init(parent, id) auto_div.line_break() - TextBox{parent=auto_div,text="Prio. Group",height=1,width=11,fg_bg=style.label} - local auto_grp = TextBox{parent=auto_div,text="Manual",height=1,width=11,fg_bg=s_field} + TextBox{parent=auto_div,text="Prio. Group",width=11,fg_bg=style.label} + local auto_grp = TextBox{parent=auto_div,text="Manual",width=11,fg_bg=s_field} auto_grp.register(u_ps, "auto_group", auto_grp.set_value) diff --git a/coordinator/ui/components/unit_flow.lua b/coordinator/ui/components/unit_flow.lua index 39c2c002..9ba29bef 100644 --- a/coordinator/ui/components/unit_flow.lua +++ b/coordinator/ui/components/unit_flow.lua @@ -73,10 +73,10 @@ local function make(parent, x, y, wide, unit) ------------------ local reactor = Rectangle{parent=root,x=1,y=1,border=border(1,colors.gray,true),width=19,height=5,fg_bg=wh_gray} - TextBox{parent=reactor,y=1,text="FISSION REACTOR",alignment=ALIGN.CENTER,height=1} - TextBox{parent=reactor,y=3,text="UNIT #"..unit.unit_id,alignment=ALIGN.CENTER,height=1} + TextBox{parent=reactor,y=1,text="FISSION REACTOR",alignment=ALIGN.CENTER} + TextBox{parent=reactor,y=3,text="UNIT #"..unit.unit_id,alignment=ALIGN.CENTER} TextBox{parent=root,x=19,y=2,text="\x1b \x80 \x1a",width=1,height=3,fg_bg=lg_gray} - TextBox{parent=root,x=3,y=5,text="\x19",width=1,height=1,fg_bg=lg_gray} + TextBox{parent=root,x=3,y=5,text="\x19",width=1,fg_bg=lg_gray} local rc_pipes = {} @@ -113,8 +113,8 @@ local function make(parent, x, y, wide, unit) hc_rate.register(unit.unit_ps, "heating_rate", hc_rate.update) local boiler = Rectangle{parent=root,x=_wide(47,40),y=1,border=border(1,colors.gray,true),width=19,height=5,fg_bg=wh_gray} - TextBox{parent=boiler,y=1,text="THERMO-ELECTRIC",alignment=ALIGN.CENTER,height=1} - TextBox{parent=boiler,y=3,text=util.trinary(unit.num_boilers>1,"BOILERS","BOILER"),alignment=ALIGN.CENTER,height=1} + TextBox{parent=boiler,y=1,text="THERMO-ELECTRIC",alignment=ALIGN.CENTER} + TextBox{parent=boiler,y=3,text=util.trinary(unit.num_boilers>1,"BOILERS","BOILER"),alignment=ALIGN.CENTER} TextBox{parent=root,x=_wide(47,40),y=2,text="\x1b \x80 \x1a",width=1,height=3,fg_bg=lg_gray} TextBox{parent=root,x=_wide(65,58),y=2,text="\x1b \x80 \x1a",width=1,height=3,fg_bg=lg_gray} @@ -132,13 +132,13 @@ local function make(parent, x, y, wide, unit) end local turbine = Rectangle{parent=root,x=_wide(93,79),y=1,border=border(1,colors.gray,true),width=19,height=5,fg_bg=wh_gray} - TextBox{parent=turbine,y=1,text="STEAM TURBINE",alignment=ALIGN.CENTER,height=1} - TextBox{parent=turbine,y=3,text=util.trinary(unit.num_turbines>1,"GENERATORS","GENERATOR"),alignment=ALIGN.CENTER,height=1} + TextBox{parent=turbine,y=1,text="STEAM TURBINE",alignment=ALIGN.CENTER} + TextBox{parent=turbine,y=3,text=util.trinary(unit.num_turbines>1,"GENERATORS","GENERATOR"),alignment=ALIGN.CENTER} TextBox{parent=root,x=_wide(93,79),y=2,text="\x1b \x80 \x1a",width=1,height=3,fg_bg=lg_gray} for i = 1, unit.num_turbines do local ry = 1 + (2 * (i - 1)) + prv_yo - TextBox{parent=root,x=_wide(125,103),y=ry,text="\x10\x11\x7f",fg_bg=text_c,width=3,height=1} + TextBox{parent=root,x=_wide(125,103),y=ry,text="\x10\x11\x7f",fg_bg=text_c,width=3} local state = TriIndicatorLight{parent=root,x=_wide(129,107),y=ry,label=v_names[i+4],c1=style.ind_bkg,c2=style.ind_yel.fgd,c3=style.ind_red.fgd} state.register(unit.turbine_ps_tbl[i], "SteamDumpOpen", state.update) end @@ -172,7 +172,7 @@ local function make(parent, x, y, wide, unit) PipeNetwork{parent=waste,x=1,y=1,pipes=waste_pipes,bg=style.theme.bg} local function _valve(vx, vy, n) - TextBox{parent=waste,x=vx,y=vy,text="\x10\x11",fg_bg=text_c,width=2,height=1} + TextBox{parent=waste,x=vx,y=vy,text="\x10\x11",fg_bg=text_c,width=2} local conn = IndicatorLight{parent=waste,x=vx-3,y=vy+1,label=v_names[n],colors=ind_grn} local open = IndicatorLight{parent=waste,x=vx-3,y=vy+2,label="OPEN",colors=ind_wht} conn.register(unit.unit_ps, util.c("V_", v_fields[n], "_conn"), conn.update) @@ -181,8 +181,8 @@ local function make(parent, x, y, wide, unit) local function _machine(mx, my, name) local l = string.len(name) + 2 - TextBox{parent=waste,x=mx,y=my,text=string.rep("\x8f",l),alignment=ALIGN.CENTER,fg_bg=cpair(style.theme.bg,style.theme.header.bkg),width=l,height=1} - TextBox{parent=waste,x=mx,y=my+1,text=name,alignment=ALIGN.CENTER,fg_bg=style.theme.header,width=l,height=1} + TextBox{parent=waste,x=mx,y=my,text=string.rep("\x8f",l),alignment=ALIGN.CENTER,fg_bg=cpair(style.theme.bg,style.theme.header.bkg),width=l} + TextBox{parent=waste,x=mx,y=my+1,text=name,alignment=ALIGN.CENTER,fg_bg=style.theme.header,width=l} end local waste_rate = DataIndicator{parent=waste,x=1,y=3,lu_colors=lu_c,label="",unit="mB/t",format="%7.2f",value=0,width=12,fg_bg=s_field} @@ -209,7 +209,7 @@ local function make(parent, x, y, wide, unit) _machine(_wide(97, 83), 4, "PRC [Po] \x1a"); _machine(_wide(116, 94), 6, "SPENT WASTE \x1b") - TextBox{parent=waste,x=_wide(30,25),y=3,text="SNAs [Po]",alignment=ALIGN.CENTER,width=19,height=1,fg_bg=wh_gray} + TextBox{parent=waste,x=_wide(30,25),y=3,text="SNAs [Po]",alignment=ALIGN.CENTER,width=19,fg_bg=wh_gray} local sna_po = Rectangle{parent=waste,x=_wide(30,25),y=4,border=border(1,colors.gray,true),width=19,height=7,thin=true,fg_bg=style.theme.highlight_box_bright} local sna_act = IndicatorLight{parent=sna_po,label="ACTIVE",colors=ind_grn} local sna_cnt = DataIndicator{parent=sna_po,x=12,y=1,lu_colors=lu_c_d,label="CNT",unit="",format="%2d",value=0,width=7} diff --git a/coordinator/ui/components/unit_overview.lua b/coordinator/ui/components/unit_overview.lua index 80e99e9c..fc4ac4ee 100644 --- a/coordinator/ui/components/unit_overview.lua +++ b/coordinator/ui/components/unit_overview.lua @@ -44,7 +44,7 @@ local function make(parent, x, y, unit) local root = Div{parent=parent,x=x,y=y,width=80,height=height} -- unit header message - TextBox{parent=root,text="Unit #"..unit.unit_id,alignment=ALIGN.CENTER,height=1,fg_bg=style.theme.header} + TextBox{parent=root,text="Unit #"..unit.unit_id,alignment=ALIGN.CENTER,fg_bg=style.theme.header} ------------- -- REACTOR -- diff --git a/coordinator/ui/layout/flow_view.lua b/coordinator/ui/layout/flow_view.lua index 06edf27b..7a7f57d3 100644 --- a/coordinator/ui/layout/flow_view.lua +++ b/coordinator/ui/layout/flow_view.lua @@ -49,9 +49,9 @@ local function init(main) local tank_list = facility.tank_list -- window header message - local header = TextBox{parent=main,y=1,text="Facility Coolant and Waste Flow Monitor",alignment=ALIGN.CENTER,height=1,fg_bg=style.theme.header} + local header = TextBox{parent=main,y=1,text="Facility Coolant and Waste Flow Monitor",alignment=ALIGN.CENTER,fg_bg=style.theme.header} -- max length example: "01:23:45 AM - Wednesday, September 28 2022" - local datetime = TextBox{parent=main,x=(header.get_width()-42),y=1,text="",alignment=ALIGN.RIGHT,width=42,height=1,fg_bg=style.theme.header} + local datetime = TextBox{parent=main,x=(header.get_width()-42),y=1,text="",alignment=ALIGN.RIGHT,width=42,fg_bg=style.theme.header} datetime.register(facility.ps, "date_time", datetime.set_value) @@ -265,7 +265,7 @@ local function init(main) if tank_defs[i] > 0 then local vy = 3 + y_ofs(i) - TextBox{parent=main,x=12,y=vy,text="\x10\x11",fg_bg=text_col,width=2,height=1} + TextBox{parent=main,x=12,y=vy,text="\x10\x11",fg_bg=text_col,width=2} local conn = IndicatorLight{parent=main,x=9,y=vy+1,label=util.sprintf("PV%02d-EMC", i * 5),colors=style.ind_grn} local open = IndicatorLight{parent=main,x=9,y=vy+2,label="OPEN",colors=style.ind_wht} @@ -292,21 +292,21 @@ local function init(main) local tank = Div{parent=main,x=3,y=7+y_offset,width=20,height=14} - TextBox{parent=tank,text=" ",height=1,x=1,y=1,fg_bg=style.lg_gray} - TextBox{parent=tank,text="DYNAMIC TANK "..id,alignment=ALIGN.CENTER,height=1,fg_bg=style.wh_gray} + TextBox{parent=tank,text=" ",x=1,y=1,fg_bg=style.lg_gray} + TextBox{parent=tank,text="DYNAMIC TANK "..id,alignment=ALIGN.CENTER,fg_bg=style.wh_gray} local tank_box = Rectangle{parent=tank,border=border(1,colors.gray,true),width=20,height=12} local status = StateIndicator{parent=tank_box,x=3,y=1,states=style.dtank.states,value=1,min_width=14} - TextBox{parent=tank_box,x=2,y=3,text="Fill",height=1,width=10,fg_bg=style.label} + TextBox{parent=tank_box,x=2,y=3,text="Fill",width=10,fg_bg=style.label} local tank_pcnt = DataIndicator{parent=tank_box,x=10,y=3,label="",format="%5.2f",value=100,unit="%",lu_colors=lu_col,width=8,fg_bg=text_col} local tank_amnt = DataIndicator{parent=tank_box,x=2,label="",format="%13d",value=0,commas=true,unit="mB",lu_colors=lu_col,width=16,fg_bg=s_field} - TextBox{parent=tank_box,x=2,y=6,text="Water Level",height=1,width=11,fg_bg=style.label} + TextBox{parent=tank_box,x=2,y=6,text="Water Level",width=11,fg_bg=style.label} local level = HorizontalBar{parent=tank_box,x=2,y=7,bar_fg_bg=cpair(colors.blue,colors.gray),height=1,width=16} - TextBox{parent=tank_box,x=2,y=9,text="In/Out Mode",height=1,width=11,fg_bg=style.label} + TextBox{parent=tank_box,x=2,y=9,text="In/Out Mode",width=11,fg_bg=style.label} local can_fill = IndicatorLight{parent=tank_box,x=2,y=10,label="FILL",colors=style.ind_wht} local can_empty = IndicatorLight{parent=tank_box,x=10,y=10,label="EMPTY",colors=style.ind_wht} @@ -344,8 +344,8 @@ local function init(main) local sps = Div{parent=main,x=140,y=3,height=12} - TextBox{parent=sps,text=" ",width=24,height=1,x=1,y=1,fg_bg=style.lg_gray} - TextBox{parent=sps,text="SPS",alignment=ALIGN.CENTER,width=24,height=1,fg_bg=wh_gray} + TextBox{parent=sps,text=" ",width=24,x=1,y=1,fg_bg=style.lg_gray} + TextBox{parent=sps,text="SPS",alignment=ALIGN.CENTER,width=24,fg_bg=wh_gray} local sps_box = Rectangle{parent=sps,border=border(1,colors.gray,true),width=24,height=10} @@ -353,12 +353,12 @@ local function init(main) status.register(facility.sps_ps_tbl[1], "computed_status", status.update) - TextBox{parent=sps_box,x=2,y=3,text="Input Rate",height=1,width=10,fg_bg=style.label} + TextBox{parent=sps_box,x=2,y=3,text="Input Rate",width=10,fg_bg=style.label} local sps_in = DataIndicator{parent=sps_box,x=2,label="",format="%15.2f",value=0,unit="mB/t",lu_colors=lu_col,width=20,fg_bg=s_field} sps_in.register(facility.ps, "po_am_rate", sps_in.update) - TextBox{parent=sps_box,x=2,y=6,text="Production Rate",height=1,width=15,fg_bg=style.label} + TextBox{parent=sps_box,x=2,y=6,text="Production Rate",width=15,fg_bg=style.label} local sps_rate = DataIndicator{parent=sps_box,x=2,label="",format="%15d",value=0,unit="\xb5B/t",lu_colors=lu_col,width=20,fg_bg=s_field} sps_rate.register(facility.sps_ps_tbl[1], "process_rate", function (r) sps_rate.update(r * 1000) end) @@ -367,13 +367,13 @@ local function init(main) -- statistics -- ---------------- - TextBox{parent=main,x=145,y=16,text="RAW WASTE",alignment=ALIGN.CENTER,width=19,height=1,fg_bg=wh_gray} + TextBox{parent=main,x=145,y=16,text="RAW WASTE",alignment=ALIGN.CENTER,width=19,fg_bg=wh_gray} local raw_waste = Rectangle{parent=main,x=145,y=17,border=border(1,colors.gray,true),width=19,height=3,thin=true,fg_bg=s_hi_bright} local sum_raw_waste = DataIndicator{parent=raw_waste,lu_colors=lu_c_d,label="SUM",unit="mB/t",format="%8.2f",value=0,width=17} sum_raw_waste.register(facility.ps, "burn_sum", sum_raw_waste.update) - TextBox{parent=main,x=145,y=21,text="PROC. WASTE",alignment=ALIGN.CENTER,width=19,height=1,fg_bg=wh_gray} + TextBox{parent=main,x=145,y=21,text="PROC. WASTE",alignment=ALIGN.CENTER,width=19,fg_bg=wh_gray} local pr_waste = Rectangle{parent=main,x=145,y=22,border=border(1,colors.gray,true),width=19,height=5,thin=true,fg_bg=s_hi_bright} local pu = DataIndicator{parent=pr_waste,lu_colors=lu_c_d,label="Pu",unit="mB/t",format="%9.3f",value=0,width=17} local po = DataIndicator{parent=pr_waste,lu_colors=lu_c_d,label="Po",unit="mB/t",format="%9.2f",value=0,width=17} @@ -383,7 +383,7 @@ local function init(main) po.register(facility.ps, "po_rate", po.update) popl.register(facility.ps, "po_pl_rate", popl.update) - TextBox{parent=main,x=145,y=28,text="SPENT WASTE",alignment=ALIGN.CENTER,width=19,height=1,fg_bg=wh_gray} + TextBox{parent=main,x=145,y=28,text="SPENT WASTE",alignment=ALIGN.CENTER,width=19,fg_bg=wh_gray} local sp_waste = Rectangle{parent=main,x=145,y=29,border=border(1,colors.gray,true),width=19,height=3,thin=true,fg_bg=s_hi_bright} local sum_sp_waste = DataIndicator{parent=sp_waste,lu_colors=lu_c_d,label="SUM",unit="mB/t",format="%8.3f",value=0,width=17} diff --git a/coordinator/ui/layout/front_panel.lua b/coordinator/ui/layout/front_panel.lua index 7f2738a1..4a87b058 100644 --- a/coordinator/ui/layout/front_panel.lua +++ b/coordinator/ui/layout/front_panel.lua @@ -39,7 +39,7 @@ local led_grn = style.led_grn local function init(panel, num_units) local ps = iocontrol.get_db().fp.ps - TextBox{parent=panel,y=1,text="SCADA COORDINATOR",alignment=ALIGN.CENTER,height=1,fg_bg=style.fp_theme.header} + TextBox{parent=panel,y=1,text="SCADA COORDINATOR",alignment=ALIGN.CENTER,fg_bg=style.fp_theme.header} local page_div = Div{parent=panel,x=1,y=3} @@ -110,7 +110,7 @@ local function init(panel, num_units) ---@diagnostic disable-next-line: undefined-field local comp_id = util.sprintf("(%d)", os.getComputerID()) - TextBox{parent=system,x=9,y=4,width=6,height=1,text=comp_id,fg_bg=style.fp.disabled_fg} + TextBox{parent=system,x=9,y=4,width=6,text=comp_id,fg_bg=style.fp.disabled_fg} local monitors = Div{parent=main_page,width=16,height=17,x=18,y=2} @@ -132,8 +132,8 @@ local function init(panel, num_units) -- local about = Div{parent=main_page,width=15,height=3,x=1,y=16,fg_bg=style.fp.disabled_fg} - local fw_v = TextBox{parent=about,x=1,y=1,text="FW: v00.00.00",alignment=ALIGN.LEFT,height=1} - local comms_v = TextBox{parent=about,x=1,y=2,text="NT: v00.00.00",alignment=ALIGN.LEFT,height=1} + local fw_v = TextBox{parent=about,x=1,y=1,text="FW: v00.00.00",alignment=ALIGN.LEFT} + local comms_v = TextBox{parent=about,x=1,y=2,text="NT: v00.00.00",alignment=ALIGN.LEFT} fw_v.register(ps, "version", function (version) fw_v.set_value(util.c("FW: ", version)) end) comms_v.register(ps, "comms_version", function (version) comms_v.set_value(util.c("NT: v", version)) end) diff --git a/coordinator/ui/layout/main_view.lua b/coordinator/ui/layout/main_view.lua index 53431390..33ed43cc 100644 --- a/coordinator/ui/layout/main_view.lua +++ b/coordinator/ui/layout/main_view.lua @@ -29,10 +29,10 @@ local function init(main) local units = iocontrol.get_db().units -- window header message - local header = TextBox{parent=main,y=1,text="Nuclear Generation Facility SCADA Coordinator",alignment=ALIGN.CENTER,height=1,fg_bg=s_header} + local header = TextBox{parent=main,y=1,text="Nuclear Generation Facility SCADA Coordinator",alignment=ALIGN.CENTER,fg_bg=s_header} local ping = DataIndicator{parent=main,x=1,y=1,label="SVTT",format="%d",value=0,unit="ms",lu_colors=style.lg_white,width=12,fg_bg=s_header} -- max length example: "01:23:45 AM - Wednesday, September 28 2022" - local datetime = TextBox{parent=main,x=(header.get_width()-42),y=1,text="",alignment=ALIGN.RIGHT,width=42,height=1,fg_bg=s_header} + local datetime = TextBox{parent=main,x=(header.get_width()-42),y=1,text="",alignment=ALIGN.RIGHT,width=42,fg_bg=s_header} ping.register(facility.ps, "sv_ping", ping.update) datetime.register(facility.ps, "date_time", datetime.set_value) @@ -79,7 +79,7 @@ local function init(main) assert(cnc_bottom_align_start >= cnc_y_start, "main display not of sufficient vertical resolution (add an additional row of monitors)") - TextBox{parent=main,y=cnc_bottom_align_start,text=string.rep("\x8c", header.get_width()),alignment=ALIGN.CENTER,height=1,fg_bg=style.lg_gray} + TextBox{parent=main,y=cnc_bottom_align_start,text=string.rep("\x8c", header.get_width()),alignment=ALIGN.CENTER,fg_bg=style.lg_gray} cnc_bottom_align_start = cnc_bottom_align_start + 2 diff --git a/pocket/configure.lua b/pocket/configure.lua index d16309c3..2d2f446c 100644 --- a/pocket/configure.lua +++ b/pocket/configure.lua @@ -125,7 +125,7 @@ local function config_view(display) ---@diagnostic disable-next-line: undefined-field local function exit() os.queueEvent("terminate") end - TextBox{parent=display,y=1,text="Pocket Configurator",alignment=CENTER,height=1,fg_bg=style.header} + TextBox{parent=display,y=1,text="Pocket Configurator",alignment=CENTER,fg_bg=style.header} local root_pane_div = Div{parent=display,x=1,y=2} @@ -173,11 +173,11 @@ local function config_view(display) local ui_c_1 = Div{parent=ui_cfg,x=2,y=4,width=24} - TextBox{parent=ui_cfg,x=1,y=2,height=1,text=" Pocket UI",fg_bg=cpair(colors.black,colors.lime)} + TextBox{parent=ui_cfg,x=1,y=2,text=" Pocket UI",fg_bg=cpair(colors.black,colors.lime)} TextBox{parent=ui_c_1,x=1,y=1,height=3,text="You may use the options below to customize formats."} - TextBox{parent=ui_c_1,x=1,y=5,height=1,text="Temperature Scale"} + TextBox{parent=ui_c_1,x=1,y=5,text="Temperature Scale"} local temp_scale = RadioButton{parent=ui_c_1,x=1,y=6,default=ini_cfg.TempScale,options=types.TEMP_SCALE_NAMES,callback=function()end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.lime} local function submit_ui_opts() @@ -199,24 +199,24 @@ local function config_view(display) local net_pane = MultiPane{parent=net_cfg,x=1,y=4,panes={net_c_1,net_c_2,net_c_3,net_c_4}} - TextBox{parent=net_cfg,x=1,y=2,height=1,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)} + TextBox{parent=net_cfg,x=1,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)} - TextBox{parent=net_c_1,x=1,y=1,height=1,text="Set network channels."} + TextBox{parent=net_c_1,x=1,y=1,text="Set network channels."} TextBox{parent=net_c_1,x=1,y=3,height=4,text="Each of the named channels must be the same within a particular SCADA network.",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_1,x=1,y=8,height=1,width=18,text="Supervisor Channel"} + TextBox{parent=net_c_1,x=1,y=8,width=18,text="Supervisor Channel"} local svr_chan = NumberField{parent=net_c_1,x=1,y=9,width=7,default=ini_cfg.SVR_Channel,min=1,max=65535,fg_bg=bw_fg_bg} TextBox{parent=net_c_1,x=9,y=9,height=4,text="[SVR_CHANNEL]",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_1,x=1,y=10,height=1,width=19,text="Coordinator Channel"} + TextBox{parent=net_c_1,x=1,y=10,width=19,text="Coordinator Channel"} local crd_chan = NumberField{parent=net_c_1,x=1,y=11,width=7,default=ini_cfg.CRD_Channel,min=1,max=65535,fg_bg=bw_fg_bg} TextBox{parent=net_c_1,x=9,y=11,height=4,text="[CRD_CHANNEL]",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_1,x=1,y=12,height=1,width=14,text="Pocket Channel"} + TextBox{parent=net_c_1,x=1,y=12,width=14,text="Pocket Channel"} local pkt_chan = NumberField{parent=net_c_1,x=1,y=13,width=7,default=ini_cfg.PKT_Channel,min=1,max=65535,fg_bg=bw_fg_bg} TextBox{parent=net_c_1,x=9,y=13,height=4,text="[PKT_CHANNEL]",fg_bg=g_lg_fg_bg} - local chan_err = TextBox{parent=net_c_1,x=1,y=14,height=1,width=24,text="Please set all channels.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local chan_err = TextBox{parent=net_c_1,x=1,y=14,width=24,text="Please set all channels.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_channels() local svr_c, crd_c, pkt_c = tonumber(svr_chan.get_value()), tonumber(crd_chan.get_value()), tonumber(pkt_chan.get_value()) @@ -230,15 +230,15 @@ local function config_view(display) PushButton{parent=net_c_1,x=1,y=15,text="\x1b Back",callback=function()main_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=net_c_1,x=19,y=15,text="Next \x1a",callback=submit_channels,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - TextBox{parent=net_c_2,x=1,y=1,height=1,text="Set connection timeout."} + TextBox{parent=net_c_2,x=1,y=1,text="Set connection timeout."} TextBox{parent=net_c_2,x=1,y=3,height=7,text="You generally should not need to modify this. On slow servers, you can try to increase this to make the system wait longer before assuming a disconnection.",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_2,x=1,y=11,height=1,width=19,text="Connection Timeout"} + TextBox{parent=net_c_2,x=1,y=11,width=19,text="Connection Timeout"} local timeout = NumberField{parent=net_c_2,x=1,y=12,width=7,default=ini_cfg.ConnTimeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg} TextBox{parent=net_c_2,x=9,y=12,height=2,text="seconds\n(default 5)",fg_bg=g_lg_fg_bg} - local ct_err = TextBox{parent=net_c_2,x=1,y=14,height=1,width=24,text="Please set timeout.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local ct_err = TextBox{parent=net_c_2,x=1,y=14,width=24,text="Please set timeout.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_timeouts() local timeout_val = tonumber(timeout.get_value()) @@ -252,13 +252,13 @@ local function config_view(display) PushButton{parent=net_c_2,x=1,y=15,text="\x1b Back",callback=function()net_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=net_c_2,x=19,y=15,text="Next \x1a",callback=submit_timeouts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - TextBox{parent=net_c_3,x=1,y=1,height=1,text="Set the trusted range."} + TextBox{parent=net_c_3,x=1,y=1,text="Set the trusted range."} TextBox{parent=net_c_3,x=1,y=3,height=4,text="Setting this to a value larger than 0 prevents connections with devices that many blocks away.",fg_bg=g_lg_fg_bg} TextBox{parent=net_c_3,x=1,y=8,height=4,text="This is optional. You can disable this functionality by setting the value to 0.",fg_bg=g_lg_fg_bg} local range = NumberField{parent=net_c_3,x=1,y=13,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg} - local tr_err = TextBox{parent=net_c_3,x=1,y=14,height=1,width=24,text="Set the trusted range.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local tr_err = TextBox{parent=net_c_3,x=1,y=14,width=24,text="Set the trusted range.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_tr() local range_val = tonumber(range.get_value()) @@ -275,7 +275,7 @@ local function config_view(display) TextBox{parent=net_c_4,x=1,y=1,height=4,text="Optionally, set the facility authentication key. Do NOT use one of your passwords."} TextBox{parent=net_c_4,x=1,y=6,height=6,text="This enables verifying that messages are authentic, so it is intended for security on multiplayer servers.",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_4,x=1,y=12,height=1,text="Facility Auth Key"} + TextBox{parent=net_c_4,x=1,y=12,text="Facility Auth Key"} local key, _, censor = TextField{parent=net_c_4,x=1,y=13,max_len=64,value=ini_cfg.AuthKey,width=24,height=1,fg_bg=bw_fg_bg} local function censor_key(enable) censor(util.trinary(enable, "*", nil)) end @@ -288,7 +288,7 @@ local function config_view(display) hide_key.set_value(true) censor_key(true) - local key_err = TextBox{parent=net_c_4,x=1,y=14,height=1,width=24,text="Length must be > 7.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local key_err = TextBox{parent=net_c_4,x=1,y=14,width=24,text="Length must be > 7.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_auth() local v = key.get_value() @@ -307,20 +307,20 @@ local function config_view(display) local log_c_1 = Div{parent=log_cfg,x=2,y=4,width=24} - TextBox{parent=log_cfg,x=1,y=2,height=1,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)} + TextBox{parent=log_cfg,x=1,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)} - TextBox{parent=log_c_1,x=1,y=1,height=1,text="Configure logging below."} + TextBox{parent=log_c_1,x=1,y=1,text="Configure logging below."} - TextBox{parent=log_c_1,x=1,y=3,height=1,text="Log File Mode"} + TextBox{parent=log_c_1,x=1,y=3,text="Log File Mode"} local mode = RadioButton{parent=log_c_1,x=1,y=4,default=ini_cfg.LogMode+1,options={"Append on Startup","Replace on Startup"},callback=function()end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.pink} - TextBox{parent=log_c_1,x=1,y=7,height=1,text="Log File Path"} + TextBox{parent=log_c_1,x=1,y=7,text="Log File Path"} local path = TextField{parent=log_c_1,x=1,y=8,width=24,height=1,value=ini_cfg.LogPath,max_len=128,fg_bg=bw_fg_bg} local en_dbg = CheckBox{parent=log_c_1,x=1,y=10,default=ini_cfg.LogDebug,label="Enable Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)} TextBox{parent=log_c_1,x=3,y=11,height=4,text="This results in much larger log files. Use only as needed.",fg_bg=g_lg_fg_bg} - local path_err = TextBox{parent=log_c_1,x=1,y=14,height=1,width=24,text="Provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local path_err = TextBox{parent=log_c_1,x=1,y=14,width=24,text="Provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_log() if path.get_value() ~= "" then @@ -350,7 +350,7 @@ local function config_view(display) local sum_pane = MultiPane{parent=summary,x=1,y=4,panes={sum_c_1,sum_c_2,sum_c_3,sum_c_4}} - TextBox{parent=summary,x=1,y=2,height=1,text=" Summary",fg_bg=cpair(colors.black,colors.green)} + TextBox{parent=summary,x=1,y=2,text=" Summary",fg_bg=cpair(colors.black,colors.green)} local setting_list = ListBox{parent=sum_c_1,x=1,y=1,height=11,width=24,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} @@ -405,7 +405,7 @@ local function config_view(display) tool_ctl.show_key_btn = PushButton{parent=sum_c_1,x=1,y=13,min_width=17,text="Unhide Auth Key",callback=function()tool_ctl.show_auth_key()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=dis_fg_bg} tool_ctl.settings_apply = PushButton{parent=sum_c_1,x=18,y=15,min_width=7,text="Apply",callback=save_and_continue,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg} - TextBox{parent=sum_c_2,x=1,y=1,height=1,text="Settings saved!"} + TextBox{parent=sum_c_2,x=1,y=1,text="Settings saved!"} local function go_home() main_pane.set_value(1) @@ -436,15 +436,15 @@ local function config_view(display) local cl = Div{parent=changelog,x=2,y=4,width=24} - TextBox{parent=changelog,x=1,y=2,height=1,text=" Config Change Log",fg_bg=bw_fg_bg} + TextBox{parent=changelog,x=1,y=2,text=" Config Change Log",fg_bg=bw_fg_bg} local c_log = ListBox{parent=cl,x=1,y=1,height=13,width=24,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} for _, change in ipairs(changes) do - TextBox{parent=c_log,text=change[1],height=1,fg_bg=bw_fg_bg} + TextBox{parent=c_log,text=change[1],fg_bg=bw_fg_bg} for _, v in ipairs(change[2]) do local e = Div{parent=c_log,height=#util.strwrap(v,21)} - TextBox{parent=e,y=1,x=1,text="- ",height=1,fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=e,y=1,x=1,text="- ",fg_bg=cpair(colors.gray,colors.white)} TextBox{parent=e,y=1,x=3,text=v,height=e.get_height(),fg_bg=cpair(colors.gray,colors.white)} end end diff --git a/pocket/ui/apps/diag_apps.lua b/pocket/ui/apps/diag_apps.lua index 27ef837f..79b3c127 100644 --- a/pocket/ui/apps/diag_apps.lua +++ b/pocket/ui/apps/diag_apps.lua @@ -46,13 +46,13 @@ local function create_pages(root) local audio = Div{parent=alarm_test,x=1,y=1} - TextBox{parent=audio,y=1,text="Alarm Sounder Tests",height=1,alignment=ALIGN.CENTER} + TextBox{parent=audio,y=1,text="Alarm Sounder Tests",alignment=ALIGN.CENTER} - ttest.ready_warn = TextBox{parent=audio,y=2,text="",height=1,alignment=ALIGN.CENTER,fg_bg=cpair(colors.yellow,colors.black)} + 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",height=1,alignment=ALIGN.CENTER,fg_bg=audio.get_fg_bg()} + 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} @@ -75,7 +75,7 @@ local function create_pages(root) local alarms = Div{parent=audio,x=11,y=3,height=15,fg_bg=cpair(colors.lightGray,colors.black)} - TextBox{parent=alarms,text="Alarms (\x13)",height=1,alignment=ALIGN.CENTER,fg_bg=audio.get_fg_bg()} + 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} @@ -102,7 +102,7 @@ local function create_pages(root) local states = Div{parent=audio,x=2,y=14,height=5,width=8} - TextBox{parent=states,text="States",height=1,alignment=ALIGN.CENTER} + 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} diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index b1748058..11f69fcc 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -46,7 +46,7 @@ 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...",height=1,alignment=ALIGN.CENTER} + 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)} local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}} @@ -93,7 +93,7 @@ local function new_view(root) ---@class _guide_section_constructor_data local sect_construct_data = { app, page_div, panes, doc_map, search_db, btn_fg_bg, btn_active } - TextBox{parent=home,y=1,text="cc-mek-scada Guide",height=1,alignment=ALIGN.CENTER} + TextBox{parent=home,y=1,text="cc-mek-scada Guide",alignment=ALIGN.CENTER} PushButton{parent=home,y=3,text="Search >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=search_page.nav_to} PushButton{parent=home,y=5,text="System Usage >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=use_page.nav_to} @@ -101,7 +101,7 @@ local function new_view(root) PushButton{parent=home,text="Front Panels >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=fps_page.nav_to} PushButton{parent=home,text="Glossary >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=gls_page.nav_to} - TextBox{parent=search,y=1,text="Search",height=1,alignment=ALIGN.CENTER} + 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)} @@ -159,7 +159,7 @@ local function new_view(root) util.nop() - TextBox{parent=use,y=1,text="System Usage",height=1,alignment=ALIGN.CENTER} + 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} 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() @@ -168,7 +168,7 @@ 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() - TextBox{parent=uis,y=1,text="Operator UIs",height=1,alignment=ALIGN.CENTER} + 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} local annunc_page = app.new_page(uis_page, #panes + 1) @@ -182,7 +182,7 @@ local function new_view(root) 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",height=1,alignment=ALIGN.CENTER} + 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 unit_gen_page = guide_section(sect_construct_data, annunc_page, "Unit General", docs.annunc.unit.main_section, 170) @@ -195,7 +195,7 @@ local function new_view(root) PushButton{parent=annunc_div,text="Facility General >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() 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=fps,y=1,text="Front Panels",height=1,alignment=ALIGN.CENTER} + 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} PushButton{parent=fps,y=3,text="Common Items >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() @@ -204,7 +204,7 @@ local function new_view(root) PushButton{parent=fps,text="Supervisor >",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,dis_fg_bg=btn_disable,callback=function()end}.disable() - TextBox{parent=gls,y=1,text="Glossary",height=1,alignment=ALIGN.CENTER} + 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} local gls_abbv_page = guide_section(sect_construct_data, gls_page, "Abbreviations", docs.glossary.abbvs, 120) diff --git a/pocket/ui/apps/sys_apps.lua b/pocket/ui/apps/sys_apps.lua index 85f8ee0f..e5fecd61 100644 --- a/pocket/ui/apps/sys_apps.lua +++ b/pocket/ui/apps/sys_apps.lua @@ -44,7 +44,7 @@ local function create_pages(root) local about = Div{parent=about_root,x=1,y=2} - TextBox{parent=about,y=1,text="System Information",height=1,alignment=ALIGN.CENTER} + TextBox{parent=about,y=1,text="System Information",alignment=ALIGN.CENTER} local btn_fg_bg = cpair(colors.lightBlue, colors.black) local btn_active = cpair(colors.white, colors.black) @@ -59,36 +59,36 @@ local function create_pages(root) local config = pocket.config local nt_div = Div{parent=about_root,x=1,y=2} - TextBox{parent=nt_div,y=1,text="Network Details",height=1,alignment=ALIGN.CENTER} + 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} - TextBox{parent=nt_div,x=2,y=3,text="Pocket Address",height=1,alignment=ALIGN.LEFT,fg_bg=label} + TextBox{parent=nt_div,x=2,y=3,text="Pocket Address",alignment=ALIGN.LEFT,fg_bg=label} ---@diagnostic disable-next-line: undefined-field - TextBox{parent=nt_div,x=2,text=util.c(os.getComputerID(),":",config.PKT_Channel),height=1,alignment=ALIGN.LEFT} + TextBox{parent=nt_div,x=2,text=util.c(os.getComputerID(),":",config.PKT_Channel),alignment=ALIGN.LEFT} nt_div.line_break() - TextBox{parent=nt_div,x=2,text="Supervisor Address",height=1,alignment=ALIGN.LEFT,fg_bg=label} - local sv = TextBox{parent=nt_div,x=2,text="",height=1,alignment=ALIGN.LEFT} + TextBox{parent=nt_div,x=2,text="Supervisor Address",alignment=ALIGN.LEFT,fg_bg=label} + local sv = TextBox{parent=nt_div,x=2,text="",alignment=ALIGN.LEFT} nt_div.line_break() - TextBox{parent=nt_div,x=2,text="Coordinator Address",height=1,alignment=ALIGN.LEFT,fg_bg=label} - local coord = TextBox{parent=nt_div,x=2,text="",height=1,alignment=ALIGN.LEFT} + TextBox{parent=nt_div,x=2,text="Coordinator Address",alignment=ALIGN.LEFT,fg_bg=label} + local coord = TextBox{parent=nt_div,x=2,text="",alignment=ALIGN.LEFT} sv.register(db.ps, "sv_addr", function (addr) sv.set_value(util.c(addr, ":", config.SVR_Channel)) end) coord.register(db.ps, "api_addr", function (addr) coord.set_value(util.c(addr, ":", config.CRD_Channel)) end) nt_div.line_break() - TextBox{parent=nt_div,x=2,text="Message Authentication",height=1,alignment=ALIGN.LEFT,fg_bg=label} + TextBox{parent=nt_div,x=2,text="Message Authentication",alignment=ALIGN.LEFT,fg_bg=label} local auth = util.trinary(type(config.AuthKey) == "string" and string.len(config.AuthKey) > 0, "HMAC-MD5", "None") - TextBox{parent=nt_div,x=2,text=auth,height=1,alignment=ALIGN.LEFT} + TextBox{parent=nt_div,x=2,text=auth,alignment=ALIGN.LEFT} --#endregion --#region Firmware Versions local fw_div = Div{parent=about_root,x=1,y=2} - TextBox{parent=fw_div,y=1,text="Firmware Versions",height=1,alignment=ALIGN.CENTER} + 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} @@ -96,44 +96,44 @@ local function create_pages(root) local fw_list = Div{parent=fw_list_box,x=1,y=2,height=18} - TextBox{parent=fw_list,x=2,text="Pocket Version",height=1,alignment=ALIGN.LEFT,fg_bg=label} - TextBox{parent=fw_list,x=2,text=db.version,height=1,alignment=ALIGN.LEFT} + TextBox{parent=fw_list,x=2,text="Pocket Version",alignment=ALIGN.LEFT,fg_bg=label} + TextBox{parent=fw_list,x=2,text=db.version,alignment=ALIGN.LEFT} fw_list.line_break() - TextBox{parent=fw_list,x=2,text="Comms Version",height=1,alignment=ALIGN.LEFT,fg_bg=label} - TextBox{parent=fw_list,x=2,text=comms.version,height=1,alignment=ALIGN.LEFT} + TextBox{parent=fw_list,x=2,text="Comms Version",alignment=ALIGN.LEFT,fg_bg=label} + TextBox{parent=fw_list,x=2,text=comms.version,alignment=ALIGN.LEFT} fw_list.line_break() - TextBox{parent=fw_list,x=2,text="API Version",height=1,alignment=ALIGN.LEFT,fg_bg=label} - TextBox{parent=fw_list,x=2,text=comms.api_version,height=1,alignment=ALIGN.LEFT} + TextBox{parent=fw_list,x=2,text="API Version",alignment=ALIGN.LEFT,fg_bg=label} + TextBox{parent=fw_list,x=2,text=comms.api_version,alignment=ALIGN.LEFT} fw_list.line_break() - TextBox{parent=fw_list,x=2,text="Common Lib Version",height=1,alignment=ALIGN.LEFT,fg_bg=label} - TextBox{parent=fw_list,x=2,text=util.version,height=1,alignment=ALIGN.LEFT} + TextBox{parent=fw_list,x=2,text="Common Lib Version",alignment=ALIGN.LEFT,fg_bg=label} + TextBox{parent=fw_list,x=2,text=util.version,alignment=ALIGN.LEFT} fw_list.line_break() - TextBox{parent=fw_list,x=2,text="Graphics Version",height=1,alignment=ALIGN.LEFT,fg_bg=label} - TextBox{parent=fw_list,x=2,text=core.version,height=1,alignment=ALIGN.LEFT} + TextBox{parent=fw_list,x=2,text="Graphics Version",alignment=ALIGN.LEFT,fg_bg=label} + TextBox{parent=fw_list,x=2,text=core.version,alignment=ALIGN.LEFT} fw_list.line_break() - TextBox{parent=fw_list,x=2,text="Lockbox Version",height=1,alignment=ALIGN.LEFT,fg_bg=label} - TextBox{parent=fw_list,x=2,text=lockbox.version,height=1,alignment=ALIGN.LEFT} + TextBox{parent=fw_list,x=2,text="Lockbox Version",alignment=ALIGN.LEFT,fg_bg=label} + TextBox{parent=fw_list,x=2,text=lockbox.version,alignment=ALIGN.LEFT} --#endregion --#region Host Versions local hw_div = Div{parent=about_root,x=1,y=2} - TextBox{parent=hw_div,y=1,text="Host Versions",height=1,alignment=ALIGN.CENTER} + 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} hw_div.line_break() - TextBox{parent=hw_div,x=2,text="Lua Version",height=1,alignment=ALIGN.LEFT,fg_bg=label} - TextBox{parent=hw_div,x=2,text=_VERSION,height=1,alignment=ALIGN.LEFT} + TextBox{parent=hw_div,x=2,text="Lua Version",alignment=ALIGN.LEFT,fg_bg=label} + TextBox{parent=hw_div,x=2,text=_VERSION,alignment=ALIGN.LEFT} hw_div.line_break() - TextBox{parent=hw_div,x=2,text="Environment",height=1,alignment=ALIGN.LEFT,fg_bg=label} + TextBox{parent=hw_div,x=2,text="Environment",alignment=ALIGN.LEFT,fg_bg=label} TextBox{parent=hw_div,x=2,text=_HOST,height=6,alignment=ALIGN.LEFT} --#endregion diff --git a/pocket/ui/apps/unit.lua b/pocket/ui/apps/unit.lua index 1481a2b3..94f33417 100644 --- a/pocket/ui/apps/unit.lua +++ b/pocket/ui/apps/unit.lua @@ -58,7 +58,7 @@ 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...",height=1,alignment=ALIGN.CENTER} + 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.yellow,colors._INHERIT)} local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}} @@ -144,12 +144,12 @@ local function new_view(root) local u_page = app.new_page(nil, i) u_page.tasks = { update } - TextBox{parent=u_div,y=1,text="Reactor Unit #"..i,height=1,alignment=ALIGN.CENTER} + TextBox{parent=u_div,y=1,text="Reactor Unit #"..i,alignment=ALIGN.CENTER} PushButton{parent=u_div,x=1,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()prev(i)end} PushButton{parent=u_div,x=21,y=1,text=">",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()next(i)end} local type = util.trinary(unit.num_boilers > 0, "Sodium Cooled Reactor", "Boiling Water Reactor") - TextBox{parent=u_div,y=3,text=type,height=1,alignment=ALIGN.CENTER,fg_bg=cpair(colors.gray,colors.black)} + TextBox{parent=u_div,y=3,text=type,alignment=ALIGN.CENTER,fg_bg=cpair(colors.gray,colors.black)} local rate = DataIndicator{parent=u_div,y=5,lu_colors=lu_col,label="Burn",unit="mB/t",format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg} local temp = DataIndicator{parent=u_div,lu_colors=lu_col,label="Temp",unit=db.temp_label,format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg} @@ -196,7 +196,7 @@ local function new_view(root) alm_page.tasks = { update } nav_links[i].alarm = alm_page.nav_to - TextBox{parent=alm_div,y=1,text="Status Info Display",height=1,alignment=ALIGN.CENTER} + TextBox{parent=alm_div,y=1,text="Status Info Display",alignment=ALIGN.CENTER} local ecam_disp = ListBox{parent=alm_div,x=2,y=3,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} @@ -206,7 +206,7 @@ local function new_view(root) ecam_disp.remove_all() for _, entry in ipairs(ecam) do local div = Div{parent=ecam_disp,height=1+#entry.items,fg_bg=cpair(entry.color,colors.black)} - local text = TextBox{parent=div,height=1,text=entry.text} + local text = TextBox{parent=div,text=entry.text} if entry.help then PushButton{parent=div,x=21,y=text.get_y(),text="?",callback=function()db.nav.open_help(entry.help)end,fg_bg=cpair(colors.gray,colors.black)} @@ -216,7 +216,7 @@ local function new_view(root) local fg_bg = nil if item.color then fg_bg = cpair(item.color, colors.black) end - text = TextBox{parent=div,x=3,height=1,text=item.text,fg_bg=fg_bg} + text = TextBox{parent=div,x=3,text=item.text,fg_bg=fg_bg} if item.help then PushButton{parent=div,x=21,y=text.get_y(),text="?",callback=function()db.nav.open_help(item.help)end,fg_bg=cpair(colors.gray,colors.black)} @@ -239,7 +239,7 @@ local function new_view(root) rps_page.tasks = { update } nav_links[i].rps = rps_page.nav_to - TextBox{parent=rps_div,y=1,text="Protection System",height=1,alignment=ALIGN.CENTER} + TextBox{parent=rps_div,y=1,text="Protection System",alignment=ALIGN.CENTER} local r_trip = IconIndicator{parent=rps_div,y=3,label="RPS Trip",states=basic_states} r_trip.register(u_ps, "U_RPS", r_trip.update) @@ -290,7 +290,7 @@ local function new_view(root) nav_links[i].rcs = rcs_page.nav_to - TextBox{parent=rcs_div,y=1,text="Coolant System",height=1,alignment=ALIGN.CENTER} + TextBox{parent=rcs_div,y=1,text="Coolant System",alignment=ALIGN.CENTER} local r_rtrip = IconIndicator{parent=rcs_div,y=3,label="RCP Trip",states=red_ind_s} local r_cflow = IconIndicator{parent=rcs_div,label="RCS Flow Lo",states=yel_ind_s} @@ -309,7 +309,7 @@ local function new_view(root) c_mwrf.register(u_ps, "MaxWaterReturnFeed", c_mwrf.update) -- rcs_div.line_break() - -- TextBox{parent=rcs_div,text="Mismatches",height=1,alignment=ALIGN.CENTER,fg_bg=label} + -- 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} @@ -319,7 +319,7 @@ 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",height=1,alignment=ALIGN.CENTER,fg_bg=label} + -- 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/main.lua b/pocket/ui/main.lua index 4a33327a..7a6e1dc3 100644 --- a/pocket/ui/main.lua +++ b/pocket/ui/main.lua @@ -42,7 +42,7 @@ local function init(main) local main_pane = Div{parent=main,x=1,y=2} -- window header message and connection status - TextBox{parent=main,y=1,text="EARLY ACCESS ALPHA S C ",alignment=ALIGN.LEFT,height=1,fg_bg=style.header} + TextBox{parent=main,y=1,text="EARLY ACCESS ALPHA S C ",alignment=ALIGN.LEFT,fg_bg=style.header} local svr_conn = SignalBar{parent=main,y=1,x=22,compact=true,colors_low_med=cpair(colors.red,colors.yellow),disconnect_color=colors.lightGray,fg_bg=cpair(colors.green,colors.gray)} local crd_conn = SignalBar{parent=main,y=1,x=26,compact=true,colors_low_med=cpair(colors.red,colors.yellow),disconnect_color=colors.lightGray,fg_bg=cpair(colors.green,colors.gray)} diff --git a/pocket/ui/pages/guide_section.lua b/pocket/ui/pages/guide_section.lua index e73567b6..0629694b 100644 --- a/pocket/ui/pages/guide_section.lua +++ b/pocket/ui/pages/guide_section.lua @@ -25,13 +25,13 @@ return function (data, base_page, title, items, scroll_height) local section_page = app.new_page(base_page, #panes + 1) local section_div = Div{parent=page_div,x=2} table.insert(panes, section_div) - TextBox{parent=section_div,y=1,text=title,height=1,alignment=ALIGN.CENTER} + 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} 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,height=1,alignment=ALIGN.CENTER} + 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} local name_list = ListBox{parent=section_div,x=1,y=3,scroll_height=30,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} diff --git a/pocket/ui/pages/home_page.lua b/pocket/ui/pages/home_page.lua index 4b7fded1..b143728c 100644 --- a/pocket/ui/pages/home_page.lua +++ b/pocket/ui/pages/home_page.lua @@ -54,7 +54,7 @@ local function new_view(root) App{parent=apps_1,x=2,y=12,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=9,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} - TextBox{parent=apps_2,text="Diagnostic Apps",x=1,y=2,height=1,alignment=ALIGN.CENTER} + TextBox{parent=apps_2,text="Diagnostic Apps",x=1,y=2,alignment=ALIGN.CENTER} App{parent=apps_2,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_2,x=9,y=4,text="\x1e",title="LoopT",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.cyan),active_fg_bg=active_fg_bg} diff --git a/pocket/ui/pages/unit_boiler.lua b/pocket/ui/pages/unit_boiler.lua index 86b963ae..4ac39934 100644 --- a/pocket/ui/pages/unit_boiler.lua +++ b/pocket/ui/pages/unit_boiler.lua @@ -43,7 +43,7 @@ return function (app, u_page, panes, blr_pane, b_id, ps, update) local blr_page = app.new_page(u_page, #panes) blr_page.tasks = { update } - TextBox{parent=blr_div,y=1,text="BLR #"..b_id,width=8,height=1} + TextBox{parent=blr_div,y=1,text="BLR #"..b_id,width=8} local status = StateIndicator{parent=blr_div,x=10,y=1,states=style.boiler.states,value=1,min_width=12} status.register(ps, "BoilerStateStatus", status.update) @@ -52,17 +52,17 @@ return function (app, u_page, panes, blr_pane, b_id, ps, update) local steam = VerticalBar{parent=blr_div,x=19,y=4,fg_bg=cpair(colors.white,colors.gray),height=5,width=1} local ccool = VerticalBar{parent=blr_div,x=21,y=4,fg_bg=cpair(colors.lightBlue,colors.gray),height=5,width=1} - TextBox{parent=blr_div,text="H",x=1,y=3,width=1,height=1,fg_bg=label} - TextBox{parent=blr_div,text="W",x=3,y=3,width=1,height=1,fg_bg=label} - TextBox{parent=blr_div,text="S",x=19,y=3,width=1,height=1,fg_bg=label} - TextBox{parent=blr_div,text="C",x=21,y=3,width=1,height=1,fg_bg=label} + TextBox{parent=blr_div,text="H",x=1,y=3,width=1,fg_bg=label} + TextBox{parent=blr_div,text="W",x=3,y=3,width=1,fg_bg=label} + TextBox{parent=blr_div,text="S",x=19,y=3,width=1,fg_bg=label} + TextBox{parent=blr_div,text="C",x=21,y=3,width=1,fg_bg=label} hcool.register(ps, "hcool_fill", hcool.update) water.register(ps, "water_fill", water.update) steam.register(ps, "steam_fill", steam.update) ccool.register(ps, "ccool_fill", ccool.update) - TextBox{parent=blr_div,text="Temperature",x=5,y=5,width=13,height=1,fg_bg=label} + TextBox{parent=blr_div,text="Temperature",x=5,y=5,width=13,fg_bg=label} local t_prec = util.trinary(db.temp_label == types.TEMP_SCALE_UNITS[types.TEMP_SCALE.KELVIN], 11, 10) local temp = DataIndicator{parent=blr_div,x=5,y=6,lu_colors=lu_col,label="",unit=db.temp_label,format="%"..t_prec..".2f",value=0,commas=true,width=13,fg_bg=text_fg} @@ -74,7 +74,7 @@ return function (app, u_page, panes, blr_pane, b_id, ps, update) b_wll.register(ps, "WaterLevelLow", b_wll.update) b_hr.register(ps, "HeatingRateLow", b_hr.update) - TextBox{parent=blr_div,text="Boil Rate",x=1,y=13,width=12,height=1,fg_bg=label} + TextBox{parent=blr_div,text="Boil Rate",x=1,y=13,width=12,fg_bg=label} local boil_r = DataIndicator{parent=blr_div,x=6,y=14,lu_colors=lu_col,label="",unit="mB/t",format="%11.0f",value=0,commas=true,width=16,fg_bg=text_fg} boil_r.register(ps, "boil_rate", boil_r.update) @@ -88,41 +88,41 @@ return function (app, u_page, panes, blr_pane, b_id, ps, update) PushButton{parent=blr_div,x=9,y=18,text="MORE",min_width=6,fg_bg=cpair(colors.lightGray,colors.gray),active_fg_bg=cpair(colors.gray,colors.lightGray),callback=blr_ext_page.nav_to} PushButton{parent=blr_ext_div,x=9,y=18,text="BACK",min_width=6,fg_bg=cpair(colors.lightGray,colors.gray),active_fg_bg=cpair(colors.gray,colors.lightGray),callback=blr_page.nav_to} - TextBox{parent=blr_ext_div,y=1,text="More Boiler Info",height=1,alignment=ALIGN.CENTER} + TextBox{parent=blr_ext_div,y=1,text="More Boiler Info",alignment=ALIGN.CENTER} local function update_amount(indicator) return function (x) indicator.update(x.amount) end end - TextBox{parent=blr_ext_div,text="Hot Coolant",x=1,y=3,width=12,height=1,fg_bg=label} + TextBox{parent=blr_ext_div,text="Hot Coolant",x=1,y=3,width=12,fg_bg=label} local heated_p = DataIndicator{parent=blr_ext_div,x=14,y=3,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} local hcool_amnt = DataIndicator{parent=blr_ext_div,x=1,y=4,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg} heated_p.register(ps, "hcool_fill", function (x) heated_p.update(x * 100) end) hcool_amnt.register(ps, "hcool", update_amount(hcool_amnt)) - TextBox{parent=blr_ext_div,text="Water Tank",x=1,y=6,width=9,height=1,fg_bg=label} + TextBox{parent=blr_ext_div,text="Water Tank",x=1,y=6,width=9,fg_bg=label} local fuel_p = DataIndicator{parent=blr_ext_div,x=14,y=6,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} local fuel_amnt = DataIndicator{parent=blr_ext_div,x=1,y=7,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg} fuel_p.register(ps, "water_fill", function (x) fuel_p.update(x * 100) end) fuel_amnt.register(ps, "water", update_amount(fuel_amnt)) - TextBox{parent=blr_ext_div,text="Steam Tank",x=1,y=9,width=10,height=1,fg_bg=label} + TextBox{parent=blr_ext_div,text="Steam Tank",x=1,y=9,width=10,fg_bg=label} local steam_p = DataIndicator{parent=blr_ext_div,x=14,y=9,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} local steam_amnt = DataIndicator{parent=blr_ext_div,x=1,y=10,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg} steam_p.register(ps, "steam_fill", function (x) steam_p.update(x * 100) end) steam_amnt.register(ps, "steam", update_amount(steam_amnt)) - TextBox{parent=blr_ext_div,text="Cool Coolant",x=1,y=12,width=12,height=1,fg_bg=label} + TextBox{parent=blr_ext_div,text="Cool Coolant",x=1,y=12,width=12,fg_bg=label} local cooled_p = DataIndicator{parent=blr_ext_div,x=14,y=12,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} local ccool_amnt = DataIndicator{parent=blr_ext_div,x=1,y=13,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg} cooled_p.register(ps, "ccool_fill", function (x) cooled_p.update(x * 100) end) ccool_amnt.register(ps, "ccool", update_amount(ccool_amnt)) - TextBox{parent=blr_ext_div,text="Env. Loss",x=1,y=15,width=9,height=1,fg_bg=label} + TextBox{parent=blr_ext_div,text="Env. Loss",x=1,y=15,width=9,fg_bg=label} local env_loss = DataIndicator{parent=blr_ext_div,x=11,y=15,lu_colors=lu_col,label="",unit="",format="%11.8f",value=0,width=11,fg_bg=text_fg} env_loss.register(ps, "env_loss", env_loss.update) diff --git a/pocket/ui/pages/unit_reactor.lua b/pocket/ui/pages/unit_reactor.lua index b7fb23fb..56b03780 100644 --- a/pocket/ui/pages/unit_reactor.lua +++ b/pocket/ui/pages/unit_reactor.lua @@ -43,7 +43,7 @@ return function (app, u_page, panes, page_div, u_ps, update) local rct_page = app.new_page(u_page, #panes) rct_page.tasks = { update } - TextBox{parent=rct_div,y=1,text="Reactor",width=8,height=1} + TextBox{parent=rct_div,y=1,text="Reactor",width=8} local status = StateIndicator{parent=rct_div,x=10,y=1,states=style.reactor.states,value=1,min_width=12} status.register(u_ps, "U_ReactorStateStatus", status.update) @@ -52,10 +52,10 @@ return function (app, u_page, panes, page_div, u_ps, update) local hcool = VerticalBar{parent=rct_div,x=19,y=4,fg_bg=cpair(colors.white,colors.gray),height=5,width=1} local waste = VerticalBar{parent=rct_div,x=21,y=4,fg_bg=cpair(colors.brown,colors.gray),height=5,width=1} - TextBox{parent=rct_div,text="F",x=1,y=3,width=1,height=1,fg_bg=label} - TextBox{parent=rct_div,text="C",x=3,y=3,width=1,height=1,fg_bg=label} - TextBox{parent=rct_div,text="H",x=19,y=3,width=1,height=1,fg_bg=label} - TextBox{parent=rct_div,text="W",x=21,y=3,width=1,height=1,fg_bg=label} + TextBox{parent=rct_div,text="F",x=1,y=3,width=1,fg_bg=label} + TextBox{parent=rct_div,text="C",x=3,y=3,width=1,fg_bg=label} + TextBox{parent=rct_div,text="H",x=19,y=3,width=1,fg_bg=label} + TextBox{parent=rct_div,text="W",x=21,y=3,width=1,fg_bg=label} fuel.register(u_ps, "fuel_fill", fuel.update) ccool.register(u_ps, "ccool_fill", ccool.update) @@ -78,9 +78,9 @@ return function (app, u_page, panes, page_div, u_ps, update) end end) - TextBox{parent=rct_div,text="Burn Rate",x=5,y=4,width=13,height=1,fg_bg=label} + TextBox{parent=rct_div,text="Burn Rate",x=5,y=4,width=13,fg_bg=label} local burn_rate = DataIndicator{parent=rct_div,x=5,y=5,lu_colors=lu_col,label="",unit="mB/t",format="%8.2f",value=0,commas=true,width=13,fg_bg=text_fg} - TextBox{parent=rct_div,text="Temperature",x=5,y=6,width=13,height=1,fg_bg=label} + TextBox{parent=rct_div,text="Temperature",x=5,y=6,width=13,fg_bg=label} local t_prec = util.trinary(db.temp_label == types.TEMP_SCALE_UNITS[types.TEMP_SCALE.KELVIN], 11, 10) local core_temp = DataIndicator{parent=rct_div,x=5,y=7,lu_colors=lu_col,label="",unit=db.temp_label,format="%"..t_prec..".2f",value=0,commas=true,width=13,fg_bg=text_fg} @@ -99,9 +99,9 @@ return function (app, u_page, panes, page_div, u_ps, update) r_wloc.register(u_ps, "WasteLineOcclusion", r_wloc.update) r_hsrt.register(u_ps, "HighStartupRate", r_hsrt.update) - TextBox{parent=rct_div,text="HR",x=1,y=16,width=4,height=1,fg_bg=label} + TextBox{parent=rct_div,text="HR",x=1,y=16,width=4,fg_bg=label} local heating_r = DataIndicator{parent=rct_div,x=6,y=16,lu_colors=lu_col,label="",unit="mB/t",format="%11.0f",value=0,commas=true,width=16,fg_bg=text_fg} - TextBox{parent=rct_div,text="DMG",x=1,y=17,width=4,height=1,fg_bg=label} + TextBox{parent=rct_div,text="DMG",x=1,y=17,width=4,fg_bg=label} local damage_p = DataIndicator{parent=rct_div,x=6,y=17,lu_colors=lu_col,label="",unit="%",format="%11.2f",value=0,width=16,fg_bg=text_fg} heating_r.register(u_ps, "heating_rate", heating_r.update) @@ -116,38 +116,38 @@ return function (app, u_page, panes, page_div, u_ps, update) PushButton{parent=rct_div,x=9,y=18,text="MORE",min_width=6,fg_bg=cpair(colors.lightGray,colors.gray),active_fg_bg=cpair(colors.gray,colors.lightGray),callback=rct_ext_page.nav_to} PushButton{parent=rct_ext_div,x=9,y=18,text="BACK",min_width=6,fg_bg=cpair(colors.lightGray,colors.gray),active_fg_bg=cpair(colors.gray,colors.lightGray),callback=rct_page.nav_to} - TextBox{parent=rct_ext_div,y=1,text="More Reactor Info",height=1,alignment=ALIGN.CENTER} + TextBox{parent=rct_ext_div,y=1,text="More Reactor Info",alignment=ALIGN.CENTER} - TextBox{parent=rct_ext_div,text="Fuel Tank",x=1,y=3,width=9,height=1,fg_bg=label} + TextBox{parent=rct_ext_div,text="Fuel Tank",x=1,y=3,width=9,fg_bg=label} local fuel_p = DataIndicator{parent=rct_ext_div,x=14,y=3,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} local fuel_amnt = DataIndicator{parent=rct_ext_div,x=1,y=4,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg} fuel_p.register(u_ps, "fuel_fill", function (x) fuel_p.update(x * 100) end) fuel_amnt.register(u_ps, "fuel", fuel_amnt.update) - TextBox{parent=rct_ext_div,text="Cool Coolant",x=1,y=6,width=12,height=1,fg_bg=label} + TextBox{parent=rct_ext_div,text="Cool Coolant",x=1,y=6,width=12,fg_bg=label} local cooled_p = DataIndicator{parent=rct_ext_div,x=14,y=6,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} local ccool_amnt = DataIndicator{parent=rct_ext_div,x=1,y=7,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg} cooled_p.register(u_ps, "ccool_fill", function (x) cooled_p.update(x * 100) end) ccool_amnt.register(u_ps, "ccool_amnt", ccool_amnt.update) - TextBox{parent=rct_ext_div,text="Hot Coolant",x=1,y=9,width=12,height=1,fg_bg=label} + TextBox{parent=rct_ext_div,text="Hot Coolant",x=1,y=9,width=12,fg_bg=label} local heated_p = DataIndicator{parent=rct_ext_div,x=14,y=9,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} local hcool_amnt = DataIndicator{parent=rct_ext_div,x=1,y=10,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg} heated_p.register(u_ps, "hcool_fill", function (x) heated_p.update(x * 100) end) hcool_amnt.register(u_ps, "hcool_amnt", hcool_amnt.update) - TextBox{parent=rct_ext_div,text="Waste Tank",x=1,y=12,width=10,height=1,fg_bg=label} + TextBox{parent=rct_ext_div,text="Waste Tank",x=1,y=12,width=10,fg_bg=label} local waste_p = DataIndicator{parent=rct_ext_div,x=14,y=12,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} local waste_amnt = DataIndicator{parent=rct_ext_div,x=1,y=13,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg} waste_p.register(u_ps, "waste_fill", function (x) waste_p.update(x * 100) end) waste_amnt.register(u_ps, "waste", waste_amnt.update) - TextBox{parent=rct_ext_div,text="Boil Eff.",x=1,y=15,width=9,height=1,fg_bg=label} - TextBox{parent=rct_ext_div,text="Env. Loss",x=1,y=16,width=9,height=1,fg_bg=label} + TextBox{parent=rct_ext_div,text="Boil Eff.",x=1,y=15,width=9,fg_bg=label} + TextBox{parent=rct_ext_div,text="Env. Loss",x=1,y=16,width=9,fg_bg=label} local boil_eff = DataIndicator{parent=rct_ext_div,x=11,y=15,lu_colors=lu_col,label="",unit="%",format="%9.2f",value=0,width=11,fg_bg=text_fg} local env_loss = DataIndicator{parent=rct_ext_div,x=11,y=16,lu_colors=lu_col,label="",unit="",format="%11.8f",value=0,width=11,fg_bg=text_fg} diff --git a/pocket/ui/pages/unit_turbine.lua b/pocket/ui/pages/unit_turbine.lua index 03cd8653..0a14c338 100644 --- a/pocket/ui/pages/unit_turbine.lua +++ b/pocket/ui/pages/unit_turbine.lua @@ -45,24 +45,24 @@ return function (app, u_page, panes, tbn_pane, u_id, t_id, ps, update) local tbn_page = app.new_page(u_page, #panes) tbn_page.tasks = { update } - TextBox{parent=tbn_div,y=1,text="TRBN #"..t_id,width=8,height=1} + TextBox{parent=tbn_div,y=1,text="TRBN #"..t_id,width=8} local status = StateIndicator{parent=tbn_div,x=10,y=1,states=style.turbine.states,value=1,min_width=12} status.register(ps, "TurbineStateStatus", status.update) local steam = VerticalBar{parent=tbn_div,x=1,y=4,fg_bg=cpair(colors.white,colors.gray),height=5,width=1} local ccool = VerticalBar{parent=tbn_div,x=21,y=4,fg_bg=cpair(colors.green,colors.gray),height=5,width=1} - TextBox{parent=tbn_div,text="S",x=1,y=3,width=1,height=1,fg_bg=label} - TextBox{parent=tbn_div,text="E",x=21,y=3,width=1,height=1,fg_bg=label} + TextBox{parent=tbn_div,text="S",x=1,y=3,width=1,fg_bg=label} + TextBox{parent=tbn_div,text="E",x=21,y=3,width=1,fg_bg=label} steam.register(ps, "steam_fill", steam.update) ccool.register(ps, "energy_fill", ccool.update) - TextBox{parent=tbn_div,text="Production",x=3,y=3,width=17,height=1,fg_bg=label} + TextBox{parent=tbn_div,text="Production",x=3,y=3,width=17,fg_bg=label} local prod_rate = PowerIndicator{parent=tbn_div,x=3,y=4,lu_colors=lu_col,label="",format="%11.2f",value=0,rate=true,width=17,fg_bg=text_fg} - TextBox{parent=tbn_div,text="Flow Rate",x=3,y=5,width=17,height=1,fg_bg=label} + TextBox{parent=tbn_div,text="Flow Rate",x=3,y=5,width=17,fg_bg=label} local flow_rate = DataIndicator{parent=tbn_div,x=3,y=6,lu_colors=lu_col,label="",unit="mB/t",format="%11.0f",value=0,commas=true,width=17,fg_bg=text_fg} - TextBox{parent=tbn_div,text="Steam Input Rate",x=3,y=7,width=17,height=1,fg_bg=label} + TextBox{parent=tbn_div,text="Steam Input Rate",x=3,y=7,width=17,fg_bg=label} local input_rate = DataIndicator{parent=tbn_div,x=3,y=8,lu_colors=lu_col,label="",unit="mB/t",format="%11.0f",value=0,commas=true,width=17,fg_bg=text_fg} prod_rate.register(ps, "prod_rate", function (val) prod_rate.update(util.joules_to_fe(val)) end) @@ -88,23 +88,23 @@ return function (app, u_page, panes, tbn_pane, u_id, t_id, ps, update) PushButton{parent=tbn_div,x=9,y=18,text="MORE",min_width=6,fg_bg=cpair(colors.lightGray,colors.gray),active_fg_bg=cpair(colors.gray,colors.lightGray),callback=tbn_ext_page.nav_to} PushButton{parent=tbn_ext_div,x=9,y=18,text="BACK",min_width=6,fg_bg=cpair(colors.lightGray,colors.gray),active_fg_bg=cpair(colors.gray,colors.lightGray),callback=tbn_page.nav_to} - TextBox{parent=tbn_ext_div,y=1,text="More Turbine Info",height=1,alignment=ALIGN.CENTER} + TextBox{parent=tbn_ext_div,y=1,text="More Turbine Info",alignment=ALIGN.CENTER} - TextBox{parent=tbn_ext_div,text="Steam Tank",x=1,y=3,width=10,height=1,fg_bg=label} + TextBox{parent=tbn_ext_div,text="Steam Tank",x=1,y=3,width=10,fg_bg=label} local steam_p = DataIndicator{parent=tbn_ext_div,x=14,y=3,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} local steam_amnt = DataIndicator{parent=tbn_ext_div,x=1,y=4,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg} steam_p.register(ps, "steam_fill", function (x) steam_p.update(x * 100) end) steam_amnt.register(ps, "steam", function (x) steam_amnt.update(x.amount) end) - TextBox{parent=tbn_ext_div,text="Energy Fill",x=1,y=6,width=12,height=1,fg_bg=label} + TextBox{parent=tbn_ext_div,text="Energy Fill",x=1,y=6,width=12,fg_bg=label} local charge_p = DataIndicator{parent=tbn_ext_div,x=14,y=6,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg} local charge_amnt = PowerIndicator{parent=tbn_ext_div,x=1,y=7,lu_colors=lu_col,label="",format="%17.4f",value=0,width=21,fg_bg=text_fg} charge_p.register(ps, "energy_fill", function (x) charge_p.update(x * 100) end) charge_amnt.register(ps, "energy", charge_amnt.update) - TextBox{parent=tbn_ext_div,text="Rotation Rate",x=1,y=9,width=13,height=1,fg_bg=label} + TextBox{parent=tbn_ext_div,text="Rotation Rate",x=1,y=9,width=13,fg_bg=label} local rotation = DataIndicator{parent=tbn_ext_div,x=1,y=10,lu_colors=lu_col,label="",unit="",format="%21.12f",value=0,width=21,fg_bg=text_fg} rotation.register(ps, "steam", function () diff --git a/reactor-plc/configure.lua b/reactor-plc/configure.lua index 482a629b..582a2dab 100644 --- a/reactor-plc/configure.lua +++ b/reactor-plc/configure.lua @@ -168,7 +168,7 @@ local function config_view(display) ---@diagnostic disable-next-line: undefined-field local function exit() os.queueEvent("terminate") end - TextBox{parent=display,y=1,text="Reactor PLC Configurator",alignment=CENTER,height=1,fg_bg=style.header} + TextBox{parent=display,y=1,text="Reactor PLC Configurator",alignment=CENTER,fg_bg=style.header} local root_pane_div = Div{parent=display,x=1,y=2} @@ -233,9 +233,9 @@ local function config_view(display) local plc_pane = MultiPane{parent=plc_cfg,x=1,y=4,panes={plc_c_1,plc_c_2,plc_c_3,plc_c_4}} - TextBox{parent=plc_cfg,x=1,y=2,height=1,text=" PLC Configuration",fg_bg=cpair(colors.black,colors.orange)} + TextBox{parent=plc_cfg,x=1,y=2,text=" PLC Configuration",fg_bg=cpair(colors.black,colors.orange)} - TextBox{parent=plc_c_1,x=1,y=1,height=1,text="Would you like to set this PLC as networked?"} + TextBox{parent=plc_c_1,x=1,y=1,text="Would you like to set this PLC as networked?"} TextBox{parent=plc_c_1,x=1,y=3,height=4,text="If you have a supervisor, select the box. You will later be prompted to select the network configuration. If you instead want to use this as a standalone safety system, don't select the box.",fg_bg=g_lg_fg_bg} local networked = CheckBox{parent=plc_c_1,x=1,y=8,label="Networked",default=ini_cfg.Networked,box_fg_bg=cpair(colors.orange,colors.black)} @@ -248,13 +248,13 @@ local function config_view(display) PushButton{parent=plc_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=plc_c_1,x=44,y=14,text="Next \x1a",callback=submit_networked,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - TextBox{parent=plc_c_2,x=1,y=1,height=1,text="Please enter the reactor unit ID for this PLC."} + TextBox{parent=plc_c_2,x=1,y=1,text="Please enter the reactor unit ID for this PLC."} TextBox{parent=plc_c_2,x=1,y=3,height=3,text="If this is a networked PLC, currently only IDs 1 through 4 are acceptable.",fg_bg=g_lg_fg_bg} - TextBox{parent=plc_c_2,x=1,y=6,height=1,text="Unit #"} + TextBox{parent=plc_c_2,x=1,y=6,text="Unit #"} local u_id = NumberField{parent=plc_c_2,x=7,y=6,width=5,max_chars=3,default=ini_cfg.UnitID,min=1,fg_bg=bw_fg_bg} - local u_id_err = TextBox{parent=plc_c_2,x=8,y=14,height=1,width=35,text="Please set a unit ID.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local u_id_err = TextBox{parent=plc_c_2,x=8,y=14,width=35,text="Please set a unit ID.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_id() local unit_id = tonumber(u_id.get_value()) @@ -285,10 +285,10 @@ local function config_view(display) PushButton{parent=plc_c_3,x=1,y=14,text="\x1b Back",callback=function()plc_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=plc_c_3,x=44,y=14,text="Next \x1a",callback=submit_en_emcool,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - TextBox{parent=plc_c_4,x=1,y=1,height=1,text="Emergency Coolant Redstone Output Side"} + TextBox{parent=plc_c_4,x=1,y=1,text="Emergency Coolant Redstone Output Side"} local side = Radio2D{parent=plc_c_4,x=1,y=2,rows=2,columns=3,default=side_to_idx(ini_cfg.EmerCoolSide),options=side_options,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.orange} - TextBox{parent=plc_c_4,x=1,y=5,height=1,text="Bundled Redstone Configuration"} + TextBox{parent=plc_c_4,x=1,y=5,text="Bundled Redstone Configuration"} local bundled = CheckBox{parent=plc_c_4,x=1,y=6,label="Is Bundled?",default=ini_cfg.EmerCoolColor~=nil,box_fg_bg=cpair(colors.orange,colors.black),callback=function(v)tool_ctl.bundled_emcool(v)end} local color = Radio2D{parent=plc_c_4,x=1,y=8,rows=4,columns=4,default=color_to_idx(ini_cfg.EmerCoolColor),options=color_options,radio_colors=cpair(colors.lightGray,colors.black),color_map=color_options_map,disable_color=colors.gray,disable_fg_bg=g_lg_fg_bg} if ini_cfg.EmerCoolColor == nil then color.disable() end @@ -312,19 +312,19 @@ local function config_view(display) local net_pane = MultiPane{parent=net_cfg,x=1,y=4,panes={net_c_1,net_c_2,net_c_3}} - TextBox{parent=net_cfg,x=1,y=2,height=1,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)} + TextBox{parent=net_cfg,x=1,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)} - TextBox{parent=net_c_1,x=1,y=1,height=1,text="Please set the network channels below."} + TextBox{parent=net_c_1,x=1,y=1,text="Please set the network channels below."} TextBox{parent=net_c_1,x=1,y=3,height=4,text="Each of the 5 uniquely named channels, including the 2 below, must be the same for each device in this SCADA network. For multiplayer servers, it is recommended to not use the default channels.",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_1,x=1,y=8,height=1,text="Supervisor Channel"} + TextBox{parent=net_c_1,x=1,y=8,text="Supervisor Channel"} local svr_chan = NumberField{parent=net_c_1,x=1,y=9,width=7,default=ini_cfg.SVR_Channel,min=1,max=65535,fg_bg=bw_fg_bg} TextBox{parent=net_c_1,x=9,y=9,height=4,text="[SVR_CHANNEL]",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_1,x=1,y=11,height=1,text="PLC Channel"} + TextBox{parent=net_c_1,x=1,y=11,text="PLC Channel"} local plc_chan = NumberField{parent=net_c_1,x=1,y=12,width=7,default=ini_cfg.PLC_Channel,min=1,max=65535,fg_bg=bw_fg_bg} TextBox{parent=net_c_1,x=9,y=12,height=4,text="[PLC_CHANNEL]",fg_bg=g_lg_fg_bg} - local chan_err = TextBox{parent=net_c_1,x=8,y=14,height=1,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local chan_err = TextBox{parent=net_c_1,x=8,y=14,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_channels() local svr_c = tonumber(svr_chan.get_value()) @@ -346,16 +346,16 @@ local function config_view(display) PushButton{parent=net_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=net_c_1,x=44,y=14,text="Next \x1a",callback=submit_channels,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - TextBox{parent=net_c_2,x=1,y=1,height=1,text="Connection Timeout"} + TextBox{parent=net_c_2,x=1,y=1,text="Connection Timeout"} local timeout = NumberField{parent=net_c_2,x=1,y=2,width=7,default=ini_cfg.ConnTimeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg} TextBox{parent=net_c_2,x=9,y=2,height=2,text="seconds (default 5)",fg_bg=g_lg_fg_bg} TextBox{parent=net_c_2,x=1,y=3,height=4,text="You generally do not want or need to modify this. On slow servers, you can increase this to make the system wait longer before assuming a disconnection.",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_2,x=1,y=8,height=1,text="Trusted Range"} + TextBox{parent=net_c_2,x=1,y=8,text="Trusted Range"} local range = NumberField{parent=net_c_2,x=1,y=9,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg} TextBox{parent=net_c_2,x=1,y=10,height=4,text="Setting this to a value larger than 0 prevents connections with devices that many meters (blocks) away in any direction.",fg_bg=g_lg_fg_bg} - local p2_err = TextBox{parent=net_c_2,x=8,y=14,height=1,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local p2_err = TextBox{parent=net_c_2,x=8,y=14,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_ct_tr() local timeout_val = tonumber(timeout.get_value()) @@ -380,7 +380,7 @@ local function config_view(display) TextBox{parent=net_c_3,x=1,y=1,height=2,text="Optionally, set the facility authentication key below. Do NOT use one of your passwords."} TextBox{parent=net_c_3,x=1,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for security on multiplayer servers. All devices on the same network MUST use the same key if any device has a key. This does result in some extra compution (can slow things down).",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_3,x=1,y=11,height=1,text="Facility Auth Key"} + TextBox{parent=net_c_3,x=1,y=11,text="Facility Auth Key"} local key, _, censor = TextField{parent=net_c_3,x=1,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg} local function censor_key(enable) censor(util.trinary(enable, "*", nil)) end @@ -390,7 +390,7 @@ local function config_view(display) hide_key.set_value(true) censor_key(true) - local key_err = TextBox{parent=net_c_3,x=8,y=14,height=1,width=35,text="Key must be at least 8 characters.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local key_err = TextBox{parent=net_c_3,x=8,y=14,width=35,text="Key must be at least 8 characters.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_auth() local v = key.get_value() @@ -410,20 +410,20 @@ local function config_view(display) local log_c_1 = Div{parent=log_cfg,x=2,y=4,width=49} - TextBox{parent=log_cfg,x=1,y=2,height=1,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)} + TextBox{parent=log_cfg,x=1,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)} - TextBox{parent=log_c_1,x=1,y=1,height=1,text="Please configure logging below."} + TextBox{parent=log_c_1,x=1,y=1,text="Please configure logging below."} - TextBox{parent=log_c_1,x=1,y=3,height=1,text="Log File Mode"} + TextBox{parent=log_c_1,x=1,y=3,text="Log File Mode"} local mode = RadioButton{parent=log_c_1,x=1,y=4,default=ini_cfg.LogMode+1,options={"Append on Startup","Replace on Startup"},callback=function()end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.pink} - TextBox{parent=log_c_1,x=1,y=7,height=1,text="Log File Path"} + TextBox{parent=log_c_1,x=1,y=7,text="Log File Path"} local path = TextField{parent=log_c_1,x=1,y=8,width=49,height=1,value=ini_cfg.LogPath,max_len=128,fg_bg=bw_fg_bg} local en_dbg = CheckBox{parent=log_c_1,x=1,y=10,default=ini_cfg.LogDebug,label="Enable Logging Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)} TextBox{parent=log_c_1,x=3,y=11,height=2,text="This results in much larger log files. It is best to only use this when there is a problem.",fg_bg=g_lg_fg_bg} - local path_err = TextBox{parent=log_c_1,x=8,y=14,height=1,width=35,text="Please provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local path_err = TextBox{parent=log_c_1,x=8,y=14,width=35,text="Please provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_log() if path.get_value() ~= "" then @@ -455,17 +455,17 @@ local function config_view(display) local clr_pane = MultiPane{parent=clr_cfg,x=1,y=4,panes={clr_c_1,clr_c_2,clr_c_3,clr_c_4}} - TextBox{parent=clr_cfg,x=1,y=2,height=1,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)} + TextBox{parent=clr_cfg,x=1,y=2,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)} TextBox{parent=clr_c_1,x=1,y=1,height=2,text="Here you can select the color theme for the front panel."} TextBox{parent=clr_c_1,x=1,y=4,height=2,text="Click 'Accessibility' below to access colorblind assistive options.",fg_bg=g_lg_fg_bg} - TextBox{parent=clr_c_1,x=1,y=7,height=1,text="Front Panel Theme"} + TextBox{parent=clr_c_1,x=1,y=7,text="Front Panel Theme"} local fp_theme = RadioButton{parent=clr_c_1,x=1,y=8,default=ini_cfg.FrontPanelTheme,options=themes.FP_THEME_NAMES,callback=function()end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta} TextBox{parent=clr_c_2,x=1,y=1,height=6,text="This system uses color heavily to distinguish ok and not, with some indicators using many colors. By selecting a mode below, indicators will change as shown. For non-standard modes, indicators with more than two colors will be split up."} - TextBox{parent=clr_c_2,x=21,y=7,height=1,text="Preview"} + TextBox{parent=clr_c_2,x=21,y=7,text="Preview"} local _ = IndLight{parent=clr_c_2,x=21,y=8,label="Good",colors=cpair(colors.black,colors.green)} _ = IndLight{parent=clr_c_2,x=21,y=9,label="Warning",colors=cpair(colors.black,colors.yellow)} _ = IndLight{parent=clr_c_2,x=21,y=10,label="Bad",colors=cpair(colors.black,colors.red)} @@ -492,7 +492,7 @@ local function config_view(display) end end - TextBox{parent=clr_c_2,x=1,y=7,height=1,width=10,text="Color Mode"} + TextBox{parent=clr_c_2,x=1,y=7,width=10,text="Color Mode"} local c_mode = RadioButton{parent=clr_c_2,x=1,y=8,default=ini_cfg.ColorMode,options=themes.COLOR_MODE_NAMES,callback=recolor,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta} TextBox{parent=clr_c_2,x=21,y=13,height=2,width=18,text="Note: exact color varies by theme.",fg_bg=g_lg_fg_bg} @@ -546,7 +546,7 @@ local function config_view(display) clr_pane.set_value(1) end - TextBox{parent=clr_c_3,x=1,y=1,height=1,text="Settings saved!"} + TextBox{parent=clr_c_3,x=1,y=1,text="Settings saved!"} PushButton{parent=clr_c_3,x=1,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)} PushButton{parent=clr_c_3,x=44,y=14,min_width=6,text="Home",callback=c_go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} @@ -565,7 +565,7 @@ local function config_view(display) local sum_pane = MultiPane{parent=summary,x=1,y=4,panes={sum_c_1,sum_c_2,sum_c_3,sum_c_4}} - TextBox{parent=summary,x=1,y=2,height=1,text=" Summary",fg_bg=cpair(colors.black,colors.green)} + TextBox{parent=summary,x=1,y=2,text=" Summary",fg_bg=cpair(colors.black,colors.green)} local setting_list = ListBox{parent=sum_c_1,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} @@ -627,7 +627,7 @@ local function config_view(display) tool_ctl.show_key_btn = PushButton{parent=sum_c_1,x=8,y=14,min_width=17,text="Unhide Auth Key",callback=function()tool_ctl.show_auth_key()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=cpair(colors.lightGray,colors.white)} tool_ctl.settings_apply = PushButton{parent=sum_c_1,x=43,y=14,min_width=7,text="Apply",callback=save_and_continue,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg} - TextBox{parent=sum_c_2,x=1,y=1,height=1,text="Settings saved!"} + TextBox{parent=sum_c_2,x=1,y=1,text="Settings saved!"} local function go_home() main_pane.set_value(1) @@ -660,15 +660,15 @@ local function config_view(display) local cl = Div{parent=changelog,x=2,y=4,width=49} - TextBox{parent=changelog,x=1,y=2,height=1,text=" Config Change Log",fg_bg=bw_fg_bg} + TextBox{parent=changelog,x=1,y=2,text=" Config Change Log",fg_bg=bw_fg_bg} local c_log = ListBox{parent=cl,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} for _, change in ipairs(changes) do - TextBox{parent=c_log,text=change[1],height=1,fg_bg=bw_fg_bg} + TextBox{parent=c_log,text=change[1],fg_bg=bw_fg_bg} for _, v in ipairs(change[2]) do local e = Div{parent=c_log,height=#util.strwrap(v,46)} - TextBox{parent=e,y=1,x=1,text="- ",height=1,fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=e,y=1,x=1,text="- ",fg_bg=cpair(colors.gray,colors.white)} TextBox{parent=e,y=1,x=3,text=v,height=e.get_height(),fg_bg=cpair(colors.gray,colors.white)} end end diff --git a/reactor-plc/panel/front_panel.lua b/reactor-plc/panel/front_panel.lua index ee2f3eda..20fc7994 100644 --- a/reactor-plc/panel/front_panel.lua +++ b/reactor-plc/panel/front_panel.lua @@ -40,7 +40,7 @@ local function init(panel) local disabled_fg = style.fp.disabled_fg - local header = TextBox{parent=panel,y=1,text="FISSION REACTOR PLC - UNIT ?",alignment=ALIGN.CENTER,height=1,fg_bg=style.theme.header} + local header = TextBox{parent=panel,y=1,text="FISSION REACTOR PLC - UNIT ?",alignment=ALIGN.CENTER,fg_bg=style.theme.header} header.register(databus.ps, "unit_id", function (id) header.set_value(util.c("FISSION REACTOR PLC - UNIT ", id)) end) -- @@ -115,7 +115,7 @@ local function init(panel) ---@diagnostic disable-next-line: undefined-field local comp_id = util.sprintf("(%d)", os.getComputerID()) - TextBox{parent=system,x=9,y=5,width=6,height=1,text=comp_id,fg_bg=disabled_fg} + TextBox{parent=system,x=9,y=5,width=6,text=comp_id,fg_bg=disabled_fg} -- -- status & controls @@ -148,8 +148,8 @@ local function init(panel) -- local about = Div{parent=panel,width=15,height=3,x=1,y=18,fg_bg=disabled_fg} - local fw_v = TextBox{parent=about,x=1,y=1,text="FW: v00.00.00",alignment=ALIGN.LEFT,height=1} - local comms_v = TextBox{parent=about,x=1,y=2,text="NT: v00.00.00",alignment=ALIGN.LEFT,height=1} + local fw_v = TextBox{parent=about,x=1,y=1,text="FW: v00.00.00",alignment=ALIGN.LEFT} + local comms_v = TextBox{parent=about,x=1,y=2,text="NT: v00.00.00",alignment=ALIGN.LEFT} fw_v.register(databus.ps, "version", function (version) fw_v.set_value(util.c("FW: ", version)) end) comms_v.register(databus.ps, "comms_version", function (version) comms_v.set_value(util.c("NT: v", version)) end) diff --git a/rtu/configure.lua b/rtu/configure.lua index 90127054..062c76d4 100644 --- a/rtu/configure.lua +++ b/rtu/configure.lua @@ -264,7 +264,7 @@ local function config_view(display) ---@diagnostic disable-next-line: undefined-field local function exit() os.queueEvent("terminate") end - TextBox{parent=display,y=1,text="RTU Gateway Configurator",alignment=CENTER,height=1,fg_bg=style.header} + TextBox{parent=display,y=1,text="RTU Gateway Configurator",alignment=CENTER,fg_bg=style.header} local root_pane_div = Div{parent=display,x=1,y=2} @@ -344,7 +344,7 @@ local function config_view(display) local spkr_c = Div{parent=spkr_cfg,x=2,y=4,width=49} - TextBox{parent=spkr_cfg,x=1,y=2,height=1,text=" Speaker Configuration",fg_bg=cpair(colors.black,colors.cyan)} + TextBox{parent=spkr_cfg,x=1,y=2,text=" Speaker Configuration",fg_bg=cpair(colors.black,colors.cyan)} TextBox{parent=spkr_c,x=1,y=1,height=2,text="Speakers can be connected to this RTU gateway without RTU unit configuration entries."} TextBox{parent=spkr_c,x=1,y=4,height=3,text="You can change the speaker audio volume from the default. The range is 0.0 to 3.0, where 1.0 is standard volume."} @@ -353,7 +353,7 @@ local function config_view(display) TextBox{parent=spkr_c,x=1,y=10,height=3,text="Note: alarm sine waves are at half scale so that multiple will be required to reach full scale.",fg_bg=g_lg_fg_bg} - local s_vol_err = TextBox{parent=spkr_c,x=8,y=14,height=1,width=35,text="Please set a volume.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local s_vol_err = TextBox{parent=spkr_c,x=8,y=14,width=35,text="Please set a volume.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_vol() local vol = tonumber(s_vol.get_value()) @@ -377,19 +377,19 @@ local function config_view(display) local net_pane = MultiPane{parent=net_cfg,x=1,y=4,panes={net_c_1,net_c_2,net_c_3}} - TextBox{parent=net_cfg,x=1,y=2,height=1,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)} + TextBox{parent=net_cfg,x=1,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)} - TextBox{parent=net_c_1,x=1,y=1,height=1,text="Please set the network channels below."} + TextBox{parent=net_c_1,x=1,y=1,text="Please set the network channels below."} TextBox{parent=net_c_1,x=1,y=3,height=4,text="Each of the 5 uniquely named channels, including the 2 below, must be the same for each device in this SCADA network. For multiplayer servers, it is recommended to not use the default channels.",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_1,x=1,y=8,height=1,text="Supervisor Channel"} + TextBox{parent=net_c_1,x=1,y=8,text="Supervisor Channel"} local svr_chan = NumberField{parent=net_c_1,x=1,y=9,width=7,default=ini_cfg.SVR_Channel,min=1,max=65535,fg_bg=bw_fg_bg} TextBox{parent=net_c_1,x=9,y=9,height=4,text="[SVR_CHANNEL]",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_1,x=1,y=11,height=1,text="RTU Channel"} + TextBox{parent=net_c_1,x=1,y=11,text="RTU Channel"} local rtu_chan = NumberField{parent=net_c_1,x=1,y=12,width=7,default=ini_cfg.RTU_Channel,min=1,max=65535,fg_bg=bw_fg_bg} TextBox{parent=net_c_1,x=9,y=12,height=4,text="[RTU_CHANNEL]",fg_bg=g_lg_fg_bg} - local chan_err = TextBox{parent=net_c_1,x=8,y=14,height=1,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local chan_err = TextBox{parent=net_c_1,x=8,y=14,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_channels() local svr_c = tonumber(svr_chan.get_value()) @@ -411,16 +411,16 @@ local function config_view(display) PushButton{parent=net_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=net_c_1,x=44,y=14,text="Next \x1a",callback=submit_channels,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - TextBox{parent=net_c_2,x=1,y=1,height=1,text="Connection Timeout"} + TextBox{parent=net_c_2,x=1,y=1,text="Connection Timeout"} local timeout = NumberField{parent=net_c_2,x=1,y=2,width=7,default=ini_cfg.ConnTimeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg} TextBox{parent=net_c_2,x=9,y=2,height=2,text="seconds (default 5)",fg_bg=g_lg_fg_bg} TextBox{parent=net_c_2,x=1,y=3,height=4,text="You generally do not want or need to modify this. On slow servers, you can increase this to make the system wait longer before assuming a disconnection.",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_2,x=1,y=8,height=1,text="Trusted Range"} + TextBox{parent=net_c_2,x=1,y=8,text="Trusted Range"} local range = NumberField{parent=net_c_2,x=1,y=9,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg} TextBox{parent=net_c_2,x=1,y=10,height=4,text="Setting this to a value larger than 0 prevents connections with devices that many meters (blocks) away in any direction.",fg_bg=g_lg_fg_bg} - local p2_err = TextBox{parent=net_c_2,x=8,y=14,height=1,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local p2_err = TextBox{parent=net_c_2,x=8,y=14,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_ct_tr() local timeout_val = tonumber(timeout.get_value()) @@ -445,7 +445,7 @@ local function config_view(display) TextBox{parent=net_c_3,x=1,y=1,height=2,text="Optionally, set the facility authentication key below. Do NOT use one of your passwords."} TextBox{parent=net_c_3,x=1,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for security on multiplayer servers. All devices on the same network MUST use the same key if any device has a key. This does result in some extra compution (can slow things down).",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_3,x=1,y=11,height=1,text="Facility Auth Key"} + TextBox{parent=net_c_3,x=1,y=11,text="Facility Auth Key"} local key, _, censor = TextField{parent=net_c_3,x=1,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg} local function censor_key(enable) censor(tri(enable, "*", nil)) end @@ -455,7 +455,7 @@ local function config_view(display) hide_key.set_value(true) censor_key(true) - local key_err = TextBox{parent=net_c_3,x=8,y=14,height=1,width=35,text="Key must be at least 8 characters.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local key_err = TextBox{parent=net_c_3,x=8,y=14,width=35,text="Key must be at least 8 characters.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_auth() local v = key.get_value() @@ -475,20 +475,20 @@ local function config_view(display) local log_c_1 = Div{parent=log_cfg,x=2,y=4,width=49} - TextBox{parent=log_cfg,x=1,y=2,height=1,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)} + TextBox{parent=log_cfg,x=1,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)} - TextBox{parent=log_c_1,x=1,y=1,height=1,text="Please configure logging below."} + TextBox{parent=log_c_1,x=1,y=1,text="Please configure logging below."} - TextBox{parent=log_c_1,x=1,y=3,height=1,text="Log File Mode"} + TextBox{parent=log_c_1,x=1,y=3,text="Log File Mode"} local mode = RadioButton{parent=log_c_1,x=1,y=4,default=ini_cfg.LogMode+1,options={"Append on Startup","Replace on Startup"},callback=function()end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.pink} - TextBox{parent=log_c_1,x=1,y=7,height=1,text="Log File Path"} + TextBox{parent=log_c_1,x=1,y=7,text="Log File Path"} local path = TextField{parent=log_c_1,x=1,y=8,width=49,height=1,value=ini_cfg.LogPath,max_len=128,fg_bg=bw_fg_bg} local en_dbg = CheckBox{parent=log_c_1,x=1,y=10,default=ini_cfg.LogDebug,label="Enable Logging Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)} TextBox{parent=log_c_1,x=3,y=11,height=2,text="This results in much larger log files. It is best to only use this when there is a problem.",fg_bg=g_lg_fg_bg} - local path_err = TextBox{parent=log_c_1,x=8,y=14,height=1,width=35,text="Please provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local path_err = TextBox{parent=log_c_1,x=8,y=14,width=35,text="Please provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_log() if path.get_value() ~= "" then @@ -516,17 +516,17 @@ local function config_view(display) local clr_pane = MultiPane{parent=clr_cfg,x=1,y=4,panes={clr_c_1,clr_c_2,clr_c_3,clr_c_4}} - TextBox{parent=clr_cfg,x=1,y=2,height=1,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)} + TextBox{parent=clr_cfg,x=1,y=2,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)} TextBox{parent=clr_c_1,x=1,y=1,height=2,text="Here you can select the color theme for the front panel."} TextBox{parent=clr_c_1,x=1,y=4,height=2,text="Click 'Accessibility' below to access colorblind assistive options.",fg_bg=g_lg_fg_bg} - TextBox{parent=clr_c_1,x=1,y=7,height=1,text="Front Panel Theme"} + TextBox{parent=clr_c_1,x=1,y=7,text="Front Panel Theme"} local fp_theme = RadioButton{parent=clr_c_1,x=1,y=8,default=ini_cfg.FrontPanelTheme,options=themes.FP_THEME_NAMES,callback=function()end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta} TextBox{parent=clr_c_2,x=1,y=1,height=6,text="This system uses color heavily to distinguish ok and not, with some indicators using many colors. By selecting a mode below, indicators will change as shown. For non-standard modes, indicators with more than two colors will be split up."} - TextBox{parent=clr_c_2,x=21,y=7,height=1,text="Preview"} + TextBox{parent=clr_c_2,x=21,y=7,text="Preview"} local _ = IndLight{parent=clr_c_2,x=21,y=8,label="Good",colors=cpair(colors.black,colors.green)} _ = IndLight{parent=clr_c_2,x=21,y=9,label="Warning",colors=cpair(colors.black,colors.yellow)} _ = IndLight{parent=clr_c_2,x=21,y=10,label="Bad",colors=cpair(colors.black,colors.red)} @@ -553,7 +553,7 @@ local function config_view(display) end end - TextBox{parent=clr_c_2,x=1,y=7,height=1,width=10,text="Color Mode"} + TextBox{parent=clr_c_2,x=1,y=7,width=10,text="Color Mode"} local c_mode = RadioButton{parent=clr_c_2,x=1,y=8,default=ini_cfg.ColorMode,options=themes.COLOR_MODE_NAMES,callback=recolor,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta} TextBox{parent=clr_c_2,x=21,y=13,height=2,width=18,text="Note: exact color varies by theme.",fg_bg=g_lg_fg_bg} @@ -603,7 +603,7 @@ local function config_view(display) tool_ctl.color_apply.hide(true) - TextBox{parent=clr_c_3,x=1,y=1,height=1,text="Settings saved!"} + TextBox{parent=clr_c_3,x=1,y=1,text="Settings saved!"} PushButton{parent=clr_c_3,x=1,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)} PushButton{parent=clr_c_3,x=44,y=14,min_width=6,text="Home",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} @@ -625,7 +625,7 @@ local function config_view(display) local sum_pane = MultiPane{parent=summary,x=1,y=4,panes={sum_c_1,sum_c_2,sum_c_3,sum_c_4,sum_c_5,sum_c_6,sum_c_7}} - TextBox{parent=summary,x=1,y=2,height=1,text=" Summary",fg_bg=cpair(colors.black,colors.green)} + TextBox{parent=summary,x=1,y=2,text=" Summary",fg_bg=cpair(colors.black,colors.green)} local setting_list = ListBox{parent=sum_c_1,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} @@ -698,13 +698,13 @@ local function config_view(display) tool_ctl.settings_confirm = PushButton{parent=sum_c_1,x=41,y=14,min_width=9,text="Confirm",callback=function()sum_pane.set_value(2)end,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg} tool_ctl.settings_confirm.hide() - TextBox{parent=sum_c_2,x=1,y=1,height=1,text="The following peripherals will be imported:"} + TextBox{parent=sum_c_2,x=1,y=1,text="The following peripherals will be imported:"} local peri_import_list = ListBox{parent=sum_c_2,x=1,y=3,height=10,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} PushButton{parent=sum_c_2,x=1,y=14,text="\x1b Back",callback=function()sum_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=sum_c_2,x=41,y=14,min_width=9,text="Confirm",callback=function()sum_pane.set_value(3)end,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg} - TextBox{parent=sum_c_3,x=1,y=1,height=1,text="The following redstone entries will be imported:"} + TextBox{parent=sum_c_3,x=1,y=1,text="The following redstone entries will be imported:"} local rs_import_list = ListBox{parent=sum_c_3,x=1,y=3,height=10,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} PushButton{parent=sum_c_3,x=1,y=14,text="\x1b Back",callback=function()sum_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} @@ -720,7 +720,7 @@ local function config_view(display) show_rs_conns() end - TextBox{parent=sum_c_4,x=1,y=1,height=1,text="Settings saved!"} + TextBox{parent=sum_c_4,x=1,y=1,text="Settings saved!"} TextBox{parent=sum_c_4,x=1,y=3,height=4,text="Remember to configure any peripherals or redstone that you have connected to this RTU gateway if you have not already done so, or if you have added, removed, or modified any of them."} PushButton{parent=sum_c_4,x=1,y=8,min_width=24,text="Peripheral Connections",callback=jump_peri_conns,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg} PushButton{parent=sum_c_4,x=1,y=10,min_width=22,text="Redstone Connections",callback=jump_rs_conns,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg} @@ -752,15 +752,15 @@ local function config_view(display) local cl = Div{parent=changelog,x=2,y=4,width=49} - TextBox{parent=changelog,x=1,y=2,height=1,text=" Config Change Log",fg_bg=bw_fg_bg} + TextBox{parent=changelog,x=1,y=2,text=" Config Change Log",fg_bg=bw_fg_bg} local c_log = ListBox{parent=cl,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} for _, change in ipairs(changes) do - TextBox{parent=c_log,text=change[1],height=1,fg_bg=bw_fg_bg} + TextBox{parent=c_log,text=change[1],fg_bg=bw_fg_bg} for _, v in ipairs(change[2]) do local e = Div{parent=c_log,height=#util.strwrap(v,46)} - TextBox{parent=e,y=1,x=1,text="- ",height=1,fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=e,y=1,x=1,text="- ",fg_bg=cpair(colors.gray,colors.white)} TextBox{parent=e,y=1,x=3,text=v,height=e.get_height(),fg_bg=cpair(colors.gray,colors.white)} end end @@ -781,7 +781,7 @@ local function config_view(display) local peri_pane = MultiPane{parent=peri_cfg,x=1,y=4,panes={peri_c_1,peri_c_2,peri_c_3,peri_c_4,peri_c_5,peri_c_6,peri_c_7}} - TextBox{parent=peri_cfg,x=1,y=2,height=1,text=" Peripheral Connections",fg_bg=cpair(colors.black,colors.purple)} + TextBox{parent=peri_cfg,x=1,y=2,text=" Peripheral Connections",fg_bg=cpair(colors.black,colors.purple)} local peri_list = ListBox{parent=peri_c_1,x=1,y=1,height=12,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} @@ -807,7 +807,7 @@ local function config_view(display) PushButton{parent=peri_c_1,x=35,y=14,min_width=7,text="Add +",callback=function()peri_pane.set_value(2)end,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg} PushButton{parent=peri_c_1,x=43,y=14,min_width=7,text="Apply",callback=peri_apply,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg} - TextBox{parent=peri_c_2,x=1,y=1,height=1,text="Select one of the below devices to use."} + TextBox{parent=peri_c_2,x=1,y=1,text="Select one of the below devices to use."} tool_ctl.ppm_devs = ListBox{parent=peri_c_2,x=1,y=3,height=10,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} @@ -815,7 +815,7 @@ local function config_view(display) PushButton{parent=peri_c_2,x=8,y=14,min_width=10,text="Manual +",callback=function()peri_pane.set_value(3)end,fg_bg=cpair(colors.black,colors.orange),active_fg_bg=btn_act_fg_bg} PushButton{parent=peri_c_2,x=26,y=14,min_width=24,text="I don't see my device!",callback=function()peri_pane.set_value(7)end,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg} - TextBox{parent=peri_c_7,x=1,y=1,height=10,text="Make sure your device is either touching the RTU or connected via wired modems. There should be a wired modem on a side of the RTU then one on the device, connected by a cable. The modem on the device needs to be right clicked to connect it (which will turn its border red), at which point the peripheral name will be shown in the chat."} + TextBox{parent=peri_c_7,x=1,y=10,text="Make sure your device is either touching the RTU or connected via wired modems. There should be a wired modem on a side of the RTU then one on the device, connected by a cable. The modem on the device needs to be right clicked to connect it (which will turn its border red), at which point the peripheral name will be shown in the chat."} TextBox{parent=peri_c_7,x=1,y=9,height=4,text="If it still does not show, it may not be compatible. Currently only Boilers, Turbines, Dynamic Tanks, SNAs, SPSs, Induction Matricies, and Environment Detectors are supported."} PushButton{parent=peri_c_7,x=1,y=14,text="\x1b Back",callback=function()peri_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} @@ -934,8 +934,8 @@ local function config_view(display) ---@cast entry ppm_entry local line = Div{parent=tool_ctl.ppm_devs,height=2,fg_bg=cpair(colors.black,bkg)} PushButton{parent=line,x=1,y=1,min_width=9,alignment=LEFT,height=1,text="> SELECT",callback=function()tool_ctl.peri_cfg_manual=false;new_peri(name,entry.type)end,fg_bg=cpair(colors.black,colors.purple),active_fg_bg=cpair(colors.white,colors.black)} - TextBox{parent=line,x=11,y=1,height=1,text=name,fg_bg=cpair(colors.black,bkg)} - TextBox{parent=line,x=11,y=2,height=1,text=entry.type,fg_bg=cpair(colors.gray,bkg)} + TextBox{parent=line,x=11,y=1,text=name,fg_bg=cpair(colors.black,bkg)} + TextBox{parent=line,x=11,y=2,text=entry.type,fg_bg=cpair(colors.gray,bkg)} alternate = not alternate end @@ -948,7 +948,7 @@ local function config_view(display) 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} - local man_p_err = TextBox{parent=peri_c_3,x=8,y=14,height=1,width=35,text="Please enter a peripheral name.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + 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) local function submit_manual_peri() @@ -988,7 +988,7 @@ local function config_view(display) tool_ctl.p_desc = TextBox{parent=peri_c_4,x=1,y=7,height=6,text="",fg_bg=g_lg_fg_bg} tool_ctl.p_desc_ext = TextBox{parent=peri_c_4,x=1,y=6,height=7,text="",fg_bg=g_lg_fg_bg} - tool_ctl.p_err = TextBox{parent=peri_c_4,x=8,y=14,height=1,width=32,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + tool_ctl.p_err = TextBox{parent=peri_c_4,x=8,y=14,width=32,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} tool_ctl.p_err.hide(true) local function back_from_peri_opts() @@ -1073,7 +1073,7 @@ local function config_view(display) PushButton{parent=peri_c_4,x=1,y=14,text="\x1b Back",callback=back_from_peri_opts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=peri_c_4,x=41,y=14,min_width=9,text="Confirm",callback=save_peri_entry,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg} - TextBox{parent=peri_c_5,x=1,y=1,height=1,text="Settings saved!"} + TextBox{parent=peri_c_5,x=1,y=1,text="Settings saved!"} PushButton{parent=peri_c_5,x=1,y=14,text="\x1b Back",callback=function()peri_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=peri_c_5,x=44,y=14,min_width=6,text="Home",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} @@ -1095,9 +1095,9 @@ local function config_view(display) local rs_pane = MultiPane{parent=rs_cfg,x=1,y=4,panes={rs_c_1,rs_c_2,rs_c_3,rs_c_4,rs_c_5,rs_c_6,rs_c_7}} - TextBox{parent=rs_cfg,x=1,y=2,height=1,text=" Redstone Connections",fg_bg=cpair(colors.black,colors.red)} + TextBox{parent=rs_cfg,x=1,y=2,text=" Redstone Connections",fg_bg=cpair(colors.black,colors.red)} - TextBox{parent=rs_c_1,x=1,y=1,height=1,text=" port side/color unit/facility",fg_bg=g_lg_fg_bg} + TextBox{parent=rs_c_1,x=1,y=1,text=" port side/color unit/facility",fg_bg=g_lg_fg_bg} local rs_list = ListBox{parent=rs_c_1,x=1,y=2,height=11,width=49,scroll_height=200,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} local function rs_revert() @@ -1125,7 +1125,7 @@ local function config_view(display) TextBox{parent=rs_c_6,x=1,y=1,height=5,text="You already configured this input. There can only be one entry for each input.\n\nPlease select a different port."} PushButton{parent=rs_c_6,x=1,y=14,text="\x1b Back",callback=function()rs_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - TextBox{parent=rs_c_2,x=1,y=1,height=1,text="Select one of the below ports to use."} + TextBox{parent=rs_c_2,x=1,y=1,text="Select one of the below ports to use."} local rs_ports = ListBox{parent=rs_c_2,x=1,y=3,height=10,width=49,scroll_height=200,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} @@ -1186,8 +1186,8 @@ local function config_view(display) -- add entries to redstone option list local all_w_macro = Div{parent=rs_ports,height=1} PushButton{parent=all_w_macro,x=1,y=1,min_width=14,alignment=LEFT,height=1,text=">ALL_WASTE",callback=function()new_rs(-1)end,fg_bg=cpair(colors.black,colors.green),active_fg_bg=cpair(colors.white,colors.black)} - TextBox{parent=all_w_macro,x=16,y=1,width=5,height=1,text="[n/a]",fg_bg=cpair(colors.lightGray,colors.white)} - TextBox{parent=all_w_macro,x=22,y=1,height=1,text="Create all 4 waste entries",fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=all_w_macro,x=16,y=1,width=5,text="[n/a]",fg_bg=cpair(colors.lightGray,colors.white)} + TextBox{parent=all_w_macro,x=22,y=1,text="Create all 4 waste entries",fg_bg=cpair(colors.gray,colors.white)} for i = 1, rsio.NUM_PORTS do local p = PORT_DESC_MAP[i][1] @@ -1197,8 +1197,8 @@ local function config_view(display) local entry = Div{parent=rs_ports,height=1} PushButton{parent=entry,x=1,y=1,min_width=14,alignment=LEFT,height=1,text=">"..name,callback=function()new_rs(p)end,fg_bg=cpair(colors.black,btn_color),active_fg_bg=cpair(colors.white,colors.black)} - TextBox{parent=entry,x=16,y=1,width=5,height=1,text=io_dir,fg_bg=cpair(colors.lightGray,colors.white)} - TextBox{parent=entry,x=22,y=1,height=1,text=PORT_DESC_MAP[i][2],fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=entry,x=16,y=1,width=5,text=io_dir,fg_bg=cpair(colors.lightGray,colors.white)} + TextBox{parent=entry,x=22,y=1,text=PORT_DESC_MAP[i][2],fg_bg=cpair(colors.gray,colors.white)} end PushButton{parent=rs_c_2,x=1,y=14,text="\x1b Back",callback=function()rs_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} @@ -1212,10 +1212,10 @@ local function config_view(display) TextBox{parent=rs_c_7,x=1,y=11,height=2,text="Analog Input: 0-15 redstone power level input\nAnalog Output: 0-15 scaled redstone power level output"} PushButton{parent=rs_c_7,x=1,y=14,text="\x1b Back",callback=function()rs_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - tool_ctl.rs_cfg_side_l = TextBox{parent=rs_c_3,x=1,y=4,width=11,height=1,text="Output Side"} + tool_ctl.rs_cfg_side_l = TextBox{parent=rs_c_3,x=1,y=4,width=11,text="Output Side"} local side = Radio2D{parent=rs_c_3,x=1,y=5,rows=1,columns=6,default=1,options=side_options,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.red} - tool_ctl.rs_cfg_unit_l = TextBox{parent=rs_c_3,x=25,y=7,width=7,height=1,text="Unit ID"} + tool_ctl.rs_cfg_unit_l = TextBox{parent=rs_c_3,x=25,y=7,width=7,text="Unit ID"} tool_ctl.rs_cfg_unit = NumberField{parent=rs_c_3,x=33,y=7,width=10,max_chars=2,min=1,max=4,fg_bg=bw_fg_bg} local function set_bundled(bundled) @@ -1229,7 +1229,7 @@ local function config_view(display) tool_ctl.rs_cfg_color = Radio2D{parent=rs_c_3,x=1,y=9,rows=4,columns=4,default=1,options=color_options,radio_colors=cpair(colors.lightGray,colors.black),color_map=color_options_map,disable_color=colors.gray,disable_fg_bg=g_lg_fg_bg} tool_ctl.rs_cfg_color.disable() - local rs_err = TextBox{parent=rs_c_3,x=8,y=14,height=1,width=30,text="Unit ID must be within 1 to 4.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local rs_err = TextBox{parent=rs_c_3,x=8,y=14,width=30,text="Unit ID must be within 1 to 4.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} rs_err.hide(true) local function back_from_rs_opts() @@ -1285,7 +1285,7 @@ local function config_view(display) PushButton{parent=rs_c_3,x=1,y=14,text="\x1b Back",callback=back_from_rs_opts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=rs_c_3,x=41,y=14,min_width=9,text="Confirm",callback=save_rs_entry,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg} - TextBox{parent=rs_c_4,x=1,y=1,height=1,text="Settings saved!"} + TextBox{parent=rs_c_4,x=1,y=1,text="Settings saved!"} PushButton{parent=rs_c_4,x=1,y=14,text="\x1b Back",callback=function()rs_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=rs_c_4,x=44,y=14,min_width=6,text="Home",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} @@ -1386,9 +1386,9 @@ local function config_view(display) end local line = Div{parent=peri_import_list,height=3} - TextBox{parent=line,x=1,y=1,height=1,text="@ "..def.name,fg_bg=cpair(colors.black,colors.white)} - TextBox{parent=line,x=1,y=2,height=1,text=status,fg_bg=cpair(color,colors.white)} - TextBox{parent=line,x=1,y=3,height=1,text=desc,fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=line,x=1,y=1,text="@ "..def.name,fg_bg=cpair(colors.black,colors.white)} + TextBox{parent=line,x=1,y=2,text=status,fg_bg=cpair(color,colors.white)} + TextBox{parent=line,x=1,y=3,text=desc,fg_bg=cpair(colors.gray,colors.white)} end rs_import_list.remove_all() @@ -1407,10 +1407,10 @@ local function config_view(display) if def.color ~= nil then conn = def.side .. "/" .. rsio.color_name(def.color) end local line = Div{parent=rs_import_list,height=1} - TextBox{parent=line,x=1,y=1,width=1,height=1,text=io_dir,fg_bg=cpair(colors.lightGray,colors.white)} - TextBox{parent=line,x=2,y=1,width=14,height=1,text=name} - TextBox{parent=line,x=18,y=1,width=string.len(conn),height=1,text=conn,fg_bg=cpair(colors.gray,colors.white)} - TextBox{parent=line,x=40,y=1,height=1,text=unit,fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=line,x=1,y=1,width=1,text=io_dir,fg_bg=cpair(colors.lightGray,colors.white)} + TextBox{parent=line,x=2,y=1,width=14,text=name} + TextBox{parent=line,x=18,y=1,width=string.len(conn),text=conn,fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=line,x=40,y=1,text=unit,fg_bg=cpair(colors.gray,colors.white)} end end @@ -1545,9 +1545,9 @@ local function config_view(display) end local entry = Div{parent=peri_list,height=3} - TextBox{parent=entry,x=1,y=1,height=1,text="@ "..def.name,fg_bg=cpair(colors.black,colors.white)} - TextBox{parent=entry,x=1,y=2,height=1,text=" \x1a "..t_str,fg_bg=cpair(colors.gray,colors.white)} - TextBox{parent=entry,x=1,y=3,height=1,text=desc,fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=entry,x=1,y=1,text="@ "..def.name,fg_bg=cpair(colors.black,colors.white)} + TextBox{parent=entry,x=1,y=2,text=" \x1a "..t_str,fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=entry,x=1,y=3,text=desc,fg_bg=cpair(colors.gray,colors.white)} local edit_btn = PushButton{parent=entry,x=41,y=2,min_width=8,height=1,text="EDIT",callback=function()edit_peri_entry(i,def,t or "")end,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=cpair(colors.lightGray,colors.white)} PushButton{parent=entry,x=41,y=3,min_width=8,height=1,text="DELETE",callback=function()delete_peri_entry(i)end,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg} @@ -1613,10 +1613,10 @@ local function config_view(display) if def.color ~= nil then conn = def.side .. "/" .. rsio.color_name(def.color) end local entry = Div{parent=rs_list,height=1} - TextBox{parent=entry,x=1,y=1,width=1,height=1,text=io_dir,fg_bg=cpair(colors.lightGray,colors.white)} - TextBox{parent=entry,x=2,y=1,width=14,height=1,text=name} - TextBox{parent=entry,x=16,y=1,width=string.len(conn),height=1,text=conn,fg_bg=cpair(colors.gray,colors.white)} - TextBox{parent=entry,x=33,y=1,width=1,height=1,text=unit,fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=entry,x=1,y=1,width=1,text=io_dir,fg_bg=cpair(colors.lightGray,colors.white)} + TextBox{parent=entry,x=2,y=1,width=14,text=name} + TextBox{parent=entry,x=16,y=1,width=string.len(conn),text=conn,fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=entry,x=33,y=1,width=1,text=unit,fg_bg=cpair(colors.gray,colors.white)} PushButton{parent=entry,x=35,y=1,min_width=6,height=1,text="EDIT",callback=function()edit_rs_entry(i)end,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg} PushButton{parent=entry,x=41,y=1,min_width=8,height=1,text="DELETE",callback=function()delete_rs_entry(i)end,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg} end diff --git a/rtu/panel/front_panel.lua b/rtu/panel/front_panel.lua index 738ccca6..a33d3e0f 100644 --- a/rtu/panel/front_panel.lua +++ b/rtu/panel/front_panel.lua @@ -35,7 +35,7 @@ local UNIT_TYPE_LABELS = { "UNKNOWN", "REDSTONE", "BOILER", "TURBINE", "DYNAMIC local function init(panel, units) local disabled_fg = style.fp.disabled_fg - TextBox{parent=panel,y=1,text="RTU GATEWAY",alignment=ALIGN.CENTER,height=1,fg_bg=style.theme.header} + TextBox{parent=panel,y=1,text="RTU GATEWAY",alignment=ALIGN.CENTER,fg_bg=style.theme.header} -- -- system indicators @@ -98,9 +98,9 @@ local function init(panel, units) ---@diagnostic disable-next-line: undefined-field local comp_id = util.sprintf("(%d)", os.getComputerID()) - TextBox{parent=system,x=9,y=4,width=6,height=1,text=comp_id,fg_bg=disabled_fg} + TextBox{parent=system,x=9,y=4,width=6,text=comp_id,fg_bg=disabled_fg} - TextBox{parent=system,x=1,y=14,text="SPEAKERS",height=1,width=8,fg_bg=style.fp.text_fg} + TextBox{parent=system,x=1,y=14,text="SPEAKERS",width=8,fg_bg=style.fp.text_fg} local speaker_count = DataIndicator{parent=system,x=10,y=14,label="",format="%3d",value=0,width=3,fg_bg=style.theme.field_box} speaker_count.register(databus.ps, "speaker_count", speaker_count.update) @@ -109,8 +109,8 @@ local function init(panel, units) -- local about = Div{parent=panel,width=15,height=3,x=1,y=18,fg_bg=disabled_fg} - local fw_v = TextBox{parent=about,x=1,y=1,text="FW: v00.00.00",alignment=ALIGN.LEFT,height=1} - local comms_v = TextBox{parent=about,x=1,y=2,text="NT: v00.00.00",alignment=ALIGN.LEFT,height=1} + local fw_v = TextBox{parent=about,x=1,y=1,text="FW: v00.00.00",alignment=ALIGN.LEFT} + local comms_v = TextBox{parent=about,x=1,y=2,text="NT: v00.00.00",alignment=ALIGN.LEFT} fw_v.register(databus.ps, "version", function (version) fw_v.set_value(util.c("FW: ", version)) end) comms_v.register(databus.ps, "comms_version", function (version) comms_v.set_value(util.c("NT: v", version)) end) @@ -126,7 +126,7 @@ local function init(panel, units) -- show routine statuses for i = 1, list_length do - TextBox{parent=threads,x=1,y=i,text=util.sprintf("%02d",i),height=1} + TextBox{parent=threads,x=1,y=i,text=util.sprintf("%02d",i)} local rt_unit = LED{parent=threads,x=4,y=i,label="RT",colors=ind_grn} rt_unit.register(databus.ps, "routine__unit_" .. i, rt_unit.update) end @@ -144,13 +144,13 @@ local function init(panel, units) -- unit name identifier (type + index) local function get_name(t) return util.c(UNIT_TYPE_LABELS[t + 1], " ", util.trinary(util.is_int(unit.index), unit.index, "")) end - local name_box = TextBox{parent=unit_hw_statuses,y=i,x=3,text=get_name(unit.type),width=15,height=1} + local name_box = TextBox{parent=unit_hw_statuses,y=i,x=3,text=get_name(unit.type),width=15} name_box.register(databus.ps, "unit_type_" .. i, function (t) name_box.set_value(get_name(t)) end) -- assignment (unit # or facility) local for_unit = util.trinary(unit.reactor == 0, "\x1a FACIL ", "\x1a UNIT " .. unit.reactor) - TextBox{parent=unit_hw_statuses,y=i,x=19,text=for_unit,height=1,fg_bg=disabled_fg} + TextBox{parent=unit_hw_statuses,y=i,x=19,text=for_unit,fg_bg=disabled_fg} end end diff --git a/supervisor/configure.lua b/supervisor/configure.lua index 8cad070b..33e20c33 100644 --- a/supervisor/configure.lua +++ b/supervisor/configure.lua @@ -159,7 +159,7 @@ local function config_view(display) ---@diagnostic disable-next-line: undefined-field local function exit() os.queueEvent("terminate") end - TextBox{parent=display,y=1,text="Supervisor Configurator",alignment=CENTER,height=1,fg_bg=style.header} + TextBox{parent=display,y=1,text="Supervisor Configurator",alignment=CENTER,fg_bg=style.header} local root_pane_div = Div{parent=display,x=1,y=2} @@ -228,13 +228,13 @@ local function config_view(display) local svr_pane = MultiPane{parent=svr_cfg,x=1,y=4,panes={svr_c_1,svr_c_2,svr_c_3,svr_c_4,svr_c_5,svr_c_6,svr_c_7}} - TextBox{parent=svr_cfg,x=1,y=2,height=1,text=" Facility Configuration",fg_bg=cpair(colors.black,colors.yellow)} + TextBox{parent=svr_cfg,x=1,y=2,text=" Facility Configuration",fg_bg=cpair(colors.black,colors.yellow)} TextBox{parent=svr_c_1,x=1,y=1,height=3,text="Please enter the number of reactors you have, also referred to as reactor units or 'units' for short. A maximum of 4 is currently supported."} local num_units = NumberField{parent=svr_c_1,x=1,y=5,width=5,max_chars=2,default=ini_cfg.UnitCount,min=1,max=4,fg_bg=bw_fg_bg} - TextBox{parent=svr_c_1,x=7,y=5,height=1,text="reactors"} + TextBox{parent=svr_c_1,x=7,y=5,text="reactors"} - local nu_error = TextBox{parent=svr_c_1,x=8,y=14,height=1,width=35,text="Please set the number of reactors.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local nu_error = TextBox{parent=svr_c_1,x=8,y=14,width=35,text="Please set the number of reactors.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_num_units() local count = tonumber(num_units.get_value()) @@ -255,7 +255,7 @@ local function config_view(display) PushButton{parent=svr_c_1,x=44,y=14,text="Next \x1a",callback=submit_num_units,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} TextBox{parent=svr_c_2,x=1,y=1,height=4,text="Please provide the reactor cooling configuration below. This includes the number of turbines, boilers, and if that reactor has a connection to a dynamic tank for emergency coolant."} - TextBox{parent=svr_c_2,x=1,y=6,height=1,text="UNIT TURBINES BOILERS HAS TANK CONNECTION?",fg_bg=g_lg_fg_bg} + TextBox{parent=svr_c_2,x=1,y=6,text="UNIT TURBINES BOILERS HAS TANK CONNECTION?",fg_bg=g_lg_fg_bg} for i = 1, 4 do local num_t, num_b, has_t = 1, 0, false @@ -277,7 +277,7 @@ local function config_view(display) tool_ctl.cooling_elems[i] = { line = line, turbines = turbines, boilers = boilers, tank = tank } end - local cool_err = TextBox{parent=svr_c_2,x=8,y=14,height=1,width=33,text="Please fill out all fields.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local cool_err = TextBox{parent=svr_c_2,x=8,y=14,width=33,text="Please fill out all fields.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_cooling() local any_missing = false @@ -345,15 +345,15 @@ local function config_view(display) local val = math.max(1, ini_cfg.FacilityTankDefs[i] or 2) local div = Div{parent=svr_c_4,x=1,y=3+(2*i),height=2} - TextBox{parent=div,x=1,y=1,width=33,height=1,text="Unit "..i.." will be connected to..."} - TextBox{parent=div,x=6,y=2,width=3,height=1,text="..."} + TextBox{parent=div,x=1,y=1,width=33,text="Unit "..i.." will be connected to..."} + TextBox{parent=div,x=6,y=2,width=3,text="..."} local tank_opt = Radio2D{parent=div,x=9,y=2,rows=1,columns=2,default=val,options={"its own Unit Tank","a Facility Tank"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.yellow,disable_color=colors.gray,disable_fg_bg=g_lg_fg_bg} - local no_tank = TextBox{parent=div,x=9,y=2,width=34,height=1,text="no tank (as you set two steps ago)",fg_bg=cpair(colors.gray,colors.lightGray),hidden=true} + local no_tank = TextBox{parent=div,x=9,y=2,width=34,text="no tank (as you set two steps ago)",fg_bg=cpair(colors.gray,colors.lightGray),hidden=true} tool_ctl.tank_elems[i] = { div = div, tank_opt = tank_opt, no_tank = no_tank } end - local tank_err = TextBox{parent=svr_c_4,x=8,y=14,height=1,width=33,text="You selected no facility tanks.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local tank_err = TextBox{parent=svr_c_4,x=8,y=14,width=33,text="You selected no facility tanks.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function hide_fconn(i) if i > 1 then tool_ctl.vis_ftanks[i].pipe_conn.hide(true) @@ -402,8 +402,8 @@ local function config_view(display) PushButton{parent=svr_c_4,x=1,y=14,text="\x1b Back",callback=function()svr_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=svr_c_4,x=44,y=14,text="Next \x1a",callback=submit_tank_defs,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - TextBox{parent=svr_c_5,x=1,y=1,height=1,text="Please select your dynamic tank layout."} - TextBox{parent=svr_c_5,x=12,y=3,height=1,text="Facility Tanks Unit Tanks",fg_bg=g_lg_fg_bg} + TextBox{parent=svr_c_5,x=1,y=1,text="Please select your dynamic tank layout."} + TextBox{parent=svr_c_5,x=12,y=3,text="Facility Tanks Unit Tanks",fg_bg=g_lg_fg_bg} --#region Tank Layout Visualizer @@ -416,25 +416,25 @@ local function config_view(display) -- draw unit tanks and their pipes for i = 1, 4 do local line = Div{parent=vis,x=22,y=(i*2)-1,width=13,height=1} - TextBox{parent=line,width=5,height=1,text=string.rep("\x8c",5),fg_bg=pipe_cpair} - local label = TextBox{parent=line,x=7,y=1,width=7,height=1,text="Tank ?"} + TextBox{parent=line,width=5,text=string.rep("\x8c",5),fg_bg=pipe_cpair} + local label = TextBox{parent=line,x=7,y=1,width=7,text="Tank ?"} tool_ctl.vis_utanks[i] = { line = line, label = label } end -- draw facility tank connections local ftank_1 = Div{parent=vis,x=1,y=1,width=13,height=1} - TextBox{parent=ftank_1,width=7,height=1,text="Tank F1"} + TextBox{parent=ftank_1,width=7,text="Tank F1"} tool_ctl.vis_ftanks[1] = { line = ftank_1, pipe_direct = TextBox{parent=ftank_1,x=9,y=1,width=5,text=string.rep("\x8c",5),fg_bg=pipe_cpair} } for i = 2, 4 do local line = Div{parent=vis,x=1,y=(i-1)*2,width=13,height=2} - local pipe_conn = TextBox{parent=line,x=13,y=2,width=1,height=1,text="\x8c",fg_bg=pipe_cpair} + local pipe_conn = TextBox{parent=line,x=13,y=2,width=1,text="\x8c",fg_bg=pipe_cpair} local pipe_chain = TextBox{parent=line,x=12,y=1,width=1,height=2,text="\x95\n\x8d",fg_bg=pipe_cpair} - local pipe_direct = TextBox{parent=line,x=9,y=2,width=4,height=1,text="\x8c\x8c\x8c\x8c",fg_bg=pipe_cpair} - local label = TextBox{parent=line,x=1,y=2,width=7,height=1,text=""} + local pipe_direct = TextBox{parent=line,x=9,y=2,width=4,text="\x8c\x8c\x8c\x8c",fg_bg=pipe_cpair} + local label = TextBox{parent=line,x=1,y=2,width=7,text=""} tool_ctl.vis_ftanks[i] = { line = line, pipe_conn = pipe_conn, pipe_chain = pipe_chain, pipe_direct = pipe_direct, label = label } end @@ -608,32 +608,32 @@ local function config_view(display) local net_pane = MultiPane{parent=net_cfg,x=1,y=4,panes={net_c_1,net_c_2,net_c_3,net_c_4}} - TextBox{parent=net_cfg,x=1,y=2,height=1,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)} + TextBox{parent=net_cfg,x=1,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)} - TextBox{parent=net_c_1,x=1,y=1,height=1,text="Please set the network channels below."} + TextBox{parent=net_c_1,x=1,y=1,text="Please set the network channels below."} TextBox{parent=net_c_1,x=1,y=3,height=4,text="Each of the 5 uniquely named channels must be the same for each device in this SCADA network. For multiplayer servers, it is recommended to not use the default channels.",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_1,x=1,y=8,height=1,width=18,text="Supervisor Channel"} + TextBox{parent=net_c_1,x=1,y=8,width=18,text="Supervisor Channel"} local svr_chan = NumberField{parent=net_c_1,x=21,y=8,width=7,default=ini_cfg.SVR_Channel,min=1,max=65535,fg_bg=bw_fg_bg} TextBox{parent=net_c_1,x=29,y=8,height=4,text="[SVR_CHANNEL]",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_1,x=1,y=9,height=1,width=11,text="PLC Channel"} + TextBox{parent=net_c_1,x=1,y=9,width=11,text="PLC Channel"} local plc_chan = NumberField{parent=net_c_1,x=21,y=9,width=7,default=ini_cfg.PLC_Channel,min=1,max=65535,fg_bg=bw_fg_bg} TextBox{parent=net_c_1,x=29,y=9,height=4,text="[PLC_CHANNEL]",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_1,x=1,y=10,height=1,width=19,text="RTU Gateway Channel"} + TextBox{parent=net_c_1,x=1,y=10,width=19,text="RTU Gateway Channel"} local rtu_chan = NumberField{parent=net_c_1,x=21,y=10,width=7,default=ini_cfg.RTU_Channel,min=1,max=65535,fg_bg=bw_fg_bg} TextBox{parent=net_c_1,x=29,y=10,height=4,text="[RTU_CHANNEL]",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_1,x=1,y=11,height=1,width=19,text="Coordinator Channel"} + TextBox{parent=net_c_1,x=1,y=11,width=19,text="Coordinator Channel"} local crd_chan = NumberField{parent=net_c_1,x=21,y=11,width=7,default=ini_cfg.CRD_Channel,min=1,max=65535,fg_bg=bw_fg_bg} TextBox{parent=net_c_1,x=29,y=11,height=4,text="[CRD_CHANNEL]",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_1,x=1,y=12,height=1,width=14,text="Pocket Channel"} + TextBox{parent=net_c_1,x=1,y=12,width=14,text="Pocket Channel"} local pkt_chan = NumberField{parent=net_c_1,x=21,y=12,width=7,default=ini_cfg.PKT_Channel,min=1,max=65535,fg_bg=bw_fg_bg} TextBox{parent=net_c_1,x=29,y=12,height=4,text="[PKT_CHANNEL]",fg_bg=g_lg_fg_bg} - local chan_err = TextBox{parent=net_c_1,x=8,y=14,height=1,width=35,text="Please set all channels.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local chan_err = TextBox{parent=net_c_1,x=8,y=14,width=35,text="Please set all channels.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_channels() local svr_c, plc_c, rtu_c = tonumber(svr_chan.get_value()), tonumber(plc_chan.get_value()), tonumber(rtu_chan.get_value()) @@ -649,24 +649,24 @@ local function config_view(display) PushButton{parent=net_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=net_c_1,x=44,y=14,text="Next \x1a",callback=submit_channels,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - TextBox{parent=net_c_2,x=1,y=1,height=1,text="Please set the connection timeouts below."} + TextBox{parent=net_c_2,x=1,y=1,text="Please set the connection timeouts below."} TextBox{parent=net_c_2,x=1,y=3,height=4,text="You generally should not need to modify these. On slow servers, you can try to increase this to make the system wait longer before assuming a disconnection. The default for all is 5 seconds.",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_2,x=1,y=8,height=1,width=11,text="PLC Timeout"} + TextBox{parent=net_c_2,x=1,y=8,width=11,text="PLC Timeout"} local plc_timeout = NumberField{parent=net_c_2,x=21,y=8,width=7,default=ini_cfg.PLC_Timeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg} - TextBox{parent=net_c_2,x=1,y=9,height=1,width=19,text="RTU Gateway Timeout"} + TextBox{parent=net_c_2,x=1,y=9,width=19,text="RTU Gateway Timeout"} local rtu_timeout = NumberField{parent=net_c_2,x=21,y=9,width=7,default=ini_cfg.RTU_Timeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg} - TextBox{parent=net_c_2,x=1,y=10,height=1,width=19,text="Coordinator Timeout"} + TextBox{parent=net_c_2,x=1,y=10,width=19,text="Coordinator Timeout"} local crd_timeout = NumberField{parent=net_c_2,x=21,y=10,width=7,default=ini_cfg.CRD_Timeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg} - TextBox{parent=net_c_2,x=1,y=11,height=1,width=14,text="Pocket Timeout"} + TextBox{parent=net_c_2,x=1,y=11,width=14,text="Pocket Timeout"} local pkt_timeout = NumberField{parent=net_c_2,x=21,y=11,width=7,default=ini_cfg.PKT_Timeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg} TextBox{parent=net_c_2,x=29,y=8,height=4,width=7,text="seconds\nseconds\nseconds\nseconds",fg_bg=g_lg_fg_bg} - local ct_err = TextBox{parent=net_c_2,x=8,y=14,height=1,width=35,text="Please set all connection timeouts.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local ct_err = TextBox{parent=net_c_2,x=8,y=14,width=35,text="Please set all connection timeouts.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_timeouts() local plc_cto, rtu_cto, crd_cto, pkt_cto = tonumber(plc_timeout.get_value()), tonumber(rtu_timeout.get_value()), tonumber(crd_timeout.get_value()), tonumber(pkt_timeout.get_value()) @@ -680,13 +680,13 @@ local function config_view(display) PushButton{parent=net_c_2,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=net_c_2,x=44,y=14,text="Next \x1a",callback=submit_timeouts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - TextBox{parent=net_c_3,x=1,y=1,height=1,text="Please set the trusted range below."} + TextBox{parent=net_c_3,x=1,y=1,text="Please set the trusted range below."} TextBox{parent=net_c_3,x=1,y=3,height=3,text="Setting this to a value larger than 0 prevents connections with devices that many meters (blocks) away in any direction.",fg_bg=g_lg_fg_bg} TextBox{parent=net_c_3,x=1,y=7,height=2,text="This is optional. You can disable this functionality by setting the value to 0.",fg_bg=g_lg_fg_bg} local range = NumberField{parent=net_c_3,x=1,y=10,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg} - local tr_err = TextBox{parent=net_c_3,x=8,y=14,height=1,width=35,text="Please set the trusted range.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local tr_err = TextBox{parent=net_c_3,x=8,y=14,width=35,text="Please set the trusted range.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_tr() local range_val = tonumber(range.get_value()) @@ -703,7 +703,7 @@ local function config_view(display) TextBox{parent=net_c_4,x=1,y=1,height=2,text="Optionally, set the facility authentication key below. Do NOT use one of your passwords."} TextBox{parent=net_c_4,x=1,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for security on multiplayer servers. All devices on the same network MUST use the same key if any device has a key. This does result in some extra compution (can slow things down).",fg_bg=g_lg_fg_bg} - TextBox{parent=net_c_4,x=1,y=11,height=1,text="Facility Auth Key"} + TextBox{parent=net_c_4,x=1,y=11,text="Facility Auth Key"} local key, _, censor = TextField{parent=net_c_4,x=1,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg} local function censor_key(enable) censor(util.trinary(enable, "*", nil)) end @@ -713,7 +713,7 @@ local function config_view(display) hide_key.set_value(true) censor_key(true) - local key_err = TextBox{parent=net_c_4,x=8,y=14,height=1,width=35,text="Key must be at least 8 characters.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local key_err = TextBox{parent=net_c_4,x=8,y=14,width=35,text="Key must be at least 8 characters.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_auth() local v = key.get_value() @@ -733,20 +733,20 @@ local function config_view(display) local log_c_1 = Div{parent=log_cfg,x=2,y=4,width=49} - TextBox{parent=log_cfg,x=1,y=2,height=1,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)} + TextBox{parent=log_cfg,x=1,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)} - TextBox{parent=log_c_1,x=1,y=1,height=1,text="Please configure logging below."} + TextBox{parent=log_c_1,x=1,y=1,text="Please configure logging below."} - TextBox{parent=log_c_1,x=1,y=3,height=1,text="Log File Mode"} + TextBox{parent=log_c_1,x=1,y=3,text="Log File Mode"} local mode = RadioButton{parent=log_c_1,x=1,y=4,default=ini_cfg.LogMode+1,options={"Append on Startup","Replace on Startup"},callback=function()end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.pink} - TextBox{parent=log_c_1,x=1,y=7,height=1,text="Log File Path"} + TextBox{parent=log_c_1,x=1,y=7,text="Log File Path"} local path = TextField{parent=log_c_1,x=1,y=8,width=49,height=1,value=ini_cfg.LogPath,max_len=128,fg_bg=bw_fg_bg} local en_dbg = CheckBox{parent=log_c_1,x=1,y=10,default=ini_cfg.LogDebug,label="Enable Logging Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)} TextBox{parent=log_c_1,x=3,y=11,height=2,text="This results in much larger log files. It is best to only use this when there is a problem.",fg_bg=g_lg_fg_bg} - local path_err = TextBox{parent=log_c_1,x=8,y=14,height=1,width=35,text="Please provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} + local path_err = TextBox{parent=log_c_1,x=8,y=14,width=35,text="Please provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true} local function submit_log() if path.get_value() ~= "" then @@ -774,17 +774,17 @@ local function config_view(display) local clr_pane = MultiPane{parent=clr_cfg,x=1,y=4,panes={clr_c_1,clr_c_2,clr_c_3,clr_c_4}} - TextBox{parent=clr_cfg,x=1,y=2,height=1,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)} + TextBox{parent=clr_cfg,x=1,y=2,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)} TextBox{parent=clr_c_1,x=1,y=1,height=2,text="Here you can select the color theme for the front panel."} TextBox{parent=clr_c_1,x=1,y=4,height=2,text="Click 'Accessibility' below to access colorblind assistive options.",fg_bg=g_lg_fg_bg} - TextBox{parent=clr_c_1,x=1,y=7,height=1,text="Front Panel Theme"} + TextBox{parent=clr_c_1,x=1,y=7,text="Front Panel Theme"} local fp_theme = RadioButton{parent=clr_c_1,x=1,y=8,default=ini_cfg.FrontPanelTheme,options=themes.FP_THEME_NAMES,callback=function()end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta} TextBox{parent=clr_c_2,x=1,y=1,height=6,text="This system uses color heavily to distinguish ok and not, with some indicators using many colors. By selecting a mode below, indicators will change as shown. For non-standard modes, indicators with more than two colors will be split up."} - TextBox{parent=clr_c_2,x=21,y=7,height=1,text="Preview"} + TextBox{parent=clr_c_2,x=21,y=7,text="Preview"} local _ = IndLight{parent=clr_c_2,x=21,y=8,label="Good",colors=cpair(colors.black,colors.green)} _ = IndLight{parent=clr_c_2,x=21,y=9,label="Warning",colors=cpair(colors.black,colors.yellow)} _ = IndLight{parent=clr_c_2,x=21,y=10,label="Bad",colors=cpair(colors.black,colors.red)} @@ -811,7 +811,7 @@ local function config_view(display) end end - TextBox{parent=clr_c_2,x=1,y=7,height=1,width=10,text="Color Mode"} + TextBox{parent=clr_c_2,x=1,y=7,width=10,text="Color Mode"} local c_mode = RadioButton{parent=clr_c_2,x=1,y=8,default=ini_cfg.ColorMode,options=themes.COLOR_MODE_NAMES,callback=recolor,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta} TextBox{parent=clr_c_2,x=21,y=13,height=2,width=18,text="Note: exact color varies by theme.",fg_bg=g_lg_fg_bg} @@ -865,7 +865,7 @@ local function config_view(display) clr_pane.set_value(1) end - TextBox{parent=clr_c_3,x=1,y=1,height=1,text="Settings saved!"} + TextBox{parent=clr_c_3,x=1,y=1,text="Settings saved!"} PushButton{parent=clr_c_3,x=1,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)} PushButton{parent=clr_c_3,x=44,y=14,min_width=6,text="Home",callback=c_go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} @@ -884,7 +884,7 @@ local function config_view(display) local sum_pane = MultiPane{parent=summary,x=1,y=4,panes={sum_c_1,sum_c_2,sum_c_3,sum_c_4}} - TextBox{parent=summary,x=1,y=2,height=1,text=" Summary",fg_bg=cpair(colors.black,colors.green)} + TextBox{parent=summary,x=1,y=2,text=" Summary",fg_bg=cpair(colors.black,colors.green)} local setting_list = ListBox{parent=sum_c_1,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} @@ -961,7 +961,7 @@ local function config_view(display) tool_ctl.show_key_btn = PushButton{parent=sum_c_1,x=8,y=14,min_width=17,text="Unhide Auth Key",callback=function()tool_ctl.show_auth_key()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=cpair(colors.lightGray,colors.white)} tool_ctl.settings_apply = PushButton{parent=sum_c_1,x=43,y=14,min_width=7,text="Apply",callback=save_and_continue,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg} - TextBox{parent=sum_c_2,x=1,y=1,height=1,text="Settings saved!"} + TextBox{parent=sum_c_2,x=1,y=1,text="Settings saved!"} local function go_home() main_pane.set_value(1) @@ -994,15 +994,15 @@ local function config_view(display) local cl = Div{parent=changelog,x=2,y=4,width=49} - TextBox{parent=changelog,x=1,y=2,height=1,text=" Config Change Log",fg_bg=bw_fg_bg} + TextBox{parent=changelog,x=1,y=2,text=" Config Change Log",fg_bg=bw_fg_bg} local c_log = ListBox{parent=cl,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} for _, change in ipairs(changes) do - TextBox{parent=c_log,text=change[1],height=1,fg_bg=bw_fg_bg} + TextBox{parent=c_log,text=change[1],fg_bg=bw_fg_bg} for _, v in ipairs(change[2]) do local e = Div{parent=c_log,height=#util.strwrap(v,46)} - TextBox{parent=e,y=1,x=1,text="- ",height=1,fg_bg=cpair(colors.gray,colors.white)} + TextBox{parent=e,y=1,x=1,text="- ",fg_bg=cpair(colors.gray,colors.white)} TextBox{parent=e,y=1,x=3,text=v,height=e.get_height(),fg_bg=cpair(colors.gray,colors.white)} end end @@ -1013,8 +1013,8 @@ local function config_view(display) local i_err = Div{parent=import_err,x=2,y=4,width=49} - TextBox{parent=import_err,x=1,y=2,height=1,text=" Import Error",fg_bg=cpair(colors.black,colors.red)} - TextBox{parent=i_err,x=1,y=1,height=1,text="There is a problem with your config.lua file:"} + TextBox{parent=import_err,x=1,y=2,text=" Import Error",fg_bg=cpair(colors.black,colors.red)} + TextBox{parent=i_err,x=1,y=1,text="There is a problem with your config.lua file:"} local import_err_msg = TextBox{parent=i_err,x=1,y=3,height=6,text=""} diff --git a/supervisor/panel/components/pdg_entry.lua b/supervisor/panel/components/pdg_entry.lua index 5bee3359..de68b8cf 100644 --- a/supervisor/panel/components/pdg_entry.lua +++ b/supervisor/panel/components/pdg_entry.lua @@ -31,18 +31,18 @@ local function init(parent, id) local ps_prefix = "pdg_" .. id .. "_" - TextBox{parent=entry,x=1,y=1,text="",width=8,height=1,fg_bg=s_hi_box} - local pdg_addr = TextBox{parent=entry,x=1,y=2,text="@ C ??",alignment=ALIGN.CENTER,width=8,height=1,fg_bg=s_hi_box,nav_active=cpair(colors.gray,colors.black)} - TextBox{parent=entry,x=1,y=3,text="",width=8,height=1,fg_bg=s_hi_box} + TextBox{parent=entry,x=1,y=1,text="",width=8,fg_bg=s_hi_box} + local pdg_addr = TextBox{parent=entry,x=1,y=2,text="@ C ??",alignment=ALIGN.CENTER,width=8,fg_bg=s_hi_box,nav_active=cpair(colors.gray,colors.black)} + TextBox{parent=entry,x=1,y=3,text="",width=8,fg_bg=s_hi_box} pdg_addr.register(databus.ps, ps_prefix .. "addr", pdg_addr.set_value) - TextBox{parent=entry,x=10,y=2,text="FW:",width=3,height=1} - local pdg_fw_v = TextBox{parent=entry,x=14,y=2,text=" ------- ",width=20,height=1,fg_bg=label_fg} + TextBox{parent=entry,x=10,y=2,text="FW:",width=3} + local pdg_fw_v = TextBox{parent=entry,x=14,y=2,text=" ------- ",width=20,fg_bg=label_fg} pdg_fw_v.register(databus.ps, ps_prefix .. "fw", pdg_fw_v.set_value) - TextBox{parent=entry,x=35,y=2,text="RTT:",width=4,height=1} + TextBox{parent=entry,x=35,y=2,text="RTT:",width=4} local pdg_rtt = DataIndicator{parent=entry,x=40,y=2,label="",unit="",format="%5d",value=0,width=5,fg_bg=label_fg} - TextBox{parent=entry,x=46,y=2,text="ms",width=4,height=1,fg_bg=label_fg} + TextBox{parent=entry,x=46,y=2,text="ms",width=4,fg_bg=label_fg} pdg_rtt.register(databus.ps, ps_prefix .. "rtt", pdg_rtt.update) pdg_rtt.register(databus.ps, ps_prefix .. "rtt_color", pdg_rtt.recolor) diff --git a/supervisor/panel/components/rtu_entry.lua b/supervisor/panel/components/rtu_entry.lua index 03c4c627..edb9b3ea 100644 --- a/supervisor/panel/components/rtu_entry.lua +++ b/supervisor/panel/components/rtu_entry.lua @@ -31,22 +31,22 @@ local function init(parent, id) local ps_prefix = "rtu_" .. id .. "_" - TextBox{parent=entry,x=1,y=1,text="",width=8,height=1,fg_bg=s_hi_box} - local rtu_addr = TextBox{parent=entry,x=1,y=2,text="@ C ??",alignment=ALIGN.CENTER,width=8,height=1,fg_bg=s_hi_box,nav_active=cpair(colors.gray,colors.black)} - TextBox{parent=entry,x=1,y=3,text="",width=8,height=1,fg_bg=s_hi_box} + TextBox{parent=entry,x=1,y=1,text="",width=8,fg_bg=s_hi_box} + local rtu_addr = TextBox{parent=entry,x=1,y=2,text="@ C ??",alignment=ALIGN.CENTER,width=8,fg_bg=s_hi_box,nav_active=cpair(colors.gray,colors.black)} + TextBox{parent=entry,x=1,y=3,text="",width=8,fg_bg=s_hi_box} rtu_addr.register(databus.ps, ps_prefix .. "addr", rtu_addr.set_value) - TextBox{parent=entry,x=10,y=2,text="UNITS:",width=7,height=1} + TextBox{parent=entry,x=10,y=2,text="UNITS:",width=7} local unit_count = DataIndicator{parent=entry,x=17,y=2,label="",unit="",format="%2d",value=0,width=2,fg_bg=style.fp.label_d_fg} unit_count.register(databus.ps, ps_prefix .. "units", unit_count.set_value) - TextBox{parent=entry,x=21,y=2,text="FW:",width=3,height=1} - local rtu_fw_v = TextBox{parent=entry,x=25,y=2,text=" ------- ",width=9,height=1,fg_bg=label_fg} + TextBox{parent=entry,x=21,y=2,text="FW:",width=3} + local rtu_fw_v = TextBox{parent=entry,x=25,y=2,text=" ------- ",width=9,fg_bg=label_fg} rtu_fw_v.register(databus.ps, ps_prefix .. "fw", rtu_fw_v.set_value) - TextBox{parent=entry,x=36,y=2,text="RTT:",width=4,height=1} + TextBox{parent=entry,x=36,y=2,text="RTT:",width=4} local rtu_rtt = DataIndicator{parent=entry,x=40,y=2,label="",unit="",format="%5d",value=0,width=5,fg_bg=label_fg} - TextBox{parent=entry,x=46,y=2,text="ms",width=4,height=1,fg_bg=label_fg} + TextBox{parent=entry,x=46,y=2,text="ms",width=4,fg_bg=label_fg} rtu_rtt.register(databus.ps, ps_prefix .. "rtt", rtu_rtt.update) rtu_rtt.register(databus.ps, ps_prefix .. "rtt_color", rtu_rtt.recolor) diff --git a/supervisor/panel/front_panel.lua b/supervisor/panel/front_panel.lua index 9bf8e7b5..5f042b0d 100644 --- a/supervisor/panel/front_panel.lua +++ b/supervisor/panel/front_panel.lua @@ -40,7 +40,7 @@ local function init(panel) local label_fg = style.fp.label_fg local label_d_fg = style.fp.label_d_fg - TextBox{parent=panel,y=1,text="SCADA SUPERVISOR",alignment=ALIGN.CENTER,height=1,fg_bg=style.theme.header} + TextBox{parent=panel,y=1,text="SCADA SUPERVISOR",alignment=ALIGN.CENTER,fg_bg=style.theme.header} local page_div = Div{parent=panel,x=1,y=3} @@ -66,15 +66,15 @@ local function init(panel) ---@diagnostic disable-next-line: undefined-field local comp_id = util.sprintf("(%d)", os.getComputerID()) - TextBox{parent=system,x=9,y=4,width=6,height=1,text=comp_id,fg_bg=style.fp.disabled_fg} + TextBox{parent=system,x=9,y=4,width=6,text=comp_id,fg_bg=style.fp.disabled_fg} -- -- about footer -- local about = Div{parent=main_page,width=15,height=3,x=1,y=16,fg_bg=style.fp.disabled_fg} - local fw_v = TextBox{parent=about,x=1,y=1,text="FW: v00.00.00",alignment=ALIGN.LEFT,height=1} - local comms_v = TextBox{parent=about,x=1,y=2,text="NT: v00.00.00",alignment=ALIGN.LEFT,height=1} + local fw_v = TextBox{parent=about,x=1,y=1,text="FW: v00.00.00",alignment=ALIGN.LEFT} + local comms_v = TextBox{parent=about,x=1,y=2,text="NT: v00.00.00",alignment=ALIGN.LEFT} fw_v.register(databus.ps, "version", function (version) fw_v.set_value(util.c("FW: ", version)) end) comms_v.register(databus.ps, "comms_version", function (version) comms_v.set_value(util.c("NT: v", version)) end) @@ -92,23 +92,23 @@ local function init(panel) local ps_prefix = "plc_" .. i .. "_" local plc_entry = Div{parent=plc_list,height=3,fg_bg=s_hi_bright} - TextBox{parent=plc_entry,x=1,y=1,text="",width=8,height=1,fg_bg=s_hi_box} - TextBox{parent=plc_entry,x=1,y=2,text="UNIT "..i,alignment=ALIGN.CENTER,width=8,height=1,fg_bg=s_hi_box} - TextBox{parent=plc_entry,x=1,y=3,text="",width=8,height=1,fg_bg=s_hi_box} + TextBox{parent=plc_entry,x=1,y=1,text="",width=8,fg_bg=s_hi_box} + TextBox{parent=plc_entry,x=1,y=2,text="UNIT "..i,alignment=ALIGN.CENTER,width=8,fg_bg=s_hi_box} + TextBox{parent=plc_entry,x=1,y=3,text="",width=8,fg_bg=s_hi_box} local conn = LED{parent=plc_entry,x=10,y=2,label="LINK",colors=cpair(colors.green_hc,colors.green_off)} conn.register(databus.ps, ps_prefix .. "conn", conn.update) - local plc_addr = TextBox{parent=plc_entry,x=17,y=2,text=" --- ",width=5,height=1,fg_bg=label_d_fg} + local plc_addr = TextBox{parent=plc_entry,x=17,y=2,text=" --- ",width=5,fg_bg=label_d_fg} plc_addr.register(databus.ps, ps_prefix .. "addr", plc_addr.set_value) - TextBox{parent=plc_entry,x=23,y=2,text="FW:",width=3,height=1} - local plc_fw_v = TextBox{parent=plc_entry,x=27,y=2,text=" ------- ",width=9,height=1,fg_bg=label_fg} + TextBox{parent=plc_entry,x=23,y=2,text="FW:",width=3} + local plc_fw_v = TextBox{parent=plc_entry,x=27,y=2,text=" ------- ",width=9,fg_bg=label_fg} plc_fw_v.register(databus.ps, ps_prefix .. "fw", plc_fw_v.set_value) - TextBox{parent=plc_entry,x=37,y=2,text="RTT:",width=4,height=1} + TextBox{parent=plc_entry,x=37,y=2,text="RTT:",width=4} local plc_rtt = DataIndicator{parent=plc_entry,x=42,y=2,label="",unit="",format="%4d",value=0,width=4,fg_bg=label_fg} - TextBox{parent=plc_entry,x=47,y=2,text="ms",width=4,height=1,fg_bg=label_fg} + TextBox{parent=plc_entry,x=47,y=2,text="ms",width=4,fg_bg=label_fg} plc_rtt.register(databus.ps, ps_prefix .. "rtt", plc_rtt.update) plc_rtt.register(databus.ps, ps_prefix .. "rtt_color", plc_rtt.recolor) @@ -129,17 +129,17 @@ local function init(panel) local crd_conn = LED{parent=crd_box,x=2,y=2,label="CONNECTION",colors=cpair(colors.green_hc,colors.green_off)} crd_conn.register(databus.ps, "crd_conn", crd_conn.update) - TextBox{parent=crd_box,x=4,y=3,text="COMPUTER",width=8,height=1,fg_bg=label_d_fg} - local crd_addr = TextBox{parent=crd_box,x=13,y=3,text="---",width=5,height=1,fg_bg=label_d_fg} + TextBox{parent=crd_box,x=4,y=3,text="COMPUTER",width=8,fg_bg=label_d_fg} + local crd_addr = TextBox{parent=crd_box,x=13,y=3,text="---",width=5,fg_bg=label_d_fg} crd_addr.register(databus.ps, "crd_addr", crd_addr.set_value) - TextBox{parent=crd_box,x=22,y=2,text="FW:",width=3,height=1} - local crd_fw_v = TextBox{parent=crd_box,x=26,y=2,text=" ------- ",width=9,height=1,fg_bg=label_fg} + TextBox{parent=crd_box,x=22,y=2,text="FW:",width=3} + local crd_fw_v = TextBox{parent=crd_box,x=26,y=2,text=" ------- ",width=9,fg_bg=label_fg} crd_fw_v.register(databus.ps, "crd_fw", crd_fw_v.set_value) - TextBox{parent=crd_box,x=36,y=2,text="RTT:",width=4,height=1} + TextBox{parent=crd_box,x=36,y=2,text="RTT:",width=4} local crd_rtt = DataIndicator{parent=crd_box,x=41,y=2,label="",unit="",format="%5d",value=0,width=5,fg_bg=label_fg} - TextBox{parent=crd_box,x=47,y=2,text="ms",width=4,height=1,fg_bg=label_fg} + TextBox{parent=crd_box,x=47,y=2,text="ms",width=4,fg_bg=label_fg} crd_rtt.register(databus.ps, "crd_rtt", crd_rtt.update) crd_rtt.register(databus.ps, "crd_rtt_color", crd_rtt.recolor) From 0ecaa42a7f70db74b2b1c8a301de174d41629588 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sun, 30 Jun 2024 14:05:34 -0400 Subject: [PATCH 39/44] restored incorrectly modified height --- rtu/configure.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtu/configure.lua b/rtu/configure.lua index 062c76d4..e34315c2 100644 --- a/rtu/configure.lua +++ b/rtu/configure.lua @@ -815,7 +815,7 @@ local function config_view(display) PushButton{parent=peri_c_2,x=8,y=14,min_width=10,text="Manual +",callback=function()peri_pane.set_value(3)end,fg_bg=cpair(colors.black,colors.orange),active_fg_bg=btn_act_fg_bg} PushButton{parent=peri_c_2,x=26,y=14,min_width=24,text="I don't see my device!",callback=function()peri_pane.set_value(7)end,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg} - TextBox{parent=peri_c_7,x=1,y=10,text="Make sure your device is either touching the RTU or connected via wired modems. There should be a wired modem on a side of the RTU then one on the device, connected by a cable. The modem on the device needs to be right clicked to connect it (which will turn its border red), at which point the peripheral name will be shown in the chat."} + TextBox{parent=peri_c_7,x=1,y=1,height=10,text="Make sure your device is either touching the RTU or connected via wired modems. There should be a wired modem on a side of the RTU then one on the device, connected by a cable. The modem on the device needs to be right clicked to connect it (which will turn its border red), at which point the peripheral name will be shown in the chat."} TextBox{parent=peri_c_7,x=1,y=9,height=4,text="If it still does not show, it may not be compatible. Currently only Boilers, Turbines, Dynamic Tanks, SNAs, SPSs, Induction Matricies, and Environment Detectors are supported."} PushButton{parent=peri_c_7,x=1,y=14,text="\x1b Back",callback=function()peri_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} From 2fb3d9b515e013c0902dad4b3da7b5c5e3c30099 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Tue, 2 Jul 2024 22:07:12 -0400 Subject: [PATCH 40/44] #514 cleaned up download logic and added retries --- ccmsi.lua | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/ccmsi.lua b/ccmsi.lua index bc911123..a2c6e186 100644 --- a/ccmsi.lua +++ b/ccmsi.lua @@ -18,7 +18,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. local function println(message) print(tostring(message)) end local function print(message) term.write(tostring(message)) end -local CCMSI_VERSION = "v1.15" +local CCMSI_VERSION = "v1.16" local install_dir = "/.install-cache" local manifest_path = "https://mikaylafischler.github.io/cc-mek-scada/manifests/" @@ -120,6 +120,22 @@ local function write_install_manifest(manifest, dependencies) imfile.close() end +-- try at most 3 times to download a file from the repository +local function http_get_file(file) + local dl, err + for i = 1, 3 do + dl, err = http.get(repo_path..file) + if dl then break + else + red();println("HTTP Error "..err) + lgray();println("retrying...") +---@diagnostic disable-next-line: undefined-field + os.sleep(0.25 * i) + end + end + return dl +end + -- recursively build a tree out of the file manifest local function gen_tree(manifest, log) local function _tree_add(tree, split) @@ -420,16 +436,16 @@ elseif mode == "install" or mode == "update" then local files = file_list[dependency] for _, file in pairs(files) do println("GET "..file) - local dl, err = http.get(repo_path..file) + local dl = http_get_file(file) - if dl == nil then - red();println("HTTP Error "..err) - success = false - break - else + if dl then local handle = fs.open(install_dir.."/"..file, "w") handle.write(dl.readAll()) handle.close() + else + red();println("failed to download "..file) + success = false + break end end end @@ -482,16 +498,16 @@ elseif mode == "install" or mode == "update" then local files = file_list[dependency] for _, file in pairs(files) do println("GET "..file) - local dl, err = http.get(repo_path..file) + local dl = http_get_file(file) - if dl == nil then - red();println("HTTP Error "..err) - success = false - break - else + if dl then local handle = fs.open("/"..file, "w") handle.write(dl.readAll()) handle.close() + else + red();println("failed to download "..file) + success = false + break end end end From 1e341af8a52210287b1821a72e8d0d42b223091c Mon Sep 17 00:00:00 2001 From: Mikayla Date: Wed, 3 Jul 2024 15:01:43 +0000 Subject: [PATCH 41/44] #514 optimizations and fixes --- ccmsi.lua | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/ccmsi.lua b/ccmsi.lua index a2c6e186..7f4647f0 100644 --- a/ccmsi.lua +++ b/ccmsi.lua @@ -120,20 +120,25 @@ local function write_install_manifest(manifest, dependencies) imfile.close() end --- try at most 3 times to download a file from the repository -local function http_get_file(file) +-- try at most 3 times to download a file from the repository and write into w_path base directory +local function http_get_file(file, w_path) local dl, err for i = 1, 3 do dl, err = http.get(repo_path..file) - if dl then break + if dl then + if i > 1 then green();println("success!");lgray() end + local f = fs.open(w_path..file, "w") + f.write(dl.readAll()) + f.close() + break else red();println("HTTP Error "..err) - lgray();println("retrying...") + if i < 3 then lgray();print("> retrying...") end ---@diagnostic disable-next-line: undefined-field - os.sleep(0.25 * i) + os.sleep(i/3.0) end end - return dl + return dl ~= nil end -- recursively build a tree out of the file manifest @@ -436,13 +441,7 @@ elseif mode == "install" or mode == "update" then local files = file_list[dependency] for _, file in pairs(files) do println("GET "..file) - local dl = http_get_file(file) - - if dl then - local handle = fs.open(install_dir.."/"..file, "w") - handle.write(dl.readAll()) - handle.close() - else + if not http_get_file(file, install_dir.."/") then red();println("failed to download "..file) success = false break @@ -498,13 +497,7 @@ elseif mode == "install" or mode == "update" then local files = file_list[dependency] for _, file in pairs(files) do println("GET "..file) - local dl = http_get_file(file) - - if dl then - local handle = fs.open("/"..file, "w") - handle.write(dl.readAll()) - handle.close() - else + if not http_get_file(file, "/") then red();println("failed to download "..file) success = false break From f2cd98c57aaa6bc83c46f904774873fc42be8515 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Wed, 3 Jul 2024 21:14:39 -0400 Subject: [PATCH 42/44] #194 fixes to log file handling, improved failure behavior, skip extra dialogs if nothing can be updated --- ccmsi.lua | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/ccmsi.lua b/ccmsi.lua index 7f4647f0..be9c2e84 100644 --- a/ccmsi.lua +++ b/ccmsi.lua @@ -132,7 +132,7 @@ local function http_get_file(file, w_path) f.close() break else - red();println("HTTP Error "..err) + red();println("HTTP Error: "..err) if i < 3 then lgray();print("> retrying...") end ---@diagnostic disable-next-line: undefined-field os.sleep(i/3.0) @@ -193,6 +193,7 @@ local function clean(manifest) local log = nil if fs.exists(app..".settings") and settings.load(app..".settings") then log = settings.get("LogPath") + if log:sub(1, 1) == "/" then log = log:sub(2) end end local tree = gen_tree(manifest, log) @@ -343,7 +344,7 @@ elseif mode == "install" or mode == "update" then local dl, err = http.get(repo_path.."ccmsi.lua") if dl == nil then - red();println("HTTP Error "..err) + red();println("HTTP Error: "..err) println("Installer download failed.");white() else local handle = fs.open(debug.getinfo(1, "S").source:sub(2), "w") -- this file, regardless of name or location @@ -380,9 +381,6 @@ elseif mode == "install" or mode == "update" then ver.graphics.changed = show_pkg_change("graphics", ver.graphics) ver.lockbox.changed = show_pkg_change("lockbox", ver.lockbox) - -- ask for confirmation - if not ask_y_n("Continue", false) then return end - -------------------------- -- START INSTALL/UPDATE -- -------------------------- @@ -397,11 +395,32 @@ elseif mode == "install" or mode == "update" then table.insert(dependencies, app) + -- helper function to check if a dependency is unchanged + local function unchanged(dependency) + if dependency == "system" then return not ver.boot.changed + elseif dependency == "graphics" then return not ver.graphics.changed + elseif dependency == "lockbox" then return not ver.lockbox.changed + elseif dependency == "common" then return not (ver.common.changed or ver.comms.changed) + elseif dependency == app then return not ver.app.changed + else return true end + end + + local any_change = false + for _, dependency in pairs(dependencies) do local size = size_list[dependency] space_required = space_required + size + any_change = any_change or not unchanged(dependency) + end + + if mode == "update" and not any_change then + yellow();println("Nothing to do, everything is already up-to-date!");white() + return end + -- ask for confirmation + if not ask_y_n("Continue", false) then return end + -- check space constraints if space_available < space_required then single_file_mode = true @@ -417,16 +436,6 @@ elseif mode == "install" or mode == "update" then local success = true - -- helper function to check if a dependency is unchanged - local function unchanged(dependency) - if dependency == "system" then return not ver.boot.changed - elseif dependency == "graphics" then return not ver.graphics.changed - elseif dependency == "lockbox" then return not ver.lockbox.changed - elseif dependency == "common" then return not (ver.common.changed or ver.comms.changed) - elseif dependency == app then return not ver.app.changed - else return true end - end - if not single_file_mode then if fs.exists(install_dir) then fs.delete(install_dir);fs.makeDir(install_dir) end @@ -448,6 +457,7 @@ elseif mode == "install" or mode == "update" then end end end + if not success then break end end -- copy in downloaded files (installation) @@ -504,6 +514,7 @@ elseif mode == "install" or mode == "update" then end end end + if not success then break end end if success then From e04bd032fed80478546dba6039a1464eaf17ca5e Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 6 Jul 2024 00:07:00 -0400 Subject: [PATCH 43/44] incremented common version --- scada-common/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scada-common/util.lua b/scada-common/util.lua index 344ffd8d..6871baae 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.3.1" +util.version = "1.4.0" util.TICK_TIME_S = 0.05 util.TICK_TIME_MS = 50 From 0364b4df7b01e4b23781c3dcec6787b5baf8afc4 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 6 Jul 2024 00:07:21 -0400 Subject: [PATCH 44/44] fixed pocket crash due to guide section height too small --- pocket/startup.lua | 2 +- pocket/ui/apps/guide.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pocket/startup.lua b/pocket/startup.lua index 945171ce..b4a6f523 100644 --- a/pocket/startup.lua +++ b/pocket/startup.lua @@ -20,7 +20,7 @@ local pocket = require("pocket.pocket") local renderer = require("pocket.renderer") local threads = require("pocket.threads") -local POCKET_VERSION = "v0.11.1-alpha" +local POCKET_VERSION = "v0.11.2-alpha" local println = util.println local println_ts = util.println_ts diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index 10bf56a6..52d16bfe 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -208,7 +208,7 @@ local function new_view(root) 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} - local gls_abbv_page = guide_section(sect_construct_data, gls_page, "Abbreviations", docs.glossary.abbvs, 120) + local gls_abbv_page = guide_section(sect_construct_data, gls_page, "Abbreviations", docs.glossary.abbvs, 130) local gls_term_page = guide_section(sect_construct_data, gls_page, "Terminology", docs.glossary.terms, 100) PushButton{parent=gls,y=3,text="Abbreviations >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=gls_abbv_page.nav_to}