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/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 b9334b5..13ac7fd 100644 --- a/pocket/startup.lua +++ b/pocket/startup.lua @@ -13,7 +13,7 @@ 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") @@ -24,27 +24,26 @@ 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)