Merge pull request #560 from MikaylaFischler/pocket-alpha-dev

Pocket Process Control
This commit is contained in:
Mikayla 2024-10-14 13:24:45 -04:00 committed by GitHub
commit 620fa362f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 827 additions and 174 deletions

View File

@ -387,10 +387,14 @@ function coordinator.comms(version, nic, sv_watchdog)
end end
-- send the auto process control configuration with a start command -- send the auto process control configuration with a start command
---@param auto_cfg sys_auto_config configuration ---@param mode PROCESS process control mode
function public.send_auto_start(auto_cfg) ---@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, { _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 end
@ -578,7 +582,7 @@ function coordinator.comms(version, nic, sv_watchdog)
if cmd == FAC_COMMAND.SCRAM_ALL then if cmd == FAC_COMMAND.SCRAM_ALL then
process.fac_ack(cmd, ack) process.fac_ack(cmd, ack)
elseif cmd == FAC_COMMAND.STOP then elseif cmd == FAC_COMMAND.STOP then
iocontrol.get_db().facility.stop_ack(ack) process.fac_ack(cmd, ack)
elseif cmd == FAC_COMMAND.START then elseif cmd == FAC_COMMAND.START then
if packet.length == 7 then if packet.length == 7 then
process.start_ack_handle({ table.unpack(packet.data, 2) }) process.start_ack_handle({ table.unpack(packet.data, 2) })

View File

@ -84,6 +84,8 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale)
all_sys_ok = false, all_sys_ok = false,
rtu_count = 0, rtu_count = 0,
status_lines = { "", "" },
auto_ready = false, auto_ready = false,
auto_active = false, auto_active = false,
auto_ramping = false, auto_ramping = false,
@ -107,8 +109,6 @@ function iocontrol.init(conf, comms, temp_scale, energy_scale)
radiation = types.new_zero_radiation_reading(), radiation = types.new_zero_radiation_reading(),
save_cfg_ack = nil, ---@type fun(success: boolean) 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 } ---@type { [TONE]: boolean }
alarm_tones = { false, false, false, false, false, false, false, false }, 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, num_snas = 0,
has_tank = conf.cooling.r_cool[i].TankConnection, has_tank = conf.cooling.r_cool[i].TankConnection,
status_lines = { "", "" },
auto_ready = false,
auto_degraded = false,
control_state = false, control_state = false,
burn_rate_cmd = 0.0, burn_rate_cmd = 0.0,
radiation = types.new_zero_radiation_reading(), 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.radiation = ctl_status[10]
fac.ascram_status.gen_fault = ctl_status[11] fac.ascram_status.gen_fault = ctl_status[11]
fac.status_line_1 = ctl_status[12] fac.status_lines[1] = ctl_status[12]
fac.status_line_2 = ctl_status[13] fac.status_lines[2] = ctl_status[13]
fac.ps.publish("all_sys_ok", fac.all_sys_ok) fac.ps.publish("all_sys_ok", fac.all_sys_ok)
fac.ps.publish("auto_ready", fac.auto_ready) 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_crit_alarm", fac.ascram_status.crit_alarm)
fac.ps.publish("as_radiation", fac.ascram_status.radiation) fac.ps.publish("as_radiation", fac.ascram_status.radiation)
fac.ps.publish("as_gen_fault", fac.ascram_status.gen_fault) 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_1", fac.status_lines[1])
fac.ps.publish("status_line_2", fac.status_line_2) fac.ps.publish("status_line_2", fac.status_lines[2])
local group_map = ctl_status[14] local group_map = ctl_status[14]
@ -1130,15 +1135,19 @@ function iocontrol.update_unit_statuses(statuses)
if type(unit_state) == "table" then if type(unit_state) == "table" then
if #unit_state == 8 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_mode = unit_state[5]
unit.waste_product = unit_state[6] unit.waste_product = unit_state[6]
unit.last_rate_change_ms = unit_state[7] unit.last_rate_change_ms = unit_state[7]
unit.turbine_flow_stable = unit_state[8] unit.turbine_flow_stable = unit_state[8]
unit.unit_ps.publish("U_StatusLine1", unit_state[1]) unit.unit_ps.publish("U_StatusLine1", unit.status_lines[1])
unit.unit_ps.publish("U_StatusLine2", unit_state[2]) unit.unit_ps.publish("U_StatusLine2", unit.status_lines[2])
unit.unit_ps.publish("U_AutoReady", unit_state[3]) unit.unit_ps.publish("U_AutoReady", unit.auto_ready)
unit.unit_ps.publish("U_AutoDegraded", unit_state[4]) 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_AutoWaste", unit.waste_mode == types.WASTE_MODE.AUTO)
unit.unit_ps.publish("U_WasteMode", unit.waste_mode) unit.unit_ps.publish("U_WasteMode", unit.waste_mode)
unit.unit_ps.publish("U_WasteProduct", unit.waste_product) unit.unit_ps.publish("U_WasteProduct", unit.waste_product)

View File

@ -25,12 +25,12 @@ local pctl = {
control_states = { control_states = {
---@class sys_auto_config ---@class sys_auto_config
process = { process = {
mode = PROCESS.INACTIVE, mode = PROCESS.INACTIVE, ---@type PROCESS
burn_target = 0.0, burn_target = 0.0,
charge_target = 0.0, charge_target = 0.0,
gen_target = 0.0, gen_target = 0.0,
limits = {}, ---@type number[] limits = {}, ---@type number[]
waste_product = PRODUCT.PLUTONIUM, waste_product = PRODUCT.PLUTONIUM, ---@type WASTE_PRODUCT
pu_fallback = false, pu_fallback = false,
sps_low_power = false sps_low_power = false
}, },
@ -49,6 +49,7 @@ local pctl = {
---@field requestors function[] list of callbacks from the requestors ---@field requestors function[] list of callbacks from the requestors
-- write auto process control to config file -- write auto process control to config file
---@return boolean saved
local function _write_auto_config() local function _write_auto_config()
-- save config -- save config
settings.set("ControlStates", pctl.control_states) settings.set("ControlStates", pctl.control_states)
@ -60,6 +61,8 @@ local function _write_auto_config()
return saved return saved
end end
--#region Core
-- initialize the process controller -- initialize the process controller
---@param iocontrol ioctl iocontrl system ---@param iocontrol ioctl iocontrl system
---@param coord_comms coord_comms coordinator communications ---@param coord_comms coord_comms coordinator communications
@ -180,6 +183,36 @@ function process.create_handle()
end end
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 = {} handle.fac_ack = {}
-- luacheck: no unused args -- luacheck: no unused args
@ -194,6 +227,16 @@ function process.create_handle()
---@diagnostic disable-next-line: unused-local ---@diagnostic disable-next-line: unused-local
function handle.fac_ack.on_ack_alarms(success) end 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 -- luacheck: unused args
--#endregion --#endregion
@ -294,6 +337,14 @@ function process.clear_timed_out()
end end
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 -- handle a command acknowledgement
---@param cmd_state process_command_state ---@param cmd_state process_command_state
---@param success boolean if the command was successful ---@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)) log.debug(util.c("PROCESS: UNIT[", id, "] SET BURN ", rate))
end 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 -- set waste mode
---@param id integer unit ID ---@param id integer unit ID
---@param mode integer waste mode ---@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)) log.debug(util.c("PROCESS: UNIT[", id, "] RESET ALARM ", alarm))
end 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 --#endregion
-------------------------- --------------------------
-- AUTO PROCESS CONTROL -- -- 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 -- set automatic process control waste mode
---@param product WASTE_PRODUCT waste product for auto control ---@param product WASTE_PRODUCT waste product for auto control
function process.set_process_waste(product) function process.set_process_waste(product)
@ -439,9 +478,9 @@ function process.set_sps_low_power(enabled)
end end
-- save process control settings -- save process control settings
---@param mode PROCESS control mode ---@param mode PROCESS process control mode
---@param burn_target number burn rate target ---@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 gen_target number generation rate target
---@param limits number[] unit burn rate limits ---@param limits number[] unit burn rate limits
function process.save(mode, burn_target, charge_target, gen_target, 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 for i = 1, math.min(#response[6], pctl.io.facility.num_units) do
ctl_proc.limits[i] = response[6][i] ctl_proc.limits[i] = response[6][i]
pctl.io.units[i].unit_ps.publish("burn_limit", ctl_proc.limits[i])
local unit = pctl.io.units[i]
unit.unit_ps.publish("burn_limit", ctl_proc.limits[i])
end end
pctl.io.facility.ps.publish("process_mode", ctl_proc.mode) 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_charge_target", pctl.io.energy_convert_from_fe(ctl_proc.charge_target))
pctl.io.facility.ps.publish("process_gen_target", pctl.io.energy_convert_from_fe(ctl_proc.gen_target)) pctl.io.facility.ps.publish("process_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 end
-- record waste product settting after attempting to change it -- 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) pctl.io.facility.ps.publish("process_sps_low_power", response)
end end
--#endregion
return process return process

View File

@ -108,14 +108,20 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
-- link callback transmissions -- link callback transmissions
self.proc_handle.fac_ack.on_scram = function (success) _send(CRDN_TYPE.FAC_CMD, { FAC_COMMAND.SCRAM_ALL, success }) end local f_ack = self.proc_handle.fac_ack
self.proc_handle.fac_ack.on_ack_alarms = function (success) _send(CRDN_TYPE.FAC_CMD, { FAC_COMMAND.ACK_ALL_ALARMS, success }) end
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 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 local u_ack = self.proc_handle.unit_ack[u]
self.proc_handle.unit_ack[u].on_scram = function (success) _send(CRDN_TYPE.UNIT_CMD, { UNIT_COMMAND.SCRAM, u, success }) end u_ack.on_start = function (success) _send(CRDN_TYPE.UNIT_CMD, { UNIT_COMMAND.START, 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 u_ack.on_scram = function (success) _send(CRDN_TYPE.UNIT_CMD, { UNIT_COMMAND.SCRAM, 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 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 end
-- handle a packet -- 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") log.info(log_tag .. "FAC SCRAM ALL")
self.proc_handle.fac_scram() self.proc_handle.fac_scram()
elseif cmd == FAC_COMMAND.STOP then elseif cmd == FAC_COMMAND.STOP then
log.info(log_tag .. "STOP PROCESS CTRL")
self.proc_handle.process_stop()
elseif cmd == FAC_COMMAND.START then 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 elseif cmd == FAC_COMMAND.ACK_ALL_ALARMS then
log.info(log_tag .. "FAC ACK ALL ALARMS") log.info(log_tag .. "FAC ACK ALL ALARMS")
self.proc_handle.fac_ack_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.ACK_ALARM then
elseif cmd == UNIT_COMMAND.RESET_ALARM then elseif cmd == UNIT_COMMAND.RESET_ALARM then
elseif cmd == UNIT_COMMAND.SET_GROUP 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 else
log.debug(log_tag .. "CRDN unit command unknown") log.debug(log_tag .. "CRDN unit command unknown")
end end
@ -259,6 +279,37 @@ function pocket.new_session(id, s_addr, i_seq_num, in_queue, out_queue, timeout)
end end
_send(CRDN_TYPE.API_GET_CTRL, data) _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 else
log.debug(log_tag .. "handler received unsupported CRDN packet type " .. pkt.type) log.debug(log_tag .. "handler received unsupported CRDN packet type " .. pkt.type)
end end

View File

@ -264,24 +264,22 @@ local function new_view(root, x, y)
local limits = {} local limits = {}
for i = 1, #rate_limits do limits[i] = rate_limits[i].get_value() end for i = 1, #rate_limits do limits[i] = rate_limits[i].get_value() end
process.save(mode.get_value(), b_target.get_value(), process.save(mode.get_value(), b_target.get_value(), db.energy_convert_to_fe(c_target.get_value()),
db.energy_convert_to_fe(c_target.get_value()), db.energy_convert_to_fe(g_target.get_value()), limits)
db.energy_convert_to_fe(g_target.get_value()),
limits)
end end
-- start automatic control after saving process control settings -- start automatic control after saving process control settings
local function _start_auto() local function _start_auto()
_save_cfg() _save_cfg()
process.start_auto() db.process.process_start()
end 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 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 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 db.process.fac_ack.on_start = start.on_response
facility.stop_ack = stop.on_response db.process.fac_ack.on_stop = stop.on_response
function facility.save_cfg_ack(ack) function facility.save_cfg_ack(ack)
tcd.dispatch(0.2, function () save.on_response(ack) end) tcd.dispatch(0.2, function () save.on_response(ack) end)

View File

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

View File

@ -11,6 +11,7 @@ local KEY_CLICK = core.events.KEY_CLICK
---@field options table button options ---@field options table button options
---@field radio_colors cpair radio button colors (inner & outer) ---@field radio_colors cpair radio button colors (inner & outer)
---@field select_color color color for radio button border when selected ---@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 default? integer default state, defaults to options[1]
---@field min_width? integer text length + 2 if omitted ---@field min_width? integer text length + 2 if omitted
---@field callback? function function to call on touch ---@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 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) 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_cur(1, i)
e.w_set_fgd(inner_color) e.w_set_fgd(inner_color)
@ -75,9 +80,14 @@ return function (args)
e.w_write("\x95") e.w_write("\x95")
-- write button text -- write button text
if i == focused_opt and e.is_focused() and e.enabled then 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_fgd(e.fg_bg.bkg)
e.w_set_bkg(e.fg_bg.fgd) e.w_set_bkg(e.fg_bg.fgd)
end
else else
e.w_set_fgd(e.fg_bg.fgd) e.w_set_fgd(e.fg_bg.fgd)
e.w_set_bkg(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)

View File

@ -44,8 +44,47 @@ return function (args)
args.max_chars = args.max_chars or e.frame.w 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 -- set initial value
e.value = "" .. (args.default or 0) _set_value(args.default or 0)
-- make an interactive field manager -- make an interactive field manager
local ifield = core.new_ifield(e, args.max_chars, args.fg_bg, args.dis_fg_bg, args.align_right) 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) -- set the value (must be a number)
---@param val number number to show ---@param val number number to show
function e.set_value(val) 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 end
-- set minimum input value -- set minimum input value
@ -136,11 +185,9 @@ return function (args)
-- handle unfocused -- handle unfocused
function e.on_unfocused() function e.on_unfocused()
local val = tonumber(e.value) local val, max, min = tonumber(e.value), tonumber(args.max), tonumber(args.min)
local max = tonumber(args.max)
local min = tonumber(args.min)
if type(val) == "number" then if val then
if args.max_int_digits or args.max_frac_digits then if args.max_int_digits or args.max_frac_digits then
local str = e.value local str = e.value
local ceil = false local ceil = false
@ -169,17 +216,17 @@ return function (args)
if parts[2] then parts[2] = "." .. parts[2] else parts[2] = "" end 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 end
if type(args.max) == "number" and val > max then if max and val > max then
e.value = "" .. max _set_value(max)
ifield.nav_start() ifield.nav_start()
elseif type(args.min) == "number" and val < min then elseif min and val < min then
e.value = "" .. min _set_value(min)
ifield.nav_start() ifield.nav_start()
else else
e.value = "" .. val _set_value(val)
ifield.nav_end() ifield.nav_end()
end end
else else
@ -198,5 +245,11 @@ return function (args)
---@class NumberField:graphics_element ---@class NumberField:graphics_element
local NumberField, id = e.complete(true) 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 return NumberField, id
end end

View File

@ -6,7 +6,6 @@ local const = require("scada-common.constants")
local psil = require("scada-common.psil") 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 log = require("scada-common.log")
local process = require("pocket.process") local process = require("pocket.process")
@ -94,7 +93,8 @@ function iocontrol.init_core(pkt_comms, nav, cfg)
---@class pocket_ioctl_api ---@class pocket_ioctl_api
io.api = { io.api = {
get_unit = function (unit) comms.api__get_unit(unit) end, 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 end
@ -138,6 +138,8 @@ function iocontrol.init_fac(conf)
all_sys_ok = false, all_sys_ok = false,
rtu_count = 0, rtu_count = 0,
status_lines = { "", "" },
auto_ready = false, auto_ready = false,
auto_active = false, auto_active = false,
auto_ramping = false, auto_ramping = false,
@ -197,6 +199,11 @@ function iocontrol.init_fac(conf)
num_snas = 0, num_snas = 0,
has_tank = conf.cooling.r_cool[i].TankConnection, has_tank = conf.cooling.r_cool[i].TankConnection,
status_lines = { "", "" },
auto_ready = false,
auto_degraded = false,
control_state = false, control_state = false,
burn_rate_cmd = 0.0, burn_rate_cmd = 0.0,
radiation = types.new_zero_radiation_reading(), radiation = types.new_zero_radiation_reading(),
@ -817,9 +824,6 @@ function iocontrol.record_control_data(data)
local unit = io.units[u_id] local unit = io.units[u_id]
local u_data = data[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.reactor_data.rps_tripped = u_data[2]
@ -857,6 +861,63 @@ function iocontrol.record_control_data(data)
unit.unit_ps.publish("U_ControlStatus", control_status) unit.unit_ps.publish("U_ControlStatus", control_status)
end end
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 end
-- get the IO controller database -- get the IO controller database

View File

@ -82,18 +82,20 @@ end
---@enum POCKET_APP_ID ---@enum POCKET_APP_ID
local APP_ID = { local APP_ID = {
-- core UI
ROOT = 1, ROOT = 1,
LOADER = 2, LOADER = 2,
-- main app pages -- main app pages
UNITS = 3, UNITS = 3,
CONTROL = 4, CONTROL = 4,
GUIDE = 5, PROCESS = 5,
ABOUT = 6, GUIDE = 6,
-- diag app page ABOUT = 7,
ALARMS = 7, -- diagnostic app pages
ALARMS = 8,
-- other -- other
DUMMY = 8, DUMMY = 9,
NUM_APPS = 8 NUM_APPS = 9
} }
pocket.APP_ID = APP_ID pocket.APP_ID = APP_ID
@ -167,9 +169,9 @@ function pocket.init_nav(smem)
-- configure the sidebar -- configure the sidebar
---@param items sidebar_entry[] ---@param items sidebar_entry[]
function app.set_sidebar(items) function app.set_sidebar(items)
app.sidebar_items = items
-- only modify the sidebar if this app is still open -- only modify the sidebar if this app is still open
if self.cur_app == app_id then if self.cur_app == app_id then
app.sidebar_items = items
if self.sidebar then self.sidebar.update(items) end if self.sidebar then self.sidebar.update(items) end
end end
end end
@ -178,8 +180,8 @@ function pocket.init_nav(smem)
---@param on_load function callback ---@param on_load function callback
function app.set_load(on_load) function app.set_load(on_load)
app.load = function () app.load = function ()
app.loaded = true -- must flag first so it can't be repeatedly attempted
on_load() on_load()
app.loaded = true
end end
end end
@ -187,8 +189,8 @@ function pocket.init_nav(smem)
---@param on_unload function callback ---@param on_unload function callback
function app.set_unload(on_unload) function app.set_unload(on_unload)
app.unload = function () app.unload = function ()
on_unload()
app.loaded = false app.loaded = false
on_unload()
end end
end end
@ -288,6 +290,9 @@ function pocket.init_nav(smem)
end end
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 -- open the app that was blocked on connecting
function nav.on_loader_connected() function nav.on_loader_connected()
if self.loader_return then 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 if self.api.linked then _send_api(CRDN_TYPE.API_GET_CTRL, {}) end
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 -- send a facility command
---@param cmd FAC_COMMAND command ---@param cmd FAC_COMMAND command
---@param option any? optional option options for the optional options (like waste mode) ---@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 }) _send_api(CRDN_TYPE.FAC_CMD, { cmd, option })
end 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 -- send a unit command
---@param cmd UNIT_COMMAND command ---@param cmd UNIT_COMMAND command
---@param unit integer unit ID ---@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 if cmd == FAC_COMMAND.SCRAM_ALL then
iocontrol.get_db().facility.scram_ack(ack) iocontrol.get_db().facility.scram_ack(ack)
elseif cmd == FAC_COMMAND.STOP then elseif cmd == FAC_COMMAND.STOP then
iocontrol.get_db().facility.stop_ack(ack)
elseif cmd == FAC_COMMAND.START then elseif cmd == FAC_COMMAND.START then
iocontrol.get_db().facility.start_ack(ack)
elseif cmd == FAC_COMMAND.ACK_ALL_ALARMS then elseif cmd == FAC_COMMAND.ACK_ALL_ALARMS then
iocontrol.get_db().facility.ack_alarms_ack(ack) iocontrol.get_db().facility.ack_alarms_ack(ack)
elseif cmd == FAC_COMMAND.SET_WASTE_MODE then 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 if _check_length(packet, #iocontrol.get_db().units) then
iocontrol.record_control_data(packet.data) iocontrol.record_control_data(packet.data)
end 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 _fail_type(packet) end
else else
log.debug("discarding coordinator SCADA_CRDN packet before linked") log.debug("discarding coordinator SCADA_CRDN packet before linked")

View File

@ -6,8 +6,8 @@ local comms = require("scada-common.comms")
local log = require("scada-common.log") local log = require("scada-common.log")
local util = require("scada-common.util") local util = require("scada-common.util")
local FAC_COMMAND = comms.FAC_COMMAND local F_CMD = comms.FAC_COMMAND
local UNIT_COMMAND = comms.UNIT_COMMAND local U_CMD = comms.UNIT_COMMAND
---@class pocket_process_controller ---@class pocket_process_controller
local process = {} local process = {}
@ -25,23 +25,32 @@ function process.init(iocontrol, pocket_comms)
self.comms = pocket_comms self.comms = pocket_comms
end end
------------------------------
--#region FACILITY COMMANDS --
-- facility SCRAM command -- facility SCRAM command
function process.fac_scram() 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") log.debug("PROCESS: FAC SCRAM ALL")
end end
-- facility alarm acknowledge command -- facility alarm acknowledge command
function process.fac_ack_alarms() 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") log.debug("PROCESS: FAC ACK ALL ALARMS")
end end
--#endregion
------------------------------
--------------------------
--#region UNIT COMMANDS --
-- start reactor -- start reactor
---@param id integer unit ID ---@param id integer unit ID
function process.start(id) function process.start(id)
self.io.units[id].control_state = true 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")) log.debug(util.c("PROCESS: UNIT[", id, "] START"))
end end
@ -49,14 +58,14 @@ end
---@param id integer unit ID ---@param id integer unit ID
function process.scram(id) function process.scram(id)
self.io.units[id].control_state = false 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")) log.debug(util.c("PROCESS: UNIT[", id, "] SCRAM"))
end end
-- reset reactor protection system -- reset reactor protection system
---@param id integer unit ID ---@param id integer unit ID
function process.reset_rps(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")) log.debug(util.c("PROCESS: UNIT[", id, "] RESET RPS"))
end end
@ -64,14 +73,22 @@ end
---@param id integer unit ID ---@param id integer unit ID
---@param rate number burn rate ---@param rate number burn rate
function process.set_rate(id, 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)) log.debug(util.c("PROCESS: UNIT[", id, "] SET BURN ", rate))
end 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 -- acknowledge all alarms
---@param id integer unit ID ---@param id integer unit ID
function process.ack_all_alarms(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")) log.debug(util.c("PROCESS: UNIT[", id, "] ACK ALL ALARMS"))
end end
@ -79,7 +96,7 @@ end
---@param id integer unit ID ---@param id integer unit ID
---@param alarm integer alarm ID ---@param alarm integer alarm ID
function process.ack_alarm(id, alarm) 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)) log.debug(util.c("PROCESS: UNIT[", id, "] ACK ALARM ", alarm))
end end
@ -87,8 +104,34 @@ end
---@param id integer unit ID ---@param id integer unit ID
---@param alarm integer alarm ID ---@param alarm integer alarm ID
function process.reset_alarm(id, alarm) 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)) log.debug(util.c("PROCESS: UNIT[", id, "] RESET ALARM ", alarm))
end 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 return process

View File

@ -20,7 +20,7 @@ local pocket = require("pocket.pocket")
local renderer = require("pocket.renderer") local renderer = require("pocket.renderer")
local threads = require("pocket.threads") 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 = util.println
local println_ts = util.println_ts local println_ts = util.println_ts

View File

@ -34,16 +34,21 @@ local cpair = core.cpair
local APP_ID = pocket.APP_ID local APP_ID = pocket.APP_ID
local label_fg_bg = style.label
local lu_col = style.label_unit_pair local lu_col = style.label_unit_pair
local text_fg = style.text_fg local text_fg = style.text_fg
local mode_states = style.icon_states.mode_states local mode_states = style.icon_states.mode_states
local hzd_fg_bg = cpair(colors.white, colors.gray) local btn_active = cpair(colors.white, colors.black)
local dis_colors = cpair(colors.white, colors.lightGray) local hzd_fg_bg = style.hzd_fg_bg
local hzd_dis_colors = style.hzd_dis_colors
-- new unit control page view -- new unit control page view
---@param root Container parent ---@param root Container parent
local function new_view(root) local function new_view(root)
local btn_fg_bg = cpair(colors.green, colors.black)
local db = iocontrol.get_db() local db = iocontrol.get_db()
local frame = Div{parent=root,x=1,y=1} 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}} 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.green, colors.black)
local btn_active = cpair(colors.white, colors.black)
local page_div = nil ---@type Div|nil local page_div = nil ---@type Div|nil
-- set sidebar to display unit-specific fields based on a specified unit -- set sidebar to display unit-specific fields based on a specified unit
local function set_sidebar() local function set_sidebar()
local list = { 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 } { 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() 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,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=cpair(colors.lightGray,colors.black)} 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=cpair(colors.white,colors.gray),dis_fg_bg=cpair(colors.gray,colors.lightGray)} 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 = 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=cpair(colors.gray,colors.black),callback=set_burn} 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) -- enable/disable controls based on group assignment (start button is separate)
burn_cmd.register(u_ps, "auto_group_id", function (gid) 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, "burn_rate", burn_cmd.set_value)
burn_cmd.register(u_ps, "max_burn", burn_cmd.set_max) 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 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,dis_colors=dis_colors,callback=unit.ack_alarms,timeout=3,fg_bg=hzd_fg_bg} 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,dis_colors=dis_colors,callback=unit.scram,timeout=3,fg_bg=hzd_fg_bg} 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,dis_colors=dis_colors,callback=unit.reset_rps,timeout=3,fg_bg=hzd_fg_bg} 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.start_ack = start.on_response
unit.ack_alarms_ack = ack_a.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} 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 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=dis_colors,callback=process.fac_ack_alarms,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.scram_ack = scram.on_response
db.facility.ack_alarms_ack = ack_a.on_response db.facility.ack_alarms_ack = ack_a.on_response
@ -215,7 +217,7 @@ local function new_view(root)
page_div = nil page_div = nil
end 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() app.delete_pages()
-- show loading screen -- show loading screen

View File

@ -56,14 +56,14 @@ local function new_view(root)
local btn_active = cpair(colors.white, colors.black) local btn_active = cpair(colors.white, colors.black)
local btn_disable = cpair(colors.gray, 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 local page_div = nil ---@type Div|nil
-- load the app (create the elements) -- load the app (create the elements)
local function load() local function load()
local list = { 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 = " \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 } { 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 page_div = nil
end 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() app.delete_pages()
-- show loading screen -- show loading screen

337
pocket/ui/apps/process.lua Normal file
View 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

View File

@ -63,7 +63,7 @@ local function new_view(root)
local load_pane = MultiPane{parent=main,x=1,y=1,panes={load_div,main}} 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_fg_bg = cpair(colors.yellow, colors.black)
local btn_active = cpair(colors.white, 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 unit = db.units[id]
local list = { 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 = "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 = " \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 }, { 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 page_div = nil
end 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() app.delete_pages()
-- show loading screen -- show loading screen

View File

@ -12,6 +12,7 @@ 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")
local loader_app = require("pocket.ui.apps.loader") 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 sys_apps = require("pocket.ui.apps.sys_apps")
local unit_app = require("pocket.ui.apps.unit") local unit_app = require("pocket.ui.apps.unit")
@ -64,6 +65,7 @@ local function init(main)
home_page(page_div) home_page(page_div)
unit_app(page_div) unit_app(page_div)
control_app(page_div) control_app(page_div)
process_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)
@ -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} 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! -- done with initial render, lets go!
root_pane.set_value(2) root_pane.set_value(2)

View File

@ -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=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.CONTROL)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.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=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}
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} 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}

View File

@ -13,9 +13,16 @@ local cpair = core.cpair
style.root = cpair(colors.white, colors.black) style.root = cpair(colors.white, colors.black)
style.header = cpair(colors.white, colors.gray) style.header = cpair(colors.white, colors.gray)
style.text_fg = cpair(colors.white, colors._INHERIT) style.text_fg = cpair(colors.white, colors._INHERIT)
style.label = cpair(colors.lightGray, colors.black) style.label = cpair(colors.lightGray, colors.black)
style.label_unit_pair = cpair(colors.lightGray, colors.lightGray) 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 = { style.colors = {
{ c = colors.red, hex = 0xdf4949 }, { c = colors.red, hex = 0xdf4949 },
{ c = colors.orange, hex = 0xffb659 }, { c = colors.orange, hex = 0xffb659 },
@ -73,6 +80,16 @@ states.yel_ind_s = {
{ color = cpair(colors.black, colors.yellow), symbol = "-" } { 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 style.icon_states = states
-- MAIN LAYOUT -- -- MAIN LAYOUT --

View File

@ -18,7 +18,7 @@ local comms = {}
-- protocol/data versions (protocol/data independent changes tracked by util.lua version) -- protocol/data versions (protocol/data independent changes tracked by util.lua version)
comms.version = "3.0.0" comms.version = "3.0.0"
comms.api_version = "0.0.5" comms.api_version = "0.0.6"
---@enum PROTOCOL ---@enum PROTOCOL
local PROTOCOL = { local PROTOCOL = {
@ -68,7 +68,8 @@ local CRDN_TYPE = {
UNIT_CMD = 6, -- command a reactor unit UNIT_CMD = 6, -- command a reactor unit
API_GET_FAC = 7, -- API: get all the facility data API_GET_FAC = 7, -- API: get all the facility data
API_GET_UNIT = 8, -- API: get reactor unit 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 ---@enum ESTABLISH_ACK

View File

@ -425,9 +425,9 @@ function facility.new(config)
ready = self.mode_set > 0 ready = self.mode_set > 0
if (self.mode_set == PROCESS.CHARGE) and (self.charge_setpoint <= 0) or 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.GEN_RATE) and (self.gen_rate_setpoint <= 0)) or
(self.mode_set == PROCESS.BURN_RATE) and (self.burn_target < 0.1) then ((self.mode_set == PROCESS.BURN_RATE) and (self.burn_target < 0.1)) then
ready = false ready = false
end end
@ -436,6 +436,8 @@ function facility.new(config)
if ready then self.mode = self.mode_set end if ready then self.mode = self.mode_set end
end end
log.debug(util.c("FAC: process start ", util.trinary(ready, "accepted", "rejected")))
return { return {
ready, ready,
self.mode_set, self.mode_set,

View File

@ -22,7 +22,7 @@ local supervisor = require("supervisor.supervisor")
local svsessions = require("supervisor.session.svsessions") local svsessions = require("supervisor.session.svsessions")
local SUPERVISOR_VERSION = "v1.5.8" local SUPERVISOR_VERSION = "v1.5.9"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts