diff --git a/ccmsi.lua b/ccmsi.lua index 327018d..432bbef 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.12b" +local CCMSI_VERSION = "v1.13" local install_dir = "/.install-cache" local manifest_path = "https://mikaylafischler.github.io/cc-mek-scada/manifests/" @@ -26,7 +26,7 @@ local repo_path = "http://raw.githubusercontent.com/MikaylaFischler/cc-mek-scada local opts = { ... } local mode, app, target -local install_manifest = manifest_path .. "main/install_manifest.json" +local install_manifest = manifest_path.."main/install_manifest.json" local function red() term.setTextColor(colors.red) end local function orange() term.setTextColor(colors.orange) end @@ -59,17 +59,17 @@ local function ask_y_n(question, default) end -- print out a white + blue text message -local function pkg_message(message, package) white();print(message .. " ");blue();println(package);white() end +local function pkg_message(message, package) white();print(message.." ");blue();println(package);white() end -- indicate actions to be taken based on package differences for installs/updates local function show_pkg_change(name, v) if v.v_local ~= nil then if v.v_local ~= v.v_remote then - print("[" .. name .. "] updating ");blue();print(v.v_local);white();print(" \xbb ");blue();println(v.v_remote);white() + print("["..name.."] updating ");blue();print(v.v_local);white();print(" \xbb ");blue();println(v.v_remote);white() elseif mode == "install" then - pkg_message("[" .. name .. "] reinstalling", v.v_local) + pkg_message("["..name.."] reinstalling", v.v_local) end - else pkg_message("[" .. name .. "] new install of", v.v_remote) end + else pkg_message("["..name.."] new install of", v.v_remote) end return v.v_local ~= v.v_remote end @@ -90,7 +90,7 @@ local function get_remote_manifest() local response, error = http.get(install_manifest) if response == nil then orange();println("Failed to get installation manifest from GitHub, cannot update or install.") - red();println("HTTP error: " .. error);white() + red();println("HTTP error: "..error);white() return false, {} end @@ -155,13 +155,13 @@ 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 + 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 ---@fixme remove condition after migration to settings files + 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) + println("deleted "..path) end end end @@ -177,13 +177,13 @@ local function clean(manifest) local ls = fs.list("/") for _, val in pairs(ls) do if fs.isDriveRoot(val) then - yellow();println("skipped mount '" .. val .. "'") + 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 + 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 + white();if ask_y_n("delete the unused file '"..val.."'") then fs.delete(val);lgray();println("deleted "..val) end end end @@ -192,7 +192,7 @@ end -- get and validate command line options -println("-- CC Mekanism SCADA Installer " .. CCMSI_VERSION .. " --") +println("-- CC Mekanism SCADA Installer "..CCMSI_VERSION.." --") if #opts == 0 or opts[1] == "help" then println("usage: ccmsi ") @@ -202,8 +202,8 @@ if #opts == 0 or opts[1] == "help" then yellow() println(" ccmsi check for target") lgray() - println(" install - fresh install, overwrites config.lua") - println(" update - update files EXCEPT for config.lua") + println(" install - fresh install") + println(" update - update files") println(" uninstall - delete files INCLUDING config/logs") white();println("");lgray() println(" reactor-plc - reactor PLC firmware") @@ -239,8 +239,8 @@ else end -- set paths - install_manifest = manifest_path .. target .. "/install_manifest.json" - repo_path = repo_path .. target .. "/" + install_manifest = manifest_path..target.."/install_manifest.json" + repo_path = repo_path..target.."/" end -- run selected mode @@ -260,7 +260,7 @@ if mode == "check" then -- list all versions for key, value in pairs(manifest.versions) do term.setTextColor(colors.purple) - print(string.format("%-14s", "[" .. key .. "]")) + print(string.format("%-14s", "["..key.."]")) if key == "installer" or (local_ok and (local_manifest.versions[key] ~= nil)) then blue();print(local_manifest.versions[key]) if value ~= local_manifest.versions[key] then @@ -315,10 +315,10 @@ elseif mode == "install" or mode == "update" then if not update_installer then yellow();println("A different version of the installer is available, it is recommended to update to it.");white() end if update_installer or ask_y_n("Would you like to update now") then lgray();println("GET ccmsi.lua") - local dl, err = http.get(repo_path .. "ccmsi.lua") + 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 @@ -342,13 +342,8 @@ elseif mode == "install" or mode == "update" then ver.lockbox.v_remote = manifest.versions.lockbox green() - if mode == "install" then - println("Installing " .. app .. " files...") - elseif mode == "update" then - if app == "pocket" then println("Updating " .. app .. " files... (keeping old config.lua)") - else println("Updating " .. app .. " files...") end - end - white() + if mode == "install" then print("Installing ") else print("Updating ") end + println(app.." files...");white() ver.boot.changed = show_pkg_change("bootldr", ver.boot) ver.common.changed = show_pkg_change("common", ver.common) @@ -374,7 +369,6 @@ elseif mode == "install" or mode == "update" then local file_list = manifest.files local size_list = manifest.sizes local dependencies = manifest.depends[app] - local config_file = app .. "/config.lua" table.insert(dependencies, app) @@ -421,15 +415,15 @@ 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) + println("GET "..file) + local dl, err = http.get(repo_path..file) if dl == nil then - red();println("HTTP Error " .. err) + red();println("HTTP Error "..err) success = false break else - local handle = fs.open(install_dir .. "/" .. file, "w") + local handle = fs.open(install_dir.."/"..file, "w") handle.write(dl.readAll()) handle.close() end @@ -448,11 +442,9 @@ elseif mode == "install" or mode == "update" then local files = file_list[dependency] for _, file in pairs(files) do - if mode == "install" or file ~= config_file then - local temp_file = install_dir .. "/" .. file - if fs.exists(file) then fs.delete(file) end - fs.move(temp_file, file) - end + local temp_file = install_dir.."/"..file + if fs.exists(file) then fs.delete(file) end + fs.move(temp_file, file) end end end @@ -485,19 +477,17 @@ elseif mode == "install" or mode == "update" then local files = file_list[dependency] for _, file in pairs(files) do - if mode == "install" or file ~= config_file then - println("GET " .. file) - local dl, err = http.get(repo_path .. file) + println("GET "..file) + local dl, err = http.get(repo_path..file) - if dl == nil then - red();println("HTTP Error " .. err) - success = false - break - else - local handle = fs.open("/" .. file, "w") - handle.write(dl.readAll()) - handle.close() - end + if dl == nil then + red();println("HTTP Error "..err) + success = false + break + else + local handle = fs.open("/"..file, "w") + handle.write(dl.readAll()) + handle.close() end end end @@ -527,11 +517,11 @@ elseif mode == "uninstall" then end if manifest.versions[app] == nil then - red();println("Error: '" .. app .. "' is not installed.") + red();println("Error: '"..app.."' is not installed.") return end - orange();println("Uninstalling all " .. app .. " files...") + orange();println("Uninstalling all "..app.." files...") -- ask for confirmation if not ask_y_n("Continue", false) then return end @@ -546,16 +536,16 @@ elseif mode == "uninstall" then -- delete log file local log_deleted = false - local settings_file = app .. ".settings" - local legacy_config_file = app .. "/config.lua" + 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") + local config = require(app..".config") if fs.exists(config.LOG_PATH) then fs.delete(config.LOG_PATH) - println("deleted log file " .. config.LOG_PATH) + println("deleted log file "..config.LOG_PATH) end end) elseif fs.exists(settings_file) and settings.load(settings_file) then @@ -563,7 +553,7 @@ elseif mode == "uninstall" then if log ~= nil and fs.exists(log) then log_deleted = true fs.delete(log) - println("deleted log file " .. log) + println("deleted log file "..log) end end @@ -577,7 +567,7 @@ elseif mode == "uninstall" then 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 + if fs.exists(file) then fs.delete(file);println("deleted "..file) end end local folder = files[1] @@ -588,13 +578,16 @@ elseif mode == "uninstall" then if fs.isDir(folder) then fs.delete(folder) - println("deleted directory " .. folder) + println("deleted directory "..folder) end end + if fs.exists(legacy_config_file) then + fs.delete(legacy_config_file);println("deleted "..legacy_config_file) + end + if fs.exists(settings_file) then - fs.delete(settings_file) - println("deleted " .. settings_file) + fs.delete(settings_file);println("deleted "..settings_file) end fs.delete("install_manifest.json") diff --git a/configure.lua b/configure.lua index 69d7f0f..ce6ed40 100644 --- a/configure.lua +++ b/configure.lua @@ -1,15 +1,10 @@ print("CONFIGURE> SCANNING FOR CONFIGURATOR...") -if fs.exists("reactor-plc/configure.lua") then - require("reactor-plc.configure").configure() -elseif fs.exists("rtu/configure.lua") then - require("rtu.configure").configure() -elseif fs.exists("supervisor/configure.lua") then - require("supervisor.configure").configure() -elseif fs.exists("coordinator/configure.lua") then - require("coordinator.configure").configure() -elseif fs.exists("pocket/startup.lua") then - print("CONFIGURE> pocket configurator not yet implemented (use 'edit pocket/config.lua' to configure)") +if fs.exists("reactor-plc/configure.lua") then require("reactor-plc.configure").configure() +elseif fs.exists("rtu/configure.lua") then require("rtu.configure").configure() +elseif fs.exists("supervisor/configure.lua") then require("supervisor.configure").configure() +elseif fs.exists("coordinator/configure.lua") then require("coordinator.configure").configure() +elseif fs.exists("pocket/configure.lua") then require("pocket.configure").configure() else print("CONFIGURE> NO CONFIGURATOR FOUND") print("CONFIGURE> EXIT") diff --git a/coordinator/configure.lua b/coordinator/configure.lua index 44b0b19..0fc68ff 100644 --- a/coordinator/configure.lua +++ b/coordinator/configure.lua @@ -347,7 +347,7 @@ local function config_view(display) if not tool_ctl.has_config then tool_ctl.view_cfg.disable() end PushButton{parent=main_page,x=2,y=17,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg} - PushButton{parent=main_page,x=39,y=17,min_width=12,text="Change Log",callback=function()main_pane.set_value(6)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + PushButton{parent=main_page,x=39,y=17,min_width=12,text="Change Log",callback=function()main_pane.set_value(9)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} --#region Network @@ -453,20 +453,22 @@ local function config_view(display) local function submit_auth() local v = key.get_value() if string.len(v) == 0 or string.len(v) >= 8 then + -- prep supervisor connection screen + tool_ctl.sv_next.hide() + tool_ctl.sv_skip.disable() + tool_ctl.sv_skip.show() + tool_ctl.sv_conn_button.enable() + tool_ctl.sv_conn_status.set_value("") + tool_ctl.sv_conn_detail.set_value("") + tmp_cfg.AuthKey = key.get_value() - main_pane.set_value(3) key_err.hide(true) -- init mac for supervisor connection if string.len(v) >= 8 then network.init_mac(tmp_cfg.AuthKey) end - -- prep supervisor connection screen - tool_ctl.sv_conn_button.enable() - tool_ctl.sv_conn_status.set_value("") - tool_ctl.sv_conn_detail.set_value("") - tool_ctl.sv_next.hide() - tool_ctl.sv_skip.show() - tool_ctl.sv_skip.disable() + main_pane.set_value(3) + tcd.dispatch_unique(2, function () tool_ctl.sv_skip.enable() end) else key_err.show() end end @@ -534,7 +536,7 @@ local function config_view(display) TextBox{parent=fac_c_3,x=1,y=1,height=2,text="The following facility configuration was fetched from your supervisor computer."} - local fac_config_list = ListBox{parent=fac_c_3,x=1,y=4,height=9,width=51,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + local fac_config_list = ListBox{parent=fac_c_3,x=1,y=4,height=9,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} PushButton{parent=fac_c_3,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=fac_c_3,x=44,y=14,text="Next \x1a",callback=function()main_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} @@ -553,7 +555,7 @@ local function config_view(display) TextBox{parent=mon_cfg,x=1,y=2,height=1,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=51,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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)} local function next_from_reqs() -- unassign unit monitors above the unit count @@ -569,7 +571,7 @@ local function config_view(display) TextBox{parent=mon_c_2,x=1,y=1,height=5,text="Please configure your monitors below. You can go back to the prior page without losing progress to double check what you need. All of those monitors must be assigned before you can proceed."} - local mon_list = ListBox{parent=mon_c_2,x=1,y=6,height=7,width=51,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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} @@ -796,7 +798,7 @@ local function config_view(display) TextBox{parent=summary,x=1,y=2,height=1,text=" Summary",fg_bg=cpair(colors.black,colors.green)} - local setting_list = ListBox{parent=sum_c_1,x=1,y=1,height=12,width=51,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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)} local function back_from_summary() if tool_ctl.viewing_config or tool_ctl.importing_legacy then @@ -818,7 +820,7 @@ local function config_view(display) local function save_and_continue() for k, v in pairs(tmp_cfg) do settings.set(k, v) end - if settings.save("coordinator.settings") then + if settings.save("/coordinator.settings") then load_settings(settings_cfg, true) load_settings(ini_cfg) @@ -895,7 +897,7 @@ local function config_view(display) TextBox{parent=changelog,x=1,y=2,height=1,text=" Config Change Log",fg_bg=bw_fg_bg} - local c_log = ListBox{parent=cl,x=1,y=1,height=12,width=51,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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} diff --git a/coordinator/coordinator.lua b/coordinator/coordinator.lua index 61ee56f..ae2ab77 100644 --- a/coordinator/coordinator.lua +++ b/coordinator/coordinator.lua @@ -121,8 +121,11 @@ function coordinator.load_config() monitors.primary = ppm.get_periph(config.MainDisplay) monitors.primary_name = config.MainDisplay + monitors.primary.setTextScale(0.5) w, _ = ppm.monitor_block_size(monitors.primary.getSize()) - if w ~= 8 then return 2, "Main monitor width is incorrect." end + if w ~= 8 then + return 2, util.c("Main monitor width is incorrect (was ", w, ", must be 8).") + end if not config.DisableFlowView then if not util.table_contains(names, config.FlowDisplay) then @@ -132,8 +135,11 @@ function coordinator.load_config() monitors.flow = ppm.get_periph(config.FlowDisplay) monitors.flow_name = config.FlowDisplay + monitors.flow.setTextScale(0.5) w, _ = ppm.monitor_block_size(monitors.flow.getSize()) - if w ~= 8 then return 2, "Flow monitor width is incorrect." end + if w ~= 8 then + return 2, util.c("Flow monitor width is incorrect (was ", w, ", must be 8).") + end end for i = 1, config.UnitCount do @@ -145,8 +151,11 @@ function coordinator.load_config() monitors.unit_displays[i] = ppm.get_periph(display) monitors.unit_name_map[i] = display + monitors.unit_displays[i].setTextScale(0.5) w, h = ppm.monitor_block_size(monitors.unit_displays[i].getSize()) - if w ~= 4 or h ~= 4 then return 2, "Unit " .. i .. " monitor size is incorrect." end + if w ~= 4 or h ~= 4 then + return 2, util.c("Unit ", i, " monitor size is incorrect (was ", w, " by ", h,", must be 4 by 4).") + end end else return 2, "Monitor configuration invalid." end end diff --git a/coordinator/startup.lua b/coordinator/startup.lua index 4301bac..5db4f90 100644 --- a/coordinator/startup.lua +++ b/coordinator/startup.lua @@ -22,7 +22,7 @@ local sounder = require("coordinator.sounder") local apisessions = require("coordinator.session.apisessions") -local COORDINATOR_VERSION = "v1.2.0" +local COORDINATOR_VERSION = "v1.2.1" local println = util.println local println_ts = util.println_ts @@ -79,6 +79,9 @@ local function main() -- system startup ---------------------------------------- + -- re-mount devices now that logging is ready + ppm.mount_all() + -- report versions/init fp PSIL iocontrol.init_fp(COORDINATOR_VERSION, comms.version) diff --git a/pocket/config.lua b/pocket/config.lua deleted file mode 100644 index 72625f4..0000000 --- a/pocket/config.lua +++ /dev/null @@ -1,27 +0,0 @@ -local config = {} - --- supervisor comms channel -config.SVR_CHANNEL = 16240 --- coordinator comms channel -config.CRD_CHANNEL = 16243 --- pocket comms channel -config.PKT_CHANNEL = 16244 --- 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/pocket/configure.lua b/pocket/configure.lua new file mode 100644 index 0000000..6c0f728 --- /dev/null +++ b/pocket/configure.lua @@ -0,0 +1,578 @@ +-- +-- Configuration GUI +-- + +local log = require("scada-common.log") +local tcd = require("scada-common.tcd") +local util = require("scada-common.util") + +local core = require("graphics.core") + +local DisplayBox = require("graphics.elements.displaybox") +local Div = require("graphics.elements.div") +local ListBox = require("graphics.elements.listbox") +local MultiPane = require("graphics.elements.multipane") +local TextBox = require("graphics.elements.textbox") + +local CheckBox = require("graphics.elements.controls.checkbox") +local PushButton = require("graphics.elements.controls.push_button") +local RadioButton = require("graphics.elements.controls.radio_button") + +local NumberField = require("graphics.elements.form.number_field") +local TextField = require("graphics.elements.form.text_field") + +local println = util.println +local tri = util.trinary + +local cpair = core.cpair + +local LEFT = core.ALIGN.LEFT +local CENTER = core.ALIGN.CENTER +local RIGHT = core.ALIGN.RIGHT + +-- changes to the config data/format to let the user know +local changes = {} + +---@class pkt_configurator +local configurator = {} + +local style = {} + +style.root = cpair(colors.black, colors.lightGray) +style.header = cpair(colors.white, colors.gray) + +style.colors = { + { c = colors.red, hex = 0xdf4949 }, + { c = colors.orange, hex = 0xffb659 }, + { c = colors.yellow, hex = 0xfffc79 }, + { c = colors.lime, hex = 0x80ff80 }, + { c = colors.green, hex = 0x4aee8a }, + { c = colors.cyan, hex = 0x34bac8 }, + { c = colors.lightBlue, hex = 0x6cc0f2 }, + { c = colors.blue, hex = 0x0096ff }, + { c = colors.purple, hex = 0xb156ee }, + { c = colors.pink, hex = 0xf26ba2 }, + { c = colors.magenta, hex = 0xf9488a }, + { c = colors.lightGray, hex = 0xcacaca }, + { c = colors.gray, hex = 0x575757 } +} + +local bw_fg_bg = cpair(colors.black, colors.white) +local g_lg_fg_bg = cpair(colors.gray, colors.lightGray) +local nav_fg_bg = bw_fg_bg +local btn_act_fg_bg = cpair(colors.white, colors.gray) +local dis_fg_bg = cpair(colors.lightGray,colors.white) + +local tool_ctl = { + ask_config = false, + has_config = false, + viewing_config = false, + importing_legacy = false, + + view_cfg = nil, ---@type graphics_element + settings_apply = nil, ---@type graphics_element + + set_networked = nil, ---@type function + bundled_emcool = nil, ---@type function + gen_summary = nil, ---@type function + show_current_cfg = 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 pkt_config +local tmp_cfg = { + SVR_Channel = nil, ---@type integer + CRD_Channel = nil, ---@type integer + PKT_Channel = nil, ---@type integer + ConnTimeout = nil, ---@type number + TrustedRange = nil, ---@type number + AuthKey = nil, ---@type string|nil + LogMode = 0, + LogPath = "", + LogDebug = false, +} + +---@class pkt_config +local ini_cfg = {} +---@class pkt_config +local settings_cfg = {} + +-- all settings fields, their nice names, and their default values +local fields = { + { "SVR_Channel", "SVR Channel", 16240 }, + { "CRD_Channel", "CRD Channel", 16243 }, + { "PKT_Channel", "PKT Channel", 16244 }, + { "ConnTimeout", "Connection Timeout", 5 }, + { "TrustedRange", "Trusted Range", 0 }, + { "AuthKey", "Facility Auth Key" , ""}, + { "LogMode", "Log Mode", log.MODE.APPEND }, + { "LogPath", "Log Path", "/log.txt" }, + { "LogDebug","Log Debug Messages", false } +} + +-- load data from the settings file +---@param target pkt_config +---@param raw boolean? true to not use default values +local function load_settings(target, raw) + for _, v in pairs(fields) do settings.unset(v[1]) end + + local loaded = settings.load("/pocket.settings") + + for _, v in pairs(fields) do target[v[1]] = settings.get(v[1], tri(raw, nil, v[3])) end + + return loaded +end + +-- create the config view +---@param display graphics_element +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} + + local root_pane_div = Div{parent=display,x=1,y=2} + + local main_page = Div{parent=root_pane_div,x=1,y=1} + local net_cfg = Div{parent=root_pane_div,x=1,y=1} + local log_cfg = Div{parent=root_pane_div,x=1,y=1} + local summary = Div{parent=root_pane_div,x=1,y=1} + local changelog = Div{parent=root_pane_div,x=1,y=1} + + local main_pane = MultiPane{parent=root_pane_div,x=1,y=1,panes={main_page,net_cfg,log_cfg,summary,changelog}} + + -- Main Page + + local y_start = 7 + + TextBox{parent=main_page,x=2,y=2,height=4,text="Welcome to the Pocket configurator! Please select one of the following options."} + + if tool_ctl.ask_config then + TextBox{parent=main_page,x=2,y=y_start,height=4,width=49,text="Please configure before starting up.",fg_bg=cpair(colors.red,colors.lightGray)} + y_start = y_start + 3 + end + + local function view_config() + tool_ctl.viewing_config = true + tool_ctl.gen_summary(settings_cfg) + tool_ctl.settings_apply.hide(true) + main_pane.set_value(4) + end + + if fs.exists("/pocket/config.lua") then + PushButton{parent=main_page,x=2,y=y_start,min_width=22,text="Import Legacy Config",callback=function()tool_ctl.load_legacy()end,fg_bg=cpair(colors.black,colors.cyan),active_fg_bg=btn_act_fg_bg} + y_start = y_start + 2 + end + + PushButton{parent=main_page,x=2,y=y_start,min_width=18,text="Configure Device",callback=function()main_pane.set_value(2)end,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg} + tool_ctl.view_cfg = PushButton{parent=main_page,x=2,y=y_start+2,min_width=20,text="View Configuration",callback=view_config,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=dis_fg_bg} + + if not tool_ctl.has_config then tool_ctl.view_cfg.disable() end + + PushButton{parent=main_page,x=2,y=18,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg} + PushButton{parent=main_page,x=14,y=18,min_width=12,text="Change Log",callback=function()main_pane.set_value(5)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + + --#region Network + + local net_c_1 = Div{parent=net_cfg,x=2,y=4,width=24} + local net_c_2 = Div{parent=net_cfg,x=2,y=4,width=24} + local net_c_3 = Div{parent=net_cfg,x=2,y=4,width=24} + local net_c_4 = Div{parent=net_cfg,x=2,y=4,width=24} + + 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_c_1,x=1,y=1,height=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"} + 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"} + 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"} + 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 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()) + if svr_c ~= nil and crd_c ~= nil and pkt_c ~= nil then + tmp_cfg.SVR_Channel, tmp_cfg.CRD_Channel, tmp_cfg.PKT_Channel = svr_c, crd_c, pkt_c + net_pane.set_value(2) + chan_err.hide(true) + else chan_err.show() end + end + + PushButton{parent=net_c_1,x=1,y=15,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=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=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"} + 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 function submit_timeouts() + local timeout_val = tonumber(timeout.get_value()) + if timeout_val ~= nil then + tmp_cfg.ConnTimeout = timeout_val + net_pane.set_value(3) + ct_err.hide(true) + else ct_err.show() end + end + + 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=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 function submit_tr() + local range_val = tonumber(range.get_value()) + if range_val ~= nil then + tmp_cfg.TrustedRange = range_val + net_pane.set_value(4) + tr_err.hide(true) + else tr_err.show() end + end + + PushButton{parent=net_c_3,x=1,y=15,text="\x1b Back",callback=function()net_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + PushButton{parent=net_c_3,x=19,y=15,text="Next \x1a",callback=submit_tr,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + + 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"} + 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 + + -- declare back first so tabbing makes sense visually + PushButton{parent=net_c_4,x=1,y=15,text="\x1b Back",callback=function()net_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + + local hide_key = CheckBox{parent=net_c_4,x=8,y=15,label="Hide Key",box_fg_bg=cpair(colors.lightBlue,colors.black),callback=censor_key} + + 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 function submit_auth() + local v = key.get_value() + if string.len(v) == 0 or string.len(v) >= 8 then + tmp_cfg.AuthKey = key.get_value() + main_pane.set_value(3) + key_err.hide(true) + else key_err.show() end + end + + PushButton{parent=net_c_4,x=19,y=15,text="Next \x1a",callback=submit_auth,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + + --#endregion + + --#region Logging + + 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_c_1,x=1,y=1,height=1,text="Configure logging below."} + + TextBox{parent=log_c_1,x=1,y=3,height=1,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"} + 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 function submit_log() + if path.get_value() ~= "" then + path_err.hide(true) + tmp_cfg.LogMode = mode.get_value() - 1 + tmp_cfg.LogPath = path.get_value() + tmp_cfg.LogDebug = en_dbg.get_value() + tool_ctl.gen_summary(tmp_cfg) + tool_ctl.viewing_config = false + tool_ctl.importing_legacy = false + tool_ctl.settings_apply.show() + main_pane.set_value(4) + else path_err.show() end + end + + PushButton{parent=log_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=log_c_1,x=19,y=15,text="Next \x1a",callback=submit_log,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + + --#endregion + + --#region Summary and Saving + + local sum_c_1 = Div{parent=summary,x=2,y=4,width=24} + local sum_c_2 = Div{parent=summary,x=2,y=4,width=24} + local sum_c_3 = Div{parent=summary,x=2,y=4,width=24} + local sum_c_4 = Div{parent=summary,x=2,y=4,width=24} + + 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)} + + 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)} + + local function back_from_summary() + if tool_ctl.viewing_config or tool_ctl.importing_legacy then + main_pane.set_value(1) + tool_ctl.viewing_config = false + tool_ctl.importing_legacy = false + tool_ctl.settings_apply.show() + else + main_pane.set_value(3) + end + end + + ---@param element graphics_element + ---@param data any + local function try_set(element, data) + if data ~= nil then element.set_value(data) end + end + + local function save_and_continue() + for k, v in pairs(tmp_cfg) do settings.set(k, v) end + + if settings.save("/pocket.settings") then + load_settings(settings_cfg, true) + load_settings(ini_cfg) + + try_set(svr_chan, ini_cfg.SVR_Channel) + try_set(crd_chan, ini_cfg.CRD_Channel) + try_set(pkt_chan, ini_cfg.PKT_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) + + tool_ctl.view_cfg.enable() + + if tool_ctl.importing_legacy then + tool_ctl.importing_legacy = false + sum_pane.set_value(3) + else + sum_pane.set_value(2) + end + else + sum_pane.set_value(4) + end + end + + PushButton{parent=sum_c_1,x=1,y=15,text="\x1b Back",callback=back_from_summary,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + 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!"} + + local function go_home() + main_pane.set_value(1) + net_pane.set_value(1) + sum_pane.set_value(1) + end + + PushButton{parent=sum_c_2,x=1,y=15,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + PushButton{parent=sum_c_2,x=19,y=15,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)} + + TextBox{parent=sum_c_3,x=1,y=1,height=4,text="The old config.lua file will now be deleted, then the configurator will exit."} + + local function delete_legacy() + fs.delete("/pocket/config.lua") + exit() + end + + PushButton{parent=sum_c_3,x=1,y=15,min_width=8,text="Cancel",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + PushButton{parent=sum_c_3,x=19,y=15,min_width=6,text="OK",callback=delete_legacy,fg_bg=cpair(colors.black,colors.green),active_fg_bg=cpair(colors.white,colors.gray)} + + TextBox{parent=sum_c_4,x=1,y=1,height=8,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."} + PushButton{parent=sum_c_4,x=1,y=15,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + PushButton{parent=sum_c_4,x=19,y=15,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)} + + --#endregion + + -- Config Change Log + + 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} + + 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} + 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=3,text=v,height=e.get_height(),fg_bg=cpair(colors.gray,colors.white)} + end + end + + PushButton{parent=cl,x=1,y=15,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} + + -- set tool functions now that we have the elements + + -- load a legacy config file + function tool_ctl.load_legacy() + local config = require("pocket.config") + + tmp_cfg.SVR_Channel = config.SVR_CHANNEL + tmp_cfg.CRD_Channel = config.CRD_CHANNEL + tmp_cfg.PKT_Channel = config.PKT_CHANNEL + tmp_cfg.ConnTimeout = config.COMMS_TIMEOUT + tmp_cfg.TrustedRange = config.TRUSTED_RANGE + 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 or false + + tool_ctl.gen_summary(tmp_cfg) + sum_pane.set_value(1) + main_pane.set_value(4) + 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 pkt_config + function tool_ctl.gen_summary(cfg) + setting_list.remove_all() + + 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 + local label_w = string.len(f[2]) + local val_max_w = (inner_width - label_w) - 1 + local raw = cfg[f[1]] + local val = util.strval(raw) + + if f[1] == "AuthKey" then val = string.rep("*", string.len(val)) + elseif f[1] == "LogMode" then val = util.trinary(raw == log.MODE.APPEND, "append", "replace") end + + if val == "nil" then val = "" end + + local c = util.trinary(alternate, g_lg_fg_bg, cpair(colors.gray,colors.white)) + alternate = not alternate + + if string.len(val) > val_max_w then + local lines = util.strwrap(val, inner_width) + height = #lines + 1 + end + + local line = Div{parent=setting_list,height=height,fg_bg=c} + TextBox{parent=line,text=f[2],width=string.len(f[2]),fg_bg=cpair(colors.black,line.get_fg_bg().bkg)} + + local textbox + if height > 1 then + textbox = TextBox{parent=line,x=1,y=2,text=val,height=height-1,alignment=LEFT} + else + 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 + +-- reset terminal screen +local function reset_term() + term.setTextColor(colors.white) + term.setBackgroundColor(colors.black) + term.clear() + term.setCursorPos(1, 1) +end + +-- run the pcoket configurator +---@param ask_config? boolean indicate if this is being called by the startup app due to an invalid configuration +function configurator.configure(ask_config) + tool_ctl.ask_config = ask_config == true + + load_settings(settings_cfg, true) + tool_ctl.has_config = load_settings(ini_cfg) + + reset_term() + + -- set overridden colors + for i = 1, #style.colors do + term.setPaletteColor(style.colors[i].c, style.colors[i].hex) + end + + local status, error = pcall(function () + local display = DisplayBox{window=term.current(),fg_bg=style.root} + config_view(display) + + while true do + local event, param1, param2, param3 = util.pull_event() + + -- handle event + if event == "timer" then + tcd.handle(param1) + elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" or event == "double_click" then + local m_e = core.events.new_mouse_event(event, param1, param2, param3) + if m_e then display.handle_mouse(m_e) end + elseif event == "char" or event == "key" or event == "key_up" then + local k_e = core.events.new_key_event(event, param1, param2) + if k_e then display.handle_key(k_e) end + elseif event == "paste" then + display.handle_paste(param1) + end + + if event == "terminate" then return end + end + end) + + -- restore colors + for i = 1, #style.colors do + local r, g, b = term.nativePaletteColor(style.colors[i].c) + term.setPaletteColor(style.colors[i].c, r, g, b) + end + + reset_term() + if not status then + println("configurator error: " .. error) + end + + return status, error +end + +return configurator diff --git a/pocket/pocket.lua b/pocket/pocket.lua index b2da51d..0bec6ba 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -13,17 +13,57 @@ local LINK_STATE = iocontrol.LINK_STATE local pocket = {} +---@type pkt_config +local config = {} + +pocket.config = config + +-- load the pocket configuration +function pocket.load_config() + if not settings.load("/pocket.settings") then return false end + + config.SVR_Channel = settings.get("SVR_Channel") + config.CRD_Channel = settings.get("CRD_Channel") + config.PKT_Channel = settings.get("PKT_Channel") + config.ConnTimeout = settings.get("ConnTimeout") + config.TrustedRange = settings.get("TrustedRange") + config.AuthKey = settings.get("AuthKey") + + config.LogMode = settings.get("LogMode") + config.LogPath = settings.get("LogPath") + config.LogDebug = settings.get("LogDebug") + + local cfv = util.new_validator() + + cfv.assert_channel(config.SVR_Channel) + cfv.assert_channel(config.CRD_Channel) + cfv.assert_channel(config.PKT_Channel) + cfv.assert_type_num(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) + + if type(config.AuthKey) == "string" then + local len = string.len(config.AuthKey) + cfv.assert(len == 0 or len >= 8) + end + + cfv.assert_type_int(config.LogMode) + cfv.assert_range(config.LogMode, 0, 1) + cfv.assert_type_str(config.LogPath) + cfv.assert_type_bool(config.LogDebug) + + return cfv.valid() +end + -- pocket coordinator + supervisor communications ---@nodiscard ---@param version string pocket version ---@param nic nic network interface device ----@param pkt_channel integer pocket comms channel ----@param svr_channel integer supervisor access channel ----@param crd_channel integer coordinator access channel ----@param range integer trusted device connection range ---@param sv_watchdog watchdog ---@param api_watchdog watchdog -function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range, sv_watchdog, api_watchdog) +function pocket.comms(version, nic, sv_watchdog, api_watchdog) local self = { sv = { linked = false, @@ -42,13 +82,13 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range establish_delay_counter = 0 } - comms.set_trusted_range(range) + comms.set_trusted_range(config.TrustedRange) -- PRIVATE FUNCTIONS -- -- configure network channels nic.closeAll() - nic.open(pkt_channel) + nic.open(config.PKT_Channel) -- send a management packet to the supervisor ---@param msg_type MGMT_TYPE @@ -60,7 +100,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range pkt.make(msg_type, msg) s_pkt.make(self.sv.addr, self.sv.seq_num, PROTOCOL.SCADA_MGMT, pkt.raw_sendable()) - nic.transmit(svr_channel, pkt_channel, s_pkt) + nic.transmit(config.SVR_Channel, config.PKT_Channel, s_pkt) self.sv.seq_num = self.sv.seq_num + 1 end @@ -74,7 +114,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range pkt.make(msg_type, msg) s_pkt.make(self.api.addr, self.api.seq_num, PROTOCOL.SCADA_MGMT, pkt.raw_sendable()) - nic.transmit(crd_channel, pkt_channel, s_pkt) + nic.transmit(config.CRD_Channel, config.PKT_Channel, s_pkt) self.api.seq_num = self.api.seq_num + 1 end @@ -217,9 +257,9 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range local protocol = packet.scada_frame.protocol() local src_addr = packet.scada_frame.src_addr() - if l_chan ~= pkt_channel then + if l_chan ~= config.PKT_Channel then log.debug("received packet on unconfigured channel " .. l_chan, true) - elseif r_chan == crd_channel then + 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() @@ -308,7 +348,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range else log.debug("illegal packet type " .. protocol .. " from coordinator", true) end - elseif r_chan == svr_channel then + 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() diff --git a/pocket/startup.lua b/pocket/startup.lua index 4929955..13ac7fd 100644 --- a/pocket/startup.lua +++ b/pocket/startup.lua @@ -13,38 +13,37 @@ local util = require("scada-common.util") local core = require("graphics.core") -local config = require("pocket.config") +local configure = require("pocket.configure") local iocontrol = require("pocket.iocontrol") local pocket = require("pocket.pocket") local renderer = require("pocket.renderer") -local POCKET_VERSION = "v0.6.3-alpha" +local POCKET_VERSION = "v0.7.0-alpha" local println = util.println local println_ts = util.println_ts ---------------------------------------- --- config validation +-- get configuration ---------------------------------------- -local cfv = util.new_validator() +if not pocket.load_config() then + -- try to reconfigure (user action) + local success, error = configure.configure(true) + if success then + assert(pocket.load_config(), "failed to load valid configuration") + else + assert(success, "pocket configuration error: " .. error) + end +end -cfv.assert_channel(config.SVR_CHANNEL) -cfv.assert_channel(config.CRD_CHANNEL) -cfv.assert_channel(config.PKT_CHANNEL) -cfv.assert_type_int(config.TRUSTED_RANGE) -cfv.assert_type_num(config.COMMS_TIMEOUT) -cfv.assert_min(config.COMMS_TIMEOUT, 2) -cfv.assert_type_str(config.LOG_PATH) -cfv.assert_type_int(config.LOG_MODE) - -assert(cfv.valid(), "bad config file: missing/invalid fields") +local config = pocket.config ---------------------------------------- -- log init ---------------------------------------- -log.init(config.LOG_PATH, config.LOG_MODE, config.LOG_DEBUG == true) +log.init(config.LogPath, config.LogMode, config.LogDebug) log.info("========================================") log.info("BOOTING pocket.startup " .. POCKET_VERSION) @@ -69,8 +68,8 @@ local function main() ---------------------------------------- -- message authentication init - if type(config.AUTH_KEY) == "string" then - network.init_mac(config.AUTH_KEY) + if type(config.AuthKey) == "string" and string.len(config.AuthKey) > 0 then + network.init_mac(config.AuthKey) end iocontrol.report_link_state(iocontrol.LINK_STATE.UNLINKED) @@ -85,8 +84,8 @@ local function main() -- create connection watchdogs local conn_wd = { - sv = util.new_watchdog(config.COMMS_TIMEOUT), - api = util.new_watchdog(config.COMMS_TIMEOUT) + sv = util.new_watchdog(config.ConnTimeout), + api = util.new_watchdog(config.ConnTimeout) } conn_wd.sv.cancel() @@ -96,8 +95,7 @@ local function main() -- create network interface then setup comms local nic = network.nic(modem) - local pocket_comms = pocket.comms(POCKET_VERSION, nic, config.PKT_CHANNEL, config.SVR_CHANNEL, - config.CRD_CHANNEL, config.TRUSTED_RANGE, conn_wd.sv, conn_wd.api) + local pocket_comms = pocket.comms(POCKET_VERSION, nic, conn_wd.sv, conn_wd.api) log.debug("startup> comms init") -- base loop clock (2Hz, 10 ticks) diff --git a/reactor-plc/configure.lua b/reactor-plc/configure.lua index fbefb97..db9162d 100644 --- a/reactor-plc/configure.lua +++ b/reactor-plc/configure.lua @@ -181,7 +181,7 @@ local function config_view(display) local main_pane = MultiPane{parent=root_pane_div,x=1,y=1,panes={main_page,plc_cfg,net_cfg,log_cfg,summary,changelog}} - -- MAIN PAGE + -- Main Page local y_start = 5 @@ -212,7 +212,7 @@ local function config_view(display) PushButton{parent=main_page,x=2,y=17,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg} PushButton{parent=main_page,x=39,y=17,min_width=12,text="Change Log",callback=function()main_pane.set_value(6)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - -- PLC CONFIG + --#region PLC local plc_c_1 = Div{parent=plc_cfg,x=2,y=4,width=49} local plc_c_2 = Div{parent=plc_cfg,x=2,y=4,width=49} @@ -290,7 +290,9 @@ local function config_view(display) PushButton{parent=plc_c_4,x=1,y=14,text="\x1b Back",callback=function()plc_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=plc_c_4,x=44,y=14,text="Next \x1a",callback=submit_emcool,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - -- NET CONFIG + --#endregion + + --#region Network local net_c_1 = Div{parent=net_cfg,x=2,y=4,width=49} local net_c_2 = Div{parent=net_cfg,x=2,y=4,width=49} @@ -390,7 +392,9 @@ local function config_view(display) PushButton{parent=net_c_3,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=net_c_3,x=44,y=14,text="Next \x1a",callback=submit_auth,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - -- LOG CONFIG + --#endregion + + --#region Logging local log_c_1 = Div{parent=log_cfg,x=2,y=4,width=49} @@ -430,7 +434,9 @@ local function config_view(display) PushButton{parent=log_c_1,x=1,y=14,text="\x1b Back",callback=back_from_log,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=log_c_1,x=44,y=14,text="Next \x1a",callback=submit_log,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - -- SUMMARY OF CHANGES + --#endregion + + --#region Summary and Saving local sum_c_1 = Div{parent=summary,x=2,y=4,width=49} local sum_c_2 = Div{parent=summary,x=2,y=4,width=49} @@ -441,7 +447,7 @@ local function config_view(display) TextBox{parent=summary,x=1,y=2,height=1,text=" Summary",fg_bg=cpair(colors.black,colors.green)} - local setting_list = ListBox{parent=sum_c_1,x=1,y=1,height=12,width=51,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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)} local function back_from_settings() if tool_ctl.viewing_config or tool_ctl.importing_legacy then @@ -463,7 +469,7 @@ local function config_view(display) local function save_and_continue() for k, v in pairs(tmp_cfg) do settings.set(k, v) end - if settings.save("reactor-plc.settings") then + if settings.save("/reactor-plc.settings") then load_settings(settings_cfg, true) load_settings(ini_cfg) @@ -525,13 +531,15 @@ local function config_view(display) PushButton{parent=sum_c_4,x=1,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=sum_c_4,x=44,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)} - -- CONFIG CHANGE LOG + --#endregion + + -- Config Change Log 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} - local c_log = ListBox{parent=cl,x=1,y=1,height=12,width=51,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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} @@ -646,7 +654,7 @@ local function reset_term() end -- run the reactor PLC configurator ----@param ask_config? boolean indicate if this is being called by the PLC startup app due to an invalid configuration +---@param ask_config? boolean indicate if this is being called by the startup app due to an invalid configuration function configurator.configure(ask_config) tool_ctl.ask_config = ask_config == true diff --git a/reactor-plc/startup.lua b/reactor-plc/startup.lua index d73037d..e667e46 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.6.10" +local R_PLC_VERSION = "v1.6.11" local println = util.println local println_ts = util.println_ts diff --git a/rtu/configure.lua b/rtu/configure.lua index c1ab9db..131623b 100644 --- a/rtu/configure.lua +++ b/rtu/configure.lua @@ -273,7 +273,7 @@ local function config_view(display) local main_pane = MultiPane{parent=root_pane_div,x=1,y=1,panes={main_page,spkr_cfg,net_cfg,log_cfg,summary,changelog,peri_cfg,rs_cfg}} - --#region MAIN PAGE + --#region Main Page local y_start = 2 @@ -324,7 +324,7 @@ local function config_view(display) --#endregion - --#region SPEAKER CONFIG + --#region Speakers local spkr_c = Div{parent=spkr_cfg,x=2,y=4,width=49} @@ -353,7 +353,7 @@ local function config_view(display) --#endregion - --#region NET CONFIG + --#region Network local net_c_1 = Div{parent=net_cfg,x=2,y=4,width=49} local net_c_2 = Div{parent=net_cfg,x=2,y=4,width=49} @@ -455,7 +455,7 @@ local function config_view(display) --#endregion - --#region LOG CONFIG + --#region Logging local log_c_1 = Div{parent=log_cfg,x=2,y=4,width=49} @@ -494,7 +494,7 @@ local function config_view(display) --#endregion - --#region SUMMARY OF CHANGES + --#region Summary and Saving local sum_c_1 = Div{parent=summary,x=2,y=4,width=49} local sum_c_2 = Div{parent=summary,x=2,y=4,width=49} @@ -508,7 +508,7 @@ local function config_view(display) TextBox{parent=summary,x=1,y=2,height=1,text=" Summary",fg_bg=cpair(colors.black,colors.green)} - local setting_list = ListBox{parent=sum_c_1,x=1,y=1,height=12,width=51,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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)} local function back_from_settings() if tool_ctl.viewing_config or tool_ctl.importing_legacy then @@ -539,7 +539,7 @@ local function config_view(display) if settings.get("Peripherals") == nil then settings.set("Peripherals", {}) end if settings.get("Redstone") == nil then settings.set("Redstone", {}) end - if settings.save("rtu.settings") then + if settings.save("/rtu.settings") then load_settings(settings_cfg, true) load_settings(ini_cfg) @@ -578,13 +578,13 @@ local function config_view(display) tool_ctl.settings_confirm.hide() TextBox{parent=sum_c_2,x=1,y=1,height=1,text="The following peripherals will be imported:"} - local peri_import_list = ListBox{parent=sum_c_2,x=1,y=3,height=10,width=51,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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:"} - local rs_import_list = ListBox{parent=sum_c_3,x=1,y=3,height=10,width=51,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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} PushButton{parent=sum_c_3,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} @@ -614,13 +614,13 @@ local function config_view(display) --#endregion - --#region CONFIG CHANGE LOG + --#region Config Change Log 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} - local c_log = ListBox{parent=cl,x=1,y=1,height=12,width=51,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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} @@ -635,7 +635,7 @@ local function config_view(display) --#endregion - --#region DEVICES + --#region Peripherals local peri_c_1 = Div{parent=peri_cfg,x=2,y=4,width=49} local peri_c_2 = Div{parent=peri_cfg,x=2,y=4,width=49} @@ -649,7 +649,7 @@ local function config_view(display) TextBox{parent=peri_cfg,x=1,y=2,height=1,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=51,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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)} local function peri_revert() tmp_cfg.Peripherals = deep_copy_peri(ini_cfg.Peripherals) @@ -659,7 +659,7 @@ local function config_view(display) local function peri_apply() settings.set("Peripherals", tmp_cfg.Peripherals) - if settings.save("rtu.settings") then + if settings.save("/rtu.settings") then load_settings(settings_cfg, true) load_settings(ini_cfg) peri_pane.set_value(5) @@ -675,7 +675,7 @@ local function config_view(display) TextBox{parent=peri_c_2,x=1,y=1,height=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=51,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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)} PushButton{parent=peri_c_2,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_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} @@ -949,7 +949,7 @@ local function config_view(display) --#endregion - --#region REDSTONE + --#region Redstone local rs_c_1 = Div{parent=rs_cfg,x=2,y=4,width=49} local rs_c_2 = Div{parent=rs_cfg,x=2,y=4,width=49} @@ -963,7 +963,7 @@ local function config_view(display) TextBox{parent=rs_cfg,x=1,y=2,height=1,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} - local rs_list = ListBox{parent=rs_c_1,x=1,y=2,height=11,width=51,scroll_height=200,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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() tmp_cfg.Redstone = deep_copy_rs(ini_cfg.Redstone) @@ -973,7 +973,7 @@ local function config_view(display) local function rs_apply() settings.set("Redstone", tmp_cfg.Redstone) - if settings.save("rtu.settings") then + if settings.save("/rtu.settings") then load_settings(settings_cfg, true) load_settings(ini_cfg) rs_pane.set_value(4) @@ -992,7 +992,7 @@ local function config_view(display) TextBox{parent=rs_c_2,x=1,y=1,height=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=51,scroll_height=200,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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)} local function new_rs(port) if (rsio.get_io_dir(port) == rsio.IO_DIR.IN) then @@ -1466,7 +1466,7 @@ local function reset_term() end -- run the RTU gateway configurator ----@param ask_config? boolean indicate if this is being called by the RTU startup app due to an invalid configuration +---@param ask_config? boolean indicate if this is being called by the startup app due to an invalid configuration function configurator.configure(ask_config) tool_ctl.ask_config = ask_config == true diff --git a/rtu/startup.lua b/rtu/startup.lua index e8e85fc..d58639c 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.7.12" +local RTU_VERSION = "v1.7.13" 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 edcb7c3..eaa7ec4 100644 --- a/scada-common/comms.lua +++ b/scada-common/comms.lua @@ -17,7 +17,7 @@ local max_distance = nil local comms = {} -- protocol/data version (protocol/data independent changes tracked by util.lua version) -comms.version = "2.4.3" +comms.version = "2.4.4" ---@enum PROTOCOL local PROTOCOL = { diff --git a/scada-common/network.lua b/scada-common/network.lua index d9fa83f..742f418 100644 --- a/scada-common/network.lua +++ b/scada-common/network.lua @@ -7,7 +7,7 @@ local log = require("scada-common.log") local util = require("scada-common.util") local md5 = require("lockbox.digest.md5") -local sha256 = require("lockbox.digest.sha2_256") +local sha1 = require("lockbox.digest.sha1") local pbkdf2 = require("lockbox.kdf.pbkdf2") local hmac = require("lockbox.mac.hmac") local stream = require("lockbox.util.stream") @@ -31,12 +31,12 @@ function network.init_mac(passkey) local key_deriv = pbkdf2() -- setup PBKDF2 - key_deriv.setPassword(passkey) + key_deriv.setPRF(hmac().setBlockSize(64).setDigest(sha1)) + key_deriv.setBlockLen(20) + key_deriv.setDKeyLen(20) + key_deriv.setIterations(256) key_deriv.setSalt("pepper") - key_deriv.setIterations(32) - key_deriv.setBlockLen(8) - key_deriv.setDKeyLen(16) - key_deriv.setPRF(hmac().setBlockSize(64).setDigest(sha256)) + key_deriv.setPassword(passkey) key_deriv.finish() c_eng.key = array.fromHex(key_deriv.asHex()) diff --git a/scada-common/util.lua b/scada-common/util.lua index f407e36..10b4202 100644 --- a/scada-common/util.lua +++ b/scada-common/util.lua @@ -22,7 +22,7 @@ local t_pack = table.pack local util = {} -- scada-common version -util.version = "1.1.13" +util.version = "1.1.14" util.TICK_TIME_S = 0.05 util.TICK_TIME_MS = 50 diff --git a/startup.lua b/startup.lua index 525402b..811f510 100644 --- a/startup.lua +++ b/startup.lua @@ -2,7 +2,7 @@ local util = require("scada-common.util") local println = util.println -local BOOTLOADER_VERSION = "0.6" +local BOOTLOADER_VERSION = "1.0" println("SCADA BOOTLOADER V" .. BOOTLOADER_VERSION) println("BOOT> SCANNING FOR APPLICATIONS...") diff --git a/supervisor/configure.lua b/supervisor/configure.lua index b8c4e00..34398b6 100644 --- a/supervisor/configure.lua +++ b/supervisor/configure.lua @@ -170,7 +170,7 @@ local function config_view(display) local main_pane = MultiPane{parent=root_pane_div,x=1,y=1,panes={main_page,svr_cfg,net_cfg,log_cfg,summary,changelog,import_err}} - -- MAIN PAGE + -- Main Page local y_start = 5 @@ -201,7 +201,7 @@ local function config_view(display) PushButton{parent=main_page,x=2,y=17,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg} PushButton{parent=main_page,x=39,y=17,min_width=12,text="Change Log",callback=function()main_pane.set_value(6)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - -- SUPERVISOR CONFIG + --#region Facility local svr_c_1 = Div{parent=svr_cfg,x=2,y=4,width=49} local svr_c_2 = Div{parent=svr_cfg,x=2,y=4,width=49} @@ -564,7 +564,9 @@ local function config_view(display) PushButton{parent=svr_c_6,x=1,y=14,text="\x1b Back",callback=function()svr_pane.set_value(5)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - -- NET CONFIG + --#endregion + + --#region Network local net_c_1 = Div{parent=net_cfg,x=2,y=4,width=49} local net_c_2 = Div{parent=net_cfg,x=2,y=4,width=49} @@ -692,7 +694,9 @@ local function config_view(display) PushButton{parent=net_c_4,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=net_c_4,x=44,y=14,text="Next \x1a",callback=submit_auth,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - -- LOG CONFIG + --#endregion + + --#region Logging local log_c_1 = Div{parent=log_cfg,x=2,y=4,width=49} @@ -728,7 +732,9 @@ local function config_view(display) PushButton{parent=log_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=log_c_1,x=44,y=14,text="Next \x1a",callback=submit_log,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} - -- SUMMARY OF CHANGES + --#endregion + + --#region Summary and Saving local sum_c_1 = Div{parent=summary,x=2,y=4,width=49} local sum_c_2 = Div{parent=summary,x=2,y=4,width=49} @@ -739,7 +745,7 @@ local function config_view(display) TextBox{parent=summary,x=1,y=2,height=1,text=" Summary",fg_bg=cpair(colors.black,colors.green)} - local setting_list = ListBox{parent=sum_c_1,x=1,y=1,height=12,width=51,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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)} local function back_from_settings() if tool_ctl.viewing_config or tool_ctl.importing_legacy then @@ -761,7 +767,7 @@ local function config_view(display) local function save_and_continue() for k, v in pairs(tmp_cfg) do settings.set(k, v) end - if settings.save("supervisor.settings") then + if settings.save("/supervisor.settings") then load_settings(settings_cfg, true) load_settings(ini_cfg) @@ -838,13 +844,15 @@ local function config_view(display) PushButton{parent=sum_c_4,x=1,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg} PushButton{parent=sum_c_4,x=44,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)} - -- CONFIG CHANGE LOG + --#endregion + + -- Config Change Log 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} - local c_log = ListBox{parent=cl,x=1,y=1,height=12,width=51,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)} + 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} @@ -857,7 +865,7 @@ local function config_view(display) PushButton{parent=cl,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} - -- IMPORT ERROR + -- Import Error local i_err = Div{parent=import_err,x=2,y=4,width=49} @@ -1033,7 +1041,7 @@ local function reset_term() end -- run the supervisor configurator ----@param ask_config? boolean indicate if this is being called by the supervisor startup app due to an invalid configuration +---@param ask_config? boolean indicate if this is being called by the startup app due to an invalid configuration function configurator.configure(ask_config) tool_ctl.ask_config = ask_config == true diff --git a/supervisor/startup.lua b/supervisor/startup.lua index a983ee4..080e318 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.2.6" +local SUPERVISOR_VERSION = "v1.2.7" local println = util.println local println_ts = util.println_ts