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)
---@class ioctl_facility
io.facility = {
all_sys_ok = false,
auto_ready = false,
auto_active = false,
auto_ramping = false,
@ -273,13 +275,15 @@ function iocontrol.update_facility_status(status)
local ctl_status = status[1]
if type(ctl_status) == "table" then
fac.auto_ready = ctl_status[1]
fac.auto_active = ctl_status[2] > 0
fac.auto_ramping = ctl_status[3]
fac.auto_scram = ctl_status[4]
fac.status_line_1 = ctl_status[5]
fac.status_line_2 = ctl_status[6]
fac.all_sys_ok = ctl_status[1]
fac.auto_ready = ctl_status[2]
fac.auto_active = ctl_status[3] > 0
fac.auto_ramping = ctl_status[4]
fac.auto_scram = ctl_status[5]
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_active", fac.auto_active)
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_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
local names = { "Manual", "Primary", "Secondary", "Tertiary", "Backup" }
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])
end
end

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.16"
local COORDINATOR_VERSION = "beta-v0.8.17"
local print = util.print
local println = util.println

View File

@ -50,10 +50,21 @@ local function new_view(root, x, y)
facility.scram_ack = scram.on_response
local auto_act = IndicatorLight{parent=main,y=5,label="Auto Active",colors=cpair(colors.green,colors.gray)}
local auto_ramp = IndicatorLight{parent=main,label="Auto Ramping",colors=cpair(colors.white,colors.gray),flash=true,period=period.BLINK_250_MS}
local auto_scram = IndicatorLight{parent=main,label="Auto SCRAM",colors=cpair(colors.red,colors.gray),flash=true,period=period.BLINK_250_MS}
local all_ok = IndicatorLight{parent=main,y=5,label="Unit Systems Online",colors=cpair(colors.green,colors.red)}
local ind_mat = IndicatorLight{parent=main,label="Induction Matrix",colors=cpair(colors.green,colors.gray)}
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_ramping", auto_ramp.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
local can_start = (not unit.reactor_data.mek_status.status) 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
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}
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()
@ -485,18 +485,27 @@ local function init(parent, id)
a_stb.update(unit.annunciator.AutoControl and (not active))
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)
u_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_stb.update(unit.reactor_data.mek_status.status == false)
else
burn_rate.enable()
set_burn_btn.enable()
set_grp_btn.enable()
a_stb.update(false)
end

View File

@ -88,33 +88,33 @@ local function init(monitor)
-- testing
---@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=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=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=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=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=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=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=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=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=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,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,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 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 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 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 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 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 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="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="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=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=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=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=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=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=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=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=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=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=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=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,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=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=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=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=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=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=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=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=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=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=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=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])

View File

@ -68,7 +68,7 @@ function plc.rps_init(reactor, is_formed)
formed = is_formed,
force_disabled = false,
tripped = false,
trip_cause = "" ---@type rps_trip_cause
trip_cause = "ok" ---@type rps_trip_cause
}
---@class rps
@ -410,6 +410,7 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co
scrammed = false,
linked = false,
resend_build = false,
auto_ack_token = 0,
status_cache = 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
no_reactor, -- no reactor peripheral connected
formed, -- reactor formed
self.auto_ack_token, -- token to indicate auto command has been received before this status update
heating_rate, -- heating rate
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)
elseif packet.type == RPLC_TYPES.AUTO_BURN_RATE then
-- 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 burn_rate = math.floor(packet.data[1] * 10) / 10
local ramp = packet.data[2]
self.auto_ack_token = packet.data[3]
-- if no known max burn rate, check again
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 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 println = util.println
@ -169,6 +169,7 @@ local function main()
log.debug("init> running without networking")
end
---@diagnostic disable-next-line: param-type-mismatch
util.push_event("clock_start")
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 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
@ -362,6 +362,10 @@ local function main()
table.insert(units, rtu_unit)
if not formed then
log.debug(util.c("configure> device '", name, "' is not formed"))
end
local for_message = "facility"
if for_reactor > 0 then
for_message = util.c("reactor ", for_reactor)

View File

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

View File

@ -110,73 +110,40 @@ function log.dmesg(msg, tag, tag_color)
local t_stamp = string.format("%12.2f", os.clock())
local out = _log_sys.dmesg_out
local out_w, out_h = out.getSize()
local lines = { msg }
if out ~= nil then
local out_w, out_h = out.getSize()
-- wrap if needed
if string.len(msg) > out_w then
local remaining = true
local s_start = 1
local s_end = out_w
local i = 1
local lines = { msg }
lines = {}
-- wrap if needed
if string.len(msg) > out_w then
local remaining = true
local s_start = 1
local s_end = out_w
local i = 1
while remaining do
local line = string.sub(msg, s_start, s_end)
lines = {}
if line == "" then
remaining = false
else
lines[i] = line
while remaining do
local line = string.sub(msg, s_start, s_end)
s_start = s_end + 1
s_end = s_end + out_w
i = i + 1
if line == "" then
remaining = false
else
lines[i] = line
s_start = s_end + 1
s_end = s_end + out_w
i = i + 1
end
end
end
end
-- start output with tag and time, assuming we have enough width for this to be on one line
local cur_x, cur_y = out.getCursorPos()
-- start output with tag and time, assuming we have enough width for this to be on one line
local cur_x, cur_y = out.getCursorPos()
if cur_x > 1 then
if cur_y == out_h then
out.scroll(1)
out.setCursorPos(1, cur_y)
else
out.setCursorPos(1, cur_y + 1)
end
end
-- colored time
local initial_color = out.getTextColor()
out.setTextColor(colors.white)
out.write("[")
out.setTextColor(colors.lightGray)
out.write(t_stamp)
ts_coord.x2, ts_coord.y = out.getCursorPos()
ts_coord.x2 = ts_coord.x2 - 1
out.setTextColor(colors.white)
out.write("] ")
-- print optionally colored tag
if tag ~= "" then
out.write("[")
if tag_color then out.setTextColor(tag_color) end
out.write(tag)
out.setTextColor(colors.white)
out.write("] ")
end
out.setTextColor(initial_color)
-- output message
for i = 1, #lines do
cur_x, cur_y = out.getCursorPos()
if i > 1 and cur_x > 1 then
if cur_x > 1 then
if cur_y == out_h then
out.scroll(1)
out.setCursorPos(1, cur_y)
@ -185,10 +152,46 @@ function log.dmesg(msg, tag, tag_color)
end
end
out.write(lines[i])
end
-- colored time
local initial_color = out.getTextColor()
out.setTextColor(colors.white)
out.write("[")
out.setTextColor(colors.lightGray)
out.write(t_stamp)
ts_coord.x2, ts_coord.y = out.getCursorPos()
ts_coord.x2 = ts_coord.x2 - 1
out.setTextColor(colors.white)
out.write("] ")
_log(util.c("[", t_stamp, "] [", tag, "] ", msg))
-- print optionally colored tag
if tag ~= "" then
out.write("[")
if tag_color then out.setTextColor(tag_color) end
out.write(tag)
out.setTextColor(colors.white)
out.write("] ")
end
out.setTextColor(initial_color)
-- output message
for i = 1, #lines do
cur_x, cur_y = out.getCursorPos()
if i > 1 and cur_x > 1 then
if cur_y == out_h then
out.scroll(1)
out.setCursorPos(1, cur_y)
else
out.setCursorPos(1, cur_y + 1)
end
end
out.write(lines[i])
end
_log(util.c("[", t_stamp, "] [", tag, "] ", msg))
end
return ts_coord
end
@ -204,52 +207,56 @@ function log.dmesg_working(msg, tag, tag_color)
local out = _log_sys.dmesg_out
local width = (ts_coord.x2 - ts_coord.x1) + 1
local initial_color = out.getTextColor()
if out ~= nil then
local initial_color = out.getTextColor()
local counter = 0
local counter = 0
local function update(sec_remaining)
local time = util.sprintf("%ds", sec_remaining)
local available = width - (string.len(time) + 2)
local progress = ""
local function update(sec_remaining)
local time = util.sprintf("%ds", sec_remaining)
local available = width - (string.len(time) + 2)
local progress = ""
out.setCursorPos(ts_coord.x1, ts_coord.y)
out.write(" ")
out.setCursorPos(ts_coord.x1, ts_coord.y)
out.write(" ")
if counter % 4 == 0 then
progress = "|"
elseif counter % 4 == 1 then
progress = "/"
elseif counter % 4 == 2 then
progress = "-"
elseif counter % 4 == 3 then
progress = "\\"
if counter % 4 == 0 then
progress = "|"
elseif counter % 4 == 1 then
progress = "/"
elseif counter % 4 == 2 then
progress = "-"
elseif counter % 4 == 3 then
progress = "\\"
end
out.setTextColor(colors.blue)
out.write(progress)
out.setTextColor(colors.lightGray)
out.write(util.spaces(available) .. time)
out.setTextColor(initial_color)
counter = counter + 1
end
out.setTextColor(colors.blue)
out.write(progress)
out.setTextColor(colors.lightGray)
out.write(util.spaces(available) .. time)
out.setTextColor(initial_color)
local function done(ok)
out.setCursorPos(ts_coord.x1, ts_coord.y)
counter = counter + 1
end
if ok or ok == nil then
out.setTextColor(colors.green)
out.write(util.pad("DONE", width))
else
out.setTextColor(colors.red)
out.write(util.pad("FAIL", width))
end
local function done(ok)
out.setCursorPos(ts_coord.x1, ts_coord.y)
if ok or ok == nil then
out.setTextColor(colors.green)
out.write(util.pad("DONE", width))
else
out.setTextColor(colors.red)
out.write(util.pad("FAIL", width))
out.setTextColor(initial_color)
end
out.setTextColor(initial_color)
return update, done
else
return function () end, function () end
end
return update, done
end
-- log debug messages

View File

@ -41,6 +41,7 @@ function facility.new(num_reactors, cooling_conf)
induction = {},
redstone = {},
status_text = { "START UP", "initializing..." },
all_sys_ok = false,
-- process control
units_ready = false,
mode = PROCESS.INACTIVE,
@ -199,6 +200,11 @@ function facility.new(num_reactors, cooling_conf)
self.im_stat_init = false
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 --
-------------------------
@ -570,6 +576,7 @@ function facility.new(num_reactors, cooling_conf)
-- get automatic process control status
function public.get_control_status()
return {
self.all_sys_ok,
self.units_ready,
self.mode,
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,
commanded_state = false,
commanded_burn_rate = 0.0,
auto_cmd_token = 0,
ramping_rate = false,
auto_scram = false,
auto_lock = false,
@ -92,6 +93,7 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
-- session database
---@class reactor_db
sDB = {
auto_ack_token = 0,
last_status_update = 0,
control_state = false,
no_reactor = false,
@ -305,18 +307,19 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
-- handle packet by type
if pkt.type == RPLC_TYPES.STATUS then
-- 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.control_state = pkt.data[2]
self.sDB.no_reactor = pkt.data[3]
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
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
if pkt.data[6] ~= nil then
local status = pcall(_copy_status, pkt.data[6])
if pkt.data[7] ~= nil then
local status = pcall(_copy_status, pkt.data[7])
if status then
-- copied in status data OK
self.received_status_cache = true
@ -496,6 +499,11 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
-- get the session database
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
function public.get_struct()
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
if cmd.val > 0 and cmd.val <= self.sDB.mek_struct.max_burn then
self.commanded_burn_rate = cmd.val
self.auto_cmd_token = 0
self.ramping_rate = false
self.acks.burn_rate = false
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
if cmd.val > 0 and cmd.val <= self.sDB.mek_struct.max_burn then
self.commanded_burn_rate = cmd.val
self.auto_cmd_token = 0
self.ramping_rate = true
self.acks.burn_rate = false
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
if self.auto_lock then
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
-- this is only for manual control, only retry auto ramps
self.acks.burn_rate = not self.ramping_rate
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
else
@ -717,10 +728,19 @@ function plc.new_session(id, for_reactor, in_queue, out_queue)
if not self.acks.burn_rate then
if rtimes.burn_rate_req - util.time() <= 0 then
if self.auto_lock then
_send(RPLC_TYPES.AUTO_BURN_RATE, { self.commanded_burn_rate, self.ramping_rate })
else
if self.auto_cmd_token > 0 then
if self.auto_lock then
_send(RPLC_TYPES.AUTO_BURN_RATE, { self.commanded_burn_rate, self.ramping_rate, self.auto_cmd_token })
log.debug("retried auto burn rate?")
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 })
else
-- shouldn't be in this state, just pretend it was acknowledged
self.acks.burn_rate = true
end
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
function public.a_ramp_complete()
if self.plc_i ~= nil then
local cur_rate = math.floor(self.plc_i.get_db().mek_status.burn_rate * 10)
return (cur_rate == self.ramp_target_br10) or (self.ramp_target_br10 == 0)
return self.plc_i.is_ramp_complete()
else return true end
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.11"
local SUPERVISOR_VERSION = "beta-v0.9.12"
local print = util.print
local println = util.println