#101 #102 work on bugfixes; disable unit controls while in auto mode

This commit is contained in:
Mikayla Fischler 2023-02-01 21:55:02 -05:00
parent e9562a140c
commit fe71615c12
8 changed files with 155 additions and 47 deletions

View File

@ -116,6 +116,8 @@ function iocontrol.init(conf, comms)
ALARM_STATE.INACTIVE -- turbine trip
},
annunciator = {}, ---@type annunciator
reactor_ps = psil.create(),
reactor_data = {}, ---@type reactor_db
@ -272,12 +274,23 @@ function iocontrol.update_facility_status(status)
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.status_line_1 = ctl_status[4]
fac.status_line_2 = ctl_status[5]
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)
fac.ps.publish("status_line_1", fac.status_line_1)
fac.ps.publish("status_line_2", fac.status_line_2)
local group_map = ctl_status[6]
if (type(group_map) == "table") and (#group_map == fac.num_units) then
local names = { "Manual", "Primary", "Secondary", "Tertiary", "Backup" }
for i = 1, #group_map do
io.units[i].reactor_ps.publish("auto_group", names[group_map[i] + 1])
end
end
else
log.debug(log_header .. "control status not a table")
end
@ -556,14 +569,14 @@ function iocontrol.update_unit_statuses(statuses)
-- annunciator
local annunciator = status[3] ---@type annunciator
unit.annunciator = status[3]
if type(annunciator) ~= "table" then
annunciator = {}
if type(unit.annunciator) ~= "table" then
unit.annunciator = {}
log.debug(log_header .. "annunciator state not a table")
end
for key, val in pairs(annunciator) do
for key, val in pairs(unit.annunciator) do
if key == "TurbineTrip" then
-- split up turbine trip table for all turbines and a general OR combination
local trips = val

View File

@ -19,7 +19,7 @@ local iocontrol = require("coordinator.iocontrol")
local renderer = require("coordinator.renderer")
local sounder = require("coordinator.sounder")
local COORDINATOR_VERSION = "beta-v0.8.10"
local COORDINATOR_VERSION = "beta-v0.8.11"
local print = util.print
local println = util.println

View File

@ -160,7 +160,6 @@ local function init(parent, id)
local plc_online = IndicatorLight{parent=annunciator,label="PLC Online",colors=cpair(colors.green,colors.red)}
local plc_hbeat = IndicatorLight{parent=annunciator,label="PLC Heartbeat",colors=cpair(colors.white,colors.gray)}
local r_active = IndicatorLight{parent=annunciator,label="Active",colors=cpair(colors.green,colors.gray)}
---@todo auto control as info sent here
local r_auto = IndicatorLight{parent=annunciator,label="Automatic Control",colors=cpair(colors.blue,colors.gray)}
annunciator.line_break()
@ -171,6 +170,7 @@ local function init(parent, id)
r_ps.subscribe("PLCOnline", plc_online.update)
r_ps.subscribe("PLCHeartbeat", plc_hbeat.update)
r_ps.subscribe("status", r_active.update)
r_ps.subscribe("AutoControl", r_auto.update)
annunciator.line_break()
@ -328,18 +328,18 @@ local function init(parent, id)
-- reactor controls --
----------------------
local dis_colors = cpair(colors.white, colors.lightGray)
local burn_control = Div{parent=main,x=12,y=28,width=19,height=3,fg_bg=cpair(colors.gray,colors.white)}
local burn_rate = SpinboxNumeric{parent=burn_control,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=burn_control,x=9,y=2,text="mB/t"}
local set_burn = function () unit.set_burn(burn_rate.get_value()) end
PushButton{parent=burn_control,x=14,y=2,text="SET",min_width=5,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=set_burn}
local set_burn_btn = PushButton{parent=burn_control,x=14,y=2,text="SET",min_width=5,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),dis_fg_bg=dis_colors,callback=set_burn}
r_ps.subscribe("burn_rate", burn_rate.set_value)
r_ps.subscribe("max_burn", burn_rate.set_max)
local dis_colors = cpair(colors.white, colors.lightGray)
local start = HazardButton{parent=main,x=2,y=28,text="START",accent=colors.lightBlue,dis_colors=dis_colors,callback=unit.start,fg_bg=hzd_fg_bg}
local ack_a = HazardButton{parent=main,x=12,y=32,text="ACK \x13",accent=colors.orange,dis_colors=dis_colors,callback=unit.ack_alarms,fg_bg=hzd_fg_bg}
local scram = HazardButton{parent=main,x=2,y=32,text="SCRAM",accent=colors.yellow,dis_colors=dis_colors,callback=unit.scram,fg_bg=hzd_fg_bg}
@ -352,7 +352,9 @@ local function init(parent, id)
local function start_button_en_check()
if (unit.reactor_data ~= nil) and (unit.reactor_data.mek_status ~= nil) then
local can_start = (not unit.reactor_data.mek_status.status) and (not unit.reactor_data.rps_tripped)
local can_start = (not unit.reactor_data.mek_status.status) and
(not unit.reactor_data.rps_tripped) and
(not unit.annunciator.AutoControl)
if can_start then start.enable() else start.disable() end
end
end
@ -455,22 +457,55 @@ local function init(parent, id)
local ctl_opts = { "Manual", "Primary", "Secondary", "Tertiary", "Backup" }
RadioButton{parent=auto_div,options=ctl_opts,callback=function()end,radio_colors=cpair(colors.blue,colors.white),radio_bg=colors.gray}
local group = RadioButton{parent=auto_div,options=ctl_opts,callback=function()end,radio_colors=cpair(colors.blue,colors.white),radio_bg=colors.gray}
auto_div.line_break()
PushButton{parent=auto_div,text="SET",x=4,min_width=5,fg_bg=cpair(colors.black,colors.white),active_fg_bg=cpair(colors.white,colors.gray),callback=function()end}
local function set_group() unit.set_group(group.get_value() - 1) end
local set_grp_btn = PushButton{parent=auto_div,text="SET",x=4,min_width=5,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),dis_fg_bg=cpair(colors.gray,colors.white),callback=set_group}
auto_div.line_break()
TextBox{parent=auto_div,text="Prio. Group",height=1,width=11,fg_bg=style.label}
local auto_grp = TextBox{parent=auto_div,text="Manual",height=1,width=11,fg_bg=bw_fg_bg}
r_ps.subscribe("auto_group", auto_grp.set_value)
auto_div.line_break()
local a_prm = IndicatorLight{parent=auto_div,label="Active",x=2,colors=cpair(colors.green,colors.gray)}
local a_act = IndicatorLight{parent=auto_div,label="Active",x=2,colors=cpair(colors.green,colors.gray)}
local a_stb = IndicatorLight{parent=auto_div,label="Standby",x=2,colors=cpair(colors.white,colors.gray)}
r_ps.subscribe("status", function (active)
if unit.annunciator.AutoControl then
a_act.update(active)
a_stb.update(not active)
else
a_act.update(false)
a_stb.update(false)
end
end)
-- enable and disable controls based on auto control state (start button is handled separately)
r_ps.subscribe("AutoControl", function (auto_active)
start_button_en_check()
if auto_active then
burn_rate.disable()
set_burn_btn.disable()
set_grp_btn.disable()
a_act.update(unit.reactor_data.mek_status.status == true)
a_stb.update(unit.reactor_data.mek_status.status == false)
else
burn_rate.enable()
set_burn_btn.enable()
set_grp_btn.enable()
a_act.update(false)
a_stb.update(false)
end
end)
return main
end

View File

@ -10,6 +10,7 @@ local element = require("graphics.element")
---@field callback function function to call on touch
---@field min_width? integer text length + 2 if omitted
---@field active_fg_bg? cpair foreground/background colors when pressed
---@field dis_fg_bg? cpair foreground/background colors when disabled
---@field parent graphics_element
---@field id? string element id
---@field x? integer 1 if omitted
@ -61,8 +62,10 @@ local function push_button(args)
-- show as unpressed in 0.25 seconds
tcd.dispatch(0.25, function ()
e.value = false
e.window.setTextColor(e.fg_bg.fgd)
e.window.setBackgroundColor(e.fg_bg.bkg)
if e.enabled then
e.window.setTextColor(e.fg_bg.fgd)
e.window.setBackgroundColor(e.fg_bg.bkg)
end
draw()
end)
end
@ -78,6 +81,26 @@ local function push_button(args)
if val then e.handle_touch(core.events.touch("", 1, 1)) end
end
-- show butten as enabled
function e.enable()
if args.dis_fg_bg ~= nil then
e.value = false
e.window.setTextColor(e.fg_bg.fgd)
e.window.setBackgroundColor(e.fg_bg.bkg)
draw()
end
end
-- show button as disabled
function e.disable()
if args.dis_fg_bg ~= nil then
e.value = false
e.window.setTextColor(args.dis_fg_bg.fgd)
e.window.setBackgroundColor(args.dis_fg_bg.bkg)
draw()
end
end
-- initial draw
draw()

View File

@ -40,6 +40,7 @@ function facility.new(num_reactors, cooling_conf)
units = {},
induction = {},
redstone = {},
status_text = { "IDLE", "control inactive" },
-- process control
mode = PROCESS.INACTIVE,
last_mode = PROCESS.INACTIVE,
@ -103,36 +104,42 @@ function facility.new(num_reactors, cooling_conf)
local unallocated = math.floor(burn_rate * 10)
-- go through alll priority groups
for i = 1, #self.prio_defs and (unallocated > 0) do
for i = 1, #self.prio_defs do
local units = self.prio_defs[i]
local split = math.floor(unallocated / #units)
local splits = {}
for u = 1, #units do splits[u] = split end
splits[#units] = splits[#units] + (unallocated % #units)
if #units > 0 then
local split = math.floor(unallocated / #units)
-- go through all reactor units in this group
for u = 1, #units do
local ctl = units[u].get_control_inf() ---@type unit_control
local last = ctl.br10
local splits = {}
for u = 1, #units do splits[u] = split end
splits[#units] = splits[#units] + (unallocated % #units)
if splits[u] <= ctl.lim_br10 then
ctl.br10 = splits[u]
else
ctl.br10 = ctl.lim_br10
-- go through all reactor units in this group
for u = 1, #units do
local ctl = units[u].get_control_inf() ---@type unit_control
local last = ctl.br10
if u < #units then
local remaining = #units - u
split = math.floor(unallocated / remaining)
for x = (u + 1), #units do splits[x] = split end
splits[#units] = splits[#units] + (unallocated % remaining)
if splits[u] <= ctl.lim_br10 then
ctl.br10 = splits[u]
else
ctl.br10 = ctl.lim_br10
if u < #units then
local remaining = #units - u
split = math.floor(unallocated / remaining)
for x = (u + 1), #units do splits[x] = split end
splits[#units] = splits[#units] + (unallocated % remaining)
end
end
unallocated = unallocated - ctl.br10
if last ~= ctl.br10 then units[u].a_commit_br10(ramp) end
end
unallocated = unallocated - ctl.br10
if last ~= ctl.br10 then units[u].a_commit_br10(ramp) end
end
-- stop if fully allocated
if unallocated <= 0 then break end
end
end
@ -216,19 +223,24 @@ function facility.new(num_reactors, cooling_conf)
)
for _, u in pairs(self.prio_defs[i]) do
blade_count = blade_count + u.get_db().blade_count
blade_count = blade_count + u.get_control_inf().blade_count
u.a_engage()
self.max_burn_combined = self.max_burn_combined + (u.get_control_inf().lim_br10 / 10.0)
end
end
self.charge_conversion = blade_count * POWER_PER_BLADE
log.debug(util.c("FAC: starting auto control: chg_conv = ", self.charge_conversion, ", blade_count = ", blade_count, ", max_burn = ", self.max_burn_combined))
elseif self.mode == PROCESS.INACTIVE then
for i = 1, #self.prio_defs do
for _, u in pairs(self.prio_defs[i]) do
u.a_disengage()
end
end
self.status_text = { "IDLE", "control disengaged" }
log.debug("FAC: disengaging auto control (now inactive)")
end
self.initial_ramp = true
@ -241,30 +253,43 @@ function facility.new(num_reactors, cooling_conf)
-- run units at their last configured set point
if state_changed then
self.time_start = now
---@todo will still need to ramp?
log.debug(util.c("FAC: SIMPLE mode first call completed"))
end
elseif self.mode == PROCESS.BURN_RATE then
-- a total aggregate burn rate
if state_changed then
-- nothing special to do
self.status_text = { "BURN RATE MODE", "starting up" }
log.debug(util.c("FAC: BURN_RATE mode first call completed"))
elseif self.waiting_on_ramp and _all_units_ramped() then
self.waiting_on_ramp = false
self.time_start = now
self.status_text = { "BURN RATE MODE", "running" }
log.debug(util.c("FAC: BURN_RATE mode initial ramp completed"))
end
if not self.waiting_on_ramp then
_allocate_burn_rate(self.burn_target, self.initial_ramp)
if self.initial_ramp then
self.status_text = { "BURN RATE MODE", "ramping reactors" }
self.waiting_on_ramp = true
log.debug(util.c("FAC: BURN_RATE mode allocated initial ramp"))
end
end
elseif self.mode == PROCESS.CHARGE then
-- target a level of charge
local error = (self.charge_target - avg_charge) / self.charge_conversion
if state_changed then
-- nothing special to do
log.debug(util.c("FAC: CHARGE mode first call completed"))
elseif self.waiting_on_ramp and _all_units_ramped() then
self.waiting_on_ramp = false
self.time_start = now
self.accumulator = 0
log.debug(util.c("FAC: CHARGE mode initial ramp completed"))
end
if not self.waiting_on_ramp then
@ -311,11 +336,13 @@ function facility.new(num_reactors, cooling_conf)
local sp_r = util.round(setpoint * 10.0) / 10.0
_allocate_burn_rate(sp_r, true)
log.debug(util.c("FAC: GEN_RATE mode first call completed"))
elseif self.waiting_on_ramp and _all_units_ramped() then
self.waiting_on_ramp = false
self.time_start = now
self.accumulator = 0
log.debug(util.c("FAC: GEN_RATE mode initial ramp completed"))
end
if not self.waiting_on_ramp then
@ -346,6 +373,9 @@ function facility.new(num_reactors, cooling_conf)
_allocate_burn_rate(sp_c, false)
end
elseif self.mode ~= PROCESS.INACTIVE then
log.error(util.c("FAC: unsupported process mode ", self.mode, ", switching to inactive"))
self.mode = PROCESS.INACTIVE
end
------------------------------
@ -389,6 +419,9 @@ function facility.new(num_reactors, cooling_conf)
self.ascram = true
end
end
-- update last mode
self.last_mode = self.mode
end
-- call the update function of all units in the facility
@ -429,8 +462,9 @@ function facility.new(num_reactors, cooling_conf)
-- only allow changes if not running
if self.mode == PROCESS.INACTIVE then
if (type(config.mode) == "number") and (config.mode > PROCESS.INACTIVE) and (config.mode <= PROCESS.SIMPLE) then
if (type(config.mode) == "number") and (config.mode > PROCESS.INACTIVE) and (config.mode <= PROCESS.GEN_RATE) then
self.mode_set = config.mode
log.debug("SET MODE " .. config.mode)
end
if (type(config.burn_target) == "number") and config.burn_target >= 0.1 then
@ -489,7 +523,7 @@ function facility.new(num_reactors, cooling_conf)
util.filter_table(self.prio_defs[old_group], function (u) return u.get_id() ~= unit_id end)
end
self.group_map[unit] = group
self.group_map[unit_id] = group
-- add to group if not independent
if group > 0 then
@ -519,7 +553,9 @@ function facility.new(num_reactors, cooling_conf)
self.mode,
self.waiting_on_ramp,
self.ascram,
self.ascram_reason
self.status_text[1],
self.status_text[2],
self.group_map
}
end

View File

@ -387,6 +387,7 @@ function unit.new(for_reactor, num_boilers, num_turbines)
self.db.annunciator.AutoControl = false
if self.plc_i ~= nil then
self.plc_i.auto_lock(false)
self.db.control.br10 = 0
end
end

View File

@ -194,7 +194,7 @@ function logic.update_annunciator(self)
local max_water_return_rate = 0
-- recompute blade count on the chance that it may have changed
self.db.blade_count = 0
self.db.control.blade_count = 0
-- go through turbines for stats and online
for i = 1, #self.turbines do
@ -204,7 +204,7 @@ function logic.update_annunciator(self)
total_flow_rate = total_flow_rate + turbine.state.flow_rate
total_input_rate = total_input_rate + turbine.state.steam_input_rate
max_water_return_rate = max_water_return_rate + turbine.build.max_water_output
self.db.blade_count = self.db.blade_count + turbine.build.blades
self.db.control.blade_count = self.db.control.blade_count + turbine.build.blades
self.db.annunciator.TurbineOnline[session.get_device_idx()] = true
end

View File

@ -14,7 +14,7 @@ local svsessions = require("supervisor.session.svsessions")
local config = require("supervisor.config")
local supervisor = require("supervisor.supervisor")
local SUPERVISOR_VERSION = "beta-v0.9.7"
local SUPERVISOR_VERSION = "beta-v0.9.8"
local print = util.print
local println = util.println