diff --git a/pocket/iorx.lua b/pocket/iorx.lua index e503f6f..3ea69c1 100644 --- a/pocket/iorx.lua +++ b/pocket/iorx.lua @@ -908,6 +908,10 @@ function iorx.record_network_data(data) ps.publish(pfx .. "_fw", entry[3]) ps.publish(pfx .. "_rtt", entry[4]) + if type == DEV_TYPE.PLC then + ps.publish(pfx .. "_unit", entry[5]) + end + if not comp_record[id] then comp_record[id] = true diff --git a/pocket/ui/apps/comps.lua b/pocket/ui/apps/comps.lua index 4b68d69..97d63f4 100644 --- a/pocket/ui/apps/comps.lua +++ b/pocket/ui/apps/comps.lua @@ -2,6 +2,7 @@ -- Computer List App -- +local comms = require("scada-common.comms") local util = require("scada-common.util") local iocontrol = require("pocket.iocontrol") @@ -21,6 +22,8 @@ local WaitingAnim = require("graphics.elements.animations.Waiting") local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local DEV_TYPE = comms.DEVICE_TYPE + local ALIGN = core.ALIGN local cpair = core.cpair local border = core.border @@ -65,7 +68,7 @@ local function new_view(root) local panes = {} ---@type Div[] -- create all page divs - for _ = 1, 3 do + for _ = 1, 4 do local div = Div{parent=page_div} table.insert(panes, div) end @@ -79,43 +82,36 @@ local function new_view(root) end end - -- create a new radiation monitor list - ---@param parent Container - ---@param ps psil - local function new_mon_list(parent, ps) - local mon_list = ListBox{parent=parent,y=6,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} + -- create indicators for the ID, firmware, and RTT + ---@param pfx string + ---@param rect Rectangle + local function create_common_indicators(pfx, rect) + TextBox{parent=rect,text="Computer ID",fg_bg=label_fg_bg} + TextBox{parent=rect,text="Firmware",fg_bg=label_fg_bg} + TextBox{parent=rect,text="Round-Trip Time",fg_bg=label_fg_bg} + local addr = TextBox{parent=rect,x=13,y=2,text="---"} + local fw = TextBox{parent=rect,x=13,y=3,text="---"} + local rtt = TextBox{parent=rect,x=13,y=3,text="---"} - local elem_list = {} ---@type graphics_element[] + addr.register(f_ps, pfx .. "_addr", addr.set_value) + fw.register(f_ps, pfx .. "_fw", fw.set_value) - mon_list.register(ps, "radiation_monitors", function (data) - local ids = textutils.unserialize(data) + rtt.register(f_ps, pfx.. "_rtt", function (value) + rtt.set_value(rtt) - -- delete any disconnected monitors - for id, elem in pairs(elem_list) do - if not util.table_contains(ids, id) then - elem.delete() - elem_list[id] = nil - end - end - - -- add newly connected monitors - for _, id in pairs(ids) do - if not elem_list[id] then - elem_list[id] = Div{parent=mon_list,height=5} - local mon_rect = Rectangle{parent=elem_list[id],height=4,x=2,width=20,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} - - TextBox{parent=mon_rect,text="Env. Detector "..id} - local mon_rad = RadIndicator{parent=mon_rect,x=2,label="",format="%13.3f",lu_colors=cpair(colors.gray,colors.gray),width=18} - mon_rad.register(ps, "radiation@" .. id, mon_rad.update) - end + if value > HIGH_RTT then + rtt.recolor(colors.red) + elseif value > WARN_RTT then + rtt.recolor(colors.yellow) + else + rtt.recolor(colors.green) end end) end --#region main computer page - local m_pane = panes[1] - local m_div = Div{parent=m_pane,x=2,width=main.get_width()-2} + local m_div = Div{parent=panes[1],x=2,width=main.get_width()-2} local main_page = app.new_page(nil, 1) main_page.tasks = { update } @@ -142,16 +138,9 @@ local function new_view(root) local crd_rect = Rectangle{parent=crd_div,height=6,x=2,width=21,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} TextBox{parent=crd_rect,text="Coordinator"} - local crd_online = TextBox{parent=svr_rect,x=12,y=1,width=7,text="Online",fg_bg=cpair(colors.green,colors._INHERIT)} - TextBox{parent=crd_rect,text="Computer ID",fg_bg=label_fg_bg} - TextBox{parent=crd_rect,text="Firmware",fg_bg=label_fg_bg} - TextBox{parent=crd_rect,text="Round-Trip Time",fg_bg=label_fg_bg} - local crd_addr = TextBox{parent=svr_rect,x=13,y=2,text="---"} - local crd_fw = TextBox{parent=svr_rect,x=13,y=3,text="---"} - local crd_rtt = TextBox{parent=svr_rect,x=13,y=3,text="---"} + local crd_online = TextBox{parent=crd_rect,x=12,y=1,width=7,text="Online",fg_bg=cpair(colors.green,colors._INHERIT)} - crd_addr.register(f_ps, "comp_crd_addr", crd_addr.set_value) - crd_fw.register(f_ps, "comp_crd_fw", crd_fw.set_value) + create_common_indicators("comp_crd", crd_rect) crd_online.register(f_ps, "comp_crd_online", function (online) if online then @@ -163,39 +152,95 @@ local function new_view(root) end end) - crd_rtt.register(f_ps, "comp_crd_rtt", function (rtt) - crd_rtt.set_value(rtt) + --#endregion - if type(rtt) ~= "number" then - crd_rtt.recolor(label_fg_bg.fgd) - else - if rtt > HIGH_RTT then - crd_rtt.recolor(colors.red) - elseif rtt > WARN_RTT then - crd_rtt.recolor(colors.yellow) - else - crd_rtt.recolor(colors.green) - end - end - end) + --#region PLC page + + local p_div = Div{parent=panes[2],width=main.get_width()} + + local plc_page = app.new_page(nil, 2) + plc_page.tasks = { update } + + TextBox{parent=p_div,y=1,text="PLC Devices",alignment=ALIGN.CENTER} + + local plc_list = ListBox{parent=p_div,y=6,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} + local plc_elems = {} ---@type graphics_element[] --#endregion - --#region overview page + --#region RTU page - local f_pane = panes[db.facility.num_units + 2] - local f_div = Div{parent=f_pane,width=main.get_width()} + local r_div = Div{parent=panes[2],width=main.get_width()} - local fac_page = app.new_page(nil, db.facility.num_units + 2) - fac_page.tasks = { update } + local rtu_page = app.new_page(nil, 3) + rtu_page.tasks = { update } - TextBox{parent=f_div,y=1,text="Facility Monitors",alignment=ALIGN.CENTER} + TextBox{parent=r_div,y=1,text="RTU Gateway Devices",alignment=ALIGN.CENTER} - TextBox{parent=f_div,x=2,y=3,text="Max Radiation",fg_bg=label_fg_bg} - local f_rad = RadIndicator{parent=f_div,x=2,label="",format="%17.3f",lu_colors=lu_col,width=21} - f_rad.register(f_ps, "radiation", f_rad.update) + local rtu_list = ListBox{parent=p_div,y=6,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} + local rtu_elems = {} ---@type graphics_element[] - new_mon_list(f_div, f_ps) + --#endregion + + --#region RTU page + + local pk_div = Div{parent=panes[2],width=main.get_width()} + + local pkt_page = app.new_page(nil, 4) + pkt_page.tasks = { update } + + TextBox{parent=pk_div,y=1,text="Pocket Devices",alignment=ALIGN.CENTER} + + local pkt_list = ListBox{parent=p_div,y=6,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} + local pkt_elems = {} ---@type graphics_element[] + + --#endregion + + --#region connect/disconnect management + + f_ps.subscribe("comp_connect", function (id) + local pfx = "comp_" .. id + local type = f_ps.get(pfx .. "_type") + + if type == DEV_TYPE.PLC then + plc_elems[id] = Div{parent=plc_list,height=5} + local rect = Rectangle{parent=plc_elems[id],height=6,x=2,width=20,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} + + local title = TextBox{parent=rect,text="PLC (Unit ?) @ "..id} + title.register(f_ps, pfx .. "_unit", function (unit) title.set_value("PLC (Unit " .. unit .. ") @ " .. id) end) + + create_common_indicators(pfx, rect) + elseif type == DEV_TYPE.RTU then + rtu_elems[id] = Div{parent=rtu_list,height=5} + local rect = Rectangle{parent=rtu_elems[id],height=6,x=2,width=20,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} + + TextBox{parent=rect,text="RTU Gateway @ "..id} + + create_common_indicators(pfx, rect) + elseif type == DEV_TYPE.PKT then + pkt_elems[id] = Div{parent=pkt_list,height=5} + local rect = Rectangle{parent=pkt_elems[id],height=6,x=2,width=20,border=border(1,colors.gray,true),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} + + TextBox{parent=rect,text="Pocket @ "..id} + + create_common_indicators(pfx, rect) + end + end) + + f_ps.subscribe("comp_disconnect", function (id) + local type = f_ps.get("comp_" ..id .. "_type") + + if type == DEV_TYPE.PLC then + if plc_elems[id] then plc_elems[id].delete() end + plc_elems[id] = nil + elseif type == DEV_TYPE.RTU then + if rtu_elems[id] then rtu_elems[id].delete() end + rtu_elems[id] = nil + elseif type == DEV_TYPE.PKT then + if pkt_elems[id] then pkt_elems[id].delete() end + pkt_elems[id] = nil + end + end) --#endregion diff --git a/supervisor/session/pocket.lua b/supervisor/session/pocket.lua index b229286..a47b1cf 100644 --- a/supervisor/session/pocket.lua +++ b/supervisor/session/pocket.lua @@ -199,7 +199,7 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, for i = 1, #facility.get_units() do local tag = "plc_" .. i if read(tag .. "_conn") then - table.insert(devices, { DEV_TYPE.CRD, read(tag .. "_addr"), read(tag .. "_fw"), read(tag .. "_rtt") }) + table.insert(devices, { DEV_TYPE.CRD, read(tag .. "_addr"), read(tag .. "_fw"), read(tag .. "_rtt"), i }) end end