fixed process controller assuming ramp complete if burn rate setpoint was identical to setpoint before process control start

This commit is contained in:
Mikayla Fischler
2023-02-04 13:47:00 -05:00
parent ba8bfb6e14
commit b5c70b0d37
14 changed files with 225 additions and 159 deletions

View File

@ -23,6 +23,8 @@ local io = {}
function iocontrol.init(conf, comms) function iocontrol.init(conf, comms)
---@class ioctl_facility ---@class ioctl_facility
io.facility = { io.facility = {
all_sys_ok = false,
auto_ready = false, auto_ready = false,
auto_active = false, auto_active = false,
auto_ramping = false, auto_ramping = false,
@ -273,13 +275,15 @@ function iocontrol.update_facility_status(status)
local ctl_status = status[1] local ctl_status = status[1]
if type(ctl_status) == "table" then if type(ctl_status) == "table" then
fac.auto_ready = ctl_status[1] fac.all_sys_ok = ctl_status[1]
fac.auto_active = ctl_status[2] > 0 fac.auto_ready = ctl_status[2]
fac.auto_ramping = ctl_status[3] fac.auto_active = ctl_status[3] > 0
fac.auto_scram = ctl_status[4] fac.auto_ramping = ctl_status[4]
fac.status_line_1 = ctl_status[5] fac.auto_scram = ctl_status[5]
fac.status_line_2 = ctl_status[6] fac.status_line_1 = ctl_status[6]
fac.status_line_2 = ctl_status[7]
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)
fac.ps.publish("auto_active", fac.auto_active) fac.ps.publish("auto_active", fac.auto_active)
fac.ps.publish("auto_ramping", fac.auto_ramping) fac.ps.publish("auto_ramping", fac.auto_ramping)
@ -287,12 +291,13 @@ function iocontrol.update_facility_status(status)
fac.ps.publish("status_line_1", fac.status_line_1) fac.ps.publish("status_line_1", fac.status_line_1)
fac.ps.publish("status_line_2", fac.status_line_2) fac.ps.publish("status_line_2", fac.status_line_2)
local group_map = ctl_status[7] local group_map = ctl_status[8]
if (type(group_map) == "table") and (#group_map == fac.num_units) then if (type(group_map) == "table") and (#group_map == fac.num_units) then
local names = { "Manual", "Primary", "Secondary", "Tertiary", "Backup" } local names = { "Manual", "Primary", "Secondary", "Tertiary", "Backup" }
for i = 1, #group_map do for i = 1, #group_map do
io.units[i].unit_ps.publish("auto_group_id", group_map[i] + 1) io.units[i].a_group = group_map[i]
io.units[i].unit_ps.publish("auto_group_id", group_map[i])
io.units[i].unit_ps.publish("auto_group", names[group_map[i] + 1]) io.units[i].unit_ps.publish("auto_group", names[group_map[i] + 1])
end end
end end

View File

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

View File

@ -50,10 +50,21 @@ local function new_view(root, x, y)
facility.scram_ack = scram.on_response facility.scram_ack = scram.on_response
local auto_act = IndicatorLight{parent=main,y=5,label="Auto Active",colors=cpair(colors.green,colors.gray)} local all_ok = IndicatorLight{parent=main,y=5,label="Unit Systems Online",colors=cpair(colors.green,colors.red)}
local auto_ramp = IndicatorLight{parent=main,label="Auto Ramping",colors=cpair(colors.white,colors.gray),flash=true,period=period.BLINK_250_MS} local ind_mat = IndicatorLight{parent=main,label="Induction Matrix",colors=cpair(colors.green,colors.gray)}
local auto_scram = IndicatorLight{parent=main,label="Auto SCRAM",colors=cpair(colors.red,colors.gray),flash=true,period=period.BLINK_250_MS} local rad_mon = IndicatorLight{parent=main,label="Radiation Monitor",colors=cpair(colors.green,colors.gray)}
facility.ps.subscribe("all_sys_ok", all_ok.update)
facility.induction_ps_tbl[1].subscribe("computed_status", function (status) ind_mat.update(status > 1) end)
main.line_break()
local auto_ready = IndicatorLight{parent=main,label="Configured Units Ready",colors=cpair(colors.green,colors.red)}
local auto_act = IndicatorLight{parent=main,label="Process Active",colors=cpair(colors.green,colors.gray)}
local auto_ramp = IndicatorLight{parent=main,label="Process Ramping",colors=cpair(colors.white,colors.gray),flash=true,period=period.BLINK_250_MS}
local auto_scram = IndicatorLight{parent=main,label="Automatic SCRAM",colors=cpair(colors.red,colors.gray),flash=true,period=period.BLINK_250_MS}
facility.ps.subscribe("auto_ready", auto_ready.update)
facility.ps.subscribe("auto_active", auto_act.update) facility.ps.subscribe("auto_active", auto_act.update)
facility.ps.subscribe("auto_ramping", auto_ramp.update) facility.ps.subscribe("auto_ramping", auto_ramp.update)
facility.ps.subscribe("auto_scram", auto_scram.update) facility.ps.subscribe("auto_scram", auto_scram.update)

View File

@ -354,7 +354,7 @@ local function init(parent, id)
if (unit.reactor_data ~= nil) and (unit.reactor_data.mek_status ~= nil) then if (unit.reactor_data ~= nil) and (unit.reactor_data.mek_status ~= nil) then
local can_start = (not unit.reactor_data.mek_status.status) and local can_start = (not unit.reactor_data.mek_status.status) and
(not unit.reactor_data.rps_tripped) and (not unit.reactor_data.rps_tripped) and
(not unit.annunciator.AutoControl) (unit.a_group == 0)
if can_start then start.enable() else start.disable() end if can_start then start.enable() else start.disable() end
end end
end end
@ -459,7 +459,7 @@ local function init(parent, id)
local group = 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}
u_ps.subscribe("auto_group_id", group.set_value) u_ps.subscribe("auto_group_id", function (gid) group.set_value(gid + 1) end)
auto_div.line_break() auto_div.line_break()
@ -485,18 +485,27 @@ local function init(parent, id)
a_stb.update(unit.annunciator.AutoControl and (not active)) a_stb.update(unit.annunciator.AutoControl and (not active))
end) end)
-- enable and disable controls based on group assignment
u_ps.subscribe("auto_group_id", function (gid)
start_button_en_check()
if gid == 0 then
burn_rate.enable()
set_burn_btn.enable()
else
burn_rate.disable()
set_burn_btn.disable()
end
end)
-- enable and disable controls based on auto control state (start button is handled separately) -- enable and disable controls based on auto control state (start button is handled separately)
u_ps.subscribe("AutoControl", function (auto_active) u_ps.subscribe("AutoControl", function (auto_active)
start_button_en_check() start_button_en_check()
if auto_active then if auto_active then
burn_rate.disable()
set_burn_btn.disable()
set_grp_btn.disable() set_grp_btn.disable()
a_stb.update(unit.reactor_data.mek_status.status == false) a_stb.update(unit.reactor_data.mek_status.status == false)
else else
burn_rate.enable()
set_burn_btn.enable()
set_grp_btn.enable() set_grp_btn.enable()
a_stb.update(false) a_stb.update(false)
end end

View File

@ -88,33 +88,33 @@ local function init(monitor)
-- testing -- testing
---@fixme remove test code ---@fixme remove test code
ColorMap{parent=main,x=132,y=(main.height()-1)} ColorMap{parent=main,x=98,y=(main.height()-1)}
local audio = Div{parent=main,width=34,height=15,x=95,y=cnc_y_start} local audio = Div{parent=main,width=23,height=23,x=107,y=cnc_y_start}
PushButton{parent=audio,x=1,y=1,text="TEST 1",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_1} PushButton{parent=audio,x=16,y=1,text="TEST 1",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_1}
PushButton{parent=audio,x=1,text="TEST 2",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_2} PushButton{parent=audio,x=16,text="TEST 2",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_2}
PushButton{parent=audio,x=1,text="TEST 3",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_3} PushButton{parent=audio,x=16,text="TEST 3",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_3}
PushButton{parent=audio,x=1,text="TEST 4",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_4} PushButton{parent=audio,x=16,text="TEST 4",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_4}
PushButton{parent=audio,x=1,text="TEST 5",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_5} PushButton{parent=audio,x=16,text="TEST 5",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_5}
PushButton{parent=audio,x=1,text="TEST 6",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_6} PushButton{parent=audio,x=16,text="TEST 6",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_6}
PushButton{parent=audio,x=1,text="TEST 7",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_7} PushButton{parent=audio,x=16,text="TEST 7",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_7}
PushButton{parent=audio,x=1,text="TEST 8",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_8} PushButton{parent=audio,x=16,text="TEST 8",min_width=8,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_8}
PushButton{parent=audio,x=1,text="STOP",min_width=8,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.stop} PushButton{parent=audio,x=16,text="STOP",min_width=8,fg_bg=cpair(colors.black,colors.red),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.stop}
PushButton{parent=audio,x=1,text="PSCALE",min_width=8,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_power_scale} PushButton{parent=audio,x=16,text="PSCALE",min_width=8,fg_bg=cpair(colors.black,colors.blue),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_power_scale}
SwitchButton{parent=audio,x=11,y=1,text="CONTAINMENT BREACH",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_breach} SwitchButton{parent=audio,x=1,y=12,text="CONTAINMENT BREACH",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_breach}
SwitchButton{parent=audio,x=11,text="CONTAINMENT RADIATION",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_rad} SwitchButton{parent=audio,x=1,text="CONTAINMENT RADIATION",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_rad}
SwitchButton{parent=audio,x=11,text="REACTOR LOST",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_lost} SwitchButton{parent=audio,x=1,text="REACTOR LOST",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_lost}
SwitchButton{parent=audio,x=11,text="CRITICAL DAMAGE",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_crit} SwitchButton{parent=audio,x=1,text="CRITICAL DAMAGE",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_crit}
SwitchButton{parent=audio,x=11,text="REACTOR DAMAGE",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_dmg} SwitchButton{parent=audio,x=1,text="REACTOR DAMAGE",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_dmg}
SwitchButton{parent=audio,x=11,text="REACTOR OVER TEMP",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_overtemp} SwitchButton{parent=audio,x=1,text="REACTOR OVER TEMP",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_overtemp}
SwitchButton{parent=audio,x=11,text="REACTOR HIGH TEMP",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_hightemp} SwitchButton{parent=audio,x=1,text="REACTOR HIGH TEMP",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_hightemp}
SwitchButton{parent=audio,x=11,text="REACTOR WASTE LEAK",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_wasteleak} SwitchButton{parent=audio,x=1,text="REACTOR WASTE LEAK",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_wasteleak}
SwitchButton{parent=audio,x=11,text="REACTOR WASTE HIGH",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_highwaste} SwitchButton{parent=audio,x=1,text="REACTOR WASTE HIGH",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_highwaste}
SwitchButton{parent=audio,x=11,text="RPS TRANSIENT",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_rps} SwitchButton{parent=audio,x=1,text="RPS TRANSIENT",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_rps}
SwitchButton{parent=audio,x=11,text="RCS TRANSIENT",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_rcs} SwitchButton{parent=audio,x=1,text="RCS TRANSIENT",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_rcs}
SwitchButton{parent=audio,x=11,text="TURBINE TRIP",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_turbinet} SwitchButton{parent=audio,x=1,text="TURBINE TRIP",min_width=23,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=sounder.test_turbinet}
local imatrix_1 = imatrix(main, 131, cnc_y_start, facility.induction_data_tbl[1], facility.induction_ps_tbl[1]) local imatrix_1 = imatrix(main, 131, cnc_y_start, facility.induction_data_tbl[1], facility.induction_ps_tbl[1])

View File

@ -68,7 +68,7 @@ function plc.rps_init(reactor, is_formed)
formed = is_formed, formed = is_formed,
force_disabled = false, force_disabled = false,
tripped = false, tripped = false,
trip_cause = "" ---@type rps_trip_cause trip_cause = "ok" ---@type rps_trip_cause
} }
---@class rps ---@class rps
@ -410,6 +410,7 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co
scrammed = false, scrammed = false,
linked = false, linked = false,
resend_build = false, resend_build = false,
auto_ack_token = 0,
status_cache = nil, status_cache = nil,
max_burn_rate = nil max_burn_rate = nil
} }
@ -656,6 +657,7 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co
(not self.scrammed), -- requested control state (not self.scrammed), -- requested control state
no_reactor, -- no reactor peripheral connected no_reactor, -- no reactor peripheral connected
formed, -- reactor formed formed, -- reactor formed
self.auto_ack_token, -- token to indicate auto command has been received before this status update
heating_rate, -- heating rate heating_rate, -- heating rate
mek_data -- mekanism status data mek_data -- mekanism status data
} }
@ -808,10 +810,11 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co
_send_ack(packet.type, true) _send_ack(packet.type, true)
elseif packet.type == RPLC_TYPES.AUTO_BURN_RATE then elseif packet.type == RPLC_TYPES.AUTO_BURN_RATE then
-- automatic control requested a new burn rate -- automatic control requested a new burn rate
if (packet.length == 2) and (type(packet.data[1]) == "number") then if (packet.length == 3) and (type(packet.data[1]) == "number") and (type(packet.data[3]) == "number") then
local ack = AUTO_ACK.FAIL local ack = AUTO_ACK.FAIL
local burn_rate = math.floor(packet.data[1] * 10) / 10 local burn_rate = math.floor(packet.data[1] * 10) / 10
local ramp = packet.data[2] local ramp = packet.data[2]
self.auto_ack_token = packet.data[3]
-- if no known max burn rate, check again -- if no known max burn rate, check again
if self.max_burn_rate == nil then if self.max_burn_rate == nil then

View File

@ -14,7 +14,7 @@ local config = require("reactor-plc.config")
local plc = require("reactor-plc.plc") local plc = require("reactor-plc.plc")
local threads = require("reactor-plc.threads") local threads = require("reactor-plc.threads")
local R_PLC_VERSION = "beta-v0.10.3" local R_PLC_VERSION = "beta-v0.10.4"
local print = util.print local print = util.print
local println = util.println local println = util.println
@ -169,6 +169,7 @@ local function main()
log.debug("init> running without networking") log.debug("init> running without networking")
end end
---@diagnostic disable-next-line: param-type-mismatch
util.push_event("clock_start") util.push_event("clock_start")
println("boot> completed") println("boot> completed")

View File

@ -25,7 +25,7 @@ local sna_rtu = require("rtu.dev.sna_rtu")
local sps_rtu = require("rtu.dev.sps_rtu") local sps_rtu = require("rtu.dev.sps_rtu")
local turbinev_rtu = require("rtu.dev.turbinev_rtu") local turbinev_rtu = require("rtu.dev.turbinev_rtu")
local RTU_VERSION = "beta-v0.9.11" local RTU_VERSION = "beta-v0.9.12"
local rtu_t = types.rtu_t local rtu_t = types.rtu_t
@ -362,6 +362,10 @@ local function main()
table.insert(units, rtu_unit) table.insert(units, rtu_unit)
if not formed then
log.debug(util.c("configure> device '", name, "' is not formed"))
end
local for_message = "facility" local for_message = "facility"
if for_reactor > 0 then if for_reactor > 0 then
for_message = util.c("reactor ", for_reactor) for_message = util.c("reactor ", for_reactor)

View File

@ -12,7 +12,7 @@ local rtu_t = types.rtu_t
local insert = table.insert local insert = table.insert
comms.version = "1.1.2" comms.version = "1.2.0"
---@alias PROTOCOLS integer ---@alias PROTOCOLS integer
local PROTOCOLS = { local PROTOCOLS = {
@ -140,11 +140,11 @@ function comms.scada_packet()
local self = { local self = {
modem_msg_in = nil, modem_msg_in = nil,
valid = false, valid = false,
raw = nil, raw = { -1, -1, {} },
seq_num = nil, seq_num = -1,
protocol = nil, protocol = -1,
length = nil, length = 0,
payload = nil payload = {}
} }
---@class scada_packet ---@class scada_packet

View File

@ -110,6 +110,8 @@ function log.dmesg(msg, tag, tag_color)
local t_stamp = string.format("%12.2f", os.clock()) local t_stamp = string.format("%12.2f", os.clock())
local out = _log_sys.dmesg_out local out = _log_sys.dmesg_out
if out ~= nil then
local out_w, out_h = out.getSize() local out_w, out_h = out.getSize()
local lines = { msg } local lines = { msg }
@ -189,6 +191,7 @@ function log.dmesg(msg, tag, tag_color)
end end
_log(util.c("[", t_stamp, "] [", tag, "] ", msg)) _log(util.c("[", t_stamp, "] [", tag, "] ", msg))
end
return ts_coord return ts_coord
end end
@ -204,6 +207,7 @@ function log.dmesg_working(msg, tag, tag_color)
local out = _log_sys.dmesg_out local out = _log_sys.dmesg_out
local width = (ts_coord.x2 - ts_coord.x1) + 1 local width = (ts_coord.x2 - ts_coord.x1) + 1
if out ~= nil then
local initial_color = out.getTextColor() local initial_color = out.getTextColor()
local counter = 0 local counter = 0
@ -250,6 +254,9 @@ function log.dmesg_working(msg, tag, tag_color)
end end
return update, done return update, done
else
return function () end, function () end
end
end end
-- log debug messages -- log debug messages

View File

@ -41,6 +41,7 @@ function facility.new(num_reactors, cooling_conf)
induction = {}, induction = {},
redstone = {}, redstone = {},
status_text = { "START UP", "initializing..." }, status_text = { "START UP", "initializing..." },
all_sys_ok = false,
-- process control -- process control
units_ready = false, units_ready = false,
mode = PROCESS.INACTIVE, mode = PROCESS.INACTIVE,
@ -199,6 +200,11 @@ function facility.new(num_reactors, cooling_conf)
self.im_stat_init = false self.im_stat_init = false
end end
self.all_sys_ok = true
for i = 1, #self.units do
self.all_sys_ok = self.all_sys_ok and not self.units[i].get_control_inf().degraded
end
------------------------- -------------------------
-- Run Process Control -- -- Run Process Control --
------------------------- -------------------------
@ -570,6 +576,7 @@ function facility.new(num_reactors, cooling_conf)
-- get automatic process control status -- get automatic process control status
function public.get_control_status() function public.get_control_status()
return { return {
self.all_sys_ok,
self.units_ready, self.units_ready,
self.mode, self.mode,
self.waiting_on_ramp, self.waiting_on_ramp,

View File

@ -59,6 +59,7 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
out_q = out_queue, out_q = out_queue,
commanded_state = false, commanded_state = false,
commanded_burn_rate = 0.0, commanded_burn_rate = 0.0,
auto_cmd_token = 0,
ramping_rate = false, ramping_rate = false,
auto_scram = false, auto_scram = false,
auto_lock = false, auto_lock = false,
@ -92,6 +93,7 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
-- session database -- session database
---@class reactor_db ---@class reactor_db
sDB = { sDB = {
auto_ack_token = 0,
last_status_update = 0, last_status_update = 0,
control_state = false, control_state = false,
no_reactor = false, no_reactor = false,
@ -305,18 +307,19 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
-- handle packet by type -- handle packet by type
if pkt.type == RPLC_TYPES.STATUS then if pkt.type == RPLC_TYPES.STATUS then
-- status packet received, update data -- status packet received, update data
if pkt.length >= 4 then if pkt.length >= 5 then
self.sDB.last_status_update = pkt.data[1] self.sDB.last_status_update = pkt.data[1]
self.sDB.control_state = pkt.data[2] self.sDB.control_state = pkt.data[2]
self.sDB.no_reactor = pkt.data[3] self.sDB.no_reactor = pkt.data[3]
self.sDB.formed = pkt.data[4] self.sDB.formed = pkt.data[4]
self.sDB.auto_ack_token = pkt.data[5]
if not self.sDB.no_reactor and self.sDB.formed then if not self.sDB.no_reactor and self.sDB.formed then
self.sDB.mek_status.heating_rate = pkt.data[5] or 0.0 self.sDB.mek_status.heating_rate = pkt.data[6] or 0.0
-- attempt to read mek_data table -- attempt to read mek_data table
if pkt.data[6] ~= nil then if pkt.data[7] ~= nil then
local status = pcall(_copy_status, pkt.data[6]) local status = pcall(_copy_status, pkt.data[7])
if status then if status then
-- copied in status data OK -- copied in status data OK
self.received_status_cache = true self.received_status_cache = true
@ -496,6 +499,11 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
-- get the session database -- get the session database
function public.get_db() return self.sDB end function public.get_db() return self.sDB end
-- check if ramping is completed by first verifying auto command token ack
function public.is_ramp_complete()
return (self.sDB.auto_ack_token == self.auto_cmd_token) and (self.commanded_burn_rate == self.sDB.mek_status.act_burn_rate)
end
-- get the reactor structure -- get the reactor structure
function public.get_struct() function public.get_struct()
if self.received_struct then if self.received_struct then
@ -618,6 +626,7 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
cmd.val = math.floor(cmd.val * 10) / 10 -- round to 10ths place cmd.val = math.floor(cmd.val * 10) / 10 -- round to 10ths place
if cmd.val > 0 and cmd.val <= self.sDB.mek_struct.max_burn then if cmd.val > 0 and cmd.val <= self.sDB.mek_struct.max_burn then
self.commanded_burn_rate = cmd.val self.commanded_burn_rate = cmd.val
self.auto_cmd_token = 0
self.ramping_rate = false self.ramping_rate = false
self.acks.burn_rate = false self.acks.burn_rate = false
self.retry_times.burn_rate_req = util.time() + INITIAL_WAIT self.retry_times.burn_rate_req = util.time() + INITIAL_WAIT
@ -630,6 +639,7 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
cmd.val = math.floor(cmd.val * 10) / 10 -- round to 10ths place cmd.val = math.floor(cmd.val * 10) / 10 -- round to 10ths place
if cmd.val > 0 and cmd.val <= self.sDB.mek_struct.max_burn then if cmd.val > 0 and cmd.val <= self.sDB.mek_struct.max_burn then
self.commanded_burn_rate = cmd.val self.commanded_burn_rate = cmd.val
self.auto_cmd_token = 0
self.ramping_rate = true self.ramping_rate = true
self.acks.burn_rate = false self.acks.burn_rate = false
self.retry_times.burn_rate_req = util.time() + INITIAL_WAIT self.retry_times.burn_rate_req = util.time() + INITIAL_WAIT
@ -640,14 +650,15 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
-- set automatic burn rate -- set automatic burn rate
if self.auto_lock then if self.auto_lock then
cmd.val = math.floor(cmd.val * 10) / 10 -- round to 10ths place cmd.val = math.floor(cmd.val * 10) / 10 -- round to 10ths place
if cmd.val > 0 and cmd.val <= self.sDB.mek_struct.max_burn then if cmd.val >= 0 and cmd.val <= self.sDB.mek_struct.max_burn then
self.auto_cmd_token = util.time_ms()
self.commanded_burn_rate = cmd.val self.commanded_burn_rate = cmd.val
-- this is only for manual control, only retry auto ramps -- this is only for manual control, only retry auto ramps
self.acks.burn_rate = not self.ramping_rate self.acks.burn_rate = not self.ramping_rate
self.retry_times.burn_rate_req = util.time() + INITIAL_AUTO_WAIT self.retry_times.burn_rate_req = util.time() + INITIAL_AUTO_WAIT
_send(RPLC_TYPES.AUTO_BURN_RATE, { self.commanded_burn_rate, self.ramping_rate }) _send(RPLC_TYPES.AUTO_BURN_RATE, { self.commanded_burn_rate, self.ramping_rate, self.auto_cmd_token })
end end
end end
else else
@ -717,10 +728,19 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
if not self.acks.burn_rate then if not self.acks.burn_rate then
if rtimes.burn_rate_req - util.time() <= 0 then if rtimes.burn_rate_req - util.time() <= 0 then
if self.auto_cmd_token > 0 then
if self.auto_lock then if self.auto_lock then
_send(RPLC_TYPES.AUTO_BURN_RATE, { self.commanded_burn_rate, self.ramping_rate }) _send(RPLC_TYPES.AUTO_BURN_RATE, { self.commanded_burn_rate, self.ramping_rate, self.auto_cmd_token })
log.debug("retried auto burn rate?")
else else
-- would have been an auto command, but disengaged, so stop retrying
self.acks.burn_rate = true
end
elseif not self.auto_lock then
_send(RPLC_TYPES.MEK_BURN_RATE, { self.commanded_burn_rate, self.ramping_rate }) _send(RPLC_TYPES.MEK_BURN_RATE, { self.commanded_burn_rate, self.ramping_rate })
else
-- shouldn't be in this state, just pretend it was acknowledged
self.acks.burn_rate = true
end end
rtimes.burn_rate_req = util.time() + RETRY_PERIOD rtimes.burn_rate_req = util.time() + RETRY_PERIOD

View File

@ -409,8 +409,7 @@ function unit.new(for_reactor, num_boilers, num_turbines)
---@return boolean complete ---@return boolean complete
function public.a_ramp_complete() function public.a_ramp_complete()
if self.plc_i ~= nil then if self.plc_i ~= nil then
local cur_rate = math.floor(self.plc_i.get_db().mek_status.burn_rate * 10) return self.plc_i.is_ramp_complete()
return (cur_rate == self.ramp_target_br10) or (self.ramp_target_br10 == 0)
else return true end else return true end
end end

View File

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