diff --git a/pocket/iocontrol.lua b/pocket/iocontrol.lua index 67ea84c..9ff06a4 100644 --- a/pocket/iocontrol.lua +++ b/pocket/iocontrol.lua @@ -64,6 +64,7 @@ function iocontrol.alloc_nav() pane = nil, ---@type graphics_element apps = {}, containers = {}, + help_map = {}, cur_app = APP_ID.ROOT } @@ -181,9 +182,6 @@ function iocontrol.alloc_nav() return app end - -- get a list of the app containers (usually Div elements) - function io.nav.get_containers() return self.containers end - -- open a given app ---@param app_id POCKET_APP_ID function io.nav.open_app(app_id) @@ -202,6 +200,9 @@ function iocontrol.alloc_nav() end end + -- get a list of the app containers (usually Div elements) + function io.nav.get_containers() return self.containers end + -- get the currently active page ---@return nav_tree_page function io.nav.get_current_page() @@ -218,6 +219,15 @@ function iocontrol.alloc_nav() io.nav.open_app(APP_ID.ROOT) end end + + function io.nav.open_help(key) + io.nav.open_app(APP_ID.GUIDE) + + local load = self.help_map[key] + if load then load() end + end + + function io.nav.link_help(map) self.help_map = map end end -- initialize facility-independent components of pocket iocontrol diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index 1d0a0a6..5d5b4ed 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -10,6 +10,8 @@ local iocontrol = require("pocket.iocontrol") local docs = require("pocket.ui.docs") local style = require("pocket.ui.style") +local guide_section = require("pocket.ui.pages.guide_section") + local core = require("graphics.core") local Div = require("graphics.elements.div") @@ -40,6 +42,7 @@ local function new_view(root) local btn_fg_bg = cpair(colors.cyan, colors.black) local btn_active = cpair(colors.white, colors.black) + local btn_disable = cpair(colors.gray, colors.black) local list = { { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = function () db.nav.open_app(iocontrol.APP_ID.ROOT) end }, @@ -68,6 +71,10 @@ local function new_view(root) local panes = { home, use, uis, fps, gls } local doc_map = {} + local search_map = {} + + ---@class _guide_section_constructor_data + local sect_construct_data = { app, page_div, panes, doc_map, search_map, btn_fg_bg, btn_active } TextBox{parent=home,y=1,text="cc-mek-scada Guide",height=1,alignment=ALIGN.CENTER} @@ -77,117 +84,65 @@ local function new_view(root) PushButton{parent=home,text="Glossary >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=gls_page.nav_to} TextBox{parent=use,y=1,text="System Usage",height=1,alignment=ALIGN.CENTER} - PushButton{parent=use,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} - PushButton{parent=use,y=3,text="Configuring Devices >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()end} - PushButton{parent=use,text="Connecting Devices >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()end} - PushButton{parent=use,text="Manual Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()end} - PushButton{parent=use,text="Automatic Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()end} - PushButton{parent=use,text="Waste Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()end} + PushButton{parent=use,y=3,text="Configuring Devices >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + PushButton{parent=use,text="Connecting Devices >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + PushButton{parent=use,text="Manual Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + PushButton{parent=use,text="Automatic Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + PushButton{parent=use,text="Waste Control >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() TextBox{parent=uis,y=1,text="Operator UIs",height=1,alignment=ALIGN.CENTER} - PushButton{parent=uis,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} - local alarms_page = app.new_page(uis_page, #panes + 1) - local alarms_div = Div{parent=page_div,x=2} - table.insert(panes, alarms_div) - local annunc_page = app.new_page(uis_page, #panes + 1) local annunc_div = Div{parent=page_div,x=2} table.insert(panes, annunc_div) + local alarms_page = guide_section(sect_construct_data, uis_page, "Alarms", docs.alarms) + PushButton{parent=uis,y=3,text="Alarms >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=alarms_page.nav_to} PushButton{parent=uis,text="Annunciators >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=annunc_page.nav_to} - PushButton{parent=uis,text="Pocket UI >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()end} - PushButton{parent=uis,text="Coordinator UI >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()end} + PushButton{parent=uis,text="Pocket UI >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + PushButton{parent=uis,text="Coordinator UI >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + + TextBox{parent=annunc_div,y=1,text="Annunciators",height=1,alignment=ALIGN.CENTER} + PushButton{parent=annunc_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=uis_page.nav_to} + + local unit_gen_page = guide_section(sect_construct_data, annunc_page, "Unit General", docs.annunc.unit.main_section) + local unit_rps_page = guide_section(sect_construct_data, annunc_page, "Unit RPS", docs.annunc.unit.rps_section) + local unit_rcs_page = guide_section(sect_construct_data, annunc_page, "Unit RCS", docs.annunc.unit.rcs_section) + + PushButton{parent=annunc_div,y=3,text="Unit General >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=unit_gen_page.nav_to} + PushButton{parent=annunc_div,text="Unit RPS >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=unit_rps_page.nav_to} + PushButton{parent=annunc_div,text="Unit RCS >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=unit_rcs_page.nav_to} + PushButton{parent=annunc_div,text="Facility General >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + PushButton{parent=annunc_div,text="Waste & Valves >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() TextBox{parent=fps,y=1,text="Front Panels",height=1,alignment=ALIGN.CENTER} - PushButton{parent=fps,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} - PushButton{parent=fps,y=3,text="Common Items >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()end} - PushButton{parent=fps,text="Reactor PLC >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()end} - PushButton{parent=fps,text="RTU Gateway >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()end} - PushButton{parent=fps,text="Supervisor >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()end} - PushButton{parent=fps,text="Coordinator >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()end} + PushButton{parent=fps,y=3,text="Common Items >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + PushButton{parent=fps,text="Reactor PLC >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + PushButton{parent=fps,text="RTU Gateway >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + PushButton{parent=fps,text="Supervisor >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() + PushButton{parent=fps,text="Coordinator >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,dis_fg_bg=btn_disable,callback=function()end}.disable() TextBox{parent=gls,y=1,text="Glossary",height=1,alignment=ALIGN.CENTER} PushButton{parent=gls,x=3,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to} - local gls_abb_page = app.new_page(gls_page, #panes + 1) - local gls_abb_div = Div{parent=page_div,x=2} - table.insert(panes, gls_abb_div) - TextBox{parent=gls_abb_div,y=1,text="Abbreviations",height=1,alignment=ALIGN.CENTER} - PushButton{parent=gls_abb_div,x=3,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=gls_page.nav_to} + local gls_abbv_page = guide_section(sect_construct_data, gls_page, "Abbreviations", docs.glossary.abbvs) + local gls_term_page = guide_section(sect_construct_data, gls_page, "Terminology", docs.glossary.terms) - local gls_abb_view_page = app.new_page(gls_abb_page, #panes + 1) - local gls_abb_view_div = Div{parent=page_div,x=2} - table.insert(panes, gls_abb_view_div) - TextBox{parent=gls_abb_view_div,y=1,text="Abbreviations",height=1,alignment=ALIGN.CENTER} - PushButton{parent=gls_abb_view_div,x=3,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=gls_abb_page.nav_to} - - local gls_term_page = app.new_page(gls_page, #panes + 1) - local gls_term_div = Div{parent=page_div,x=2} - table.insert(panes, gls_term_div) - TextBox{parent=gls_term_div,y=1,text="Terminology",height=1,alignment=ALIGN.CENTER} - PushButton{parent=gls_term_div,x=3,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=gls_page.nav_to} - - local gls_term_view_page = app.new_page(gls_term_page, #panes + 1) - local gls_term_view_div = Div{parent=page_div,x=2} - table.insert(panes, gls_term_view_div) - TextBox{parent=gls_term_view_div,y=1,text="Terminology",height=1,alignment=ALIGN.CENTER} - PushButton{parent=gls_term_view_div,x=3,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=gls_term_page.nav_to} - - PushButton{parent=gls,y=3,text="Abbreviations >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=gls_abb_page.nav_to} + PushButton{parent=gls,y=3,text="Abbreviations >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=gls_abbv_page.nav_to} PushButton{parent=gls,text="Terminology >",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=gls_term_page.nav_to} - local abb_name_list = ListBox{parent=gls_abb_div,x=1,y=3,scroll_height=20,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} - local abb_def_list = ListBox{parent=gls_abb_view_div,x=1,y=3,scroll_height=101,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} - - local _end = nil - - for i = 1, #docs.glossary.abbvs do - local item = docs.glossary.abbvs[i] ---@type pocket_doc_item - - doc_map[item.key] = TextBox{parent=abb_def_list,text=item.name,anchor=true,fg_bg=cpair(colors.blue,colors.black)} - TextBox{parent=abb_def_list,text=item.desc,fg_bg=label} - _end = Div{parent=abb_def_list,height=1,can_focus=true} - - local function view() - _end.focus() - gls_abb_view_page.nav_to() - doc_map[item.key].focus() - end - - PushButton{parent=abb_name_list,text=item.name,fg_bg=cpair(colors.blue,colors.black),active_fg_bg=btn_active,callback=view} - end - - local term_name_list = ListBox{parent=gls_term_div,x=1,y=3,scroll_height=20,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} - local term_def_list = ListBox{parent=gls_term_view_div,x=1,y=3,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} - - local _end_b = nil - - for i = 1, #docs.glossary.terms do - local item = docs.glossary.terms[i] ---@type pocket_doc_item - - doc_map[item.key] = TextBox{parent=term_def_list,text=item.name,anchor=true,fg_bg=cpair(colors.blue,colors.black)} - TextBox{parent=term_def_list,text=item.desc,fg_bg=label} - _end_b = Div{parent=term_def_list,height=1,can_focus=true} - - local function view() - _end_b.focus() - gls_term_view_page.nav_to() - doc_map[item.key].focus() - end - - PushButton{parent=term_name_list,text=item.name,fg_bg=cpair(colors.blue,colors.black),active_fg_bg=btn_active,callback=view} - end - -- setup multipane local u_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes} app.set_root_pane(u_pane) + + -- link help resources + db.nav.link_help(doc_map) end app.set_on_load(load) diff --git a/pocket/ui/docs.lua b/pocket/ui/docs.lua index 50e20fa..24090ec 100644 --- a/pocket/ui/docs.lua +++ b/pocket/ui/docs.lua @@ -50,9 +50,32 @@ doc("HighStartupRate", "Startup Rate High", "This is a rough calculation of if y target = docs.annunc.unit.rps_section doc("rps_tripped", "RPS Trip", "Indicates if the reactor protection system has caused a SCRAM.") +doc("manual", "Manual Reactor SCRAM", "Indicates if the operator (you) tripped the RPS by pressing SCRAM.") +doc("automatic", "Auto Reactor SCRAM", "Indicates if the automatic control system tripped the RPS.") +doc("sys_fail", "System Failure", "Indicates if the RPS tripped due to the reactor not being formed.") doc("high_dmg", "Damage Level High", "Indicates if the RPS tripped due to significant reactor damage.") +doc("ex_waste", "Excess Waste", "Indicates if the RPS tripped due to very high waste levels.") +doc("ex_hcool", "Excess Heated Coolant", "Indicates if the RPS tripped due to very high waste levels.") +doc("high_temp", "Temperature High", "Indicates if the RPS tripped due to reaching damaging temperatures.") +doc("low_cool", "Coolant Level Low Low", "Indicates if the RPS tripped due to very low coolant levels that result in the temperature uncontrollably rising.") +doc("no_fuel", "No Fuel", "Indicates if the RPS tripped due to no fuel being available.") +doc("fault", "PPM Fault", "Indicates if the RPS tripped due to a peripheral access fault.") +doc("timeout", "Connection Timeout", "Indicates if the RPS tripped due to losing connection with the supervisory computer.") +doc("sys_fail", "System Failure", "Indicates if the RPS tripped due to the reactor not being formed.") -target = docs.annunc.unit.main_section +target = docs.annunc.unit.rcs_section +doc("RCSFault", "RCS Hardware Fault", "Indicates if one or more of the RCS devices have a peripheral fault.") +doc("EmergencyCoolant", "Emergency Coolant", "Off if no emergency coolant redstone is configured, white when it is configured but not in use, and green/blue when it is activated.") +doc("CoolantFeedMismatch", "Coolant Feed Mismatch", "The coolant system is accumulating heated coolant or losing cooled coolant, likely due to one of the machines not keeping up with the needs of the reactor.") +doc("BoilRateMismatch", "Boil Rate Mismatch", "The total heating rate of the reactor is more than 4% off from the steam input rate of the turbines OR for sodium setups, the boiler boil rates are more than 4% off from the steam input rate of the turbines.") +doc("SteamFeedMismatch", "Steam Feed Mismatch", "There is an above tolerance difference between turbine flow and steam input rates or the reactor/boilers are gaining steam or losing water.") +doc("MaxWaterReturnFeed", "Max Water Return Feed", "The turbines are condensing the max rate of water that they can per the structure build.") +doc("WaterLevelLow", "Water Level Low", "The water level in the boiler is low.") +doc("HeatingRateLow", "Heating Rate Low", "The boiler is not hot enough to boil water, but it is receiving heated coolant.") +doc("SteamDumpOpen", "Steam Relief Valve Open", "This turns yellow if the turbine is set to dumping excess and red if it is set to dumping all. 'Relief Valve' in this case is that setting allowing the venting of steam.") +doc("TurbineOverSpeed", "Turbine Over Speed", "The turbine is at steam capacity, but not tripped. You may need more turbines if they can't keep up.") +doc("GeneratorTrip", "Generator Trip", "The turbine is no longer outputting power due to it having nowhere to go. Likely due to full power storage.") +doc("TurbineTrip", "Turbine Trip", "The turbine has reached its maximum power charge and has stopped rotating, and as a result stopped cooling steam to water.") docs.glossary = { abbvs = {}, terms = {} @@ -62,6 +85,7 @@ target = docs.glossary.abbvs doc("G_ACK", "ACK", "Alarm ACKnowledge. This indicates you understand an alarm occured and would like to stop the audio tone(s).") doc("G_CRD", "CRD", "Coordinator. Abbreviation for the coordinator computer.") doc("G_DBG", "DBG", "Debug. Abbreviation for the debugging sessions from pocket computers found on the supervisor's front panel.") +doc("G_FP", "FP", "Front Panel. See Terminology.") doc("G_PKT", "PKT", "Pocket. Abbreviation for the pocket computer.") doc("G_PLC", "PLC", "Programmable Logic Controller. A device that not only reports data and controls outputs, but also can make decisions on its own.") doc("G_PPM", "PPM", "Protected Peripheral Manager. This is an abstraction layer created for this project that prevents peripheral calls from crashing applications.") @@ -71,6 +95,7 @@ doc("G_RPS", "RPS", "Reactor Protection System. A component of the reactor PLC r doc("G_RTU", "RTU", "Remote Terminal Unit. Provides monitoring to and basic output from a SCADA system, interfacing with various types of devices/controls.") doc("G_SCADA", "SCADA", "Supervisory Control and Data Acquisition. A control systems architecture used in many different process control applications.") doc("G_SVR", "SVR", "Supervisor. Abbreviation for the supervisory computer.") +doc("G_UI", "UI", "User Interface.") target = docs.glossary.terms doc("G_Fault", "Fault", "Something has gone wrong and/or failed to function.") diff --git a/pocket/ui/pages/guide_section.lua b/pocket/ui/pages/guide_section.lua new file mode 100644 index 0000000..344f6c7 --- /dev/null +++ b/pocket/ui/pages/guide_section.lua @@ -0,0 +1,58 @@ +local core = require("graphics.core") + +local Div = require("graphics.elements.div") +local ListBox = require("graphics.elements.listbox") +local TextBox = require("graphics.elements.textbox") + +local PushButton = require("graphics.elements.controls.push_button") + +local ALIGN = core.ALIGN +local cpair = core.cpair + +-- new guide documentation section +---@param data _guide_section_constructor_data +---@param base_page nav_tree_page +---@param title string +---@param items table +---@return nav_tree_page +return function (data, base_page, title, items) + local app, page_div, panes, doc_map, search_map, btn_fg_bg, btn_active = table.unpack(data) + + local section_page = app.new_page(base_page, #panes + 1) + local gls_term_div = Div{parent=page_div,x=2} + table.insert(panes, gls_term_div) + TextBox{parent=gls_term_div,y=1,text=title,height=1,alignment=ALIGN.CENTER} + PushButton{parent=gls_term_div,x=3,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=base_page.nav_to} + + local gls_term_view_page = app.new_page(section_page, #panes + 1) + local gls_term_view_div = Div{parent=page_div,x=2} + table.insert(panes, gls_term_view_div) + TextBox{parent=gls_term_view_div,y=1,text=title,height=1,alignment=ALIGN.CENTER} + PushButton{parent=gls_term_view_div,x=3,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=section_page.nav_to} + + local name_list = ListBox{parent=gls_term_div,x=1,y=3,scroll_height=30,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} + local def_list = ListBox{parent=gls_term_view_div,x=1,y=3,scroll_height=120,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)} + + local _end = nil + + for i = 1, #items do + local item = items[i] ---@type pocket_doc_item + + local anchor = TextBox{parent=def_list,text=item.name,anchor=true,fg_bg=cpair(colors.blue,colors.black)} + TextBox{parent=def_list,text=item.desc} + _end = Div{parent=def_list,height=1,can_focus=true} + + local function view() + _end.focus() + gls_term_view_page.nav_to() + anchor.focus() + end + + doc_map[item.key] = view + search_map[item.name] = view + + PushButton{parent=name_list,text=item.name,fg_bg=cpair(colors.blue,colors.black),active_fg_bg=btn_active,callback=view} + end + + return section_page +end