diff --git a/graphics/core.lua b/graphics/core.lua index 2f17d98..062bf60 100644 --- a/graphics/core.lua +++ b/graphics/core.lua @@ -115,8 +115,7 @@ end -- extract the custom element assert message, dropping the path to the element file function core.extract_assert_msg(msg) - local start = (string.find(msg, "@") + 1) or 1 - return string.sub(msg, start) + return string.sub(msg, (string.find(msg, "@") + 1) or 1) end -- Interactive Field Manager @@ -163,11 +162,8 @@ function core.new_ifield(e, max_len, fg_bg, dis_fg_bg) function public.censor(censor) if type(censor) == "string" and string.len(censor) == 1 then self.censor = censor - public.show() - else - self.censor = nil - public.show() - end + else self.censor = nil end + public.show() end -- show the field diff --git a/graphics/element.lua b/graphics/element.lua index 2ace4e1..41e4c57 100644 --- a/graphics/element.lua +++ b/graphics/element.lua @@ -315,8 +315,8 @@ function element.new(args, child_offset_x, child_offset_y) -- defocus this element function protected.defocus() public.unfocus_all() end - -- request focus management to focus this element - function protected.req_focus() args.parent.__focus_child(public) end + -- focus this element and take away focus from all other elements + function protected.take_focus() args.parent.__focus_child(public) end -- action handlers -- @@ -426,7 +426,7 @@ function element.new(args, child_offset_x, child_offset_y) self.id = args.id or "__ROOT__" protected.prepare_template(0, 0, 1) else - self.id, self.ordinal = args.parent.__add_child(args.id, protected) + self.id = args.parent.__add_child(args.id, protected) end ---------------------- diff --git a/graphics/elements/controls/app.lua b/graphics/elements/controls/app.lua index 1433193..f610393 100644 --- a/graphics/elements/controls/app.lua +++ b/graphics/elements/controls/app.lua @@ -118,11 +118,8 @@ local function app_button(args) -- element redraw function e.redraw() - -- write app title, centered e.w_set_cur(math.floor((e.frame.w - string.len(args.title)) / 2) + 1, 4) e.w_write(args.title) - - -- draw button draw() end diff --git a/graphics/elements/controls/radio_2d.lua b/graphics/elements/controls/radio_2d.lua index fde886f..65d4c09 100644 --- a/graphics/elements/controls/radio_2d.lua +++ b/graphics/elements/controls/radio_2d.lua @@ -188,11 +188,9 @@ local function radio_2d_button(args) end end - -- handle focus + -- handle focus & enable e.on_focused = e.redraw e.on_unfocused = e.redraw - - -- handle enable e.on_enabled = e.redraw e.on_disabled = e.redraw diff --git a/graphics/elements/controls/radio_button.lua b/graphics/elements/controls/radio_button.lua index 93540f3..aee7060 100644 --- a/graphics/elements/controls/radio_button.lua +++ b/graphics/elements/controls/radio_button.lua @@ -132,11 +132,9 @@ local function radio_button(args) end end - -- handle focus + -- handle focus & enable e.on_focused = e.redraw e.on_unfocused = e.redraw - - -- handle enable e.on_enabled = e.redraw e.on_disabled = e.redraw diff --git a/graphics/elements/form/number_field.lua b/graphics/elements/form/number_field.lua index b519c8a..53fc473 100644 --- a/graphics/elements/form/number_field.lua +++ b/graphics/elements/form/number_field.lua @@ -48,7 +48,7 @@ local function number_field(args) -- only handle if on an increment or decrement arrow if e.enabled then if core.events.was_clicked(event.type) then - e.req_focus() + e.take_focus() if event.type == MOUSE_CLICK.UP then ifield.move_cursor(event.current.x) diff --git a/graphics/elements/form/text_field.lua b/graphics/elements/form/text_field.lua index 5fc1062..aee910d 100644 --- a/graphics/elements/form/text_field.lua +++ b/graphics/elements/form/text_field.lua @@ -43,7 +43,7 @@ local function text_field(args) -- only handle if on an increment or decrement arrow if e.enabled then if core.events.was_clicked(event.type) then - e.req_focus() + e.take_focus() if event.type == MOUSE_CLICK.UP then ifield.move_cursor(event.current.x) diff --git a/graphics/elements/indicators/power.lua b/graphics/elements/indicators/power.lua index 96cbfd5..69e4a0b 100644 --- a/graphics/elements/indicators/power.lua +++ b/graphics/elements/indicators/power.lua @@ -23,7 +23,7 @@ local element = require("graphics.element") ---@param args power_indicator_args ---@return graphics_element element, element_id id local function power(args) - element.assert(type(args.value) == "number", "value is a required number field") + element.assert(type(args.value) == "number", "value is a required field") element.assert(util.is_int(args.width), "width is a required field") args.height = 1 diff --git a/graphics/elements/indicators/rad.lua b/graphics/elements/indicators/rad.lua index d13655e..545ea41 100644 --- a/graphics/elements/indicators/rad.lua +++ b/graphics/elements/indicators/rad.lua @@ -33,7 +33,7 @@ local function rad(args) -- create new graphics element base object local e = element.new(args) - e.value = types.new_zero_radiation_reading() + e.value = args.value or types.new_zero_radiation_reading() local label_len = string.len(args.label) local data_start = 1 diff --git a/graphics/elements/listbox.lua b/graphics/elements/listbox.lua index a35330a..d138e19 100644 --- a/graphics/elements/listbox.lua +++ b/graphics/elements/listbox.lua @@ -278,12 +278,6 @@ local function listbox(args) function e.redraw() draw_arrows(0) draw_bar() - - -- redraw all children - for i = 1, #list do - local item = list[i] ---@type listbox_item - item.e.redraw() - end end -- initial draw diff --git a/pocket/startup.lua b/pocket/startup.lua index 68fb2c1..4929955 100644 --- a/pocket/startup.lua +++ b/pocket/startup.lua @@ -170,7 +170,7 @@ local function main() -- got a packet local packet = pocket_comms.parse_packet(param1, param2, param3, param4, param5) pocket_comms.handle_packet(packet) - elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll"or + elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" or event == "double_click" then -- handle a monitor touch event renderer.handle_mouse(core.events.new_mouse_event(event, param1, param2, param3)) diff --git a/reactor-plc/config.lua b/reactor-plc/config.lua deleted file mode 100644 index 066ccf6..0000000 --- a/reactor-plc/config.lua +++ /dev/null @@ -1,34 +0,0 @@ -local config = {} - --- set to false to run in offline mode (safety regulation only) -config.NETWORKED = true --- unique reactor ID -config.REACTOR_ID = 1 - --- for offline mode, this redstone interface will turn off (open a valve) --- when emergency coolant is needed due to low coolant --- config.EMERGENCY_COOL = { side = "right", color = nil } - --- supervisor comms channel -config.SVR_CHANNEL = 16240 --- PLC comms channel -config.PLC_CHANNEL = 16241 --- max trusted modem message distance (0 to disable check) -config.TRUSTED_RANGE = 0 --- time in seconds (>= 2) before assuming a remote device is no longer active -config.COMMS_TIMEOUT = 5 --- facility authentication key (do NOT use one of your passwords) --- this enables verifying that messages are authentic --- all devices on the same network must use the same key --- config.AUTH_KEY = "SCADAfacility123" - --- log path -config.LOG_PATH = "/log.txt" --- log mode --- 0 = APPEND (adds to existing file on start) --- 1 = NEW (replaces existing file on start) -config.LOG_MODE = 0 --- true to log verbose debug messages -config.LOG_DEBUG = false - -return config diff --git a/reactor-plc/configure.lua b/reactor-plc/configure.lua index 1373a08..c1b0481 100644 --- a/reactor-plc/configure.lua +++ b/reactor-plc/configure.lua @@ -16,8 +16,8 @@ local TextBox = require("graphics.elements.textbox") local CheckBox = require("graphics.elements.controls.checkbox") local PushButton = require("graphics.elements.controls.push_button") -local RadioButton = require("graphics.elements.controls.radio_button") local Radio2D = require("graphics.elements.controls.radio_2d") +local RadioButton = require("graphics.elements.controls.radio_button") local NumberField = require("graphics.elements.form.number_field") local TextField = require("graphics.elements.form.text_field") @@ -68,7 +68,12 @@ local tool_ctl = { bundled_emcool = nil, ---@type function gen_summary = nil, ---@type function show_current_cfg = nil, ---@type function - load_legacy = nil ---@type function + load_legacy = nil, ---@type function + + show_auth_key = nil, ---@type function + show_key_btn = nil, ---@type graphics_element + auth_key_textbox = nil, ---@type graphics_element + auth_key_value = "" } ---@class plc_config @@ -160,7 +165,7 @@ local function load_settings(target) target.ConnTimeout = settings.get("ConnTimeout", 5) target.TrustedRange = settings.get("TrustedRange", 0) target.AuthKey = settings.get("AuthKey", "") - target.LogMode = settings.get("LogMode", 0) + target.LogMode = settings.get("LogMode", log.MODE.APPEND) target.LogPath = settings.get("LogPath", "/log.txt") target.LogDebug = settings.get("LogDebug", false) end @@ -171,10 +176,8 @@ local function config_view(display) local nav_fg_bg = cpair(colors.black,colors.white) local btn_act_fg_bg = cpair(colors.white,colors.gray) - local function exit() ---@diagnostic disable-next-line: undefined-field - os.queueEvent("terminate") - end + local function exit() os.queueEvent("terminate") end TextBox{parent=display,y=1,text="Reactor PLC Configurator",alignment=CENTER,height=1,fg_bg=style.header} @@ -289,7 +292,7 @@ local function config_view(display) local function submit_emcool() tmp_cfg.EmerCoolSide = side_options_map[side.get_value()] - tmp_cfg.EmerCoolColor = util.trinary(bundled.get_value(), color_options_map[color.get_value()], nil) + tmp_cfg.EmerCoolColor = color_options_map[color.get_value()] next_from_plc() end @@ -307,7 +310,7 @@ local function config_view(display) TextBox{parent=net_cfg,x=1,y=2,height=1,text_align=CENTER,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)} TextBox{parent=net_c_1,x=1,y=1,height=1,text_align=CENTER,text="Please set the network channels below."} - TextBox{parent=net_c_1,x=1,y=3,height=4,text_align=CENTER,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=cpair(colors.gray,colors.lightGray)} + TextBox{parent=net_c_1,x=1,y=3,height=4,text_align=CENTER,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=cpair(colors.gray,colors.lightGray)} TextBox{parent=net_c_1,x=1,y=8,height=1,text_align=CENTER,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=cpair(colors.black,colors.white)} @@ -464,22 +467,22 @@ local function config_view(display) for k, v in pairs(tmp_cfg) do settings.set(k, v) end if settings.save("reactor-plc.settings") then - load_settings(tmp_cfg) + load_settings(ini_cfg) - try_set(networked, tmp_cfg.Networked) - try_set(u_id, tmp_cfg.UnitID) - try_set(en_em_cool, tmp_cfg.EmerCoolEnable) - try_set(side, side_to_idx(tmp_cfg.EmerCoolSide)) - try_set(bundled, tmp_cfg.EmerCoolColor ~= nil) - if tmp_cfg.EmerCoolColor ~= nil then try_set(color, color_to_idx(tmp_cfg.EmerCoolColor)) end - try_set(svr_chan, tmp_cfg.SVR_Channel) - try_set(plc_chan, tmp_cfg.PLC_Channel) - try_set(timeout, tmp_cfg.ConnTimeout) - try_set(range, tmp_cfg.TrustedRange) - try_set(key, tmp_cfg.AuthKey) - try_set(mode, tmp_cfg.LogMode) - try_set(path, tmp_cfg.LogPath) - try_set(en_dbg, tmp_cfg.LogDebug) + try_set(networked, ini_cfg.Networked) + try_set(u_id, ini_cfg.UnitID) + try_set(en_em_cool, ini_cfg.EmerCoolEnable) + try_set(side, side_to_idx(ini_cfg.EmerCoolSide)) + try_set(bundled, ini_cfg.EmerCoolColor ~= nil) + if ini_cfg.EmerCoolColor ~= nil then try_set(color, color_to_idx(ini_cfg.EmerCoolColor)) end + try_set(svr_chan, ini_cfg.SVR_Channel) + try_set(plc_chan, ini_cfg.PLC_Channel) + try_set(timeout, ini_cfg.ConnTimeout) + try_set(range, ini_cfg.TrustedRange) + try_set(key, ini_cfg.AuthKey) + try_set(mode, ini_cfg.LogMode) + try_set(path, ini_cfg.LogPath) + try_set(en_dbg, ini_cfg.LogDebug) if tool_ctl.importing_legacy then tool_ctl.importing_legacy = false @@ -493,6 +496,7 @@ local function config_view(display) end PushButton{parent=sum_c_1,x=1,y=14,min_width=6,text="\x1b Back",callback=back_from_settings,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + 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_align=CENTER,text="Settings saved!"} @@ -554,7 +558,7 @@ local function config_view(display) tmp_cfg.AuthKey = config.AUTH_KEY or "" tmp_cfg.LogMode = config.LOG_MODE tmp_cfg.LogPath = config.LOG_PATH - tmp_cfg.LogDebug = config.LOG_DEBUG + tmp_cfg.LogDebug = config.LOG_DEBUG or false tool_ctl.gen_summary(tmp_cfg) sum_pane.set_value(1) @@ -562,6 +566,12 @@ local function config_view(display) tool_ctl.importing_legacy = true end + -- expose the auth key on the summary page + function tool_ctl.show_auth_key() + tool_ctl.show_key_btn.disable() + tool_ctl.auth_key_textbox.set_value(tool_ctl.auth_key_value) + end + -- generate the summary list ---@param cfg plc_config function tool_ctl.gen_summary(cfg) @@ -570,6 +580,9 @@ local function config_view(display) local alternate = false local inner_width = setting_list.get_width() - 1 + tool_ctl.show_key_btn.enable() + tool_ctl.auth_key_value = cfg.AuthKey or "" -- to show auth key + for i = 1, #fields do local f = fields[i] local height = 1 @@ -578,7 +591,7 @@ local function config_view(display) local raw = cfg[f[1]] local val = util.strval(raw) - if f[1] == "AuthKey" and hide_key.get_value() then val = string.rep("*", string.len(val)) end + if f[1] == "AuthKey" then val = string.rep("*", string.len(val)) end if f[1] == "LogMode" then val = util.trinary(raw == log.MODE.APPEND, "append", "replace") end if f[1] == "EmerCoolColor" and raw ~= nil then val = color_name_map[raw] end if val == "nil" then val = "n/a" end @@ -594,11 +607,14 @@ local function config_view(display) local line = Div{parent=setting_list,height=height,fg_bg=c} TextBox{parent=line,text=f[2],width=string.len(f[2]),fg_bg=cpair(colors.black,line.get_fg_bg().bkg)} + local textbox if height > 1 then - TextBox{parent=line,x=1,y=2,text=val,height=height-1,alignment=LEFT} + textbox = TextBox{parent=line,x=1,y=2,text=val,height=height-1,alignment=LEFT} else - TextBox{parent=line,x=label_w+1,y=1,text=val,alignment=RIGHT} + textbox = TextBox{parent=line,x=label_w+1,y=1,text=val,alignment=RIGHT} end + + if f[1] == "AuthKey" then tool_ctl.auth_key_textbox = textbox end end end end @@ -627,7 +643,6 @@ function configurator.configure(ask_config) end local status, error = pcall(function () - -- init front panel view local display = DisplayBox{window=term.current(),fg_bg=style.root} config_view(display) diff --git a/reactor-plc/plc.lua b/reactor-plc/plc.lua index 0942bdc..02d7c3d 100644 --- a/reactor-plc/plc.lua +++ b/reactor-plc/plc.lua @@ -33,7 +33,7 @@ plc.config = config -- load the PLC configuration function plc.load_config() - assert(settings.load("/reactor-plc.settings"), "failed to load settings file, please reconfigure.") + if not settings.load("/reactor-plc.settings") then return false end config.Networked = settings.get("Networked") config.UnitID = settings.get("UnitID") @@ -59,6 +59,7 @@ function plc.load_config() cfv.assert_type_int(config.ConnTimeout) cfv.assert_min(config.ConnTimeout, 2) cfv.assert_type_num(config.TrustedRange) + cfv.assert_min(config.TrustedRange, 0) cfv.assert_type_str(config.AuthKey) cfv.assert_type_int(config.LogMode) cfv.assert_type_str(config.LogPath) diff --git a/reactor-plc/startup.lua b/reactor-plc/startup.lua index 300fd16..7ad0d27 100644 --- a/reactor-plc/startup.lua +++ b/reactor-plc/startup.lua @@ -106,10 +106,10 @@ local function main() -- system objects plc_sys = { - rps = nil, ---@type rps - nic = nil, ---@type nic - plc_comms = nil, ---@type plc_comms - conn_watchdog = nil---@type watchdog + rps = nil, ---@type rps + nic = nil, ---@type nic + plc_comms = nil, ---@type plc_comms + conn_watchdog = nil ---@type watchdog }, -- message queues diff --git a/reactor-plc/threads.lua b/reactor-plc/threads.lua index ccbc196..6699ea3 100644 --- a/reactor-plc/threads.lua +++ b/reactor-plc/threads.lua @@ -265,7 +265,7 @@ function threads.thread__main(smem, init) -- update indicators databus.tx_hw_status(plc_state) - elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll"or + 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 renderer.handle_mouse(core.events.new_mouse_event(event, param1, param2, param3)) diff --git a/rtu/threads.lua b/rtu/threads.lua index 29e54cf..d76d062 100644 --- a/rtu/threads.lua +++ b/rtu/threads.lua @@ -279,7 +279,7 @@ function threads.thread__main(smem) end end end - elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll"or + 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 renderer.handle_mouse(core.events.new_mouse_event(event, param1, param2, param3)) diff --git a/supervisor/startup.lua b/supervisor/startup.lua index 11f0948..76fd746 100644 --- a/supervisor/startup.lua +++ b/supervisor/startup.lua @@ -213,7 +213,7 @@ local function main() -- got a packet local packet = superv_comms.parse_packet(param1, param2, param3, param4, param5) superv_comms.handle_packet(packet) - elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll"or + 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 renderer.handle_mouse(core.events.new_mouse_event(event, param1, param2, param3))