#580 work on supervisor wired modem configuration
This commit is contained in:
parent
bee1cdf01c
commit
4a7fc6200e
@ -62,8 +62,10 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
|
||||
local net_c_2 = Div{parent=net_cfg,x=2,y=4,width=49}
|
||||
local net_c_3 = Div{parent=net_cfg,x=2,y=4,width=49}
|
||||
local net_c_4 = Div{parent=net_cfg,x=2,y=4,width=49}
|
||||
local net_c_5 = Div{parent=net_cfg,x=2,y=4,width=49}
|
||||
local net_c_6 = Div{parent=net_cfg,x=2,y=4,width=49}
|
||||
|
||||
local net_pane = MultiPane{parent=net_cfg,x=1,y=4,panes={net_c_1,net_c_2,net_c_3,net_c_4}}
|
||||
local net_pane = MultiPane{parent=net_cfg,x=1,y=4,panes={net_c_1,net_c_2,net_c_3,net_c_4,net_c_5,net_c_6}}
|
||||
|
||||
TextBox{parent=net_cfg,x=1,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)}
|
||||
|
||||
@ -137,40 +139,54 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
|
||||
PushButton{parent=net_c_2,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
|
||||
PushButton{parent=net_c_2,x=44,y=14,text="Next \x1a",callback=submit_timeouts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
|
||||
|
||||
TextBox{parent=net_c_3,x=1,y=1,text="Please set the trusted range below."}
|
||||
TextBox{parent=net_c_3,x=1,y=3,height=3,text="Setting this to a value larger than 0 prevents connections with devices that many meters (blocks) away in any direction.",fg_bg=g_lg_fg_bg}
|
||||
TextBox{parent=net_c_3,x=1,y=7,height=2,text="This is optional. You can disable this functionality by setting the value to 0.",fg_bg=g_lg_fg_bg}
|
||||
TextBox{parent=net_c_3,x=1,y=1,text="Please set the modem configuration below."}
|
||||
TextBox{parent=net_c_3,x=1,y=3,height=3,text="Communications with the coordinator,",fg_bg=g_lg_fg_bg}
|
||||
-- TextBox{parent=net_c_3,x=1,y=7,height=2,text="This is optional. You can disable this functionality by setting the value to 0.",fg_bg=g_lg_fg_bg}
|
||||
|
||||
local range = NumberField{parent=net_c_3,x=1,y=10,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg}
|
||||
local use_wired = Checkbox{parent=net_c_3,x=1,y=12,label="Use Wired Modem",default=ini_cfg.ExtChargeIdling,box_fg_bg=cpair(colors.yellow,colors.black)}
|
||||
|
||||
local tr_err = TextBox{parent=net_c_3,x=8,y=14,width=35,text="Please set the trusted range.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
|
||||
local function submit_modems()
|
||||
-- tmp_cfg. = use_wired.get_value()
|
||||
net_pane.set_value(4)
|
||||
end
|
||||
|
||||
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_modems,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
|
||||
|
||||
TextBox{parent=net_c_5,x=1,y=1,text="Please set the trusted range below."}
|
||||
TextBox{parent=net_c_5,x=1,y=3,height=3,text="Setting this to a value larger than 0 prevents connections with devices that many meters (blocks) away in any direction.",fg_bg=g_lg_fg_bg}
|
||||
TextBox{parent=net_c_5,x=1,y=7,height=2,text="This is optional. You can disable this functionality by setting the value to 0.",fg_bg=g_lg_fg_bg}
|
||||
|
||||
local range = NumberField{parent=net_c_5,x=1,y=10,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg}
|
||||
|
||||
local tr_err = TextBox{parent=net_c_5,x=8,y=14,width=35,text="Please set the trusted range.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
|
||||
|
||||
local function submit_tr()
|
||||
local range_val = tonumber(range.get_value())
|
||||
if range_val ~= nil then
|
||||
tmp_cfg.TrustedRange = range_val
|
||||
net_pane.set_value(4)
|
||||
net_pane.set_value(6)
|
||||
tr_err.hide(true)
|
||||
else tr_err.show() end
|
||||
end
|
||||
|
||||
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_tr,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
|
||||
PushButton{parent=net_c_5,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_5,x=44,y=14,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=2,text="Optionally, set the facility authentication key below. Do NOT use one of your passwords."}
|
||||
TextBox{parent=net_c_4,x=1,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for security on multiplayer servers. All devices on the same network MUST use the same key if any device has a key. This does result in some extra computation (can slow things down).",fg_bg=g_lg_fg_bg}
|
||||
TextBox{parent=net_c_6,x=1,y=1,height=2,text="Optionally, set the facility authentication key below. Do NOT use one of your passwords."}
|
||||
TextBox{parent=net_c_6,x=1,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for security on multiplayer servers. All devices on the same network MUST use the same key if any device has a key. This does result in some extra computation (can slow things down).",fg_bg=g_lg_fg_bg}
|
||||
|
||||
TextBox{parent=net_c_4,x=1,y=11,text="Facility Auth Key"}
|
||||
local key, _ = TextField{parent=net_c_4,x=1,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg}
|
||||
TextBox{parent=net_c_6,x=1,y=11,text="Facility Auth Key"}
|
||||
local key, _ = TextField{parent=net_c_6,x=1,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg}
|
||||
|
||||
local function censor_key(enable) key.censor(tri(enable, "*", nil)) end
|
||||
|
||||
local hide_key = Checkbox{parent=net_c_4,x=34,y=12,label="Hide",box_fg_bg=cpair(colors.lightBlue,colors.black),callback=censor_key}
|
||||
local hide_key = Checkbox{parent=net_c_6,x=34,y=12,label="Hide",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=8,y=14,width=35,text="Key must be at least 8 characters.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
|
||||
local key_err = TextBox{parent=net_c_6,x=8,y=14,width=35,text="Key must be at least 8 characters.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
|
||||
|
||||
local function submit_auth()
|
||||
local v = key.get_value()
|
||||
@ -181,8 +197,8 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
|
||||
else key_err.show() end
|
||||
end
|
||||
|
||||
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}
|
||||
PushButton{parent=net_c_6,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(5)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
|
||||
PushButton{parent=net_c_6,x=44,y=14,text="Next \x1a",callback=submit_auth,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
|
||||
|
||||
--#endregion
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
--
|
||||
|
||||
local log = require("scada-common.log")
|
||||
local ppm = require("scada-common.ppm")
|
||||
local tcd = require("scada-common.tcd")
|
||||
local util = require("scada-common.util")
|
||||
|
||||
@ -96,8 +97,11 @@ local tmp_cfg = {
|
||||
RTU_Timeout = nil, ---@type number
|
||||
CRD_Timeout = nil, ---@type number
|
||||
PKT_Timeout = nil, ---@type number
|
||||
WiredModem = false, ---@type string|false
|
||||
WirelessModem = false, ---@type boolean
|
||||
TrustedRange = nil, ---@type number
|
||||
AuthKey = nil, ---@type string|nil
|
||||
PocketTest = true, ---@type boolean
|
||||
LogMode = 0, ---@type LOG_MODE
|
||||
LogPath = "",
|
||||
LogDebug = false,
|
||||
@ -130,8 +134,11 @@ local fields = {
|
||||
{ "RTU_Timeout", "RTU Connection Timeout", 5 },
|
||||
{ "CRD_Timeout", "CRD Connection Timeout", 5 },
|
||||
{ "PKT_Timeout", "PKT Connection Timeout", 5 },
|
||||
{ "WiredModem", "Wired Modem", false },
|
||||
{ "WirelessModem", "Pocket Wireless/Ender Modem", true },
|
||||
{ "TrustedRange", "Trusted Range", 0 },
|
||||
{ "AuthKey", "Facility Auth Key" , "" },
|
||||
{ "PocketTest", "Pocket Testing Features", true },
|
||||
{ "LogMode", "Log Mode", log.MODE.APPEND },
|
||||
{ "LogPath", "Log Path", "/log.txt" },
|
||||
{ "LogDebug", "Log Debug Messages", false },
|
||||
@ -314,6 +321,14 @@ function configurator.configure(ask_config)
|
||||
if k_e then display.handle_key(k_e) end
|
||||
elseif event == "paste" then
|
||||
display.handle_paste(param1)
|
||||
elseif event == "peripheral_detach" then
|
||||
---@diagnostic disable-next-line: discard-returns
|
||||
ppm.handle_unmount(param1)
|
||||
tool_ctl.gen_modem_list()
|
||||
elseif event == "peripheral" then
|
||||
---@diagnostic disable-next-line: discard-returns
|
||||
ppm.mount(param1)
|
||||
tool_ctl.gen_modem_list()
|
||||
end
|
||||
|
||||
if event == "terminate" then return end
|
||||
|
||||
@ -27,10 +27,16 @@ function databus.tx_versions(sv_v, comms_v)
|
||||
databus.ps.publish("comms_version", comms_v)
|
||||
end
|
||||
|
||||
-- transmit hardware status for modem connection state
|
||||
-- transmit hardware status for the core comms modem connection state
|
||||
---@param has_modem boolean
|
||||
function databus.tx_hw_modem(has_modem)
|
||||
databus.ps.publish("has_modem", has_modem)
|
||||
function databus.tx_hw_c_modem(has_modem)
|
||||
databus.ps.publish("has_c_modem", has_modem)
|
||||
end
|
||||
|
||||
-- transmit hardware status for the pocket modem connection state
|
||||
---@param has_modem boolean
|
||||
function databus.tx_hw_p_modem(has_modem)
|
||||
databus.ps.publish("has_p_modem", has_modem)
|
||||
end
|
||||
|
||||
-- transmit PLC firmware version and session connection state
|
||||
|
||||
@ -34,7 +34,8 @@ local ind_grn = style.ind_grn
|
||||
|
||||
-- create new front panel view
|
||||
---@param panel DisplayBox main displaybox
|
||||
local function init(panel)
|
||||
---@param wl_modem boolean if there is a separate wireless modem
|
||||
local function init(panel, wl_modem)
|
||||
local s_hi_box = style.theme.highlight_box
|
||||
local s_hi_bright = style.theme.highlight_box_bright
|
||||
|
||||
@ -53,7 +54,7 @@ local function init(panel)
|
||||
|
||||
local main_page = Div{parent=page_div,x=1,y=1}
|
||||
|
||||
local system = Div{parent=main_page,width=14,height=17,x=2,y=2}
|
||||
local system = Div{parent=main_page,width=18,height=17,x=2,y=2}
|
||||
|
||||
local on = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)}
|
||||
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=ind_grn}
|
||||
@ -62,14 +63,21 @@ local function init(panel)
|
||||
|
||||
heartbeat.register(databus.ps, "heartbeat", heartbeat.update)
|
||||
|
||||
local modem = LED{parent=system,label="MODEM",colors=ind_grn}
|
||||
local c_modem = LED{parent=system,label="MODEM"..util.trinary(wl_modem," A",""),colors=ind_grn}
|
||||
system.line_break()
|
||||
|
||||
modem.register(databus.ps, "has_modem", modem.update)
|
||||
c_modem.register(databus.ps, "has_modem_a", c_modem.update)
|
||||
|
||||
if wl_modem then
|
||||
local p_modem = LED{parent=system,label="MODEM B",colors=ind_grn}
|
||||
system.line_break()
|
||||
|
||||
p_modem.register(databus.ps, "has_modem_b", p_modem.update)
|
||||
end
|
||||
|
||||
---@diagnostic disable-next-line: undefined-field
|
||||
local comp_id = util.sprintf("(%d)", os.getComputerID())
|
||||
TextBox{parent=system,x=9,y=4,width=6,text=comp_id,fg_bg=style.fp.disabled_fg}
|
||||
TextBox{parent=system,x=11,y=4,width=6,text=comp_id,fg_bg=style.fp.disabled_fg}
|
||||
|
||||
--
|
||||
-- about footer
|
||||
|
||||
159
supervisor/pcie.lua
Normal file
159
supervisor/pcie.lua
Normal file
@ -0,0 +1,159 @@
|
||||
--
|
||||
-- PCIe - Borrowed the name of that protocol for fun (this manages physical peripherals)
|
||||
--
|
||||
|
||||
local log = require("scada-common.log")
|
||||
local network = require("scada-common.network")
|
||||
local ppm = require("scada-common.ppm")
|
||||
|
||||
local databus = require("supervisor.databus")
|
||||
|
||||
local pcie_bus = {}
|
||||
|
||||
local bus = {
|
||||
c_wired = false, ---@type string|false wired comms modem
|
||||
c_nic = nil, ---@type nic core nic
|
||||
p_nic = nil ---@type nic|nil pocket nic
|
||||
}
|
||||
|
||||
-- network cards
|
||||
---@class _svr_pcie_nic
|
||||
---@field core nic the core comms NIC
|
||||
---@field pocket nic the pocket NIC
|
||||
pcie_bus.nic = {
|
||||
-- close all channels then open a specified one on all nics
|
||||
---@param channel integer
|
||||
reset_open = function (channel)
|
||||
bus.c_nic.closeAll()
|
||||
bus.c_nic.open(channel)
|
||||
|
||||
if bus.p_nic then
|
||||
bus.p_nic.closeAll()
|
||||
bus.p_nic.open(channel)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
-- initialize peripherals
|
||||
---@param config svr_config
|
||||
---@param println function
|
||||
function pcie_bus.init(config, println)
|
||||
-- setup networking peripheral(s)
|
||||
local core_modem, core_iface = ppm.get_wireless_modem()
|
||||
if type(config.WiredModem) == "string" then
|
||||
bus.c_wired = config.WiredModem
|
||||
core_modem = ppm.get_wired_modem(config.WiredModem)
|
||||
end
|
||||
|
||||
if not (core_modem and core_iface) then
|
||||
println("startup> core comms modem not found")
|
||||
log.fatal("no core comms modem on startup")
|
||||
return
|
||||
end
|
||||
|
||||
bus.c_nic = network.nic(core_iface, core_modem)
|
||||
|
||||
if config.WirelessModem and config.WiredModem then
|
||||
local pocket_modem, pocket_iface = ppm.get_wireless_modem()
|
||||
|
||||
if not (pocket_modem and pocket_iface) then
|
||||
println("startup> pocket wireless modem not found")
|
||||
log.fatal("no pocket wireless modem on startup")
|
||||
return
|
||||
end
|
||||
|
||||
bus.p_nic = network.nic(pocket_iface, pocket_modem)
|
||||
end
|
||||
|
||||
pcie_bus.nic.core = bus.c_nic
|
||||
pcie_bus.nic.pocket = bus.p_nic or bus.c_nic
|
||||
|
||||
databus.tx_hw_c_modem(true)
|
||||
databus.tx_hw_p_modem(config.WirelessModem)
|
||||
end
|
||||
|
||||
-- handle the connecting of a device
|
||||
---@param iface string
|
||||
---@param type string
|
||||
---@param device table
|
||||
---@param println function
|
||||
function pcie_bus.connect(iface, type, device, println)
|
||||
if type == "modem" then
|
||||
---@cast device Modem
|
||||
if device.isWireless() then
|
||||
if not (bus.c_wired or bus.c_nic.is_connected()) then
|
||||
-- reconnected comms modem
|
||||
bus.c_nic.connect(device)
|
||||
|
||||
println("core comms modem reconnected")
|
||||
log.info("core comms modem reconnected")
|
||||
|
||||
databus.tx_hw_c_modem(true)
|
||||
elseif bus.p_nic and not bus.p_nic.is_connected() then
|
||||
-- reconnected pocket modem
|
||||
bus.p_nic.connect(device)
|
||||
|
||||
println("pocket modem reconnected")
|
||||
log.info("pocket modem reconnected")
|
||||
|
||||
databus.tx_hw_p_modem(true)
|
||||
else
|
||||
log.info("unused wireless modem reconnected")
|
||||
end
|
||||
elseif iface == bus.c_wired then
|
||||
-- reconnected wired comms modem
|
||||
bus.c_nic.connect(device)
|
||||
|
||||
println("core comms modem reconnected")
|
||||
log.info("core comms modem reconnected")
|
||||
|
||||
databus.tx_hw_c_modem(true)
|
||||
else
|
||||
log.info("wired modem reconnected")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- handle the removal of a device
|
||||
---@param type string
|
||||
---@param device table
|
||||
---@param println function
|
||||
function pcie_bus.remove(type, device, println)
|
||||
if type == "modem" then
|
||||
---@cast device Modem
|
||||
if bus.c_nic.is_modem(device) then
|
||||
bus.c_nic.disconnect()
|
||||
|
||||
println("core comms modem disconnected")
|
||||
log.warning("core comms modem disconnected")
|
||||
|
||||
local other_modem = ppm.get_wireless_modem()
|
||||
if other_modem and not bus.c_wired then
|
||||
log.info("found another wireless modem, using it for comms")
|
||||
bus.c_nic.connect(other_modem)
|
||||
else
|
||||
databus.tx_hw_c_modem(false)
|
||||
end
|
||||
elseif bus.p_nic and bus.p_nic.is_modem(device) then
|
||||
bus.p_nic.disconnect()
|
||||
|
||||
println("pocket modem disconnected")
|
||||
log.warning("pocket modem disconnected")
|
||||
|
||||
local other_modem = ppm.get_wireless_modem()
|
||||
if other_modem then
|
||||
log.info("found another wireless modem, using it for pocket comms")
|
||||
bus.p_nic.connect(other_modem)
|
||||
else
|
||||
databus.tx_hw_p_modem(false)
|
||||
end
|
||||
else
|
||||
log.warning("non-comms modem disconnected")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- check if a dedicated pocket nic is in use
|
||||
function pcie_bus.has_pocket_nic() return bus.p_nic ~= nil end
|
||||
|
||||
return pcie_bus
|
||||
@ -19,10 +19,11 @@ local ui = {
|
||||
}
|
||||
|
||||
-- try to start the UI
|
||||
---@param wl_modem boolean if there is a separate wireless modem to display the status of
|
||||
---@param theme FP_THEME front panel theme
|
||||
---@param color_mode COLOR_MODE color mode
|
||||
---@return boolean success, any error_msg
|
||||
function renderer.try_start_ui(theme, color_mode)
|
||||
function renderer.try_start_ui(wl_modem, theme, color_mode)
|
||||
local status, msg = true, nil
|
||||
|
||||
if ui.display == nil then
|
||||
@ -49,7 +50,7 @@ function renderer.try_start_ui(theme, color_mode)
|
||||
-- init front panel view
|
||||
status, msg = pcall(function ()
|
||||
ui.display = DisplayBox{window=term.current(),fg_bg=style.fp.root}
|
||||
panel_view(ui.display)
|
||||
panel_view(ui.display, wl_modem)
|
||||
end)
|
||||
|
||||
if status then
|
||||
|
||||
@ -6,6 +6,7 @@ local log = require("scada-common.log")
|
||||
local mqueue = require("scada-common.mqueue")
|
||||
local types = require("scada-common.types")
|
||||
local util = require("scada-common.util")
|
||||
local pcie = require("supervisor.pcie")
|
||||
|
||||
local databus = require("supervisor.databus")
|
||||
|
||||
@ -41,20 +42,17 @@ svsessions.SESSION_TYPE = SESSION_TYPE
|
||||
|
||||
local self = {
|
||||
-- references to supervisor state and other data
|
||||
nic = nil, ---@type nic|nil
|
||||
fp_ok = false,
|
||||
config = nil, ---@type svr_config
|
||||
config = nil, ---@type svr_config|nil
|
||||
facility = nil, ---@type facility|nil
|
||||
plc_ini_reset = {},
|
||||
-- lists of connected sessions
|
||||
---@diagnostic disable: missing-fields
|
||||
sessions = {
|
||||
rtu = {}, ---@type rtu_session_struct
|
||||
plc = {}, ---@type plc_session_struct
|
||||
crd = {}, ---@type crd_session_struct
|
||||
pdg = {} ---@type pdg_session_struct
|
||||
rtu = {}, ---@type rtu_session_struct[]
|
||||
plc = {}, ---@type plc_session_struct[]
|
||||
crd = {}, ---@type crd_session_struct[]
|
||||
pdg = {} ---@type pdg_session_struct[]
|
||||
},
|
||||
---@diagnostic enable: missing-fields
|
||||
-- next session IDs
|
||||
next_ids = { rtu = 0, plc = 0, crd = 0, pdg = 0 },
|
||||
-- rtu device tracking and invalid assignment detection
|
||||
@ -83,7 +81,9 @@ local function _sv_handle_outq(session)
|
||||
if msg ~= nil then
|
||||
if msg.qtype == mqueue.TYPE.PACKET then
|
||||
-- handle a packet to be sent
|
||||
self.nic.transmit(session.r_chan, self.config.SVR_Channel, msg.message)
|
||||
if session.r_chan == self.config.PKT_Channel then
|
||||
pcie.nic.pocket.transmit(session.r_chan, self.config.SVR_Channel, msg.message)
|
||||
else pcie.nic.core.transmit(session.r_chan, self.config.SVR_Channel, msg.message) end
|
||||
elseif msg.qtype == mqueue.TYPE.COMMAND then
|
||||
-- handle instruction/notification
|
||||
elseif msg.qtype == mqueue.TYPE.DATA then
|
||||
@ -139,12 +139,9 @@ end
|
||||
local function _iterate(sessions)
|
||||
for i = 1, #sessions do
|
||||
local session = sessions[i]
|
||||
|
||||
if session.open and session.instance.iterate() then
|
||||
_sv_handle_outq(session)
|
||||
else
|
||||
session.open = false
|
||||
end
|
||||
else session.open = false end
|
||||
end
|
||||
end
|
||||
|
||||
@ -158,7 +155,9 @@ local function _shutdown(session)
|
||||
while session.out_queue.ready() do
|
||||
local msg = session.out_queue.pop()
|
||||
if msg ~= nil and msg.qtype == mqueue.TYPE.PACKET then
|
||||
self.nic.transmit(session.r_chan, self.config.SVR_Channel, msg.message)
|
||||
if session.r_chan == self.config.PKT_Channel then
|
||||
pcie.nic.pocket.transmit(session.r_chan, self.config.SVR_Channel, msg.message)
|
||||
else pcie.nic.core.transmit(session.r_chan, self.config.SVR_Channel, msg.message) end
|
||||
end
|
||||
end
|
||||
|
||||
@ -358,12 +357,10 @@ function svsessions.check_rtu_id(unit, list, max)
|
||||
end
|
||||
|
||||
-- initialize svsessions
|
||||
---@param nic nic network interface device
|
||||
---@param fp_ok boolean front panel active
|
||||
---@param config svr_config supervisor configuration
|
||||
---@param facility facility
|
||||
function svsessions.init(nic, fp_ok, config, facility)
|
||||
self.nic = nic
|
||||
function svsessions.init(fp_ok, config, facility)
|
||||
self.fp_ok = fp_ok
|
||||
self.config = config
|
||||
self.facility = facility
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
--
|
||||
|
||||
require("/initenv").init_env()
|
||||
local pcie = require("supervisor.pcie")
|
||||
|
||||
local crash = require("scada-common.crash")
|
||||
local comms = require("scada-common.comms")
|
||||
@ -125,18 +126,11 @@ local function main()
|
||||
network.init_mac(config.AuthKey)
|
||||
end
|
||||
|
||||
-- get modem
|
||||
local modem = ppm.get_wireless_modem()
|
||||
if modem == nil then
|
||||
println("startup> wireless modem not found")
|
||||
log.fatal("no wireless modem on startup")
|
||||
return
|
||||
end
|
||||
|
||||
databus.tx_hw_modem(true)
|
||||
-- hardware bus initialization
|
||||
pcie.init(config, println)
|
||||
|
||||
-- start UI
|
||||
local fp_ok, message = renderer.try_start_ui(config.FrontPanelTheme, config.ColorMode)
|
||||
local fp_ok, message = renderer.try_start_ui(pcie.has_pocket_nic(), config.FrontPanelTheme, config.ColorMode)
|
||||
|
||||
if not fp_ok then
|
||||
println_ts(util.c("UI error: ", message))
|
||||
@ -150,8 +144,7 @@ local function main()
|
||||
local sv_facility = facility.new(config)
|
||||
|
||||
-- create network interface then setup comms
|
||||
local nic = network.nic(modem)
|
||||
local superv_comms = supervisor.comms(SUPERVISOR_VERSION, nic, fp_ok, sv_facility)
|
||||
local superv_comms = supervisor.comms(SUPERVISOR_VERSION, fp_ok, sv_facility)
|
||||
|
||||
-- base loop clock (6.67Hz, 3 ticks)
|
||||
local MAIN_CLOCK = 0.15
|
||||
@ -173,49 +166,13 @@ local function main()
|
||||
-- handle event
|
||||
if event == "peripheral_detach" then
|
||||
local type, device = ppm.handle_unmount(param1)
|
||||
|
||||
if type ~= nil and device ~= nil then
|
||||
if type == "modem" then
|
||||
---@cast device Modem
|
||||
-- we only care if this is our wireless modem
|
||||
if nic.is_modem(device) then
|
||||
nic.disconnect()
|
||||
|
||||
println_ts("wireless modem disconnected!")
|
||||
log.warning("comms modem disconnected")
|
||||
|
||||
local other_modem = ppm.get_wireless_modem()
|
||||
if other_modem then
|
||||
log.info("found another wireless modem, using it for comms")
|
||||
nic.connect(other_modem)
|
||||
else
|
||||
databus.tx_hw_modem(false)
|
||||
end
|
||||
else
|
||||
log.warning("non-comms modem disconnected")
|
||||
end
|
||||
end
|
||||
pcie.remove(type, device, println_ts)
|
||||
end
|
||||
elseif event == "peripheral" then
|
||||
local type, device = ppm.mount(param1)
|
||||
|
||||
if type ~= nil and device ~= nil then
|
||||
if type == "modem" then
|
||||
---@cast device Modem
|
||||
if device.isWireless() and not nic.is_connected() then
|
||||
-- reconnected modem
|
||||
nic.connect(device)
|
||||
|
||||
println_ts("wireless modem reconnected.")
|
||||
log.info("comms modem reconnected")
|
||||
|
||||
databus.tx_hw_modem(true)
|
||||
elseif device.isWireless() then
|
||||
log.info("unused wireless modem reconnected")
|
||||
else
|
||||
log.info("wired modem reconnected")
|
||||
end
|
||||
end
|
||||
pcie.connect(param1, type, device, println_ts)
|
||||
end
|
||||
elseif event == "timer" and loop_clock.is_clock(param1) then
|
||||
-- main loop tick
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
local comms = require("scada-common.comms")
|
||||
local log = require("scada-common.log")
|
||||
local util = require("scada-common.util")
|
||||
local pcie = require("supervisor.pcie")
|
||||
|
||||
local themes = require("graphics.themes")
|
||||
|
||||
@ -123,11 +124,10 @@ end
|
||||
-- supervisory controller communications
|
||||
---@nodiscard
|
||||
---@param _version string supervisor version
|
||||
---@param nic nic network interface device
|
||||
---@param fp_ok boolean if the front panel UI is running
|
||||
---@param facility facility facility instance
|
||||
---@diagnostic disable-next-line: unused-local
|
||||
function supervisor.comms(_version, nic, fp_ok, facility)
|
||||
function supervisor.comms(_version, fp_ok, facility)
|
||||
-- print a log message to the terminal as long as the UI isn't running
|
||||
local function println(message) if not fp_ok then util.println_ts(message) end end
|
||||
|
||||
@ -137,20 +137,24 @@ function supervisor.comms(_version, nic, fp_ok, facility)
|
||||
|
||||
comms.set_trusted_range(config.TrustedRange)
|
||||
|
||||
-- PRIVATE FUNCTIONS --
|
||||
|
||||
-- configure modem channels
|
||||
nic.closeAll()
|
||||
nic.open(config.SVR_Channel)
|
||||
pcie.nic.reset_open(config.SVR_Channel)
|
||||
|
||||
-- pass system data and objects to svsessions
|
||||
svsessions.init(nic, fp_ok, config, facility)
|
||||
svsessions.init(fp_ok, config, facility)
|
||||
|
||||
-- get nic references
|
||||
local c_nic = pcie.nic.core
|
||||
local p_nic = pcie.nic.pocket
|
||||
|
||||
-- PRIVATE FUNCTIONS --
|
||||
|
||||
-- send an establish request response
|
||||
---@param nic nic
|
||||
---@param packet scada_packet
|
||||
---@param ack ESTABLISH_ACK
|
||||
---@param data? any optional data
|
||||
local function _send_establish(packet, ack, data)
|
||||
local function _send_establish(nic, packet, ack, data)
|
||||
local s_pkt = comms.scada_packet()
|
||||
local m_pkt = comms.mgmt_packet()
|
||||
|
||||
@ -175,36 +179,33 @@ function supervisor.comms(_version, nic, fp_ok, facility)
|
||||
---@param distance integer
|
||||
---@return modbus_frame|rplc_frame|mgmt_frame|crdn_frame|nil packet
|
||||
function public.parse_packet(side, sender, reply_to, message, distance)
|
||||
local s_pkt = nic.receive(side, sender, reply_to, message, distance)
|
||||
local pkt = nil
|
||||
local s_pkt = c_nic.receive(side, sender, reply_to, message, distance)
|
||||
|
||||
if p_nic and not s_pkt then
|
||||
-- try for it being from the pocket modem
|
||||
s_pkt = p_nic.receive(side, sender, reply_to, message, distance)
|
||||
end
|
||||
|
||||
if s_pkt then
|
||||
-- get as MODBUS TCP packet
|
||||
if s_pkt.protocol() == PROTOCOL.MODBUS_TCP then
|
||||
local m_pkt = comms.modbus_packet()
|
||||
if m_pkt.decode(s_pkt) then
|
||||
pkt = m_pkt.get()
|
||||
end
|
||||
if m_pkt.decode(s_pkt) then pkt = m_pkt.get() end
|
||||
-- get as RPLC packet
|
||||
elseif s_pkt.protocol() == PROTOCOL.RPLC then
|
||||
local rplc_pkt = comms.rplc_packet()
|
||||
if rplc_pkt.decode(s_pkt) then
|
||||
pkt = rplc_pkt.get()
|
||||
end
|
||||
if rplc_pkt.decode(s_pkt) then pkt = rplc_pkt.get() end
|
||||
-- get as SCADA management packet
|
||||
elseif s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
|
||||
local mgmt_pkt = comms.mgmt_packet()
|
||||
if mgmt_pkt.decode(s_pkt) then
|
||||
pkt = mgmt_pkt.get()
|
||||
end
|
||||
if mgmt_pkt.decode(s_pkt) then pkt = mgmt_pkt.get() end
|
||||
-- get as coordinator packet
|
||||
elseif s_pkt.protocol() == PROTOCOL.SCADA_CRDN then
|
||||
local crdn_pkt = comms.crdn_packet()
|
||||
if crdn_pkt.decode(s_pkt) then
|
||||
pkt = crdn_pkt.get()
|
||||
end
|
||||
if crdn_pkt.decode(s_pkt) then pkt = crdn_pkt.get() end
|
||||
else
|
||||
log.debug("attempted parse of illegal packet type " .. s_pkt.protocol(), true)
|
||||
log.debug("receive[" .. side .. "] attempted parse of illegal packet type " .. s_pkt.protocol(), true)
|
||||
end
|
||||
end
|
||||
|
||||
@ -257,7 +258,7 @@ function supervisor.comms(_version, nic, fp_ok, facility)
|
||||
log.info(util.c("dropping PLC establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
|
||||
end
|
||||
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
||||
elseif dev_type == DEVICE_TYPE.PLC then
|
||||
-- PLC linking request
|
||||
if packet.length == 4 and type(packet.data[4]) == "number" then
|
||||
@ -270,7 +271,7 @@ function supervisor.comms(_version, nic, fp_ok, facility)
|
||||
log.warning(util.c("PLC_ESTABLISH: denied assignment ", reactor_id, " outside of configured unit count ", config.UnitCount))
|
||||
end
|
||||
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
else
|
||||
-- try to establish the session
|
||||
local plc_id = svsessions.establish_plc_session(src_addr, i_seq_num, reactor_id, firmware_v)
|
||||
@ -281,25 +282,25 @@ function supervisor.comms(_version, nic, fp_ok, facility)
|
||||
log.warning(util.c("PLC_ESTABLISH: assignment collision with reactor ", reactor_id))
|
||||
end
|
||||
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.COLLISION)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.COLLISION)
|
||||
else
|
||||
-- got an ID; assigned to a reactor successfully
|
||||
println(util.c("PLC (", firmware_v, ") [@", src_addr, "] \xbb reactor ", reactor_id, " connected"))
|
||||
log.info(util.c("PLC_ESTABLISH: PLC (", firmware_v, ") [@", src_addr, "] reactor unit ", reactor_id, " PLC connected with session ID ", plc_id))
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.ALLOW)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.ALLOW)
|
||||
end
|
||||
end
|
||||
else
|
||||
log.debug("PLC_ESTABLISH: packet length mismatch/bad parameter type")
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
end
|
||||
else
|
||||
log.debug(util.c("illegal establish packet for device ", dev_type, " on PLC channel"))
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
end
|
||||
else
|
||||
log.debug("invalid establish packet (on PLC channel)")
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
end
|
||||
else
|
||||
-- any other packet should be session related, discard it
|
||||
@ -343,7 +344,7 @@ function supervisor.comms(_version, nic, fp_ok, facility)
|
||||
log.info(util.c("dropping RTU establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
|
||||
end
|
||||
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
||||
elseif dev_type == DEVICE_TYPE.RTU then
|
||||
if packet.length == 4 then
|
||||
-- this is an RTU advertisement for a new session
|
||||
@ -352,18 +353,18 @@ function supervisor.comms(_version, nic, fp_ok, facility)
|
||||
|
||||
println(util.c("RTU (", firmware_v, ") [@", src_addr, "] \xbb connected"))
|
||||
log.info(util.c("RTU_ESTABLISH: RTU (",firmware_v, ") [@", src_addr, "] connected with session ID ", s_id))
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.ALLOW)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.ALLOW)
|
||||
else
|
||||
log.debug("RTU_ESTABLISH: packet length mismatch")
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
end
|
||||
else
|
||||
log.debug(util.c("illegal establish packet for device ", dev_type, " on RTU channel"))
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
end
|
||||
else
|
||||
log.debug("invalid establish packet (on RTU channel)")
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
end
|
||||
else
|
||||
-- any other packet should be session related, discard it
|
||||
@ -397,7 +398,7 @@ function supervisor.comms(_version, nic, fp_ok, facility)
|
||||
log.info(util.c("dropping coordinator establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
|
||||
end
|
||||
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
||||
elseif dev_type == DEVICE_TYPE.CRD then
|
||||
-- this is an attempt to establish a new coordinator session
|
||||
local s_id = svsessions.establish_crd_session(src_addr, i_seq_num, firmware_v)
|
||||
@ -406,21 +407,21 @@ function supervisor.comms(_version, nic, fp_ok, facility)
|
||||
println(util.c("CRD (", firmware_v, ") [@", src_addr, "] \xbb connected"))
|
||||
log.info(util.c("CRD_ESTABLISH: coordinator (", firmware_v, ") [@", src_addr, "] connected with session ID ", s_id))
|
||||
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.ALLOW, { config.UnitCount, facility.get_cooling_conf() })
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.ALLOW, { config.UnitCount, facility.get_cooling_conf() })
|
||||
else
|
||||
if last_ack ~= ESTABLISH_ACK.COLLISION then
|
||||
log.info("CRD_ESTABLISH: denied new coordinator [@" .. src_addr .. "] due to already being connected to another coordinator")
|
||||
end
|
||||
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.COLLISION)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.COLLISION)
|
||||
end
|
||||
else
|
||||
log.debug(util.c("illegal establish packet for device ", dev_type, " on coordinator channel"))
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
end
|
||||
else
|
||||
log.debug("CRD_ESTABLISH: establish packet length mismatch")
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
_send_establish(c_nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
end
|
||||
else
|
||||
-- any other packet should be session related, discard it
|
||||
@ -464,7 +465,7 @@ function supervisor.comms(_version, nic, fp_ok, facility)
|
||||
log.info(util.c("dropping PDG establish packet with incorrect comms version v", comms_v, " (expected v", comms.version, ")"))
|
||||
end
|
||||
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
||||
_send_establish(p_nic or c_nic, packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
|
||||
elseif dev_type == DEVICE_TYPE.PKT then
|
||||
-- this is an attempt to establish a new pocket diagnostic session
|
||||
local s_id = svsessions.establish_pdg_session(src_addr, i_seq_num, firmware_v)
|
||||
@ -472,14 +473,14 @@ function supervisor.comms(_version, nic, fp_ok, facility)
|
||||
println(util.c("PKT (", firmware_v, ") [@", src_addr, "] \xbb connected"))
|
||||
log.info(util.c("PDG_ESTABLISH: pocket (", firmware_v, ") [@", src_addr, "] connected with session ID ", s_id))
|
||||
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.ALLOW)
|
||||
_send_establish(p_nic or c_nic, packet.scada_frame, ESTABLISH_ACK.ALLOW)
|
||||
else
|
||||
log.debug(util.c("illegal establish packet for device ", dev_type, " on pocket channel"))
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
_send_establish(p_nic or c_nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
end
|
||||
else
|
||||
log.debug("PDG_ESTABLISH: establish packet length mismatch")
|
||||
_send_establish(packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
_send_establish(p_nic or c_nic, packet.scada_frame, ESTABLISH_ACK.DENY)
|
||||
end
|
||||
else
|
||||
-- any other packet should be session related, discard it
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user