diff --git a/coordinator/configure.lua b/coordinator/configure.lua index 31d359c..1cd945b 100644 --- a/coordinator/configure.lua +++ b/coordinator/configure.lua @@ -13,20 +13,20 @@ local util = require("scada-common.util") local core = require("graphics.core") local themes = require("graphics.themes") -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") +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") -local CheckBox = require("graphics.elements.controls.checkbox") -local PushButton = require("graphics.elements.controls.push_button") -local RadioButton = require("graphics.elements.controls.radio_button") +local Checkbox = require("graphics.elements.controls.Checkbox") +local PushButton = require("graphics.elements.controls.PushButton") +local RadioButton = require("graphics.elements.controls.RadioButton") -local NumberField = require("graphics.elements.form.number_field") -local TextField = require("graphics.elements.form.text_field") +local NumberField = require("graphics.elements.form.NumberField") +local TextField = require("graphics.elements.form.TextField") -local IndLight = require("graphics.elements.indicators.light") +local IndLight = require("graphics.elements.indicators.IndicatorLight") local println = util.println local tri = util.trinary @@ -71,7 +71,7 @@ local tool_ctl = { net_listen = false, sv_addr = comms.BROADCAST, sv_seq_num = util.time_ms() * 10, - sv_cool_conf = nil, ---@type table list of boiler & turbine counts + sv_cool_conf = nil, ---@type [ integer, integer ][] list of boiler & turbine counts show_sv_cfg = nil, ---@type function start_fail = 0, @@ -81,36 +81,36 @@ local tool_ctl = { importing_legacy = false, jumped_to_color = false, - view_cfg = nil, ---@type graphics_element - color_cfg = nil, ---@type graphics_element - color_next = nil, ---@type graphics_element - color_apply = nil, ---@type graphics_element - settings_apply = nil, ---@type graphics_element + view_cfg = nil, ---@type PushButton + color_cfg = nil, ---@type PushButton + color_next = nil, ---@type PushButton + color_apply = nil, ---@type PushButton + settings_apply = nil, ---@type PushButton gen_summary = nil, ---@type function show_current_cfg = nil, ---@type function load_legacy = nil, ---@type function show_auth_key = nil, ---@type function - show_key_btn = nil, ---@type graphics_element - auth_key_textbox = nil, ---@type graphics_element + show_key_btn = nil, ---@type PushButton + auth_key_textbox = nil, ---@type TextBox auth_key_value = "", sv_connect = nil, ---@type function - sv_conn_button = nil, ---@type graphics_element - sv_conn_status = nil, ---@type graphics_element - sv_conn_detail = nil, ---@type graphics_element - sv_skip = nil, ---@type graphics_element - sv_next = nil, ---@type graphics_element + sv_conn_button = nil, ---@type PushButton + sv_conn_status = nil, ---@type TextBox + sv_conn_detail = nil, ---@type TextBox + sv_skip = nil, ---@type PushButton + sv_next = nil, ---@type PushButton - apply_mon = nil, ---@type graphics_element + apply_mon = nil, ---@type PushButton update_mon_reqs = nil, ---@type function gen_mon_list = function () end, edit_monitor = nil, ---@type function mon_iface = "", - mon_expect = {} + mon_expect = {} ---@type integer[] } ---@class crd_config @@ -302,7 +302,7 @@ local function load_settings(target, raw) end -- create the config view ----@param display graphics_element +---@param display DisplayBox local function config_view(display) ---@diagnostic disable-next-line: undefined-field local function exit() os.queueEvent("terminate") end @@ -460,11 +460,11 @@ local function config_view(display) TextBox{parent=net_c_4,x=1,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for security on multiplayer servers. All devices on the same network MUST use the same key if any device has a key. This does result in some extra compution (can slow things down).",fg_bg=g_lg_fg_bg} TextBox{parent=net_c_4,x=1,y=11,text="Facility Auth Key"} - local key, _, censor = 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} + 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} - local function censor_key(enable) censor(util.trinary(enable, "*", nil)) end + local function censor_key(enable) key.censor(util.trinary(enable, "*", nil)) end - local hide_key = CheckBox{parent=net_c_4,x=34,y=12,label="Hide",box_fg_bg=cpair(colors.lightBlue,colors.black),callback=censor_key} + local hide_key = Checkbox{parent=net_c_4,x=34,y=12,label="Hide",box_fg_bg=cpair(colors.lightBlue,colors.black),callback=censor_key} hide_key.set_value(true) censor_key(true) @@ -622,7 +622,7 @@ local function config_view(display) local mon_desc = TextBox{parent=mon_c_3,x=1,y=1,height=4,text=""} - local mon_unit_l, mon_unit = nil, nil ---@type graphics_element, graphics_element + 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)} @@ -706,7 +706,7 @@ local function config_view(display) 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."} - local 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)} + local 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)} local function back_from_legacy() tmp_cfg.DisableFlowView = dis_flow_view.get_value() @@ -790,7 +790,7 @@ local function config_view(display) 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} - 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,x=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} @@ -1263,7 +1263,7 @@ local function config_view(display) -- list connected monitors local monitors = ppm.get_monitor_list() for iface, device in pairs(monitors) do - local dev = device.dev + local dev = device.dev ---@type Monitor dev.setTextScale(0.5) dev.setTextColor(colors.white) diff --git a/coordinator/coordinator.lua b/coordinator/coordinator.lua index bb8bcee..78748c8 100644 --- a/coordinator/coordinator.lua +++ b/coordinator/coordinator.lua @@ -111,12 +111,12 @@ function coordinator.load_config() ---@class monitors_struct local monitors = { - main = nil, ---@type table|nil + main = nil, ---@type Monitor|nil main_name = "", - flow = nil, ---@type table|nil + flow = nil, ---@type Monitor|nil flow_name = "", - unit_displays = {}, - unit_name_map = {} + unit_displays = {}, ---@type Monitor[] + unit_name_map = {} ---@type string[] } local mon_cfv = util.new_validator() @@ -623,7 +623,7 @@ function coordinator.comms(version, nic, sv_watchdog) local unit_id = packet.data[2] local ack = packet.data[3] == true - local unit = iocontrol.get_db().units[unit_id] ---@type ioctl_unit + local unit = iocontrol.get_db().units[unit_id] if unit ~= nil then if cmd == UNIT_COMMAND.SCRAM then diff --git a/coordinator/iocontrol.lua b/coordinator/iocontrol.lua index 37230b3..41bb058 100644 --- a/coordinator/iocontrol.lua +++ b/coordinator/iocontrol.lua @@ -29,15 +29,6 @@ local iocontrol = {} ---@class ioctl local io = {} --- luacheck: no unused args - --- placeholder acknowledge function for type hinting ----@param success boolean ----@diagnostic disable-next-line: unused-local -local function __generic_ack(success) end - --- luacheck: unused args - -- initialize front panel PSIL ---@param firmware_v string coordinator version ---@param comms_v string comms version @@ -115,25 +106,23 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale) radiation = types.new_zero_radiation_reading(), - save_cfg_ack = __generic_ack, - start_ack = __generic_ack, - stop_ack = __generic_ack, + save_cfg_ack = nil, ---@type fun(success: boolean) + start_ack = nil, ---@type fun(success: boolean) + stop_ack = nil, ---@type fun(success: boolean) + ---@type { [TONE]: boolean } alarm_tones = { false, false, false, false, false, false, false, false }, ps = psil.create(), - induction_ps_tbl = {}, - induction_data_tbl = {}, + induction_ps_tbl = {}, ---@type psil[] + induction_data_tbl = {}, ---@type imatrix_session_db[] - sps_ps_tbl = {}, - sps_data_tbl = {}, + sps_ps_tbl = {}, ---@type psil[] + sps_data_tbl = {}, ---@type sps_session_db[] - tank_ps_tbl = {}, - tank_data_tbl = {}, - - env_d_ps = psil.create(), - env_d_data = {} + tank_ps_tbl = {}, ---@type psil[] + tank_data_tbl = {} ---@type dynamicv_session_db[] } -- create induction and SPS tables (currently only 1 of each is supported) @@ -151,7 +140,7 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale) end -- create unit data structures - io.units = {} + io.units = {} ---@type ioctl_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 @@ -160,7 +149,10 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale) local entry = { unit_id = i, connected = false, - rtu_hw = { boilers = {}, turbines = {} }, + rtu_hw = { + boilers = {}, ---@type { connected: boolean, faulted: boolean }[] + turbines = {} ---@type { connected: boolean, faulted: boolean }[] + }, num_boilers = 0, num_turbines = 0, @@ -208,7 +200,7 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale) t_trip = { ack = function () ack(12) end, reset = function () reset(12) end } }, - ---@type alarms + ---@type { [ALARM]: ALARM_STATE } alarms = { ALARM_STATE.INACTIVE, -- containment breach ALARM_STATE.INACTIVE, -- containment radiation @@ -224,19 +216,19 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale) ALARM_STATE.INACTIVE -- turbine trip }, - annunciator = {}, ---@type annunciator + annunciator = {}, ---@type annunciator unit_ps = psil.create(), - reactor_data = {}, ---@type reactor_db + reactor_data = {}, ---@type reactor_db - boiler_ps_tbl = {}, - boiler_data_tbl = {}, + boiler_ps_tbl = {}, ---@type psil[] + boiler_data_tbl = {}, ---@type boilerv_session_db[] - turbine_ps_tbl = {}, - turbine_data_tbl = {}, + turbine_ps_tbl = {}, ---@type psil[] + turbine_data_tbl = {}, ---@type turbinev_session_db[] - tank_ps_tbl = {}, - tank_data_tbl = {} + tank_ps_tbl = {}, ---@type psil[] + tank_data_tbl = {} ---@type dynamicv_session_db[] } -- on other facility modes, overwrite unit TANK option with facility tank defs @@ -357,8 +349,8 @@ end -- record and publish multiblock RTU build data ---@param id integer ---@param entry table ----@param data_tbl table ----@param ps_tbl table +---@param data_tbl (imatrix_session_db|sps_session_db|dynamicv_session_db|turbinev_session_db|boilerv_session_db)[] +---@param ps_tbl psil[] ---@param create boolean? true to create an entry if non exists, false to fail on missing ---@return boolean ok true if data saved, false if invalid ID local function _record_multiblock_build(id, entry, data_tbl, ps_tbl, create) @@ -369,8 +361,8 @@ local function _record_multiblock_build(id, entry, data_tbl, ps_tbl, create) data_tbl[id] = {} end - data_tbl[id].formed = entry[1] ---@type boolean - data_tbl[id].build = entry[2] ---@type table + data_tbl[id].formed = entry[1] + data_tbl[id].build = entry[2] ps_tbl[id].publish("formed", entry[1]) @@ -444,7 +436,7 @@ function iocontrol.record_unit_builds(builds) else -- reactor build if type(build.reactor) == "table" then - unit.reactor_data.mek_struct = build.reactor ---@type mek_struct + unit.reactor_data.mek_struct = build.reactor for key, val in pairs(unit.reactor_data.mek_struct) do unit.unit_ps.publish(key, val) end @@ -497,10 +489,10 @@ end ---@param ps psil ---@return boolean is_faulted local function _record_multiblock_status(entry, data, ps) - local is_faulted = entry[1] ---@type boolean - data.formed = entry[2] ---@type boolean - data.state = entry[3] ---@type table - data.tanks = entry[4] ---@type table + local is_faulted = entry[1] + data.formed = entry[2] + data.state = entry[3] + data.tanks = entry[4] ps.publish("formed", data.formed) ps.publish("faulted", is_faulted) @@ -600,8 +592,8 @@ function iocontrol.update_facility_status(status) -- power statistics if type(rtu_statuses.power) == "table" and #rtu_statuses.power == 4 then - local data = fac.induction_data_tbl[1] ---@type imatrix_session_db - local ps = fac.induction_ps_tbl[1] ---@type psil + local data = fac.induction_data_tbl[1] + local ps = fac.induction_ps_tbl[1] local chg = tonumber(rtu_statuses.power[1]) local in_f = tonumber(rtu_statuses.power[2]) @@ -636,23 +628,23 @@ function iocontrol.update_facility_status(status) for id, matrix in pairs(rtu_statuses.induction) do if type(fac.induction_data_tbl[id]) == "table" then - local data = fac.induction_data_tbl[id] ---@type imatrix_session_db - local ps = fac.induction_ps_tbl[id] ---@type psil + local data = fac.induction_data_tbl[id] + local ps = fac.induction_ps_tbl[id] local rtu_faulted = _record_multiblock_status(matrix, data, ps) if rtu_faulted then - ps.publish("computed_status", 3) -- faulted + ps.publish("computed_status", 3) -- faulted elseif data.formed then if data.tanks.energy_fill >= 0.99 then - ps.publish("computed_status", 6) -- full + ps.publish("computed_status", 6) -- full elseif data.tanks.energy_fill <= 0.01 then - ps.publish("computed_status", 5) -- empty + ps.publish("computed_status", 5) -- empty else - ps.publish("computed_status", 4) -- on-line + ps.publish("computed_status", 4) -- on-line end else - ps.publish("computed_status", 2) -- not formed + ps.publish("computed_status", 2) -- not formed end else log.debug(util.c(log_header, "invalid induction matrix id ", id)) @@ -674,21 +666,21 @@ function iocontrol.update_facility_status(status) for id, sps in pairs(rtu_statuses.sps) do if type(fac.sps_data_tbl[id]) == "table" then - local data = fac.sps_data_tbl[id] ---@type sps_session_db - local ps = fac.sps_ps_tbl[id] ---@type psil + local data = fac.sps_data_tbl[id] + local ps = fac.sps_ps_tbl[id] local rtu_faulted = _record_multiblock_status(sps, data, ps) if rtu_faulted then - ps.publish("computed_status", 3) -- faulted + ps.publish("computed_status", 3) -- faulted elseif data.formed then if data.state.process_rate > 0 then - ps.publish("computed_status", 5) -- active + ps.publish("computed_status", 5) -- active else - ps.publish("computed_status", 4) -- idle + ps.publish("computed_status", 4) -- idle end else - ps.publish("computed_status", 2) -- not formed + ps.publish("computed_status", 2) -- not formed end io.facility.ps.publish("am_rate", data.state.process_rate * 1000) @@ -712,23 +704,23 @@ function iocontrol.update_facility_status(status) for id, tank in pairs(rtu_statuses.tanks) do if type(fac.tank_data_tbl[id]) == "table" then - local data = fac.tank_data_tbl[id] ---@type dynamicv_session_db - local ps = fac.tank_ps_tbl[id] ---@type psil + local data = fac.tank_data_tbl[id] + local ps = fac.tank_ps_tbl[id] local rtu_faulted = _record_multiblock_status(tank, data, ps) if rtu_faulted then - ps.publish("computed_status", 3) -- faulted + ps.publish("computed_status", 3) -- faulted elseif data.formed then if data.tanks.fill >= 0.99 then - ps.publish("computed_status", 6) -- full + ps.publish("computed_status", 6) -- full elseif data.tanks.fill < 0.20 then - ps.publish("computed_status", 5) -- low + ps.publish("computed_status", 5) -- low else - ps.publish("computed_status", 4) -- on-line + ps.publish("computed_status", 4) -- on-line end else - ps.publish("computed_status", 2) -- not formed + ps.publish("computed_status", 2) -- not formed end else log.debug(util.c(log_header, "invalid dynamic tank id ", id)) @@ -812,7 +804,7 @@ function iocontrol.update_unit_statuses(statuses) for i = 1, #statuses do local log_header = util.c("iocontrol.update_unit_statuses[unit ", i, "]: ") - local unit = io.units[i] ---@type ioctl_unit + local unit = io.units[i] local status = statuses[i] local burn_rate = 0.0 @@ -848,8 +840,8 @@ function iocontrol.update_unit_statuses(statuses) log.debug(log_header .. "reactor general status length mismatch") end - unit.reactor_data.rps_status = rps_status ---@type rps_status - unit.reactor_data.mek_status = mek_status ---@type mek_status + unit.reactor_data.rps_status = rps_status + unit.reactor_data.mek_status = mek_status -- if status hasn't been received, mek_status = {} if type(unit.reactor_data.mek_status.act_burn_rate) == "number" then @@ -858,18 +850,18 @@ function iocontrol.update_unit_statuses(statuses) end if unit.reactor_data.mek_status.status then - unit.unit_ps.publish("computed_status", 5) -- running + unit.unit_ps.publish("computed_status", 5) -- running else if unit.reactor_data.no_reactor then - unit.unit_ps.publish("computed_status", 3) -- faulted + unit.unit_ps.publish("computed_status", 3) -- faulted elseif not unit.reactor_data.formed then - unit.unit_ps.publish("computed_status", 2) -- multiblock not formed + unit.unit_ps.publish("computed_status", 2) -- multiblock not formed elseif unit.reactor_data.rps_status.force_dis then - unit.unit_ps.publish("computed_status", 7) -- reactor force disabled + unit.unit_ps.publish("computed_status", 7) -- reactor force disabled elseif unit.reactor_data.rps_tripped and unit.reactor_data.rps_trip_cause ~= "manual" then - unit.unit_ps.publish("computed_status", 6) -- SCRAM + unit.unit_ps.publish("computed_status", 6) -- SCRAM else - unit.unit_ps.publish("computed_status", 4) -- disabled + unit.unit_ps.publish("computed_status", 4) -- disabled end end @@ -917,24 +909,24 @@ function iocontrol.update_unit_statuses(statuses) for id, boiler in pairs(rtu_statuses.boilers) do if type(unit.boiler_data_tbl[id]) == "table" then - local data = unit.boiler_data_tbl[id] ---@type boilerv_session_db - local ps = unit.boiler_ps_tbl[id] ---@type psil + local data = unit.boiler_data_tbl[id] + local ps = unit.boiler_ps_tbl[id] local rtu_faulted = _record_multiblock_status(boiler, data, ps) unit.rtu_hw.boilers[id].faulted = rtu_faulted if rtu_faulted then - ps.publish("computed_status", 3) -- faulted + ps.publish("computed_status", 3) -- faulted elseif data.formed then boil_sum = boil_sum + data.state.boil_rate if data.state.boil_rate > 0 then - ps.publish("computed_status", 5) -- active + ps.publish("computed_status", 5) -- active else - ps.publish("computed_status", 4) -- idle + ps.publish("computed_status", 4) -- idle end else - ps.publish("computed_status", 2) -- not formed + ps.publish("computed_status", 2) -- not formed end else log.debug(util.c(log_header, "invalid boiler id ", id)) @@ -964,26 +956,26 @@ function iocontrol.update_unit_statuses(statuses) for id, turbine in pairs(rtu_statuses.turbines) do if type(unit.turbine_data_tbl[id]) == "table" then - local data = unit.turbine_data_tbl[id] ---@type turbinev_session_db - local ps = unit.turbine_ps_tbl[id] ---@type psil + local data = unit.turbine_data_tbl[id] + local ps = unit.turbine_ps_tbl[id] local rtu_faulted = _record_multiblock_status(turbine, data, ps) unit.rtu_hw.turbines[id].faulted = rtu_faulted if rtu_faulted then - ps.publish("computed_status", 3) -- faulted + ps.publish("computed_status", 3) -- faulted elseif data.formed then flow_sum = flow_sum + data.state.flow_rate if data.tanks.energy_fill >= 0.99 then - ps.publish("computed_status", 6) -- trip + ps.publish("computed_status", 6) -- trip elseif data.state.flow_rate < 100 then - ps.publish("computed_status", 4) -- idle + ps.publish("computed_status", 4) -- idle else - ps.publish("computed_status", 5) -- active + ps.publish("computed_status", 5) -- active end else - ps.publish("computed_status", 2) -- not formed + ps.publish("computed_status", 2) -- not formed end else log.debug(util.c(log_header, "invalid turbine id ", id)) @@ -1008,23 +1000,23 @@ function iocontrol.update_unit_statuses(statuses) for id, tank in pairs(rtu_statuses.tanks) do if type(unit.tank_data_tbl[id]) == "table" then - local data = unit.tank_data_tbl[id] ---@type dynamicv_session_db - local ps = unit.tank_ps_tbl[id] ---@type psil + local data = unit.tank_data_tbl[id] + local ps = unit.tank_ps_tbl[id] local rtu_faulted = _record_multiblock_status(tank, data, ps) if rtu_faulted then - ps.publish("computed_status", 3) -- faulted + ps.publish("computed_status", 3) -- faulted elseif data.formed then if data.tanks.fill >= 0.99 then - ps.publish("computed_status", 6) -- full + ps.publish("computed_status", 6) -- full elseif data.tanks.fill < 0.20 then - ps.publish("computed_status", 5) -- low + ps.publish("computed_status", 5) -- low else - ps.publish("computed_status", 4) -- on-line + ps.publish("computed_status", 4) -- on-line end else - ps.publish("computed_status", 2) -- not formed + ps.publish("computed_status", 2) -- not formed end else log.debug(util.c(log_header, "invalid dynamic tank id ", id)) diff --git a/coordinator/process.lua b/coordinator/process.lua index 5f7f010..f96b3e7 100644 --- a/coordinator/process.lua +++ b/coordinator/process.lua @@ -29,13 +29,13 @@ local pctl = { burn_target = 0.0, charge_target = 0.0, gen_target = 0.0, - limits = {}, + limits = {}, ---@type number[] waste_product = PRODUCT.PLUTONIUM, pu_fallback = false, sps_low_power = false }, - waste_modes = {}, - priority_groups = {} + waste_modes = {}, ---@type WASTE_MODE[] + priority_groups = {} ---@type AUTO_GROUP[] }, commands = { unit = {}, ---@type process_command_state[][] @@ -46,7 +46,7 @@ local pctl = { ---@class process_command_state ---@field active boolean if this command is live ---@field timeout integer expiration time of this command request ----@field requestors table list of callbacks from the requestors +---@field requestors function[] list of callbacks from the requestors -- write auto process control to config file local function _write_auto_config() @@ -80,8 +80,8 @@ function process.init(iocontrol, coord_comms) ctl_proc.limits[i] = 0.1 end - local ctrl_states = settings.get("ControlStates", {}) - local config = ctrl_states.process ---@type sys_auto_config + local ctrl_states = settings.get("ControlStates", {}) ---@type sys_control_states + local config = ctrl_states.process -- facility auto control configuration if type(config) == "table" then @@ -103,7 +103,7 @@ function process.init(iocontrol, coord_comms) 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] ---@type ioctl_unit + local unit = pctl.io.units[id] unit.unit_ps.publish("burn_limit", ctl_proc.limits[id]) end @@ -116,7 +116,7 @@ function process.init(iocontrol, coord_comms) end -- unit waste states - local waste_modes = ctrl_states.waste_modes ---@type table|nil + local waste_modes = ctrl_states.waste_modes if type(waste_modes) == "table" then for id, mode in pairs(waste_modes) do pctl.control_states.waste_modes[id] = mode @@ -127,7 +127,7 @@ function process.init(iocontrol, coord_comms) end -- unit priority groups - local prio_groups = ctrl_states.priority_groups ---@type table|nil + local prio_groups = ctrl_states.priority_groups if type(prio_groups) == "table" then for id, group in pairs(prio_groups) do pctl.control_states.priority_groups[id] = group @@ -443,7 +443,7 @@ end ---@param burn_target number burn rate target ---@param charge_target number charge target ---@param gen_target number generation rate target ----@param limits table unit burn rate limits +---@param limits number[] unit burn rate limits function process.save(mode, burn_target, charge_target, gen_target, limits) log.debug("PROCESS: SAVE") @@ -473,7 +473,7 @@ function process.start_ack_handle(response) for i = 1, math.min(#response[6], pctl.io.facility.num_units) do ctl_proc.limits[i] = response[6][i] - local unit = pctl.io.units[i] ---@type ioctl_unit + local unit = pctl.io.units[i] unit.unit_ps.publish("burn_limit", ctl_proc.limits[i]) end diff --git a/coordinator/renderer.lua b/coordinator/renderer.lua index f2d2418..cfa5013 100644 --- a/coordinator/renderer.lua +++ b/coordinator/renderer.lua @@ -19,7 +19,7 @@ local unit_view = require("coordinator.ui.layout.unit_view") local core = require("graphics.core") local flasher = require("graphics.flasher") -local DisplayBox = require("graphics.elements.displaybox") +local DisplayBox = require("graphics.elements.DisplayBox") local log_render = coordinator.log_render @@ -30,20 +30,20 @@ local renderer = {} local engine = { color_mode = 1, ---@type COLOR_MODE monitors = nil, ---@type monitors_struct|nil - dmesg_window = nil, ---@type table|nil + dmesg_window = nil, ---@type Window|nil ui_ready = false, fp_ready = false, ui = { - front_panel = nil, ---@type graphics_element|nil - main_display = nil, ---@type graphics_element|nil - flow_display = nil, ---@type graphics_element|nil - unit_displays = {} + front_panel = nil, ---@type DisplayBox|nil + main_display = nil, ---@type DisplayBox|nil + flow_display = nil, ---@type DisplayBox|nil + unit_displays = {} ---@type (DisplayBox|nil)[] }, disable_flow_view = false } -- init a display to the "default", but set text scale to 0.5 ----@param monitor table monitor +---@param monitor Monitor monitor local function _init_display(monitor) monitor.setTextScale(0.5) monitor.setTextColor(colors.white) @@ -64,7 +64,7 @@ local function _init_display(monitor) end -- print out that the monitor is too small ----@param monitor table monitor +---@param monitor Monitor monitor local function _print_too_small(monitor) monitor.setCursorPos(1, 1) monitor.setBackgroundColor(colors.black) @@ -275,7 +275,7 @@ function renderer.fp_ready() return engine.fp_ready end function renderer.ui_ready() return engine.ui_ready end -- handle a monitor peripheral being disconnected ----@param device table monitor +---@param device Monitor monitor ---@return boolean is_used if the monitor is one of the configured monitors function renderer.handle_disconnect(device) local is_used = false @@ -326,7 +326,7 @@ end -- handle a monitor peripheral being reconnected ---@param name string monitor name ----@param device table monitor +---@param device Monitor monitor ---@return boolean is_used if the monitor is one of the configured monitors function renderer.handle_reconnect(name, device) local is_used = false @@ -373,7 +373,7 @@ function renderer.handle_resize(name) if not engine.monitors then return false, false end if engine.monitors.main_name == name and engine.monitors.main then - local device = engine.monitors.main ---@type table + local device = engine.monitors.main ---@type Monitor -- this is necessary if the bottom left block was broken and on reconnect _init_display(device) @@ -416,7 +416,7 @@ function renderer.handle_resize(name) end else engine.dmesg_window.redraw() end elseif engine.monitors.flow_name == name and engine.monitors.flow then - local device = engine.monitors.flow ---@type table + local device = engine.monitors.flow ---@type Monitor -- this is necessary if the bottom left block was broken and on reconnect _init_display(device) diff --git a/coordinator/session/apisessions.lua b/coordinator/session/apisessions.lua index 5c4a38a..30fee09 100644 --- a/coordinator/session/apisessions.lua +++ b/coordinator/session/apisessions.lua @@ -13,7 +13,7 @@ local self = { nic = nil, ---@type nic config = nil, ---@type crd_config next_id = 0, - sessions = {} + sessions = {} ---@type pkt_session_struct[] } -- PRIVATE FUNCTIONS -- @@ -129,7 +129,7 @@ end ---@param timer_event number function apisessions.check_all_watchdogs(timer_event) for i = 1, #self.sessions do - local session = self.sessions[i] ---@type pkt_session_struct + local session = self.sessions[i] if session.open then local triggered = session.instance.check_wd(timer_event) if triggered then @@ -143,7 +143,7 @@ end -- iterate all the API sessions function apisessions.iterate_all() for i = 1, #self.sessions do - local session = self.sessions[i] ---@type pkt_session_struct + local session = self.sessions[i] if session.open and session.instance.iterate() then _api_handle_outq(session) @@ -168,7 +168,7 @@ end -- close all open connections function apisessions.close_all() for i = 1, #self.sessions do - local session = self.sessions[i] ---@type pkt_session_struct + local session = self.sessions[i] if session.open then _shutdown(session) end end diff --git a/coordinator/session/pocket.lua b/coordinator/session/pocket.lua index 0205397..aba0584 100644 --- a/coordinator/session/pocket.lua +++ b/coordinator/session/pocket.lua @@ -217,7 +217,7 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout) _send(CRDN_TYPE.API_GET_FAC, data) elseif pkt.type == CRDN_TYPE.API_GET_UNIT then if pkt.length == 1 and type(pkt.data[1]) == "number" then - local u = db.units[pkt.data[1]] ---@type ioctl_unit + local u = db.units[pkt.data[1]] if u then local data = { diff --git a/coordinator/sounder.lua b/coordinator/sounder.lua index e7a02ac..7ec48c5 100644 --- a/coordinator/sounder.lua +++ b/coordinator/sounder.lua @@ -9,7 +9,7 @@ local log = require("scada-common.log") local sounder = {} local alarm_ctl = { - speaker = nil, + speaker = nil, ---@type Speaker volume = 0.5, stream = audio.new_stream() } @@ -24,7 +24,7 @@ local function play() end -- initialize the annunciator alarm system ----@param speaker table speaker peripheral +---@param speaker Speaker speaker peripheral ---@param volume number speaker volume function sounder.init(speaker, volume) alarm_ctl.speaker = speaker @@ -36,7 +36,7 @@ function sounder.init(speaker, volume) end -- reconnect the speaker peripheral ----@param speaker table speaker peripheral +---@param speaker Speaker speaker peripheral function sounder.reconnect(speaker) alarm_ctl.speaker = speaker alarm_ctl.playing = false @@ -44,7 +44,7 @@ function sounder.reconnect(speaker) end -- set alarm tones ----@param states table alarm tone commands from supervisor +---@param states { [TONE]: boolean } alarm tone commands from supervisor function sounder.set(states) -- set tone states for id = 1, #states do alarm_ctl.stream.set_active(id, states[id]) end diff --git a/coordinator/startup.lua b/coordinator/startup.lua index 52ed4a6..637f500 100644 --- a/coordinator/startup.lua +++ b/coordinator/startup.lua @@ -19,7 +19,7 @@ local renderer = require("coordinator.renderer") local sounder = require("coordinator.sounder") local threads = require("coordinator.threads") -local COORDINATOR_VERSION = "v1.5.8" +local COORDINATOR_VERSION = "v1.5.9" local CHUNK_LOAD_DELAY_S = 30.0 @@ -152,7 +152,7 @@ local function main() -- core coordinator devices crd_dev = { modem = ppm.get_wireless_modem(), - speaker = ppm.get_device("speaker") + speaker = ppm.get_device("speaker") ---@type Speaker|nil }, -- system objects diff --git a/coordinator/threads.lua b/coordinator/threads.lua index cefe705..0392178 100644 --- a/coordinator/threads.lua +++ b/coordinator/threads.lua @@ -68,6 +68,7 @@ function threads.thread__main(smem) if type ~= nil and device ~= nil then if type == "modem" then + ---@cast device Modem -- we only really care if this is our wireless modem -- if it is another modem, handle other peripheral losses separately if nic.is_modem(device) then @@ -91,8 +92,10 @@ function threads.thread__main(smem) log_sys("non-comms modem disconnected") end elseif type == "monitor" then + ---@cast device Monitor smem.q.mq_render.push_data(MQ__RENDER_DATA.MON_DISCONNECT, device) elseif type == "speaker" then + ---@cast device Speaker log_sys("lost alarm sounder speaker") iocontrol.fp_has_speaker(false) end @@ -102,6 +105,7 @@ function threads.thread__main(smem) if type ~= nil and device ~= nil then if type == "modem" then + ---@cast device Modem if device.isWireless() and not nic.is_connected() then -- reconnected modem log_sys("comms modem reconnected") @@ -113,8 +117,10 @@ function threads.thread__main(smem) log_sys("wired modem reconnected") end elseif type == "monitor" then + ---@cast device Monitor smem.q.mq_render.push_data(MQ__RENDER_DATA.MON_CONNECT, { name = param1, device = device }) elseif type == "speaker" then + ---@cast device Speaker log_sys("alarm sounder speaker reconnected") sounder.reconnect(device) iocontrol.fp_has_speaker(true) diff --git a/coordinator/ui/components/boiler.lua b/coordinator/ui/components/boiler.lua index 86866f5..38bd05c 100644 --- a/coordinator/ui/components/boiler.lua +++ b/coordinator/ui/components/boiler.lua @@ -4,18 +4,18 @@ local style = require("coordinator.ui.style") local core = require("graphics.core") -local Rectangle = require("graphics.elements.rectangle") -local TextBox = require("graphics.elements.textbox") +local Rectangle = require("graphics.elements.Rectangle") +local TextBox = require("graphics.elements.TextBox") -local DataIndicator = require("graphics.elements.indicators.data") -local StateIndicator = require("graphics.elements.indicators.state") -local VerticalBar = require("graphics.elements.indicators.vbar") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local StateIndicator = require("graphics.elements.indicators.StateIndicator") +local VerticalBar = require("graphics.elements.indicators.VerticalBar") local cpair = core.cpair local border = core.border -- new boiler view ----@param root graphics_element parent +---@param root Container parent ---@param x integer top left x ---@param y integer top left y ---@param ps psil ps interface diff --git a/coordinator/ui/components/imatrix.lua b/coordinator/ui/components/imatrix.lua index cfec34d..186f7bd 100644 --- a/coordinator/ui/components/imatrix.lua +++ b/coordinator/ui/components/imatrix.lua @@ -6,15 +6,15 @@ local style = require("coordinator.ui.style") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local Rectangle = require("graphics.elements.rectangle") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local Rectangle = require("graphics.elements.Rectangle") +local TextBox = require("graphics.elements.TextBox") -local DataIndicator = require("graphics.elements.indicators.data") -local IndicatorLight = require("graphics.elements.indicators.light") -local PowerIndicator = require("graphics.elements.indicators.power") -local StateIndicator = require("graphics.elements.indicators.state") -local VerticalBar = require("graphics.elements.indicators.vbar") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local IndicatorLight = require("graphics.elements.indicators.IndicatorLight") +local PowerIndicator = require("graphics.elements.indicators.PowerIndicator") +local StateIndicator = require("graphics.elements.indicators.StateIndicator") +local VerticalBar = require("graphics.elements.indicators.VerticalBar") local cpair = core.cpair local border = core.border @@ -22,7 +22,7 @@ local border = core.border local ALIGN = core.ALIGN -- new induction matrix view ----@param root graphics_element parent +---@param root Container parent ---@param x integer top left x ---@param y integer top left y ---@param data imatrix_session_db matrix data diff --git a/coordinator/ui/components/pkt_entry.lua b/coordinator/ui/components/pkt_entry.lua index e377e2e..b7a8d1e 100644 --- a/coordinator/ui/components/pkt_entry.lua +++ b/coordinator/ui/components/pkt_entry.lua @@ -8,17 +8,17 @@ local style = require("coordinator.ui.style") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local TextBox = require("graphics.elements.TextBox") -local DataIndicator = require("graphics.elements.indicators.data") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") local ALIGN = core.ALIGN local cpair = core.cpair -- create a pocket list entry ----@param parent graphics_element parent +---@param parent ListBox parent ---@param id integer PKT session ID local function init(parent, id) local s_hi_box = style.fp_theme.highlight_box diff --git a/coordinator/ui/components/process_ctl.lua b/coordinator/ui/components/process_ctl.lua index 85e0436..44c9ceb 100644 --- a/coordinator/ui/components/process_ctl.lua +++ b/coordinator/ui/components/process_ctl.lua @@ -8,20 +8,20 @@ local style = require("coordinator.ui.style") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local Rectangle = require("graphics.elements.rectangle") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local Rectangle = require("graphics.elements.Rectangle") +local TextBox = require("graphics.elements.TextBox") -local DataIndicator = require("graphics.elements.indicators.data") -local IndicatorLight = require("graphics.elements.indicators.light") -local RadIndicator = require("graphics.elements.indicators.rad") -local StateIndicator = require("graphics.elements.indicators.state") -local TriIndicatorLight = require("graphics.elements.indicators.trilight") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local IndicatorLight = require("graphics.elements.indicators.IndicatorLight") +local RadIndicator = require("graphics.elements.indicators.RadIndicator") +local StateIndicator = require("graphics.elements.indicators.StateIndicator") +local TriIndicatorLight = require("graphics.elements.indicators.TriIndicatorLight") -local Checkbox = require("graphics.elements.controls.checkbox") -local HazardButton = require("graphics.elements.controls.hazard_button") -local RadioButton = require("graphics.elements.controls.radio_button") -local SpinboxNumeric = require("graphics.elements.controls.spinbox_numeric") +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 ALIGN = core.ALIGN @@ -33,7 +33,7 @@ local bw_fg_bg = style.bw_fg_bg local period = core.flasher.PERIOD -- new process control view ----@param root graphics_element parent +---@param root Container parent ---@param x integer top left x ---@param y integer top left y local function new_view(root, x, y) @@ -131,7 +131,7 @@ local function new_view(root, x, y) 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} - local b_target = SpinboxNumeric{parent=burn_target,x=11,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,arrow_fg_bg=arrow_fg_bg,arrow_disable=style.theme.disabled} + local b_target = NumericSpinbox{parent=burn_target,x=11,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,arrow_fg_bg=arrow_fg_bg,arrow_disable=style.theme.disabled} TextBox{parent=burn_target,x=18,y=2,text="mB/t",fg_bg=style.theme.label_fg} local burn_sum = DataIndicator{parent=targets,x=9,y=4,label="",format="%18.1f",value=0,unit="mB/t",commas=true,lu_colors=black,width=23,fg_bg=blk_brn} @@ -142,7 +142,7 @@ local function new_view(root, x, y) 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 = SpinboxNumeric{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} + 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} @@ -153,7 +153,7 @@ local function new_view(root, x, y) 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} - local g_target = SpinboxNumeric{parent=gen_target,x=8,y=1,whole_num_precision=9,fractional_precision=0,min=0,arrow_fg_bg=arrow_fg_bg,arrow_disable=style.theme.disabled} + local g_target = NumericSpinbox{parent=gen_target,x=8,y=1,whole_num_precision=9,fractional_precision=0,min=0,arrow_fg_bg=arrow_fg_bg,arrow_disable=style.theme.disabled} TextBox{parent=gen_target,x=18,y=2,text="k"..db.energy_label.."/t",fg_bg=style.theme.label_fg} local cur_gen = DataIndicator{parent=targets,x=9,y=14,label="",format="%17d",value=0,unit="k"..db.energy_label.."/t",commas=true,lu_colors=black,width=23,fg_bg=blk_brn} @@ -177,7 +177,7 @@ local function new_view(root, x, y) local cur_lu = style.theme.disabled if i <= facility.num_units then - unit = units[i] ---@type ioctl_unit + unit = units[i] tag_fg_bg = cpair(colors.black, colors.lightBlue) lim_fg_bg = s_hi_box label_fg = style.theme.label_fg @@ -191,7 +191,7 @@ local function new_view(root, x, y) 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} - local lim = SpinboxNumeric{parent=lim_ctl,x=2,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,arrow_fg_bg=arrow_fg_bg,arrow_disable=style.theme.disabled,fg_bg=lim_fg_bg} + local lim = NumericSpinbox{parent=lim_ctl,x=2,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,arrow_fg_bg=arrow_fg_bg,arrow_disable=style.theme.disabled,fg_bg=lim_fg_bg} TextBox{parent=lim_ctl,x=9,y=2,text="mB/t",width=4,fg_bg=label_fg} local cur_burn = DataIndicator{parent=limit_div,x=9,y=_y+3,label="",format="%7.1f",value=0,unit="mB/t",commas=false,lu_colors=cpair(cur_lu,cur_lu),width=14,fg_bg=cur_fg_bg} @@ -234,7 +234,7 @@ local function new_view(root, x, y) local degraded = IndicatorLight{parent=lights,x=2,y=3,label="Degraded",colors=cpair(ind_red.fgd,ind_off),flash=true,period=period.BLINK_250_MS} if i <= facility.num_units then - local unit = units[i] ---@type ioctl_unit + local unit = units[i] ready.register(unit.unit_ps, "U_AutoReady", ready.update) degraded.register(unit.unit_ps, "U_AutoDegraded", degraded.update) @@ -323,7 +323,7 @@ local function new_view(root, x, y) local waste_status = Div{parent=proc,width=24,height=4,x=57,y=1,} for i = 1, facility.num_units do - local unit = units[i] ---@type ioctl_unit + local unit = units[i] TextBox{parent=waste_status,y=i,text="U"..i.." Waste",width=8} local a_waste = IndicatorLight{parent=waste_status,x=10,y=i,label="Auto",colors=ind_wht} diff --git a/coordinator/ui/components/reactor.lua b/coordinator/ui/components/reactor.lua index 2319f76..f1cec6d 100644 --- a/coordinator/ui/components/reactor.lua +++ b/coordinator/ui/components/reactor.lua @@ -6,18 +6,18 @@ local style = require("coordinator.ui.style") local core = require("graphics.core") -local Rectangle = require("graphics.elements.rectangle") -local TextBox = require("graphics.elements.textbox") +local Rectangle = require("graphics.elements.Rectangle") +local TextBox = require("graphics.elements.TextBox") -local DataIndicator = require("graphics.elements.indicators.data") -local HorizontalBar = require("graphics.elements.indicators.hbar") -local StateIndicator = require("graphics.elements.indicators.state") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local HorizontalBar = require("graphics.elements.indicators.HorizontalBar") +local StateIndicator = require("graphics.elements.indicators.StateIndicator") local cpair = core.cpair local border = core.border -- create new reactor view ----@param root graphics_element parent +---@param root Container parent ---@param x integer top left x ---@param y integer top left y ---@param ps psil ps interface diff --git a/coordinator/ui/components/turbine.lua b/coordinator/ui/components/turbine.lua index fd6049a..6ce3d11 100644 --- a/coordinator/ui/components/turbine.lua +++ b/coordinator/ui/components/turbine.lua @@ -4,19 +4,19 @@ local style = require("coordinator.ui.style") local core = require("graphics.core") -local Rectangle = require("graphics.elements.rectangle") -local TextBox = require("graphics.elements.textbox") +local Rectangle = require("graphics.elements.Rectangle") +local TextBox = require("graphics.elements.TextBox") -local DataIndicator = require("graphics.elements.indicators.data") -local PowerIndicator = require("graphics.elements.indicators.power") -local StateIndicator = require("graphics.elements.indicators.state") -local VerticalBar = require("graphics.elements.indicators.vbar") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local PowerIndicator = require("graphics.elements.indicators.PowerIndicator") +local StateIndicator = require("graphics.elements.indicators.StateIndicator") +local VerticalBar = require("graphics.elements.indicators.VerticalBar") local cpair = core.cpair local border = core.border -- new turbine view ----@param root graphics_element parent +---@param root Container parent ---@param x integer top left x ---@param y integer top left y ---@param ps psil ps interface diff --git a/coordinator/ui/components/unit_detail.lua b/coordinator/ui/components/unit_detail.lua index fcfd062..709b684 100644 --- a/coordinator/ui/components/unit_detail.lua +++ b/coordinator/ui/components/unit_detail.lua @@ -11,23 +11,23 @@ local style = require("coordinator.ui.style") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local Rectangle = require("graphics.elements.rectangle") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local Rectangle = require("graphics.elements.Rectangle") +local TextBox = require("graphics.elements.TextBox") -local AlarmLight = require("graphics.elements.indicators.alight") -local CoreMap = require("graphics.elements.indicators.coremap") -local DataIndicator = require("graphics.elements.indicators.data") -local IndicatorLight = require("graphics.elements.indicators.light") -local RadIndicator = require("graphics.elements.indicators.rad") -local TriIndicatorLight = require("graphics.elements.indicators.trilight") -local VerticalBar = require("graphics.elements.indicators.vbar") +local AlarmLight = require("graphics.elements.indicators.AlarmLight") +local CoreMap = require("graphics.elements.indicators.CoreMap") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local IndicatorLight = require("graphics.elements.indicators.IndicatorLight") +local RadIndicator = require("graphics.elements.indicators.RadIndicator") +local TriIndicatorLight = require("graphics.elements.indicators.TriIndicatorLight") +local VerticalBar = require("graphics.elements.indicators.VerticalBar") -local HazardButton = require("graphics.elements.controls.hazard_button") -local MultiButton = require("graphics.elements.controls.multi_button") -local PushButton = require("graphics.elements.controls.push_button") -local RadioButton = require("graphics.elements.controls.radio_button") -local SpinboxNumeric = require("graphics.elements.controls.spinbox_numeric") +local HazardButton = require("graphics.elements.controls.HazardButton") +local MultiButton = require("graphics.elements.controls.MultiButton") +local NumericSpinbox = require("graphics.elements.controls.NumericSpinbox") +local PushButton = require("graphics.elements.controls.PushButton") +local RadioButton = require("graphics.elements.controls.RadioButton") local AUTO_GROUP = types.AUTO_GROUP @@ -42,7 +42,7 @@ local gry_wht = style.gray_white local period = core.flasher.PERIOD -- create a unit view ----@param parent graphics_element parent +---@param parent Container parent ---@param id integer local function init(parent, id) local s_hi_box = style.theme.highlight_box @@ -62,7 +62,7 @@ local function init(parent, id) local ind_wht = style.ind_wht local db = iocontrol.get_db() - local unit = db.units[id] ---@type ioctl_unit + local unit = db.units[id] local f_ps = db.facility.ps local main = Div{parent=parent,x=1,y=1} @@ -361,7 +361,7 @@ local function init(parent, id) ---------------------- local burn_control = Div{parent=main,x=12,y=28,width=19,height=3,fg_bg=s_hi_box} - local burn_rate = SpinboxNumeric{parent=burn_control,x=2,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,arrow_fg_bg=arrow_fg_bg,arrow_disable=style.theme.disabled} + local burn_rate = NumericSpinbox{parent=burn_control,x=2,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,arrow_fg_bg=arrow_fg_bg,arrow_disable=style.theme.disabled} TextBox{parent=burn_control,x=9,y=2,text="mB/t",fg_bg=style.theme.label_fg} local set_burn = function () unit.set_burn(burn_rate.get_value()) end diff --git a/coordinator/ui/components/unit_flow.lua b/coordinator/ui/components/unit_flow.lua index 9ba29be..27e4d0d 100644 --- a/coordinator/ui/components/unit_flow.lua +++ b/coordinator/ui/components/unit_flow.lua @@ -8,16 +8,16 @@ local style = require("coordinator.ui.style") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local PipeNetwork = require("graphics.elements.pipenet") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local PipeNetwork = require("graphics.elements.PipeNetwork") +local TextBox = require("graphics.elements.TextBox") -local Rectangle = require("graphics.elements.rectangle") +local Rectangle = require("graphics.elements.Rectangle") -local DataIndicator = require("graphics.elements.indicators.data") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") -local IndicatorLight = require("graphics.elements.indicators.light") -local TriIndicatorLight = require("graphics.elements.indicators.trilight") +local IndicatorLight = require("graphics.elements.indicators.IndicatorLight") +local TriIndicatorLight = require("graphics.elements.indicators.TriIndicatorLight") local ALIGN = core.ALIGN @@ -31,7 +31,7 @@ local wh_gray = style.wh_gray local lg_gray = style.lg_gray -- make a new unit flow window ----@param parent graphics_element parent +---@param parent Container parent ---@param x integer top left x ---@param y integer top left y ---@param wide boolean whether to render wide version diff --git a/coordinator/ui/components/unit_overview.lua b/coordinator/ui/components/unit_overview.lua index fc4ac4e..a3f41c1 100644 --- a/coordinator/ui/components/unit_overview.lua +++ b/coordinator/ui/components/unit_overview.lua @@ -10,16 +10,16 @@ local reactor_view = require("coordinator.ui.components.reactor") local boiler_view = require("coordinator.ui.components.boiler") local turbine_view = require("coordinator.ui.components.turbine") -local Div = require("graphics.elements.div") -local PipeNetwork = require("graphics.elements.pipenet") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local PipeNetwork = require("graphics.elements.PipeNetwork") +local TextBox = require("graphics.elements.TextBox") local ALIGN = core.ALIGN local pipe = core.pipe -- make a new unit overview window ----@param parent graphics_element parent +---@param parent Container parent ---@param x integer top left x ---@param y integer top left y ---@param unit ioctl_unit unit database entry diff --git a/coordinator/ui/layout/flow_view.lua b/coordinator/ui/layout/flow_view.lua index 7a7f57d..b002f24 100644 --- a/coordinator/ui/layout/flow_view.lua +++ b/coordinator/ui/layout/flow_view.lua @@ -13,15 +13,15 @@ local unit_flow = require("coordinator.ui.components.unit_flow") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local PipeNetwork = require("graphics.elements.pipenet") -local Rectangle = require("graphics.elements.rectangle") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local PipeNetwork = require("graphics.elements.PipeNetwork") +local Rectangle = require("graphics.elements.Rectangle") +local TextBox = require("graphics.elements.TextBox") -local DataIndicator = require("graphics.elements.indicators.data") -local HorizontalBar = require("graphics.elements.indicators.hbar") -local IndicatorLight = require("graphics.elements.indicators.light") -local StateIndicator = require("graphics.elements.indicators.state") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local HorizontalBar = require("graphics.elements.indicators.HorizontalBar") +local IndicatorLight = require("graphics.elements.indicators.IndicatorLight") +local StateIndicator = require("graphics.elements.indicators.StateIndicator") local CONTAINER_MODE = types.CONTAINER_MODE @@ -34,7 +34,7 @@ local pipe = core.pipe local wh_gray = style.wh_gray -- create new flow view ----@param main graphics_element main displaybox +---@param main DisplayBox main displaybox local function init(main) local s_hi_bright = style.theme.highlight_box_bright local s_field = style.theme.field_box @@ -84,8 +84,7 @@ local function init(main) table.insert(water_pipes, pipe(2, y, 2, y + 3, colors.blue, true)) table.insert(water_pipes, pipe(2, y, 21, y, colors.blue, true)) - local u = units[i] ---@type ioctl_unit - local x = util.trinary(u.num_boilers == 0, 45, 84) + local x = util.trinary(units[i].num_boilers == 0, 45, 84) table.insert(water_pipes, pipe(21, y, x, y + 2, colors.blue, true, true)) end end @@ -102,8 +101,7 @@ local function init(main) table.insert(water_pipes, pipe(2, y, 21, y, colors.blue, true)) end - local u = units[i] ---@type ioctl_unit - local x = util.trinary(u.num_boilers == 0, 45, 84) + local x = util.trinary(units[i].num_boilers == 0, 45, 84) table.insert(water_pipes, pipe(21, y, x, y + 2, colors.blue, true, true)) end end diff --git a/coordinator/ui/layout/front_panel.lua b/coordinator/ui/layout/front_panel.lua index 3573fb2..11ae58f 100644 --- a/coordinator/ui/layout/front_panel.lua +++ b/coordinator/ui/layout/front_panel.lua @@ -14,16 +14,16 @@ local pkt_entry = require("coordinator.ui.components.pkt_entry") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local ListBox = require("graphics.elements.listbox") -local MultiPane = require("graphics.elements.multipane") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local ListBox = require("graphics.elements.ListBox") +local MultiPane = require("graphics.elements.MultiPane") +local TextBox = require("graphics.elements.TextBox") -local TabBar = require("graphics.elements.controls.tabbar") +local TabBar = require("graphics.elements.controls.TabBar") -local LED = require("graphics.elements.indicators.led") -local LEDPair = require("graphics.elements.indicators.ledpair") -local RGBLED = require("graphics.elements.indicators.ledrgb") +local LED = require("graphics.elements.indicators.LED") +local LEDPair = require("graphics.elements.indicators.LEDPair") +local RGBLED = require("graphics.elements.indicators.RGBLED") local LINK_STATE = types.PANEL_LINK_STATE @@ -34,7 +34,7 @@ local cpair = core.cpair local led_grn = style.led_grn -- create new front panel view ----@param panel graphics_element main displaybox +---@param panel DisplayBox main displaybox ---@param num_units integer number of units (number of unit monitors) local function init(panel, num_units) local ps = iocontrol.get_db().fp.ps diff --git a/coordinator/ui/layout/main_view.lua b/coordinator/ui/layout/main_view.lua index 33ed43c..ebc9cc3 100644 --- a/coordinator/ui/layout/main_view.lua +++ b/coordinator/ui/layout/main_view.lua @@ -14,14 +14,14 @@ local unit_overview = require("coordinator.ui.components.unit_overview") local core = require("graphics.core") -local TextBox = require("graphics.elements.textbox") +local TextBox = require("graphics.elements.TextBox") -local DataIndicator = require("graphics.elements.indicators.data") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") local ALIGN = core.ALIGN -- create new main view ----@param main graphics_element main displaybox +---@param main DisplayBox main displaybox local function init(main) local s_header = style.theme.header @@ -37,7 +37,8 @@ local function init(main) ping.register(facility.ps, "sv_ping", ping.update) datetime.register(facility.ps, "date_time", datetime.set_value) - local uo_1, uo_2, uo_3, uo_4 ---@type graphics_element + ---@type Div, Div, Div, Div + local uo_1, uo_2, uo_3, uo_4 local cnc_y_start = 3 local row_1_height = 0 diff --git a/coordinator/ui/layout/unit_view.lua b/coordinator/ui/layout/unit_view.lua index 7ac1b7c..7a8ec26 100644 --- a/coordinator/ui/layout/unit_view.lua +++ b/coordinator/ui/layout/unit_view.lua @@ -5,7 +5,7 @@ local unit_detail = require("coordinator.ui.components.unit_detail") -- create a unit view ----@param main graphics_element main displaybox +---@param main DisplayBox main displaybox ---@param id integer local function init(main, id) unit_detail(main, id) diff --git a/coordinator/ui/pgi.lua b/coordinator/ui/pgi.lua index b603465..70ca0b8 100644 --- a/coordinator/ui/pgi.lua +++ b/coordinator/ui/pgi.lua @@ -8,15 +8,17 @@ local util = require("scada-common.util") local pgi = {} local data = { - pkt_list = nil, ---@type nil|graphics_element - pkt_entry = nil, ---@type function + pkt_list = nil, ---@type ListBox|nil + pkt_entry = nil, ---@type function -- session entries - s_entries = { pkt = {} } + s_entries = { + pkt = {} ---@type Div[] + } } -- link list boxes ----@param pkt_list graphics_element pocket list element ----@param pkt_entry function pocket entry constructor +---@param pkt_list ListBox pocket list element +---@param pkt_entry fun(parent: ListBox, id: integer) : Div pocket entry constructor function pgi.link_elements(pkt_list, pkt_entry) data.pkt_list = pkt_list data.pkt_entry = pkt_entry diff --git a/graphics/core.lua b/graphics/core.lua index fe3b291..4b8e13c 100644 --- a/graphics/core.lua +++ b/graphics/core.lua @@ -7,7 +7,7 @@ local flasher = require("graphics.flasher") local core = {} -core.version = "2.3.4" +core.version = "2.4.0" core.flasher = flasher core.events = events @@ -17,6 +17,8 @@ core.events = events ---@enum ALIGN core.ALIGN = { LEFT = 1, CENTER = 2, RIGHT = 3 } +---@alias Container DisplayBox|Div|ListBox|MultiPane|AppMultiPane|Rectangle + ---@class graphics_border ---@field width integer ---@field color color @@ -124,10 +126,10 @@ end -- Interactive Field Manager ---@param e graphics_base element ----@param max_len any max value length ----@param fg_bg any enabled fg/bg ----@param dis_fg_bg any disabled fg/bg ----@param align_right any true to align content right while unfocused +---@param max_len integer max value length +---@param fg_bg cpair enabled fg/bg +---@param dis_fg_bg? cpair disabled fg/bg +---@param align_right? boolean true to align content right while unfocused function core.new_ifield(e, max_len, fg_bg, dis_fg_bg, align_right) local self = { frame_start = 1, diff --git a/graphics/element.lua b/graphics/element.lua index 1e94edd..0d6800a 100644 --- a/graphics/element.lua +++ b/graphics/element.lua @@ -11,8 +11,8 @@ local events = core.events local element = {} ----@class graphics_args_generic ----@field window? table +---@class graphics_args +---@field window? Window ---@field parent? graphics_element ---@field id? string element id ---@field x? integer 1 if omitted @@ -24,47 +24,6 @@ local element = {} ---@field hidden? boolean true to hide on initial draw ---@field can_focus? boolean true if this element can be focused, false by default ----@alias graphics_args graphics_args_generic ----|waiting_args ----|app_button_args ----|checkbox_args ----|hazard_button_args ----|multi_button_args ----|push_button_args ----|radio_2d_args ----|radio_button_args ----|sidebar_args ----|spinbox_args ----|switch_button_args ----|tabbar_args ----|number_field_args ----|text_field_args ----|alarm_indicator_light ----|core_map_args ----|data_indicator_args ----|hbar_args ----|icon_indicator_args ----|indicator_led_args ----|indicator_led_pair_args ----|indicator_led_rgb_args ----|indicator_light_args ----|power_indicator_args ----|rad_indicator_args ----|signal_bar_args ----|state_indicator_args ----|tristate_indicator_light_args ----|vbar_args ----|app_multipane_args ----|colormap_args ----|displaybox_args ----|div_args ----|listbox_args ----|multipane_args ----|pipenet_args ----|rectangle_args ----|textbox_args ----|tiling_args - ---@class element_subscription ---@field ps psil ps used ---@field key string data key @@ -92,14 +51,14 @@ function element.new(args, constraint, child_offset_x, child_offset_y) is_root = args.parent == nil, elem_type = debug.getinfo(2).name, define_completed = false, - p_window = nil, ---@type table + p_window = nil, ---@type Window position = events.new_coord_2d(1, 1), bounds = { x1 = 1, y1 = 1, x2 = 1, y2 = 1 }, ---@class element_bounds offset_x = 0, offset_y = 0, next_y = 1, -- next child y coordinate next_id = 0, -- next child ID - subscriptions = {}, + subscriptions = {}, ---@type { ps: psil, key: string, func: function }[] button_down = { events.new_coord_2d(-1, -1), events.new_coord_2d(-1, -1), events.new_coord_2d(-1, -1) }, focused = false, mt = {} @@ -109,13 +68,13 @@ function element.new(args, constraint, child_offset_x, child_offset_y) local protected = { enabled = true, value = nil, ---@type any - window = nil, ---@type table - content_window = nil, ---@type table|nil + window = nil, ---@type Window + content_window = nil, ---@type Window|nil mouse_window_shift = { x = 0, y = 0 }, fg_bg = core.cpair(colors.white, colors.black), frame = core.gframe(1, 1, 1, 1), - children = {}, - child_id_map = {} + children = {}, ---@type graphics_base[] + child_id_map = {} ---@type { [element_id]: integer } } -- element as string @@ -128,9 +87,9 @@ function element.new(args, constraint, child_offset_x, child_offset_y) setmetatable(public, self.mt) - ----------------------- - -- PRIVATE FUNCTIONS -- - ----------------------- + ------------------------------ + --#region PRIVATE FUNCTIONS -- + ------------------------------ -- use tab to jump to the next focusable field ---@param reverse boolean @@ -168,10 +127,10 @@ function element.new(args, constraint, child_offset_x, child_offset_y) end end - ---@param children table + ---@param children graphics_base[] local function traverse(children) for i = 1, #children do - local child = children[i] ---@type graphics_base + local child = children[i] handle_element(child.get()) if child.get().is_visible() then traverse(child.children) end end @@ -191,9 +150,11 @@ function element.new(args, constraint, child_offset_x, child_offset_y) end end - ------------------------- - -- PROTECTED FUNCTIONS -- - ------------------------- + --#endregion + + -------------------------------- + --#region PROTECTED FUNCTIONS -- + -------------------------------- -- prepare the template ---@param offset_x integer x offset for mouse events @@ -286,24 +247,29 @@ function element.new(args, constraint, child_offset_x, child_offset_y) -- alias functions - -- window set cursor position + -- window set cursor position
+ ---@see Window.setCursorPos ---@param x integer ---@param y integer function protected.w_set_cur(x, y) protected.window.setCursorPos(x, y) end - -- set background color + -- set background color
+ ---@see Window.setBackgroundColor ---@param c color function protected.w_set_bkg(c) protected.window.setBackgroundColor(c) end - -- set foreground (text) color + -- set foreground (text) color
+ ---@see Window.setTextColor ---@param c color function protected.w_set_fgd(c) protected.window.setTextColor(c) end - -- write text + -- write text
+ ---@see Window.write ---@param str string function protected.w_write(str) protected.window.write(str) end - -- blit text + -- blit text
+ ---@see Window.blit ---@param str string ---@param fg string ---@param bg string @@ -335,8 +301,10 @@ function element.new(args, constraint, child_offset_x, child_offset_y) -- report completion of element instantiation and get the public interface ---@nodiscard + ---@param redraw? boolean true to call redraw as part of completing this element ---@return graphics_element element, element_id id - function protected.complete() + function protected.complete(redraw) + if redraw then protected.redraw() end if args.parent ~= nil then args.parent.__child_ready(self.id, public) end return public, self.id end @@ -352,7 +320,7 @@ function element.new(args, constraint, child_offset_x, child_offset_y) -- focus this element and take away focus from all other elements function protected.take_focus() args.parent.__focus_child(public) end - -- action handlers -- + --#region Action Handlers -- luacheck: push ignore ---@diagnostic disable: unused-local, unused-vararg @@ -401,14 +369,12 @@ function element.new(args, constraint, child_offset_x, child_offset_y) function protected.handle_paste(text) end -- handle data value changes - ---@vararg any value(s) + ---@param ... any value(s) function protected.on_update(...) end - -- callback on control press responses - ---@param result any - function protected.response_callback(result) end + --#endregion - -- accessors and control -- + --#region Accessors and Control -- get value ---@nodiscard @@ -427,11 +393,11 @@ function element.new(args, constraint, child_offset_x, child_offset_y) function protected.set_max(max) end -- custom recolor command, varies by element if implemented - ---@vararg cpair|color color(s) + ---@param ... cpair|color color(s) function protected.recolor(...) end -- custom resize command, varies by element if implemented - ---@vararg integer sizing + ---@param ... integer sizing function protected.resize(...) end -- luacheck: pop @@ -446,9 +412,13 @@ function element.new(args, constraint, child_offset_x, child_offset_y) -- stop animations function protected.stop_anim() end - ----------- - -- SETUP -- - ----------- + --#endregion + + --#endregion + + ------------------ + --#region SETUP -- + ------------------ -- get the parent window self.p_window = args.window @@ -467,9 +437,11 @@ function element.new(args, constraint, child_offset_x, child_offset_y) self.id = args.parent.__add_child(args.id, protected) end - ---------------------- - -- PUBLIC FUNCTIONS -- - ---------------------- + --#endregion + + ----------------------------- + --#region PUBLIC FUNCTIONS -- + ----------------------------- -- get the window object ---@nodiscard @@ -511,9 +483,10 @@ function element.new(args, constraint, child_offset_x, child_offset_y) end end - -- ELEMENT TREE -- + --#region ELEMENT TREE -- add a child element + ---@package ---@nodiscard ---@param key string|nil id ---@param child graphics_base @@ -523,7 +496,7 @@ function element.new(args, constraint, child_offset_x, child_offset_y) self.next_y = child.frame.y + child.frame.h - local id = key ---@type string|integer|nil + local id = key ---@type element_id|nil if id == nil then id = self.next_id self.next_id = self.next_id + 1 @@ -537,6 +510,7 @@ function element.new(args, constraint, child_offset_x, child_offset_y) end -- remove a child element + ---@package ---@param id element_id id function public.__remove_child(id) local index = protected.child_id_map[id] @@ -548,11 +522,13 @@ function element.new(args, constraint, child_offset_x, child_offset_y) end -- actions to take upon a child element becoming ready (initial draw/construction completed) + ---@package ---@param key element_id id ---@param child graphics_element function public.__child_ready(key, child) protected.on_added(key, child) end -- focus solely on this child + ---@package ---@param child graphics_element function public.__focus_child(child) if self.is_root then @@ -562,6 +538,7 @@ function element.new(args, constraint, child_offset_x, child_offset_y) end -- a child was focused, used to make sure it is actually visible to the user in the content frame + ---@package ---@param child graphics_element function public.__child_focused(child) protected.on_child_focused(child) @@ -571,8 +548,8 @@ function element.new(args, constraint, child_offset_x, child_offset_y) -- get a child element ---@nodiscard ---@param id element_id - ---@return graphics_element - function public.get_child(id) return protected.children[protected.child_id_map[id]].get() end + ---@return graphics_element element + function public.get_child(id) return ({ protected.children[protected.child_id_map[id]].get() })[1] end -- get all children ---@nodiscard @@ -598,7 +575,7 @@ function element.new(args, constraint, child_offset_x, child_offset_y) -- remove all child elements and reset next y function public.remove_all() for i = 1, #protected.children do - local child = protected.children[i].get() ---@type graphics_element + local child = protected.children[i].get() ---@type graphics_element child.delete() protected.on_removed(child.get_id()) end @@ -619,29 +596,33 @@ function element.new(args, constraint, child_offset_x, child_offset_y) local elem = child.get().get_element_by_id(id) if elem ~= nil then return elem end end - else return protected.children[index].get() end + else return ({ protected.children[index].get() })[1] end end - -- AUTO-PLACEMENT -- + --#endregion + + --#region AUTO-PLACEMENT -- skip a line for automatically placed elements function public.line_break() self.next_y = self.next_y + 1 end - -- PROPERTIES -- + --#endregion - -- get element id + --#region PROPERTIES + + -- get element ID ---@nodiscard ---@return element_id function public.get_id() return self.id end - -- get element x + -- get element relative x position ---@nodiscard ---@return integer x function public.get_x() return protected.frame.x end - -- get element y + -- get element relative y position ---@nodiscard ---@return integer y function public.get_y() return protected.frame.y end @@ -661,12 +642,12 @@ function element.new(args, constraint, child_offset_x, child_offset_y) ---@return cpair fg_bg function public.get_fg_bg() return protected.fg_bg end - -- get the element value + -- get the element's value ---@nodiscard ---@return any value function public.get_value() return protected.get_value() end - -- set the element value + -- set the element's value ---@param value any new value function public.set_value(value) protected.set_value(value) end @@ -728,11 +709,11 @@ function element.new(args, constraint, child_offset_x, child_offset_y) end -- custom recolor command, varies by element if implemented - ---@vararg cpair|color color(s) + ---@param ... cpair|color color(s) function public.recolor(...) protected.recolor(...) end -- resize attributes of the element value if supported - ---@vararg number dimensions (element specific) + ---@param ... number dimensions (element specific) function public.resize(...) protected.resize(...) end -- reposition the element window
@@ -756,7 +737,9 @@ function element.new(args, constraint, child_offset_x, child_offset_y) self.bounds.y2 = self.position.y + protected.frame.h - 1 end - -- FUNCTION CALLBACKS -- + --#endregion + + --#region FUNCTION CALLBACKS -- handle a monitor touch or mouse click if this element is visible ---@param event mouse_interaction mouse interaction event @@ -818,13 +801,9 @@ function element.new(args, constraint, child_offset_x, child_offset_y) end -- draw the element given new data - ---@vararg any new data + ---@param ... any new data function public.update(...) protected.on_update(...) end - -- on a control request response - ---@param result any - function public.on_response(result) protected.response_callback(result) end - -- register a callback with a PSIL, allowing for automatic unregister on delete
-- do not use graphics elements directly with PSIL subscribe() ---@param ps psil PSIL to subscribe to @@ -835,7 +814,9 @@ function element.new(args, constraint, child_offset_x, child_offset_y) ps.subscribe(key, func) end - -- VISIBILITY & ANIMATIONS -- + --#endregion + + --#region VISIBILITY & ANIMATIONS -- check if this element is visible function public.is_visible() return protected.window.isVisible() end @@ -849,6 +830,7 @@ function element.new(args, constraint, child_offset_x, child_offset_y) -- hide the element and disables animations
-- this alone does not cause an element to be fully hidden, it only prevents updates from being shown
+ ---@see Window.redraw ---@see graphics_element.redraw ---@see graphics_element.content_redraw ---@param clear? boolean true to visibly hide this element (redraws the parent) @@ -900,6 +882,10 @@ function element.new(args, constraint, child_offset_x, child_offset_y) end end + --#endregion + + --#endregion + return protected end diff --git a/graphics/elements/appmultipane.lua b/graphics/elements/AppMultiPane.lua similarity index 92% rename from graphics/elements/appmultipane.lua rename to graphics/elements/AppMultiPane.lua index 5973182..948cb32 100644 --- a/graphics/elements/appmultipane.lua +++ b/graphics/elements/AppMultiPane.lua @@ -24,15 +24,15 @@ local MOUSE_CLICK = core.events.MOUSE_CLICK ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new app multipane element +-- Create a new app multipane container element. ---@nodiscard ---@param args app_multipane_args ----@return graphics_element element, element_id id -local function multipane(args) +---@return AppMultiPane element, element_id id +return function (args) element.assert(type(args.panes) == "table", "panes is a required field") -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = 1 @@ -100,10 +100,8 @@ local function multipane(args) end end - -- initial draw - e.redraw() + ---@class AppMultiPane:graphics_element + local AppMultiPane, id = e.complete(true) - return e.complete() + return AppMultiPane, id end - -return multipane diff --git a/graphics/elements/colormap.lua b/graphics/elements/ColorMap.lua similarity index 66% rename from graphics/elements/colormap.lua rename to graphics/elements/ColorMap.lua index 7e3554f..1a4b0a7 100644 --- a/graphics/elements/colormap.lua +++ b/graphics/elements/ColorMap.lua @@ -9,10 +9,10 @@ local element = require("graphics.element") ---@field y? integer auto incremented if omitted ---@field hidden? boolean true to hide on initial draw --- new color map +-- Create a horizontal reference color map. Primarily used for tuning custom colors. ---@param args colormap_args ----@return graphics_element element, element_id id -local function colormap(args) +---@return ColorMap element, element_id id +return function (args) local bkg = "008877FFCCEE114455DD9933BBAA2266" local spaces = string.rep(" ", 32) @@ -20,7 +20,7 @@ local function colormap(args) args.height = 1 -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) -- draw color map function e.redraw() @@ -28,10 +28,8 @@ local function colormap(args) e.w_blit(spaces, bkg, bkg) end - -- initial draw - e.redraw() + ---@class ColorMap:graphics_element + local ColorMap, id = e.complete(true) - return e.complete() + return ColorMap, id end - -return colormap diff --git a/graphics/elements/displaybox.lua b/graphics/elements/DisplayBox.lua similarity index 69% rename from graphics/elements/displaybox.lua rename to graphics/elements/DisplayBox.lua index 3578a63..ecfe03a 100644 --- a/graphics/elements/displaybox.lua +++ b/graphics/elements/DisplayBox.lua @@ -13,13 +13,16 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new root display box +-- Create a root display box. ---@nodiscard ---@param args displaybox_args ----@return graphics_element element, element_id id -local function displaybox(args) +---@return DisplayBox element, element_id id +return function (args) -- create new graphics element base object - return element.new(args).complete() -end + local e = element.new(args --[[@as graphics_args]]) -return displaybox + ---@class DisplayBox:graphics_element + local DisplayBox, id = e.complete() + + return DisplayBox, id +end diff --git a/graphics/elements/div.lua b/graphics/elements/Div.lua similarity index 72% rename from graphics/elements/div.lua rename to graphics/elements/Div.lua index 0af3259..2be440b 100644 --- a/graphics/elements/div.lua +++ b/graphics/elements/Div.lua @@ -13,13 +13,16 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new div element +-- Create a new div container element. ---@nodiscard ---@param args div_args ----@return graphics_element element, element_id id -local function div(args) +---@return Div element, element_id id +return function (args) -- create new graphics element base object - return element.new(args).complete() -end + local e = element.new(args --[[@as graphics_args]]) -return div + ---@class Div:graphics_element + local Div, id = e.complete() + + return Div, id +end diff --git a/graphics/elements/listbox.lua b/graphics/elements/ListBox.lua similarity index 97% rename from graphics/elements/listbox.lua rename to graphics/elements/ListBox.lua index 86cacd4..e1c8dec 100644 --- a/graphics/elements/listbox.lua +++ b/graphics/elements/ListBox.lua @@ -30,15 +30,15 @@ local MOUSE_CLICK = core.events.MOUSE_CLICK ---@field y integer y position ---@field h integer element height --- new listbox element +-- Create a new scrollable listbox container element. ---@nodiscard ---@param args listbox_args ----@return graphics_element element, element_id id -local function listbox(args) +---@return ListBox element, element_id id +return function (args) args.can_focus = true -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) -- create content window for child elements local scroll_frame = window.create(e.window, 1, 1, e.frame.w - 1, args.scroll_height, false) @@ -339,10 +339,8 @@ local function listbox(args) draw_bar() end - -- initial draw - e.redraw() + ---@class ListBox:graphics_element + local ListBox, id = e.complete(true) - return e.complete() + return ListBox, id end - -return listbox diff --git a/graphics/elements/multipane.lua b/graphics/elements/MultiPane.lua similarity index 81% rename from graphics/elements/multipane.lua rename to graphics/elements/MultiPane.lua index a283ed8..aae22ac 100644 --- a/graphics/elements/multipane.lua +++ b/graphics/elements/MultiPane.lua @@ -14,15 +14,15 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new multipane element +-- Create a new multipane container element. ---@nodiscard ---@param args multipane_args ----@return graphics_element element, element_id id -local function multipane(args) +---@return MultiPane element, element_id id +return function (args) element.assert(type(args.panes) == "table", "panes is a required field") -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = 1 @@ -41,10 +41,8 @@ local function multipane(args) end end - -- initial draw - e.redraw() + ---@class MultiPane:graphics_element + local MultiPane, id = e.complete(true) - return e.complete() + return MultiPane, id end - -return multipane diff --git a/graphics/elements/pipenet.lua b/graphics/elements/PipeNetwork.lua similarity index 97% rename from graphics/elements/pipenet.lua rename to graphics/elements/PipeNetwork.lua index 625a70d..7045bd0 100644 --- a/graphics/elements/pipenet.lua +++ b/graphics/elements/PipeNetwork.lua @@ -20,10 +20,10 @@ local element = require("graphics.element") ---@field fg string foreground blit ---@field bg string background blit --- new pipe network +-- Create a pipe network diagram. ---@param args pipenet_args ----@return graphics_element element, element_id id -local function pipenet(args) +---@return PipeNetwork element, element_id id +return function (args) element.assert(type(args.pipes) == "table", "pipes is a required field") args.width = 0 @@ -47,7 +47,7 @@ local function pipenet(args) end -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) -- determine if there are any thin pipes involved local any_thin = false @@ -322,10 +322,8 @@ local function pipenet(args) if any_thin then map_draw() else vector_draw() end end - -- initial draw - e.redraw() + ---@class PipeNetwork:graphics_element + local PipeNetwork, id = e.complete(true) - return e.complete() + return PipeNetwork, id end - -return pipenet diff --git a/graphics/elements/rectangle.lua b/graphics/elements/Rectangle.lua similarity index 96% rename from graphics/elements/rectangle.lua rename to graphics/elements/Rectangle.lua index eceb9bd..ce5fbba 100644 --- a/graphics/elements/rectangle.lua +++ b/graphics/elements/Rectangle.lua @@ -18,10 +18,10 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new rectangle +-- Create a new rectangle container element. ---@param args rectangle_args ----@return graphics_element element, element_id id -local function rectangle(args) +---@return Rectangle element, element_id id +return function (args) element.assert(args.border ~= nil or args.thin ~= true, "thin requires border to be provided") -- if thin, then width will always need to be 1 @@ -45,7 +45,7 @@ local function rectangle(args) end -- create new graphics element base object - local e = element.new(args, nil, offset_x, offset_y) + local e = element.new(args --[[@as graphics_args]], nil, offset_x, offset_y) -- create content window for child elements e.content_window = window.create(e.window, 1 + offset_x, 1 + offset_y, e.frame.w - (2 * offset_x), e.frame.h - (2 * offset_y)) @@ -191,7 +191,8 @@ local function rectangle(args) e.redraw() end - return e.complete() -end + ---@class Rectangle:graphics_element + local Rectangle, id = e.complete() -return rectangle + return Rectangle, id +end diff --git a/graphics/elements/textbox.lua b/graphics/elements/TextBox.lua similarity index 89% rename from graphics/elements/textbox.lua rename to graphics/elements/TextBox.lua index a52d528..cc3c4aa 100644 --- a/graphics/elements/textbox.lua +++ b/graphics/elements/TextBox.lua @@ -21,10 +21,10 @@ local ALIGN = core.ALIGN ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new text box +-- Create a new text box element. ---@param args textbox_args ----@return graphics_element element, element_id id -local function textbox(args) +---@return TextBox element, element_id id +return function (args) element.assert(type(args.text) == "string", "text is a required field") if args.anchor == true then args.can_focus = true end @@ -42,7 +42,7 @@ local function textbox(args) end -- create new graphics element base object - local e = element.new(args, constrain) + local e = element.new(args --[[@as graphics_args]], constrain) e.value = args.text @@ -82,10 +82,8 @@ local function textbox(args) e.redraw() end - -- initial draw - e.redraw() + ---@class TextBox:graphics_element + local TextBox, id = e.complete(true) - return e.complete() + return TextBox, id end - -return textbox diff --git a/graphics/elements/tiling.lua b/graphics/elements/Tiling.lua similarity index 90% rename from graphics/elements/tiling.lua rename to graphics/elements/Tiling.lua index 02e2605..d4b48d2 100644 --- a/graphics/elements/tiling.lua +++ b/graphics/elements/Tiling.lua @@ -18,14 +18,14 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new tiling box +-- Create a new tiling box element. ---@param args tiling_args ----@return graphics_element element, element_id id -local function tiling(args) +---@return Tiling element, element_id id +return function (args) element.assert(type(args.fill_c) == "table", "fill_c is a required field") -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) local fill_a = args.fill_c.blit_a local fill_b = args.fill_c.blit_b @@ -52,7 +52,7 @@ local function tiling(args) element.assert(start_x <= inner_width, "start_x > inner_width") element.assert(start_y <= inner_height, "start_y > inner_height") - -- draw tiling box + -- draw the tiling box function e.redraw() local alternator = true @@ -86,10 +86,8 @@ local function tiling(args) end end - -- initial draw - e.redraw() + ---@class Tiling:graphics_element + local Tiling, id = e.complete(true) - return e.complete() + return Tiling, id end - -return tiling diff --git a/graphics/elements/animations/waiting.lua b/graphics/elements/animations/Waiting.lua similarity index 91% rename from graphics/elements/animations/waiting.lua rename to graphics/elements/animations/Waiting.lua index 36aa432..0456ef3 100644 --- a/graphics/elements/animations/waiting.lua +++ b/graphics/elements/animations/Waiting.lua @@ -12,10 +12,10 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new waiting animation element +-- Create a new waiting animation element. ---@param args waiting_args ----@return graphics_element element, element_id id -local function waiting(args) +---@return Waiting element, element_id id +return function (args) local state = 0 local run_animation = false @@ -23,7 +23,7 @@ local function waiting(args) args.height = 3 -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) local blit_fg = e.fg_bg.blit_fgd local blit_bg = e.fg_bg.blit_bkg @@ -103,7 +103,8 @@ local function waiting(args) e.start_anim() - return e.complete() -end + ---@class Waiting:graphics_element + local Waiting, id = e.complete() -return waiting + return Waiting, id +end diff --git a/graphics/elements/controls/app.lua b/graphics/elements/controls/App.lua similarity index 92% rename from graphics/elements/controls/app.lua rename to graphics/elements/controls/App.lua index 4ac936d..2d6ca01 100644 --- a/graphics/elements/controls/app.lua +++ b/graphics/elements/controls/App.lua @@ -20,10 +20,10 @@ local MOUSE_CLICK = core.events.MOUSE_CLICK ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new app button +-- Create a new app icon style button control element, like on a mobile device. ---@param args app_button_args ----@return graphics_element element, element_id id -local function app_button(args) +---@return App element, element_id id +return function (args) element.assert(type(args.text) == "string", "text is a required field") element.assert(type(args.title) == "string", "title is a required field") element.assert(type(args.callback) == "function", "callback is a required field") @@ -33,7 +33,7 @@ local function app_button(args) args.width = 7 -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) -- draw the app button local function draw() @@ -123,10 +123,8 @@ local function app_button(args) draw() end - -- initial draw - e.redraw() + ---@class App:graphics_element + local App, id = e.complete(true) - return e.complete() + return App, id end - -return app_button diff --git a/graphics/elements/controls/checkbox.lua b/graphics/elements/controls/Checkbox.lua similarity index 92% rename from graphics/elements/controls/checkbox.lua rename to graphics/elements/controls/Checkbox.lua index d63ca69..26d4faf 100644 --- a/graphics/elements/controls/checkbox.lua +++ b/graphics/elements/controls/Checkbox.lua @@ -15,10 +15,10 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new checkbox control +-- Create a new checkbox control element. ---@param args checkbox_args ----@return graphics_element element, element_id id -local function checkbox(args) +---@return Checkbox element, element_id id +return function (args) element.assert(type(args.label) == "string", "label is a required field") element.assert(type(args.box_fg_bg) == "table", "box_fg_bg is a required field") @@ -27,7 +27,7 @@ local function checkbox(args) args.width = 2 + string.len(args.label) -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = args.default == true @@ -112,10 +112,8 @@ local function checkbox(args) draw_label() end - -- initial draw - e.redraw() + ---@class Checkbox:graphics_element + local Checkbox, id = e.complete(true) - return e.complete() + return Checkbox, id end - -return checkbox diff --git a/graphics/elements/controls/hazard_button.lua b/graphics/elements/controls/HazardButton.lua similarity index 92% rename from graphics/elements/controls/hazard_button.lua rename to graphics/elements/controls/HazardButton.lua index 5a3d37f..7815ba3 100644 --- a/graphics/elements/controls/hazard_button.lua +++ b/graphics/elements/controls/HazardButton.lua @@ -18,10 +18,10 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new hazard button +-- Create a new hazard button control element. ---@param args hazard_button_args ----@return graphics_element element, element_id id -local function hazard_button(args) +---@return HazardButton element, element_id id +return function (args) element.assert(type(args.text) == "string", "text is a required field") element.assert(type(args.accent) == "number", "accent is a required field") element.assert(type(args.callback) == "function", "callback is a required field") @@ -32,7 +32,7 @@ local function hazard_button(args) local timeout = args.timeout or 1.5 -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) -- draw border ---@param accent color accent color @@ -159,13 +159,6 @@ local function hazard_button(args) end end - -- callback on request response - ---@param result boolean true for success, false for failure - function e.response_callback(result) - tcd.abort(on_timeout) - if result then on_success() else on_failure(0) end - end - -- set the value (true simulates pressing the button) ---@param val boolean new value function e.set_value(val) @@ -198,10 +191,15 @@ local function hazard_button(args) draw_border(args.accent) end - -- initial draw - e.redraw() + ---@class HazardButton:graphics_element + local HazardButton, id = e.complete(true) - return e.complete() + -- callback for request response + ---@param success boolean + function HazardButton.on_response(success) + tcd.abort(on_timeout) + if success then on_success() else on_failure(0) end + end + + return HazardButton, id end - -return hazard_button diff --git a/graphics/elements/controls/multi_button.lua b/graphics/elements/controls/MultiButton.lua similarity index 92% rename from graphics/elements/controls/multi_button.lua rename to graphics/elements/controls/MultiButton.lua index d686b9d..4e44ebe 100644 --- a/graphics/elements/controls/multi_button.lua +++ b/graphics/elements/controls/MultiButton.lua @@ -25,10 +25,10 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new multi button (latch selection, exclusively one button at a time) +-- Create a new multi button control element (latch selection, exclusively one button at a time). ---@param args multi_button_args ----@return graphics_element element, element_id id -local function multi_button(args) +---@return MultiButton element, element_id id +return function (args) element.assert(type(args.options) == "table", "options is a required field") element.assert(#args.options > 0, "at least one option is required") element.assert(type(args.callback) == "function", "callback is a required field") @@ -52,7 +52,7 @@ local function multi_button(args) args.width = (button_width * #args.options) + #args.options + 1 -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) -- button state (convert nil to 1 if missing) e.value = args.default or 1 @@ -126,10 +126,8 @@ local function multi_button(args) e.redraw() end - -- initial draw - e.redraw() + ---@class MultiButton:graphics_element + local MultiButton, id = e.complete(true) - return e.complete() + return MultiButton, id end - -return multi_button diff --git a/graphics/elements/controls/spinbox_numeric.lua b/graphics/elements/controls/NumericSpinbox.lua similarity index 94% rename from graphics/elements/controls/spinbox_numeric.lua rename to graphics/elements/controls/NumericSpinbox.lua index e114c6a..0b530f4 100644 --- a/graphics/elements/controls/spinbox_numeric.lua +++ b/graphics/elements/controls/NumericSpinbox.lua @@ -20,10 +20,10 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new spinbox control (minimum value is 0) +-- Create a new spinbox control element (minimum value is 0). ---@param args spinbox_args ----@return graphics_element element, element_id id -local function spinbox(args) +---@return NumericSpinbox element, element_id id +return function (args) -- properties local digits = {} local wn_prec = args.whole_num_precision @@ -51,7 +51,7 @@ local function spinbox(args) args.height = 3 -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) -- set initial value e.value = args.default or 0 @@ -179,10 +179,8 @@ local function spinbox(args) draw_arrows(util.trinary(e.enabled, args.arrow_fg_bg.fgd, args.arrow_disable or colors.lightGray)) end - -- initial draw - e.redraw() + ---@class NumericSpinbox:graphics_element + local NumericSpinbox, id = e.complete(true) - return e.complete() + return NumericSpinbox, id end - -return spinbox diff --git a/graphics/elements/controls/push_button.lua b/graphics/elements/controls/PushButton.lua similarity index 94% rename from graphics/elements/controls/push_button.lua rename to graphics/elements/controls/PushButton.lua index f060901..bc8b7dd 100644 --- a/graphics/elements/controls/push_button.lua +++ b/graphics/elements/controls/PushButton.lua @@ -25,10 +25,10 @@ local KEY_CLICK = core.events.KEY_CLICK ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new push button +-- Create a new push button control element. ---@param args push_button_args ----@return graphics_element element, element_id id -local function push_button(args) +---@return PushButton element, element_id id +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.min_width) == "nil" or (type(args.min_width) == "number" and args.min_width > 0), "min_width must be nil or a number > 0") @@ -48,7 +48,7 @@ local function push_button(args) end -- create new graphics element base object - local e = element.new(args, constrain) + local e = element.new(args --[[@as graphics_args]], constrain) local text_lines = util.strwrap(args.text, e.frame.w) @@ -157,10 +157,8 @@ local function push_button(args) e.on_focused = show_pressed e.on_unfocused = show_unpressed - -- initial draw - e.redraw() + ---@class PushButton:graphics_element + local PushButton, id = e.complete(true) - return e.complete() + return PushButton, id end - -return push_button diff --git a/graphics/elements/controls/radio_2d.lua b/graphics/elements/controls/Radio2D.lua similarity index 95% rename from graphics/elements/controls/radio_2d.lua rename to graphics/elements/controls/Radio2D.lua index 65d4c09..cf2da34 100644 --- a/graphics/elements/controls/radio_2d.lua +++ b/graphics/elements/controls/Radio2D.lua @@ -23,10 +23,10 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new 2D radio button list (latch selection, exclusively one color at a time) +-- Create a new 2-dimensional (rows and columns of options) radio button list control element (latch selection, exclusively one color at a time). ---@param args radio_2d_args ----@return graphics_element element, element_id id -local function radio_2d_button(args) +---@return Radio2D element, element_id id +return function (args) element.assert(type(args.options) == "table" and #args.options > 0, "options should be a table with length >= 1") element.assert(util.is_int(args.rows) and util.is_int(args.columns), "rows/columns must be integers") element.assert((args.rows * args.columns) >= #args.options, "rows x columns size insufficient for provided number of options") @@ -70,7 +70,7 @@ local function radio_2d_button(args) args.height = max_rows -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) -- selected option (convert nil to 1 if missing) e.value = args.default or 1 @@ -194,10 +194,8 @@ local function radio_2d_button(args) e.on_enabled = e.redraw e.on_disabled = e.redraw - -- initial draw - e.redraw() + ---@class Radio2D:graphics_element + local Radio2D, id = e.complete(true) - return e.complete() + return Radio2D, id end - -return radio_2d_button diff --git a/graphics/elements/controls/radio_button.lua b/graphics/elements/controls/RadioButton.lua similarity index 93% rename from graphics/elements/controls/radio_button.lua rename to graphics/elements/controls/RadioButton.lua index be9b1ee..a2acffc 100644 --- a/graphics/elements/controls/radio_button.lua +++ b/graphics/elements/controls/RadioButton.lua @@ -21,10 +21,10 @@ local KEY_CLICK = core.events.KEY_CLICK ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new radio button list (latch selection, exclusively one button at a time) +-- Create a new radio button list control element (latch selection, exclusively one button at a time). ---@param args radio_button_args ----@return graphics_element element, element_id id -local function radio_button(args) +---@return RadioButton element, element_id id +return function (args) element.assert(type(args.options) == "table", "options is a required field") element.assert(#args.options > 0, "at least one option is required") element.assert(type(args.radio_colors) == "table", "radio_colors is a required field") @@ -49,7 +49,7 @@ local function radio_button(args) args.height = #args.options -- one line per option -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) local focused_opt = 1 @@ -139,10 +139,8 @@ local function radio_button(args) e.on_enabled = e.redraw e.on_disabled = e.redraw - -- initial draw - e.redraw() + ---@class RadioButton:graphics_element + local RadioButton, id = e.complete(true) - return e.complete() + return RadioButton, id end - -return radio_button diff --git a/graphics/elements/controls/sidebar.lua b/graphics/elements/controls/Sidebar.lua similarity index 90% rename from graphics/elements/controls/sidebar.lua rename to graphics/elements/controls/Sidebar.lua index 58e8b13..7c3eac6 100644 --- a/graphics/elements/controls/sidebar.lua +++ b/graphics/elements/controls/Sidebar.lua @@ -17,14 +17,14 @@ local MOUSE_CLICK = core.events.MOUSE_CLICK ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new sidebar tab selector +-- Create a new sidebar tab selector control element. ---@param args sidebar_args ----@return graphics_element element, element_id id -local function sidebar(args) +---@return Sidebar element, element_id id +return function (args) args.width = 3 -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) -- default to 1st tab e.value = 1 @@ -129,8 +129,14 @@ local function sidebar(args) end -- update the sidebar navigation options - ---@param items table sidebar entries + ---@param items sidebar_entry[] sidebar entries function e.on_update(items) + ---@class sidebar_entry + ---@field label string + ---@field tall boolean + ---@field color cpair + ---@field callback function|nil + local next_y = 1 tabs = {} @@ -160,9 +166,8 @@ local function sidebar(args) -- element redraw e.redraw = draw - e.redraw() + ---@class Sidebar:graphics_element + local Sidebar, id = e.complete(true) - return e.complete() + return Sidebar, id end - -return sidebar diff --git a/graphics/elements/controls/switch_button.lua b/graphics/elements/controls/SwitchButton.lua similarity index 88% rename from graphics/elements/controls/switch_button.lua rename to graphics/elements/controls/SwitchButton.lua index 8abf8a7..e23db03 100644 --- a/graphics/elements/controls/switch_button.lua +++ b/graphics/elements/controls/SwitchButton.lua @@ -17,10 +17,10 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new switch button (latch high/low) +-- Create a new latching switch button control element. ---@param args switch_button_args ----@return graphics_element element, element_id id -local function switch_button(args) +---@return SwitchButton element, element_id id +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") @@ -33,7 +33,7 @@ local function switch_button(args) args.width = math.max(text_width, args.min_width) -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = args.default or false @@ -72,10 +72,8 @@ local function switch_button(args) e.redraw() end - -- initial draw - e.redraw() + ---@class SwitchButton:graphics_element + local SwitchButton, id = e.complete(true) - return e.complete() + return SwitchButton, id end - -return switch_button diff --git a/graphics/elements/controls/tabbar.lua b/graphics/elements/controls/TabBar.lua similarity index 93% rename from graphics/elements/controls/tabbar.lua rename to graphics/elements/controls/TabBar.lua index c76781b..f6aa13c 100644 --- a/graphics/elements/controls/tabbar.lua +++ b/graphics/elements/controls/TabBar.lua @@ -23,10 +23,10 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new tab selector +-- Create a new tab selector control element. ---@param args tabbar_args ----@return graphics_element element, element_id id -local function tabbar(args) +---@return TabBar element, element_id id +return function (args) element.assert(type(args.tabs) == "table", "tabs is a required field") element.assert(#args.tabs > 0, "at least one tab is required") element.assert(type(args.callback) == "function", "callback is a required field") @@ -46,7 +46,7 @@ local function tabbar(args) local button_width = math.max(max_width, args.min_width or 0) -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) element.assert(e.frame.w >= (button_width * #args.tabs), "width insufficent to display all tabs") @@ -120,10 +120,8 @@ local function tabbar(args) e.redraw() end - -- initial draw - e.redraw() + ---@class TabBar:graphics_element + local TabBar, id = e.complete(true) - return e.complete() + return TabBar, id end - -return tabbar diff --git a/graphics/elements/form/number_field.lua b/graphics/elements/form/NumberField.lua similarity index 96% rename from graphics/elements/form/number_field.lua rename to graphics/elements/form/NumberField.lua index 01a4dad..2653069 100644 --- a/graphics/elements/form/number_field.lua +++ b/graphics/elements/form/NumberField.lua @@ -27,10 +27,10 @@ local MOUSE_CLICK = core.events.MOUSE_CLICK ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new numeric entry field +-- Create a new numeric entry field. ---@param args number_field_args ----@return graphics_element element, element_id id -local function number_field(args) +---@return NumberField element, element_id id +return function (args) element.assert(args.max_int_digits == nil or (util.is_int(args.max_int_digits) and args.max_int_digits > 0), "max_int_digits must be an integer greater than zero if supplied") element.assert(args.max_frac_digits == nil or (util.is_int(args.max_frac_digits) and args.max_frac_digits > 0), "max_frac_digits must be an integer greater than zero if supplied") @@ -38,7 +38,7 @@ local function number_field(args) args.can_focus = true -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) local has_decimal = false @@ -195,10 +195,8 @@ local function number_field(args) e.on_disabled = ifield.show e.redraw = ifield.show - -- initial draw - e.redraw() + ---@class NumberField:graphics_element + local NumberField, id = e.complete(true) - return e.complete() + return NumberField, id end - -return number_field diff --git a/graphics/elements/form/text_field.lua b/graphics/elements/form/TextField.lua similarity index 91% rename from graphics/elements/form/text_field.lua rename to graphics/elements/form/TextField.lua index f912b9e..1382a11 100644 --- a/graphics/elements/form/text_field.lua +++ b/graphics/elements/form/TextField.lua @@ -19,15 +19,15 @@ local MOUSE_CLICK = core.events.MOUSE_CLICK ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new text entry field +-- Create a new text entry field. ---@param args text_field_args ----@return graphics_element element, element_id id, function censor_ctl -local function text_field(args) +---@return TextField element, element_id id +return function (args) args.height = 1 args.can_focus = true -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) -- set initial value e.value = args.value or "" @@ -95,11 +95,10 @@ local function text_field(args) e.on_disabled = ifield.show e.redraw = ifield.show - -- initial draw - e.redraw() + ---@class TextField:graphics_element + local TextField, id = e.complete(true) - local elem, id = e.complete() - return elem, id, ifield.censor + TextField.censor = ifield.censor + + return TextField, id end - -return text_field diff --git a/graphics/elements/indicators/alight.lua b/graphics/elements/indicators/AlarmLight.lua similarity index 92% rename from graphics/elements/indicators/alight.lua rename to graphics/elements/indicators/AlarmLight.lua index e05569c..7350462 100644 --- a/graphics/elements/indicators/alight.lua +++ b/graphics/elements/indicators/AlarmLight.lua @@ -20,11 +20,11 @@ local flasher = require("graphics.flasher") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new alarm indicator light +-- Create a new alarm indicator light element. ---@nodiscard ---@param args alarm_indicator_light ----@return graphics_element element, element_id id -local function alarm_indicator_light(args) +---@return AlarmLight element, element_id id +return function (args) element.assert(type(args.label) == "string", "label is a required field") element.assert(type(args.c1) == "number", "c1 is a required field") element.assert(type(args.c2) == "number", "c2 is a required field") @@ -49,7 +49,7 @@ local function alarm_indicator_light(args) local c3 = colors.toBlit(args.c3) -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = 1 @@ -113,10 +113,8 @@ local function alarm_indicator_light(args) e.w_write(args.label) end - -- initial draw - e.redraw() + ---@class AlarmLight:graphics_element + local AlarmLight, id = e.complete(true) - return e.complete() + return AlarmLight, id end - -return alarm_indicator_light diff --git a/graphics/elements/indicators/coremap.lua b/graphics/elements/indicators/CoreMap.lua similarity index 94% rename from graphics/elements/indicators/coremap.lua rename to graphics/elements/indicators/CoreMap.lua index 9084b99..071fdc0 100644 --- a/graphics/elements/indicators/coremap.lua +++ b/graphics/elements/indicators/CoreMap.lua @@ -13,11 +13,11 @@ local element = require("graphics.element") ---@field x? integer 1 if omitted ---@field y? integer auto incremented if omitted --- new core map box +-- Create a new core map diagram indicator element. ---@nodiscard ---@param args core_map_args ----@return graphics_element element, element_id id -local function core_map(args) +---@return CoreMap element, element_id id +return function (args) element.assert(util.is_int(args.reactor_l), "reactor_l is a required field") element.assert(util.is_int(args.reactor_w), "reactor_w is a required field") @@ -29,7 +29,7 @@ local function core_map(args) args.fg_bg = core.cpair(args.parent.get_fg_bg().fgd, colors.gray) -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = 0 @@ -165,10 +165,8 @@ local function core_map(args) draw_core(e.value) end - -- initial draw - e.redraw() + ---@class CoreMap:graphics_element + local CoreMap, id = e.complete(true) - return e.complete() + return CoreMap, id end - -return core_map diff --git a/graphics/elements/indicators/data.lua b/graphics/elements/indicators/DataIndicator.lua similarity index 90% rename from graphics/elements/indicators/data.lua rename to graphics/elements/indicators/DataIndicator.lua index 2304807..38a253a 100644 --- a/graphics/elements/indicators/data.lua +++ b/graphics/elements/indicators/DataIndicator.lua @@ -19,11 +19,11 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new data indicator +-- Create new data indicator element. ---@nodiscard ---@param args data_indicator_args ----@return graphics_element element, element_id id -local function data(args) +---@return DataIndicator element, element_id id +return function (args) element.assert(type(args.label) == "string", "label is a required field") element.assert(type(args.format) == "string", "format is a required field") element.assert(args.value ~= nil, "value is a required field") @@ -32,7 +32,7 @@ local function data(args) args.height = 1 -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = args.value @@ -94,10 +94,8 @@ local function data(args) e.on_update(e.value) end - -- initial draw - e.redraw() + ---@class DataIndicator:graphics_element + local DataIndicator, id = e.complete(true) - return e.complete() + return DataIndicator, id end - -return data diff --git a/graphics/elements/indicators/hbar.lua b/graphics/elements/indicators/HorizontalBar.lua similarity index 93% rename from graphics/elements/indicators/hbar.lua rename to graphics/elements/indicators/HorizontalBar.lua index eb4607a..892cac7 100644 --- a/graphics/elements/indicators/hbar.lua +++ b/graphics/elements/indicators/HorizontalBar.lua @@ -17,13 +17,13 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new horizontal bar +-- Create a new horizontal fill bar indicator element. ---@nodiscard ---@param args hbar_args ---@return graphics_element element, element_id id -local function hbar(args) +return function (args) -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = 0.0 @@ -119,10 +119,8 @@ local function hbar(args) e.on_update(e.value) end - -- initial draw - e.redraw() + ---@class HorizontalBar:graphics_element + local HorizontalBar, id = e.complete(true) - return e.complete() + return HorizontalBar, id end - -return hbar diff --git a/graphics/elements/indicators/icon.lua b/graphics/elements/indicators/IconIndicator.lua similarity index 88% rename from graphics/elements/indicators/icon.lua rename to graphics/elements/indicators/IconIndicator.lua index 15aef3a..377c447 100644 --- a/graphics/elements/indicators/icon.lua +++ b/graphics/elements/indicators/IconIndicator.lua @@ -18,11 +18,11 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new icon indicator +-- Create a new icon indicator element. ---@nodiscard ---@param args icon_indicator_args ----@return graphics_element element, element_id id -local function icon(args) +---@return IconIndicator element, element_id id +return function (args) element.assert(type(args.label) == "string", "label is a required field") element.assert(type(args.states) == "table", "states is a required field") @@ -30,7 +30,7 @@ local function icon(args) args.width = math.max(args.min_label_width or 1, string.len(args.label)) + 4 -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = args.value or 1 if e.value == true then e.value = 2 end @@ -71,10 +71,8 @@ local function icon(args) e.on_update(e.value) end - -- initial draw - e.redraw() + ---@class IconIndicator:graphics_element + local IconIndicator, id = e.complete(true) - return e.complete() + return IconIndicator, id end - -return icon diff --git a/graphics/elements/indicators/light.lua b/graphics/elements/indicators/IndicatorLight.lua similarity index 90% rename from graphics/elements/indicators/light.lua rename to graphics/elements/indicators/IndicatorLight.lua index 290118c..15e3ddd 100644 --- a/graphics/elements/indicators/light.lua +++ b/graphics/elements/indicators/IndicatorLight.lua @@ -18,11 +18,11 @@ local flasher = require("graphics.flasher") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new indicator light +-- Create a new indicator light element. ---@nodiscard ---@param args indicator_light_args ----@return graphics_element element, element_id id -local function indicator_light(args) +---@return IndicatorLight element, element_id id +return function (args) element.assert(type(args.label) == "string", "label is a required field") element.assert(type(args.colors) == "table", "colors is a required field") @@ -36,7 +36,7 @@ local function indicator_light(args) local flash_on = true -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = false @@ -93,10 +93,8 @@ local function indicator_light(args) e.w_write(args.label) end - -- initial draw - e.redraw() + ---@class IndicatorLight:graphics_element + local IndicatorLight, id = e.complete(true) - return e.complete() + return IndicatorLight, id end - -return indicator_light diff --git a/graphics/elements/indicators/led.lua b/graphics/elements/indicators/LED.lua similarity index 91% rename from graphics/elements/indicators/led.lua rename to graphics/elements/indicators/LED.lua index 011ee62..9cdb072 100644 --- a/graphics/elements/indicators/led.lua +++ b/graphics/elements/indicators/LED.lua @@ -18,11 +18,11 @@ local flasher = require("graphics.flasher") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new indicator LED +-- Create a new indicator LED element. ---@nodiscard ---@param args indicator_led_args ----@return graphics_element element, element_id id -local function indicator_led(args) +---@return LED element, element_id id +return function (args) element.assert(type(args.label) == "string", "label is a required field") element.assert(type(args.colors) == "table", "colors is a required field") @@ -36,7 +36,7 @@ local function indicator_led(args) local flash_on = true -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = false @@ -95,10 +95,8 @@ local function indicator_led(args) end end - -- initial draw - e.redraw() + ---@class LED:graphics_element + local LED, id = e.complete(true) - return e.complete() + return LED, id end - -return indicator_led diff --git a/graphics/elements/indicators/ledpair.lua b/graphics/elements/indicators/LEDPair.lua similarity index 89% rename from graphics/elements/indicators/ledpair.lua rename to graphics/elements/indicators/LEDPair.lua index 1a81854..46e55c6 100644 --- a/graphics/elements/indicators/ledpair.lua +++ b/graphics/elements/indicators/LEDPair.lua @@ -20,11 +20,12 @@ local flasher = require("graphics.flasher") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new dual LED indicator light +-- Create a new three-state LED indicator light. Two "active" states (colors c1 and c2) and an inactive state (off).
+-- Values: 1 = off, 2 = c1, 3 = c2 ---@nodiscard ---@param args indicator_led_pair_args ----@return graphics_element element, element_id id -local function indicator_led_pair(args) +---@return LEDPair element, element_id id +return function (args) element.assert(type(args.label) == "string", "label is a required field") element.assert(type(args.off) == "number", "off is a required field") element.assert(type(args.c1) == "number", "c1 is a required field") @@ -44,7 +45,7 @@ local function indicator_led_pair(args) local c2 = colors.toBlit(args.c2) -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = 1 @@ -104,10 +105,8 @@ local function indicator_led_pair(args) end end - -- initial draw - e.redraw() + ---@class LEDPair:graphics_element + local LEDPair, id = e.complete(true) - return e.complete() + return LEDPair, id end - -return indicator_led_pair diff --git a/graphics/elements/indicators/power.lua b/graphics/elements/indicators/PowerIndicator.lua similarity index 87% rename from graphics/elements/indicators/power.lua rename to graphics/elements/indicators/PowerIndicator.lua index 7a09f95..53c18aa 100644 --- a/graphics/elements/indicators/power.lua +++ b/graphics/elements/indicators/PowerIndicator.lua @@ -19,11 +19,11 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new power indicator +-- Create a new power indicator. Variant of a data indicator with dynamic energy units. ---@nodiscard ---@param args power_indicator_args ----@return graphics_element element, element_id id -local function power(args) +---@return PowerIndicator element, element_id id +return function (args) element.assert(type(args.label) == "string", "label is a required field") element.assert(type(args.unit) == "string", "unit is a required field") element.assert(type(args.value) == "number", "value is a required field") @@ -32,7 +32,7 @@ local function power(args) args.height = 1 -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = args.value @@ -82,10 +82,8 @@ local function power(args) e.on_update(e.value) end - -- initial draw - e.redraw() + ---@class PowerIndicator:graphics_element + local PowerIndicator, id = e.complete(true) - return e.complete() + return PowerIndicator, id end - -return power diff --git a/graphics/elements/indicators/ledrgb.lua b/graphics/elements/indicators/RGBLED.lua similarity index 85% rename from graphics/elements/indicators/ledrgb.lua rename to graphics/elements/indicators/RGBLED.lua index 406e0cc..aacd484 100644 --- a/graphics/elements/indicators/ledrgb.lua +++ b/graphics/elements/indicators/RGBLED.lua @@ -13,11 +13,11 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new RGB LED indicator light +-- Create a new RGB LED indicator light element. ---@nodiscard ---@param args indicator_led_rgb_args ----@return graphics_element element, element_id id -local function indicator_led_rgb(args) +---@return RGBLED element, element_id id +return function (args) element.assert(type(args.label) == "string", "label is a required field") element.assert(type(args.colors) == "table", "colors is a required field") @@ -25,7 +25,7 @@ local function indicator_led_rgb(args) args.width = math.max(args.min_label_width or 0, string.len(args.label)) + 2 -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = 1 @@ -52,10 +52,8 @@ local function indicator_led_rgb(args) end end - -- initial draw - e.redraw() + ---@class RGBLED:graphics_element + local RGBLED, id = e.complete(true) - return e.complete() + return RGBLED, id end - -return indicator_led_rgb diff --git a/graphics/elements/indicators/rad.lua b/graphics/elements/indicators/RadIndicator.lua similarity index 87% rename from graphics/elements/indicators/rad.lua rename to graphics/elements/indicators/RadIndicator.lua index 545ea41..73fc9b3 100644 --- a/graphics/elements/indicators/rad.lua +++ b/graphics/elements/indicators/RadIndicator.lua @@ -19,11 +19,11 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new radiation indicator +-- Create a new radiation indicator element. Variant of a data indicator using dynamic Sievert unit precision. ---@nodiscard ---@param args rad_indicator_args ----@return graphics_element element, element_id id -local function rad(args) +---@return RadIndicator element, element_id id +return function (args) element.assert(type(args.label) == "string", "label is a required field") element.assert(type(args.format) == "string", "format is a required field") element.assert(util.is_int(args.width), "width is a required field") @@ -31,7 +31,7 @@ local function rad(args) args.height = 1 -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = args.value or types.new_zero_radiation_reading() @@ -83,10 +83,8 @@ local function rad(args) e.on_update(e.value) end - -- initial draw - e.redraw() + ---@class RadIndicator:graphics_element + local RadIndicator, id = e.complete(true) - return e.complete() + return RadIndicator, id end - -return rad diff --git a/graphics/elements/indicators/signal.lua b/graphics/elements/indicators/SignalBar.lua similarity index 90% rename from graphics/elements/indicators/signal.lua rename to graphics/elements/indicators/SignalBar.lua index 7e9c1b8..37d1359 100644 --- a/graphics/elements/indicators/signal.lua +++ b/graphics/elements/indicators/SignalBar.lua @@ -15,16 +15,16 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors (foreground is used for high signal quality) ---@field hidden? boolean true to hide on initial draw --- new signal bar +-- Create a new signal bar indicator element. ---@nodiscard ---@param args signal_bar_args ----@return graphics_element element, element_id id -local function signal_bar(args) +---@return SignalBar element, element_id id +return function (args) args.height = 1 args.width = util.trinary(args.compact, 1, 2) -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = 0 @@ -76,10 +76,8 @@ local function signal_bar(args) end end - -- initial draw - e.redraw() + ---@class SignalBar:graphics_element + local SignalBar, id = e.complete(true) - return e.complete() + return SignalBar, id end - -return signal_bar diff --git a/graphics/elements/indicators/state.lua b/graphics/elements/indicators/StateIndicator.lua similarity index 88% rename from graphics/elements/indicators/state.lua rename to graphics/elements/indicators/StateIndicator.lua index f2dc134..8ee2cdc 100644 --- a/graphics/elements/indicators/state.lua +++ b/graphics/elements/indicators/StateIndicator.lua @@ -20,11 +20,11 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new state indicator +-- Create a new state indicator element. ---@nodiscard ---@param args state_indicator_args ----@return graphics_element element, element_id id -local function state_indicator(args) +---@return StateIndicator element, element_id id +return function (args) element.assert(type(args.states) == "table", "states is a required field") if util.is_int(args.height) then @@ -52,7 +52,7 @@ local function state_indicator(args) end -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = args.value or 1 @@ -74,10 +74,8 @@ local function state_indicator(args) ---@param val integer indicator state function e.set_value(val) e.on_update(val) end - -- initial draw - e.redraw() + ---@class StateIndicator:graphics_element + local StateIndicator, id = e.complete(true) - return e.complete() + return StateIndicator, id end - -return state_indicator diff --git a/graphics/elements/indicators/trilight.lua b/graphics/elements/indicators/TriIndicatorLight.lua similarity index 91% rename from graphics/elements/indicators/trilight.lua rename to graphics/elements/indicators/TriIndicatorLight.lua index f5d441c..e01d12d 100644 --- a/graphics/elements/indicators/trilight.lua +++ b/graphics/elements/indicators/TriIndicatorLight.lua @@ -20,11 +20,11 @@ local flasher = require("graphics.flasher") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new tri-state indicator light +-- Create a new tri-state indicator light element. ---@nodiscard ---@param args tristate_indicator_light_args ----@return graphics_element element, element_id id -local function tristate_indicator_light(args) +---@return TriIndicatorLight element, element_id id +return function (args) element.assert(type(args.label) == "string", "label is a required field") element.assert(type(args.c1) == "number", "c1 is a required field") element.assert(type(args.c2) == "number", "c2 is a required field") @@ -38,7 +38,7 @@ local function tristate_indicator_light(args) args.width = math.max(args.min_label_width or 1, string.len(args.label)) + 2 -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = 1 @@ -102,10 +102,8 @@ local function tristate_indicator_light(args) e.w_write(args.label) end - -- initial draw - e.redraw() + ---@class TriIndicatorLight:graphics_element + local TriIndicatorLight, id = e.complete(true) - return e.complete() + return TriIndicatorLight, id end - -return tristate_indicator_light diff --git a/graphics/elements/indicators/vbar.lua b/graphics/elements/indicators/VerticalBar.lua similarity index 90% rename from graphics/elements/indicators/vbar.lua rename to graphics/elements/indicators/VerticalBar.lua index afe56fc..d04c286 100644 --- a/graphics/elements/indicators/vbar.lua +++ b/graphics/elements/indicators/VerticalBar.lua @@ -15,13 +15,13 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new vertical bar +-- Create a new vertical fill bar indicator element. ---@nodiscard ---@param args vbar_args ----@return graphics_element element, element_id id -local function vbar(args) +---@return VerticalBar element, element_id id +return function (args) -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = 0.0 @@ -98,10 +98,8 @@ local function vbar(args) e.redraw() end - -- initial draw - e.redraw() + ---@class VerticalBar:graphics_element + local VerticalBar, id = e.complete(true) - return e.complete() + return VerticalBar, id end - -return vbar diff --git a/graphics/flasher.lua b/graphics/flasher.lua index 9412ac7..624822b 100644 --- a/graphics/flasher.lua +++ b/graphics/flasher.lua @@ -18,7 +18,7 @@ local PERIOD = { flasher.PERIOD = PERIOD local active = false -local registry = { {}, {}, {} } -- one registry table per period +local registry = { {}, {}, {} } ---@type [ function[], function[], function [] ] one registry table per period local callback_counter = 0 -- blink registered indicators
diff --git a/pocket/configure.lua b/pocket/configure.lua index 0e91caa..e2585a6 100644 --- a/pocket/configure.lua +++ b/pocket/configure.lua @@ -9,18 +9,18 @@ local util = require("scada-common.util") local core = require("graphics.core") local themes = require("graphics.themes") -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") +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") -local CheckBox = require("graphics.elements.controls.checkbox") -local PushButton = require("graphics.elements.controls.push_button") -local RadioButton = require("graphics.elements.controls.radio_button") +local Checkbox = require("graphics.elements.controls.Checkbox") +local PushButton = require("graphics.elements.controls.PushButton") +local RadioButton = require("graphics.elements.controls.RadioButton") -local NumberField = require("graphics.elements.form.number_field") -local TextField = require("graphics.elements.form.text_field") +local NumberField = require("graphics.elements.form.NumberField") +local TextField = require("graphics.elements.form.TextField") local println = util.println local tri = util.trinary @@ -58,8 +58,8 @@ local tool_ctl = { viewing_config = false, importing_legacy = false, - view_cfg = nil, ---@type graphics_element - settings_apply = nil, ---@type graphics_element + view_cfg = nil, ---@type PushButton + settings_apply = nil, ---@type PushButton set_networked = nil, ---@type function bundled_emcool = nil, ---@type function @@ -68,8 +68,8 @@ local tool_ctl = { load_legacy = nil, ---@type function show_auth_key = nil, ---@type function - show_key_btn = nil, ---@type graphics_element - auth_key_textbox = nil, ---@type graphics_element + show_key_btn = nil, ---@type PushButton + auth_key_textbox = nil, ---@type TextBox auth_key_value = "" } @@ -122,7 +122,7 @@ local function load_settings(target, raw) end -- create the config view ----@param display graphics_element +---@param display DisplayBox local function config_view(display) ---@diagnostic disable-next-line: undefined-field local function exit() os.queueEvent("terminate") end @@ -282,14 +282,14 @@ local function config_view(display) 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,x=1,y=12,text="Facility Auth Key"} - local key, _, censor = 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} + 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} - local function censor_key(enable) censor(util.trinary(enable, "*", nil)) end + local function censor_key(enable) key.censor(util.trinary(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} - 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} + 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) @@ -323,7 +323,7 @@ local function config_view(display) 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} - 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,x=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} diff --git a/pocket/iocontrol.lua b/pocket/iocontrol.lua index b04f64d..89b96c5 100644 --- a/pocket/iocontrol.lua +++ b/pocket/iocontrol.lua @@ -39,15 +39,6 @@ local io = { ps = psil.create() } --- luacheck: no unused args - --- placeholder acknowledge function for type hinting ----@param success boolean ----@diagnostic disable-next-line: unused-local -local function __generic_ack(success) end - --- luacheck: unused args - local config = nil ---@type pkt_config local comms = nil ---@type pocket_comms @@ -92,10 +83,10 @@ function iocontrol.init_core(pkt_comms, nav, cfg) get_tone_states = function () comms.diag__get_alarm_tones() end, - ready_warn = nil, ---@type graphics_element - tone_buttons = {}, - alarm_buttons = {}, - tone_indicators = {} -- indicators to update from supervisor tone states + ready_warn = nil, ---@type TextBox + tone_buttons = {}, ---@type SwitchButton[] + alarm_buttons = {}, ---@type Checkbox[] + tone_indicators = {} ---@type IndicatorLight[] indicators to update from supervisor tone states } -- API access @@ -166,24 +157,21 @@ function iocontrol.init_fac(conf) radiation = types.new_zero_radiation_reading(), - start_ack = __generic_ack, - stop_ack = __generic_ack, - scram_ack = __generic_ack, - ack_alarms_ack = __generic_ack, + start_ack = nil, ---@type fun(success: boolean) + stop_ack = nil, ---@type fun(success: boolean) + scram_ack = nil, ---@type fun(success: boolean) + ack_alarms_ack = nil, ---@type fun(success: boolean) ps = psil.create(), - induction_ps_tbl = {}, - induction_data_tbl = {}, + induction_ps_tbl = {}, ---@type psil[] + induction_data_tbl = {}, ---@type imatrix_session_db[] - sps_ps_tbl = {}, - sps_data_tbl = {}, + sps_ps_tbl = {}, ---@type psil[] + sps_data_tbl = {}, ---@type sps_session_db[] - tank_ps_tbl = {}, - tank_data_tbl = {}, - - env_d_ps = psil.create(), - env_d_data = {} + tank_ps_tbl = {}, ---@type psil[] + tank_data_tbl = {} ---@type dynamicv_session_db[] } -- create induction and SPS tables (currently only 1 of each is supported) @@ -192,107 +180,14 @@ function iocontrol.init_fac(conf) table.insert(io.facility.sps_ps_tbl, psil.create()) table.insert(io.facility.sps_data_tbl, {}) - -- determine tank information - if io.facility.tank_mode == 0 then - io.facility.tank_defs = {} - -- on facility tank mode 0, setup tank defs to match unit tank option - for i = 1, conf.num_units do - io.facility.tank_defs[i] = util.trinary(conf.cooling.r_cool[i].TankConnection, 1, 0) - end - - io.facility.tank_list = { table.unpack(io.facility.tank_defs) } - else - -- decode the layout of tanks from the connections definitions - local tank_mode = io.facility.tank_mode - local tank_defs = io.facility.tank_defs - local tank_list = { table.unpack(tank_defs) } - - local function calc_fdef(start_idx, end_idx) - local first = 4 - for i = start_idx, end_idx do - if io.facility.tank_defs[i] == 2 then - if i < first then first = i end - end - end - return first - end - - if tank_mode == 1 then - -- (1) 1 total facility tank (A A A A) - local first_fdef = calc_fdef(1, #tank_defs) - for i = 1, #tank_defs do - if i > first_fdef and tank_defs[i] == 2 then - tank_list[i] = 0 - end - end - elseif tank_mode == 2 then - -- (2) 2 total facility tanks (A A A B) - local first_fdef = calc_fdef(1, math.min(3, #tank_defs)) - for i = 1, #tank_defs do - if (i ~= 4) and (i > first_fdef) and (tank_defs[i] == 2) then - tank_list[i] = 0 - end - end - elseif tank_mode == 3 then - -- (3) 2 total facility tanks (A A B B) - for _, a in pairs({ 1, 3 }) do - local b = a + 1 - if (tank_defs[a] == 2) and (tank_defs[b] == 2) then - tank_list[b] = 0 - end - end - elseif tank_mode == 4 then - -- (4) 2 total facility tanks (A B B B) - local first_fdef = calc_fdef(2, #tank_defs) - for i = 1, #tank_defs do - if (i ~= 1) and (i > first_fdef) and (tank_defs[i] == 2) then - tank_list[i] = 0 - end - end - elseif tank_mode == 5 then - -- (5) 3 total facility tanks (A A B C) - local first_fdef = calc_fdef(1, math.min(2, #tank_defs)) - for i = 1, #tank_defs do - if (not (i == 3 or i == 4)) and (i > first_fdef) and (tank_defs[i] == 2) then - tank_list[i] = 0 - end - end - elseif tank_mode == 6 then - -- (6) 3 total facility tanks (A B B C) - local first_fdef = calc_fdef(2, math.min(3, #tank_defs)) - for i = 1, #tank_defs do - if (not (i == 1 or i == 4)) and (i > first_fdef) and (tank_defs[i] == 2) then - tank_list[i] = 0 - end - end - elseif tank_mode == 7 then - -- (7) 3 total facility tanks (A B C C) - local first_fdef = calc_fdef(3, #tank_defs) - for i = 1, #tank_defs do - if (not (i == 1 or i == 2)) and (i > first_fdef) and (tank_defs[i] == 2) then - tank_list[i] = 0 - end - end - end - - io.facility.tank_list = tank_list - end - - -- create facility tank tables - for i = 1, #io.facility.tank_list do - if io.facility.tank_list[i] == 2 then - table.insert(io.facility.tank_ps_tbl, psil.create()) - table.insert(io.facility.tank_data_tbl, {}) - end - end - -- create unit data structures - io.units = {} + io.units = {} ---@type pioctl_unit[] for i = 1, conf.num_units do ---@class pioctl_unit local entry = { unit_id = i, connected = false, + ---@type { boilers: { connected: boolean, faulted: boolean }[], turbines: { connected: boolean, faulted: boolean }[] } rtu_hw = {}, num_boilers = 0, @@ -323,27 +218,27 @@ function iocontrol.init_fac(conf) ack_alarms = function () process.ack_all_alarms(i) end, set_burn = function (rate) process.set_rate(i, rate) end, ---@param rate number burn rate - start_ack = __generic_ack, - scram_ack = __generic_ack, - reset_rps_ack = __generic_ack, - ack_alarms_ack = __generic_ack, + start_ack = nil, ---@type fun(success: boolean) + scram_ack = nil, ---@type fun(success: boolean) + reset_rps_ack = nil, ---@type fun(success: boolean) + ack_alarms_ack = nil, ---@type fun(success: boolean) - ---@type alarms + ---@type { [ALARM]: ALARM_STATE } alarms = { ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE }, - annunciator = {}, ---@type annunciator + annunciator = {}, ---@type annunciator unit_ps = psil.create(), - reactor_data = {}, ---@type reactor_db + reactor_data = {}, ---@type reactor_db - boiler_ps_tbl = {}, - boiler_data_tbl = {}, + boiler_ps_tbl = {}, ---@type psil[] + boiler_data_tbl = {}, ---@type boilerv_session_db[] - turbine_ps_tbl = {}, - turbine_data_tbl = {}, + turbine_ps_tbl = {}, ---@type psil[] + turbine_data_tbl = {}, ---@type turbinev_session_db[] - tank_ps_tbl = {}, - tank_data_tbl = {} + tank_ps_tbl = {}, ---@type psil[] + tank_data_tbl = {} ---@type dynamicv_session_db[] } -- on other facility modes, overwrite unit TANK option with facility tank defs @@ -485,7 +380,7 @@ end -- update unit status data from API_GET_UNIT ---@param data table function iocontrol.record_unit_data(data) - local unit = io.units[data[1]] ---@type pioctl_unit + local unit = io.units[data[1]] unit.connected = data[2] unit.rtu_hw = data[3] @@ -650,8 +545,8 @@ function iocontrol.record_unit_data(data) unit.boiler_data_tbl = data[8] for id = 1, #unit.boiler_data_tbl do - local boiler = unit.boiler_data_tbl[id] ---@type boilerv_session_db - local ps = unit.boiler_ps_tbl[id] ---@type psil + local boiler = unit.boiler_data_tbl[id] + local ps = unit.boiler_ps_tbl[id] local boiler_status = 1 local computed_status = 1 @@ -683,8 +578,8 @@ function iocontrol.record_unit_data(data) unit.turbine_data_tbl = data[9] for id = 1, #unit.turbine_data_tbl do - local turbine = unit.turbine_data_tbl[id] ---@type turbinev_session_db - local ps = unit.turbine_ps_tbl[id] ---@type psil + local turbine = unit.turbine_data_tbl[id] + local ps = unit.turbine_ps_tbl[id] local turbine_status = 1 local computed_status = 1 diff --git a/pocket/pocket.lua b/pocket/pocket.lua index 80a2cb5..e759160 100644 --- a/pocket/pocket.lua +++ b/pocket/pocket.lua @@ -100,22 +100,22 @@ pocket.APP_ID = APP_ID ---@class nav_tree_page ---@field _p nav_tree_page|nil page's parent ----@field _c table page's children +---@field _c nav_tree_page[] page's children ---@field nav_to function function to navigate to this page ---@field switcher function|nil function to switch between children ----@field tasks table tasks to run while viewing this page +---@field tasks function[] tasks to run while viewing this page -- initialize the page navigation system ---@param smem pkt_shared_memory function pocket.init_nav(smem) local self = { - pane = nil, ---@type graphics_element - sidebar = nil, ---@type graphics_element - apps = {}, - containers = {}, - help_map = {}, - help_return = nil, - loader_return = nil, + pane = nil, ---@type AppMultiPane|MultiPane|nil + sidebar = nil, ---@type Sidebar|nil + apps = {}, ---@type pocket_app[] + containers = {}, ---@type Container[] + help_map = {}, ---@type { [string]: function } + help_return = nil, ---@type POCKET_APP_ID|nil + loader_return = nil, ---@type POCKET_APP_ID|nil cur_app = APP_ID.ROOT } @@ -125,27 +125,27 @@ function pocket.init_nav(smem) local nav = {} -- set the root pane element to switch between apps with - ---@param root_pane graphics_element + ---@param root_pane MultiPane function nav.set_pane(root_pane) self.pane = root_pane end -- link sidebar element - ---@param sidebar graphics_element + ---@param sidebar Sidebar function nav.set_sidebar(sidebar) self.sidebar = sidebar end -- register an app ---@param app_id POCKET_APP_ID app ID - ---@param container graphics_element element that contains this app (usually a Div) - ---@param pane? graphics_element multipane if this is a simple paned app, then nav_to must be a number + ---@param container Container element that contains this app (usually a Div) + ---@param pane? AppMultiPane|MultiPane multipane if this is a simple paned app, then nav_to must be a number ---@param require_sv? boolean true to specifiy if this app should be unloaded when the supervisor connection is lost ---@param require_api? boolean true to specifiy if this app should be unloaded when the api connection is lost function nav.register_app(app_id, container, pane, require_sv, require_api) ---@class pocket_app local app = { loaded = false, - cur_page = nil, ---@type nav_tree_page + cur_page = nil, ---@type nav_tree_page pane = pane, - paned_pages = {}, - sidebar_items = {} + paned_pages = {}, ---@type nav_tree_page[] + sidebar_items = {} ---@type sidebar_entry[] } app.load = function () app.loaded = true end @@ -159,13 +159,13 @@ function pocket.init_nav(smem) function app.requires_conn() return require_sv or require_api or false end -- delayed set of the pane if it wasn't ready at the start - ---@param root_pane graphics_element multipane + ---@param root_pane AppMultiPane|MultiPane multipane function app.set_root_pane(root_pane) app.pane = root_pane end -- configure the sidebar - ---@param items table + ---@param items sidebar_entry[] function app.set_sidebar(items) app.sidebar_items = items if self.sidebar then self.sidebar.update(items) end @@ -263,7 +263,7 @@ function pocket.init_nav(smem) -- reset help return on navigating out of an app if app_id == APP_ID.ROOT then self.help_return = nil end - local app = self.apps[app_id] ---@type pocket_app + local app = self.apps[app_id] if app then if app.requires_conn() and not smem.pkt_sys.pocket_comms.is_linked() then -- bring up the app loader @@ -339,7 +339,7 @@ function pocket.init_nav(smem) return end - local app = self.apps[self.cur_app] ---@type pocket_app + local app = self.apps[self.cur_app] log.debug("attempting app nav up for app " .. self.cur_app) if not app.nav_up() then @@ -359,6 +359,7 @@ function pocket.init_nav(smem) end -- link the help map from the guide app + ---@param map { [string]: function } function nav.link_help(map) self.help_map = map end return nav diff --git a/pocket/renderer.lua b/pocket/renderer.lua index bc16037..727a74b 100644 --- a/pocket/renderer.lua +++ b/pocket/renderer.lua @@ -8,7 +8,7 @@ local style = require("pocket.ui.style") local core = require("graphics.core") local flasher = require("graphics.flasher") -local DisplayBox = require("graphics.elements.displaybox") +local DisplayBox = require("graphics.elements.DisplayBox") ---@class pocket_renderer local renderer = {} diff --git a/pocket/startup.lua b/pocket/startup.lua index 28b37d9..c31b599 100644 --- a/pocket/startup.lua +++ b/pocket/startup.lua @@ -20,7 +20,7 @@ local pocket = require("pocket.pocket") local renderer = require("pocket.renderer") local threads = require("pocket.threads") -local POCKET_VERSION = "v0.12.1-alpha" +local POCKET_VERSION = "v0.12.2-alpha" local println = util.println local println_ts = util.println_ts diff --git a/pocket/ui/apps/control.lua b/pocket/ui/apps/control.lua index 4066603..a9129b4 100644 --- a/pocket/ui/apps/control.lua +++ b/pocket/ui/apps/control.lua @@ -13,19 +13,19 @@ local style = require("pocket.ui.style") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local MultiPane = require("graphics.elements.multipane") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local MultiPane = require("graphics.elements.MultiPane") +local TextBox = require("graphics.elements.TextBox") -local WaitingAnim = require("graphics.elements.animations.waiting") +local WaitingAnim = require("graphics.elements.animations.Waiting") -local HazardButton = require("graphics.elements.controls.hazard_button") -local PushButton = require("graphics.elements.controls.push_button") +local HazardButton = require("graphics.elements.controls.HazardButton") +local PushButton = require("graphics.elements.controls.PushButton") -local NumberField = require("graphics.elements.form.number_field") +local NumberField = require("graphics.elements.form.NumberField") -local DataIndicator = require("graphics.elements.indicators.data") -local IconIndicator = require("graphics.elements.indicators.icon") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local IconIndicator = require("graphics.elements.indicators.IconIndicator") local AUTO_GROUP = types.AUTO_GROUP @@ -42,7 +42,7 @@ local hzd_fg_bg = cpair(colors.white, colors.gray) local dis_colors = cpair(colors.white, colors.lightGray) -- new unit control page view ----@param root graphics_element parent +---@param root Container parent local function new_view(root) local db = iocontrol.get_db() @@ -63,7 +63,7 @@ local function new_view(root) local btn_fg_bg = cpair(colors.green, colors.black) local btn_active = cpair(colors.white, colors.black) - local page_div = nil ---@type nil|graphics_element + local page_div = nil ---@type Div|nil -- set sidebar to display unit-specific fields based on a specified unit local function set_sidebar() @@ -83,7 +83,7 @@ local function new_view(root) local function load() page_div = Div{parent=main,y=2,width=main.get_width()} - local panes = {} + local panes = {} ---@type Div[] local active_unit = 1 @@ -108,7 +108,7 @@ local function new_view(root) for i = 1, db.facility.num_units do local u_pane = panes[i] local u_div = Div{parent=u_pane,x=2,width=main.get_width()-2} - local unit = db.units[i] ---@type pioctl_unit + local unit = db.units[i] local u_ps = unit.unit_ps -- refresh data callback, every 500ms it will re-send the query diff --git a/pocket/ui/apps/diag_apps.lua b/pocket/ui/apps/diag_apps.lua index 79b3c12..ba2bed3 100644 --- a/pocket/ui/apps/diag_apps.lua +++ b/pocket/ui/apps/diag_apps.lua @@ -7,14 +7,14 @@ local pocket = require("pocket.pocket") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local TextBox = require("graphics.elements.TextBox") -local IndicatorLight = require("graphics.elements.indicators.light") +local IndicatorLight = require("graphics.elements.indicators.IndicatorLight") -local Checkbox = require("graphics.elements.controls.checkbox") -local PushButton = require("graphics.elements.controls.push_button") -local SwitchButton = require("graphics.elements.controls.switch_button") +local Checkbox = require("graphics.elements.controls.Checkbox") +local PushButton = require("graphics.elements.controls.PushButton") +local SwitchButton = require("graphics.elements.controls.SwitchButton") local ALIGN = core.ALIGN local cpair = core.cpair @@ -22,7 +22,7 @@ local cpair = core.cpair local APP_ID = pocket.APP_ID -- create diagnostic app pages ----@param root graphics_element parent +---@param root Container parent local function create_pages(root) local db = iocontrol.get_db() diff --git a/pocket/ui/apps/dummy_app.lua b/pocket/ui/apps/dummy_app.lua index 6e92493..a564761 100644 --- a/pocket/ui/apps/dummy_app.lua +++ b/pocket/ui/apps/dummy_app.lua @@ -7,13 +7,13 @@ local pocket = require("pocket.pocket") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local TextBox = require("graphics.elements.TextBox") local APP_ID = pocket.APP_ID -- create placeholder app page ----@param root graphics_element parent +---@param root Container parent local function create_pages(root) local db = iocontrol.get_db() diff --git a/pocket/ui/apps/guide.lua b/pocket/ui/apps/guide.lua index 768824a..660fcc4 100644 --- a/pocket/ui/apps/guide.lua +++ b/pocket/ui/apps/guide.lua @@ -15,16 +15,16 @@ local guide_section = require("pocket.ui.pages.guide_section") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local ListBox = require("graphics.elements.listbox") -local MultiPane = require("graphics.elements.multipane") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local ListBox = require("graphics.elements.ListBox") +local MultiPane = require("graphics.elements.MultiPane") +local TextBox = require("graphics.elements.TextBox") -local WaitingAnim = require("graphics.elements.animations.waiting") +local WaitingAnim = require("graphics.elements.animations.Waiting") -local PushButton = require("graphics.elements.controls.push_button") +local PushButton = require("graphics.elements.controls.PushButton") -local TextField = require("graphics.elements.form.text_field") +local TextField = require("graphics.elements.form.TextField") local ALIGN = core.ALIGN local cpair = core.cpair @@ -36,7 +36,7 @@ local APP_ID = pocket.APP_ID -- local text_fg = style.text_fg -- new system guide view ----@param root graphics_element parent +---@param root Container parent local function new_view(root) local db = iocontrol.get_db() @@ -58,7 +58,7 @@ local function new_view(root) app.set_sidebar({{ label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = function () db.nav.open_app(APP_ID.ROOT) end }}) - local page_div = nil ---@type nil|graphics_element + local page_div = nil ---@type Div|nil -- load the app (create the elements) local function load() @@ -88,12 +88,11 @@ local function new_view(root) local fps = Div{parent=page_div,x=2,width=p_width} local gls = Div{parent=page_div,x=2,width=p_width} local lnk = Div{parent=page_div,x=2,width=p_width} - local panes = { home, search, use, uis, fps, gls, lnk } + local panes = { home, search, use, uis, fps, gls, lnk } ---@type Div[] - local doc_map = {} - local search_db = {} + local doc_map = {} ---@type { [string]: function } + local search_db = {} ---@type [ string, string, string, function ][] - ---@class _guide_section_constructor_data local sect_construct_data = { app, page_div, panes, doc_map, search_db, btn_fg_bg, btn_active } TextBox{parent=home,y=1,text="cc-mek-scada Guide",alignment=ALIGN.CENTER} @@ -117,7 +116,7 @@ local function new_view(root) function func_ref.run_search() local query = string.lower(query_field.get_value()) - local s_results = { {}, {}, {}, {} } + local s_results = { {}, {}, {}, {} } ---@type [ string, string, string, function ][][] search_results.remove_all() diff --git a/pocket/ui/apps/loader.lua b/pocket/ui/apps/loader.lua index 8ea72f0..7a45a7a 100644 --- a/pocket/ui/apps/loader.lua +++ b/pocket/ui/apps/loader.lua @@ -9,16 +9,16 @@ local conn_waiting = require("pocket.ui.components.conn_waiting") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local MultiPane = require("graphics.elements.multipane") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local MultiPane = require("graphics.elements.MultiPane") +local TextBox = require("graphics.elements.TextBox") local APP_ID = pocket.APP_ID local LINK_STATE = iocontrol.LINK_STATE -- create the connecting to SV & API page ----@param root graphics_element parent +---@param root Container parent local function create_pages(root) local db = iocontrol.get_db() diff --git a/pocket/ui/apps/sys_apps.lua b/pocket/ui/apps/sys_apps.lua index 197a4f6..d797caf 100644 --- a/pocket/ui/apps/sys_apps.lua +++ b/pocket/ui/apps/sys_apps.lua @@ -12,12 +12,12 @@ local pocket = require("pocket.pocket") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local ListBox = require("graphics.elements.listbox") -local MultiPane = require("graphics.elements.multipane") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local ListBox = require("graphics.elements.ListBox") +local MultiPane = require("graphics.elements.MultiPane") +local TextBox = require("graphics.elements.TextBox") -local PushButton = require("graphics.elements.controls.push_button") +local PushButton = require("graphics.elements.controls.PushButton") local ALIGN = core.ALIGN local cpair = core.cpair @@ -25,7 +25,7 @@ local cpair = core.cpair local APP_ID = pocket.APP_ID -- create system app pages ----@param root graphics_element parent +---@param root Container parent local function create_pages(root) local db = iocontrol.get_db() diff --git a/pocket/ui/apps/unit.lua b/pocket/ui/apps/unit.lua index 94f3341..2f97bf9 100644 --- a/pocket/ui/apps/unit.lua +++ b/pocket/ui/apps/unit.lua @@ -15,17 +15,17 @@ local turbine = require("pocket.ui.pages.unit_turbine") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local ListBox = require("graphics.elements.listbox") -local MultiPane = require("graphics.elements.multipane") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local ListBox = require("graphics.elements.ListBox") +local MultiPane = require("graphics.elements.MultiPane") +local TextBox = require("graphics.elements.TextBox") -local WaitingAnim = require("graphics.elements.animations.waiting") +local WaitingAnim = require("graphics.elements.animations.Waiting") -local PushButton = require("graphics.elements.controls.push_button") +local PushButton = require("graphics.elements.controls.PushButton") -local DataIndicator = require("graphics.elements.indicators.data") -local IconIndicator = require("graphics.elements.indicators.icon") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local IconIndicator = require("graphics.elements.indicators.IconIndicator") local ALIGN = core.ALIGN local cpair = core.cpair @@ -47,7 +47,7 @@ local emc_ind_s = { } -- new unit page view ----@param root graphics_element parent +---@param root Container parent local function new_view(root) local db = iocontrol.get_db() @@ -69,11 +69,11 @@ local function new_view(root) local btn_active = cpair(colors.white, colors.black) local nav_links = {} - local page_div = nil ---@type nil|graphics_element + local page_div = nil ---@type Div|nil -- set sidebar to display unit-specific fields based on a specified unit local function set_sidebar(id) - local unit = db.units[id] ---@type pioctl_unit + local unit = db.units[id] local list = { { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = function () db.nav.open_app(APP_ID.ROOT) end }, @@ -99,7 +99,7 @@ local function new_view(root) local function load() page_div = Div{parent=main,y=2,width=main.get_width()} - local panes = {} + local panes = {} ---@type Div[] local active_unit = 1 @@ -127,7 +127,7 @@ local function new_view(root) for i = 1, db.facility.num_units do local u_pane = panes[i] local u_div = Div{parent=u_pane,x=2,width=main.get_width()-2} - local unit = db.units[i] ---@type pioctl_unit + local unit = db.units[i] local u_ps = unit.unit_ps -- refresh data callback, every 500ms it will re-send the query diff --git a/pocket/ui/components/conn_waiting.lua b/pocket/ui/components/conn_waiting.lua index b55f067..6050241 100644 --- a/pocket/ui/components/conn_waiting.lua +++ b/pocket/ui/components/conn_waiting.lua @@ -8,17 +8,17 @@ local style = require("pocket.ui.style") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local TextBox = require("graphics.elements.TextBox") -local WaitingAnim = require("graphics.elements.animations.waiting") +local WaitingAnim = require("graphics.elements.animations.Waiting") local ALIGN = core.ALIGN local cpair = core.cpair -- create a waiting view ----@param parent graphics_element parent +---@param parent Container parent ---@param y integer y offset local function init(parent, y, is_api) -- root div diff --git a/pocket/ui/main.lua b/pocket/ui/main.lua index bf66f9b..eb9c7f1 100644 --- a/pocket/ui/main.lua +++ b/pocket/ui/main.lua @@ -21,16 +21,16 @@ local style = require("pocket.ui.style") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local MultiPane = require("graphics.elements.multipane") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local MultiPane = require("graphics.elements.MultiPane") +local TextBox = require("graphics.elements.TextBox") -local WaitingAnim = require("graphics.elements.animations.waiting") +local WaitingAnim = require("graphics.elements.animations.Waiting") -local PushButton = require("graphics.elements.controls.push_button") -local Sidebar = require("graphics.elements.controls.sidebar") +local PushButton = require("graphics.elements.controls.PushButton") +local Sidebar = require("graphics.elements.controls.Sidebar") -local SignalBar = require("graphics.elements.indicators.signal") +local SignalBar = require("graphics.elements.indicators.SignalBar") local ALIGN = core.ALIGN local cpair = core.cpair @@ -38,7 +38,7 @@ local cpair = core.cpair local APP_ID = pocket.APP_ID -- create new main view ----@param main graphics_element main displaybox +---@param main DisplayBox main displaybox local function init(main) local db = iocontrol.get_db() diff --git a/pocket/ui/pages/guide_section.lua b/pocket/ui/pages/guide_section.lua index c14a6ab..76ceaf6 100644 --- a/pocket/ui/pages/guide_section.lua +++ b/pocket/ui/pages/guide_section.lua @@ -5,14 +5,14 @@ local docs = require("pocket.ui.docs") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local ListBox = require("graphics.elements.listbox") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local ListBox = require("graphics.elements.ListBox") +local TextBox = require("graphics.elements.TextBox") -local PushButton = require("graphics.elements.controls.push_button") +local PushButton = require("graphics.elements.controls.PushButton") -local IndicatorLight = require("graphics.elements.indicators.light") -local LED = require("graphics.elements.indicators.led") +local IndicatorLight = require("graphics.elements.indicators.IndicatorLight") +local LED = require("graphics.elements.indicators.LED") local ALIGN = core.ALIGN local cpair = core.cpair @@ -21,14 +21,14 @@ local DOC_TYPE = docs.DOC_ITEM_TYPE local LIST_TYPE = docs.DOC_LIST_TYPE -- new guide documentation section ----@param data _guide_section_constructor_data +---@param data { [1]: pocket_app, [2]: Div, [3]: Div[], [4]: { [string]: function }, [5]: [ string, string, string, function ][], [6]: cpair, [7]: cpair } ---@param base_page nav_tree_page ---@param title string ---@param items table ---@param scroll_height integer ---@return nav_tree_page return function (data, base_page, title, items, scroll_height) - local app, page_div, panes, doc_map, search_db, btn_fg_bg, btn_active = table.unpack(data) + local app, page_div, panes, doc_map, search_db, btn_fg_bg, btn_active = data[1], data[2], data[3], data[4], data[5], data[6], data[7] local section_page = app.new_page(base_page, #panes + 1) local section_div = Div{parent=page_div,x=2} diff --git a/pocket/ui/pages/home_page.lua b/pocket/ui/pages/home_page.lua index 38385be..80c7a24 100644 --- a/pocket/ui/pages/home_page.lua +++ b/pocket/ui/pages/home_page.lua @@ -7,11 +7,11 @@ local pocket = require("pocket.pocket") local core = require("graphics.core") -local AppMultiPane = require("graphics.elements.appmultipane") -local Div = require("graphics.elements.div") -local TextBox = require("graphics.elements.textbox") +local AppMultiPane = require("graphics.elements.AppMultiPane") +local Div = require("graphics.elements.Div") +local TextBox = require("graphics.elements.TextBox") -local App = require("graphics.elements.controls.app") +local App = require("graphics.elements.controls.App") local ALIGN = core.ALIGN local cpair = core.cpair @@ -19,7 +19,7 @@ local cpair = core.cpair local APP_ID = pocket.APP_ID -- new home page view ----@param root graphics_element parent +---@param root Container parent local function new_view(root) local db = iocontrol.get_db() diff --git a/pocket/ui/pages/unit_boiler.lua b/pocket/ui/pages/unit_boiler.lua index 4ac3993..1790268 100644 --- a/pocket/ui/pages/unit_boiler.lua +++ b/pocket/ui/pages/unit_boiler.lua @@ -7,15 +7,15 @@ local style = require("pocket.ui.style") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local TextBox = require("graphics.elements.TextBox") -local PushButton = require("graphics.elements.controls.push_button") +local PushButton = require("graphics.elements.controls.PushButton") -local DataIndicator = require("graphics.elements.indicators.data") -local StateIndicator = require("graphics.elements.indicators.state") -local IconIndicator = require("graphics.elements.indicators.icon") -local VerticalBar = require("graphics.elements.indicators.vbar") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local StateIndicator = require("graphics.elements.indicators.StateIndicator") +local IconIndicator = require("graphics.elements.indicators.IconIndicator") +local VerticalBar = require("graphics.elements.indicators.VerticalBar") local ALIGN = core.ALIGN local cpair = core.cpair @@ -29,8 +29,8 @@ local yel_ind_s = style.icon_states.yel_ind_s -- create a boiler view in the unit app ---@param app pocket_app ---@param u_page nav_tree_page ----@param panes table ----@param blr_pane graphics_element +---@param panes Div[] +---@param blr_pane Div ---@param b_id integer boiler ID ---@param ps psil ---@param update function diff --git a/pocket/ui/pages/unit_reactor.lua b/pocket/ui/pages/unit_reactor.lua index 56b0378..a3333f5 100644 --- a/pocket/ui/pages/unit_reactor.lua +++ b/pocket/ui/pages/unit_reactor.lua @@ -7,15 +7,15 @@ local style = require("pocket.ui.style") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local TextBox = require("graphics.elements.TextBox") -local PushButton = require("graphics.elements.controls.push_button") +local PushButton = require("graphics.elements.controls.PushButton") -local DataIndicator = require("graphics.elements.indicators.data") -local StateIndicator = require("graphics.elements.indicators.state") -local IconIndicator = require("graphics.elements.indicators.icon") -local VerticalBar = require("graphics.elements.indicators.vbar") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local StateIndicator = require("graphics.elements.indicators.StateIndicator") +local IconIndicator = require("graphics.elements.indicators.IconIndicator") +local VerticalBar = require("graphics.elements.indicators.VerticalBar") local ALIGN = core.ALIGN local cpair = core.cpair @@ -29,8 +29,8 @@ local yel_ind_s = style.icon_states.yel_ind_s -- create a reactor view in the unit app ---@param app pocket_app ---@param u_page nav_tree_page ----@param panes table ----@param page_div graphics_element +---@param panes Div[] +---@param page_div Div ---@param u_ps psil ---@param update function return function (app, u_page, panes, page_div, u_ps, update) diff --git a/pocket/ui/pages/unit_turbine.lua b/pocket/ui/pages/unit_turbine.lua index df90061..94541ad 100644 --- a/pocket/ui/pages/unit_turbine.lua +++ b/pocket/ui/pages/unit_turbine.lua @@ -6,16 +6,16 @@ local style = require("pocket.ui.style") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local TextBox = require("graphics.elements.TextBox") -local PushButton = require("graphics.elements.controls.push_button") +local PushButton = require("graphics.elements.controls.PushButton") -local DataIndicator = require("graphics.elements.indicators.data") -local IconIndicator = require("graphics.elements.indicators.icon") -local PowerIndicator = require("graphics.elements.indicators.power") -local StateIndicator = require("graphics.elements.indicators.state") -local VerticalBar = require("graphics.elements.indicators.vbar") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local IconIndicator = require("graphics.elements.indicators.IconIndicator") +local PowerIndicator = require("graphics.elements.indicators.PowerIndicator") +local StateIndicator = require("graphics.elements.indicators.StateIndicator") +local VerticalBar = require("graphics.elements.indicators.VerticalBar") local ALIGN = core.ALIGN local cpair = core.cpair @@ -30,8 +30,8 @@ local yel_ind_s = style.icon_states.yel_ind_s -- create a turbine view in the unit app ---@param app pocket_app ---@param u_page nav_tree_page ----@param panes table ----@param tbn_pane graphics_element +---@param panes Div[] +---@param tbn_pane Div ---@param u_id integer unit ID ---@param t_id integer turbine ID ---@param ps psil diff --git a/reactor-plc/config/check.lua b/reactor-plc/config/check.lua index 106a51d..7a964fe 100644 --- a/reactor-plc/config/check.lua +++ b/reactor-plc/config/check.lua @@ -8,11 +8,11 @@ local plc = require("reactor-plc.plc") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local ListBox = require("graphics.elements.listbox") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local ListBox = require("graphics.elements.ListBox") +local TextBox = require("graphics.elements.TextBox") -local PushButton = require("graphics.elements.controls.push_button") +local PushButton = require("graphics.elements.controls.PushButton") local tri = util.trinary @@ -33,8 +33,8 @@ local self = { settings = nil, ---@type plc_config - run_test_btn = nil, ---@type graphics_element - sc_log = nil, ---@type graphics_element + run_test_btn = nil, ---@type PushButton + sc_log = nil, ---@type ListBox self_check_msg = nil ---@type function } @@ -160,7 +160,7 @@ local function self_check() end -- exit self check back home ----@param main_pane graphics_element +---@param main_pane MultiPane local function exit_self_check(main_pane) tcd.abort(handle_timeout) self.net_listen = false @@ -172,10 +172,10 @@ end local check = {} -- create the self-check view ----@param main_pane graphics_element +---@param main_pane MultiPane ---@param settings_cfg plc_config ----@param check_sys graphics_element ----@param style table +---@param check_sys Div +---@param style { [string]: cpair } function check.create(main_pane, settings_cfg, check_sys, style) local bw_fg_bg = style.bw_fg_bg local g_lg_fg_bg = style.g_lg_fg_bg diff --git a/reactor-plc/config/system.lua b/reactor-plc/config/system.lua index f612f9e..7ad213f 100644 --- a/reactor-plc/config/system.lua +++ b/reactor-plc/config/system.lua @@ -5,20 +5,20 @@ local util = require("scada-common.util") local core = require("graphics.core") local themes = require("graphics.themes") -local Div = require("graphics.elements.div") -local ListBox = require("graphics.elements.listbox") -local MultiPane = require("graphics.elements.multipane") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local ListBox = require("graphics.elements.ListBox") +local MultiPane = require("graphics.elements.MultiPane") +local TextBox = require("graphics.elements.TextBox") -local CheckBox = require("graphics.elements.controls.checkbox") -local PushButton = require("graphics.elements.controls.push_button") -local Radio2D = require("graphics.elements.controls.radio_2d") -local RadioButton = require("graphics.elements.controls.radio_button") +local Checkbox = require("graphics.elements.controls.Checkbox") +local PushButton = require("graphics.elements.controls.PushButton") +local Radio2D = require("graphics.elements.controls.Radio2D") +local RadioButton = require("graphics.elements.controls.RadioButton") -local NumberField = require("graphics.elements.form.number_field") -local TextField = require("graphics.elements.form.text_field") +local NumberField = require("graphics.elements.form.NumberField") +local TextField = require("graphics.elements.form.TextField") -local IndLight = require("graphics.elements.indicators.light") +local IndLight = require("graphics.elements.indicators.IndicatorLight") local cpair = core.cpair @@ -31,8 +31,8 @@ local self = { bundled_emcool = nil, ---@type function show_auth_key = nil, ---@type function - show_key_btn = nil, ---@type graphics_element - auth_key_textbox = nil, ---@type graphics_element + show_key_btn = nil, ---@type PushButton + auth_key_textbox = nil, ---@type TextBox auth_key_value = "" } @@ -61,17 +61,14 @@ local system = {} -- create the system configuration view ---@param tool_ctl _plc_cfg_tool_ctl ----@param main_pane graphics_element ----@param cfg_sys table ----@param divs table ----@param style table +---@param main_pane MultiPane +---@param cfg_sys [ plc_config, plc_config, plc_config, table, function ] +---@param divs Div[] +---@param style { [string]: cpair } ---@param exit function function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit) - ---@type plc_config, plc_config, plc_config, table, function - local settings_cfg, ini_cfg, tmp_cfg, fields, load_settings = table.unpack(cfg_sys) - - ---@type graphics_element, graphics_element, graphics_element, graphics_element, graphics_element - local plc_cfg, net_cfg, log_cfg, clr_cfg, summary = table.unpack(divs) + local settings_cfg, ini_cfg, tmp_cfg, fields, load_settings = cfg_sys[1], cfg_sys[2], cfg_sys[3], cfg_sys[4], cfg_sys[5] + local plc_cfg, net_cfg, log_cfg, clr_cfg, summary = divs[1], divs[2], divs[3], divs[4], divs[5] local bw_fg_bg = style.bw_fg_bg local g_lg_fg_bg = style.g_lg_fg_bg @@ -93,7 +90,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit) 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} - 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,x=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()) @@ -131,7 +128,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit) 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} - 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,x=1,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 @@ -149,7 +146,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit) 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,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 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} if ini_cfg.EmerCoolColor == nil then color.disable() end @@ -243,11 +240,11 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit) TextBox{parent=net_c_3,x=1,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for security on multiplayer servers. All devices on the same network MUST use the same key if any device has a key. This does result in some extra compution (can slow things down).",fg_bg=g_lg_fg_bg} TextBox{parent=net_c_3,x=1,y=11,text="Facility Auth Key"} - local key, _, censor = TextField{parent=net_c_3,x=1,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg} + local key, _ = TextField{parent=net_c_3,x=1,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg} - local function censor_key(enable) censor(util.trinary(enable, "*", nil)) end + local function censor_key(enable) key.censor(util.trinary(enable, "*", nil)) end - local hide_key = CheckBox{parent=net_c_3,x=34,y=12,label="Hide",box_fg_bg=cpair(colors.lightBlue,colors.black),callback=censor_key} + local hide_key = Checkbox{parent=net_c_3,x=34,y=12,label="Hide",box_fg_bg=cpair(colors.lightBlue,colors.black),callback=censor_key} hide_key.set_value(true) censor_key(true) @@ -282,7 +279,7 @@ function system.create(tool_ctl, main_pane, cfg_sys, divs, style, exit) 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} - 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,x=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} diff --git a/reactor-plc/configure.lua b/reactor-plc/configure.lua index 81933f9..e8b32d1 100644 --- a/reactor-plc/configure.lua +++ b/reactor-plc/configure.lua @@ -12,13 +12,13 @@ local system = require("reactor-plc.config.system") local core = require("graphics.core") local themes = require("graphics.themes") -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") +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") -local PushButton = require("graphics.elements.controls.push_button") +local PushButton = require("graphics.elements.controls.PushButton") local println = util.println local tri = util.trinary @@ -58,11 +58,11 @@ local tool_ctl = { viewing_config = false, jumped_to_color = false, - view_cfg = nil, ---@type graphics_element - color_cfg = nil, ---@type graphics_element - color_next = nil, ---@type graphics_element - color_apply = nil, ---@type graphics_element - settings_apply = nil, ---@type graphics_element + view_cfg = nil, ---@type PushButton + color_cfg = nil, ---@type PushButton + color_next = nil, ---@type PushButton + color_apply = nil, ---@type PushButton + settings_apply = nil, ---@type PushButton gen_summary = nil, ---@type function load_legacy = nil, ---@type function @@ -125,7 +125,7 @@ local function load_settings(target, raw) end -- create the config view ----@param display graphics_element +---@param display DisplayBox local function config_view(display) local bw_fg_bg = style.bw_fg_bg local g_lg_fg_bg = style.g_lg_fg_bg diff --git a/reactor-plc/databus.lua b/reactor-plc/databus.lua index 7436dbb..b2bd1c2 100644 --- a/reactor-plc/databus.lua +++ b/reactor-plc/databus.lua @@ -77,7 +77,7 @@ end -- transmit RPS data across the bus ---@param tripped boolean RPS tripped ----@param status table RPS status +---@param status boolean[] RPS status ---@param emer_cool_active boolean RPS activated the emergency coolant function databus.tx_rps(tripped, status, emer_cool_active) databus.ps.publish("rps_scram", tripped) diff --git a/reactor-plc/panel/front_panel.lua b/reactor-plc/panel/front_panel.lua index d07395f..8bb6a0f 100644 --- a/reactor-plc/panel/front_panel.lua +++ b/reactor-plc/panel/front_panel.lua @@ -13,15 +13,15 @@ local style = require("reactor-plc.panel.style") local core = require("graphics.core") local flasher = require("graphics.flasher") -local Div = require("graphics.elements.div") -local Rectangle = require("graphics.elements.rectangle") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local Rectangle = require("graphics.elements.Rectangle") +local TextBox = require("graphics.elements.TextBox") -local PushButton = require("graphics.elements.controls.push_button") +local PushButton = require("graphics.elements.controls.PushButton") -local LED = require("graphics.elements.indicators.led") -local LEDPair = require("graphics.elements.indicators.ledpair") -local RGBLED = require("graphics.elements.indicators.ledrgb") +local LED = require("graphics.elements.indicators.LED") +local LEDPair = require("graphics.elements.indicators.LEDPair") +local RGBLED = require("graphics.elements.indicators.RGBLED") local LINK_STATE = types.PANEL_LINK_STATE @@ -34,7 +34,7 @@ local ind_grn = style.ind_grn local ind_red = style.ind_red -- create new front panel view ----@param panel graphics_element main displaybox +---@param panel DisplayBox main displaybox local function init(panel) local s_hi_box = style.theme.highlight_box diff --git a/reactor-plc/plc.lua b/reactor-plc/plc.lua index eee2bc6..73a1126 100644 --- a/reactor-plc/plc.lua +++ b/reactor-plc/plc.lua @@ -110,22 +110,8 @@ end ---@param reactor table ---@param is_formed boolean function plc.rps_init(reactor, is_formed) - local state_keys = { - high_dmg = 1, - high_temp = 2, - low_coolant = 3, - ex_waste = 4, - ex_hcoolant = 5, - no_fuel = 6, - fault = 7, - timeout = 8, - manual = 9, - automatic = 10, - sys_fail = 11, - force_disabled = 12 - } - 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, @@ -136,12 +122,27 @@ function plc.rps_init(reactor, is_formed) trip_cause = "ok" ---@type rps_trip_cause } + local CHK = { + HIGH_DMG = 1, + HIGH_TEMP = 2, + LOW_COOLANT = 3, + EX_WASTE = 4, + EX_HCOOLANT = 5, + NO_FUEL = 6, + FAULT = 7, + TIMEOUT = 8, + MANUAL = 9, + AUTOMATIC = 10, + SYS_FAIL = 11, + FORCE_DISABLED = 12 + } + -- PRIVATE FUNCTIONS -- -- set reactor access fault flag local function _set_fault() if reactor.__p_last_fault() ~= "Terminated" then - self.state[state_keys.fault] = true + self.state[CHK.FAULT] = true end end @@ -203,8 +204,8 @@ function plc.rps_init(reactor, is_formed) end -- always update, since some ppm failures constitute not being formed - if not self.state[state_keys.sys_fail] then - self.state[state_keys.sys_fail] = not self.formed + if not self.state[CHK.SYS_FAIL] then + self.state[CHK.SYS_FAIL] = not self.formed end end @@ -214,8 +215,8 @@ function plc.rps_init(reactor, is_formed) if _check_and_handle_ppm_call(disabled) then self.force_disabled = disabled - if not self.state[state_keys.force_disabled] then - self.state[state_keys.force_disabled] = disabled + if not self.state[CHK.FORCE_DISABLED] then + self.state[CHK.FORCE_DISABLED] = disabled end end end @@ -223,8 +224,8 @@ function plc.rps_init(reactor, is_formed) -- check for high damage local function _high_damage() local damage_percent = reactor.getDamagePercent() - if _check_and_handle_ppm_call(damage_percent) and not self.state[state_keys.high_dmg] then - self.state[state_keys.high_dmg] = damage_percent >= RPS_LIMITS.MAX_DAMAGE_PERCENT + if _check_and_handle_ppm_call(damage_percent) and not self.state[CHK.HIGH_DMG] then + self.state[CHK.HIGH_DMG] = damage_percent >= RPS_LIMITS.MAX_DAMAGE_PERCENT end end @@ -232,40 +233,40 @@ function plc.rps_init(reactor, is_formed) local function _high_temp() -- mekanism: MAX_DAMAGE_TEMPERATURE = 1200K local temp = reactor.getTemperature() - if _check_and_handle_ppm_call(temp) and not self.state[state_keys.high_temp] then - self.state[state_keys.high_temp] = temp >= RPS_LIMITS.MAX_DAMAGE_TEMPERATURE + if _check_and_handle_ppm_call(temp) and not self.state[CHK.HIGH_TEMP] then + self.state[CHK.HIGH_TEMP] = temp >= RPS_LIMITS.MAX_DAMAGE_TEMPERATURE end end -- check if there is very low coolant local function _low_coolant() local coolant_filled = reactor.getCoolantFilledPercentage() - if _check_and_handle_ppm_call(coolant_filled) and not self.state[state_keys.low_coolant] then - self.state[state_keys.low_coolant] = coolant_filled < RPS_LIMITS.MIN_COOLANT_FILL + if _check_and_handle_ppm_call(coolant_filled) and not self.state[CHK.LOW_COOLANT] then + self.state[CHK.LOW_COOLANT] = coolant_filled < RPS_LIMITS.MIN_COOLANT_FILL end end -- check for excess waste (>80% filled) local function _excess_waste() local w_filled = reactor.getWasteFilledPercentage() - if _check_and_handle_ppm_call(w_filled) and not self.state[state_keys.ex_waste] then - self.state[state_keys.ex_waste] = w_filled > RPS_LIMITS.MAX_WASTE_FILL + if _check_and_handle_ppm_call(w_filled) and not self.state[CHK.EX_WASTE] then + self.state[CHK.EX_WASTE] = w_filled > RPS_LIMITS.MAX_WASTE_FILL end end -- check for heated coolant backup (>95% filled) local function _excess_heated_coolant() local hc_filled = reactor.getHeatedCoolantFilledPercentage() - if _check_and_handle_ppm_call(hc_filled) and not self.state[state_keys.ex_hcoolant] then - self.state[state_keys.ex_hcoolant] = hc_filled > RPS_LIMITS.MAX_HEATED_COLLANT_FILL + if _check_and_handle_ppm_call(hc_filled) and not self.state[CHK.EX_HCOOLANT] then + self.state[CHK.EX_HCOOLANT] = hc_filled > RPS_LIMITS.MAX_HEATED_COLLANT_FILL end end -- check if there is no fuel local function _insufficient_fuel() local fuel = reactor.getFuelFilledPercentage() - if _check_and_handle_ppm_call(fuel) and not self.state[state_keys.no_fuel] then - self.state[state_keys.no_fuel] = fuel <= RPS_LIMITS.NO_FUEL_FILL + if _check_and_handle_ppm_call(fuel) and not self.state[CHK.NO_FUEL] then + self.state[CHK.NO_FUEL] = fuel <= RPS_LIMITS.NO_FUEL_FILL end end @@ -287,23 +288,23 @@ function plc.rps_init(reactor, is_formed) -- trip for a PLC comms timeout function public.trip_timeout() - self.state[state_keys.timeout] = true + self.state[CHK.TIMEOUT] = true end -- manually SCRAM the reactor function public.trip_manual() - self.state[state_keys.manual] = true + self.state[CHK.MANUAL] = true end -- automatic SCRAM commanded by supervisor function public.trip_auto() - self.state[state_keys.automatic] = true + self.state[CHK.AUTOMATIC] = true end -- trip for unformed reactor function public.trip_sys_fail() - self.state[state_keys.fault] = true - self.state[state_keys.sys_fail] = true + self.state[CHK.FAULT] = true + self.state[CHK.SYS_FAIL] = true end -- SCRAM the reactor now
@@ -350,7 +351,7 @@ function plc.rps_init(reactor, is_formed) function public.auto_activate() -- clear automatic SCRAM if it was the cause if self.tripped and self.trip_cause == "automatic" then - self.state[state_keys.automatic] = true + self.state[CHK.AUTOMATIC] = true self.trip_cause = RPS_TRIP_CAUSE.OK self.tripped = false @@ -388,40 +389,40 @@ function plc.rps_init(reactor, is_formed) -- check system states in order of severity if self.tripped then status = self.trip_cause - elseif self.state[state_keys.sys_fail] then + elseif self.state[CHK.SYS_FAIL] then log.warning("RPS: system failure, reactor not formed") status = RPS_TRIP_CAUSE.SYS_FAIL - elseif self.state[state_keys.force_disabled] then + elseif self.state[CHK.FORCE_DISABLED] then log.warning("RPS: reactor was force disabled") status = RPS_TRIP_CAUSE.FORCE_DISABLED - elseif self.state[state_keys.high_dmg] then + elseif self.state[CHK.HIGH_DMG] then log.warning("RPS: high damage") status = RPS_TRIP_CAUSE.HIGH_DMG - elseif self.state[state_keys.high_temp] then + elseif self.state[CHK.HIGH_TEMP] then log.warning("RPS: high temperature") status = RPS_TRIP_CAUSE.HIGH_TEMP - elseif self.state[state_keys.low_coolant] then + elseif self.state[CHK.LOW_COOLANT] then log.warning("RPS: low coolant") status = RPS_TRIP_CAUSE.LOW_COOLANT - elseif self.state[state_keys.ex_waste] then + elseif self.state[CHK.EX_WASTE] then log.warning("RPS: full waste") status = RPS_TRIP_CAUSE.EX_WASTE - elseif self.state[state_keys.ex_hcoolant] then + elseif self.state[CHK.EX_HCOOLANT] then log.warning("RPS: heated coolant backup") status = RPS_TRIP_CAUSE.EX_HCOOLANT - elseif self.state[state_keys.no_fuel] then + elseif self.state[CHK.NO_FUEL] then log.warning("RPS: no fuel") status = RPS_TRIP_CAUSE.NO_FUEL - elseif self.state[state_keys.fault] then + elseif self.state[CHK.FAULT] then log.warning("RPS: reactor access fault") status = RPS_TRIP_CAUSE.FAULT - elseif self.state[state_keys.timeout] then + elseif self.state[CHK.TIMEOUT] then log.warning("RPS: supervisor connection timeout") status = RPS_TRIP_CAUSE.TIMEOUT - elseif self.state[state_keys.manual] then + elseif self.state[CHK.MANUAL] then log.warning("RPS: manual SCRAM requested") status = RPS_TRIP_CAUSE.MANUAL - elseif self.state[state_keys.automatic] then + elseif self.state[CHK.AUTOMATIC] then log.warning("RPS: automatic SCRAM requested") status = RPS_TRIP_CAUSE.AUTOMATIC else @@ -449,7 +450,7 @@ function plc.rps_init(reactor, is_formed) end -- update emergency coolant control if configured - _set_emer_cool(self.state[state_keys.low_coolant]) + _set_emer_cool(self.state[CHK.LOW_COOLANT]) -- report RPS status databus.tx_rps(self.tripped, self.state, self.emer_cool_active) @@ -465,7 +466,7 @@ function plc.rps_init(reactor, is_formed) ---@nodiscard function public.get_trip_cause() return self.trip_cause end ---@nodiscard - function public.is_low_coolant() return self.states[state_keys.low_coolant] end + function public.is_low_coolant() return self.states[CHK.LOW_COOLANT] end ---@nodiscard function public.is_active() return self.reactor_enabled end @@ -495,16 +496,16 @@ function plc.rps_init(reactor, is_formed) self.tripped = false self.trip_cause = RPS_TRIP_CAUSE.OK - self.state[state_keys.fault] = false - self.state[state_keys.sys_fail] = false + self.state[CHK.FAULT] = false + self.state[CHK.SYS_FAIL] = false log.info("RPS: partial reset on formed") end -- reset the automatic and timeout trip flags, then clear trip if that was the trip cause function public.auto_reset() - self.state[state_keys.automatic] = false - self.state[state_keys.timeout] = false + self.state[CHK.AUTOMATIC] = false + self.state[CHK.TIMEOUT] = false if self.trip_cause == RPS_TRIP_CAUSE.AUTOMATIC or self.trip_cause == RPS_TRIP_CAUSE.TIMEOUT then self.trip_cause = RPS_TRIP_CAUSE.OK diff --git a/reactor-plc/renderer.lua b/reactor-plc/renderer.lua index aa62e63..f8a8044 100644 --- a/reactor-plc/renderer.lua +++ b/reactor-plc/renderer.lua @@ -8,7 +8,7 @@ local style = require("reactor-plc.panel.style") local core = require("graphics.core") local flasher = require("graphics.flasher") -local DisplayBox = require("graphics.elements.displaybox") +local DisplayBox = require("graphics.elements.DisplayBox") ---@class reactor_plc_renderer local renderer = {} diff --git a/reactor-plc/startup.lua b/reactor-plc/startup.lua index cb40ead..61af7cc 100644 --- a/reactor-plc/startup.lua +++ b/reactor-plc/startup.lua @@ -18,7 +18,7 @@ local plc = require("reactor-plc.plc") local renderer = require("reactor-plc.renderer") local threads = require("reactor-plc.threads") -local R_PLC_VERSION = "v1.8.8" +local R_PLC_VERSION = "v1.8.9" local println = util.println local println_ts = util.println_ts diff --git a/reactor-plc/threads.lua b/reactor-plc/threads.lua index b3a0251..b56ccc7 100644 --- a/reactor-plc/threads.lua +++ b/reactor-plc/threads.lua @@ -144,6 +144,7 @@ function threads.thread__main(smem, init) plc_state.no_reactor = true plc_state.degraded = true elseif networked and type == "modem" then + ---@cast device Modem -- we only care if this is our wireless modem -- note, check init_ok first since nic will be nil if it is false if plc_state.init_ok and nic.is_modem(device) then @@ -208,6 +209,7 @@ function threads.thread__main(smem, init) rps.reset_formed() end elseif networked and type == "modem" then + ---@cast device Modem -- note, check init_ok first since nic will be nil if it is false if device.isWireless() and not (plc_state.init_ok and nic.is_connected()) then -- reconnected modem @@ -628,9 +630,10 @@ function threads.thread__setpoint_control(smem) local reactor = plc_dev.reactor if plc_state.init_ok and (not plc_state.no_reactor) then + ---@cast reactor table won't be nil + -- check if we should start ramping if setpoints.burn_rate_en and (setpoints.burn_rate ~= last_burn_sp) then ----@diagnostic disable-next-line: need-check-nil local cur_burn_rate = reactor.getBurnRate() if (type(cur_burn_rate) == "number") and (setpoints.burn_rate ~= cur_burn_rate) and rps.is_active() then @@ -644,7 +647,6 @@ function threads.thread__setpoint_control(smem) 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")) ----@diagnostic disable-next-line: need-check-nil reactor.setBurnRate(setpoints.burn_rate) end end @@ -658,7 +660,6 @@ function threads.thread__setpoint_control(smem) -- adjust burn rate (setpoints.burn_rate) if setpoints.burn_rate_en then if rps.is_active() then ----@diagnostic disable-next-line: need-check-nil local current_burn_rate = reactor.getBurnRate() -- we yielded, check enable again @@ -679,7 +680,6 @@ function threads.thread__setpoint_control(smem) running = running or (new_burn_rate ~= setpoints.burn_rate) -- set the burn rate ----@diagnostic disable-next-line: need-check-nil reactor.setBurnRate(new_burn_rate) end else diff --git a/rtu/configure.lua b/rtu/configure.lua index 0c571de..c0d45a5 100644 --- a/rtu/configure.lua +++ b/rtu/configure.lua @@ -12,21 +12,21 @@ local util = require("scada-common.util") local core = require("graphics.core") local themes = require("graphics.themes") -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") +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") -local CheckBox = require("graphics.elements.controls.checkbox") -local PushButton = require("graphics.elements.controls.push_button") -local Radio2D = require("graphics.elements.controls.radio_2d") -local RadioButton = require("graphics.elements.controls.radio_button") +local Checkbox = require("graphics.elements.controls.Checkbox") +local PushButton = require("graphics.elements.controls.PushButton") +local Radio2D = require("graphics.elements.controls.Radio2D") +local RadioButton = require("graphics.elements.controls.RadioButton") -local NumberField = require("graphics.elements.form.number_field") -local TextField = require("graphics.elements.form.text_field") +local NumberField = require("graphics.elements.form.NumberField") +local TextField = require("graphics.elements.form.TextField") -local IndLight = require("graphics.elements.indicators.light") +local IndLight = require("graphics.elements.indicators.IndicatorLight") local println = util.println local tri = util.trinary @@ -88,17 +88,17 @@ local changes = { { "v1.10.2", { "Re-organized peripheral configuration UI, resulting in some input fields being re-ordered" } } } +---@class rtu_peri_definition +---@field unit integer|nil +---@field index integer|nil +---@field name string + ---@class rtu_rs_definition ---@field unit integer|nil ---@field port IO_PORT ---@field side side ---@field color color|nil ----@class rtu_peri_definition ----@field unit integer|nil ----@field index integer|nil ----@field name string - local RTU_DEV_TYPES = { "boilerValve", "turbineValve", "dynamicValve", "inductionPort", "spsPort", "solarNeutronActivator", "environmentDetector" } local NEEDS_UNIT = { "boilerValve", "turbineValve", "dynamicValve", "solarNeutronActivator", "environmentDetector" } @@ -130,14 +130,14 @@ local tool_ctl = { rs_cfg_port = IO.F_SCRAM, ---@type IO_PORT rs_cfg_editing = false, ---@type integer|false - view_gw_cfg = nil, ---@type graphics_element - dev_cfg = nil, ---@type graphics_element - rs_cfg = nil, ---@type graphics_element - color_cfg = nil, ---@type graphics_element - color_next = nil, ---@type graphics_element - color_apply = nil, ---@type graphics_element - settings_apply = nil, ---@type graphics_element - settings_confirm = nil, ---@type graphics_element + view_gw_cfg = nil, ---@type PushButton + dev_cfg = nil, ---@type PushButton + rs_cfg = nil, ---@type PushButton + color_cfg = nil, ---@type PushButton + color_next = nil, ---@type PushButton + color_apply = nil, ---@type PushButton + settings_apply = nil, ---@type PushButton + settings_confirm = nil, ---@type PushButton go_home = nil, ---@type function gen_summary = nil, ---@type function @@ -149,33 +149,33 @@ local tool_ctl = { gen_rs_summary = nil, ---@type function show_auth_key = nil, ---@type function - show_key_btn = nil, ---@type graphics_element - auth_key_textbox = nil, ---@type graphics_element + show_key_btn = nil, ---@type PushButton + auth_key_textbox = nil, ---@type TextBox auth_key_value = "", - ppm_devs = nil, ---@type graphics_element - p_name_msg = nil, ---@type graphics_element - p_prompt = nil, ---@type graphics_element - p_idx = nil, ---@type graphics_element - p_unit = nil, ---@type graphics_element - p_assign_btn = nil, ---@type graphics_element - p_desc = nil, ---@type graphics_element - p_desc_ext = nil, ---@type graphics_element - p_err = nil, ---@type graphics_element + ppm_devs = nil, ---@type ListBox + p_name_msg = nil, ---@type TextBox + p_prompt = nil, ---@type TextBox + p_idx = nil, ---@type NumberField + p_unit = nil, ---@type NumberField + p_assign_btn = nil, ---@type RadioButton + p_desc = nil, ---@type TextBox + p_desc_ext = nil, ---@type TextBox + p_err = nil, ---@type TextBox - rs_cfg_selection = nil, ---@type graphics_element - rs_cfg_unit_l = nil, ---@type graphics_element - rs_cfg_unit = nil, ---@type graphics_element - rs_cfg_side_l = nil, ---@type graphics_element - rs_cfg_color = nil, ---@type graphics_element - rs_cfg_shortcut = nil ---@type graphics_element + rs_cfg_selection = nil, ---@type TextBox + rs_cfg_unit_l = nil, ---@type TextBox + rs_cfg_unit = nil, ---@type NumberField + rs_cfg_side_l = nil, ---@type TextBox + rs_cfg_color = nil, ---@type Radio2D + rs_cfg_shortcut = nil ---@type TextBox } ---@class rtu_config local tmp_cfg = { SpeakerVolume = 1.0, - Peripherals = {}, - Redstone = {}, + Peripherals = {}, ---@type rtu_peri_definition[] + Redstone = {}, ---@type rtu_rs_definition[] SVR_Channel = nil, ---@type integer RTU_Channel = nil, ---@type integer ConnTimeout = nil, ---@type number @@ -259,7 +259,7 @@ local function load_settings(target, raw) end -- create the config view ----@param display graphics_element +---@param display DisplayBox local function config_view(display) ---@diagnostic disable-next-line: undefined-field local function exit() os.queueEvent("terminate") end @@ -446,11 +446,11 @@ local function config_view(display) TextBox{parent=net_c_3,x=1,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for security on multiplayer servers. All devices on the same network MUST use the same key if any device has a key. This does result in some extra compution (can slow things down).",fg_bg=g_lg_fg_bg} TextBox{parent=net_c_3,x=1,y=11,text="Facility Auth Key"} - local key, _, censor = TextField{parent=net_c_3,x=1,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg} + local key, _ = TextField{parent=net_c_3,x=1,y=12,max_len=64,value=ini_cfg.AuthKey,width=32,height=1,fg_bg=bw_fg_bg} - local function censor_key(enable) censor(tri(enable, "*", nil)) end + local function censor_key(enable) key.censor(tri(enable, "*", nil)) end - local hide_key = CheckBox{parent=net_c_3,x=34,y=12,label="Hide",box_fg_bg=cpair(colors.lightBlue,colors.black),callback=censor_key} + local hide_key = Checkbox{parent=net_c_3,x=34,y=12,label="Hide",box_fg_bg=cpair(colors.lightBlue,colors.black),callback=censor_key} hide_key.set_value(true) censor_key(true) @@ -485,7 +485,7 @@ local function config_view(display) 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} - 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,x=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} @@ -1198,7 +1198,7 @@ local function config_view(display) tool_ctl.rs_cfg_shortcut = TextBox{parent=rs_c_3,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."} tool_ctl.rs_cfg_shortcut.hide(true) - local bundled = CheckBox{parent=rs_c_3,x=1,y=7,label="Is Bundled?",default=false,box_fg_bg=cpair(colors.red,colors.black),callback=set_bundled} + local bundled = Checkbox{parent=rs_c_3,x=1,y=7,label="Is Bundled?",default=false,box_fg_bg=cpair(colors.red,colors.black),callback=set_bundled} tool_ctl.rs_cfg_color = Radio2D{parent=rs_c_3,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} tool_ctl.rs_cfg_color.disable() @@ -1296,7 +1296,7 @@ local function config_view(display) local ini_unit = tri(for_facility, nil, entry.for_reactor) local def = { name = entry.name, unit = ini_unit, index = entry.index } - local mount = mounts[def.name] ---@type ppm_entry|nil + local mount = mounts[def.name] local status = " \x13 not connected, please re-config later" local color = colors.orange @@ -1497,7 +1497,7 @@ local function config_view(display) peri_list.remove_all() for i = 1, #cfg.Peripherals do - local def = cfg.Peripherals[i] ---@type rtu_peri_definition + local def = cfg.Peripherals[i] local t = ppm.get_type(def.name) local t_str = " (connect to edit)" @@ -1529,7 +1529,7 @@ local function config_view(display) end local function edit_rs_entry(idx) - local def = tmp_cfg.Redstone[idx] ---@type rtu_rs_definition + local def = tmp_cfg.Redstone[idx] tool_ctl.rs_cfg_shortcut.hide(true) tool_ctl.rs_cfg_color.show() diff --git a/rtu/databus.lua b/rtu/databus.lua index 4fe183a..0d086f4 100644 --- a/rtu/databus.lua +++ b/rtu/databus.lua @@ -10,15 +10,15 @@ local databus = {} -- databus PSIL databus.ps = psil.create() ----@enum RTU_UNIT_HW_STATE -local RTU_UNIT_HW_STATE = { +---@enum RTU_HW_STATE +local RTU_HW_STATE = { OFFLINE = 1, FAULTED = 2, UNFORMED = 3, OK = 4 } -databus.RTU_UNIT_HW_STATE = RTU_UNIT_HW_STATE +databus.RTU_HW_STATE = RTU_HW_STATE -- call to toggle heartbeat signal function databus.heartbeat() databus.ps.toggle("heartbeat") end @@ -52,7 +52,7 @@ end -- transmit unit hardware status across the bus ---@param uid integer unit ID ----@param status RTU_UNIT_HW_STATE +---@param status RTU_HW_STATE function databus.tx_unit_hw_status(uid, status) databus.ps.publish("unit_hw_" .. uid, status) end diff --git a/rtu/panel/front_panel.lua b/rtu/panel/front_panel.lua index b5b773a..6fc40e5 100644 --- a/rtu/panel/front_panel.lua +++ b/rtu/panel/front_panel.lua @@ -11,13 +11,13 @@ local style = require("rtu.panel.style") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local TextBox = require("graphics.elements.TextBox") -local DataIndicator = require("graphics.elements.indicators.data") -local LED = require("graphics.elements.indicators.led") -local LEDPair = require("graphics.elements.indicators.ledpair") -local RGBLED = require("graphics.elements.indicators.ledrgb") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") +local LED = require("graphics.elements.indicators.LED") +local LEDPair = require("graphics.elements.indicators.LEDPair") +local RGBLED = require("graphics.elements.indicators.RGBLED") local LINK_STATE = types.PANEL_LINK_STATE @@ -30,8 +30,8 @@ local ind_grn = style.ind_grn local UNIT_TYPE_LABELS = { "UNKNOWN", "REDSTONE", "BOILER", "TURBINE", "DYNAMIC TANK", "IND MATRIX", "SPS", "SNA", "ENV DETECTOR" } -- create new front panel view ----@param panel graphics_element main displaybox ----@param units table unit list +---@param panel DisplayBox main displaybox +---@param units rtu_registry_entry[] unit list local function init(panel, units) local disabled_fg = style.fp.disabled_fg @@ -135,7 +135,7 @@ local function init(panel, units) -- show hardware statuses for i = 1, list_length do - local unit = units[i] ---@type rtu_unit_registry_entry + local unit = units[i] -- hardware status local unit_hw = RGBLED{parent=unit_hw_statuses,y=i,label="",colors={colors.red,colors.orange,colors.yellow,colors.green}} diff --git a/rtu/renderer.lua b/rtu/renderer.lua index bdbc25b..dd86a06 100644 --- a/rtu/renderer.lua +++ b/rtu/renderer.lua @@ -8,7 +8,7 @@ local style = require("rtu.panel.style") local core = require("graphics.core") local flasher = require("graphics.flasher") -local DisplayBox = require("graphics.elements.displaybox") +local DisplayBox = require("graphics.elements.DisplayBox") ---@class rtu_renderer local renderer = {} @@ -18,7 +18,7 @@ local ui = { } -- try to start the UI ----@param units table RTU units +---@param units rtu_registry_entry[] RTU entries ---@param theme FP_THEME front panel theme ---@param color_mode COLOR_MODE color mode ---@return boolean success, any error_msg diff --git a/rtu/rtu.lua b/rtu/rtu.lua index dc398b2..0ea1779 100644 --- a/rtu/rtu.lua +++ b/rtu/rtu.lua @@ -235,7 +235,7 @@ function rtu.init_unit(device) end -- create an alarm speaker sounder ----@param speaker table device peripheral +---@param speaker Speaker device peripheral function rtu.init_sounder(speaker) ---@class rtu_speaker_sounder local spkr_ctl = { @@ -322,13 +322,13 @@ function rtu.comms(version, nic, conn_watchdog) -- generate device advertisement table ---@nodiscard - ---@param units table + ---@param units rtu_registry_entry[] ---@return table advertisement local function _generate_advertisement(units) local advertisement = {} for i = 1, #units do - local unit = units[i] ---@type rtu_unit_registry_entry + local unit = units[i] if unit.type ~= nil then local advert = { unit.type, unit.index, unit.reactor } @@ -429,9 +429,9 @@ function rtu.comms(version, nic, conn_watchdog) -- handle a MODBUS/SCADA packet ---@param packet modbus_frame|mgmt_frame - ---@param units table RTU units + ---@param units rtu_registry_entry[] RTU entries ---@param rtu_state rtu_state - ---@param sounders table speaker alarm sounders + ---@param sounders rtu_speaker_sounder[] speaker alarm sounders function public.handle_packet(packet, units, rtu_state, sounders) -- print a log message to the terminal as long as the UI isn't running local function println_ts(message) if not rtu_state.fp_ok then util.println_ts(message) end end @@ -467,7 +467,7 @@ function rtu.comms(version, nic, conn_watchdog) -- handle MODBUS instruction if packet.unit_id <= #units then - local unit = units[packet.unit_id] ---@type rtu_unit_registry_entry + local unit = units[packet.unit_id] local unit_dbg_tag = " (unit " .. packet.unit_id .. ")" if unit.name == "redstone_io" then @@ -538,11 +538,9 @@ function rtu.comms(version, nic, conn_watchdog) if (packet.length == 1) and type(packet.data[1] == "table") and (#packet.data[1] == 8) then local states = packet.data[1] + -- set tone states for i = 1, #sounders do - local s = sounders[i] ---@type rtu_speaker_sounder - - -- set tone states - for id = 1, #states do s.stream.set_active(id, states[id] == true) end + for id = 1, #states do sounders[i].stream.set_active(id, states[id] == true) end end end else diff --git a/rtu/startup.lua b/rtu/startup.lua index cb0d4ea..7a30f42 100644 --- a/rtu/startup.lua +++ b/rtu/startup.lua @@ -31,10 +31,10 @@ local sna_rtu = require("rtu.dev.sna_rtu") local sps_rtu = require("rtu.dev.sps_rtu") local turbinev_rtu = require("rtu.dev.turbinev_rtu") -local RTU_VERSION = "v1.10.8" +local RTU_VERSION = "v1.10.9" local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE -local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE +local RTU_HW_STATE = databus.RTU_HW_STATE local println = util.println local println_ts = util.println_ts @@ -109,7 +109,7 @@ local function main() -- RTU gateway devices (not RTU units) rtu_dev = { modem = ppm.get_wireless_modem(), - sounders = {} + sounders = {} ---@type rtu_speaker_sounder[] }, -- system objects @@ -117,7 +117,7 @@ local function main() nic = nil, ---@type nic rtu_comms = nil, ---@type rtu_comms conn_watchdog = nil, ---@type watchdog - units = {} + units = {} ---@type rtu_registry_entry[] }, -- message queues @@ -143,11 +143,11 @@ local function main() -- configure RTU gateway based on settings file definitions local function sys_config() -- redstone interfaces - local rs_rtus = {} + local rs_rtus = {} ---@type { rtu: rtu_rs_device, capabilities: IO_PORT[] }[] -- go through redstone definitions list for entry_idx = 1, #rtu_redstone do - local entry = rtu_redstone[entry_idx] ---@type rtu_rs_definition + local entry = rtu_redstone[entry_idx] local assignment local for_reactor = entry.unit local iface_name = util.trinary(entry.color ~= nil, util.c(entry.side, "/", rsio.color_name(entry.color)), entry.side) @@ -227,21 +227,21 @@ local function main() -- create unit entries for redstone RTUs for for_reactor, def in pairs(rs_rtus) do - ---@class rtu_unit_registry_entry + ---@class rtu_registry_entry local unit = { - uid = 0, ---@type integer - name = "redstone_io", ---@type string - type = RTU_UNIT_TYPE.REDSTONE, ---@type RTU_UNIT_TYPE - index = false, ---@type integer|false - reactor = for_reactor, ---@type integer - device = def.capabilities, ---@type table use device field for redstone ports - is_multiblock = false, ---@type boolean - formed = nil, ---@type boolean|nil - hw_state = RTU_UNIT_HW_STATE.OK, ---@type RTU_UNIT_HW_STATE - rtu = def.rtu, ---@type rtu_device|rtu_rs_device + uid = 0, ---@type integer + name = "redstone_io", ---@type string + type = RTU_UNIT_TYPE.REDSTONE, ---@type RTU_UNIT_TYPE + index = false, ---@type integer|false + reactor = for_reactor, ---@type integer + device = def.capabilities, ---@type IO_PORT[] use device field for redstone ports + is_multiblock = false, ---@type boolean + formed = nil, ---@type boolean|nil + hw_state = RTU_HW_STATE.OK, ---@type RTU_HW_STATE + rtu = def.rtu, ---@type rtu_device|rtu_rs_device modbus_io = modbus.new(def.rtu, false), - pkt_queue = nil, ---@type mqueue|nil - thread = nil ---@type parallel_thread|nil + pkt_queue = nil, ---@type mqueue|nil + thread = nil ---@type parallel_thread|nil } table.insert(units, unit) @@ -440,21 +440,21 @@ local function main() end end - ---@class rtu_unit_registry_entry + ---@class rtu_registry_entry local rtu_unit = { - uid = 0, ---@type integer - name = name, ---@type string - type = rtu_type, ---@type RTU_UNIT_TYPE - index = index or false, ---@type integer|false - reactor = for_reactor, ---@type integer - device = device, ---@type table - is_multiblock = is_multiblock, ---@type boolean - formed = formed, ---@type boolean|nil - hw_state = RTU_UNIT_HW_STATE.OFFLINE, ---@type RTU_UNIT_HW_STATE - rtu = rtu_iface, ---@type rtu_device|rtu_rs_device + uid = 0, ---@type integer + name = name, ---@type string + type = rtu_type, ---@type RTU_UNIT_TYPE + index = index or false, ---@type integer|false + reactor = for_reactor, ---@type integer + device = device, ---@type table peripheral reference + is_multiblock = is_multiblock, ---@type boolean + formed = formed, ---@type boolean|nil + hw_state = RTU_HW_STATE.OFFLINE, ---@type RTU_HW_STATE + rtu = rtu_iface, ---@type rtu_device|rtu_rs_device modbus_io = modbus.new(rtu_iface, true), - pkt_queue = mqueue.new(), ---@type mqueue|nil - thread = nil ---@type parallel_thread|nil + pkt_queue = mqueue.new(), ---@type mqueue|nil + thread = nil ---@type parallel_thread|nil } rtu_unit.thread = threads.thread__unit_comms(__shared_memory, rtu_unit) @@ -473,14 +473,14 @@ local function main() -- determine hardware status if rtu_unit.type == RTU_UNIT_TYPE.VIRTUAL then - rtu_unit.hw_state = RTU_UNIT_HW_STATE.OFFLINE + rtu_unit.hw_state = RTU_HW_STATE.OFFLINE else if rtu_unit.is_multiblock then - rtu_unit.hw_state = util.trinary(rtu_unit.formed == true, RTU_UNIT_HW_STATE.OK, RTU_UNIT_HW_STATE.UNFORMED) + rtu_unit.hw_state = util.trinary(rtu_unit.formed == true, RTU_HW_STATE.OK, RTU_HW_STATE.UNFORMED) elseif faulted then - rtu_unit.hw_state = RTU_UNIT_HW_STATE.FAULTED + rtu_unit.hw_state = RTU_HW_STATE.FAULTED else - rtu_unit.hw_state = RTU_UNIT_HW_STATE.OK + rtu_unit.hw_state = RTU_HW_STATE.OK end end diff --git a/rtu/threads.lua b/rtu/threads.lua index 011b617..4ad5fcb 100644 --- a/rtu/threads.lua +++ b/rtu/threads.lua @@ -23,7 +23,7 @@ local core = require("graphics.core") local threads = {} local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE -local UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE +local RTU_HW_STATE = databus.RTU_HW_STATE local MAIN_CLOCK = 0.5 -- (2Hz, 10 ticks) local COMMS_SLEEP = 100 -- (100ms, 2 ticks) @@ -33,7 +33,7 @@ local COMMS_SLEEP = 100 -- (100ms, 2 ticks) ---@param iface string ---@param type string ---@param device table ----@param unit rtu_unit_registry_entry +---@param unit rtu_registry_entry local function handle_unit_mount(smem, println_ts, iface, type, device, unit) local sys = smem.rtu_sys @@ -106,7 +106,7 @@ local function handle_unit_mount(smem, println_ts, iface, type, device, unit) -- if disconnected on startup, config wouldn't have been validated -- checking now that it has connected; the config isn't valid, so don't connect it if invalid then - unit.hw_state = UNIT_HW_STATE.OFFLINE + unit.hw_state = RTU_HW_STATE.OFFLINE databus.tx_unit_hw_status(unit.uid, unit.hw_state) return end @@ -138,16 +138,16 @@ local function handle_unit_mount(smem, println_ts, iface, type, device, unit) end if unit.is_multiblock then - unit.hw_state = UNIT_HW_STATE.UNFORMED + unit.hw_state = RTU_HW_STATE.UNFORMED if unit.formed == false then log.info(util.c("assuming ", unit.name, " is not formed due to PPM faults while initializing")) end elseif faulted then - unit.hw_state = UNIT_HW_STATE.FAULTED + unit.hw_state = RTU_HW_STATE.FAULTED elseif not unknown then - unit.hw_state = UNIT_HW_STATE.OK + unit.hw_state = RTU_HW_STATE.OK else - unit.hw_state = UNIT_HW_STATE.OFFLINE + unit.hw_state = RTU_HW_STATE.OFFLINE end databus.tx_unit_hw_status(unit.uid, unit.hw_state) @@ -245,6 +245,7 @@ function threads.thread__main(smem) if type ~= nil and device ~= nil then if type == "modem" then + ---@cast device Modem -- we only care if this is our wireless modem if nic.is_modem(device) then nic.disconnect() @@ -263,6 +264,7 @@ function threads.thread__main(smem) log.warning("non-comms modem disconnected") end elseif type == "speaker" then + ---@cast device Speaker for i = 1, #sounders do if sounders[i].speaker == device then table.remove(sounders, i) @@ -279,13 +281,13 @@ function threads.thread__main(smem) -- find disconnected device if units[i].device == device then -- will let the PPM prevent crashes, which will indicate failures in MODBUS queries - local unit = units[i] ---@type rtu_unit_registry_entry + local unit = units[i] local type_name = types.rtu_type_to_string(unit.type) println_ts(util.c("lost the ", type_name, " on interface ", unit.name)) log.warning(util.c("lost the ", type_name, " unit peripheral on interface ", unit.name)) - unit.hw_state = UNIT_HW_STATE.OFFLINE + unit.hw_state = RTU_HW_STATE.OFFLINE databus.tx_unit_hw_status(unit.uid, unit.hw_state) break end @@ -298,6 +300,7 @@ function threads.thread__main(smem) if type ~= nil and device ~= nil then if type == "modem" then + ---@cast device Modem if device.isWireless() and not nic.is_connected() then -- reconnected modem nic.connect(device) @@ -312,6 +315,7 @@ function threads.thread__main(smem) log.info("wired modem reconnected") end elseif type == "speaker" then + ---@cast device Speaker table.insert(sounders, rtu.init_sounder(device)) println_ts("speaker connected") @@ -332,7 +336,7 @@ function threads.thread__main(smem) elseif event == "speaker_audio_empty" then -- handle empty speaker audio buffer for i = 1, #sounders do - local sounder = sounders[i] ---@type rtu_speaker_sounder + local sounder = sounders[i] if sounder.name == param1 then sounder.continue() break @@ -460,7 +464,7 @@ end -- per-unit communications handler thread ---@nodiscard ---@param smem rtu_shared_memory ----@param unit rtu_unit_registry_entry +---@param unit rtu_registry_entry function threads.thread__unit_comms(smem, unit) ---@class parallel_thread local public = {} @@ -523,13 +527,13 @@ function threads.thread__unit_comms(smem, unit) if unit.formed == nil then unit.formed = is_formed - if is_formed then unit.hw_state = UNIT_HW_STATE.OK end + if is_formed then unit.hw_state = RTU_HW_STATE.OK end elseif not unit.formed then - unit.hw_state = UNIT_HW_STATE.UNFORMED + unit.hw_state = RTU_HW_STATE.UNFORMED end if (is_formed == true) and not unit.formed then - unit.hw_state = UNIT_HW_STATE.OK + unit.hw_state = RTU_HW_STATE.OK log.info(util.c(detail_name, " is now formed")) rtu_comms.send_remounted(unit.uid) elseif (is_formed == false) and unit.formed then @@ -541,9 +545,9 @@ function threads.thread__unit_comms(smem, unit) -- check hardware status if unit.device.__p_is_healthy() then - if unit.hw_state == UNIT_HW_STATE.FAULTED then unit.hw_state = UNIT_HW_STATE.OK end + if unit.hw_state == RTU_HW_STATE.FAULTED then unit.hw_state = RTU_HW_STATE.OK end else - if unit.hw_state == UNIT_HW_STATE.OK then unit.hw_state = UNIT_HW_STATE.FAULTED end + if unit.hw_state == RTU_HW_STATE.OK then unit.hw_state = RTU_HW_STATE.FAULTED end end -- update hw status diff --git a/scada-common/audio.lua b/scada-common/audio.lua index 019b510..e1a6958 100644 --- a/scada-common/audio.lua +++ b/scada-common/audio.lua @@ -6,10 +6,10 @@ -- note: max samples = 0x20000 (128 * 1024 samples) -local _2_PI = 2 * math.pi -- 2 whole pies, hope you're hungry -local _DRATE = 48000 -- 48kHz audio -local _MAX_VAL = 127 / 2 -- max signed integer in this 8-bit audio -local _05s_SAMPLES = 24000 -- half a second worth of samples +local _2_PI = 2 * math.pi -- 2 whole pies, hope you're hungry +local _DRATE = 48000 -- 48kHz audio data rate +local _MAX_VAL = 127 / 2 -- max signed integer in this 8-bit audio +local _05s_SAMPLES = 24000 -- half a second worth of samples ---@class audio local audio = {} @@ -28,6 +28,7 @@ local TONE = { audio.TONE = TONE +---@type integer[][][] local tone_data = { { {}, {}, {}, {} }, -- 340Hz @ 2Hz Intermittent { {}, {}, {}, {} }, -- 544Hz 100mS / 440Hz 400mS Alternating @@ -214,7 +215,14 @@ end -- generate all 8 tone sequences function audio.generate_tones() - gen_tone_1(); gen_tone_2(); gen_tone_3(); gen_tone_4(); gen_tone_5(); gen_tone_6(); gen_tone_7(); gen_tone_8() + gen_tone_1() + gen_tone_2() + gen_tone_3() + gen_tone_4() + gen_tone_5() + gen_tone_6() + gen_tone_7() + gen_tone_8() end -- hard audio limiter @@ -226,7 +234,7 @@ local function limit(output) end -- clear output buffer ----@param buffer table quad buffer +---@param buffer integer[][] quad buffer local function clear(buffer) for i = 1, 4 do for s = 1, _05s_SAMPLES do buffer[i][s] = 0 end @@ -239,7 +247,7 @@ function audio.new_stream() any_active = false, need_recompute = false, next_block = 1, - -- split audio up into 0.5s samples, so specific components can be ended quicker + ---@type integer[][] split audio up into 0.5s samples, so specific components can be ended quicker quad_buffer = { {}, {}, {}, {} }, -- all tone enable states tone_active = { false, false, false, false, false, false, false, false } @@ -263,14 +271,17 @@ function audio.new_stream() -- check if a tone is active ---@param index TONE tone index function public.is_active(index) - if self.tone_active[index] then return self.tone_active[index] end - return false + return self.tone_active[index] or false end -- set all tones inactive, reset next block, and clear output buffer function public.stop() - for i = 1, #self.tone_active do self.tone_active[i] = false end + for i = 1, #self.tone_active do + self.tone_active[i] = false + end + self.next_block = 1 + clear(self.quad_buffer) end @@ -287,9 +298,11 @@ function audio.new_stream() for id = 1, #tone_data do if self.tone_active[id] then self.any_active = true + for i = 1, 4 do local buffer = self.quad_buffer[i] local values = tone_data[id][i] + for s = 1, _05s_SAMPLES do self.quad_buffer[i][s] = limit(buffer[s] + values[s]) end end end @@ -305,8 +318,13 @@ function audio.new_stream() -- get the next audio block function public.get_next_block() local block = self.quad_buffer[self.next_block] + self.next_block = self.next_block + 1 - if self.next_block > 4 then self.next_block = 1 end + + if self.next_block > 4 then + self.next_block = 1 + end + return block end diff --git a/scada-common/comms.lua b/scada-common/comms.lua index 6a82228..6f12fb2 100644 --- a/scada-common/comms.lua +++ b/scada-common/comms.lua @@ -405,7 +405,7 @@ function comms.modbus_packet() self.raw = { self.txn_id, self.unit_id, self.func_code } for i = 1, self.length do insert(self.raw, data[i]) end else - log.error("comms.modbus_packet.make(): data not table") + log.error("comms.modbus_packet.make(): data not a table") end end @@ -491,7 +491,7 @@ function comms.rplc_packet() self.raw = { self.id, self.type } for i = 1, #data do insert(self.raw, data[i]) end else - log.error("comms.rplc_packet.make(): data not table") + log.error("comms.rplc_packet.make(): data not a table") end end @@ -573,7 +573,7 @@ function comms.mgmt_packet() self.raw = { self.type } for i = 1, #data do insert(self.raw, data[i]) end else - log.error("comms.mgmt_packet.make(): data not table") + log.error("comms.mgmt_packet.make(): data not a table") end end @@ -652,7 +652,7 @@ function comms.crdn_packet() self.raw = { self.type } for i = 1, #data do insert(self.raw, data[i]) end else - log.error("comms.crdn_packet.make(): data not table") + log.error("comms.crdn_packet.make(): data not a table") end end diff --git a/scada-common/log.lua b/scada-common/log.lua index f876eaa..0df1efc 100644 --- a/scada-common/log.lua +++ b/scada-common/log.lua @@ -4,10 +4,14 @@ local util = require("scada-common.util") +-- constant strings for speed +local DBG_TAG, INF_TAG, WRN_TAG, ERR_TAG, FTL_TAG = "[DBG] ", "[INF] ", "[WRN] ", "[ERR] ", "[FTL] " +local COLON, FUNC, ARROW = ":", "():", " > " + ---@class logger local log = {} ----@alias MODE integer +---@enum MODE local MODE = { APPEND = 0, NEW = 1 } log.MODE = MODE @@ -18,7 +22,7 @@ local logger = { mode = MODE.APPEND, debug = false, file = nil, ---@type table|nil - dmesg_out = nil, + dmesg_out = nil, ---@type Redirect|nil dmesg_restore_coord = { 1, 1 }, dmesg_scroll_count = 0 } @@ -31,13 +35,13 @@ local free_space = fs.getFreeSpace ----------------------- -- private log write function ----@param msg string -local function _log(msg) +---@param msg_bits any[] +local function _log(msg_bits) if logger.not_ready then return end local out_of_space = false - local time_stamp = os.date("[%c] ") - local stamped = time_stamp .. util.strval(msg) + local time_stamp = os.date("[%c] ") + local stamped = util.c(time_stamp, table.unpack(msg_bits)) -- attempt to write log local status, result = pcall(function () @@ -80,7 +84,7 @@ end ---@param path string file path ---@param write_mode MODE file write mode ---@param include_debug boolean whether or not to include debug logs ----@param dmesg_redirect? table terminal/window to direct dmesg to +---@param dmesg_redirect? Redirect terminal/window to direct dmesg to function log.init(path, write_mode, include_debug, dmesg_redirect) logger.path = path logger.mode = write_mode @@ -102,16 +106,14 @@ function log.init(path, write_mode, include_debug, dmesg_redirect) end -- close the log file handle -function log.close() - logger.file.close() -end +function log.close() logger.file.close() end -- direct dmesg output to a monitor/window ----@param window table window or terminal reference +---@param window Window window or terminal reference function log.direct_dmesg(window) logger.dmesg_out = window end -- dmesg style logging for boot because I like linux-y things ----@param msg string message +---@param msg any message ---@param tag? string log tag ---@param tag_color? integer log tag color ---@return dmesg_ts_coord coordinates line area to place working indicator @@ -120,8 +122,7 @@ function log.dmesg(msg, tag, tag_color) local ts_coord = { x1 = 2, x2 = 3, y = 1 } msg = util.strval(msg) - tag = tag or "" - tag = util.strval(tag) + tag = util.strval(tag or "") local t_stamp = string.format("%12.2f", os.clock()) local out = logger.dmesg_out @@ -209,7 +210,7 @@ function log.dmesg(msg, tag, tag_color) logger.dmesg_restore_coord = { out.getCursorPos() } - _log(util.c("[", t_stamp, "] [", tag, "] ", msg)) + _log{"[", t_stamp, "] [", tag, "] ", msg} end return ts_coord @@ -291,63 +292,51 @@ function log.dmesg_working(msg, tag, tag_color) end -- log debug messages ----@param msg string message +---@param msg any message ---@param trace? boolean include file trace function log.debug(msg, trace) if logger.debug then - local dbg_info = "" - if trace then local info = debug.getinfo(2) - local name = "" if info.name ~= nil then - name = ":" .. info.name .. "():" + _log{DBG_TAG, info.short_src, COLON, info.name, FUNC, info.currentline, ARROW, msg} + else + _log{DBG_TAG, info.short_src, COLON, info.currentline, ARROW, msg} end - - dbg_info = info.short_src .. ":" .. name .. info.currentline .. " > " + else + _log{DBG_TAG, msg} end - - _log("[DBG] " .. dbg_info .. util.strval(msg)) end end -- log info messages ----@param msg string message -function log.info(msg) - _log("[INF] " .. util.strval(msg)) -end +---@param msg any message +function log.info(msg) _log{INF_TAG, msg} end -- log warning messages ----@param msg string message -function log.warning(msg) - _log("[WRN] " .. util.strval(msg)) -end +---@param msg any message +function log.warning(msg) _log{WRN_TAG, msg} end -- log error messages ----@param msg string message +---@param msg any message ---@param trace? boolean include file trace function log.error(msg, trace) - local dbg_info = "" - if trace then local info = debug.getinfo(2) - local name = "" if info.name ~= nil then - name = ":" .. info.name .. "():" + _log{ERR_TAG, info.short_src, COLON, info.name, FUNC, info.currentline, ARROW, msg} + else + _log{ERR_TAG, info.short_src, COLON, info.currentline, ARROW, msg} end - - dbg_info = info.short_src .. ":" .. name .. info.currentline .. " > " + else + _log{ERR_TAG, msg} end - - _log("[ERR] " .. dbg_info .. util.strval(msg)) end -- log fatal errors ----@param msg string message -function log.fatal(msg) - _log("[FTL] " .. util.strval(msg)) -end +---@param msg any message +function log.fatal(msg) _log{FTL_TAG, msg} end return log diff --git a/scada-common/mqueue.lua b/scada-common/mqueue.lua index fc60a1e..db09509 100644 --- a/scada-common/mqueue.lua +++ b/scada-common/mqueue.lua @@ -27,6 +27,7 @@ local remove = table.remove -- create a new message queue ---@nodiscard function mqueue.new() + ---@type queue_item[] local queue = {} ---@class mqueue diff --git a/scada-common/network.lua b/scada-common/network.lua index c34a1d5..7eccff7 100644 --- a/scada-common/network.lua +++ b/scada-common/network.lua @@ -77,26 +77,14 @@ end -- NIC: Network Interface Controller
-- utilizes HMAC-MD5 for message authentication, if enabled ----@param modem table modem to use +---@param modem Modem modem to use function network.nic(modem) local self = { connected = true, -- used to avoid costly MAC calculations if modem isn't even present channels = {} } - ---@class nic - ---@field open function - ---@field isOpen function - ---@field close function - ---@field closeAll function - ---@field isWireless function - ---@field getNameLocal function - ---@field getNamesRemote function - ---@field isPresentRemote function - ---@field getTypeRemote function - ---@field hasTypeRemote function - ---@field getMethodsRemote function - ---@field callRemote function + ---@class nic:Modem local public = {} -- check if this NIC has a connected modem @@ -104,7 +92,7 @@ function network.nic(modem) function public.is_connected() return self.connected end -- connect to a modem peripheral - ---@param reconnected_modem table + ---@param reconnected_modem Modem function public.connect(reconnected_modem) modem = reconnected_modem self.connected = true diff --git a/scada-common/ppm.lua b/scada-common/ppm.lua index e6a95e8..7d6071e 100644 --- a/scada-common/ppm.lua +++ b/scada-common/ppm.lua @@ -23,7 +23,7 @@ ppm.VIRTUAL_DEVICE_TYPE = VIRTUAL_DEVICE_TYPE local REPORT_FREQUENCY = 20 -- log every 20 faults per function local ppm_sys = { - mounts = {}, + mounts = {}, ---@type { [string]: ppm_entry } next_vid = 0, auto_cf = false, faulted = false, @@ -40,10 +40,10 @@ local function peri_init(iface) local self = { faulted = false, last_fault = "", - fault_counts = {}, + fault_counts = {}, ---@type { [string]: integer } auto_cf = true, - type = VIRTUAL_DEVICE_TYPE, - device = {} + type = VIRTUAL_DEVICE_TYPE, ---@type string + device = {} ---@type { [string]: function } } if iface ~= "__virtual__" then @@ -181,7 +181,7 @@ local function peri_init(iface) setmetatable(self.device, mt) ---@class ppm_entry - local entry = { type = self.type, dev = self.device } + local entry = { type = self.type, dev = self.device } return entry end @@ -284,10 +284,10 @@ end ---@param device table device table function ppm.unmount(device) if device then - for side, data in pairs(ppm_sys.mounts) do + for iface, data in pairs(ppm_sys.mounts) do if data.dev == device then - log.warning(util.c("PPM: manually unmounted ", data.type, " mounted to ", side)) - ppm_sys.mounts[side] = nil + log.warning(util.c("PPM: manually unmounted ", data.type, " mounted to ", iface)) + ppm_sys.mounts[iface] = nil break end end @@ -334,12 +334,12 @@ end -- list all available peripherals ---@nodiscard ----@return table names +---@return string[] names function ppm.list_avail() return peripheral.getNames() end -- list mounted peripherals ---@nodiscard ----@return table mounts +---@return { [string]: ppm_entry } mounts function ppm.list_mounts() local list = {} for k, v in pairs(ppm_sys.mounts) do list[k] = v end @@ -352,8 +352,8 @@ end ---@return string|nil iface CC peripheral interface function ppm.get_iface(device) if device then - for side, data in pairs(ppm_sys.mounts) do - if data.dev == device then return side end + for iface, data in pairs(ppm_sys.mounts) do + if data.dev == device then return iface end end end @@ -363,7 +363,7 @@ end -- get a mounted peripheral by side/interface ---@nodiscard ---@param iface string CC peripheral interface ----@return table|nil device function table +---@return { [string]: function }|nil device function table function ppm.get_periph(iface) if ppm_sys.mounts[iface] then return ppm_sys.mounts[iface].dev @@ -423,7 +423,7 @@ function ppm.get_fission_reactor() return ppm.get_device("fissionReactorLogicAda -- get the wireless modem (if multiple, returns the first)
-- if this is in a CraftOS emulated environment, wired modems will be used instead ---@nodiscard ----@return table|nil modem function table +---@return Modem|nil modem function table function ppm.get_wireless_modem() local w_modem = nil local emulated_env = periphemu ~= nil @@ -440,7 +440,7 @@ end -- list all connected monitors ---@nodiscard ----@return table monitors +---@return { [string]: ppm_entry } monitors function ppm.get_monitor_list() local list = {} diff --git a/scada-common/psil.lua b/scada-common/psil.lua index 09686bf..f3d810a 100644 --- a/scada-common/psil.lua +++ b/scada-common/psil.lua @@ -6,9 +6,10 @@ local util = require("scada-common.util") local psil = {} --- instantiate a new PSI layer +-- instantiate a new interconnect layer ---@nodiscard function psil.create() + ---@type { [string]: { subscribers: { notify: fun(param: any) }[], value: any } } interconnect table local ic = {} -- allocate a new interconnect field diff --git a/scada-common/rsio.lua b/scada-common/rsio.lua index fb3a50a..b88180a 100644 --- a/scada-common/rsio.lua +++ b/scada-common/rsio.lua @@ -113,10 +113,13 @@ assert(#dup_chk == rsio.NUM_PORTS, "port list malformed") local IO = IO_PORT -- list of all port names +---@type string[] local PORT_NAMES = {} + for k, v in pairs(IO) do PORT_NAMES[v] = k end -- list of all port I/O modes +---@type { [IO_PORT]: IO_MODE } local MODES = { [IO.F_SCRAM] = IO_MODE.DIGITAL_IN, [IO.F_ACK] = IO_MODE.DIGITAL_IN, @@ -233,6 +236,7 @@ end --#region Generic Checks +---@type string[] local RS_SIDES = rs.getSides() -- check if a port is valid diff --git a/scada-common/tcd.lua b/scada-common/tcd.lua index a3c920f..f11c2d8 100644 --- a/scada-common/tcd.lua +++ b/scada-common/tcd.lua @@ -7,6 +7,7 @@ local util = require("scada-common.util") local tcd = {} +---@type { callback: function, duration: number, expiry: number }[] local registry = {} -- request a function to be called after the specified time diff --git a/scada-common/types.lua b/scada-common/types.lua index 2bf6ae1..29c52c5 100644 --- a/scada-common/types.lua +++ b/scada-common/types.lua @@ -5,6 +5,66 @@ ---@class types local types = {} +--#region CC: TWEAKED CLASSES https://tweaked.cc + +---@class Redirect +---@field write fun(text: string) Write text at the current cursor position, moving the cursor to the end of the text. +---@field scroll fun(y: integer) Move all positions up (or down) by y pixels. +---@field getCursorPos fun() : x: integer, y: integer Get the position of the cursor. +---@field setCursorPos fun(x: integer, y: integer) Set the position of the cursor. +---@field getCursorBlink fun() : boolean Checks if the cursor is currently blinking. +---@field setCursorBlink fun(blink: boolean) Sets whether the cursor should be visible (and blinking) at the current cursor position. +---@field getSize fun() : width: integer, height: integer Get the size of the terminal. +---@field clear fun() Clears the terminal, filling it with the current background color. +---@field clearLine fun() Clears the line the cursor is currently on, filling it with the current background color. +---@field getTextColor fun() : color Return the color that new text will be written as. +---@field setTextColor fun(color: color) Set the colour that new text will be written as. +---@field getBackgroundColor fun() : color Return the current background color. +---@field setBackgroundColor fun(color: color) set the current background color. +---@field isColor fun() Determine if this terminal supports color. +---@field blit fun(text: string, textColor: string, backgroundColor: string) Writes text to the terminal with the specific foreground and background colors. +---@diagnostic disable-next-line: duplicate-doc-field +---@field setPaletteColor fun(index: color, color: integer) Set the palette for a specific color. +---@diagnostic disable-next-line: duplicate-doc-field +---@field setPaletteColor fun(index: color, r: number, g: number, b:number) Set the palette for a specific color. R/G/B are 0 to 1. +---@field getPaletteColor fun(color: color) : r: number, g: number, b:number Get the current palette for a specific color. + +---@class Window:Redirect +---@field getLine fun(y: integer) : content: string, fg: string, bg: string Get the buffered contents of a line in this window. +---@field setVisible fun(visible: boolean) Set whether this window is visible. Invisible windows will not be drawn to the screen until they are made visible again. +---@field isVisible fun() : visible: boolean Get whether this window is visible. Invisible windows will not be drawn to the screen until they are made visible again. +---@field redraw fun() Draw this window. This does nothing if the window is not visible. +---@field restoreCursor fun() Set the current terminal's cursor to where this window's cursor is. This does nothing if the window is not visible. +---@field getPosition fun() : x: integer, y: integer Get the position of the top left corner of this window. +---@field reposition fun(new_x: integer, new_y: integer, new_width?: integer, new_height?: integer, new_parent?: Redirect) Reposition or resize the given window. + +---@class Monitor:Redirect +---@field setTextScale fun(scale: number) Set the scale of this monitor. +---@field getTextScale fun() : number Get the monitor's current text scale. + +---@class Modem +---@field open fun(channel: integer) Open a channel on a modem. +---@field isOpen fun(channel: integer) : boolean Check if a channel is open. +---@field close fun(channel: integer) Close an open channel, meaning it will no longer receive messages. +---@field closeAll fun() Close all open channels. +---@field transmit fun(channel: integer, replyChannel: integer, payload: any) Sends a modem message on a certain channel. +---@field isWireless fun() : boolean Determine if this is a wired or wireless modem. +---@field getNamesRemote fun() : string[] List all remote peripherals on the wired network. +---@field isPresentRemote fun(name: string) : boolean Determine if a peripheral is available on this wired network. +---@field getTypeRemote fun(name: string) : string|nil Get the type of a peripheral is available on this wired network. +---@field hasTypeRemote fun(name: string, type: string) : boolean|nil Check a peripheral is of a particular . +---@field getMethodsRemote fun(name: string) : string[] Get all available methods for the remote peripheral with the given name. +---@field callRemote fun(remoteName: string, method: string, ...) : table Call a method on a peripheral on this wired network. +---@field getNameLocal fun() : string|nil Returns the network name of the current computer, if the modem is on. + +---@class Speaker +---@field playNote fun(instrument: string, volume?: number, pitch?: number) : success: boolean Plays a note block note through the speaker. +---@field playSound fun(name: string, volume?: number, pitch?: number) : success: boolean Plays a Minecraft sound through the speaker. +---@field playAudio fun(audio: number[], volume?: number) : success: boolean Attempt to stream some audio data to the speaker. +---@field stop fun() Stop all audio being played by this speaker. + +--#endregion + --#region CLASSES ---@class tank_fluid @@ -65,7 +125,7 @@ function types.new_zero_coordinate() return { x = 0, y = 0, z = 0 } end ---@field type RTU_UNIT_TYPE ---@field index integer|false ---@field reactor integer ----@field rsio table|nil +---@field rsio IO_PORT[]|nil --#endregion diff --git a/scada-common/util.lua b/scada-common/util.lua index 36a73fc..2ae76a7 100644 --- a/scada-common/util.lua +++ b/scada-common/util.lua @@ -24,7 +24,7 @@ local t_pack = table.pack local util = {} -- scada-common version -util.version = "1.4.4" +util.version = "1.4.5" util.TICK_TIME_S = 0.05 util.TICK_TIME_MS = 50 @@ -33,9 +33,9 @@ util.TICK_TIME_MS = 50 -- trinary operator ---@nodiscard ----@param cond boolean|nil condition ----@param a any return if true ----@param b any return if false +---@param cond any condition +---@param a any return if evaluated as true +---@param b any return if false or nil ---@return any value function util.trinary(cond, a, b) if cond then return a else return b end @@ -84,7 +84,7 @@ end -- does not behave exactly like C's strtok ---@param str string string to tokenize ---@param sep string separator to tokenize by ----@return table token_list +---@return string[] token_list function util.strtok(str, sep) local list = {} for part in string.gmatch(str, "([^" .. sep .. "]+)") do t_insert(list, part) end @@ -123,7 +123,7 @@ end ---@nodiscard ---@param str string ---@param limit integer line limit, must be greater than 0 ----@return table lines +---@return string[] lines function util.strwrap(str, limit) assert(limit > 0, "util.strwrap() limit not greater than 0") return cc_strings.wrap(str, limit) @@ -138,7 +138,7 @@ function util.strminw(str, width) return cc_strings.ensure_width(str, width) end -- concatenation with built-in to string ---@nodiscard ----@vararg any +---@param ... any ---@return string function util.concat(...) local args, strings = t_pack(...), {} @@ -152,7 +152,7 @@ util.c = util.concat -- sprintf implementation ---@nodiscard ---@param format string ----@vararg any +---@param ... any function util.sprintf(format, ...) return string.format(format, ...) end -- format a number string with commas as the thousands separator
@@ -343,8 +343,9 @@ end -- delete elements from a table if the passed function returns false when passed a table element
-- put briefly: deletes elements that return false, keeps elements that return true ----@param t table table to remove elements from ----@param f function should return false to delete an element when passed the element: f(elem) = true|false +---@generic Type +---@param t Type[] table to remove elements from +---@param f fun(t_elem: Type) : boolean should return false to delete an element when passed the element ---@param on_delete? function optional function to execute on deletion, passed the table element to be deleted as the parameter function util.filter_table(t, f, on_delete) local move_to = 1 @@ -366,9 +367,10 @@ function util.filter_table(t, f, on_delete) end -- check if a table contains the provided element +---@generic Type ---@nodiscard ----@param t table table to check ----@param element any element to check for +---@param t Type[] table to check +---@param element Type element to check for function util.table_contains(t, element) for i = 1, #t do if t[i] == element then return true end diff --git a/supervisor/configure.lua b/supervisor/configure.lua index 0c90538..362c41d 100644 --- a/supervisor/configure.lua +++ b/supervisor/configure.lua @@ -9,21 +9,21 @@ local util = require("scada-common.util") local core = require("graphics.core") local themes = require("graphics.themes") -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") +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") -local CheckBox = require("graphics.elements.controls.checkbox") -local PushButton = require("graphics.elements.controls.push_button") -local Radio2D = require("graphics.elements.controls.radio_2d") -local RadioButton = require("graphics.elements.controls.radio_button") +local Checkbox = require("graphics.elements.controls.Checkbox") +local PushButton = require("graphics.elements.controls.PushButton") +local Radio2D = require("graphics.elements.controls.Radio2D") +local RadioButton = require("graphics.elements.controls.RadioButton") -local NumberField = require("graphics.elements.form.number_field") -local TextField = require("graphics.elements.form.text_field") +local NumberField = require("graphics.elements.form.NumberField") +local TextField = require("graphics.elements.form.TextField") -local IndLight = require("graphics.elements.indicators.light") +local IndLight = require("graphics.elements.indicators.IndicatorLight") local println = util.println local tri = util.trinary @@ -62,46 +62,46 @@ local tool_ctl = { importing_legacy = false, jumped_to_color = false, - view_cfg = nil, ---@type graphics_element - color_cfg = nil, ---@type graphics_element - color_next = nil, ---@type graphics_element - color_apply = nil, ---@type graphics_element - settings_apply = nil, ---@type graphics_element + view_cfg = nil, ---@type PushButton + color_cfg = nil, ---@type PushButton + color_next = nil, ---@type PushButton + color_apply = nil, ---@type PushButton + settings_apply = nil, ---@type PushButton gen_summary = nil, ---@type function show_current_cfg = nil, ---@type function load_legacy = nil, ---@type function show_auth_key = nil, ---@type function - show_key_btn = nil, ---@type graphics_element - auth_key_textbox = nil, ---@type graphics_element + show_key_btn = nil, ---@type PushButton + auth_key_textbox = nil, ---@type TextBox auth_key_value = "", - cooling_elems = {}, - tank_elems = {}, + cooling_elems = {}, ---@type { line: Div, turbines: NumberField, boilers: NumberField, tank: Checkbox }[] + tank_elems = {}, ---@type { div: Div, tank_opt: Radio2D, no_tank: TextBox }[] - vis_ftanks = {}, - vis_utanks = {} + vis_ftanks = {}, ---@type { line: Div, pipe_conn?: TextBox, pipe_chain?: TextBox, pipe_direct?: TextBox, label?: TextBox }[] + vis_utanks = {} ---@type { line: Div, label: TextBox }[] } ---@class svr_config local tmp_cfg = { UnitCount = 1, - CoolingConfig = {}, + CoolingConfig = {}, ---@type { TurbineCount: integer, BoilerCount: integer, TankConnection: boolean }[] FacilityTankMode = 0, - FacilityTankDefs = {}, + FacilityTankDefs = {}, ---@type integer[] ExtChargeIdling = false, - SVR_Channel = nil, ---@type integer - PLC_Channel = nil, ---@type integer - RTU_Channel = nil, ---@type integer - CRD_Channel = nil, ---@type integer - PKT_Channel = nil, ---@type integer - PLC_Timeout = nil, ---@type number - RTU_Timeout = nil, ---@type number - CRD_Timeout = nil, ---@type number - PKT_Timeout = nil, ---@type number - TrustedRange = nil, ---@type number - AuthKey = nil, ---@type string|nil + SVR_Channel = nil, ---@type integer + PLC_Channel = nil, ---@type integer + RTU_Channel = nil, ---@type integer + CRD_Channel = nil, ---@type integer + PKT_Channel = nil, ---@type integer + PLC_Timeout = nil, ---@type number + RTU_Timeout = nil, ---@type number + CRD_Timeout = nil, ---@type number + PKT_Timeout = nil, ---@type number + TrustedRange = nil, ---@type number + AuthKey = nil, ---@type string|nil LogMode = 0, LogPath = "", LogDebug = false, @@ -153,7 +153,7 @@ local function load_settings(target, raw) end -- create the config view ----@param display graphics_element +---@param display DisplayBox local function config_view(display) ---@diagnostic disable-next-line: undefined-field local function exit() os.queueEvent("terminate") end @@ -271,7 +271,7 @@ local function config_view(display) 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} local boilers = NumberField{parent=line,x=20,y=1,width=5,max_chars=2,default=num_b,min=0,max=2,fg_bg=bw_fg_bg} - local tank = CheckBox{parent=line,x=30,y=1,label="Is Connected",default=has_t,box_fg_bg=cpair(colors.yellow,colors.black)} + local tank = Checkbox{parent=line,x=30,y=1,label="Is Connected",default=has_t,box_fg_bg=cpair(colors.yellow,colors.black)} tool_ctl.cooling_elems[i] = { line = line, turbines = turbines, boilers = boilers, tank = tank } end @@ -294,7 +294,13 @@ local function config_view(display) tmp_cfg.CoolingConfig = {} for i = 1, tmp_cfg.UnitCount do local conf = tool_ctl.cooling_elems[i] - tmp_cfg.CoolingConfig[i] = { TurbineCount = tonumber(conf.turbines.get_value()), BoilerCount = tonumber(conf.boilers.get_value()), TankConnection = conf.tank.get_value() } + -- already verified fields are numbers + tmp_cfg.CoolingConfig[i] = { + TurbineCount = tonumber(conf.turbines.get_value()) --[[@as number]], + BoilerCount = tonumber(conf.boilers.get_value()) --[[@as number]], + TankConnection = conf.tank.get_value() + } + if conf.tank.get_value() then any_has_tank = true end end @@ -322,7 +328,7 @@ local function config_view(display) TextBox{parent=svr_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=svr_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."} - local en_fac_tanks = CheckBox{parent=svr_c_3,x=1,y=12,label="Use Facility Dynamic Tanks",default=ini_cfg.FacilityTankMode>0,box_fg_bg=cpair(colors.yellow,colors.black)} + local en_fac_tanks = Checkbox{parent=svr_c_3,x=1,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 en_fac_tanks.get_value() then @@ -583,7 +589,7 @@ local function config_view(display) TextBox{parent=svr_c_7,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=svr_c_7,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=svr_c_7,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=svr_c_7,x=1,y=12,label="Enable Extended Idling",default=ini_cfg.ExtChargeIdling,box_fg_bg=cpair(colors.yellow,colors.black)} local function back_from_idling() svr_pane.set_value(util.trinary(tmp_cfg.FacilityTankMode == 0, 3, 5)) @@ -704,11 +710,11 @@ local function config_view(display) TextBox{parent=net_c_4,x=1,y=4,height=6,text="This enables verifying that messages are authentic, so it is intended for security on multiplayer servers. All devices on the same network MUST use the same key if any device has a key. This does result in some extra compution (can slow things down).",fg_bg=g_lg_fg_bg} TextBox{parent=net_c_4,x=1,y=11,text="Facility Auth Key"} - local key, _, censor = 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} + 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} - local function censor_key(enable) censor(util.trinary(enable, "*", nil)) end + local function censor_key(enable) key.censor(util.trinary(enable, "*", nil)) end - local hide_key = CheckBox{parent=net_c_4,x=34,y=12,label="Hide",box_fg_bg=cpair(colors.lightBlue,colors.black),callback=censor_key} + local hide_key = Checkbox{parent=net_c_4,x=34,y=12,label="Hide",box_fg_bg=cpair(colors.lightBlue,colors.black),callback=censor_key} hide_key.set_value(true) censor_key(true) @@ -743,7 +749,7 @@ local function config_view(display) 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} - 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,x=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} diff --git a/supervisor/facility.lua b/supervisor/facility.lua index 7b786a2..3ec2b82 100644 --- a/supervisor/facility.lua +++ b/supervisor/facility.lua @@ -40,7 +40,7 @@ local facility = {} function facility.new(config) ---@class _facility_self local self = { - units = {}, + units = {}, ---@type reactor_unit[] types = { AUTO_SCRAM = AUTO_SCRAM, START_STATUS = START_STATUS }, status_text = { "START UP", "initializing..." }, all_sys_ok = false, @@ -51,16 +51,16 @@ function facility.new(config) r_cool = config.CoolingConfig, fac_tank_mode = config.FacilityTankMode, fac_tank_defs = config.FacilityTankDefs, - fac_tank_list = {} + fac_tank_list = {} ---@type integer[] }, -- rtus - rtu_conn_count = 0, - rtu_list = {}, - redstone = {}, - induction = {}, - sps = {}, - tanks = {}, - envd = {}, + rtu_gw_conn_count = 0, + rtu_list = {}, ---@type unit_session[][] + redstone = {}, ---@type redstone_session[] + induction = {}, ---@type imatrix_session[] + sps = {}, ---@type sps_session[] + tanks = {}, ---@type dynamicv_session[] + envd = {}, ---@type envd_session[] -- redstone I/O control io_ctl = nil, ---@type rs_controller -- process control @@ -105,11 +105,11 @@ function facility.new(config) sps_low_power = false, disabled_sps = false, -- alarm tones - tone_states = {}, + tone_states = {}, ---@type { [TONE]: boolean } test_tone_set = false, test_tone_reset = false, - test_tone_states = {}, - test_alarm_states = {}, + test_tone_states = {}, ---@type { [TONE]: boolean } + test_alarm_states = {}, ---@type { [ALARM]: boolean } -- statistics im_stat_init = false, avg_charge = util.mov_avg(3), -- 3 seconds @@ -350,7 +350,7 @@ function facility.new(config) -- additionally sets the requested auto waste mode if applicable function public.update_units() for i = 1, #self.units do - local u = self.units[i] ---@type reactor_unit + local u = self.units[i] u.auto_set_waste(self.current_waste_product) u.update() end @@ -363,16 +363,14 @@ function facility.new(config) -- SCRAM all reactor units function public.scram_all() for i = 1, #self.units do - local u = self.units[i] ---@type reactor_unit - u.scram() + self.units[i].scram() end end -- ack all alarms on all reactor units function public.ack_all() for i = 1, #self.units do - local u = self.units[i] ---@type reactor_unit - u.ack_all() + self.units[i].ack_all() end end @@ -393,8 +391,7 @@ function facility.new(config) -- load up current limits local limits = {} for i = 1, config.UnitCount do - local u = self.units[i] ---@type reactor_unit - limits[i] = u.get_control_inf().lim_br100 * 100 + limits[i] = self.units[i].get_control_inf().lim_br100 * 100 end -- only allow changes if not running @@ -512,7 +509,7 @@ function facility.new(config) -- attempt to set a test tone state ---@param id TONE|0 tone ID or 0 to disable all ---@param state boolean state - ---@return boolean allow_testing, table test_tone_states + ---@return boolean allow_testing, { [TONE]: boolean } test_tone_states function public.diag_set_test_tone(id, state) if self.allow_testing then self.test_tone_set = true @@ -531,7 +528,7 @@ function facility.new(config) -- attempt to set a test alarm state ---@param id ALARM|0 alarm ID or 0 to disable all ---@param state boolean state - ---@return boolean allow_testing, table test_alarm_states + ---@return boolean allow_testing, { [ALARM]: boolean } test_alarm_states function public.diag_set_test_alarm(id, state) if self.allow_testing then self.test_tone_set = true @@ -565,7 +562,7 @@ function facility.new(config) if all or type == RTU_UNIT_TYPE.IMATRIX then build.induction = {} for i = 1, #self.induction do - local matrix = self.induction[i] ---@type unit_session + local matrix = self.induction[i] build.induction[i] = { matrix.get_db().formed, matrix.get_db().build } end end @@ -573,7 +570,7 @@ function facility.new(config) if all or type == RTU_UNIT_TYPE.SPS then build.sps = {} for i = 1, #self.sps do - local sps = self.sps[i] ---@type unit_session + local sps = self.sps[i] build.sps[i] = { sps.get_db().formed, sps.get_db().build } end end @@ -581,7 +578,7 @@ function facility.new(config) if all or type == RTU_UNIT_TYPE.DYNAMIC_VALVE then build.tanks = {} for i = 1, #self.tanks do - local tank = self.tanks[i] ---@type unit_session + local tank = self.tanks[i] build.tanks[tank.get_device_idx()] = { tank.get_db().formed, tank.get_db().build } end end @@ -636,7 +633,7 @@ function facility.new(config) local status = {} -- total count of all connected RTUs in the facility - status.count = self.rtu_conn_count + status.count = self.rtu_gw_conn_count -- power averages from induction matricies status.power = { @@ -649,8 +646,8 @@ function facility.new(config) -- status of induction matricies (including tanks) status.induction = {} for i = 1, #self.induction do - local matrix = self.induction[i] ---@type unit_session - local db = matrix.get_db() ---@type imatrix_session_db + local matrix = self.induction[i] + local db = matrix.get_db() status.induction[i] = { matrix.is_faulted(), db.formed, db.state, db.tanks } @@ -662,24 +659,24 @@ function facility.new(config) -- status of sps status.sps = {} for i = 1, #self.sps do - local sps = self.sps[i] ---@type unit_session - local db = sps.get_db() ---@type sps_session_db + local sps = self.sps[i] + local db = sps.get_db() status.sps[i] = { sps.is_faulted(), db.formed, db.state, db.tanks } end -- status of dynamic tanks status.tanks = {} for i = 1, #self.tanks do - local tank = self.tanks[i] ---@type unit_session - local db = tank.get_db() ---@type dynamicv_session_db + local tank = self.tanks[i] + local db = tank.get_db() status.tanks[tank.get_device_idx()] = { tank.is_faulted(), db.formed, db.state, db.tanks } end -- radiation monitors (environment detectors) status.envds = {} for i = 1, #self.envd do - local envd = self.envd[i] ---@type unit_session - local db = envd.get_db() ---@type envd_session_db + local envd = self.envd[i] + local db = envd.get_db() status.envds[envd.get_device_idx()] = { envd.is_faulted(), db.radiation, db.radiation_raw } end @@ -688,9 +685,9 @@ function facility.new(config) --#endregion - -- supervisor sessions reporting the list of active RTU sessions - ---@param rtu_sessions table session list of all connected RTUs - function public.report_rtus(rtu_sessions) self.rtu_conn_count = #rtu_sessions end + -- supervisor sessions reporting the list of active RTU gateway sessions + ---@param sessions rtu_session_struct[] session list of all connected RTU gateways + function public.report_rtu_gateways(sessions) self.rtu_gw_conn_count = #sessions end -- get the facility cooling configuration function public.get_cooling_conf() return self.cooling_conf end diff --git a/supervisor/facility_update.lua b/supervisor/facility_update.lua index 43fe86b..6375077 100644 --- a/supervisor/facility_update.lua +++ b/supervisor/facility_update.lua @@ -84,7 +84,7 @@ local function allocate_burn_rate(burn_rate, ramp, abort_on_fault) -- go through all reactor units in this group for id = 1, #units do - local u = units[id] ---@type reactor_unit + local u = units[id] local ctl = u.get_control_inf() local lim_br100 = u.auto_get_effective_limit() @@ -139,7 +139,7 @@ function update.pre_auto() -- check if test routines are allowed right now self.allow_testing = true for i = 1, #self.units do - local u = self.units[i] ---@type reactor_unit + local u = self.units[i] self.allow_testing = self.allow_testing and u.is_safe_idle() end @@ -149,8 +149,8 @@ function update.pre_auto() -- calculate moving averages for induction matrix if self.induction[1] ~= nil then - local matrix = self.induction[1] ---@type unit_session - local db = matrix.get_db() ---@type imatrix_session_db + local matrix = self.induction[1] + local db = matrix.get_db() local build_update = db.build.last_update rate_update = db.state.last_update @@ -512,7 +512,7 @@ function update.auto_safety() local astatus = self.ascram_status if self.induction[1] ~= nil then - local db = self.induction[1].get_db() ---@type imatrix_session_db + local db = self.induction[1].get_db() -- clear matrix disconnected if astatus.matrix_dc then @@ -531,7 +531,7 @@ function update.auto_safety() -- check for critical unit alarms astatus.crit_alarm = false for i = 1, #self.units do - local u = self.units[i] ---@type reactor_unit + local u = self.units[i] if u.has_alarm_min_prio(PRIO.CRITICAL) then astatus.crit_alarm = true @@ -544,8 +544,8 @@ function update.auto_safety() local max_rad = 0 for i = 1, #self.envd do - local envd = self.envd[i] ---@type unit_session - local e_db = envd.get_db() ---@type envd_session_db + local envd = self.envd[i] + local e_db = envd.get_db() if e_db.radiation_raw > max_rad then max_rad = e_db.radiation_raw end end @@ -620,7 +620,7 @@ function update.auto_safety() -- reset PLC RPS trips if we should for i = 1, #self.units do - local u = self.units[i] ---@type reactor_unit + local u = self.units[i] u.auto_cond_rps_reset() end end @@ -647,7 +647,7 @@ function update.alarm_audio() else -- check all alarms for all units for i = 1, #self.units do - local u = self.units[i] ---@type reactor_unit + local u = self.units[i] for id, alarm in pairs(u.get_alarms()) do alarms[id] = alarms[id] or (alarm == ALARM_STATE.TRIPPED) end @@ -730,7 +730,7 @@ function update.redstone(ack_all) -- handle facility SCRAM if self.io_ctl.digital_read(IO.F_SCRAM) then for i = 1, #self.units do - local u = self.units[i] ---@type reactor_unit + local u = self.units[i] u.cond_scram() end end @@ -741,7 +741,7 @@ function update.redstone(ack_all) -- update facility alarm outputs local has_prio_alarm, has_any_alarm = false, false for i = 1, #self.units do - local u = self.units[i] ---@type reactor_unit + local u = self.units[i] if u.has_alarm_min_prio(PRIO.EMERGENCY) then has_prio_alarm, has_any_alarm = true, true @@ -756,7 +756,7 @@ function update.redstone(ack_all) -- update induction matrix related outputs if self.induction[1] ~= nil then - local db = self.induction[1].get_db() ---@type imatrix_session_db + local db = self.induction[1].get_db() self.io_ctl.digital_write(IO.F_MATRIX_LOW, db.tanks.energy_fill < const.RS_THRESHOLDS.IMATRIX_CHARGE_LOW) self.io_ctl.digital_write(IO.F_MATRIX_HIGH, db.tanks.energy_fill > const.RS_THRESHOLDS.IMATRIX_CHARGE_HIGH) @@ -771,7 +771,7 @@ function update.unit_mgmt() local need_emcool = false for i = 1, #self.units do - local u = self.units[i] ---@type reactor_unit + local u = self.units[i] -- update auto waste processing if u.get_control_inf().waste_mode == WASTE_MODE.AUTO then @@ -791,7 +791,7 @@ function update.unit_mgmt() self.current_waste_product = self.waste_product if (not self.sps_low_power) and (self.waste_product == WASTE.ANTI_MATTER) and (self.induction[1] ~= nil) then - local db = self.induction[1].get_db() ---@type imatrix_session_db + local db = self.induction[1].get_db() if db.tanks.energy_fill >= 0.15 then self.disabled_sps = false @@ -812,8 +812,8 @@ function update.unit_mgmt() -- there should be no need for any to be in fill only mode if need_emcool then for i = 1, #self.tanks do - local session = self.tanks[i] ---@type unit_session - local tank = session.get_db() ---@type dynamicv_session_db + local session = self.tanks[i] + local tank = session.get_db() if tank.state.container_mode == CONTAINER_MODE.FILL then session.get_cmd_queue().push_data(DTV_RTU_S_DATA.SET_CONT_MODE, CONTAINER_MODE.BOTH) diff --git a/supervisor/panel/components/chk_entry.lua b/supervisor/panel/components/chk_entry.lua index ff4a24b..eebba3b 100644 --- a/supervisor/panel/components/chk_entry.lua +++ b/supervisor/panel/components/chk_entry.lua @@ -8,15 +8,15 @@ local style = require("supervisor.panel.style") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local TextBox = require("graphics.elements.TextBox") local ALIGN = core.ALIGN local cpair = core.cpair -- create an ID check list entry ----@param parent graphics_element parent +---@param parent ListBox parent ---@param msg string message ---@param fail_code integer failure code local function init(parent, msg, fail_code) diff --git a/supervisor/panel/components/pdg_entry.lua b/supervisor/panel/components/pdg_entry.lua index de68b8c..d160ef3 100644 --- a/supervisor/panel/components/pdg_entry.lua +++ b/supervisor/panel/components/pdg_entry.lua @@ -8,17 +8,17 @@ local style = require("supervisor.panel.style") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local TextBox = require("graphics.elements.TextBox") -local DataIndicator = require("graphics.elements.indicators.data") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") local ALIGN = core.ALIGN local cpair = core.cpair -- create a pocket diagnostics list entry ----@param parent graphics_element parent +---@param parent ListBox parent ---@param id integer PDG session ID local function init(parent, id) local s_hi_box = style.theme.highlight_box diff --git a/supervisor/panel/components/rtu_entry.lua b/supervisor/panel/components/rtu_entry.lua index edb9b3e..4ca4058 100644 --- a/supervisor/panel/components/rtu_entry.lua +++ b/supervisor/panel/components/rtu_entry.lua @@ -8,17 +8,17 @@ local style = require("supervisor.panel.style") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local TextBox = require("graphics.elements.TextBox") -local DataIndicator = require("graphics.elements.indicators.data") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") local ALIGN = core.ALIGN local cpair = core.cpair -- create an RTU list entry ----@param parent graphics_element parent +---@param parent ListBox parent ---@param id integer RTU session ID local function init(parent, id) local s_hi_box = style.theme.highlight_box diff --git a/supervisor/panel/front_panel.lua b/supervisor/panel/front_panel.lua index 245122e..845ed84 100644 --- a/supervisor/panel/front_panel.lua +++ b/supervisor/panel/front_panel.lua @@ -16,15 +16,15 @@ local rtu_entry = require("supervisor.panel.components.rtu_entry") local core = require("graphics.core") -local Div = require("graphics.elements.div") -local ListBox = require("graphics.elements.listbox") -local MultiPane = require("graphics.elements.multipane") -local TextBox = require("graphics.elements.textbox") +local Div = require("graphics.elements.Div") +local ListBox = require("graphics.elements.ListBox") +local MultiPane = require("graphics.elements.MultiPane") +local TextBox = require("graphics.elements.TextBox") -local TabBar = require("graphics.elements.controls.tabbar") +local TabBar = require("graphics.elements.controls.TabBar") -local LED = require("graphics.elements.indicators.led") -local DataIndicator = require("graphics.elements.indicators.data") +local LED = require("graphics.elements.indicators.LED") +local DataIndicator = require("graphics.elements.indicators.DataIndicator") local ALIGN = core.ALIGN @@ -33,7 +33,7 @@ local cpair = core.cpair local ind_grn = style.ind_grn -- create new front panel view ----@param panel graphics_element main displaybox +---@param panel DisplayBox main displaybox local function init(panel) local s_hi_box = style.theme.highlight_box local s_hi_bright = style.theme.highlight_box_bright diff --git a/supervisor/panel/pgi.lua b/supervisor/panel/pgi.lua index 2d8ee93..5eb35c6 100644 --- a/supervisor/panel/pgi.lua +++ b/supervisor/panel/pgi.lua @@ -8,23 +8,28 @@ local util = require("scada-common.util") local pgi = {} local data = { - rtu_list = nil, ---@type nil|graphics_element - pdg_list = nil, ---@type nil|graphics_element - chk_list = nil, ---@type nil|graphics_element - rtu_entry = nil, ---@type function - pdg_entry = nil, ---@type function - chk_entry = nil, ---@type function + rtu_list = nil, ---@type ListBox|nil + pdg_list = nil, ---@type ListBox|nil + chk_list = nil, ---@type ListBox|nil + rtu_entry = nil, ---@type function + pdg_entry = nil, ---@type function + chk_entry = nil, ---@type function -- list entries - entries = { rtu = {}, pdg = {}, chk = {}, missing = {} } + entries = { + rtu = {}, ---@type Div[] + pdg = {}, ---@type Div[] + chk = {}, ---@type Div[][] + missing = {} ---@type Div[] + } } -- link list boxes ----@param rtu_list graphics_element RTU list element ----@param rtu_entry function RTU entry constructor ----@param pdg_list graphics_element pocket diagnostics list element ----@param pdg_entry function pocket diagnostics entry constructor ----@param chk_list graphics_element CHK list element ----@param chk_entry function CHK entry constructor +---@param rtu_list ListBox RTU list element +---@param rtu_entry fun(parent: ListBox, id: integer) : Div RTU entry constructor +---@param pdg_list ListBox pocket diagnostics list element +---@param pdg_entry fun(parent: ListBox, id: integer) : Div pocket diagnostics entry constructor +---@param chk_list ListBox CHK list element +---@param chk_entry fun(parent: ListBox, msg: string, fail_code: integer) : Div CHK entry constructor function pgi.link_elements(rtu_list, rtu_entry, pdg_list, pdg_entry, chk_list, chk_entry) data.rtu_list = rtu_list data.pdg_list = pdg_list @@ -130,8 +135,8 @@ function pgi.create_chk_entry(unit, fail_code, msg) end end --- delete a device ID check failure entry from the CHK list ----@note this assumes only one type of failure can occur per each RTU gateway session's RTU, which is the case +-- delete a device ID check failure entry from the CHK list
+-- this assumes only one type of failure can occur per each RTU gateway session's RTU, which is the case ---@param unit unit_session RTU session function pgi.delete_chk_entry(unit) local gw_session = unit.get_session_id() diff --git a/supervisor/renderer.lua b/supervisor/renderer.lua index fde7fc3..57c6b4b 100644 --- a/supervisor/renderer.lua +++ b/supervisor/renderer.lua @@ -9,7 +9,7 @@ local style = require("supervisor.panel.style") local core = require("graphics.core") local flasher = require("graphics.flasher") -local DisplayBox = require("graphics.elements.displaybox") +local DisplayBox = require("graphics.elements.DisplayBox") ---@class supervisor_renderer local renderer = {} diff --git a/supervisor/session/coordinator.lua b/supervisor/session/coordinator.lua index 8b9c0d9..771e210 100644 --- a/supervisor/session/coordinator.lua +++ b/supervisor/session/coordinator.lua @@ -128,7 +128,7 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim local unit_builds = {} for i = 1, #self.units do - local unit = self.units[i] ---@type reactor_unit + local unit = self.units[i] unit_builds[unit.get_id()] = unit.get_build() end @@ -145,7 +145,7 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim local builds = {} for i = 1, #self.units do - local unit = self.units[i] ---@type reactor_unit + local unit = self.units[i] builds[unit.get_id()] = unit.get_build() end @@ -168,7 +168,7 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim local status = {} for i = 1, #self.units do - local unit = self.units[i] ---@type reactor_unit + local unit = self.units[i] status[unit.get_id()] = { unit.get_reactor_status(), @@ -308,7 +308,7 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim -- continue if valid unit id if util.is_int(uid) and uid > 0 and uid <= #self.units then - local unit = self.units[uid] ---@type reactor_unit + local unit = self.units[uid] local manual = facility.get_group(uid) == AUTO_GROUP.MANUAL if cmd == UNIT_COMMAND.SCRAM then @@ -432,8 +432,7 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim local unit_id = cmd.val local builds = {} - local unit = self.units[unit_id] ---@type reactor_unit - builds[unit_id] = unit.get_build(-1) + builds[unit_id] = self.units[unit_id].get_build(-1) _send(CRDN_TYPE.UNIT_BUILDS, { builds }) elseif cmd.key == CRD_S_DATA.RESEND_RTU_BUILD then @@ -446,8 +445,7 @@ function coordinator.new_session(id, s_addr, i_seq_num, in_queue, out_queue, tim local builds = {} - local unit = self.units[unit_id] ---@type reactor_unit - builds[unit_id] = unit.get_build(cmd.val.type) + builds[unit_id] = self.units[unit_id].get_build(cmd.val.type) _send(CRDN_TYPE.UNIT_BUILDS, { builds }) else diff --git a/supervisor/session/rsctl.lua b/supervisor/session/rsctl.lua index a369937..b270267 100644 --- a/supervisor/session/rsctl.lua +++ b/supervisor/session/rsctl.lua @@ -8,7 +8,7 @@ local rsctl = {} -- create a new redstone RTU I/O controller ---@nodiscard ----@param redstone_rtus table redstone RTU sessions +---@param redstone_rtus redstone_session[] redstone RTU sessions function rsctl.new(redstone_rtus) ---@class rs_controller local public = {} @@ -18,8 +18,7 @@ function rsctl.new(redstone_rtus) ---@return boolean function public.is_connected(port) for i = 1, #redstone_rtus do - local db = redstone_rtus[i].get_db() ---@type redstone_session_db - if db.io[port] ~= nil then return true end + if redstone_rtus[i].get_db().io[port] ~= nil then return true end end return false @@ -30,8 +29,7 @@ function rsctl.new(redstone_rtus) ---@param value boolean function public.digital_write(port, value) for i = 1, #redstone_rtus do - local db = redstone_rtus[i].get_db() ---@type redstone_session_db - local io = db.io[port] ---@type rs_db_dig_io|nil + local io = redstone_rtus[i].get_db().io[port] if io ~= nil then io.write(value) end end end @@ -42,9 +40,8 @@ function rsctl.new(redstone_rtus) ---@return boolean|nil function public.digital_read(port) for i = 1, #redstone_rtus do - local db = redstone_rtus[i].get_db() ---@type redstone_session_db - local io = db.io[port] ---@type rs_db_dig_io|nil - if io ~= nil then return io.read() end + local io = redstone_rtus[i].get_db().io[port] + if io ~= nil then return io.read() --[[@as boolean|nil]] end end end @@ -55,8 +52,7 @@ function rsctl.new(redstone_rtus) ---@param max number maximum value for scaling 0 to 15 function public.analog_write(port, value, min, max) for i = 1, #redstone_rtus do - local db = redstone_rtus[i].get_db() ---@type redstone_session_db - local io = db.io[port] ---@type rs_db_ana_io|nil + local io = redstone_rtus[i].get_db().io[port] if io ~= nil then io.write(rsio.analog_write(value, min, max)) end end end diff --git a/supervisor/session/rtu.lua b/supervisor/session/rtu.lua index 7d2494a..a38559c 100644 --- a/supervisor/session/rtu.lua +++ b/supervisor/session/rtu.lua @@ -63,7 +63,7 @@ function rtu.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, ad keep_alive = 0, alarm_tones = 0 }, - units = {} + units = {} ---@type unit_session[] } ---@class rtu_session @@ -80,13 +80,13 @@ function rtu.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, ad _reset_config() for i = 1, #self.fac_units do - local unit = self.fac_units[i] ---@type reactor_unit + local unit = self.fac_units[i] unit.purge_rtu_devices(id) facility.purge_rtu_devices(id) end for i = 1, #self.advert do - local unit = nil ---@type unit_session|nil + local unit = nil ---@type rtu_advertisement local unit_advert = { @@ -96,7 +96,7 @@ function rtu.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, ad rsio = self.advert[i][4] } - local u_type = unit_advert.type ---@type integer|boolean + local u_type = unit_advert.type ---@type RTU_UNIT_TYPE|boolean -- validate unit advertisement @@ -127,7 +127,7 @@ function rtu.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, ad log.debug(log_tag .. "_handle_advertisement(): advertisement unit validation failure") else if unit_advert.reactor > 0 then - local target_unit = self.fac_units[unit_advert.reactor] ---@type reactor_unit + local target_unit = self.fac_units[unit_advert.reactor] -- unit RTUs if u_type == RTU_UNIT_TYPE.REDSTONE then @@ -255,8 +255,7 @@ function rtu.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, ad if pkt.scada_frame.protocol() == PROTOCOL.MODBUS_TCP then ---@cast pkt modbus_frame if self.units[pkt.unit_id] ~= nil then - local unit = self.units[pkt.unit_id] ---@type unit_session - unit.handle_packet(pkt) + self.units[pkt.unit_id].handle_packet(pkt) end elseif pkt.scada_frame.protocol() == PROTOCOL.SCADA_MGMT then ---@cast pkt mgmt_frame @@ -298,8 +297,7 @@ function rtu.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout, ad if pkt.length == 1 then local unit_id = pkt.data[1] if self.units[unit_id] ~= nil then - local unit = self.units[unit_id] ---@type unit_session - unit.invalidate_cache() + self.units[unit_id].invalidate_cache() end else log.debug(log_tag .. "SCADA RTU GW device re-mount packet length mismatch") diff --git a/supervisor/session/rtu/boilerv.lua b/supervisor/session/rtu/boilerv.lua index 26a8f2d..a1a1a99 100644 --- a/supervisor/session/rtu/boilerv.lua +++ b/supervisor/session/rtu/boilerv.lua @@ -99,6 +99,7 @@ function boilerv.new(session_id, unit_id, advert, out_queue) } } + ---@class boilerv_session:unit_session local public = self.session.get() -- PRIVATE FUNCTIONS -- diff --git a/supervisor/session/rtu/dynamicv.lua b/supervisor/session/rtu/dynamicv.lua index 13239a7..0c06d7b 100644 --- a/supervisor/session/rtu/dynamicv.lua +++ b/supervisor/session/rtu/dynamicv.lua @@ -84,7 +84,7 @@ function dynamicv.new(session_id, unit_id, advert, out_queue) }, state = { last_update = 0, - container_mode = CONTAINER_MODE.BOTH ---@type container_mode + container_mode = CONTAINER_MODE.BOTH ---@type container_mode }, tanks = { last_update = 0, @@ -94,6 +94,7 @@ function dynamicv.new(session_id, unit_id, advert, out_queue) } } + ---@class dynamicv_session:unit_session local public = self.session.get() -- PRIVATE FUNCTIONS -- @@ -224,7 +225,7 @@ function dynamicv.new(session_id, unit_id, advert, out_queue) end elseif msg.qtype == mqueue.TYPE.DATA then -- instruction with body - local cmd = msg.message ---@type queue_data + local cmd = msg.message ---@type queue_data if cmd.key == DTV_RTU_S_DATA.SET_CONT_MODE then if cmd.val == types.CONTAINER_MODE.BOTH or cmd.val == types.CONTAINER_MODE.FILL or diff --git a/supervisor/session/rtu/envd.lua b/supervisor/session/rtu/envd.lua index 046ef0a..269975a 100644 --- a/supervisor/session/rtu/envd.lua +++ b/supervisor/session/rtu/envd.lua @@ -52,6 +52,7 @@ function envd.new(session_id, unit_id, advert, out_queue) } } + ---@class envd_session:unit_session local public = self.session.get() -- PRIVATE FUNCTIONS -- diff --git a/supervisor/session/rtu/imatrix.lua b/supervisor/session/rtu/imatrix.lua index 84bfc1e..aa7a984 100644 --- a/supervisor/session/rtu/imatrix.lua +++ b/supervisor/session/rtu/imatrix.lua @@ -83,6 +83,7 @@ function imatrix.new(session_id, unit_id, advert, out_queue) } } + ---@class imatrix_session:unit_session local public = self.session.get() -- PRIVATE FUNCTIONS -- diff --git a/supervisor/session/rtu/redstone.lua b/supervisor/session/rtu/redstone.lua index b99c0d9..ce9d6c4 100644 --- a/supervisor/session/rtu/redstone.lua +++ b/supervisor/session/rtu/redstone.lua @@ -39,9 +39,13 @@ local PERIODICS = { OUTPUT_SYNC = 200 } ----@class phy_entry ----@field phy IO_LVL ----@field req IO_LVL +---@class dig_phy_entry +---@field phy IO_LVL actual value +---@field req IO_LVL commanded value + +---@class ana_phy_entry +---@field phy number actual value +---@field req number commanded value -- create a new redstone rtu session runner ---@nodiscard @@ -72,27 +76,29 @@ function redstone.new(session_id, unit_id, advert, out_queue) }, ---@class rs_io_list io_list = { - digital_in = {}, -- discrete inputs - digital_out = {}, -- coils - analog_in = {}, -- input registers - analog_out = {} -- holding registers + digital_in = {}, ---@type IO_PORT[] discrete inputs + digital_out = {}, ---@type IO_PORT[] coils + analog_in = {}, ---@type IO_PORT[] input registers + analog_out = {} ---@type IO_PORT[] holding registers }, phy_trans = { coils = -1, hold_regs = -1 }, -- last set/read ports (reflecting the current state of the RTU) ---@class rs_io_states phy_io = { - digital_in = {}, -- discrete inputs - digital_out = {}, -- coils - analog_in = {}, -- input registers - analog_out = {} -- holding registers + digital_in = {}, ---@type dig_phy_entry[] discrete inputs + digital_out = {}, ---@type dig_phy_entry[] coils + analog_in = {}, ---@type ana_phy_entry[] input registers + analog_out = {} ---@type ana_phy_entry[] holding registers }, ---@class redstone_session_db db = { -- read/write functions for connected I/O + ---@type (rs_db_dig_io|rs_db_ana_io)[] io = {} } } + ---@class redstone_session:unit_session local public = self.session.get() -- INITIALIZE -- diff --git a/supervisor/session/rtu/sna.lua b/supervisor/session/rtu/sna.lua index a75e185..7e0fc34 100644 --- a/supervisor/session/rtu/sna.lua +++ b/supervisor/session/rtu/sna.lua @@ -74,6 +74,7 @@ function sna.new(session_id, unit_id, advert, out_queue) } } + ---@class sna_session:unit_session local public = self.session.get() -- PRIVATE FUNCTIONS -- diff --git a/supervisor/session/rtu/sps.lua b/supervisor/session/rtu/sps.lua index a631e58..1dacd61 100644 --- a/supervisor/session/rtu/sps.lua +++ b/supervisor/session/rtu/sps.lua @@ -88,6 +88,7 @@ function sps.new(session_id, unit_id, advert, out_queue) } } + ---@class sps_session:unit_session local public = self.session.get() -- PRIVATE FUNCTIONS -- diff --git a/supervisor/session/rtu/turbinev.lua b/supervisor/session/rtu/turbinev.lua index 4541e56..3581884 100644 --- a/supervisor/session/rtu/turbinev.lua +++ b/supervisor/session/rtu/turbinev.lua @@ -95,7 +95,7 @@ function turbinev.new(session_id, unit_id, advert, out_queue) flow_rate = 0, prod_rate = 0, steam_input_rate = 0, - dumping_mode = DUMPING_MODE.IDLE ---@type dumping_mode + dumping_mode = DUMPING_MODE.IDLE ---@type dumping_mode }, tanks = { last_update = 0, @@ -109,6 +109,7 @@ function turbinev.new(session_id, unit_id, advert, out_queue) } } + ---@class turbinev_session:unit_session local public = self.session.get() -- PRIVATE FUNCTIONS -- @@ -254,7 +255,7 @@ function turbinev.new(session_id, unit_id, advert, out_queue) end elseif msg.qtype == mqueue.TYPE.DATA then -- instruction with body - local cmd = msg.message ---@type queue_data + local cmd = msg.message ---@type queue_data if cmd.key == TBV_RTU_S_DATA.SET_DUMP_MODE then if cmd.val == types.DUMPING_MODE.IDLE or cmd.val == types.DUMPING_MODE.DUMPING_EXCESS or diff --git a/supervisor/session/rtu/txnctrl.lua b/supervisor/session/rtu/txnctrl.lua index 25ab3ed..cb8de47 100644 --- a/supervisor/session/rtu/txnctrl.lua +++ b/supervisor/session/rtu/txnctrl.lua @@ -6,7 +6,8 @@ local util = require("scada-common.util") local txnctrl = {} -local TIMEOUT = 2000 -- 2000ms max wait +-- 2000ms max wait +local TIMEOUT = 2000 -- create a new transaction controller ---@nodiscard diff --git a/supervisor/session/rtu/unit_session.lua b/supervisor/session/rtu/unit_session.lua index 4f516c8..632890b 100644 --- a/supervisor/session/rtu/unit_session.lua +++ b/supervisor/session/rtu/unit_session.lua @@ -29,7 +29,7 @@ unit_session.RTU_US_DATA = RTU_US_DATA ---@param advert rtu_advertisement RTU advertisement for this unit ---@param out_queue mqueue send queue ---@param log_tag string logging tag ----@param txn_tags table transaction log tags +---@param txn_tags string[] transaction log tags function unit_session.new(session_id, unit_id, advert, out_queue, log_tag, txn_tags) local self = { device_index = advert.index, @@ -52,7 +52,7 @@ function unit_session.new(session_id, unit_id, advert, out_queue, log_tag, txn_t -- send a MODBUS message, creating a transaction in the process ---@param txn_type integer transaction type ---@param f_code MODBUS_FCODE function code - ---@param register_param table register range or register and values + ---@param register_param (number|string)[] register range or register and values ---@return integer txn_id transaction ID of this transaction function protected.send_request(txn_type, f_code, register_param) local m_pkt = comms.modbus_packet() @@ -164,7 +164,6 @@ function unit_session.new(session_id, unit_id, advert, out_queue, log_tag, txn_t function public.get_cmd_queue() return protected.in_q end -- close this unit - ---@nodiscard function public.close() self.connected = false end -- check if this unit is connected ---@nodiscard diff --git a/supervisor/session/svsessions.lua b/supervisor/session/svsessions.lua index 30ef729..6090eff 100644 --- a/supervisor/session/svsessions.lua +++ b/supervisor/session/svsessions.lua @@ -40,13 +40,26 @@ local SESSION_TYPE = { svsessions.SESSION_TYPE = SESSION_TYPE local self = { - nic = nil, ---@type nic|nil + -- references to supervisor state and other data + nic = nil, ---@type nic|nil fp_ok = false, - config = nil, ---@type svr_config - facility = nil, ---@type facility|nil - sessions = { rtu = {}, plc = {}, crd = {}, pdg = {} }, + config = nil, ---@type svr_config + facility = nil, ---@type facility|nil + -- lists of connected sessions + sessions = { + rtu = {}, ---@type rtu_session_struct + plc = {}, ---@type plc_session_struct + crd = {}, ---@type crd_session_struct + pdg = {} ---@type pdg_session_struct + }, + -- next session IDs next_ids = { rtu = 0, plc = 0, crd = 0, pdg = 0 }, - dev_dbg = { duplicate = {}, out_of_range = {}, connected = {} } + -- rtu device tracking and invalid assignment detection + dev_dbg = { + duplicate = {}, ---@type unit_session[] + out_of_range = {}, ---@type unit_session[] + connected = {} ---@type { induction: boolean, sps: boolean, tanks: boolean[], units: unit_connections[] } + } } ---@alias sv_session_structs plc_session_struct|rtu_session_struct|crd_session_struct|pdg_session_struct @@ -119,10 +132,10 @@ local function _sv_handle_outq(session) end -- iterate all the given sessions ----@param sessions table +---@param sessions sv_session_structs[] local function _iterate(sessions) for i = 1, #sessions do - local session = sessions[i] ---@type sv_session_structs + local session = sessions[i] if session.open and session.instance.iterate() then _sv_handle_outq(session) @@ -150,20 +163,20 @@ local function _shutdown(session) end -- close connections ----@param sessions table +---@param sessions sv_session_structs[] local function _close(sessions) for i = 1, #sessions do - local session = sessions[i] ---@type sv_session_structs + local session = sessions[i] if session.open then _shutdown(session) end end end -- check if a watchdog timer event matches that of one of the provided sessions ----@param sessions table +---@param sessions sv_session_structs[] ---@param timer_event number local function _check_watchdogs(sessions, timer_event) for i = 1, #sessions do - local session = sessions[i] ---@type sv_session_structs + local session = sessions[i] if session.open then local triggered = session.instance.check_wd(timer_event) if triggered then @@ -175,8 +188,9 @@ local function _check_watchdogs(sessions, timer_event) end -- delete any closed sessions ----@param sessions table +---@param sessions sv_session_structs[] local function _free_closed(sessions) + ---@param session sv_session_structs local f = function (session) return session.open end ---@param session sv_session_structs @@ -189,7 +203,7 @@ end -- find a session by computer ID ---@nodiscard ----@param list table +---@param list sv_session_structs[] ---@param s_addr integer ---@return sv_session_structs|nil local function _find_session(list, s_addr) @@ -273,7 +287,7 @@ end -- on attempted link of an RTU to a facility or unit object, verify its ID and report a problem if it can't be accepted ---@param unit unit_session RTU session ----@param list table table of RTU sessions +---@param list unit_session[] table of RTU sessions ---@param max integer max of this type of RTU ---@return RTU_ID_FAIL fail_code, string fail_str function svsessions.check_rtu_id(unit, list, max) @@ -366,7 +380,7 @@ function svsessions.init(nic, fp_ok, config, facility) for i = 1, config.UnitCount do local r_cool = cool_conf.r_cool[i] - local conns = { boilers = {}, turbines = {}, tanks = {} } + local conns = { boilers = {}, turbines = {}, tanks = {} } ---@type unit_connections for b = 1, r_cool.BoilerCount do conns.boilers[b] = true end for t = 1, r_cool.TurbineCount do conns.turbines[t] = true end @@ -633,8 +647,8 @@ function svsessions.iterate_all() -- iterate sessions for _, list in pairs(self.sessions) do _iterate(list) end - -- report RTU sessions to facility - self.facility.report_rtus(self.sessions.rtu) + -- report RTU gateway sessions to facility + self.facility.report_rtu_gateways(self.sessions.rtu) -- iterate facility self.facility.update() diff --git a/supervisor/startup.lua b/supervisor/startup.lua index 4f6726c..08a1a89 100644 --- a/supervisor/startup.lua +++ b/supervisor/startup.lua @@ -22,7 +22,7 @@ local supervisor = require("supervisor.supervisor") local svsessions = require("supervisor.session.svsessions") -local SUPERVISOR_VERSION = "v1.5.3" +local SUPERVISOR_VERSION = "v1.5.4" local println = util.println local println_ts = util.println_ts @@ -157,6 +157,7 @@ local function main() if type ~= nil and device ~= nil then if type == "modem" then + ---@cast device Modem -- we only care if this is our wireless modem if nic.is_modem(device) then nic.disconnect() @@ -181,6 +182,7 @@ local function main() if type ~= nil and device ~= nil then if type == "modem" then + ---@cast device Modem if device.isWireless() and not nic.is_connected() then -- reconnected modem nic.connect(device) diff --git a/supervisor/unit.lua b/supervisor/unit.lua index 3290af0..16f065a 100644 --- a/supervisor/unit.lua +++ b/supervisor/unit.lua @@ -81,13 +81,13 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) num_turbines = num_turbines, types = { DT_KEYS = DT_KEYS, AISTATE = AISTATE }, -- rtus - rtu_list = {}, - redstone = {}, - boilers = {}, - turbines = {}, - tanks = {}, - snas = {}, - envd = {}, + rtu_list = {}, ---@type unit_session[][] + redstone = {}, ---@type redstone_session[] + boilers = {}, ---@type boilerv_session[] + turbines = {}, ---@type turbinev_session[] + tanks = {}, ---@type dynamicv_session[] + snas = {}, ---@type sna_session[] + envd = {}, ---@type envd_session[] -- redstone control io_ctl = nil, ---@type rs_controller valves = {}, ---@type unit_valves @@ -100,7 +100,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) auto_was_alarmed = false, ramp_target_br100 = 0, -- state tracking - deltas = {}, + deltas = {}, ---@type { last_t: number, last_v: number, dt: number }[] last_heartbeat = 0, last_radiation = 0, damage_decreasing = false, @@ -108,12 +108,12 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) damage_start = 0, damage_last = 0, damage_est_last = 0, - waste_product = WASTE.PLUTONIUM, ---@type WASTE_PRODUCT + waste_product = WASTE.PLUTONIUM, ---@type WASTE_PRODUCT status_text = { "UNKNOWN", "awaiting connection..." }, -- logic for alarms had_reactor = false, turbine_flow_stable = false, - turbine_stability_data = {}, + turbine_stability_data = {}, ---@type { time_state: integer, time_tanks: integer, rotation: number, input_rate: integer }[] last_rate_change_ms = 0, ---@type rps_status last_rps_trips = { @@ -154,7 +154,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) waste = 0, high_temp_lim = 1150 }, - ---@class alarm_monitors + ---@type { [string]: alarm_def } alarms = { -- reactor lost under the condition of meltdown imminent ContainmentBreach = { state = AISTATE.INACTIVE, trip_time = 0, hold_time = 0, id = ALARM.ContainmentBreach, tier = PRIO.CRITICAL }, @@ -211,17 +211,17 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) SteamFeedMismatch = false, MaxWaterReturnFeed = false, -- boilers - BoilerOnline = {}, - HeatingRateLow = {}, - WaterLevelLow = {}, + BoilerOnline = {}, ---@type boolean[] + HeatingRateLow = {}, ---@type boolean[] + WaterLevelLow = {}, ---@type boolean[] -- turbines - TurbineOnline = {}, - SteamDumpOpen = {}, - TurbineOverSpeed = {}, - GeneratorTrip = {}, - TurbineTrip = {} + TurbineOnline = {}, ---@type boolean[] + SteamDumpOpen = {}, ---@type integer[] + TurbineOverSpeed = {}, ---@type boolean[] + GeneratorTrip = {}, ---@type boolean[] + TurbineTrip = {} ---@type boolean[] }, - ---@class alarms + ---@type { [ALARM]: ALARM_STATE } alarm_states = { ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, @@ -244,7 +244,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) blade_count = 0, br100 = 0, lim_br100 = 0, - waste_mode = WASTE_MODE.AUTO ---@type WASTE_MODE + waste_mode = WASTE_MODE.AUTO ---@type WASTE_MODE } } } @@ -324,8 +324,8 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) end for i = 1, #self.boilers do - local boiler = self.boilers[i] ---@type unit_session - local db = boiler.get_db() ---@type boilerv_session_db + local boiler = self.boilers[i] + local db = boiler.get_db() local last_update_s = db.tanks.last_update / 1000.0 @@ -336,8 +336,8 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) end for i = 1, #self.turbines do - local turbine = self.turbines[i] ---@type unit_session - local db = turbine.get_db() ---@type turbinev_session_db + local turbine = self.turbines[i] + local db = turbine.get_db() local last_update_s = db.tanks.last_update / 1000.0 @@ -553,8 +553,8 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) -- check boilers formed/faulted for i = 1, #self.boilers do - local sess = self.boilers[i] ---@type unit_session - local boiler = sess.get_db() ---@type boilerv_session_db + local sess = self.boilers[i] + local boiler = sess.get_db() if sess.is_faulted() or not boiler.formed then self.db.control.degraded = true end @@ -562,8 +562,8 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) -- check turbines formed/faulted for i = 1, #self.turbines do - local sess = self.turbines[i] ---@type unit_session - local turbine = sess.get_db() ---@type turbinev_session_db + local sess = self.turbines[i] + local turbine = sess.get_db() if sess.is_faulted() or not turbine.formed then self.db.control.degraded = true end @@ -881,7 +881,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) if all or (filter == RTU_UNIT_TYPE.BOILER_VALVE) then build.boilers = {} for i = 1, #self.boilers do - local boiler = self.boilers[i] ---@type unit_session + local boiler = self.boilers[i] build.boilers[boiler.get_device_idx()] = { boiler.get_db().formed, boiler.get_db().build } end end @@ -889,7 +889,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) if all or (filter == RTU_UNIT_TYPE.TURBINE_VALVE) then build.turbines = {} for i = 1, #self.turbines do - local turbine = self.turbines[i] ---@type unit_session + local turbine = self.turbines[i] build.turbines[turbine.get_device_idx()] = { turbine.get_db().formed, turbine.get_db().build } end end @@ -897,7 +897,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) if all or (filter == RTU_UNIT_TYPE.DYNAMIC_VALVE) then build.tanks = {} for i = 1, #self.tanks do - local tank = self.tanks[i] ---@type unit_session + local tank = self.tanks[i] build.tanks[tank.get_device_idx()] = { tank.get_db().formed, tank.get_db().build } end end @@ -927,6 +927,10 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) -- check which RTUs are connected ---@nodiscard function public.check_rtu_conns() + ---@class unit_connections + ---@field boilers boolean[] + ---@field turbines boolean[] + ---@field tanks boolean[] local conns = {} conns.boilers = {} @@ -955,31 +959,31 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) -- status of boilers (including tanks) status.boilers = {} for i = 1, #self.boilers do - local boiler = self.boilers[i] ---@type unit_session - local db = boiler.get_db() ---@type boilerv_session_db + local boiler = self.boilers[i] + local db = boiler.get_db() status.boilers[boiler.get_device_idx()] = { boiler.is_faulted(), db.formed, db.state, db.tanks } end -- status of turbines (including tanks) status.turbines = {} for i = 1, #self.turbines do - local turbine = self.turbines[i] ---@type unit_session - local db = turbine.get_db() ---@type turbinev_session_db + local turbine = self.turbines[i] + local db = turbine.get_db() status.turbines[turbine.get_device_idx()] = { turbine.is_faulted(), db.formed, db.state, db.tanks } end -- status of dynamic tanks status.tanks = {} for i = 1, #self.tanks do - local tank = self.tanks[i] ---@type unit_session - local db = tank.get_db() ---@type dynamicv_session_db + local tank = self.tanks[i] + local db = tank.get_db() status.tanks[tank.get_device_idx()] = { tank.is_faulted(), db.formed, db.state, db.tanks } end -- SNA statistical information local total_peak, total_avail, total_out = 0, 0, 0 for i = 1, #self.snas do - local db = self.snas[i].get_db() ---@type sna_session_db + local db = self.snas[i].get_db() total_peak = total_peak + db.state.peak_production total_avail = total_avail + db.state.production_rate total_out = total_out + math.min(db.tanks.input.amount / 10, db.state.production_rate) @@ -989,8 +993,8 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) -- radiation monitors (environment detectors) status.envds = {} for i = 1, #self.envd do - local envd = self.envd[i] ---@type unit_session - local db = envd.get_db() ---@type envd_session_db + local envd = self.envd[i] + local db = envd.get_db() status.envds[envd.get_device_idx()] = { envd.is_faulted(), db.radiation, db.radiation_raw } end @@ -1004,7 +1008,7 @@ function unit.new(reactor_id, num_boilers, num_turbines, ext_idle) local total_avail_rate = 0 for i = 1, #self.snas do - local db = self.snas[i].get_db() ---@type sna_session_db + local db = self.snas[i].get_db() total_avail_rate = total_avail_rate + db.state.production_rate end diff --git a/supervisor/unitlogic.lua b/supervisor/unitlogic.lua index b1e1fc8..f0e4c33 100644 --- a/supervisor/unitlogic.lua +++ b/supervisor/unitlogic.lua @@ -161,8 +161,8 @@ function logic.update_annunciator(self) local max_rad, any_faulted = 0, false for i = 1, #self.envd do - local envd = self.envd[i] ---@type unit_session - local db = envd.get_db() ---@type envd_session_db + local envd = self.envd[i] + local db = envd.get_db() any_faulted = any_faulted or envd.is_faulted() if db.radiation_raw > max_rad then max_rad = db.radiation_raw end end @@ -173,8 +173,7 @@ function logic.update_annunciator(self) annunc.EmergencyCoolant = 1 for i = 1, #self.redstone do - local db = self.redstone[i].get_db() ---@type redstone_session_db - local io = db.io[IO.U_EMER_COOL] ---@type rs_db_dig_io|nil + local io = self.redstone[i].get_db().io[IO.U_EMER_COOL] if io ~= nil then annunc.EmergencyCoolant = util.trinary(io.read(), 3, 2) break @@ -197,8 +196,8 @@ function logic.update_annunciator(self) if num_boilers > 0 then -- go through boilers for stats and online for i = 1, #self.boilers do - local session = self.boilers[i] ---@type unit_session - local boiler = session.get_db() ---@type boilerv_session_db + local session = self.boilers[i] + local boiler = session.get_db() local idx = session.get_device_idx() annunc.RCSFault = annunc.RCSFault or (not boiler.formed) or session.is_faulted() @@ -225,9 +224,9 @@ function logic.update_annunciator(self) -- check for inactive boilers while reactor is active for i = 1, #self.boilers do - local boiler = self.boilers[i] ---@type unit_session + local boiler = self.boilers[i] local idx = boiler.get_device_idx() - local db = boiler.get_db() ---@type boilerv_session_db + local db = boiler.get_db() if r_db.mek_status.status then annunc.HeatingRateLow[idx] = db.state.boil_rate == 0 @@ -250,9 +249,9 @@ function logic.update_annunciator(self) if num_boilers > 0 then for i = 1, #self.boilers do - local boiler = self.boilers[i] ---@type unit_session + local boiler = self.boilers[i] local idx = boiler.get_device_idx() - local db = boiler.get_db() ---@type boilerv_session_db + local db = boiler.get_db() local gaining_hc = _get_dt(DT_KEYS.BoilerHCool .. idx) > 10.0 or db.tanks.hcool_fill == 1 @@ -294,8 +293,8 @@ function logic.update_annunciator(self) -- go through turbines for stats and online for i = 1, #self.turbines do - local session = self.turbines[i] ---@type unit_session - local turbine = session.get_db() ---@type turbinev_session_db + local session = self.turbines[i] + local turbine = session.get_db() local idx = session.get_device_idx() annunc.RCSFault = annunc.RCSFault or (not turbine.formed) or session.is_faulted() @@ -380,8 +379,8 @@ function logic.update_annunciator(self) -- turbine safety checks for i = 1, #self.turbines do - local turbine = self.turbines[i] ---@type unit_session - local db = turbine.get_db() ---@type turbinev_session_db + local turbine = self.turbines[i] + local db = turbine.get_db() local idx = turbine.get_device_idx() -- check if steam dumps are open @@ -652,7 +651,7 @@ function logic.update_status_text(self) -- check if an alarm is active (tripped or ack'd) ---@nodiscard - ---@param alarm table alarm entry + ---@param alarm alarm_def alarm entry ---@return boolean active local function is_active(alarm) return alarm.state == AISTATE.TRIPPED or alarm.state == AISTATE.ACKED @@ -818,7 +817,7 @@ function logic.handle_redstone(self) -- check if an alarm is active (tripped or ack'd) ---@nodiscard - ---@param alarm table alarm entry + ---@param alarm alarm_def alarm entry ---@return boolean active local function is_active(alarm) return alarm.state == AISTATE.TRIPPED or alarm.state == AISTATE.ACKED @@ -904,8 +903,8 @@ function logic.handle_redstone(self) if not cache.rps_trip then -- set turbines to not dump steam for i = 1, #self.turbines do - local session = self.turbines[i] ---@type unit_session - local turbine = session.get_db() ---@type turbinev_session_db + local session = self.turbines[i] + local turbine = session.get_db() if turbine.state.dumping_mode ~= DUMPING_MODE.IDLE then session.get_cmd_queue().push_data(TBV_RTU_S_DATA.SET_DUMP_MODE, DUMPING_MODE.IDLE) @@ -921,8 +920,8 @@ function logic.handle_redstone(self) elseif enable_emer_cool or self.emcool_opened then -- set turbines to dump excess steam for i = 1, #self.turbines do - local session = self.turbines[i] ---@type unit_session - local turbine = session.get_db() ---@type turbinev_session_db + local session = self.turbines[i] + local turbine = session.get_db() if turbine.state.dumping_mode ~= DUMPING_MODE.DUMPING_EXCESS then session.get_cmd_queue().push_data(TBV_RTU_S_DATA.SET_DUMP_MODE, DUMPING_MODE.DUMPING_EXCESS) @@ -931,8 +930,8 @@ function logic.handle_redstone(self) -- make sure dynamic tanks are allowing outflow for i = 1, #self.tanks do - local session = self.tanks[i] ---@type unit_session - local tank = session.get_db() ---@type dynamicv_session_db + local session = self.tanks[i] + local tank = session.get_db() if tank.state.container_mode == CONTAINER_MODE.FILL then session.get_cmd_queue().push_data(DTV_RTU_S_DATA.SET_CONT_MODE, CONTAINER_MODE.BOTH)