#143 #103 #101 #102 work in progress auto control, added coordinator controls, save/auto load configuration, auto enable/disable on reactor PLC for auto control (untested)
This commit is contained in:
@@ -2,10 +2,10 @@ local comms = require("scada-common.comms")
|
||||
local log = require("scada-common.log")
|
||||
local ppm = require("scada-common.ppm")
|
||||
local util = require("scada-common.util")
|
||||
local process = require("coordinator.process")
|
||||
|
||||
local apisessions = require("coordinator.apisessions")
|
||||
local iocontrol = require("coordinator.iocontrol")
|
||||
local process = require("coordinator.process")
|
||||
|
||||
local dialog = require("coordinator.ui.dialog")
|
||||
|
||||
@@ -20,6 +20,7 @@ local ESTABLISH_ACK = comms.ESTABLISH_ACK
|
||||
local SCADA_MGMT_TYPES = comms.SCADA_MGMT_TYPES
|
||||
local SCADA_CRDN_TYPES = comms.SCADA_CRDN_TYPES
|
||||
local UNIT_COMMANDS = comms.UNIT_COMMANDS
|
||||
local FAC_COMMANDS = comms.FAC_COMMANDS
|
||||
|
||||
local coordinator = {}
|
||||
|
||||
@@ -313,11 +314,25 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, sv_wa
|
||||
return self.sv_linked
|
||||
end
|
||||
|
||||
-- send a facility command
|
||||
---@param cmd FAC_COMMANDS command
|
||||
function public.send_fac_command(cmd)
|
||||
_send_sv(PROTOCOLS.SCADA_CRDN, SCADA_CRDN_TYPES.FAC_CMD, { cmd })
|
||||
end
|
||||
|
||||
-- send the auto process control configuration with a start command
|
||||
---@param config coord_auto_config configuration
|
||||
function public.send_auto_start(config)
|
||||
_send_sv(PROTOCOLS.SCADA_CRDN, SCADA_CRDN_TYPES.FAC_CMD, {
|
||||
FAC_COMMANDS.START, config.mode, config.burn_target, config.charge_target, config.gen_target, config.limits
|
||||
})
|
||||
end
|
||||
|
||||
-- send a unit command
|
||||
---@param cmd UNIT_COMMANDS command
|
||||
---@param unit integer unit ID
|
||||
---@param option any? optional options (like burn rate)
|
||||
function public.send_command(cmd, unit, option)
|
||||
---@param option any? optional option options for the optional options (like burn rate) (does option still look like a word?)
|
||||
function public.send_unit_command(cmd, unit, option)
|
||||
_send_sv(PROTOCOLS.SCADA_CRDN, SCADA_CRDN_TYPES.UNIT_CMD, { cmd, unit, option })
|
||||
end
|
||||
|
||||
@@ -412,6 +427,26 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, sv_wa
|
||||
end
|
||||
elseif packet.type == SCADA_CRDN_TYPES.FAC_CMD then
|
||||
-- facility command acknowledgement
|
||||
if packet.length >= 2 then
|
||||
local cmd = packet.data[1]
|
||||
local ack = packet.data[2] == true
|
||||
|
||||
if cmd == FAC_COMMANDS.SCRAM_ALL then
|
||||
iocontrol.get_db().facility.scram_ack(ack)
|
||||
elseif cmd == FAC_COMMANDS.STOP then
|
||||
iocontrol.get_db().facility.stop_ack(ack)
|
||||
elseif cmd == FAC_COMMANDS.START then
|
||||
if packet.length == 7 then
|
||||
process.start_ack_handle({ table.unpack(packet.data, 2) })
|
||||
else
|
||||
log.debug("SCADA_CRDN process start (with configuration) ack echo packet length mismatch")
|
||||
end
|
||||
else
|
||||
log.debug(util.c("received facility command ack with unknown command ", cmd))
|
||||
end
|
||||
else
|
||||
log.debug("SCADA_CRDN facility command ack packet length mismatch")
|
||||
end
|
||||
elseif packet.type == SCADA_CRDN_TYPES.UNIT_BUILDS then
|
||||
-- record builds
|
||||
if iocontrol.record_unit_builds(packet.data) then
|
||||
|
||||
@@ -24,9 +24,17 @@ function iocontrol.init(conf, comms)
|
||||
---@class ioctl_facility
|
||||
io.facility = {
|
||||
auto_active = false,
|
||||
scram = false,
|
||||
auto_ramping = false,
|
||||
auto_scram = false,
|
||||
auto_scram_cause = "ok", ---@type auto_scram_cause
|
||||
|
||||
num_units = conf.num_units, ---@type integer
|
||||
|
||||
save_cfg_ack = function (success) end, ---@param success boolean
|
||||
start_ack = function (success) end, ---@param success boolean
|
||||
stop_ack = function (success) end, ---@param success boolean
|
||||
scram_ack = function (success) end, ---@param success boolean
|
||||
|
||||
num_units = conf.num_units, ---@type integer
|
||||
ps = psil.create(),
|
||||
|
||||
induction_ps_tbl = {},
|
||||
@@ -69,7 +77,6 @@ function iocontrol.init(conf, comms)
|
||||
set_waste = function (mode) process.set_waste(i, mode) end, ---@param mode integer waste processing mode
|
||||
|
||||
set_group = function (grp) process.set_group(i, grp) end, ---@param grp integer|0 group ID or 0
|
||||
set_limit = function (lim) process.set_limit(i, lim) end, ---@param lim number burn rate limit
|
||||
|
||||
start_ack = function (success) end, ---@param success boolean
|
||||
scram_ack = function (success) end, ---@param success boolean
|
||||
@@ -195,7 +202,7 @@ function iocontrol.record_unit_builds(builds)
|
||||
|
||||
-- reactor build
|
||||
if type(build.reactor) == "table" then
|
||||
unit.reactor_data.mek_struct = build.reactor
|
||||
unit.reactor_data.mek_struct = build.reactor ---@type mek_struct
|
||||
for key, val in pairs(unit.reactor_data.mek_struct) do
|
||||
unit.reactor_ps.publish(key, val)
|
||||
end
|
||||
@@ -257,11 +264,38 @@ function iocontrol.update_facility_status(status)
|
||||
else
|
||||
local fac = io.facility
|
||||
|
||||
-- auto control status information
|
||||
|
||||
local ctl_status = status[1]
|
||||
|
||||
if type(ctl_status) == "table" then
|
||||
fac.auto_active = ctl_status[1] > 0
|
||||
fac.auto_ramping = ctl_status[2]
|
||||
fac.auto_scram = ctl_status[3]
|
||||
fac.auto_scram_cause = ctl_status[4]
|
||||
|
||||
fac.ps.publish("auto_active", fac.auto_active)
|
||||
fac.ps.publish("auto_ramping", fac.auto_ramping)
|
||||
fac.ps.publish("auto_scram", fac.auto_scram)
|
||||
fac.ps.publish("auto_scram_cause", fac.auto_scram_cause)
|
||||
else
|
||||
log.debug(log_header .. "control status not a table")
|
||||
end
|
||||
|
||||
-- RTU statuses
|
||||
|
||||
local rtu_statuses = status[1]
|
||||
local rtu_statuses = status[2]
|
||||
|
||||
if type(rtu_statuses) == "table" then
|
||||
-- power statistics
|
||||
if type(rtu_statuses.power) == "table" then
|
||||
fac.ps.publish("avg_charge", rtu_statuses.power[1])
|
||||
fac.ps.publish("avg_inflow", rtu_statuses.power[2])
|
||||
fac.ps.publish("avg_outflow", rtu_statuses.power[3])
|
||||
else
|
||||
log.debug(log_header .. "power statistics list not a table")
|
||||
end
|
||||
|
||||
-- induction matricies statuses
|
||||
if type(rtu_statuses.induction) == "table" then
|
||||
for id = 1, #fac.induction_ps_tbl do
|
||||
@@ -328,6 +362,8 @@ function iocontrol.update_unit_statuses(statuses)
|
||||
log.debug("iocontrol.update_unit_statuses: number of provided unit statuses does not match expected number of units")
|
||||
return false
|
||||
else
|
||||
local burn_rate_sum = 0.0
|
||||
|
||||
-- get all unit statuses
|
||||
for i = 1, #statuses do
|
||||
local log_header = util.c("iocontrol.update_unit_statuses[unit ", i, "]: ")
|
||||
@@ -369,6 +405,11 @@ function iocontrol.update_unit_statuses(statuses)
|
||||
unit.reactor_data.rps_status = rps_status ---@type rps_status
|
||||
unit.reactor_data.mek_status = mek_status ---@type mek_status
|
||||
|
||||
-- if status hasn't been received, mek_status = {}
|
||||
if type(unit.reactor_data.mek_status.act_burn_rate) == "number" then
|
||||
burn_rate_sum = burn_rate_sum + unit.reactor_data.mek_status.act_burn_rate
|
||||
end
|
||||
|
||||
if unit.reactor_data.mek_status.status then
|
||||
unit.reactor_ps.publish("computed_status", 5) -- running
|
||||
else
|
||||
@@ -596,8 +637,8 @@ function iocontrol.update_unit_statuses(statuses)
|
||||
local auto_ctl_state = status[6]
|
||||
|
||||
if type(auto_ctl_state) == "table" then
|
||||
if #auto_ctl_state == 1 then
|
||||
unit.reactor_ps.publish("burn_limit", auto_ctl_state[1])
|
||||
if #auto_ctl_state == 0 then
|
||||
---@todo
|
||||
else
|
||||
log.debug(log_header .. "auto control state length mismatch")
|
||||
end
|
||||
@@ -606,6 +647,8 @@ function iocontrol.update_unit_statuses(statuses)
|
||||
end
|
||||
end
|
||||
|
||||
io.facility.ps.publish("burn_sum", burn_rate_sum)
|
||||
|
||||
-- update alarm sounder
|
||||
sounder.eval(io.units)
|
||||
end
|
||||
|
||||
@@ -1,16 +1,28 @@
|
||||
|
||||
local comms = require("scada-common.comms")
|
||||
local log = require("scada-common.log")
|
||||
local types = require("scada-common.types")
|
||||
local util = require("scada-common.util")
|
||||
|
||||
local FAC_COMMANDS = comms.FAC_COMMANDS
|
||||
local UNIT_COMMANDS = comms.UNIT_COMMANDS
|
||||
|
||||
local PROCESS = types.PROCESS
|
||||
|
||||
---@class process_controller
|
||||
local process = {}
|
||||
|
||||
local self = {
|
||||
io = nil, ---@type ioctl
|
||||
comms = nil ---@type coord_comms
|
||||
comms = nil, ---@type coord_comms
|
||||
---@class coord_auto_config
|
||||
config = {
|
||||
mode = 0, ---@type PROCESS
|
||||
burn_target = 0.0,
|
||||
charge_target = 0.0,
|
||||
gen_target = 0.0,
|
||||
limits = {} ---@type table
|
||||
}
|
||||
}
|
||||
|
||||
--------------------------
|
||||
@@ -24,11 +36,37 @@ function process.init(iocontrol, comms)
|
||||
self.io = iocontrol
|
||||
self.comms = comms
|
||||
|
||||
for i = 1, self.io.facility.num_units do
|
||||
self.config.limits[i] = 0.1
|
||||
end
|
||||
|
||||
-- load settings
|
||||
if not settings.load("/coord.settings") then
|
||||
log.error("process.init(): failed to load coordinator settings file")
|
||||
end
|
||||
|
||||
local config = settings.get("PROCESS") ---@type coord_auto_config|nil
|
||||
|
||||
if type(config) == "table" then
|
||||
self.config.mode = config.mode
|
||||
self.config.burn_target = config.burn_target
|
||||
self.config.charge_target = config.charge_target
|
||||
self.config.gen_target = config.gen_target
|
||||
self.config.limits = config.limits
|
||||
|
||||
self.io.facility.ps.publish("process_mode", self.config.mode)
|
||||
self.io.facility.ps.publish("process_burn_target", self.config.burn_target)
|
||||
self.io.facility.ps.publish("process_charge_target", self.config.charge_target)
|
||||
self.io.facility.ps.publish("process_gen_target", self.config.gen_target)
|
||||
|
||||
for id = 1, math.min(#self.config.limits, self.io.facility.num_units) do
|
||||
local unit = self.io.units[id] ---@type ioctl_unit
|
||||
unit.reactor_ps.publish("burn_limit", self.config.limits[id])
|
||||
end
|
||||
|
||||
log.info("PROCESS: loaded auto control settings from coord.settings")
|
||||
end
|
||||
|
||||
local waste_mode = settings.get("WASTE_MODES") ---@type table|nil
|
||||
|
||||
if type(waste_mode) == "table" then
|
||||
@@ -44,7 +82,7 @@ end
|
||||
---@param id integer unit ID
|
||||
function process.start(id)
|
||||
self.io.units[id].control_state = true
|
||||
self.comms.send_command(UNIT_COMMANDS.START, id)
|
||||
self.comms.send_unit_command(UNIT_COMMANDS.START, id)
|
||||
log.debug(util.c("UNIT[", id, "]: START"))
|
||||
end
|
||||
|
||||
@@ -52,14 +90,14 @@ end
|
||||
---@param id integer unit ID
|
||||
function process.scram(id)
|
||||
self.io.units[id].control_state = false
|
||||
self.comms.send_command(UNIT_COMMANDS.SCRAM, id)
|
||||
self.comms.send_unit_command(UNIT_COMMANDS.SCRAM, id)
|
||||
log.debug(util.c("UNIT[", id, "]: SCRAM"))
|
||||
end
|
||||
|
||||
-- reset reactor protection system
|
||||
---@param id integer unit ID
|
||||
function process.reset_rps(id)
|
||||
self.comms.send_command(UNIT_COMMANDS.RESET_RPS, id)
|
||||
self.comms.send_unit_command(UNIT_COMMANDS.RESET_RPS, id)
|
||||
log.debug(util.c("UNIT[", id, "]: RESET RPS"))
|
||||
end
|
||||
|
||||
@@ -67,7 +105,7 @@ end
|
||||
---@param id integer unit ID
|
||||
---@param rate number burn rate
|
||||
function process.set_rate(id, rate)
|
||||
self.comms.send_command(UNIT_COMMANDS.SET_BURN, id, rate)
|
||||
self.comms.send_unit_command(UNIT_COMMANDS.SET_BURN, id, rate)
|
||||
log.debug(util.c("UNIT[", id, "]: SET BURN = ", rate))
|
||||
end
|
||||
|
||||
@@ -75,7 +113,7 @@ end
|
||||
---@param id integer unit ID
|
||||
---@param mode integer waste mode
|
||||
function process.set_waste(id, mode)
|
||||
self.comms.send_command(UNIT_COMMANDS.SET_WASTE, id, mode)
|
||||
self.comms.send_unit_command(UNIT_COMMANDS.SET_WASTE, id, mode)
|
||||
log.debug(util.c("UNIT[", id, "]: SET WASTE = ", mode))
|
||||
|
||||
local waste_mode = settings.get("WASTE_MODES") ---@type table|nil
|
||||
@@ -96,7 +134,7 @@ end
|
||||
-- acknowledge all alarms
|
||||
---@param id integer unit ID
|
||||
function process.ack_all_alarms(id)
|
||||
self.comms.send_command(UNIT_COMMANDS.ACK_ALL_ALARMS, id)
|
||||
self.comms.send_unit_command(UNIT_COMMANDS.ACK_ALL_ALARMS, id)
|
||||
log.debug(util.c("UNIT[", id, "]: ACK ALL ALARMS"))
|
||||
end
|
||||
|
||||
@@ -104,7 +142,7 @@ end
|
||||
---@param id integer unit ID
|
||||
---@param alarm integer alarm ID
|
||||
function process.ack_alarm(id, alarm)
|
||||
self.comms.send_command(UNIT_COMMANDS.ACK_ALARM, id, alarm)
|
||||
self.comms.send_unit_command(UNIT_COMMANDS.ACK_ALARM, id, alarm)
|
||||
log.debug(util.c("UNIT[", id, "]: ACK ALARM ", alarm))
|
||||
end
|
||||
|
||||
@@ -112,7 +150,7 @@ end
|
||||
---@param id integer unit ID
|
||||
---@param alarm integer alarm ID
|
||||
function process.reset_alarm(id, alarm)
|
||||
self.comms.send_command(UNIT_COMMANDS.RESET_ALARM, id, alarm)
|
||||
self.comms.send_unit_command(UNIT_COMMANDS.RESET_ALARM, id, alarm)
|
||||
log.debug(util.c("UNIT[", id, "]: RESET ALARM ", alarm))
|
||||
end
|
||||
|
||||
@@ -120,16 +158,86 @@ end
|
||||
---@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_command(UNIT_COMMANDS.SET_GROUP, unit_id, group_id)
|
||||
self.comms.send_unit_command(UNIT_COMMANDS.SET_GROUP, unit_id, group_id)
|
||||
log.debug(util.c("UNIT[", unit_id, "]: SET GROUP ", group_id))
|
||||
end
|
||||
|
||||
-- set the burn rate limit
|
||||
---@param id integer unit ID
|
||||
---@param limit number burn rate limit
|
||||
function process.set_limit(id, limit)
|
||||
self.comms.send_command(UNIT_COMMANDS.SET_LIMIT, id, limit)
|
||||
log.debug(util.c("UNIT[", id, "]: SET LIMIT = ", limit))
|
||||
--------------------------
|
||||
-- AUTO PROCESS CONTROL --
|
||||
--------------------------
|
||||
|
||||
-- facility SCRAM command
|
||||
function process.fac_scram()
|
||||
self.comms.send_fac_command(FAC_COMMANDS.SCRAM_ALL)
|
||||
log.debug("FAC: SCRAM ALL")
|
||||
end
|
||||
|
||||
-- stop automatic process control
|
||||
function process.stop_auto()
|
||||
self.comms.send_fac_command(FAC_COMMANDS.STOP)
|
||||
log.debug("FAC: STOP AUTO")
|
||||
end
|
||||
|
||||
-- start automatic process control
|
||||
function process.start_auto()
|
||||
self.comms.send_auto_start(self.config)
|
||||
log.debug("FAC: START AUTO")
|
||||
end
|
||||
|
||||
-- save process control settings
|
||||
---@param mode PROCESS control mode
|
||||
---@param burn_target number burn rate target
|
||||
---@param charge_target number charge target
|
||||
---@param gen_target number generation rate target
|
||||
---@param limits table unit burn rate limits
|
||||
function process.save(mode, burn_target, charge_target, gen_target, limits)
|
||||
-- attempt to load settings
|
||||
if not settings.load("/coord.settings") then
|
||||
log.warning("process.save(): failed to load coordinator settings file")
|
||||
end
|
||||
|
||||
-- config table
|
||||
self.config = {
|
||||
mode = mode,
|
||||
burn_target = burn_target,
|
||||
charge_target = charge_target,
|
||||
gen_target = gen_target,
|
||||
limits = limits
|
||||
}
|
||||
|
||||
-- save config
|
||||
settings.set("PROCESS", self.config)
|
||||
local saved = settings.save("/coord.settings")
|
||||
|
||||
if not saved then
|
||||
log.warning("process.save(): failed to save coordinator settings file")
|
||||
end
|
||||
|
||||
log.debug("saved = " .. util.strval(saved))
|
||||
|
||||
self.io.facility.save_cfg_ack(saved)
|
||||
end
|
||||
|
||||
-- handle a start command acknowledgement
|
||||
---@param response table ack and configuration reply
|
||||
function process.start_ack_handle(response)
|
||||
local ack = response[1]
|
||||
|
||||
self.config.mode = response[2]
|
||||
self.config.burn_target = response[3]
|
||||
self.config.charge_target = response[4]
|
||||
self.config.gen_target = response[5]
|
||||
|
||||
for i = 1, #response[6] do
|
||||
self.config.limits[i] = response[6][i]
|
||||
end
|
||||
|
||||
self.io.facility.ps.publish("auto_mode", self.config.mode)
|
||||
self.io.facility.ps.publish("burn_target", self.config.burn_target)
|
||||
self.io.facility.ps.publish("charge_target", self.config.charge_target)
|
||||
self.io.facility.ps.publish("gen_target", self.config.gen_target)
|
||||
|
||||
self.io.facility.start_ack(ack)
|
||||
end
|
||||
|
||||
--------------------------
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
local tcd = require("scada-common.tcallbackdsp")
|
||||
local util = require("scada-common.util")
|
||||
|
||||
local iocontrol = require("coordinator.iocontrol")
|
||||
local process = require("coordinator.process")
|
||||
|
||||
local style = require("coordinator.ui.style")
|
||||
|
||||
@@ -36,29 +38,127 @@ local function new_view(root, x, y)
|
||||
local facility = iocontrol.get_db().facility
|
||||
local units = iocontrol.get_db().units
|
||||
|
||||
local bw_fg_bg = cpair(colors.black, colors.white)
|
||||
local bw_fg_bg = cpair(colors.black, colors.white)
|
||||
local hzd_fg_bg = cpair(colors.white, colors.gray)
|
||||
local dis_colors = cpair(colors.white, colors.lightGray)
|
||||
|
||||
local proc = Div{parent=root,width=60,height=24,x=x,y=y}
|
||||
local main = Div{parent=root,width=80,height=24,x=x,y=y}
|
||||
|
||||
local limits = Div{parent=proc,width=40,height=24,x=30,y=1}
|
||||
local scram = HazardButton{parent=main,x=1,y=1,text="FAC SCRAM",accent=colors.yellow,dis_colors=dis_colors,callback=process.fac_scram,fg_bg=hzd_fg_bg}
|
||||
|
||||
facility.scram_ack = scram.on_response
|
||||
|
||||
---------------------
|
||||
-- process control --
|
||||
---------------------
|
||||
|
||||
local proc = Div{parent=main,width=54,height=24,x=27,y=1}
|
||||
|
||||
-----------------------------
|
||||
-- process control targets --
|
||||
-----------------------------
|
||||
|
||||
local targets = Div{parent=proc,width=31,height=24,x=1,y=1}
|
||||
|
||||
local burn_tag = Div{parent=targets,x=1,y=1,width=8,height=4,fg_bg=cpair(colors.black,colors.purple)}
|
||||
TextBox{parent=burn_tag,x=2,y=2,text="Burn Target",width=7,height=2}
|
||||
|
||||
local burn_target = Div{parent=targets,x=9,y=1,width=23,height=3,fg_bg=cpair(colors.gray,colors.white)}
|
||||
local b_target = SpinboxNumeric{parent=burn_target,x=11,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,arrow_fg_bg=cpair(colors.gray,colors.white),fg_bg=bw_fg_bg}
|
||||
TextBox{parent=burn_target,x=18,y=2,text="mB/t"}
|
||||
local burn_sum = DataIndicator{parent=targets,x=9,y=4,label="",format="%18.1f",value=0,unit="mB/t",commas=true,lu_colors=cpair(colors.black,colors.black),width=23,fg_bg=cpair(colors.black,colors.brown)}
|
||||
|
||||
facility.ps.subscribe("process_burn_target", b_target.set_value)
|
||||
facility.ps.subscribe("burn_sum", burn_sum.update)
|
||||
|
||||
local chg_tag = Div{parent=targets,x=1,y=6,width=8,height=4,fg_bg=cpair(colors.black,colors.purple)}
|
||||
TextBox{parent=chg_tag,x=2,y=2,text="Charge Target",width=7,height=2}
|
||||
|
||||
local chg_target = Div{parent=targets,x=9,y=6,width=23,height=3,fg_bg=cpair(colors.gray,colors.white)}
|
||||
local c_target = SpinboxNumeric{parent=chg_target,x=2,y=1,whole_num_precision=15,fractional_precision=0,min=0,arrow_fg_bg=cpair(colors.gray,colors.white),fg_bg=bw_fg_bg}
|
||||
TextBox{parent=chg_target,x=18,y=2,text="kFE"}
|
||||
local cur_charge = DataIndicator{parent=targets,x=9,y=9,label="",format="%19d",value=0,unit="kFE",commas=true,lu_colors=cpair(colors.black,colors.black),width=23,fg_bg=cpair(colors.black,colors.brown)}
|
||||
|
||||
facility.ps.subscribe("process_charge_target", c_target.set_value)
|
||||
facility.induction_ps_tbl[1].subscribe("energy", function (j) cur_charge.update(util.joules_to_fe(j) / 1000) end)
|
||||
|
||||
local gen_tag = Div{parent=targets,x=1,y=11,width=8,height=4,fg_bg=cpair(colors.black,colors.purple)}
|
||||
TextBox{parent=gen_tag,x=2,y=2,text="Gen. Target",width=7,height=2}
|
||||
|
||||
local gen_target = Div{parent=targets,x=9,y=11,width=23,height=3,fg_bg=cpair(colors.gray,colors.white)}
|
||||
local g_target = SpinboxNumeric{parent=gen_target,x=8,y=1,whole_num_precision=9,fractional_precision=0,min=0,arrow_fg_bg=cpair(colors.gray,colors.white),fg_bg=bw_fg_bg}
|
||||
TextBox{parent=gen_target,x=18,y=2,text="kFE/t"}
|
||||
local cur_gen = DataIndicator{parent=targets,x=9,y=14,label="",format="%17d",value=0,unit="kFE/t",commas=true,lu_colors=cpair(colors.black,colors.black),width=23,fg_bg=cpair(colors.black,colors.brown)}
|
||||
|
||||
facility.ps.subscribe("process_gen_target", g_target.set_value)
|
||||
facility.induction_ps_tbl[1].subscribe("last_input", function (j) cur_gen.update(util.joules_to_fe(j) / 1000) end)
|
||||
|
||||
-----------------
|
||||
-- unit limits --
|
||||
-----------------
|
||||
|
||||
local limit_div = Div{parent=proc,width=40,height=19,x=34,y=6}
|
||||
|
||||
local rate_limits = {}
|
||||
|
||||
for i = 1, facility.num_units do
|
||||
local unit = units[i] ---@type ioctl_entry
|
||||
local unit = units[i] ---@type ioctl_unit
|
||||
|
||||
local _y = ((i - 1) * 4) + 1
|
||||
local _y = ((i - 1) * 5) + 1
|
||||
|
||||
TextBox{parent=limits,x=1,y=_y+1,text="Unit "..i}
|
||||
|
||||
local lim_ctl = Div{parent=limits,x=8,y=_y,width=20,height=3,fg_bg=cpair(colors.gray,colors.white)}
|
||||
local burn_rate = SpinboxNumeric{parent=lim_ctl,x=2,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,max=0.1,arrow_fg_bg=cpair(colors.gray,colors.white),fg_bg=bw_fg_bg}
|
||||
|
||||
unit.reactor_ps.subscribe("max_burn", burn_rate.set_max)
|
||||
unit.reactor_ps.subscribe("burn_limit", burn_rate.set_value)
|
||||
local unit_tag = Div{parent=limit_div,x=1,y=_y,width=8,height=4,fg_bg=cpair(colors.black,colors.lightBlue)}
|
||||
TextBox{parent=unit_tag,x=2,y=2,text="Unit "..i.." Limit",width=7,height=2}
|
||||
|
||||
local lim_ctl = Div{parent=limit_div,x=9,y=_y,width=14,height=3,fg_bg=cpair(colors.gray,colors.white)}
|
||||
rate_limits[i] = SpinboxNumeric{parent=lim_ctl,x=2,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,arrow_fg_bg=cpair(colors.gray,colors.white),fg_bg=bw_fg_bg}
|
||||
TextBox{parent=lim_ctl,x=9,y=2,text="mB/t"}
|
||||
|
||||
local set_burn = function () unit.set_limit(burn_rate.get_value()) end
|
||||
PushButton{parent=lim_ctl,x=14,y=2,text="SAVE",min_width=6,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=set_burn}
|
||||
unit.reactor_ps.subscribe("max_burn", rate_limits[i].set_max)
|
||||
unit.reactor_ps.subscribe("burn_limit", rate_limits[i].set_value)
|
||||
|
||||
local cur_burn = DataIndicator{parent=limit_div,x=9,y=_y+3,label="",format="%7.1f",value=0,unit="mB/t",commas=false,lu_colors=cpair(colors.black,colors.black),width=14,fg_bg=cpair(colors.black,colors.brown)}
|
||||
|
||||
unit.reactor_ps.subscribe("act_burn_rate", cur_burn.update)
|
||||
end
|
||||
|
||||
-------------------------
|
||||
-- controls and status --
|
||||
-------------------------
|
||||
|
||||
local ctl_opts = { "Regulated", "Burn Rate", "Charge Level", "Generation Rate" }
|
||||
local mode = RadioButton{parent=proc,x=34,y=1,options=ctl_opts,callback=function()end,radio_colors=cpair(colors.purple,colors.black),radio_bg=colors.gray}
|
||||
|
||||
facility.ps.subscribe("process_mode", mode.set_value)
|
||||
|
||||
local u_stat = Rectangle{parent=proc,border=border(1,colors.gray,true),thin=true,width=31,height=4,x=1,y=16,fg_bg=bw_fg_bg}
|
||||
local stat_line_1 = TextBox{parent=u_stat,x=1,y=1,text="UNKNOWN",width=31,height=1,alignment=TEXT_ALIGN.CENTER,fg_bg=bw_fg_bg}
|
||||
local stat_line_2 = TextBox{parent=u_stat,x=1,y=2,text="awaiting data",width=31,height=1,alignment=TEXT_ALIGN.CENTER,fg_bg=cpair(colors.gray, colors.white)}
|
||||
|
||||
local auto_controls = Div{parent=proc,x=1,y=20,width=31,height=5,fg_bg=cpair(colors.gray,colors.white)}
|
||||
|
||||
-- save the automatic process control configuration without starting
|
||||
local function _save_cfg()
|
||||
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(), c_target.get_value(), g_target.get_value(), limits)
|
||||
end
|
||||
|
||||
-- start automatic control after saving process control settings
|
||||
local function _start_auto()
|
||||
_save_cfg()
|
||||
process.start_auto()
|
||||
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.orange,dis_colors=dis_colors,callback=process.stop_auto,fg_bg=hzd_fg_bg}
|
||||
|
||||
facility.start_ack = start.on_response
|
||||
facility.stop_ack = stop.on_response
|
||||
|
||||
function facility.save_cfg_ack(ack)
|
||||
tcd.dispatch(0.2, function () save.on_response(ack) end)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ local function init(monitor)
|
||||
-- testing
|
||||
---@fixme remove test code
|
||||
|
||||
ColorMap{parent=main,x=2,y=(main.height()-1)}
|
||||
ColorMap{parent=main,x=132,y=(main.height()-1)}
|
||||
|
||||
local audio = Div{parent=main,width=34,height=15,x=95,y=cnc_y_start}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user