2023-09-20 03:52:22 +00:00
--
-- Configuration GUI
--
2024-07-27 00:27:38 +00:00
local log = require ( " scada-common.log " )
local tcd = require ( " scada-common.tcd " )
local util = require ( " scada-common.util " )
2023-09-20 03:52:22 +00:00
2024-07-27 00:27:38 +00:00
local check = require ( " reactor-plc.config.check " )
local system = require ( " reactor-plc.config.system " )
2024-07-25 02:42:14 +00:00
2024-07-27 00:27:38 +00:00
local core = require ( " graphics.core " )
local themes = require ( " graphics.themes " )
2023-09-20 03:52:22 +00:00
2024-07-27 00:27:38 +00:00
local DisplayBox = require ( " graphics.elements.displaybox " )
local Div = require ( " graphics.elements.div " )
local ListBox = require ( " graphics.elements.listbox " )
local MultiPane = require ( " graphics.elements.multipane " )
local TextBox = require ( " graphics.elements.textbox " )
2023-09-24 00:22:02 +00:00
2024-07-27 00:27:38 +00:00
local PushButton = require ( " graphics.elements.controls.push_button " )
2024-03-07 23:00:33 +00:00
2023-09-20 03:52:22 +00:00
local println = util.println
2023-11-04 16:49:14 +00:00
local tri = util.trinary
2023-09-20 03:52:22 +00:00
local cpair = core.cpair
2023-10-04 03:16:46 +00:00
local CENTER = core.ALIGN . CENTER
2023-09-20 03:52:22 +00:00
2023-10-14 16:02:25 +00:00
-- changes to the config data/format to let the user know
local changes = {
2024-03-08 00:23:46 +00:00
{ " v1.6.2 " , { " AuthKey minimum length is now 8 (if set) " } } ,
{ " v1.6.8 " , { " ConnTimeout can now have a fractional part " } } ,
2024-03-24 16:56:51 +00:00
{ " v1.6.15 " , { " Added front panel UI theme " , " Added color accessibility modes " } } ,
2024-03-25 14:11:35 +00:00
{ " v1.7.3 " , { " Added standard with black off state color mode " , " Added blue indicator color modes " } }
2023-10-14 16:02:25 +00:00
}
2023-09-20 03:52:22 +00:00
---@class plc_configurator
local configurator = { }
local style = { }
2024-07-27 00:27:38 +00:00
style.root = cpair ( colors.black , colors.lightGray )
style.header = cpair ( colors.white , colors.gray )
2023-09-20 03:52:22 +00:00
2024-07-27 00:27:38 +00:00
style.colors = themes.smooth_stone . colors
2023-09-20 03:52:22 +00:00
2024-07-27 00:27:38 +00:00
style.bw_fg_bg = cpair ( colors.black , colors.white )
style.g_lg_fg_bg = cpair ( colors.gray , colors.lightGray )
style.nav_fg_bg = style.bw_fg_bg
style.btn_act_fg_bg = cpair ( colors.white , colors.gray )
style.btn_dis_fg_bg = cpair ( colors.lightGray , colors.white )
2023-10-14 16:02:25 +00:00
2024-03-08 00:23:46 +00:00
---@class _plc_cfg_tool_ctl
2023-09-20 03:52:22 +00:00
local tool_ctl = {
2023-10-01 04:21:46 +00:00
ask_config = false ,
has_config = false ,
viewing_config = false ,
2024-03-07 23:00:33 +00:00
jumped_to_color = false ,
2023-10-01 04:21:46 +00:00
view_cfg = nil , ---@type graphics_element
2024-03-07 23:00:33 +00:00
color_cfg = nil , ---@type graphics_element
color_next = nil , ---@type graphics_element
color_apply = nil , ---@type graphics_element
2023-10-01 04:21:46 +00:00
settings_apply = nil , ---@type graphics_element
gen_summary = nil , ---@type function
2023-10-04 02:52:13 +00:00
load_legacy = nil , ---@type function
2023-09-24 00:22:02 +00:00
}
2023-10-01 21:12:59 +00:00
---@class plc_config
2023-09-24 00:22:02 +00:00
local tmp_cfg = {
Networked = false ,
UnitID = 0 ,
2023-10-01 04:21:46 +00:00
EmerCoolEnable = false ,
2023-12-29 19:33:22 +00:00
EmerCoolSide = nil , ---@type string|nil
EmerCoolColor = nil , ---@type color|nil
SVR_Channel = nil , ---@type integer
PLC_Channel = nil , ---@type integer
ConnTimeout = nil , ---@type number
TrustedRange = nil , ---@type number
AuthKey = nil , ---@type string|nil
2023-09-24 00:22:02 +00:00
LogMode = 0 ,
LogPath = " " ,
LogDebug = false ,
2024-03-07 23:00:33 +00:00
FrontPanelTheme = 1 ,
ColorMode = 1
2023-09-24 00:22:02 +00:00
}
2023-10-01 21:12:59 +00:00
---@class plc_config
2023-10-01 04:21:46 +00:00
local ini_cfg = { }
2023-11-04 16:49:14 +00:00
---@class plc_config
local settings_cfg = { }
2023-10-01 04:21:46 +00:00
2023-11-04 16:49:14 +00:00
-- all settings fields, their nice names, and their default values
2023-09-24 00:22:02 +00:00
local fields = {
2023-11-04 16:49:14 +00:00
{ " Networked " , " Networked " , false } ,
{ " UnitID " , " Unit ID " , 1 } ,
{ " EmerCoolEnable " , " Emergency Coolant " , false } ,
{ " EmerCoolSide " , " Emergency Coolant Side " , nil } ,
{ " EmerCoolColor " , " Emergency Coolant Color " , nil } ,
{ " SVR_Channel " , " SVR Channel " , 16240 } ,
{ " PLC_Channel " , " PLC Channel " , 16241 } ,
{ " ConnTimeout " , " Connection Timeout " , 5 } ,
{ " TrustedRange " , " Trusted Range " , 0 } ,
{ " AuthKey " , " Facility Auth Key " , " " } ,
{ " LogMode " , " Log Mode " , log.MODE . APPEND } ,
{ " LogPath " , " Log Path " , " /log.txt " } ,
2024-03-11 16:35:06 +00:00
{ " LogDebug " , " Log Debug Messages " , false } ,
2024-03-13 01:09:37 +00:00
{ " FrontPanelTheme " , " Front Panel Theme " , themes.FP_THEME . SANDSTONE } ,
{ " ColorMode " , " Color Mode " , themes.COLOR_MODE . STANDARD }
2023-09-20 03:52:22 +00:00
}
2023-10-01 04:21:46 +00:00
-- load data from the settings file
2023-10-01 21:12:59 +00:00
---@param target plc_config
2023-11-04 16:49:14 +00:00
---@param raw boolean? true to not use default values
local function load_settings ( target , raw )
for _ , v in pairs ( fields ) do settings.unset ( v [ 1 ] ) end
local loaded = settings.load ( " /reactor-plc.settings " )
for _ , v in pairs ( fields ) do target [ v [ 1 ] ] = settings.get ( v [ 1 ] , tri ( raw , nil , v [ 3 ] ) ) end
return loaded
2023-10-01 04:21:46 +00:00
end
-- create the config view
---@param display graphics_element
local function config_view ( display )
2024-07-27 00:27:38 +00:00
local bw_fg_bg = style.bw_fg_bg
local g_lg_fg_bg = style.g_lg_fg_bg
local nav_fg_bg = style.nav_fg_bg
local btn_act_fg_bg = style.btn_act_fg_bg
local btn_dis_fg_bg = style.btn_dis_fg_bg
2023-10-01 04:21:46 +00:00
---@diagnostic disable-next-line: undefined-field
2023-10-04 02:52:13 +00:00
local function exit ( ) os.queueEvent ( " terminate " ) end
2023-10-01 04:21:46 +00:00
2024-06-30 17:55:13 +00:00
TextBox { parent = display , y = 1 , text = " Reactor PLC Configurator " , alignment = CENTER , fg_bg = style.header }
2023-09-20 03:52:22 +00:00
local root_pane_div = Div { parent = display , x = 1 , 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 }
2024-03-07 23:00:33 +00:00
local clr_cfg = Div { parent = root_pane_div , x = 1 , y = 1 }
2023-09-24 00:22:02 +00:00
local summary = Div { parent = root_pane_div , x = 1 , y = 1 }
2023-10-14 16:02:25 +00:00
local changelog = Div { parent = root_pane_div , x = 1 , y = 1 }
2024-07-20 18:17:36 +00:00
local check_sys = Div { parent = root_pane_div , x = 1 , y = 1 }
2023-09-20 03:52:22 +00:00
2024-07-20 18:17:36 +00:00
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 } }
2023-09-20 03:52:22 +00:00
2024-07-20 18:17:36 +00:00
--#region Main Page
2023-09-20 03:52:22 +00:00
2023-10-01 21:12:59 +00:00
local y_start = 5
2023-09-24 00:22:02 +00:00
2023-11-12 23:27:24 +00:00
TextBox { parent = main_page , x = 2 , y = 2 , height = 2 , text = " Welcome to the Reactor PLC configurator! Please select one of the following options. " }
2023-09-20 03:52:22 +00:00
2023-10-01 04:21:46 +00:00
if tool_ctl.ask_config then
2024-07-25 02:42:14 +00:00
TextBox { parent = main_page , x = 2 , y = y_start , height = 4 , width = 49 , text = " Notice: This device had no valid config so the configurator has been automatically started. If you previously had a valid config, you may want to check the Change Log to see what changed. " , fg_bg = cpair ( colors.red , colors.lightGray ) }
2023-10-14 16:02:25 +00:00
y_start = y_start + 5
2023-09-24 00:22:02 +00:00
end
2023-10-01 04:21:46 +00:00
local function view_config ( )
tool_ctl.viewing_config = true
2023-11-04 16:49:14 +00:00
tool_ctl.gen_summary ( settings_cfg )
2023-10-01 04:21:46 +00:00
tool_ctl.settings_apply . hide ( true )
2024-03-07 23:00:33 +00:00
main_pane.set_value ( 6 )
2023-10-01 04:21:46 +00:00
end
2023-09-24 00:22:02 +00:00
if fs.exists ( " /reactor-plc/config.lua " ) then
2023-10-01 21:12:59 +00:00
PushButton { parent = main_page , x = 2 , y = y_start , min_width = 28 , text = " Import Legacy 'config.lua' " , callback = function ( ) tool_ctl.load_legacy ( ) end , fg_bg = cpair ( colors.black , colors.cyan ) , active_fg_bg = btn_act_fg_bg }
y_start = y_start + 2
2023-09-24 00:22:02 +00:00
end
2023-10-01 21:12:59 +00:00
PushButton { parent = main_page , x = 2 , y = y_start , min_width = 18 , text = " Configure System " , callback = function ( ) main_pane.set_value ( 2 ) end , fg_bg = cpair ( colors.black , colors.blue ) , active_fg_bg = btn_act_fg_bg }
2024-07-23 03:44:12 +00:00
tool_ctl.view_cfg = PushButton { parent = main_page , x = 2 , y = y_start + 2 , min_width = 20 , text = " View Configuration " , callback = view_config , fg_bg = cpair ( colors.black , colors.blue ) , active_fg_bg = btn_act_fg_bg , dis_fg_bg = btn_dis_fg_bg }
2023-09-20 03:52:22 +00:00
2024-03-07 23:00:33 +00:00
local function jump_color ( )
tool_ctl.jumped_to_color = true
2024-03-11 16:35:06 +00:00
tool_ctl.color_next . hide ( true )
tool_ctl.color_apply . show ( )
2024-03-07 23:00:33 +00:00
main_pane.set_value ( 5 )
end
2023-10-01 04:21:46 +00:00
PushButton { parent = main_page , x = 2 , y = 17 , min_width = 6 , text = " Exit " , callback = exit , fg_bg = cpair ( colors.black , colors.red ) , active_fg_bg = btn_act_fg_bg }
2024-07-28 20:41:39 +00:00
PushButton { parent = main_page , x = 10 , y = 17 , min_width = 12 , text = " Self-Check " , callback = function ( ) main_pane.set_value ( 8 ) end , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg , dis_fg_bg = btn_dis_fg_bg }
2024-07-23 03:44:12 +00:00
tool_ctl.color_cfg = PushButton { parent = main_page , x = 23 , y = 17 , min_width = 15 , text = " Color Options " , callback = jump_color , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg , dis_fg_bg = btn_dis_fg_bg }
2024-03-07 23:00:33 +00:00
PushButton { parent = main_page , x = 39 , y = 17 , min_width = 12 , text = " Change Log " , callback = function ( ) main_pane.set_value ( 7 ) end , fg_bg = nav_fg_bg , active_fg_bg = btn_act_fg_bg }
if not tool_ctl.has_config then
tool_ctl.view_cfg . disable ( )
tool_ctl.color_cfg . disable ( )
end
2023-09-20 03:52:22 +00:00
2024-07-20 18:17:36 +00:00
--#endregion
2024-07-27 00:27:38 +00:00
--#region System Configuration
2023-09-20 03:52:22 +00:00
2024-07-27 00:27:38 +00:00
local settings = { settings_cfg , ini_cfg , tmp_cfg , fields , load_settings }
local divs = { plc_cfg , net_cfg , log_cfg , clr_cfg , summary }
2023-09-20 03:52:22 +00:00
2024-07-27 00:27:38 +00:00
system.create ( tool_ctl , main_pane , settings , divs , style , exit )
2023-10-01 04:21:46 +00:00
2024-02-20 01:32:33 +00:00
--#endregion
2024-07-20 18:17:36 +00:00
--#region Config Change Log
2023-10-14 16:02:25 +00:00
local cl = Div { parent = changelog , x = 2 , y = 4 , width = 49 }
2024-06-30 17:55:13 +00:00
TextBox { parent = changelog , x = 1 , y = 2 , text = " Config Change Log " , fg_bg = bw_fg_bg }
2023-10-14 16:02:25 +00:00
2024-02-19 18:54:23 +00:00
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 ) }
2023-10-14 16:02:25 +00:00
for _ , change in ipairs ( changes ) do
2024-06-30 17:55:13 +00:00
TextBox { parent = c_log , text = change [ 1 ] , fg_bg = bw_fg_bg }
2023-10-14 16:02:25 +00:00
for _ , v in ipairs ( change [ 2 ] ) do
local e = Div { parent = c_log , height =# util.strwrap ( v , 46 ) }
2024-06-30 17:55:13 +00:00
TextBox { parent = e , y = 1 , x = 1 , text = " - " , fg_bg = cpair ( colors.gray , colors.white ) }
2023-10-14 16:02:25 +00:00
TextBox { parent = e , y = 1 , x = 3 , text = v , height = e.get_height ( ) , fg_bg = cpair ( colors.gray , colors.white ) }
end
end
2023-12-15 01:51:54 +00:00
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 }
2023-10-14 16:02:25 +00:00
2024-07-20 18:17:36 +00:00
--#endregion
--#region Self-Check
2024-07-27 00:27:38 +00:00
check.create ( main_pane , settings_cfg , check_sys , style )
2024-07-23 03:44:12 +00:00
2024-07-27 00:27:38 +00:00
--#endregion
2023-09-20 03:52:22 +00:00
end
2023-10-01 04:21:46 +00:00
-- reset terminal screen
local function reset_term ( )
2023-09-20 03:52:22 +00:00
term.setTextColor ( colors.white )
term.setBackgroundColor ( colors.black )
term.clear ( )
term.setCursorPos ( 1 , 1 )
2023-10-01 04:21:46 +00:00
end
-- run the reactor PLC configurator
2024-02-20 01:32:33 +00:00
---@param ask_config? boolean indicate if this is being called by the startup app due to an invalid configuration
2023-10-01 04:21:46 +00:00
function configurator . configure ( ask_config )
tool_ctl.ask_config = ask_config == true
2023-11-16 00:28:32 +00:00
2023-11-04 16:49:14 +00:00
load_settings ( settings_cfg , true )
2023-11-16 00:28:32 +00:00
tool_ctl.has_config = load_settings ( ini_cfg )
2023-10-01 04:21:46 +00:00
reset_term ( )
2023-09-20 03:52:22 +00:00
-- set overridden colors
for i = 1 , # style.colors do
term.setPaletteColor ( style.colors [ i ] . c , style.colors [ i ] . hex )
end
2023-10-01 19:30:49 +00:00
local status , error = pcall ( function ( )
2023-10-01 04:21:46 +00:00
local display = DisplayBox { window = term.current ( ) , fg_bg = style.root }
config_view ( display )
while true do
2024-07-23 03:44:12 +00:00
local event , param1 , param2 , param3 , param4 , param5 = util.pull_event ( )
2023-10-01 04:21:46 +00:00
-- handle event
if event == " timer " then
tcd.handle ( param1 )
elseif event == " mouse_click " or event == " mouse_up " or event == " mouse_drag " or event == " mouse_scroll " or event == " double_click " then
local m_e = core.events . new_mouse_event ( event , param1 , param2 , param3 )
if m_e then display.handle_mouse ( m_e ) end
elseif event == " char " or event == " key " or event == " key_up " then
local k_e = core.events . new_key_event ( event , param1 , param2 )
if k_e then display.handle_key ( k_e ) end
elseif event == " paste " then
display.handle_paste ( param1 )
2024-07-27 00:27:38 +00:00
elseif event == " modem_message " then
2024-07-27 03:06:42 +00:00
check.receive_sv ( param1 , param2 , param3 , param4 , param5 )
2023-10-01 04:21:46 +00:00
end
2023-09-24 00:22:02 +00:00
2023-10-01 21:12:59 +00:00
if event == " terminate " then return end
2023-09-20 03:52:22 +00:00
end
2023-10-01 04:21:46 +00:00
end )
2023-09-20 03:52:22 +00:00
2023-10-01 04:21:46 +00:00
-- restore colors
for i = 1 , # style.colors do
local r , g , b = term.nativePaletteColor ( style.colors [ i ] . c )
term.setPaletteColor ( style.colors [ i ] . c , r , g , b )
2023-09-20 03:52:22 +00:00
end
2023-10-01 04:21:46 +00:00
reset_term ( )
2023-10-01 21:12:59 +00:00
if not status then
2023-10-01 19:30:49 +00:00
println ( " configurator error: " .. error )
end
return status , error
2023-09-20 03:52:22 +00:00
end
return configurator