mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#184 support supervisor running without front panel, halved heartbeat blink rate
This commit is contained in:
parent
69df5edbeb
commit
529371a0fd
1
install_manifest.json
Normal file
1
install_manifest.json
Normal file
File diff suppressed because one or more lines are too long
@ -18,21 +18,16 @@ local core = require("graphics.core")
|
||||
local Div = require("graphics.elements.div")
|
||||
local ListBox = require("graphics.elements.listbox")
|
||||
local MultiPane = require("graphics.elements.multipane")
|
||||
local Rectangle = require("graphics.elements.rectangle")
|
||||
local TextBox = require("graphics.elements.textbox")
|
||||
|
||||
local PushButton = require("graphics.elements.controls.push_button")
|
||||
local TabBar = require("graphics.elements.controls.tabbar")
|
||||
|
||||
local LED = require("graphics.elements.indicators.led")
|
||||
local LEDPair = require("graphics.elements.indicators.ledpair")
|
||||
local RGBLED = require("graphics.elements.indicators.ledrgb")
|
||||
local DataIndicator = require("graphics.elements.indicators.data")
|
||||
|
||||
local TEXT_ALIGN = core.TEXT_ALIGN
|
||||
|
||||
local cpair = core.cpair
|
||||
local border = core.border
|
||||
|
||||
-- create new main view
|
||||
---@param panel graphics_element main displaybox
|
||||
|
@ -28,6 +28,14 @@ function pgi.link_elements(rtu_list, rtu_entry, pdg_list, pdg_entry)
|
||||
data.pdg_entry = pdg_entry
|
||||
end
|
||||
|
||||
-- unlink all fields, disabling the PGI
|
||||
function pgi.unlink()
|
||||
data.rtu_list = nil
|
||||
data.pdg_list = nil
|
||||
data.rtu_entry = nil
|
||||
data.pdg_entry = nil
|
||||
end
|
||||
|
||||
-- add an RTU entry to the RTU list
|
||||
---@param session_id integer RTU session
|
||||
function pgi.create_rtu_entry(session_id)
|
||||
|
@ -3,6 +3,7 @@
|
||||
--
|
||||
|
||||
local panel_view = require("supervisor.panel.front_panel")
|
||||
local pgi = require("supervisor.panel.pgi")
|
||||
local style = require("supervisor.panel.style")
|
||||
|
||||
local flasher = require("graphics.flasher")
|
||||
@ -44,6 +45,9 @@ function renderer.close_ui()
|
||||
-- stop blinking indicators
|
||||
flasher.clear()
|
||||
|
||||
-- disable PGI
|
||||
pgi.unlink()
|
||||
|
||||
-- hide to stop animation callbacks
|
||||
ui.display.hide()
|
||||
|
||||
|
@ -20,9 +20,6 @@ local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
|
||||
|
||||
local SV_Q_DATA = svqtypes.SV_Q_DATA
|
||||
|
||||
-- local println = util.println
|
||||
local println = function (str) end
|
||||
|
||||
-- retry time constants in ms
|
||||
-- local INITIAL_WAIT = 1500
|
||||
local RETRY_PERIOD = 1000
|
||||
@ -52,7 +49,11 @@ local PERIODICS = {
|
||||
---@param out_queue mqueue out message queue
|
||||
---@param timeout number communications timeout
|
||||
---@param facility facility facility data table
|
||||
function coordinator.new_session(id, in_queue, out_queue, timeout, facility)
|
||||
---@param fp_ok boolean if the front panel UI is running
|
||||
function coordinator.new_session(id, in_queue, out_queue, timeout, facility, fp_ok)
|
||||
-- print a log message to the terminal as long as the UI isn't running
|
||||
local function println(message) if not fp_ok then util.println_ts(message) end end
|
||||
|
||||
local log_header = "crdn_session(" .. id .. "): "
|
||||
|
||||
local self = {
|
||||
|
@ -16,9 +16,6 @@ local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE
|
||||
local PLC_AUTO_ACK = comms.PLC_AUTO_ACK
|
||||
local UNIT_COMMAND = comms.UNIT_COMMAND
|
||||
|
||||
-- local println = util.println
|
||||
local println = function (str) end
|
||||
|
||||
-- retry time constants in ms
|
||||
local INITIAL_WAIT = 1500
|
||||
local INITIAL_AUTO_WAIT = 1000
|
||||
@ -52,7 +49,11 @@ local PERIODICS = {
|
||||
---@param in_queue mqueue in message queue
|
||||
---@param out_queue mqueue out message queue
|
||||
---@param timeout number communications timeout
|
||||
function plc.new_session(id, reactor_id, in_queue, out_queue, timeout)
|
||||
---@param fp_ok boolean if the front panel UI is running
|
||||
function plc.new_session(id, reactor_id, in_queue, out_queue, timeout, fp_ok)
|
||||
-- print a log message to the terminal as long as the UI isn't running
|
||||
local function println(message) if not fp_ok then util.println_ts(message) end end
|
||||
|
||||
local log_header = "plc_session(" .. id .. "): "
|
||||
|
||||
local self = {
|
||||
|
@ -9,9 +9,6 @@ local pocket = {}
|
||||
local PROTOCOL = comms.PROTOCOL
|
||||
local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE
|
||||
|
||||
-- local println = util.println
|
||||
local println = function (str) end
|
||||
|
||||
-- retry time constants in ms
|
||||
-- local INITIAL_WAIT = 1500
|
||||
-- local RETRY_PERIOD = 1000
|
||||
@ -35,7 +32,11 @@ local PERIODICS = {
|
||||
---@param in_queue mqueue in message queue
|
||||
---@param out_queue mqueue out message queue
|
||||
---@param timeout number communications timeout
|
||||
function pocket.new_session(id, in_queue, out_queue, timeout)
|
||||
---@param fp_ok boolean if the front panel UI is running
|
||||
function pocket.new_session(id, in_queue, out_queue, timeout, fp_ok)
|
||||
-- print a log message to the terminal as long as the UI isn't running
|
||||
local function println(message) if not fp_ok then util.println_ts(message) end end
|
||||
|
||||
local log_header = "pdg_session(" .. id .. "): "
|
||||
|
||||
local self = {
|
||||
|
@ -24,9 +24,6 @@ local PROTOCOL = comms.PROTOCOL
|
||||
local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE
|
||||
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
|
||||
|
||||
-- local println = util.println
|
||||
local println = function (str) end
|
||||
|
||||
local PERIODICS = {
|
||||
KEEP_ALIVE = 2000
|
||||
}
|
||||
@ -39,7 +36,11 @@ local PERIODICS = {
|
||||
---@param timeout number communications timeout
|
||||
---@param advertisement table RTU device advertisement
|
||||
---@param facility facility facility data table
|
||||
function rtu.new_session(id, in_queue, out_queue, timeout, advertisement, facility)
|
||||
---@param fp_ok boolean if the front panel UI is running
|
||||
function rtu.new_session(id, in_queue, out_queue, timeout, advertisement, facility, fp_ok)
|
||||
-- print a log message to the terminal as long as the UI isn't running
|
||||
local function println(message) if not fp_ok then util.println_ts(message) end end
|
||||
|
||||
local log_header = "rtu_session(" .. id .. "): "
|
||||
|
||||
local self = {
|
||||
|
@ -35,6 +35,7 @@ svsessions.SESSION_TYPE = SESSION_TYPE
|
||||
|
||||
local self = {
|
||||
modem = nil, ---@type table|nil
|
||||
fp_ok = false,
|
||||
num_reactors = 0,
|
||||
facility = nil, ---@type facility|nil
|
||||
sessions = { rtu = {}, plc = {}, coord = {}, pdg = {} },
|
||||
@ -196,11 +197,13 @@ end
|
||||
-- PUBLIC FUNCTIONS --
|
||||
|
||||
-- initialize svsessions
|
||||
---@param modem table
|
||||
---@param num_reactors integer
|
||||
---@param cooling_conf table
|
||||
function svsessions.init(modem, num_reactors, cooling_conf)
|
||||
---@param modem table modem device
|
||||
---@param fp_ok boolean front panel active
|
||||
---@param num_reactors integer number of reactors
|
||||
---@param cooling_conf table cooling configuration definition
|
||||
function svsessions.init(modem, fp_ok, num_reactors, cooling_conf)
|
||||
self.modem = modem
|
||||
self.fp_ok = fp_ok
|
||||
self.num_reactors = num_reactors
|
||||
self.facility = facility.new(num_reactors, cooling_conf)
|
||||
end
|
||||
@ -308,13 +311,15 @@ function svsessions.establish_plc_session(local_port, remote_port, for_reactor,
|
||||
instance = nil ---@type plc_session
|
||||
}
|
||||
|
||||
plc_s.instance = plc.new_session(self.next_ids.plc, for_reactor, plc_s.in_queue, plc_s.out_queue, config.PLC_TIMEOUT)
|
||||
plc_s.instance = plc.new_session(self.next_ids.plc, for_reactor, plc_s.in_queue, plc_s.out_queue,
|
||||
config.PLC_TIMEOUT, self.fp_ok)
|
||||
table.insert(self.sessions.plc, plc_s)
|
||||
|
||||
local units = self.facility.get_units()
|
||||
units[for_reactor].link_plc_session(plc_s)
|
||||
|
||||
log.debug(util.c("established new PLC session to ", remote_port, " with ID ", self.next_ids.plc, " for reactor ", for_reactor))
|
||||
log.debug(util.c("established new PLC session to ", remote_port, " with ID ", self.next_ids.plc,
|
||||
" for reactor ", for_reactor))
|
||||
|
||||
databus.tx_plc_connected(for_reactor, version, remote_port)
|
||||
|
||||
@ -348,7 +353,8 @@ function svsessions.establish_rtu_session(local_port, remote_port, advertisement
|
||||
instance = nil ---@type rtu_session
|
||||
}
|
||||
|
||||
rtu_s.instance = rtu.new_session(self.next_ids.rtu, rtu_s.in_queue, rtu_s.out_queue, config.RTU_TIMEOUT, advertisement, self.facility)
|
||||
rtu_s.instance = rtu.new_session(self.next_ids.rtu, rtu_s.in_queue, rtu_s.out_queue, config.RTU_TIMEOUT, advertisement,
|
||||
self.facility, self.fp_ok)
|
||||
table.insert(self.sessions.rtu, rtu_s)
|
||||
|
||||
log.debug("established new RTU session to " .. remote_port .. " with ID " .. self.next_ids.rtu)
|
||||
@ -381,7 +387,8 @@ function svsessions.establish_coord_session(local_port, remote_port, version)
|
||||
instance = nil ---@type coord_session
|
||||
}
|
||||
|
||||
coord_s.instance = coordinator.new_session(self.next_ids.coord, coord_s.in_queue, coord_s.out_queue, config.CRD_TIMEOUT, self.facility)
|
||||
coord_s.instance = coordinator.new_session(self.next_ids.coord, coord_s.in_queue, coord_s.out_queue, config.CRD_TIMEOUT,
|
||||
self.facility, self.fp_ok)
|
||||
table.insert(self.sessions.coord, coord_s)
|
||||
|
||||
log.debug("established new coordinator session to " .. remote_port .. " with ID " .. self.next_ids.coord)
|
||||
@ -417,7 +424,7 @@ function svsessions.establish_pdg_session(local_port, remote_port, version)
|
||||
instance = nil ---@type pdg_session
|
||||
}
|
||||
|
||||
pdg_s.instance = pocket.new_session(self.next_ids.pdg, pdg_s.in_queue, pdg_s.out_queue, config.PKT_TIMEOUT)
|
||||
pdg_s.instance = pocket.new_session(self.next_ids.pdg, pdg_s.in_queue, pdg_s.out_queue, config.PKT_TIMEOUT, self.fp_ok)
|
||||
table.insert(self.sessions.pdg, pdg_s)
|
||||
|
||||
log.debug("established new pocket diagnostics session to " .. remote_port .. " with ID " .. self.next_ids.pdg)
|
||||
|
@ -108,93 +108,104 @@ local function main()
|
||||
println_ts(util.c("UI error: ", message))
|
||||
log.error(util.c("GUI crashed with error ", message))
|
||||
else
|
||||
-- start comms, open all channels
|
||||
local superv_comms = supervisor.comms(SUPERVISOR_VERSION, config.NUM_REACTORS, config.REACTOR_COOLING, modem,
|
||||
config.SCADA_DEV_LISTEN, config.SCADA_SV_CTL_LISTEN, config.TRUSTED_RANGE)
|
||||
|
||||
-- base loop clock (6.67Hz, 3 ticks)
|
||||
local MAIN_CLOCK = 0.15
|
||||
local loop_clock = util.new_clock(MAIN_CLOCK)
|
||||
|
||||
-- start clock
|
||||
loop_clock.start()
|
||||
|
||||
-- event loop
|
||||
while true do
|
||||
local event, param1, param2, param3, param4, param5 = util.pull_event()
|
||||
|
||||
-- handle event
|
||||
if event == "peripheral_detach" then
|
||||
local type, device = ppm.handle_unmount(param1)
|
||||
|
||||
if type ~= nil and device ~= nil then
|
||||
if type == "modem" then
|
||||
-- we only care if this is our wireless modem
|
||||
if device == modem then
|
||||
log.warning("comms modem disconnected")
|
||||
databus.tx_hw_modem(false)
|
||||
else
|
||||
log.warning("non-comms modem disconnected")
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif event == "peripheral" then
|
||||
local type, device = ppm.mount(param1)
|
||||
|
||||
if type ~= nil and device ~= nil then
|
||||
if type == "modem" then
|
||||
if device.isWireless() then
|
||||
-- reconnected modem
|
||||
modem = device
|
||||
superv_comms.reconnect_modem(modem)
|
||||
|
||||
log.info("comms modem reconnected")
|
||||
|
||||
databus.tx_hw_modem(true)
|
||||
else
|
||||
log.info("wired modem reconnected")
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif event == "timer" and loop_clock.is_clock(param1) then
|
||||
-- main loop tick
|
||||
databus.heartbeat()
|
||||
|
||||
-- iterate sessions
|
||||
svsessions.iterate_all()
|
||||
|
||||
-- free any closed sessions
|
||||
svsessions.free_all_closed()
|
||||
|
||||
loop_clock.start()
|
||||
elseif event == "timer" then
|
||||
-- a non-clock timer event, check watchdogs
|
||||
svsessions.check_all_watchdogs(param1)
|
||||
|
||||
-- notify timer callback dispatcher
|
||||
tcd.handle(param1)
|
||||
elseif event == "modem_message" then
|
||||
-- got a packet
|
||||
local packet = superv_comms.parse_packet(param1, param2, param3, param4, param5)
|
||||
superv_comms.handle_packet(packet)
|
||||
elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" then
|
||||
-- handle a mouse event
|
||||
renderer.handle_mouse(core.events.new_mouse_event(event, param1, param2, param3))
|
||||
end
|
||||
|
||||
-- check for termination request
|
||||
if event == "terminate" or ppm.should_terminate() then
|
||||
log.info("terminate requested, closing sessions...")
|
||||
svsessions.close_all()
|
||||
log.info("sessions closed")
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
renderer.close_ui()
|
||||
-- redefine println_ts local to not print as we have the front panel running
|
||||
println_ts = function (_) end
|
||||
end
|
||||
|
||||
println_ts("exited")
|
||||
-- start comms, open all channels
|
||||
local superv_comms = supervisor.comms(SUPERVISOR_VERSION, config.NUM_REACTORS, config.REACTOR_COOLING, modem,
|
||||
config.SCADA_DEV_LISTEN, config.SCADA_SV_CTL_LISTEN, config.TRUSTED_RANGE, fp_ok)
|
||||
|
||||
-- base loop clock (6.67Hz, 3 ticks)
|
||||
local MAIN_CLOCK = 0.15
|
||||
local loop_clock = util.new_clock(MAIN_CLOCK)
|
||||
|
||||
-- start clock
|
||||
loop_clock.start()
|
||||
|
||||
-- halve the rate heartbeat LED flash
|
||||
local heartbeat_toggle = true
|
||||
|
||||
-- event loop
|
||||
while true do
|
||||
local event, param1, param2, param3, param4, param5 = util.pull_event()
|
||||
|
||||
-- handle event
|
||||
if event == "peripheral_detach" then
|
||||
local type, device = ppm.handle_unmount(param1)
|
||||
|
||||
if type ~= nil and device ~= nil then
|
||||
if type == "modem" then
|
||||
-- we only care if this is our wireless modem
|
||||
if device == modem then
|
||||
println_ts("wireless modem disconnected!")
|
||||
log.warning("comms modem disconnected")
|
||||
databus.tx_hw_modem(false)
|
||||
else
|
||||
log.warning("non-comms modem disconnected")
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif event == "peripheral" then
|
||||
local type, device = ppm.mount(param1)
|
||||
|
||||
if type ~= nil and device ~= nil then
|
||||
if type == "modem" then
|
||||
if device.isWireless() then
|
||||
-- reconnected modem
|
||||
modem = device
|
||||
superv_comms.reconnect_modem(modem)
|
||||
|
||||
println_ts("wireless modem reconnected.")
|
||||
log.info("comms modem reconnected")
|
||||
|
||||
databus.tx_hw_modem(true)
|
||||
else
|
||||
log.info("wired modem reconnected")
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif event == "timer" and loop_clock.is_clock(param1) then
|
||||
-- main loop tick
|
||||
|
||||
if heartbeat_toggle then databus.heartbeat() end
|
||||
heartbeat_toggle = not heartbeat_toggle
|
||||
|
||||
-- iterate sessions
|
||||
svsessions.iterate_all()
|
||||
|
||||
-- free any closed sessions
|
||||
svsessions.free_all_closed()
|
||||
|
||||
loop_clock.start()
|
||||
elseif event == "timer" then
|
||||
-- a non-clock timer event, check watchdogs
|
||||
svsessions.check_all_watchdogs(param1)
|
||||
|
||||
-- notify timer callback dispatcher
|
||||
tcd.handle(param1)
|
||||
elseif event == "modem_message" then
|
||||
-- got a packet
|
||||
local packet = superv_comms.parse_packet(param1, param2, param3, param4, param5)
|
||||
superv_comms.handle_packet(packet)
|
||||
elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" then
|
||||
-- handle a mouse event
|
||||
renderer.handle_mouse(core.events.new_mouse_event(event, param1, param2, param3))
|
||||
end
|
||||
|
||||
-- check for termination request
|
||||
if event == "terminate" or ppm.should_terminate() then
|
||||
println_ts("closing sesssions...")
|
||||
log.info("terminate requested, closing sessions...")
|
||||
svsessions.close_all()
|
||||
log.info("sessions closed")
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
renderer.close_ui()
|
||||
|
||||
util.println_ts("exited")
|
||||
log.info("exited")
|
||||
end
|
||||
|
||||
|
@ -11,9 +11,6 @@ local DEVICE_TYPE = comms.DEVICE_TYPE
|
||||
local ESTABLISH_ACK = comms.ESTABLISH_ACK
|
||||
local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE
|
||||
|
||||
-- local println = util.println
|
||||
local println = function (str) end
|
||||
|
||||
-- supervisory controller communications
|
||||
---@nodiscard
|
||||
---@param _version string supervisor version
|
||||
@ -23,8 +20,12 @@ local println = function (str) end
|
||||
---@param dev_listen integer listening port for PLC/RTU devices
|
||||
---@param svctl_listen integer listening port for supervisor access
|
||||
---@param range integer trusted device connection range
|
||||
---@param fp_ok boolean if the front panel UI is running
|
||||
---@diagnostic disable-next-line: unused-local
|
||||
function supervisor.comms(_version, num_reactors, cooling_conf, modem, dev_listen, svctl_listen, range)
|
||||
function supervisor.comms(_version, num_reactors, cooling_conf, modem, dev_listen, svctl_listen, range, fp_ok)
|
||||
-- print a log message to the terminal as long as the UI isn't running
|
||||
local function println(message) if not fp_ok then util.println_ts(message) end end
|
||||
|
||||
local self = {
|
||||
last_est_acks = {}
|
||||
}
|
||||
@ -42,8 +43,8 @@ function supervisor.comms(_version, num_reactors, cooling_conf, modem, dev_liste
|
||||
|
||||
_conf_channels()
|
||||
|
||||
-- link modem to svsessions
|
||||
svsessions.init(modem, num_reactors, cooling_conf)
|
||||
-- pass modem, status, and config data to svsessions
|
||||
svsessions.init(modem, fp_ok, num_reactors, cooling_conf)
|
||||
|
||||
-- send an establish request response to a PLC/RTU
|
||||
---@param dest integer
|
||||
|
Loading…
Reference in New Issue
Block a user