Compare commits

...

65 Commits

Author SHA1 Message Date
Mikayla Fischler
4f71fb91b8 Merge branch 'devel' into 346-non-linear-ramp-option 2026-02-18 22:56:26 -05:00
Mikayla
1ae37f53c0 Merge pull request #692 from MikaylaFischler/570-range-based-operation
570 range based operation
2026-02-18 22:48:05 -05:00
Mikayla Fischler
dcd04b36c2 Merge branch '570-range-based-operation' of github.com:MikaylaFischler/cc-mek-scada into 570-range-based-operation 2026-02-18 22:42:14 -05:00
Mikayla Fischler
e73a0a2d5b still publish default process parameters if none are found in settings 2026-02-18 22:42:04 -05:00
Mikayla
d35f43d575 #570 updated default range values on supervisor to match coordinator 2026-02-17 17:06:40 +00:00
Mikayla
3bf7f9cbd8 #570 edge case fixes 2026-02-17 17:05:25 +00:00
Mikayla
5e58d7482f #570 comment fixes and cleanup 2026-02-17 17:04:44 +00:00
Mikayla Fischler
83adad1ef6 #570 updated pocket docs for charge range control 2026-02-16 22:08:44 -05:00
Mikayla Fischler
7973d80486 #570 fixed bug with range control mode not using the right data 2026-02-16 18:45:07 -05:00
Mikayla Fischler
6dcb6febdf #570 enable/disable mode switch button 2026-02-16 18:44:42 -05:00
Mikayla Fischler
5d90f879db #507 properly enable/disable range settings in pocket
process app
2026-02-16 18:44:22 -05:00
Mikayla Fischler
522292d5df changed pocket to just change range control value on other input rather than setting min/max 2026-02-14 13:31:17 -05:00
Mikayla Fischler
9b3842345c enforce start less than stop on range control automatically 2026-02-14 13:29:34 -05:00
Mikayla Fischler
8bfd218fef added callback to numeric spinbox element 2026-02-14 13:28:48 -05:00
Mikayla Fischler
2e423e641b #570 pocket version bump 2026-02-14 13:17:29 -05:00
Mikayla Fischler
ba1909e13f #570 GUI updates to pocket process app for range control 2026-02-14 13:16:10 -05:00
Mikayla Fischler
2abd212f28 added on unfocus to form fields 2026-02-14 13:15:41 -05:00
Mikayla
308308d56f pocket code refactors for code size 2026-02-14 00:03:31 +00:00
Mikayla
99239a135a #570 pocket range control 2026-02-14 00:03:02 +00:00
Mikayla
1dbc89d4ce #570 supervisor range control mode 2026-02-13 20:02:12 +00:00
Mikayla
7ca0e9481d #570 exchange of range control settings with supervisor 2026-02-13 19:36:35 +00:00
Mikayla Fischler
8781a063e6 #570 fixes to GUI, automatically sync modes, overwrite invalid start/stop values before saving/applying 2026-02-10 21:51:43 -05:00
Mikayla
50f830efa3 #570 GUI and saving of settings for range control mode 2026-02-10 21:46:18 +00:00
Mikayla
a5b134d446 updated switchbutton to support disabling and call the callback when changing the value with set_value 2026-02-10 21:44:44 +00:00
Mikayla Fischler
0a6e33ac17 #570 toggle button for charge target/range 2026-02-08 22:57:27 -05:00
Mikayla Fischler
3e018aa412 added alternate text to switch buttons when pressed 2026-02-08 22:57:12 -05:00
Mikayla Fischler
b51a0d68e7 #346 only use fast ramp when configured to 2026-02-07 22:26:41 -05:00
Mikayla Fischler
cdddb4d5c4 #346 plc configurator bug fixes 2026-02-07 22:23:56 -05:00
Mikayla Fischler
2f7a227ee8 #346 updated configurator messages and fixed confirmation logic 2026-02-07 22:20:14 -05:00
Mikayla
36d40b7f3e #346 configurator option for fast ramp 2026-02-07 22:30:56 +00:00
Mikayla
b573c3cdbd #346 corrected fast ramp timescale 2026-02-07 22:04:41 +00:00
Mikayla
3c5959caa9 #346 ramp down 2026-02-07 22:04:23 +00:00
Mikayla
3eefac4551 typo fixes 2026-02-02 18:29:23 +00:00
Mikayla Fischler
e84737f4fe #346 fixed incorrect minimum step value 2026-02-01 19:38:55 -05:00
Mikayla Fischler
a76afe9a5f #346 bugfixes 2026-02-01 19:21:33 -05:00
Mikayla Fischler
69741bf228 raised aux cool enable threshold to 85% from 60% 2026-01-31 23:33:24 -05:00
Mikayla Fischler
1771cc5b08 #346 SPCTL cleanup, comments, optimizations 2026-01-31 23:29:32 -05:00
Mikayla Fischler
d63b2d935b #346 safe fast ramp using coolant fill percentage as a slowing factor when needed 2026-01-31 19:00:57 -05:00
Mikayla Fischler
d6bd995c3a #346 monitor fill percent instead of value 2026-01-31 19:00:00 -05:00
Mikayla Fischler
02c4f3d782 #346 use coolant level delta in rate limiting 2026-01-19 13:50:48 -05:00
Mikayla Fischler
5f0019e803 #346 fixed crashes and added debug messages 2026-01-19 13:50:31 -05:00
Mikayla Fischler
15d7891b99 #346 initial WIP of PLC ramping rework 2025-12-30 18:32:22 -05:00
Mikayla Fischler
962807154d #346 moved setpoint controller to a new file 2025-12-28 14:23:38 -05:00
Mikayla Fischler
28e87fd8fa luacheck fix and moved some defines out of thread loops due to prior changes in init 2025-12-28 13:46:50 -05:00
Mikayla Fischler
bc83a1b577 #676 reworked enabled state tracking logic, removed scram on formed/reconnected 2025-12-27 16:54:07 -05:00
Mikayla
d408ca8748 Merge pull request #685 from MikaylaFischler/675-refactor-io-control-object-and-types
675 refactor io control object and types
2025-12-27 16:02:12 -05:00
Mikayla Fischler
ee29fbc4b6 version increments 2025-12-26 18:43:16 -05:00
Mikayla Fischler
f3dfcbd0cb #675 pocket io refactors 2025-12-26 18:42:54 -05:00
Mikayla Fischler
b9b7b323dc #675 coordinator io refactors 2025-12-26 17:36:41 -05:00
Mikayla
fb5f339204 Merge pull request #684 from MikaylaFischler/683-update-pocket-guide-app
#683 updated guide app for comms and other front panel changes
2025-12-26 16:50:01 -05:00
Mikayla Fischler
b39d52606c #683 increased common fp doc section height, added more led lists 2025-12-26 16:49:18 -05:00
Mikayla
88975add1b #683 updated guide app for comms and other front panel changes 2025-12-24 21:42:26 +00:00
Mikayla Fischler
30eb757889 #682 fixed RTU gateway configurator all_waste not showing unit ID 2025-12-20 19:01:21 -05:00
Mikayla
dd11afe5cb Merge pull request #678 from MikaylaFischler/672-remove-redundant-x1-from-graphics-object-creation
672 removed redundant x=1's
2025-12-19 15:28:58 -05:00
Mikayla Fischler
18cadcf8ca incremented versions 2025-12-19 15:15:24 -05:00
Mikayla Fischler
dfda8b5d1a Merge branch 'devel' into 672-remove-redundant-x1-from-graphics-object-creation 2025-12-19 15:14:40 -05:00
Mikayla
8929786315 Merge pull request #679 from MikaylaFischler/673-close-always-broadcasts
673 send close before calling unlink()
2025-12-19 15:13:16 -05:00
Mikayla Fischler
1aafa8b574 version increments 2025-12-19 15:10:07 -05:00
Mikayla Fischler
6272473c95 Merge branch 'devel' into 673-close-always-broadcasts 2025-12-19 15:09:19 -05:00
Mikayla
311b8d19d1 Merge pull request #677 from MikaylaFischler/671-optimize-event-loop-ordering
671 optimize event loop ordering
2025-12-19 15:08:15 -05:00
Mikayla
d80c7a5826 Merge branch 'devel' into 671-optimize-event-loop-ordering 2025-12-19 15:07:54 -05:00
Mikayla
25d31b8a0c #673 send close before calling unlink() 2025-12-15 22:20:35 +00:00
Mikayla
6399301f9c #672 removed redundant x=1's 2025-12-15 22:17:27 +00:00
Mikayla
d65750c282 #671 moved peripheral event checks to before peripheral_detach event checks 2025-12-15 21:37:47 +00:00
Mikayla
d3d62fb924 #671 re-ordered event handlers to have most common events first, moved main loop tasks to functions 2025-12-15 21:36:42 +00:00
92 changed files with 2341 additions and 1848 deletions

View File

@@ -8,7 +8,7 @@ local ppm = require("scada-common.ppm")
local util = require("scada-common.util")
local coordinator = require("coordinator.coordinator")
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local sounder = require("coordinator.sounder")
local println = util.println
@@ -84,7 +84,7 @@ function backplane.init_displays(config)
log.info("BKPLN: DISPLAY LINK_" .. util.trinary(disp, "UP", "DOWN") .. " MAIN/" .. iface)
iocontrol.fp_monitor_state("main", util.trinary(disp, 2, 1))
ioctl.fp_monitor_state("main", util.trinary(disp, 2, 1))
if not disp then
return false, "Main monitor is not connected."
@@ -107,7 +107,7 @@ function backplane.init_displays(config)
log.info("BKPLN: DISPLAY LINK_" .. util.trinary(disp, "UP", "DOWN") .. " FLOW/" .. iface)
iocontrol.fp_monitor_state("flow", util.trinary(disp, 2, 1))
ioctl.fp_monitor_state("flow", util.trinary(disp, 2, 1))
if not disp then
return false, "Flow monitor is not connected."
@@ -131,7 +131,7 @@ function backplane.init_displays(config)
log.info("BKPLN: DISPLAY LINK_" .. util.trinary(disp, "UP", "DOWN") .. " UNIT_" .. i .. "/" .. iface)
iocontrol.fp_monitor_state(i, util.trinary(disp, 2, 1))
ioctl.fp_monitor_state(i, util.trinary(disp, 2, 1))
if not disp then
return false, "Unit " .. i .. " monitor is not connected."
@@ -176,7 +176,7 @@ function backplane.init(config, __shared_memory)
wd_nic.closeAll()
wd_nic.open(config.CRD_Channel)
iocontrol.fp_has_wd_modem(modem ~= nil)
ioctl.fp_has_wd_modem(modem ~= nil)
end
-- init wireless NIC(s)
@@ -199,7 +199,7 @@ function backplane.init(config, __shared_memory)
wl_nic.closeAll()
wl_nic.open(config.CRD_Channel)
iocontrol.fp_has_wl_modem(modem ~= nil)
ioctl.fp_has_wl_modem(modem ~= nil)
end
-- at least one comms modem is required
@@ -231,7 +231,7 @@ function backplane.init(config, __shared_memory)
log_boot("tone generation took " .. (util.time_ms() - sounder_start) .. "ms")
log_sys("annunciator alarm configured")
iocontrol.fp_has_speaker(true)
ioctl.fp_has_speaker(true)
end
return true
@@ -252,8 +252,8 @@ function backplane.displays() return _bp.displays end
-- periodic backplane peripheral tasks
function backplane.periodic()
if _bp.wd_nic then iocontrol.fp_has_wd_net(_bp.wd_nic.periodic()) end
if _bp.wl_nic then iocontrol.fp_has_wl_net(_bp.wl_nic.periodic()) end
if _bp.wd_nic then ioctl.fp_has_wd_net(_bp.wd_nic.periodic()) end
if _bp.wl_nic then ioctl.fp_has_wl_net(_bp.wl_nic.periodic()) end
end
-- handle a backplane peripheral attach
@@ -282,7 +282,7 @@ function backplane.attach(type, device, iface)
log.info("BKPLN: WIRED PHY_UP " .. iface)
log_sys("wired comms modem reconnected")
iocontrol.fp_has_wd_modem(true)
ioctl.fp_has_wd_modem(true)
if (_bp.act_nic ~= wd_nic) and not _bp.wlan_pref then
-- switch back to preferred wired
@@ -299,7 +299,7 @@ function backplane.attach(type, device, iface)
log.info("BKPLN: WIRELESS PHY_UP " .. iface)
log_sys("wireless comms modem reconnected")
iocontrol.fp_has_wl_modem(true)
ioctl.fp_has_wl_modem(true)
if (_bp.act_nic ~= wl_nic) and _bp.wlan_pref then
-- switch back to preferred wireless
@@ -333,14 +333,14 @@ function backplane.attach(type, device, iface)
_bp.displays.main = device
log.info("BKPLN: main display reconnected")
iocontrol.fp_monitor_state("main", 2)
ioctl.fp_monitor_state("main", 2)
elseif _bp.displays.flow_iface == iface then
is_used = true
_bp.displays.flow = device
log.info("BKPLN: flow display reconnected")
iocontrol.fp_monitor_state("flow", 2)
ioctl.fp_monitor_state("flow", 2)
else
for idx, monitor in ipairs(_bp.displays.unit_ifaces) do
if monitor == iface then
@@ -349,7 +349,7 @@ function backplane.attach(type, device, iface)
_bp.displays.unit_displays[idx] = device
log.info("BKPLN: unit " .. idx .. " display reconnected")
iocontrol.fp_monitor_state(idx, 2)
ioctl.fp_monitor_state(idx, 2)
break
end
end
@@ -371,7 +371,7 @@ function backplane.attach(type, device, iface)
log_sys("alarm sounder speaker reconnected")
iocontrol.fp_has_speaker(true)
ioctl.fp_has_speaker(true)
end
end
@@ -398,12 +398,12 @@ function backplane.detach(type, device, iface)
wd_nic.disconnect()
log.info("BKPLN: WIRED PHY_DOWN " .. iface)
iocontrol.fp_has_wd_modem(false)
ioctl.fp_has_wd_modem(false)
elseif wl_nic and wl_nic.is_modem(device) then
wl_nic.disconnect()
log.info("BKPLN: WIRELESS PHY_DOWN " .. iface)
iocontrol.fp_has_wl_modem(false)
ioctl.fp_has_wl_modem(false)
end
-- we only care if this is our active comms modem
@@ -424,7 +424,7 @@ function backplane.detach(type, device, iface)
log.info("BKPLN: WIRELESS PHY_UP " .. m_iface)
iocontrol.fp_has_wl_modem(true)
ioctl.fp_has_wl_modem(true)
elseif wd_nic and wd_nic.is_connected() then
_bp.act_nic = wd_nic
@@ -474,19 +474,19 @@ function backplane.detach(type, device, iface)
is_used = true
log.info("BKPLN: main display disconnected")
iocontrol.fp_monitor_state("main", 1)
ioctl.fp_monitor_state("main", 1)
elseif _bp.displays.flow == device then
is_used = true
log.info("BKPLN: flow display disconnected")
iocontrol.fp_monitor_state("flow", 1)
ioctl.fp_monitor_state("flow", 1)
else
for idx, monitor in pairs(_bp.displays.unit_displays) do
if monitor == device then
is_used = true
log.info("BKPLN: unit " .. idx .. " display disconnected")
iocontrol.fp_monitor_state(idx, 1)
ioctl.fp_monitor_state(idx, 1)
break
end
end
@@ -506,7 +506,7 @@ function backplane.detach(type, device, iface)
log_sys("alarm sounder speaker disconnected")
iocontrol.fp_has_speaker(false)
ioctl.fp_has_speaker(false)
end
end

View File

@@ -219,17 +219,17 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
local fac_c_2 = Div{parent=fac_cfg,x=2,y=4,width=49}
local fac_c_3 = Div{parent=fac_cfg,x=2,y=4,width=49}
local fac_pane = MultiPane{parent=fac_cfg,x=1,y=4,panes={fac_c_1,fac_c_2,fac_c_3}}
local fac_pane = MultiPane{parent=fac_cfg,y=4,panes={fac_c_1,fac_c_2,fac_c_3}}
TextBox{parent=fac_cfg,x=1,y=2,text=" Facility Configuration",fg_bg=cpair(colors.black,colors.yellow)}
TextBox{parent=fac_cfg,y=2,text=" Facility Configuration",fg_bg=cpair(colors.black,colors.yellow)}
TextBox{parent=fac_c_1,x=1,y=1,height=4,text="This tool can attempt to connect to your supervisor computer. This would load facility information in order to get the unit count and aid monitor setup."}
TextBox{parent=fac_c_1,x=1,y=6,height=2,text="The supervisor startup app must be running and fully configured on your supervisor computer."}
TextBox{parent=fac_c_1,y=1,height=4,text="This tool can attempt to connect to your supervisor computer. This would load facility information in order to get the unit count and aid monitor setup."}
TextBox{parent=fac_c_1,y=6,height=2,text="The supervisor startup app must be running and fully configured on your supervisor computer."}
self.sv_conn_status = TextBox{parent=fac_c_1,x=11,y=9,text=""}
self.sv_conn_detail = TextBox{parent=fac_c_1,x=1,y=11,height=2,text=""}
self.sv_conn_detail = TextBox{parent=fac_c_1,y=11,height=2,text=""}
self.sv_conn_button = PushButton{parent=fac_c_1,x=1,y=9,text="Connect",min_width=9,callback=function()sv_connect(tmp_cfg)end,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
self.sv_conn_button = PushButton{parent=fac_c_1,y=9,text="Connect",min_width=9,callback=function()sv_connect(tmp_cfg)end,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
local function sv_skip()
tcd.abort(handle_timeout)
@@ -244,15 +244,15 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
fac_pane.set_value(3)
end
PushButton{parent=fac_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_1,y=14,text="\x1b Back",callback=function()main_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
self.sv_skip = PushButton{parent=fac_c_1,x=44,y=14,text="Skip \x1a",callback=sv_skip,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
self.sv_next = PushButton{parent=fac_c_1,x=44,y=14,text="Next \x1a",callback=sv_next,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,hidden=true}
TextBox{parent=fac_c_2,x=1,y=1,height=3,text="Please enter the number of reactors you have, also referred to as reactor units or 'units' for short. A maximum of 4 is currently supported."}
tool_ctl.num_units = NumberField{parent=fac_c_2,x=1,y=5,width=5,max_chars=2,default=ini_cfg.UnitCount,min=1,max=4,fg_bg=bw_fg_bg}
TextBox{parent=fac_c_2,y=1,height=3,text="Please enter the number of reactors you have, also referred to as reactor units or 'units' for short. A maximum of 4 is currently supported."}
tool_ctl.num_units = NumberField{parent=fac_c_2,y=5,width=5,max_chars=2,default=ini_cfg.UnitCount,min=1,max=4,fg_bg=bw_fg_bg}
TextBox{parent=fac_c_2,x=7,y=5,text="reactors"}
TextBox{parent=fac_c_2,x=1,y=7,height=3,text="This will decide how many monitors you need. If this does not match the supervisor's number of reactor units, the coordinator will not connect.",fg_bg=cpair(colors.yellow,colors._INHERIT)}
TextBox{parent=fac_c_2,x=1,y=10,height=3,text="Since you skipped supervisor sync, the main monitor minimum height can't be determined precisely. It is marked with * on the next page.",fg_bg=g_lg_fg_bg}
TextBox{parent=fac_c_2,y=7,height=3,text="This will decide how many monitors you need. If this does not match the supervisor's number of reactor units, the coordinator will not connect.",fg_bg=cpair(colors.yellow,colors._INHERIT)}
TextBox{parent=fac_c_2,y=10,height=3,text="Since you skipped supervisor sync, the main monitor minimum height can't be determined precisely. It is marked with * on the next page.",fg_bg=g_lg_fg_bg}
local nu_error = TextBox{parent=fac_c_2,x=8,y=14,width=35,text="Please set the number of reactors.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -266,14 +266,14 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
else nu_error.show() end
end
PushButton{parent=fac_c_2,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_2,y=14,text="\x1b Back",callback=function()fac_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_2,x=44,y=14,text="Next \x1a",callback=submit_num_units,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=fac_c_3,x=1,y=1,height=2,text="The following facility configuration was fetched from your supervisor computer."}
TextBox{parent=fac_c_3,y=1,height=2,text="The following facility configuration was fetched from your supervisor computer."}
local fac_config_list = ListBox{parent=fac_c_3,x=1,y=4,height=9,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local fac_config_list = ListBox{parent=fac_c_3,y=4,height=9,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
PushButton{parent=fac_c_3,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_3,y=14,text="\x1b Back",callback=function()fac_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_3,x=44,y=14,text="Next \x1a",callback=function()main_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion

View File

@@ -52,12 +52,12 @@ function hmi.create(tool_ctl, main_pane, cfg_sys, divs, style)
local mon_c_3 = Div{parent=mon_cfg,x=2,y=4,width=49}
local mon_c_4 = Div{parent=mon_cfg,x=2,y=4,width=49}
local mon_pane = MultiPane{parent=mon_cfg,x=1,y=4,panes={mon_c_1,mon_c_2,mon_c_3,mon_c_4}}
local mon_pane = MultiPane{parent=mon_cfg,y=4,panes={mon_c_1,mon_c_2,mon_c_3,mon_c_4}}
TextBox{parent=mon_cfg,x=1,y=2,text=" Monitor Configuration",fg_bg=cpair(colors.black,colors.blue)}
TextBox{parent=mon_cfg,y=2,text=" Monitor Configuration",fg_bg=cpair(colors.black,colors.blue)}
TextBox{parent=mon_c_1,x=1,y=1,height=5,text="Your configuration requires the following monitors. The main and flow monitors' heights are dependent on your unit count and cooling setup. If you manually entered the unit count, a * will be shown on potentially inaccurate calculations."}
local mon_reqs = ListBox{parent=mon_c_1,x=1,y=7,height=6,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
TextBox{parent=mon_c_1,y=1,height=5,text="Your configuration requires the following monitors. The main and flow monitors' heights are dependent on your unit count and cooling setup. If you manually entered the unit count, a * will be shown on potentially inaccurate calculations."}
local mon_reqs = ListBox{parent=mon_c_1,y=7,height=6,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local function next_from_reqs()
-- unassign unit monitors above the unit count
@@ -67,13 +67,13 @@ function hmi.create(tool_ctl, main_pane, cfg_sys, divs, style)
mon_pane.set_value(2)
end
PushButton{parent=mon_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=mon_c_1,y=14,text="\x1b Back",callback=function()main_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=mon_c_1,x=8,y=14,text="Legacy Options",min_width=16,callback=function()mon_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=mon_c_1,x=44,y=14,text="Next \x1a",callback=next_from_reqs,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=mon_c_2,x=1,y=1,height=5,text="Please configure your monitors below. You can go back to the prior page without losing progress to double check what you need. All of those monitors must be assigned before you can proceed."}
TextBox{parent=mon_c_2,y=1,height=5,text="Please configure your monitors below. You can go back to the prior page without losing progress to double check what you need. All of those monitors must be assigned before you can proceed."}
local mon_list = ListBox{parent=mon_c_2,x=1,y=6,height=7,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local mon_list = ListBox{parent=mon_c_2,y=6,height=7,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local assign_err = TextBox{parent=mon_c_2,x=8,y=14,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -98,14 +98,14 @@ function hmi.create(tool_ctl, main_pane, cfg_sys, divs, style)
assign_err.show()
end
PushButton{parent=mon_c_2,x=1,y=14,text="\x1b Back",callback=function()mon_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=mon_c_2,y=14,text="\x1b Back",callback=function()mon_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=mon_c_2,x=44,y=14,text="Next \x1a",callback=submit_monitors,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
local mon_desc = TextBox{parent=mon_c_3,x=1,y=1,height=4,text=""}
local mon_desc = TextBox{parent=mon_c_3,y=1,height=4,text=""}
local mon_unit_l, mon_unit = nil, nil ---@type TextBox, NumberField
local mon_warn = TextBox{parent=mon_c_3,x=1,y=11,height=2,text="",fg_bg=cpair(colors.red,colors.lightGray)}
local mon_warn = TextBox{parent=mon_c_3,y=11,height=2,text="",fg_bg=cpair(colors.red,colors.lightGray)}
---@param val integer assignment type
local function on_assign_mon(val)
@@ -135,8 +135,8 @@ function hmi.create(tool_ctl, main_pane, cfg_sys, divs, style)
if value == "0" or value == nil then mon_unit.set_value(0) end
end
TextBox{parent=mon_c_3,x=1,y=6,width=10,text="Assignment"}
local mon_assign = RadioButton{parent=mon_c_3,x=1,y=7,default=1,options={"Main Monitor","Flow Monitor","Unit Monitor"},callback=on_assign_mon,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.blue}
TextBox{parent=mon_c_3,y=6,width=10,text="Assignment"}
local mon_assign = RadioButton{parent=mon_c_3,y=7,default=1,options={"Main Monitor","Flow Monitor","Unit Monitor"},callback=on_assign_mon,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.blue}
mon_unit_l = TextBox{parent=mon_c_3,x=18,y=6,width=7,text="Unit ID"}
mon_unit = NumberField{parent=mon_c_3,x=18,y=7,width=10,max_chars=2,min=1,max=4,fg_bg=bw_fg_bg}
@@ -181,13 +181,13 @@ function hmi.create(tool_ctl, main_pane, cfg_sys, divs, style)
mon_pane.set_value(2)
end
PushButton{parent=mon_c_3,x=1,y=14,text="\x1b Back",callback=function()mon_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=mon_c_3,y=14,text="\x1b Back",callback=function()mon_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
self.apply_mon = PushButton{parent=mon_c_3,x=43,y=14,min_width=7,text="Apply",callback=apply_monitor,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
TextBox{parent=mon_c_4,x=1,y=1,height=3,text="For legacy compatibility with facilities built without space for a flow monitor, you can disable the flow monitor requirement here."}
TextBox{parent=mon_c_4,x=1,y=5,height=3,text="Please be aware that THIS OPTION WILL BE REMOVED ON RELEASE. Disabling it will only be available for the remainder of the beta."}
TextBox{parent=mon_c_4,y=1,height=3,text="For legacy compatibility with facilities built without space for a flow monitor, you can disable the flow monitor requirement here."}
TextBox{parent=mon_c_4,y=5,height=3,text="Please be aware that THIS OPTION WILL BE REMOVED ON RELEASE. Disabling it will only be available for the remainder of the beta."}
tool_ctl.dis_flow_view = Checkbox{parent=mon_c_4,x=1,y=9,default=ini_cfg.DisableFlowView,label="Disable Flow View Monitor",box_fg_bg=cpair(colors.blue,colors.black)}
tool_ctl.dis_flow_view = Checkbox{parent=mon_c_4,y=9,default=ini_cfg.DisableFlowView,label="Disable Flow View Monitor",box_fg_bg=cpair(colors.blue,colors.black)}
local function back_from_legacy()
tmp_cfg.DisableFlowView = tool_ctl.dis_flow_view.get_value()
@@ -203,14 +203,14 @@ function hmi.create(tool_ctl, main_pane, cfg_sys, divs, style)
local spkr_c = Div{parent=spkr_cfg,x=2,y=4,width=49}
TextBox{parent=spkr_cfg,x=1,y=2,text=" Speaker Configuration",fg_bg=cpair(colors.black,colors.cyan)}
TextBox{parent=spkr_cfg,y=2,text=" Speaker Configuration",fg_bg=cpair(colors.black,colors.cyan)}
TextBox{parent=spkr_c,x=1,y=1,height=2,text="The coordinator uses a speaker to play alarm sounds."}
TextBox{parent=spkr_c,x=1,y=4,height=3,text="You can change the speaker audio volume from the default. The range is 0.0 to 3.0, where 1.0 is standard volume."}
TextBox{parent=spkr_c,y=1,height=2,text="The coordinator uses a speaker to play alarm sounds."}
TextBox{parent=spkr_c,y=4,height=3,text="You can change the speaker audio volume from the default. The range is 0.0 to 3.0, where 1.0 is standard volume."}
tool_ctl.s_vol = NumberField{parent=spkr_c,x=1,y=8,width=9,max_chars=7,allow_decimal=true,default=ini_cfg.SpeakerVolume,min=0,max=3,fg_bg=bw_fg_bg}
tool_ctl.s_vol = NumberField{parent=spkr_c,y=8,width=9,max_chars=7,allow_decimal=true,default=ini_cfg.SpeakerVolume,min=0,max=3,fg_bg=bw_fg_bg}
TextBox{parent=spkr_c,x=1,y=10,height=3,text="Note: alarm sine waves are at half scale so that multiple will be required to reach full scale.",fg_bg=g_lg_fg_bg}
TextBox{parent=spkr_c,y=10,height=3,text="Note: alarm sine waves are at half scale so that multiple will be required to reach full scale.",fg_bg=g_lg_fg_bg}
local s_vol_err = TextBox{parent=spkr_c,x=8,y=14,width=35,text="Please set a volume.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -223,7 +223,7 @@ function hmi.create(tool_ctl, main_pane, cfg_sys, divs, style)
else s_vol_err.show() end
end
PushButton{parent=spkr_c,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=spkr_c,y=14,text="\x1b Back",callback=function()main_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=spkr_c,x=44,y=14,text="Next \x1a",callback=submit_vol,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -232,18 +232,18 @@ function hmi.create(tool_ctl, main_pane, cfg_sys, divs, style)
local crd_c_1 = Div{parent=crd_cfg,x=2,y=4,width=49}
TextBox{parent=crd_cfg,x=1,y=2,text=" Coordinator UI Configuration",fg_bg=cpair(colors.black,colors.lime)}
TextBox{parent=crd_cfg,y=2,text=" Coordinator UI Configuration",fg_bg=cpair(colors.black,colors.lime)}
TextBox{parent=crd_c_1,x=1,y=1,height=2,text="You can customize the UI with the interface options below."}
TextBox{parent=crd_c_1,y=1,height=2,text="You can customize the UI with the interface options below."}
TextBox{parent=crd_c_1,x=1,y=4,text="Clock Time Format"}
tool_ctl.clock_fmt = RadioButton{parent=crd_c_1,x=1,y=5,default=util.trinary(ini_cfg.Time24Hour,1,2),options={"24-Hour","12-Hour"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.lime}
TextBox{parent=crd_c_1,y=4,text="Clock Time Format"}
tool_ctl.clock_fmt = RadioButton{parent=crd_c_1,y=5,default=util.trinary(ini_cfg.Time24Hour,1,2),options={"24-Hour","12-Hour"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.lime}
TextBox{parent=crd_c_1,x=20,y=4,text="Po/Pu Pellet Color"}
tool_ctl.pellet_color = RadioButton{parent=crd_c_1,x=20,y=5,default=util.trinary(ini_cfg.GreenPuPellet,1,2),options={"Green Pu/Cyan Po","Cyan Pu/Green Po (Mek 10.4+)"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.lime}
TextBox{parent=crd_c_1,x=1,y=8,text="Temperature Scale"}
tool_ctl.temp_scale = RadioButton{parent=crd_c_1,x=1,y=9,default=ini_cfg.TempScale,options=types.TEMP_SCALE_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.lime}
TextBox{parent=crd_c_1,y=8,text="Temperature Scale"}
tool_ctl.temp_scale = RadioButton{parent=crd_c_1,y=9,default=ini_cfg.TempScale,options=types.TEMP_SCALE_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.lime}
TextBox{parent=crd_c_1,x=20,y=8,text="Energy Scale"}
tool_ctl.energy_scale = RadioButton{parent=crd_c_1,x=20,y=9,default=ini_cfg.EnergyScale,options=types.ENERGY_SCALE_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.lime}
@@ -256,7 +256,7 @@ function hmi.create(tool_ctl, main_pane, cfg_sys, divs, style)
main_pane.set_value(7)
end
PushButton{parent=crd_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(5)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=crd_c_1,y=14,text="\x1b Back",callback=function()main_pane.set_value(5)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=crd_c_1,x=44,y=14,text="Next \x1a",callback=submit_ui_opts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -295,13 +295,13 @@ function hmi.create(tool_ctl, main_pane, cfg_sys, divs, style)
mon_reqs.remove_all()
TextBox{parent=mon_reqs,x=1,y=1,text="\x1a "..tmp_cfg.UnitCount.." Unit View Monitor"..util.trinary(plural,"s","")}
TextBox{parent=mon_reqs,x=1,y=1,text=" "..util.trinary(plural,"each ","").."must be 4 blocks wide by 4 tall",fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=mon_reqs,x=1,y=1,text="\x1a 1 Main View Monitor"}
TextBox{parent=mon_reqs,x=1,y=1,text=" must be 8 blocks wide by "..m_at_least..tool_ctl.main_mon_h..asterisk.." tall",fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=mon_reqs,y=1,text="\x1a "..tmp_cfg.UnitCount.." Unit View Monitor"..util.trinary(plural,"s","")}
TextBox{parent=mon_reqs,y=1,text=" "..util.trinary(plural,"each ","").."must be 4 blocks wide by 4 tall",fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=mon_reqs,y=1,text="\x1a 1 Main View Monitor"}
TextBox{parent=mon_reqs,y=1,text=" must be 8 blocks wide by "..m_at_least..tool_ctl.main_mon_h..asterisk.." tall",fg_bg=cpair(colors.gray,colors.white)}
if not tmp_cfg.DisableFlowView then
TextBox{parent=mon_reqs,x=1,y=1,text="\x1a 1 Flow View Monitor"}
TextBox{parent=mon_reqs,x=1,y=1,text=" must be 8 blocks wide by "..f_at_least..tool_ctl.flow_mon_h.." tall",fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=mon_reqs,y=1,text="\x1a 1 Flow View Monitor"}
TextBox{parent=mon_reqs,y=1,text=" must be 8 blocks wide by "..f_at_least..tool_ctl.flow_mon_h.." tall",fg_bg=cpair(colors.gray,colors.white)}
end
end
@@ -401,9 +401,9 @@ function hmi.create(tool_ctl, main_pane, cfg_sys, divs, style)
end
end
local line = Div{parent=mon_list,x=1,y=1,height=1}
local line = Div{parent=mon_list,y=1,height=1}
TextBox{parent=line,x=1,y=1,width=6,text=assignment,fg_bg=cpair(util.trinary(assignment=="Unused",colors.red,colors.blue),colors.white)}
TextBox{parent=line,y=1,width=6,text=assignment,fg_bg=cpair(util.trinary(assignment=="Unused",colors.red,colors.blue),colors.white)}
TextBox{parent=line,x=8,y=1,text=iface}
local w, h = ppm.monitor_block_size(dev.getSize())
@@ -430,9 +430,9 @@ function hmi.create(tool_ctl, main_pane, cfg_sys, divs, style)
-- add monitors that are assigned but not connected
for i = 1, #dc_list do
local line = Div{parent=mon_list,x=1,y=1,height=1}
local line = Div{parent=mon_list,y=1,height=1}
TextBox{parent=line,x=1,y=1,width=6,text=dc_list[i][1],fg_bg=cpair(colors.blue,colors.white)}
TextBox{parent=line,y=1,width=6,text=dc_list[i][1],fg_bg=cpair(colors.blue,colors.white)}
TextBox{parent=line,x=8,y=1,text="disconnected",fg_bg=cpair(colors.red,colors.white)}
local function unset_mon()

View File

@@ -70,21 +70,21 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
local net_c_5 = Div{parent=net_cfg,x=2,y=4,width=49}
local net_c_6 = Div{parent=net_cfg,x=2,y=4,width=49}
local net_pane = MultiPane{parent=net_cfg,x=1,y=4,panes={net_c_1,net_c_2,net_c_3,net_c_4,net_c_5,net_c_6}}
local net_pane = MultiPane{parent=net_cfg,y=4,panes={net_c_1,net_c_2,net_c_3,net_c_4,net_c_5,net_c_6}}
TextBox{parent=net_cfg,x=1,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)}
TextBox{parent=net_cfg,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)}
TextBox{parent=net_c_1,x=1,y=1,text="Please select the network interface(s)."}
TextBox{parent=net_c_1,y=1,text="Please select the network interface(s)."}
TextBox{parent=net_c_1,x=41,y=1,text="new!",fg_bg=cpair(colors.red,colors._INHERIT)} ---@todo remove NEW tag on next revision
local function on_wired_change(_) tool_ctl.gen_modem_list() end
local wireless = Checkbox{parent=net_c_1,x=1,y=3,label="Wireless/Ender Modem",default=ini_cfg.WirelessModem,box_fg_bg=cpair(colors.lightBlue,colors.black)}
local wireless = Checkbox{parent=net_c_1,y=3,label="Wireless/Ender Modem",default=ini_cfg.WirelessModem,box_fg_bg=cpair(colors.lightBlue,colors.black)}
TextBox{parent=net_c_1,x=24,y=3,text="(required for Pocket)",fg_bg=g_lg_fg_bg}
local wired = Checkbox{parent=net_c_1,x=1,y=5,label="Wired Modem",default=ini_cfg.WiredModem~=false,box_fg_bg=cpair(colors.lightBlue,colors.black),callback=on_wired_change}
local wired = Checkbox{parent=net_c_1,y=5,label="Wired Modem",default=ini_cfg.WiredModem~=false,box_fg_bg=cpair(colors.lightBlue,colors.black),callback=on_wired_change}
TextBox{parent=net_c_1,x=3,y=6,text="this one MUST ONLY connect to SCADA computers",fg_bg=cpair(colors.red,colors._INHERIT)}
TextBox{parent=net_c_1,x=3,y=7,text="connecting it to peripherals will cause issues",fg_bg=g_lg_fg_bg}
local modem_list = ListBox{parent=net_c_1,x=1,y=8,height=5,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local modem_list = ListBox{parent=net_c_1,y=8,height=5,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local modem_err = TextBox{parent=net_c_1,x=8,y=14,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -122,7 +122,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
end
end
PushButton{parent=net_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_1,x=44,y=14,text="Next \x1a",callback=submit_interfaces,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_2,text="If you selected multiple interfaces, please specify if this device should prefer wireless or otherwise wired. The preferred interface is switched too when reconnected even if failover has succeeded onto the fallback interface."}
@@ -153,21 +153,21 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
net_pane.set_value(3)
end
PushButton{parent=net_c_2,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_2,y=14,text="\x1b Back",callback=function()net_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_2,x=44,y=14,text="Next \x1a",callback=submit_net_cfg_opts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_3,x=1,y=1,text="Please set the network channels below."}
TextBox{parent=net_c_3,x=1,y=3,height=4,text="Each of the 5 uniquely named channels, including the 3 below, must be the same for each device in this SCADA network. For multiplayer servers, it is recommended to not use the default channels.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,y=1,text="Please set the network channels below."}
TextBox{parent=net_c_3,y=3,height=4,text="Each of the 5 uniquely named channels, including the 3 below, must be the same for each device in this SCADA network. For multiplayer servers, it is recommended to not use the default channels.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,x=1,y=8,width=18,text="Supervisor Channel"}
TextBox{parent=net_c_3,y=8,width=18,text="Supervisor Channel"}
local svr_chan = NumberField{parent=net_c_3,x=21,y=8,width=7,default=ini_cfg.SVR_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_3,x=29,y=8,height=4,text="[SVR_CHANNEL]",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,x=1,y=10,width=19,text="Coordinator Channel"}
TextBox{parent=net_c_3,y=10,width=19,text="Coordinator Channel"}
local crd_chan = NumberField{parent=net_c_3,x=21,y=10,width=7,default=ini_cfg.CRD_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_3,x=29,y=10,height=4,text="[CRD_CHANNEL]",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,x=1,y=12,width=14,text="Pocket Channel"}
TextBox{parent=net_c_3,y=12,width=14,text="Pocket Channel"}
self.pkt_chan = NumberField{parent=net_c_3,x=21,y=12,width=7,default=ini_cfg.PKT_Channel,min=1,max=65535,fg_bg=bw_fg_bg,dis_fg_bg=cpair(colors.lightGray,colors.white)}
TextBox{parent=net_c_3,x=29,y=12,height=4,text="[PKT_CHANNEL]",fg_bg=g_lg_fg_bg}
@@ -185,16 +185,16 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
else chan_err.show() end
end
PushButton{parent=net_c_3,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_3,y=14,text="\x1b Back",callback=function()net_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_3,x=44,y=14,text="Next \x1a",callback=submit_channels,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_4,x=1,y=1,text="Please set the connection timeouts below."}
TextBox{parent=net_c_4,x=1,y=3,height=4,text="You generally should not need to modify these. On slow servers, you can try to increase this to make the system wait longer before assuming a disconnection. The default for all is 5 seconds.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_4,y=1,text="Please set the connection timeouts below."}
TextBox{parent=net_c_4,y=3,height=4,text="You generally should not need to modify these. On slow servers, you can try to increase this to make the system wait longer before assuming a disconnection. The default for all is 5 seconds.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_4,x=1,y=8,width=19,text="Supervisor Timeout"}
TextBox{parent=net_c_4,y=8,width=19,text="Supervisor Timeout"}
local svr_timeout = NumberField{parent=net_c_4,x=20,y=8,width=7,default=ini_cfg.SVR_Timeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg}
TextBox{parent=net_c_4,x=1,y=10,width=14,text="Pocket Timeout"}
TextBox{parent=net_c_4,y=10,width=14,text="Pocket Timeout"}
self.api_timeout = NumberField{parent=net_c_4,x=20,y=10,width=7,default=ini_cfg.API_Timeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg,dis_fg_bg=cpair(colors.lightGray,colors.white)}
TextBox{parent=net_c_4,x=28,y=8,height=4,width=7,text="seconds\n\nseconds",fg_bg=g_lg_fg_bg}
@@ -227,14 +227,14 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
else ct_err.show() end
end
PushButton{parent=net_c_4,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_4,y=14,text="\x1b Back",callback=function()net_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_4,x=44,y=14,text="Next \x1a",callback=submit_timeouts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_5,x=1,y=1,text="Please set the wireless trusted range below."}
TextBox{parent=net_c_5,x=1,y=3,height=3,text="Setting this to a value larger than 0 prevents wireless connections with devices that many meters (blocks) away in any direction.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_5,x=1,y=7,height=2,text="This is optional. You can disable this functionality by setting the value to 0.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_5,y=1,text="Please set the wireless trusted range below."}
TextBox{parent=net_c_5,y=3,height=3,text="Setting this to a value larger than 0 prevents wireless connections with devices that many meters (blocks) away in any direction.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_5,y=7,height=2,text="This is optional. You can disable this functionality by setting the value to 0.",fg_bg=g_lg_fg_bg}
local range = NumberField{parent=net_c_5,x=1,y=10,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg}
local range = NumberField{parent=net_c_5,y=10,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg}
local tr_err = TextBox{parent=net_c_5,x=8,y=14,width=35,text="Please set the trusted range.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -248,14 +248,14 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
else tr_err.show() end
end
PushButton{parent=net_c_5,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_5,y=14,text="\x1b Back",callback=function()net_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_5,x=44,y=14,text="Next \x1a",callback=submit_tr,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_6,x=1,y=1,height=2,text="Optionally, set the facility authentication key below. Do NOT use one of your passwords."}
TextBox{parent=net_c_6,x=1,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for wireless security on multiplayer servers. All devices on the same wireless network MUST use the same key if any device has a key. This does result in some extra computation (can slow things down).",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_6,y=1,height=2,text="Optionally, set the facility authentication key below. Do NOT use one of your passwords."}
TextBox{parent=net_c_6,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for wireless security on multiplayer servers. All devices on the same wireless network MUST use the same key if any device has a key. This does result in some extra computation (can slow things down).",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_6,x=1,y=11,text="Auth Key (Wireless Only, Not Used for Wired)"}
local key, _ = TextField{parent=net_c_6,x=1,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg}
TextBox{parent=net_c_6,y=11,text="Auth Key (Wireless Only, Not Used for Wired)"}
local key, _ = TextField{parent=net_c_6,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg}
local function censor_key(enable) key.censor(tri(enable, "*", nil)) end
@@ -282,7 +282,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
else key_err.show() end
end
PushButton{parent=net_c_6,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(5)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_6,y=14,text="\x1b Back",callback=function()net_pane.set_value(5)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_6,x=44,y=14,text="Next \x1a",callback=submit_auth,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -291,17 +291,17 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
local log_c_1 = Div{parent=log_cfg,x=2,y=4,width=49}
TextBox{parent=log_cfg,x=1,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)}
TextBox{parent=log_cfg,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)}
TextBox{parent=log_c_1,x=1,y=1,text="Please configure logging below."}
TextBox{parent=log_c_1,y=1,text="Please configure logging below."}
TextBox{parent=log_c_1,x=1,y=3,text="Log File Mode"}
local mode = RadioButton{parent=log_c_1,x=1,y=4,default=ini_cfg.LogMode+1,options={"Append on Startup","Replace on Startup"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.pink}
TextBox{parent=log_c_1,y=3,text="Log File Mode"}
local mode = RadioButton{parent=log_c_1,y=4,default=ini_cfg.LogMode+1,options={"Append on Startup","Replace on Startup"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.pink}
TextBox{parent=log_c_1,x=1,y=7,text="Log File Path"}
local path = TextField{parent=log_c_1,x=1,y=8,width=49,height=1,value=ini_cfg.LogPath,max_len=128,fg_bg=bw_fg_bg}
TextBox{parent=log_c_1,y=7,text="Log File Path"}
local path = TextField{parent=log_c_1,y=8,width=49,height=1,value=ini_cfg.LogPath,max_len=128,fg_bg=bw_fg_bg}
local en_dbg = Checkbox{parent=log_c_1,x=1,y=10,default=ini_cfg.LogDebug,label="Enable Logging Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)}
local en_dbg = Checkbox{parent=log_c_1,y=10,default=ini_cfg.LogDebug,label="Enable Logging Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)}
TextBox{parent=log_c_1,x=3,y=11,height=2,text="This results in much larger log files. It is best to only use this when there is a problem.",fg_bg=g_lg_fg_bg}
local path_err = TextBox{parent=log_c_1,x=8,y=14,width=35,text="Please provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -318,7 +318,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
else path_err.show() end
end
PushButton{parent=log_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(6)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=log_c_1,y=14,text="\x1b Back",callback=function()main_pane.set_value(6)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=log_c_1,x=44,y=14,text="Next \x1a",callback=submit_log,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -330,20 +330,20 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
local clr_c_3 = Div{parent=clr_cfg,x=2,y=4,width=49}
local clr_c_4 = Div{parent=clr_cfg,x=2,y=4,width=49}
local clr_pane = MultiPane{parent=clr_cfg,x=1,y=4,panes={clr_c_1,clr_c_2,clr_c_3,clr_c_4}}
local clr_pane = MultiPane{parent=clr_cfg,y=4,panes={clr_c_1,clr_c_2,clr_c_3,clr_c_4}}
TextBox{parent=clr_cfg,x=1,y=2,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)}
TextBox{parent=clr_cfg,y=2,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)}
TextBox{parent=clr_c_1,x=1,y=1,height=2,text="Here you can select the color themes for the different UI displays."}
TextBox{parent=clr_c_1,x=1,y=4,height=2,text="Click 'Accessibility' below to access colorblind assistive options.",fg_bg=g_lg_fg_bg}
TextBox{parent=clr_c_1,y=1,height=2,text="Here you can select the color themes for the different UI displays."}
TextBox{parent=clr_c_1,y=4,height=2,text="Click 'Accessibility' below to access colorblind assistive options.",fg_bg=g_lg_fg_bg}
TextBox{parent=clr_c_1,x=1,y=7,text="Main UI Theme"}
local main_theme = RadioButton{parent=clr_c_1,x=1,y=8,default=ini_cfg.MainTheme,options=themes.UI_THEME_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_1,y=7,text="Main UI Theme"}
local main_theme = RadioButton{parent=clr_c_1,y=8,default=ini_cfg.MainTheme,options=themes.UI_THEME_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_1,x=18,y=7,text="Front Panel Theme"}
local fp_theme = RadioButton{parent=clr_c_1,x=18,y=8,default=ini_cfg.FrontPanelTheme,options=themes.FP_THEME_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_2,x=1,y=1,height=6,text="This system uses color heavily to distinguish ok and not, with some indicators using many colors. By selecting a mode below, indicators will change as shown. For non-standard modes, indicators with more than two colors will usually be split up."}
TextBox{parent=clr_c_2,y=1,height=6,text="This system uses color heavily to distinguish ok and not, with some indicators using many colors. By selecting a mode below, indicators will change as shown. For non-standard modes, indicators with more than two colors will usually be split up."}
TextBox{parent=clr_c_2,x=21,y=7,text="Preview"}
local _ = IndLight{parent=clr_c_2,x=21,y=8,label="Good",colors=cpair(colors.black,colors.green)}
@@ -372,8 +372,8 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
end
end
TextBox{parent=clr_c_2,x=1,y=7,width=10,text="Color Mode"}
local c_mode = RadioButton{parent=clr_c_2,x=1,y=8,default=ini_cfg.ColorMode,options=themes.COLOR_MODE_NAMES,callback=recolor,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_2,y=7,width=10,text="Color Mode"}
local c_mode = RadioButton{parent=clr_c_2,y=8,default=ini_cfg.ColorMode,options=themes.COLOR_MODE_NAMES,callback=recolor,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_2,x=21,y=13,height=2,width=18,text="Note: exact color varies by theme.",fg_bg=g_lg_fg_bg}
@@ -416,7 +416,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
end
end
PushButton{parent=clr_c_1,x=1,y=14,text="\x1b Back",callback=back_from_colors,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=clr_c_1,y=14,text="\x1b Back",callback=back_from_colors,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=clr_c_1,x=8,y=14,min_width=15,text="Accessibility",callback=show_access,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
tool_ctl.color_next = PushButton{parent=clr_c_1,x=44,y=14,text="Next \x1a",callback=submit_colors,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
tool_ctl.color_apply = PushButton{parent=clr_c_1,x=43,y=14,min_width=7,text="Apply",callback=submit_colors,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg}
@@ -428,12 +428,12 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
clr_pane.set_value(1)
end
TextBox{parent=clr_c_3,x=1,y=1,text="Settings saved!"}
PushButton{parent=clr_c_3,x=1,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=clr_c_3,y=1,text="Settings saved!"}
PushButton{parent=clr_c_3,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
PushButton{parent=clr_c_3,x=44,y=14,min_width=6,text="Home",callback=c_go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=clr_c_4,x=1,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=clr_c_4,x=1,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=clr_c_4,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=clr_c_4,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
PushButton{parent=clr_c_4,x=44,y=14,min_width=6,text="Home",callback=c_go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -445,11 +445,11 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
local sum_c_3 = Div{parent=summary,x=2,y=4,width=49}
local sum_c_4 = Div{parent=summary,x=2,y=4,width=49}
local sum_pane = MultiPane{parent=summary,x=1,y=4,panes={sum_c_1,sum_c_2,sum_c_3,sum_c_4}}
local sum_pane = MultiPane{parent=summary,y=4,panes={sum_c_1,sum_c_2,sum_c_3,sum_c_4}}
TextBox{parent=summary,x=1,y=2,text=" Summary",fg_bg=cpair(colors.black,colors.green)}
TextBox{parent=summary,y=2,text=" Summary",fg_bg=cpair(colors.black,colors.green)}
local setting_list = ListBox{parent=sum_c_1,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local setting_list = ListBox{parent=sum_c_1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local function back_from_summary()
if tool_ctl.viewing_config or self.importing_legacy then
@@ -521,11 +521,11 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
end
end
PushButton{parent=sum_c_1,x=1,y=14,text="\x1b Back",callback=back_from_summary,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_1,y=14,text="\x1b Back",callback=back_from_summary,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
self.show_key_btn = PushButton{parent=sum_c_1,x=8,y=14,min_width=17,text="Unhide Auth Key",callback=function()self.show_auth_key()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
tool_ctl.settings_apply = PushButton{parent=sum_c_1,x=43,y=14,min_width=7,text="Apply",callback=save_and_continue,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg}
TextBox{parent=sum_c_2,x=1,y=1,text="Settings saved!"}
TextBox{parent=sum_c_2,y=1,text="Settings saved!"}
local function go_home()
main_pane.set_value(1)
@@ -536,10 +536,10 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
sum_pane.set_value(1)
end
PushButton{parent=sum_c_2,x=1,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_2,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_2,x=44,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=sum_c_3,x=1,y=1,height=2,text="The old config.lua and coord.settings files will now be deleted, then the configurator will exit."}
TextBox{parent=sum_c_3,y=1,height=2,text="The old config.lua and coord.settings files will now be deleted, then the configurator will exit."}
local function delete_legacy()
fs.delete("/coordinator/config.lua")
@@ -547,11 +547,11 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
exit()
end
PushButton{parent=sum_c_3,x=1,y=14,min_width=8,text="Cancel",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_3,y=14,min_width=8,text="Cancel",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_3,x=44,y=14,min_width=6,text="OK",callback=delete_legacy,fg_bg=cpair(colors.black,colors.green),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=sum_c_4,x=1,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=sum_c_4,x=1,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=sum_c_4,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=sum_c_4,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_4,x=44,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
--#endregion
@@ -677,7 +677,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
local textbox
if height > 1 then
textbox = TextBox{parent=line,x=1,y=2,text=val,height=height-1}
textbox = TextBox{parent=line,y=2,text=val,height=height-1}
else
textbox = TextBox{parent=line,x=label_w+1,y=1,text=val,alignment=RIGHT}
end
@@ -706,19 +706,19 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
end
if missing.tmp and tmp_cfg.WiredModem then
local line = Div{parent=modem_list,x=1,y=1,height=1}
local line = Div{parent=modem_list,y=1,height=1}
TextBox{parent=line,x=1,y=1,width=4,text="Used",fg_bg=cpair(tri(enable,colors.blue,colors.gray),colors.white)}
TextBox{parent=line,y=1,width=4,text="Used",fg_bg=cpair(tri(enable,colors.blue,colors.gray),colors.white)}
PushButton{parent=line,x=6,y=1,min_width=8,height=1,text="SELECT",callback=function()end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=g_lg_fg_bg}.disable()
TextBox{parent=line,x=15,y=1,text="[missing]",fg_bg=cpair(colors.red,colors.white)}
TextBox{parent=line,x=25,y=1,text=tmp_cfg.WiredModem}
end
if missing.ini and ini_cfg.WiredModem and (tmp_cfg.WiredModem ~= ini_cfg.WiredModem) then
local line = Div{parent=modem_list,x=1,y=1,height=1}
local line = Div{parent=modem_list,y=1,height=1}
local used = tmp_cfg.WiredModem == ini_cfg.WiredModem
TextBox{parent=line,x=1,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
TextBox{parent=line,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
local select_btn = PushButton{parent=line,x=6,y=1,min_width=8,height=1,text="SELECT",callback=function()select(ini_cfg.WiredModem)end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=g_lg_fg_bg}
TextBox{parent=line,x=15,y=1,text="[missing]",fg_bg=cpair(colors.red,colors.white)}
TextBox{parent=line,x=25,y=1,text=ini_cfg.WiredModem}
@@ -728,10 +728,10 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
-- list wired modems
for iface, _ in pairs(modems) do
local line = Div{parent=modem_list,x=1,y=1,height=1}
local line = Div{parent=modem_list,y=1,height=1}
local used = tmp_cfg.WiredModem == iface
TextBox{parent=line,x=1,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
TextBox{parent=line,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
local select_btn = PushButton{parent=line,x=6,y=1,min_width=8,height=1,text="SELECT",callback=function()select(iface)end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=g_lg_fg_bg}
TextBox{parent=line,x=15,y=1,text=iface}

View File

@@ -200,20 +200,20 @@ local function config_view(display)
TextBox{parent=display,y=1,text="Coordinator Configurator",alignment=CENTER,fg_bg=style.header}
local root_pane_div = Div{parent=display,x=1,y=2}
local root_pane_div = Div{parent=display,y=2}
local main_page = Div{parent=root_pane_div,x=1,y=1}
local net_cfg = Div{parent=root_pane_div,x=1,y=1}
local fac_cfg = Div{parent=root_pane_div,x=1,y=1}
local mon_cfg = Div{parent=root_pane_div,x=1,y=1}
local spkr_cfg = Div{parent=root_pane_div,x=1,y=1}
local crd_cfg = Div{parent=root_pane_div,x=1,y=1}
local log_cfg = Div{parent=root_pane_div,x=1,y=1}
local clr_cfg = Div{parent=root_pane_div,x=1,y=1}
local summary = Div{parent=root_pane_div,x=1,y=1}
local changelog = Div{parent=root_pane_div,x=1,y=1}
local main_page = Div{parent=root_pane_div,y=1}
local net_cfg = Div{parent=root_pane_div,y=1}
local fac_cfg = Div{parent=root_pane_div,y=1}
local mon_cfg = Div{parent=root_pane_div,y=1}
local spkr_cfg = Div{parent=root_pane_div,y=1}
local crd_cfg = Div{parent=root_pane_div,y=1}
local log_cfg = Div{parent=root_pane_div,y=1}
local clr_cfg = Div{parent=root_pane_div,y=1}
local summary = Div{parent=root_pane_div,y=1}
local changelog = Div{parent=root_pane_div,y=1}
local main_pane = MultiPane{parent=root_pane_div,x=1,y=1,panes={main_page,net_cfg,fac_cfg,mon_cfg,spkr_cfg,crd_cfg,log_cfg,clr_cfg,summary,changelog}}
local main_pane = MultiPane{parent=root_pane_div,y=1,panes={main_page,net_cfg,fac_cfg,mon_cfg,spkr_cfg,crd_cfg,log_cfg,clr_cfg,summary,changelog}}
--#region Main Page
@@ -298,20 +298,20 @@ local function config_view(display)
local cl = Div{parent=changelog,x=2,y=4,width=49}
TextBox{parent=changelog,x=1,y=2,text=" Config Change Log",fg_bg=bw_fg_bg}
TextBox{parent=changelog,y=2,text=" Config Change Log",fg_bg=bw_fg_bg}
local c_log = ListBox{parent=cl,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local c_log = ListBox{parent=cl,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
for _, change in ipairs(changes) do
TextBox{parent=c_log,text=change[1],fg_bg=bw_fg_bg}
for _, v in ipairs(change[2]) do
local e = Div{parent=c_log,height=#util.strwrap(v,46)}
TextBox{parent=e,y=1,x=1,text="- ",fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=e,y=1,text="- ",fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=e,y=1,x=3,text=v,height=e.get_height(),fg_bg=cpair(colors.gray,colors.white)}
end
end
PushButton{parent=cl,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=cl,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
end

View File

@@ -5,7 +5,7 @@ local types = require("scada-common.types")
local themes = require("graphics.themes")
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local process = require("coordinator.process")
local apisessions = require("coordinator.session.apisessions")
@@ -362,26 +362,20 @@ function coordinator.comms(version, backplane, sv_watchdog)
self.sv_addr = comms.BROADCAST
self.sv_linked = false
self.sv_r_seq_num = nil
iocontrol.fp_link_state(types.PANEL_LINK_STATE.DISCONNECTED)
ioctl.fp_link_state(types.PANEL_LINK_STATE.DISCONNECTED)
end
-- close the connection to the server
function public.close()
sv_watchdog.cancel()
public.unlink()
_send_sv(PROTOCOL.SCADA_MGMT, MGMT_TYPE.CLOSE, {})
public.unlink()
end
-- send the resume ready state to the supervisor
---@param mode PROCESS process control mode
---@param burn_target number burn rate target
---@param charge_target number charge level target
---@param gen_target number generation rate target
---@param limits number[] unit burn rate limits
function public.send_ready(mode, burn_target, charge_target, gen_target, limits)
_send_sv(PROTOCOL.SCADA_CRDN, CRDN_TYPE.PROCESS_READY, {
mode, burn_target, charge_target, gen_target, limits
})
---@param settings auto_ctl_cfg auto control settings
function public.send_ready(settings)
_send_sv(PROTOCOL.SCADA_CRDN, CRDN_TYPE.PROCESS_READY, { table.unpack(settings) })
end
-- send a facility command
@@ -392,15 +386,9 @@ function coordinator.comms(version, backplane, sv_watchdog)
end
-- send the auto process control configuration with a start command
---@param mode PROCESS process control mode
---@param burn_target number burn rate target
---@param charge_target number charge level target
---@param gen_target number generation rate target
---@param limits number[] unit burn rate limits
function public.send_auto_start(mode, burn_target, charge_target, gen_target, limits)
_send_sv(PROTOCOL.SCADA_CRDN, CRDN_TYPE.FAC_CMD, {
FAC_COMMAND.START, mode, burn_target, charge_target, gen_target, limits
})
---@param settings auto_ctl_cfg auto control settings
function public.send_auto_start(settings)
_send_sv(PROTOCOL.SCADA_CRDN, CRDN_TYPE.FAC_CMD, { FAC_COMMAND.START, table.unpack(settings) })
end
-- send a unit command
@@ -507,7 +495,7 @@ function coordinator.comms(version, backplane, sv_watchdog)
local id = apisessions.establish_session(src_addr, packet.scada_frame.seq_num(), firmware_v)
coordinator.log_comms(util.c("API_ESTABLISH: pocket (", firmware_v, ") [@", src_addr, "] connected with session ID ", id))
local conf = iocontrol.get_db().facility.conf
local conf = ioctl.get_db().facility.conf
_send_api_establish_ack(packet.scada_frame, ESTABLISH_ACK.ALLOW, { conf.num_units, conf.cooling })
else
log.debug(util.c("API_ESTABLISH: illegal establish packet for device ", dev_type, " on pocket channel"))
@@ -548,8 +536,8 @@ function coordinator.comms(version, backplane, sv_watchdog)
if packet.type == CRDN_TYPE.INITIAL_BUILDS then
if packet.length == 2 then
-- record builds
local fac_builds = iocontrol.record_facility_builds(packet.data[1])
local unit_builds = iocontrol.record_unit_builds(packet.data[2])
local fac_builds = ioctl.record_facility_builds(packet.data[1])
local unit_builds = ioctl.record_unit_builds(packet.data[2])
if fac_builds and unit_builds then
-- acknowledge receipt of builds
@@ -563,7 +551,7 @@ function coordinator.comms(version, backplane, sv_watchdog)
elseif packet.type == CRDN_TYPE.FAC_BUILDS then
if packet.length == 1 then
-- record facility builds
if iocontrol.record_facility_builds(packet.data[1]) then
if ioctl.record_facility_builds(packet.data[1]) then
-- acknowledge receipt of builds
_send_sv(PROTOCOL.SCADA_CRDN, CRDN_TYPE.FAC_BUILDS, {})
else
@@ -574,7 +562,7 @@ function coordinator.comms(version, backplane, sv_watchdog)
end
elseif packet.type == CRDN_TYPE.FAC_STATUS then
-- update facility status
if not iocontrol.update_facility_status(packet.data) then
if not ioctl.update_facility_status(packet.data) then
log.debug("received invalid FAC_STATUS packet")
end
elseif packet.type == CRDN_TYPE.FAC_CMD then
@@ -588,7 +576,7 @@ function coordinator.comms(version, backplane, sv_watchdog)
elseif cmd == FAC_COMMAND.STOP then
process.fac_ack(cmd, ack)
elseif cmd == FAC_COMMAND.START then
if packet.length == 7 then
if packet.length == 9 then
process.start_ack_handle({ table.unpack(packet.data, 2) })
else
log.debug("SCADA_CRDN process start (with configuration) ack echo packet length mismatch")
@@ -610,7 +598,7 @@ function coordinator.comms(version, backplane, sv_watchdog)
elseif packet.type == CRDN_TYPE.UNIT_BUILDS then
-- record builds
if packet.length == 1 then
if iocontrol.record_unit_builds(packet.data[1]) then
if ioctl.record_unit_builds(packet.data[1]) then
-- acknowledge receipt of builds
_send_sv(PROTOCOL.SCADA_CRDN, CRDN_TYPE.UNIT_BUILDS, {})
else
@@ -621,7 +609,7 @@ function coordinator.comms(version, backplane, sv_watchdog)
end
elseif packet.type == CRDN_TYPE.UNIT_STATUSES then
-- update statuses
if not iocontrol.update_unit_statuses(packet.data) then
if not ioctl.update_unit_statuses(packet.data) then
log.debug("received invalid UNIT_STATUSES packet")
end
elseif packet.type == CRDN_TYPE.UNIT_CMD then
@@ -631,7 +619,7 @@ function coordinator.comms(version, backplane, sv_watchdog)
local unit_id = packet.data[2]
local ack = packet.data[3] == true
local unit = iocontrol.get_db().units[unit_id]
local unit = ioctl.get_db().units[unit_id]
if unit ~= nil then
if cmd == UNIT_COMMAND.SCRAM then
@@ -672,7 +660,7 @@ function coordinator.comms(version, backplane, sv_watchdog)
-- log.debug("coordinator RTT = " .. trip_time .. "ms")
iocontrol.get_db().facility.ps.publish("sv_ping", trip_time)
ioctl.get_db().facility.ps.publish("sv_ping", trip_time)
_send_keep_alive_ack(timestamp)
else
@@ -681,10 +669,7 @@ function coordinator.comms(version, backplane, sv_watchdog)
elseif packet.type == MGMT_TYPE.CLOSE then
-- handle session close
sv_watchdog.cancel()
self.sv_addr = comms.BROADCAST
self.sv_linked = false
self.sv_r_seq_num = nil
iocontrol.fp_link_state(types.PANEL_LINK_STATE.DISCONNECTED)
public.unlink()
log.info("server connection closed by remote host")
else
log.debug("received unknown SCADA_MGMT packet type " .. packet.type)
@@ -697,7 +682,7 @@ function coordinator.comms(version, backplane, sv_watchdog)
if est_ack == ESTABLISH_ACK.ALLOW then
-- reset to disconnected before validating
iocontrol.fp_link_state(types.PANEL_LINK_STATE.DISCONNECTED)
ioctl.fp_link_state(types.PANEL_LINK_STATE.DISCONNECTED)
if type(sv_config) == "table" and #sv_config == 2 then
-- get configuration
@@ -714,13 +699,13 @@ function coordinator.comms(version, backplane, sv_watchdog)
log.info(util.c("supervisor establish request approved, linked to SV (CID#", src_addr, ") on ", tx_nic.phy_name()))
-- init io controller
iocontrol.init(conf, public, config.TempScale, config.EnergyScale)
ioctl.init(conf, public, config.TempScale, config.EnergyScale)
self.sv_addr = src_addr
self.sv_linked = true
self.sv_config_err = false
iocontrol.fp_link_state(types.PANEL_LINK_STATE.LINKED)
ioctl.fp_link_state(types.PANEL_LINK_STATE.LINKED)
else
self.sv_config_err = true
log.warning("supervisor config's number of units don't match coordinator's config, establish failed")
@@ -738,17 +723,17 @@ function coordinator.comms(version, backplane, sv_watchdog)
if est_ack == ESTABLISH_ACK.DENY then
if self.last_est_ack ~= est_ack then
iocontrol.fp_link_state(types.PANEL_LINK_STATE.DENIED)
ioctl.fp_link_state(types.PANEL_LINK_STATE.DENIED)
log.info("supervisor connection denied")
end
elseif est_ack == ESTABLISH_ACK.COLLISION then
if self.last_est_ack ~= est_ack then
iocontrol.fp_link_state(types.PANEL_LINK_STATE.COLLISION)
ioctl.fp_link_state(types.PANEL_LINK_STATE.COLLISION)
log.warning("supervisor connection denied due to collision")
end
elseif est_ack == ESTABLISH_ACK.BAD_VERSION then
if self.last_est_ack ~= est_ack then
iocontrol.fp_link_state(types.PANEL_LINK_STATE.BAD_VERSION)
ioctl.fp_link_state(types.PANEL_LINK_STATE.BAD_VERSION)
log.warning("supervisor comms version mismatch")
end
else

View File

@@ -31,7 +31,7 @@ local SPS_STATE = types.SPS_STATE
local WARN_RTT = 1000 -- 2x as long as expected w/ 0 ping
local HIGH_RTT = 1500 -- 3.33x as long as expected w/ 0 ping
local iocontrol = {}
local ioctl = {}
local _ioctl = {
-- connection states for status evaluation
@@ -42,9 +42,9 @@ local _ioctl = {
coroutines = {}
}
---@class ioctl
---@class crd_io
local io = {
---@class ioctl_front_panel
---@class crd_io_fp
fp = { ps = psil.create() }
}
@@ -53,7 +53,7 @@ local io = {
---@param comms coord_comms comms reference
---@param temp_scale TEMP_SCALE temperature unit
---@param energy_scale ENERGY_SCALE energy unit
function iocontrol.init(conf, comms, temp_scale, energy_scale)
function ioctl.init(conf, comms, temp_scale, energy_scale)
io.temp_label = TEMP_UNITS[temp_scale]
io.energy_label = ENERGY_UNITS[energy_scale]
@@ -82,7 +82,7 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale)
end
-- facility data structure
---@class ioctl_facility
---@class crd_io_facility
io.facility = {
conf = conf,
num_units = conf.num_units,
@@ -153,12 +153,12 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale)
end
-- create unit data structures
io.units = {} ---@type ioctl_unit[]
io.units = {} ---@type crd_io_unit[]
for i = 1, conf.num_units do
local function ack(alarm) process.ack_alarm(i, alarm) end
local function reset(alarm) process.reset_alarm(i, alarm) end
---@class ioctl_unit
---@class crd_io_unit
local entry = {
unit_id = i,
connected = false,
@@ -298,19 +298,19 @@ local function fp_eval_status()
end
-- toggle heartbeat indicator
function iocontrol.heartbeat() io.fp.ps.toggle("heartbeat") end
function ioctl.heartbeat() io.fp.ps.toggle("heartbeat") end
-- report versions to front panel
---@param firmware_v string coordinator version
---@param comms_v string comms version
function iocontrol.fp_versions(firmware_v, comms_v)
function ioctl.fp_versions(firmware_v, comms_v)
io.fp.ps.publish("version", firmware_v)
io.fp.ps.publish("comms_version", comms_v)
end
-- report presence of the wired comms modem
---@param has_modem boolean
function iocontrol.fp_has_wd_modem(has_modem)
function ioctl.fp_has_wd_modem(has_modem)
io.fp.ps.publish("has_wd_modem", has_modem)
_ioctl.wd_modem = has_modem
@@ -319,7 +319,7 @@ end
-- report presence of the wireless comms modem
---@param has_modem boolean
function iocontrol.fp_has_wl_modem(has_modem)
function ioctl.fp_has_wl_modem(has_modem)
io.fp.ps.publish("has_wl_modem", has_modem)
_ioctl.wl_modem = has_modem
@@ -328,19 +328,19 @@ end
-- report if the wired network is up
---@param up boolean
function iocontrol.fp_has_wd_net(up)
function ioctl.fp_has_wd_net(up)
io.fp.ps.publish("has_wd_net", up)
end
-- report if the wireless network is up
---@param up boolean
function iocontrol.fp_has_wl_net(up)
function ioctl.fp_has_wl_net(up)
io.fp.ps.publish("has_wl_net", up)
end
-- report presence of the speaker
---@param has_speaker boolean
function iocontrol.fp_has_speaker(has_speaker)
function ioctl.fp_has_speaker(has_speaker)
io.fp.ps.publish("has_speaker", has_speaker)
_ioctl.speaker = has_speaker
@@ -349,12 +349,12 @@ end
-- report supervisor link state
---@param state integer
function iocontrol.fp_link_state(state) io.fp.ps.publish("link_state", state) end
function ioctl.fp_link_state(state) io.fp.ps.publish("link_state", state) end
-- report monitor connection state
---@param id string|integer unit ID for unit monitor, "main" for main monitor, or "flow" for flow monitor
---@param connected 1|2|3 1 for disconnected, 2 for connected but no view (may not fit), 3 for connected with view rendered
function iocontrol.fp_monitor_state(id, connected)
function ioctl.fp_monitor_state(id, connected)
local name = nil
if id == "main" then
@@ -376,7 +376,7 @@ end
-- report thread (routine) statuses
---@param thread string thread name
---@param ok boolean thread state
function iocontrol.fp_rt_status(thread, ok)
function ioctl.fp_rt_status(thread, ok)
local name = util.c("routine__", thread)
io.fp.ps.publish(name, ok)
@@ -389,7 +389,7 @@ end
---@param session_id integer PKT session
---@param fw string firmware version
---@param s_addr integer PKT computer ID
function iocontrol.fp_pkt_connected(session_id, fw, s_addr)
function ioctl.fp_pkt_connected(session_id, fw, s_addr)
io.fp.ps.publish("pkt_" .. session_id .. "_fw", fw)
io.fp.ps.publish("pkt_" .. session_id .. "_addr", util.sprintf("@ C% 3d", s_addr))
pgi.create_pkt_entry(session_id)
@@ -397,14 +397,14 @@ end
-- report PKT session disconnected
---@param session_id integer PKT session
function iocontrol.fp_pkt_disconnected(session_id)
function ioctl.fp_pkt_disconnected(session_id)
pgi.delete_pkt_entry(session_id)
end
-- transmit PKT session RTT
---@param session_id integer PKT session
---@param rtt integer round trip time
function iocontrol.fp_pkt_rtt(session_id, rtt)
function ioctl.fp_pkt_rtt(session_id, rtt)
io.fp.ps.publish("pkt_" .. session_id .. "_rtt", rtt)
if rtt > HIGH_RTT then
@@ -450,7 +450,7 @@ end
-- populate facility structure builds
---@param build table
---@return boolean valid
function iocontrol.record_facility_builds(build)
function ioctl.record_facility_builds(build)
local valid = true
if type(build) == "table" then
@@ -493,12 +493,12 @@ end
-- populate unit structure builds
---@param builds table
---@return boolean valid
function iocontrol.record_unit_builds(builds)
function ioctl.record_unit_builds(builds)
local valid = true
-- note: if not all units and RTUs are connected, some will be nil
for id, build in pairs(builds) do
local unit = io.units[id] ---@type ioctl_unit
local unit = io.units[id] ---@type crd_io_unit
local log_header = util.c("iocontrol.record_unit_builds[UNIT ", id, "]: ")
@@ -624,7 +624,7 @@ end
-- update facility status
---@param status table
---@return boolean valid
function iocontrol.update_facility_status(status)
function ioctl.update_facility_status(status)
local valid = true
local log_header = util.c("iocontrol.update_facility_status: ")
@@ -916,7 +916,7 @@ end
-- update unit statuses
---@param statuses table
---@return boolean valid
function iocontrol.update_unit_statuses(statuses)
function ioctl.update_unit_statuses(statuses)
local valid = true
if type(statuses) ~= "table" then
@@ -1370,6 +1370,6 @@ end
--#endregion
-- get the IO controller database
function iocontrol.get_db() return io end
function ioctl.get_db() return io end
return iocontrol
return ioctl

View File

@@ -19,14 +19,17 @@ local REQUEST_TIMEOUT_MS = 10000
local process = {}
local pctl = {
io = nil, ---@type ioctl
io = nil, ---@type crd_io
comms = nil, ---@type coord_comms
---@class sys_control_states
control_states = {
---@class sys_auto_config
process = {
mode = PROCESS.INACTIVE, ---@type PROCESS
alt_mode = false,
burn_target = 0.0,
range_start = 10,
range_stop = 90,
charge_target = 0.0,
gen_target = 0.0,
limits = {}, ---@type number[]
@@ -64,10 +67,10 @@ end
--#region Core
-- initialize the process controller
---@param iocontrol ioctl iocontrl system
---@param crd_io crd_io iocontrol system
---@param coord_comms coord_comms coordinator communications
function process.init(iocontrol, coord_comms)
pctl.io = iocontrol
function process.init(crd_io, coord_comms)
pctl.io = crd_io
pctl.comms = coord_comms
-- create command handling objects
@@ -85,29 +88,13 @@ function process.init(iocontrol, coord_comms)
local ctrl_states = settings.get("ControlStates", {}) ---@type sys_control_states
local config = ctrl_states.process
local f_ps = crd_io.facility.ps
-- facility auto control configuration
if type(config) == "table" then
ctl_proc.mode = config.mode
ctl_proc.burn_target = config.burn_target
ctl_proc.charge_target = config.charge_target
ctl_proc.gen_target = config.gen_target
ctl_proc.limits = config.limits
ctl_proc.waste_product = config.waste_product
ctl_proc.pu_fallback = config.pu_fallback
ctl_proc.sps_low_power = config.sps_low_power
pctl.io.facility.ps.publish("process_mode", ctl_proc.mode)
pctl.io.facility.ps.publish("process_burn_target", ctl_proc.burn_target)
pctl.io.facility.ps.publish("process_charge_target", pctl.io.energy_convert_from_fe(ctl_proc.charge_target))
pctl.io.facility.ps.publish("process_gen_target", pctl.io.energy_convert_from_fe(ctl_proc.gen_target))
pctl.io.facility.ps.publish("process_waste_product", ctl_proc.waste_product)
pctl.io.facility.ps.publish("process_pu_fallback", ctl_proc.pu_fallback)
pctl.io.facility.ps.publish("process_sps_low_power", ctl_proc.sps_low_power)
for id = 1, math.min(#ctl_proc.limits, pctl.io.facility.num_units) do
local unit = pctl.io.units[id]
unit.unit_ps.publish("burn_limit", ctl_proc.limits[id])
-- update each field if present in the config
for key, _ in pairs(ctl_proc) do
ctl_proc[key] = config[key] or ctl_proc[key]
end
log.info("PROCESS: loaded auto control settings")
@@ -118,6 +105,22 @@ function process.init(iocontrol, coord_comms)
pctl.comms.send_fac_command(F_CMD.SET_SPS_LP, ctl_proc.sps_low_power)
end
f_ps.publish("process_mode", ctl_proc.mode)
f_ps.publish("process_alt_mode", ctl_proc.alt_mode)
f_ps.publish("process_burn_target", ctl_proc.burn_target)
f_ps.publish("process_range_start", ctl_proc.range_start)
f_ps.publish("process_range_stop", ctl_proc.range_stop)
f_ps.publish("process_charge_target", pctl.io.energy_convert_from_fe(ctl_proc.charge_target))
f_ps.publish("process_gen_target", pctl.io.energy_convert_from_fe(ctl_proc.gen_target))
f_ps.publish("process_waste_product", ctl_proc.waste_product)
f_ps.publish("process_pu_fallback", ctl_proc.pu_fallback)
f_ps.publish("process_sps_low_power", ctl_proc.sps_low_power)
for id = 1, math.min(#ctl_proc.limits, pctl.io.facility.num_units) do
local unit = pctl.io.units[id]
unit.unit_ps.publish("burn_limit", ctl_proc.limits[id])
end
-- unit waste states
local waste_modes = ctrl_states.waste_modes
if type(waste_modes) == "table" then
@@ -142,8 +145,9 @@ function process.init(iocontrol, coord_comms)
-- report to the supervisor all initial configuration data has been sent
-- startup resume can occur if needed
local p = ctl_proc
pctl.comms.send_ready(p.mode, p.burn_target, p.charge_target, p.gen_target, p.limits)
local p = ctl_proc
local mode = util.trinary(p.alt_mode and p.mode == PROCESS.CHARGE, PROCESS.RANGE_CONTROL, p.mode)
pctl.comms.send_ready({ mode, p.burn_target, p.range_start, p.range_stop, p.charge_target, p.gen_target, p.limits })
end
-- create a handle to process control for usage of commands that get acknowledgements
@@ -191,21 +195,19 @@ function process.create_handle()
-- start automatic process control with current settings
function handle.process_start()
if f_request(F_CMD.START, handle.fac_ack.on_start) then
local p = pctl.control_states.process
pctl.comms.send_auto_start(p.mode, p.burn_target, p.charge_target, p.gen_target, p.limits)
local p = pctl.control_states.process
local mode = util.trinary(p.alt_mode and p.mode == PROCESS.CHARGE, PROCESS.RANGE_CONTROL, p.mode)
pctl.comms.send_auto_start({ mode, p.burn_target, p.range_start, p.range_stop, p.charge_target, p.gen_target, p.limits })
log.debug("PROCESS: START AUTO CTRL")
end
end
-- start automatic process control with remote settings that haven't been set on the coordinator
---@param mode PROCESS process control mode
---@param burn_target number burn rate target
---@param charge_target number charge level target
---@param gen_target number generation rate target
---@param limits number[] unit burn rate limits
function handle.process_start_remote(mode, burn_target, charge_target, gen_target, limits)
---@param settings auto_ctl_cfg auto control settings
function handle.process_start_remote(settings)
if f_request(F_CMD.START, handle.fac_ack.on_start) then
pctl.comms.send_auto_start(mode, burn_target, charge_target, gen_target, limits)
pctl.comms.send_auto_start(settings)
log.debug("PROCESS: START AUTO CTRL")
end
end
@@ -470,20 +472,26 @@ end
-- save process control settings
---@param mode PROCESS process control mode
---@param alt_mode boolean true if using range control instead of charge control
---@param burn_target number burn rate target
---@param range_start integer range control activation threshold
---@param range_stop integer range control deactivation threshold
---@param charge_target number charge level target
---@param gen_target number generation rate target
---@param limits number[] unit burn rate limits
function process.save(mode, burn_target, charge_target, gen_target, limits)
function process.save(mode, alt_mode, burn_target, range_start, range_stop, charge_target, gen_target, limits)
log.debug("PROCESS: SAVE")
-- update config table
local ctl_proc = pctl.control_states.process
ctl_proc.mode = mode
ctl_proc.burn_target = burn_target
ctl_proc.charge_target = charge_target
ctl_proc.gen_target = gen_target
ctl_proc.limits = limits
local p = pctl.control_states.process
p.mode = mode
p.alt_mode = alt_mode
p.burn_target = burn_target
p.range_start = range_start
p.range_stop = range_stop
p.charge_target = charge_target
p.gen_target = gen_target
p.limits = limits
-- save config
pctl.io.facility.save_cfg_ack(_write_auto_config())
@@ -494,21 +502,35 @@ end
function process.start_ack_handle(response)
local ack = response[1]
local ctl_proc = pctl.control_states.process
ctl_proc.mode = response[2]
ctl_proc.burn_target = response[3]
ctl_proc.charge_target = response[4]
ctl_proc.gen_target = response[5]
local p = pctl.control_states.process
p.mode = response[2]
p.burn_target = response[3]
p.range_start = response[4]
p.range_stop = response[5]
p.charge_target = response[6]
p.gen_target = response[7]
for i = 1, math.min(#response[6], pctl.io.facility.num_units) do
ctl_proc.limits[i] = response[6][i]
pctl.io.units[i].unit_ps.publish("burn_limit", ctl_proc.limits[i])
for i = 1, math.min(#response[8], pctl.io.facility.num_units) do
p.limits[i] = response[8][i]
pctl.io.units[i].unit_ps.publish("burn_limit", p.limits[i])
end
pctl.io.facility.ps.publish("process_mode", ctl_proc.mode)
pctl.io.facility.ps.publish("process_burn_target", ctl_proc.burn_target)
pctl.io.facility.ps.publish("process_charge_target", pctl.io.energy_convert_from_fe(ctl_proc.charge_target))
pctl.io.facility.ps.publish("process_gen_target", pctl.io.energy_convert_from_fe(ctl_proc.gen_target))
if p.mode == PROCESS.RANGE_CONTROL then
p.mode = PROCESS.CHARGE
p.alt_mode = true
elseif p.mode == PROCESS.CHARGE then
p.alt_mode = false
end
local f_ps = pctl.io.facility.ps
f_ps.publish("process_mode", p.mode)
f_ps.publish("process_alt_mode", p.alt_mode)
f_ps.publish("process_burn_target", p.burn_target)
f_ps.publish("process_range_start", p.range_start)
f_ps.publish("process_range_stop", p.range_stop)
f_ps.publish("process_charge_target", pctl.io.energy_convert_from_fe(p.charge_target))
f_ps.publish("process_gen_target", pctl.io.energy_convert_from_fe(p.gen_target))
_write_auto_config()

View File

@@ -6,7 +6,7 @@ local log = require("scada-common.log")
local util = require("scada-common.util")
local coordinator = require("coordinator.coordinator")
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local style = require("coordinator.ui.style")
local pgi = require("coordinator.ui.pgi")
@@ -193,7 +193,7 @@ function renderer.try_start_ui()
if engine.monitors.main ~= nil then
engine.ui.main_display = DisplayBox{window=engine.monitors.main,fg_bg=style.root}
main_view(engine.ui.main_display)
iocontrol.fp_monitor_state("main", 3)
ioctl.fp_monitor_state("main", 3)
util.nop()
end
@@ -201,7 +201,7 @@ function renderer.try_start_ui()
if engine.monitors.flow ~= nil then
engine.ui.flow_display = DisplayBox{window=engine.monitors.flow,fg_bg=style.root}
flow_view(engine.ui.flow_display)
iocontrol.fp_monitor_state("flow", 3)
ioctl.fp_monitor_state("flow", 3)
util.nop()
end
@@ -209,7 +209,7 @@ function renderer.try_start_ui()
for idx, display in pairs(engine.monitors.unit_displays) do
engine.ui.unit_displays[idx] = DisplayBox{window=display,fg_bg=style.root}
unit_view(engine.ui.unit_displays[idx], idx)
iocontrol.fp_monitor_state(idx, 3)
ioctl.fp_monitor_state(idx, 3)
util.nop()
end
end)
@@ -239,17 +239,17 @@ function renderer.close_ui()
if engine.ui.main_display ~= nil then
engine.ui.main_display.delete()
iocontrol.fp_monitor_state("main", 2)
ioctl.fp_monitor_state("main", 2)
end
if engine.ui.flow_display ~= nil then
engine.ui.flow_display.delete()
iocontrol.fp_monitor_state("flow", 2)
ioctl.fp_monitor_state("flow", 2)
end
for idx, display in pairs(engine.ui.unit_displays) do
display.delete()
iocontrol.fp_monitor_state(idx, 2)
ioctl.fp_monitor_state(idx, 2)
end
-- report ui as not ready
@@ -360,7 +360,7 @@ function renderer.handle_resize(name)
ui.main_display = nil
end
iocontrol.fp_monitor_state("main", 2)
ioctl.fp_monitor_state("main", 2)
engine.dmesg_window.setVisible(not engine.ui_ready)
@@ -372,7 +372,7 @@ function renderer.handle_resize(name)
end)
if ok then
iocontrol.fp_monitor_state("main", 3)
ioctl.fp_monitor_state("main", 3)
log_render("main view re-draw completed in " .. (util.time_ms() - draw_start) .. "ms")
else
@@ -399,7 +399,7 @@ function renderer.handle_resize(name)
ui.flow_display = nil
end
iocontrol.fp_monitor_state("flow", 2)
ioctl.fp_monitor_state("flow", 2)
if engine.ui_ready then
local draw_start = util.time_ms()
@@ -409,7 +409,7 @@ function renderer.handle_resize(name)
end)
if ok then
iocontrol.fp_monitor_state("flow", 3)
ioctl.fp_monitor_state("flow", 3)
log_render("flow view re-draw completed in " .. (util.time_ms() - draw_start) .. "ms")
else
@@ -438,7 +438,7 @@ function renderer.handle_resize(name)
ui.unit_displays[idx] = nil
end
iocontrol.fp_monitor_state(idx, 2)
ioctl.fp_monitor_state(idx, 2)
if engine.ui_ready then
local draw_start = util.time_ms()
@@ -448,7 +448,7 @@ function renderer.handle_resize(name)
end)
if ok then
iocontrol.fp_monitor_state(idx, 3)
ioctl.fp_monitor_state(idx, 3)
log_render("unit " .. idx .. " view re-draw completed in " .. (util.time_ms() - draw_start) .. "ms")
else

View File

@@ -1,11 +1,11 @@
local log = require("scada-common.log")
local mqueue = require("scada-common.mqueue")
local util = require("scada-common.util")
local log = require("scada-common.log")
local mqueue = require("scada-common.mqueue")
local util = require("scada-common.util")
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local pocket = require("coordinator.session.pocket")
local pocket = require("coordinator.session.pocket")
local apisessions = {}
@@ -112,7 +112,7 @@ function apisessions.establish_session(source_addr, i_seq_num, version)
setmetatable(pkt_s, mt)
iocontrol.fp_pkt_connected(id, version, source_addr)
ioctl.fp_pkt_connected(id, version, source_addr)
log.debug(util.c("API: established new session: ", pkt_s))
self.next_id = id + 1
@@ -123,6 +123,7 @@ end
-- attempt to identify which session's watchdog timer fired
---@param timer_event number
---@return boolean was_watchdog if this event was one of the watchdogs
function apisessions.check_all_watchdogs(timer_event)
for i = 1, #self.sessions do
local session = self.sessions[i]
@@ -131,9 +132,12 @@ function apisessions.check_all_watchdogs(timer_event)
if triggered then
log.debug(util.c("API: watchdog closing session ", session, "..."))
_shutdown(session)
return true
end
end
end
return false
end
-- iterate all the API sessions

View File

@@ -1,11 +1,11 @@
local comms = require("scada-common.comms")
local log = require("scada-common.log")
local mqueue = require("scada-common.mqueue")
local types = require("scada-common.types")
local util = require("scada-common.util")
local comms = require("scada-common.comms")
local log = require("scada-common.log")
local mqueue = require("scada-common.mqueue")
local types = require("scada-common.types")
local util = require("scada-common.util")
local iocontrol = require("coordinator.iocontrol")
local process = require("coordinator.process")
local ioctl = require("coordinator.ioctl")
local process = require("coordinator.process")
local pocket = {}
@@ -16,6 +16,7 @@ local FAC_COMMAND = comms.FAC_COMMAND
local UNIT_COMMAND = comms.UNIT_COMMAND
local AUTO_GROUP = types.AUTO_GROUP
local PROCESS = types.PROCESS
local WASTE_MODE = types.WASTE_MODE
-- retry time constants in ms
@@ -79,7 +80,7 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
local function _close()
self.conn_watchdog.cancel()
self.connected = false
iocontrol.fp_pkt_disconnected(id)
ioctl.fp_pkt_disconnected(id)
end
-- send a CRDN packet
@@ -118,7 +119,7 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
f_ack.on_start = function (success) _send(CRDN_TYPE.FAC_CMD, { FAC_COMMAND.START, success }) end
f_ack.on_stop = function (success) _send(CRDN_TYPE.FAC_CMD, { FAC_COMMAND.STOP, success }) end
for u = 1, iocontrol.get_db().facility.num_units do
for u = 1, ioctl.get_db().facility.num_units do
local u_ack = self.proc_handle.unit_ack[u]
u_ack.on_start = function (success) _send(CRDN_TYPE.UNIT_CMD, { UNIT_COMMAND.START, u, success }) end
u_ack.on_scram = function (success) _send(CRDN_TYPE.UNIT_CMD, { UNIT_COMMAND.SCRAM, u, success }) end
@@ -144,7 +145,7 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
if pkt.scada_frame.protocol() == PROTOCOL.SCADA_CRDN then
---@cast pkt crdn_packet
local db = iocontrol.get_db()
local db = ioctl.get_db()
-- handle packet by type
if pkt.type == CRDN_TYPE.FAC_CMD then
@@ -158,9 +159,9 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
log.info(log_tag .. "STOP PROCESS CTRL")
self.proc_handle.process_stop()
elseif cmd == FAC_COMMAND.START then
if pkt.length == 6 then
if pkt.length == 8 then
log.info(log_tag .. "START PROCESS CTRL")
self.proc_handle.process_start_remote(pkt.data[2], pkt.data[3], pkt.data[4], pkt.data[5], pkt.data[6])
self.proc_handle.process_start_remote({ table.unpack(pkt.data, 2) })
else
log.debug(log_tag .. "CRDN auto start (with configuration) packet length mismatch")
end
@@ -374,13 +375,15 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
}
end
local mode = util.trinary(proc.alt_mode and proc.mode == PROCESS.CHARGE, PROCESS.RANGE_CONTROL, proc.mode)
-- facility data
data[#db.units + 1] = {
fac.status_lines,
{ fac.auto_ready, fac.auto_active, fac.auto_ramping, fac.auto_saturated },
fac.auto_scram,
fac.ascram_status,
{ proc.mode, proc.burn_target, proc.charge_target, proc.gen_target }
{ mode, proc.burn_target, proc.range_start, proc.range_stop, proc.charge_target, proc.gen_target }
}
_send(CRDN_TYPE.API_GET_PROC, data)
@@ -452,7 +455,7 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
-- log.debug(log_header .. "PKT RTT = " .. self.last_rtt .. "ms")
-- log.debug(log_header .. "PKT TT = " .. (srv_now - api_send) .. "ms")
iocontrol.fp_pkt_rtt(id, self.last_rtt)
ioctl.fp_pkt_rtt(id, self.last_rtt)
else
log.debug(log_tag .. "SCADA keep alive packet length mismatch")
end

View File

@@ -15,12 +15,12 @@ local util = require("scada-common.util")
local backplane = require("coordinator.backplane")
local configure = require("coordinator.configure")
local coordinator = require("coordinator.coordinator")
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local renderer = require("coordinator.renderer")
local sounder = require("coordinator.sounder")
local threads = require("coordinator.threads")
local COORDINATOR_VERSION = "v1.7.8"
local COORDINATOR_VERSION = "v1.8.1"
local CHUNK_LOAD_DELAY_S = 30.0
@@ -137,7 +137,7 @@ local function main()
----------------------------------------
-- report versions
iocontrol.fp_versions(COORDINATOR_VERSION, comms.version)
ioctl.fp_versions(COORDINATOR_VERSION, comms.version)
-- init renderer
renderer.configure(config)

View File

@@ -6,7 +6,7 @@ local util = require("scada-common.util")
local backplane = require("coordinator.backplane")
local coordinator = require("coordinator.coordinator")
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local process = require("coordinator.process")
local renderer = require("coordinator.renderer")
local sounder = require("coordinator.sounder")
@@ -33,7 +33,7 @@ function threads.thread__main(smem)
-- execute thread
function public.exec()
iocontrol.fp_rt_status("main", true)
ioctl.fp_rt_status("main", true)
log.debug("OS: main thread start")
local loop_clock = util.new_clock(MAIN_CLOCK)
@@ -51,78 +51,52 @@ function threads.thread__main(smem)
local MQ__RENDER_CMD = smem.q_types.MQ__RENDER_CMD
local MQ__RENDER_DATA = smem.q_types.MQ__RENDER_DATA
-- main loop periodic tasks
---@return boolean exit if the application should exit
local function loop_tick()
-- toggle heartbeat
ioctl.heartbeat()
-- periodic hardware tasks
backplane.periodic()
-- maintain connection
local ok, start_ui = coord_comms.manage_link()
if not ok then
crd_state.link_fail = true
crd_state.shutdown = true
log_sys("supervisor connection failed, shutting down...")
log.fatal("failed to connect to supervisor")
return true
elseif start_ui then
log_sys("supervisor connected, dispatching main UI start")
smem.q.mq_render.push_command(MQ__RENDER_CMD.START_MAIN_UI)
end
-- iterate sessions and free any closed ones
apisessions.iterate_all()
apisessions.free_all_closed()
-- clear timed out process commands
process.clear_timed_out()
if renderer.ui_ready() then
-- update clock used on main and flow monitors
ioctl.get_db().facility.ps.publish("date_time", os.date(smem.date_format))
end
-- start next clock timer
loop_clock.start()
return false
end
-- 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
backplane.detach(type, device, param1)
end
elseif event == "peripheral" then
local type, device = ppm.mount(param1)
if type ~= nil and device ~= nil then
backplane.attach(type, device, param1)
end
elseif event == "monitor_resize" then
smem.q.mq_render.push_data(MQ__RENDER_DATA.MON_RESIZE, param1)
elseif event == "timer" then
if loop_clock.is_clock(param1) then
-- main loop tick
-- toggle heartbeat
iocontrol.heartbeat()
-- periodic hardware tasks
backplane.periodic()
-- maintain connection
local ok, start_ui = coord_comms.manage_link()
if not ok then
crd_state.link_fail = true
crd_state.shutdown = true
log_sys("supervisor connection failed, shutting down...")
log.fatal("failed to connect to supervisor")
break
elseif start_ui then
log_sys("supervisor connected, dispatching main UI start")
smem.q.mq_render.push_command(MQ__RENDER_CMD.START_MAIN_UI)
end
-- iterate sessions and free any closed ones
apisessions.iterate_all()
apisessions.free_all_closed()
-- clear timed out process commands
process.clear_timed_out()
if renderer.ui_ready() then
-- update clock used on main and flow monitors
iocontrol.get_db().facility.ps.publish("date_time", os.date(smem.date_format))
end
-- start next clock timer
loop_clock.start()
elseif conn_watchdog.is_timer(param1) then
-- supervisor watchdog timeout
log_comms("supervisor server timeout")
-- close main UI, connection, and stop sounder
smem.q.mq_render.push_command(MQ__RENDER_CMD.CLOSE_MAIN_UI)
coord_comms.close()
sounder.stop()
else
-- a non-clock/main watchdog timer event
-- check API watchdogs
apisessions.check_all_watchdogs(param1)
-- notify timer callback dispatcher
tcd.handle(param1)
end
elseif event == "modem_message" then
if event == "modem_message" then
-- got a packet
local packet = coord_comms.parse_packet(param1, param2, param3, param4, param5)
@@ -135,13 +109,42 @@ function threads.thread__main(smem)
coord_comms.close()
sounder.stop()
end
elseif event == "timer" then
-- pass this timer event onto the right handler
if loop_clock.is_clock(param1) then
-- main loop tick
if loop_tick() then break end
elseif conn_watchdog.is_timer(param1) then
-- supervisor connection timed out
log_comms("supervisor server timeout")
-- close main UI, connection, and stop sounder
smem.q.mq_render.push_command(MQ__RENDER_CMD.CLOSE_MAIN_UI)
coord_comms.close()
sounder.stop()
elseif not apisessions.check_all_watchdogs(param1) then -- check API watchdogs
-- notify timer callback dispatcher, no other handler claimed this event
tcd.handle(param1)
end
elseif event == "speaker_audio_empty" then
-- handle speaker buffer emptied
sounder.continue()
elseif event == "monitor_touch" or event == "mouse_click" or event == "mouse_up" or
event == "mouse_drag" or event == "mouse_scroll" or event == "double_click" then
-- handle a mouse event
renderer.handle_mouse(core.events.new_mouse_event(event, param1, param2, param3))
elseif event == "speaker_audio_empty" then
-- handle speaker buffer emptied
sounder.continue()
elseif event == "monitor_resize" then
smem.q.mq_render.push_data(MQ__RENDER_DATA.MON_RESIZE, param1)
elseif event == "peripheral" then
local type, device = ppm.mount(param1)
if type ~= nil and device ~= nil then
backplane.attach(type, device, param1)
end
elseif event == "peripheral_detach" then
local type, device = ppm.handle_unmount(param1)
if type ~= nil and device ~= nil then
backplane.detach(type, device, param1)
end
end
-- check for termination request or UI crash
@@ -183,7 +186,7 @@ function threads.thread__main(smem)
log.fatal(util.strval(result))
end
iocontrol.fp_rt_status("main", false)
ioctl.fp_rt_status("main", false)
-- if status is true, then we are probably exiting, so this won't matter
-- this thread cannot be slept because it will miss events (namely "terminate")
@@ -205,7 +208,7 @@ function threads.thread__render(smem)
-- execute thread
function public.exec()
iocontrol.fp_rt_status("render", true)
ioctl.fp_rt_status("render", true)
log.debug("OS: render thread start")
-- load in from shared memory
@@ -300,7 +303,7 @@ function threads.thread__render(smem)
log.fatal(util.strval(result))
end
iocontrol.fp_rt_status("render", false)
ioctl.fp_rt_status("render", false)
if not crd_state.shutdown then
log.info("OS: render thread restarting in 5 seconds...")

View File

@@ -1,4 +1,4 @@
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local style = require("coordinator.ui.style")
@@ -23,7 +23,7 @@ local function new_view(root, x, y, ps)
local text_fg = style.theme.text_fg
local lu_col = style.lu_colors
local db = iocontrol.get_db()
local db = ioctl.get_db()
local boiler = Rectangle{parent=root,border=border(1,colors.gray,true),width=31,height=7,x=x,y=y}

View File

@@ -1,6 +1,6 @@
local util = require("scada-common.util")
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local style = require("coordinator.ui.style")
@@ -35,7 +35,7 @@ local function new_view(root, x, y, ps, id)
local ind_yel = style.ind_yel
local ind_wht = style.ind_wht
local db = iocontrol.get_db()
local db = ioctl.get_db()
local title = "INDUCTION MATRIX"
if type(id) == "number" then title = title .. id end
@@ -45,10 +45,10 @@ local function new_view(root, x, y, ps, id)
-- black has low contrast with dark gray, so if background is black use white instead
local cutout_fg_bg = cpair(util.trinary(style.theme.bg == colors.black, colors.white, style.theme.bg), colors.gray)
TextBox{parent=matrix,text=" ",width=33,x=1,y=1,fg_bg=cutout_fg_bg}
TextBox{parent=matrix,text=title,alignment=ALIGN.CENTER,width=33,x=1,y=2,fg_bg=cutout_fg_bg}
TextBox{parent=matrix,text=" ",width=33,y=1,fg_bg=cutout_fg_bg}
TextBox{parent=matrix,text=title,alignment=ALIGN.CENTER,width=33,y=2,fg_bg=cutout_fg_bg}
local rect = Rectangle{parent=matrix,border=border(1,colors.gray,true),width=33,height=22,x=1,y=3}
local rect = Rectangle{parent=matrix,border=border(1,colors.gray,true),width=33,height=22,y=3}
local status = StateIndicator{parent=rect,x=10,y=1,states=style.imatrix.states,value=1,min_width=14}
local capacity = PowerIndicator{parent=rect,x=7,y=3,lu_colors=lu_col,label="Capacity:",unit=db.energy_label,format="%8.2f",value=0,width=26,fg_bg=text_fg}

View File

@@ -2,7 +2,7 @@
-- Pocket Connection Entry
--
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local style = require("coordinator.ui.style")
@@ -26,7 +26,7 @@ local function init(parent, id)
local label_fg = style.fp.label_fg
local ps = iocontrol.get_db().fp.ps
local ps = ioctl.get_db().fp.ps
local term_w, _ = term.getSize()
@@ -36,9 +36,9 @@ local function init(parent, id)
local ps_prefix = "pkt_" .. id .. "_"
TextBox{parent=entry,x=1,y=1,text="",width=8,fg_bg=s_hi_box}
local pkt_addr = TextBox{parent=entry,x=1,y=2,text="@ C ??",alignment=ALIGN.CENTER,width=8,fg_bg=s_hi_box,nav_active=cpair(colors.gray,colors.black)}
TextBox{parent=entry,x=1,y=3,text="",width=8,fg_bg=s_hi_box}
TextBox{parent=entry,y=1,text="",width=8,fg_bg=s_hi_box}
local pkt_addr = TextBox{parent=entry,y=2,text="@ C ??",alignment=ALIGN.CENTER,width=8,fg_bg=s_hi_box,nav_active=cpair(colors.gray,colors.black)}
TextBox{parent=entry,y=3,text="",width=8,fg_bg=s_hi_box}
pkt_addr.register(ps, ps_prefix .. "addr", pkt_addr.set_value)
TextBox{parent=entry,x=10,y=2,text="FW:",width=3}

View File

@@ -1,7 +1,7 @@
local tcd = require("scada-common.tcd")
local util = require("scada-common.util")
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local process = require("coordinator.process")
local style = require("coordinator.ui.style")
@@ -22,6 +22,7 @@ local Checkbox = require("graphics.elements.controls.Checkbox")
local HazardButton = require("graphics.elements.controls.HazardButton")
local NumericSpinbox = require("graphics.elements.controls.NumericSpinbox")
local RadioButton = require("graphics.elements.controls.RadioButton")
local SwitchButton = require("graphics.elements.controls.SwitchButton")
local ALIGN = core.ALIGN
@@ -56,14 +57,14 @@ local function new_view(root, x, y)
local blk_brn = cpair(colors.black, colors.brown)
local blk_pur = cpair(colors.black, colors.purple)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local facility = db.facility
local units = db.units
local main = Div{parent=root,width=128,height=24,x=x,y=y}
local scram = HazardButton{parent=main,x=1,y=1,text="FAC SCRAM",accent=colors.yellow,dis_colors=dis_colors,callback=db.process.fac_scram,fg_bg=hzd_fg_bg}
local scram = HazardButton{parent=main,y=1,text="FAC SCRAM",accent=colors.yellow,dis_colors=dis_colors,callback=db.process.fac_scram,fg_bg=hzd_fg_bg}
local ack_a = HazardButton{parent=main,x=16,y=1,text="ACK \x13",accent=colors.orange,dis_colors=dis_colors,callback=db.process.fac_ack_alarms,fg_bg=hzd_fg_bg}
db.process.fac_ack.on_scram = scram.on_response
@@ -125,9 +126,9 @@ local function new_view(root, x, y)
-- process control targets --
-----------------------------
local targets = Div{parent=proc,width=31,height=24,x=1,y=1}
local targets = Div{parent=proc,width=31,height=24,y=1}
local burn_tag = Div{parent=targets,x=1,y=1,width=8,height=4,fg_bg=blk_pur}
local burn_tag = Div{parent=targets,y=1,width=8,height=4,fg_bg=blk_pur}
TextBox{parent=burn_tag,x=2,y=2,text="Burn Target",width=7,height=2}
local burn_target = Div{parent=targets,x=9,y=1,width=23,height=3,fg_bg=s_hi_box}
@@ -138,18 +139,47 @@ local function new_view(root, x, y)
b_target.register(facility.ps, "process_burn_target", b_target.set_value)
burn_sum.register(facility.ps, "burn_sum", burn_sum.update)
local chg_tag = Div{parent=targets,x=1,y=6,width=8,height=4,fg_bg=blk_pur}
TextBox{parent=chg_tag,x=2,y=2,text="Charge Target",width=7,height=2}
local chg_tag = Div{parent=targets,y=6,width=8,height=4,fg_bg=blk_pur}
local chg_tag_text = TextBox{parent=chg_tag,x=2,y=2,text="Charge Target",width=7,height=2}
local chg_target = Div{parent=targets,x=9,y=6,width=23,height=3,fg_bg=s_hi_box}
local c_target = NumericSpinbox{parent=chg_target,x=2,y=1,whole_num_precision=15,fractional_precision=0,min=0,arrow_fg_bg=arrow_fg_bg,arrow_disable=style.theme.disabled}
TextBox{parent=chg_target,x=18,y=2,text="M"..db.energy_label,fg_bg=style.theme.label_fg}
local cur_charge = DataIndicator{parent=targets,x=9,y=9,label="",format="%19d",value=0,unit="M"..db.energy_label,commas=true,lu_colors=black,width=23,fg_bg=blk_brn}
local range_start, range_stop ---@type NumericSpinbox, NumericSpinbox
local function _update_start_val(value) range_start.set_value(math.min(range_start.get_value(), value - 1)) end
local function _update_stop_val(value) range_stop.set_value(math.max(range_stop.get_value(), value + 1)) end
local chg_range = Div{parent=targets,x=9,y=6,width=23,height=3,fg_bg=s_hi_box,hidden=true}
TextBox{parent=chg_range,x=2,y=2,text="START",fg_bg=style.theme.label_fg}
range_start = NumericSpinbox{parent=chg_range,x=8,y=1,whole_num_precision=3,fractional_precision=0,min=0,max=99,callback=_update_stop_val,arrow_fg_bg=arrow_fg_bg,arrow_disable=style.theme.disabled}
TextBox{parent=chg_range,x=11,y=2,text="% \x1a STOP",fg_bg=style.theme.label_fg}
range_stop = NumericSpinbox{parent=chg_range,x=20,y=1,whole_num_precision=3,fractional_precision=0,min=1,max=100,callback=_update_start_val,arrow_fg_bg=arrow_fg_bg,arrow_disable=style.theme.disabled}
TextBox{parent=chg_range,x=23,y=2,text="%",fg_bg=style.theme.label_fg}
local cur_charge = DataIndicator{parent=targets,x=11,y=9,label="",format="%17d",value=0,unit="M"..db.energy_label,commas=true,lu_colors=black,width=23,fg_bg=blk_brn}
local chg_mode = SwitchButton{parent=targets,x=9,y=9,text="\x12T",active_text="\x12R",callback=function(v)facility.ps.publish("process_alt_mode", v)end,fg_bg=cpair(colors.black,colors.pink),dis_fg_bg=dis_colors}
c_target.register(facility.ps, "process_charge_target", c_target.set_value)
range_start.register(facility.ps, "process_range_start", range_start.set_value)
range_stop.register(facility.ps, "process_range_stop", range_stop.set_value)
cur_charge.register(facility.induction_ps_tbl[1], "avg_charge", function (fe) cur_charge.update(db.energy_convert_from_fe(fe) / 1000000) end)
chg_mode.register(facility.ps, "process_alt_mode", chg_mode.set_value)
local gen_tag = Div{parent=targets,x=1,y=11,width=8,height=4,fg_bg=blk_pur}
targets.register(facility.ps, "process_alt_mode", function (alt)
if alt then
chg_target.hide()
chg_range.show()
chg_tag_text.set_value("Charge Range")
else
chg_target.show()
chg_range.hide()
chg_tag_text.set_value("Charge Target")
end
end)
local gen_tag = Div{parent=targets,y=11,width=8,height=4,fg_bg=blk_pur}
TextBox{parent=gen_tag,x=2,y=2,text="Gen. Target",width=7,height=2}
local gen_target = Div{parent=targets,x=9,y=11,width=23,height=3,fg_bg=s_hi_box}
@@ -187,7 +217,7 @@ local function new_view(root, x, y)
local _y = ((i - 1) * 5) + 1
local unit_tag = Div{parent=limit_div,x=1,y=_y,width=8,height=4,fg_bg=tag_fg_bg}
local unit_tag = Div{parent=limit_div,y=_y,width=8,height=4,fg_bg=tag_fg_bg}
TextBox{parent=unit_tag,x=2,y=2,text="Unit "..i.." Limit",width=7,height=2}
local lim_ctl = Div{parent=limit_div,x=9,y=_y,width=14,height=3,fg_bg=s_hi_box}
@@ -226,7 +256,7 @@ local function new_view(root, x, y)
local _y = ((i - 1) * 5) + 1
local unit_tag = Div{parent=stat_div,x=1,y=_y,width=8,height=4,fg_bg=tag_fg_bg}
local unit_tag = Div{parent=stat_div,y=_y,width=8,height=4,fg_bg=tag_fg_bg}
TextBox{parent=unit_tag,x=2,y=2,text="Unit "..i.." Status",width=7,height=2}
local lights = Div{parent=stat_div,x=9,y=_y,width=14,height=4,fg_bg=ind_fg_bg}
@@ -246,26 +276,48 @@ local function new_view(root, x, y)
-------------------------
local ctl_opts = { "Monitored Max Burn", "Combined Burn Rate", "Charge Level", "Generation Rate" }
local alt_opts = { "Monitored Max Burn", "Combined Burn Rate", "Charge Range", "Generation Rate" }
local mode = RadioButton{parent=proc,x=34,y=1,options=ctl_opts,radio_colors=cpair(style.theme.accent_dark,style.theme.accent_light),select_color=colors.purple}
local alt_mode = RadioButton{parent=proc,x=34,y=1,options=alt_opts,radio_colors=cpair(style.theme.accent_dark,style.theme.accent_light),select_color=colors.purple,callback=function(v)mode.set_value(v)end,hidden=true}
mode.register(facility.ps, "process_mode", mode.set_value)
alt_mode.register(facility.ps, "process_mode", alt_mode.set_value)
local u_stat = Rectangle{parent=proc,border=border(1,colors.gray,true),thin=true,width=31,height=4,x=1,y=16,fg_bg=bw_fg_bg}
local stat_line_1 = TextBox{parent=u_stat,x=1,y=1,text="UNKNOWN",width=31,alignment=ALIGN.CENTER,fg_bg=bw_fg_bg}
local stat_line_2 = TextBox{parent=u_stat,x=1,y=2,text="awaiting data...",width=31,alignment=ALIGN.CENTER,fg_bg=cpair(colors.gray,colors.white)}
proc.register(facility.ps, "process_alt_mode", function (alt)
if alt then
alt_mode.set_value(mode.get_value())
mode.hide()
alt_mode.show()
chg_tag_text.set_value("Charge Range")
else
mode.set_value(alt_mode.get_value())
alt_mode.hide()
mode.show()
chg_tag_text.set_value("Charge Target")
end
end)
local u_stat = Rectangle{parent=proc,border=border(1,colors.gray,true),thin=true,width=31,height=4,y=16,fg_bg=bw_fg_bg}
local stat_line_1 = TextBox{parent=u_stat,y=1,text="UNKNOWN",width=31,alignment=ALIGN.CENTER,fg_bg=bw_fg_bg}
local stat_line_2 = TextBox{parent=u_stat,y=2,text="awaiting data...",width=31,alignment=ALIGN.CENTER,fg_bg=cpair(colors.gray,colors.white)}
stat_line_1.register(facility.ps, "status_line_1", stat_line_1.set_value)
stat_line_2.register(facility.ps, "status_line_2", stat_line_2.set_value)
local auto_controls = Div{parent=proc,x=1,y=20,width=31,height=5,fg_bg=s_hi_box}
local auto_controls = Div{parent=proc,y=20,width=31,height=5,fg_bg=s_hi_box}
-- save the automatic process control configuration without starting
local function _save_cfg()
local limits = {}
for i = 1, #rate_limits do limits[i] = rate_limits[i].get_value() end
process.save(mode.get_value(), b_target.get_value(), db.energy_convert_to_fe(c_target.get_value()),
db.energy_convert_to_fe(g_target.get_value()), limits)
-- make sure stop is always above start (start maxes at 99 and stop maxes at 100 so this always works)
if range_stop.get_value() <= range_start.get_value() then
range_stop.set_value(range_start.get_value() + 1)
end
process.save(mode.get_value(), chg_mode.get_value(), b_target.get_value(), range_start.get_value(), range_stop.get_value(),
db.energy_convert_to_fe(c_target.get_value()), db.energy_convert_to_fe(g_target.get_value()), limits)
end
-- start automatic control after saving process control settings
@@ -296,18 +348,26 @@ local function new_view(root, x, y)
if active then
b_target.disable()
c_target.disable()
range_start.disable()
range_stop.disable()
g_target.disable()
mode.disable()
alt_mode.disable()
chg_mode.disable()
start.disable()
for i = 1, #rate_limits do rate_limits[i].disable() end
else
b_target.enable()
c_target.enable()
range_start.enable()
range_stop.enable()
g_target.enable()
mode.enable()
alt_mode.enable()
chg_mode.enable()
if facility.auto_ready then start.enable() end
for i = 1, #rate_limits do rate_limits[i].enable() end
@@ -335,10 +395,10 @@ local function new_view(root, x, y)
local cutout_fg_bg = cpair(style.theme.bg, colors.brown)
TextBox{parent=waste_sel,text=" ",width=21,x=1,y=1,fg_bg=cutout_fg_bg}
TextBox{parent=waste_sel,text="WASTE PRODUCTION",alignment=ALIGN.CENTER,width=21,x=1,y=2,fg_bg=cutout_fg_bg}
TextBox{parent=waste_sel,text=" ",width=21,y=1,fg_bg=cutout_fg_bg}
TextBox{parent=waste_sel,text="WASTE PRODUCTION",alignment=ALIGN.CENTER,width=21,y=2,fg_bg=cutout_fg_bg}
local rect = Rectangle{parent=waste_sel,border=border(1,colors.brown,true),width=21,height=22,x=1,y=3}
local rect = Rectangle{parent=waste_sel,border=border(1,colors.brown,true),width=21,height=22,y=3}
local status = StateIndicator{parent=rect,x=2,y=1,states=style.get_waste().states,value=1,min_width=17}
status.register(facility.ps, "current_waste_product", status.update)

View File

@@ -1,6 +1,6 @@
local types = require("scada-common.types")
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local style = require("coordinator.ui.style")
@@ -25,7 +25,7 @@ local function new_view(root, x, y, ps)
local text_fg = style.theme.text_fg
local lu_col = style.lu_colors
local db = iocontrol.get_db()
local db = ioctl.get_db()
local reactor = Rectangle{parent=root,border=border(1,colors.gray,true),width=30,height=7,x=x,y=y}

View File

@@ -1,4 +1,4 @@
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local style = require("coordinator.ui.style")
@@ -24,7 +24,7 @@ local function new_view(root, x, y, ps)
local text_fg = style.theme.text_fg
local lu_col = style.lu_colors
local db = iocontrol.get_db()
local db = ioctl.get_db()
local turbine = Rectangle{parent=root,border=border(1,colors.gray,true),width=23,height=7,x=x,y=y}

View File

@@ -5,7 +5,7 @@
local types = require("scada-common.types")
local util = require("scada-common.util")
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local style = require("coordinator.ui.style")
@@ -61,11 +61,11 @@ local function init(parent, id)
local ind_red = style.ind_red
local ind_wht = style.ind_wht
local db = iocontrol.get_db()
local db = ioctl.get_db()
local unit = db.units[id]
local f_ps = db.facility.ps
local main = Div{parent=parent,x=1,y=1}
local main = Div{parent=parent,y=1}
if unit == nil then return main end
@@ -146,8 +146,8 @@ local function init(parent, id)
-------------------
local u_stat = Rectangle{parent=main,border=border(1,colors.gray,true),thin=true,width=33,height=4,x=46,y=3,fg_bg=bw_fg_bg}
local stat_line_1 = TextBox{parent=u_stat,x=1,y=1,text="UNKNOWN",width=33,alignment=ALIGN.CENTER,fg_bg=bw_fg_bg}
local stat_line_2 = TextBox{parent=u_stat,x=1,y=2,text="awaiting data...",width=33,alignment=ALIGN.CENTER,fg_bg=gry_wht}
local stat_line_1 = TextBox{parent=u_stat,y=1,text="UNKNOWN",width=33,alignment=ALIGN.CENTER,fg_bg=bw_fg_bg}
local stat_line_2 = TextBox{parent=u_stat,y=2,text="awaiting data...",width=33,alignment=ALIGN.CENTER,fg_bg=gry_wht}
stat_line_1.register(u_ps, "U_StatusLine1", stat_line_1.set_value)
stat_line_2.register(u_ps, "U_StatusLine2", stat_line_2.set_value)
@@ -238,7 +238,7 @@ local function init(parent, id)
TextBox{parent=main,text="REACTOR COOLANT SYSTEM",fg_bg=cpair(colors.black,colors.blue),alignment=ALIGN.CENTER,width=33,x=46,y=22}
local rcs = Rectangle{parent=main,border=border(1,colors.blue,true),thin=true,width=33,height=24,x=46,y=23}
local rcs_annunc = Div{parent=rcs,width=27,height=22,x=3,y=1}
local rcs_tags = Div{parent=rcs,width=2,height=16,x=1,y=7}
local rcs_tags = Div{parent=rcs,width=2,height=16,y=7}
local c_flt = IndicatorLight{parent=rcs_annunc,label="RCS Hardware Fault",colors=ind_yel}
local c_emg = TriIndicatorLight{parent=rcs_annunc,label="Emergency Coolant",c1=ind_bkg,c2=ind_wht.fgd,c3=ind_grn.fgd}
@@ -267,7 +267,7 @@ local function init(parent, id)
if unit.num_boilers > 0 then
if available_space > 0 then _add_space() end
TextBox{parent=rcs_tags,x=1,text="B1",width=2,fg_bg=hc_text}
TextBox{parent=rcs_tags,text="B1",width=2,fg_bg=hc_text}
local b1_wll = IndicatorLight{parent=rcs_annunc,label="Water Level Low",colors=ind_red}
b1_wll.register(b_ps[1], "WaterLevelLow", b1_wll.update)
@@ -398,7 +398,7 @@ local function init(parent, id)
local waste_proc = Rectangle{parent=main,border=border(1,colors.brown,true),thin=true,width=33,height=3,x=46,y=49}
local waste_div = Div{parent=waste_proc,x=2,y=1,width=31,height=1}
local waste_mode = MultiButton{parent=waste_div,x=1,y=1,options=style.get_waste().unit_opts,callback=unit.set_waste,min_width=6}
local waste_mode = MultiButton{parent=waste_div,y=1,options=style.get_waste().unit_opts,callback=unit.set_waste,min_width=6}
waste_mode.register(u_ps, "U_WasteMode", waste_mode.set_value)
@@ -484,7 +484,7 @@ local function init(parent, id)
TextBox{parent=main,text="AUTO CTRL",fg_bg=cpair(colors.black,colors.purple),alignment=ALIGN.CENTER,width=13,x=32,y=36}
local auto_ctl = Rectangle{parent=main,border=border(1,colors.purple,true),thin=true,width=13,height=15,x=32,y=37}
local auto_div = Div{parent=auto_ctl,width=13,height=15,x=1,y=1}
local auto_div = Div{parent=auto_ctl,width=13,height=15,y=1}
local group = RadioButton{parent=auto_div,options=types.AUTO_GROUP_NAMES,radio_colors=cpair(style.theme.accent_dark,style.theme.accent_light),select_color=colors.purple}

View File

@@ -5,7 +5,7 @@
local types = require("scada-common.types")
local util = require("scada-common.util")
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local style = require("coordinator.ui.style")
@@ -53,11 +53,11 @@ local function make(parent, x, y, wide, unit_id)
local height = 16
local facility = iocontrol.get_db().facility
local unit = iocontrol.get_db().units[unit_id]
local fac = ioctl.get_db().facility
local unit = ioctl.get_db().units[unit_id]
local tank_conns = facility.tank_conns
local tank_types = facility.tank_fluid_types
local tank_conns = fac.tank_conns
local tank_types = fac.tank_fluid_types
local v_start = 1 + ((unit.unit_id - 1) * 6)
local prv_start = 1 + ((unit.unit_id - 1) * 3)
@@ -83,7 +83,7 @@ local function make(parent, x, y, wide, unit_id)
-- COOLING LOOP --
------------------
local reactor = Rectangle{parent=root,x=1,y=1,border=border(1,colors.gray,true),width=19,height=5,fg_bg=wh_gray}
local reactor = Rectangle{parent=root,y=1,border=border(1,colors.gray,true),width=19,height=5,fg_bg=wh_gray}
TextBox{parent=reactor,y=1,text="FISSION REACTOR",alignment=ALIGN.CENTER}
TextBox{parent=reactor,y=3,text="UNIT #"..unit.unit_id,alignment=ALIGN.CENTER}
TextBox{parent=root,x=19,y=2,text="\x1b \x80 \x1a",width=1,height=3,fg_bg=lg_gray}
@@ -98,7 +98,7 @@ local function make(parent, x, y, wide, unit_id)
table.insert(rc_pipes, pipe(_wide(46, 39), 3, _wide(72, 58), 3, colors.white, true))
if unit.aux_coolant then
local em_water = facility.tank_fluid_types[facility.tank_conns[unit_id]] == COOLANT_TYPE.WATER
local em_water = fac.tank_fluid_types[fac.tank_conns[unit_id]] == COOLANT_TYPE.WATER
local offset = util.trinary(unit.has_tank and em_water, 3, 0)
table.insert(rc_pipes, pipe(_wide(51, 41) + offset, 0, _wide(51, 41) + offset, 0, colors.blue, true))
end
@@ -191,7 +191,7 @@ local function make(parent, x, y, wide, unit_id)
pipe(_wide(132, 110), 6, _wide(130, 108), 6, waste_c, true, true)
}
PipeNetwork{parent=waste,x=1,y=1,pipes=waste_pipes,bg=style.theme.bg}
PipeNetwork{parent=waste,y=1,pipes=waste_pipes,bg=style.theme.bg}
local function _valve(vx, vy, n)
TextBox{parent=waste,x=vx,y=vy,text="\x10\x11",fg_bg=text_c,width=2}
@@ -207,7 +207,7 @@ local function make(parent, x, y, wide, unit_id)
TextBox{parent=waste,x=mx,y=my+1,text=name,alignment=ALIGN.CENTER,fg_bg=style.theme.header,width=l}
end
local waste_rate = DataIndicator{parent=waste,x=1,y=3,lu_colors=lu_c,label="",unit="mB/t",format="%7.2f",value=0,width=12,fg_bg=s_field}
local waste_rate = DataIndicator{parent=waste,y=3,lu_colors=lu_c,label="",unit="mB/t",format="%7.2f",value=0,width=12,fg_bg=s_field}
local pu_rate = DataIndicator{parent=waste,x=_wide(82,70),y=3,lu_colors=lu_c,label="",unit="mB/t",format="%7.3f",value=0,width=12,fg_bg=s_field}
local po_rate = DataIndicator{parent=waste,x=_wide(52,45),y=6,lu_colors=lu_c,label="",unit="mB/t",format="%7.2f",value=0,width=12,fg_bg=s_field}
local popl_rate = DataIndicator{parent=waste,x=_wide(82,70),y=6,lu_colors=lu_c,label="",unit="mB/t",format="%7.2f",value=0,width=12,fg_bg=s_field}

View File

@@ -22,7 +22,7 @@ local pipe = core.pipe
---@param parent Container parent
---@param x integer top left x
---@param y integer top left y
---@param unit ioctl_unit unit database entry
---@param unit crd_io_unit unit database entry
local function make(parent, x, y, unit)
local num_boilers = #unit.boiler_data_tbl
local num_turbines = #unit.turbine_data_tbl

View File

@@ -5,7 +5,7 @@
local types = require("scada-common.types")
local util = require("scada-common.util")
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local style = require("coordinator.ui.style")
@@ -43,20 +43,20 @@ local function init(main)
local lu_col = style.lu_colors
local lu_c_d = style.lu_colors_dark
local facility = iocontrol.get_db().facility
local units = iocontrol.get_db().units
local fac = ioctl.get_db().facility
local units = ioctl.get_db().units
local tank_defs = facility.tank_defs
local tank_conns = facility.tank_conns
local tank_list = facility.tank_list
local tank_types = facility.tank_fluid_types
local tank_defs = fac.tank_defs
local tank_conns = fac.tank_conns
local tank_list = fac.tank_list
local tank_types = fac.tank_fluid_types
-- window header message
local header = TextBox{parent=main,y=1,text="Facility Coolant and Waste Flow Monitor",alignment=ALIGN.CENTER,fg_bg=style.theme.header}
-- max length example: "01:23:45 AM - Wednesday, September 28 2022"
local datetime = TextBox{parent=main,x=(header.get_width()-42),y=1,text="",alignment=ALIGN.RIGHT,width=42,fg_bg=style.theme.header}
datetime.register(facility.ps, "date_time", datetime.set_value)
datetime.register(fac.ps, "date_time", datetime.set_value)
local po_pipes = {}
local emcool_pipes = {}
@@ -83,9 +83,9 @@ local function init(main)
return first, last
end
if facility.tank_mode == 0 or facility.tank_mode == 8 then
if fac.tank_mode == 0 or fac.tank_mode == 8 then
-- (0) tanks belong to reactor units OR (8) 4 total facility tanks (A B C D)
for i = 1, facility.num_units do
for i = 1, fac.num_units do
if units[i].has_tank then
local y = y_ofs(i)
local color = c_clr(i)
@@ -116,7 +116,7 @@ local function init(main)
end
end
if facility.tank_mode == 1 then
if fac.tank_mode == 1 then
-- (1) 1 total facility tank (A A A A)
local first_fdef, last_fdef = find_fdef(1, #tank_defs)
@@ -133,7 +133,7 @@ local function init(main)
end
end
end
elseif facility.tank_mode == 2 then
elseif fac.tank_mode == 2 then
-- (2) 2 total facility tanks (A A A B)
local first_fdef, last_fdef = find_fdef(1, math.min(3, #tank_defs))
@@ -155,7 +155,7 @@ local function init(main)
end
end
end
elseif facility.tank_mode == 3 then
elseif fac.tank_mode == 3 then
-- (3) 2 total facility tanks (A A B B)
for _, a in pairs({ 1, 3 }) do
local b = a + 1
@@ -168,7 +168,7 @@ local function init(main)
table.insert(emcool_pipes, pipe(0, y_ofs(b), 1, y_ofs(b) + 6, c_clr(b), true))
end
end
elseif facility.tank_mode == 4 then
elseif fac.tank_mode == 4 then
-- (4) 2 total facility tanks (A B B B)
local first_fdef, last_fdef = find_fdef(2, #tank_defs)
@@ -190,7 +190,7 @@ local function init(main)
end
end
end
elseif facility.tank_mode == 5 then
elseif fac.tank_mode == 5 then
-- (5) 3 total facility tanks (A A B C)
local first_fdef, last_fdef = find_fdef(1, math.min(2, #tank_defs))
@@ -212,7 +212,7 @@ local function init(main)
end
end
end
elseif facility.tank_mode == 6 then
elseif fac.tank_mode == 6 then
-- (6) 3 total facility tanks (A B B C)
local first_fdef, last_fdef = find_fdef(2, math.min(3, #tank_defs))
@@ -234,7 +234,7 @@ local function init(main)
end
end
end
elseif facility.tank_mode == 7 then
elseif fac.tank_mode == 7 then
-- (7) 3 total facility tanks (A B C C)
local first_fdef, last_fdef = find_fdef(3, #tank_defs)
@@ -265,7 +265,7 @@ local function init(main)
PipeNetwork{parent=main,x=2,y=3,pipes=emcool_pipes,bg=style.theme.bg}
end
for i = 1, facility.num_units do
for i = 1, fac.num_units do
local y_offset = y_ofs(i)
unit_flow(main, flow_x, 5 + y_offset, #emcool_pipes == 0, i)
table.insert(po_pipes, pipe(0, 3 + y_offset, 4, 0, colors.green, true, true))
@@ -298,7 +298,7 @@ local function init(main)
-- auxiliary coolant valves --
------------------------------
for i = 1, facility.num_units do
for i = 1, fac.num_units do
if units[i].aux_coolant then
local vx
local vy = 3 + y_ofs(i)
@@ -340,7 +340,7 @@ local function init(main)
local tank = Div{parent=main,x=3,y=7+y_offset,width=20,height=14}
TextBox{parent=tank,text=" ",x=1,y=1,fg_bg=style.lg_gray}
TextBox{parent=tank,text=" ",y=1,fg_bg=style.lg_gray}
TextBox{parent=tank,text="DYNAMIC TANK "..id,alignment=ALIGN.CENTER,fg_bg=style.wh_gray}
local tank_box = Rectangle{parent=tank,border=border(1,colors.gray,true),width=20,height=12}
@@ -376,12 +376,12 @@ local function init(main)
can_fill.register(units[i].tank_ps_tbl[1], "container_mode", _can_fill)
can_empty.register(units[i].tank_ps_tbl[1], "container_mode", _can_empty)
else
status.register(facility.tank_ps_tbl[f_id], "computed_status", status.update)
tank_pcnt.register(facility.tank_ps_tbl[f_id], "fill", function (f) tank_pcnt.update(f * 100) end)
tank_amnt.register(facility.tank_ps_tbl[f_id], "stored", function (sto) tank_amnt.update(sto.amount) end)
level.register(facility.tank_ps_tbl[f_id], "fill", level.update)
can_fill.register(facility.tank_ps_tbl[f_id], "container_mode", _can_fill)
can_empty.register(facility.tank_ps_tbl[f_id], "container_mode", _can_empty)
status.register(fac.tank_ps_tbl[f_id], "computed_status", status.update)
tank_pcnt.register(fac.tank_ps_tbl[f_id], "fill", function (f) tank_pcnt.update(f * 100) end)
tank_amnt.register(fac.tank_ps_tbl[f_id], "stored", function (sto) tank_amnt.update(sto.amount) end)
level.register(fac.tank_ps_tbl[f_id], "fill", level.update)
can_fill.register(fac.tank_ps_tbl[f_id], "container_mode", _can_fill)
can_empty.register(fac.tank_ps_tbl[f_id], "container_mode", _can_empty)
end
end
end
@@ -394,24 +394,24 @@ local function init(main)
local sps = Div{parent=main,x=140,y=3,height=12}
TextBox{parent=sps,text=" ",width=24,x=1,y=1,fg_bg=style.lg_gray}
TextBox{parent=sps,text=" ",width=24,y=1,fg_bg=style.lg_gray}
TextBox{parent=sps,text="SPS",alignment=ALIGN.CENTER,width=24,fg_bg=wh_gray}
local sps_box = Rectangle{parent=sps,border=border(1,colors.gray,true),width=24,height=10}
local status = StateIndicator{parent=sps_box,x=5,y=1,states=style.sps.states,value=1,min_width=14}
status.register(facility.sps_ps_tbl[1], "computed_status", status.update)
status.register(fac.sps_ps_tbl[1], "computed_status", status.update)
TextBox{parent=sps_box,x=2,y=3,text="Input Rate",width=10,fg_bg=style.label}
local sps_in = DataIndicator{parent=sps_box,x=2,label="",format="%15.2f",value=0,unit="mB/t",lu_colors=lu_col,width=20,fg_bg=s_field}
sps_in.register(facility.ps, "po_am_rate", sps_in.update)
sps_in.register(fac.ps, "po_am_rate", sps_in.update)
TextBox{parent=sps_box,x=2,y=6,text="Production Rate",width=15,fg_bg=style.label}
local sps_rate = DataIndicator{parent=sps_box,x=2,label="",format="%15d",value=0,unit="\xb5B/t",lu_colors=lu_col,width=20,fg_bg=s_field}
sps_rate.register(facility.sps_ps_tbl[1], "process_rate", function (r) sps_rate.update(r * 1000) end)
sps_rate.register(fac.sps_ps_tbl[1], "process_rate", function (r) sps_rate.update(r * 1000) end)
----------------
-- statistics --
@@ -421,7 +421,7 @@ local function init(main)
local raw_waste = Rectangle{parent=main,x=145,y=17,border=border(1,colors.gray,true),width=19,height=3,thin=true,fg_bg=s_hi_bright}
local sum_raw_waste = DataIndicator{parent=raw_waste,lu_colors=lu_c_d,label="SUM",unit="mB/t",format="%8.2f",value=0,width=17}
sum_raw_waste.register(facility.ps, "burn_sum", sum_raw_waste.update)
sum_raw_waste.register(fac.ps, "burn_sum", sum_raw_waste.update)
TextBox{parent=main,x=145,y=21,text="PROC. WASTE",alignment=ALIGN.CENTER,width=19,fg_bg=wh_gray}
local pr_waste = Rectangle{parent=main,x=145,y=22,border=border(1,colors.gray,true),width=19,height=5,thin=true,fg_bg=s_hi_bright}
@@ -429,15 +429,15 @@ local function init(main)
local po = DataIndicator{parent=pr_waste,lu_colors=lu_c_d,label="Po",unit="mB/t",format="%9.2f",value=0,width=17}
local popl = DataIndicator{parent=pr_waste,lu_colors=lu_c_d,label="PoPl",unit="mB/t",format="%7.2f",value=0,width=17}
pu.register(facility.ps, "pu_rate", pu.update)
po.register(facility.ps, "po_rate", po.update)
popl.register(facility.ps, "po_pl_rate", popl.update)
pu.register(fac.ps, "pu_rate", pu.update)
po.register(fac.ps, "po_rate", po.update)
popl.register(fac.ps, "po_pl_rate", popl.update)
TextBox{parent=main,x=145,y=28,text="SPENT WASTE",alignment=ALIGN.CENTER,width=19,fg_bg=wh_gray}
local sp_waste = Rectangle{parent=main,x=145,y=29,border=border(1,colors.gray,true),width=19,height=3,thin=true,fg_bg=s_hi_bright}
local sum_sp_waste = DataIndicator{parent=sp_waste,lu_colors=lu_c_d,label="SUM",unit="mB/t",format="%8.3f",value=0,width=17}
sum_sp_waste.register(facility.ps, "spent_waste_rate", sum_sp_waste.update)
sum_sp_waste.register(fac.ps, "spent_waste_rate", sum_sp_waste.update)
end
return init

View File

@@ -5,7 +5,7 @@
local types = require("scada-common.types")
local util = require("scada-common.util")
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local pgi = require("coordinator.ui.pgi")
local style = require("coordinator.ui.style")
@@ -41,19 +41,19 @@ local led_grn = style.led_grn
local function init(panel, config)
local s_hi_box = style.fp_theme.highlight_box
local ps = iocontrol.get_db().fp.ps
local ps = ioctl.get_db().fp.ps
local term_w, term_h = term.getSize()
TextBox{parent=panel,y=1,text="SCADA COORDINATOR",alignment=ALIGN.CENTER,fg_bg=style.fp_theme.header}
local page_div = Div{parent=panel,x=1,y=3}
local page_div = Div{parent=panel,y=3}
--
-- system indicators
--
local main_page = Div{parent=page_div,x=1,y=1}
local main_page = Div{parent=page_div,y=1}
local system = Div{parent=main_page,width=14,height=17,x=2,y=2}
@@ -185,7 +185,7 @@ local function init(panel, config)
-- API page
local api_page = Div{parent=page_div,x=1,y=1,hidden=true}
local api_page = Div{parent=page_div,y=1,hidden=true}
local api_list = ListBox{parent=api_page,y=1,height=term_h-2,width=term_w,scroll_height=1000,fg_bg=style.fp.text_fg,nav_fg_bg=cpair(colors.gray,colors.lightGray),nav_active=cpair(colors.black,colors.gray)}
local _ = Div{parent=api_list,height=1} -- padding
@@ -193,7 +193,7 @@ local function init(panel, config)
local panes = { main_page, api_page }
local page_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
local page_pane = MultiPane{parent=page_div,y=1,panes=panes}
local tabs = {
{ name = "CRD", color = style.fp.text },

View File

@@ -4,7 +4,7 @@
local util = require("scada-common.util")
local iocontrol = require("coordinator.iocontrol")
local ioctl = require("coordinator.ioctl")
local style = require("coordinator.ui.style")
@@ -25,17 +25,17 @@ local ALIGN = core.ALIGN
local function init(main)
local s_header = style.theme.header
local facility = iocontrol.get_db().facility
local units = iocontrol.get_db().units
local fac = ioctl.get_db().facility
local units = ioctl.get_db().units
-- window header message
local header = TextBox{parent=main,y=1,text="Nuclear Generation Facility SCADA Coordinator",alignment=ALIGN.CENTER,fg_bg=s_header}
local ping = DataIndicator{parent=main,x=1,y=1,label="SVTT",format="%d",value=0,unit="ms",lu_colors=style.lg_white,width=12,fg_bg=s_header}
local ping = DataIndicator{parent=main,y=1,label="SVTT",format="%d",value=0,unit="ms",lu_colors=style.lg_white,width=12,fg_bg=s_header}
-- max length example: "01:23:45 AM - Wednesday, September 28 2022"
local datetime = TextBox{parent=main,x=(header.get_width()-42),y=1,text="",alignment=ALIGN.RIGHT,width=42,fg_bg=s_header}
ping.register(facility.ps, "sv_ping", ping.update)
datetime.register(facility.ps, "date_time", datetime.set_value)
ping.register(fac.ps, "sv_ping", ping.update)
datetime.register(fac.ps, "date_time", datetime.set_value)
---@type Div, Div, Div, Div
local uo_1, uo_2, uo_3, uo_4
@@ -44,12 +44,12 @@ local function init(main)
local row_1_height = 0
-- unit overviews
if facility.num_units >= 1 then
if fac.num_units >= 1 then
uo_1 = unit_overview(main, 2, 3, units[1])
row_1_height = uo_1.get_height()
end
if facility.num_units >= 2 then
if fac.num_units >= 2 then
uo_2 = unit_overview(main, 84, 3, units[2])
row_1_height = math.max(row_1_height, uo_2.get_height())
end
@@ -58,14 +58,14 @@ local function init(main)
util.nop()
if facility.num_units >= 3 then
if fac.num_units >= 3 then
-- base offset 3, spacing 1, max height of units 1 and 2
local row_2_offset = cnc_y_start
uo_3 = unit_overview(main, 2, row_2_offset, units[3])
cnc_y_start = row_2_offset + uo_3.get_height() + 1
if facility.num_units == 4 then
if fac.num_units == 4 then
uo_4 = unit_overview(main, 84, row_2_offset, units[4])
cnc_y_start = math.max(cnc_y_start, row_2_offset + uo_4.get_height() + 1)
end
@@ -88,7 +88,7 @@ local function init(main)
util.nop()
imatrix(main, 131, cnc_bottom_align_start, facility.induction_ps_tbl[1])
imatrix(main, 131, cnc_bottom_align_start, fac.induction_ps_tbl[1])
end
return init

View File

@@ -7,7 +7,7 @@ local flasher = require("graphics.flasher")
local core = {}
core.version = "2.4.9"
core.version = "2.4.10"
core.flasher = flasher
core.events = events

View File

@@ -13,6 +13,7 @@ local element = require("graphics.element")
---@field fractional_precision integer number of fractional digits
---@field arrow_fg_bg cpair arrow foreground/background colors
---@field arrow_disable? color color when disabled (default light gray)
---@field callback? function function to call on touch
---@field parent graphics_element
---@field id? string element id
---@field x? integer 1 if omitted
@@ -140,6 +141,8 @@ return function (args)
update_value()
show_num()
if type(args.callback) == "function" then args.callback(e.value) end
end
end
end

View File

@@ -1,14 +1,18 @@
-- Button Graphics Element
local util = require("scada-common.util")
local core = require("graphics.core")
local element = require("graphics.element")
---@class switch_button_args
---@field text string button text
---@field active_text? string button text when active (optional if active_fg_bg set)
---@field callback function function to call on touch
---@field default? boolean default state, defaults to off (false)
---@field min_width? integer text length + 2 if omitted
---@field active_fg_bg cpair foreground/background colors when pressed
---@field active_fg_bg? cpair foreground/background colors when pressed (optional if active_text set)
---@field dis_fg_bg? cpair foreground/background colors when disabled
---@field parent graphics_element
---@field id? string element id
---@field x? integer 1 if omitted
@@ -23,8 +27,8 @@ local element = require("graphics.element")
return function (args)
element.assert(type(args.text) == "string", "text is a required field")
element.assert(type(args.callback) == "function", "callback is a required field")
element.assert(type(args.active_fg_bg) == "table", "active_fg_bg is a required field")
element.assert(type(args.min_width) == "nil" or (type(args.min_width) == "number" and args.min_width > 0), "min_width must be nil or a number > 0")
element.assert((type(args.min_width) == "nil") or (type(args.min_width) == "number" and args.min_width > 0), "min_width must be nil or a number > 0")
element.assert((type(args.active_text) == "string") or (type(args.active_fg_bg) == "table"), "active_text or active_fg_bg must be set")
local text_width = string.len(args.text)
@@ -42,17 +46,22 @@ return function (args)
-- show the button state
function e.redraw()
if e.value then
e.w_set_fgd(args.active_fg_bg.fgd)
e.w_set_bkg(args.active_fg_bg.bkg)
else
e.w_set_fgd(e.fg_bg.fgd)
e.w_set_bkg(e.fg_bg.bkg)
if e.enabled then
if e.value and args.active_fg_bg then
e.w_set_fgd(args.active_fg_bg.fgd)
e.w_set_bkg(args.active_fg_bg.bkg)
else
e.w_set_fgd(e.fg_bg.fgd)
e.w_set_bkg(e.fg_bg.bkg)
end
elseif args.dis_fg_bg ~= nil then
e.w_set_fgd(args.dis_fg_bg.fgd)
e.w_set_bkg(args.dis_fg_bg.bkg)
end
e.window.clear()
e.w_set_cur(h_pad, v_pad)
e.w_write(args.text)
e.w_write(util.trinary(e.value and args.active_text, args.active_text, args.text))
end
-- handle mouse interaction
@@ -68,8 +77,21 @@ return function (args)
-- set the value (does not call the callback)
---@param val boolean new value
function e.set_value(val)
e.value = val
e.redraw()
if e.value ~= val then
e.value = val
e.redraw()
args.callback(e.value)
end
end
-- show butten as enabled
function e.on_enabled()
if args.dis_fg_bg ~= nil then e.redraw() end
end
-- show button as disabled
function e.on_disabled()
if args.dis_fg_bg ~= nil then e.redraw() end
end
---@class SwitchButton:graphics_element

View File

@@ -19,6 +19,7 @@ local MOUSE_CLICK = core.events.MOUSE_CLICK
---@field allow_negative? boolean true to allow negative numbers
---@field align_right? boolean true to align right while unfocused
---@field dis_fg_bg? cpair foreground/background colors when disabled
---@field on_unfocus? function callback when the field becomes unfocused
---@field parent graphics_element
---@field id? string element id
---@field x? integer 1 if omitted
@@ -89,6 +90,59 @@ return function (args)
-- make an interactive field manager
local ifield = core.new_ifield(e, args.max_chars, args.fg_bg, args.dis_fg_bg, args.align_right)
-- parse provided input text and apply it
local function _parse_input()
local val, max, min = tonumber(e.value), tonumber(args.max), tonumber(args.min)
if val then
if args.max_int_digits or args.max_frac_digits then
local str = e.value
local ceil = false
if string.find(str, "-") then str = string.sub(e.value, 2) end
local parts = util.strtok(str, ".")
if parts[1] and args.max_int_digits then
if string.len(parts[1]) > args.max_int_digits then
parts[1] = string.rep("9", args.max_int_digits)
ceil = true
end
end
if args.allow_decimal and args.max_frac_digits then
if ceil then
parts[2] = string.rep("9", args.max_frac_digits)
elseif parts[2] and (string.len(parts[2]) > args.max_frac_digits) then
-- add a half of the highest precision fractional value in order to round using floor
local scaled = math.fmod(val, 1) * (10 ^ (args.max_frac_digits))
local value = math.floor(scaled + 0.5)
local unscaled = value * (10 ^ (-args.max_frac_digits))
parts[2] = string.sub(tostring(unscaled), 3) -- remove starting "0."
end
end
if parts[2] then parts[2] = "." .. parts[2] else parts[2] = "" end
val = tonumber((parts[1] or "") .. parts[2]) or 0
end
if max and val > max then
_set_value(max)
ifield.nav_start()
elseif min and val < min then
_set_value(min)
ifield.nav_start()
else
_set_value(val)
ifield.nav_end()
end
else
e.value = ""
end
ifield.show()
end
-- handle mouse interaction
---@param event mouse_interaction mouse event
function e.handle_mouse(event)
@@ -163,14 +217,14 @@ return function (args)
---@param min integer minimum allowed value
function e.set_min(min)
args.min = min
e.on_unfocused()
_parse_input()
end
-- set maximum input value
---@param max integer maximum allowed value
function e.set_max(max)
args.max = max
e.on_unfocused()
_parse_input()
end
-- replace text with pasted text if its a number
@@ -185,55 +239,9 @@ return function (args)
-- handle unfocused
function e.on_unfocused()
local val, max, min = tonumber(e.value), tonumber(args.max), tonumber(args.min)
_parse_input()
if val then
if args.max_int_digits or args.max_frac_digits then
local str = e.value
local ceil = false
if string.find(str, "-") then str = string.sub(e.value, 2) end
local parts = util.strtok(str, ".")
if parts[1] and args.max_int_digits then
if string.len(parts[1]) > args.max_int_digits then
parts[1] = string.rep("9", args.max_int_digits)
ceil = true
end
end
if args.allow_decimal and args.max_frac_digits then
if ceil then
parts[2] = string.rep("9", args.max_frac_digits)
elseif parts[2] and (string.len(parts[2]) > args.max_frac_digits) then
-- add a half of the highest precision fractional value in order to round using floor
local scaled = math.fmod(val, 1) * (10 ^ (args.max_frac_digits))
local value = math.floor(scaled + 0.5)
local unscaled = value * (10 ^ (-args.max_frac_digits))
parts[2] = string.sub(tostring(unscaled), 3) -- remove starting "0."
end
end
if parts[2] then parts[2] = "." .. parts[2] else parts[2] = "" end
val = tonumber((parts[1] or "") .. parts[2]) or 0
end
if max and val > max then
_set_value(max)
ifield.nav_start()
elseif min and val < min then
_set_value(min)
ifield.nav_start()
else
_set_value(val)
ifield.nav_end()
end
else
e.value = ""
end
ifield.show()
if type(args.on_unfocus) == "function" then args.on_unfocus(tonumber(e.value)) end
end
-- handle focus (not unfocus), enable, and redraw with show()

View File

@@ -11,6 +11,7 @@ local MOUSE_CLICK = core.events.MOUSE_CLICK
---@field max_len? integer maximum string length
---@field censor? string character to replace text with when printing to screen
---@field dis_fg_bg? cpair foreground/background colors when disabled
---@field on_unfocus? function callback when the field becomes unfocused
---@field parent graphics_element
---@field id? string element id
---@field x? integer 1 if omitted
@@ -77,20 +78,20 @@ return function (args)
end
-- set the value
---@param val string string to set
function e.set_value(val)
ifield.set_value(val)
end
e.set_value = ifield.set_value
-- replace text with pasted text
---@param text string string to set
function e.handle_paste(text)
ifield.set_value(text)
e.handle_paste = ifield.set_value
-- handle unfocused
function e.on_unfocused()
ifield.show()
if type(args.on_unfocus) == "function" then args.on_unfocus(e.value) end
end
-- handle focus, enable, and redraw with show()
e.on_focused = ifield.show
e.on_unfocused = ifield.show
e.on_enabled = ifield.show
e.on_disabled = ifield.show
e.redraw = ifield.show

View File

@@ -55,11 +55,11 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
local ui_c_1 = Div{parent=ui_cfg,x=2,y=4,width=24}
local ui_c_2 = Div{parent=ui_cfg,x=2,y=4,width=24}
local ui_pane = MultiPane{parent=net_cfg,x=1,y=4,panes={ui_c_1,ui_c_2}}
local ui_pane = MultiPane{parent=net_cfg,y=4,panes={ui_c_1,ui_c_2}}
TextBox{parent=ui_cfg,x=1,y=2,text=" Pocket UI",fg_bg=cpair(colors.black,colors.lime)}
TextBox{parent=ui_cfg,y=2,text=" Pocket UI",fg_bg=cpair(colors.black,colors.lime)}
TextBox{parent=ui_c_1,x=1,y=1,height=3,text="You may customize UI options below."}
TextBox{parent=ui_c_1,y=1,height=3,text="You may customize UI options below."}
TextBox{parent=ui_c_1,y=4,text="Po/Pu Pellet Color"}
TextBox{parent=ui_c_1,x=20,y=4,text="new!",fg_bg=cpair(colors.red,colors._INHERIT)} ---@todo remove NEW tag on next revision
@@ -72,16 +72,16 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
ui_pane.set_value(2)
end
PushButton{parent=ui_c_1,x=1,y=15,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=ui_c_1,y=15,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=ui_c_1,x=19,y=15,text="Next \x1a",callback=submit_ui_opts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=ui_c_2,x=1,y=1,height=3,text="You may customize units below."}
TextBox{parent=ui_c_2,y=1,height=3,text="You may customize units below."}
TextBox{parent=ui_c_2,x=1,y=4,text="Temperature Scale"}
local temp_scale = RadioButton{parent=ui_c_2,x=1,y=5,default=ini_cfg.TempScale,options=types.TEMP_SCALE_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.lime}
TextBox{parent=ui_c_2,y=4,text="Temperature Scale"}
local temp_scale = RadioButton{parent=ui_c_2,y=5,default=ini_cfg.TempScale,options=types.TEMP_SCALE_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.lime}
TextBox{parent=ui_c_2,x=1,y=10,text="Energy Scale"}
local energy_scale = RadioButton{parent=ui_c_2,x=1,y=11,default=ini_cfg.EnergyScale,options=types.ENERGY_SCALE_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.lime}
TextBox{parent=ui_c_2,y=10,text="Energy Scale"}
local energy_scale = RadioButton{parent=ui_c_2,y=11,default=ini_cfg.EnergyScale,options=types.ENERGY_SCALE_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.lime}
local function submit_ui_units()
tmp_cfg.TempScale = temp_scale.get_value()
@@ -89,7 +89,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
main_pane.set_value(3)
end
PushButton{parent=ui_c_2,x=1,y=15,text="\x1b Back",callback=function()ui_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=ui_c_2,y=15,text="\x1b Back",callback=function()ui_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=ui_c_2,x=19,y=15,text="Next \x1a",callback=submit_ui_units,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -101,26 +101,26 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
local net_c_3 = Div{parent=net_cfg,x=2,y=4,width=24}
local net_c_4 = Div{parent=net_cfg,x=2,y=4,width=24}
local net_pane = MultiPane{parent=net_cfg,x=1,y=4,panes={net_c_1,net_c_2,net_c_3,net_c_4}}
local net_pane = MultiPane{parent=net_cfg,y=4,panes={net_c_1,net_c_2,net_c_3,net_c_4}}
TextBox{parent=net_cfg,x=1,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)}
TextBox{parent=net_cfg,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)}
TextBox{parent=net_c_1,x=1,y=1,text="Set network channels."}
TextBox{parent=net_c_1,x=1,y=3,height=4,text="Each of the named channels must be the same within a particular SCADA network.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_1,y=1,text="Set network channels."}
TextBox{parent=net_c_1,y=3,height=4,text="Each of the named channels must be the same within a particular SCADA network.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_1,x=1,y=8,width=18,text="Supervisor Channel"}
local svr_chan = NumberField{parent=net_c_1,x=1,y=9,width=7,default=ini_cfg.SVR_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_1,y=8,width=18,text="Supervisor Channel"}
local svr_chan = NumberField{parent=net_c_1,y=9,width=7,default=ini_cfg.SVR_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_1,x=9,y=9,height=4,text="[SVR_CHANNEL]",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_1,x=1,y=10,width=19,text="Coordinator Channel"}
local crd_chan = NumberField{parent=net_c_1,x=1,y=11,width=7,default=ini_cfg.CRD_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_1,y=10,width=19,text="Coordinator Channel"}
local crd_chan = NumberField{parent=net_c_1,y=11,width=7,default=ini_cfg.CRD_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_1,x=9,y=11,height=4,text="[CRD_CHANNEL]",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_1,x=1,y=12,width=14,text="Pocket Channel"}
local pkt_chan = NumberField{parent=net_c_1,x=1,y=13,width=7,default=ini_cfg.PKT_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_1,y=12,width=14,text="Pocket Channel"}
local pkt_chan = NumberField{parent=net_c_1,y=13,width=7,default=ini_cfg.PKT_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_1,x=9,y=13,height=4,text="[PKT_CHANNEL]",fg_bg=g_lg_fg_bg}
local chan_err = TextBox{parent=net_c_1,x=1,y=14,width=24,text="Please set all channels.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
local chan_err = TextBox{parent=net_c_1,y=14,width=24,text="Please set all channels.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
local function submit_channels()
local svr_c, crd_c, pkt_c = tonumber(svr_chan.get_value()), tonumber(crd_chan.get_value()), tonumber(pkt_chan.get_value())
@@ -131,18 +131,18 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
else chan_err.show() end
end
PushButton{parent=net_c_1,x=1,y=15,text="\x1b Back",callback=function()main_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_1,y=15,text="\x1b Back",callback=function()main_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_1,x=19,y=15,text="Next \x1a",callback=submit_channels,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_2,x=1,y=1,text="Set connection timeout."}
TextBox{parent=net_c_2,x=1,y=3,height=7,text="You generally should not need to modify this. On slow servers, you can try to increase this to make the system wait longer before assuming a disconnection.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_2,y=1,text="Set connection timeout."}
TextBox{parent=net_c_2,y=3,height=7,text="You generally should not need to modify this. On slow servers, you can try to increase this to make the system wait longer before assuming a disconnection.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_2,x=1,y=11,width=19,text="Connection Timeout"}
local timeout = NumberField{parent=net_c_2,x=1,y=12,width=7,default=ini_cfg.ConnTimeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg}
TextBox{parent=net_c_2,y=11,width=19,text="Connection Timeout"}
local timeout = NumberField{parent=net_c_2,y=12,width=7,default=ini_cfg.ConnTimeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg}
TextBox{parent=net_c_2,x=9,y=12,height=2,text="seconds\n(default 5)",fg_bg=g_lg_fg_bg}
local ct_err = TextBox{parent=net_c_2,x=1,y=14,width=24,text="Please set timeout.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
local ct_err = TextBox{parent=net_c_2,y=14,width=24,text="Please set timeout.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
local function submit_timeouts()
local timeout_val = tonumber(timeout.get_value())
@@ -153,16 +153,16 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
else ct_err.show() end
end
PushButton{parent=net_c_2,x=1,y=15,text="\x1b Back",callback=function()net_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_2,y=15,text="\x1b Back",callback=function()net_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_2,x=19,y=15,text="Next \x1a",callback=submit_timeouts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_3,x=1,y=1,text="Set the trusted range."}
TextBox{parent=net_c_3,x=1,y=3,height=4,text="Setting this to a value larger than 0 prevents connections with devices that many blocks away.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,x=1,y=8,height=4,text="This is optional. You can disable this functionality by setting the value to 0.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,y=1,text="Set the trusted range."}
TextBox{parent=net_c_3,y=3,height=4,text="Setting this to a value larger than 0 prevents connections with devices that many blocks away.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,y=8,height=4,text="This is optional. You can disable this functionality by setting the value to 0.",fg_bg=g_lg_fg_bg}
local range = NumberField{parent=net_c_3,x=1,y=13,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg}
local range = NumberField{parent=net_c_3,y=13,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg}
local tr_err = TextBox{parent=net_c_3,x=1,y=14,width=24,text="Set the trusted range.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
local tr_err = TextBox{parent=net_c_3,y=14,width=24,text="Set the trusted range.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
local function submit_tr()
local range_val = tonumber(range.get_value())
@@ -173,26 +173,26 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
else tr_err.show() end
end
PushButton{parent=net_c_3,x=1,y=15,text="\x1b Back",callback=function()net_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_3,y=15,text="\x1b Back",callback=function()net_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_3,x=19,y=15,text="Next \x1a",callback=submit_tr,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_4,x=1,y=1,height=4,text="Optionally, set the facility authentication key. Do NOT use one of your passwords."}
TextBox{parent=net_c_4,x=1,y=6,height=6,text="This enables verifying that messages are authentic, so it is intended for security on multiplayer servers.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_4,y=1,height=4,text="Optionally, set the facility authentication key. Do NOT use one of your passwords."}
TextBox{parent=net_c_4,y=6,height=6,text="This enables verifying that messages are authentic, so it is intended for security on multiplayer servers.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_4,x=1,y=12,text="Facility Auth Key"}
local key, _ = TextField{parent=net_c_4,x=1,y=13,max_len=64,value=ini_cfg.AuthKey,width=24,height=1,fg_bg=bw_fg_bg}
TextBox{parent=net_c_4,y=12,text="Facility Auth Key"}
local key, _ = TextField{parent=net_c_4,y=13,max_len=64,value=ini_cfg.AuthKey,width=24,height=1,fg_bg=bw_fg_bg}
local function censor_key(enable) key.censor(tri(enable, "*", nil)) end
-- declare back first so tabbing makes sense visually
PushButton{parent=net_c_4,x=1,y=15,text="\x1b Back",callback=function()net_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_4,y=15,text="\x1b Back",callback=function()net_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
local hide_key = Checkbox{parent=net_c_4,x=8,y=15,label="Hide Key",box_fg_bg=cpair(colors.lightBlue,colors.black),callback=censor_key}
hide_key.set_value(true)
censor_key(true)
local key_err = TextBox{parent=net_c_4,x=1,y=14,width=24,text="Length must be > 7.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
local key_err = TextBox{parent=net_c_4,y=14,width=24,text="Length must be > 7.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
local function submit_auth()
local v = key.get_value()
@@ -211,20 +211,20 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
local log_c_1 = Div{parent=log_cfg,x=2,y=4,width=24}
TextBox{parent=log_cfg,x=1,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)}
TextBox{parent=log_cfg,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)}
TextBox{parent=log_c_1,x=1,y=1,text="Configure logging below."}
TextBox{parent=log_c_1,y=1,text="Configure logging below."}
TextBox{parent=log_c_1,x=1,y=3,text="Log File Mode"}
local mode = RadioButton{parent=log_c_1,x=1,y=4,default=ini_cfg.LogMode+1,options={"Append on Startup","Replace on Startup"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.pink}
TextBox{parent=log_c_1,y=3,text="Log File Mode"}
local mode = RadioButton{parent=log_c_1,y=4,default=ini_cfg.LogMode+1,options={"Append on Startup","Replace on Startup"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.pink}
TextBox{parent=log_c_1,x=1,y=7,text="Log File Path"}
local path = TextField{parent=log_c_1,x=1,y=8,width=24,height=1,value=ini_cfg.LogPath,max_len=128,fg_bg=bw_fg_bg}
TextBox{parent=log_c_1,y=7,text="Log File Path"}
local path = TextField{parent=log_c_1,y=8,width=24,height=1,value=ini_cfg.LogPath,max_len=128,fg_bg=bw_fg_bg}
local en_dbg = Checkbox{parent=log_c_1,x=1,y=10,default=ini_cfg.LogDebug,label="Enable Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)}
local en_dbg = Checkbox{parent=log_c_1,y=10,default=ini_cfg.LogDebug,label="Enable Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)}
TextBox{parent=log_c_1,x=3,y=11,height=4,text="This results in much larger log files. Use only as needed.",fg_bg=g_lg_fg_bg}
local path_err = TextBox{parent=log_c_1,x=1,y=14,width=24,text="Provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
local path_err = TextBox{parent=log_c_1,y=14,width=24,text="Provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
local function submit_log()
if path.get_value() ~= "" then
@@ -240,7 +240,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
else path_err.show() end
end
PushButton{parent=log_c_1,x=1,y=15,text="\x1b Back",callback=function()main_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=log_c_1,y=15,text="\x1b Back",callback=function()main_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=log_c_1,x=19,y=15,text="Next \x1a",callback=submit_log,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -252,11 +252,11 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
local sum_c_3 = Div{parent=summary,x=2,y=4,width=24}
local sum_c_4 = Div{parent=summary,x=2,y=4,width=24}
local sum_pane = MultiPane{parent=summary,x=1,y=4,panes={sum_c_1,sum_c_2,sum_c_3,sum_c_4}}
local sum_pane = MultiPane{parent=summary,y=4,panes={sum_c_1,sum_c_2,sum_c_3,sum_c_4}}
TextBox{parent=summary,x=1,y=2,text=" Summary",fg_bg=cpair(colors.black,colors.green)}
TextBox{parent=summary,y=2,text=" Summary",fg_bg=cpair(colors.black,colors.green)}
local setting_list = ListBox{parent=sum_c_1,x=1,y=1,height=11,width=24,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local setting_list = ListBox{parent=sum_c_1,y=1,height=11,width=24,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local function back_from_summary()
if tool_ctl.viewing_config or self.importing_legacy then
@@ -311,11 +311,11 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
end
end
PushButton{parent=sum_c_1,x=1,y=15,text="\x1b Back",callback=back_from_summary,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
self.show_key_btn = PushButton{parent=sum_c_1,x=1,y=13,min_width=17,text="Unhide Auth Key",callback=function()self.show_auth_key()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
PushButton{parent=sum_c_1,y=15,text="\x1b Back",callback=back_from_summary,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
self.show_key_btn = PushButton{parent=sum_c_1,y=13,min_width=17,text="Unhide Auth Key",callback=function()self.show_auth_key()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
tool_ctl.settings_apply = PushButton{parent=sum_c_1,x=18,y=15,min_width=7,text="Apply",callback=save_and_continue,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg}
TextBox{parent=sum_c_2,x=1,y=1,text="Settings saved!"}
TextBox{parent=sum_c_2,y=1,text="Settings saved!"}
local function go_home()
main_pane.set_value(1)
@@ -323,21 +323,21 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
sum_pane.set_value(1)
end
PushButton{parent=sum_c_2,x=1,y=15,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_2,y=15,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_2,x=19,y=15,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=sum_c_3,x=1,y=1,height=4,text="The old config.lua file will now be deleted, then the configurator will exit."}
TextBox{parent=sum_c_3,y=1,height=4,text="The old config.lua file will now be deleted, then the configurator will exit."}
local function delete_legacy()
fs.delete("/pocket/config.lua")
exit()
end
PushButton{parent=sum_c_3,x=1,y=15,min_width=8,text="Cancel",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_3,y=15,min_width=8,text="Cancel",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_3,x=19,y=15,min_width=6,text="OK",callback=delete_legacy,fg_bg=cpair(colors.black,colors.green),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=sum_c_4,x=1,y=1,height=8,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=sum_c_4,x=1,y=15,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=sum_c_4,y=1,height=8,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=sum_c_4,y=15,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_4,x=19,y=15,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
--#endregion
@@ -417,7 +417,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
local textbox
if height > 1 then
textbox = TextBox{parent=line,x=1,y=2,text=val,height=height-1}
textbox = TextBox{parent=line,y=2,text=val,height=height-1}
else
textbox = TextBox{parent=line,x=label_w+1,y=1,text=val,alignment=RIGHT}
end

View File

@@ -127,16 +127,16 @@ local function config_view(display)
TextBox{parent=display,y=1,text="Pocket Configurator",alignment=CENTER,fg_bg=style.header}
local root_pane_div = Div{parent=display,x=1,y=2}
local root_pane_div = Div{parent=display,y=2}
local main_page = Div{parent=root_pane_div,x=1,y=1}
local ui_cfg = Div{parent=root_pane_div,x=1,y=1}
local net_cfg = Div{parent=root_pane_div,x=1,y=1}
local log_cfg = Div{parent=root_pane_div,x=1,y=1}
local summary = Div{parent=root_pane_div,x=1,y=1}
local changelog = Div{parent=root_pane_div,x=1,y=1}
local main_page = Div{parent=root_pane_div,y=1}
local ui_cfg = Div{parent=root_pane_div,y=1}
local net_cfg = Div{parent=root_pane_div,y=1}
local log_cfg = Div{parent=root_pane_div,y=1}
local summary = Div{parent=root_pane_div,y=1}
local changelog = Div{parent=root_pane_div,y=1}
local main_pane = MultiPane{parent=root_pane_div,x=1,y=1,panes={main_page,ui_cfg,net_cfg,log_cfg,summary,changelog}}
local main_pane = MultiPane{parent=root_pane_div,y=1,panes={main_page,ui_cfg,net_cfg,log_cfg,summary,changelog}}
--#region Main Page
@@ -192,20 +192,20 @@ local function config_view(display)
local cl = Div{parent=changelog,x=2,y=4,width=24}
TextBox{parent=changelog,x=1,y=2,text=" Config Change Log",fg_bg=bw_fg_bg}
TextBox{parent=changelog,y=2,text=" Config Change Log",fg_bg=bw_fg_bg}
local c_log = ListBox{parent=cl,x=1,y=1,height=13,width=24,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local c_log = ListBox{parent=cl,y=1,height=13,width=24,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
for _, change in ipairs(changes) do
TextBox{parent=c_log,text=change[1],fg_bg=bw_fg_bg}
for _, v in ipairs(change[2]) do
local e = Div{parent=c_log,height=#util.strwrap(v,21)}
TextBox{parent=e,y=1,x=1,text="- ",fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=e,y=1,text="- ",fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=e,y=1,x=3,text=v,height=e.get_height(),fg_bg=cpair(colors.gray,colors.white)}
end
end
PushButton{parent=cl,x=1,y=15,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=cl,y=15,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
end

View File

@@ -20,7 +20,7 @@ local TEMP_UNITS = types.TEMP_SCALE_UNITS
local WARN_TT = 40
local HIGH_TT = 80
local iocontrol = {}
local ioctl = {}
---@enum POCKET_LINK_STATE
local LINK_STATE = {
@@ -30,9 +30,9 @@ local LINK_STATE = {
LINKED = 3
}
iocontrol.LINK_STATE = LINK_STATE
ioctl.LINK_STATE = LINK_STATE
---@class pocket_ioctl
---@class pkt_io
local io = {
version = "unknown", -- pocket version
ps = psil.create(), -- pocket PSIL
@@ -46,11 +46,11 @@ local comms = nil ---@type pocket_comms
---@param pkt_comms pocket_comms
---@param nav pocket_nav
---@param cfg pkt_config
function iocontrol.init_core(pkt_comms, nav, cfg)
function ioctl.init_core(pkt_comms, nav, cfg)
comms = pkt_comms
config = cfg
iocontrol.rx = iorx(io)
ioctl.rx = iorx(io)
io.nav = nav
@@ -106,7 +106,7 @@ end
-- initialize facility-dependent components of pocket iocontrol
---@param conf facility_conf facility configuration
function iocontrol.init_fac(conf)
function ioctl.init_fac(conf)
local temp_scale, energy_scale = config.TempScale, config.EnergyScale
io.temp_label = TEMP_UNITS[temp_scale]
io.energy_label = ENERGY_UNITS[energy_scale]
@@ -136,7 +136,7 @@ function iocontrol.init_fac(conf)
end
-- facility data structure
---@class pioctl_facility
---@class pkt_io_facility
io.facility = {
num_units = conf.num_units,
tank_mode = conf.cooling.fac_tank_mode,
@@ -206,9 +206,9 @@ function iocontrol.init_fac(conf)
end
-- create unit data structures
io.units = {} ---@type pioctl_unit[]
io.units = {} ---@type pkt_io_unit[]
for i = 1, conf.num_units do
---@class pioctl_unit
---@class pkt_io_unit
local entry = {
unit_id = i,
connected = false,
@@ -310,7 +310,7 @@ end
---@param state POCKET_LINK_STATE
---@param sv_addr integer|false|nil supervisor address if linked, nil if unchanged, false if unlinked
---@param api_addr integer|false|nil coordinator address if linked, nil if unchanged, false if unlinked
function iocontrol.report_link_state(state, sv_addr, api_addr)
function ioctl.report_link_state(state, sv_addr, api_addr)
io.ps.publish("link_state", state)
if state == LINK_STATE.API_LINK_ONLY or state == LINK_STATE.UNLINKED then
@@ -335,14 +335,14 @@ function iocontrol.report_link_state(state, sv_addr, api_addr)
end
-- show the reason the supervisor connection isn't linking
function iocontrol.report_svr_link_error(msg) io.ps.publish("svr_link_msg", msg) end
function ioctl.report_svr_link_error(msg) io.ps.publish("svr_link_msg", msg) end
-- show the reason the coordinator api connection isn't linking
function iocontrol.report_crd_link_error(msg) io.ps.publish("api_link_msg", msg) end
function ioctl.report_crd_link_error(msg) io.ps.publish("api_link_msg", msg) end
-- determine supervisor connection quality (trip time)
---@param trip_time integer
function iocontrol.report_svr_tt(trip_time)
function ioctl.report_svr_tt(trip_time)
local state = 3
if trip_time > HIGH_TT then
state = 1
@@ -355,7 +355,7 @@ end
-- determine coordinator connection quality (trip time)
---@param trip_time integer
function iocontrol.report_crd_tt(trip_time)
function ioctl.report_crd_tt(trip_time)
local state = 3
if trip_time > HIGH_TT then
state = 1
@@ -367,6 +367,6 @@ function iocontrol.report_crd_tt(trip_time)
end
-- get the IO controller database
function iocontrol.get_db() return io end
function ioctl.get_db() return io end
return iocontrol
return ioctl

View File

@@ -18,7 +18,7 @@ local TNK_STATE = types.TANK_STATE
local MTX_STATE = types.IMATRIX_STATE
local SPS_STATE = types.SPS_STATE
local io ---@type pocket_ioctl
local io ---@type pkt_io
local iorx = {} ---@class iorx
-- populate facility data from API_GET_FAC
@@ -72,6 +72,7 @@ end
---@param data table
function iorx.record_unit_data(data)
local unit = io.units[data[1]]
local u_ps = unit.unit_ps
unit.connected = data[2]
local comp_statuses = data[3]
@@ -80,8 +81,8 @@ function iorx.record_unit_data(data)
local next_c_stat = 1
unit.unit_ps.publish("auto_group_id", unit.a_group)
unit.unit_ps.publish("auto_group", types.AUTO_GROUP_NAMES[unit.a_group + 1])
u_ps.publish("auto_group_id", unit.a_group)
u_ps.publish("auto_group", types.AUTO_GROUP_NAMES[unit.a_group + 1])
--#region Annunciator
@@ -106,7 +107,7 @@ function iorx.record_unit_data(data)
if not every then rcs_disconn = true end
unit.unit_ps.publish("U_" .. key, every)
u_ps.publish("U_" .. key, every)
elseif key == "HeatingRateLow" or key == "WaterLevelLow" then
-- split up array for all boilers
local any = false
@@ -121,7 +122,7 @@ function iorx.record_unit_data(data)
rcs_hazard = true
end
unit.unit_ps.publish("U_" .. key, any)
u_ps.publish("U_" .. key, any)
elseif key == "SteamDumpOpen" or key == "TurbineOverSpeed" or key == "GeneratorTrip" or key == "TurbineTrip" then
-- split up array for all turbines
local any = false
@@ -136,10 +137,10 @@ function iorx.record_unit_data(data)
rcs_hazard = true
end
unit.unit_ps.publish("U_" .. key, any)
u_ps.publish("U_" .. key, any)
else
-- non-table fields
unit.unit_ps.publish(key, val)
u_ps.publish(key, val)
end
end
@@ -157,7 +158,7 @@ function iorx.record_unit_data(data)
rcs_status = 1
end
unit.unit_ps.publish("U_RCS", rcs_status)
u_ps.publish("U_RCS", rcs_status)
--#endregion
@@ -193,27 +194,27 @@ function iorx.record_unit_data(data)
for key, val in pairs(unit.reactor_data) do
if key ~= "rps_status" and key ~= "mek_struct" and key ~= "mek_status" then
unit.unit_ps.publish(key, val)
u_ps.publish(key, val)
end
end
for key, val in pairs(unit.reactor_data.rps_status) do
unit.unit_ps.publish(key, val)
u_ps.publish(key, val)
end
for key, val in pairs(unit.reactor_data.mek_struct) do
unit.unit_ps.publish(key, val)
u_ps.publish(key, val)
end
for key, val in pairs(unit.reactor_data.mek_status) do
unit.unit_ps.publish(key, val)
u_ps.publish(key, val)
end
end
unit.unit_ps.publish("U_ControlStatus", control_status)
unit.unit_ps.publish("U_ReactorStatus", reactor_status)
unit.unit_ps.publish("U_ReactorStateStatus", comp_statuses[next_c_stat])
unit.unit_ps.publish("U_RPS", rps_status)
u_ps.publish("U_ControlStatus", control_status)
u_ps.publish("U_ReactorStatus", reactor_status)
u_ps.publish("U_ReactorStateStatus", comp_statuses[next_c_stat])
u_ps.publish("U_RPS", rps_status)
next_c_stat = next_c_stat + 1
@@ -493,7 +494,7 @@ function iorx.record_unit_data(data)
table.insert(ecam, { color = colors.green, text = "TURBINE" .. plural .. util.trinary(unit.turbine_flow_stable, " STABLE", " STABILIZING"), items = {}})
end
unit.unit_ps.publish("U_ECAM", textutils.serialize(ecam))
u_ps.publish("U_ECAM", textutils.serialize(ecam))
--#endregion
end
@@ -503,43 +504,45 @@ end
function iorx.record_control_data(data)
for u_id = 1, #data do
local unit = io.units[u_id]
local u_ps = unit.unit_ps
local u_data = data[u_id]
local rct = unit.reactor_data
unit.connected = u_data[1]
unit.reactor_data.rps_tripped = u_data[2]
unit.unit_ps.publish("rps_tripped", u_data[2])
unit.reactor_data.mek_status.status = u_data[3]
unit.unit_ps.publish("status", u_data[3])
unit.reactor_data.mek_status.temp = u_data[4]
unit.unit_ps.publish("temp", u_data[4])
unit.reactor_data.mek_status.burn_rate = u_data[5]
unit.unit_ps.publish("burn_rate", u_data[5])
unit.reactor_data.mek_status.act_burn_rate = u_data[6]
unit.unit_ps.publish("act_burn_rate", u_data[6])
unit.reactor_data.mek_struct.max_burn = u_data[7]
unit.unit_ps.publish("max_burn", u_data[7])
rct.rps_tripped = u_data[2]
u_ps.publish("rps_tripped", u_data[2])
rct.mek_status.status = u_data[3]
u_ps.publish("status", u_data[3])
rct.mek_status.temp = u_data[4]
u_ps.publish("temp", u_data[4])
rct.mek_status.burn_rate = u_data[5]
u_ps.publish("burn_rate", u_data[5])
rct.mek_status.act_burn_rate = u_data[6]
u_ps.publish("act_burn_rate", u_data[6])
rct.mek_struct.max_burn = u_data[7]
u_ps.publish("max_burn", u_data[7])
unit.annunciator.AutoControl = u_data[8]
unit.unit_ps.publish("AutoControl", u_data[8])
u_ps.publish("AutoControl", u_data[8])
unit.a_group = u_data[9]
unit.unit_ps.publish("auto_group_id", unit.a_group)
unit.unit_ps.publish("auto_group", types.AUTO_GROUP_NAMES[unit.a_group + 1])
u_ps.publish("auto_group_id", unit.a_group)
u_ps.publish("auto_group", types.AUTO_GROUP_NAMES[unit.a_group + 1])
local control_status = 1
if unit.connected then
if unit.reactor_data.rps_tripped then
if rct.rps_tripped then
control_status = 2
end
if unit.reactor_data.mek_status.status then
if rct.mek_status.status then
control_status = util.trinary(unit.annunciator.AutoControl, 4, 3)
end
end
unit.unit_ps.publish("U_ControlStatus", control_status)
u_ps.publish("U_ControlStatus", control_status)
end
end
@@ -549,6 +552,7 @@ function iorx.record_process_data(data)
-- get unit data
for u_id = 1, #io.units do
local unit = io.units[u_id]
local u_ps = unit.unit_ps
local u_data = data[u_id]
unit.reactor_data.mek_status.status = u_data[1]
@@ -556,18 +560,19 @@ function iorx.record_process_data(data)
unit.annunciator.AutoControl = u_data[6]
unit.a_group = u_data[7]
unit.unit_ps.publish("status", u_data[1])
unit.unit_ps.publish("max_burn", u_data[2])
unit.unit_ps.publish("burn_limit", u_data[3])
unit.unit_ps.publish("U_AutoReady", u_data[4])
unit.unit_ps.publish("U_AutoDegraded", u_data[5])
unit.unit_ps.publish("AutoControl", u_data[6])
unit.unit_ps.publish("auto_group_id", unit.a_group)
unit.unit_ps.publish("auto_group", types.AUTO_GROUP_NAMES[unit.a_group + 1])
u_ps.publish("status", u_data[1])
u_ps.publish("max_burn", u_data[2])
u_ps.publish("burn_limit", u_data[3])
u_ps.publish("U_AutoReady", u_data[4])
u_ps.publish("U_AutoDegraded", u_data[5])
u_ps.publish("AutoControl", u_data[6])
u_ps.publish("auto_group_id", unit.a_group)
u_ps.publish("auto_group", types.AUTO_GROUP_NAMES[unit.a_group + 1])
end
-- get facility data
local fac = io.facility
local f_ps = fac.ps
local f_data = data[#io.units + 1]
fac.status_lines = f_data[1]
@@ -580,25 +585,27 @@ function iorx.record_process_data(data)
fac.auto_scram = f_data[3]
fac.ascram_status = f_data[4]
fac.ps.publish("status_line_1", fac.status_lines[1])
fac.ps.publish("status_line_2", fac.status_lines[2])
f_ps.publish("status_line_1", fac.status_lines[1])
f_ps.publish("status_line_2", fac.status_lines[2])
fac.ps.publish("auto_ready", fac.auto_ready)
fac.ps.publish("auto_active", fac.auto_active)
fac.ps.publish("auto_ramping", fac.auto_ramping)
fac.ps.publish("auto_saturated", fac.auto_saturated)
f_ps.publish("auto_ready", fac.auto_ready)
f_ps.publish("auto_active", fac.auto_active)
f_ps.publish("auto_ramping", fac.auto_ramping)
f_ps.publish("auto_saturated", fac.auto_saturated)
fac.ps.publish("auto_scram", fac.auto_scram)
fac.ps.publish("as_matrix_fault", fac.ascram_status.matrix_fault)
fac.ps.publish("as_matrix_fill", fac.ascram_status.matrix_fill)
fac.ps.publish("as_crit_alarm", fac.ascram_status.crit_alarm)
fac.ps.publish("as_radiation", fac.ascram_status.radiation)
fac.ps.publish("as_gen_fault", fac.ascram_status.gen_fault)
f_ps.publish("auto_scram", fac.auto_scram)
f_ps.publish("as_matrix_fault", fac.ascram_status.matrix_fault)
f_ps.publish("as_matrix_fill", fac.ascram_status.matrix_fill)
f_ps.publish("as_crit_alarm", fac.ascram_status.crit_alarm)
f_ps.publish("as_radiation", fac.ascram_status.radiation)
f_ps.publish("as_gen_fault", fac.ascram_status.gen_fault)
fac.ps.publish("process_mode", f_data[5][1])
fac.ps.publish("process_burn_target", f_data[5][2])
fac.ps.publish("process_charge_target", f_data[5][3])
fac.ps.publish("process_gen_target", f_data[5][4])
f_ps.publish("process_mode", f_data[5][1])
f_ps.publish("process_burn_target", f_data[5][2])
f_ps.publish("process_range_start", f_data[5][3])
f_ps.publish("process_range_stop", f_data[5][4])
f_ps.publish("process_charge_target", f_data[5][5])
f_ps.publish("process_gen_target", f_data[5][6])
end
-- update waste app with unit data from API_GET_WASTE
@@ -607,6 +614,7 @@ function iorx.record_waste_data(data)
-- get unit data
for u_id = 1, #io.units do
local unit = io.units[u_id]
local u_ps = unit.unit_ps
local u_data = data[u_id]
unit.waste_mode = u_data[1]
@@ -617,53 +625,55 @@ function iorx.record_waste_data(data)
unit.sna_out_rate = u_data[6]
unit.waste_stats = u_data[7]
unit.unit_ps.publish("U_AutoWaste", unit.waste_mode == types.WASTE_MODE.AUTO)
unit.unit_ps.publish("U_WasteMode", unit.waste_mode)
unit.unit_ps.publish("U_WasteProduct", unit.waste_product)
u_ps.publish("U_AutoWaste", unit.waste_mode == types.WASTE_MODE.AUTO)
u_ps.publish("U_WasteMode", unit.waste_mode)
u_ps.publish("U_WasteProduct", unit.waste_product)
unit.unit_ps.publish("sna_count", unit.num_snas)
unit.unit_ps.publish("sna_peak_rate", unit.sna_peak_rate)
unit.unit_ps.publish("sna_max_rate", unit.sna_max_rate)
unit.unit_ps.publish("sna_out_rate", unit.sna_out_rate)
u_ps.publish("sna_count", unit.num_snas)
u_ps.publish("sna_peak_rate", unit.sna_peak_rate)
u_ps.publish("sna_max_rate", unit.sna_max_rate)
u_ps.publish("sna_out_rate", unit.sna_out_rate)
unit.unit_ps.publish("pu_rate", unit.waste_stats[1])
unit.unit_ps.publish("po_rate", unit.waste_stats[2])
unit.unit_ps.publish("po_pl_rate", unit.waste_stats[3])
u_ps.publish("pu_rate", unit.waste_stats[1])
u_ps.publish("po_rate", unit.waste_stats[2])
u_ps.publish("po_pl_rate", unit.waste_stats[3])
end
-- get facility data
local fac = io.facility
local f_ps = fac.ps
local f_data = data[#io.units + 1]
fac.auto_current_waste_product = f_data[1]
fac.auto_pu_fallback_active = f_data[2]
fac.auto_sps_disabled = f_data[3]
fac.ps.publish("current_waste_product", fac.auto_current_waste_product)
fac.ps.publish("pu_fallback_active", fac.auto_pu_fallback_active)
fac.ps.publish("sps_disabled_low_power", fac.auto_sps_disabled)
f_ps.publish("current_waste_product", fac.auto_current_waste_product)
f_ps.publish("pu_fallback_active", fac.auto_pu_fallback_active)
f_ps.publish("sps_disabled_low_power", fac.auto_sps_disabled)
fac.ps.publish("process_waste_product", f_data[4])
fac.ps.publish("process_pu_fallback", f_data[5])
fac.ps.publish("process_sps_low_power", f_data[6])
f_ps.publish("process_waste_product", f_data[4])
f_ps.publish("process_pu_fallback", f_data[5])
f_ps.publish("process_sps_low_power", f_data[6])
fac.waste_stats = f_data[7]
fac.ps.publish("burn_sum", fac.waste_stats[1])
fac.ps.publish("pu_rate", fac.waste_stats[2])
fac.ps.publish("po_rate", fac.waste_stats[3])
fac.ps.publish("po_pl_rate", fac.waste_stats[4])
fac.ps.publish("po_am_rate", fac.waste_stats[5])
fac.ps.publish("spent_waste_rate", fac.waste_stats[6])
f_ps.publish("burn_sum", fac.waste_stats[1])
f_ps.publish("pu_rate", fac.waste_stats[2])
f_ps.publish("po_rate", fac.waste_stats[3])
f_ps.publish("po_pl_rate", fac.waste_stats[4])
f_ps.publish("po_am_rate", fac.waste_stats[5])
f_ps.publish("spent_waste_rate", fac.waste_stats[6])
fac.sps_ps_tbl[1].publish("SPSStateStatus", f_data[8])
fac.ps.publish("sps_process_rate", f_data[9])
f_ps.publish("sps_process_rate", f_data[9])
end
-- update facility app with facility and unit data from API_GET_FAC_DTL
---@param data table
function iorx.record_fac_detail_data(data)
local fac = io.facility
local f_ps = fac.ps
local tank_statuses = data[5]
local next_t_stat = 1
@@ -675,14 +685,14 @@ function iorx.record_fac_detail_data(data)
fac.auto_scram = data[3]
fac.ascram_status = data[4]
fac.ps.publish("all_sys_ok", fac.all_sys_ok)
fac.ps.publish("rtu_count", fac.rtu_count)
fac.ps.publish("auto_scram", fac.auto_scram)
fac.ps.publish("as_matrix_fault", fac.ascram_status.matrix_fault)
fac.ps.publish("as_matrix_fill", fac.ascram_status.matrix_fill)
fac.ps.publish("as_crit_alarm", fac.ascram_status.crit_alarm)
fac.ps.publish("as_radiation", fac.ascram_status.radiation)
fac.ps.publish("as_gen_fault", fac.ascram_status.gen_fault)
f_ps.publish("all_sys_ok", fac.all_sys_ok)
f_ps.publish("rtu_count", fac.rtu_count)
f_ps.publish("auto_scram", fac.auto_scram)
f_ps.publish("as_matrix_fault", fac.ascram_status.matrix_fault)
f_ps.publish("as_matrix_fill", fac.ascram_status.matrix_fill)
f_ps.publish("as_crit_alarm", fac.ascram_status.crit_alarm)
f_ps.publish("as_radiation", fac.ascram_status.radiation)
f_ps.publish("as_gen_fault", fac.ascram_status.gen_fault)
-- unit data

View File

@@ -1,8 +1,8 @@
local comms = require("scada-common.comms")
local log = require("scada-common.log")
local util = require("scada-common.util")
local comms = require("scada-common.comms")
local log = require("scada-common.log")
local util = require("scada-common.util")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local PROTOCOL = comms.PROTOCOL
local DEVICE_TYPE = comms.DEVICE_TYPE
@@ -12,7 +12,7 @@ local CRDN_TYPE = comms.CRDN_TYPE
local UNIT_COMMAND = comms.UNIT_COMMAND
local FAC_COMMAND = comms.FAC_COMMAND
local LINK_STATE = iocontrol.LINK_STATE
local LINK_STATE = ioctl.LINK_STATE
local pocket = {}
@@ -276,8 +276,8 @@ function pocket.init_nav(smem)
if (req_sv and not p_comms.is_sv_linked()) or (req_api and not p_comms.is_api_linked()) then
-- report required connction(s)
iocontrol.get_db().loader_require = { sv = req_sv, api = req_api }
iocontrol.get_db().ps.toggle("loader_reqs")
ioctl.get_db().loader_require = { sv = req_sv, api = req_api }
ioctl.get_db().ps.toggle("loader_reqs")
-- bring up the app loader
self.loader_return = app_id
@@ -489,13 +489,13 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
sv_watchdog.cancel()
nav.unload_sv()
self.sv.r_seq_num = nil
self.sv.addr = comms.BROADCAST
if self.sv.linked then
self.sv.linked = false
_send_sv(MGMT_TYPE.CLOSE, {})
end
self.sv.r_seq_num = nil
self.sv.addr = comms.BROADCAST
end
-- close connection to coordinator API server
@@ -503,13 +503,13 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
api_watchdog.cancel()
nav.unload_api()
self.api.r_seq_num = nil
self.api.addr = comms.BROADCAST
if self.api.linked then
self.api.linked = false
_send_crd(MGMT_TYPE.CLOSE, {})
end
self.api.r_seq_num = nil
self.api.addr = comms.BROADCAST
end
-- close the connections to the servers
@@ -522,11 +522,11 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
function public.link_update()
if not (self.sv.linked and self.api.linked) then
if self.api.linked then
iocontrol.report_link_state(LINK_STATE.API_LINK_ONLY, false, nil)
ioctl.report_link_state(LINK_STATE.API_LINK_ONLY, false, nil)
elseif self.sv.linked then
iocontrol.report_link_state(LINK_STATE.SV_LINK_ONLY, nil, false)
ioctl.report_link_state(LINK_STATE.SV_LINK_ONLY, nil, false)
else
iocontrol.report_link_state(LINK_STATE.UNLINKED, false, false)
ioctl.report_link_state(LINK_STATE.UNLINKED, false, false)
end
if self.establish_delay_counter <= 0 then
@@ -601,7 +601,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
end
-- send the auto process control configuration with a start command
---@param auto_cfg [ PROCESS, number, number, number, number[] ]
---@param auto_cfg auto_ctl_cfg
function public.send_auto_start(auto_cfg)
_send_api(CRDN_TYPE.FAC_CMD, { FAC_COMMAND.START, table.unpack(auto_cfg) })
end
@@ -660,8 +660,8 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
-- handle a packet
---@param packet mgmt_packet|crdn_packet|nil
function public.handle_packet(packet)
local diag = iocontrol.get_db().diag
local ps = iocontrol.get_db().ps
local diag = ioctl.get_db().diag
local ps = ioctl.get_db().ps
if packet ~= nil then
local l_chan = packet.scada_frame.local_channel()
@@ -699,13 +699,13 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
local ack = packet.data[2] == true
if cmd == FAC_COMMAND.SCRAM_ALL then
iocontrol.get_db().facility.scram_ack(ack)
ioctl.get_db().facility.scram_ack(ack)
elseif cmd == FAC_COMMAND.STOP then
iocontrol.get_db().facility.stop_ack(ack)
ioctl.get_db().facility.stop_ack(ack)
elseif cmd == FAC_COMMAND.START then
iocontrol.get_db().facility.start_ack(ack)
ioctl.get_db().facility.start_ack(ack)
elseif cmd == FAC_COMMAND.ACK_ALL_ALARMS then
iocontrol.get_db().facility.ack_alarms_ack(ack)
ioctl.get_db().facility.ack_alarms_ack(ack)
elseif cmd == FAC_COMMAND.SET_WASTE_MODE then
elseif cmd == FAC_COMMAND.SET_PU_FB then
elseif cmd == FAC_COMMAND.SET_SPS_LP then
@@ -722,7 +722,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
local unit_id = packet.data[2]
local ack = packet.data[3] == true
local unit = iocontrol.get_db().units[unit_id] ---@type pioctl_unit
local unit = ioctl.get_db().units[unit_id] ---@type pkt_io_unit
if unit ~= nil then
if cmd == UNIT_COMMAND.SCRAM then
@@ -740,31 +740,31 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
end
elseif packet.type == CRDN_TYPE.API_GET_FAC then
if _check_length(packet, 11) then
iocontrol.rx.record_facility_data(packet.data)
ioctl.rx.record_facility_data(packet.data)
end
elseif packet.type == CRDN_TYPE.API_GET_FAC_DTL then
if _check_length(packet, 12) then
iocontrol.rx.record_fac_detail_data(packet.data)
ioctl.rx.record_fac_detail_data(packet.data)
end
elseif packet.type == CRDN_TYPE.API_GET_UNIT then
if _check_length(packet, 12) and type(packet.data[1]) == "number" and iocontrol.get_db().units[packet.data[1]] then
iocontrol.rx.record_unit_data(packet.data)
if _check_length(packet, 12) and type(packet.data[1]) == "number" and ioctl.get_db().units[packet.data[1]] then
ioctl.rx.record_unit_data(packet.data)
end
elseif packet.type == CRDN_TYPE.API_GET_CTRL then
if _check_length(packet, #iocontrol.get_db().units) then
iocontrol.rx.record_control_data(packet.data)
if _check_length(packet, #ioctl.get_db().units) then
ioctl.rx.record_control_data(packet.data)
end
elseif packet.type == CRDN_TYPE.API_GET_PROC then
if _check_length(packet, #iocontrol.get_db().units + 1) then
iocontrol.rx.record_process_data(packet.data)
if _check_length(packet, #ioctl.get_db().units + 1) then
ioctl.rx.record_process_data(packet.data)
end
elseif packet.type == CRDN_TYPE.API_GET_WASTE then
if _check_length(packet, #iocontrol.get_db().units + 1) then
iocontrol.rx.record_waste_data(packet.data)
if _check_length(packet, #ioctl.get_db().units + 1) then
ioctl.rx.record_waste_data(packet.data)
end
elseif packet.type == CRDN_TYPE.API_GET_RAD then
if _check_length(packet, #iocontrol.get_db().units + 1) then
iocontrol.rx.record_radiation_data(packet.data)
if _check_length(packet, #ioctl.get_db().units + 1) then
ioctl.rx.record_radiation_data(packet.data)
end
else _fail_type(packet) end
else
@@ -787,7 +787,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
_send_api_keep_alive_ack(timestamp)
iocontrol.report_crd_tt(trip_time)
ioctl.report_crd_tt(trip_time)
end
elseif packet.type == MGMT_TYPE.CLOSE then
-- handle session close
@@ -811,19 +811,19 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
-- get configuration
local conf = { num_units = fac_config[1], cooling = fac_config[2] }
iocontrol.init_fac(conf)
ioctl.init_fac(conf)
log.info("coordinator connection established")
self.establish_delay_counter = 0
self.api.linked = true
self.api.addr = src_addr
iocontrol.report_crd_link_error("")
ioctl.report_crd_link_error("")
if self.sv.linked then
iocontrol.report_link_state(LINK_STATE.LINKED, nil, self.api.addr)
ioctl.report_link_state(LINK_STATE.LINKED, nil, self.api.addr)
else
iocontrol.report_link_state(LINK_STATE.API_LINK_ONLY, nil, self.api.addr)
ioctl.report_link_state(LINK_STATE.API_LINK_ONLY, nil, self.api.addr)
end
else
log.debug("invalid facility configuration table received from coordinator, establish failed")
@@ -835,19 +835,19 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
if self.api.last_est_ack ~= est_ack then
if est_ack == ESTABLISH_ACK.DENY then
log.info("coordinator connection denied")
iocontrol.report_crd_link_error("denied")
ioctl.report_crd_link_error("denied")
elseif est_ack == ESTABLISH_ACK.COLLISION then
log.info("coordinator connection denied due to collision")
iocontrol.report_crd_link_error("collision")
ioctl.report_crd_link_error("collision")
elseif est_ack == ESTABLISH_ACK.BAD_VERSION then
log.info("coordinator comms version mismatch")
iocontrol.report_crd_link_error("comms version mismatch")
ioctl.report_crd_link_error("comms version mismatch")
elseif est_ack == ESTABLISH_ACK.BAD_API_VERSION then
log.info("coordinator api version mismatch")
iocontrol.report_crd_link_error("API version mismatch")
ioctl.report_crd_link_error("API version mismatch")
else
log.debug("coordinator SCADA_MGMT establish packet reply unsupported")
iocontrol.report_crd_link_error("unknown reply")
ioctl.report_crd_link_error("unknown reply")
end
end
@@ -900,7 +900,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
_send_sv_keep_alive_ack(timestamp)
iocontrol.report_svr_tt(trip_time)
ioctl.report_svr_tt(trip_time)
end
elseif packet.type == MGMT_TYPE.CLOSE then
-- handle session close
@@ -954,7 +954,7 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
log.debug("supervisor SCADA diag alarm set packet length/type mismatch")
end
elseif packet.type == MGMT_TYPE.INFO_LIST_CMP then
iocontrol.rx.record_network_data(packet.data)
ioctl.rx.record_network_data(packet.data)
else _fail_type(packet) end
elseif packet.type == MGMT_TYPE.ESTABLISH then
-- connection with supervisor established
@@ -967,27 +967,27 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
self.sv.linked = true
self.sv.addr = src_addr
iocontrol.report_svr_link_error("")
ioctl.report_svr_link_error("")
if self.api.linked then
iocontrol.report_link_state(LINK_STATE.LINKED, self.sv.addr, nil)
ioctl.report_link_state(LINK_STATE.LINKED, self.sv.addr, nil)
else
iocontrol.report_link_state(LINK_STATE.SV_LINK_ONLY, self.sv.addr, nil)
ioctl.report_link_state(LINK_STATE.SV_LINK_ONLY, self.sv.addr, nil)
end
else
if self.sv.last_est_ack ~= est_ack then
if est_ack == ESTABLISH_ACK.DENY then
log.info("supervisor connection denied")
iocontrol.report_svr_link_error("denied")
ioctl.report_svr_link_error("denied")
elseif est_ack == ESTABLISH_ACK.COLLISION then
log.info("supervisor connection denied due to collision")
iocontrol.report_svr_link_error("collision")
ioctl.report_svr_link_error("collision")
elseif est_ack == ESTABLISH_ACK.BAD_VERSION then
log.info("supervisor comms version mismatch")
iocontrol.report_svr_link_error("comms version mismatch")
ioctl.report_svr_link_error("comms version mismatch")
else
log.debug("supervisor SCADA_MGMT establish packet reply unsupported")
iocontrol.report_svr_link_error("unknown reply")
ioctl.report_svr_link_error("unknown reply")
end
end

View File

@@ -13,15 +13,15 @@ local U_CMD = comms.UNIT_COMMAND
local process = {}
local self = {
io = nil, ---@type ioctl
io = nil, ---@type crd_io
comms = nil ---@type pocket_comms
}
-- initialize the process controller
---@param iocontrol pocket_ioctl iocontrl system
---@param ioctl pkt_io iocontrol system
---@param pocket_comms pocket_comms pocket communications
function process.init(iocontrol, pocket_comms)
self.io = iocontrol
function process.init(ioctl, pocket_comms)
self.io = ioctl
self.comms = pocket_comms
end
@@ -125,11 +125,13 @@ end
-- process start command
---@param mode PROCESS process control mode
---@param burn_target number burn rate target
---@param range_start integer range control activation threshold
---@param range_stop integer range control deactivation threshold
---@param charge_target number charge level target
---@param gen_target number generation rate target
---@param limits number[] unit burn rate limits
function process.process_start(mode, burn_target, charge_target, gen_target, limits)
self.comms.send_auto_start({ mode, burn_target, charge_target, gen_target, limits })
function process.process_start(mode, burn_target, range_start, range_stop, charge_target, gen_target, limits)
self.comms.send_auto_start({ mode, burn_target, range_start, range_stop, charge_target, gen_target, limits })
log.debug("PROCESS: START AUTO CTRL")
end

View File

@@ -17,12 +17,12 @@ local ppm = require("scada-common.ppm")
local util = require("scada-common.util")
local configure = require("pocket.configure")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local pocket = require("pocket.pocket")
local renderer = require("pocket.renderer")
local threads = require("pocket.threads")
local POCKET_VERSION = "v1.0.7"
local POCKET_VERSION = "v1.1.0"
local println = util.println
local println_ts = util.println_ts
@@ -79,7 +79,7 @@ local function main()
ppm.mount_all()
-- record version for GUI
iocontrol.get_db().version = POCKET_VERSION
ioctl.get_db().version = POCKET_VERSION
----------------------------------------
-- memory allocation
@@ -132,7 +132,7 @@ local function main()
network.init_mac(config.AuthKey)
end
iocontrol.report_link_state(iocontrol.LINK_STATE.UNLINKED)
ioctl.report_link_state(ioctl.LINK_STATE.UNLINKED)
-- get the communications modem
if smem_dev.modem == nil then
@@ -154,7 +154,7 @@ local function main()
log.debug("startup> comms init")
-- init I/O control
iocontrol.init_core(smem_sys.pocket_comms, smem_sys.nav, config)
ioctl.init_core(smem_sys.pocket_comms, smem_sys.nav, config)
----------------------------------------
-- start the UI

View File

@@ -40,6 +40,24 @@ function threads.thread__main(smem)
local nav = smem.pkt_sys.nav
local nic = smem.pkt_sys.nic
-- main loop periodic tasks
local function loop_tick()
-- relink if necessary
pocket_comms.link_update()
-- update any tasks for the active page
if nav.get_current_page() then
local page_tasks = nav.get_current_page().tasks
for i = 1, #page_tasks do page_tasks[i]() end
end
-- NIC periodic link-layer tasks
nic.periodic()
-- start next clock timer
loop_clock.start()
end
-- start connection watchdogs
sv_wd.feed()
api_wd.feed()
@@ -50,41 +68,27 @@ function threads.thread__main(smem)
local event, param1, param2, param3, param4, param5 = util.pull_event()
-- handle event
if event == "timer" then
if loop_clock.is_clock(param1) then
-- main loop tick
-- relink if necessary
pocket_comms.link_update()
-- update any tasks for the active page
if nav.get_current_page() then
local page_tasks = nav.get_current_page().tasks
for i = 1, #page_tasks do page_tasks[i]() end
end
-- NIC periodic link-layer tasks
nic.periodic()
-- start next clock timer
loop_clock.start()
elseif sv_wd.is_timer(param1) then
-- supervisor watchdog timeout
log.info("supervisor server timeout")
pocket_comms.close_sv()
elseif api_wd.is_timer(param1) then
-- coordinator watchdog timeout
log.info("coordinator api server timeout")
pocket_comms.close_api()
else
-- a non-clock/main watchdog timer event
-- notify timer callback dispatcher
tcd.handle(param1)
end
elseif event == "modem_message" then
if event == "modem_message" then
-- got a packet
local packet = pocket_comms.parse_packet(param1, param2, param3, param4, param5)
pocket_comms.handle_packet(packet)
elseif event == "timer" then
-- pass this timer event onto the right handler
if loop_clock.is_clock(param1) then
-- main loop tick
loop_tick()
elseif sv_wd.is_timer(param1) then
-- supervisor connection timed out
log.info("supervisor server timeout")
pocket_comms.close_sv()
elseif api_wd.is_timer(param1) then
-- coordinator connection timed out
log.info("coordinator api server timeout")
pocket_comms.close_api()
else
-- notify timer callback dispatcher, no other handler claimed this event
tcd.handle(param1)
end
elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" or
event == "double_click" then
-- handle a mouse event

View File

@@ -7,7 +7,7 @@ local util = require("scada-common.util")
local lockbox = require("lockbox")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local pocket = require("pocket.pocket")
local core = require("graphics.core")
@@ -27,9 +27,9 @@ local APP_ID = pocket.APP_ID
-- create about page view
---@param root Container parent
local function create_pages(root)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local frame = Div{parent=root,x=1,y=1}
local frame = Div{parent=root,y=1}
local app = db.nav.register_app(APP_ID.ABOUT, frame)
@@ -38,7 +38,7 @@ local function create_pages(root)
local fw_page = app.new_page(about_page, 3)
local hw_page = app.new_page(about_page, 4)
local about = Div{parent=frame,x=1,y=2}
local about = Div{parent=frame,y=2}
TextBox{parent=about,y=1,text="System Information",alignment=ALIGN.CENTER}
@@ -54,7 +54,7 @@ local function create_pages(root)
local config = pocket.config
local nt_div = Div{parent=frame,x=1,y=2}
local nt_div = Div{parent=frame,y=2}
TextBox{parent=nt_div,y=1,text="Network Details",alignment=ALIGN.CENTER}
PushButton{parent=nt_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=about_page.nav_to}
@@ -83,14 +83,14 @@ local function create_pages(root)
--#region Firmware Versions
local fw_div = Div{parent=frame,x=1,y=2}
local fw_div = Div{parent=frame,y=2}
TextBox{parent=fw_div,y=1,text="Firmware Versions",alignment=ALIGN.CENTER}
PushButton{parent=fw_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=about_page.nav_to}
local fw_list_box = ListBox{parent=fw_div,x=1,y=3,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)}
local fw_list_box = ListBox{parent=fw_div,y=3,scroll_height=100,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)}
local fw_list = Div{parent=fw_list_box,x=1,y=2,height=18}
local fw_list = Div{parent=fw_list_box,y=2,height=18}
TextBox{parent=fw_list,x=2,text="Pocket Version",fg_bg=label}
TextBox{parent=fw_list,x=2,text=db.version}
@@ -119,7 +119,7 @@ local function create_pages(root)
--#region Host Versions
local hw_div = Div{parent=frame,x=1,y=2}
local hw_div = Div{parent=frame,y=2}
TextBox{parent=hw_div,y=1,text="Host Versions",alignment=ALIGN.CENTER}
PushButton{parent=hw_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=about_page.nav_to}
@@ -134,7 +134,7 @@ local function create_pages(root)
--#endregion
local root_pane = MultiPane{parent=frame,x=1,y=1,panes={about,nt_div,fw_div,hw_div}}
local root_pane = MultiPane{parent=frame,y=1,panes={about,nt_div,fw_div,hw_div}}
app.set_root_pane(root_pane)
end

View File

@@ -2,7 +2,7 @@
-- Alarm Test App
--
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local pocket = require("pocket.pocket")
local core = require("graphics.core")
@@ -30,15 +30,15 @@ local c_blue_gray = cpair(colors.blue, colors.gray)
-- create alarm test page view
---@param root Container parent
local function new_view(root)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local ps = db.ps
local ttest = db.diag.tone_test
local frame = Div{parent=root,x=1,y=1}
local frame = Div{parent=root,y=1}
local app = db.nav.register_app(APP_ID.ALARMS, frame, nil, true)
local main = Div{parent=frame,x=1,y=1}
local main = Div{parent=frame,y=1}
local page_div = Div{parent=main,y=2,width=main.get_width()}
--#region alarm testing
@@ -168,7 +168,7 @@ local function new_view(root)
--#endregion
-- setup multipane
local u_pane = MultiPane{parent=page_div,x=1,y=1,panes={alarms_div,tones_div,info_div}}
local u_pane = MultiPane{parent=page_div,y=1,panes={alarms_div,tones_div,info_div}}
app.set_root_pane(u_pane)
local list = {

View File

@@ -6,7 +6,7 @@ local comms = require("scada-common.comms")
local const = require("scada-common.constants")
local util = require("scada-common.util")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local pocket = require("pocket.pocket")
local style = require("pocket.ui.style")
@@ -37,19 +37,19 @@ local box_label = cpair(colors.lightGray, colors.gray)
-- new computer list page view
---@param root Container parent
local function new_view(root)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local frame = Div{parent=root,x=1,y=1}
local frame = Div{parent=root,y=1}
local app = db.nav.register_app(APP_ID.COMPS, frame, nil, true, false)
local load_div = Div{parent=frame,x=1,y=1}
local main = Div{parent=frame,x=1,y=1}
local load_div = Div{parent=frame,y=1}
local main = Div{parent=frame,y=1}
TextBox{parent=load_div,y=12,text="Loading...",alignment=ALIGN.CENTER}
WaitingAnim{parent=load_div,x=math.floor(main.get_width()/2)-1,y=8,fg_bg=cpair(colors.orange,colors._INHERIT)}
local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}}
local load_pane = MultiPane{parent=main,y=1,panes={load_div,main}}
app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
@@ -251,7 +251,7 @@ local function new_view(root)
--#endregion
-- setup multipane
local u_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
local u_pane = MultiPane{parent=page_div,y=1,panes=panes}
app.set_root_pane(u_pane)
-- setup sidebar
@@ -285,7 +285,7 @@ local function new_view(root)
load_pane.set_value(1)
-- clear the list of connected computers so that connections re-appear on reload of this app
iocontrol.rx.clear_comp_record()
ioctl.rx.clear_comp_record()
end
app.set_load(load)

View File

@@ -5,7 +5,7 @@
local types = require("scada-common.types")
local util = require("scada-common.util")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local pocket = require("pocket.pocket")
local process = require("pocket.process")
@@ -49,19 +49,19 @@ local hzd_dis_colors = style.hzd_dis_colors
local function new_view(root)
local btn_fg_bg = cpair(colors.green, colors.black)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local frame = Div{parent=root,x=1,y=1}
local frame = Div{parent=root,y=1}
local app = db.nav.register_app(APP_ID.CONTROL, frame, nil, false, true)
local load_div = Div{parent=frame,x=1,y=1}
local main = Div{parent=frame,x=1,y=1}
local load_div = Div{parent=frame,y=1}
local main = Div{parent=frame,y=1}
TextBox{parent=load_div,y=12,text="Loading...",alignment=ALIGN.CENTER}
WaitingAnim{parent=load_div,x=math.floor(main.get_width()/2)-1,y=8,fg_bg=cpair(colors.green,colors._INHERIT)}
local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}}
local load_pane = MultiPane{parent=main,y=1,panes={load_div,main}}
app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
@@ -126,13 +126,13 @@ local function new_view(root)
u_page.tasks = { update }
TextBox{parent=u_div,y=1,text="Reactor Unit #"..i,alignment=ALIGN.CENTER}
PushButton{parent=u_div,x=1,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()prev(i)end}
PushButton{parent=u_div,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()prev(i)end}
PushButton{parent=u_div,x=21,y=1,text=">",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()next(i)end}
local rate = DataIndicator{parent=u_div,y=3,lu_colors=lu_col,label="Burn",unit="mB/t",format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg}
local temp = DataIndicator{parent=u_div,lu_colors=lu_col,label="Temp",unit=db.temp_label,format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg}
local ctrl = IconIndicator{parent=u_div,x=1,y=6,label="Control State",states=mode_states}
local ctrl = IconIndicator{parent=u_div,y=6,label="Control State",states=mode_states}
rate.register(u_ps, "act_burn_rate", rate.update)
temp.register(u_ps, "temp", function (t) temp.update(db.temp_convert(t)) end)
@@ -201,7 +201,7 @@ local function new_view(root)
db.facility.ack_alarms_ack = ack_a.on_response
-- setup multipane
local u_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
local u_pane = MultiPane{parent=page_div,y=1,panes=panes}
app.set_root_pane(u_pane)
set_sidebar()

View File

@@ -4,7 +4,7 @@
local util = require("scada-common.util")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local pocket = require("pocket.pocket")
local style = require("pocket.ui.style")
@@ -41,19 +41,19 @@ local grn_ind_s = style.icon_states.grn_ind_s
-- new unit page view
---@param root Container parent
local function new_view(root)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local frame = Div{parent=root,x=1,y=1}
local frame = Div{parent=root,y=1}
local app = db.nav.register_app(APP_ID.FACILITY, frame, nil, false, true)
local load_div = Div{parent=frame,x=1,y=1}
local main = Div{parent=frame,x=1,y=1}
local load_div = Div{parent=frame,y=1}
local main = Div{parent=frame,y=1}
TextBox{parent=load_div,y=12,text="Loading...",alignment=ALIGN.CENTER}
WaitingAnim{parent=load_div,x=math.floor(main.get_width()/2)-1,y=8,fg_bg=cpair(colors.orange,colors._INHERIT)}
local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}}
local load_pane = MultiPane{parent=main,y=1,panes={load_div,main}}
app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
@@ -100,7 +100,7 @@ local function new_view(root)
TextBox{parent=f_div,y=8,text="Induction Matrix",alignment=ALIGN.CENTER}
local eta = TextBox{parent=f_div,x=1,y=10,text="ETA Unknown",alignment=ALIGN.CENTER,fg_bg=cpair(colors.white,colors.gray)}
local eta = TextBox{parent=f_div,y=10,text="ETA Unknown",alignment=ALIGN.CENTER,fg_bg=cpair(colors.white,colors.gray)}
eta.register(fac.induction_ps_tbl[1], "eta_string", eta.set_value)
TextBox{parent=f_div,y=12,text="Unit Statuses",alignment=ALIGN.CENTER}
@@ -179,7 +179,7 @@ local function new_view(root)
if fac.tank_list[t] == 1 then
t_div.line_break()
local tank = IconIndicator{parent=t_div,x=1,label="Unit Tank "..t.." (U-"..t..")",states=basic_states}
local tank = IconIndicator{parent=t_div,label="Unit Tank "..t.." (U-"..t..")",states=basic_states}
tank.register(db.units[t].tank_ps_tbl[1], "DynamicTankStatus", tank.update)
TextBox{parent=t_div,x=5,text="\x07 Unit "..t,fg_bg=label_fg_bg}
@@ -188,7 +188,7 @@ local function new_view(root)
t_div.line_break()
local tank = IconIndicator{parent=t_div,x=1,label="Fac. Tank "..f_tank_id.." (F-"..f_tank_id..")",states=basic_states}
local tank = IconIndicator{parent=t_div,label="Fac. Tank "..f_tank_id.." (F-"..f_tank_id..")",states=basic_states}
tank.register(fac.tank_ps_tbl[f_tank_id], "DynamicTankStatus", tank.update)
local connections = ""
@@ -211,7 +211,7 @@ local function new_view(root)
--#endregion
-- setup multipane
local f_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
local f_pane = MultiPane{parent=page_div,y=1,panes=panes}
app.set_root_pane(f_pane)
-- setup sidebar

View File

@@ -5,7 +5,7 @@
local util = require("scada-common.util")
local log = require("scada-common.log")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local pocket = require("pocket.pocket")
local docs = require("pocket.ui.docs")
@@ -33,14 +33,14 @@ local APP_ID = pocket.APP_ID
-- new system guide view
---@param root Container parent
local function new_view(root)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local frame = Div{parent=root,x=1,y=1}
local frame = Div{parent=root,y=1}
local app = db.nav.register_app(APP_ID.GUIDE, frame)
local load_div = Div{parent=frame,x=1,y=1}
local main = Div{parent=frame,x=1,y=1}
local load_div = Div{parent=frame,y=1}
local main = Div{parent=frame,y=1}
WaitingAnim{parent=load_div,x=math.floor(main.get_width()/2)-1,y=8,fg_bg=cpair(colors.cyan,colors._INHERIT)}
TextBox{parent=load_div,y=12,text="Loading...",alignment=ALIGN.CENTER}
@@ -53,7 +53,7 @@ local function new_view(root)
load_text_2.set_value(b or "")
end
local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}}
local load_pane = MultiPane{parent=main,y=1,panes={load_div,main}}
local btn_fg_bg = cpair(colors.cyan, colors.black)
local btn_active = cpair(colors.white, colors.black)
@@ -110,13 +110,13 @@ local function new_view(root)
TextBox{parent=search,y=1,text="Search",alignment=ALIGN.CENTER}
local query_field = TextField{parent=search,x=1,y=3,width=18,fg_bg=cpair(colors.white,colors.gray)}
local query_field = TextField{parent=search,y=3,width=18,fg_bg=cpair(colors.white,colors.gray)}
local func_ref = {}
PushButton{parent=search,x=20,y=3,text="GO",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()func_ref.run_search()end}
local search_results = ListBox{parent=search,x=1,y=5,scroll_height=200,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)}
local search_results = ListBox{parent=search,y=5,scroll_height=200,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)}
function func_ref.run_search()
local query = string.lower(query_field.get_value())
@@ -239,7 +239,7 @@ local function new_view(root)
PushButton{parent=coord_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=uis_page.nav_to}
load_text(false, "Main Display")
local main_disp_page = guide_section(sect_construct_data, coord_page, "Main Display", docs.c_ui.main, 300)
local main_disp_page = guide_section(sect_construct_data, coord_page, "Main Display", docs.c_ui.main, 310)
load_text(false, "Flow Display")
local flow_disp_page = guide_section(sect_construct_data, coord_page, "Flow Display", docs.c_ui.flow, 210)
load_text(false, "Unit Displays")
@@ -255,7 +255,7 @@ local function new_view(root)
PushButton{parent=fps,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to}
load_text(false, "Common Items")
local fp_common_page = guide_section(sect_construct_data, fps_page, "Common Items", docs.fp.common, 100)
local fp_common_page = guide_section(sect_construct_data, fps_page, "Common Items", docs.fp.common, 130)
load_text(false, "Reactor PLC")
local fp_rplc_page = guide_section(sect_construct_data, fps_page, "Reactor PLC", docs.fp.r_plc, 190)
load_text(false, "RTU Gateway")
@@ -285,7 +285,7 @@ local function new_view(root)
load_text("Links")
TextBox{parent=lnk,y=1,text="Wiki and Discord",alignment=ALIGN.CENTER}
PushButton{parent=lnk,x=1,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to}
PushButton{parent=lnk,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=main_page.nav_to}
lnk.line_break()
TextBox{parent=lnk,text="GitHub",fg_bg=cpair(colors.lightGray,colors.black)}
@@ -298,7 +298,7 @@ local function new_view(root)
TextBox{parent=lnk,text="discord.gg/R9NSCkhcwt"}
-- setup multipane
local u_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
local u_pane = MultiPane{parent=page_div,y=1,panes=panes}
app.set_root_pane(u_pane)
-- link help resources

View File

@@ -2,7 +2,7 @@
-- Loading Screen App
--
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local pocket = require("pocket.pocket")
local conn_waiting = require("pocket.ui.components.conn_waiting")
@@ -15,22 +15,22 @@ local TextBox = require("graphics.elements.TextBox")
local APP_ID = pocket.APP_ID
local LINK_STATE = iocontrol.LINK_STATE
local LINK_STATE = ioctl.LINK_STATE
-- create the connecting to SV & API page
---@param root Container parent
local function create_pages(root)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local main = Div{parent=root,x=1,y=1}
local main = Div{parent=root,y=1}
db.nav.register_app(APP_ID.LOADER, main).new_page(nil, function () end)
local conn_sv_wait = conn_waiting(main, 6, false)
local conn_api_wait = conn_waiting(main, 6, true)
local main_pane = Div{parent=main,x=1,y=2}
local main_pane = Div{parent=main,y=2}
local root_pane = MultiPane{parent=main,x=1,y=1,panes={conn_sv_wait,conn_api_wait,main_pane}}
local root_pane = MultiPane{parent=main,y=1,panes={conn_sv_wait,conn_api_wait,main_pane}}
local function update()
local state = db.ps.get("link_state")
@@ -56,7 +56,7 @@ local function create_pages(root)
root_pane.register(db.ps, "link_state", update)
root_pane.register(db.ps, "loader_reqs", update)
TextBox{parent=main_pane,text="Connected!",x=1,y=6,alignment=core.ALIGN.CENTER}
TextBox{parent=main_pane,text="Connected!",y=6,alignment=core.ALIGN.CENTER}
end
return create_pages

View File

@@ -5,7 +5,7 @@
local types = require("scada-common.types")
local util = require("scada-common.util")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local pocket = require("pocket.pocket")
local process = require("pocket.process")
@@ -27,6 +27,8 @@ local NumberField = require("graphics.elements.form.NumberField")
local IconIndicator = require("graphics.elements.indicators.IconIndicator")
local PROCESS = types.PROCESS
local ALIGN = core.ALIGN
local cpair = core.cpair
local border = core.border
@@ -50,19 +52,19 @@ local dis_colors = cpair(colors.white, colors.lightGray)
-- new process control page view
---@param root Container parent
local function new_view(root)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local frame = Div{parent=root,x=1,y=1}
local frame = Div{parent=root,y=1}
local app = db.nav.register_app(APP_ID.PROCESS, frame, nil, false, true)
local load_div = Div{parent=frame,x=1,y=1}
local main = Div{parent=frame,x=1,y=1}
local load_div = Div{parent=frame,y=1}
local main = Div{parent=frame,y=1}
TextBox{parent=load_div,y=12,text="Loading...",alignment=ALIGN.CENTER}
WaitingAnim{parent=load_div,x=math.floor(main.get_width()/2)-1,y=8,fg_bg=cpair(colors.purple,colors._INHERIT)}
local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}}
local load_pane = MultiPane{parent=main,y=1,panes={load_div,main}}
app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
@@ -77,7 +79,7 @@ local function new_view(root)
local panes = {} ---@type Div[]
-- create all page divs
for _ = 1, db.facility.num_units + 3 do
for _ = 1, db.facility.num_units + 4 do
local div = Div{parent=page_div}
table.insert(panes, div)
end
@@ -107,7 +109,7 @@ local function new_view(root)
TextBox{parent=u_div,y=1,text="Reactor Unit #"..i,alignment=ALIGN.CENTER}
TextBox{parent=u_div,y=3,text="Auto Rate Limit",fg_bg=label_fg_bg}
rate_limits[i] = NumberField{parent=u_div,x=1,y=4,width=16,default=0.01,min=0.01,max_frac_digits=2,max_chars=8,allow_decimal=true,align_right=true,fg_bg=field_fg_bg,dis_fg_bg=field_dis_fg_bg}
rate_limits[i] = NumberField{parent=u_div,y=4,width=16,default=0.01,min=0.01,max_frac_digits=2,max_chars=8,allow_decimal=true,align_right=true,fg_bg=field_fg_bg,dis_fg_bg=field_dis_fg_bg}
TextBox{parent=u_div,x=18,y=4,text="mB/t",width=4,fg_bg=label_fg_bg}
rate_limits[i].register(unit.unit_ps, "max_burn", rate_limits[i].set_max)
@@ -151,36 +153,82 @@ local function new_view(root)
--#endregion
--#region process control options page
--#region process control mode page
local o_pane = panes[db.facility.num_units + 2]
local o_div = Div{parent=o_pane,x=2,width=main.get_width()-2}
local m_pane = panes[db.facility.num_units + 3]
local m_div = Div{parent=m_pane,x=2,width=main.get_width()-2}
local opt_page = app.new_page(nil, db.facility.num_units + 2)
opt_page.tasks = { update }
local mode_page = app.new_page(nil, db.facility.num_units + 3)
mode_page.tasks = { update }
TextBox{parent=o_div,y=1,text="Process Options",alignment=ALIGN.CENTER}
TextBox{parent=m_div,y=1,text="Process Mode",alignment=ALIGN.CENTER}
local ctl_opts = { "Monitored Max Burn", "Combined Burn Rate", "Charge Level", "Generation Rate" }
local mode = RadioButton{parent=o_div,x=1,y=3,options=ctl_opts,radio_colors=cpair(colors.lightGray,colors.gray),select_color=colors.purple,dis_fg_bg=style.btn_disable}
local desc = TextBox{parent=m_div,y=9,height=9,text="",fg_bg=label_fg_bg}
local function _set_desc(m)
if m == PROCESS.MAX_BURN then
desc.set_value("This mode runs all assigned reactors at their configured unit auto rate limits.")
elseif m == PROCESS.BURN_RATE then
desc.set_value("This mode runs assigned reactors by priority group to meet the requested burn rate. Primary ones are used, then secondary if they can't keep up, etc.")
elseif m == PROCESS.CHARGE then
desc.set_value("This mode runs assigned reactors by priority group to meet the requested induction matrix charge level. Primary ones are used, then secondary if they can't keep up, etc.")
elseif m == PROCESS.GEN_RATE then
desc.set_value("This mode runs assigned reactors by priority group to meet the requested energy generation rate. Primary ones are used, then secondary if they can't keep up, etc.")
elseif m == PROCESS.RANGE_CONTROL then
desc.set_value("This mode runs all assigned reactors at their configured unit auto rate limits once charge drops below the start percentage until it meets the stop percentage.")
else
desc.set_value("Unknown mode selected.")
end
end
local ctl_opts = { "Monitored Max Burn", "Combined Burn Rate", "Charge Level", "Generation Rate", "Charge Range" }
local mode = RadioButton{parent=m_div,y=3,options=ctl_opts,radio_colors=cpair(colors.lightGray,colors.gray),select_color=colors.purple,callback=_set_desc,dis_fg_bg=style.btn_disable}
mode.register(f_ps, "process_mode", mode.set_value)
desc.register(f_ps, "process_mode", _set_desc)
TextBox{parent=o_div,y=9,text="Burn Rate Target",fg_bg=label_fg_bg}
local b_target = NumberField{parent=o_div,x=1,y=10,width=15,default=0.01,min=0.01,max_frac_digits=2,max_chars=8,allow_decimal=true,align_right=true,fg_bg=field_fg_bg,dis_fg_bg=field_dis_fg_bg}
TextBox{parent=o_div,x=17,y=10,text="mB/t",fg_bg=label_fg_bg}
--#endregion
TextBox{parent=o_div,y=12,text="Charge Level Target",fg_bg=label_fg_bg}
local c_target = NumberField{parent=o_div,x=1,y=13,width=15,default=0,min=0,max_chars=16,align_right=true,fg_bg=field_fg_bg,dis_fg_bg=field_dis_fg_bg}
TextBox{parent=o_div,x=17,y=13,text="M"..db.energy_label,fg_bg=label_fg_bg}
--#region process control setpoints page
TextBox{parent=o_div,y=15,text="Generation Target",fg_bg=label_fg_bg}
local g_target = NumberField{parent=o_div,x=1,y=16,width=15,default=0,min=0,max_chars=16,align_right=true,fg_bg=field_fg_bg,dis_fg_bg=field_dis_fg_bg}
TextBox{parent=o_div,x=17,y=16,text="k"..db.energy_label.."/t",fg_bg=label_fg_bg}
local s_pane = panes[db.facility.num_units + 4]
local s_div = Div{parent=s_pane,x=2,width=main.get_width()-2}
local sp_page = app.new_page(nil, db.facility.num_units + 4)
sp_page.tasks = { update }
TextBox{parent=s_div,y=1,text="Process Setpoints",alignment=ALIGN.CENTER}
TextBox{parent=s_div,y=3,text="Burn Rate Target",fg_bg=label_fg_bg}
local b_target = NumberField{parent=s_div,y=4,width=15,default=0.01,min=0.01,max_frac_digits=2,max_chars=8,allow_decimal=true,align_right=true,fg_bg=field_fg_bg,dis_fg_bg=field_dis_fg_bg}
TextBox{parent=s_div,x=17,y=4,text="mB/t",fg_bg=label_fg_bg}
TextBox{parent=s_div,y=6,text="Charge Level Target",fg_bg=label_fg_bg}
local c_target = NumberField{parent=s_div,y=7,width=15,default=0,min=0,max_chars=16,align_right=true,fg_bg=field_fg_bg,dis_fg_bg=field_dis_fg_bg}
TextBox{parent=s_div,x=17,y=7,text="M"..db.energy_label,fg_bg=label_fg_bg}
TextBox{parent=s_div,y=9,text="Generation Target",fg_bg=label_fg_bg}
local g_target = NumberField{parent=s_div,y=10,width=15,default=0,min=0,max_chars=16,align_right=true,fg_bg=field_fg_bg,dis_fg_bg=field_dis_fg_bg}
TextBox{parent=s_div,x=17,y=10,text="k"..db.energy_label.."/t",fg_bg=label_fg_bg}
local range_start, range_stop ---@type NumberField, NumberField
local function _update_start_val(value) range_start.set_value(math.min(range_start.get_value(), value - 1)) end
local function _update_stop_val(value) range_stop.set_value(math.max(range_stop.get_value(), value + 1)) end
TextBox{parent=s_div,y=12,text="Charge Range - Start",fg_bg=label_fg_bg}
range_start = NumberField{parent=s_div,y=13,width=15,default=0,min=0,max=99,align_right=true,on_unfocus=_update_stop_val,fg_bg=field_fg_bg,dis_fg_bg=field_dis_fg_bg}
TextBox{parent=s_div,x=17,y=13,text="%",fg_bg=label_fg_bg}
TextBox{parent=s_div,y=15,text="Charge Range - Stop",fg_bg=label_fg_bg}
range_stop = NumberField{parent=s_div,y=16,width=15,default=0,min=1,max=100,align_right=true,on_unfocus=_update_start_val,fg_bg=field_fg_bg,dis_fg_bg=field_dis_fg_bg}
TextBox{parent=s_div,x=17,y=16,text="%",fg_bg=label_fg_bg}
b_target.register(f_ps, "process_burn_target", b_target.set_value)
c_target.register(f_ps, "process_charge_target", c_target.set_value)
g_target.register(f_ps, "process_gen_target", g_target.set_value)
range_start.register(f_ps, "process_range_start", range_start.set_value)
range_stop.register(f_ps, "process_range_stop", range_stop.set_value)
--#endregion
@@ -194,9 +242,9 @@ local function new_view(root)
TextBox{parent=c_div,y=1,text="Process Control",alignment=ALIGN.CENTER}
local u_stat = Rectangle{parent=c_div,border=border(1,colors.gray,true),thin=true,width=21,height=5,x=1,y=3,fg_bg=cpair(colors.black,colors.lightGray)}
local stat_line_1 = TextBox{parent=u_stat,x=1,y=1,text="UNKNOWN",alignment=ALIGN.CENTER}
local stat_line_2 = TextBox{parent=u_stat,x=1,y=2,text="awaiting data...",height=2,alignment=ALIGN.CENTER,trim_whitespace=true,fg_bg=cpair(colors.gray,colors.lightGray)}
local u_stat = Rectangle{parent=c_div,border=border(1,colors.gray,true),thin=true,width=21,height=5,y=3,fg_bg=cpair(colors.black,colors.lightGray)}
local stat_line_1 = TextBox{parent=u_stat,y=1,text="UNKNOWN",alignment=ALIGN.CENTER}
local stat_line_2 = TextBox{parent=u_stat,y=2,text="awaiting data...",height=2,alignment=ALIGN.CENTER,trim_whitespace=true,fg_bg=cpair(colors.gray,colors.lightGray)}
stat_line_1.register(f_ps, "status_line_1", stat_line_1.set_value)
stat_line_2.register(f_ps, "status_line_2", stat_line_2.set_value)
@@ -205,8 +253,13 @@ local function new_view(root)
local limits = {}
for i = 1, #rate_limits do limits[i] = rate_limits[i].get_numeric() end
process.process_start(mode.get_value(), b_target.get_numeric(), db.energy_convert_to_fe(c_target.get_numeric()),
db.energy_convert_to_fe(g_target.get_numeric()), limits)
-- make sure stop is always above start (start maxes at 99 and stop maxes at 100 so this always works)
if range_stop.get_value() <= range_start.get_value() then
range_stop.set_value(range_start.get_value() + 1)
end
process.process_start(mode.get_value(), b_target.get_numeric(), range_start.get_numeric(), range_stop.get_numeric(),
db.energy_convert_to_fe(c_target.get_numeric()), db.energy_convert_to_fe(g_target.get_numeric()), limits)
end
local start = HazardButton{parent=c_div,x=2,y=9,text="START",accent=colors.lightBlue,callback=_start_auto,timeout=3,fg_bg=hzd_fg_bg,dis_colors=dis_colors}
@@ -237,6 +290,8 @@ local function new_view(root)
b_target.disable()
c_target.disable()
g_target.disable()
range_start.disable()
range_stop.disable()
mode.disable()
start.disable()
@@ -246,6 +301,8 @@ local function new_view(root)
b_target.enable()
c_target.enable()
g_target.enable()
range_start.enable()
range_stop.enable()
mode.enable()
if db.facility.auto_ready then start.enable() end
@@ -258,10 +315,10 @@ local function new_view(root)
--#region auto-SCRAM annunciator page
local a_pane = panes[db.facility.num_units + 3]
local a_pane = panes[db.facility.num_units + 2]
local a_div = Div{parent=a_pane,x=2,width=main.get_width()-2}
local annunc_page = app.new_page(nil, db.facility.num_units + 3)
local annunc_page = app.new_page(nil, db.facility.num_units + 2)
annunc_page.tasks = { update }
TextBox{parent=a_div,y=1,text="Automatic SCRAM",alignment=ALIGN.CENTER}
@@ -291,7 +348,7 @@ local function new_view(root)
--#endregion
-- setup multipane
local u_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
local u_pane = MultiPane{parent=page_div,y=1,panes=panes}
app.set_root_pane(u_pane)
-- setup sidebar
@@ -300,7 +357,8 @@ local function new_view(root)
{ label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home },
{ label = " \x17 ", color = core.cpair(colors.black, colors.purple), callback = proc_ctrl.nav_to },
{ label = " \x13 ", color = core.cpair(colors.black, colors.red), callback = annunc_page.nav_to },
{ label = "OPT", color = core.cpair(colors.black, colors.yellow), callback = opt_page.nav_to }
{ label = " \x07 ", color = core.cpair(colors.black, colors.yellow), callback = mode_page.nav_to },
{ label = " \x12 ", color = core.cpair(colors.black, colors.lightBlue), callback = sp_page.nav_to }
}
for i = 1, db.facility.num_units do

View File

@@ -4,7 +4,7 @@
local util = require("scada-common.util")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local pocket = require("pocket.pocket")
local style = require("pocket.ui.style")
@@ -33,19 +33,19 @@ local lu_col = style.label_unit_pair
-- new radiation monitor page view
---@param root Container parent
local function new_view(root)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local frame = Div{parent=root,x=1,y=1}
local frame = Div{parent=root,y=1}
local app = db.nav.register_app(APP_ID.RADMON, frame, nil, false, true)
local load_div = Div{parent=frame,x=1,y=1}
local main = Div{parent=frame,x=1,y=1}
local load_div = Div{parent=frame,y=1}
local main = Div{parent=frame,y=1}
TextBox{parent=load_div,y=12,text="Loading...",alignment=ALIGN.CENTER}
WaitingAnim{parent=load_div,x=math.floor(main.get_width()/2)-1,y=8,fg_bg=cpair(colors.yellow,colors._INHERIT)}
local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}}
local load_pane = MultiPane{parent=main,y=1,panes={load_div,main}}
app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
@@ -174,7 +174,7 @@ local function new_view(root)
--#endregion
-- setup multipane
local u_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
local u_pane = MultiPane{parent=page_div,y=1,panes=panes}
app.set_root_pane(u_pane)
-- setup sidebar

View File

@@ -4,7 +4,7 @@
local util = require("scada-common.util")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local pocket = require("pocket.pocket")
local style = require("pocket.ui.style")
@@ -49,19 +49,19 @@ local emc_ind_s = {
-- new unit page view
---@param root Container parent
local function new_view(root)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local frame = Div{parent=root,x=1,y=1}
local frame = Div{parent=root,y=1}
local app = db.nav.register_app(APP_ID.UNITS, frame, nil, false, true)
local load_div = Div{parent=frame,x=1,y=1}
local main = Div{parent=frame,x=1,y=1}
local load_div = Div{parent=frame,y=1}
local main = Div{parent=frame,y=1}
TextBox{parent=load_div,y=12,text="Loading...",alignment=ALIGN.CENTER}
WaitingAnim{parent=load_div,x=math.floor(main.get_width()/2)-1,y=8,fg_bg=cpair(colors.yellow,colors._INHERIT)}
local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}}
local load_pane = MultiPane{parent=main,y=1,panes={load_div,main}}
app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
@@ -149,7 +149,7 @@ local function new_view(root)
u_page.tasks = { update }
TextBox{parent=u_div,y=1,text="Reactor Unit #"..i,alignment=ALIGN.CENTER}
PushButton{parent=u_div,x=1,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()prev(i)end}
PushButton{parent=u_div,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()prev(i)end}
PushButton{parent=u_div,x=21,y=1,text=">",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()next(i)end}
local type = util.trinary(unit.num_boilers > 0, "Sodium Cooled Reactor", "Boiling Water Reactor")
@@ -158,7 +158,7 @@ local function new_view(root)
local rate = DataIndicator{parent=u_div,y=5,lu_colors=lu_col,label="Burn",unit="mB/t",format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg}
local temp = DataIndicator{parent=u_div,lu_colors=lu_col,label="Temp",unit=db.temp_label,format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg}
local ctrl = IconIndicator{parent=u_div,x=1,y=8,label="Control State",states=mode_states}
local ctrl = IconIndicator{parent=u_div,y=8,label="Control State",states=mode_states}
rate.register(u_ps, "act_burn_rate", rate.update)
temp.register(u_ps, "temp", function (t) temp.update(db.temp_convert(t)) end)
@@ -166,24 +166,24 @@ local function new_view(root)
u_div.line_break()
local rct = IconIndicator{parent=u_div,x=1,label="Fission Reactor",states=basic_states}
local rps = IconIndicator{parent=u_div,x=1,label="Protection System",states=basic_states}
local rct = IconIndicator{parent=u_div,label="Fission Reactor",states=basic_states}
local rps = IconIndicator{parent=u_div,label="Protection System",states=basic_states}
rct.register(u_ps, "U_ReactorStatus", rct.update)
rps.register(u_ps, "U_RPS", rps.update)
u_div.line_break()
local rcs = IconIndicator{parent=u_div,x=1,label="Coolant System",states=basic_states}
local rcs = IconIndicator{parent=u_div,label="Coolant System",states=basic_states}
rcs.register(u_ps, "U_RCS", rcs.update)
for b = 1, unit.num_boilers do
local blr = IconIndicator{parent=u_div,x=1,label="Boiler "..b,states=basic_states}
local blr = IconIndicator{parent=u_div,label="Boiler "..b,states=basic_states}
blr.register(unit.boiler_ps_tbl[b], "BoilerStatus", blr.update)
end
for t = 1, unit.num_turbines do
local tbn = IconIndicator{parent=u_div,x=1,label="Turbine "..t,states=basic_states}
local tbn = IconIndicator{parent=u_div,label="Turbine "..t,states=basic_states}
tbn.register(unit.turbine_ps_tbl[t], "TurbineStatus", tbn.update)
end
@@ -377,7 +377,7 @@ local function new_view(root)
end
-- setup multipane
local u_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
local u_pane = MultiPane{parent=page_div,y=1,panes=panes}
app.set_root_pane(u_pane)
set_sidebar(active_unit)

View File

@@ -4,7 +4,7 @@
local util = require("scada-common.util")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local pocket = require("pocket.pocket")
local process = require("pocket.process")
@@ -40,19 +40,19 @@ local wht_ind_s = style.icon_states.wht_ind_s
-- new waste control page view
---@param root Container parent
local function new_view(root)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local frame = Div{parent=root,x=1,y=1}
local frame = Div{parent=root,y=1}
local app = db.nav.register_app(APP_ID.WASTE, frame, nil, false, true)
local load_div = Div{parent=frame,x=1,y=1}
local main = Div{parent=frame,x=1,y=1}
local load_div = Div{parent=frame,y=1}
local main = Div{parent=frame,y=1}
TextBox{parent=load_div,y=12,text="Loading...",alignment=ALIGN.CENTER}
WaitingAnim{parent=load_div,x=math.floor(main.get_width()/2)-1,y=8,fg_bg=cpair(colors.brown,colors._INHERIT)}
local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}}
local load_pane = MultiPane{parent=main,y=1,panes={load_div,main}}
app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
@@ -262,7 +262,7 @@ local function new_view(root)
--#endregion
-- setup multipane
local w_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
local w_pane = MultiPane{parent=page_div,y=1,panes=panes}
app.set_root_pane(w_pane)
-- setup sidebar

View File

@@ -2,7 +2,7 @@
-- Connection Waiting Spinner
--
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local style = require("pocket.ui.style")
@@ -22,10 +22,10 @@ local cpair = core.cpair
---@param y integer y offset
local function init(parent, y, is_api)
-- root div
local root = Div{parent=parent,x=1,y=1}
local root = Div{parent=parent,y=1}
-- bounding box div
local box = Div{parent=root,x=1,y=y,height=12}
local box = Div{parent=root,y=y,height=12}
local waiting_x = math.floor(parent.get_width() / 2) - 1
@@ -34,11 +34,11 @@ local function init(parent, y, is_api)
if is_api then
WaitingAnim{parent=box,x=waiting_x,y=1,fg_bg=cpair(colors.blue,style.root.bkg)}
TextBox{parent=box,y=5,text="Connecting to API",alignment=ALIGN.CENTER,fg_bg=cpair(colors.white,style.root.bkg),trim_whitespace=true}
msg.register(iocontrol.get_db().ps, "api_link_msg", msg.set_value)
msg.register(ioctl.get_db().ps, "api_link_msg", msg.set_value)
else
WaitingAnim{parent=box,x=waiting_x,y=1,fg_bg=cpair(colors.green,style.root.bkg)}
TextBox{parent=box,y=5,text="Connecting to Supervisor",alignment=ALIGN.CENTER,fg_bg=cpair(colors.white,style.root.bkg),trim_whitespace=true}
msg.register(iocontrol.get_db().ps, "svr_link_msg", msg.set_value)
msg.register(ioctl.get_db().ps, "svr_link_msg", msg.set_value)
end
return root

View File

@@ -95,7 +95,7 @@ text("A wired modem is only connected to the block when you right click it and i
tip("Do not connect all peripherals in the system on the same network cable, since Reactor PLCs will grab the first reactor they find and you may accidentally duplicate RTUs.")
sect("Computer Conns")
tip("It helps to be familiar with how ComputerCraft manages peripherals before using this system, though it is not necessary.")
doc("usage_conn_network", "Network", "All computers in the system communicate with each other via wireless or ender modems. Ender modems are preferred due to the unlimited range.")
doc("usage_conn_network", "Network", "All computers in the system communicate with each other via wired, wireless, and/or Ender modems. Ender modems are preferred over wireless due to the unlimited range.")
text("Five different network channels are used and must have the same value for each name across all devices.")
text("For example, the supervisor channel SVR_CHANNEL must be set to the same channel for all devices in your system. Two different named channels should not share the same value (such as SVR_CHANNEL vs CRD_CHANNEL).")
doc("usage_conn_peri", "Peripherals", "ComputerCraft peripherals like monitors and speakers need to touch the computer or be connected via wired modems.")
@@ -167,10 +167,11 @@ doc("usage_auto_setpoints", "Setpoints", "Three setpoint spinner inputs are avai
doc("usage_auto_limits", "Unit Limits", "Each unit can be limited to a maximum auto control burn rate to prevent exceeding any safe levels that you know of.")
doc("usage_auto_states", "Unit States", "Any assigned units must be shown as Ready and not Degraded to use auto control. See Operator UIs > Coordinator > Main Display for more.")
sect("Operation Modes")
text("Four auto control modes are available that function based on configurations set on the main display. All modes except Monitored Max Burn will try to only use the primary group until it can't keep up, then the secondary, etc.")
text("Five auto control modes are available that function based on configurations set on the main display. All modes except Monitored Max Burn and Charge Range will try to only use the primary group until it can't keep up, then the secondary, etc.")
note("No units will be set to a burn rate higher than their limit.")
doc("usage_op_mon_max", "Monitored Max Burn", "This mode runs all units assigned to auto control at their unit limit burn rate regardless of priority group.")
doc("usage_op_com_rate", "Combined Burn Rate", "Assigned units will be commanded to meet the Burn Target setpoint.")
doc("usage_op_chg_range", "Charge Range", "This mode runs all units assigned to auto control at their unit limit burn rate regardless of priority group if the charge percentage drops to the start threshold until it reaches the stop threshold, keeping it within that range.")
doc("usage_op_chg_level", "Charge Level", "Assigned units will be commanded to bring the induction matrix up to the requested Charge Target.")
doc("usage_op_gen_rate", "Generation Rate", "Assigned units will be commanded to maintain the requested Generation Target.")
note("The rate used is the input rate into the induction matrix, so using other power generation sources may disrupt this control mode.")
@@ -324,7 +325,9 @@ doc("ui_fac_rad", "Radiation", "The facility radiation, which is the current max
doc("ui_fac_linked", "Linked RTUs", "The number of RTU Gateways connected.")
sect("Automatic Control")
text("This interface is used for managing automatic facility control, which only applies to units set via the unit display to be under auto control. This includes setpoints, status, configuration, and control.")
doc("ui_fac_auto_alt", "\x12T/\x12R", "This selector next to Charge Target/Range lets you toggle between charge target and charge range control.")
doc("ui_fac_auto_bt", "Burn Target", "When set to Combined Burn Rate mode, assigned units will ramp up to meet this combined target.")
doc("ui_fac_auto_cr", "Charge Range", "When set to Charge Range mode, assigned units will run once the induction matrix charge percentage falls to the start threshold until it reaches the stop threshold, keeping it within the range.")
doc("ui_fac_auto_ct", "Charge Target", "When set to Charge Level mode, assigned units will run to reach and maintain this induction matrix charge level.")
doc("ui_fac_auto_gt", "Gen. Target", "When set to Generation Rate mode, assigned units will run to reach and maintain this continuous power output, using the induction matrix input rate.")
doc("ui_fac_save", "SAVE", "This saves your configuration without starting control.")
@@ -427,15 +430,21 @@ sect("Core Status")
doc("fp_status", "STATUS", "This is always lit, except on the Reactor PLC (see Reactor PLC section).")
doc("fp_heartbeat", "HEARTBEAT", "This alternates between lit and unlit as the main loop on the device runs. If this freezes, something is wrong and the logs will indicate why.")
sect("Hardware & Network")
doc("fp_modem", "MODEM", "This lights up if the wireless/ender modem is connected. In parentheses is the unique computer ID of this device, which will show up in places such as the Supervisor's connection lists.")
doc("fp_modem", "NETWORK", "This is present when in standard color modes and indicates the network status using multiple colors.")
doc("fp_modem", "MODEM", "This indicates the status of the comms modem, if you only have one. If you have two, they will be named WD/WL MODEM.")
list(DOC_LIST_TYPE.LED, { "disconnected", "link down", "link up" }, { colors.gray, colors.yellow, colors.green })
doc("fp_modem", "WD MODEM", "This indicates the status of the wired comms modem.")
list(DOC_LIST_TYPE.LED, { "disconnected", "link down", "link up" }, { colors.gray, colors.yellow, colors.green })
doc("fp_modem", "WL MODEM", "This indicates the status of the wireless/Ender comms modem.")
list(DOC_LIST_TYPE.LED, { "disconnected", "link down", "link up" }, { colors.gray, colors.yellow, colors.green })
doc("fp_network", "NETWORK", "This is present when in standard color modes and indicates the network status using multiple colors.")
list(DOC_LIST_TYPE.LED, { "not linked", "linked", "link denied", "bad comms version", "duplicate PLC" }, { colors.gray, colors.green, colors.red, colors.orange, colors.yellow })
text("You can fix \"bad comms version\" by ensuring all devices are up-to-date, as this indicates a communications protocol version mismatch. Note that yellow is Reactor PLC-specific, indicating duplicate unit IDs in use.")
doc("fp_nt_linked", "NT LINKED", "(color accessibility modes only)", "This indicates the device is linked to the Supervisor.")
doc("fp_nt_version", "NT VERSION", "(color accessibility modes only)", "This indicates the communications versions of the Supervisor and this device do not match. Make sure everything is up-to-date.")
sect("Versions")
sect("Hardware Labels")
doc("fp_fw", "FW", "Firmware application version of this device.")
doc("fp_nt", "NT", "Network (comms) version this device has. These must match between devices in order for them to connect.")
doc("fp_sn", "SN", "Device \"serial number\", made up of the Computer ID (shown on the Supervisor, Coordinator, and Pocket connection lists) and the device type.")
target = docs.fp.r_plc
sect("Overview")
@@ -518,10 +527,12 @@ text("This tab includes information about the Coordinator, partially covered by
doc("fp_crd_rt_main", "RT MAIN", "This indicates that the device's main loop co-routine is running.")
doc("fp_crd_rt_render", "RT RENDER", "This indicates that the Coordinator graphics renderer co-routine is running.")
doc("fp_crd_spkr", "SPEAKER", "This indicates if the speaker is connected.")
list(DOC_LIST_TYPE.LED, { "Disconnected", "Display View Unloaded", "Display View Loaded" }, { colors.gray, colors.red, colors.green })
doc("fp_crd_mon_main", "MAIN DISPLAY", "The connection status of the main display monitor.")
doc("fp_crd_mon_flow", "FLOW DISPLAY", "The connection status of the coolant and waste flow display monitor.")
doc("fp_crd_mon_unit", "UNIT X DISPLAY", "The connection status of the monitor associated with a given unit.")
doc("fp_crd_mon_main", "MAIN DISPLAY", "The status of the main display monitor.")
list(DOC_LIST_TYPE.LED, { "disconnected", "view unloaded", "view loaded" }, { colors.gray, colors.red, colors.green })
doc("fp_crd_mon_flow", "FLOW DISPLAY", "The status of the coolant and waste flow display monitor.")
list(DOC_LIST_TYPE.LED, { "disconnected", "view unloaded", "view loaded" }, { colors.gray, colors.red, colors.green })
doc("fp_crd_mon_unit", "UNIT X DISPLAY", "The status of the monitor associated with a given unit.")
list(DOC_LIST_TYPE.LED, { "disconnected", "view unloaded", "view loaded" }, { colors.gray, colors.red, colors.green })
sect("API Tab")
text("This tab lists connected pocket computers. Refer to the Supervisor PKT tab documentation for details on fields.")

View File

@@ -4,7 +4,7 @@
local util = require("scada-common.util")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local pocket = require("pocket.pocket")
local about_app = require("pocket.ui.apps.about")
@@ -44,7 +44,7 @@ local APP_ID = pocket.APP_ID
-- create new main view
---@param main DisplayBox main displaybox
local function init(main)
local db = iocontrol.get_db()
local db = ioctl.get_db()
-- window header message and connection status
TextBox{parent=main,y=1,text=" S C ",fg_bg=style.header}
@@ -54,13 +54,13 @@ local function init(main)
db.ps.subscribe("svr_conn_quality", svr_conn.set_value)
db.ps.subscribe("crd_conn_quality", crd_conn.set_value)
local start_pane = Div{parent=main,x=1,y=2}
local main_pane = Div{parent=main,x=1,y=2}
local start_pane = Div{parent=main,y=2}
local main_pane = Div{parent=main,y=2}
WaitingAnim{parent=start_pane,x=12,y=7,fg_bg=cpair(colors.lightBlue,style.root.bkg)}
TextBox{parent=start_pane,y=11,text="starting up...",alignment=ALIGN.CENTER,fg_bg=cpair(colors.lightGray,style.root.bkg)}
local root_pane = MultiPane{parent=main,x=1,y=2,panes={start_pane,main_pane}}
local root_pane = MultiPane{parent=main,y=2,panes={start_pane,main_pane}}
local page_div = Div{parent=main_pane,x=4,y=1}
@@ -81,10 +81,10 @@ local function init(main)
-- verify all apps were created
assert(util.table_len(db.nav.get_containers()) == APP_ID.NUM_APPS, "app IDs were not sequential or some apps weren't registered")
db.nav.set_pane(MultiPane{parent=page_div,x=1,y=1,panes=db.nav.get_containers()})
db.nav.set_sidebar(Sidebar{parent=main_pane,x=1,y=1,height=18,fg_bg=cpair(colors.white,colors.gray)})
db.nav.set_pane(MultiPane{parent=page_div,y=1,panes=db.nav.get_containers()})
db.nav.set_sidebar(Sidebar{parent=main_pane,y=1,height=18,fg_bg=cpair(colors.white,colors.gray)})
PushButton{parent=main_pane,x=1,y=19,text="\x1b",min_width=3,fg_bg=cpair(colors.white,colors.gray),active_fg_bg=cpair(colors.gray,colors.black),callback=db.nav.nav_up}
PushButton{parent=main_pane,y=19,text="\x1b",min_width=3,fg_bg=cpair(colors.white,colors.gray),active_fg_bg=cpair(colors.gray,colors.black),callback=db.nav.nav_up}
db.nav.go_home()

View File

@@ -5,7 +5,7 @@
local types = require("scada-common.types")
local util = require("scada-common.util")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local style = require("pocket.ui.style")
@@ -43,7 +43,7 @@ local mode_ind_s = {
---@param ps psil
---@param update function
return function (app, page, panes, tank_pane, tank_id, ps, update)
local fac = iocontrol.get_db().facility
local fac = ioctl.get_db().facility
local tank_div = Div{parent=tank_pane,x=2,width=tank_pane.get_width()-2}
table.insert(panes, tank_div)

View File

@@ -2,7 +2,7 @@
-- Induction Matrix View
--
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local style = require("pocket.ui.style")
@@ -36,7 +36,7 @@ local wht_ind_s = style.icon_states.wht_ind_s
---@param ps psil
---@param update function
return function (app, panes, matrix_pane, ps, update)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local fac = db.facility
local mtx_div = Div{parent=matrix_pane,x=2,width=matrix_pane.get_width()-2}
@@ -95,7 +95,7 @@ return function (app, panes, matrix_pane, ps, update)
local chging = IconIndicator{parent=mtx_ext_div,y=3,label="Charging",states=wht_ind_s}
local dischg = IconIndicator{parent=mtx_ext_div,y=4,label="Discharging",states=wht_ind_s}
TextBox{parent=mtx_ext_div,text="Energy Fill",x=1,y=6,width=13,fg_bg=label}
TextBox{parent=mtx_ext_div,text="Energy Fill",y=6,width=13,fg_bg=label}
local fill = DataIndicator{parent=mtx_ext_div,x=14,y=6,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg}
chging.register(ps, "is_charging", chging.update)
@@ -104,18 +104,18 @@ return function (app, panes, matrix_pane, ps, update)
local max_io = IconIndicator{parent=mtx_ext_div,y=8,label="Max I/O Rate",states=yel_ind_s}
TextBox{parent=mtx_ext_div,text="Input Util.",x=1,y=10,width=13,fg_bg=label}
TextBox{parent=mtx_ext_div,text="Input Util.",y=10,width=13,fg_bg=label}
local in_util = DataIndicator{parent=mtx_ext_div,x=14,y=10,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg}
TextBox{parent=mtx_ext_div,text="Output Util.",x=1,y=11,width=13,fg_bg=label}
TextBox{parent=mtx_ext_div,text="Output Util.",y=11,width=13,fg_bg=label}
local out_util = DataIndicator{parent=mtx_ext_div,x=14,y=11,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg}
max_io.register(ps, "at_max_io", max_io.update)
in_util.register(ps, "last_input", function (x) in_util.update(calc_saturation(x) * 100) end)
out_util.register(ps, "last_output", function (x) out_util.update(calc_saturation(x) * 100) end)
TextBox{parent=mtx_ext_div,text="Capacity ("..db.energy_label..")",x=1,y=13,fg_bg=label}
TextBox{parent=mtx_ext_div,text="Capacity ("..db.energy_label..")",y=13,fg_bg=label}
local capacity = DataIndicator{parent=mtx_ext_div,y=14,lu_colors=lu_col,label="",unit="",format="%21d",value=0,width=21,fg_bg=text_fg}
TextBox{parent=mtx_ext_div,text="Max In/Out ("..db.energy_label.."/t)",x=1,y=15,fg_bg=label}
TextBox{parent=mtx_ext_div,text="Max In/Out ("..db.energy_label.."/t)",y=15,fg_bg=label}
local trans_cap = DataIndicator{parent=mtx_ext_div,y=16,lu_colors=lu_col,label="",unit="",format="%21d",rate=true,value=0,width=21,fg_bg=text_fg}
capacity.register(ps, "max_energy", function (val) capacity.update(db.energy_convert(val)) end)

View File

@@ -2,7 +2,7 @@
-- SPS View
--
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local style = require("pocket.ui.style")
@@ -31,7 +31,7 @@ local text_fg = style.text_fg
---@param ps psil
---@param update function
return function (app, panes, sps_pane, ps, update)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local sps_div = Div{parent=sps_pane,x=2,width=sps_pane.get_width()-2}
table.insert(panes, sps_div)
@@ -70,16 +70,16 @@ return function (app, panes, sps_pane, ps, update)
TextBox{parent=sps_ext_div,y=1,text="More SPS Info",alignment=ALIGN.CENTER}
TextBox{parent=sps_ext_div,text="Polonium",x=1,y=3,width=13,fg_bg=label}
TextBox{parent=sps_ext_div,text="Polonium",y=3,width=13,fg_bg=label}
local input_p = DataIndicator{parent=sps_ext_div,x=14,y=3,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg}
local input_amnt = DataIndicator{parent=sps_ext_div,x=1,y=4,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
local input_amnt = DataIndicator{parent=sps_ext_div,y=4,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
input_p.register(ps, "input_fill", function (x) input_p.update(x * 100) end)
input_amnt.register(ps, "input", function (x) input_amnt.update(x.amount) end)
TextBox{parent=sps_ext_div,text="Antimatter",x=1,y=6,width=15,fg_bg=label}
TextBox{parent=sps_ext_div,text="Antimatter",y=6,width=15,fg_bg=label}
local output_p = DataIndicator{parent=sps_ext_div,x=14,y=6,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg}
local output_amnt = DataIndicator{parent=sps_ext_div,x=1,y=7,lu_colors=lu_col,label="",unit="\xb5B",format="%18.3f",value=0,commas=true,width=21,fg_bg=text_fg}
local output_amnt = DataIndicator{parent=sps_ext_div,y=7,lu_colors=lu_col,label="",unit="\xb5B",format="%18.3f",value=0,commas=true,width=21,fg_bg=text_fg}
output_p.register(ps, "output_fill", function (x) output_p.update(x * 100) end)
output_amnt.register(ps, "output", function (x) output_amnt.update(x.amount) end)

View File

@@ -46,8 +46,8 @@ return function (data, base_page, title, items, scroll_height)
TextBox{parent=section_view_div,y=1,text=title,alignment=ALIGN.CENTER}
PushButton{parent=section_view_div,x=2,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=section_page.nav_to}
local name_list = ListBox{parent=section_div,x=1,y=3,scroll_height=60,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)}
local def_list = ListBox{parent=section_view_div,x=1,y=3,scroll_height=scroll_height,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)}
local name_list = ListBox{parent=section_div,y=3,scroll_height=60,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)}
local def_list = ListBox{parent=section_view_div,y=3,scroll_height=scroll_height,nav_fg_bg=cpair(colors.lightGray,colors.gray),nav_active=cpair(colors.white,colors.gray)}
local sect_id = 1
local page_end
@@ -62,7 +62,7 @@ return function (data, base_page, title, items, scroll_height)
local title_offs = string.len(title_text) + 2
local sect_title = Div{parent=def_list,height=1}
TextBox{parent=sect_title,x=1,text=title_text,fg_bg=cpair(colors.lightGray,colors.black)}
TextBox{parent=sect_title,text=title_text,fg_bg=cpair(colors.lightGray,colors.black)}
local anchor = TextBox{parent=sect_title,x=title_offs,y=1,text=item.name,anchor=true,fg_bg=cpair(colors.green,colors.black)}
page_end = Div{parent=def_list,height=1,can_focus=true}
@@ -80,7 +80,7 @@ return function (data, base_page, title, items, scroll_height)
table.insert(search_db, { string.lower(item.name), item.name, title, view })
local name_title = Div{parent=name_list,height=1}
TextBox{parent=name_title,x=1,text=title_text,fg_bg=cpair(colors.lightGray,colors.black)}
TextBox{parent=name_title,text=title_text,fg_bg=cpair(colors.lightGray,colors.black)}
PushButton{parent=name_title,x=title_offs,y=1,text=item.name,alignment=ALIGN.LEFT,fg_bg=cpair(colors.green,colors.black),active_fg_bg=btn_active,callback=view}
sect_id = sect_id + 1
@@ -107,7 +107,7 @@ return function (data, base_page, title, items, scroll_height)
table.insert(search_db, { string.lower(item.name), item.name, title, view })
local name_entry = Div{parent=name_list,height=#util.strwrap(item.name,name_list.get_width()-3)}
TextBox{parent=name_entry,x=1,text="\x10",fg_bg=cpair(colors.gray,colors.black)}
TextBox{parent=name_entry,text="\x10",fg_bg=cpair(colors.gray,colors.black)}
PushButton{parent=name_entry,x=3,y=1,text=item.name,alignment=ALIGN.LEFT,fg_bg=cpair(colors.blue,colors.black),active_fg_bg=btn_active,callback=view}
elseif item.type == DOC_TYPE.TEXT then
---@cast item pocket_doc_text

View File

@@ -2,7 +2,7 @@
-- Main Home Page
--
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local pocket = require("pocket.pocket")
local core = require("graphics.core")
@@ -19,18 +19,18 @@ local APP_ID = pocket.APP_ID
-- new home page view
---@param root Container parent
local function new_view(root)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local main = Div{parent=root,x=1,y=1,height=19}
local main = Div{parent=root,y=1,height=19}
local app = db.nav.register_app(APP_ID.ROOT, main)
local apps_1 = Div{parent=main,x=1,y=1,height=15}
local apps_2 = Div{parent=main,x=1,y=1,height=15}
local apps_1 = Div{parent=main,y=1,height=15}
local apps_2 = Div{parent=main,y=1,height=15}
local panes = { apps_1, apps_2 }
local app_pane = AppMultiPane{parent=main,x=1,y=1,height=18,panes=panes,active_color=colors.lightGray,nav_colors=cpair(colors.lightGray,colors.gray),scroll_nav=true,drag_nav=true,callback=app.switcher}
local app_pane = AppMultiPane{parent=main,y=1,height=18,panes=panes,active_color=colors.lightGray,nav_colors=cpair(colors.lightGray,colors.gray),scroll_nav=true,drag_nav=true,callback=app.switcher}
app.set_root_pane(app_pane)
app.new_page(app.new_page(nil, 1), 2)

View File

@@ -5,7 +5,7 @@
local types = require("scada-common.types")
local util = require("scada-common.util")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local style = require("pocket.ui.style")
@@ -39,7 +39,7 @@ local yel_ind_s = style.icon_states.yel_ind_s
---@param ps psil
---@param update function
return function (app, u_page, panes, blr_pane, b_id, ps, update)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local blr_div = Div{parent=blr_pane,x=2,width=blr_pane.get_width()-2}
table.insert(panes, blr_div)
@@ -51,12 +51,12 @@ return function (app, u_page, panes, blr_pane, b_id, ps, update)
local status = StateIndicator{parent=blr_div,x=10,y=1,states=style.boiler.states,value=1,min_width=12}
status.register(ps, "BoilerStateStatus", status.update)
local hcool = VerticalBar{parent=blr_div,x=1,y=4,fg_bg=cpair(colors.orange,colors.gray),height=5,width=1}
local hcool = VerticalBar{parent=blr_div,y=4,fg_bg=cpair(colors.orange,colors.gray),height=5,width=1}
local water = VerticalBar{parent=blr_div,x=3,y=4,fg_bg=cpair(colors.blue,colors.gray),height=5,width=1}
local steam = VerticalBar{parent=blr_div,x=19,y=4,fg_bg=cpair(colors.white,colors.gray),height=5,width=1}
local ccool = VerticalBar{parent=blr_div,x=21,y=4,fg_bg=cpair(colors.lightBlue,colors.gray),height=5,width=1}
TextBox{parent=blr_div,text="H",x=1,y=3,width=1,fg_bg=label}
TextBox{parent=blr_div,text="H",y=3,width=1,fg_bg=label}
TextBox{parent=blr_div,text="W",x=3,y=3,width=1,fg_bg=label}
TextBox{parent=blr_div,text="S",x=19,y=3,width=1,fg_bg=label}
TextBox{parent=blr_div,text="C",x=21,y=3,width=1,fg_bg=label}
@@ -78,7 +78,7 @@ return function (app, u_page, panes, blr_pane, b_id, ps, update)
b_wll.register(ps, "WaterLevelLow", b_wll.update)
b_hr.register(ps, "HeatingRateLow", b_hr.update)
TextBox{parent=blr_div,text="Boil Rate",x=1,y=13,width=12,fg_bg=label}
TextBox{parent=blr_div,text="Boil Rate",y=13,width=12,fg_bg=label}
local boil_r = DataIndicator{parent=blr_div,x=6,y=14,lu_colors=lu_col,label="",unit="mB/t",format="%11.0f",value=0,commas=true,width=16,fg_bg=text_fg}
boil_r.register(ps, "boil_rate", boil_r.update)
@@ -98,35 +98,35 @@ return function (app, u_page, panes, blr_pane, b_id, ps, update)
return function (x) indicator.update(x.amount) end
end
TextBox{parent=blr_ext_div,text="Hot Coolant",x=1,y=3,width=12,fg_bg=label}
TextBox{parent=blr_ext_div,text="Hot Coolant",y=3,width=12,fg_bg=label}
local heated_p = DataIndicator{parent=blr_ext_div,x=14,y=3,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg}
local hcool_amnt = DataIndicator{parent=blr_ext_div,x=1,y=4,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
local hcool_amnt = DataIndicator{parent=blr_ext_div,y=4,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
heated_p.register(ps, "hcool_fill", function (x) heated_p.update(x * 100) end)
hcool_amnt.register(ps, "hcool", update_amount(hcool_amnt))
TextBox{parent=blr_ext_div,text="Water Tank",x=1,y=6,width=9,fg_bg=label}
TextBox{parent=blr_ext_div,text="Water Tank",y=6,width=9,fg_bg=label}
local fuel_p = DataIndicator{parent=blr_ext_div,x=14,y=6,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg}
local fuel_amnt = DataIndicator{parent=blr_ext_div,x=1,y=7,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
local fuel_amnt = DataIndicator{parent=blr_ext_div,y=7,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
fuel_p.register(ps, "water_fill", function (x) fuel_p.update(x * 100) end)
fuel_amnt.register(ps, "water", update_amount(fuel_amnt))
TextBox{parent=blr_ext_div,text="Steam Tank",x=1,y=9,width=10,fg_bg=label}
TextBox{parent=blr_ext_div,text="Steam Tank",y=9,width=10,fg_bg=label}
local steam_p = DataIndicator{parent=blr_ext_div,x=14,y=9,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg}
local steam_amnt = DataIndicator{parent=blr_ext_div,x=1,y=10,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
local steam_amnt = DataIndicator{parent=blr_ext_div,y=10,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
steam_p.register(ps, "steam_fill", function (x) steam_p.update(x * 100) end)
steam_amnt.register(ps, "steam", update_amount(steam_amnt))
TextBox{parent=blr_ext_div,text="Cool Coolant",x=1,y=12,width=12,fg_bg=label}
TextBox{parent=blr_ext_div,text="Cool Coolant",y=12,width=12,fg_bg=label}
local cooled_p = DataIndicator{parent=blr_ext_div,x=14,y=12,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg}
local ccool_amnt = DataIndicator{parent=blr_ext_div,x=1,y=13,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
local ccool_amnt = DataIndicator{parent=blr_ext_div,y=13,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
cooled_p.register(ps, "ccool_fill", function (x) cooled_p.update(x * 100) end)
ccool_amnt.register(ps, "ccool", update_amount(ccool_amnt))
TextBox{parent=blr_ext_div,text="Env. Loss",x=1,y=15,width=9,fg_bg=label}
TextBox{parent=blr_ext_div,text="Env. Loss",y=15,width=9,fg_bg=label}
local env_loss = DataIndicator{parent=blr_ext_div,x=11,y=15,lu_colors=lu_col,label="",unit="",format="%11.8f",value=0,width=11,fg_bg=text_fg}
env_loss.register(ps, "env_loss", env_loss.update)

View File

@@ -5,7 +5,7 @@
local types = require("scada-common.types")
local util = require("scada-common.util")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local style = require("pocket.ui.style")
@@ -38,7 +38,7 @@ local yel_ind_s = style.icon_states.yel_ind_s
---@param u_ps psil
---@param update function
return function (app, u_page, panes, page_div, u_ps, update)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local rct_pane = Div{parent=page_div}
local rct_div = Div{parent=rct_pane,x=2,width=page_div.get_width()-2}
@@ -51,12 +51,12 @@ return function (app, u_page, panes, page_div, u_ps, update)
local status = StateIndicator{parent=rct_div,x=10,y=1,states=style.reactor.states,value=1,min_width=12}
status.register(u_ps, "U_ReactorStateStatus", status.update)
local fuel = VerticalBar{parent=rct_div,x=1,y=4,fg_bg=cpair(colors.lightGray,colors.gray),height=5,width=1}
local fuel = VerticalBar{parent=rct_div,y=4,fg_bg=cpair(colors.lightGray,colors.gray),height=5,width=1}
local ccool = VerticalBar{parent=rct_div,x=3,y=4,fg_bg=cpair(colors.blue,colors.gray),height=5,width=1}
local hcool = VerticalBar{parent=rct_div,x=19,y=4,fg_bg=cpair(colors.white,colors.gray),height=5,width=1}
local waste = VerticalBar{parent=rct_div,x=21,y=4,fg_bg=cpair(colors.brown,colors.gray),height=5,width=1}
TextBox{parent=rct_div,text="F",x=1,y=3,width=1,fg_bg=label}
TextBox{parent=rct_div,text="F",y=3,width=1,fg_bg=label}
TextBox{parent=rct_div,text="C",x=3,y=3,width=1,fg_bg=label}
TextBox{parent=rct_div,text="H",x=19,y=3,width=1,fg_bg=label}
TextBox{parent=rct_div,text="W",x=21,y=3,width=1,fg_bg=label}
@@ -103,9 +103,9 @@ return function (app, u_page, panes, page_div, u_ps, update)
r_wloc.register(u_ps, "WasteLineOcclusion", r_wloc.update)
r_hsrt.register(u_ps, "HighStartupRate", r_hsrt.update)
TextBox{parent=rct_div,text="HR",x=1,y=16,width=4,fg_bg=label}
TextBox{parent=rct_div,text="HR",y=16,width=4,fg_bg=label}
local heating_r = DataIndicator{parent=rct_div,x=6,y=16,lu_colors=lu_col,label="",unit="mB/t",format="%11.0f",value=0,commas=true,width=16,fg_bg=text_fg}
TextBox{parent=rct_div,text="DMG",x=1,y=17,width=4,fg_bg=label}
TextBox{parent=rct_div,text="DMG",y=17,width=4,fg_bg=label}
local damage_p = DataIndicator{parent=rct_div,x=6,y=17,lu_colors=lu_col,label="",unit="%",format="%11.2f",value=0,width=16,fg_bg=text_fg}
heating_r.register(u_ps, "heating_rate", heating_r.update)
@@ -122,36 +122,36 @@ return function (app, u_page, panes, page_div, u_ps, update)
TextBox{parent=rct_ext_div,y=1,text="More Reactor Info",alignment=ALIGN.CENTER}
TextBox{parent=rct_ext_div,text="Fuel Tank",x=1,y=3,width=9,fg_bg=label}
TextBox{parent=rct_ext_div,text="Fuel Tank",y=3,width=9,fg_bg=label}
local fuel_p = DataIndicator{parent=rct_ext_div,x=14,y=3,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg}
local fuel_amnt = DataIndicator{parent=rct_ext_div,x=1,y=4,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
local fuel_amnt = DataIndicator{parent=rct_ext_div,y=4,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
fuel_p.register(u_ps, "fuel_fill", function (x) fuel_p.update(x * 100) end)
fuel_amnt.register(u_ps, "fuel", fuel_amnt.update)
TextBox{parent=rct_ext_div,text="Cool Coolant",x=1,y=6,width=12,fg_bg=label}
TextBox{parent=rct_ext_div,text="Cool Coolant",y=6,width=12,fg_bg=label}
local cooled_p = DataIndicator{parent=rct_ext_div,x=14,y=6,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg}
local ccool_amnt = DataIndicator{parent=rct_ext_div,x=1,y=7,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
local ccool_amnt = DataIndicator{parent=rct_ext_div,y=7,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
cooled_p.register(u_ps, "ccool_fill", function (x) cooled_p.update(x * 100) end)
ccool_amnt.register(u_ps, "ccool_amnt", ccool_amnt.update)
TextBox{parent=rct_ext_div,text="Hot Coolant",x=1,y=9,width=12,fg_bg=label}
TextBox{parent=rct_ext_div,text="Hot Coolant",y=9,width=12,fg_bg=label}
local heated_p = DataIndicator{parent=rct_ext_div,x=14,y=9,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg}
local hcool_amnt = DataIndicator{parent=rct_ext_div,x=1,y=10,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
local hcool_amnt = DataIndicator{parent=rct_ext_div,y=10,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
heated_p.register(u_ps, "hcool_fill", function (x) heated_p.update(x * 100) end)
hcool_amnt.register(u_ps, "hcool_amnt", hcool_amnt.update)
TextBox{parent=rct_ext_div,text="Waste Tank",x=1,y=12,width=10,fg_bg=label}
TextBox{parent=rct_ext_div,text="Waste Tank",y=12,width=10,fg_bg=label}
local waste_p = DataIndicator{parent=rct_ext_div,x=14,y=12,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg}
local waste_amnt = DataIndicator{parent=rct_ext_div,x=1,y=13,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
local waste_amnt = DataIndicator{parent=rct_ext_div,y=13,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
waste_p.register(u_ps, "waste_fill", function (x) waste_p.update(x * 100) end)
waste_amnt.register(u_ps, "waste", waste_amnt.update)
TextBox{parent=rct_ext_div,text="Boil Eff.",x=1,y=15,width=9,fg_bg=label}
TextBox{parent=rct_ext_div,text="Env. Loss",x=1,y=16,width=9,fg_bg=label}
TextBox{parent=rct_ext_div,text="Boil Eff.",y=15,width=9,fg_bg=label}
TextBox{parent=rct_ext_div,text="Env. Loss",y=16,width=9,fg_bg=label}
local boil_eff = DataIndicator{parent=rct_ext_div,x=11,y=15,lu_colors=lu_col,label="",unit="%",format="%9.2f",value=0,width=11,fg_bg=text_fg}
local env_loss = DataIndicator{parent=rct_ext_div,x=11,y=16,lu_colors=lu_col,label="",unit="",format="%11.8f",value=0,width=11,fg_bg=text_fg}

View File

@@ -4,7 +4,7 @@
local util = require("scada-common.util")
local iocontrol = require("pocket.iocontrol")
local ioctl = require("pocket.ioctl")
local style = require("pocket.ui.style")
@@ -41,7 +41,7 @@ local yel_ind_s = style.icon_states.yel_ind_s
---@param ps psil
---@param update function
return function (app, u_page, panes, tbn_pane, u_id, t_id, ps, update)
local db = iocontrol.get_db()
local db = ioctl.get_db()
local tbn_div = Div{parent=tbn_pane,x=2,width=tbn_pane.get_width()-2}
table.insert(panes, tbn_div)
@@ -53,10 +53,10 @@ return function (app, u_page, panes, tbn_pane, u_id, t_id, ps, update)
local status = StateIndicator{parent=tbn_div,x=10,y=1,states=style.turbine.states,value=1,min_width=12}
status.register(ps, "TurbineStateStatus", status.update)
local steam = VerticalBar{parent=tbn_div,x=1,y=4,fg_bg=cpair(colors.white,colors.gray),height=5,width=1}
local steam = VerticalBar{parent=tbn_div,y=4,fg_bg=cpair(colors.white,colors.gray),height=5,width=1}
local ccool = VerticalBar{parent=tbn_div,x=21,y=4,fg_bg=cpair(colors.green,colors.gray),height=5,width=1}
TextBox{parent=tbn_div,text="S",x=1,y=3,width=1,fg_bg=label}
TextBox{parent=tbn_div,text="S",y=3,width=1,fg_bg=label}
TextBox{parent=tbn_div,text="E",x=21,y=3,width=1,fg_bg=label}
steam.register(ps, "steam_fill", steam.update)
@@ -94,22 +94,22 @@ return function (app, u_page, panes, tbn_pane, u_id, t_id, ps, update)
TextBox{parent=tbn_ext_div,y=1,text="More Turbine Info",alignment=ALIGN.CENTER}
TextBox{parent=tbn_ext_div,text="Steam Tank",x=1,y=3,width=10,fg_bg=label}
TextBox{parent=tbn_ext_div,text="Steam Tank",y=3,width=10,fg_bg=label}
local steam_p = DataIndicator{parent=tbn_ext_div,x=14,y=3,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg}
local steam_amnt = DataIndicator{parent=tbn_ext_div,x=1,y=4,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
local steam_amnt = DataIndicator{parent=tbn_ext_div,y=4,lu_colors=lu_col,label="",unit="mB",format="%18.0f",value=0,commas=true,width=21,fg_bg=text_fg}
steam_p.register(ps, "steam_fill", function (x) steam_p.update(x * 100) end)
steam_amnt.register(ps, "steam", function (x) steam_amnt.update(x.amount) end)
TextBox{parent=tbn_ext_div,text="Energy Fill",x=1,y=6,width=12,fg_bg=label}
TextBox{parent=tbn_ext_div,text="Energy Fill",y=6,width=12,fg_bg=label}
local charge_p = DataIndicator{parent=tbn_ext_div,x=14,y=6,lu_colors=lu_col,label="",unit="%",format="%6.2f",value=0,width=8,fg_bg=text_fg}
local charge_amnt = PowerIndicator{parent=tbn_ext_div,x=1,y=7,lu_colors=lu_col,label="",unit=db.energy_label,format="%17.4f",value=0,width=21,fg_bg=text_fg}
local charge_amnt = PowerIndicator{parent=tbn_ext_div,y=7,lu_colors=lu_col,label="",unit=db.energy_label,format="%17.4f",value=0,width=21,fg_bg=text_fg}
charge_p.register(ps, "energy_fill", function (x) charge_p.update(x * 100) end)
charge_amnt.register(ps, "energy", function (val) charge_amnt.update(db.energy_convert(val)) end)
TextBox{parent=tbn_ext_div,text="Rotation Rate",x=1,y=9,width=13,fg_bg=label}
local rotation = DataIndicator{parent=tbn_ext_div,x=1,y=10,lu_colors=lu_col,label="",unit="",format="%21.12f",value=0,width=21,fg_bg=text_fg}
TextBox{parent=tbn_ext_div,text="Rotation Rate",y=9,width=13,fg_bg=label}
local rotation = DataIndicator{parent=tbn_ext_div,y=10,lu_colors=lu_col,label="",unit="",format="%21.12f",value=0,width=21,fg_bg=text_fg}
rotation.register(ps, "steam", function ()
local ok, result = pcall(function () return util.turbine_rotation(db.units[u_id].turbine_data_tbl[t_id]) end)

View File

@@ -196,8 +196,6 @@ function backplane.attach(iface, type, device, print_no_fp)
state.degraded = false
end
_bp.smem.q.mq_rps.push_command(MQ__RPS_CMD.SCRAM)
sys.rps.reconnect_reactor(dev.reactor)
if networked then
sys.plc_comms.reconnect_reactor(dev.reactor)

View File

@@ -209,9 +209,9 @@ function check.create(main_pane, settings_cfg, check_sys, style)
local sc = Div{parent=check_sys,x=2,y=4,width=49}
TextBox{parent=check_sys,x=1,y=2,text=" Reactor PLC Self-Check",fg_bg=bw_fg_bg}
TextBox{parent=check_sys,y=2,text=" Reactor PLC Self-Check",fg_bg=bw_fg_bg}
self.sc_log = ListBox{parent=sc,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
self.sc_log = ListBox{parent=sc,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local last_check = { nil, nil }
@@ -234,7 +234,7 @@ function check.create(main_pane, settings_cfg, check_sys, style)
end
end
PushButton{parent=sc,x=1,y=14,text="\x1b Back",callback=function()exit_self_check(main_pane)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sc,y=14,text="\x1b Back",callback=function()exit_self_check(main_pane)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
self.run_test_btn = PushButton{parent=sc,x=40,y=14,min_width=10,text="Run Test",callback=function()self_check()end,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
end

View File

@@ -90,28 +90,30 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
local plc_c_3 = Div{parent=plc_cfg,x=2,y=4,width=49}
local plc_c_4 = Div{parent=plc_cfg,x=2,y=4,width=49}
local plc_c_5 = Div{parent=plc_cfg,x=2,y=4,width=49}
local plc_c_6 = Div{parent=plc_cfg,x=2,y=4,width=49}
local plc_c_7 = Div{parent=plc_cfg,x=2,y=4,width=49}
local plc_pane = MultiPane{parent=plc_cfg,x=1,y=4,panes={plc_c_1,plc_c_2,plc_c_3,plc_c_4,plc_c_5}}
local plc_pane = MultiPane{parent=plc_cfg,y=4,panes={plc_c_1,plc_c_2,plc_c_3,plc_c_4,plc_c_5,plc_c_6,plc_c_7}}
TextBox{parent=plc_cfg,x=1,y=2,text=" PLC Configuration",fg_bg=cpair(colors.black,colors.orange)}
TextBox{parent=plc_cfg,y=2,text=" PLC Configuration",fg_bg=cpair(colors.black,colors.orange)}
TextBox{parent=plc_c_1,x=1,y=1,text="Would you like to set this PLC as networked?"}
TextBox{parent=plc_c_1,x=1,y=3,height=4,text="If you have a supervisor, select the box. You will later be prompted to select the network configuration. If you instead want to use this as a standalone safety system, don't select the box.",fg_bg=g_lg_fg_bg}
TextBox{parent=plc_c_1,y=1,text="Would you like to set this PLC as networked?"}
TextBox{parent=plc_c_1,y=3,height=4,text="If you have a supervisor, select the box. You will later be prompted to select the network configuration. If you instead want to use this as a standalone safety system, don't select the box.",fg_bg=g_lg_fg_bg}
local networked = Checkbox{parent=plc_c_1,x=1,y=8,label="Networked",default=ini_cfg.Networked,box_fg_bg=cpair(colors.orange,colors.black)}
local networked = Checkbox{parent=plc_c_1,y=8,label="Networked",default=ini_cfg.Networked,box_fg_bg=cpair(colors.orange,colors.black)}
local function submit_networked()
self.set_networked(networked.get_value())
plc_pane.set_value(2)
end
PushButton{parent=plc_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=plc_c_1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=plc_c_1,x=44,y=14,text="Next \x1a",callback=submit_networked,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=plc_c_2,x=1,y=1,text="Please enter the reactor unit ID for this PLC."}
TextBox{parent=plc_c_2,x=1,y=3,height=3,text="If this is a networked PLC, currently only IDs 1 through 4 are acceptable.",fg_bg=g_lg_fg_bg}
TextBox{parent=plc_c_2,y=1,text="Please enter the reactor unit ID for this PLC."}
TextBox{parent=plc_c_2,y=3,height=3,text="If this is a networked PLC, currently only IDs 1 through 4 are acceptable.",fg_bg=g_lg_fg_bg}
TextBox{parent=plc_c_2,x=1,y=6,text="Unit #"}
TextBox{parent=plc_c_2,y=6,text="Unit #"}
local u_id = NumberField{parent=plc_c_2,x=7,y=6,width=5,max_chars=3,default=ini_cfg.UnitID,min=1,fg_bg=bw_fg_bg}
local u_id_err = TextBox{parent=plc_c_2,x=8,y=14,width=35,text="Please set a unit ID.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -130,13 +132,13 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
else u_id_err.show() end
end
PushButton{parent=plc_c_2,x=1,y=14,text="\x1b Back",callback=function()plc_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=plc_c_2,y=14,text="\x1b Back",callback=function()plc_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=plc_c_2,x=44,y=14,text="Next \x1a",callback=submit_id,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=plc_c_3,x=1,y=1,height=4,text="When networked, the supervisor takes care of emergency coolant via RTUs. However, you can configure independent emergency coolant via the PLC."}
TextBox{parent=plc_c_3,x=1,y=6,height=5,text="This independent control can be used with or without a supervisor. To configure, you would next select the interface of the redstone output connected to one or more mekanism pipes.",fg_bg=g_lg_fg_bg}
TextBox{parent=plc_c_3,y=1,height=4,text="When networked, the supervisor takes care of emergency coolant via RTUs. However, you can configure independent emergency coolant via the PLC."}
TextBox{parent=plc_c_3,y=6,height=5,text="This independent control can be used with or without a supervisor. To configure, you would next select the interface of the redstone output connected to one or more mekanism pipes.",fg_bg=g_lg_fg_bg}
local en_em_cool = Checkbox{parent=plc_c_3,x=1,y=11,label="Enable PLC Emergency Coolant Control",default=ini_cfg.EmerCoolEnable,box_fg_bg=cpair(colors.orange,colors.black)}
local en_em_cool = Checkbox{parent=plc_c_3,y=11,label="Enable PLC Emergency Coolant Control",default=ini_cfg.EmerCoolEnable,box_fg_bg=cpair(colors.orange,colors.black)}
local function next_from_plc()
if tmp_cfg.Networked then main_pane.set_value(3) else main_pane.set_value(4) end
@@ -147,34 +149,65 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
if tmp_cfg.EmerCoolEnable then plc_pane.set_value(4) else next_from_plc() end
end
PushButton{parent=plc_c_3,x=1,y=14,text="\x1b Back",callback=function()plc_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=plc_c_3,y=14,text="\x1b Back",callback=function()plc_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=plc_c_3,x=44,y=14,text="Next \x1a",callback=submit_en_emcool,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=plc_c_4,x=1,y=1,text="Emergency Coolant Redstone Output Side"}
local side = Radio2D{parent=plc_c_4,x=1,y=2,rows=2,columns=3,default=side_to_idx(ini_cfg.EmerCoolSide),options=side_options,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.orange}
TextBox{parent=plc_c_4,y=1,text="Emergency Coolant Redstone Output Side"}
local side = Radio2D{parent=plc_c_4,y=2,rows=2,columns=3,default=side_to_idx(ini_cfg.EmerCoolSide),options=side_options,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.orange}
TextBox{parent=plc_c_4,x=1,y=5,text="Bundled Redstone Configuration"}
local bundled = Checkbox{parent=plc_c_4,x=1,y=6,label="Is Bundled?",default=ini_cfg.EmerCoolColor~=nil,box_fg_bg=cpair(colors.orange,colors.black),callback=function(v)self.bundled_emcool(v)end}
local color = Radio2D{parent=plc_c_4,x=1,y=8,rows=4,columns=4,default=color_to_idx(ini_cfg.EmerCoolColor),options=color_options,radio_colors=cpair(colors.lightGray,colors.black),color_map=color_options_map,disable_color=colors.gray,disable_fg_bg=g_lg_fg_bg}
TextBox{parent=plc_c_4,y=5,text="Bundled Redstone Configuration"}
local bundled = Checkbox{parent=plc_c_4,y=6,label="Is Bundled?",default=ini_cfg.EmerCoolColor~=nil,box_fg_bg=cpair(colors.orange,colors.black),callback=function(v)self.bundled_emcool(v)end}
local color = Radio2D{parent=plc_c_4,y=8,rows=4,columns=4,default=color_to_idx(ini_cfg.EmerCoolColor),options=color_options,radio_colors=cpair(colors.lightGray,colors.black),color_map=color_options_map,disable_color=colors.gray,disable_fg_bg=g_lg_fg_bg}
if ini_cfg.EmerCoolColor == nil then color.disable() end
function self.bundled_emcool(en) if en then color.enable() else color.disable() end end
TextBox{parent=plc_c_5,x=1,y=1,height=5,text="Advanced Options"}
local invert = Checkbox{parent=plc_c_5,x=1,y=3,label="Invert",default=ini_cfg.EmerCoolInvert,box_fg_bg=cpair(colors.orange,colors.black)}
TextBox{parent=plc_c_5,y=1,height=5,text="Advanced Options"}
local invert = Checkbox{parent=plc_c_5,y=3,label="Invert",default=ini_cfg.EmerCoolInvert,box_fg_bg=cpair(colors.orange,colors.black)}
TextBox{parent=plc_c_5,x=3,y=4,height=4,text="Digital I/O is already inverted (or not) based on intended use. If you have a non-standard setup, you can use this option to avoid needing a redstone inverter.",fg_bg=cpair(colors.gray,colors.lightGray)}
PushButton{parent=plc_c_5,x=1,y=14,text="\x1b Back",callback=function()plc_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=plc_c_5,y=14,text="\x1b Back",callback=function()plc_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
local function submit_emcool()
tmp_cfg.EmerCoolSide = side_options_map[side.get_value()]
tmp_cfg.EmerCoolColor = tri(bundled.get_value(), color_options_map[color.get_value()], nil)
tmp_cfg.EmerCoolInvert = invert.get_value()
plc_pane.set_value(6)
end
PushButton{parent=plc_c_4,y=14,text="\x1b Back",callback=function()plc_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=plc_c_4,x=33,y=14,min_width=10,text="Advanced",callback=function()plc_pane.set_value(5)end,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
PushButton{parent=plc_c_4,x=44,y=14,text="Next \x1a",callback=submit_emcool,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=plc_c_6,y=1,height=6,text="Slow ramping is always used up to 40 mB/t, which is ~5 mB/t per second. If you enable fast ramping, it will then hold at 40 mB/t until cooled coolant stabilizes (at least 2 seconds) then increase to a faster ramp rate, which is a percentage of the maximum burn rate."}
TextBox{parent=plc_c_6,y=8,height=3,text="When fast ramping is used, if the reactor drops below 80% cooled coolant, it will scale back the ramping proportionally as the coolant level drops.",fg_bg=g_lg_fg_bg}
local fast_ramp = Checkbox{parent=plc_c_6,y=12,label="Enable Fast Ramping",default=ini_cfg.FastRamp,box_fg_bg=cpair(colors.orange,colors.black)}
TextBox{parent=plc_c_6,x=23,y=12,text="new!",fg_bg=cpair(colors.red,colors._INHERIT)} ---@todo remove NEW tag on next revision
local function submit_ramp()
tmp_cfg.FastRamp = fast_ramp.get_value()
if tmp_cfg.FastRampConfirmed or ini_cfg.FastRampConfirmed then
next_from_plc()
else plc_pane.set_value(7) end
end
PushButton{parent=plc_c_6,y=14,text="\x1b Back",callback=function()plc_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=plc_c_6,x=44,y=14,text="Next \x1a",callback=submit_ramp,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=plc_c_7,y=1,text="!! CAUTION !!",fg_bg=cpair(colors.red,colors._INHERIT)}
TextBox{parent=plc_c_7,y=2,height=6,text="Fast ramping has an increased risk of your reactor running low on coolant and overheating. First test this under supervision, as an insufficient cooling setup or lack of auxiliary coolant can cause the reactor to ramp faster than your turbine(s)/boiler(s) can handle."}
TextBox{parent=plc_c_7,y=9,height=4,text="In most cases, the low coolant or high temperature automatic SCRAM should prevent damage to the reactor as long as coolant is not lost from the cooling loop.",fg_bg=g_lg_fg_bg}
local fast_ramp_confirm = Checkbox{parent=plc_c_7,y=14,x=13,label="Don't show this warning again",default=ini_cfg.FastRampConfirmed,box_fg_bg=cpair(colors.orange,colors.black)}
local function submit_ramp_conf()
tmp_cfg.FastRampConfirmed = fast_ramp_confirm.get_value()
next_from_plc()
end
PushButton{parent=plc_c_4,x=1,y=14,text="\x1b Back",callback=function()plc_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=plc_c_4,x=33,y=14,min_width=10,text="Advanced",callback=function()plc_pane.set_value(5)end,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
PushButton{parent=plc_c_4,x=44,y=14,text="Next \x1a",callback=submit_emcool,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=plc_c_7,y=14,text="\x1b Back",callback=function()plc_pane.set_value(6)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=plc_c_7,x=8,y=14,text=" OK ",callback=submit_ramp_conf,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -185,11 +218,11 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
local net_c_3 = Div{parent=net_cfg,x=2,y=4,width=49}
local net_c_4 = Div{parent=net_cfg,x=2,y=4,width=49}
local net_pane = MultiPane{parent=net_cfg,x=1,y=4,panes={net_c_1,net_c_2,net_c_3,net_c_4}}
local net_pane = MultiPane{parent=net_cfg,y=4,panes={net_c_1,net_c_2,net_c_3,net_c_4}}
TextBox{parent=net_cfg,x=1,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)}
TextBox{parent=net_cfg,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)}
TextBox{parent=net_c_1,x=1,y=1,text="Please select the network interface(s)."}
TextBox{parent=net_c_1,y=1,text="Please select the network interface(s)."}
TextBox{parent=net_c_1,x=41,y=1,text="new!",fg_bg=cpair(colors.red,colors._INHERIT)} ---@todo remove NEW tag on next revision
local function en_dis_pref()
@@ -206,12 +239,12 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
tool_ctl.gen_modem_list()
end
self.wireless = Checkbox{parent=net_c_1,x=1,y=3,label="Wireless/Ender Modem",default=ini_cfg.WirelessModem,box_fg_bg=cpair(colors.lightBlue,colors.black),callback=en_dis_pref}
self.wireless = Checkbox{parent=net_c_1,y=3,label="Wireless/Ender Modem",default=ini_cfg.WirelessModem,box_fg_bg=cpair(colors.lightBlue,colors.black),callback=en_dis_pref}
self.wl_pref = Checkbox{parent=net_c_1,x=30,y=3,label="Prefer Wireless",default=ini_cfg.PreferWireless,box_fg_bg=cpair(colors.lightBlue,colors.black),disable_fg_bg=g_lg_fg_bg}
self.wired = Checkbox{parent=net_c_1,x=1,y=5,label="Wired Modem",default=ini_cfg.WiredModem~=false,box_fg_bg=cpair(colors.lightBlue,colors.black),callback=on_wired_change}
self.wired = Checkbox{parent=net_c_1,y=5,label="Wired Modem",default=ini_cfg.WiredModem~=false,box_fg_bg=cpair(colors.lightBlue,colors.black),callback=on_wired_change}
TextBox{parent=net_c_1,x=3,y=6,text="this one MUST ONLY connect to SCADA computers",fg_bg=cpair(colors.red,colors._INHERIT)}
TextBox{parent=net_c_1,x=3,y=7,text="connecting it to peripherals will cause issues",fg_bg=g_lg_fg_bg}
local modem_list = ListBox{parent=net_c_1,x=1,y=8,height=5,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local modem_list = ListBox{parent=net_c_1,y=8,height=5,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local modem_err = TextBox{parent=net_c_1,x=8,y=14,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -251,17 +284,22 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
end
end
PushButton{parent=net_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
local function back_to_plc()
plc_pane.set_value(6)
main_pane.set_value(2)
end
PushButton{parent=net_c_1,y=14,text="\x1b Back",callback=back_to_plc,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_1,x=44,y=14,text="Next \x1a",callback=submit_interfaces,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_2,x=1,y=1,text="Please set the network channels below."}
TextBox{parent=net_c_2,x=1,y=3,height=4,text="Each of the 5 uniquely named channels, including the 2 below, must be the same for each device in this SCADA network. For multiplayer servers, it is recommended to not use the default channels.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_2,y=1,text="Please set the network channels below."}
TextBox{parent=net_c_2,y=3,height=4,text="Each of the 5 uniquely named channels, including the 2 below, must be the same for each device in this SCADA network. For multiplayer servers, it is recommended to not use the default channels.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_2,x=1,y=8,text="Supervisor Channel"}
local svr_chan = NumberField{parent=net_c_2,x=1,y=9,width=7,default=ini_cfg.SVR_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_2,y=8,text="Supervisor Channel"}
local svr_chan = NumberField{parent=net_c_2,y=9,width=7,default=ini_cfg.SVR_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_2,x=9,y=9,height=4,text="[SVR_CHANNEL]",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_2,x=1,y=11,text="PLC Channel"}
local plc_chan = NumberField{parent=net_c_2,x=1,y=12,width=7,default=ini_cfg.PLC_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_2,y=11,text="PLC Channel"}
local plc_chan = NumberField{parent=net_c_2,y=12,width=7,default=ini_cfg.PLC_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_2,x=9,y=12,height=4,text="[PLC_CHANNEL]",fg_bg=g_lg_fg_bg}
local chan_err = TextBox{parent=net_c_2,x=8,y=14,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -283,17 +321,17 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
end
end
PushButton{parent=net_c_2,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_2,y=14,text="\x1b Back",callback=function()net_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_2,x=44,y=14,text="Next \x1a",callback=submit_channels,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_3,x=1,y=1,text="Connection Timeout"}
local timeout = NumberField{parent=net_c_3,x=1,y=2,width=7,default=ini_cfg.ConnTimeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg}
TextBox{parent=net_c_3,y=1,text="Connection Timeout"}
local timeout = NumberField{parent=net_c_3,y=2,width=7,default=ini_cfg.ConnTimeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg}
TextBox{parent=net_c_3,x=9,y=2,height=2,text="seconds (default 5)",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,x=1,y=3,height=4,text="You generally do not want or need to modify this. On slow servers, you can increase this to make the system wait longer before assuming a disconnection.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,y=3,height=4,text="You generally do not want or need to modify this. On slow servers, you can increase this to make the system wait longer before assuming a disconnection.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,x=1,y=8,text="Trusted Range (Wireless Only)"}
self.range = NumberField{parent=net_c_3,x=1,y=9,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg,dis_fg_bg=cpair(colors.lightGray,colors.white)}
TextBox{parent=net_c_3,x=1,y=10,height=4,text="Setting this to a value larger than 0 prevents wireless connections with devices that many meters (blocks) away in any direction.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,y=8,text="Trusted Range (Wireless Only)"}
self.range = NumberField{parent=net_c_3,y=9,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg,dis_fg_bg=cpair(colors.lightGray,colors.white)}
TextBox{parent=net_c_3,y=10,height=4,text="Setting this to a value larger than 0 prevents wireless connections with devices that many meters (blocks) away in any direction.",fg_bg=g_lg_fg_bg}
local n3_err = TextBox{parent=net_c_3,x=8,y=14,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -322,14 +360,14 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
end
end
PushButton{parent=net_c_3,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_3,y=14,text="\x1b Back",callback=function()net_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_3,x=44,y=14,text="Next \x1a",callback=submit_ct_tr,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_4,x=1,y=1,height=2,text="Optionally, set the facility authentication key below. Do NOT use one of your passwords."}
TextBox{parent=net_c_4,x=1,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for wireless security on multiplayer servers. All devices on the same wireless network MUST use the same key if any device has a key. This does result in some extra computation (can slow things down).",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_4,y=1,height=2,text="Optionally, set the facility authentication key below. Do NOT use one of your passwords."}
TextBox{parent=net_c_4,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for wireless security on multiplayer servers. All devices on the same wireless network MUST use the same key if any device has a key. This does result in some extra computation (can slow things down).",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_4,x=1,y=11,text="Auth Key (Wireless Only, Not Used for Wired)"}
local key, _ = TextField{parent=net_c_4,x=1,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg}
TextBox{parent=net_c_4,y=11,text="Auth Key (Wireless Only, Not Used for Wired)"}
local key, _ = TextField{parent=net_c_4,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg}
local function censor_key(enable) key.censor(tri(enable, "*", nil)) end
@@ -349,7 +387,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
else key_err.show() end
end
PushButton{parent=net_c_4,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_4,y=14,text="\x1b Back",callback=function()net_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_4,x=44,y=14,text="Next \x1a",callback=submit_auth,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -358,17 +396,17 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
local log_c_1 = Div{parent=log_cfg,x=2,y=4,width=49}
TextBox{parent=log_cfg,x=1,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)}
TextBox{parent=log_cfg,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)}
TextBox{parent=log_c_1,x=1,y=1,text="Please configure logging below."}
TextBox{parent=log_c_1,y=1,text="Please configure logging below."}
TextBox{parent=log_c_1,x=1,y=3,text="Log File Mode"}
local mode = RadioButton{parent=log_c_1,x=1,y=4,default=ini_cfg.LogMode+1,options={"Append on Startup","Replace on Startup"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.pink}
TextBox{parent=log_c_1,y=3,text="Log File Mode"}
local mode = RadioButton{parent=log_c_1,y=4,default=ini_cfg.LogMode+1,options={"Append on Startup","Replace on Startup"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.pink}
TextBox{parent=log_c_1,x=1,y=7,text="Log File Path"}
local path = TextField{parent=log_c_1,x=1,y=8,width=49,height=1,value=ini_cfg.LogPath,max_len=128,fg_bg=bw_fg_bg}
TextBox{parent=log_c_1,y=7,text="Log File Path"}
local path = TextField{parent=log_c_1,y=8,width=49,height=1,value=ini_cfg.LogPath,max_len=128,fg_bg=bw_fg_bg}
local en_dbg = Checkbox{parent=log_c_1,x=1,y=10,default=ini_cfg.LogDebug,label="Enable Logging Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)}
local en_dbg = Checkbox{parent=log_c_1,y=10,default=ini_cfg.LogDebug,label="Enable Logging Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)}
TextBox{parent=log_c_1,x=3,y=11,height=2,text="This results in much larger log files. It is best to only use this when there is a problem.",fg_bg=g_lg_fg_bg}
local path_err = TextBox{parent=log_c_1,x=8,y=14,width=35,text="Please provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -389,7 +427,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
if tmp_cfg.Networked then main_pane.set_value(3) else main_pane.set_value(2) end
end
PushButton{parent=log_c_1,x=1,y=14,text="\x1b Back",callback=back_from_log,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=log_c_1,y=14,text="\x1b Back",callback=back_from_log,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=log_c_1,x=44,y=14,text="Next \x1a",callback=submit_log,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -401,17 +439,17 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
local clr_c_3 = Div{parent=clr_cfg,x=2,y=4,width=49}
local clr_c_4 = Div{parent=clr_cfg,x=2,y=4,width=49}
local clr_pane = MultiPane{parent=clr_cfg,x=1,y=4,panes={clr_c_1,clr_c_2,clr_c_3,clr_c_4}}
local clr_pane = MultiPane{parent=clr_cfg,y=4,panes={clr_c_1,clr_c_2,clr_c_3,clr_c_4}}
TextBox{parent=clr_cfg,x=1,y=2,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)}
TextBox{parent=clr_cfg,y=2,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)}
TextBox{parent=clr_c_1,x=1,y=1,height=2,text="Here you can select the color theme for the front panel."}
TextBox{parent=clr_c_1,x=1,y=4,height=2,text="Click 'Accessibility' below to access colorblind assistive options.",fg_bg=g_lg_fg_bg}
TextBox{parent=clr_c_1,y=1,height=2,text="Here you can select the color theme for the front panel."}
TextBox{parent=clr_c_1,y=4,height=2,text="Click 'Accessibility' below to access colorblind assistive options.",fg_bg=g_lg_fg_bg}
TextBox{parent=clr_c_1,x=1,y=7,text="Front Panel Theme"}
local fp_theme = RadioButton{parent=clr_c_1,x=1,y=8,default=ini_cfg.FrontPanelTheme,options=themes.FP_THEME_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_1,y=7,text="Front Panel Theme"}
local fp_theme = RadioButton{parent=clr_c_1,y=8,default=ini_cfg.FrontPanelTheme,options=themes.FP_THEME_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_2,x=1,y=1,height=6,text="This system uses color heavily to distinguish ok and not, with some indicators using many colors. By selecting a mode below, indicators will change as shown. For non-standard modes, indicators with more than two colors will be split up."}
TextBox{parent=clr_c_2,y=1,height=6,text="This system uses color heavily to distinguish ok and not, with some indicators using many colors. By selecting a mode below, indicators will change as shown. For non-standard modes, indicators with more than two colors will be split up."}
TextBox{parent=clr_c_2,x=21,y=7,text="Preview"}
local _ = IndLight{parent=clr_c_2,x=21,y=8,label="Good",colors=cpair(colors.black,colors.green)}
@@ -440,8 +478,8 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
end
end
TextBox{parent=clr_c_2,x=1,y=7,width=10,text="Color Mode"}
local c_mode = RadioButton{parent=clr_c_2,x=1,y=8,default=ini_cfg.ColorMode,options=themes.COLOR_MODE_NAMES,callback=recolor,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_2,y=7,width=10,text="Color Mode"}
local c_mode = RadioButton{parent=clr_c_2,y=8,default=ini_cfg.ColorMode,options=themes.COLOR_MODE_NAMES,callback=recolor,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_2,x=21,y=13,height=2,width=18,text="Note: exact color varies by theme.",fg_bg=g_lg_fg_bg}
@@ -482,7 +520,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
end
end
PushButton{parent=clr_c_1,x=1,y=14,text="\x1b Back",callback=back_from_colors,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=clr_c_1,y=14,text="\x1b Back",callback=back_from_colors,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=clr_c_1,x=8,y=14,min_width=15,text="Accessibility",callback=show_access,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
tool_ctl.color_next = PushButton{parent=clr_c_1,x=44,y=14,text="Next \x1a",callback=submit_colors,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
tool_ctl.color_apply = PushButton{parent=clr_c_1,x=43,y=14,min_width=7,text="Apply",callback=submit_colors,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg}
@@ -494,12 +532,12 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
clr_pane.set_value(1)
end
TextBox{parent=clr_c_3,x=1,y=1,text="Settings saved!"}
PushButton{parent=clr_c_3,x=1,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=clr_c_3,y=1,text="Settings saved!"}
PushButton{parent=clr_c_3,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
PushButton{parent=clr_c_3,x=44,y=14,min_width=6,text="Home",callback=c_go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=clr_c_4,x=1,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=clr_c_4,x=1,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=clr_c_4,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=clr_c_4,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
PushButton{parent=clr_c_4,x=44,y=14,min_width=6,text="Home",callback=c_go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -511,11 +549,11 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
local sum_c_3 = Div{parent=summary,x=2,y=4,width=49}
local sum_c_4 = Div{parent=summary,x=2,y=4,width=49}
local sum_pane = MultiPane{parent=summary,x=1,y=4,panes={sum_c_1,sum_c_2,sum_c_3,sum_c_4}}
local sum_pane = MultiPane{parent=summary,y=4,panes={sum_c_1,sum_c_2,sum_c_3,sum_c_4}}
TextBox{parent=summary,x=1,y=2,text=" Summary",fg_bg=cpair(colors.black,colors.green)}
TextBox{parent=summary,y=2,text=" Summary",fg_bg=cpair(colors.black,colors.green)}
local setting_list = ListBox{parent=sum_c_1,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local setting_list = ListBox{parent=sum_c_1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local function back_from_settings()
if tool_ctl.viewing_config or self.importing_legacy then
@@ -551,6 +589,8 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
try_set(bundled, ini_cfg.EmerCoolColor ~= nil)
if ini_cfg.EmerCoolColor ~= nil then try_set(color, color_to_idx(ini_cfg.EmerCoolColor)) end
try_set(invert, ini_cfg.EmerCoolInvert)
try_set(fast_ramp, ini_cfg.FastRamp)
try_set(fast_ramp_confirm, ini_cfg.FastRampConfirmed)
try_set(self.wireless, ini_cfg.WirelessModem)
try_set(self.wired, ini_cfg.WiredModem ~= false)
try_set(self.wl_pref, ini_cfg.PreferWireless)
@@ -579,12 +619,12 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
end
end
PushButton{parent=sum_c_1,x=1,y=14,text="\x1b Back",callback=back_from_settings,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_1,y=14,text="\x1b Back",callback=back_from_settings,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
self.show_key_btn = PushButton{parent=sum_c_1,x=8,y=14,min_width=17,text="Unhide Auth Key",callback=function()self.show_auth_key()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
tool_ctl.settings_apply = PushButton{parent=sum_c_1,x=43,y=14,min_width=7,text="Apply",callback=save_and_continue,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg}
TextBox{parent=sum_c_2,x=1,y=1,text="Settings saved!"}
TextBox{parent=sum_c_2,x=1,y=3,text="Tip: you can run a Self-Check from the configurator home screen to make sure everything is going to work right!"}
TextBox{parent=sum_c_2,y=1,text="Settings saved!"}
TextBox{parent=sum_c_2,y=3,text="Tip: you can run a Self-Check from the configurator home screen to make sure everything is going to work right!"}
local function go_home()
main_pane.set_value(1)
@@ -594,21 +634,21 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
sum_pane.set_value(1)
end
PushButton{parent=sum_c_2,x=1,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_2,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_2,x=44,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=sum_c_3,x=1,y=1,height=2,text="The old config.lua file will now be deleted, then the configurator will exit."}
TextBox{parent=sum_c_3,y=1,height=2,text="The old config.lua file will now be deleted, then the configurator will exit."}
local function delete_legacy()
fs.delete("/reactor-plc/config.lua")
exit()
end
PushButton{parent=sum_c_3,x=1,y=14,min_width=8,text="Cancel",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_3,y=14,min_width=8,text="Cancel",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_3,x=44,y=14,min_width=6,text="OK",callback=delete_legacy,fg_bg=cpair(colors.black,colors.green),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=sum_c_4,x=1,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=sum_c_4,x=1,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=sum_c_4,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=sum_c_4,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_4,x=44,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
--#endregion
@@ -621,6 +661,8 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
tmp_cfg.Networked = config.NETWORKED
tmp_cfg.UnitID = config.REACTOR_ID
tmp_cfg.FastRamp = false
tmp_cfg.FastRampConfirmed = false
tmp_cfg.EmerCoolEnable = type(config.EMERGENCY_COOL) == "table"
if tmp_cfg.EmerCoolEnable then
@@ -685,21 +727,25 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
if val == "nil" then val = "<not set>" end
local c = tri(alternate, g_lg_fg_bg, cpair(colors.gray,colors.white))
alternate = not alternate
if (string.len(val) > val_max_w) or string.find(val, "\n") then
local lines = util.strwrap(val, inner_width)
height = #lines + 1
end
local line = Div{parent=setting_list,height=height,fg_bg=c}
TextBox{parent=line,text=f[2],width=string.len(f[2]),fg_bg=cpair(colors.black,line.get_fg_bg().bkg)}
local textbox
if height > 1 then
textbox = TextBox{parent=line,x=1,y=2,text=val,height=height-1}
else
textbox = TextBox{parent=line,x=label_w+1,y=1,text=val,alignment=RIGHT}
if f[1] ~= "FastRampConfirmed" then
alternate = not alternate
local line = Div{parent=setting_list,height=height,fg_bg=c}
TextBox{parent=line,text=f[2],width=string.len(f[2]),fg_bg=cpair(colors.black,line.get_fg_bg().bkg)}
if height > 1 then
textbox = TextBox{parent=line,y=2,text=val,height=height-1}
else
textbox = TextBox{parent=line,x=label_w+1,y=1,text=val,alignment=RIGHT}
end
end
if f[1] == "AuthKey" then self.auth_key_textbox = textbox end
@@ -726,19 +772,19 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
end
if missing.tmp and tmp_cfg.WiredModem then
local line = Div{parent=modem_list,x=1,y=1,height=1}
local line = Div{parent=modem_list,y=1,height=1}
TextBox{parent=line,x=1,y=1,width=4,text="Used",fg_bg=cpair(tri(enable,colors.blue,colors.gray),colors.white)}
TextBox{parent=line,y=1,width=4,text="Used",fg_bg=cpair(tri(enable,colors.blue,colors.gray),colors.white)}
PushButton{parent=line,x=6,y=1,min_width=8,height=1,text="SELECT",callback=function()end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=g_lg_fg_bg}.disable()
TextBox{parent=line,x=15,y=1,text="[missing]",fg_bg=cpair(colors.red,colors.white)}
TextBox{parent=line,x=25,y=1,text=tmp_cfg.WiredModem}
end
if missing.ini and ini_cfg.WiredModem and (tmp_cfg.WiredModem ~= ini_cfg.WiredModem) then
local line = Div{parent=modem_list,x=1,y=1,height=1}
local line = Div{parent=modem_list,y=1,height=1}
local used = tmp_cfg.WiredModem == ini_cfg.WiredModem
TextBox{parent=line,x=1,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
TextBox{parent=line,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
local select_btn = PushButton{parent=line,x=6,y=1,min_width=8,height=1,text="SELECT",callback=function()select(ini_cfg.WiredModem)end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=g_lg_fg_bg}
TextBox{parent=line,x=15,y=1,text="[missing]",fg_bg=cpair(colors.red,colors.white)}
TextBox{parent=line,x=25,y=1,text=ini_cfg.WiredModem}
@@ -748,10 +794,10 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit)
-- list wired modems
for iface, _ in pairs(modems) do
local line = Div{parent=modem_list,x=1,y=1,height=1}
local line = Div{parent=modem_list,y=1,height=1}
local used = tmp_cfg.WiredModem == iface
TextBox{parent=line,x=1,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
TextBox{parent=line,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
local select_btn = PushButton{parent=line,x=6,y=1,min_width=8,height=1,text="SELECT",callback=function()select(iface)end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=g_lg_fg_bg}
TextBox{parent=line,x=15,y=1,text=iface}

View File

@@ -78,6 +78,8 @@ local tool_ctl = {
local tmp_cfg = {
Networked = false,
UnitID = 0,
FastRamp = true,
FastRampConfirmed = false,
EmerCoolEnable = false,
EmerCoolSide = nil, ---@type string|nil
EmerCoolColor = nil, ---@type color|nil
@@ -106,6 +108,8 @@ local settings_cfg = {}
local fields = {
{ "Networked", "Networked", false },
{ "UnitID", "Unit ID", 1 },
{ "FastRamp", "Fast Ramp", true },
{ "FastRampConfirmed", "Fast Ramp Confirmed", false },
{ "EmerCoolEnable", "Emergency Coolant", false },
{ "EmerCoolSide", "Emergency Coolant Side", nil },
{ "EmerCoolColor", "Emergency Coolant Color", nil },
@@ -152,18 +156,18 @@ local function config_view(display)
TextBox{parent=display,y=1,text="Reactor PLC Configurator",alignment=CENTER,fg_bg=style.header}
local root_pane_div = Div{parent=display,x=1,y=2}
local root_pane_div = Div{parent=display,y=2}
local main_page = Div{parent=root_pane_div,x=1,y=1}
local plc_cfg = Div{parent=root_pane_div,x=1,y=1}
local net_cfg = Div{parent=root_pane_div,x=1,y=1}
local log_cfg = Div{parent=root_pane_div,x=1,y=1}
local clr_cfg = Div{parent=root_pane_div,x=1,y=1}
local summary = Div{parent=root_pane_div,x=1,y=1}
local changelog = Div{parent=root_pane_div,x=1,y=1}
local check_sys = Div{parent=root_pane_div,x=1,y=1}
local main_page = Div{parent=root_pane_div,y=1}
local plc_cfg = Div{parent=root_pane_div,y=1}
local net_cfg = Div{parent=root_pane_div,y=1}
local log_cfg = Div{parent=root_pane_div,y=1}
local clr_cfg = Div{parent=root_pane_div,y=1}
local summary = Div{parent=root_pane_div,y=1}
local changelog = Div{parent=root_pane_div,y=1}
local check_sys = Div{parent=root_pane_div,y=1}
local main_pane = MultiPane{parent=root_pane_div,x=1,y=1,panes={main_page,plc_cfg,net_cfg,log_cfg,clr_cfg,summary,changelog,check_sys}}
local main_pane = MultiPane{parent=root_pane_div,y=1,panes={main_page,plc_cfg,net_cfg,log_cfg,clr_cfg,summary,changelog,check_sys}}
--#region Main Page
@@ -231,20 +235,20 @@ local function config_view(display)
local cl = Div{parent=changelog,x=2,y=4,width=49}
TextBox{parent=changelog,x=1,y=2,text=" Config Change Log",fg_bg=bw_fg_bg}
TextBox{parent=changelog,y=2,text=" Config Change Log",fg_bg=bw_fg_bg}
local c_log = ListBox{parent=cl,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local c_log = ListBox{parent=cl,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
for _, change in ipairs(changes) do
TextBox{parent=c_log,text=change[1],fg_bg=bw_fg_bg}
for _, v in ipairs(change[2]) do
local e = Div{parent=c_log,height=#util.strwrap(v,46)}
TextBox{parent=e,y=1,x=1,text="- ",fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=e,y=1,text="- ",fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=e,y=1,x=3,text=v,height=e.get_height(),fg_bg=cpair(colors.gray,colors.white)}
end
end
PushButton{parent=cl,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=cl,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion

View File

@@ -171,11 +171,11 @@ local function init(panel, config)
emer_cool.register(databus.ps, "emer_cool", emer_cool.update)
end
local status_trip_rct = Rectangle{parent=status,height=3,x=1,border=border(1,s_hi_box.bkg,true),even_inner=true}
local status_trip_rct = Rectangle{parent=status,height=3,border=border(1,s_hi_box.bkg,true),even_inner=true}
local status_trip = Div{parent=status_trip_rct,height=1,fg_bg=s_hi_box}
local scram = LED{parent=status_trip,width=10,label="RPS TRIP",colors=ind_red,flash=true,period=flasher.PERIOD.BLINK_250_MS}
local controls_rct = Rectangle{parent=status,width=status.get_width()-2,height=3,x=1,border=border(1,s_hi_box.bkg,true),even_inner=true}
local controls_rct = Rectangle{parent=status,width=status.get_width()-2,height=3,border=border(1,s_hi_box.bkg,true),even_inner=true}
local controls = Div{parent=controls_rct,width=controls_rct.get_width()-2,height=1,fg_bg=s_hi_box}
local button_padding = math.floor((controls.get_width() - 14) / 3)
PushButton{parent=controls,x=button_padding+1,y=1,min_width=7,text="SCRAM",callback=databus.rps_scram,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.black,colors.red_off)}
@@ -184,7 +184,7 @@ local function init(panel, config)
active.register(databus.ps, "reactor_active", active.update)
scram.register(databus.ps, "rps_scram", scram.update)
local hw_labels = Rectangle{parent=status,width=status.get_width()-2,height=5,x=1,border=border(1,s_hi_box.bkg,true),even_inner=true}
local hw_labels = Rectangle{parent=status,width=status.get_width()-2,height=5,border=border(1,s_hi_box.bkg,true),even_inner=true}
---@diagnostic disable-next-line: undefined-field
local comp_id = util.sprintf("%03d", os.getComputerID())

View File

@@ -44,6 +44,7 @@ function plc.load_config()
config.Networked = settings.get("Networked")
config.UnitID = settings.get("UnitID")
config.FastRamp = settings.get("FastRamp")
config.EmerCoolEnable = settings.get("EmerCoolEnable")
config.EmerCoolSide = settings.get("EmerCoolSide")
@@ -76,6 +77,7 @@ function plc.validate_config(cfg)
cfv.assert_type_bool(cfg.Networked)
cfv.assert_type_int(cfg.UnitID)
cfv.assert_type_bool(cfg.FastRamp)
cfv.assert_type_bool(cfg.EmerCoolEnable)
if cfg.Networked then
@@ -127,8 +129,7 @@ function plc.rps_init(reactor, is_formed)
local self = {
---@type boolean[] check states
state = { false, false, false, false, false, false, false, false, false, false, false, false },
reactor_enabled = false,
enabled_at = 0,
reactor_active = false,
emer_cool_active = nil, ---@type boolean
formed = is_formed, ---@type boolean|nil
force_disabled = false,
@@ -296,6 +297,14 @@ function plc.rps_init(reactor, is_formed)
reactor = new_reactor
end
-- check the reactor enable state and update the internal tracking flag
---@return boolean active
--- EVENT_CONSUMER: this function consumes events
function public.check_active()
self.reactor_active = reactor.getStatus() == true
return self.reactor_active
end
-- trip for lost peripheral
function public.trip_fault()
_set_fault()
@@ -332,11 +341,7 @@ function plc.rps_init(reactor, is_formed)
if reactor.__p_is_faulted() and not string.find(reactor.__p_last_fault(), PCALL_SCRAM_MSG) then
log.error("RPS: failed reactor SCRAM")
return false
else
self.reactor_enabled = false
self.last_runtime = util.time_ms() - self.enabled_at
return true
end
else return true end
end
-- start the reactor now<br>
@@ -349,11 +354,7 @@ function plc.rps_init(reactor, is_formed)
reactor.activate()
if reactor.__p_is_faulted() and not string.find(reactor.__p_last_fault(), PCALL_START_MSG) then
log.error("RPS: failed reactor start")
else
self.reactor_enabled = true
self.enabled_at = util.time_ms()
return true
end
else return true end
else
log.debug(util.c("RPS: failed start, RPS tripped: ", self.trip_cause))
end
@@ -363,6 +364,7 @@ function plc.rps_init(reactor, is_formed)
-- automatic control activate/re-activate
---@return boolean success
--- EVENT_CONSUMER: this function consumes events
function public.auto_activate()
-- clear automatic SCRAM if it was the cause
if self.tripped and self.trip_cause == "automatic" then
@@ -380,6 +382,7 @@ function plc.rps_init(reactor, is_formed)
---@nodiscard
---@param has_reactor boolean if the PLC state indicates we have a reactor
---@return boolean tripped, rps_trip_cause trip_status, boolean first_trip
--- EVENT_CONSUMER: this function consumes events
function public.check(has_reactor)
local status = RPS_TRIP_CAUSE.OK
local was_tripped = self.tripped
@@ -451,20 +454,16 @@ function plc.rps_init(reactor, is_formed)
self.trip_cause = RPS_TRIP_CAUSE.OK
end
-- if a new trip occured...
-- SCRAM on a new trip, RPS thread handles reactor becoming active while already tripped
if (not was_tripped) and (status ~= RPS_TRIP_CAUSE.OK) then
first_trip = true
self.tripped = true
self.trip_cause = status
-- in the case that the reactor is detected to be active,
-- it will be scrammed shortly after this in the main RPS loop if we don't here
if self.formed then
if not self.force_disabled then
public.scram()
else
if self.force_disabled then
log.warning("RPS: skipping SCRAM due to reactor being force disabled")
end
else public.scram() end
else
log.warning("RPS: skipping SCRAM due to not being formed")
end
@@ -490,18 +489,13 @@ function plc.rps_init(reactor, is_formed)
function public.is_low_coolant() return self.states[CHK.LOW_COOLANT] end
---@nodiscard
function public.is_active() return self.reactor_enabled end
function public.is_active() return self.reactor_active end
---@nodiscard
---@return boolean|nil formed true if formed, false if not, nil if unknown
function public.is_formed() return self.formed end
---@nodiscard
function public.is_force_disabled() return self.force_disabled end
-- get the runtime of the reactor if active, or the last runtime if disabled
---@nodiscard
---@return integer runtime time since last enable
function public.get_runtime() return util.trinary(self.reactor_enabled, util.time_ms() - self.enabled_at, self.last_runtime) end
-- reset the RPS
---@param quiet? boolean true to suppress the info log message
function public.reset(quiet)
@@ -885,8 +879,8 @@ function plc.comms(version, tx_nic, reactor, rps, conn_watchdog)
-- close the connection to the server
function public.close()
conn_watchdog.cancel()
public.unlink()
_send_mgmt(MGMT_TYPE.CLOSE, {})
public.unlink()
end
-- attempt to establish link with supervisor

246
reactor-plc/spctl.lua Normal file
View File

@@ -0,0 +1,246 @@
local log = require("scada-common.log")
local util = require("scada-common.util")
local plc = require("reactor-plc.plc")
local SLOW_RAMP_mB_s = 5.0
local FAST_SWITCH_mB_s = 40.0
local FAST_MAX_PERCENT_s = 0.04
local spctl = {}
---@enum RAMP_STATES
local STATES = {
STOPPED = 1,
INIT = 2,
SLOW_RAMP_UP = 3,
SLOW_RAMP_DOWN = 4,
STABLE_WAIT = 5,
CCOOL_MON = 6,
FAST_RAMP_UP = 7,
FAST_RAMP_DOWN = 8
}
local STATE_NAMES = {
"STOPPED",
"INIT",
"SLOW_RAMP_UP",
"SLOW_RAMP_DOWN",
"STABLE_WAIT",
"CCOOL_MON",
"FAST_RAMP_UP",
"FAST_RAMP_DOWN"
}
local _spctl = {
fast_ramp_en = plc.config.FastRamp,
max_br = 0.0,
last_sp = 0.0,
last_ccool = 0.0,
last_change = 0,
next_state = STATES.STOPPED, ---@type RAMP_STATES
last_state = STATES.STOPPED ---@type RAMP_STATES
}
local rps = nil ---@type rps
local setpoints = nil ---@type plc_setpoints
-- initialize with shared memory data
---@param smem plc_shared_memory
function spctl.init(smem)
rps = smem.plc_sys.rps
setpoints = smem.setpoints
end
-- initialize ramping, or set right away if acceptable
---@param reactor table
---@param cur_br number
local function ramp_init(reactor, cur_br)
_spctl.last_sp = setpoints.burn_rate
-- update without ramp if <= 2.5 mB/t increase
-- no need to ramp down, as the ramp up poses the safety risks
if (setpoints.burn_rate - cur_br) > 2.5 then
log.debug(util.c("SPCTL: starting burn rate ramp from ", cur_br, " mB/t to ", setpoints.burn_rate, " mB/t"))
_spctl.last_change = os.clock()
_spctl.next_state = STATES.INIT
else
log.debug(util.c("SPCTL: setting burn rate directly to ", setpoints.burn_rate, " mB/t"))
reactor.setBurnRate(setpoints.burn_rate)
end
end
-- reset states and last value tracking
local function ramp_reset()
_spctl.last_sp = 0
_spctl.last_ccool = 0
_spctl.next_state = STATES.STOPPED
_spctl.last_state = STATES.STOPPED
end
-- run the setpoint ramp controller loop
---@param reactor table reactor
---@param cur_br number current burn rate
---@param cur_ccool number coolant filled percentage (0 to 1)
---@param elapsed_s number seconds elapsed in the ramp
local function ramp_run(reactor, cur_br, cur_ccool, elapsed_s)
local now = os.clock()
local state_time = now - _spctl.last_change
local state = _spctl.next_state
local new_state = _spctl.next_state
local new_br = cur_br
if state == STATES.INIT then
-- transition to the appropriate direction and phase
if setpoints.burn_rate > cur_br then
-- need to ramp up
if _spctl.fast_ramp_en and (cur_br >= FAST_SWITCH_mB_s) then
new_state = STATES.STABLE_WAIT
else
new_state = STATES.SLOW_RAMP_UP
end
else
-- need to ramp down
if _spctl.fast_ramp_en and (cur_br >= FAST_SWITCH_mB_s) then
new_state = STATES.FAST_RAMP_DOWN
else
new_state = STATES.SLOW_RAMP_DOWN
end
end
elseif state == STATES.SLOW_RAMP_UP then
-- slowly ramp up
new_br = cur_br + (SLOW_RAMP_mB_s * elapsed_s)
if new_br > setpoints.burn_rate then new_br = setpoints.burn_rate end
-- transition out of slow ramp after hitting the limit
if _spctl.fast_ramp_en and (new_br >= FAST_SWITCH_mB_s) then
new_br = FAST_SWITCH_mB_s
new_state = STATES.STABLE_WAIT
end
elseif state == STATES.SLOW_RAMP_DOWN then
-- slowly ramp down
new_br = cur_br - (SLOW_RAMP_mB_s * elapsed_s)
if new_br < setpoints.burn_rate then new_br = setpoints.burn_rate end
elseif state == STATES.STABLE_WAIT then
-- wait a minimum of 2 seconds to help with flow stability
-- this helps detect broken things before getting too high
if state_time >= 2 then
new_state = STATES.CCOOL_MON
end
elseif state == STATES.CCOOL_MON then
-- don't move on until coolant is not decreasing
if cur_ccool >= _spctl.last_ccool then
new_state = STATES.FAST_RAMP_UP
end
elseif state == STATES.FAST_RAMP_UP then
-- step by a percent of the max burn rate
local scaler = math.min(FAST_MAX_PERCENT_s, FAST_MAX_PERCENT_s * (state_time / 5.0)) * elapsed_s
local step = scaler * _spctl.max_br
-- slow the step if we are losing coolant
if cur_ccool < 0.8 then
-- map 0.4-0.8 to 0-1
local a = (cur_ccool - 0.4) * 2.5
-- slow as we approach low coolant condition
step = step * a
end
-- minimum is the slow rate, maintain old behavior
-- if we overheat, it will be gentle and recoverable, then the user can solve the coolant issue rather than see the reactor not ramping
step = math.max((SLOW_RAMP_mB_s * elapsed_s), step)
-- don't exceed the setpoint
new_br = math.min(cur_br + step, setpoints.burn_rate)
log.debug(util.sprintf("SPCTL: scaler[%f] cur_ccool[%f] step[%f] new_br[%f]", scaler, cur_ccool, step, new_br))
elseif state == STATES.FAST_RAMP_DOWN then
-- step by a percent of the max burn rate
local scaler = math.min(FAST_MAX_PERCENT_s, FAST_MAX_PERCENT_s * (state_time / 5.0)) * elapsed_s
local step = scaler * _spctl.max_br
-- minimum is the slow rate, maintain old behavior
-- if we overheat, it will be gentle and recoverable, then the user can solve the coolant issue rather than see the reactor not ramping
step = math.max((SLOW_RAMP_mB_s * elapsed_s), step)
-- don't fall below the setpoint
new_br = math.max(cur_br - step, setpoints.burn_rate)
log.debug(util.sprintf("SPCTL: scaler[%f] cur_ccool[%f] step[%f] new_br[%f]", scaler, cur_ccool, step, new_br))
end
-- set the burn rate
reactor.setBurnRate(new_br)
if new_br ~= setpoints.burn_rate then
-- update tracked values and continue
_spctl.last_ccool = cur_ccool
else
new_state = STATES.STOPPED
end
-- state change management
if new_state ~= state then
log.debug("SPCTL: state changed to " .. (STATE_NAMES[new_state] or "UNKNOWN"))
_spctl.next_state = new_state
_spctl.last_change = now
end
end
-- update setpoint controller
---@param reactor table
---@param elapsed_s integer iteration elapsed time reference
function spctl.update(reactor, elapsed_s)
-- check if we should start ramping
if setpoints.burn_rate_en and (setpoints.burn_rate ~= _spctl.last_sp) and rps.is_active() then
local cur_br = reactor.getBurnRate()
_spctl.max_br = reactor.getMaxBurnRate()
if (type(cur_br) == "number") and (type(_spctl.max_br) == "number") and (setpoints.burn_rate ~= cur_br) then
ramp_init(reactor, cur_br)
end
end
-- minimize operations when not running
if _spctl.next_state ~= STATES.STOPPED then
-- adjust burn rate (setpoints.burn_rate)
if setpoints.burn_rate_en then
local cur_br, cur_ccool = 0, 0
parallel.waitForAll(
function () cur_br = reactor.getBurnRate() end,
function () cur_ccool = reactor.getCoolantFilledPercentage() end
)
if not rps.is_active() then
log.info("SPCTL: ramping aborted (reactor inactive)")
setpoints.burn_rate_en = false
ramp_reset()
-- we yielded, check enable again
elseif setpoints.burn_rate_en then
if (type(cur_br) == "number") and (type(cur_ccool) == "number") then
ramp_run(reactor, cur_br, cur_ccool, elapsed_s)
else
log.error(util.c("SPCTL: skipped running loop due to bad data (cur_br=", cur_br, ",cur_ccool=", cur_ccool, ")"))
end
else
log.info("SPCTL: ramping cancelled")
ramp_reset()
end
else
log.info("SPCTL: ramping cancelled")
ramp_reset()
end
elseif setpoints.burn_rate_en then
log.info(util.c("SPCTL: ramping completed (setpoint of ", setpoints.burn_rate, " mB/t)"))
setpoints.burn_rate_en = false
ramp_reset()
end
end
return spctl

View File

@@ -19,7 +19,7 @@ local plc = require("reactor-plc.plc")
local renderer = require("reactor-plc.renderer")
local threads = require("reactor-plc.threads")
local R_PLC_VERSION = "v1.10.10"
local R_PLC_VERSION = "v1.11.5"
local println = util.println
local println_ts = util.println_ts

View File

@@ -7,6 +7,7 @@ local util = require("scada-common.util")
local backplane = require("reactor-plc.backplane")
local databus = require("reactor-plc.databus")
local renderer = require("reactor-plc.renderer")
local spctl = require("reactor-plc.spctl")
local core = require("graphics.core")
@@ -17,8 +18,6 @@ local RPS_SLEEP = 250 -- 250ms, 5 ticks
local COMMS_SLEEP = 150 -- 150ms, 3 ticks
local SP_CTRL_SLEEP = 250 -- 250ms, 5 ticks
local BURN_RATE_RAMP_mB_s = 5.0
-- main thread
---@nodiscard
---@param smem plc_shared_memory
@@ -50,6 +49,67 @@ function threads.thread__main(smem)
local MQ__RPS_CMD = smem.q_types.MQ__RPS_CMD
local MQ__COMM_CMD = smem.q_types.MQ__COMM_CMD
-- main loop periodic tasks
local function loop_tick()
-- blink heartbeat indicator
databus.heartbeat()
-- start next clock timer
loop_clock.start()
-- periodic hardware tasks
backplane.periodic()
-- send updated data or try to link
if networked then
if plc_comms.is_linked() then
smem.q.mq_comms_tx.push_command(MQ__COMM_CMD.SEND_STATUS)
plc_comms.manage_failover(backplane.active_nic())
elseif ticks_to_update == 0 then
local a_nic, s_nic = backplane.active_nic(), backplane.standby_nic()
if a_nic.is_network_up() then
plc_comms.send_link_req(a_nic)
elseif s_nic and s_nic.is_network_up() then
plc_comms.send_link_req(s_nic)
end
ticks_to_update = LINK_TICKS
else
ticks_to_update = ticks_to_update - 1
end
end
-- check for formed state change
if (not plc_state.reactor_formed) and rps.is_formed() then
-- reactor now formed
plc_state.reactor_formed = true
println_ts("reactor is now formed")
log.info("reactor is now formed")
-- determine if we are still in a degraded state
if (not networked) or backplane.active_nic().is_connected() then
plc_state.degraded = false
end
-- partial reset of RPS, specific to becoming formed
-- without this, auto control can't resume on chunk load
smem.q.mq_rps.push_command(MQ__RPS_CMD.RESET_REATTACH)
elseif plc_state.reactor_formed and (rps.is_formed() == false) then
-- reactor no longer formed
println_ts("reactor is no longer formed")
log.info("reactor is no longer formed")
plc_state.reactor_formed = false
plc_state.degraded = true
end
-- update indicators
databus.tx_hw_status(plc_state)
end
-- start clock
loop_clock.start()
@@ -58,90 +118,30 @@ function threads.thread__main(smem)
local event, param1, param2, param3, param4, param5 = util.pull_event()
-- handle event
if event == "timer" and loop_clock.is_clock(param1) then
-- blink heartbeat indicator
databus.heartbeat()
-- start next clock timer
loop_clock.start()
-- periodic hardware tasks
backplane.periodic()
-- send updated data or try to link
if networked then
if plc_comms.is_linked() then
smem.q.mq_comms_tx.push_command(MQ__COMM_CMD.SEND_STATUS)
plc_comms.manage_failover(backplane.active_nic())
elseif ticks_to_update == 0 then
local a_nic, s_nic = backplane.active_nic(), backplane.standby_nic()
if a_nic.is_network_up() then
plc_comms.send_link_req(a_nic)
elseif s_nic and s_nic.is_network_up() then
plc_comms.send_link_req(s_nic)
end
ticks_to_update = LINK_TICKS
else
ticks_to_update = ticks_to_update - 1
end
end
-- check for formed state change
if (not plc_state.reactor_formed) and rps.is_formed() then
-- reactor now formed
plc_state.reactor_formed = true
println_ts("reactor is now formed")
log.info("reactor is now formed")
-- SCRAM newly formed reactor
smem.q.mq_rps.push_command(MQ__RPS_CMD.SCRAM)
-- determine if we are still in a degraded state
if (not networked) or backplane.active_nic().is_connected() then
plc_state.degraded = false
end
-- partial reset of RPS, specific to becoming formed
-- without this, auto control can't resume on chunk load
smem.q.mq_rps.push_command(MQ__RPS_CMD.RESET_REATTACH)
elseif plc_state.reactor_formed and (rps.is_formed() == false) then
-- reactor no longer formed
println_ts("reactor is no longer formed")
log.info("reactor is no longer formed")
plc_state.reactor_formed = false
plc_state.degraded = true
end
-- update indicators
databus.tx_hw_status(plc_state)
elseif event == "modem_message" and networked then
if event == "modem_message" and networked then
-- got a packet
local packet = plc_comms.parse_packet(param1, param2, param3, param4, param5)
if packet ~= nil then
-- pass the packet onto the comms message queue
smem.q.mq_comms_rx.push_network(packet)
end
elseif event == "timer" and networked and conn_watchdog.is_timer(param1) then
-- haven't heard from server recently? close connection and shutdown reactor
plc_comms.close()
smem.q.mq_rps.push_command(MQ__RPS_CMD.TRIP_TIMEOUT)
elseif event == "timer" then
-- notify timer callback dispatcher if no other timer case claimed this event
tcd.handle(param1)
elseif event == "peripheral_detach" then
-- peripheral disconnect
local type, device = ppm.handle_unmount(param1)
if type ~= nil and device ~= nil then
backplane.detach(param1, type, device, println_ts)
-- pass this timer event onto the right handler
if loop_clock.is_clock(param1) then
-- main loop tick
loop_tick()
elseif networked and conn_watchdog.is_timer(param1) then
-- supervisor connection timed out
plc_comms.close()
smem.q.mq_rps.push_command(MQ__RPS_CMD.TRIP_TIMEOUT)
else
-- notify timer callback dispatcher, no other handler claimed this event
tcd.handle(param1)
end
-- update indicators
databus.tx_hw_status(plc_state)
elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" or
event == "double_click" then
-- handle a mouse event
renderer.handle_mouse(core.events.new_mouse_event(event, param1, param2, param3))
elseif event == "peripheral" then
-- peripheral connect
local type, device = ppm.mount(param1)
@@ -151,10 +151,15 @@ function threads.thread__main(smem)
-- update indicators
databus.tx_hw_status(plc_state)
elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" or
event == "double_click" then
-- handle a mouse event
renderer.handle_mouse(core.events.new_mouse_event(event, param1, param2, param3))
elseif event == "peripheral_detach" then
-- peripheral disconnect
local type, device = ppm.handle_unmount(param1)
if type ~= nil and device ~= nil then
backplane.detach(param1, type, device, println_ts)
end
-- update indicators
databus.tx_hw_status(plc_state)
end
-- check for termination request
@@ -209,7 +214,9 @@ function threads.thread__rps(smem)
-- load in from shared memory
local networked = smem.networked
local plc_state = smem.plc_state
local plc_dev = smem.plc_dev
local rps = smem.plc_sys.rps
local plc_comms = smem.plc_sys.plc_comms
local rps_queue = smem.q.mq_rps
@@ -220,12 +227,6 @@ function threads.thread__rps(smem)
-- thread loop
while true do
-- get plc_sys fields (may have been set late due to degraded boot)
local rps = smem.plc_sys.rps
local plc_comms = smem.plc_sys.plc_comms
-- get reactor, it may have changed due to a disconnect/reconnect
local reactor = plc_dev.reactor
-- SCRAM if no open connection
if networked and not plc_comms.is_linked() then
if was_linked then
@@ -236,12 +237,13 @@ function threads.thread__rps(smem)
-- check reactor status
if (not plc_state.no_reactor) and rps.is_formed() then
local reactor_status = reactor.getStatus()
databus.tx_reactor_state(reactor_status)
local active = rps.check_active()
databus.tx_reactor_state(active)
-- if we tried to SCRAM but failed, keep trying
-- in that case, SCRAM won't be called until it reconnects (this is the expected use of this check)
if rps.is_tripped() and reactor_status then rps.scram() end
if rps.is_tripped() and active then rps.scram() end
end
-- if we are in standalone mode and the front panel isn't working, continuously reset RPS
@@ -345,6 +347,8 @@ function threads.thread__comms_tx(smem)
-- load in from shared memory
local plc_state = smem.plc_state
local plc_comms = smem.plc_sys.plc_comms
local comms_queue = smem.q.mq_comms_tx
local MQ__COMM_CMD = smem.q_types.MQ__COMM_CMD
@@ -353,9 +357,6 @@ function threads.thread__comms_tx(smem)
-- thread loop
while true do
-- get plc_sys fields (may have been set late due to degraded boot)
local plc_comms = smem.plc_sys.plc_comms
-- check for messages in the message queue
while comms_queue.ready() and not plc_state.shutdown do
local msg = comms_queue.pop()
@@ -427,15 +428,14 @@ function threads.thread__comms_rx(smem)
local plc_state = smem.plc_state
local setpoints = smem.setpoints
local plc_comms = smem.plc_sys.plc_comms
local comms_queue = smem.q.mq_comms_rx
local last_update = util.time()
-- thread loop
while true do
-- get plc_sys fields (may have been set late due to degraded boot)
local plc_comms = smem.plc_sys.plc_comms
-- check for messages in the message queue
while comms_queue.ready() and not plc_state.shutdown do
local msg = comms_queue.pop()
@@ -499,89 +499,22 @@ function threads.thread__setpoint_control(smem)
log.debug("OS: setpoint control thread start")
-- load in from shared memory
local plc_state = smem.plc_state
local setpoints = smem.setpoints
local plc_dev = smem.plc_dev
local plc_state = smem.plc_state
local plc_dev = smem.plc_dev
local last_update = util.time()
local running = false
local last_burn_sp = 0.0
local last_update = util.time()
-- do not use the actual elapsed time, it could spike
-- we do not want to have big jumps as that is what we are trying to avoid in the first place
local min_elapsed_s = SP_CTRL_SLEEP / 1000.0
-- init controller
spctl.init(smem)
-- thread loop
while true do
-- get plc_sys fields (may have been set late due to degraded boot)
local rps = smem.plc_sys.rps
-- get reactor, may have changed do to disconnect/reconnect
local reactor = plc_dev.reactor
if not plc_state.no_reactor then
-- check if we should start ramping
if setpoints.burn_rate_en and (setpoints.burn_rate ~= last_burn_sp) then
local cur_burn_rate = reactor.getBurnRate()
if (type(cur_burn_rate) == "number") and (setpoints.burn_rate ~= cur_burn_rate) and rps.is_active() then
last_burn_sp = setpoints.burn_rate
-- update without ramp if <= 2.5 mB/t increase
-- no need to ramp down, as the ramp up poses the safety risks
running = (setpoints.burn_rate - cur_burn_rate) > 2.5
if running then
log.debug(util.c("SPCTL: starting burn rate ramp from ", cur_burn_rate, " mB/t to ", setpoints.burn_rate, " mB/t"))
else
log.debug(util.c("SPCTL: setting burn rate directly to ", setpoints.burn_rate, " mB/t"))
reactor.setBurnRate(setpoints.burn_rate)
end
end
end
-- only check I/O if active to save on processing time
if running then
-- clear so we can later evaluate if we should keep running
running = false
-- adjust burn rate (setpoints.burn_rate)
if setpoints.burn_rate_en then
if rps.is_active() then
local current_burn_rate = reactor.getBurnRate()
-- we yielded, check enable again
if setpoints.burn_rate_en and (type(current_burn_rate) == "number") and (current_burn_rate ~= setpoints.burn_rate) then
-- calculate new burn rate
local new_burn_rate ---@type number
if setpoints.burn_rate > current_burn_rate then
-- need to ramp up
new_burn_rate = current_burn_rate + (BURN_RATE_RAMP_mB_s * min_elapsed_s)
if new_burn_rate > setpoints.burn_rate then new_burn_rate = setpoints.burn_rate end
else
-- need to ramp down
new_burn_rate = current_burn_rate - (BURN_RATE_RAMP_mB_s * min_elapsed_s)
if new_burn_rate < setpoints.burn_rate then new_burn_rate = setpoints.burn_rate end
end
running = running or (new_burn_rate ~= setpoints.burn_rate)
-- set the burn rate
reactor.setBurnRate(new_burn_rate)
end
else
log.debug("SPCTL: ramping aborted (reactor inactive)")
setpoints.burn_rate_en = false
end
end
elseif setpoints.burn_rate_en then
log.debug(util.c("SPCTL: ramping completed (setpoint of ", setpoints.burn_rate, " mB/t)"))
setpoints.burn_rate_en = false
end
-- if ramping completed or was aborted, reset last burn setpoint so that if it is requested again it will be re-attempted
if not setpoints.burn_rate_en then last_burn_sp = 0 end
spctl.update(plc_dev.reactor, min_elapsed_s)
end
-- check for termination request

View File

@@ -285,9 +285,9 @@ function check.create(main_pane, settings_cfg, check_sys, style)
local sc = Div{parent=check_sys,x=2,y=4,width=49}
TextBox{parent=check_sys,x=1,y=2,text=" RTU Gateway Self-Check",fg_bg=bw_fg_bg}
TextBox{parent=check_sys,y=2,text=" RTU Gateway Self-Check",fg_bg=bw_fg_bg}
self.sc_log = ListBox{parent=sc,x=1,y=1,height=12,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
self.sc_log = ListBox{parent=sc,y=1,height=12,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local last_check = { nil, nil }
@@ -310,7 +310,7 @@ function check.create(main_pane, settings_cfg, check_sys, style)
end
end
PushButton{parent=sc,x=1,y=14,text="\x1b Back",callback=function()exit_self_check(main_pane)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sc,y=14,text="\x1b Back",callback=function()exit_self_check(main_pane)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
self.run_test_btn = PushButton{parent=sc,x=40,y=14,min_width=10,text="Run Test",callback=function()self_check()end,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
end

View File

@@ -72,11 +72,11 @@ function peripherals.create(tool_ctl, main_pane, cfg_sys, peri_cfg, style)
local peri_c_6 = Div{parent=peri_cfg,x=2,y=4,width=49}
local peri_c_7 = Div{parent=peri_cfg,x=2,y=4,width=49}
local peri_pane = MultiPane{parent=peri_cfg,x=1,y=4,panes={peri_c_1,peri_c_2,peri_c_3,peri_c_4,peri_c_5,peri_c_6,peri_c_7}}
local peri_pane = MultiPane{parent=peri_cfg,y=4,panes={peri_c_1,peri_c_2,peri_c_3,peri_c_4,peri_c_5,peri_c_6,peri_c_7}}
TextBox{parent=peri_cfg,x=1,y=2,text=" Peripheral Connections",fg_bg=cpair(colors.black,colors.purple)}
TextBox{parent=peri_cfg,y=2,text=" Peripheral Connections",fg_bg=cpair(colors.black,colors.purple)}
local peri_list = ListBox{parent=peri_c_1,x=1,y=1,height=12,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local peri_list = ListBox{parent=peri_c_1,y=1,height=12,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local function peri_revert()
tmp_cfg.Peripherals = tool_ctl.deep_copy_peri(ini_cfg.Peripherals)
@@ -99,22 +99,22 @@ function peripherals.create(tool_ctl, main_pane, cfg_sys, peri_cfg, style)
end
end
PushButton{parent=peri_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=peri_c_1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
local peri_revert_btn = PushButton{parent=peri_c_1,x=8,y=14,min_width=16,text="Revert Changes",callback=peri_revert,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
PushButton{parent=peri_c_1,x=35,y=14,min_width=7,text="Add +",callback=function()peri_pane.set_value(2)end,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg}
local peri_apply_btn = PushButton{parent=peri_c_1,x=43,y=14,min_width=7,text="Apply",callback=peri_apply,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
TextBox{parent=peri_c_2,x=1,y=1,text="Select one of the below devices to use."}
TextBox{parent=peri_c_2,y=1,text="Select one of the below devices to use."}
self.ppm_devs = ListBox{parent=peri_c_2,x=1,y=3,height=10,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
self.ppm_devs = ListBox{parent=peri_c_2,y=3,height=10,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
PushButton{parent=peri_c_2,x=1,y=14,text="\x1b Back",callback=function()peri_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=peri_c_2,y=14,text="\x1b Back",callback=function()peri_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=peri_c_2,x=8,y=14,min_width=10,text="Manual +",callback=function()peri_pane.set_value(3)end,fg_bg=cpair(colors.black,colors.orange),active_fg_bg=btn_act_fg_bg}
PushButton{parent=peri_c_2,x=26,y=14,min_width=24,text="I don't see my device!",callback=function()peri_pane.set_value(7)end,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg}
TextBox{parent=peri_c_7,x=1,y=1,height=10,text="Make sure your device is either touching the RTU or connected via wired modems. There should be a wired modem on a side of the RTU then one on the device, connected by a cable. The modem on the device needs to be right clicked to connect it (which will turn its border red), at which point the peripheral name will be shown in the chat."}
TextBox{parent=peri_c_7,x=1,y=9,height=4,text="If it still does not show, it may not be compatible. Currently only Boilers, Turbines, Dynamic Tanks, SNAs, SPSs, Induction Matricies, and Environment Detectors are supported."}
PushButton{parent=peri_c_7,x=1,y=14,text="\x1b Back",callback=function()peri_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=peri_c_7,y=1,height=10,text="Make sure your device is either touching the RTU or connected via wired modems. There should be a wired modem on a side of the RTU then one on the device, connected by a cable. The modem on the device needs to be right clicked to connect it (which will turn its border red), at which point the peripheral name will be shown in the chat."}
TextBox{parent=peri_c_7,y=9,height=4,text="If it still does not show, it may not be compatible. Currently only Boilers, Turbines, Dynamic Tanks, SNAs, SPSs, Induction Matricies, and Environment Detectors are supported."}
PushButton{parent=peri_c_7,y=14,text="\x1b Back",callback=function()peri_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
local new_peri_attrs = { "", "" }
local function new_peri(name, type)
@@ -201,7 +201,7 @@ function peripherals.create(tool_ctl, main_pane, cfg_sys, peri_cfg, style)
---@cast entry ppm_entry
local line = Div{parent=self.ppm_devs,height=2,fg_bg=cpair(colors.black,bkg)}
PushButton{parent=line,x=1,y=1,min_width=9,alignment=LEFT,height=1,text="> SELECT",callback=function()new_peri(name,entry.type)end,fg_bg=cpair(colors.black,colors.purple),active_fg_bg=cpair(colors.white,colors.black)}
PushButton{parent=line,y=1,min_width=9,alignment=LEFT,height=1,text="> SELECT",callback=function()new_peri(name,entry.type)end,fg_bg=cpair(colors.black,colors.purple),active_fg_bg=cpair(colors.white,colors.black)}
TextBox{parent=line,x=11,y=1,text=name,fg_bg=cpair(colors.black,bkg)}
TextBox{parent=line,x=11,y=2,text=entry.type,fg_bg=cpair(colors.gray,bkg)}
@@ -212,10 +212,10 @@ function peripherals.create(tool_ctl, main_pane, cfg_sys, peri_cfg, style)
tool_ctl.update_peri_list()
TextBox{parent=peri_c_3,x=1,y=1,height=4,text="This feature is intended for advanced users. If you just can't see your device, click 'I don't see my device!' instead."}
TextBox{parent=peri_c_3,x=1,y=5,height=4,text="Peripheral Name"}
local p_name = TextField{parent=peri_c_3,x=1,y=6,width=49,height=1,max_len=128,fg_bg=bw_fg_bg}
local p_type = Radio2D{parent=peri_c_3,x=1,y=8,rows=5,columns=2,default=1,options=RTU_DEV_TYPES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.purple}
TextBox{parent=peri_c_3,y=1,height=4,text="This feature is intended for advanced users. If you just can't see your device, click 'I don't see my device!' instead."}
TextBox{parent=peri_c_3,y=5,height=4,text="Peripheral Name"}
local p_name = TextField{parent=peri_c_3,y=6,width=49,height=1,max_len=128,fg_bg=bw_fg_bg}
local p_type = Radio2D{parent=peri_c_3,y=8,rows=5,columns=2,default=1,options=RTU_DEV_TYPES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.purple}
local man_p_err = TextBox{parent=peri_c_3,x=8,y=14,width=35,text="Please enter a peripheral name.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
man_p_err.hide(true)
@@ -228,13 +228,13 @@ function peripherals.create(tool_ctl, main_pane, cfg_sys, peri_cfg, style)
else man_p_err.show() end
end
PushButton{parent=peri_c_3,x=1,y=14,text="\x1b Back",callback=function()peri_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=peri_c_3,y=14,text="\x1b Back",callback=function()peri_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=peri_c_3,x=44,y=14,text="Next \x1a",callback=submit_manual_peri,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
self.p_name_msg = TextBox{parent=peri_c_4,x=1,y=1,height=2,text=""}
self.p_prompt = TextBox{parent=peri_c_4,x=1,y=4,height=2,text=""}
self.p_name_msg = TextBox{parent=peri_c_4,y=1,height=2,text=""}
self.p_prompt = TextBox{parent=peri_c_4,y=4,height=2,text=""}
self.p_idx = NumberField{parent=peri_c_4,x=31,y=4,width=4,max_chars=2,min=1,max=2,default=1,fg_bg=bw_fg_bg,dis_fg_bg=btn_dis_fg_bg}
self.p_assign_btn = RadioButton{parent=peri_c_4,x=1,y=5,default=1,options={"the facility","reactor unit #"},callback=function(v)self.p_assign(v)end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.purple}
self.p_assign_btn = RadioButton{parent=peri_c_4,y=5,default=1,options={"the facility","reactor unit #"},callback=function(v)self.p_assign(v)end,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.purple}
self.p_unit = NumberField{parent=peri_c_4,x=23,y=4,width=4,max_chars=2,min=1,max=4,default=1,fg_bg=bw_fg_bg,dis_fg_bg=btn_dis_fg_bg}
self.p_unit.disable()
@@ -252,8 +252,8 @@ function peripherals.create(tool_ctl, main_pane, cfg_sys, peri_cfg, style)
end
end
self.p_desc = TextBox{parent=peri_c_4,x=1,y=7,height=6,text="",fg_bg=g_lg_fg_bg}
self.p_desc_ext = TextBox{parent=peri_c_4,x=1,y=6,height=7,text="",fg_bg=g_lg_fg_bg}
self.p_desc = TextBox{parent=peri_c_4,y=7,height=6,text="",fg_bg=g_lg_fg_bg}
self.p_desc_ext = TextBox{parent=peri_c_4,y=6,height=7,text="",fg_bg=g_lg_fg_bg}
self.p_err = TextBox{parent=peri_c_4,x=8,y=14,width=32,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
self.p_err.hide(true)
@@ -337,15 +337,15 @@ function peripherals.create(tool_ctl, main_pane, cfg_sys, peri_cfg, style)
self.p_idx.set_value(1)
end
PushButton{parent=peri_c_4,x=1,y=14,text="\x1b Back",callback=back_from_peri_opts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=peri_c_4,y=14,text="\x1b Back",callback=back_from_peri_opts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=peri_c_4,x=41,y=14,min_width=9,text="Confirm",callback=save_peri_entry,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg}
TextBox{parent=peri_c_5,x=1,y=1,text="Settings saved!"}
PushButton{parent=peri_c_5,x=1,y=14,text="\x1b Back",callback=function()peri_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=peri_c_5,y=1,text="Settings saved!"}
PushButton{parent=peri_c_5,y=14,text="\x1b Back",callback=function()peri_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=peri_c_5,x=44,y=14,min_width=6,text="Home",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=peri_c_6,x=1,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=peri_c_6,x=1,y=14,text="\x1b Back",callback=function()peri_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=peri_c_6,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=peri_c_6,y=14,text="\x1b Back",callback=function()peri_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=peri_c_6,x=44,y=14,min_width=6,text="Home",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -405,9 +405,9 @@ function peripherals.create(tool_ctl, main_pane, cfg_sys, peri_cfg, style)
end
local entry = Div{parent=peri_list,height=3}
TextBox{parent=entry,x=1,y=1,text="@ "..def.name,fg_bg=cpair(colors.black,colors.white)}
TextBox{parent=entry,x=1,y=2,text=" \x1a "..t_str,fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=entry,x=1,y=3,text=desc,fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=entry,y=1,text="@ "..def.name,fg_bg=cpair(colors.black,colors.white)}
TextBox{parent=entry,y=2,text=" \x1a "..t_str,fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=entry,y=3,text=desc,fg_bg=cpair(colors.gray,colors.white)}
local edit_btn = PushButton{parent=entry,x=41,y=2,min_width=8,height=1,text="EDIT",callback=function()edit_peri_entry(i,def,t or "")end,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
PushButton{parent=entry,x=41,y=3,min_width=8,height=1,text="DELETE",callback=function()delete_peri_entry(i)end,fg_bg=cpair(colors.black,colors.red),active_fg_bg=btn_act_fg_bg}

View File

@@ -168,14 +168,14 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
local rs_c_9 = Div{parent=rs_cfg,x=2,y=4,width=49}
local rs_c_10 = Div{parent=rs_cfg,x=2,y=4,width=49}
local rs_pane = MultiPane{parent=rs_cfg,x=1,y=4,panes={rs_c_1,rs_c_2,rs_c_3,rs_c_4,rs_c_5,rs_c_6,rs_c_7,rs_c_8,rs_c_9,rs_c_10}}
local rs_pane = MultiPane{parent=rs_cfg,y=4,panes={rs_c_1,rs_c_2,rs_c_3,rs_c_4,rs_c_5,rs_c_6,rs_c_7,rs_c_8,rs_c_9,rs_c_10}}
local header = TextBox{parent=rs_cfg,x=1,y=2,text=" Redstone Connections",fg_bg=cpair(colors.black,colors.red)}
local header = TextBox{parent=rs_cfg,y=2,text=" Redstone Connections",fg_bg=cpair(colors.black,colors.red)}
--#region Interface Selection
TextBox{parent=rs_c_1,x=1,y=1,text="Configure this computer or a redstone relay."}
local iface_list = ListBox{parent=rs_c_1,x=1,y=3,height=10,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
TextBox{parent=rs_c_1,y=1,text="Configure this computer or a redstone relay."}
local iface_list = ListBox{parent=rs_c_1,y=3,height=10,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
-- update relay interface list
function tool_ctl.update_relay_list()
@@ -209,7 +209,7 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
end
local line = Div{parent=iface_list,height=2,fg_bg=cpair(colors.black,colors.white)}
TextBox{parent=line,x=1,y=1,text="@ local",fg_bg=cpair(colors.black,colors.white)}
TextBox{parent=line,y=1,text="@ local",fg_bg=cpair(colors.black,colors.white)}
TextBox{parent=line,x=3,y=2,text="This Computer",fg_bg=cpair(colors.gray,colors.white)}
local count = #redstone_subset(ini_cfg.Redstone, nil)
TextBox{parent=line,x=33,y=2,width=16,alignment=core.ALIGN.RIGHT,text=count.." connections",fg_bg=cpair(colors.gray,colors.white)}
@@ -220,7 +220,7 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
local name = relays[i]
line = Div{parent=iface_list,height=2,fg_bg=cpair(colors.black,colors.white)}
TextBox{parent=line,x=1,y=1,text="@ "..name,fg_bg=cpair(colors.black,colors.white)}
TextBox{parent=line,y=1,text="@ "..name,fg_bg=cpair(colors.black,colors.white)}
TextBox{parent=line,x=3,y=2,text="Redstone Relay",fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=line,x=18,y=2,text=tri(mounts[name],"ONLINE","OFFLINE"),fg_bg=cpair(tri(mounts[name],colors.green,colors.red),colors.white)}
count = #redstone_subset(ini_cfg.Redstone, name)
@@ -232,14 +232,14 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
tool_ctl.update_relay_list()
PushButton{parent=rs_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=rs_c_1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=rs_c_1,x=27,y=14,min_width=23,text="I don't see my relay!",callback=function()rs_pane.set_value(10)end,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg}
--#endregion
--#region Configuration List
TextBox{parent=rs_c_2,x=1,y=1,text=" port side/color unit/facility",fg_bg=g_lg_fg_bg}
local rs_list = ListBox{parent=rs_c_2,x=1,y=2,height=11,width=49,scroll_height=200,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
TextBox{parent=rs_c_2,y=1,text=" port side/color unit/facility",fg_bg=g_lg_fg_bg}
local rs_list = ListBox{parent=rs_c_2,y=2,height=11,width=49,scroll_height=200,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local function rs_revert()
tmp_cfg.Redstone = tool_ctl.deep_copy_rs(ini_cfg.Redstone)
@@ -275,7 +275,7 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
header.set_value(" Redstone Connections")
end
PushButton{parent=rs_c_2,x=1,y=14,text="\x1b Back",callback=rs_back,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=rs_c_2,y=14,text="\x1b Back",callback=rs_back,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
local rs_revert_btn = PushButton{parent=rs_c_2,x=8,y=14,min_width=16,text="Revert Changes",callback=rs_revert,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
PushButton{parent=rs_c_2,x=35,y=14,min_width=7,text="New +",callback=function()rs_pane.set_value(3)end,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg}
local rs_apply_btn = PushButton{parent=rs_c_2,x=43,y=14,min_width=7,text="Apply",callback=rs_apply,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
@@ -283,9 +283,9 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
--#endregion
--#region Port Selection
TextBox{parent=rs_c_3,x=1,y=1,text="Select one of the below ports to use."}
TextBox{parent=rs_c_3,y=1,text="Select one of the below ports to use."}
local rs_ports = ListBox{parent=rs_c_3,x=1,y=3,height=10,width=49,scroll_height=200,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local rs_ports = ListBox{parent=rs_c_3,y=3,height=10,width=49,scroll_height=200,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local function new_rs(port)
self.rs_cfg_editing = false
@@ -298,6 +298,7 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
self.rs_cfg_side_l.set_value("Output Side")
self.rs_cfg_bundled.enable()
self.rs_cfg_advanced.disable()
text = "You selected the ALL_WASTE shortcut."
else
self.rs_cfg_shortcut.hide(true)
@@ -329,17 +330,15 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
io_type = "analog output "
end
text = "You selected the " .. io_type .. rsio.to_string(port) .. " (for "
text = "You selected the " .. io_type .. rsio.to_string(port) .. " (for " .. tri(PORT_DSGN[port] == 1, "a unit).", "the facility).")
end
if PORT_DSGN[port] == 1 then
text = text .. "a unit)."
self.rs_cfg_unit_l.show()
self.rs_cfg_unit.show()
else
self.rs_cfg_unit_l.hide(true)
self.rs_cfg_unit.hide(true)
text = text .. "the facility)."
end
if PORT_DSGN[port] == 1 then
self.rs_cfg_unit_l.show()
self.rs_cfg_unit.show()
else
self.rs_cfg_unit_l.hide(true)
self.rs_cfg_unit.hide(true)
end
self.rs_cfg_selection.set_value(text)
@@ -349,7 +348,7 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
-- add entries to redstone option list
local all_w_macro = Div{parent=rs_ports,height=1}
PushButton{parent=all_w_macro,x=1,y=1,min_width=14,alignment=LEFT,height=1,text=">ALL_WASTE",callback=function()new_rs(-1)end,fg_bg=cpair(colors.black,colors.green),active_fg_bg=cpair(colors.white,colors.black)}
PushButton{parent=all_w_macro,y=1,min_width=14,alignment=LEFT,height=1,text=">ALL_WASTE",callback=function()new_rs(-1)end,fg_bg=cpair(colors.black,colors.green),active_fg_bg=cpair(colors.white,colors.black)}
TextBox{parent=all_w_macro,x=16,y=1,width=5,text="[n/a]",fg_bg=cpair(colors.lightGray,colors.white)}
TextBox{parent=all_w_macro,x=22,y=1,text="Create all 4 waste entries",fg_bg=cpair(colors.gray,colors.white)}
@@ -360,22 +359,22 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
local btn_color = tri(rsio.get_io_dir(p) == rsio.IO_DIR.IN, colors.yellow, colors.lightBlue)
local entry = Div{parent=rs_ports,height=1}
PushButton{parent=entry,x=1,y=1,min_width=14,alignment=LEFT,height=1,text=">"..name,callback=function()new_rs(p)end,fg_bg=cpair(colors.black,btn_color),active_fg_bg=cpair(colors.white,colors.black)}
PushButton{parent=entry,y=1,min_width=14,alignment=LEFT,height=1,text=">"..name,callback=function()new_rs(p)end,fg_bg=cpair(colors.black,btn_color),active_fg_bg=cpair(colors.white,colors.black)}
TextBox{parent=entry,x=16,y=1,width=5,text=io_dir,fg_bg=cpair(colors.lightGray,colors.white)}
TextBox{parent=entry,x=22,y=1,text=PORT_DESC_MAP[i][2],fg_bg=cpair(colors.gray,colors.white)}
end
PushButton{parent=rs_c_3,x=1,y=14,text="\x1b Back",callback=function()rs_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=rs_c_3,y=14,text="\x1b Back",callback=function()rs_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
--#region Port Configuration
self.rs_cfg_selection = TextBox{parent=rs_c_4,x=1,y=1,height=2,text=""}
self.rs_cfg_selection = TextBox{parent=rs_c_4,y=1,height=2,text=""}
PushButton{parent=rs_c_4,x=36,y=3,text="What's that?",min_width=14,callback=function()rs_pane.set_value(8)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
self.rs_cfg_side_l = TextBox{parent=rs_c_4,x=1,y=4,width=11,text="Output Side"}
local side = Radio2D{parent=rs_c_4,x=1,y=5,rows=1,columns=6,default=1,options=side_options,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.red}
self.rs_cfg_side_l = TextBox{parent=rs_c_4,y=4,width=11,text="Output Side"}
local side = Radio2D{parent=rs_c_4,y=5,rows=1,columns=6,default=1,options=side_options,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.red}
self.rs_cfg_unit_l = TextBox{parent=rs_c_4,x=25,y=7,width=7,text="Unit ID"}
self.rs_cfg_unit = NumberField{parent=rs_c_4,x=33,y=7,width=10,max_chars=2,min=1,max=4,fg_bg=bw_fg_bg}
@@ -384,11 +383,11 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
if bundled then self.rs_cfg_color.enable() else self.rs_cfg_color.disable() end
end
self.rs_cfg_shortcut = TextBox{parent=rs_c_4,x=1,y=9,height=4,text="This shortcut will add entries for each of the 4 waste outputs. If you select bundled, 4 colors will be assigned to the selected side. Otherwise, 4 default sides will be used."}
self.rs_cfg_shortcut = TextBox{parent=rs_c_4,y=9,height=4,text="This shortcut will add entries for each of the 4 waste outputs. If you select bundled, 4 colors will be assigned to the selected side. Otherwise, 4 default sides will be used."}
self.rs_cfg_shortcut.hide(true)
self.rs_cfg_bundled = Checkbox{parent=rs_c_4,x=1,y=7,label="Is Bundled?",default=false,box_fg_bg=cpair(colors.red,colors.black),callback=set_bundled,disable_fg_bg=g_lg_fg_bg}
self.rs_cfg_color = Radio2D{parent=rs_c_4,x=1,y=9,rows=4,columns=4,default=1,options=color_options,radio_colors=cpair(colors.lightGray,colors.black),color_map=color_options_map,disable_color=colors.gray,disable_fg_bg=g_lg_fg_bg}
self.rs_cfg_bundled = Checkbox{parent=rs_c_4,y=7,label="Is Bundled?",default=false,box_fg_bg=cpair(colors.red,colors.black),callback=set_bundled,disable_fg_bg=g_lg_fg_bg}
self.rs_cfg_color = Radio2D{parent=rs_c_4,y=9,rows=4,columns=4,default=1,options=color_options,radio_colors=cpair(colors.lightGray,colors.black),color_map=color_options_map,disable_color=colors.gray,disable_fg_bg=g_lg_fg_bg}
self.rs_cfg_color.disable()
local rs_err = TextBox{parent=rs_c_4,x=8,y=14,width=30,text="Unit ID invalid.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -461,35 +460,35 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
else rs_err.show() end
end
PushButton{parent=rs_c_4,x=1,y=14,text="\x1b Back",callback=back_from_rs_opts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=rs_c_4,y=14,text="\x1b Back",callback=back_from_rs_opts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
self.rs_cfg_advanced = PushButton{parent=rs_c_4,x=30,y=14,min_width=10,text="Advanced",callback=function()rs_pane.set_value(9)end,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
PushButton{parent=rs_c_4,x=41,y=14,min_width=9,text="Confirm",callback=save_rs_entry,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=btn_act_fg_bg}
--#endregion
TextBox{parent=rs_c_5,x=1,y=1,text="Settings saved!"}
PushButton{parent=rs_c_5,x=1,y=14,text="\x1b Back",callback=function()rs_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=rs_c_5,y=1,text="Settings saved!"}
PushButton{parent=rs_c_5,y=14,text="\x1b Back",callback=function()rs_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=rs_c_5,x=44,y=14,min_width=6,text="Home",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=rs_c_6,x=1,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=rs_c_6,x=1,y=14,text="\x1b Back",callback=function()rs_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=rs_c_6,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=rs_c_6,y=14,text="\x1b Back",callback=function()rs_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=rs_c_6,x=44,y=14,min_width=6,text="Home",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=rs_c_7,x=1,y=1,height=6,text="You already configured this input for this facility/unit assignment. There can only be one entry for each input per each unit or the facility (for facility inputs).\n\nPlease select a different port."}
PushButton{parent=rs_c_7,x=1,y=14,text="\x1b Back",callback=function()rs_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=rs_c_7,y=1,height=6,text="You already configured this input for this facility/unit assignment. There can only be one entry for each input per each unit or the facility (for facility inputs).\n\nPlease select a different port."}
PushButton{parent=rs_c_7,y=14,text="\x1b Back",callback=function()rs_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=rs_c_8,x=1,y=1,height=4,text="(Normal) Digital Input: On if there is a redstone signal, off otherwise\nInverted Digital Input: On without a redstone signal, off otherwise"}
TextBox{parent=rs_c_8,x=1,y=6,height=4,text="(Normal) Digital Output: Redstone signal to 'turn it on', none to 'turn it off'\nInverted Digital Output: No redstone signal to 'turn it on', redstone signal to 'turn it off'"}
TextBox{parent=rs_c_8,x=1,y=11,height=2,text="Analog Input: 0-15 redstone power level input\nAnalog Output: 0-15 scaled redstone power level output"}
PushButton{parent=rs_c_8,x=1,y=14,text="\x1b Back",callback=function()rs_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=rs_c_8,y=1,height=4,text="(Normal) Digital Input: On if there is a redstone signal, off otherwise\nInverted Digital Input: On without a redstone signal, off otherwise"}
TextBox{parent=rs_c_8,y=6,height=4,text="(Normal) Digital Output: Redstone signal to 'turn it on', none to 'turn it off'\nInverted Digital Output: No redstone signal to 'turn it on', redstone signal to 'turn it off'"}
TextBox{parent=rs_c_8,y=11,height=2,text="Analog Input: 0-15 redstone power level input\nAnalog Output: 0-15 scaled redstone power level output"}
PushButton{parent=rs_c_8,y=14,text="\x1b Back",callback=function()rs_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=rs_c_9,x=1,y=1,height=5,text="Advanced Options"}
self.rs_cfg_inverted = Checkbox{parent=rs_c_9,x=1,y=3,label="Invert",default=false,box_fg_bg=cpair(colors.red,colors.black),disable_fg_bg=g_lg_fg_bg}
TextBox{parent=rs_c_9,y=1,height=5,text="Advanced Options"}
self.rs_cfg_inverted = Checkbox{parent=rs_c_9,y=3,label="Invert",default=false,box_fg_bg=cpair(colors.red,colors.black),disable_fg_bg=g_lg_fg_bg}
TextBox{parent=rs_c_9,x=3,y=4,height=4,text="Digital I/O is already inverted (or not) based on intended use. If you have a non-standard setup, you can use this option to avoid needing a redstone inverter.",fg_bg=cpair(colors.gray,colors.lightGray)}
PushButton{parent=rs_c_9,x=1,y=14,text="\x1b Back",callback=function()rs_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=rs_c_9,y=14,text="\x1b Back",callback=function()rs_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=rs_c_10,x=1,y=1,height=10,text="Make sure your relay is either touching the RTU gateway or connected via wired modems. There should be a wired modem on a side of the RTU gateway then one on the device, connected by a cable. The modem on the device needs to be right clicked to connect it (which will turn its border red), at which point the peripheral name will be shown in the chat."}
PushButton{parent=rs_c_10,x=1,y=14,text="\x1b Back",callback=function()rs_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=rs_c_10,y=1,height=10,text="Make sure your relay is either touching the RTU gateway or connected via wired modems. There should be a wired modem on a side of the RTU gateway then one on the device, connected by a cable. The modem on the device needs to be right clicked to connect it (which will turn its border red), at which point the peripheral name will be shown in the chat."}
PushButton{parent=rs_c_10,y=14,text="\x1b Back",callback=function()rs_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -571,7 +570,7 @@ function redstone.create(tool_ctl, main_pane, cfg_sys, rs_cfg, style)
if def.color ~= nil then conn = def.side .. "/" .. rsio.color_name(def.color) end
local entry = Div{parent=rs_list,height=1}
TextBox{parent=entry,x=1,y=1,width=1,text=io_dir,fg_bg=cpair(tri(def.invert,colors.orange,io_c),colors.white)}
TextBox{parent=entry,y=1,width=1,text=io_dir,fg_bg=cpair(tri(def.invert,colors.orange,io_c),colors.white)}
TextBox{parent=entry,x=2,y=1,width=14,text=name}
TextBox{parent=entry,x=16,y=1,width=string.len(conn),text=conn,fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=entry,x=33,y=1,width=1,text=unit,fg_bg=cpair(colors.gray,colors.white)}

View File

@@ -64,14 +64,14 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
local spkr_c = Div{parent=spkr_cfg,x=2,y=4,width=49}
TextBox{parent=spkr_cfg,x=1,y=2,text=" Speaker Configuration",fg_bg=cpair(colors.black,colors.cyan)}
TextBox{parent=spkr_cfg,y=2,text=" Speaker Configuration",fg_bg=cpair(colors.black,colors.cyan)}
TextBox{parent=spkr_c,x=1,y=1,height=2,text="Speakers can be connected to this RTU gateway without RTU unit configuration entries."}
TextBox{parent=spkr_c,x=1,y=4,height=3,text="You can change the speaker audio volume from the default. The range is 0.0 to 3.0, where 1.0 is standard volume."}
TextBox{parent=spkr_c,y=1,height=2,text="Speakers can be connected to this RTU gateway without RTU unit configuration entries."}
TextBox{parent=spkr_c,y=4,height=3,text="You can change the speaker audio volume from the default. The range is 0.0 to 3.0, where 1.0 is standard volume."}
local s_vol = NumberField{parent=spkr_c,x=1,y=8,width=9,max_chars=7,allow_decimal=true,default=ini_cfg.SpeakerVolume,min=0,max=3,fg_bg=bw_fg_bg}
local s_vol = NumberField{parent=spkr_c,y=8,width=9,max_chars=7,allow_decimal=true,default=ini_cfg.SpeakerVolume,min=0,max=3,fg_bg=bw_fg_bg}
TextBox{parent=spkr_c,x=1,y=10,height=3,text="Note: alarm sine waves are at half scale so that multiple will be required to reach full scale.",fg_bg=g_lg_fg_bg}
TextBox{parent=spkr_c,y=10,height=3,text="Note: alarm sine waves are at half scale so that multiple will be required to reach full scale.",fg_bg=g_lg_fg_bg}
local s_vol_err = TextBox{parent=spkr_c,x=8,y=14,width=35,text="Please set a volume.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -84,7 +84,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
else s_vol_err.show() end
end
PushButton{parent=spkr_c,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=spkr_c,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=spkr_c,x=44,y=14,text="Next \x1a",callback=submit_vol,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -96,11 +96,11 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
local net_c_3 = Div{parent=net_cfg,x=2,y=4,width=49}
local net_c_4 = Div{parent=net_cfg,x=2,y=4,width=49}
local net_pane = MultiPane{parent=net_cfg,x=1,y=4,panes={net_c_1,net_c_2,net_c_3,net_c_4}}
local net_pane = MultiPane{parent=net_cfg,y=4,panes={net_c_1,net_c_2,net_c_3,net_c_4}}
TextBox{parent=net_cfg,x=1,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)}
TextBox{parent=net_cfg,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)}
TextBox{parent=net_c_1,x=1,y=1,text="Please select the network interface(s)."}
TextBox{parent=net_c_1,y=1,text="Please select the network interface(s)."}
TextBox{parent=net_c_1,x=41,y=1,text="new!",fg_bg=cpair(colors.red,colors._INHERIT)} ---@todo remove NEW tag on next revision
local function en_dis_pref()
@@ -117,12 +117,12 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
tool_ctl.gen_modem_list()
end
self.wireless = Checkbox{parent=net_c_1,x=1,y=3,label="Wireless/Ender Modem",default=ini_cfg.WirelessModem,box_fg_bg=cpair(colors.lightBlue,colors.black),callback=en_dis_pref}
self.wireless = Checkbox{parent=net_c_1,y=3,label="Wireless/Ender Modem",default=ini_cfg.WirelessModem,box_fg_bg=cpair(colors.lightBlue,colors.black),callback=en_dis_pref}
self.wl_pref = Checkbox{parent=net_c_1,x=30,y=3,label="Prefer Wireless",default=ini_cfg.PreferWireless,box_fg_bg=cpair(colors.lightBlue,colors.black),disable_fg_bg=g_lg_fg_bg}
self.wired = Checkbox{parent=net_c_1,x=1,y=5,label="Wired Modem",default=ini_cfg.WiredModem~=false,box_fg_bg=cpair(colors.lightBlue,colors.black),callback=on_wired_change}
self.wired = Checkbox{parent=net_c_1,y=5,label="Wired Modem",default=ini_cfg.WiredModem~=false,box_fg_bg=cpair(colors.lightBlue,colors.black),callback=on_wired_change}
TextBox{parent=net_c_1,x=3,y=6,text="this one MUST ONLY connect to SCADA computers",fg_bg=cpair(colors.red,colors._INHERIT)}
TextBox{parent=net_c_1,x=3,y=7,text="connecting it to peripherals will cause issues",fg_bg=g_lg_fg_bg}
local modem_list = ListBox{parent=net_c_1,x=1,y=8,height=5,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local modem_list = ListBox{parent=net_c_1,y=8,height=5,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local modem_err = TextBox{parent=net_c_1,x=8,y=14,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -162,17 +162,17 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
end
end
PushButton{parent=net_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_1,y=14,text="\x1b Back",callback=function()main_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_1,x=44,y=14,text="Next \x1a",callback=submit_interfaces,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_2,x=1,y=1,text="Please set the network channels below."}
TextBox{parent=net_c_2,x=1,y=3,height=4,text="Each of the 5 uniquely named channels, including the 2 below, must be the same for each device in this SCADA network. For multiplayer servers, it is recommended to not use the default channels.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_2,y=1,text="Please set the network channels below."}
TextBox{parent=net_c_2,y=3,height=4,text="Each of the 5 uniquely named channels, including the 2 below, must be the same for each device in this SCADA network. For multiplayer servers, it is recommended to not use the default channels.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_2,x=1,y=8,text="Supervisor Channel"}
local svr_chan = NumberField{parent=net_c_2,x=1,y=9,width=7,default=ini_cfg.SVR_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_2,y=8,text="Supervisor Channel"}
local svr_chan = NumberField{parent=net_c_2,y=9,width=7,default=ini_cfg.SVR_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_2,x=9,y=9,height=4,text="[SVR_CHANNEL]",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_2,x=1,y=11,text="RTU Channel"}
local rtu_chan = NumberField{parent=net_c_2,x=1,y=12,width=7,default=ini_cfg.RTU_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_2,y=11,text="RTU Channel"}
local rtu_chan = NumberField{parent=net_c_2,y=12,width=7,default=ini_cfg.RTU_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_2,x=9,y=12,height=4,text="[RTU_CHANNEL]",fg_bg=g_lg_fg_bg}
local chan_err = TextBox{parent=net_c_2,x=8,y=14,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -194,17 +194,17 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
end
end
PushButton{parent=net_c_2,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_2,y=14,text="\x1b Back",callback=function()net_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_2,x=44,y=14,text="Next \x1a",callback=submit_channels,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_3,x=1,y=1,text="Connection Timeout"}
local timeout = NumberField{parent=net_c_3,x=1,y=2,width=7,default=ini_cfg.ConnTimeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg}
TextBox{parent=net_c_3,y=1,text="Connection Timeout"}
local timeout = NumberField{parent=net_c_3,y=2,width=7,default=ini_cfg.ConnTimeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg}
TextBox{parent=net_c_3,x=9,y=2,height=2,text="seconds (default 5)",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,x=1,y=3,height=4,text="You generally do not want or need to modify this. On slow servers, you can increase this to make the system wait longer before assuming a disconnection.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,y=3,height=4,text="You generally do not want or need to modify this. On slow servers, you can increase this to make the system wait longer before assuming a disconnection.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,x=1,y=8,text="Trusted Range (Wireless Only)"}
self.range = NumberField{parent=net_c_3,x=1,y=9,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg,dis_fg_bg=cpair(colors.lightGray,colors.white)}
TextBox{parent=net_c_3,x=1,y=10,height=4,text="Setting this to a value larger than 0 prevents wireless connections with devices that many meters (blocks) away in any direction.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,y=8,text="Trusted Range (Wireless Only)"}
self.range = NumberField{parent=net_c_3,y=9,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg,dis_fg_bg=cpair(colors.lightGray,colors.white)}
TextBox{parent=net_c_3,y=10,height=4,text="Setting this to a value larger than 0 prevents wireless connections with devices that many meters (blocks) away in any direction.",fg_bg=g_lg_fg_bg}
local n3_err = TextBox{parent=net_c_3,x=8,y=14,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -233,14 +233,14 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
end
end
PushButton{parent=net_c_3,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_3,y=14,text="\x1b Back",callback=function()net_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_3,x=44,y=14,text="Next \x1a",callback=submit_ct_tr,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_4,x=1,y=1,height=2,text="Optionally, set the facility authentication key below. Do NOT use one of your passwords."}
TextBox{parent=net_c_4,x=1,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for wireless security on multiplayer servers. All devices on the same wireless network MUST use the same key if any device has a key. This does result in some extra computation (can slow things down).",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_4,y=1,height=2,text="Optionally, set the facility authentication key below. Do NOT use one of your passwords."}
TextBox{parent=net_c_4,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for wireless security on multiplayer servers. All devices on the same wireless network MUST use the same key if any device has a key. This does result in some extra computation (can slow things down).",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_4,x=1,y=11,text="Auth Key (Wireless Only, Not Used for Wired)"}
local key, _ = TextField{parent=net_c_4,x=1,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg}
TextBox{parent=net_c_4,y=11,text="Auth Key (Wireless Only, Not Used for Wired)"}
local key, _ = TextField{parent=net_c_4,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg}
local function censor_key(enable) key.censor(tri(enable, "*", nil)) end
@@ -260,7 +260,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
else key_err.show() end
end
PushButton{parent=net_c_4,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_4,y=14,text="\x1b Back",callback=function()net_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_4,x=44,y=14,text="Next \x1a",callback=submit_auth,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -269,17 +269,17 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
local log_c_1 = Div{parent=log_cfg,x=2,y=4,width=49}
TextBox{parent=log_cfg,x=1,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)}
TextBox{parent=log_cfg,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)}
TextBox{parent=log_c_1,x=1,y=1,text="Please configure logging below."}
TextBox{parent=log_c_1,y=1,text="Please configure logging below."}
TextBox{parent=log_c_1,x=1,y=3,text="Log File Mode"}
local mode = RadioButton{parent=log_c_1,x=1,y=4,default=ini_cfg.LogMode+1,options={"Append on Startup","Replace on Startup"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.pink}
TextBox{parent=log_c_1,y=3,text="Log File Mode"}
local mode = RadioButton{parent=log_c_1,y=4,default=ini_cfg.LogMode+1,options={"Append on Startup","Replace on Startup"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.pink}
TextBox{parent=log_c_1,x=1,y=7,text="Log File Path"}
local path = TextField{parent=log_c_1,x=1,y=8,width=49,height=1,value=ini_cfg.LogPath,max_len=128,fg_bg=bw_fg_bg}
TextBox{parent=log_c_1,y=7,text="Log File Path"}
local path = TextField{parent=log_c_1,y=8,width=49,height=1,value=ini_cfg.LogPath,max_len=128,fg_bg=bw_fg_bg}
local en_dbg = Checkbox{parent=log_c_1,x=1,y=10,default=ini_cfg.LogDebug,label="Enable Logging Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)}
local en_dbg = Checkbox{parent=log_c_1,y=10,default=ini_cfg.LogDebug,label="Enable Logging Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)}
TextBox{parent=log_c_1,x=3,y=11,height=2,text="This results in much larger log files. It is best to only use this when there is a problem.",fg_bg=g_lg_fg_bg}
local path_err = TextBox{parent=log_c_1,x=8,y=14,width=35,text="Please provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -296,7 +296,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
else path_err.show() end
end
PushButton{parent=log_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=log_c_1,y=14,text="\x1b Back",callback=function()main_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=log_c_1,x=44,y=14,text="Next \x1a",callback=submit_log,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -308,17 +308,17 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
local clr_c_3 = Div{parent=clr_cfg,x=2,y=4,width=49}
local clr_c_4 = Div{parent=clr_cfg,x=2,y=4,width=49}
local clr_pane = MultiPane{parent=clr_cfg,x=1,y=4,panes={clr_c_1,clr_c_2,clr_c_3,clr_c_4}}
local clr_pane = MultiPane{parent=clr_cfg,y=4,panes={clr_c_1,clr_c_2,clr_c_3,clr_c_4}}
TextBox{parent=clr_cfg,x=1,y=2,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)}
TextBox{parent=clr_cfg,y=2,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)}
TextBox{parent=clr_c_1,x=1,y=1,height=2,text="Here you can select the color theme for the front panel."}
TextBox{parent=clr_c_1,x=1,y=4,height=2,text="Click 'Accessibility' below to access colorblind assistive options.",fg_bg=g_lg_fg_bg}
TextBox{parent=clr_c_1,y=1,height=2,text="Here you can select the color theme for the front panel."}
TextBox{parent=clr_c_1,y=4,height=2,text="Click 'Accessibility' below to access colorblind assistive options.",fg_bg=g_lg_fg_bg}
TextBox{parent=clr_c_1,x=1,y=7,text="Front Panel Theme"}
local fp_theme = RadioButton{parent=clr_c_1,x=1,y=8,default=ini_cfg.FrontPanelTheme,options=themes.FP_THEME_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_1,y=7,text="Front Panel Theme"}
local fp_theme = RadioButton{parent=clr_c_1,y=8,default=ini_cfg.FrontPanelTheme,options=themes.FP_THEME_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_2,x=1,y=1,height=6,text="This system uses color heavily to distinguish ok and not, with some indicators using many colors. By selecting a mode below, indicators will change as shown. For non-standard modes, indicators with more than two colors will be split up."}
TextBox{parent=clr_c_2,y=1,height=6,text="This system uses color heavily to distinguish ok and not, with some indicators using many colors. By selecting a mode below, indicators will change as shown. For non-standard modes, indicators with more than two colors will be split up."}
TextBox{parent=clr_c_2,x=21,y=7,text="Preview"}
local _ = IndLight{parent=clr_c_2,x=21,y=8,label="Good",colors=cpair(colors.black,colors.green)}
@@ -347,8 +347,8 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
end
end
TextBox{parent=clr_c_2,x=1,y=7,width=10,text="Color Mode"}
local c_mode = RadioButton{parent=clr_c_2,x=1,y=8,default=ini_cfg.ColorMode,options=themes.COLOR_MODE_NAMES,callback=recolor,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_2,y=7,width=10,text="Color Mode"}
local c_mode = RadioButton{parent=clr_c_2,y=8,default=ini_cfg.ColorMode,options=themes.COLOR_MODE_NAMES,callback=recolor,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_2,x=21,y=13,height=2,width=18,text="Note: exact color varies by theme.",fg_bg=g_lg_fg_bg}
@@ -390,19 +390,19 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
end
end
PushButton{parent=clr_c_1,x=1,y=14,text="\x1b Back",callback=back_from_colors,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=clr_c_1,y=14,text="\x1b Back",callback=back_from_colors,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=clr_c_1,x=8,y=14,min_width=15,text="Accessibility",callback=show_access,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
tool_ctl.color_next = PushButton{parent=clr_c_1,x=44,y=14,text="Next \x1a",callback=submit_colors,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
tool_ctl.color_apply = PushButton{parent=clr_c_1,x=43,y=14,min_width=7,text="Apply",callback=submit_colors,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg}
tool_ctl.color_apply.hide(true)
TextBox{parent=clr_c_3,x=1,y=1,text="Settings saved!"}
PushButton{parent=clr_c_3,x=1,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=clr_c_3,y=1,text="Settings saved!"}
PushButton{parent=clr_c_3,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
PushButton{parent=clr_c_3,x=44,y=14,min_width=6,text="Home",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=clr_c_4,x=1,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=clr_c_4,x=1,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=clr_c_4,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=clr_c_4,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
PushButton{parent=clr_c_4,x=44,y=14,min_width=6,text="Home",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -417,11 +417,11 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
local sum_c_6 = Div{parent=summary,x=2,y=4,width=49}
local sum_c_7 = Div{parent=summary,x=2,y=4,width=49}
local sum_pane = MultiPane{parent=summary,x=1,y=4,panes={sum_c_1,sum_c_2,sum_c_3,sum_c_4,sum_c_5,sum_c_6,sum_c_7}}
local sum_pane = MultiPane{parent=summary,y=4,panes={sum_c_1,sum_c_2,sum_c_3,sum_c_4,sum_c_5,sum_c_6,sum_c_7}}
TextBox{parent=summary,x=1,y=2,text=" Summary",fg_bg=cpair(colors.black,colors.green)}
TextBox{parent=summary,y=2,text=" Summary",fg_bg=cpair(colors.black,colors.green)}
local setting_list = ListBox{parent=sum_c_1,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local setting_list = ListBox{parent=sum_c_1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local function back_from_settings()
if tool_ctl.viewing_config or self.importing_legacy then
@@ -492,22 +492,22 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
else sum_pane.set_value(6) end
end
PushButton{parent=sum_c_1,x=1,y=14,text="\x1b Back",callback=back_from_settings,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_1,y=14,text="\x1b Back",callback=back_from_settings,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
self.show_key_btn = PushButton{parent=sum_c_1,x=8,y=14,min_width=17,text="Unhide Auth Key",callback=function()self.show_auth_key()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
tool_ctl.settings_apply = PushButton{parent=sum_c_1,x=43,y=14,min_width=7,text="Apply",callback=function()save_and_continue(true)end,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg}
tool_ctl.settings_confirm = PushButton{parent=sum_c_1,x=41,y=14,min_width=9,text="Confirm",callback=function()sum_pane.set_value(2)end,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg}
tool_ctl.settings_confirm.hide()
TextBox{parent=sum_c_2,x=1,y=1,text="The following peripherals will be imported:"}
local peri_import_list = ListBox{parent=sum_c_2,x=1,y=3,height=10,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
TextBox{parent=sum_c_2,y=1,text="The following peripherals will be imported:"}
local peri_import_list = ListBox{parent=sum_c_2,y=3,height=10,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
PushButton{parent=sum_c_2,x=1,y=14,text="\x1b Back",callback=function()sum_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_2,y=14,text="\x1b Back",callback=function()sum_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_2,x=41,y=14,min_width=9,text="Confirm",callback=function()sum_pane.set_value(3)end,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg}
TextBox{parent=sum_c_3,x=1,y=1,text="The following redstone entries will be imported:"}
local rs_import_list = ListBox{parent=sum_c_3,x=1,y=3,height=10,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
TextBox{parent=sum_c_3,y=1,text="The following redstone entries will be imported:"}
local rs_import_list = ListBox{parent=sum_c_3,y=3,height=10,width=49,scroll_height=1000,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
PushButton{parent=sum_c_3,x=1,y=14,text="\x1b Back",callback=function()sum_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_3,y=14,text="\x1b Back",callback=function()sum_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_3,x=43,y=14,min_width=7,text="Apply",callback=save_and_continue,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg}
local function jump_peri_conns()
@@ -520,30 +520,30 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
show_rs_conns()
end
TextBox{parent=sum_c_4,x=1,y=1,text="Settings saved!"}
TextBox{parent=sum_c_4,x=1,y=3,height=4,text="Remember to configure any peripherals or redstone that you have connected to this RTU gateway if you have not already done so, or if you have added, removed, or modified any of them."}
PushButton{parent=sum_c_4,x=1,y=8,min_width=24,text="Peripheral Connections",callback=jump_peri_conns,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_4,x=1,y=10,min_width=22,text="Redstone Connections",callback=jump_rs_conns,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_4,x=1,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=sum_c_4,y=1,text="Settings saved!"}
TextBox{parent=sum_c_4,y=3,height=4,text="Remember to configure any peripherals or redstone that you have connected to this RTU gateway if you have not already done so, or if you have added, removed, or modified any of them."}
PushButton{parent=sum_c_4,y=8,min_width=24,text="Peripheral Connections",callback=jump_peri_conns,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_4,y=10,min_width=22,text="Redstone Connections",callback=jump_rs_conns,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_4,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
PushButton{parent=sum_c_4,x=44,y=14,min_width=6,text="Home",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=sum_c_5,x=1,y=1,height=2,text="The old config.lua file will now be deleted, then the configurator will exit."}
TextBox{parent=sum_c_5,y=1,height=2,text="The old config.lua file will now be deleted, then the configurator will exit."}
local function delete_legacy()
fs.delete("/rtu/config.lua")
exit()
end
PushButton{parent=sum_c_5,x=1,y=14,min_width=8,text="Cancel",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_5,y=14,min_width=8,text="Cancel",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_5,x=44,y=14,min_width=6,text="OK",callback=delete_legacy,fg_bg=cpair(colors.black,colors.green),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=sum_c_6,x=1,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=sum_c_6,x=1,y=14,min_width=6,text="Home",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=sum_c_6,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=sum_c_6,y=14,min_width=6,text="Home",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_6,x=44,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=sum_c_7,x=1,y=1,height=8,text="Warning!\n\nSome of the devices in your old config file aren't currently connected. If the device isn't connected, the options can't be properly validated. Please either connect your devices and try again or complete the import without validation on those entry's settings."}
TextBox{parent=sum_c_7,x=1,y=10,height=3,text="Afterwards, either (a) edit then save entries for currently disconnected devices to properly configure or (b) delete those entries."}
PushButton{parent=sum_c_7,x=1,y=14,text="\x1b Back",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=sum_c_7,y=1,height=8,text="Warning!\n\nSome of the devices in your old config file aren't currently connected. If the device isn't connected, the options can't be properly validated. Please either connect your devices and try again or complete the import without validation on those entry's settings."}
TextBox{parent=sum_c_7,y=10,height=3,text="Afterwards, either (a) edit then save entries for currently disconnected devices to properly configure or (b) delete those entries."}
PushButton{parent=sum_c_7,y=14,text="\x1b Back",callback=function()tool_ctl.go_home()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_7,x=41,y=14,min_width=9,text="Confirm",callback=function()sum_pane.set_value(1)end,fg_bg=cpair(colors.black,colors.orange),active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -639,9 +639,9 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
end
local line = Div{parent=peri_import_list,height=3}
TextBox{parent=line,x=1,y=1,text="@ "..def.name,fg_bg=cpair(colors.black,colors.white)}
TextBox{parent=line,x=1,y=2,text=status,fg_bg=cpair(color,colors.white)}
TextBox{parent=line,x=1,y=3,text=desc,fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=line,y=1,text="@ "..def.name,fg_bg=cpair(colors.black,colors.white)}
TextBox{parent=line,y=2,text=status,fg_bg=cpair(color,colors.white)}
TextBox{parent=line,y=3,text=desc,fg_bg=cpair(colors.gray,colors.white)}
end
rs_import_list.remove_all()
@@ -660,7 +660,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
if def.color ~= nil then conn = def.side .. "/" .. rsio.color_name(def.color) end
local line = Div{parent=rs_import_list,height=1}
TextBox{parent=line,x=1,y=1,width=1,text=io_dir,fg_bg=cpair(colors.lightGray,colors.white)}
TextBox{parent=line,y=1,width=1,text=io_dir,fg_bg=cpair(colors.lightGray,colors.white)}
TextBox{parent=line,x=2,y=1,width=14,text=name}
TextBox{parent=line,x=18,y=1,width=string.len(conn),text=conn,fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=line,x=40,y=1,text=unit,fg_bg=cpair(colors.gray,colors.white)}
@@ -737,7 +737,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
local textbox
if height > 1 then
textbox = TextBox{parent=line,x=1,y=2,text=val,height=height-1}
textbox = TextBox{parent=line,y=2,text=val,height=height-1}
else
textbox = TextBox{parent=line,x=label_w+1,y=1,text=val,alignment=RIGHT}
end
@@ -766,19 +766,19 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
end
if missing.tmp and tmp_cfg.WiredModem then
local line = Div{parent=modem_list,x=1,y=1,height=1}
local line = Div{parent=modem_list,y=1,height=1}
TextBox{parent=line,x=1,y=1,width=4,text="Used",fg_bg=cpair(tri(enable,colors.blue,colors.gray),colors.white)}
TextBox{parent=line,y=1,width=4,text="Used",fg_bg=cpair(tri(enable,colors.blue,colors.gray),colors.white)}
PushButton{parent=line,x=6,y=1,min_width=8,height=1,text="SELECT",callback=function()end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=g_lg_fg_bg}.disable()
TextBox{parent=line,x=15,y=1,text="[missing]",fg_bg=cpair(colors.red,colors.white)}
TextBox{parent=line,x=25,y=1,text=tmp_cfg.WiredModem}
end
if missing.ini and ini_cfg.WiredModem and (tmp_cfg.WiredModem ~= ini_cfg.WiredModem) then
local line = Div{parent=modem_list,x=1,y=1,height=1}
local line = Div{parent=modem_list,y=1,height=1}
local used = tmp_cfg.WiredModem == ini_cfg.WiredModem
TextBox{parent=line,x=1,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
TextBox{parent=line,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
local select_btn = PushButton{parent=line,x=6,y=1,min_width=8,height=1,text="SELECT",callback=function()select(ini_cfg.WiredModem)end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=g_lg_fg_bg}
TextBox{parent=line,x=15,y=1,text="[missing]",fg_bg=cpair(colors.red,colors.white)}
TextBox{parent=line,x=25,y=1,text=ini_cfg.WiredModem}
@@ -788,10 +788,10 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, ext, style)
-- list wired modems
for iface, _ in pairs(modems) do
local line = Div{parent=modem_list,x=1,y=1,height=1}
local line = Div{parent=modem_list,y=1,height=1}
local used = tmp_cfg.WiredModem == iface
TextBox{parent=line,x=1,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
TextBox{parent=line,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
local select_btn = PushButton{parent=line,x=6,y=1,min_width=8,height=1,text="SELECT",callback=function()select(iface)end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=g_lg_fg_bg}
TextBox{parent=line,x=15,y=1,text=iface}

View File

@@ -173,20 +173,20 @@ local function config_view(display)
TextBox{parent=display,y=1,text="RTU Gateway Configurator",alignment=CENTER,fg_bg=style.header}
local root_pane_div = Div{parent=display,x=1,y=2}
local root_pane_div = Div{parent=display,y=2}
local main_page = Div{parent=root_pane_div,x=1,y=1}
local spkr_cfg = Div{parent=root_pane_div,x=1,y=1}
local net_cfg = Div{parent=root_pane_div,x=1,y=1}
local log_cfg = Div{parent=root_pane_div,x=1,y=1}
local clr_cfg = Div{parent=root_pane_div,x=1,y=1}
local summary = Div{parent=root_pane_div,x=1,y=1}
local changelog = Div{parent=root_pane_div,x=1,y=1}
local peri_cfg = Div{parent=root_pane_div,x=1,y=1}
local rs_cfg = Div{parent=root_pane_div,x=1,y=1}
local check_sys = Div{parent=root_pane_div,x=1,y=1}
local main_page = Div{parent=root_pane_div,y=1}
local spkr_cfg = Div{parent=root_pane_div,y=1}
local net_cfg = Div{parent=root_pane_div,y=1}
local log_cfg = Div{parent=root_pane_div,y=1}
local clr_cfg = Div{parent=root_pane_div,y=1}
local summary = Div{parent=root_pane_div,y=1}
local changelog = Div{parent=root_pane_div,y=1}
local peri_cfg = Div{parent=root_pane_div,y=1}
local rs_cfg = Div{parent=root_pane_div,y=1}
local check_sys = Div{parent=root_pane_div,y=1}
local main_pane = MultiPane{parent=root_pane_div,x=1,y=1,panes={main_page,spkr_cfg,net_cfg,log_cfg,clr_cfg,summary,changelog,peri_cfg,rs_cfg,check_sys}}
local main_pane = MultiPane{parent=root_pane_div,y=1,panes={main_page,spkr_cfg,net_cfg,log_cfg,clr_cfg,summary,changelog,peri_cfg,rs_cfg,check_sys}}
--#region Main Page
@@ -283,20 +283,20 @@ local function config_view(display)
local cl = Div{parent=changelog,x=2,y=4,width=49}
TextBox{parent=changelog,x=1,y=2,text=" Config Change Log",fg_bg=bw_fg_bg}
TextBox{parent=changelog,y=2,text=" Config Change Log",fg_bg=bw_fg_bg}
local c_log = ListBox{parent=cl,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local c_log = ListBox{parent=cl,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
for _, change in ipairs(changes) do
TextBox{parent=c_log,text=change[1],fg_bg=bw_fg_bg}
for _, v in ipairs(change[2]) do
local e = Div{parent=c_log,height=#util.strwrap(v,46)}
TextBox{parent=e,y=1,x=1,text="- ",fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=e,y=1,text="- ",fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=e,y=1,x=3,text=v,height=e.get_height(),fg_bg=cpair(colors.gray,colors.white)}
end
end
PushButton{parent=cl,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=cl,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion

View File

@@ -173,7 +173,7 @@ local function init(panel, config, units)
-- show routine statuses
for i = 1, list_length do
TextBox{parent=threads,x=1,y=i,text=util.sprintf("%02d",i)}
TextBox{parent=threads,y=i,text=util.sprintf("%02d",i)}
local rt_unit = LED{parent=threads,x=4,y=i,label="RT",colors=util.trinary(units[i].type~=RTU_UNIT_TYPE.REDSTONE,ind_grn,cpair(style.ind_bkg,style.ind_bkg))}
rt_unit.register(databus.ps, "routine__unit_" .. i, rt_unit.update)
end

View File

@@ -409,8 +409,8 @@ function rtu.comms(version, backplane, conn_watchdog)
---@param rtu_state rtu_state
function public.close(rtu_state)
conn_watchdog.cancel()
public.unlink(rtu_state)
_send(MGMT_TYPE.CLOSE, {})
public.unlink(rtu_state)
end
-- send a MODBUS TCP packet

View File

@@ -21,7 +21,7 @@ local rtu = require("rtu.rtu")
local threads = require("rtu.threads")
local uinit = require("rtu.uinit")
local RTU_VERSION = "v1.13.7"
local RTU_VERSION = "v1.13.11"
local println = util.println
local println_ts = util.println_ts

View File

@@ -197,6 +197,41 @@ function threads.thread__main(smem)
local sounders = backplane.sounders()
-- main loop periodic tasks
local function loop_tick()
-- blink heartbeat indicator
databus.heartbeat()
-- periodic hardware tasks
backplane.periodic()
-- update speaker states
for _, sounder in pairs(sounders) do
-- re-compute output if needed, then play audio if available
if sounder.stream.is_recompute_needed() then
sounder.stream.compute_buffer()
if sounder.stream.any_active() then sounder.play() else sounder.stop() end
end
end
-- period tick, if we are not linked send establish request
if rtu_state.linked then
rtu_comms.manage_failover(backplane.active_nic())
else
-- advertise units
local a_nic, s_nic = backplane.active_nic(), backplane.standby_nic()
if a_nic.is_network_up() then
rtu_comms.send_establish(a_nic, units)
elseif s_nic and s_nic.is_network_up() then
rtu_comms.send_establish(s_nic, units)
end
end
-- start next clock timer
loop_clock.start()
end
-- start unlinked (in case of restart)
rtu_comms.unlink(rtu_state)
@@ -207,51 +242,52 @@ function threads.thread__main(smem)
while true do
local event, param1, param2, param3, param4, param5 = util.pull_event()
if event == "timer" and loop_clock.is_clock(param1) then
-- blink heartbeat indicator
databus.heartbeat()
-- periodic hardware tasks
backplane.periodic()
-- update speaker states
for _, sounder in pairs(sounders) do
-- re-compute output if needed, then play audio if available
if sounder.stream.is_recompute_needed() then
sounder.stream.compute_buffer()
if sounder.stream.any_active() then sounder.play() else sounder.stop() end
end
end
-- period tick, if we are not linked send establish request
if rtu_state.linked then
rtu_comms.manage_failover(backplane.active_nic())
else
-- advertise units
local a_nic, s_nic = backplane.active_nic(), backplane.standby_nic()
if a_nic.is_network_up() then
rtu_comms.send_establish(a_nic, units)
elseif s_nic and s_nic.is_network_up() then
rtu_comms.send_establish(s_nic, units)
end
end
-- start next clock timer
loop_clock.start()
elseif event == "modem_message" then
if event == "modem_message" then
-- got a packet
local packet = rtu_comms.parse_packet(param1, param2, param3, param4, param5)
if packet ~= nil then
-- pass the packet onto the comms message queue
smem.q.mq_comms.push_network(packet)
end
elseif event == "timer" and conn_watchdog.is_timer(param1) then
-- haven't heard from server recently? close connection
rtu_comms.close(rtu_state)
elseif event == "timer" then
-- notify timer callback dispatcher if no other timer case claimed this event
tcd.handle(param1)
-- pass this timer event onto the right handler
if loop_clock.is_clock(param1) then
-- main loop tick
loop_tick()
elseif conn_watchdog.is_timer(param1) then
-- supervisor connection timed out
rtu_comms.close(rtu_state)
else
-- notify timer callback dispatcher, no other handler claimed this event
tcd.handle(param1)
end
elseif event == "speaker_audio_empty" then
-- handle empty speaker audio buffer
for i = 1, #sounders do
local sounder = sounders[i]
if sounder.name == param1 then
sounder.continue()
break
end
end
elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" or
event == "double_click" then
-- handle a mouse event
renderer.handle_mouse(core.events.new_mouse_event(event, param1, param2, param3))
elseif event == "peripheral" then
-- peripheral connect
local type, device = ppm.mount(param1)
if type ~= nil and device ~= nil then
if type == "modem" or type == "speaker" then
backplane.attach(type, device, param1, println_ts)
else
-- relink lost peripheral to correct unit entry
for i = 1, #units do
handle_unit_mount(smem, println_ts, param1, type, device, units[i])
end
end
end
elseif event == "peripheral_detach" then
-- handle loss of a device
local type, device = ppm.handle_unmount(param1)
@@ -277,33 +313,6 @@ function threads.thread__main(smem)
end
end
end
elseif event == "peripheral" then
-- peripheral connect
local type, device = ppm.mount(param1)
if type ~= nil and device ~= nil then
if type == "modem" or type == "speaker" then
backplane.attach(type, device, param1, println_ts)
else
-- relink lost peripheral to correct unit entry
for i = 1, #units do
handle_unit_mount(smem, println_ts, param1, type, device, units[i])
end
end
end
elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" or
event == "double_click" then
-- handle a mouse event
renderer.handle_mouse(core.events.new_mouse_event(event, param1, param2, param3))
elseif event == "speaker_audio_empty" then
-- handle empty speaker audio buffer
for i = 1, #sounders do
local sounder = sounders[i]
if sounder.name == param1 then
sounder.continue()
break
end
end
end
-- check for termination request

View File

@@ -72,7 +72,7 @@ local rs = {}
rs.IMATRIX_CHARGE_LOW = 0.05 -- activation threshold (less than) for F_MATRIX_LOW
rs.IMATRIX_CHARGE_HIGH = 0.95 -- activation threshold (greater than) for F_MATRIX_HIGH
rs.AUX_COOL_ENABLE = 0.60 -- actiation threshold (less than or equal) for U_AUX_COOL
rs.AUX_COOL_ENABLE = 0.85 -- actiation threshold (less than or equal) for U_AUX_COOL
rs.AUX_COOL_DISABLE = 1.00 -- deactivation threshold (greater than or equal) for U_AUX_COOL
constants.RS_THRESHOLDS = rs

View File

@@ -210,6 +210,8 @@ end
---@alias color integer
---@alias auto_ctl_cfg [ PROCESS, number, integer, integer, number, number, number[] ]
--#region ENUMERATION TYPES
---@enum LISTEN_MODE
@@ -392,9 +394,10 @@ types.PROCESS = {
BURN_RATE = 2,
CHARGE = 3,
GEN_RATE = 4,
MATRIX_FAULT_IDLE = 5,
SYSTEM_ALARM_IDLE = 6,
GEN_RATE_FAULT_IDLE = 7
RANGE_CONTROL = 5,
MATRIX_FAULT_IDLE = 6,
SYSTEM_ALARM_IDLE = 7,
GEN_RATE_FAULT_IDLE = 8
}
types.PROCESS_NAMES = {
@@ -403,6 +406,7 @@ types.PROCESS_NAMES = {
"BURN_RATE",
"CHARGE",
"GEN_RATE",
"RANGE_CONTROL",
"MATRIX_FAULT_IDLE",
"SYSTEM_ALARM_IDLE",
"GEN_RATE_FAULT_IDLE"

View File

@@ -24,7 +24,7 @@ local t_pack = table.pack
local util = {}
-- scada-common version
util.version = "1.8.1"
util.version = "1.8.2"
util.TICK_TIME_S = 0.05
util.TICK_TIME_MS = 50
@@ -199,7 +199,7 @@ function util.sign(x) return util.trinary(x < 0, -1, 1) end
---@return integer rounded
function util.round(x) return math.floor(x + 0.5) end
-- get a new moving average object
-- get a new moving average object (FIR filter)
---@nodiscard
---@param length integer history length
function util.mov_avg(length)

View File

@@ -185,16 +185,16 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
local fac_c_8 = Div{parent=fac_cfg,x=2,y=4,width=49}
local fac_c_9 = Div{parent=fac_cfg,x=2,y=4,width=49}
local fac_pane = MultiPane{parent=fac_cfg,x=1,y=4,panes={fac_c_1,fac_c_2,fac_c_3,fac_c_4,fac_c_5,fac_c_6,fac_c_7,fac_c_8,fac_c_9}}
local fac_pane = MultiPane{parent=fac_cfg,y=4,panes={fac_c_1,fac_c_2,fac_c_3,fac_c_4,fac_c_5,fac_c_6,fac_c_7,fac_c_8,fac_c_9}}
TextBox{parent=fac_cfg,x=1,y=2,text=" Facility Configuration",fg_bg=cpair(colors.black,colors.yellow)}
TextBox{parent=fac_cfg,y=2,text=" Facility Configuration",fg_bg=cpair(colors.black,colors.yellow)}
--#region Unit Count
TextBox{parent=fac_c_1,x=1,y=1,height=3,text="Please enter the number of reactors you have, also referred to as reactor units or 'units' for short. A maximum of 4 is currently supported."}
tool_ctl.num_units = NumberField{parent=fac_c_1,x=1,y=5,width=5,max_chars=2,default=ini_cfg.UnitCount,min=1,max=4,fg_bg=bw_fg_bg}
TextBox{parent=fac_c_1,y=1,height=3,text="Please enter the number of reactors you have, also referred to as reactor units or 'units' for short. A maximum of 4 is currently supported."}
tool_ctl.num_units = NumberField{parent=fac_c_1,y=5,width=5,max_chars=2,default=ini_cfg.UnitCount,min=1,max=4,fg_bg=bw_fg_bg}
TextBox{parent=fac_c_1,x=7,y=5,text="reactors"}
TextBox{parent=fac_c_1,x=1,y=7,height=3,text="If you already configured your coordinator, make sure you update the coordinator's configured unit count.",fg_bg=cpair(colors.yellow,colors._INHERIT)}
TextBox{parent=fac_c_1,y=7,height=3,text="If you already configured your coordinator, make sure you update the coordinator's configured unit count.",fg_bg=cpair(colors.yellow,colors._INHERIT)}
local nu_error = TextBox{parent=fac_c_1,x=8,y=14,width=35,text="Please set the number of reactors.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -221,14 +221,14 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
else nu_error.show() end
end
PushButton{parent=fac_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_1,x=44,y=14,text="Next \x1a",callback=submit_num_units,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
--#region Cooling Configuration
TextBox{parent=fac_c_2,x=1,y=1,height=4,text="Please provide the reactor cooling configuration below. This includes the number of turbines, boilers, and if that reactor has a connection to a dynamic tank for emergency coolant."}
TextBox{parent=fac_c_2,x=1,y=6,text="UNIT TURBINES BOILERS HAS TANK CONNECTION?",fg_bg=g_lg_fg_bg}
TextBox{parent=fac_c_2,y=1,height=4,text="Please provide the reactor cooling configuration below. This includes the number of turbines, boilers, and if that reactor has a connection to a dynamic tank for emergency coolant."}
TextBox{parent=fac_c_2,y=6,text="UNIT TURBINES BOILERS HAS TANK CONNECTION?",fg_bg=g_lg_fg_bg}
for i = 1, 4 do
local num_t, num_b, has_t = 1, 0, false
@@ -240,7 +240,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
has_t = conf.TankConnection == true
end
local line = Div{parent=fac_c_2,x=1,y=7+i,height=1}
local line = Div{parent=fac_c_2,y=7+i,height=1}
TextBox{parent=line,text="Unit "..i,width=6}
local turbines = NumberField{parent=line,x=9,y=1,width=5,max_chars=2,default=num_t,min=1,max=3,fg_bg=bw_fg_bg}
@@ -304,16 +304,16 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
end
end
PushButton{parent=fac_c_2,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_2,y=14,text="\x1b Back",callback=function()fac_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_2,x=44,y=14,text="Next \x1a",callback=submit_cooling,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
--#region Facility Tanks Option
TextBox{parent=fac_c_3,x=1,y=1,height=6,text="You have set one or more of your units to use dynamic tanks for emergency coolant. You have two paths for configuration. The first is to assign dynamic tanks to reactor units; one tank per reactor, only connected to that reactor. RTU configurations must also assign it as such."}
TextBox{parent=fac_c_3,x=1,y=8,height=3,text="Alternatively, you can configure them as facility tanks to connect to multiple reactor units. These can intermingle with unit-specific tanks."}
TextBox{parent=fac_c_3,y=1,height=6,text="You have set one or more of your units to use dynamic tanks for emergency coolant. You have two paths for configuration. The first is to assign dynamic tanks to reactor units; one tank per reactor, only connected to that reactor. RTU configurations must also assign it as such."}
TextBox{parent=fac_c_3,y=8,height=3,text="Alternatively, you can configure them as facility tanks to connect to multiple reactor units. These can intermingle with unit-specific tanks."}
tool_ctl.en_fac_tanks = Checkbox{parent=fac_c_3,x=1,y=12,label="Use Facility Dynamic Tanks",default=ini_cfg.FacilityTankMode>0,box_fg_bg=cpair(colors.yellow,colors.black)}
tool_ctl.en_fac_tanks = Checkbox{parent=fac_c_3,y=12,label="Use Facility Dynamic Tanks",default=ini_cfg.FacilityTankMode>0,box_fg_bg=cpair(colors.yellow,colors.black)}
local function submit_en_fac_tank()
if tool_ctl.en_fac_tanks.get_value() then
@@ -336,19 +336,19 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
end
end
PushButton{parent=fac_c_3,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_3,y=14,text="\x1b Back",callback=function()fac_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_3,x=44,y=14,text="Next \x1a",callback=submit_en_fac_tank,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
--#region Facility Tank Connections
TextBox{parent=fac_c_4,x=1,y=1,height=4,text="Please set unit connections to dynamic tanks, selecting at least one facility tank. The layout for facility tanks will be configured next."}
TextBox{parent=fac_c_4,y=1,height=4,text="Please set unit connections to dynamic tanks, selecting at least one facility tank. The layout for facility tanks will be configured next."}
for i = 1, 4 do
local val = math.max(1, ini_cfg.FacilityTankDefs[i] or 2)
local div = Div{parent=fac_c_4,x=1,y=3+(2*i),height=2}
local div = Div{parent=fac_c_4,y=3+(2*i),height=2}
TextBox{parent=div,x=1,y=1,width=33,text="Unit "..i.." will be connected to..."}
TextBox{parent=div,y=1,width=33,text="Unit "..i.." will be connected to..."}
TextBox{parent=div,x=6,y=2,width=3,text="..."}
local tank_opt = Radio2D{parent=div,x=9,y=2,rows=1,columns=2,default=val,options={"its own Unit Tank","a Facility Tank"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.yellow,disable_color=colors.gray,disable_fg_bg=g_lg_fg_bg}
local no_tank = TextBox{parent=div,x=9,y=2,width=34,text="no tank (as you set two steps ago)",fg_bg=cpair(colors.gray,colors.lightGray),hidden=true}
@@ -402,13 +402,13 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
else tank_err.show() end
end
PushButton{parent=fac_c_4,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_4,y=14,text="\x1b Back",callback=function()fac_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_4,x=44,y=14,text="Next \x1a",callback=submit_tank_defs,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
--#region Facility Tank Mode
TextBox{parent=fac_c_5,x=1,y=1,text="Please select your dynamic tank layout."}
TextBox{parent=fac_c_5,y=1,text="Please select your dynamic tank layout."}
TextBox{parent=fac_c_5,x=12,y=3,text="Facility Tanks Unit Tanks",fg_bg=g_lg_fg_bg}
--#region Tank Layout Visualizer
@@ -429,18 +429,18 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
-- draw facility tank connections
local ftank_1 = Div{parent=vis,x=1,y=1,width=13,height=1}
local ftank_1 = Div{parent=vis,y=1,width=13,height=1}
TextBox{parent=ftank_1,width=7,text="Tank F1"}
self.vis_ftanks[1] = {
line = ftank_1, pipe_direct = TextBox{parent=ftank_1,x=9,y=1,width=5,text=string.rep("\x8c",5),fg_bg=pipe_cpair}
}
for i = 2, 4 do
local line = Div{parent=vis,x=1,y=(i-1)*2,width=13,height=2}
local line = Div{parent=vis,y=(i-1)*2,width=13,height=2}
local pipe_conn = TextBox{parent=line,x=13,y=2,width=1,text="\x8c",fg_bg=pipe_cpair}
local pipe_chain = TextBox{parent=line,x=12,y=1,width=1,height=2,text="\x95\n\x8d",fg_bg=pipe_cpair}
local pipe_direct = TextBox{parent=line,x=9,y=2,width=4,text="\x8c\x8c\x8c\x8c",fg_bg=pipe_cpair}
local label = TextBox{parent=line,x=1,y=2,width=7,text=""}
local label = TextBox{parent=line,y=2,width=7,text=""}
self.vis_ftanks[i] = { line = line, pipe_conn = pipe_conn, pipe_chain = pipe_chain, pipe_direct = pipe_direct, label = label }
end
@@ -572,7 +572,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
end
local tank_modes = { "Mode 1", "Mode 2", "Mode 3", "Mode 4", "Mode 5", "Mode 6", "Mode 7", "Mode 8" }
tool_ctl.tank_mode = RadioButton{parent=fac_c_5,x=1,y=4,callback=change_mode,default=math.max(1,ini_cfg.FacilityTankMode),options=tank_modes,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.yellow}
tool_ctl.tank_mode = RadioButton{parent=fac_c_5,y=4,callback=change_mode,default=math.max(1,ini_cfg.FacilityTankMode),options=tank_modes,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.yellow}
--#endregion
@@ -585,7 +585,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
fac_pane.set_value(7)
end
PushButton{parent=fac_c_5,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_5,y=14,text="\x1b Back",callback=function()fac_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_5,x=44,y=14,text="Next \x1a",callback=next_from_tank_mode,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_5,x=8,y=14,min_width=7,text="About",callback=function()fac_pane.set_value(6)end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg}
@@ -597,14 +597,14 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
TextBox{parent=fac_c_6,y=5,height=4,text="Examples: A U2 tank should be configured on an RTU as the dynamic tank for unit #2. An F3 tank should be configured on an RTU as the #3 dynamic tank for the facility."}
TextBox{parent=fac_c_6,y=10,height=3,text="Some modes may look the same if you are not using 4 total reactor units. The wiki has details. Modes that look the same will function the same.",fg_bg=g_lg_fg_bg}
PushButton{parent=fac_c_6,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(5)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_6,y=14,text="\x1b Back",callback=function()fac_pane.set_value(5)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
--#region Dynamic Tank Fluid Types
TextBox{parent=fac_c_7,height=3,text="Specify each tank's coolant type, for display use only. Water is the only option if one or more of the connected units is water cooled."}
local tank_fluid_list = Div{parent=fac_c_7,x=1,y=5,height=8}
local tank_fluid_list = Div{parent=fac_c_7,y=5,height=8}
function self.draw_fluid_ops()
tank_fluid_list.remove_all()
@@ -682,7 +682,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
fac_pane.set_value(8)
end
PushButton{parent=fac_c_7,x=1,y=14,text="\x1b Back",callback=back_from_fluids,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_7,y=14,text="\x1b Back",callback=back_from_fluids,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_7,x=44,y=14,text="Next \x1a",callback=submit_tank_fluids,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -691,7 +691,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
TextBox{parent=fac_c_8,height=5,text="Auxiliary water coolant can be enabled for units to provide extra water during turbine ramp-up. For water cooled reactors, this goes to the reactor. For sodium cooled reactors, water goes to the boiler."}
for i = 1, 4 do
local line = Div{parent=fac_c_8,x=1,y=7+i,height=1}
local line = Div{parent=fac_c_8,y=7+i,height=1}
TextBox{parent=line,text="Unit "..i.." -",width=8}
local aux_cool = Checkbox{parent=line,x=10,y=1,label="Has Auxiliary Coolant",default=ini_cfg.AuxiliaryCoolant[i],box_fg_bg=cpair(colors.yellow,colors.black)}
@@ -709,7 +709,7 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
fac_pane.set_value(9)
end
PushButton{parent=fac_c_8,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(7)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_8,y=14,text="\x1b Back",callback=function()fac_pane.set_value(7)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_8,x=44,y=14,text="Next \x1a",callback=submit_aux_cool,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -718,14 +718,14 @@ function facility.create(tool_ctl, main_pane, cfg_sys, fac_cfg, style)
TextBox{parent=fac_c_9,height=6,text="Charge control provides automatic control to maintain an induction matrix charge level. In order to have smoother control, reactors that were activated will be held on at 0.01 mB/t for a short period before allowing them to turn off. This minimizes overshooting the charge target."}
TextBox{parent=fac_c_9,y=8,height=3,text="You can extend this to a full minute to minimize reactors flickering on/off, but there may be more overshoot of the target."}
local ext_idling = Checkbox{parent=fac_c_9,x=1,y=12,label="Enable Extended Idling",default=ini_cfg.ExtChargeIdling,box_fg_bg=cpair(colors.yellow,colors.black)}
local ext_idling = Checkbox{parent=fac_c_9,y=12,label="Enable Extended Idling",default=ini_cfg.ExtChargeIdling,box_fg_bg=cpair(colors.yellow,colors.black)}
local function submit_idling()
tmp_cfg.ExtChargeIdling = ext_idling.get_value()
main_pane.set_value(3)
end
PushButton{parent=fac_c_9,x=1,y=14,text="\x1b Back",callback=function()fac_pane.set_value(8)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_9,y=14,text="\x1b Back",callback=function()fac_pane.set_value(8)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=fac_c_9,x=44,y=14,text="Next \x1a",callback=submit_idling,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion

View File

@@ -75,21 +75,21 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
local net_c_5 = Div{parent=net_cfg,x=2,y=4,width=49}
local net_c_6 = Div{parent=net_cfg,x=2,y=4,width=49}
local net_pane = MultiPane{parent=net_cfg,x=1,y=4,panes={net_c_1,net_c_2,net_c_3,net_c_4,net_c_5,net_c_6}}
local net_pane = MultiPane{parent=net_cfg,y=4,panes={net_c_1,net_c_2,net_c_3,net_c_4,net_c_5,net_c_6}}
TextBox{parent=net_cfg,x=1,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)}
TextBox{parent=net_cfg,y=2,text=" Network Configuration",fg_bg=cpair(colors.black,colors.lightBlue)}
TextBox{parent=net_c_1,x=1,y=1,text="Please select the network interface(s)."}
TextBox{parent=net_c_1,y=1,text="Please select the network interface(s)."}
TextBox{parent=net_c_1,x=41,y=1,text="new!",fg_bg=cpair(colors.red,colors._INHERIT)} ---@todo remove NEW tag on next revision
local function on_wired_change(_) tool_ctl.gen_modem_list() end
local wireless = Checkbox{parent=net_c_1,x=1,y=3,label="Wireless/Ender Modem",default=ini_cfg.WirelessModem,box_fg_bg=cpair(colors.lightBlue,colors.black)}
local wireless = Checkbox{parent=net_c_1,y=3,label="Wireless/Ender Modem",default=ini_cfg.WirelessModem,box_fg_bg=cpair(colors.lightBlue,colors.black)}
TextBox{parent=net_c_1,x=24,y=3,text="(required for Pocket)",fg_bg=g_lg_fg_bg}
local wired = Checkbox{parent=net_c_1,x=1,y=5,label="Wired Modem",default=ini_cfg.WiredModem~=false,box_fg_bg=cpair(colors.lightBlue,colors.black),callback=on_wired_change}
local wired = Checkbox{parent=net_c_1,y=5,label="Wired Modem",default=ini_cfg.WiredModem~=false,box_fg_bg=cpair(colors.lightBlue,colors.black),callback=on_wired_change}
TextBox{parent=net_c_1,x=3,y=6,text="this one MUST ONLY connect to SCADA computers",fg_bg=cpair(colors.red,colors._INHERIT)}
TextBox{parent=net_c_1,x=3,y=7,text="connecting it to peripherals will cause issues",fg_bg=g_lg_fg_bg}
local modem_list = ListBox{parent=net_c_1,x=1,y=8,height=5,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local modem_list = ListBox{parent=net_c_1,y=8,height=5,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local modem_err = TextBox{parent=net_c_1,x=8,y=14,width=35,text="",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -114,12 +114,12 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
end
end
PushButton{parent=net_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_1,y=14,text="\x1b Back",callback=function()main_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_1,x=44,y=14,text="Next \x1a",callback=submit_interfaces,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_2,x=1,y=1,text="Please assign device connection interfaces if you selected multiple network interfaces."}
TextBox{parent=net_c_2,y=1,text="Please assign device connection interfaces if you selected multiple network interfaces."}
TextBox{parent=net_c_2,x=39,y=2,text="new!",fg_bg=cpair(colors.red,colors._INHERIT)} ---@todo remove NEW tag on next revision
TextBox{parent=net_c_2,x=1,y=4,text="Reactor PLC\nRTU Gateway\nCoordinator",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_2,y=4,text="Reactor PLC\nRTU Gateway\nCoordinator",fg_bg=g_lg_fg_bg}
local opts = { "Wireless", "Wired", "Both" }
local plc_listen = Radio2D{parent=net_c_2,x=14,y=4,rows=1,columns=3,default=ini_cfg.PLC_Listen,options=opts,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.lightBlue,disable_color=colors.gray,disable_fg_bg=g_lg_fg_bg}
local rtu_listen = Radio2D{parent=net_c_2,x=14,rows=1,columns=3,default=ini_cfg.RTU_Listen,options=opts,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.lightBlue,disable_color=colors.gray,disable_fg_bg=g_lg_fg_bg}
@@ -175,29 +175,29 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
net_pane.set_value(3)
end
PushButton{parent=net_c_2,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_2,y=14,text="\x1b Back",callback=function()net_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_2,x=44,y=14,text="Next \x1a",callback=submit_net_cfg_opts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_3,x=1,y=1,text="Please set the network channels below."}
TextBox{parent=net_c_3,x=1,y=3,height=4,text="Each of the 5 uniquely named channels must be the same for each device in this SCADA network. For multiplayer servers, it is recommended to not use the default channels.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,y=1,text="Please set the network channels below."}
TextBox{parent=net_c_3,y=3,height=4,text="Each of the 5 uniquely named channels must be the same for each device in this SCADA network. For multiplayer servers, it is recommended to not use the default channels.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,x=1,y=8,width=18,text="Supervisor Channel"}
TextBox{parent=net_c_3,y=8,width=18,text="Supervisor Channel"}
local svr_chan = NumberField{parent=net_c_3,x=21,y=8,width=7,default=ini_cfg.SVR_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_3,x=29,y=8,height=4,text="[SVR_CHANNEL]",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,x=1,y=9,width=11,text="PLC Channel"}
TextBox{parent=net_c_3,y=9,width=11,text="PLC Channel"}
local plc_chan = NumberField{parent=net_c_3,x=21,y=9,width=7,default=ini_cfg.PLC_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_3,x=29,y=9,height=4,text="[PLC_CHANNEL]",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,x=1,y=10,width=19,text="RTU Gateway Channel"}
TextBox{parent=net_c_3,y=10,width=19,text="RTU Gateway Channel"}
local rtu_chan = NumberField{parent=net_c_3,x=21,y=10,width=7,default=ini_cfg.RTU_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_3,x=29,y=10,height=4,text="[RTU_CHANNEL]",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,x=1,y=11,width=19,text="Coordinator Channel"}
TextBox{parent=net_c_3,y=11,width=19,text="Coordinator Channel"}
local crd_chan = NumberField{parent=net_c_3,x=21,y=11,width=7,default=ini_cfg.CRD_Channel,min=1,max=65535,fg_bg=bw_fg_bg}
TextBox{parent=net_c_3,x=29,y=11,height=4,text="[CRD_CHANNEL]",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_3,x=1,y=12,width=14,text="Pocket Channel"}
TextBox{parent=net_c_3,y=12,width=14,text="Pocket Channel"}
self.pkt_chan = NumberField{parent=net_c_3,x=21,y=12,width=7,default=ini_cfg.PKT_Channel,min=1,max=65535,fg_bg=bw_fg_bg,dis_fg_bg=cpair(colors.lightGray,colors.white)}
TextBox{parent=net_c_3,x=29,y=12,height=4,text="[PKT_CHANNEL]",fg_bg=g_lg_fg_bg}
@@ -217,22 +217,22 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
else chan_err.show() end
end
PushButton{parent=net_c_3,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_3,y=14,text="\x1b Back",callback=function()net_pane.set_value(2)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_3,x=44,y=14,text="Next \x1a",callback=submit_channels,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_4,x=1,y=1,text="Please set the connection timeouts below."}
TextBox{parent=net_c_4,x=1,y=3,height=4,text="You generally should not need to modify these. On slow servers, you can try to increase this to make the system wait longer before assuming a disconnection. The default for all is 5 seconds.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_4,y=1,text="Please set the connection timeouts below."}
TextBox{parent=net_c_4,y=3,height=4,text="You generally should not need to modify these. On slow servers, you can try to increase this to make the system wait longer before assuming a disconnection. The default for all is 5 seconds.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_4,x=1,y=8,width=11,text="PLC Timeout"}
TextBox{parent=net_c_4,y=8,width=11,text="PLC Timeout"}
local plc_timeout = NumberField{parent=net_c_4,x=21,y=8,width=7,default=ini_cfg.PLC_Timeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg}
TextBox{parent=net_c_4,x=1,y=9,width=19,text="RTU Gateway Timeout"}
TextBox{parent=net_c_4,y=9,width=19,text="RTU Gateway Timeout"}
local rtu_timeout = NumberField{parent=net_c_4,x=21,y=9,width=7,default=ini_cfg.RTU_Timeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg}
TextBox{parent=net_c_4,x=1,y=10,width=19,text="Coordinator Timeout"}
TextBox{parent=net_c_4,y=10,width=19,text="Coordinator Timeout"}
local crd_timeout = NumberField{parent=net_c_4,x=21,y=10,width=7,default=ini_cfg.CRD_Timeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg}
TextBox{parent=net_c_4,x=1,y=11,width=14,text="Pocket Timeout"}
TextBox{parent=net_c_4,y=11,width=14,text="Pocket Timeout"}
self.pkt_timeout = NumberField{parent=net_c_4,x=21,y=11,width=7,default=ini_cfg.PKT_Timeout,min=2,max=25,max_chars=6,max_frac_digits=2,allow_decimal=true,fg_bg=bw_fg_bg,dis_fg_bg=cpair(colors.lightGray,colors.white)}
TextBox{parent=net_c_4,x=29,y=8,height=4,width=7,text="seconds\nseconds\nseconds\nseconds",fg_bg=g_lg_fg_bg}
@@ -259,14 +259,14 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
else ct_err.show() end
end
PushButton{parent=net_c_4,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_4,y=14,text="\x1b Back",callback=function()net_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_4,x=44,y=14,text="Next \x1a",callback=submit_timeouts,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_5,x=1,y=1,text="Please set the wireless trusted range below."}
TextBox{parent=net_c_5,x=1,y=3,height=3,text="Setting this to a value larger than 0 prevents wireless connections with devices that many meters (blocks) away in any direction.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_5,x=1,y=7,height=2,text="This is optional. You can disable this functionality by setting the value to 0.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_5,y=1,text="Please set the wireless trusted range below."}
TextBox{parent=net_c_5,y=3,height=3,text="Setting this to a value larger than 0 prevents wireless connections with devices that many meters (blocks) away in any direction.",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_5,y=7,height=2,text="This is optional. You can disable this functionality by setting the value to 0.",fg_bg=g_lg_fg_bg}
local range = NumberField{parent=net_c_5,x=1,y=10,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg}
local range = NumberField{parent=net_c_5,y=10,width=10,default=ini_cfg.TrustedRange,min=0,max_chars=20,allow_decimal=true,fg_bg=bw_fg_bg}
local tr_err = TextBox{parent=net_c_5,x=8,y=14,width=35,text="Please set the trusted range.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -279,14 +279,14 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
else tr_err.show() end
end
PushButton{parent=net_c_5,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_5,y=14,text="\x1b Back",callback=function()net_pane.set_value(4)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_5,x=44,y=14,text="Next \x1a",callback=submit_tr,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=net_c_6,x=1,y=1,height=2,text="Optionally, set the facility authentication key below. Do NOT use one of your passwords."}
TextBox{parent=net_c_6,x=1,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for wireless security on multiplayer servers. All devices on the same wireless network MUST use the same key if any device has a key. This does result in some extra computation (can slow things down).",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_6,y=1,height=2,text="Optionally, set the facility authentication key below. Do NOT use one of your passwords."}
TextBox{parent=net_c_6,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for wireless security on multiplayer servers. All devices on the same wireless network MUST use the same key if any device has a key. This does result in some extra computation (can slow things down).",fg_bg=g_lg_fg_bg}
TextBox{parent=net_c_6,x=1,y=11,text="Auth Key (Wireless Only, Not Used for Wired)"}
local key, _ = TextField{parent=net_c_6,x=1,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg}
TextBox{parent=net_c_6,y=11,text="Auth Key (Wireless Only, Not Used for Wired)"}
local key, _ = TextField{parent=net_c_6,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg}
local function censor_key(enable) key.censor(tri(enable, "*", nil)) end
@@ -306,7 +306,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
else key_err.show() end
end
PushButton{parent=net_c_6,x=1,y=14,text="\x1b Back",callback=function()net_pane.set_value(5)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_6,y=14,text="\x1b Back",callback=function()net_pane.set_value(5)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=net_c_6,x=44,y=14,text="Next \x1a",callback=submit_auth,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -315,17 +315,17 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
local log_c_1 = Div{parent=log_cfg,x=2,y=4,width=49}
TextBox{parent=log_cfg,x=1,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)}
TextBox{parent=log_cfg,y=2,text=" Logging Configuration",fg_bg=cpair(colors.black,colors.pink)}
TextBox{parent=log_c_1,x=1,y=1,text="Please configure logging below."}
TextBox{parent=log_c_1,y=1,text="Please configure logging below."}
TextBox{parent=log_c_1,x=1,y=3,text="Log File Mode"}
local mode = RadioButton{parent=log_c_1,x=1,y=4,default=ini_cfg.LogMode+1,options={"Append on Startup","Replace on Startup"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.pink}
TextBox{parent=log_c_1,y=3,text="Log File Mode"}
local mode = RadioButton{parent=log_c_1,y=4,default=ini_cfg.LogMode+1,options={"Append on Startup","Replace on Startup"},radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.pink}
TextBox{parent=log_c_1,x=1,y=7,text="Log File Path"}
local path = TextField{parent=log_c_1,x=1,y=8,width=49,height=1,value=ini_cfg.LogPath,max_len=128,fg_bg=bw_fg_bg}
TextBox{parent=log_c_1,y=7,text="Log File Path"}
local path = TextField{parent=log_c_1,y=8,width=49,height=1,value=ini_cfg.LogPath,max_len=128,fg_bg=bw_fg_bg}
local en_dbg = Checkbox{parent=log_c_1,x=1,y=10,default=ini_cfg.LogDebug,label="Enable Logging Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)}
local en_dbg = Checkbox{parent=log_c_1,y=10,default=ini_cfg.LogDebug,label="Enable Logging Debug Messages",box_fg_bg=cpair(colors.pink,colors.black)}
TextBox{parent=log_c_1,x=3,y=11,height=2,text="This results in much larger log files. It is best to only use this when there is a problem.",fg_bg=g_lg_fg_bg}
local path_err = TextBox{parent=log_c_1,x=8,y=14,width=35,text="Please provide a log file path.",fg_bg=cpair(colors.red,colors.lightGray),hidden=true}
@@ -342,7 +342,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
else path_err.show() end
end
PushButton{parent=log_c_1,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=log_c_1,y=14,text="\x1b Back",callback=function()main_pane.set_value(3)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=log_c_1,x=44,y=14,text="Next \x1a",callback=submit_log,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -354,17 +354,17 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
local clr_c_3 = Div{parent=clr_cfg,x=2,y=4,width=49}
local clr_c_4 = Div{parent=clr_cfg,x=2,y=4,width=49}
local clr_pane = MultiPane{parent=clr_cfg,x=1,y=4,panes={clr_c_1,clr_c_2,clr_c_3,clr_c_4}}
local clr_pane = MultiPane{parent=clr_cfg,y=4,panes={clr_c_1,clr_c_2,clr_c_3,clr_c_4}}
TextBox{parent=clr_cfg,x=1,y=2,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)}
TextBox{parent=clr_cfg,y=2,text=" Color Configuration",fg_bg=cpair(colors.black,colors.magenta)}
TextBox{parent=clr_c_1,x=1,y=1,height=2,text="Here you can select the color theme for the front panel."}
TextBox{parent=clr_c_1,x=1,y=4,height=2,text="Click 'Accessibility' below to access colorblind assistive options.",fg_bg=g_lg_fg_bg}
TextBox{parent=clr_c_1,y=1,height=2,text="Here you can select the color theme for the front panel."}
TextBox{parent=clr_c_1,y=4,height=2,text="Click 'Accessibility' below to access colorblind assistive options.",fg_bg=g_lg_fg_bg}
TextBox{parent=clr_c_1,x=1,y=7,text="Front Panel Theme"}
local fp_theme = RadioButton{parent=clr_c_1,x=1,y=8,default=ini_cfg.FrontPanelTheme,options=themes.FP_THEME_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_1,y=7,text="Front Panel Theme"}
local fp_theme = RadioButton{parent=clr_c_1,y=8,default=ini_cfg.FrontPanelTheme,options=themes.FP_THEME_NAMES,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_2,x=1,y=1,height=6,text="This system uses color heavily to distinguish ok and not, with some indicators using many colors. By selecting a mode below, indicators will change as shown. For non-standard modes, indicators with more than two colors will be split up."}
TextBox{parent=clr_c_2,y=1,height=6,text="This system uses color heavily to distinguish ok and not, with some indicators using many colors. By selecting a mode below, indicators will change as shown. For non-standard modes, indicators with more than two colors will be split up."}
TextBox{parent=clr_c_2,x=21,y=7,text="Preview"}
local _ = IndLight{parent=clr_c_2,x=21,y=8,label="Good",colors=cpair(colors.black,colors.green)}
@@ -393,8 +393,8 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
end
end
TextBox{parent=clr_c_2,x=1,y=7,width=10,text="Color Mode"}
local c_mode = RadioButton{parent=clr_c_2,x=1,y=8,default=ini_cfg.ColorMode,options=themes.COLOR_MODE_NAMES,callback=recolor,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_2,y=7,width=10,text="Color Mode"}
local c_mode = RadioButton{parent=clr_c_2,y=8,default=ini_cfg.ColorMode,options=themes.COLOR_MODE_NAMES,callback=recolor,radio_colors=cpair(colors.lightGray,colors.black),select_color=colors.magenta}
TextBox{parent=clr_c_2,x=21,y=13,height=2,width=18,text="Note: exact color varies by theme.",fg_bg=g_lg_fg_bg}
@@ -435,7 +435,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
end
end
PushButton{parent=clr_c_1,x=1,y=14,text="\x1b Back",callback=back_from_colors,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=clr_c_1,y=14,text="\x1b Back",callback=back_from_colors,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=clr_c_1,x=8,y=14,min_width=15,text="Accessibility",callback=show_access,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
tool_ctl.color_next = PushButton{parent=clr_c_1,x=44,y=14,text="Next \x1a",callback=submit_colors,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
tool_ctl.color_apply = PushButton{parent=clr_c_1,x=43,y=14,min_width=7,text="Apply",callback=submit_colors,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg}
@@ -447,12 +447,12 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
clr_pane.set_value(1)
end
TextBox{parent=clr_c_3,x=1,y=1,text="Settings saved!"}
PushButton{parent=clr_c_3,x=1,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=clr_c_3,y=1,text="Settings saved!"}
PushButton{parent=clr_c_3,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
PushButton{parent=clr_c_3,x=44,y=14,min_width=6,text="Home",callback=c_go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=clr_c_4,x=1,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=clr_c_4,x=1,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=clr_c_4,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=clr_c_4,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
PushButton{parent=clr_c_4,x=44,y=14,min_width=6,text="Home",callback=c_go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
@@ -464,11 +464,11 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
local sum_c_3 = Div{parent=summary,x=2,y=4,width=49}
local sum_c_4 = Div{parent=summary,x=2,y=4,width=49}
local sum_pane = MultiPane{parent=summary,x=1,y=4,panes={sum_c_1,sum_c_2,sum_c_3,sum_c_4}}
local sum_pane = MultiPane{parent=summary,y=4,panes={sum_c_1,sum_c_2,sum_c_3,sum_c_4}}
TextBox{parent=summary,x=1,y=2,text=" Summary",fg_bg=cpair(colors.black,colors.green)}
TextBox{parent=summary,y=2,text=" Summary",fg_bg=cpair(colors.black,colors.green)}
local setting_list = ListBox{parent=sum_c_1,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local setting_list = ListBox{parent=sum_c_1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local function back_from_settings()
if tool_ctl.viewing_config or self.importing_legacy then
@@ -564,11 +564,11 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
end
end
PushButton{parent=sum_c_1,x=1,y=14,text="\x1b Back",callback=back_from_settings,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_1,y=14,text="\x1b Back",callback=back_from_settings,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
self.show_key_btn = PushButton{parent=sum_c_1,x=8,y=14,min_width=17,text="Unhide Auth Key",callback=function()self.show_auth_key()end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg,dis_fg_bg=btn_dis_fg_bg}
tool_ctl.settings_apply = PushButton{parent=sum_c_1,x=43,y=14,min_width=7,text="Apply",callback=save_and_continue,fg_bg=cpair(colors.black,colors.green),active_fg_bg=btn_act_fg_bg}
TextBox{parent=sum_c_2,x=1,y=1,text="Settings saved!"}
TextBox{parent=sum_c_2,y=1,text="Settings saved!"}
local function go_home()
main_pane.set_value(1)
@@ -578,21 +578,21 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
sum_pane.set_value(1)
end
PushButton{parent=sum_c_2,x=1,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_2,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_2,x=44,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=sum_c_3,x=1,y=1,height=2,text="The old config.lua file will now be deleted, then the configurator will exit."}
TextBox{parent=sum_c_3,y=1,height=2,text="The old config.lua file will now be deleted, then the configurator will exit."}
local function delete_legacy()
fs.delete("/supervisor/config.lua")
exit()
end
PushButton{parent=sum_c_3,x=1,y=14,min_width=8,text="Cancel",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_3,y=14,min_width=8,text="Cancel",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_3,x=44,y=14,min_width=6,text="OK",callback=delete_legacy,fg_bg=cpair(colors.black,colors.green),active_fg_bg=cpair(colors.white,colors.gray)}
TextBox{parent=sum_c_4,x=1,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=sum_c_4,x=1,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
TextBox{parent=sum_c_4,y=1,height=5,text="Failed to save the settings file.\n\nThere may not be enough space for the modification or server file permissions may be denying writes."}
PushButton{parent=sum_c_4,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=sum_c_4,x=44,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
--#endregion
@@ -601,12 +601,12 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
local i_err = Div{parent=import_err,x=2,y=4,width=49}
TextBox{parent=import_err,x=1,y=2,text=" Import Error",fg_bg=cpair(colors.black,colors.red)}
TextBox{parent=i_err,x=1,y=1,text="There is a problem with your config.lua file:"}
TextBox{parent=import_err,y=2,text=" Import Error",fg_bg=cpair(colors.black,colors.red)}
TextBox{parent=i_err,y=1,text="There is a problem with your config.lua file:"}
local import_err_msg = TextBox{parent=i_err,x=1,y=3,height=6,text=""}
local import_err_msg = TextBox{parent=i_err,y=3,height=6,text=""}
PushButton{parent=i_err,x=1,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=i_err,y=14,min_width=6,text="Home",callback=go_home,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=i_err,x=44,y=14,min_width=6,text="Exit",callback=exit,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray)}
--#endregion
@@ -870,7 +870,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
local textbox
if height > 1 then
textbox = TextBox{parent=line,x=1,y=2,text=val,height=height-1}
textbox = TextBox{parent=line,y=2,text=val,height=height-1}
else
textbox = TextBox{parent=line,x=label_w+1,y=1,text=val,alignment=RIGHT}
end
@@ -900,19 +900,19 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
end
if missing.tmp and tmp_cfg.WiredModem then
local line = Div{parent=modem_list,x=1,y=1,height=1}
local line = Div{parent=modem_list,y=1,height=1}
TextBox{parent=line,x=1,y=1,width=4,text="Used",fg_bg=cpair(tri(enable,colors.blue,colors.gray),colors.white)}
TextBox{parent=line,y=1,width=4,text="Used",fg_bg=cpair(tri(enable,colors.blue,colors.gray),colors.white)}
PushButton{parent=line,x=6,y=1,min_width=8,height=1,text="SELECT",callback=function()end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=g_lg_fg_bg}.disable()
TextBox{parent=line,x=15,y=1,text="[missing]",fg_bg=cpair(colors.red,colors.white)}
TextBox{parent=line,x=25,y=1,text=tmp_cfg.WiredModem}
end
if missing.ini and ini_cfg.WiredModem and (tmp_cfg.WiredModem ~= ini_cfg.WiredModem) then
local line = Div{parent=modem_list,x=1,y=1,height=1}
local line = Div{parent=modem_list,y=1,height=1}
local used = tmp_cfg.WiredModem == ini_cfg.WiredModem
TextBox{parent=line,x=1,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
TextBox{parent=line,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
local select_btn = PushButton{parent=line,x=6,y=1,min_width=8,height=1,text="SELECT",callback=function()select(ini_cfg.WiredModem)end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=g_lg_fg_bg}
TextBox{parent=line,x=15,y=1,text="[missing]",fg_bg=cpair(colors.red,colors.white)}
TextBox{parent=line,x=25,y=1,text=ini_cfg.WiredModem}
@@ -922,10 +922,10 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, fac_pane, style, exit
-- list wired modems
for iface, _ in pairs(modems) do
local line = Div{parent=modem_list,x=1,y=1,height=1}
local line = Div{parent=modem_list,y=1,height=1}
local used = tmp_cfg.WiredModem == iface
TextBox{parent=line,x=1,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
TextBox{parent=line,y=1,width=4,text=tri(used,"Used","----"),fg_bg=cpair(tri(used and enable,colors.blue,colors.gray),colors.white)}
local select_btn = PushButton{parent=line,x=6,y=1,min_width=8,height=1,text="SELECT",callback=function()select(iface)end,fg_bg=cpair(colors.black,colors.lightBlue),active_fg_bg=btn_act_fg_bg,dis_fg_bg=g_lg_fg_bg}
TextBox{parent=line,x=15,y=1,text=iface}

View File

@@ -186,18 +186,18 @@ local function config_view(display)
TextBox{parent=display,y=1,text="Supervisor Configurator",alignment=CENTER,fg_bg=style.header}
local root_pane_div = Div{parent=display,x=1,y=2}
local root_pane_div = Div{parent=display,y=2}
local main_page = Div{parent=root_pane_div,x=1,y=1}
local fac_cfg = Div{parent=root_pane_div,x=1,y=1}
local net_cfg = Div{parent=root_pane_div,x=1,y=1}
local log_cfg = Div{parent=root_pane_div,x=1,y=1}
local clr_cfg = Div{parent=root_pane_div,x=1,y=1}
local summary = Div{parent=root_pane_div,x=1,y=1}
local changelog = Div{parent=root_pane_div,x=1,y=1}
local import_err = Div{parent=root_pane_div,x=1,y=1}
local main_page = Div{parent=root_pane_div,y=1}
local fac_cfg = Div{parent=root_pane_div,y=1}
local net_cfg = Div{parent=root_pane_div,y=1}
local log_cfg = Div{parent=root_pane_div,y=1}
local clr_cfg = Div{parent=root_pane_div,y=1}
local summary = Div{parent=root_pane_div,y=1}
local changelog = Div{parent=root_pane_div,y=1}
local import_err = Div{parent=root_pane_div,y=1}
local main_pane = MultiPane{parent=root_pane_div,x=1,y=1,panes={main_page,fac_cfg,net_cfg,log_cfg,clr_cfg,summary,changelog,import_err}}
local main_pane = MultiPane{parent=root_pane_div,y=1,panes={main_page,fac_cfg,net_cfg,log_cfg,clr_cfg,summary,changelog,import_err}}
--#region Main Page
@@ -271,20 +271,20 @@ local function config_view(display)
local cl = Div{parent=changelog,x=2,y=4,width=49}
TextBox{parent=changelog,x=1,y=2,text=" Config Change Log",fg_bg=bw_fg_bg}
TextBox{parent=changelog,y=2,text=" Config Change Log",fg_bg=bw_fg_bg}
local c_log = ListBox{parent=cl,x=1,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
local c_log = ListBox{parent=cl,y=1,height=12,width=49,scroll_height=100,fg_bg=bw_fg_bg,nav_fg_bg=g_lg_fg_bg,nav_active=cpair(colors.black,colors.gray)}
for _, change in ipairs(changes) do
TextBox{parent=c_log,text=change[1],fg_bg=bw_fg_bg}
for _, v in ipairs(change[2]) do
local e = Div{parent=c_log,height=#util.strwrap(v,46)}
TextBox{parent=e,y=1,x=1,text="- ",fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=e,y=1,text="- ",fg_bg=cpair(colors.gray,colors.white)}
TextBox{parent=e,y=1,x=3,text=v,height=e.get_height(),fg_bg=cpair(colors.gray,colors.white)}
end
end
PushButton{parent=cl,x=1,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
PushButton{parent=cl,y=14,text="\x1b Back",callback=function()main_pane.set_value(1)end,fg_bg=nav_fg_bg,active_fg_bg=btn_act_fg_bg}
--#endregion
end

View File

@@ -94,9 +94,13 @@ function facility.new(config)
mode_set = PROCESS.MAX_BURN, ---@type PROCESS
start_fail = START_STATUS.OK, ---@type START_STATUS
max_burn_combined = 0.0, -- maximum burn rate to clamp at
burn_target = 0.1, -- burn rate target for aggregate burn mode
charge_setpoint = 0, -- FE charge target setpoint
gen_rate_setpoint = 0, -- FE/t charge rate target setpoint
sp = {
burn_target = 0.1, -- burn rate target for aggregate burn mode
range_start = 10, -- start threshold for range control
range_stop = 90, -- stop threshold for range control
charge_setpoint = 0, -- FE charge target setpoint
gen_rate_setpoint = 0 -- FE/t charge rate target setpoint
},
group_map = {}, ---@type AUTO_GROUP[] units -> group IDs
prio_defs = { {}, {}, {}, {} }, ---@type reactor_unit[][] priority definitions (each level is a table of units)
at_max_burn = false,
@@ -116,6 +120,7 @@ function facility.new(config)
initial_ramp = true,
waiting_on_ramp = false, -- waiting on auto ramping
waiting_on_stable = false, -- waiting on gen rate stabilization
range_control_en = false,
accumulator = 0.0,
saturated = false,
last_update = 0,
@@ -135,6 +140,7 @@ function facility.new(config)
test_alarm_states = {}, ---@type { [ALARM]: boolean }
-- statistics
im_stat_init = false,
imtx_percent = 0.0,
avg_charge = util.mov_avg(3), -- 3 seconds
avg_inflow = util.mov_avg(6), -- 3 seconds
avg_outflow = util.mov_avg(6), -- 3 seconds
@@ -207,21 +213,31 @@ function facility.new(config)
-- only allow changes if not running
if self.mode == PROCESS.INACTIVE then
if (type(auto_cfg.mode) == "number") and (auto_cfg.mode > PROCESS.INACTIVE) and (auto_cfg.mode <= PROCESS.GEN_RATE) then
if (type(auto_cfg.mode) == "number") and (auto_cfg.mode > PROCESS.INACTIVE) and (auto_cfg.mode <= PROCESS.RANGE_CONTROL) then
self.mode_set = auto_cfg.mode
end
ready = self.mode_set > 0
if (type(auto_cfg.burn_target) == "number") and auto_cfg.burn_target >= 0.1 then
self.burn_target = auto_cfg.burn_target
end
self.sp.burn_target = auto_cfg.burn_target
elseif self.mode_set == PROCESS.BURN_RATE then ready = false end
if (type(auto_cfg.range_start) == "number") and (auto_cfg.range_start >= 0) and (auto_cfg.range_start < 100) then
self.sp.range_start = auto_cfg.range_start
elseif self.mode_set == PROCESS.RANGE_CONTROL then ready = false end
if (type(auto_cfg.range_stop) == "number") and (auto_cfg.range_stop <= 100) and (auto_cfg.range_stop > auto_cfg.range_start) then
self.sp.range_stop = auto_cfg.range_stop
elseif self.mode_set == PROCESS.RANGE_CONTROL then ready = false end
if (type(auto_cfg.charge_target) == "number") and auto_cfg.charge_target >= 0 then
self.charge_setpoint = auto_cfg.charge_target * CHARGE_SCALER
end
self.sp.charge_setpoint = auto_cfg.charge_target * CHARGE_SCALER
elseif self.mode_set == PROCESS.CHARGE then ready = false end
if (type(auto_cfg.gen_target) == "number") and auto_cfg.gen_target >= 0 then
self.gen_rate_setpoint = auto_cfg.gen_target * GEN_SCALER
end
self.sp.gen_rate_setpoint = auto_cfg.gen_target * GEN_SCALER
elseif self.mode_set == PROCESS.GEN_RATE then ready = false end
if (type(auto_cfg.limits) == "table") and (#auto_cfg.limits == config.UnitCount) then
for i = 1, config.UnitCount do
@@ -233,14 +249,6 @@ function facility.new(config)
end
end
end
ready = self.mode_set > 0
if ((self.mode_set == PROCESS.CHARGE) and (self.charge_setpoint <= 0)) or
((self.mode_set == PROCESS.GEN_RATE) and (self.gen_rate_setpoint <= 0)) or
((self.mode_set == PROCESS.BURN_RATE) and (self.burn_target < 0.1)) then
ready = false
end
end
return ready, limits
@@ -455,9 +463,11 @@ function facility.new(config)
return {
ready,
self.mode_set,
self.burn_target,
self.charge_setpoint / CHARGE_SCALER,
self.gen_rate_setpoint / GEN_SCALER,
self.sp.burn_target,
self.sp.range_start,
self.sp.range_stop,
self.sp.charge_setpoint / CHARGE_SCALER,
self.sp.gen_rate_setpoint / GEN_SCALER,
limits
}
end

View File

@@ -230,6 +230,8 @@ function update.pre_auto()
local input = util.joules_to_fe_rf(db.state.last_input)
local output = util.joules_to_fe_rf(db.state.last_output)
self.imtx_percent = db.tanks.energy_fill * 100
if self.im_stat_init then
self.avg_charge.record(energy, charge_update)
self.avg_inflow.record(input, rate_update)
@@ -431,8 +433,42 @@ function update.auto_control(ExtChargeIdling)
end
end
local unallocated = allocate_burn_rate(self.burn_target, true)
self.saturated = self.burn_target == self.max_burn_combined or unallocated > 0
local unallocated = allocate_burn_rate(self.sp.burn_target, true)
self.saturated = self.sp.burn_target == self.max_burn_combined or unallocated > 0
elseif self.mode == PROCESS.RANGE_CONTROL then
-- run units at their limits if within the enable range
if state_changed then
self.time_start = now
self.waiting_on_ramp = false
self.range_control_en = false
self.status_text = { "RANGE CONTROL", "idle, sufficient charge" }
log.info("FAC: RANGE_CONTROL process mode started")
elseif self.range_control_en and (self.imtx_percent >= self.sp.range_stop) then
self.range_control_en = false
self.waiting_on_ramp = false
self.status_text = { "RANGE CONTROL", "stopped, sufficient charge" }
log.info("FAC: RANGE_CONTROL process mode started")
elseif (not self.range_control_en) and (self.imtx_percent <= self.sp.range_start) then
self.range_control_en = true
self.waiting_on_ramp = true
self.status_text = { "RANGE CONTROL", "ramping reactors to limit" }
log.info("FAC: CONTROL process mode ramp completed")
elseif self.waiting_on_ramp then
if all_units_ramped() then
self.waiting_on_ramp = false
self.status_text = { "RANGE CONTROL", "running reactors at limit" }
log.info("FAC: CONTROL process mode ramp completed")
end
end
local burn_rate = util.trinary(self.range_control_en, self.max_burn_combined, 0)
local unallocated = allocate_burn_rate(burn_rate, true)
self.saturated = burn_rate == self.max_burn_combined or unallocated > 0
elseif self.mode == PROCESS.CHARGE then
-- target a level of charge
if state_changed then
@@ -448,7 +484,7 @@ function update.auto_control(ExtChargeIdling)
log.info("FAC: CHARGE mode starting PID control")
elseif self.last_update < charge_update then
-- convert to kFE to make constants not microscopic
local error = util.round((self.charge_setpoint - avg_charge) / 1000) / 1000
local error = util.round((self.sp.charge_setpoint - avg_charge) / 1000) / 1000
-- stop accumulator when saturated to avoid windup
if not self.saturated then
@@ -489,7 +525,7 @@ function update.auto_control(ExtChargeIdling)
-- target a rate of generation
if state_changed then
-- estimate an initial output
local output = self.gen_rate_setpoint / self.charge_conversion
local output = self.sp.gen_rate_setpoint / self.charge_conversion
local unallocated = allocate_burn_rate(output, true)
@@ -522,7 +558,7 @@ function update.auto_control(ExtChargeIdling)
end
elseif self.last_update < rate_update then
-- convert to MFE (in rounded kFE) to make constants not microscopic
local error = util.round((self.gen_rate_setpoint - avg_inflow) / 1000) / 1000
local error = util.round((self.sp.gen_rate_setpoint - avg_inflow) / 1000) / 1000
-- stop accumulator when saturated to avoid windup
if not self.saturated then
@@ -538,7 +574,7 @@ function update.auto_control(ExtChargeIdling)
local D = RATE_Kd * derivative
-- velocity (rate) (derivative of charge level => rate) feed forward
local FF = self.gen_rate_setpoint / self.charge_conversion
local FF = self.sp.gen_rate_setpoint / self.charge_conversion
local output = P + I + D + FF

View File

@@ -33,9 +33,9 @@ local function init(parent, id)
local ps_prefix = "pdg_" .. id .. "_"
TextBox{parent=entry,x=1,y=1,text="",width=8,fg_bg=s_hi_box}
local pdg_addr = TextBox{parent=entry,x=1,y=2,text="@ C ??",alignment=ALIGN.CENTER,width=8,fg_bg=s_hi_box,nav_active=cpair(colors.gray,colors.black)}
TextBox{parent=entry,x=1,y=3,text="",width=8,fg_bg=s_hi_box}
TextBox{parent=entry,y=1,text="",width=8,fg_bg=s_hi_box}
local pdg_addr = TextBox{parent=entry,y=2,text="@ C ??",alignment=ALIGN.CENTER,width=8,fg_bg=s_hi_box,nav_active=cpair(colors.gray,colors.black)}
TextBox{parent=entry,y=3,text="",width=8,fg_bg=s_hi_box}
pdg_addr.register(databus.ps, ps_prefix .. "addr", pdg_addr.set_value)
TextBox{parent=entry,x=10,y=2,text="FW:",width=3}

View File

@@ -33,9 +33,9 @@ local function init(parent, id)
local ps_prefix = "rtu_" .. id .. "_"
TextBox{parent=entry,x=1,y=1,text="",width=8,fg_bg=s_hi_box}
local rtu_addr = TextBox{parent=entry,x=1,y=2,text="@ C ??",alignment=ALIGN.CENTER,width=8,fg_bg=s_hi_box,nav_active=cpair(colors.gray,colors.black)}
TextBox{parent=entry,x=1,y=3,text="",width=8,fg_bg=s_hi_box}
TextBox{parent=entry,y=1,text="",width=8,fg_bg=s_hi_box}
local rtu_addr = TextBox{parent=entry,y=2,text="@ C ??",alignment=ALIGN.CENTER,width=8,fg_bg=s_hi_box,nav_active=cpair(colors.gray,colors.black)}
TextBox{parent=entry,y=3,text="",width=8,fg_bg=s_hi_box}
rtu_addr.register(databus.ps, ps_prefix .. "addr", rtu_addr.set_value)
TextBox{parent=entry,x=10,y=2,text="UNITS:",width=7}

View File

@@ -48,13 +48,13 @@ local function init(panel, config)
TextBox{parent=panel,y=1,text="SCADA SUPERVISOR",alignment=ALIGN.CENTER,fg_bg=style.theme.header}
local page_div = Div{parent=panel,x=1,y=3}
local page_div = Div{parent=panel,y=3}
--
-- system indicators
--
local main_page = Div{parent=page_div,x=1,y=1}
local main_page = Div{parent=page_div,y=1}
local system = Div{parent=main_page,width=18,height=17,x=2,y=2}
@@ -94,16 +94,16 @@ local function init(panel, config)
-- plc sessions page
local plc_page = Div{parent=page_div,x=1,y=1,hidden=true}
local plc_page = Div{parent=page_div,y=1,hidden=true}
local plc_list = Div{parent=plc_page,x=2,y=2,width=term_w-2}
for i = 1, supervisor.config.UnitCount do
local ps_prefix = "plc_" .. i .. "_"
local plc_entry = Div{parent=plc_list,height=3,fg_bg=s_hi_bright}
TextBox{parent=plc_entry,x=1,y=1,text="",width=8,fg_bg=s_hi_box}
TextBox{parent=plc_entry,x=1,y=2,text="UNIT "..i,alignment=ALIGN.CENTER,width=8,fg_bg=s_hi_box}
TextBox{parent=plc_entry,x=1,y=3,text="",width=8,fg_bg=s_hi_box}
TextBox{parent=plc_entry,y=1,text="",width=8,fg_bg=s_hi_box}
TextBox{parent=plc_entry,y=2,text="UNIT "..i,alignment=ALIGN.CENTER,width=8,fg_bg=s_hi_box}
TextBox{parent=plc_entry,y=3,text="",width=8,fg_bg=s_hi_box}
local conn = LED{parent=plc_entry,x=10,y=2,label="LINK",colors=cpair(colors.green_hc,colors.green_off)}
conn.register(databus.ps, ps_prefix .. "conn", conn.update)
@@ -126,13 +126,13 @@ local function init(panel, config)
-- rtu sessions page
local rtu_page = Div{parent=page_div,x=1,y=1,hidden=true}
local rtu_page = Div{parent=page_div,y=1,hidden=true}
local rtu_list = ListBox{parent=rtu_page,y=1,height=term_h-2,width=term_w,scroll_height=1000,fg_bg=cpair(colors.black,colors.ivory),nav_fg_bg=cpair(colors.gray,colors.lightGray),nav_active=cpair(colors.black,colors.gray)}
local _ = Div{parent=rtu_list,height=1} -- padding
-- coordinator session page
local crd_page = Div{parent=page_div,x=1,y=1,hidden=true}
local crd_page = Div{parent=page_div,y=1,hidden=true}
local crd_box = Div{parent=crd_page,x=2,y=2,width=term_w-2,height=4,fg_bg=s_hi_bright}
local crd_conn = LED{parent=crd_box,x=2,y=2,label="CONNECTION",colors=cpair(colors.green_hc,colors.green_off)}
@@ -184,7 +184,7 @@ local function init(panel, config)
local panes = { main_page, plc_page, rtu_page, crd_page, pkt_page, chk_page, info_page }
local page_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
local page_pane = MultiPane{parent=page_div,y=1,panes=panes}
local tabs = {
{ name = "SVR", color = style.fp.text },

View File

@@ -243,9 +243,11 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim
local config = {
mode = pkt.data[1],
burn_target = pkt.data[2],
charge_target = pkt.data[3],
gen_target = pkt.data[4],
limits = pkt.data[5]
range_start = pkt.data[3],
range_stop = pkt.data[4],
charge_target = pkt.data[5],
gen_target = pkt.data[6],
limits = pkt.data[7]
}
facility.boot_recovery_start(config)
@@ -276,14 +278,16 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim
elseif cmd == FAC_COMMAND.START then
facility.cancel_recovery()
if pkt.length == 6 then
if pkt.length == 8 then
---@class start_auto_config
local config = {
mode = pkt.data[2], ---@type PROCESS
burn_target = pkt.data[3], ---@type number
charge_target = pkt.data[4], ---@type number
gen_target = pkt.data[5], ---@type number
limits = pkt.data[6] ---@type number[]
range_start = pkt.data[4], ---@type integer
range_stop = pkt.data[5], ---@type integer
charge_target = pkt.data[6], ---@type number
gen_target = pkt.data[7], ---@type number
limits = pkt.data[8] ---@type number[]
}
_send(CRDN_TYPE.FAC_CMD, { cmd, table.unpack(facility.auto_start(config)) })

View File

@@ -174,6 +174,7 @@ end
-- check if a watchdog timer event matches that of one of the provided sessions
---@param sessions sv_session_structs[]
---@param timer_event number
---@return boolean was_watchdog if this event was one of the watchdogs
local function _check_watchdogs(sessions, timer_event)
for i = 1, #sessions do
local session = sessions[i]
@@ -182,9 +183,12 @@ local function _check_watchdogs(sessions, timer_event)
if triggered then
log.debug(util.c("SVS: watchdog closing session ", session, "..."))
_shutdown(session)
return true
end
end
end
return false
end
-- delete any closed sessions
@@ -648,8 +652,13 @@ end
-- attempt to identify which session's watchdog timer fired
---@param timer_event number
---@return boolean was_watchdog if this event was one of the watchdogs
function svsessions.check_all_watchdogs(timer_event)
for _, list in pairs(self.sessions) do _check_watchdogs(list, timer_event) end
for _, list in pairs(self.sessions) do
if _check_watchdogs(list, timer_event) then return true end
end
return false
end
-- iterate all sessions, and update facility/unit data & process control logic

View File

@@ -24,7 +24,7 @@ local supervisor = require("supervisor.supervisor")
local svsessions = require("supervisor.session.svsessions")
local SUPERVISOR_VERSION = "v1.8.7"
local SUPERVISOR_VERSION = "v1.9.0"
local println = util.println
local println_ts = util.println_ts
@@ -150,17 +150,35 @@ local function main()
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
-- local counters = {}
-- main loop periodic tasks
local function loop_tick()
-- blink heartbeat indicator at half the main loop rate due to how quick it runs
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()
-- start next clock timer
loop_clock.start()
-- log.debug(textutils.serialize(counters, { compact = true })); counters = {}
end
-- start clock
loop_clock.start()
-- init startup recovery
sv_facility.boot_recovery_init(supervisor.boot_state)
-- local counters = {}
-- event loop
while true do
local event, param1, param2, param3, param4, param5 = util.pull_event()
@@ -168,46 +186,33 @@ local function main()
-- counters[event] = (counters[event] or 0) + 1
-- handle event
if event == "peripheral_detach" then
local type, device = ppm.handle_unmount(param1)
if type ~= nil and device ~= nil then
backplane.detach(param1, type, device, println_ts)
if event == "modem_message" then
-- got a packet
local packet = superv_comms.parse_packet(param1, param2, param3, param4, param5)
if packet then superv_comms.handle_packet(packet) end
elseif event == "timer" then
-- pass this timer event onto the right handler
if loop_clock.is_clock(param1) then
-- main loop tick
loop_tick()
elseif not svsessions.check_all_watchdogs(param1) then -- check session watchdogs
-- notify timer callback dispatcher, no other handler claimed this event
tcd.handle(param1)
end
elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" or
event == "double_click" then
-- handle a mouse event
renderer.handle_mouse(core.events.new_mouse_event(event, param1, param2, param3))
elseif event == "peripheral" then
local type, device = ppm.mount(param1)
if type ~= nil and device ~= nil then
backplane.attach(param1, type, device, println_ts)
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()
-- start next clock timer
loop_clock.start()
-- log.debug(textutils.serialize(counters, { compact = true })); counters = {}
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)
if packet then superv_comms.handle_packet(packet) end
elseif event == "mouse_click" or event == "mouse_up" or event == "mouse_drag" or event == "mouse_scroll" or
event == "double_click" then
-- handle a mouse event
renderer.handle_mouse(core.events.new_mouse_event(event, param1, param2, param3))
elseif event == "peripheral_detach" then
local type, device = ppm.handle_unmount(param1)
if type ~= nil and device ~= nil then
backplane.detach(param1, type, device, println_ts)
end
end
-- check for termination request