Merge branch 'devel' into color-update

This commit is contained in:
Mikayla Fischler 2024-03-05 22:03:24 -05:00
commit c714e49ad8
19 changed files with 240 additions and 174 deletions

View File

@ -95,8 +95,8 @@ function coordinator.load_config()
---@class monitors_struct ---@class monitors_struct
local monitors = { local monitors = {
primary = nil, ---@type table|nil main = nil, ---@type table|nil
primary_name = "", main_name = "",
flow = nil, ---@type table|nil flow = nil, ---@type table|nil
flow_name = "", flow_name = "",
unit_displays = {}, unit_displays = {},
@ -121,11 +121,11 @@ function coordinator.load_config()
return 2, "Main monitor is not connected." return 2, "Main monitor is not connected."
end end
monitors.primary = ppm.get_periph(config.MainDisplay) monitors.main = ppm.get_periph(config.MainDisplay)
monitors.primary_name = config.MainDisplay monitors.main_name = config.MainDisplay
monitors.primary.setTextScale(0.5) monitors.main.setTextScale(0.5)
w, _ = ppm.monitor_block_size(monitors.primary.getSize()) w, _ = ppm.monitor_block_size(monitors.main.getSize())
if w ~= 8 then if w ~= 8 then
return 2, util.c("Main monitor width is incorrect (was ", w, ", must be 8).") return 2, util.c("Main monitor width is incorrect (was ", w, ", must be 8).")
end end

View File

@ -235,7 +235,10 @@ function iocontrol.init(conf, comms, temp_scale)
control_state = false, control_state = false,
burn_rate_cmd = 0.0, burn_rate_cmd = 0.0,
radiation = types.new_zero_radiation_reading(), radiation = types.new_zero_radiation_reading(),
sna_prod_rate = 0.0,
sna_peak_rate = 0.0,
sna_max_rate = 0.0,
sna_out_rate = 0.0,
waste_mode = types.WASTE_MODE.MANUAL_PLUTONIUM, waste_mode = types.WASTE_MODE.MANUAL_PLUTONIUM,
waste_product = types.WASTE_PRODUCT.PLUTONIUM, waste_product = types.WASTE_PRODUCT.PLUTONIUM,
@ -1064,12 +1067,14 @@ function iocontrol.update_unit_statuses(statuses)
-- solar neutron activator status info -- solar neutron activator status info
if type(rtu_statuses.sna) == "table" then if type(rtu_statuses.sna) == "table" then
unit.num_snas = rtu_statuses.sna[1] ---@type integer unit.num_snas = rtu_statuses.sna[1] ---@type integer
unit.sna_prod_rate = rtu_statuses.sna[2] ---@type number unit.sna_peak_rate = rtu_statuses.sna[2] ---@type number
unit.sna_peak_rate = rtu_statuses.sna[3] ---@type number unit.sna_max_rate = rtu_statuses.sna[3] ---@type number
unit.sna_out_rate = rtu_statuses.sna[4] ---@type number
unit.unit_ps.publish("sna_count", unit.num_snas) unit.unit_ps.publish("sna_count", unit.num_snas)
unit.unit_ps.publish("sna_prod_rate", unit.sna_prod_rate)
unit.unit_ps.publish("sna_peak_rate", unit.sna_peak_rate) unit.unit_ps.publish("sna_peak_rate", unit.sna_peak_rate)
unit.unit_ps.publish("sna_max_rate", unit.sna_max_rate)
unit.unit_ps.publish("sna_out_rate", unit.sna_out_rate)
sna_count_sum = sna_count_sum + unit.num_snas sna_count_sum = sna_count_sum + unit.num_snas
else else
@ -1217,7 +1222,7 @@ function iocontrol.update_unit_statuses(statuses)
local u_spent_rate = waste_rate local u_spent_rate = waste_rate
local u_pu_rate = util.trinary(is_pu, waste_rate, 0.0) local u_pu_rate = util.trinary(is_pu, waste_rate, 0.0)
local u_po_rate = util.trinary(not is_pu, math.min(waste_rate, unit.sna_prod_rate), 0.0) local u_po_rate = unit.sna_out_rate
unit.unit_ps.publish("pu_rate", u_pu_rate) unit.unit_ps.publish("pu_rate", u_pu_rate)
unit.unit_ps.publish("po_rate", u_po_rate) unit.unit_ps.publish("po_rate", u_po_rate)
@ -1225,14 +1230,15 @@ function iocontrol.update_unit_statuses(statuses)
unit.unit_ps.publish("sna_in", util.trinary(is_pu, 0, burn_rate)) unit.unit_ps.publish("sna_in", util.trinary(is_pu, 0, burn_rate))
if unit.waste_product == types.WASTE_PRODUCT.POLONIUM then if unit.waste_product == types.WASTE_PRODUCT.POLONIUM then
u_spent_rate = u_po_rate
unit.unit_ps.publish("po_pl_rate", u_po_rate) unit.unit_ps.publish("po_pl_rate", u_po_rate)
unit.unit_ps.publish("po_am_rate", 0) unit.unit_ps.publish("po_am_rate", 0)
po_pl_rate = po_pl_rate + u_po_rate po_pl_rate = po_pl_rate + u_po_rate
elseif unit.waste_product == types.WASTE_PRODUCT.ANTI_MATTER then elseif unit.waste_product == types.WASTE_PRODUCT.ANTI_MATTER then
u_spent_rate = 0
unit.unit_ps.publish("po_pl_rate", 0) unit.unit_ps.publish("po_pl_rate", 0)
unit.unit_ps.publish("po_am_rate", u_po_rate) unit.unit_ps.publish("po_am_rate", u_po_rate)
po_am_rate = po_am_rate + u_po_rate po_am_rate = po_am_rate + u_po_rate
u_spent_rate = 0
else else
unit.unit_ps.publish("po_pl_rate", 0) unit.unit_ps.publish("po_pl_rate", 0)
unit.unit_ps.publish("po_am_rate", 0) unit.unit_ps.publish("po_am_rate", 0)

View File

@ -52,6 +52,16 @@ local function _init_display(monitor)
end end
end end
-- print out that the monitor is too small
---@param monitor table monitor
local function _print_too_small(monitor)
monitor.setCursorPos(1, 1)
monitor.setBackgroundColor(colors.black)
monitor.setTextColor(colors.red)
monitor.clear()
monitor.write("monitor too small")
end
-- disable the flow view -- disable the flow view
---@param disable boolean ---@param disable boolean
function renderer.legacy_disable_flow_view(disable) function renderer.legacy_disable_flow_view(disable)
@ -64,15 +74,15 @@ function renderer.set_displays(monitors)
engine.monitors = monitors engine.monitors = monitors
-- report to front panel as connected -- report to front panel as connected
iocontrol.fp_monitor_state("main", engine.monitors.primary ~= nil) iocontrol.fp_monitor_state("main", engine.monitors.main ~= nil)
iocontrol.fp_monitor_state("flow", engine.monitors.flow ~= nil) iocontrol.fp_monitor_state("flow", engine.monitors.flow ~= nil)
for i = 1, #engine.monitors.unit_displays do iocontrol.fp_monitor_state(i, true) end for i = 1, #engine.monitors.unit_displays do iocontrol.fp_monitor_state(i, true) end
end end
-- init all displays in use by the renderer -- init all displays in use by the renderer
function renderer.init_displays() function renderer.init_displays()
-- init primary and flow monitors -- init main and flow monitors
_init_display(engine.monitors.primary) _init_display(engine.monitors.main)
if not engine.disable_flow_view then _init_display(engine.monitors.flow) end if not engine.disable_flow_view then _init_display(engine.monitors.flow) end
-- init unit displays -- init unit displays
@ -94,8 +104,8 @@ end
-- initialize the dmesg output window -- initialize the dmesg output window
function renderer.init_dmesg() function renderer.init_dmesg()
local disp_w, disp_h = engine.monitors.primary.getSize() local disp_w, disp_h = engine.monitors.main.getSize()
engine.dmesg_window = window.create(engine.monitors.primary, 1, 1, disp_w, disp_h) engine.dmesg_window = window.create(engine.monitors.main, 1, 1, disp_w, disp_h)
log.direct_dmesg(engine.dmesg_window) log.direct_dmesg(engine.dmesg_window)
end end
@ -166,8 +176,8 @@ function renderer.try_start_ui()
status, msg = pcall(function () status, msg = pcall(function ()
-- show main view on main monitor -- show main view on main monitor
if engine.monitors.primary ~= nil then if engine.monitors.main ~= nil then
engine.ui.main_display = DisplayBox{window=engine.monitors.primary,fg_bg=style.root} engine.ui.main_display = DisplayBox{window=engine.monitors.main,fg_bg=style.root}
main_view(engine.ui.main_display) main_view(engine.ui.main_display)
end end
@ -244,14 +254,14 @@ function renderer.handle_disconnect(device)
if not engine.monitors then return false end if not engine.monitors then return false end
if engine.monitors.primary == device then if engine.monitors.main == device then
if engine.ui.main_display ~= nil then if engine.ui.main_display ~= nil then
-- delete element tree and clear root UI elements -- delete element tree and clear root UI elements
engine.ui.main_display.delete() engine.ui.main_display.delete()
end end
is_used = true is_used = true
engine.monitors.primary = nil engine.monitors.main = nil
engine.ui.main_display = nil engine.ui.main_display = nil
iocontrol.fp_monitor_state("main", false) iocontrol.fp_monitor_state("main", false)
@ -298,9 +308,9 @@ function renderer.handle_reconnect(name, device)
-- note: handle_resize is a more adaptive way of re-initializing a connected monitor -- note: handle_resize is a more adaptive way of re-initializing a connected monitor
-- since it can handle a monitor being reconnected that isn't the right size -- since it can handle a monitor being reconnected that isn't the right size
if engine.monitors.primary_name == name then if engine.monitors.main_name == name then
is_used = true is_used = true
engine.monitors.primary = device engine.monitors.main = device
renderer.handle_resize(name) renderer.handle_resize(name)
elseif engine.monitors.flow_name == name then elseif engine.monitors.flow_name == name then
@ -334,8 +344,8 @@ function renderer.handle_resize(name)
if not engine.monitors then return false, false end if not engine.monitors then return false, false end
if engine.monitors.primary_name == name and engine.monitors.primary then if engine.monitors.main_name == name and engine.monitors.main then
local device = engine.monitors.primary ---@type table local device = engine.monitors.main ---@type table
-- this is necessary if the bottom left block was broken and on reconnect -- this is necessary if the bottom left block was broken and on reconnect
_init_display(device) _init_display(device)
@ -343,9 +353,9 @@ function renderer.handle_resize(name)
is_used = true is_used = true
-- resize dmesg window if needed, but don't make it thinner -- resize dmesg window if needed, but don't make it thinner
local disp_w, disp_h = engine.monitors.primary.getSize() local disp_w, disp_h = engine.monitors.main.getSize()
local dmsg_w, _ = engine.dmesg_window.getSize() local dmsg_w, _ = engine.dmesg_window.getSize()
engine.dmesg_window.reposition(1, 1, math.max(disp_w, dmsg_w), disp_h, engine.monitors.primary) engine.dmesg_window.reposition(1, 1, math.max(disp_w, dmsg_w), disp_h, engine.monitors.main)
if ui.main_display then if ui.main_display then
ui.main_display.delete() ui.main_display.delete()
@ -368,11 +378,7 @@ function renderer.handle_resize(name)
ui.main_display = nil ui.main_display = nil
end end
device.setCursorPos(1, 1) _print_too_small(device)
device.setBackgroundColor(colors.black)
device.setTextColor(colors.red)
device.clear()
device.write("monitor too small")
iocontrol.fp_monitor_state("main", false) iocontrol.fp_monitor_state("main", false)
is_ok = false is_ok = false
@ -407,11 +413,7 @@ function renderer.handle_resize(name)
ui.flow_display = nil ui.flow_display = nil
end end
device.setCursorPos(1, 1) _print_too_small(device)
device.setBackgroundColor(colors.black)
device.setTextColor(colors.red)
device.clear()
device.write("monitor too small")
iocontrol.fp_monitor_state("flow", false) iocontrol.fp_monitor_state("flow", false)
is_ok = false is_ok = false
@ -448,11 +450,7 @@ function renderer.handle_resize(name)
ui.unit_displays[idx] = nil ui.unit_displays[idx] = nil
end end
device.setCursorPos(1, 1) _print_too_small(device)
device.setBackgroundColor(colors.black)
device.setTextColor(colors.red)
device.clear()
device.write("monitor too small")
iocontrol.fp_monitor_state(idx, false) iocontrol.fp_monitor_state(idx, false)
is_ok = false is_ok = false
@ -474,7 +472,7 @@ function renderer.handle_mouse(event)
if engine.fp_ready and event.monitor == "terminal" then if engine.fp_ready and event.monitor == "terminal" then
engine.ui.front_panel.handle_mouse(event) engine.ui.front_panel.handle_mouse(event)
elseif engine.ui_ready then elseif engine.ui_ready then
if event.monitor == engine.monitors.primary_name then if event.monitor == engine.monitors.main_name then
if engine.ui.main_display then engine.ui.main_display.handle_mouse(event) end if engine.ui.main_display then engine.ui.main_display.handle_mouse(event) end
elseif event.monitor == engine.monitors.flow_name then elseif event.monitor == engine.monitors.flow_name then
if engine.ui.flow_display then engine.ui.flow_display.handle_mouse(event) end if engine.ui.flow_display then engine.ui.flow_display.handle_mouse(event) end

View File

@ -22,9 +22,9 @@ local sounder = require("coordinator.sounder")
local apisessions = require("coordinator.session.apisessions") local apisessions = require("coordinator.session.apisessions")
local COORDINATOR_VERSION = "v1.2.7" local COORDINATOR_VERSION = "v1.2.11"
local CHUNK_LOAD_DELAY_S = 20.0 local CHUNK_LOAD_DELAY_S = 30.0
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts
@ -42,24 +42,33 @@ local log_crypto = coordinator.log_crypto
-- mount connected devices (required for monitor setup) -- mount connected devices (required for monitor setup)
ppm.mount_all() ppm.mount_all()
local wait_on_load = true
local loaded, monitors = coordinator.load_config() local loaded, monitors = coordinator.load_config()
-- if the computer just started, its chunk may have just loaded (...or the user rebooted) -- if the computer just started, its chunk may have just loaded (...or the user rebooted)
-- if monitor config failed, maybe an adjacent chunk containing all or part of a monitor has not loaded yet, so keep trying -- if monitor config failed, maybe an adjacent chunk containing all or part of a monitor has not loaded yet, so keep trying
while loaded == 2 and os.clock() < CHUNK_LOAD_DELAY_S do while wait_on_load and loaded == 2 and os.clock() < CHUNK_LOAD_DELAY_S do
term.clear() term.clear()
term.setCursorPos(1, 1) term.setCursorPos(1, 1)
println("There was a monitor configuration problem at boot.\n") println("There was a monitor configuration problem at boot.\n")
println("Startup will keep trying every 2s in case of chunk load delays.\n") println("Startup will keep trying every 2s in case of chunk load delays.\n")
println(util.sprintf("The configurator will be started in %ds if all attempts fail.\n", math.max(0, CHUNK_LOAD_DELAY_S - os.clock()))) println(util.sprintf("The configurator will be started in %ds if all attempts fail.\n", math.max(0, CHUNK_LOAD_DELAY_S - os.clock())))
println("(exit early with ctrl-t)") println("(click to skip to the configurator)")
---@diagnostic disable-next-line: undefined-field local timer_id = util.start_timer(2)
os.sleep(2)
while true do
local event, param1 = util.pull_event()
if event == "timer" and param1 == timer_id then
-- remount and re-attempt -- remount and re-attempt
ppm.mount_all() ppm.mount_all()
loaded, monitors = coordinator.load_config() loaded, monitors = coordinator.load_config()
break
elseif event == "mouse_click" or event == "terminate" then
wait_on_load = false
break
end
end
end end
if loaded ~= 0 then if loaded ~= 0 then
@ -67,9 +76,13 @@ if loaded ~= 0 then
local success, error = configure.configure(loaded, monitors) local success, error = configure.configure(loaded, monitors)
if success then if success then
loaded, monitors = coordinator.load_config() loaded, monitors = coordinator.load_config()
assert(loaded == 0, util.trinary(loaded == 1, "failed to load valid configuration", "monitor configuration invalid")) if loaded ~= 0 then
println(util.trinary(loaded == 2, "monitor configuration invalid", "failed to load a valid configuration") .. ", please reconfigure")
return
end
else else
assert(success, "coordinator configuration error: " .. error) println("configuration error: " .. error)
return
end end
end end

View File

@ -187,10 +187,10 @@ local function make(parent, x, y, wide, unit)
local waste_rate = DataIndicator{parent=waste,x=1,y=3,lu_colors=lu_c,label="",unit="mB/t",format="%7.2f",value=0,width=12,fg_bg=s_field} local waste_rate = DataIndicator{parent=waste,x=1,y=3,lu_colors=lu_c,label="",unit="mB/t",format="%7.2f",value=0,width=12,fg_bg=s_field}
local pu_rate = DataIndicator{parent=waste,x=_wide(82,70),y=3,lu_colors=lu_c,label="",unit="mB/t",format="%7.3f",value=0,width=12,fg_bg=s_field} local pu_rate = DataIndicator{parent=waste,x=_wide(82,70),y=3,lu_colors=lu_c,label="",unit="mB/t",format="%7.3f",value=0,width=12,fg_bg=s_field}
local po_rate = DataIndicator{parent=waste,x=_wide(52,45),y=6,lu_colors=lu_c,label="",unit="mB/t",format="%7.3f",value=0,width=12,fg_bg=s_field} local po_rate = DataIndicator{parent=waste,x=_wide(52,45),y=6,lu_colors=lu_c,label="",unit="mB/t",format="%7.2f",value=0,width=12,fg_bg=s_field}
local popl_rate = DataIndicator{parent=waste,x=_wide(82,70),y=6,lu_colors=lu_c,label="",unit="mB/t",format="%7.3f",value=0,width=12,fg_bg=s_field} local popl_rate = DataIndicator{parent=waste,x=_wide(82,70),y=6,lu_colors=lu_c,label="",unit="mB/t",format="%7.2f",value=0,width=12,fg_bg=s_field}
local poam_rate = DataIndicator{parent=waste,x=_wide(82,70),y=10,lu_colors=lu_c,label="",unit="mB/t",format="%7.3f",value=0,width=12,fg_bg=s_field} local poam_rate = DataIndicator{parent=waste,x=_wide(82,70),y=10,lu_colors=lu_c,label="",unit="mB/t",format="%7.2f",value=0,width=12,fg_bg=s_field}
local spent_rate = DataIndicator{parent=waste,x=_wide(117,99),y=3,lu_colors=lu_c,label="",unit="mB/t",format="%7.3f",value=0,width=12,fg_bg=s_field} local spent_rate = DataIndicator{parent=waste,x=_wide(117,98),y=3,lu_colors=lu_c,label="",unit="mB/t",format="%8.3f",value=0,width=13,fg_bg=s_field}
waste_rate.register(unit.unit_ps, "act_burn_rate", waste_rate.update) waste_rate.register(unit.unit_ps, "act_burn_rate", waste_rate.update)
pu_rate.register(unit.unit_ps, "pu_rate", pu_rate.update) pu_rate.register(unit.unit_ps, "pu_rate", pu_rate.update)
@ -220,7 +220,7 @@ local function make(parent, x, y, wide, unit)
sna_act.register(unit.unit_ps, "po_rate", function (r) sna_act.update(r > 0) end) sna_act.register(unit.unit_ps, "po_rate", function (r) sna_act.update(r > 0) end)
sna_cnt.register(unit.unit_ps, "sna_count", sna_cnt.update) sna_cnt.register(unit.unit_ps, "sna_count", sna_cnt.update)
sna_pk.register(unit.unit_ps, "sna_peak_rate", sna_pk.update) sna_pk.register(unit.unit_ps, "sna_peak_rate", sna_pk.update)
sna_max.register(unit.unit_ps, "sna_prod_rate", sna_max.update) sna_max.register(unit.unit_ps, "sna_max_rate", sna_max.update)
sna_in.register(unit.unit_ps, "sna_in", sna_in.update) sna_in.register(unit.unit_ps, "sna_in", sna_in.update)
return root return root

View File

@ -351,7 +351,7 @@ local function init(main)
status.register(facility.sps_ps_tbl[1], "computed_status", status.update) status.register(facility.sps_ps_tbl[1], "computed_status", status.update)
TextBox{parent=sps_box,x=2,y=3,text="Input Rate",height=1,width=10,fg_bg=style.label} TextBox{parent=sps_box,x=2,y=3,text="Input Rate",height=1,width=10,fg_bg=style.label}
local sps_in = DataIndicator{parent=sps_box,x=2,label="",format="%15.3f",value=0,unit="mB/t",lu_colors=lu_col,width=20,fg_bg=s_field} local sps_in = DataIndicator{parent=sps_box,x=2,label="",format="%15.2f",value=0,unit="mB/t",lu_colors=lu_col,width=20,fg_bg=s_field}
sps_in.register(facility.ps, "po_am_rate", sps_in.update) sps_in.register(facility.ps, "po_am_rate", sps_in.update)
@ -373,8 +373,8 @@ local function init(main)
TextBox{parent=main,x=145,y=21,text="PROC. WASTE",alignment=ALIGN.CENTER,width=19,height=1,fg_bg=wh_gray} TextBox{parent=main,x=145,y=21,text="PROC. WASTE",alignment=ALIGN.CENTER,width=19,height=1,fg_bg=wh_gray}
local pr_waste = Rectangle{parent=main,x=145,y=22,border=border(1,colors.gray,true),width=19,height=5,thin=true,fg_bg=s_hi_bright} local pr_waste = Rectangle{parent=main,x=145,y=22,border=border(1,colors.gray,true),width=19,height=5,thin=true,fg_bg=s_hi_bright}
local pu = DataIndicator{parent=pr_waste,lu_colors=lu_c_d,label="Pu",unit="mB/t",format="%9.3f",value=0,width=17} local pu = DataIndicator{parent=pr_waste,lu_colors=lu_c_d,label="Pu",unit="mB/t",format="%9.3f",value=0,width=17}
local po = DataIndicator{parent=pr_waste,lu_colors=lu_c_d,label="Po",unit="mB/t",format="%9.3f",value=0,width=17} local po = DataIndicator{parent=pr_waste,lu_colors=lu_c_d,label="Po",unit="mB/t",format="%9.2f",value=0,width=17}
local popl = DataIndicator{parent=pr_waste,lu_colors=lu_c_d,label="PoPl",unit="mB/t",format="%7.3f",value=0,width=17} local popl = DataIndicator{parent=pr_waste,lu_colors=lu_c_d,label="PoPl",unit="mB/t",format="%7.2f",value=0,width=17}
pu.register(facility.ps, "pu_rate", pu.update) pu.register(facility.ps, "pu_rate", pu.update)
po.register(facility.ps, "po_rate", po.update) po.register(facility.ps, "po_rate", po.update)

View File

@ -18,7 +18,7 @@ local iocontrol = require("pocket.iocontrol")
local pocket = require("pocket.pocket") local pocket = require("pocket.pocket")
local renderer = require("pocket.renderer") local renderer = require("pocket.renderer")
local POCKET_VERSION = "v0.7.0-alpha" local POCKET_VERSION = "v0.7.1-alpha"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts
@ -31,9 +31,13 @@ if not pocket.load_config() then
-- try to reconfigure (user action) -- try to reconfigure (user action)
local success, error = configure.configure(true) local success, error = configure.configure(true)
if success then if success then
assert(pocket.load_config(), "failed to load valid configuration") if not pocket.load_config() then
println("failed to load a valid configuration, please reconfigure")
return
end
else else
assert(success, "pocket configuration error: " .. error) println("configuration error: " .. error)
return
end end
end end

View File

@ -70,9 +70,9 @@ function databus.tx_link_state(state)
end end
-- transmit reactor enable state across the bus -- transmit reactor enable state across the bus
---@param active boolean reactor active ---@param active any reactor active
function databus.tx_reactor_state(active) function databus.tx_reactor_state(active)
databus.ps.publish("reactor_active", active) databus.ps.publish("reactor_active", active == true)
end end
-- transmit RPS data across the bus -- transmit RPS data across the bus

View File

@ -129,6 +129,21 @@ function plc.rps_init(reactor, is_formed)
end end
end end
-- check if the result of a peripheral call was OK, handle the failure if not
---@nodiscard
---@param result any PPM function call result
---@return boolean succeeded if the result is OK, false if it was a PPM failure
local function _check_and_handle_ppm_call(result)
if result == ppm.ACCESS_FAULT then
_set_fault()
elseif result == ppm.UNDEFINED_FIELD then
_set_fault()
self.formed = false
else return true end
return false
end
-- set emergency coolant control (if configured) -- set emergency coolant control (if configured)
---@param state boolean true to enable emergency coolant, false to disable ---@param state boolean true to enable emergency coolant, false to disable
local function _set_emer_cool(state) local function _set_emer_cool(state)
@ -167,25 +182,20 @@ function plc.rps_init(reactor, is_formed)
-- check if the reactor is formed -- check if the reactor is formed
local function _is_formed() local function _is_formed()
local formed = reactor.isFormed() local formed = reactor.isFormed()
if formed == ppm.ACCESS_FAULT then if _check_and_handle_ppm_call(formed) then
-- lost the peripheral or terminated, handled later
_set_fault()
else
self.formed = formed self.formed = formed
if not self.state[state_keys.sys_fail] then
self.state[state_keys.sys_fail] = not formed
end end
-- always update, since some ppm failures constitute not being formed
if not self.state[state_keys.sys_fail] then
self.state[state_keys.sys_fail] = not self.formed
end end
end end
-- check if the reactor is force disabled -- check if the reactor is force disabled
local function _is_force_disabled() local function _is_force_disabled()
local disabled = reactor.isForceDisabled() local disabled = reactor.isForceDisabled()
if disabled == ppm.ACCESS_FAULT then if _check_and_handle_ppm_call(disabled) then
-- lost the peripheral or terminated, handled later
_set_fault()
else
self.force_disabled = disabled self.force_disabled = disabled
if not self.state[state_keys.force_disabled] then if not self.state[state_keys.force_disabled] then
@ -197,22 +207,16 @@ function plc.rps_init(reactor, is_formed)
-- check for high damage -- check for high damage
local function _high_damage() local function _high_damage()
local damage_percent = reactor.getDamagePercent() local damage_percent = reactor.getDamagePercent()
if damage_percent == ppm.ACCESS_FAULT then if _check_and_handle_ppm_call(damage_percent) and not self.state[state_keys.high_dmg] then
-- lost the peripheral or terminated, handled later
_set_fault()
elseif not self.state[state_keys.high_dmg] then
self.state[state_keys.high_dmg] = damage_percent >= RPS_LIMITS.MAX_DAMAGE_PERCENT self.state[state_keys.high_dmg] = damage_percent >= RPS_LIMITS.MAX_DAMAGE_PERCENT
end end
end end
-- check if the reactor is at a critically high temperature -- check if the reactor is at a critically high temperature
local function _high_temp() local function _high_temp()
-- mekanism: MAX_DAMAGE_TEMPERATURE = 1_200 -- mekanism: MAX_DAMAGE_TEMPERATURE = 1200K
local temp = reactor.getTemperature() local temp = reactor.getTemperature()
if temp == ppm.ACCESS_FAULT then if _check_and_handle_ppm_call(temp) and not self.state[state_keys.high_temp] then
-- lost the peripheral or terminated, handled later
_set_fault()
elseif not self.state[state_keys.high_temp] then
self.state[state_keys.high_temp] = temp >= RPS_LIMITS.MAX_DAMAGE_TEMPERATURE self.state[state_keys.high_temp] = temp >= RPS_LIMITS.MAX_DAMAGE_TEMPERATURE
end end
end end
@ -220,10 +224,7 @@ function plc.rps_init(reactor, is_formed)
-- check if there is very low coolant -- check if there is very low coolant
local function _low_coolant() local function _low_coolant()
local coolant_filled = reactor.getCoolantFilledPercentage() local coolant_filled = reactor.getCoolantFilledPercentage()
if coolant_filled == ppm.ACCESS_FAULT then if _check_and_handle_ppm_call(coolant_filled) and not self.state[state_keys.low_coolant] then
-- lost the peripheral or terminated, handled later
_set_fault()
elseif not self.state[state_keys.low_coolant] then
self.state[state_keys.low_coolant] = coolant_filled < RPS_LIMITS.MIN_COOLANT_FILL self.state[state_keys.low_coolant] = coolant_filled < RPS_LIMITS.MIN_COOLANT_FILL
end end
end end
@ -231,10 +232,7 @@ function plc.rps_init(reactor, is_formed)
-- check for excess waste (>80% filled) -- check for excess waste (>80% filled)
local function _excess_waste() local function _excess_waste()
local w_filled = reactor.getWasteFilledPercentage() local w_filled = reactor.getWasteFilledPercentage()
if w_filled == ppm.ACCESS_FAULT then if _check_and_handle_ppm_call(w_filled) and not self.state[state_keys.ex_waste] then
-- lost the peripheral or terminated, handled later
_set_fault()
elseif not self.state[state_keys.ex_waste] then
self.state[state_keys.ex_waste] = w_filled > RPS_LIMITS.MAX_WASTE_FILL self.state[state_keys.ex_waste] = w_filled > RPS_LIMITS.MAX_WASTE_FILL
end end
end end
@ -242,10 +240,7 @@ function plc.rps_init(reactor, is_formed)
-- check for heated coolant backup (>95% filled) -- check for heated coolant backup (>95% filled)
local function _excess_heated_coolant() local function _excess_heated_coolant()
local hc_filled = reactor.getHeatedCoolantFilledPercentage() local hc_filled = reactor.getHeatedCoolantFilledPercentage()
if hc_filled == ppm.ACCESS_FAULT then if _check_and_handle_ppm_call(hc_filled) and not self.state[state_keys.ex_hcoolant] then
-- lost the peripheral or terminated, handled later
_set_fault()
elseif not self.state[state_keys.ex_hcoolant] then
self.state[state_keys.ex_hcoolant] = hc_filled > RPS_LIMITS.MAX_HEATED_COLLANT_FILL self.state[state_keys.ex_hcoolant] = hc_filled > RPS_LIMITS.MAX_HEATED_COLLANT_FILL
end end
end end
@ -253,10 +248,7 @@ function plc.rps_init(reactor, is_formed)
-- check if there is no fuel -- check if there is no fuel
local function _insufficient_fuel() local function _insufficient_fuel()
local fuel = reactor.getFuelFilledPercentage() local fuel = reactor.getFuelFilledPercentage()
if fuel == ppm.ACCESS_FAULT then if _check_and_handle_ppm_call(fuel) and not self.state[state_keys.no_fuel] then
-- lost the peripheral or terminated, handled later
_set_fault()
elseif not self.state[state_keys.no_fuel] then
self.state[state_keys.no_fuel] = fuel <= RPS_LIMITS.NO_FUEL_FILL self.state[state_keys.no_fuel] = fuel <= RPS_LIMITS.NO_FUEL_FILL
end end
end end
@ -477,13 +469,22 @@ function plc.rps_init(reactor, is_formed)
self.tripped = false self.tripped = false
self.trip_cause = RPS_TRIP_CAUSE.OK self.trip_cause = RPS_TRIP_CAUSE.OK
for i = 1, #self.state do for i = 1, #self.state do self.state[i] = false end
self.state[i] = false
end
if not quiet then log.info("RPS: reset") end if not quiet then log.info("RPS: reset") end
end end
-- partial RPS reset that only clears fault and sys_fail
function public.reset_formed()
self.tripped = false
self.trip_cause = RPS_TRIP_CAUSE.OK
self.state[state_keys.fault] = false
self.state[state_keys.sys_fail] = false
log.info("RPS: partial reset on formed")
end
-- reset the automatic and timeout trip flags, then clear trip if that was the trip cause -- reset the automatic and timeout trip flags, then clear trip if that was the trip cause
function public.auto_reset() function public.auto_reset()
self.state[state_keys.automatic] = false self.state[state_keys.automatic] = false

View File

@ -18,7 +18,7 @@ local plc = require("reactor-plc.plc")
local renderer = require("reactor-plc.renderer") local renderer = require("reactor-plc.renderer")
local threads = require("reactor-plc.threads") local threads = require("reactor-plc.threads")
local R_PLC_VERSION = "v1.6.11" local R_PLC_VERSION = "v1.6.14"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts
@ -31,9 +31,13 @@ if not plc.load_config() then
-- try to reconfigure (user action) -- try to reconfigure (user action)
local success, error = configure.configure(true) local success, error = configure.configure(true)
if success then if success then
assert(plc.load_config(), "failed to load valid configuration") if not plc.load_config() then
println("failed to load a valid configuration, please reconfigure")
return
end
else else
assert(success, "reactor PLC configuration error: " .. error) println("configuration error: " .. error)
return
end end
end end
@ -131,15 +135,22 @@ local function main()
-- we need a reactor, can at least do some things even if it isn't formed though -- we need a reactor, can at least do some things even if it isn't formed though
if plc_state.no_reactor then if plc_state.no_reactor then
println("init> fission reactor not found"); println("init> fission reactor not found")
log.warning("init> no reactor on startup") log.warning("init> no reactor on startup")
plc_state.init_ok = false plc_state.init_ok = false
plc_state.degraded = true plc_state.degraded = true
elseif not smem_dev.reactor.isFormed() then elseif not smem_dev.reactor.isFormed() then
println("init> fission reactor not formed"); println("init> fission reactor is not formed")
log.warning("init> reactor logic adapter present, but reactor is not formed") log.warning("init> reactor logic adapter present, but reactor is not formed")
plc_state.degraded = true
plc_state.reactor_formed = false
elseif smem_dev.reactor.getStatus() == ppm.UNDEFINED_FIELD then
-- reactor formed after ppm.mount_all was called
println("init> fission reactor was not formed")
log.warning("init> reactor reported formed, but multiblock functions are not available")
plc_state.degraded = true plc_state.degraded = true
plc_state.reactor_formed = false plc_state.reactor_formed = false
end end

View File

@ -125,9 +125,8 @@ function threads.thread__main(smem, init)
plc_comms.reconnect_reactor(plc_dev.reactor) plc_comms.reconnect_reactor(plc_dev.reactor)
end end
-- reset RPS for newly connected reactor -- partial reset of RPS, specific to becoming formed
-- without this, is_formed will be out of date and cause it to think its no longer formed again rps.reset_formed()
rps.reset()
else else
-- fully lost the reactor now :( -- fully lost the reactor now :(
println_ts("reactor lost (failed reconnect)!") println_ts("reactor lost (failed reconnect)!")
@ -231,9 +230,8 @@ function threads.thread__main(smem, init)
plc_comms.reconnect_reactor(plc_dev.reactor) plc_comms.reconnect_reactor(plc_dev.reactor)
end end
-- reset RPS for newly connected reactor -- partial reset of RPS, specific to becoming formed
-- without this, is_formed will be out of date and cause it to think its no longer formed again rps.reset_formed()
rps.reset()
end end
elseif networked and type == "modem" then elseif networked and type == "modem" then
-- note, check init_ok first since nic will be nil if it is false -- note, check init_ok first since nic will be nil if it is false

View File

@ -31,7 +31,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 = "v1.7.13" local RTU_VERSION = "v1.7.14"
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE
@ -47,9 +47,13 @@ if not rtu.load_config() then
-- try to reconfigure (user action) -- try to reconfigure (user action)
local success, error = configure.configure(true) local success, error = configure.configure(true)
if success then if success then
assert(rtu.load_config(), "failed to load valid configuration") if not rtu.load_config() then
println("failed to load a valid configuration, please reconfigure")
return
end
else else
assert(success, "RTU configuration error: " .. error) println("configuration error: " .. error)
return
end end
end end

View File

@ -17,7 +17,7 @@ local max_distance = nil
local comms = {} local comms = {}
-- protocol/data version (protocol/data independent changes tracked by util.lua version) -- protocol/data version (protocol/data independent changes tracked by util.lua version)
comms.version = "2.4.4" comms.version = "2.4.5"
---@enum PROTOCOL ---@enum PROTOCOL
local PROTOCOL = { local PROTOCOL = {

View File

@ -9,7 +9,7 @@ local util = require("scada-common.util")
local ppm = {} local ppm = {}
local ACCESS_FAULT = nil ---@type nil local ACCESS_FAULT = nil ---@type nil
local UNDEFINED_FIELD = "undefined field" local UNDEFINED_FIELD = "__PPM_UNDEF_FIELD__"
local VIRTUAL_DEVICE_TYPE = "ppm_vdev" local VIRTUAL_DEVICE_TYPE = "ppm_vdev"
ppm.ACCESS_FAULT = ACCESS_FAULT ppm.ACCESS_FAULT = ACCESS_FAULT
@ -155,7 +155,7 @@ local function peri_init(iface)
self.fault_counts[key] = self.fault_counts[key] + 1 self.fault_counts[key] = self.fault_counts[key] + 1
return (function () return ACCESS_FAULT end) return (function () return UNDEFINED_FIELD end)
end end
} }
@ -306,7 +306,7 @@ function ppm.log_mounts()
log.info(util.c("PPM: had found a ", mount.type, " (", iface, ")")) log.info(util.c("PPM: had found a ", mount.type, " (", iface, ")"))
end end
if #ppm_sys.mounts == 0 then if util.table_len(ppm_sys.mounts) == 0 then
log.warning("PPM: no devices had been found") log.warning("PPM: no devices had been found")
end end
end end

View File

@ -22,7 +22,7 @@ local t_pack = table.pack
local util = {} local util = {}
-- scada-common version -- scada-common version
util.version = "1.1.16" util.version = "1.1.18"
util.TICK_TIME_S = 0.05 util.TICK_TIME_S = 0.05
util.TICK_TIME_MS = 50 util.TICK_TIME_MS = 50
@ -284,11 +284,13 @@ function util.cancel_timer(timer) os.cancelTimer(timer) end
--#region PARALLELIZATION --#region PARALLELIZATION
-- protected sleep call so we still are in charge of catching termination -- protected sleep call so we still are in charge of catching termination<br>
---@param t integer seconds -- returns the result of pcall
---@param t number seconds
---@return boolean success, any result, any ...
--- EVENT_CONSUMER: this function consumes events --- EVENT_CONSUMER: this function consumes events
---@diagnostic disable-next-line: undefined-field ---@diagnostic disable-next-line: undefined-field
function util.psleep(t) pcall(os.sleep, t) end function util.psleep(t) return pcall(os.sleep, t) end
-- no-op to provide a brief pause (1 tick) to yield<br> -- no-op to provide a brief pause (1 tick) to yield<br>
--- EVENT_CONSUMER: this function consumes events --- EVENT_CONSUMER: this function consumes events

View File

@ -152,6 +152,8 @@ function facility.new(num_reactors, cooling_conf)
table.insert(self.test_tone_states, false) table.insert(self.test_tone_states, false)
end end
-- PRIVATE FUNCTIONS --
-- check if all auto-controlled units completed ramping -- check if all auto-controlled units completed ramping
---@nodiscard ---@nodiscard
local function _all_units_ramped() local function _all_units_ramped()
@ -228,7 +230,7 @@ function facility.new(num_reactors, cooling_conf)
---@class facility ---@class facility
local public = {} local public = {}
-- ADD/LINK DEVICES -- --#region Add/Link Devices
-- link a redstone RTU session -- link a redstone RTU session
---@param rs_unit unit_session ---@param rs_unit unit_session
@ -268,11 +270,9 @@ function facility.new(num_reactors, cooling_conf)
for _, v in pairs(self.rtu_list) do util.filter_table(v, function (s) return s.get_session_id() ~= session end) end for _, v in pairs(self.rtu_list) do util.filter_table(v, function (s) return s.get_session_id() ~= session end) end
end end
-- UPDATE -- --#endregion
-- supervisor sessions reporting the list of active RTU sessions --#region Update
---@param rtu_sessions table session list of all connected RTUs
function public.report_rtus(rtu_sessions) self.rtu_conn_count = #rtu_sessions end
-- update (iterate) the facility management -- update (iterate) the facility management
function public.update() function public.update()
@ -323,7 +323,7 @@ function facility.new(num_reactors, cooling_conf)
-- Run Process Control -- -- Run Process Control --
------------------------- -------------------------
--#region Process Control --#region
local avg_charge = self.avg_charge.compute() local avg_charge = self.avg_charge.compute()
local avg_inflow = self.avg_inflow.compute() local avg_inflow = self.avg_inflow.compute()
@ -597,7 +597,7 @@ function facility.new(num_reactors, cooling_conf)
-- Evaluate Automatic SCRAM -- -- Evaluate Automatic SCRAM --
------------------------------ ------------------------------
--#region Automatic SCRAM --#region
local astatus = self.ascram_status local astatus = self.ascram_status
@ -727,6 +727,8 @@ function facility.new(num_reactors, cooling_conf)
-- Handle Redstone I/O -- -- Handle Redstone I/O --
------------------------- -------------------------
--#region
if #self.redstone > 0 then if #self.redstone > 0 then
-- handle facility SCRAM -- handle facility SCRAM
if self.io_ctl.digital_read(IO.F_SCRAM) then if self.io_ctl.digital_read(IO.F_SCRAM) then
@ -756,10 +758,14 @@ function facility.new(num_reactors, cooling_conf)
self.io_ctl.digital_write(IO.F_ALARM_ANY, has_any_alarm) self.io_ctl.digital_write(IO.F_ALARM_ANY, has_any_alarm)
end end
--#endregion
---------------- ----------------
-- Unit Tasks -- -- Unit Tasks --
---------------- ----------------
--#region
local insufficent_po_rate = false local insufficent_po_rate = false
local need_emcool = false local need_emcool = false
@ -798,10 +804,14 @@ function facility.new(num_reactors, cooling_conf)
end end
end end
--#endregion
------------------------ ------------------------
-- Update Alarm Tones -- -- Update Alarm Tones --
------------------------ ------------------------
--#region
local allow_test = self.allow_testing and self.test_tone_set local allow_test = self.allow_testing and self.test_tone_set
local alarms = { false, false, false, false, false, false, false, false, false, false, false, false } local alarms = { false, false, false, false, false, false, false, false, false, false, false, false }
@ -888,6 +898,8 @@ function facility.new(num_reactors, cooling_conf)
self.test_tone_set = false self.test_tone_set = false
self.test_tone_reset = true self.test_tone_reset = true
end end
--#endregion
end end
-- call the update function of all units in the facility<br> -- call the update function of all units in the facility<br>
@ -900,7 +912,9 @@ function facility.new(num_reactors, cooling_conf)
end end
end end
-- COMMANDS -- --#endregion
--#region Commands
-- SCRAM all reactor units -- SCRAM all reactor units
function public.scram_all() function public.scram_all()
@ -988,7 +1002,9 @@ function facility.new(num_reactors, cooling_conf)
} }
end end
-- SETTINGS -- --#endregion
--#region Settings
-- set the automatic control group of a unit -- set the automatic control group of a unit
---@param unit_id integer unit ID ---@param unit_id integer unit ID
@ -1029,7 +1045,9 @@ function facility.new(num_reactors, cooling_conf)
return self.pu_fallback return self.pu_fallback
end end
-- DIAGNOSTIC TESTING -- --#endregion
--#region Diagnostic Testing
-- attempt to set a test tone state -- attempt to set a test tone state
---@param id TONE|0 tone ID or 0 to disable all ---@param id TONE|0 tone ID or 0 to disable all
@ -1069,7 +1087,9 @@ function facility.new(num_reactors, cooling_conf)
return self.allow_testing, self.test_alarm_states return self.allow_testing, self.test_alarm_states
end end
-- READ STATES/PROPERTIES -- --#endregion
--#region Read States/Properties
-- get current alarm tone on/off states -- get current alarm tone on/off states
---@nodiscard ---@nodiscard
@ -1183,6 +1203,12 @@ function facility.new(num_reactors, cooling_conf)
return status return status
end end
--#endregion
-- supervisor sessions reporting the list of active RTU sessions
---@param rtu_sessions table session list of all connected RTUs
function public.report_rtus(rtu_sessions) self.rtu_conn_count = #rtu_sessions end
-- get the units in this facility -- get the units in this facility
---@nodiscard ---@nodiscard
function public.get_units() return self.units end function public.get_units() return self.units end

View File

@ -21,7 +21,7 @@ local supervisor = require("supervisor.supervisor")
local svsessions = require("supervisor.session.svsessions") local svsessions = require("supervisor.session.svsessions")
local SUPERVISOR_VERSION = "v1.2.8" local SUPERVISOR_VERSION = "v1.2.11"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts
@ -34,9 +34,13 @@ if not supervisor.load_config() then
-- try to reconfigure (user action) -- try to reconfigure (user action)
local success, error = configure.configure(true) local success, error = configure.configure(true)
if success then if success then
assert(supervisor.load_config(), "failed to load valid configuration") if not supervisor.load_config() then
println("failed to load a valid configuration, please reconfigure")
return
end
else else
assert(success, "supervisor configuration error: " .. error) println("configuration error: " .. error)
return
end end
end end

View File

@ -77,7 +77,6 @@ function unit.new(reactor_id, num_boilers, num_turbines)
tanks = {}, tanks = {},
snas = {}, snas = {},
envd = {}, envd = {},
sna_prod_rate = 0,
-- redstone control -- redstone control
io_ctl = nil, ---@type rs_controller io_ctl = nil, ---@type rs_controller
valves = {}, ---@type unit_valves valves = {}, ---@type unit_valves
@ -256,7 +255,7 @@ function unit.new(reactor_id, num_boilers, num_turbines)
-- PRIVATE FUNCTIONS -- -- PRIVATE FUNCTIONS --
--#region time derivative utility functions --#region Time Derivative Utility Functions
-- compute a change with respect to time of the given value -- compute a change with respect to time of the given value
---@param key string value key ---@param key string value key
@ -331,7 +330,7 @@ function unit.new(reactor_id, num_boilers, num_turbines)
--#endregion --#endregion
--#region redstone I/O --#region Redstone I/O
-- create a generic valve interface -- create a generic valve interface
---@nodiscard ---@nodiscard
@ -398,8 +397,7 @@ function unit.new(reactor_id, num_boilers, num_turbines)
---@class reactor_unit ---@class reactor_unit
local public = {} local public = {}
-- ADD/LINK DEVICES -- --#region Add/Link Devices
--#region
-- link the PLC -- link the PLC
---@param plc_session plc_session_struct ---@param plc_session plc_session_struct
@ -489,7 +487,7 @@ function unit.new(reactor_id, num_boilers, num_turbines)
--#endregion --#endregion
-- UPDATE SESSION -- --#region Update Session
-- update (iterate) this unit -- update (iterate) this unit
function public.update() function public.update()
@ -557,8 +555,9 @@ function unit.new(reactor_id, num_boilers, num_turbines)
end end
end end
-- AUTO CONTROL OPERATIONS -- --#endregion
--#region
--#region Auto Control Operations
-- engage automatic control -- engage automatic control
function public.auto_engage() function public.auto_engage()
@ -645,8 +644,7 @@ function unit.new(reactor_id, num_boilers, num_turbines)
--#endregion --#endregion
-- OPERATIONS -- --#region Operations
--#region
-- queue a command to disable the reactor -- queue a command to disable the reactor
function public.disable() function public.disable()
@ -726,8 +724,7 @@ function unit.new(reactor_id, num_boilers, num_turbines)
--#endregion --#endregion
-- READ STATES/PROPERTIES -- --#region Read States/Properties
--#region
-- check if an alarm of at least a certain priority level is tripped -- check if an alarm of at least a certain priority level is tripped
---@nodiscard ---@nodiscard
@ -857,13 +854,15 @@ function unit.new(reactor_id, num_boilers, num_turbines)
status.tanks[tank.get_device_idx()] = { tank.is_faulted(), db.formed, db.state, db.tanks } status.tanks[tank.get_device_idx()] = { tank.is_faulted(), db.formed, db.state, db.tanks }
end end
-- basic SNA statistical information -- SNA statistical information
local total_peak = 0 local total_peak, total_avail, total_out = 0, 0, 0
for i = 1, #self.snas do for i = 1, #self.snas do
local db = self.snas[i].get_db() ---@type sna_session_db local db = self.snas[i].get_db() ---@type sna_session_db
total_peak = total_peak + db.state.peak_production total_peak = total_peak + db.state.peak_production
total_avail = total_avail + db.state.production_rate
total_out = total_out + math.min(db.tanks.input.amount / 10, db.state.production_rate)
end end
status.sna = { #self.snas, public.get_sna_rate(), total_peak } status.sna = { #self.snas, total_peak, total_avail, total_out }
-- radiation monitors (environment detectors) -- radiation monitors (environment detectors)
status.envds = {} status.envds = {}
@ -876,7 +875,7 @@ function unit.new(reactor_id, num_boilers, num_turbines)
return status return status
end end
-- get the current total [max] production rate is -- get the current total max production rate
---@nodiscard ---@nodiscard
---@return number total_avail_rate ---@return number total_avail_rate
function public.get_sna_rate() function public.get_sna_rate()

View File

@ -54,9 +54,7 @@ function logic.update_annunciator(self)
-- variables for boiler, or reactor if no boilers used -- variables for boiler, or reactor if no boilers used
local total_boil_rate = 0.0 local total_boil_rate = 0.0
------------- --#region Reactor
-- REACTOR --
-------------
annunc.AutoControl = self.auto_engaged annunc.AutoControl = self.auto_engaged
@ -143,9 +141,9 @@ function logic.update_annunciator(self)
self.plc_cache.ok = false self.plc_cache.ok = false
end end
--------------- --#endregion
-- MISC RTUs --
--------------- --#region Misc RTUs
local max_rad, any_faulted = 0, false local max_rad, any_faulted = 0, false
@ -170,9 +168,9 @@ function logic.update_annunciator(self)
end end
end end
------------- --#endregion
-- BOILERS --
------------- --#region Boilers
local boilers_ready = num_boilers == #self.boilers local boilers_ready = num_boilers == #self.boilers
@ -230,9 +228,9 @@ function logic.update_annunciator(self)
boiler_water_dt_sum = _get_dt(DT_KEYS.ReactorCCool) boiler_water_dt_sum = _get_dt(DT_KEYS.ReactorCCool)
end end
--------------------------- --#endregion
-- COOLANT FEED MISMATCH --
--------------------------- --#region Coolant Feed Mismatch
-- check coolant feed mismatch if using boilers, otherwise calculate with reactor -- check coolant feed mismatch if using boilers, otherwise calculate with reactor
local cfmismatch = false local cfmismatch = false
@ -263,9 +261,9 @@ function logic.update_annunciator(self)
annunc.CoolantFeedMismatch = cfmismatch annunc.CoolantFeedMismatch = cfmismatch
-------------- --#endregion
-- TURBINES --
-------------- --#region Turbines
local turbines_ready = num_turbines == #self.turbines local turbines_ready = num_turbines == #self.turbines
@ -340,6 +338,8 @@ function logic.update_annunciator(self)
annunc.TurbineTrip[idx] = has_steam and db.state.flow_rate == 0 annunc.TurbineTrip[idx] = has_steam and db.state.flow_rate == 0
end end
--#endregion
-- update auto control ready state for this unit -- update auto control ready state for this unit
self.db.control.ready = plc_ready and boilers_ready and turbines_ready self.db.control.ready = plc_ready and boilers_ready and turbines_ready
end end