#634 coordinator backplane interface
This commit is contained in:
228
coordinator/backplane.lua
Normal file
228
coordinator/backplane.lua
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
--
|
||||||
|
-- Coordinator System Core Peripheral Backplane
|
||||||
|
--
|
||||||
|
|
||||||
|
local log = require("scada-common.log")
|
||||||
|
local network = require("scada-common.network")
|
||||||
|
local ppm = require("scada-common.ppm")
|
||||||
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
|
local coordinator = require("coordinator.coordinator")
|
||||||
|
local iocontrol = require("coordinator.iocontrol")
|
||||||
|
local sounder = require("coordinator.sounder")
|
||||||
|
|
||||||
|
local println = util.println
|
||||||
|
|
||||||
|
local log_sys = coordinator.log_sys
|
||||||
|
local log_boot = coordinator.log_boot
|
||||||
|
local log_comms = coordinator.log_comms
|
||||||
|
|
||||||
|
---@class crd_backplane
|
||||||
|
local backplane = {}
|
||||||
|
|
||||||
|
local _bp = {
|
||||||
|
smem = nil, ---@type crd_shared_memory
|
||||||
|
|
||||||
|
wlan_pref = true,
|
||||||
|
lan_iface = "",
|
||||||
|
|
||||||
|
act_nic = nil, ---@type nic
|
||||||
|
wd_nic = nil, ---@type nic|nil
|
||||||
|
wl_nic = nil, ---@type nic|nil
|
||||||
|
|
||||||
|
speaker = nil, ---@type Speaker|nil
|
||||||
|
|
||||||
|
---@class crd_displays
|
||||||
|
displays = {
|
||||||
|
main = nil, ---@type Monitor|nil
|
||||||
|
main_iface = "",
|
||||||
|
flow = nil, ---@type Monitor|nil
|
||||||
|
flow_iface = "",
|
||||||
|
unit_displays = {}, ---@type Monitor[]
|
||||||
|
unit_ifaces = {} ---@type string[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- initialize the display peripheral backplane
|
||||||
|
---@param config crd_config
|
||||||
|
---@return boolean success, string error_msg
|
||||||
|
function backplane.init_displays(config)
|
||||||
|
local displays = _bp.displays
|
||||||
|
|
||||||
|
local w, h, _
|
||||||
|
|
||||||
|
log.info("BKPLN: DISPLAY INIT")
|
||||||
|
|
||||||
|
-- monitor configuration verification
|
||||||
|
|
||||||
|
local mon_cfv = util.new_validator()
|
||||||
|
|
||||||
|
mon_cfv.assert_type_str(config.MainDisplay)
|
||||||
|
if not config.DisableFlowView then mon_cfv.assert_type_str(config.FlowDisplay) end
|
||||||
|
|
||||||
|
mon_cfv.assert_eq(#config.UnitDisplays, config.UnitCount)
|
||||||
|
for i = 1, #config.UnitDisplays do
|
||||||
|
mon_cfv.assert_type_str(config.UnitDisplays[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
if not mon_cfv.valid() then
|
||||||
|
return false, "Monitor configuration invalid."
|
||||||
|
end
|
||||||
|
|
||||||
|
-- setup and check display peripherals
|
||||||
|
|
||||||
|
-- main display
|
||||||
|
|
||||||
|
local disp, iface = ppm.get_periph(config.MainDisplay), config.MainDisplay
|
||||||
|
|
||||||
|
displays.main = disp
|
||||||
|
displays.main_iface = iface
|
||||||
|
|
||||||
|
log.info("BKPLN: DISPLAY LINK_" .. util.trinary(disp, "UP", "DOWN") .. " MAIN/" .. iface)
|
||||||
|
|
||||||
|
if not disp then
|
||||||
|
return false, "Main monitor is not connected."
|
||||||
|
end
|
||||||
|
|
||||||
|
disp.setTextScale(0.5)
|
||||||
|
w, _ = ppm.monitor_block_size(disp.getSize())
|
||||||
|
if w ~= 8 then
|
||||||
|
log.info("BKPLN: DISPLAY MAIN/" .. iface .. " BAD RESOLUTION")
|
||||||
|
return false, util.c("Main monitor width is incorrect (was ", w, ", must be 8).")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- flow display
|
||||||
|
|
||||||
|
if not config.DisableFlowView then
|
||||||
|
disp, iface = ppm.get_periph(config.FlowDisplay), config.FlowDisplay
|
||||||
|
|
||||||
|
displays.flow = disp
|
||||||
|
displays.flow_iface = iface
|
||||||
|
|
||||||
|
log.info("BKPLN: DISPLAY LINK_" .. util.trinary(disp, "UP", "DOWN") .. " FLOW/" .. iface)
|
||||||
|
|
||||||
|
if not disp then
|
||||||
|
return false, "Flow monitor is not connected."
|
||||||
|
end
|
||||||
|
|
||||||
|
disp.setTextScale(0.5)
|
||||||
|
w, _ = ppm.monitor_block_size(disp.getSize())
|
||||||
|
if w ~= 8 then
|
||||||
|
log.info("BKPLN: DISPLAY FLOW/" .. iface .. " BAD RESOLUTION")
|
||||||
|
return false, util.c("Flow monitor width is incorrect (was ", w, ", must be 8).")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- unit display(s)
|
||||||
|
|
||||||
|
for i = 1, config.UnitCount do
|
||||||
|
disp, iface = ppm.get_periph(config.UnitDisplays[i]), config.UnitDisplays[i]
|
||||||
|
|
||||||
|
displays.unit_displays[i] = disp
|
||||||
|
displays.unit_ifaces[i] = iface
|
||||||
|
|
||||||
|
log.info("BKPLN: DISPLAY LINK_" .. util.trinary(disp, "UP", "DOWN") .. " UNIT_" .. i .. "/" .. iface)
|
||||||
|
|
||||||
|
if not disp then
|
||||||
|
return false, "Unit " .. i .. " monitor is not connected."
|
||||||
|
end
|
||||||
|
|
||||||
|
disp.setTextScale(0.5)
|
||||||
|
w, h = ppm.monitor_block_size(disp.getSize())
|
||||||
|
if w ~= 4 or h ~= 4 then
|
||||||
|
log.info("BKPLN: DISPLAY UNIT_" .. i .. "/" .. iface .. " BAD RESOLUTION")
|
||||||
|
return false, util.c("Unit ", i, " monitor size is incorrect (was ", w, " by ", h,", must be 4 by 4).")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
log.info("BKPLN: DISPLAY INIT OK")
|
||||||
|
|
||||||
|
return true, ""
|
||||||
|
end
|
||||||
|
|
||||||
|
-- initialize the system peripheral backplane
|
||||||
|
---@param config crd_config
|
||||||
|
---@param __shared_memory crd_shared_memory
|
||||||
|
---@return boolean success
|
||||||
|
function backplane.init(config, __shared_memory)
|
||||||
|
_bp.smem = __shared_memory
|
||||||
|
_bp.wlan_pref = config.PreferWireless
|
||||||
|
_bp.lan_iface = config.WiredModem
|
||||||
|
|
||||||
|
-- Modem Init
|
||||||
|
|
||||||
|
-- init wired NIC
|
||||||
|
if type(config.WiredModem) == "string" then
|
||||||
|
local modem = ppm.get_modem(_bp.lan_iface)
|
||||||
|
local wd_nic = network.nic(modem)
|
||||||
|
|
||||||
|
log.info("BKPLN: WIRED PHY_" .. util.trinary(modem, "UP ", "DOWN ") .. _bp.lan_iface)
|
||||||
|
log_comms("wired comms modem " .. util.trinary(modem, "connected", "not found"))
|
||||||
|
|
||||||
|
-- set this as active for now
|
||||||
|
_bp.act_nic = wd_nic
|
||||||
|
_bp.wd_nic = wd_nic
|
||||||
|
|
||||||
|
iocontrol.fp_has_wd_modem(modem ~= nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- init wireless NIC(s)
|
||||||
|
if config.WirelessModem then
|
||||||
|
local modem, iface = ppm.get_wireless_modem()
|
||||||
|
local wl_nic = network.nic(modem)
|
||||||
|
|
||||||
|
log.info("BKPLN: WIRELESS PHY_" .. util.trinary(modem, "UP ", "DOWN ") .. iface)
|
||||||
|
log_comms("wireless comms modem " .. util.trinary(modem, "connected", "not found"))
|
||||||
|
|
||||||
|
-- set this as active if connected or if both modems are disconnected and this is preferred
|
||||||
|
if (modem and _bp.wlan_pref) or not (_bp.act_nic and _bp.act_nic.is_connected()) then
|
||||||
|
_bp.act_nic = wl_nic
|
||||||
|
end
|
||||||
|
|
||||||
|
_bp.wl_nic = wl_nic
|
||||||
|
|
||||||
|
iocontrol.fp_has_wl_modem(modem ~= nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- at least one comms modem is required
|
||||||
|
if not ((_bp.wd_nic and _bp.wd_nic.is_connected()) or (_bp.wl_nic and _bp.wl_nic.is_connected())) then
|
||||||
|
log_comms("no comms modem found")
|
||||||
|
println("startup> no comms modem found")
|
||||||
|
log.warning("BKPLN: no comms modem on startup")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Speaker Init
|
||||||
|
|
||||||
|
_bp.speaker = ppm.get_device("speaker")
|
||||||
|
|
||||||
|
if not _bp.speaker then
|
||||||
|
log_boot("annunciator alarm speaker not found")
|
||||||
|
|
||||||
|
println("startup> speaker not found")
|
||||||
|
log.fatal("BKPLN: no annunciator alarm speaker found")
|
||||||
|
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
log.info("BKPLN: SPEAKER LINK_UP " .. ppm.get_iface(_bp.speaker))
|
||||||
|
log_boot("annunciator alarm speaker connected")
|
||||||
|
|
||||||
|
local sounder_start = util.time_ms()
|
||||||
|
sounder.init(_bp.speaker, config.SpeakerVolume)
|
||||||
|
|
||||||
|
log_boot("tone generation took " .. (util.time_ms() - sounder_start) .. "ms")
|
||||||
|
log_sys("annunciator alarm configured")
|
||||||
|
|
||||||
|
iocontrol.fp_has_speaker(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- get the active NIC
|
||||||
|
---@return nic
|
||||||
|
function backplane.active_nic() return _bp.act_nic end
|
||||||
|
|
||||||
|
function backplane.displays() return _bp.displays end
|
||||||
|
|
||||||
|
return backplane
|
||||||
@@ -29,11 +29,9 @@ local config = {}
|
|||||||
|
|
||||||
coordinator.config = config
|
coordinator.config = config
|
||||||
|
|
||||||
-- load the coordinator configuration<br>
|
-- load the coordinator configuration
|
||||||
-- status of 0 is OK, 1 is bad config, 2 is bad monitor config
|
|
||||||
---@return 0|1|2 status, nil|monitors_struct|string monitors (or error message)
|
|
||||||
function coordinator.load_config()
|
function coordinator.load_config()
|
||||||
if not settings.load("/coordinator.settings") then return 1 end
|
if not settings.load("/coordinator.settings") then return false end
|
||||||
|
|
||||||
config.UnitCount = settings.get("UnitCount")
|
config.UnitCount = settings.get("UnitCount")
|
||||||
config.SpeakerVolume = settings.get("SpeakerVolume")
|
config.SpeakerVolume = settings.get("SpeakerVolume")
|
||||||
@@ -121,85 +119,7 @@ function coordinator.load_config()
|
|||||||
cfv.assert_type_int(config.ColorMode)
|
cfv.assert_type_int(config.ColorMode)
|
||||||
cfv.assert_range(config.ColorMode, 1, themes.COLOR_MODE.NUM_MODES)
|
cfv.assert_range(config.ColorMode, 1, themes.COLOR_MODE.NUM_MODES)
|
||||||
|
|
||||||
-- Monitor Setup
|
return cfv.valid()
|
||||||
|
|
||||||
---@class monitors_struct
|
|
||||||
local monitors = {
|
|
||||||
main = nil, ---@type Monitor|nil
|
|
||||||
main_name = "",
|
|
||||||
flow = nil, ---@type Monitor|nil
|
|
||||||
flow_name = "",
|
|
||||||
unit_displays = {}, ---@type Monitor[]
|
|
||||||
unit_name_map = {} ---@type string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
local mon_cfv = util.new_validator()
|
|
||||||
|
|
||||||
-- get all interface names
|
|
||||||
local names = {}
|
|
||||||
for iface, _ in pairs(ppm.get_monitor_list()) do table.insert(names, iface) end
|
|
||||||
|
|
||||||
local function setup_monitors()
|
|
||||||
mon_cfv.assert_type_str(config.MainDisplay)
|
|
||||||
if not config.DisableFlowView then mon_cfv.assert_type_str(config.FlowDisplay) end
|
|
||||||
mon_cfv.assert_eq(#config.UnitDisplays, config.UnitCount)
|
|
||||||
|
|
||||||
if mon_cfv.valid() then
|
|
||||||
local w, h, _
|
|
||||||
|
|
||||||
if not util.table_contains(names, config.MainDisplay) then
|
|
||||||
return 2, "Main monitor is not connected."
|
|
||||||
end
|
|
||||||
|
|
||||||
monitors.main = ppm.get_periph(config.MainDisplay)
|
|
||||||
monitors.main_name = config.MainDisplay
|
|
||||||
|
|
||||||
monitors.main.setTextScale(0.5)
|
|
||||||
w, _ = ppm.monitor_block_size(monitors.main.getSize())
|
|
||||||
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
|
|
||||||
return 2, "Flow monitor is not connected."
|
|
||||||
end
|
|
||||||
|
|
||||||
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, util.c("Flow monitor width is incorrect (was ", w, ", must be 8).")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = 1, config.UnitCount do
|
|
||||||
local display = config.UnitDisplays[i]
|
|
||||||
if type(display) ~= "string" or not util.table_contains(names, display) then
|
|
||||||
return 2, "Unit " .. i .. " monitor is not connected."
|
|
||||||
end
|
|
||||||
|
|
||||||
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, 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
|
|
||||||
|
|
||||||
if cfv.valid() then
|
|
||||||
local ok, result, message = pcall(setup_monitors)
|
|
||||||
assert(ok, util.c("fatal error while trying to verify monitors: ", result))
|
|
||||||
if result == 2 then return 2, message end
|
|
||||||
else return 1 end
|
|
||||||
|
|
||||||
return 0, monitors
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- dmesg print wrapper
|
-- dmesg print wrapper
|
||||||
|
|||||||
@@ -290,9 +290,13 @@ end
|
|||||||
-- toggle heartbeat indicator
|
-- toggle heartbeat indicator
|
||||||
function iocontrol.heartbeat() io.fp.ps.toggle("heartbeat") end
|
function iocontrol.heartbeat() io.fp.ps.toggle("heartbeat") end
|
||||||
|
|
||||||
|
-- report presence of the wired modem
|
||||||
|
---@param has_modem boolean
|
||||||
|
function iocontrol.fp_has_wd_modem(has_modem) io.fp.ps.publish("has_wd_modem", has_modem) end
|
||||||
|
|
||||||
-- report presence of the wireless modem
|
-- report presence of the wireless modem
|
||||||
---@param has_modem boolean
|
---@param has_modem boolean
|
||||||
function iocontrol.fp_has_modem(has_modem) io.fp.ps.publish("has_modem", has_modem) end
|
function iocontrol.fp_has_wl_modem(has_modem) io.fp.ps.publish("has_wl_modem", has_modem) end
|
||||||
|
|
||||||
-- report presence of the speaker
|
-- report presence of the speaker
|
||||||
---@param has_speaker boolean
|
---@param has_speaker boolean
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ local renderer = {}
|
|||||||
-- render engine
|
-- render engine
|
||||||
local engine = {
|
local engine = {
|
||||||
color_mode = 1, ---@type COLOR_MODE
|
color_mode = 1, ---@type COLOR_MODE
|
||||||
monitors = nil, ---@type monitors_struct|nil
|
monitors = nil, ---@type crd_displays|nil
|
||||||
dmesg_window = nil, ---@type Window|nil
|
dmesg_window = nil, ---@type Window|nil
|
||||||
ui_ready = false,
|
ui_ready = false,
|
||||||
fp_ready = false,
|
fp_ready = false,
|
||||||
@@ -83,7 +83,7 @@ function renderer.configure(config)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- link to the monitor peripherals
|
-- link to the monitor peripherals
|
||||||
---@param monitors monitors_struct
|
---@param monitors crd_displays
|
||||||
function renderer.set_displays(monitors)
|
function renderer.set_displays(monitors)
|
||||||
engine.monitors = monitors
|
engine.monitors = monitors
|
||||||
|
|
||||||
@@ -336,18 +336,18 @@ function renderer.handle_reconnect(name, device)
|
|||||||
-- note: handle_resize is a more adaptive way of re-initializing a connected monitor
|
-- note: handle_resize is a more adaptive way of re-initializing a connected monitor
|
||||||
-- since it can handle a monitor being reconnected that isn't the right size
|
-- since it can handle a monitor being reconnected that isn't the right size
|
||||||
|
|
||||||
if engine.monitors.main_name == name then
|
if engine.monitors.main_iface == name then
|
||||||
is_used = true
|
is_used = true
|
||||||
engine.monitors.main = device
|
engine.monitors.main = device
|
||||||
|
|
||||||
renderer.handle_resize(name)
|
renderer.handle_resize(name)
|
||||||
elseif engine.monitors.flow_name == name then
|
elseif engine.monitors.flow_iface == name then
|
||||||
is_used = true
|
is_used = true
|
||||||
engine.monitors.flow = device
|
engine.monitors.flow = device
|
||||||
|
|
||||||
renderer.handle_resize(name)
|
renderer.handle_resize(name)
|
||||||
else
|
else
|
||||||
for idx, monitor in ipairs(engine.monitors.unit_name_map) do
|
for idx, monitor in ipairs(engine.monitors.unit_ifaces) do
|
||||||
if monitor == name then
|
if monitor == name then
|
||||||
is_used = true
|
is_used = true
|
||||||
engine.monitors.unit_displays[idx] = device
|
engine.monitors.unit_displays[idx] = device
|
||||||
@@ -372,7 +372,7 @@ function renderer.handle_resize(name)
|
|||||||
|
|
||||||
if not engine.monitors then return false, false end
|
if not engine.monitors then return false, false end
|
||||||
|
|
||||||
if engine.monitors.main_name == name and engine.monitors.main then
|
if engine.monitors.main_iface == name and engine.monitors.main then
|
||||||
local device = engine.monitors.main ---@type Monitor
|
local device = engine.monitors.main ---@type Monitor
|
||||||
|
|
||||||
-- this is necessary if the bottom left block was broken and on reconnect
|
-- this is necessary if the bottom left block was broken and on reconnect
|
||||||
@@ -415,7 +415,7 @@ function renderer.handle_resize(name)
|
|||||||
is_ok = false
|
is_ok = false
|
||||||
end
|
end
|
||||||
else engine.dmesg_window.redraw() end
|
else engine.dmesg_window.redraw() end
|
||||||
elseif engine.monitors.flow_name == name and engine.monitors.flow then
|
elseif engine.monitors.flow_iface == name and engine.monitors.flow then
|
||||||
local device = engine.monitors.flow ---@type Monitor
|
local device = engine.monitors.flow ---@type Monitor
|
||||||
|
|
||||||
-- this is necessary if the bottom left block was broken and on reconnect
|
-- this is necessary if the bottom left block was broken and on reconnect
|
||||||
@@ -452,7 +452,7 @@ function renderer.handle_resize(name)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
for idx, monitor in ipairs(engine.monitors.unit_name_map) do
|
for idx, monitor in ipairs(engine.monitors.unit_ifaces) do
|
||||||
local device = engine.monitors.unit_displays[idx]
|
local device = engine.monitors.unit_displays[idx]
|
||||||
|
|
||||||
if monitor == name and device then
|
if monitor == name and device then
|
||||||
@@ -505,12 +505,12 @@ function renderer.handle_mouse(event)
|
|||||||
if engine.fp_ready and event.monitor == "terminal" then
|
if engine.fp_ready and event.monitor == "terminal" then
|
||||||
engine.ui.front_panel.handle_mouse(event)
|
engine.ui.front_panel.handle_mouse(event)
|
||||||
elseif engine.ui_ready then
|
elseif engine.ui_ready then
|
||||||
if event.monitor == engine.monitors.main_name then
|
if event.monitor == engine.monitors.main_iface then
|
||||||
if engine.ui.main_display then engine.ui.main_display.handle_mouse(event) end
|
if engine.ui.main_display then engine.ui.main_display.handle_mouse(event) end
|
||||||
elseif event.monitor == engine.monitors.flow_name then
|
elseif event.monitor == engine.monitors.flow_iface then
|
||||||
if engine.ui.flow_display then engine.ui.flow_display.handle_mouse(event) end
|
if engine.ui.flow_display then engine.ui.flow_display.handle_mouse(event) end
|
||||||
else
|
else
|
||||||
for id, monitor in ipairs(engine.monitors.unit_name_map) do
|
for id, monitor in ipairs(engine.monitors.unit_ifaces) do
|
||||||
local display = engine.ui.unit_displays[id]
|
local display = engine.ui.unit_displays[id]
|
||||||
if event.monitor == monitor and display then
|
if event.monitor == monitor and display then
|
||||||
if display then display.handle_mouse(event) end
|
if display then display.handle_mouse(event) end
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ local network = require("scada-common.network")
|
|||||||
local ppm = require("scada-common.ppm")
|
local ppm = require("scada-common.ppm")
|
||||||
local util = require("scada-common.util")
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
|
local backplane = require("coordinator.backplane")
|
||||||
local configure = require("coordinator.configure")
|
local configure = require("coordinator.configure")
|
||||||
local coordinator = require("coordinator.coordinator")
|
local coordinator = require("coordinator.coordinator")
|
||||||
local iocontrol = require("coordinator.iocontrol")
|
local iocontrol = require("coordinator.iocontrol")
|
||||||
@@ -36,45 +37,13 @@ local log_crypto = coordinator.log_crypto
|
|||||||
-- get configuration
|
-- get configuration
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
-- mount connected devices (required for monitor setup)
|
-- first pass configuration check before validating monitors
|
||||||
ppm.mount_all()
|
if not coordinator.load_config() then
|
||||||
|
|
||||||
local wait_on_load = true
|
|
||||||
local loaded, monitors = coordinator.load_config()
|
|
||||||
|
|
||||||
-- if the computer just started, its chunk may have just loaded (...or the user rebooted)
|
|
||||||
-- if monitor config failed, maybe an adjacent chunk containing all or part of a monitor has not loaded yet, so keep trying
|
|
||||||
while wait_on_load and loaded == 2 and os.clock() < CHUNK_LOAD_DELAY_S do
|
|
||||||
term.clear()
|
|
||||||
term.setCursorPos(1, 1)
|
|
||||||
println("There was a monitor configuration problem at boot.\n")
|
|
||||||
println("Startup will keep trying every 2s in case of chunk load delays.\n")
|
|
||||||
println(util.sprintf("The configurator will be started in %ds if all attempts fail.\n", math.max(0, CHUNK_LOAD_DELAY_S - os.clock())))
|
|
||||||
println("(click to skip to the configurator)")
|
|
||||||
|
|
||||||
local timer_id = util.start_timer(2)
|
|
||||||
|
|
||||||
while true do
|
|
||||||
local event, param1 = util.pull_event()
|
|
||||||
if event == "timer" and param1 == timer_id then
|
|
||||||
-- remount and re-attempt
|
|
||||||
ppm.mount_all()
|
|
||||||
loaded, monitors = coordinator.load_config()
|
|
||||||
break
|
|
||||||
elseif event == "mouse_click" or event == "terminate" then
|
|
||||||
wait_on_load = false
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if loaded ~= 0 then
|
|
||||||
-- try to reconfigure (user action)
|
-- try to reconfigure (user action)
|
||||||
local success, error = configure.configure(loaded, monitors)
|
local success, error = configure.configure(1)
|
||||||
if success then
|
if success then
|
||||||
loaded, monitors = coordinator.load_config()
|
if not coordinator.load_config() then
|
||||||
if loaded ~= 0 then
|
println("failed to load a valid configuration, please reconfigure")
|
||||||
println(util.trinary(loaded == 2, "monitor configuration invalid", "failed to load a valid configuration") .. ", please reconfigure")
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -83,9 +52,6 @@ if loaded ~= 0 then
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- passed checks, good now
|
|
||||||
---@cast monitors monitors_struct
|
|
||||||
|
|
||||||
local config = coordinator.config
|
local config = coordinator.config
|
||||||
|
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
@@ -102,6 +68,64 @@ println(">> SCADA Coordinator " .. COORDINATOR_VERSION .. " <<")
|
|||||||
crash.set_env("coordinator", COORDINATOR_VERSION)
|
crash.set_env("coordinator", COORDINATOR_VERSION)
|
||||||
crash.dbg_log_env()
|
crash.dbg_log_env()
|
||||||
|
|
||||||
|
----------------------------------------
|
||||||
|
-- display init
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
-- mount connected devices (required for monitor setup)
|
||||||
|
ppm.mount_all()
|
||||||
|
|
||||||
|
local wait_on_load = true
|
||||||
|
|
||||||
|
local disp_ok, disp_err = backplane.init_displays(config)
|
||||||
|
|
||||||
|
-- if the computer just started, its chunk may have just loaded (...or the user rebooted)
|
||||||
|
-- if monitor config failed, maybe an adjacent chunk containing all or part of a monitor has not loaded yet, so keep trying
|
||||||
|
while wait_on_load and (not disp_ok) and os.clock() < CHUNK_LOAD_DELAY_S do
|
||||||
|
term.clear()
|
||||||
|
term.setCursorPos(1, 1)
|
||||||
|
println("There was a monitor configuration problem at boot.\n")
|
||||||
|
println("Startup will keep trying every 2s in case of chunk load delays.\n")
|
||||||
|
println(util.sprintf("The configurator will be started in %ds if all attempts fail.\n", math.max(0, CHUNK_LOAD_DELAY_S - os.clock())))
|
||||||
|
println("(click to skip to the configurator)")
|
||||||
|
|
||||||
|
local timer_id = util.start_timer(2)
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local event, param1 = util.pull_event()
|
||||||
|
if event == "timer" and param1 == timer_id then
|
||||||
|
-- remount and re-attempt
|
||||||
|
ppm.mount_all()
|
||||||
|
disp_ok, disp_err = backplane.init_displays(config)
|
||||||
|
break
|
||||||
|
elseif event == "mouse_click" or event == "terminate" then
|
||||||
|
wait_on_load = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not disp_ok then
|
||||||
|
-- try to reconfigure (user action)
|
||||||
|
local success, error = configure.configure(2, disp_err)
|
||||||
|
if success then
|
||||||
|
if not coordinator.load_config() then
|
||||||
|
println("failed to load a valid configuration, please reconfigure")
|
||||||
|
return
|
||||||
|
else
|
||||||
|
disp_ok, disp_err = backplane.init_displays(config)
|
||||||
|
|
||||||
|
if not disp_ok then
|
||||||
|
println("monitor configuration invalid, please reconfigure")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
println("configuration error: " .. error)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
-- main application
|
-- main application
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
@@ -111,15 +135,12 @@ local function main()
|
|||||||
-- system startup
|
-- system startup
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
-- log mounts now since mounting was done before logging was ready
|
|
||||||
ppm.log_mounts()
|
|
||||||
|
|
||||||
-- report versions/init fp PSIL
|
-- report versions/init fp PSIL
|
||||||
iocontrol.init_fp(COORDINATOR_VERSION, comms.version)
|
iocontrol.init_fp(COORDINATOR_VERSION, comms.version)
|
||||||
|
|
||||||
-- init renderer
|
-- init renderer
|
||||||
renderer.configure(config)
|
renderer.configure(config)
|
||||||
renderer.set_displays(monitors)
|
renderer.set_displays(backplane.displays())
|
||||||
renderer.init_displays()
|
renderer.init_displays()
|
||||||
renderer.init_dmesg()
|
renderer.init_dmesg()
|
||||||
|
|
||||||
@@ -130,6 +151,12 @@ local function main()
|
|||||||
log_sys("system start on " .. os.date("%c"))
|
log_sys("system start on " .. os.date("%c"))
|
||||||
log_boot("starting " .. COORDINATOR_VERSION)
|
log_boot("starting " .. COORDINATOR_VERSION)
|
||||||
|
|
||||||
|
-- message authentication init
|
||||||
|
if type(config.AuthKey) == "string" and string.len(config.AuthKey) > 0 then
|
||||||
|
local init_time = network.init_mac(config.AuthKey)
|
||||||
|
log_crypto("HMAC init took " .. init_time .. "ms")
|
||||||
|
end
|
||||||
|
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
-- memory allocation
|
-- memory allocation
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
@@ -149,15 +176,9 @@ local function main()
|
|||||||
shutdown = false
|
shutdown = false
|
||||||
},
|
},
|
||||||
|
|
||||||
-- core coordinator devices
|
|
||||||
crd_dev = {
|
|
||||||
modem = ppm.get_wireless_modem(),
|
|
||||||
speaker = ppm.get_device("speaker") ---@type Speaker|nil
|
|
||||||
},
|
|
||||||
|
|
||||||
-- system objects
|
-- system objects
|
||||||
|
---@class crd_sys
|
||||||
crd_sys = {
|
crd_sys = {
|
||||||
nic = nil, ---@type nic
|
|
||||||
coord_comms = nil, ---@type coord_comms
|
coord_comms = nil, ---@type coord_comms
|
||||||
conn_watchdog = nil ---@type watchdog
|
conn_watchdog = nil ---@type watchdog
|
||||||
},
|
},
|
||||||
@@ -168,65 +189,17 @@ local function main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
local smem_dev = __shared_memory.crd_dev
|
|
||||||
local smem_sys = __shared_memory.crd_sys
|
local smem_sys = __shared_memory.crd_sys
|
||||||
|
|
||||||
local crd_state = __shared_memory.crd_state
|
local crd_state = __shared_memory.crd_state
|
||||||
|
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
-- setup alarm sounder subsystem
|
-- init system
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
if smem_dev.speaker == nil then
|
-- modem and speaker initialization
|
||||||
log_boot("annunciator alarm speaker not found")
|
if not backplane.init(config, __shared_memory) then return end
|
||||||
println("startup> speaker not found")
|
|
||||||
log.fatal("no annunciator alarm speaker found")
|
|
||||||
return
|
|
||||||
else
|
|
||||||
local sounder_start = util.time_ms()
|
|
||||||
log_boot("annunciator alarm speaker connected")
|
|
||||||
sounder.init(smem_dev.speaker, config.SpeakerVolume)
|
|
||||||
log_boot("tone generation took " .. (util.time_ms() - sounder_start) .. "ms")
|
|
||||||
log_sys("annunciator alarm configured")
|
|
||||||
iocontrol.fp_has_speaker(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
----------------------------------------
|
|
||||||
-- setup communications
|
|
||||||
----------------------------------------
|
|
||||||
|
|
||||||
-- message authentication init
|
|
||||||
if type(config.AuthKey) == "string" and string.len(config.AuthKey) > 0 then
|
|
||||||
local init_time = network.init_mac(config.AuthKey)
|
|
||||||
log_crypto("HMAC init took " .. init_time .. "ms")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get the communications modem
|
|
||||||
if smem_dev.modem == nil then
|
|
||||||
log_comms("wireless modem not found")
|
|
||||||
println("startup> wireless modem not found")
|
|
||||||
log.fatal("no wireless modem on startup")
|
|
||||||
return
|
|
||||||
else
|
|
||||||
log_comms("wireless modem connected")
|
|
||||||
iocontrol.fp_has_modem(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- create connection watchdog
|
|
||||||
smem_sys.conn_watchdog = util.new_watchdog(config.SVR_Timeout)
|
|
||||||
smem_sys.conn_watchdog.cancel()
|
|
||||||
log.debug("startup> conn watchdog created")
|
|
||||||
|
|
||||||
-- create network interface then setup comms
|
|
||||||
smem_sys.nic = network.nic(smem_dev.modem)
|
|
||||||
smem_sys.coord_comms = coordinator.comms(COORDINATOR_VERSION, smem_sys.nic, smem_sys.conn_watchdog)
|
|
||||||
log.debug("startup> comms init")
|
|
||||||
log_comms("comms initialized")
|
|
||||||
|
|
||||||
----------------------------------------
|
|
||||||
-- start front panel
|
-- start front panel
|
||||||
----------------------------------------
|
|
||||||
|
|
||||||
log_render("starting front panel UI...")
|
log_render("starting front panel UI...")
|
||||||
|
|
||||||
local fp_message
|
local fp_message
|
||||||
@@ -238,6 +211,16 @@ local function main()
|
|||||||
return
|
return
|
||||||
else log_render("front panel ready") end
|
else log_render("front panel ready") end
|
||||||
|
|
||||||
|
-- create connection watchdog
|
||||||
|
smem_sys.conn_watchdog = util.new_watchdog(config.SVR_Timeout)
|
||||||
|
smem_sys.conn_watchdog.cancel()
|
||||||
|
log.debug("startup> conn watchdog created")
|
||||||
|
|
||||||
|
-- setup comms
|
||||||
|
smem_sys.coord_comms = coordinator.comms(COORDINATOR_VERSION, backplane.active_nic(), smem_sys.conn_watchdog)
|
||||||
|
log.debug("startup> comms init")
|
||||||
|
log_comms("comms initialized")
|
||||||
|
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
-- start system
|
-- start system
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user