From ece7c0fe9ac47c0b2782ffa03e8789f31c9538c9 Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Tue, 23 May 2023 19:22:22 -0400 Subject: [PATCH] #184 supervisor graphics updates for new system, added PLC and CRD pages on supervisor front panel --- graphics/elements/indicators/data.lua | 11 ++- supervisor/databus.lua | 81 +++++++++++++-- supervisor/panel/components/plc_entry.lua | 0 supervisor/panel/front_panel.lua | 115 +++++++++++++++++----- supervisor/panel/style.lua | 5 +- supervisor/session/coordinator.lua | 5 + supervisor/session/plc.lua | 5 + supervisor/session/svsessions.lua | 5 + supervisor/startup.lua | 2 +- 9 files changed, 190 insertions(+), 39 deletions(-) delete mode 100644 supervisor/panel/components/plc_entry.lua diff --git a/graphics/elements/indicators/data.lua b/graphics/elements/indicators/data.lua index 66d45dc..748c17a 100644 --- a/graphics/elements/indicators/data.lua +++ b/graphics/elements/indicators/data.lua @@ -52,6 +52,8 @@ local function data(args) clear_width = args.width - (label_len + 1) end + local value_color = e.fg_bg.fgd + -- on state change ---@param value any new value function e.on_update(value) @@ -64,7 +66,7 @@ local function data(args) -- write data local data_str = util.sprintf(args.format, value) e.window.setCursorPos(data_start, 1) - e.window.setTextColor(e.fg_bg.fgd) + e.window.setTextColor(value_color) if args.commas then e.window.write(util.comma_format(data_str)) else @@ -84,6 +86,13 @@ local function data(args) ---@param val any new value function e.set_value(val) e.on_update(val) end + -- change the foreground color of the value, or all text if no label/unit colors provided + ---@param c color + function e.recolor(c) + value_color = c + e.on_update(e.value) + end + -- initial value draw e.on_update(args.value) diff --git a/supervisor/databus.lua b/supervisor/databus.lua index e6bbee7..082a71e 100644 --- a/supervisor/databus.lua +++ b/supervisor/databus.lua @@ -6,39 +6,102 @@ local psil = require("scada-common.psil") local databus = {} +-- databus PSIL +databus.ps = psil.create() + local dbus_iface = { - ps = psil.create(), - session_entries = { rtu = {}, plc = {}, coord = {}, diag = {} } + session_entries = { rtu = {}, diag = {} } } -- call to toggle heartbeat signal -function databus.heartbeat() dbus_iface.ps.toggle("heartbeat") end +function databus.heartbeat() databus.ps.toggle("heartbeat") end -- transmit firmware versions across the bus ---@param plc_v string supervisor version ---@param comms_v string comms version function databus.tx_versions(plc_v, comms_v) - dbus_iface.ps.publish("version", plc_v) - dbus_iface.ps.publish("comms_version", comms_v) + databus.ps.publish("version", plc_v) + databus.ps.publish("comms_version", comms_v) end -- transmit hardware status for modem connection state ---@param has_modem boolean function databus.tx_hw_modem(has_modem) - dbus_iface.ps.publish("has_modem", has_modem) + databus.ps.publish("has_modem", has_modem) end -function databus.tx_svs_connection(type, data) +-- transmit PLC firmware version and session connection state +---@param reactor_id integer reactor unit ID +---@param fw string firmware version +---@param channel integer PLC remote port +function databus.tx_plc_connected(reactor_id, fw, channel) + databus.ps.publish("plc_" .. reactor_id .. "_fw", fw) + databus.ps.publish("plc_" .. reactor_id .. "_conn", true) + databus.ps.publish("plc_" .. reactor_id .. "_chan", tostring(channel)) end -function databus.tx_svs_disconnection(type, data) +-- transmit PLC session connection state +---@param reactor_id integer reactor unit ID +function databus.tx_plc_disconnected(reactor_id) + databus.ps.publish("plc_" .. reactor_id .. "_fw", " ------- ") + databus.ps.publish("plc_" .. reactor_id .. "_conn", false) + databus.ps.publish("plc_" .. reactor_id .. "_chan", " --- ") + databus.ps.publish("plc_" .. reactor_id .. "_rtt", 0) + databus.ps.publish("plc_" .. reactor_id .. "_rtt_color", colors.lightGray) +end + +-- transmit PLC session RTT +---@param reactor_id integer reactor unit ID +---@param rtt integer round trip time +function databus.tx_plc_rtt(reactor_id, rtt) + databus.ps.publish("plc_" .. reactor_id .. "_rtt", rtt) + + if rtt > 700 then + databus.ps.publish("plc_" .. reactor_id .. "_rtt_color", colors.red) + elseif rtt > 300 then + databus.ps.publish("plc_" .. reactor_id .. "_rtt_color", colors.yellow_hc) + else + databus.ps.publish("plc_" .. reactor_id .. "_rtt_color", colors.green) + end +end + +-- transmit coordinator firmware version and session connection state +---@param fw string firmware version +---@param channel integer coordinator remote port +function databus.tx_crd_connected(fw, channel) + databus.ps.publish("crd_fw", fw) + databus.ps.publish("crd_conn", true) + databus.ps.publish("crd_chan", tostring(channel)) +end + +-- transmit coordinator session connection state +function databus.tx_crd_disconnected() + databus.ps.publish("crd_fw", " ------- ") + databus.ps.publish("crd_conn", false) + databus.ps.publish("crd_chan", "---") + databus.ps.publish("crd_rtt", 0) + databus.ps.publish("crd_rtt_color", colors.lightGray) +end + +-- transmit coordinator session RTT +---@param rtt integer round trip time +function databus.tx_crd_rtt(rtt) + databus.ps.publish("crd_rtt", rtt) + + if rtt > 700 then + databus.ps.publish("crd_rtt_color", colors.red) + elseif rtt > 300 then + databus.ps.publish("crd_rtt_color", colors.yellow_hc) + else + databus.ps.publish("crd_rtt_color", colors.green) + end 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) - dbus_iface.ps.subscribe(field, func) + databus.ps.subscribe(field, func) end return databus diff --git a/supervisor/panel/components/plc_entry.lua b/supervisor/panel/components/plc_entry.lua deleted file mode 100644 index e69de29..0000000 diff --git a/supervisor/panel/front_panel.lua b/supervisor/panel/front_panel.lua index 21d631b..bf95c6b 100644 --- a/supervisor/panel/front_panel.lua +++ b/supervisor/panel/front_panel.lua @@ -2,25 +2,28 @@ -- Main SCADA Coordinator GUI -- -local util = require("scada-common.util") +local util = require("scada-common.util") -local databus = require("supervisor.databus") +local config = require("supervisor.config") +local databus = require("supervisor.databus") -local style = require("supervisor.panel.style") +local style = require("supervisor.panel.style") -local core = require("graphics.core") +local core = require("graphics.core") -local Div = require("graphics.elements.div") -local MultiPane = require("graphics.elements.multipane") -local Rectangle = require("graphics.elements.rectangle") -local TextBox = require("graphics.elements.textbox") +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 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 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 @@ -47,12 +50,12 @@ local function init(panel) on.update(true) system.line_break() - databus.rx_field("heartbeat", heartbeat.update) + heartbeat.register(databus.ps, "heartbeat", heartbeat.update) local modem = LED{parent=system,label="MODEM",colors=cpair(colors.green,colors.green_off)} system.line_break() - databus.rx_field("has_modem", modem.update) + modem.register(databus.ps, "has_modem", modem.update) -- -- about footer @@ -62,30 +65,90 @@ local function init(panel) local fw_v = TextBox{parent=about,x=1,y=1,text="FW: v00.00.00",alignment=TEXT_ALIGN.LEFT,height=1} local comms_v = TextBox{parent=about,x=1,y=2,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) + fw_v.register(databus.ps, "version", function (version) fw_v.set_value(util.c("FW: ", version)) end) + comms_v.register(databus.ps, "comms_version", function (version) comms_v.set_value(util.c("NT: v", version)) end) -- -- page handling -- - local plc_list = Div{parent=page_div,x=1,y=1} + -- plc page - TextBox{parent=plc_list,x=2,y=2,text="v1.1.17 - PLC - UNIT 4 - :15004",alignment=TEXT_ALIGN.LEFT,height=1} + local plc_page = Div{parent=page_div,x=1,y=1} + local plc_list = Div{parent=plc_page,x=2,y=2,width=49} - local panes = { main_page, plc_list, main_page, main_page, main_page } + for i = 1, config.NUM_REACTORS do + local ps_prefix = "plc_" .. i .. "_" + local plc_entry = Div{parent=plc_list,height=3,fg_bg=cpair(colors.black,colors.white)} + + TextBox{parent=plc_entry,x=1,y=1,text="",width=8,height=1,fg_bg=cpair(colors.black,colors.lightGray)} + TextBox{parent=plc_entry,x=1,y=2,text="UNIT "..i,alignment=TEXT_ALIGN.CENTER,width=8,height=1,fg_bg=cpair(colors.black,colors.lightGray)} + TextBox{parent=plc_entry,x=1,y=3,text="",width=8,height=1,fg_bg=cpair(colors.black,colors.lightGray)} + + local conn = LED{parent=plc_entry,x=10,y=2,label="CONN",colors=cpair(colors.green,colors.green_off)} + conn.register(databus.ps, ps_prefix .. "conn", conn.update) + + local plc_chan = TextBox{parent=plc_entry,x=17,y=2,text=" --- ",width=5,height=1,fg_bg=cpair(colors.gray,colors.white)} + plc_chan.register(databus.ps, ps_prefix .. "chan", plc_chan.set_value) + + TextBox{parent=plc_entry,x=23,y=2,text="FW:",width=3,height=1} + local plc_fw_v = TextBox{parent=plc_entry,x=27,y=2,text=" ------- ",width=9,height=1,fg_bg=cpair(colors.lightGray,colors.white)} + plc_fw_v.register(databus.ps, ps_prefix .. "fw", plc_fw_v.set_value) + + TextBox{parent=plc_entry,x=37,y=2,text="RTT:",width=4,height=1} + local plc_rtt = DataIndicator{parent=plc_entry,x=42,y=2,label="",unit="",format="%4d",value=0,width=4,fg_bg=cpair(colors.lightGray,colors.white)} + TextBox{parent=plc_entry,x=47,y=2,text="ms",width=4,height=1,fg_bg=cpair(colors.lightGray,colors.white)} + plc_rtt.register(databus.ps, ps_prefix .. "rtt", plc_rtt.update) + plc_rtt.register(databus.ps, ps_prefix .. "rtt_color", plc_rtt.recolor) + + plc_list.line_break() + end + + -- rtu page + + local rtu_page = Div{parent=page_div,x=1,y=1} + local rtu_list = Div{parent=rtu_page,x=2,y=2,width=49} + + -- coordinator page + + local crd_page = Div{parent=page_div,x=1,y=1} + local crd_box = Div{parent=crd_page,x=2,y=2,width=49,height=4,fg_bg=cpair(colors.black,colors.white)} + + local crd_conn = LED{parent=crd_box,x=2,y=2,label="CONNECTION",colors=cpair(colors.green,colors.green_off)} + crd_conn.register(databus.ps, "crd_conn", crd_conn.update) + + TextBox{parent=crd_box,x=4,y=3,text="CHANNEL ",width=8,height=1,fg_bg=cpair(colors.gray,colors.white)} + local crd_chan = TextBox{parent=crd_box,x=12,y=3,text="---",width=5,height=1,fg_bg=cpair(colors.gray,colors.white)} + crd_chan.register(databus.ps, "crd_chan", crd_chan.set_value) + + TextBox{parent=crd_box,x=22,y=2,text="FW:",width=3,height=1} + local crd_fw_v = TextBox{parent=crd_box,x=26,y=2,text=" ------- ",width=9,height=1,fg_bg=cpair(colors.lightGray,colors.white)} + crd_fw_v.register(databus.ps, "crd_fw", crd_fw_v.set_value) + + TextBox{parent=crd_box,x=36,y=2,text="RTT:",width=4,height=1} + local crd_rtt = DataIndicator{parent=crd_box,x=41,y=2,label="",unit="",format="%5d",value=0,width=5,fg_bg=cpair(colors.lightGray,colors.white)} + TextBox{parent=crd_box,x=47,y=2,text="ms",width=4,height=1,fg_bg=cpair(colors.lightGray,colors.white)} + crd_rtt.register(databus.ps, "crd_rtt", crd_rtt.update) + crd_rtt.register(databus.ps, "crd_rtt_color", crd_rtt.recolor) + + -- pocket page + + local pkt_page = Div{parent=page_div,x=1,y=1} + local pkt_box = Div{parent=pkt_page,x=2,y=2,width=49} + + local panes = { main_page, plc_page, rtu_page, crd_page, pkt_page } local page_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes} local tabs = { - { name = "Main", color = cpair(colors.black, colors.ivory) }, - { name = "PLCs", color = cpair(colors.black, colors.ivory) }, - { name = "RTUs", color = cpair(colors.black, colors.ivory) }, - { name = "CRDs", color = cpair(colors.black, colors.ivory) }, - { name = "PKTs", color = cpair(colors.black, colors.ivory) }, + { name = "SVR", color = cpair(colors.black, colors.ivory) }, + { name = "PLC", color = cpair(colors.black, colors.ivory) }, + { name = "RTU", color = cpair(colors.black, colors.ivory) }, + { name = "CRD", color = cpair(colors.black, colors.ivory) }, + { name = "PKT", color = cpair(colors.black, colors.ivory) }, } - TabBar{parent=panel,y=2,tabs=tabs,min_width=10,callback=page_pane.set_value,fg_bg=cpair(colors.black,colors.white)} + TabBar{parent=panel,y=2,tabs=tabs,min_width=9,callback=page_pane.set_value,fg_bg=cpair(colors.black,colors.white)} end return init diff --git a/supervisor/panel/style.lua b/supervisor/panel/style.lua index 996453c..0668ccc 100644 --- a/supervisor/panel/style.lua +++ b/supervisor/panel/style.lua @@ -12,6 +12,7 @@ local cpair = core.cpair -- remap global colors colors.ivory = colors.pink +colors.yellow_hc = colors.purple colors.red_off = colors.brown colors.yellow_off = colors.magenta colors.green_off = colors.lime @@ -27,8 +28,8 @@ style.colors = { { c = colors.green, hex = 0x6be551 }, -- GREEN ON { c = colors.cyan, hex = 0x34bac8 }, { c = colors.lightBlue, hex = 0x6cc0f2 }, - { c = colors.blue, hex = 0x0096ff }, - { c = colors.purple, hex = 0xb156ee }, + { c = colors.blue, hex = 0x0008fe }, -- LCD BLUE + { c = colors.purple, hex = 0xe3bc2a }, -- YELLOW HIGH CONTRAST { c = colors.pink, hex = 0xdcd9ca }, -- IVORY { c = colors.magenta, hex = 0x85862c }, -- YELLOW OFF -- { c = colors.white, hex = 0xdcd9ca }, diff --git a/supervisor/session/coordinator.lua b/supervisor/session/coordinator.lua index b68d815..03a579d 100644 --- a/supervisor/session/coordinator.lua +++ b/supervisor/session/coordinator.lua @@ -4,6 +4,8 @@ local mqueue = require("scada-common.mqueue") local types = require("scada-common.types") local util = require("scada-common.util") +local databus = require("supervisor.databus") + local svqtypes = require("supervisor.session.svqtypes") local coordinator = {} @@ -85,6 +87,7 @@ function coordinator.new_session(id, in_queue, out_queue, timeout, facility) local function _close() self.conn_watchdog.cancel() self.connected = false + databus.tx_crd_disconnected() end -- send a CRDN packet @@ -206,6 +209,8 @@ function coordinator.new_session(id, in_queue, out_queue, timeout, facility) -- log.debug(log_header .. "COORD RTT = " .. self.last_rtt .. "ms") -- log.debug(log_header .. "COORD TT = " .. (srv_now - coord_send) .. "ms") + + databus.tx_crd_rtt(self.last_rtt) else log.debug(log_header .. "SCADA keep alive packet length mismatch") end diff --git a/supervisor/session/plc.lua b/supervisor/session/plc.lua index 8c61221..0fb987a 100644 --- a/supervisor/session/plc.lua +++ b/supervisor/session/plc.lua @@ -4,6 +4,8 @@ local mqueue = require("scada-common.mqueue") local types = require("scada-common.types") local util = require("scada-common.util") +local databus = require("supervisor.databus") + local svqtypes = require("supervisor.session.svqtypes") local plc = {} @@ -236,6 +238,7 @@ function plc.new_session(id, reactor_id, in_queue, out_queue, timeout) local function _close() self.conn_watchdog.cancel() self.connected = false + databus.tx_plc_disconnected(reactor_id) end -- send an RPLC packet @@ -486,6 +489,8 @@ function plc.new_session(id, reactor_id, in_queue, out_queue, timeout) -- log.debug(log_header .. "PLC RTT = " .. self.last_rtt .. "ms") -- log.debug(log_header .. "PLC TT = " .. (srv_now - plc_send) .. "ms") + + databus.tx_plc_rtt(reactor_id, self.last_rtt) else log.debug(log_header .. "SCADA keep alive packet length mismatch") end diff --git a/supervisor/session/svsessions.lua b/supervisor/session/svsessions.lua index 93b35b9..8c56419 100644 --- a/supervisor/session/svsessions.lua +++ b/supervisor/session/svsessions.lua @@ -3,6 +3,7 @@ local mqueue = require("scada-common.mqueue") local util = require("scada-common.util") local config = require("supervisor.config") +local databus = require("supervisor.databus") local facility = require("supervisor.facility") local svqtypes = require("supervisor.session.svqtypes") @@ -317,6 +318,8 @@ function svsessions.establish_plc_session(local_port, remote_port, for_reactor, self.next_ids.plc = self.next_ids.plc + 1 + databus.tx_plc_connected(for_reactor, version, remote_port) + -- success return plc_s.instance.get_id() else @@ -383,6 +386,8 @@ function svsessions.establish_coord_session(local_port, remote_port, version) self.next_ids.coord = self.next_ids.coord + 1 + databus.tx_crd_connected(version, remote_port) + -- success return coord_s.instance.get_id() else diff --git a/supervisor/startup.lua b/supervisor/startup.lua index c3d966a..1c3f84c 100644 --- a/supervisor/startup.lua +++ b/supervisor/startup.lua @@ -19,7 +19,7 @@ local supervisor = require("supervisor.supervisor") local svsessions = require("supervisor.session.svsessions") -local SUPERVISOR_VERSION = "v0.16.1" +local SUPERVISOR_VERSION = "v0.16.2" local println = util.println local println_ts = util.println_ts