207 lines
6.0 KiB
Lua
207 lines
6.0 KiB
Lua
--
|
|
-- RTU Gateway: Remote Terminal Unit Gateway
|
|
--
|
|
|
|
require("/initenv").init_env()
|
|
|
|
local audio = require("scada-common.audio")
|
|
local comms = require("scada-common.comms")
|
|
local crash = require("scada-common.crash")
|
|
local log = require("scada-common.log")
|
|
local mqueue = require("scada-common.mqueue")
|
|
local network = require("scada-common.network")
|
|
local ppm = require("scada-common.ppm")
|
|
local util = require("scada-common.util")
|
|
|
|
local configure = require("rtu.configure")
|
|
local databus = require("rtu.databus")
|
|
local renderer = require("rtu.renderer")
|
|
local rtu = require("rtu.rtu")
|
|
local threads = require("rtu.threads")
|
|
local uinit = require("rtu.uinit")
|
|
|
|
local RTU_VERSION = "v1.12.3"
|
|
|
|
local println = util.println
|
|
local println_ts = util.println_ts
|
|
|
|
----------------------------------------
|
|
-- get configuration
|
|
----------------------------------------
|
|
|
|
if not rtu.load_config() then
|
|
-- try to reconfigure (user action)
|
|
local success, error = configure.configure(true)
|
|
if success then
|
|
if not rtu.load_config() then
|
|
println("failed to load a valid configuration, please reconfigure")
|
|
return
|
|
end
|
|
else
|
|
println("configuration error: " .. error)
|
|
return
|
|
end
|
|
end
|
|
|
|
local config = rtu.config
|
|
|
|
----------------------------------------
|
|
-- log init
|
|
----------------------------------------
|
|
|
|
log.init(config.LogPath, config.LogMode, config.LogDebug)
|
|
|
|
log.info("========================================")
|
|
log.info("BOOTING rtu.startup " .. RTU_VERSION)
|
|
log.info("========================================")
|
|
println(">> RTU GATEWAY " .. RTU_VERSION .. " <<")
|
|
|
|
crash.set_env("rtu", RTU_VERSION)
|
|
crash.dbg_log_env()
|
|
|
|
----------------------------------------
|
|
-- main application
|
|
----------------------------------------
|
|
|
|
local function main()
|
|
----------------------------------------
|
|
-- startup
|
|
----------------------------------------
|
|
|
|
-- record firmware versions and ID
|
|
databus.tx_versions(RTU_VERSION, comms.version)
|
|
|
|
-- mount connected devices
|
|
ppm.mount_all()
|
|
|
|
-- message authentication init
|
|
if type(config.AuthKey) == "string" and string.len(config.AuthKey) > 0 then
|
|
network.init_mac(config.AuthKey)
|
|
end
|
|
|
|
-- generate alarm tones
|
|
audio.generate_tones()
|
|
|
|
---@class rtu_shared_memory
|
|
local __shared_memory = {
|
|
-- RTU system state flags
|
|
---@class rtu_state
|
|
rtu_state = {
|
|
fp_ok = false,
|
|
linked = false,
|
|
shutdown = false
|
|
},
|
|
|
|
-- RTU gateway devices (not RTU units)
|
|
rtu_dev = {
|
|
modem_wired = type(config.WiredModem) == "string",
|
|
modem_iface = config.WiredModem,
|
|
modem = nil,
|
|
sounders = {} ---@type rtu_speaker_sounder[]
|
|
},
|
|
|
|
-- system objects
|
|
rtu_sys = {
|
|
nic = nil, ---@type nic
|
|
rtu_comms = nil, ---@type rtu_comms
|
|
conn_watchdog = nil, ---@type watchdog
|
|
units = {} ---@type rtu_registry_entry[]
|
|
},
|
|
|
|
-- message queues
|
|
q = {
|
|
mq_comms = mqueue.new()
|
|
}
|
|
}
|
|
|
|
local smem_sys = __shared_memory.rtu_sys
|
|
local smem_dev = __shared_memory.rtu_dev
|
|
local rtu_state = __shared_memory.rtu_state
|
|
local units = __shared_memory.rtu_sys.units
|
|
|
|
-- get the configured modem
|
|
if smem_dev.modem_wired then
|
|
smem_dev.modem = ppm.get_wired_modem(smem_dev.modem_iface)
|
|
else smem_dev.modem = ppm.get_wireless_modem() end
|
|
|
|
----------------------------------------
|
|
-- start system
|
|
----------------------------------------
|
|
|
|
log.debug("boot> running uinit()")
|
|
|
|
if uinit(config, __shared_memory) then
|
|
-- check comms modem
|
|
if smem_dev.modem == nil then
|
|
println("startup> comms modem not found")
|
|
log.fatal("no comms modem on startup")
|
|
return
|
|
end
|
|
|
|
databus.tx_hw_modem(true)
|
|
|
|
-- find and setup all speakers
|
|
local speakers = ppm.get_all_devices("speaker")
|
|
for _, s in pairs(speakers) do
|
|
local sounder = rtu.init_sounder(s)
|
|
|
|
table.insert(smem_dev.sounders, sounder)
|
|
|
|
log.debug(util.c("startup> added speaker, attached as ", sounder.name))
|
|
end
|
|
|
|
databus.tx_hw_spkr_count(#smem_dev.sounders)
|
|
|
|
-- start UI
|
|
local message
|
|
rtu_state.fp_ok, message = renderer.try_start_ui(units, config.FrontPanelTheme, config.ColorMode)
|
|
|
|
if not rtu_state.fp_ok then
|
|
println_ts(util.c("UI error: ", message))
|
|
println("startup> running without front panel")
|
|
log.error(util.c("front panel GUI render failed with error ", message))
|
|
log.info("startup> running in headless mode without front panel")
|
|
end
|
|
|
|
-- start connection watchdog
|
|
smem_sys.conn_watchdog = util.new_watchdog(config.ConnTimeout)
|
|
log.debug("startup> conn watchdog started")
|
|
|
|
-- setup comms
|
|
smem_sys.nic = network.nic(smem_dev.modem)
|
|
smem_sys.rtu_comms = rtu.comms(RTU_VERSION, smem_sys.nic, smem_sys.conn_watchdog)
|
|
log.debug("startup> comms init")
|
|
|
|
-- init threads
|
|
local main_thread = threads.thread__main(__shared_memory)
|
|
local comms_thread = threads.thread__comms(__shared_memory)
|
|
|
|
-- assemble thread list
|
|
local _threads = { main_thread.p_exec, comms_thread.p_exec }
|
|
for i = 1, #units do
|
|
if units[i].thread ~= nil then
|
|
table.insert(_threads, units[i].thread.p_exec)
|
|
end
|
|
end
|
|
|
|
log.info("startup> completed")
|
|
|
|
-- run threads
|
|
parallel.waitForAll(table.unpack(_threads))
|
|
else
|
|
println("system initialization failed, exiting...")
|
|
end
|
|
|
|
renderer.close_ui()
|
|
|
|
println_ts("exited")
|
|
log.info("exited")
|
|
end
|
|
|
|
if not xpcall(main, crash.handler) then
|
|
pcall(renderer.close_ui)
|
|
crash.exit()
|
|
else
|
|
log.close()
|
|
end
|