cc-mek-scada/pocket/startup.lua
2024-06-29 12:18:55 -04:00

201 lines
5.6 KiB
Lua

--
-- SCADA System Access on a Pocket Computer
--
---@diagnostic disable-next-line: undefined-global
local _is_pocket_env = pocket or periphemu -- luacheck: ignore pocket
require("/initenv").init_env()
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("pocket.configure")
local iocontrol = require("pocket.iocontrol")
local pocket = require("pocket.pocket")
local renderer = require("pocket.renderer")
local threads = require("pocket.threads")
local POCKET_VERSION = "v0.11.0-alpha"
local println = util.println
local println_ts = util.println_ts
-- check environment (allows Pocket or CraftOS-PC)
if not _is_pocket_env then
println("You can only use this application on a pocket computer.")
return
end
----------------------------------------
-- get configuration
----------------------------------------
if not pocket.load_config() then
-- try to reconfigure (user action)
local success, error = configure.configure(true)
if success then
if not pocket.load_config() then
println("failed to load a valid configuration, please reconfigure")
return
end
else
println("configuration error: " .. error)
return
end
end
local config = pocket.config
----------------------------------------
-- log init
----------------------------------------
log.init(config.LogPath, config.LogMode, config.LogDebug)
log.info("========================================")
log.info("BOOTING pocket.startup " .. POCKET_VERSION)
log.info("========================================")
crash.set_env("pocket", POCKET_VERSION)
crash.dbg_log_env()
----------------------------------------
-- main application
----------------------------------------
local function main()
----------------------------------------
-- system startup
----------------------------------------
-- mount connected devices
ppm.mount_all()
-- record version for GUI
iocontrol.get_db().version = POCKET_VERSION
----------------------------------------
-- memory allocation
----------------------------------------
-- shared memory across threads
---@class pkt_shared_memory
local __shared_memory = {
-- pocket system state flags
---@class pkt_state
pkt_state = {
ui_ok = false,
ui_error = nil,
shutdown = false
},
-- core pocket devices
pkt_dev = {
modem = ppm.get_wireless_modem()
},
-- system objects
pkt_sys = {
nic = nil, ---@type nic
pocket_comms = nil, ---@type pocket_comms
sv_wd = nil, ---@type watchdog
api_wd = nil, ---@type watchdog
nav = nil ---@type pocket_nav
},
-- message queues
q = {
mq_render = mqueue.new()
}
}
local smem_dev = __shared_memory.pkt_dev
local smem_sys = __shared_memory.pkt_sys
local pkt_state = __shared_memory.pkt_state
----------------------------------------
-- setup system
----------------------------------------
smem_sys.nav = pocket.init_nav(__shared_memory)
-- message authentication init
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)
-- get the communications modem
if smem_dev.modem == nil then
println("startup> wireless modem not found: please craft the pocket computer with a wireless modem")
log.fatal("startup> no wireless modem on startup")
return
end
-- create connection watchdogs
smem_sys.sv_wd = util.new_watchdog(config.ConnTimeout)
smem_sys.sv_wd.cancel()
smem_sys.api_wd = util.new_watchdog(config.ConnTimeout)
smem_sys.api_wd.cancel()
log.debug("startup> conn watchdogs created")
-- create network interface then setup comms
smem_sys.nic = network.nic(smem_dev.modem)
smem_sys.pocket_comms = pocket.comms(POCKET_VERSION, smem_sys.nic, smem_sys.sv_wd, smem_sys.api_wd, smem_sys.nav)
log.debug("startup> comms init")
-- init I/O control
iocontrol.init_core(smem_sys.pocket_comms, smem_sys.nav)
----------------------------------------
-- start the UI
----------------------------------------
local ui_message
pkt_state.ui_ok, ui_message = renderer.try_start_ui()
if not pkt_state.ui_ok then
println(util.c("UI error: ", ui_message))
log.error(util.c("startup> GUI render failed with error ", ui_message))
end
----------------------------------------
-- start system
----------------------------------------
if pkt_state.ui_ok then
-- init threads
local main_thread = threads.thread__main(__shared_memory)
local render_thread = threads.thread__render(__shared_memory)
log.info("startup> completed")
-- run threads
parallel.waitForAll(main_thread.p_exec, render_thread.p_exec)
renderer.close_ui()
if not pkt_state.ui_ok then
println(util.c("UI crashed with error: ", pkt_state.ui_error))
end
else
println_ts("UI creation failed")
end
println_ts("exited")
log.info("exited")
end
if not xpcall(main, crash.handler) then
pcall(renderer.close_ui)
crash.exit()
else
log.close()
end