mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#498 work on pocket control app and support process code
This commit is contained in:
parent
11e9c11cf7
commit
c299dce8ef
@ -8,6 +8,8 @@ local psil = require("scada-common.psil")
|
|||||||
local types = require("scada-common.types")
|
local types = require("scada-common.types")
|
||||||
local util = require("scada-common.util")
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
|
local process = require("pocket.process")
|
||||||
|
|
||||||
local ALARM = types.ALARM
|
local ALARM = types.ALARM
|
||||||
local ALARM_STATE = types.ALARM_STATE
|
local ALARM_STATE = types.ALARM_STATE
|
||||||
|
|
||||||
@ -38,6 +40,15 @@ local io = {
|
|||||||
ps = psil.create()
|
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 config = nil ---@type pkt_config
|
||||||
|
|
||||||
-- initialize facility-independent components of pocket iocontrol
|
-- initialize facility-independent components of pocket iocontrol
|
||||||
@ -91,6 +102,9 @@ function iocontrol.init_core(comms, nav, cfg)
|
|||||||
io.api = {
|
io.api = {
|
||||||
get_unit = function (unit) comms.api__get_unit(unit) end
|
get_unit = function (unit) comms.api__get_unit(unit) end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- pass IO control here since it can't be require'd due to a require loop
|
||||||
|
process.init(io, comms)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- initialize facility-dependent components of pocket iocontrol
|
-- initialize facility-dependent components of pocket iocontrol
|
||||||
@ -300,6 +314,20 @@ function iocontrol.init_fac(conf)
|
|||||||
-- auto control group
|
-- auto control group
|
||||||
a_group = 0,
|
a_group = 0,
|
||||||
|
|
||||||
|
start = function () process.start(i) end,
|
||||||
|
scram = function () process.scram(i) end,
|
||||||
|
reset_rps = function () process.reset_rps(i) end,
|
||||||
|
ack_alarms = function () process.ack_all_alarms(i) end,
|
||||||
|
set_burn = function (rate) process.set_rate(i, rate) end, ---@param rate number burn rate
|
||||||
|
set_waste = function (mode) process.set_unit_waste(i, mode) end, ---@param mode WASTE_MODE waste processing mode
|
||||||
|
|
||||||
|
set_group = function (grp) process.set_group(i, grp) end, ---@param grp integer|0 group ID or 0 for manual
|
||||||
|
|
||||||
|
start_ack = __generic_ack,
|
||||||
|
scram_ack = __generic_ack,
|
||||||
|
reset_rps_ack = __generic_ack,
|
||||||
|
ack_alarms_ack = __generic_ack,
|
||||||
|
|
||||||
---@type alarms
|
---@type alarms
|
||||||
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 },
|
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 },
|
||||||
|
|
||||||
@ -689,7 +717,7 @@ function iocontrol.record_unit_data(data)
|
|||||||
|
|
||||||
--#region Status Information Display
|
--#region Status Information Display
|
||||||
|
|
||||||
local ecam = {} -- aviation reference :) back to VATSIM I go...
|
local ecam = {} -- aviation reference :)
|
||||||
|
|
||||||
-- local function red(text) return { text = text, color = colors.red } end
|
-- local function red(text) return { text = text, color = colors.red } end
|
||||||
local function white(text) return { text = text, color = colors.white } end
|
local function white(text) return { text = text, color = colors.white } end
|
||||||
|
@ -9,6 +9,8 @@ local DEVICE_TYPE = comms.DEVICE_TYPE
|
|||||||
local ESTABLISH_ACK = comms.ESTABLISH_ACK
|
local ESTABLISH_ACK = comms.ESTABLISH_ACK
|
||||||
local MGMT_TYPE = comms.MGMT_TYPE
|
local MGMT_TYPE = comms.MGMT_TYPE
|
||||||
local CRDN_TYPE = comms.CRDN_TYPE
|
local CRDN_TYPE = comms.CRDN_TYPE
|
||||||
|
local UNIT_COMMAND = comms.UNIT_COMMAND
|
||||||
|
local FAC_COMMAND = comms.FAC_COMMAND
|
||||||
|
|
||||||
local LINK_STATE = iocontrol.LINK_STATE
|
local LINK_STATE = iocontrol.LINK_STATE
|
||||||
|
|
||||||
@ -84,13 +86,14 @@ local APP_ID = {
|
|||||||
LOADER = 2,
|
LOADER = 2,
|
||||||
-- main app pages
|
-- main app pages
|
||||||
UNITS = 3,
|
UNITS = 3,
|
||||||
GUIDE = 4,
|
CONTROL = 4,
|
||||||
ABOUT = 5,
|
GUIDE = 5,
|
||||||
|
ABOUT = 6,
|
||||||
-- diag app page
|
-- diag app page
|
||||||
ALARMS = 6,
|
ALARMS = 7,
|
||||||
-- other
|
-- other
|
||||||
DUMMY = 7,
|
DUMMY = 8,
|
||||||
NUM_APPS = 7
|
NUM_APPS = 8
|
||||||
}
|
}
|
||||||
|
|
||||||
pocket.APP_ID = APP_ID
|
pocket.APP_ID = APP_ID
|
||||||
@ -541,6 +544,29 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
|
|||||||
if self.api.linked then _send_api(CRDN_TYPE.API_GET_UNIT, { unit }) end
|
if self.api.linked then _send_api(CRDN_TYPE.API_GET_UNIT, { unit }) end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- send a facility command
|
||||||
|
---@param cmd FAC_COMMAND command
|
||||||
|
---@param option any? optional option options for the optional options (like waste mode)
|
||||||
|
function public.send_fac_command(cmd, option)
|
||||||
|
_send_api(CRDN_TYPE.FAC_CMD, { cmd, option })
|
||||||
|
end
|
||||||
|
|
||||||
|
-- send the auto process control configuration with a start command
|
||||||
|
---@param auto_cfg sys_auto_config configuration
|
||||||
|
function public.send_auto_start(auto_cfg)
|
||||||
|
_send_api(CRDN_TYPE.FAC_CMD, {
|
||||||
|
FAC_COMMAND.START, auto_cfg.mode, auto_cfg.burn_target, auto_cfg.charge_target, auto_cfg.gen_target, auto_cfg.limits
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- send a unit command
|
||||||
|
---@param cmd UNIT_COMMAND command
|
||||||
|
---@param unit integer unit ID
|
||||||
|
---@param option any? optional option options for the optional options (like burn rate)
|
||||||
|
function public.send_unit_command(cmd, unit, option)
|
||||||
|
_send_api(CRDN_TYPE.UNIT_CMD, { cmd, unit, option })
|
||||||
|
end
|
||||||
|
|
||||||
-- parse a packet
|
-- parse a packet
|
||||||
---@param side string
|
---@param side string
|
||||||
---@param sender integer
|
---@param sender integer
|
||||||
|
342
pocket/process.lua
Normal file
342
pocket/process.lua
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
--
|
||||||
|
-- Process Control Management
|
||||||
|
--
|
||||||
|
|
||||||
|
local comms = require("scada-common.comms")
|
||||||
|
local log = require("scada-common.log")
|
||||||
|
local types = require("scada-common.types")
|
||||||
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
|
local FAC_COMMAND = comms.FAC_COMMAND
|
||||||
|
local UNIT_COMMAND = comms.UNIT_COMMAND
|
||||||
|
|
||||||
|
local PROCESS = types.PROCESS
|
||||||
|
local PRODUCT = types.WASTE_PRODUCT
|
||||||
|
|
||||||
|
---@class pocket_process_controller
|
||||||
|
local process = {}
|
||||||
|
|
||||||
|
local self = {
|
||||||
|
io = nil, ---@type ioctl
|
||||||
|
comms = nil, ---@type pocket_comms
|
||||||
|
---@class sys_control_states
|
||||||
|
control_states = {
|
||||||
|
---@class sys_auto_config
|
||||||
|
process = {
|
||||||
|
mode = PROCESS.INACTIVE,
|
||||||
|
burn_target = 0.0,
|
||||||
|
charge_target = 0.0,
|
||||||
|
gen_target = 0.0,
|
||||||
|
limits = {},
|
||||||
|
waste_product = PRODUCT.PLUTONIUM,
|
||||||
|
pu_fallback = false,
|
||||||
|
sps_low_power = false
|
||||||
|
},
|
||||||
|
waste_modes = {},
|
||||||
|
priority_groups = {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
--------------------------
|
||||||
|
-- UNIT COMMAND CONTROL --
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
-- initialize the process controller
|
||||||
|
---@param iocontrol pocket_ioctl iocontrl system
|
||||||
|
---@param pocket_comms pocket_comms pocket communications
|
||||||
|
function process.init(iocontrol, pocket_comms)
|
||||||
|
self.io = iocontrol
|
||||||
|
self.comms = pocket_comms
|
||||||
|
|
||||||
|
local ctl_proc = self.control_states.process
|
||||||
|
|
||||||
|
for i = 1, self.io.facility.num_units do
|
||||||
|
ctl_proc.limits[i] = 0.1
|
||||||
|
end
|
||||||
|
|
||||||
|
local ctrl_states = settings.get("ControlStates", {})
|
||||||
|
local config = ctrl_states.process ---@type sys_auto_config
|
||||||
|
|
||||||
|
-- facility auto control configuration
|
||||||
|
if type(config) == "table" then
|
||||||
|
ctl_proc.mode = config.mode
|
||||||
|
ctl_proc.burn_target = config.burn_target
|
||||||
|
ctl_proc.charge_target = config.charge_target
|
||||||
|
ctl_proc.gen_target = config.gen_target
|
||||||
|
ctl_proc.limits = config.limits
|
||||||
|
ctl_proc.waste_product = config.waste_product
|
||||||
|
ctl_proc.pu_fallback = config.pu_fallback
|
||||||
|
ctl_proc.sps_low_power = config.sps_low_power
|
||||||
|
|
||||||
|
self.io.facility.ps.publish("process_mode", ctl_proc.mode)
|
||||||
|
self.io.facility.ps.publish("process_burn_target", ctl_proc.burn_target)
|
||||||
|
self.io.facility.ps.publish("process_charge_target", self.io.energy_convert_from_fe(ctl_proc.charge_target))
|
||||||
|
self.io.facility.ps.publish("process_gen_target", self.io.energy_convert_from_fe(ctl_proc.gen_target))
|
||||||
|
self.io.facility.ps.publish("process_waste_product", ctl_proc.waste_product)
|
||||||
|
self.io.facility.ps.publish("process_pu_fallback", ctl_proc.pu_fallback)
|
||||||
|
self.io.facility.ps.publish("process_sps_low_power", ctl_proc.sps_low_power)
|
||||||
|
|
||||||
|
for id = 1, math.min(#ctl_proc.limits, self.io.facility.num_units) do
|
||||||
|
local unit = self.io.units[id] ---@type ioctl_unit
|
||||||
|
unit.unit_ps.publish("burn_limit", ctl_proc.limits[id])
|
||||||
|
end
|
||||||
|
|
||||||
|
log.info("PROCESS: loaded auto control settings")
|
||||||
|
|
||||||
|
-- notify supervisor of auto waste config
|
||||||
|
self.comms.send_fac_command(FAC_COMMAND.SET_WASTE_MODE, ctl_proc.waste_product)
|
||||||
|
self.comms.send_fac_command(FAC_COMMAND.SET_PU_FB, ctl_proc.pu_fallback)
|
||||||
|
self.comms.send_fac_command(FAC_COMMAND.SET_SPS_LP, ctl_proc.sps_low_power)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- unit waste states
|
||||||
|
local waste_modes = ctrl_states.waste_modes ---@type table|nil
|
||||||
|
if type(waste_modes) == "table" then
|
||||||
|
for id, mode in pairs(waste_modes) do
|
||||||
|
self.control_states.waste_modes[id] = mode
|
||||||
|
self.comms.send_unit_command(UNIT_COMMAND.SET_WASTE, id, mode)
|
||||||
|
end
|
||||||
|
|
||||||
|
log.info("PROCESS: loaded unit waste mode settings")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- unit priority groups
|
||||||
|
local prio_groups = ctrl_states.priority_groups ---@type table|nil
|
||||||
|
if type(prio_groups) == "table" then
|
||||||
|
for id, group in pairs(prio_groups) do
|
||||||
|
self.control_states.priority_groups[id] = group
|
||||||
|
self.comms.send_unit_command(UNIT_COMMAND.SET_GROUP, id, group)
|
||||||
|
end
|
||||||
|
|
||||||
|
log.info("PROCESS: loaded priority groups settings")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function process.init_fac_data()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- facility SCRAM command
|
||||||
|
function process.fac_scram()
|
||||||
|
self.comms.send_fac_command(FAC_COMMAND.SCRAM_ALL)
|
||||||
|
log.debug("PROCESS: FAC SCRAM ALL")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- facility alarm acknowledge command
|
||||||
|
function process.fac_ack_alarms()
|
||||||
|
self.comms.send_fac_command(FAC_COMMAND.ACK_ALL_ALARMS)
|
||||||
|
log.debug("PROCESS: FAC ACK ALL ALARMS")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- start reactor
|
||||||
|
---@param id integer unit ID
|
||||||
|
function process.start(id)
|
||||||
|
self.io.units[id].control_state = true
|
||||||
|
self.comms.send_unit_command(UNIT_COMMAND.START, id)
|
||||||
|
log.debug(util.c("PROCESS: UNIT[", id, "] START"))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- SCRAM reactor
|
||||||
|
---@param id integer unit ID
|
||||||
|
function process.scram(id)
|
||||||
|
self.io.units[id].control_state = false
|
||||||
|
self.comms.send_unit_command(UNIT_COMMAND.SCRAM, id)
|
||||||
|
log.debug(util.c("PROCESS: UNIT[", id, "] SCRAM"))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- reset reactor protection system
|
||||||
|
---@param id integer unit ID
|
||||||
|
function process.reset_rps(id)
|
||||||
|
self.comms.send_unit_command(UNIT_COMMAND.RESET_RPS, id)
|
||||||
|
log.debug(util.c("PROCESS: UNIT[", id, "] RESET RPS"))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- set burn rate
|
||||||
|
---@param id integer unit ID
|
||||||
|
---@param rate number burn rate
|
||||||
|
function process.set_rate(id, rate)
|
||||||
|
self.comms.send_unit_command(UNIT_COMMAND.SET_BURN, id, rate)
|
||||||
|
log.debug(util.c("PROCESS: UNIT[", id, "] SET BURN ", rate))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- set waste mode
|
||||||
|
---@param id integer unit ID
|
||||||
|
---@param mode integer waste mode
|
||||||
|
function process.set_unit_waste(id, mode)
|
||||||
|
-- publish so that if it fails then it gets reset
|
||||||
|
self.io.units[id].unit_ps.publish("U_WasteMode", mode)
|
||||||
|
|
||||||
|
self.comms.send_unit_command(UNIT_COMMAND.SET_WASTE, id, mode)
|
||||||
|
log.debug(util.c("PROCESS: UNIT[", id, "] SET WASTE ", mode))
|
||||||
|
|
||||||
|
self.control_states.waste_modes[id] = mode
|
||||||
|
settings.set("ControlStates", self.control_states)
|
||||||
|
|
||||||
|
if not settings.save("/coordinator.settings") then
|
||||||
|
log.error("process.set_unit_waste(): failed to save coordinator settings file")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- acknowledge all alarms
|
||||||
|
---@param id integer unit ID
|
||||||
|
function process.ack_all_alarms(id)
|
||||||
|
self.comms.send_unit_command(UNIT_COMMAND.ACK_ALL_ALARMS, id)
|
||||||
|
log.debug(util.c("PROCESS: UNIT[", id, "] ACK ALL ALARMS"))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- acknowledge an alarm
|
||||||
|
---@param id integer unit ID
|
||||||
|
---@param alarm integer alarm ID
|
||||||
|
function process.ack_alarm(id, alarm)
|
||||||
|
self.comms.send_unit_command(UNIT_COMMAND.ACK_ALARM, id, alarm)
|
||||||
|
log.debug(util.c("PROCESS: UNIT[", id, "] ACK ALARM ", alarm))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- reset an alarm
|
||||||
|
---@param id integer unit ID
|
||||||
|
---@param alarm integer alarm ID
|
||||||
|
function process.reset_alarm(id, alarm)
|
||||||
|
self.comms.send_unit_command(UNIT_COMMAND.RESET_ALARM, id, alarm)
|
||||||
|
log.debug(util.c("PROCESS: UNIT[", id, "] RESET ALARM ", alarm))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- assign a unit to a group
|
||||||
|
---@param unit_id integer unit ID
|
||||||
|
---@param group_id integer|0 group ID or 0 for independent
|
||||||
|
function process.set_group(unit_id, group_id)
|
||||||
|
self.comms.send_unit_command(UNIT_COMMAND.SET_GROUP, unit_id, group_id)
|
||||||
|
log.debug(util.c("PROCESS: UNIT[", unit_id, "] SET GROUP ", group_id))
|
||||||
|
|
||||||
|
self.control_states.priority_groups[unit_id] = group_id
|
||||||
|
settings.set("ControlStates", self.control_states)
|
||||||
|
|
||||||
|
if not settings.save("/coordinator.settings") then
|
||||||
|
log.error("process.set_group(): failed to save coordinator settings file")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------
|
||||||
|
-- AUTO PROCESS CONTROL --
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
-- write auto process control to config file
|
||||||
|
local function _write_auto_config()
|
||||||
|
-- save config
|
||||||
|
settings.set("ControlStates", self.control_states)
|
||||||
|
local saved = settings.save("/coordinator.settings")
|
||||||
|
if not saved then
|
||||||
|
log.warning("process._write_auto_config(): failed to save coordinator settings file")
|
||||||
|
end
|
||||||
|
|
||||||
|
return saved
|
||||||
|
end
|
||||||
|
|
||||||
|
-- stop automatic process control
|
||||||
|
function process.stop_auto()
|
||||||
|
self.comms.send_fac_command(FAC_COMMAND.STOP)
|
||||||
|
log.debug("PROCESS: STOP AUTO CTL")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- start automatic process control
|
||||||
|
function process.start_auto()
|
||||||
|
self.comms.send_auto_start(self.control_states.process)
|
||||||
|
log.debug("PROCESS: START AUTO CTL")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- set automatic process control waste mode
|
||||||
|
---@param product WASTE_PRODUCT waste product for auto control
|
||||||
|
function process.set_process_waste(product)
|
||||||
|
self.comms.send_fac_command(FAC_COMMAND.SET_WASTE_MODE, product)
|
||||||
|
|
||||||
|
log.debug(util.c("PROCESS: SET WASTE ", product))
|
||||||
|
|
||||||
|
-- update config table and save
|
||||||
|
self.control_states.process.waste_product = product
|
||||||
|
_write_auto_config()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- set automatic process control plutonium fallback
|
||||||
|
---@param enabled boolean whether to enable plutonium fallback
|
||||||
|
function process.set_pu_fallback(enabled)
|
||||||
|
self.comms.send_fac_command(FAC_COMMAND.SET_PU_FB, enabled)
|
||||||
|
|
||||||
|
log.debug(util.c("PROCESS: SET PU FALLBACK ", enabled))
|
||||||
|
|
||||||
|
-- update config table and save
|
||||||
|
self.control_states.process.pu_fallback = enabled
|
||||||
|
_write_auto_config()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- set automatic process control SPS usage at low power
|
||||||
|
---@param enabled boolean whether to enable SPS usage at low power
|
||||||
|
function process.set_sps_low_power(enabled)
|
||||||
|
self.comms.send_fac_command(FAC_COMMAND.SET_SPS_LP, enabled)
|
||||||
|
|
||||||
|
log.debug(util.c("PROCESS: SET SPS LOW POWER ", enabled))
|
||||||
|
|
||||||
|
-- update config table and save
|
||||||
|
self.control_states.process.sps_low_power = enabled
|
||||||
|
_write_auto_config()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- save process control settings
|
||||||
|
---@param mode PROCESS control mode
|
||||||
|
---@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
|
||||||
|
function process.save(mode, burn_target, charge_target, gen_target, limits)
|
||||||
|
log.debug("PROCESS: SAVE")
|
||||||
|
|
||||||
|
-- update config table
|
||||||
|
local ctl_proc = self.control_states.process
|
||||||
|
ctl_proc.mode = mode
|
||||||
|
ctl_proc.burn_target = burn_target
|
||||||
|
ctl_proc.charge_target = charge_target
|
||||||
|
ctl_proc.gen_target = gen_target
|
||||||
|
ctl_proc.limits = limits
|
||||||
|
|
||||||
|
-- save config
|
||||||
|
self.io.facility.save_cfg_ack(_write_auto_config())
|
||||||
|
end
|
||||||
|
|
||||||
|
-- handle a start command acknowledgement
|
||||||
|
---@param response table ack and configuration reply
|
||||||
|
function process.start_ack_handle(response)
|
||||||
|
local ack = response[1]
|
||||||
|
|
||||||
|
local ctl_proc = self.control_states.process
|
||||||
|
ctl_proc.mode = response[2]
|
||||||
|
ctl_proc.burn_target = response[3]
|
||||||
|
ctl_proc.charge_target = response[4]
|
||||||
|
ctl_proc.gen_target = response[5]
|
||||||
|
|
||||||
|
for i = 1, math.min(#response[6], self.io.facility.num_units) do
|
||||||
|
ctl_proc.limits[i] = response[6][i]
|
||||||
|
|
||||||
|
local unit = self.io.units[i] ---@type ioctl_unit
|
||||||
|
unit.unit_ps.publish("burn_limit", ctl_proc.limits[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
self.io.facility.ps.publish("process_mode", ctl_proc.mode)
|
||||||
|
self.io.facility.ps.publish("process_burn_target", ctl_proc.burn_target)
|
||||||
|
self.io.facility.ps.publish("process_charge_target", self.io.energy_convert_from_fe(ctl_proc.charge_target))
|
||||||
|
self.io.facility.ps.publish("process_gen_target", self.io.energy_convert_from_fe(ctl_proc.gen_target))
|
||||||
|
|
||||||
|
self.io.facility.start_ack(ack)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- record waste product state after attempting to change it
|
||||||
|
---@param response WASTE_PRODUCT supervisor waste product state
|
||||||
|
function process.waste_ack_handle(response)
|
||||||
|
self.control_states.process.waste_product = response
|
||||||
|
self.io.facility.ps.publish("process_waste_product", response)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- record plutonium fallback state after attempting to change it
|
||||||
|
---@param response boolean supervisor plutonium fallback state
|
||||||
|
function process.pu_fb_ack_handle(response)
|
||||||
|
self.control_states.process.pu_fallback = response
|
||||||
|
self.io.facility.ps.publish("process_pu_fallback", response)
|
||||||
|
end
|
||||||
|
|
||||||
|
return process
|
199
pocket/ui/apps/control.lua
Normal file
199
pocket/ui/apps/control.lua
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
--
|
||||||
|
-- Unit Control Page
|
||||||
|
--
|
||||||
|
|
||||||
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
|
local iocontrol = require("pocket.iocontrol")
|
||||||
|
local pocket = require("pocket.pocket")
|
||||||
|
|
||||||
|
local style = require("pocket.ui.style")
|
||||||
|
|
||||||
|
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 WaitingAnim = require("graphics.elements.animations.waiting")
|
||||||
|
|
||||||
|
local HazardButton = require("graphics.elements.controls.hazard_button")
|
||||||
|
local PushButton = require("graphics.elements.controls.push_button")
|
||||||
|
|
||||||
|
local NumberField = require("graphics.elements.form.number_field")
|
||||||
|
|
||||||
|
local DataIndicator = require("graphics.elements.indicators.data")
|
||||||
|
local IconIndicator = require("graphics.elements.indicators.icon")
|
||||||
|
|
||||||
|
local ALIGN = core.ALIGN
|
||||||
|
local cpair = core.cpair
|
||||||
|
|
||||||
|
local APP_ID = pocket.APP_ID
|
||||||
|
|
||||||
|
-- local label = style.label
|
||||||
|
local lu_col = style.label_unit_pair
|
||||||
|
local text_fg = style.text_fg
|
||||||
|
local basic_states = style.icon_states.basic_states
|
||||||
|
local mode_states = style.icon_states.mode_states
|
||||||
|
local red_ind_s = style.icon_states.red_ind_s
|
||||||
|
local yel_ind_s = style.icon_states.yel_ind_s
|
||||||
|
|
||||||
|
|
||||||
|
local hzd_fg_bg = cpair(colors.white, colors.gray)
|
||||||
|
local dis_colors = cpair(colors.white, colors.lightGray)
|
||||||
|
|
||||||
|
local emc_ind_s = {
|
||||||
|
{ color = cpair(colors.black, colors.gray), symbol = "-" },
|
||||||
|
{ color = cpair(colors.black, colors.white), symbol = "\x07" },
|
||||||
|
{ color = cpair(colors.black, colors.green), symbol = "+" }
|
||||||
|
}
|
||||||
|
|
||||||
|
-- new unit control page view
|
||||||
|
---@param root graphics_element parent
|
||||||
|
local function new_view(root)
|
||||||
|
local db = iocontrol.get_db()
|
||||||
|
|
||||||
|
local frame = Div{parent=root,x=1,y=1}
|
||||||
|
|
||||||
|
local app = db.nav.register_app(APP_ID.CONTROL, frame, nil, false, true)
|
||||||
|
|
||||||
|
local load_div = Div{parent=frame,x=1,y=1}
|
||||||
|
local main = Div{parent=frame,x=1,y=1}
|
||||||
|
|
||||||
|
TextBox{parent=load_div,y=12,text="Loading...",alignment=ALIGN.CENTER}
|
||||||
|
WaitingAnim{parent=load_div,x=math.floor(main.get_width()/2)-1,y=8,fg_bg=cpair(colors.green,colors._INHERIT)}
|
||||||
|
|
||||||
|
local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}}
|
||||||
|
|
||||||
|
app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = function () db.nav.open_app(APP_ID.ROOT) end } })
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
-- set sidebar to display unit-specific fields based on a specified unit
|
||||||
|
local function set_sidebar()
|
||||||
|
local list = {
|
||||||
|
{ label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = function () db.nav.open_app(APP_ID.ROOT) end },
|
||||||
|
}
|
||||||
|
|
||||||
|
for i = 1, db.facility.num_units do
|
||||||
|
table.insert(list, { label = "U-" .. i, color = core.cpair(colors.black, colors.lightGray), callback = function () app.switcher(i) end })
|
||||||
|
end
|
||||||
|
|
||||||
|
app.set_sidebar(list)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- load the app (create the elements)
|
||||||
|
local function load()
|
||||||
|
page_div = Div{parent=main,y=2,width=main.get_width()}
|
||||||
|
|
||||||
|
local panes = {}
|
||||||
|
|
||||||
|
local active_unit = 1
|
||||||
|
|
||||||
|
-- create all page divs
|
||||||
|
for _ = 1, db.facility.num_units do
|
||||||
|
local div = Div{parent=page_div}
|
||||||
|
table.insert(panes, div)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- previous unit
|
||||||
|
local function prev(x)
|
||||||
|
active_unit = util.trinary(x == 1, db.facility.num_units, x - 1)
|
||||||
|
app.switcher(active_unit)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- next unit
|
||||||
|
local function next(x)
|
||||||
|
active_unit = util.trinary(x == db.facility.num_units, 1, x + 1)
|
||||||
|
app.switcher(active_unit)
|
||||||
|
end
|
||||||
|
|
||||||
|
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 u_ps = unit.unit_ps
|
||||||
|
|
||||||
|
-- refresh data callback, every 500ms it will re-send the query
|
||||||
|
local last_update = 0
|
||||||
|
local function update()
|
||||||
|
if util.time_ms() - last_update >= 500 then
|
||||||
|
db.api.get_unit(i)
|
||||||
|
last_update = util.time_ms()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--#region Main Unit Overview
|
||||||
|
|
||||||
|
local u_page = app.new_page(nil, i)
|
||||||
|
u_page.tasks = { update }
|
||||||
|
|
||||||
|
TextBox{parent=u_div,y=1,text="Reactor Unit #"..i,alignment=ALIGN.CENTER}
|
||||||
|
PushButton{parent=u_div,x=1,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()prev(i)end}
|
||||||
|
PushButton{parent=u_div,x=21,y=1,text=">",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()next(i)end}
|
||||||
|
|
||||||
|
local rate = DataIndicator{parent=u_div,y=3,lu_colors=lu_col,label="Burn",unit="mB/t",format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg}
|
||||||
|
local temp = DataIndicator{parent=u_div,lu_colors=lu_col,label="Temp",unit=db.temp_label,format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg}
|
||||||
|
|
||||||
|
local ctrl = IconIndicator{parent=u_div,x=1,y=6,label="Control State",states=mode_states}
|
||||||
|
|
||||||
|
rate.register(u_ps, "act_burn_rate", rate.update)
|
||||||
|
temp.register(u_ps, "temp", function (t) temp.update(db.temp_convert(t)) end)
|
||||||
|
ctrl.register(u_ps, "U_ControlStatus", ctrl.update)
|
||||||
|
|
||||||
|
u_div.line_break()
|
||||||
|
|
||||||
|
TextBox{parent=u_div,y=8,text="CMD",width=4,fg_bg=cpair(colors.lightGray,colors.black)}
|
||||||
|
TextBox{parent=u_div,x=14,y=8,text="mB/t",width=4,fg_bg=cpair(colors.lightGray,colors.black)}
|
||||||
|
local burn_cmd = NumberField{parent=u_div,x=5,y=8,width=8,default=0.01,min=0.01,max_frac_digits=2,max_chars=8,allow_decimal=true,align_right=true,fg_bg=cpair(colors.white,colors.gray)}
|
||||||
|
|
||||||
|
local set_burn = function () unit.set_burn(burn_cmd.get_value()) end
|
||||||
|
local set_burn_btn = PushButton{parent=u_div,x=19,y=8,text="SET",min_width=5,fg_bg=cpair(colors.green,colors.black),active_fg_bg=cpair(colors.white,colors.black),dis_fg_bg=cpair(colors.gray,colors.black),callback=set_burn}
|
||||||
|
|
||||||
|
burn_cmd.register(u_ps, "max_burn", burn_cmd.set_max)
|
||||||
|
|
||||||
|
local start = HazardButton{parent=u_div,x=2,y=11,text="START",accent=colors.lightBlue,dis_colors=dis_colors,callback=unit.start,fg_bg=hzd_fg_bg}
|
||||||
|
local ack_a = HazardButton{parent=u_div,x=12,y=11,text="ACK \x13",accent=colors.orange,dis_colors=dis_colors,callback=unit.ack_alarms,fg_bg=hzd_fg_bg}
|
||||||
|
local scram = HazardButton{parent=u_div,x=2,y=15,text="SCRAM",accent=colors.yellow,dis_colors=dis_colors,callback=unit.scram,fg_bg=hzd_fg_bg}
|
||||||
|
local reset = HazardButton{parent=u_div,x=12,y=15,text="RESET",accent=colors.red,dis_colors=dis_colors,callback=unit.reset_rps,fg_bg=hzd_fg_bg}
|
||||||
|
|
||||||
|
--#endregion
|
||||||
|
|
||||||
|
util.nop()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- setup multipane
|
||||||
|
local u_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
|
||||||
|
app.set_root_pane(u_pane)
|
||||||
|
|
||||||
|
set_sidebar()
|
||||||
|
|
||||||
|
-- done, show the app
|
||||||
|
load_pane.set_value(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- delete the elements and switch back to the loading screen
|
||||||
|
local function unload()
|
||||||
|
if page_div then
|
||||||
|
page_div.delete()
|
||||||
|
page_div = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = function () db.nav.open_app(APP_ID.ROOT) end } })
|
||||||
|
app.delete_pages()
|
||||||
|
|
||||||
|
-- show loading screen
|
||||||
|
load_pane.set_value(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
app.set_load(load)
|
||||||
|
app.set_unload(unload)
|
||||||
|
|
||||||
|
return main
|
||||||
|
end
|
||||||
|
|
||||||
|
return new_view
|
@ -7,6 +7,7 @@ local util = require("scada-common.util")
|
|||||||
local iocontrol = require("pocket.iocontrol")
|
local iocontrol = require("pocket.iocontrol")
|
||||||
local pocket = require("pocket.pocket")
|
local pocket = require("pocket.pocket")
|
||||||
|
|
||||||
|
local control_app = require("pocket.ui.apps.control")
|
||||||
local diag_apps = require("pocket.ui.apps.diag_apps")
|
local diag_apps = require("pocket.ui.apps.diag_apps")
|
||||||
local dummy_app = require("pocket.ui.apps.dummy_app")
|
local dummy_app = require("pocket.ui.apps.dummy_app")
|
||||||
local guide_app = require("pocket.ui.apps.guide")
|
local guide_app = require("pocket.ui.apps.guide")
|
||||||
@ -62,6 +63,7 @@ local function init(main)
|
|||||||
-- create all the apps & pages
|
-- create all the apps & pages
|
||||||
home_page(page_div)
|
home_page(page_div)
|
||||||
unit_app(page_div)
|
unit_app(page_div)
|
||||||
|
control_app(page_div)
|
||||||
guide_app(page_div)
|
guide_app(page_div)
|
||||||
loader_app(page_div)
|
loader_app(page_div)
|
||||||
sys_apps(page_div)
|
sys_apps(page_div)
|
||||||
|
@ -47,7 +47,7 @@ local function new_view(root)
|
|||||||
|
|
||||||
App{parent=apps_1,x=2,y=2,text="U",title="Units",callback=function()open(APP_ID.UNITS)end,app_fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=active_fg_bg}
|
App{parent=apps_1,x=2,y=2,text="U",title="Units",callback=function()open(APP_ID.UNITS)end,app_fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=active_fg_bg}
|
||||||
App{parent=apps_1,x=9,y=2,text="F",title="Facil",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.orange),active_fg_bg=active_fg_bg}
|
App{parent=apps_1,x=9,y=2,text="F",title="Facil",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.orange),active_fg_bg=active_fg_bg}
|
||||||
App{parent=apps_1,x=16,y=2,text="\x15",title="Control",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.green),active_fg_bg=active_fg_bg}
|
App{parent=apps_1,x=16,y=2,text="\x15",title="Control",callback=function()open(APP_ID.CONTROL)end,app_fg_bg=cpair(colors.black,colors.green),active_fg_bg=active_fg_bg}
|
||||||
App{parent=apps_1,x=2,y=7,text="\x17",title="Process",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.purple),active_fg_bg=active_fg_bg}
|
App{parent=apps_1,x=2,y=7,text="\x17",title="Process",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.purple),active_fg_bg=active_fg_bg}
|
||||||
App{parent=apps_1,x=9,y=7,text="\x7f",title="Waste",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.brown),active_fg_bg=active_fg_bg}
|
App{parent=apps_1,x=9,y=7,text="\x7f",title="Waste",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.brown),active_fg_bg=active_fg_bg}
|
||||||
App{parent=apps_1,x=16,y=7,text="\x08",title="Devices",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.lightGray),active_fg_bg=active_fg_bg}
|
App{parent=apps_1,x=16,y=7,text="\x08",title="Devices",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.lightGray),active_fg_bg=active_fg_bg}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user