diff --git a/graphics/core.lua b/graphics/core.lua index 13f97ec..8089ca1 100644 --- a/graphics/core.lua +++ b/graphics/core.lua @@ -7,7 +7,7 @@ local flasher = require("graphics.flasher") local core = {} -core.version = "2.1.0" +core.version = "2.2.0" core.flasher = flasher core.events = events diff --git a/graphics/element.lua b/graphics/element.lua index 6debaf4..e1420b7 100644 --- a/graphics/element.lua +++ b/graphics/element.lua @@ -49,6 +49,7 @@ local element = {} ---|indicator_light_args ---|power_indicator_args ---|rad_indicator_args +---|signal_bar_args ---|state_indicator_args ---|tristate_indicator_light_args ---|vbar_args diff --git a/graphics/elements/controls/switch_button.lua b/graphics/elements/controls/switch_button.lua index f649b10..1dcd1db 100644 --- a/graphics/elements/controls/switch_button.lua +++ b/graphics/elements/controls/switch_button.lua @@ -65,7 +65,7 @@ local function switch_button(args) end end - -- set the value + -- set the value (does not call the callback) ---@param val boolean new value function e.set_value(val) e.value = val diff --git a/graphics/elements/indicators/signal.lua b/graphics/elements/indicators/signal.lua new file mode 100644 index 0000000..fb21ca0 --- /dev/null +++ b/graphics/elements/indicators/signal.lua @@ -0,0 +1,72 @@ +-- Signal Bars Graphics Element + +local util = require("scada-common.util") + +local element = require("graphics.element") + +---@class signal_bar_args +---@field colors_low_med? cpair color a for low signal quality, color b for medium signal quality +---@field disconnect_color? color color for the 'x' on disconnect +---@field parent graphics_element +---@field id? string element id +---@field x? integer 1 if omitted +---@field y? integer auto incremented if omitted +---@field fg_bg? cpair foreground/background colors (foreground is used for high signal quality) +---@field hidden? boolean true to hide on initial draw + +-- new signal bar +---@nodiscard +---@param args signal_bar_args +---@return graphics_element element, element_id id +local function signal_bar(args) + args.height = 1 + args.width = 2 + + -- create new graphics element base object + local e = element.new(args) + + e.value = 0 + + local blit_bkg = args.fg_bg.blit_bkg + local blit_0, blit_1, blit_2, blit_3 = args.fg_bg.blit_fgd, args.fg_bg.blit_fgd, args.fg_bg.blit_fgd, args.fg_bg.blit_fgd + + if type(args.colors_low_med) == "table" then + blit_1 = args.colors_low_med.blit_a or blit_1 + blit_2 = args.colors_low_med.blit_b or blit_2 + end + + if util.is_int(args.disconnect_color) then blit_0 = colors.toBlit(args.disconnect_color) end + + -- on state change (0 = offline, 1 through 3 = low to high signal) + ---@param new_state integer signal state + function e.on_update(new_state) + e.value = new_state + e.redraw() + end + + -- set signal state (0 = offline, 1 through 3 = low to high signal) + ---@param val integer signal state + function e.set_value(val) e.on_update(val) end + + -- draw label and signal bar + function e.redraw() + e.w_set_cur(1, 1) + + if e.value == 1 then + e.w_blit("\x9f ", blit_bkg .. blit_bkg, blit_1 .. blit_bkg) + elseif e.value == 2 then + e.w_blit("\x9f\x94", blit_bkg .. blit_2, blit_2 .. blit_bkg) + elseif e.value == 3 then + e.w_blit("\x9f\x81", blit_bkg .. blit_bkg, blit_3 .. blit_3) + else + e.w_blit(" x", blit_0 .. blit_0, blit_bkg .. blit_bkg) + end + end + + -- initial draw + e.redraw() + + return e.complete() +end + +return signal_bar diff --git a/pocket/iocontrol.lua b/pocket/iocontrol.lua index d698d9e..38d1d20 100644 --- a/pocket/iocontrol.lua +++ b/pocket/iocontrol.lua @@ -8,13 +8,11 @@ local types = require("scada-common.types") local ALARM = types.ALARM -local iocontrol = {} +---@todo nominal trip time is ping (0ms to 10ms usually) +local WARN_TT = 40 +local HIGH_TT = 80 ----@class pocket_ioctl -local io = { - nav_root = nil, ---@type nav_tree_node - ps = psil.create() -} +local iocontrol = {} ---@enum POCKET_LINK_STATE local LINK_STATE = { @@ -26,6 +24,12 @@ local LINK_STATE = { iocontrol.LINK_STATE = LINK_STATE +---@class pocket_ioctl +local io = { + nav_root = nil, ---@type nav_tree_node + ps = psil.create() +} + ---@class nav_tree_node ---@field _p nav_tree_node|nil page's parent ---@field _c table page's children @@ -161,7 +165,43 @@ function iocontrol.init_fac() end -- set network link state ---@param state POCKET_LINK_STATE -function iocontrol.report_link_state(state) io.ps.publish("link_state", state) end +function iocontrol.report_link_state(state) + io.ps.publish("link_state", state) + + if state == LINK_STATE.API_LINK_ONLY or state == LINK_STATE.UNLINKED then + io.ps.publish("svr_conn_quality", 0) + end + + if state == LINK_STATE.SV_LINK_ONLY or state == LINK_STATE.UNLINKED then + io.ps.publish("crd_conn_quality", 0) + end +end + +-- determine supervisor connection quality (trip time) +---@param trip_time integer +function iocontrol.report_svr_tt(trip_time) + local state = 3 + if trip_time > HIGH_TT then + state = 1 + elseif trip_time > WARN_TT then + state = 2 + end + + io.ps.publish("svr_conn_quality", state) +end + +-- determine coordinator connection quality (trip time) +---@param trip_time integer +function iocontrol.report_crd_tt(trip_time) + local state = 3 + if trip_time > HIGH_TT then + state = 1 + elseif trip_time > WARN_TT then + state = 2 + end + + io.ps.publish("crd_conn_quality", state) +end -- get the IO controller database function iocontrol.get_db() return io end diff --git a/pocket/pocket.lua b/pocket/pocket.lua index 1005c2a..e2afe84 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -250,9 +250,11 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range log.warning("pocket coordinator KEEP_ALIVE trip time > 750ms (" .. trip_time .. "ms)") end - -- log.debug("pocket coordinator RTT = " .. trip_time .. "ms") + log.debug("pocket coordinator TT = " .. trip_time .. "ms") _send_api_keep_alive_ack(timestamp) + + iocontrol.report_crd_tt(trip_time) else log.debug("coordinator SCADA keep alive packet length mismatch") end @@ -340,9 +342,11 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range log.warning("pocket supervisor KEEP_ALIVE trip time > 750ms (" .. trip_time .. "ms)") end - -- log.debug("pocket supervisor RTT = " .. trip_time .. "ms") + log.debug("pocket supervisor TT = " .. trip_time .. "ms") _send_sv_keep_alive_ack(timestamp) + + iocontrol.report_svr_tt(trip_time) else log.debug("supervisor SCADA keep alive packet length mismatch") end diff --git a/pocket/ui/main.lua b/pocket/ui/main.lua index 49f375d..5f848b2 100644 --- a/pocket/ui/main.lua +++ b/pocket/ui/main.lua @@ -24,6 +24,8 @@ local TextBox = require("graphics.elements.textbox") local PushButton = require("graphics.elements.controls.push_button") local Sidebar = require("graphics.elements.controls.sidebar") +local SignalBar = require("graphics.elements.indicators.signal") + local LINK_STATE = iocontrol.LINK_STATE local ALIGN = core.ALIGN @@ -36,7 +38,12 @@ local function init(main) local db = iocontrol.get_db() -- window header message - TextBox{parent=main,y=1,text="ALPHA APP - INCOMPLETE",alignment=ALIGN.CENTER,height=1,fg_bg=style.header} + TextBox{parent=main,y=1,text="DEV ALPHA APP S C ",alignment=ALIGN.LEFT,height=1,fg_bg=style.header} + local svr_conn = SignalBar{parent=main,y=1,x=20,colors_low_med=cpair(colors.red,colors.yellow),disconnect_color=colors.lightGray,fg_bg=cpair(colors.white,colors.gray)} + local crd_conn = SignalBar{parent=main,y=1,x=24,colors_low_med=cpair(colors.red,colors.yellow),disconnect_color=colors.lightGray,fg_bg=cpair(colors.white,colors.gray)} + + db.ps.subscribe("svr_conn_quality", svr_conn.set_value) + db.ps.subscribe("crd_conn_quality", crd_conn.set_value) --#region root panel panes (connection screens + main screen)