-- -- 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