Merge branch 'devel' into 580-wired-comms-networking

This commit is contained in:
Mikayla Fischler
2025-10-26 17:08:12 -04:00
9 changed files with 451 additions and 473 deletions

View File

@@ -87,7 +87,6 @@ local function main()
-- PLC system state flags
---@class plc_state
plc_state = {
init_ok = true,
fp_ok = false,
shutdown = false,
degraded = true,
@@ -97,21 +96,24 @@ local function main()
},
-- control setpoints
---@class setpoints
---@class plc_setpoints
setpoints = {
burn_rate_en = false,
burn_rate = 0.0
},
-- core PLC devices
---@class plc_dev
plc_dev = {
reactor = ppm.get_fission_reactor(),
---@diagnostic disable-next-line: assign-type-mismatch
reactor = ppm.get_fission_reactor(), ---@type table
modem = nil, ---@type Modem|nil
modem_wired = type(config.WiredModem) == "string",
modem_iface = config.WiredModem,
modem = nil
modem_iface = config.WiredModem
},
-- system objects
---@class plc_sys
plc_sys = {
rps = nil, ---@type rps
nic = nil, ---@type nic
@@ -143,14 +145,20 @@ local function main()
-- we need a reactor, can at least do some things even if it isn't formed though
if plc_state.no_reactor then
println("init> fission reactor not found")
log.warning("init> no reactor on startup")
println("startup> fission reactor not found")
log.warning("startup> no reactor on startup")
plc_state.init_ok = false
plc_state.degraded = true
plc_state.reactor_formed = false
-- mount a virtual peripheral to init the RPS with
local _, dev = ppm.mount_virtual()
smem_dev.reactor = dev
log.info("startup> mounted virtual device as reactor")
elseif not smem_dev.reactor.isFormed() then
println("init> fission reactor is not formed")
log.warning("init> reactor logic adapter present, but reactor is not formed")
println("startup> fission reactor is not formed")
log.warning("startup> reactor logic adapter present, but reactor is not formed")
plc_state.degraded = true
plc_state.reactor_formed = false
@@ -158,89 +166,74 @@ local function main()
-- comms modem is required if networked
if __shared_memory.networked and plc_state.no_modem then
println("init> comms modem not found")
log.warning("init> no comms modem on startup")
println("startup> comms modem not found")
log.warning("startup> no comms modem on startup")
-- scram reactor if present and enabled
if (smem_dev.reactor ~= nil) and plc_state.reactor_formed and smem_dev.reactor.getStatus() then
smem_dev.reactor.scram()
end
plc_state.init_ok = false
plc_state.degraded = true
end
-- print a log message to the terminal as long as the UI isn't running
local function _println_no_fp(message) if not plc_state.fp_ok then println(message) end end
-- PLC init<br>
--- EVENT_CONSUMER: this function consumes events
local function init()
-- scram on boot if networked, otherwise leave the reactor be
if __shared_memory.networked and (not plc_state.no_reactor) and plc_state.reactor_formed and smem_dev.reactor.getStatus() then
smem_dev.reactor.scram()
end
-- setup front panel
if not renderer.ui_ready() then
local message
plc_state.fp_ok, message = renderer.try_start_ui(config.FrontPanelTheme, config.ColorMode)
-- ...or not
if not plc_state.fp_ok then
println_ts(util.c("UI error: ", message))
println("init> running without front panel")
log.error(util.c("front panel GUI render failed with error ", message))
log.info("init> running in headless mode without front panel")
end
end
if plc_state.init_ok then
-- init reactor protection system
smem_sys.rps = plc.rps_init(smem_dev.reactor, plc_state.reactor_formed)
log.debug("init> rps init")
if __shared_memory.networked then
-- comms watchdog
smem_sys.conn_watchdog = util.new_watchdog(config.ConnTimeout)
log.debug("init> conn watchdog started")
-- create network interface then setup comms
smem_sys.nic = network.nic(smem_dev.modem)
smem_sys.plc_comms = plc.comms(R_PLC_VERSION, smem_sys.nic, smem_dev.reactor, smem_sys.rps, smem_sys.conn_watchdog)
log.debug("init> comms init")
else
_println_no_fp("init> starting in offline mode")
log.info("init> running without networking")
end
-- notify user of emergency coolant configuration status
if config.EmerCoolEnable then
println("init> emergency coolant control ready")
log.info("init> running with emergency coolant control available")
end
util.push_event("clock_start")
_println_no_fp("init> completed")
log.info("init> startup completed")
else
_println_no_fp("init> system in degraded state, awaiting devices...")
log.warning("init> started in a degraded state, awaiting peripheral connections...")
end
databus.tx_hw_status(plc_state)
-- scram on boot if networked, otherwise leave the reactor be
if __shared_memory.networked and (not plc_state.no_reactor) and plc_state.reactor_formed and smem_dev.reactor.getStatus() then
log.debug("startup> power-on SCRAM")
smem_dev.reactor.scram()
end
-- setup front panel
local message
plc_state.fp_ok, message = renderer.try_start_ui(config.FrontPanelTheme, config.ColorMode)
-- ...or not
if not plc_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
-- print a log message to the terminal as long as the UI isn't running
local function _println_no_fp(msg) if not plc_state.fp_ok then println(msg) end end
----------------------------------------
-- start system
-- initialize PLC
----------------------------------------
-- initialize PLC
init()
-- init reactor protection system
smem_sys.rps = plc.rps_init(smem_dev.reactor, util.trinary(plc_state.no_reactor, nil, plc_state.reactor_formed))
log.debug("startup> rps init")
-- notify user of emergency coolant configuration status
if config.EmerCoolEnable then
_println_no_fp("startup> emergency coolant control ready")
log.info("startup> emergency coolant control available")
end
-- conditionally init comms
if __shared_memory.networked then
-- comms watchdog
smem_sys.conn_watchdog = util.new_watchdog(config.ConnTimeout)
log.debug("startup> conn watchdog started")
-- create network interface then setup comms
smem_sys.nic = network.nic(smem_dev.modem)
smem_sys.plc_comms = plc.comms(R_PLC_VERSION, smem_sys.nic, smem_dev.reactor, smem_sys.rps, smem_sys.conn_watchdog)
log.debug("startup> comms init")
else
_println_no_fp("startup> starting in non-networked mode")
log.info("startup> starting without networking")
end
databus.tx_hw_status(plc_state)
_println_no_fp("startup> completed")
log.info("startup> completed")
-- init threads
local main_thread = threads.thread__main(__shared_memory, init)
local main_thread = threads.thread__main(__shared_memory)
local rps_thread = threads.thread__rps(__shared_memory)
if __shared_memory.networked then
@@ -254,14 +247,12 @@ local function main()
-- run threads
parallel.waitForAll(main_thread.p_exec, rps_thread.p_exec, comms_thread_tx.p_exec, comms_thread_rx.p_exec, sp_ctrl_thread.p_exec)
if plc_state.init_ok then
-- send status one last time after RPS shutdown
smem_sys.plc_comms.send_status(plc_state.no_reactor, plc_state.reactor_formed)
smem_sys.plc_comms.send_rps_status()
-- send status one last time after RPS shutdown
smem_sys.plc_comms.send_status(plc_state.no_reactor, plc_state.reactor_formed)
smem_sys.plc_comms.send_rps_status()
-- close connection
smem_sys.plc_comms.close()
end
-- close connection
smem_sys.plc_comms.close()
else
-- run threads, excluding comms
parallel.waitForAll(main_thread.p_exec, rps_thread.p_exec)