#182 WIP work on PLC PSIL
This commit is contained in:
@@ -10,15 +10,15 @@ local core = require("graphics.core")
|
|||||||
|
|
||||||
local DisplayBox = require("graphics.elements.displaybox")
|
local DisplayBox = require("graphics.elements.displaybox")
|
||||||
local Div = require("graphics.elements.div")
|
local Div = require("graphics.elements.div")
|
||||||
local Rectangle = require("graphics.elements.rectangle")
|
local Rectangle = require("graphics.elements.rectangle")
|
||||||
local TextBox = require("graphics.elements.textbox")
|
local TextBox = require("graphics.elements.textbox")
|
||||||
local ColorMap = require("graphics.elements.colormap")
|
local ColorMap = require("graphics.elements.colormap")
|
||||||
|
|
||||||
local PushButton = require("graphics.elements.controls.push_button")
|
local PushButton = require("graphics.elements.controls.push_button")
|
||||||
local SwitchButton = require("graphics.elements.controls.switch_button")
|
|
||||||
|
|
||||||
local DataIndicator = require("graphics.elements.indicators.data")
|
local DataIndicator = require("graphics.elements.indicators.data")
|
||||||
local LED = require("graphics.elements.indicators.led")
|
local LED = require("graphics.elements.indicators.led")
|
||||||
|
local LEDPair = require("graphics.elements.indicators.ledpair")
|
||||||
|
|
||||||
local TEXT_ALIGN = core.graphics.TEXT_ALIGN
|
local TEXT_ALIGN = core.graphics.TEXT_ALIGN
|
||||||
|
|
||||||
@@ -27,31 +27,50 @@ local border = core.graphics.border
|
|||||||
|
|
||||||
-- create new main view
|
-- create new main view
|
||||||
---@param monitor table main viewscreen
|
---@param monitor table main viewscreen
|
||||||
local function init(monitor)
|
---@param fp_ps psil front panel PSIL
|
||||||
|
local function init(monitor, fp_ps)
|
||||||
local panel = DisplayBox{window=monitor,fg_bg=style.root}
|
local panel = DisplayBox{window=monitor,fg_bg=style.root}
|
||||||
|
|
||||||
-- window header message
|
local _ = TextBox{parent=panel,y=1,text="REACTOR PLC",alignment=TEXT_ALIGN.CENTER,height=1,fg_bg=style.header}
|
||||||
local header = TextBox{parent=panel,y=1,text="REACTOR PLC",alignment=TEXT_ALIGN.CENTER,height=1,fg_bg=style.header}
|
|
||||||
|
|
||||||
local system = Div{parent=panel,width=14,height=18,x=2,y=3}
|
local system = Div{parent=panel,width=14,height=18,x=2,y=3}
|
||||||
|
|
||||||
local init_ok = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)}
|
local init_ok = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)}
|
||||||
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=cpair(colors.green,colors.green_off)}
|
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=cpair(colors.green,colors.green_off)}
|
||||||
system.line_break()
|
system.line_break()
|
||||||
local reactor = LED{parent=system,label="REACTOR",colors=cpair(colors.green,colors.red)}
|
|
||||||
local modem = LED{parent=system,label="MODEM",colors=cpair(colors.green,colors.gray)}
|
fp_ps.subscribe("init_ok", init_ok.update)
|
||||||
local network = LED{parent=system,label="NETWORK",colors=cpair(colors.green,colors.gray)}
|
fp_ps.subscribe("heartbeat", heartbeat.update)
|
||||||
|
|
||||||
|
local reactor = LEDPair{parent=system,label="REACTOR",off=colors.red,c1=colors.yellow,c2=colors.green}
|
||||||
|
local modem = LED{parent=system,label="MODEM",colors=cpair(colors.green,colors.green_off)}
|
||||||
|
local network = LEDPair{parent=system,label="NETWORK",off=colors.gray,c1=colors.yellow,c2=colors.green}
|
||||||
system.line_break()
|
system.line_break()
|
||||||
local _ = LED{parent=system,label="RT MAIN",colors=cpair(colors.green,colors.gray)}
|
|
||||||
local _ = LED{parent=system,label="RT RPS",colors=cpair(colors.green,colors.gray)}
|
fp_ps.subscribe("reactor_dev_state", reactor.update)
|
||||||
local _ = LED{parent=system,label="RT COMMS TX",colors=cpair(colors.green,colors.gray)}
|
fp_ps.subscribe("has_modem", modem.update)
|
||||||
local _ = LED{parent=system,label="RT COMMS RX",colors=cpair(colors.green,colors.gray)}
|
fp_ps.subscribe("link_state", network.update)
|
||||||
local _ = LED{parent=system,label="RT SPCTL",colors=cpair(colors.green,colors.gray)}
|
|
||||||
|
local rt_main = LED{parent=system,label="RT MAIN",colors=cpair(colors.green,colors.green_off)}
|
||||||
|
local rt_rps = LED{parent=system,label="RT RPS",colors=cpair(colors.green,colors.green_off)}
|
||||||
|
local rt_cmtx = LED{parent=system,label="RT COMMS TX",colors=cpair(colors.green,colors.green_off)}
|
||||||
|
local rt_cmrx = LED{parent=system,label="RT COMMS RX",colors=cpair(colors.green,colors.green_off)}
|
||||||
|
local rt_sctl = LED{parent=system,label="RT SPCTL",colors=cpair(colors.green,colors.green_off)}
|
||||||
system.line_break()
|
system.line_break()
|
||||||
|
|
||||||
|
fp_ps.subscribe("routine__main", rt_main.update)
|
||||||
|
fp_ps.subscribe("routine__rps", rt_rps.update)
|
||||||
|
fp_ps.subscribe("routine__comms_tx", rt_cmtx.update)
|
||||||
|
fp_ps.subscribe("routine__comms_rx", rt_cmrx.update)
|
||||||
|
fp_ps.subscribe("routine__spctl", rt_sctl.update)
|
||||||
|
|
||||||
local active = LED{parent=system,label="RCT ACTIVE",colors=cpair(colors.green,colors.green_off)}
|
local active = LED{parent=system,label="RCT ACTIVE",colors=cpair(colors.green,colors.green_off)}
|
||||||
local scram = LED{parent=system,label="RPS TRIP",colors=cpair(colors.red,colors.red_off)}
|
local scram = LED{parent=system,label="RPS TRIP",colors=cpair(colors.red,colors.red_off)}
|
||||||
system.line_break()
|
system.line_break()
|
||||||
|
|
||||||
|
fp_ps.subscribe("reactor_active", active.update)
|
||||||
|
fp_ps.subscribe("rps_scram", scram.update)
|
||||||
|
|
||||||
local about = Rectangle{parent=panel,width=16,height=4,x=18,y=15,border=border(1,colors.white),thin=true,fg_bg=cpair(colors.black,colors.white)}
|
local about = Rectangle{parent=panel,width=16,height=4,x=18,y=15,border=border(1,colors.white),thin=true,fg_bg=cpair(colors.black,colors.white)}
|
||||||
local _ = TextBox{parent=about,text="FW: v1.0.0",alignment=TEXT_ALIGN.LEFT,height=1}
|
local _ = TextBox{parent=about,text="FW: v1.0.0",alignment=TEXT_ALIGN.LEFT,height=1}
|
||||||
local _ = TextBox{parent=about,text="NT: v1.4.0",alignment=TEXT_ALIGN.LEFT,height=1}
|
local _ = TextBox{parent=about,text="NT: v1.4.0",alignment=TEXT_ALIGN.LEFT,height=1}
|
||||||
@@ -59,25 +78,35 @@ local function init(monitor)
|
|||||||
-- local _ = TextBox{parent=about,text="SVTT: 10ms",alignment=TEXT_ALIGN.LEFT,height=1}
|
-- local _ = TextBox{parent=about,text="SVTT: 10ms",alignment=TEXT_ALIGN.LEFT,height=1}
|
||||||
|
|
||||||
local rps = Rectangle{parent=panel,width=16,height=16,x=36,y=3,border=border(1,colors.lightGray),thin=true,fg_bg=cpair(colors.black,colors.lightGray)}
|
local rps = Rectangle{parent=panel,width=16,height=16,x=36,y=3,border=border(1,colors.lightGray),thin=true,fg_bg=cpair(colors.black,colors.lightGray)}
|
||||||
local _ = LED{parent=rps,label="MANUAL",colors=cpair(colors.red,colors.red_off)}
|
local rps_man = LED{parent=rps,label="MANUAL",colors=cpair(colors.red,colors.red_off)}
|
||||||
local _ = LED{parent=rps,label="AUTOMATIC",colors=cpair(colors.red,colors.red_off)}
|
local rps_auto = LED{parent=rps,label="AUTOMATIC",colors=cpair(colors.red,colors.red_off)}
|
||||||
local _ = LED{parent=rps,label="TIMEOUT",colors=cpair(colors.red,colors.red_off)}
|
local rps_tmo = LED{parent=rps,label="TIMEOUT",colors=cpair(colors.red,colors.red_off)}
|
||||||
local _ = LED{parent=rps,label="PLC FAULT",colors=cpair(colors.red,colors.red_off)}
|
local rps_flt = LED{parent=rps,label="PLC FAULT",colors=cpair(colors.red,colors.red_off)}
|
||||||
local _ = LED{parent=rps,label="RCT FAULT",colors=cpair(colors.red,colors.red_off)}
|
local rps_fail = LED{parent=rps,label="RCT FAULT",colors=cpair(colors.red,colors.red_off)}
|
||||||
rps.line_break()
|
rps.line_break()
|
||||||
local _ = LED{parent=rps,label="HI DAMAGE",colors=cpair(colors.red,colors.red_off)}
|
local rps_dmg = LED{parent=rps,label="HI DAMAGE",colors=cpair(colors.red,colors.red_off)}
|
||||||
local _ = LED{parent=rps,label="HI TEMP",colors=cpair(colors.red,colors.red_off)}
|
local rps_tmp = LED{parent=rps,label="HI TEMP",colors=cpair(colors.red,colors.red_off)}
|
||||||
rps.line_break()
|
rps.line_break()
|
||||||
local _ = LED{parent=rps,label="LO FUEL",colors=cpair(colors.red,colors.red_off)}
|
local rps_nof = LED{parent=rps,label="LO FUEL",colors=cpair(colors.red,colors.red_off)}
|
||||||
local _ = LED{parent=rps,label="HI WASTE",colors=cpair(colors.red,colors.red_off)}
|
local rps_wst = LED{parent=rps,label="HI WASTE",colors=cpair(colors.red,colors.red_off)}
|
||||||
rps.line_break()
|
rps.line_break()
|
||||||
local _ = LED{parent=rps,label="LO CCOOLANT",colors=cpair(colors.red,colors.red_off)}
|
local rps_ccl = LED{parent=rps,label="LO CCOOLANT",colors=cpair(colors.red,colors.red_off)}
|
||||||
local _ = LED{parent=rps,label="HI HCOOLANT",colors=cpair(colors.red,colors.red_off)}
|
local rps_hcl = LED{parent=rps,label="HI HCOOLANT",colors=cpair(colors.red,colors.red_off)}
|
||||||
|
|
||||||
|
fp_ps.subscribe("rps_manual", rps_man.update)
|
||||||
|
fp_ps.subscribe("rps_automatic", rps_auto.update)
|
||||||
|
fp_ps.subscribe("rps_timeout", rps_tmo.update)
|
||||||
|
fp_ps.subscribe("rps_fault", rps_flt.update)
|
||||||
|
fp_ps.subscribe("rps_sysfail", rps_fail.update)
|
||||||
|
fp_ps.subscribe("rps_damage", rps_dmg.update)
|
||||||
|
fp_ps.subscribe("rps_high_temp", rps_tmp.update)
|
||||||
|
fp_ps.subscribe("rps_no_fuel", rps_nof.update)
|
||||||
|
fp_ps.subscribe("rps_high_waste", rps_wst.update)
|
||||||
|
fp_ps.subscribe("rps_low_ccool", rps_ccl.update)
|
||||||
|
fp_ps.subscribe("rps_high_hcool", rps_hcl.update)
|
||||||
|
|
||||||
ColorMap{parent=panel,x=1,y=19}
|
ColorMap{parent=panel,x=1,y=19}
|
||||||
-- facility.ps.subscribe("sv_ping", ping.update)
|
-- facility.ps.subscribe("sv_ping", ping.update)
|
||||||
-- facility.ps.subscribe("date_time", datetime.set_value)
|
|
||||||
|
|
||||||
return panel
|
return panel
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ local ui = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
-- start the UI
|
-- start the UI
|
||||||
function renderer.start_ui()
|
---@param fp_ps psil front panel PSIL
|
||||||
|
function renderer.start_ui(fp_ps)
|
||||||
if ui.view == nil then
|
if ui.view == nil then
|
||||||
term.setTextColor(colors.white)
|
term.setTextColor(colors.white)
|
||||||
term.setBackgroundColor(colors.black)
|
term.setBackgroundColor(colors.black)
|
||||||
@@ -25,7 +26,7 @@ function renderer.start_ui()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- init front panel view
|
-- init front panel view
|
||||||
ui.view = panel_view(term.current())
|
ui.view = panel_view(term.current(), fp_ps)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ local function main()
|
|||||||
---@class plc_state
|
---@class plc_state
|
||||||
plc_state = {
|
plc_state = {
|
||||||
init_ok = true,
|
init_ok = true,
|
||||||
|
fp_ok = false,
|
||||||
shutdown = false,
|
shutdown = false,
|
||||||
degraded = false,
|
degraded = false,
|
||||||
reactor_formed = true,
|
reactor_formed = true,
|
||||||
@@ -150,18 +151,33 @@ local function main()
|
|||||||
plc_state.no_modem = true
|
plc_state.no_modem = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- print a log message to the terminal as long as the UI isn't running
|
||||||
|
local function _print_no_fp(message)
|
||||||
|
if not plc_state.fp_ok then println(message) end
|
||||||
|
end
|
||||||
|
|
||||||
-- PLC init<br>
|
-- PLC init<br>
|
||||||
--- EVENT_CONSUMER: this function consumes events
|
--- EVENT_CONSUMER: this function consumes events
|
||||||
local function init()
|
local function init()
|
||||||
|
-- just booting up, no fission allowed (neutrons stay put thanks)
|
||||||
|
if (not plc_state.no_reactor) and plc_state.reactor_formed and smem_dev.reactor.getStatus() then
|
||||||
|
smem_dev.reactor.scram()
|
||||||
|
end
|
||||||
|
|
||||||
-- front panel time!
|
-- front panel time!
|
||||||
renderer.start_ui()
|
if not renderer.ui_ready() then
|
||||||
|
local message = nil
|
||||||
|
plc_state.fp_ok, message = pcall(renderer.start_ui, __shared_memory.fp_ps)
|
||||||
|
if not plc_state.fp_ok then
|
||||||
|
renderer.close_ui()
|
||||||
|
println_ts(util.c("UI error: ", message))
|
||||||
|
println("init> running without front panel")
|
||||||
|
log.error(util.c("GUI crashed with error ", message))
|
||||||
|
log.info("init> running in headless mode without front panel")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if plc_state.init_ok then
|
if plc_state.init_ok then
|
||||||
-- just booting up, no fission allowed (neutrons stay put thanks)
|
|
||||||
if plc_state.reactor_formed and smem_dev.reactor.getStatus() then
|
|
||||||
smem_dev.reactor.scram()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- init reactor protection system
|
-- init reactor protection system
|
||||||
smem_sys.rps = plc.rps_init(smem_dev.reactor, plc_state.reactor_formed)
|
smem_sys.rps = plc.rps_init(smem_dev.reactor, plc_state.reactor_formed)
|
||||||
log.debug("init> rps init")
|
log.debug("init> rps init")
|
||||||
@@ -176,18 +192,23 @@ local function main()
|
|||||||
config.TRUSTED_RANGE, smem_dev.reactor, smem_sys.rps, smem_sys.conn_watchdog)
|
config.TRUSTED_RANGE, smem_dev.reactor, smem_sys.rps, smem_sys.conn_watchdog)
|
||||||
log.debug("init> comms init")
|
log.debug("init> comms init")
|
||||||
else
|
else
|
||||||
println("init> starting in offline mode")
|
_print_no_fp("init> starting in offline mode")
|
||||||
log.info("init> running without networking")
|
log.info("init> running without networking")
|
||||||
end
|
end
|
||||||
|
|
||||||
util.push_event("clock_start")
|
util.push_event("clock_start")
|
||||||
|
|
||||||
println("init> completed")
|
_print_no_fp("init> completed")
|
||||||
log.info("init> startup completed")
|
log.info("init> startup completed")
|
||||||
else
|
else
|
||||||
-- println("init> system in degraded state, awaiting devices...")
|
_print_no_fp("init> system in degraded state, awaiting devices...")
|
||||||
log.warning("init> started in a degraded state, awaiting peripheral connections...")
|
log.warning("init> started in a degraded state, awaiting peripheral connections...")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
__shared_memory.fp_ps.publish("reactor_dev_state", util.trinary(plc_state.no_reactor, 1, util.trinary(plc_state.reactor_formed, 3, 2)))
|
||||||
|
__shared_memory.fp_ps.publish("has_modem", not plc_state.no_modem)
|
||||||
|
__shared_memory.fp_ps.publish("degraded", plc_state.degraded)
|
||||||
|
__shared_memory.fp_ps.publish("init_ok", plc_state.init_ok)
|
||||||
end
|
end
|
||||||
|
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ function threads.thread__main(smem, init)
|
|||||||
smem.q.mq_comms_tx.push_command(MQ__COMM_CMD.SEND_STATUS)
|
smem.q.mq_comms_tx.push_command(MQ__COMM_CMD.SEND_STATUS)
|
||||||
else
|
else
|
||||||
if ticks_to_update == 0 then
|
if ticks_to_update == 0 then
|
||||||
|
smem.fp_ps.toggle("heartbeat")
|
||||||
plc_comms.send_link_req()
|
plc_comms.send_link_req()
|
||||||
ticks_to_update = LINK_TICKS
|
ticks_to_update = LINK_TICKS
|
||||||
else
|
else
|
||||||
@@ -79,6 +80,14 @@ function threads.thread__main(smem, init)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
-- use ticks to update just for heartbeat if not networked
|
||||||
|
if ticks_to_update == 0 then
|
||||||
|
smem.fp_ps.toggle("heartbeat")
|
||||||
|
ticks_to_update = LINK_TICKS
|
||||||
|
else
|
||||||
|
ticks_to_update = ticks_to_update - 1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- are we now formed after waiting to be formed?
|
-- are we now formed after waiting to be formed?
|
||||||
@@ -133,6 +142,12 @@ function threads.thread__main(smem, init)
|
|||||||
-- reactor no longer formed
|
-- reactor no longer formed
|
||||||
plc_state.reactor_formed = false
|
plc_state.reactor_formed = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- update indicators
|
||||||
|
smem.fp_ps.publish("init_ok", plc_state.init_ok)
|
||||||
|
smem.fp_ps.publish("reactor_dev_state", not plc_state.no_reactor)
|
||||||
|
smem.fp_ps.publish("has_modem", not plc_state.no_modem)
|
||||||
|
smem.fp_ps.publish("degraded", plc_state.degraded)
|
||||||
elseif event == "modem_message" and networked and plc_state.init_ok and not plc_state.no_modem then
|
elseif event == "modem_message" and networked and plc_state.init_ok and not plc_state.no_modem then
|
||||||
-- got a packet
|
-- got a packet
|
||||||
local packet = plc_comms.parse_packet(param1, param2, param3, param4, param5)
|
local packet = plc_comms.parse_packet(param1, param2, param3, param4, param5)
|
||||||
@@ -174,6 +189,12 @@ function threads.thread__main(smem, init)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- update indicators
|
||||||
|
smem.fp_ps.publish("has_reactor", not plc_state.no_reactor)
|
||||||
|
smem.fp_ps.publish("has_modem", not plc_state.no_modem)
|
||||||
|
smem.fp_ps.publish("degraded", plc_state.degraded)
|
||||||
|
smem.fp_ps.publish("init_ok", plc_state.init_ok)
|
||||||
elseif event == "peripheral" then
|
elseif event == "peripheral" then
|
||||||
-- peripheral connect
|
-- peripheral connect
|
||||||
local type, device = ppm.mount(param1)
|
local type, device = ppm.mount(param1)
|
||||||
@@ -237,6 +258,12 @@ function threads.thread__main(smem, init)
|
|||||||
plc_state.init_ok = true
|
plc_state.init_ok = true
|
||||||
init()
|
init()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- update indicators
|
||||||
|
smem.fp_ps.publish("has_reactor", not plc_state.no_reactor)
|
||||||
|
smem.fp_ps.publish("has_modem", not plc_state.no_modem)
|
||||||
|
smem.fp_ps.publish("degraded", plc_state.degraded)
|
||||||
|
smem.fp_ps.publish("init_ok", plc_state.init_ok)
|
||||||
elseif event == "clock_start" then
|
elseif event == "clock_start" then
|
||||||
-- start loop clock
|
-- start loop clock
|
||||||
loop_clock.start()
|
loop_clock.start()
|
||||||
|
|||||||
@@ -51,6 +51,19 @@ function psil.create()
|
|||||||
self.ic[key].value = value
|
self.ic[key].value = value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- publish a toggled boolean value to a given key, passing it to all subscribers if it has changed<br>
|
||||||
|
-- this is intended to be used to toggle boolean indicators such as heartbeats without extra state variables
|
||||||
|
---@param key string data key
|
||||||
|
function public.toggle(key)
|
||||||
|
if self.ic[key] == nil then alloc(key) end
|
||||||
|
|
||||||
|
self.ic[key].value = self.ic[key].value == false
|
||||||
|
|
||||||
|
for i = 1, #self.ic[key].subscribers do
|
||||||
|
self.ic[key].subscribers[i].notify(self.ic[key].value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return public
|
return public
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user