Merge pull request #560 from MikaylaFischler/pocket-alpha-dev
Pocket Process Control
This commit is contained in:
commit
620fa362f6
@ -387,10 +387,14 @@ function coordinator.comms(version, nic, sv_watchdog)
|
||||
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)
|
||||
---@param mode PROCESS process control mode
|
||||
---@param burn_target number burn rate target
|
||||
---@param charge_target number charge level target
|
||||
---@param gen_target number generation rate target
|
||||
---@param limits number[] unit burn rate limits
|
||||
function public.send_auto_start(mode, burn_target, charge_target, gen_target, limits)
|
||||
_send_sv(PROTOCOL.SCADA_CRDN, CRDN_TYPE.FAC_CMD, {
|
||||
FAC_COMMAND.START, auto_cfg.mode, auto_cfg.burn_target, auto_cfg.charge_target, auto_cfg.gen_target, auto_cfg.limits
|
||||
FAC_COMMAND.START, mode, burn_target, charge_target, gen_target, limits
|
||||
})
|
||||
end
|
||||
|
||||
@ -578,7 +582,7 @@ function coordinator.comms(version, nic, sv_watchdog)
|
||||
if cmd == FAC_COMMAND.SCRAM_ALL then
|
||||
process.fac_ack(cmd, ack)
|
||||
elseif cmd == FAC_COMMAND.STOP then
|
||||
iocontrol.get_db().facility.stop_ack(ack)
|
||||
process.fac_ack(cmd, ack)
|
||||
elseif cmd == FAC_COMMAND.START then
|
||||
if packet.length == 7 then
|
||||
process.start_ack_handle({ table.unpack(packet.data, 2) })
|
||||
|
||||
@ -84,6 +84,8 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale)
|
||||
all_sys_ok = false,
|
||||
rtu_count = 0,
|
||||
|
||||
status_lines = { "", "" },
|
||||
|
||||
auto_ready = false,
|
||||
auto_active = false,
|
||||
auto_ramping = false,
|
||||
@ -107,8 +109,6 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale)
|
||||
radiation = types.new_zero_radiation_reading(),
|
||||
|
||||
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 },
|
||||
@ -159,6 +159,11 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale)
|
||||
num_snas = 0,
|
||||
has_tank = conf.cooling.r_cool[i].TankConnection,
|
||||
|
||||
status_lines = { "", "" },
|
||||
|
||||
auto_ready = false,
|
||||
auto_degraded = false,
|
||||
|
||||
control_state = false,
|
||||
burn_rate_cmd = 0.0,
|
||||
radiation = types.new_zero_radiation_reading(),
|
||||
@ -541,8 +546,8 @@ function iocontrol.update_facility_status(status)
|
||||
fac.ascram_status.radiation = ctl_status[10]
|
||||
fac.ascram_status.gen_fault = ctl_status[11]
|
||||
|
||||
fac.status_line_1 = ctl_status[12]
|
||||
fac.status_line_2 = ctl_status[13]
|
||||
fac.status_lines[1] = ctl_status[12]
|
||||
fac.status_lines[2] = ctl_status[13]
|
||||
|
||||
fac.ps.publish("all_sys_ok", fac.all_sys_ok)
|
||||
fac.ps.publish("auto_ready", fac.auto_ready)
|
||||
@ -555,8 +560,8 @@ function iocontrol.update_facility_status(status)
|
||||
fac.ps.publish("as_crit_alarm", fac.ascram_status.crit_alarm)
|
||||
fac.ps.publish("as_radiation", fac.ascram_status.radiation)
|
||||
fac.ps.publish("as_gen_fault", fac.ascram_status.gen_fault)
|
||||
fac.ps.publish("status_line_1", fac.status_line_1)
|
||||
fac.ps.publish("status_line_2", fac.status_line_2)
|
||||
fac.ps.publish("status_line_1", fac.status_lines[1])
|
||||
fac.ps.publish("status_line_2", fac.status_lines[2])
|
||||
|
||||
local group_map = ctl_status[14]
|
||||
|
||||
@ -1130,15 +1135,19 @@ function iocontrol.update_unit_statuses(statuses)
|
||||
|
||||
if type(unit_state) == "table" then
|
||||
if #unit_state == 8 then
|
||||
unit.status_lines[1] = unit_state[1]
|
||||
unit.status_lines[2] = unit_state[2]
|
||||
unit.auto_ready = unit_state[3]
|
||||
unit.auto_degraded = unit_state[4]
|
||||
unit.waste_mode = unit_state[5]
|
||||
unit.waste_product = unit_state[6]
|
||||
unit.last_rate_change_ms = unit_state[7]
|
||||
unit.turbine_flow_stable = unit_state[8]
|
||||
|
||||
unit.unit_ps.publish("U_StatusLine1", unit_state[1])
|
||||
unit.unit_ps.publish("U_StatusLine2", unit_state[2])
|
||||
unit.unit_ps.publish("U_AutoReady", unit_state[3])
|
||||
unit.unit_ps.publish("U_AutoDegraded", unit_state[4])
|
||||
unit.unit_ps.publish("U_StatusLine1", unit.status_lines[1])
|
||||
unit.unit_ps.publish("U_StatusLine2", unit.status_lines[2])
|
||||
unit.unit_ps.publish("U_AutoReady", unit.auto_ready)
|
||||
unit.unit_ps.publish("U_AutoDegraded", unit.auto_degraded)
|
||||
unit.unit_ps.publish("U_AutoWaste", unit.waste_mode == types.WASTE_MODE.AUTO)
|
||||
unit.unit_ps.publish("U_WasteMode", unit.waste_mode)
|
||||
unit.unit_ps.publish("U_WasteProduct", unit.waste_product)
|
||||
|
||||
@ -25,12 +25,12 @@ local pctl = {
|
||||
control_states = {
|
||||
---@class sys_auto_config
|
||||
process = {
|
||||
mode = PROCESS.INACTIVE,
|
||||
mode = PROCESS.INACTIVE, ---@type PROCESS
|
||||
burn_target = 0.0,
|
||||
charge_target = 0.0,
|
||||
gen_target = 0.0,
|
||||
limits = {}, ---@type number[]
|
||||
waste_product = PRODUCT.PLUTONIUM,
|
||||
limits = {}, ---@type number[]
|
||||
waste_product = PRODUCT.PLUTONIUM, ---@type WASTE_PRODUCT
|
||||
pu_fallback = false,
|
||||
sps_low_power = false
|
||||
},
|
||||
@ -49,6 +49,7 @@ local pctl = {
|
||||
---@field requestors function[] list of callbacks from the requestors
|
||||
|
||||
-- write auto process control to config file
|
||||
---@return boolean saved
|
||||
local function _write_auto_config()
|
||||
-- save config
|
||||
settings.set("ControlStates", pctl.control_states)
|
||||
@ -60,6 +61,8 @@ local function _write_auto_config()
|
||||
return saved
|
||||
end
|
||||
|
||||
--#region Core
|
||||
|
||||
-- initialize the process controller
|
||||
---@param iocontrol ioctl iocontrl system
|
||||
---@param coord_comms coord_comms coordinator communications
|
||||
@ -180,6 +183,36 @@ function process.create_handle()
|
||||
end
|
||||
end
|
||||
|
||||
-- start automatic process control with current settings
|
||||
function handle.process_start()
|
||||
if f_request(F_CMD.START, handle.fac_ack.on_start) then
|
||||
local p = pctl.control_states.process
|
||||
pctl.comms.send_auto_start(p.mode, p.burn_target, p.charge_target, p.gen_target, p.limits)
|
||||
log.debug("PROCESS: START AUTO CTRL")
|
||||
end
|
||||
end
|
||||
|
||||
-- start automatic process control with remote settings that haven't been set on the coordinator
|
||||
---@param mode PROCESS process control mode
|
||||
---@param burn_target number burn rate target
|
||||
---@param charge_target number charge level target
|
||||
---@param gen_target number generation rate target
|
||||
---@param limits number[] unit burn rate limits
|
||||
function handle.process_start_remote(mode, burn_target, charge_target, gen_target, limits)
|
||||
if f_request(F_CMD.START, handle.fac_ack.on_start) then
|
||||
pctl.comms.send_auto_start(mode, burn_target, charge_target, gen_target, limits)
|
||||
log.debug("PROCESS: START AUTO CTRL")
|
||||
end
|
||||
end
|
||||
|
||||
-- stop process control
|
||||
function handle.process_stop()
|
||||
if f_request(F_CMD.STOP, handle.fac_ack.on_stop) then
|
||||
pctl.comms.send_fac_command(F_CMD.STOP)
|
||||
log.debug("PROCESS: STOP AUTO CTRL")
|
||||
end
|
||||
end
|
||||
|
||||
handle.fac_ack = {}
|
||||
|
||||
-- luacheck: no unused args
|
||||
@ -194,6 +227,16 @@ function process.create_handle()
|
||||
---@diagnostic disable-next-line: unused-local
|
||||
function handle.fac_ack.on_ack_alarms(success) end
|
||||
|
||||
-- facility auto control start ack, override to implement
|
||||
---@param success boolean
|
||||
---@diagnostic disable-next-line: unused-local
|
||||
function handle.fac_ack.on_start(success) end
|
||||
|
||||
-- facility auto control stop ack, override to implement
|
||||
---@param success boolean
|
||||
---@diagnostic disable-next-line: unused-local
|
||||
function handle.fac_ack.on_stop(success) end
|
||||
|
||||
-- luacheck: unused args
|
||||
|
||||
--#endregion
|
||||
@ -294,6 +337,14 @@ function process.clear_timed_out()
|
||||
end
|
||||
end
|
||||
|
||||
-- get the control states table
|
||||
---@nodiscard
|
||||
function process.get_control_states() return pctl.control_states end
|
||||
|
||||
--#endregion
|
||||
|
||||
--#region Command Handling
|
||||
|
||||
-- handle a command acknowledgement
|
||||
---@param cmd_state process_command_state
|
||||
---@param success boolean if the command was successful
|
||||
@ -335,6 +386,21 @@ function process.set_rate(id, rate)
|
||||
log.debug(util.c("PROCESS: UNIT[", id, "] SET BURN ", rate))
|
||||
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)
|
||||
pctl.comms.send_unit_command(U_CMD.SET_GROUP, unit_id, group_id)
|
||||
log.debug(util.c("PROCESS: UNIT[", unit_id, "] SET GROUP ", group_id))
|
||||
|
||||
pctl.control_states.priority_groups[unit_id] = group_id
|
||||
settings.set("ControlStates", pctl.control_states)
|
||||
|
||||
if not settings.save("/coordinator.settings") then
|
||||
log.error("process.set_group(): failed to save coordinator settings file")
|
||||
end
|
||||
end
|
||||
|
||||
-- set waste mode
|
||||
---@param id integer unit ID
|
||||
---@param mode integer waste mode
|
||||
@ -369,39 +435,12 @@ function process.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)
|
||||
pctl.comms.send_unit_command(U_CMD.SET_GROUP, unit_id, group_id)
|
||||
log.debug(util.c("PROCESS: UNIT[", unit_id, "] SET GROUP ", group_id))
|
||||
|
||||
pctl.control_states.priority_groups[unit_id] = group_id
|
||||
settings.set("ControlStates", pctl.control_states)
|
||||
|
||||
if not settings.save("/coordinator.settings") then
|
||||
log.error("process.set_group(): failed to save coordinator settings file")
|
||||
end
|
||||
end
|
||||
|
||||
--#endregion
|
||||
|
||||
--------------------------
|
||||
-- AUTO PROCESS CONTROL --
|
||||
--------------------------
|
||||
|
||||
-- start automatic process control
|
||||
function process.start_auto()
|
||||
pctl.comms.send_auto_start(pctl.control_states.process)
|
||||
log.debug("PROCESS: START AUTO CTL")
|
||||
end
|
||||
|
||||
-- stop automatic process control
|
||||
function process.stop_auto()
|
||||
pctl.comms.send_fac_command(F_CMD.STOP)
|
||||
log.debug("PROCESS: STOP AUTO CTL")
|
||||
end
|
||||
|
||||
-- set automatic process control waste mode
|
||||
---@param product WASTE_PRODUCT waste product for auto control
|
||||
function process.set_process_waste(product)
|
||||
@ -439,9 +478,9 @@ function process.set_sps_low_power(enabled)
|
||||
end
|
||||
|
||||
-- save process control settings
|
||||
---@param mode PROCESS control mode
|
||||
---@param mode PROCESS process control mode
|
||||
---@param burn_target number burn rate target
|
||||
---@param charge_target number charge target
|
||||
---@param charge_target number charge level target
|
||||
---@param gen_target number generation rate target
|
||||
---@param limits number[] unit burn rate limits
|
||||
function process.save(mode, burn_target, charge_target, gen_target, limits)
|
||||
@ -472,9 +511,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]
|
||||
unit.unit_ps.publish("burn_limit", ctl_proc.limits[i])
|
||||
pctl.io.units[i].unit_ps.publish("burn_limit", ctl_proc.limits[i])
|
||||
end
|
||||
|
||||
pctl.io.facility.ps.publish("process_mode", ctl_proc.mode)
|
||||
@ -482,7 +519,9 @@ function process.start_ack_handle(response)
|
||||
pctl.io.facility.ps.publish("process_charge_target", pctl.io.energy_convert_from_fe(ctl_proc.charge_target))
|
||||
pctl.io.facility.ps.publish("process_gen_target", pctl.io.energy_convert_from_fe(ctl_proc.gen_target))
|
||||
|
||||
pctl.io.facility.start_ack(ack)
|
||||
_write_auto_config()
|
||||
|
||||
process.fac_ack(F_CMD.START, ack)
|
||||
end
|
||||
|
||||
-- record waste product settting after attempting to change it
|
||||
@ -506,4 +545,6 @@ function process.sps_lp_ack_handle(response)
|
||||
pctl.io.facility.ps.publish("process_sps_low_power", response)
|
||||
end
|
||||
|
||||
--#endregion
|
||||
|
||||
return process
|
||||
|
||||
@ -108,14 +108,20 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
|
||||
|
||||
-- link callback transmissions
|
||||
|
||||
self.proc_handle.fac_ack.on_scram = function (success) _send(CRDN_TYPE.FAC_CMD, { FAC_COMMAND.SCRAM_ALL, success }) end
|
||||
self.proc_handle.fac_ack.on_ack_alarms = function (success) _send(CRDN_TYPE.FAC_CMD, { FAC_COMMAND.ACK_ALL_ALARMS, success }) end
|
||||
local f_ack = self.proc_handle.fac_ack
|
||||
|
||||
f_ack.on_scram = function (success) _send(CRDN_TYPE.FAC_CMD, { FAC_COMMAND.SCRAM_ALL, success }) end
|
||||
f_ack.on_ack_alarms = function (success) _send(CRDN_TYPE.FAC_CMD, { FAC_COMMAND.ACK_ALL_ALARMS, success }) end
|
||||
|
||||
f_ack.on_start = function (success) _send(CRDN_TYPE.FAC_CMD, { FAC_COMMAND.START, success }) end
|
||||
f_ack.on_stop = function (success) _send(CRDN_TYPE.FAC_CMD, { FAC_COMMAND.STOP, success }) end
|
||||
|
||||
for u = 1, iocontrol.get_db().facility.num_units do
|
||||
self.proc_handle.unit_ack[u].on_start = function (success) _send(CRDN_TYPE.UNIT_CMD, { UNIT_COMMAND.START, u, success }) end
|
||||
self.proc_handle.unit_ack[u].on_scram = function (success) _send(CRDN_TYPE.UNIT_CMD, { UNIT_COMMAND.SCRAM, u, success }) end
|
||||
self.proc_handle.unit_ack[u].on_rps_reset = function (success) _send(CRDN_TYPE.UNIT_CMD, { UNIT_COMMAND.RESET_RPS, u, success }) end
|
||||
self.proc_handle.unit_ack[u].on_ack_alarms = function (success) _send(CRDN_TYPE.UNIT_CMD, { UNIT_COMMAND.ACK_ALL_ALARMS, u, success }) end
|
||||
local u_ack = self.proc_handle.unit_ack[u]
|
||||
u_ack.on_start = function (success) _send(CRDN_TYPE.UNIT_CMD, { UNIT_COMMAND.START, u, success }) end
|
||||
u_ack.on_scram = function (success) _send(CRDN_TYPE.UNIT_CMD, { UNIT_COMMAND.SCRAM, u, success }) end
|
||||
u_ack.on_rps_reset = function (success) _send(CRDN_TYPE.UNIT_CMD, { UNIT_COMMAND.RESET_RPS, u, success }) end
|
||||
u_ack.on_ack_alarms = function (success) _send(CRDN_TYPE.UNIT_CMD, { UNIT_COMMAND.ACK_ALL_ALARMS, u, success }) end
|
||||
end
|
||||
|
||||
-- handle a packet
|
||||
@ -147,7 +153,15 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
|
||||
log.info(log_tag .. "FAC SCRAM ALL")
|
||||
self.proc_handle.fac_scram()
|
||||
elseif cmd == FAC_COMMAND.STOP then
|
||||
log.info(log_tag .. "STOP PROCESS CTRL")
|
||||
self.proc_handle.process_stop()
|
||||
elseif cmd == FAC_COMMAND.START then
|
||||
if pkt.length == 6 then
|
||||
log.info(log_tag .. "START PROCESS CTRL")
|
||||
self.proc_handle.process_start_remote(pkt.data[2], pkt.data[3], pkt.data[4], pkt.data[5], pkt.data[6])
|
||||
else
|
||||
log.debug(log_tag .. "CRDN auto start (with configuration) packet length mismatch")
|
||||
end
|
||||
elseif cmd == FAC_COMMAND.ACK_ALL_ALARMS then
|
||||
log.info(log_tag .. "FAC ACK ALL ALARMS")
|
||||
self.proc_handle.fac_ack_alarms()
|
||||
@ -191,6 +205,12 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
|
||||
elseif cmd == UNIT_COMMAND.ACK_ALARM then
|
||||
elseif cmd == UNIT_COMMAND.RESET_ALARM then
|
||||
elseif cmd == UNIT_COMMAND.SET_GROUP then
|
||||
if pkt.length == 3 then
|
||||
log.info(util.c(log_tag, "UNIT[", uid, "] SET GROUP ", pkt.data[3]))
|
||||
process.set_group(uid, pkt.data[3])
|
||||
else
|
||||
log.debug(log_tag .. "CRDN unit set group missing option")
|
||||
end
|
||||
else
|
||||
log.debug(log_tag .. "CRDN unit command unknown")
|
||||
end
|
||||
@ -259,6 +279,37 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
|
||||
end
|
||||
|
||||
_send(CRDN_TYPE.API_GET_CTRL, data)
|
||||
elseif pkt.type == CRDN_TYPE.API_GET_PROC then
|
||||
local data = {}
|
||||
|
||||
local fac = db.facility
|
||||
local proc = process.get_control_states().process
|
||||
|
||||
-- unit data
|
||||
for i = 1, #db.units do
|
||||
local u = db.units[i]
|
||||
|
||||
data[i] = {
|
||||
u.reactor_data.mek_status.status,
|
||||
u.reactor_data.mek_struct.max_burn,
|
||||
proc.limits[i],
|
||||
u.auto_ready,
|
||||
u.auto_degraded,
|
||||
u.annunciator.AutoControl,
|
||||
u.a_group
|
||||
}
|
||||
end
|
||||
|
||||
-- facility data
|
||||
data[#db.units + 1] = {
|
||||
fac.status_lines,
|
||||
{ fac.auto_ready, fac.auto_active, fac.auto_ramping, fac.auto_saturated },
|
||||
fac.auto_scram,
|
||||
fac.ascram_status,
|
||||
{ proc.mode, proc.burn_target, proc.charge_target, proc.gen_target }
|
||||
}
|
||||
|
||||
_send(CRDN_TYPE.API_GET_PROC, data)
|
||||
else
|
||||
log.debug(log_tag .. "handler received unsupported CRDN packet type " .. pkt.type)
|
||||
end
|
||||
|
||||
@ -264,24 +264,22 @@ local function new_view(root, x, y)
|
||||
local limits = {}
|
||||
for i = 1, #rate_limits do limits[i] = rate_limits[i].get_value() end
|
||||
|
||||
process.save(mode.get_value(), b_target.get_value(),
|
||||
db.energy_convert_to_fe(c_target.get_value()),
|
||||
db.energy_convert_to_fe(g_target.get_value()),
|
||||
limits)
|
||||
process.save(mode.get_value(), b_target.get_value(), db.energy_convert_to_fe(c_target.get_value()),
|
||||
db.energy_convert_to_fe(g_target.get_value()), limits)
|
||||
end
|
||||
|
||||
-- start automatic control after saving process control settings
|
||||
local function _start_auto()
|
||||
_save_cfg()
|
||||
process.start_auto()
|
||||
db.process.process_start()
|
||||
end
|
||||
|
||||
local save = HazardButton{parent=auto_controls,x=2,y=2,text="SAVE",accent=colors.purple,dis_colors=dis_colors,callback=_save_cfg,fg_bg=hzd_fg_bg}
|
||||
local start = HazardButton{parent=auto_controls,x=13,y=2,text="START",accent=colors.lightBlue,dis_colors=dis_colors,callback=_start_auto,fg_bg=hzd_fg_bg}
|
||||
local stop = HazardButton{parent=auto_controls,x=23,y=2,text="STOP",accent=colors.red,dis_colors=dis_colors,callback=process.stop_auto,fg_bg=hzd_fg_bg}
|
||||
local stop = HazardButton{parent=auto_controls,x=23,y=2,text="STOP",accent=colors.red,dis_colors=dis_colors,callback=db.process.process_stop,fg_bg=hzd_fg_bg}
|
||||
|
||||
facility.start_ack = start.on_response
|
||||
facility.stop_ack = stop.on_response
|
||||
db.process.fac_ack.on_start = start.on_response
|
||||
db.process.fac_ack.on_stop = stop.on_response
|
||||
|
||||
function facility.save_cfg_ack(ack)
|
||||
tcd.dispatch(0.2, function () save.on_response(ack) end)
|
||||
|
||||
@ -7,7 +7,7 @@ local flasher = require("graphics.flasher")
|
||||
|
||||
local core = {}
|
||||
|
||||
core.version = "2.4.3"
|
||||
core.version = "2.4.5"
|
||||
|
||||
core.flasher = flasher
|
||||
core.events = events
|
||||
|
||||
@ -11,6 +11,7 @@ local KEY_CLICK = core.events.KEY_CLICK
|
||||
---@field options table button options
|
||||
---@field radio_colors cpair radio button colors (inner & outer)
|
||||
---@field select_color color color for radio button border when selected
|
||||
---@field dis_fg_bg? cpair foreground/background colors when disabled
|
||||
---@field default? integer default state, defaults to options[1]
|
||||
---@field min_width? integer text length + 2 if omitted
|
||||
---@field callback? function function to call on touch
|
||||
@ -64,6 +65,10 @@ return function (args)
|
||||
local inner_color = util.trinary(e.value == i, args.radio_colors.color_b, args.radio_colors.color_a)
|
||||
local outer_color = util.trinary(e.value == i, args.select_color, args.radio_colors.color_b)
|
||||
|
||||
if e.value == i and args.dis_fg_bg and not e.enabled then
|
||||
outer_color = args.radio_colors.color_a
|
||||
end
|
||||
|
||||
e.w_set_cur(1, i)
|
||||
|
||||
e.w_set_fgd(inner_color)
|
||||
@ -75,9 +80,14 @@ return function (args)
|
||||
e.w_write("\x95")
|
||||
|
||||
-- write button text
|
||||
if i == focused_opt and e.is_focused() and e.enabled then
|
||||
e.w_set_fgd(e.fg_bg.bkg)
|
||||
e.w_set_bkg(e.fg_bg.fgd)
|
||||
if args.dis_fg_bg and not e.enabled then
|
||||
e.w_set_fgd(args.dis_fg_bg.fgd)
|
||||
e.w_set_bkg(args.dis_fg_bg.bkg)
|
||||
elseif i == focused_opt and e.is_focused() then
|
||||
if e.enabled then
|
||||
e.w_set_fgd(e.fg_bg.bkg)
|
||||
e.w_set_bkg(e.fg_bg.fgd)
|
||||
end
|
||||
else
|
||||
e.w_set_fgd(e.fg_bg.fgd)
|
||||
e.w_set_bkg(e.fg_bg.bkg)
|
||||
|
||||
@ -44,8 +44,47 @@ return function (args)
|
||||
|
||||
args.max_chars = args.max_chars or e.frame.w
|
||||
|
||||
-- determine the format to convert the number to a string
|
||||
local format = "%d"
|
||||
if args.allow_decimal then
|
||||
if args.max_frac_digits then
|
||||
format = "%."..args.max_frac_digits.."f"
|
||||
else format = "%f" end
|
||||
end
|
||||
|
||||
-- set the value to a formatted numeric string<br>
|
||||
-- trims trailing zeros from floating point numbers
|
||||
---@param num number
|
||||
local function _set_value(num)
|
||||
local str = util.sprintf(format, num)
|
||||
|
||||
if args.allow_decimal then
|
||||
local found_nonzero = false
|
||||
local str_table = {}
|
||||
|
||||
for i = #str, 1, -1 do
|
||||
local c = string.sub(str, i, i)
|
||||
|
||||
if found_nonzero then
|
||||
str_table[i] = c
|
||||
else
|
||||
if c == "." then
|
||||
found_nonzero = true
|
||||
elseif c ~= "0" then
|
||||
str_table[i] = c
|
||||
found_nonzero = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
e.value = table.concat(str_table)
|
||||
else
|
||||
e.value = str
|
||||
end
|
||||
end
|
||||
|
||||
-- set initial value
|
||||
e.value = "" .. (args.default or 0)
|
||||
_set_value(args.default or 0)
|
||||
|
||||
-- make an interactive field manager
|
||||
local ifield = core.new_ifield(e, args.max_chars, args.fg_bg, args.dis_fg_bg, args.align_right)
|
||||
@ -107,7 +146,17 @@ return function (args)
|
||||
-- set the value (must be a number)
|
||||
---@param val number number to show
|
||||
function e.set_value(val)
|
||||
if tonumber(val) then ifield.set_value("" .. tonumber(val)) end
|
||||
local num, max, min = tonumber(val), tonumber(args.max), tonumber(args.min)
|
||||
|
||||
if max and num > max then
|
||||
_set_value(max)
|
||||
elseif min and num < min then
|
||||
_set_value(min)
|
||||
elseif num then
|
||||
_set_value(num)
|
||||
end
|
||||
|
||||
ifield.set_value(e.value)
|
||||
end
|
||||
|
||||
-- set minimum input value
|
||||
@ -136,11 +185,9 @@ return function (args)
|
||||
|
||||
-- handle unfocused
|
||||
function e.on_unfocused()
|
||||
local val = tonumber(e.value)
|
||||
local max = tonumber(args.max)
|
||||
local min = tonumber(args.min)
|
||||
local val, max, min = tonumber(e.value), tonumber(args.max), tonumber(args.min)
|
||||
|
||||
if type(val) == "number" then
|
||||
if val then
|
||||
if args.max_int_digits or args.max_frac_digits then
|
||||
local str = e.value
|
||||
local ceil = false
|
||||
@ -169,17 +216,17 @@ return function (args)
|
||||
|
||||
if parts[2] then parts[2] = "." .. parts[2] else parts[2] = "" end
|
||||
|
||||
val = tonumber((parts[1] or "") .. parts[2])
|
||||
val = tonumber((parts[1] or "") .. parts[2]) or 0
|
||||
end
|
||||
|
||||
if type(args.max) == "number" and val > max then
|
||||
e.value = "" .. max
|
||||
if max and val > max then
|
||||
_set_value(max)
|
||||
ifield.nav_start()
|
||||
elseif type(args.min) == "number" and val < min then
|
||||
e.value = "" .. min
|
||||
elseif min and val < min then
|
||||
_set_value(min)
|
||||
ifield.nav_start()
|
||||
else
|
||||
e.value = "" .. val
|
||||
_set_value(val)
|
||||
ifield.nav_end()
|
||||
end
|
||||
else
|
||||
@ -198,5 +245,11 @@ return function (args)
|
||||
---@class NumberField:graphics_element
|
||||
local NumberField, id = e.complete(true)
|
||||
|
||||
-- get the numeric value of this field
|
||||
---@return number value the value, or 0 if not a valid number
|
||||
function NumberField.get_numeric()
|
||||
return tonumber(e.value) or 0
|
||||
end
|
||||
|
||||
return NumberField, id
|
||||
end
|
||||
|
||||
@ -6,7 +6,6 @@ local const = require("scada-common.constants")
|
||||
local psil = require("scada-common.psil")
|
||||
local types = require("scada-common.types")
|
||||
local util = require("scada-common.util")
|
||||
local log = require("scada-common.log")
|
||||
|
||||
local process = require("pocket.process")
|
||||
|
||||
@ -94,7 +93,8 @@ function iocontrol.init_core(pkt_comms, nav, cfg)
|
||||
---@class pocket_ioctl_api
|
||||
io.api = {
|
||||
get_unit = function (unit) comms.api__get_unit(unit) end,
|
||||
get_ctrl = function () comms.api__get_control() end
|
||||
get_ctrl = function () comms.api__get_control() end,
|
||||
get_proc = function () comms.api__get_process() end
|
||||
}
|
||||
end
|
||||
|
||||
@ -138,6 +138,8 @@ function iocontrol.init_fac(conf)
|
||||
all_sys_ok = false,
|
||||
rtu_count = 0,
|
||||
|
||||
status_lines = { "", "" },
|
||||
|
||||
auto_ready = false,
|
||||
auto_active = false,
|
||||
auto_ramping = false,
|
||||
@ -197,6 +199,11 @@ function iocontrol.init_fac(conf)
|
||||
num_snas = 0,
|
||||
has_tank = conf.cooling.r_cool[i].TankConnection,
|
||||
|
||||
status_lines = { "", "" },
|
||||
|
||||
auto_ready = false,
|
||||
auto_degraded = false,
|
||||
|
||||
control_state = false,
|
||||
burn_rate_cmd = 0.0,
|
||||
radiation = types.new_zero_radiation_reading(),
|
||||
@ -817,48 +824,102 @@ function iocontrol.record_control_data(data)
|
||||
local unit = io.units[u_id]
|
||||
local u_data = data[u_id]
|
||||
|
||||
if type(u_data) ~= "table" then
|
||||
log.debug(util.c("iocontrol.record_control_data: unit ", u_id, " data invalid"))
|
||||
else
|
||||
unit.connected = u_data[1]
|
||||
unit.connected = u_data[1]
|
||||
|
||||
unit.reactor_data.rps_tripped = u_data[2]
|
||||
unit.unit_ps.publish("rps_tripped", u_data[2])
|
||||
unit.reactor_data.mek_status.status = u_data[3]
|
||||
unit.unit_ps.publish("status", u_data[3])
|
||||
unit.reactor_data.mek_status.temp = u_data[4]
|
||||
unit.unit_ps.publish("temp", u_data[4])
|
||||
unit.reactor_data.mek_status.burn_rate = u_data[5]
|
||||
unit.unit_ps.publish("burn_rate", u_data[5])
|
||||
unit.reactor_data.mek_status.act_burn_rate = u_data[6]
|
||||
unit.unit_ps.publish("act_burn_rate", u_data[6])
|
||||
unit.reactor_data.mek_struct.max_burn = u_data[7]
|
||||
unit.unit_ps.publish("max_burn", u_data[7])
|
||||
unit.reactor_data.rps_tripped = u_data[2]
|
||||
unit.unit_ps.publish("rps_tripped", u_data[2])
|
||||
unit.reactor_data.mek_status.status = u_data[3]
|
||||
unit.unit_ps.publish("status", u_data[3])
|
||||
unit.reactor_data.mek_status.temp = u_data[4]
|
||||
unit.unit_ps.publish("temp", u_data[4])
|
||||
unit.reactor_data.mek_status.burn_rate = u_data[5]
|
||||
unit.unit_ps.publish("burn_rate", u_data[5])
|
||||
unit.reactor_data.mek_status.act_burn_rate = u_data[6]
|
||||
unit.unit_ps.publish("act_burn_rate", u_data[6])
|
||||
unit.reactor_data.mek_struct.max_burn = u_data[7]
|
||||
unit.unit_ps.publish("max_burn", u_data[7])
|
||||
|
||||
unit.annunciator.AutoControl = u_data[8]
|
||||
unit.unit_ps.publish("AutoControl", u_data[8])
|
||||
unit.annunciator.AutoControl = u_data[8]
|
||||
unit.unit_ps.publish("AutoControl", u_data[8])
|
||||
|
||||
unit.a_group = u_data[9]
|
||||
unit.unit_ps.publish("auto_group_id", unit.a_group)
|
||||
unit.unit_ps.publish("auto_group", types.AUTO_GROUP_NAMES[unit.a_group + 1])
|
||||
unit.a_group = u_data[9]
|
||||
unit.unit_ps.publish("auto_group_id", unit.a_group)
|
||||
unit.unit_ps.publish("auto_group", types.AUTO_GROUP_NAMES[unit.a_group + 1])
|
||||
|
||||
local control_status = 1
|
||||
local control_status = 1
|
||||
|
||||
if unit.connected then
|
||||
if unit.reactor_data.rps_tripped then
|
||||
control_status = 2
|
||||
end
|
||||
|
||||
if unit.reactor_data.mek_status.status then
|
||||
control_status = util.trinary(unit.annunciator.AutoControl, 4, 3)
|
||||
end
|
||||
if unit.connected then
|
||||
if unit.reactor_data.rps_tripped then
|
||||
control_status = 2
|
||||
end
|
||||
|
||||
unit.unit_ps.publish("U_ControlStatus", control_status)
|
||||
if unit.reactor_data.mek_status.status then
|
||||
control_status = util.trinary(unit.annunciator.AutoControl, 4, 3)
|
||||
end
|
||||
end
|
||||
|
||||
unit.unit_ps.publish("U_ControlStatus", control_status)
|
||||
end
|
||||
end
|
||||
|
||||
-- update process app with unit data from API_GET_PROC
|
||||
---@param data table
|
||||
function iocontrol.record_process_data(data)
|
||||
-- get unit data
|
||||
for u_id = 1, #io.units do
|
||||
local unit = io.units[u_id]
|
||||
local u_data = data[u_id]
|
||||
|
||||
unit.reactor_data.mek_status.status = u_data[1]
|
||||
unit.reactor_data.mek_struct.max_burn = u_data[2]
|
||||
unit.annunciator.AutoControl = u_data[6]
|
||||
unit.a_group = u_data[7]
|
||||
|
||||
unit.unit_ps.publish("status", u_data[1])
|
||||
unit.unit_ps.publish("max_burn", u_data[2])
|
||||
unit.unit_ps.publish("burn_limit", u_data[3])
|
||||
unit.unit_ps.publish("U_AutoReady", u_data[4])
|
||||
unit.unit_ps.publish("U_AutoDegraded", u_data[5])
|
||||
unit.unit_ps.publish("AutoControl", u_data[6])
|
||||
unit.unit_ps.publish("auto_group_id", unit.a_group)
|
||||
unit.unit_ps.publish("auto_group", types.AUTO_GROUP_NAMES[unit.a_group + 1])
|
||||
end
|
||||
|
||||
-- get facility data
|
||||
local fac = io.facility
|
||||
local f_data = data[#io.units + 1]
|
||||
|
||||
fac.status_lines = f_data[1]
|
||||
|
||||
fac.auto_ready = f_data[2][1]
|
||||
fac.auto_active = f_data[2][2]
|
||||
fac.auto_ramping = f_data[2][3]
|
||||
fac.auto_saturated = f_data[2][4]
|
||||
|
||||
fac.auto_scram = f_data[3]
|
||||
fac.ascram_status = f_data[4]
|
||||
|
||||
fac.ps.publish("status_line_1", fac.status_lines[1])
|
||||
fac.ps.publish("status_line_2", fac.status_lines[2])
|
||||
|
||||
fac.ps.publish("auto_ready", fac.auto_ready)
|
||||
fac.ps.publish("auto_active", fac.auto_active)
|
||||
fac.ps.publish("auto_ramping", fac.auto_ramping)
|
||||
fac.ps.publish("auto_saturated", fac.auto_saturated)
|
||||
|
||||
fac.ps.publish("auto_scram", fac.auto_scram)
|
||||
fac.ps.publish("as_matrix_dc", fac.ascram_status.matrix_dc)
|
||||
fac.ps.publish("as_matrix_fill", fac.ascram_status.matrix_fill)
|
||||
fac.ps.publish("as_crit_alarm", fac.ascram_status.crit_alarm)
|
||||
fac.ps.publish("as_radiation", fac.ascram_status.radiation)
|
||||
fac.ps.publish("as_gen_fault", fac.ascram_status.gen_fault)
|
||||
|
||||
fac.ps.publish("process_mode", f_data[5][1])
|
||||
fac.ps.publish("process_burn_target", f_data[5][2])
|
||||
fac.ps.publish("process_charge_target", f_data[5][3])
|
||||
fac.ps.publish("process_gen_target", f_data[5][4])
|
||||
end
|
||||
|
||||
-- get the IO controller database
|
||||
function iocontrol.get_db() return io end
|
||||
|
||||
|
||||
@ -82,18 +82,20 @@ end
|
||||
|
||||
---@enum POCKET_APP_ID
|
||||
local APP_ID = {
|
||||
-- core UI
|
||||
ROOT = 1,
|
||||
LOADER = 2,
|
||||
-- main app pages
|
||||
UNITS = 3,
|
||||
CONTROL = 4,
|
||||
GUIDE = 5,
|
||||
ABOUT = 6,
|
||||
-- diag app page
|
||||
ALARMS = 7,
|
||||
PROCESS = 5,
|
||||
GUIDE = 6,
|
||||
ABOUT = 7,
|
||||
-- diagnostic app pages
|
||||
ALARMS = 8,
|
||||
-- other
|
||||
DUMMY = 8,
|
||||
NUM_APPS = 8
|
||||
DUMMY = 9,
|
||||
NUM_APPS = 9
|
||||
}
|
||||
|
||||
pocket.APP_ID = APP_ID
|
||||
@ -167,9 +169,9 @@ function pocket.init_nav(smem)
|
||||
-- configure the sidebar
|
||||
---@param items sidebar_entry[]
|
||||
function app.set_sidebar(items)
|
||||
app.sidebar_items = items
|
||||
-- only modify the sidebar if this app is still open
|
||||
if self.cur_app == app_id then
|
||||
app.sidebar_items = items
|
||||
if self.sidebar then self.sidebar.update(items) end
|
||||
end
|
||||
end
|
||||
@ -178,8 +180,8 @@ function pocket.init_nav(smem)
|
||||
---@param on_load function callback
|
||||
function app.set_load(on_load)
|
||||
app.load = function ()
|
||||
app.loaded = true -- must flag first so it can't be repeatedly attempted
|
||||
on_load()
|
||||
app.loaded = true
|
||||
end
|
||||
end
|
||||
|
||||
@ -187,8 +189,8 @@ function pocket.init_nav(smem)
|
||||
---@param on_unload function callback
|
||||
function app.set_unload(on_unload)
|
||||
app.unload = function ()
|
||||
on_unload()
|
||||
app.loaded = false
|
||||
on_unload()
|
||||
end
|
||||
end
|
||||
|
||||
@ -288,6 +290,9 @@ function pocket.init_nav(smem)
|
||||
end
|
||||
end
|
||||
|
||||
-- go home (open the home screen app)
|
||||
function nav.go_home() nav.open_app(APP_ID.ROOT) end
|
||||
|
||||
-- open the app that was blocked on connecting
|
||||
function nav.on_loader_connected()
|
||||
if self.loader_return then
|
||||
@ -555,6 +560,11 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
|
||||
if self.api.linked then _send_api(CRDN_TYPE.API_GET_CTRL, {}) end
|
||||
end
|
||||
|
||||
-- coordinator get process app data
|
||||
function public.api__get_process()
|
||||
if self.api.linked then _send_api(CRDN_TYPE.API_GET_PROC, {}) end
|
||||
end
|
||||
|
||||
-- send a facility command
|
||||
---@param cmd FAC_COMMAND command
|
||||
---@param option any? optional option options for the optional options (like waste mode)
|
||||
@ -562,6 +572,12 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
|
||||
_send_api(CRDN_TYPE.FAC_CMD, { cmd, option })
|
||||
end
|
||||
|
||||
-- send the auto process control configuration with a start command
|
||||
---@param auto_cfg [ PROCESS, number, number, number, number[] ]
|
||||
function public.send_auto_start(auto_cfg)
|
||||
_send_api(CRDN_TYPE.FAC_CMD, { FAC_COMMAND.START, table.unpack(auto_cfg) })
|
||||
end
|
||||
|
||||
-- send a unit command
|
||||
---@param cmd UNIT_COMMAND command
|
||||
---@param unit integer unit ID
|
||||
@ -664,7 +680,9 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
|
||||
if cmd == FAC_COMMAND.SCRAM_ALL then
|
||||
iocontrol.get_db().facility.scram_ack(ack)
|
||||
elseif cmd == FAC_COMMAND.STOP then
|
||||
iocontrol.get_db().facility.stop_ack(ack)
|
||||
elseif cmd == FAC_COMMAND.START then
|
||||
iocontrol.get_db().facility.start_ack(ack)
|
||||
elseif cmd == FAC_COMMAND.ACK_ALL_ALARMS then
|
||||
iocontrol.get_db().facility.ack_alarms_ack(ack)
|
||||
elseif cmd == FAC_COMMAND.SET_WASTE_MODE then
|
||||
@ -711,6 +729,10 @@ function pocket.comms(version, nic, sv_watchdog, api_watchdog, nav)
|
||||
if _check_length(packet, #iocontrol.get_db().units) then
|
||||
iocontrol.record_control_data(packet.data)
|
||||
end
|
||||
elseif packet.type == CRDN_TYPE.API_GET_PROC then
|
||||
if _check_length(packet, #iocontrol.get_db().units + 1) then
|
||||
iocontrol.record_process_data(packet.data)
|
||||
end
|
||||
else _fail_type(packet) end
|
||||
else
|
||||
log.debug("discarding coordinator SCADA_CRDN packet before linked")
|
||||
|
||||
@ -6,8 +6,8 @@ local comms = require("scada-common.comms")
|
||||
local log = require("scada-common.log")
|
||||
local util = require("scada-common.util")
|
||||
|
||||
local FAC_COMMAND = comms.FAC_COMMAND
|
||||
local UNIT_COMMAND = comms.UNIT_COMMAND
|
||||
local F_CMD = comms.FAC_COMMAND
|
||||
local U_CMD = comms.UNIT_COMMAND
|
||||
|
||||
---@class pocket_process_controller
|
||||
local process = {}
|
||||
@ -25,23 +25,32 @@ function process.init(iocontrol, pocket_comms)
|
||||
self.comms = pocket_comms
|
||||
end
|
||||
|
||||
------------------------------
|
||||
--#region FACILITY COMMANDS --
|
||||
|
||||
-- facility SCRAM command
|
||||
function process.fac_scram()
|
||||
self.comms.send_fac_command(FAC_COMMAND.SCRAM_ALL)
|
||||
self.comms.send_fac_command(F_CMD.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)
|
||||
self.comms.send_fac_command(F_CMD.ACK_ALL_ALARMS)
|
||||
log.debug("PROCESS: FAC ACK ALL ALARMS")
|
||||
end
|
||||
|
||||
--#endregion
|
||||
------------------------------
|
||||
|
||||
--------------------------
|
||||
--#region UNIT COMMANDS --
|
||||
|
||||
-- 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)
|
||||
self.comms.send_unit_command(U_CMD.START, id)
|
||||
log.debug(util.c("PROCESS: UNIT[", id, "] START"))
|
||||
end
|
||||
|
||||
@ -49,14 +58,14 @@ end
|
||||
---@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)
|
||||
self.comms.send_unit_command(U_CMD.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)
|
||||
self.comms.send_unit_command(U_CMD.RESET_RPS, id)
|
||||
log.debug(util.c("PROCESS: UNIT[", id, "] RESET RPS"))
|
||||
end
|
||||
|
||||
@ -64,14 +73,22 @@ end
|
||||
---@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)
|
||||
self.comms.send_unit_command(U_CMD.SET_BURN, id, rate)
|
||||
log.debug(util.c("PROCESS: UNIT[", id, "] SET BURN ", rate))
|
||||
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(U_CMD.SET_GROUP, unit_id, group_id)
|
||||
log.debug(util.c("PROCESS: UNIT[", unit_id, "] SET GROUP ", group_id))
|
||||
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)
|
||||
self.comms.send_unit_command(U_CMD.ACK_ALL_ALARMS, id)
|
||||
log.debug(util.c("PROCESS: UNIT[", id, "] ACK ALL ALARMS"))
|
||||
end
|
||||
|
||||
@ -79,7 +96,7 @@ end
|
||||
---@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)
|
||||
self.comms.send_unit_command(U_CMD.ACK_ALARM, id, alarm)
|
||||
log.debug(util.c("PROCESS: UNIT[", id, "] ACK ALARM ", alarm))
|
||||
end
|
||||
|
||||
@ -87,8 +104,34 @@ end
|
||||
---@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)
|
||||
self.comms.send_unit_command(U_CMD.RESET_ALARM, id, alarm)
|
||||
log.debug(util.c("PROCESS: UNIT[", id, "] RESET ALARM ", alarm))
|
||||
end
|
||||
|
||||
-- #endregion
|
||||
--------------------------
|
||||
|
||||
---------------------------------
|
||||
--#region AUTO PROCESS CONTROL --
|
||||
|
||||
-- process start command
|
||||
---@param mode PROCESS process control mode
|
||||
---@param burn_target number burn rate target
|
||||
---@param charge_target number charge level target
|
||||
---@param gen_target number generation rate target
|
||||
---@param limits number[] unit burn rate limits
|
||||
function process.process_start(mode, burn_target, charge_target, gen_target, limits)
|
||||
self.comms.send_auto_start({ mode, burn_target, charge_target, gen_target, limits })
|
||||
log.debug("PROCESS: START AUTO CTRL")
|
||||
end
|
||||
|
||||
-- process stop command
|
||||
function process.process_stop()
|
||||
self.comms.send_fac_command(F_CMD.STOP)
|
||||
log.debug("PROCESS: STOP AUTO CTRL")
|
||||
end
|
||||
|
||||
-- #endregion
|
||||
---------------------------------
|
||||
|
||||
return process
|
||||
|
||||
@ -20,7 +20,7 @@ local pocket = require("pocket.pocket")
|
||||
local renderer = require("pocket.renderer")
|
||||
local threads = require("pocket.threads")
|
||||
|
||||
local POCKET_VERSION = "v0.12.5-alpha"
|
||||
local POCKET_VERSION = "v0.12.7-alpha"
|
||||
|
||||
local println = util.println
|
||||
local println_ts = util.println_ts
|
||||
|
||||
@ -34,16 +34,21 @@ local cpair = core.cpair
|
||||
|
||||
local APP_ID = pocket.APP_ID
|
||||
|
||||
local lu_col = style.label_unit_pair
|
||||
local text_fg = style.text_fg
|
||||
local mode_states = style.icon_states.mode_states
|
||||
local label_fg_bg = style.label
|
||||
local lu_col = style.label_unit_pair
|
||||
local text_fg = style.text_fg
|
||||
|
||||
local hzd_fg_bg = cpair(colors.white, colors.gray)
|
||||
local dis_colors = cpair(colors.white, colors.lightGray)
|
||||
local mode_states = style.icon_states.mode_states
|
||||
|
||||
local btn_active = cpair(colors.white, colors.black)
|
||||
local hzd_fg_bg = style.hzd_fg_bg
|
||||
local hzd_dis_colors = style.hzd_dis_colors
|
||||
|
||||
-- new unit control page view
|
||||
---@param root Container parent
|
||||
local function new_view(root)
|
||||
local btn_fg_bg = cpair(colors.green, colors.black)
|
||||
|
||||
local db = iocontrol.get_db()
|
||||
|
||||
local frame = Div{parent=root,x=1,y=1}
|
||||
@ -58,17 +63,14 @@ local function new_view(root)
|
||||
|
||||
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)
|
||||
app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
|
||||
|
||||
local page_div = nil ---@type Div|nil
|
||||
|
||||
-- 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 },
|
||||
{ label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home },
|
||||
{ label = "FAC", color = core.cpair(colors.black, colors.orange), callback = function () app.switcher(db.facility.num_units + 1) end }
|
||||
}
|
||||
|
||||
@ -138,12 +140,12 @@ local function new_view(root)
|
||||
|
||||
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),dis_fg_bg=cpair(colors.gray,colors.lightGray)}
|
||||
TextBox{parent=u_div,y=8,text="CMD",width=4,fg_bg=label_fg_bg}
|
||||
TextBox{parent=u_div,x=14,y=8,text="mB/t",width=4,fg_bg=label_fg_bg}
|
||||
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=style.field,dis_fg_bg=style.field_disable}
|
||||
|
||||
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}
|
||||
local set_burn = function () unit.set_burn(burn_cmd.get_numeric()) 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=style.btn_disable,callback=set_burn}
|
||||
|
||||
-- enable/disable controls based on group assignment (start button is separate)
|
||||
burn_cmd.register(u_ps, "auto_group_id", function (gid)
|
||||
@ -156,10 +158,10 @@ local function new_view(root)
|
||||
burn_cmd.register(u_ps, "burn_rate", burn_cmd.set_value)
|
||||
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,timeout=3,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,timeout=3,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,timeout=3,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,timeout=3,fg_bg=hzd_fg_bg}
|
||||
local start = HazardButton{parent=u_div,x=2,y=11,text="START",accent=colors.lightBlue,callback=unit.start,timeout=3,fg_bg=hzd_fg_bg,dis_colors=hzd_dis_colors}
|
||||
local ack_a = HazardButton{parent=u_div,x=12,y=11,text="ACK \x13",accent=colors.orange,callback=unit.ack_alarms,timeout=3,fg_bg=hzd_fg_bg,dis_colors=hzd_dis_colors}
|
||||
local scram = HazardButton{parent=u_div,x=2,y=15,text="SCRAM",accent=colors.yellow,callback=unit.scram,timeout=3,fg_bg=hzd_fg_bg,dis_colors=hzd_dis_colors}
|
||||
local reset = HazardButton{parent=u_div,x=12,y=15,text="RESET",accent=colors.red,callback=unit.reset_rps,timeout=3,fg_bg=hzd_fg_bg,dis_colors=hzd_dis_colors}
|
||||
|
||||
unit.start_ack = start.on_response
|
||||
unit.ack_alarms_ack = ack_a.on_response
|
||||
@ -192,8 +194,8 @@ local function new_view(root)
|
||||
|
||||
TextBox{parent=f_div,y=1,text="Facility Commands",alignment=ALIGN.CENTER}
|
||||
|
||||
local scram = HazardButton{parent=f_div,x=5,y=6,text="FAC SCRAM",accent=colors.yellow,dis_colors=dis_colors,callback=process.fac_scram,timeout=3,fg_bg=hzd_fg_bg}
|
||||
local ack_a = HazardButton{parent=f_div,x=7,y=11,text="ACK \x13",accent=colors.orange,dis_colors=dis_colors,callback=process.fac_ack_alarms,timeout=3,fg_bg=hzd_fg_bg}
|
||||
local scram = HazardButton{parent=f_div,x=5,y=6,text="FAC SCRAM",accent=colors.yellow,dis_colors=hzd_dis_colors,callback=process.fac_scram,timeout=3,fg_bg=hzd_fg_bg}
|
||||
local ack_a = HazardButton{parent=f_div,x=7,y=11,text="ACK \x13",accent=colors.orange,dis_colors=hzd_dis_colors,callback=process.fac_ack_alarms,timeout=3,fg_bg=hzd_fg_bg}
|
||||
|
||||
db.facility.scram_ack = scram.on_response
|
||||
db.facility.ack_alarms_ack = ack_a.on_response
|
||||
@ -215,7 +217,7 @@ local function new_view(root)
|
||||
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.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
|
||||
app.delete_pages()
|
||||
|
||||
-- show loading screen
|
||||
|
||||
@ -56,14 +56,14 @@ local function new_view(root)
|
||||
local btn_active = cpair(colors.white, colors.black)
|
||||
local btn_disable = cpair(colors.gray, colors.black)
|
||||
|
||||
app.set_sidebar({{ label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = function () db.nav.open_app(APP_ID.ROOT) end }})
|
||||
app.set_sidebar({{ label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home }})
|
||||
|
||||
local page_div = nil ---@type Div|nil
|
||||
|
||||
-- load the app (create the elements)
|
||||
local function load()
|
||||
local list = {
|
||||
{ label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = function () db.nav.open_app(APP_ID.ROOT) end },
|
||||
{ label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home },
|
||||
{ label = " \x14 ", color = core.cpair(colors.black, colors.cyan), callback = function () app.switcher(1) end },
|
||||
{ label = "__?", color = core.cpair(colors.black, colors.lightGray), callback = function () app.switcher(2) end }
|
||||
}
|
||||
@ -263,7 +263,7 @@ local function new_view(root)
|
||||
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.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
|
||||
app.delete_pages()
|
||||
|
||||
-- show loading screen
|
||||
|
||||
337
pocket/ui/apps/process.lua
Normal file
337
pocket/ui/apps/process.lua
Normal file
@ -0,0 +1,337 @@
|
||||
--
|
||||
-- Process Control Page
|
||||
--
|
||||
|
||||
local types = require("scada-common.types")
|
||||
local util = require("scada-common.util")
|
||||
|
||||
local iocontrol = require("pocket.iocontrol")
|
||||
local pocket = require("pocket.pocket")
|
||||
local process = require("pocket.process")
|
||||
|
||||
local style = require("pocket.ui.style")
|
||||
|
||||
local core = require("graphics.core")
|
||||
|
||||
local Div = require("graphics.elements.Div")
|
||||
local MultiPane = require("graphics.elements.MultiPane")
|
||||
local Rectangle = require("graphics.elements.Rectangle")
|
||||
local TextBox = require("graphics.elements.TextBox")
|
||||
|
||||
local WaitingAnim = require("graphics.elements.animations.Waiting")
|
||||
|
||||
local HazardButton = require("graphics.elements.controls.HazardButton")
|
||||
local RadioButton = require("graphics.elements.controls.RadioButton")
|
||||
|
||||
local NumberField = require("graphics.elements.form.NumberField")
|
||||
|
||||
local IconIndicator = require("graphics.elements.indicators.IconIndicator")
|
||||
|
||||
local ALIGN = core.ALIGN
|
||||
local cpair = core.cpair
|
||||
local border = core.border
|
||||
|
||||
local APP_ID = pocket.APP_ID
|
||||
|
||||
local label_fg_bg = style.label
|
||||
local text_fg = style.text_fg
|
||||
|
||||
local field_fg_bg = style.field
|
||||
local field_dis_fg_bg = style.field_disable
|
||||
|
||||
local red_ind_s = style.icon_states.red_ind_s
|
||||
local yel_ind_s = style.icon_states.yel_ind_s
|
||||
local grn_ind_s = style.icon_states.grn_ind_s
|
||||
local wht_ind_s = style.icon_states.wht_ind_s
|
||||
|
||||
local hzd_fg_bg = style.hzd_fg_bg
|
||||
local dis_colors = cpair(colors.white, colors.lightGray)
|
||||
|
||||
-- new process control page view
|
||||
---@param root Container parent
|
||||
local function new_view(root)
|
||||
local db = iocontrol.get_db()
|
||||
|
||||
local frame = Div{parent=root,x=1,y=1}
|
||||
|
||||
local app = db.nav.register_app(APP_ID.PROCESS, frame, nil, false, true)
|
||||
|
||||
local load_div = Div{parent=frame,x=1,y=1}
|
||||
local main = Div{parent=frame,x=1,y=1}
|
||||
|
||||
TextBox{parent=load_div,y=12,text="Loading...",alignment=ALIGN.CENTER}
|
||||
WaitingAnim{parent=load_div,x=math.floor(main.get_width()/2)-1,y=8,fg_bg=cpair(colors.purple,colors._INHERIT)}
|
||||
|
||||
local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}}
|
||||
|
||||
app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
|
||||
|
||||
local page_div = nil ---@type Div|nil
|
||||
|
||||
-- load the app (create the elements)
|
||||
local function load()
|
||||
local f_ps = db.facility.ps
|
||||
|
||||
page_div = Div{parent=main,y=2,width=main.get_width()}
|
||||
|
||||
local panes = {} ---@type Div[]
|
||||
|
||||
-- create all page divs
|
||||
for _ = 1, db.facility.num_units + 3 do
|
||||
local div = Div{parent=page_div}
|
||||
table.insert(panes, div)
|
||||
end
|
||||
|
||||
local last_update = 0
|
||||
-- refresh data callback, every 500ms it will re-send the query
|
||||
local function update()
|
||||
if util.time_ms() - last_update >= 500 then
|
||||
db.api.get_proc()
|
||||
last_update = util.time_ms()
|
||||
end
|
||||
end
|
||||
|
||||
--#region unit settings/status
|
||||
|
||||
local rate_limits = {} ---@type NumberField[]
|
||||
|
||||
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]
|
||||
local u_ps = unit.unit_ps
|
||||
|
||||
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}
|
||||
|
||||
TextBox{parent=u_div,y=3,text="Auto Rate Limit",fg_bg=label_fg_bg}
|
||||
rate_limits[i] = NumberField{parent=u_div,x=1,y=4,width=16,default=0.01,min=0.01,max_frac_digits=2,max_chars=8,allow_decimal=true,align_right=true,fg_bg=field_fg_bg,dis_fg_bg=field_dis_fg_bg}
|
||||
TextBox{parent=u_div,x=18,y=4,text="mB/t",width=4,fg_bg=label_fg_bg}
|
||||
|
||||
rate_limits[i].register(unit.unit_ps, "max_burn", rate_limits[i].set_max)
|
||||
rate_limits[i].register(unit.unit_ps, "burn_limit", rate_limits[i].set_value)
|
||||
|
||||
local ready = IconIndicator{parent=u_div,y=6,label="Auto Ready",states=grn_ind_s}
|
||||
local a_stb = IconIndicator{parent=u_div,label="Auto Standby",states=wht_ind_s}
|
||||
local degraded = IconIndicator{parent=u_div,label="Unit Degraded",states=red_ind_s}
|
||||
|
||||
ready.register(u_ps, "U_AutoReady", ready.update)
|
||||
degraded.register(u_ps, "U_AutoDegraded", degraded.update)
|
||||
|
||||
-- update standby indicator
|
||||
a_stb.register(u_ps, "status", function (active)
|
||||
a_stb.update(unit.annunciator.AutoControl and (not active))
|
||||
end)
|
||||
a_stb.register(u_ps, "AutoControl", function (auto_active)
|
||||
if auto_active then
|
||||
a_stb.update(unit.reactor_data.mek_status.status == false)
|
||||
else a_stb.update(false) end
|
||||
end)
|
||||
|
||||
local function _set_group(value) process.set_group(i, value - 1) end
|
||||
|
||||
local group = RadioButton{parent=u_div,y=10,options=types.AUTO_GROUP_NAMES,callback=_set_group,radio_colors=cpair(colors.lightGray,colors.gray),select_color=colors.purple,dis_fg_bg=style.btn_disable}
|
||||
|
||||
-- can't change group if auto is engaged regardless of if this unit is part of auto control
|
||||
group.register(f_ps, "auto_active", function (auto_active)
|
||||
if auto_active then group.disable() else group.enable() end
|
||||
end)
|
||||
|
||||
group.register(u_ps, "auto_group_id", function (gid) group.set_value(gid + 1) end)
|
||||
|
||||
TextBox{parent=u_div,y=16,text="Assigned Group",fg_bg=style.label}
|
||||
local auto_grp = TextBox{parent=u_div,text="Manual",width=11,fg_bg=text_fg}
|
||||
|
||||
auto_grp.register(u_ps, "auto_group", auto_grp.set_value)
|
||||
|
||||
util.nop()
|
||||
end
|
||||
|
||||
--#endregion
|
||||
|
||||
--#region process control options page
|
||||
|
||||
local o_pane = panes[db.facility.num_units + 2]
|
||||
local o_div = Div{parent=o_pane,x=2,width=main.get_width()-2}
|
||||
|
||||
local opt_page = app.new_page(nil, db.facility.num_units + 2)
|
||||
opt_page.tasks = { update }
|
||||
|
||||
TextBox{parent=o_div,y=1,text="Process Options",alignment=ALIGN.CENTER}
|
||||
|
||||
local ctl_opts = { "Monitored Max Burn", "Combined Burn Rate", "Charge Level", "Generation Rate" }
|
||||
local mode = RadioButton{parent=o_div,x=1,y=3,options=ctl_opts,callback=function()end,radio_colors=cpair(colors.lightGray,colors.gray),select_color=colors.purple,dis_fg_bg=style.btn_disable}
|
||||
|
||||
mode.register(f_ps, "process_mode", mode.set_value)
|
||||
|
||||
TextBox{parent=o_div,y=9,text="Burn Rate Target",fg_bg=label_fg_bg}
|
||||
local b_target = NumberField{parent=o_div,x=1,y=10,width=15,default=0.01,min=0.01,max_frac_digits=2,max_chars=8,allow_decimal=true,align_right=true,fg_bg=field_fg_bg,dis_fg_bg=field_dis_fg_bg}
|
||||
TextBox{parent=o_div,x=17,y=10,text="mB/t",fg_bg=label_fg_bg}
|
||||
|
||||
TextBox{parent=o_div,y=12,text="Charge Level Target",fg_bg=label_fg_bg}
|
||||
local c_target = NumberField{parent=o_div,x=1,y=13,width=15,default=0,min=0,max_chars=16,align_right=true,fg_bg=field_fg_bg,dis_fg_bg=field_dis_fg_bg}
|
||||
TextBox{parent=o_div,x=17,y=13,text="M"..db.energy_label,fg_bg=label_fg_bg}
|
||||
|
||||
TextBox{parent=o_div,y=15,text="Generation Target",fg_bg=label_fg_bg}
|
||||
local g_target = NumberField{parent=o_div,x=1,y=16,width=15,default=0,min=0,max_chars=16,align_right=true,fg_bg=field_fg_bg,dis_fg_bg=field_dis_fg_bg}
|
||||
TextBox{parent=o_div,x=17,y=16,text="k"..db.energy_label.."/t",fg_bg=label_fg_bg}
|
||||
|
||||
b_target.register(f_ps, "process_burn_target", b_target.set_value)
|
||||
c_target.register(f_ps, "process_charge_target", c_target.set_value)
|
||||
g_target.register(f_ps, "process_gen_target", g_target.set_value)
|
||||
|
||||
--#endregion
|
||||
|
||||
--#region process control page
|
||||
|
||||
local c_pane = panes[db.facility.num_units + 1]
|
||||
local c_div = Div{parent=c_pane,x=2,width=main.get_width()-2}
|
||||
|
||||
local proc_ctrl = app.new_page(nil, db.facility.num_units + 1)
|
||||
proc_ctrl.tasks = { update }
|
||||
|
||||
TextBox{parent=c_div,y=1,text="Process Control",alignment=ALIGN.CENTER}
|
||||
|
||||
local u_stat = Rectangle{parent=c_div,border=border(1,colors.gray,true),thin=true,width=21,height=5,x=1,y=3,fg_bg=cpair(colors.black,colors.lightGray)}
|
||||
local stat_line_1 = TextBox{parent=u_stat,x=1,y=1,text="UNKNOWN",alignment=ALIGN.CENTER}
|
||||
local stat_line_2 = TextBox{parent=u_stat,x=1,y=2,text="awaiting data...",height=2,alignment=ALIGN.CENTER,trim_whitespace=true,fg_bg=cpair(colors.gray,colors.lightGray)}
|
||||
|
||||
stat_line_1.register(f_ps, "status_line_1", stat_line_1.set_value)
|
||||
stat_line_2.register(f_ps, "status_line_2", stat_line_2.set_value)
|
||||
|
||||
local function _start_auto()
|
||||
local limits = {}
|
||||
for i = 1, #rate_limits do limits[i] = rate_limits[i].get_numeric() end
|
||||
|
||||
process.process_start(mode.get_value(), b_target.get_numeric(), db.energy_convert_to_fe(c_target.get_numeric()),
|
||||
db.energy_convert_to_fe(g_target.get_numeric()), limits)
|
||||
end
|
||||
|
||||
local start = HazardButton{parent=c_div,x=2,y=9,text="START",accent=colors.lightBlue,callback=_start_auto,timeout=3,fg_bg=hzd_fg_bg,dis_colors=dis_colors}
|
||||
local stop = HazardButton{parent=c_div,x=13,y=9,text="STOP",accent=colors.red,callback=process.process_stop,timeout=3,fg_bg=hzd_fg_bg,dis_colors=dis_colors}
|
||||
|
||||
db.facility.start_ack = start.on_response
|
||||
db.facility.stop_ack = stop.on_response
|
||||
|
||||
start.register(f_ps, "auto_ready", function (ready)
|
||||
if ready and (not db.facility.auto_active) then start.enable() else start.disable() end
|
||||
end)
|
||||
|
||||
local auto_ready = IconIndicator{parent=c_div,y=14,label="Units Ready",states=grn_ind_s}
|
||||
local auto_act = IconIndicator{parent=c_div,label="Process Active",states=grn_ind_s}
|
||||
local auto_ramp = IconIndicator{parent=c_div,label="Process Ramping",states=wht_ind_s}
|
||||
local auto_sat = IconIndicator{parent=c_div,label="Min/Max Burn Rate",states=yel_ind_s}
|
||||
|
||||
auto_ready.register(f_ps, "auto_ready", auto_ready.update)
|
||||
auto_act.register(f_ps, "auto_active", auto_act.update)
|
||||
auto_ramp.register(f_ps, "auto_ramping", auto_ramp.update)
|
||||
auto_sat.register(f_ps, "auto_saturated", auto_sat.update)
|
||||
|
||||
-- REGISTER_NOTE: for optimization/brevity, due to not deleting anything but the whole element tree
|
||||
-- when it comes to unloading the process app, child elements will not directly be registered here
|
||||
-- (preventing garbage collection until the parent 'page_div' is deleted)
|
||||
page_div.register(f_ps, "auto_active", function (active)
|
||||
if active then
|
||||
b_target.disable()
|
||||
c_target.disable()
|
||||
g_target.disable()
|
||||
|
||||
mode.disable()
|
||||
start.disable()
|
||||
|
||||
for i = 1, #rate_limits do rate_limits[i].disable() end
|
||||
else
|
||||
b_target.enable()
|
||||
c_target.enable()
|
||||
g_target.enable()
|
||||
|
||||
mode.enable()
|
||||
if db.facility.auto_ready then start.enable() end
|
||||
|
||||
for i = 1, #rate_limits do rate_limits[i].enable() end
|
||||
end
|
||||
end)
|
||||
|
||||
--#endregion
|
||||
|
||||
--#region auto-SCRAM annunciator page
|
||||
|
||||
local a_pane = panes[db.facility.num_units + 3]
|
||||
local a_div = Div{parent=a_pane,x=2,width=main.get_width()-2}
|
||||
|
||||
local annunc_page = app.new_page(nil, db.facility.num_units + 3)
|
||||
annunc_page.tasks = { update }
|
||||
|
||||
TextBox{parent=a_div,y=1,text="Automatic SCRAM",alignment=ALIGN.CENTER}
|
||||
|
||||
local auto_scram = IconIndicator{parent=a_div,y=3,label="Automatic SCRAM",states=red_ind_s}
|
||||
|
||||
TextBox{parent=a_div,y=5,text="Induction Matrix",fg_bg=label_fg_bg}
|
||||
local matrix_dc = IconIndicator{parent=a_div,label="Disconnected",states=yel_ind_s}
|
||||
local matrix_fill = IconIndicator{parent=a_div,label="Charge High",states=red_ind_s}
|
||||
|
||||
TextBox{parent=a_div,y=9,text="Assigned Units",fg_bg=label_fg_bg}
|
||||
local unit_crit = IconIndicator{parent=a_div,label="Critical Alarm",states=red_ind_s}
|
||||
|
||||
TextBox{parent=a_div,y=12,text="Facility",fg_bg=label_fg_bg}
|
||||
local fac_rad_h = IconIndicator{parent=a_div,label="Radiation High",states=red_ind_s}
|
||||
|
||||
TextBox{parent=a_div,y=15,text="Generation Rate Mode",fg_bg=label_fg_bg}
|
||||
local gen_fault = IconIndicator{parent=a_div,label="Control Fault",states=yel_ind_s}
|
||||
|
||||
auto_scram.register(f_ps, "auto_scram", auto_scram.update)
|
||||
matrix_dc.register(f_ps, "as_matrix_dc", matrix_dc.update)
|
||||
matrix_fill.register(f_ps, "as_matrix_fill", matrix_fill.update)
|
||||
unit_crit.register(f_ps, "as_crit_alarm", unit_crit.update)
|
||||
fac_rad_h.register(f_ps, "as_radiation", fac_rad_h.update)
|
||||
gen_fault.register(f_ps, "as_gen_fault", gen_fault.update)
|
||||
|
||||
--#endregion
|
||||
|
||||
-- setup multipane
|
||||
local u_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
|
||||
app.set_root_pane(u_pane)
|
||||
|
||||
-- setup sidebar
|
||||
|
||||
local list = {
|
||||
{ label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home },
|
||||
{ label = " \x17 ", color = core.cpair(colors.black, colors.purple), callback = proc_ctrl.nav_to },
|
||||
{ label = " \x13 ", color = core.cpair(colors.black, colors.red), callback = annunc_page.nav_to },
|
||||
{ label = "OPT", color = core.cpair(colors.black, colors.yellow), callback = opt_page.nav_to }
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
-- done, show the app
|
||||
proc_ctrl.nav_to()
|
||||
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 = db.nav.go_home } })
|
||||
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
|
||||
@ -63,7 +63,7 @@ local function new_view(root)
|
||||
|
||||
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 } })
|
||||
app.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
|
||||
|
||||
local btn_fg_bg = cpair(colors.yellow, colors.black)
|
||||
local btn_active = cpair(colors.white, colors.black)
|
||||
@ -76,7 +76,7 @@ local function new_view(root)
|
||||
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 },
|
||||
{ label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home },
|
||||
{ label = "U-" .. id, color = core.cpair(colors.black, colors.yellow), callback = function () app.switcher(id) end },
|
||||
{ label = " \x13 ", color = core.cpair(colors.black, colors.red), callback = nav_links[id].alarm },
|
||||
{ label = "RPS", tall = true, color = core.cpair(colors.black, colors.cyan), callback = nav_links[id].rps },
|
||||
@ -383,7 +383,7 @@ local function new_view(root)
|
||||
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.set_sidebar({ { label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = db.nav.go_home } })
|
||||
app.delete_pages()
|
||||
|
||||
-- show loading screen
|
||||
|
||||
@ -12,6 +12,7 @@ local diag_apps = require("pocket.ui.apps.diag_apps")
|
||||
local dummy_app = require("pocket.ui.apps.dummy_app")
|
||||
local guide_app = require("pocket.ui.apps.guide")
|
||||
local loader_app = require("pocket.ui.apps.loader")
|
||||
local process_app = require("pocket.ui.apps.process")
|
||||
local sys_apps = require("pocket.ui.apps.sys_apps")
|
||||
local unit_app = require("pocket.ui.apps.unit")
|
||||
|
||||
@ -64,6 +65,7 @@ local function init(main)
|
||||
home_page(page_div)
|
||||
unit_app(page_div)
|
||||
control_app(page_div)
|
||||
process_app(page_div)
|
||||
guide_app(page_div)
|
||||
loader_app(page_div)
|
||||
sys_apps(page_div)
|
||||
@ -78,7 +80,7 @@ local function init(main)
|
||||
|
||||
PushButton{parent=main_pane,x=1,y=19,text="\x1b",min_width=3,fg_bg=cpair(colors.white,colors.gray),active_fg_bg=cpair(colors.gray,colors.black),callback=db.nav.nav_up}
|
||||
|
||||
db.nav.open_app(APP_ID.ROOT)
|
||||
db.nav.go_home()
|
||||
|
||||
-- done with initial render, lets go!
|
||||
root_pane.set_value(2)
|
||||
|
||||
@ -48,7 +48,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=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.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.PROCESS)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=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=2,y=12,text="\xb6",title="Guide",callback=function()open(APP_ID.GUIDE)end,app_fg_bg=cpair(colors.black,colors.cyan),active_fg_bg=active_fg_bg}
|
||||
|
||||
@ -10,12 +10,19 @@ local cpair = core.cpair
|
||||
|
||||
-- GLOBAL --
|
||||
|
||||
style.root = cpair(colors.white, colors.black)
|
||||
style.header = cpair(colors.white, colors.gray)
|
||||
style.text_fg = cpair(colors.white, colors._INHERIT)
|
||||
style.label = cpair(colors.lightGray, colors.black)
|
||||
style.root = cpair(colors.white, colors.black)
|
||||
style.header = cpair(colors.white, colors.gray)
|
||||
style.text_fg = cpair(colors.white, colors._INHERIT)
|
||||
|
||||
style.label = cpair(colors.lightGray, colors.black)
|
||||
style.label_unit_pair = cpair(colors.lightGray, colors.lightGray)
|
||||
|
||||
style.field = cpair(colors.white, colors.gray)
|
||||
style.field_disable = cpair(colors.gray, colors.lightGray)
|
||||
style.btn_disable = cpair(colors.gray, colors.black)
|
||||
style.hzd_fg_bg = cpair(colors.white, colors.gray)
|
||||
style.hzd_dis_colors = cpair(colors.white, colors.lightGray)
|
||||
|
||||
style.colors = {
|
||||
{ c = colors.red, hex = 0xdf4949 },
|
||||
{ c = colors.orange, hex = 0xffb659 },
|
||||
@ -73,6 +80,16 @@ states.yel_ind_s = {
|
||||
{ color = cpair(colors.black, colors.yellow), symbol = "-" }
|
||||
}
|
||||
|
||||
states.grn_ind_s = {
|
||||
{ color = cpair(colors.black, colors.lightGray), symbol = "\x07" },
|
||||
{ color = cpair(colors.black, colors.green), symbol = "+" }
|
||||
}
|
||||
|
||||
states.wht_ind_s = {
|
||||
{ color = cpair(colors.black, colors.lightGray), symbol = "\x07" },
|
||||
{ color = cpair(colors.black, colors.white), symbol = "+" }
|
||||
}
|
||||
|
||||
style.icon_states = states
|
||||
|
||||
-- MAIN LAYOUT --
|
||||
|
||||
@ -18,7 +18,7 @@ local comms = {}
|
||||
|
||||
-- protocol/data versions (protocol/data independent changes tracked by util.lua version)
|
||||
comms.version = "3.0.0"
|
||||
comms.api_version = "0.0.5"
|
||||
comms.api_version = "0.0.6"
|
||||
|
||||
---@enum PROTOCOL
|
||||
local PROTOCOL = {
|
||||
@ -68,7 +68,8 @@ local CRDN_TYPE = {
|
||||
UNIT_CMD = 6, -- command a reactor unit
|
||||
API_GET_FAC = 7, -- API: get all the facility data
|
||||
API_GET_UNIT = 8, -- API: get reactor unit data
|
||||
API_GET_CTRL = 9 -- API: get data used for the control app
|
||||
API_GET_CTRL = 9, -- API: get data used for the control app
|
||||
API_GET_PROC = 10 -- API: get data used for the process app
|
||||
}
|
||||
|
||||
---@enum ESTABLISH_ACK
|
||||
|
||||
@ -425,9 +425,9 @@ function facility.new(config)
|
||||
|
||||
ready = self.mode_set > 0
|
||||
|
||||
if (self.mode_set == PROCESS.CHARGE) and (self.charge_setpoint <= 0) or
|
||||
(self.mode_set == PROCESS.GEN_RATE) and (self.gen_rate_setpoint <= 0) or
|
||||
(self.mode_set == PROCESS.BURN_RATE) and (self.burn_target < 0.1) then
|
||||
if ((self.mode_set == PROCESS.CHARGE) and (self.charge_setpoint <= 0)) or
|
||||
((self.mode_set == PROCESS.GEN_RATE) and (self.gen_rate_setpoint <= 0)) or
|
||||
((self.mode_set == PROCESS.BURN_RATE) and (self.burn_target < 0.1)) then
|
||||
ready = false
|
||||
end
|
||||
|
||||
@ -436,6 +436,8 @@ function facility.new(config)
|
||||
if ready then self.mode = self.mode_set end
|
||||
end
|
||||
|
||||
log.debug(util.c("FAC: process start ", util.trinary(ready, "accepted", "rejected")))
|
||||
|
||||
return {
|
||||
ready,
|
||||
self.mode_set,
|
||||
|
||||
@ -22,7 +22,7 @@ local supervisor = require("supervisor.supervisor")
|
||||
|
||||
local svsessions = require("supervisor.session.svsessions")
|
||||
|
||||
local SUPERVISOR_VERSION = "v1.5.8"
|
||||
local SUPERVISOR_VERSION = "v1.5.9"
|
||||
|
||||
local println = util.println
|
||||
local println_ts = util.println_ts
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user