mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#182 linked up PLC front panel indicators, cleaned up panel display and added flashing to RPS trip
This commit is contained in:
parent
9bc4f0f7a6
commit
4aad591d3a
@ -34,6 +34,7 @@ local element = {}
|
||||
---|icon_indicator_args
|
||||
---|indicator_led_args
|
||||
---|indicator_led_pair_args
|
||||
---|indicator_led_rgb_args
|
||||
---|indicator_light_args
|
||||
---|power_indicator_args
|
||||
---|rad_indicator_args
|
||||
|
@ -103,6 +103,7 @@ local function indicator_led_pair(args)
|
||||
|
||||
-- write label and initial indicator light
|
||||
e.on_update(1)
|
||||
e.window.setCursorPos(3, 1)
|
||||
e.window.write(args.label)
|
||||
|
||||
return e.get()
|
||||
|
57
graphics/elements/indicators/ledrgb.lua
Normal file
57
graphics/elements/indicators/ledrgb.lua
Normal file
@ -0,0 +1,57 @@
|
||||
-- Indicator RGB LED Graphics Element
|
||||
|
||||
local element = require("graphics.element")
|
||||
|
||||
---@class indicator_led_rgb_args
|
||||
---@field label string indicator label
|
||||
---@field colors table colors to use
|
||||
---@field min_label_width? integer label length if omitted
|
||||
---@field parent graphics_element
|
||||
---@field id? string element id
|
||||
---@field x? integer 1 if omitted
|
||||
---@field y? integer 1 if omitted
|
||||
---@field fg_bg? cpair foreground/background colors
|
||||
|
||||
-- new tri-state indicator light
|
||||
---@nodiscard
|
||||
---@param args indicator_led_rgb_args
|
||||
---@return graphics_element element, element_id id
|
||||
local function indicator_led_rgb(args)
|
||||
assert(type(args.label) == "string", "graphics.elements.indicators.ledrgb: label is a required field")
|
||||
assert(type(args.colors) == "table", "graphics.elements.indicators.ledrgb: colors is a required field")
|
||||
|
||||
-- single line
|
||||
args.height = 1
|
||||
|
||||
-- determine width
|
||||
args.width = math.max(args.min_label_width or 1, string.len(args.label)) + 2
|
||||
|
||||
-- create new graphics element base object
|
||||
local e = element.new(args)
|
||||
|
||||
-- init value for initial check in on_update
|
||||
e.value = 1
|
||||
|
||||
-- on state change
|
||||
---@param new_state integer indicator state
|
||||
function e.on_update(new_state)
|
||||
e.value = new_state
|
||||
e.window.setCursorPos(1, 1)
|
||||
if type(args.colors[new_state]) == "number" then
|
||||
e.window.blit("\x8c", colors.toBlit(args.colors[new_state]), e.fg_bg.blit_bkg)
|
||||
end
|
||||
end
|
||||
|
||||
-- set indicator state
|
||||
---@param val integer indicator state
|
||||
function e.set_value(val) e.on_update(val) end
|
||||
|
||||
-- write label and initial indicator light
|
||||
e.on_update(1)
|
||||
e.window.setCursorPos(3, 1)
|
||||
e.window.write(args.label)
|
||||
|
||||
return e.get()
|
||||
end
|
||||
|
||||
return indicator_led_rgb
|
84
reactor-plc/databus.lua
Normal file
84
reactor-plc/databus.lua
Normal file
@ -0,0 +1,84 @@
|
||||
--
|
||||
-- Data Bus - Central Communication Linking for PLC PSIL
|
||||
--
|
||||
|
||||
local psil = require("scada-common.psil")
|
||||
local util = require("scada-common.util")
|
||||
|
||||
local databus = {}
|
||||
|
||||
local ps = psil.create()
|
||||
|
||||
-- call to toggle heartbeat signal
|
||||
function databus.heartbeat()
|
||||
ps.toggle("heartbeat")
|
||||
end
|
||||
|
||||
-- transmit firmware versions across the bus
|
||||
---@param plc_v string PLC version
|
||||
---@param comms_v string comms version
|
||||
function databus.tx_versions(plc_v, comms_v)
|
||||
ps.publish("version", plc_v)
|
||||
ps.publish("comms_version", comms_v)
|
||||
end
|
||||
|
||||
-- transmit unit ID across the bus
|
||||
---@param id integer unit ID
|
||||
function databus.tx_id(id)
|
||||
ps.publish("unit_id", id)
|
||||
end
|
||||
|
||||
-- transmit hardware status across the bus
|
||||
---@param plc_state plc_state
|
||||
function databus.tx_hw_status(plc_state)
|
||||
ps.publish("reactor_dev_state", util.trinary(plc_state.no_reactor, 1, util.trinary(plc_state.reactor_formed, 3, 2)))
|
||||
ps.publish("has_modem", not plc_state.no_modem)
|
||||
ps.publish("degraded", plc_state.degraded)
|
||||
ps.publish("init_ok", plc_state.init_ok)
|
||||
end
|
||||
|
||||
-- transmit thread (routine) statuses
|
||||
---@param thread string thread name
|
||||
---@param ok boolean thread state
|
||||
function databus.tx_rt_status(thread, ok)
|
||||
ps.publish(util.c("routine__", thread), ok)
|
||||
end
|
||||
|
||||
-- transmit supervisor link state across the bus
|
||||
---@param state integer
|
||||
function databus.tx_link_state(state)
|
||||
ps.publish("link_state", state)
|
||||
end
|
||||
|
||||
-- transmit reactor enable state across the bus
|
||||
---@param active boolean reactor active
|
||||
function databus.tx_reactor_state(active)
|
||||
ps.publish("reactor_active", active)
|
||||
end
|
||||
|
||||
-- transmit RPS data across the bus
|
||||
---@param tripped boolean RPS tripped
|
||||
---@param status table RPS status
|
||||
function databus.tx_rps(tripped, status)
|
||||
ps.publish("rps_scram", tripped)
|
||||
ps.publish("rps_damage", status[1])
|
||||
ps.publish("rps_high_temp", status[2])
|
||||
ps.publish("rps_low_ccool", status[3])
|
||||
ps.publish("rps_high_waste", status[4])
|
||||
ps.publish("rps_high_hcool", status[5])
|
||||
ps.publish("rps_no_fuel", status[6])
|
||||
ps.publish("rps_fault", status[7])
|
||||
ps.publish("rps_timeout", status[8])
|
||||
ps.publish("rps_manual", status[9])
|
||||
ps.publish("rps_automatic", status[10])
|
||||
ps.publish("rps_sysfail", status[11])
|
||||
end
|
||||
|
||||
-- link a function to receive data from the bus
|
||||
---@param field string field name
|
||||
---@param func function function to link
|
||||
function databus.rx_field(field, func)
|
||||
ps.subscribe(field, func)
|
||||
end
|
||||
|
||||
return databus
|
@ -4,21 +4,21 @@
|
||||
|
||||
local util = require("scada-common.util")
|
||||
|
||||
local databus = require("reactor-plc.databus")
|
||||
|
||||
local style = require("reactor-plc.panel.style")
|
||||
|
||||
local core = require("graphics.core")
|
||||
local flasher = require("graphics.flasher")
|
||||
|
||||
local DisplayBox = require("graphics.elements.displaybox")
|
||||
local Div = require("graphics.elements.div")
|
||||
local Rectangle = require("graphics.elements.rectangle")
|
||||
local TextBox = require("graphics.elements.textbox")
|
||||
local ColorMap = require("graphics.elements.colormap")
|
||||
|
||||
local PushButton = require("graphics.elements.controls.push_button")
|
||||
|
||||
local DataIndicator = require("graphics.elements.indicators.data")
|
||||
local LED = require("graphics.elements.indicators.led")
|
||||
local LEDPair = require("graphics.elements.indicators.ledpair")
|
||||
local RGBLED = require("graphics.elements.indicators.ledrgb")
|
||||
|
||||
local TEXT_ALIGN = core.graphics.TEXT_ALIGN
|
||||
|
||||
@ -27,11 +27,11 @@ local border = core.graphics.border
|
||||
|
||||
-- create new main view
|
||||
---@param monitor table main viewscreen
|
||||
---@param fp_ps psil front panel PSIL
|
||||
local function init(monitor, fp_ps)
|
||||
local function init(monitor)
|
||||
local panel = DisplayBox{window=monitor,fg_bg=style.root}
|
||||
|
||||
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 - UNIT ?",alignment=TEXT_ALIGN.CENTER,height=1,fg_bg=style.header}
|
||||
databus.rx_field("unit_id", function (id) header.set_value(util.c("REACTOR PLC - UNIT ", id)) end)
|
||||
|
||||
local system = Div{parent=panel,width=14,height=18,x=2,y=3}
|
||||
|
||||
@ -39,17 +39,18 @@ local function init(monitor, fp_ps)
|
||||
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=cpair(colors.green,colors.green_off)}
|
||||
system.line_break()
|
||||
|
||||
fp_ps.subscribe("init_ok", init_ok.update)
|
||||
fp_ps.subscribe("heartbeat", heartbeat.update)
|
||||
databus.rx_field("init_ok", init_ok.update)
|
||||
databus.rx_field("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}
|
||||
local network = RGBLED{parent=system,label="NETWORK",colors={colors.green,colors.red,colors.orange,colors.yellow,colors.gray}}
|
||||
network.update(5)
|
||||
system.line_break()
|
||||
|
||||
fp_ps.subscribe("reactor_dev_state", reactor.update)
|
||||
fp_ps.subscribe("has_modem", modem.update)
|
||||
fp_ps.subscribe("link_state", network.update)
|
||||
databus.rx_field("reactor_dev_state", reactor.update)
|
||||
databus.rx_field("has_modem", modem.update)
|
||||
databus.rx_field("link_state", network.update)
|
||||
|
||||
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)}
|
||||
@ -58,24 +59,27 @@ local function init(monitor, fp_ps)
|
||||
local rt_sctl = LED{parent=system,label="RT SPCTL",colors=cpair(colors.green,colors.green_off)}
|
||||
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)
|
||||
databus.rx_field("routine__main", rt_main.update)
|
||||
databus.rx_field("routine__rps", rt_rps.update)
|
||||
databus.rx_field("routine__comms_tx", rt_cmtx.update)
|
||||
databus.rx_field("routine__comms_rx", rt_cmrx.update)
|
||||
databus.rx_field("routine__spctl", rt_sctl.update)
|
||||
|
||||
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 status = Div{parent=panel,width=16,height=4,x=18,y=3}
|
||||
|
||||
local active = LED{parent=status,label="RCT ACTIVE",colors=cpair(colors.green,colors.green_off)}
|
||||
local scram = LED{parent=status,label="RPS TRIP",colors=cpair(colors.red,colors.red_off),flash=true,period=flasher.PERIOD.BLINK_250_MS}
|
||||
system.line_break()
|
||||
|
||||
fp_ps.subscribe("reactor_active", active.update)
|
||||
fp_ps.subscribe("rps_scram", scram.update)
|
||||
databus.rx_field("reactor_active", active.update)
|
||||
databus.rx_field("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 _ = 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}
|
||||
-- about.line_break()
|
||||
-- local _ = TextBox{parent=about,text="SVTT: 10ms",alignment=TEXT_ALIGN.LEFT,height=1}
|
||||
local about = Rectangle{parent=panel,width=32,height=3,x=2,y=16,border=border(1,colors.ivory),thin=true,fg_bg=cpair(colors.black,colors.white)}
|
||||
local fw_v = TextBox{parent=about,x=2,y=1,text="FW: v00.00.00",alignment=TEXT_ALIGN.LEFT,height=1}
|
||||
local comms_v = TextBox{parent=about,x=17,y=1,text="NT: v00.00.00",alignment=TEXT_ALIGN.LEFT,height=1}
|
||||
|
||||
databus.rx_field("version", function (version) fw_v.set_value(util.c("FW: ", version)) end)
|
||||
databus.rx_field("comms_version", function (version) comms_v.set_value(util.c("NT: v", version)) end)
|
||||
|
||||
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_man = LED{parent=rps,label="MANUAL",colors=cpair(colors.red,colors.red_off)}
|
||||
@ -93,20 +97,17 @@ local function init(monitor, fp_ps)
|
||||
local rps_ccl = LED{parent=rps,label="LO CCOOLANT",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}
|
||||
-- facility.ps.subscribe("sv_ping", ping.update)
|
||||
databus.rx_field("rps_manual", rps_man.update)
|
||||
databus.rx_field("rps_automatic", rps_auto.update)
|
||||
databus.rx_field("rps_timeout", rps_tmo.update)
|
||||
databus.rx_field("rps_fault", rps_flt.update)
|
||||
databus.rx_field("rps_sysfail", rps_fail.update)
|
||||
databus.rx_field("rps_damage", rps_dmg.update)
|
||||
databus.rx_field("rps_high_temp", rps_tmp.update)
|
||||
databus.rx_field("rps_no_fuel", rps_nof.update)
|
||||
databus.rx_field("rps_high_waste", rps_wst.update)
|
||||
databus.rx_field("rps_low_ccool", rps_ccl.update)
|
||||
databus.rx_field("rps_high_hcool", rps_hcl.update)
|
||||
|
||||
return panel
|
||||
end
|
||||
|
@ -17,12 +17,11 @@ colors.green_off = colors.lime
|
||||
|
||||
style.root = cpair(colors.black, colors.ivory)
|
||||
style.header = cpair(colors.black, colors.lightGray)
|
||||
style.label = cpair(colors.gray, colors.lightGray)
|
||||
|
||||
style.colors = {
|
||||
{ c = colors.red, hex = 0xdf4949 }, -- RED ON
|
||||
{ c = colors.orange, hex = 0xffb659 },
|
||||
{ c = colors.yellow, hex = 0xe5e552 },
|
||||
{ c = colors.yellow, hex = 0xf9fb53 },
|
||||
{ c = colors.lime, hex = 0x16665a }, -- GREEN OFF
|
||||
{ c = colors.green, hex = 0x6be551 }, -- GREEN ON
|
||||
{ c = colors.cyan, hex = 0x34bac8 },
|
||||
|
@ -1,9 +1,10 @@
|
||||
local comms = require("scada-common.comms")
|
||||
local const = require("scada-common.constants")
|
||||
local log = require("scada-common.log")
|
||||
local ppm = require("scada-common.ppm")
|
||||
local types = require("scada-common.types")
|
||||
local util = require("scada-common.util")
|
||||
local comms = require("scada-common.comms")
|
||||
local const = require("scada-common.constants")
|
||||
local log = require("scada-common.log")
|
||||
local ppm = require("scada-common.ppm")
|
||||
local types = require("scada-common.types")
|
||||
local util = require("scada-common.util")
|
||||
local databus = require("reactor-plc.databus")
|
||||
|
||||
local plc = {}
|
||||
|
||||
@ -18,11 +19,6 @@ local AUTO_ACK = comms.PLC_AUTO_ACK
|
||||
|
||||
local RPS_LIMITS = const.RPS_LIMITS
|
||||
|
||||
local print = util.print
|
||||
local println = util.println
|
||||
local print_ts = util.print_ts
|
||||
local println_ts = util.println_ts
|
||||
|
||||
-- I sure hope the devs don't change this error message, not that it would have safety implications
|
||||
-- I wish they didn't change it to be like this
|
||||
local PCALL_SCRAM_MSG = "pcall: Scram requires the reactor to be active."
|
||||
@ -348,6 +344,9 @@ function plc.rps_init(reactor, is_formed)
|
||||
end
|
||||
end
|
||||
|
||||
-- report RPS status
|
||||
databus.tx_rps(self.tripped, self.state)
|
||||
|
||||
return self.tripped, status, first_trip
|
||||
end
|
||||
|
||||
@ -733,6 +732,11 @@ function plc.comms(id, version, modem, local_port, server_port, range, reactor,
|
||||
---@param plc_state plc_state PLC state
|
||||
---@param setpoints setpoints setpoint control table
|
||||
function public.handle_packet(packet, plc_state, setpoints)
|
||||
-- print a log message to the terminal as long as the UI isn't running
|
||||
local function println(message) if not plc_state.fp_ok then util.println(message) end end
|
||||
local function println_ts(message) if not plc_state.fp_ok then util.println_ts(message) end end
|
||||
|
||||
-- handle packets now that we have prints setup
|
||||
if packet.scada_frame.local_port() == local_port then
|
||||
-- check sequence number
|
||||
if self.r_seq_num == nil then
|
||||
@ -919,6 +923,9 @@ function plc.comms(id, version, modem, local_port, server_port, range, reactor,
|
||||
|
||||
-- clear this since this is for something that was unsolicited
|
||||
self.last_est_ack = ESTABLISH_ACK.ALLOW
|
||||
|
||||
-- report link state
|
||||
databus.tx_link_state(est_ack + 1)
|
||||
else
|
||||
log.debug("SCADA_MGMT establish packet length mismatch")
|
||||
end
|
||||
@ -982,6 +989,9 @@ function plc.comms(id, version, modem, local_port, server_port, range, reactor,
|
||||
|
||||
self.linked = est_ack == ESTABLISH_ACK.ALLOW
|
||||
self.last_est_ack = est_ack
|
||||
|
||||
-- report link state
|
||||
databus.tx_link_state(est_ack + 1)
|
||||
else
|
||||
log.debug("SCADA_MGMT establish packet length mismatch")
|
||||
end
|
||||
|
@ -5,6 +5,8 @@
|
||||
local style = require("reactor-plc.panel.style")
|
||||
local panel_view = require("reactor-plc.panel.front_panel")
|
||||
|
||||
local flasher = require("graphics.flasher")
|
||||
|
||||
local renderer = {}
|
||||
|
||||
local ui = {
|
||||
@ -12,9 +14,9 @@ local ui = {
|
||||
}
|
||||
|
||||
-- start the UI
|
||||
---@param fp_ps psil front panel PSIL
|
||||
function renderer.start_ui(fp_ps)
|
||||
function renderer.start_ui()
|
||||
if ui.view == nil then
|
||||
-- reset terminal
|
||||
term.setTextColor(colors.white)
|
||||
term.setBackgroundColor(colors.black)
|
||||
term.clear()
|
||||
@ -25,13 +27,19 @@ function renderer.start_ui(fp_ps)
|
||||
term.setPaletteColor(style.colors[i].c, style.colors[i].hex)
|
||||
end
|
||||
|
||||
-- start flasher callback task
|
||||
flasher.run()
|
||||
|
||||
-- init front panel view
|
||||
ui.view = panel_view(term.current(), fp_ps)
|
||||
ui.view = panel_view(term.current())
|
||||
end
|
||||
end
|
||||
|
||||
-- close out the UI
|
||||
function renderer.close_ui()
|
||||
-- stop blinking indicators
|
||||
flasher.clear()
|
||||
|
||||
if ui.view ~= nil then
|
||||
-- hide to stop animation callbacks
|
||||
ui.view.hide()
|
||||
@ -46,7 +54,11 @@ function renderer.close_ui()
|
||||
term.setPaletteColor(style.colors[i].c, r, g, b)
|
||||
end
|
||||
|
||||
-- reset terminal
|
||||
term.setTextColor(colors.white)
|
||||
term.setBackgroundColor(colors.black)
|
||||
term.clear()
|
||||
term.setCursorPos(1, 1)
|
||||
end
|
||||
|
||||
-- is the UI ready?
|
||||
|
@ -4,19 +4,20 @@
|
||||
|
||||
require("/initenv").init_env()
|
||||
|
||||
local crash = require("scada-common.crash")
|
||||
local log = require("scada-common.log")
|
||||
local mqueue = require("scada-common.mqueue")
|
||||
local ppm = require("scada-common.ppm")
|
||||
local psil = require("scada-common.psil")
|
||||
local util = require("scada-common.util")
|
||||
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 ppm = require("scada-common.ppm")
|
||||
local util = require("scada-common.util")
|
||||
|
||||
local config = require("reactor-plc.config")
|
||||
local plc = require("reactor-plc.plc")
|
||||
local config = require("reactor-plc.config")
|
||||
local databus = require("reactor-plc.databus")
|
||||
local plc = require("reactor-plc.plc")
|
||||
local renderer = require("reactor-plc.renderer")
|
||||
local threads = require("reactor-plc.threads")
|
||||
local threads = require("reactor-plc.threads")
|
||||
|
||||
local R_PLC_VERSION = "v1.1.0"
|
||||
local R_PLC_VERSION = "v1.1.1"
|
||||
|
||||
local print = util.print
|
||||
local println = util.println
|
||||
@ -63,6 +64,10 @@ local function main()
|
||||
-- startup
|
||||
----------------------------------------
|
||||
|
||||
-- record firmware versions and ID
|
||||
databus.tx_versions(R_PLC_VERSION, comms.version)
|
||||
databus.tx_id(config.REACTOR_ID)
|
||||
|
||||
-- mount connected devices
|
||||
ppm.mount_all()
|
||||
|
||||
@ -109,10 +114,7 @@ local function main()
|
||||
mq_rps = mqueue.new(),
|
||||
mq_comms_tx = mqueue.new(),
|
||||
mq_comms_rx = mqueue.new()
|
||||
},
|
||||
|
||||
-- publisher/subscriber interface for front panel
|
||||
fp_ps = psil.create()
|
||||
}
|
||||
}
|
||||
|
||||
local smem_dev = __shared_memory.plc_dev
|
||||
@ -152,9 +154,7 @@ local function main()
|
||||
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
|
||||
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
|
||||
@ -167,7 +167,7 @@ local function main()
|
||||
-- front panel time!
|
||||
if not renderer.ui_ready() then
|
||||
local message = nil
|
||||
plc_state.fp_ok, message = pcall(renderer.start_ui, __shared_memory.fp_ps)
|
||||
plc_state.fp_ok, message = pcall(renderer.start_ui)
|
||||
if not plc_state.fp_ok then
|
||||
renderer.close_ui()
|
||||
println_ts(util.c("UI error: ", message))
|
||||
@ -192,23 +192,20 @@ local function main()
|
||||
config.TRUSTED_RANGE, smem_dev.reactor, smem_sys.rps, smem_sys.conn_watchdog)
|
||||
log.debug("init> comms init")
|
||||
else
|
||||
_print_no_fp("init> starting in offline mode")
|
||||
_println_no_fp("init> starting in offline mode")
|
||||
log.info("init> running without networking")
|
||||
end
|
||||
|
||||
util.push_event("clock_start")
|
||||
|
||||
_print_no_fp("init> completed")
|
||||
_println_no_fp("init> completed")
|
||||
log.info("init> startup completed")
|
||||
else
|
||||
_print_no_fp("init> system in degraded state, awaiting devices...")
|
||||
_println_no_fp("init> system in degraded state, awaiting devices...")
|
||||
log.warning("init> started in a degraded state, awaiting peripheral connections...")
|
||||
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)
|
||||
databus.tx_hw_status(plc_state)
|
||||
end
|
||||
|
||||
----------------------------------------
|
||||
|
@ -1,15 +1,13 @@
|
||||
local log = require("scada-common.log")
|
||||
local mqueue = require("scada-common.mqueue")
|
||||
local ppm = require("scada-common.ppm")
|
||||
local util = require("scada-common.util")
|
||||
local log = require("scada-common.log")
|
||||
local mqueue = require("scada-common.mqueue")
|
||||
local ppm = require("scada-common.ppm")
|
||||
local tcallbackdsp = require("scada-common.tcallbackdsp")
|
||||
local util = require("scada-common.util")
|
||||
|
||||
local databus = require("reactor-plc.databus")
|
||||
|
||||
local threads = {}
|
||||
|
||||
local print = util.print
|
||||
local println = util.println
|
||||
local print_ts = util.print_ts
|
||||
local println_ts = util.println_ts
|
||||
|
||||
local MAIN_CLOCK = 0.5 -- (2Hz, 10 ticks)
|
||||
local RPS_SLEEP = 250 -- (250ms, 5 ticks)
|
||||
local COMMS_SLEEP = 150 -- (150ms, 3 ticks)
|
||||
@ -32,11 +30,16 @@ local MQ__COMM_CMD = {
|
||||
---@param smem plc_shared_memory
|
||||
---@param init function
|
||||
function threads.thread__main(smem, init)
|
||||
-- print a log message to the terminal as long as the UI isn't running
|
||||
local function println(message) if not smem.plc_state.fp_ok then util.println(message) end end
|
||||
local function println_ts(message) if not smem.plc_state.fp_ok then util.println_ts(message) end end
|
||||
|
||||
---@class parallel_thread
|
||||
local public = {}
|
||||
|
||||
-- execute thread
|
||||
function public.exec()
|
||||
databus.tx_rt_status("main", true)
|
||||
log.debug("main thread init, clock inactive")
|
||||
|
||||
-- send status updates at 2Hz (every 10 server ticks) (every loop tick)
|
||||
@ -61,6 +64,9 @@ function threads.thread__main(smem, init)
|
||||
|
||||
-- handle event
|
||||
if event == "timer" and loop_clock.is_clock(param1) then
|
||||
-- blink heartbeat indicator
|
||||
databus.heartbeat()
|
||||
|
||||
-- core clock tick
|
||||
if networked then
|
||||
-- start next clock timer
|
||||
@ -72,7 +78,6 @@ function threads.thread__main(smem, init)
|
||||
smem.q.mq_comms_tx.push_command(MQ__COMM_CMD.SEND_STATUS)
|
||||
else
|
||||
if ticks_to_update == 0 then
|
||||
smem.fp_ps.toggle("heartbeat")
|
||||
plc_comms.send_link_req()
|
||||
ticks_to_update = LINK_TICKS
|
||||
else
|
||||
@ -80,14 +85,6 @@ function threads.thread__main(smem, init)
|
||||
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
|
||||
|
||||
-- are we now formed after waiting to be formed?
|
||||
@ -144,10 +141,7 @@ function threads.thread__main(smem, init)
|
||||
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)
|
||||
databus.tx_hw_status(plc_state)
|
||||
elseif event == "modem_message" and networked and plc_state.init_ok and not plc_state.no_modem then
|
||||
-- got a packet
|
||||
local packet = plc_comms.parse_packet(param1, param2, param3, param4, param5)
|
||||
@ -159,6 +153,9 @@ function threads.thread__main(smem, init)
|
||||
-- haven't heard from server recently? shutdown reactor
|
||||
plc_comms.unlink()
|
||||
smem.q.mq_rps.push_command(MQ__RPS_CMD.TRIP_TIMEOUT)
|
||||
elseif event == "timer" then
|
||||
-- notify timer callback dispatcher if no other timer case claimed this event
|
||||
tcallbackdsp.handle(param1)
|
||||
elseif event == "peripheral_detach" then
|
||||
-- peripheral disconnect
|
||||
local type, device = ppm.handle_unmount(param1)
|
||||
@ -191,10 +188,7 @@ function threads.thread__main(smem, init)
|
||||
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)
|
||||
databus.tx_hw_status(plc_state)
|
||||
elseif event == "peripheral" then
|
||||
-- peripheral connect
|
||||
local type, device = ppm.mount(param1)
|
||||
@ -260,10 +254,7 @@ function threads.thread__main(smem, init)
|
||||
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)
|
||||
databus.tx_hw_status(plc_state)
|
||||
elseif event == "clock_start" then
|
||||
-- start loop clock
|
||||
loop_clock.start()
|
||||
@ -290,6 +281,8 @@ function threads.thread__main(smem, init)
|
||||
log.fatal(util.strval(result))
|
||||
end
|
||||
|
||||
databus.tx_rt_status("main", false)
|
||||
|
||||
-- if status is true, then we are probably exiting, so this won't matter
|
||||
-- if not, we need to restart the clock
|
||||
-- this thread cannot be slept because it will miss events (namely "terminate" otherwise)
|
||||
@ -307,11 +300,16 @@ end
|
||||
---@nodiscard
|
||||
---@param smem plc_shared_memory
|
||||
function threads.thread__rps(smem)
|
||||
-- print a log message to the terminal as long as the UI isn't running
|
||||
local function println(message) if not smem.plc_state.fp_ok then util.println(message) end end
|
||||
local function println_ts(message) if not smem.plc_state.fp_ok then util.println_ts(message) end end
|
||||
|
||||
---@class parallel_thread
|
||||
local public = {}
|
||||
|
||||
-- execute thread
|
||||
function public.exec()
|
||||
databus.tx_rt_status("rps", true)
|
||||
log.debug("rps thread start")
|
||||
|
||||
-- load in from shared memory
|
||||
@ -345,11 +343,17 @@ function threads.thread__rps(smem)
|
||||
was_linked = true
|
||||
end
|
||||
|
||||
-- if we tried to SCRAM but failed, keep trying
|
||||
-- in that case, SCRAM won't be called until it reconnects (this is the expected use of this check)
|
||||
if (not plc_state.no_reactor) and rps.is_formed() then
|
||||
-- check reactor status
|
||||
---@diagnostic disable-next-line: need-check-nil
|
||||
if (not plc_state.no_reactor) and rps.is_formed() and rps.is_tripped() and reactor.getStatus() then
|
||||
rps.scram()
|
||||
local reactor_status = reactor.getStatus()
|
||||
databus.tx_reactor_state(reactor_status)
|
||||
|
||||
-- if we tried to SCRAM but failed, keep trying
|
||||
-- in that case, SCRAM won't be called until it reconnects (this is the expected use of this check)
|
||||
if rps.is_tripped() and reactor_status then
|
||||
rps.scram()
|
||||
end
|
||||
end
|
||||
|
||||
-- if we are in standalone mode, continuously reset RPS
|
||||
@ -433,6 +437,8 @@ function threads.thread__rps(smem)
|
||||
log.fatal(util.strval(result))
|
||||
end
|
||||
|
||||
databus.tx_rt_status("rps", false)
|
||||
|
||||
if not plc_state.shutdown then
|
||||
if plc_state.init_ok then smem.plc_sys.rps.scram() end
|
||||
log.info("rps thread restarting in 5 seconds...")
|
||||
@ -453,6 +459,7 @@ function threads.thread__comms_tx(smem)
|
||||
|
||||
-- execute thread
|
||||
function public.exec()
|
||||
databus.tx_rt_status("comms_tx", true)
|
||||
log.debug("comms tx thread start")
|
||||
|
||||
-- load in from shared memory
|
||||
@ -510,6 +517,8 @@ function threads.thread__comms_tx(smem)
|
||||
log.fatal(util.strval(result))
|
||||
end
|
||||
|
||||
databus.tx_rt_status("comms_tx", false)
|
||||
|
||||
if not plc_state.shutdown then
|
||||
log.info("comms tx thread restarting in 5 seconds...")
|
||||
util.psleep(5)
|
||||
@ -529,6 +538,7 @@ function threads.thread__comms_rx(smem)
|
||||
|
||||
-- execute thread
|
||||
function public.exec()
|
||||
databus.tx_rt_status("comms_rx", true)
|
||||
log.debug("comms rx thread start")
|
||||
|
||||
-- load in from shared memory
|
||||
@ -586,6 +596,8 @@ function threads.thread__comms_rx(smem)
|
||||
log.fatal(util.strval(result))
|
||||
end
|
||||
|
||||
databus.tx_rt_status("comms_rx", false)
|
||||
|
||||
if not plc_state.shutdown then
|
||||
log.info("comms rx thread restarting in 5 seconds...")
|
||||
util.psleep(5)
|
||||
@ -605,6 +617,7 @@ function threads.thread__setpoint_control(smem)
|
||||
|
||||
-- execute thread
|
||||
function public.exec()
|
||||
databus.tx_rt_status("spctl", true)
|
||||
log.debug("setpoint control thread start")
|
||||
|
||||
-- load in from shared memory
|
||||
@ -719,6 +732,8 @@ function threads.thread__setpoint_control(smem)
|
||||
log.fatal(util.strval(result))
|
||||
end
|
||||
|
||||
databus.tx_rt_status("spctl", false)
|
||||
|
||||
if not plc_state.shutdown then
|
||||
log.info("setpoint control thread restarting in 5 seconds...")
|
||||
util.psleep(5)
|
||||
|
Loading…
Reference in New Issue
Block a user