#47 reactor plc docs and bugfixes

This commit is contained in:
Mikayla Fischler 2022-05-10 21:49:14 -04:00
parent 22a6159520
commit faac421b63
3 changed files with 219 additions and 175 deletions

View File

@ -1,3 +1,4 @@
---@diagnostic disable: redefined-local
local comms = require("scada-common.comms") local comms = require("scada-common.comms")
local log = require("scada-common.log") local log = require("scada-common.log")
local ppm = require("scada-common.ppm") local ppm = require("scada-common.ppm")
@ -18,9 +19,11 @@ local println = util.println
local print_ts = util.print_ts local print_ts = util.print_ts
local println_ts = util.println_ts local println_ts = util.println_ts
-- Reactor Protection System --- RPS: Reactor Protection System
-- identifies dangerous states and SCRAMs reactor if warranted ---
-- autonomous from main SCADA supervisor/coordinator control --- identifies dangerous states and SCRAMs reactor if warranted
---
--- autonomous from main SCADA supervisor/coordinator control
plc.rps_init = function (reactor) plc.rps_init = function (reactor)
local state_keys = { local state_keys = {
dmg_crit = 1, dmg_crit = 1,
@ -42,6 +45,9 @@ plc.rps_init = function (reactor)
trip_cause = "" trip_cause = ""
} }
---@class rps
local public = {}
-- PRIVATE FUNCTIONS -- -- PRIVATE FUNCTIONS --
-- set reactor access fault flag -- set reactor access fault flag
@ -136,22 +142,28 @@ plc.rps_init = function (reactor)
-- PUBLIC FUNCTIONS -- -- PUBLIC FUNCTIONS --
-- re-link a reactor after a peripheral re-connect -- re-link a reactor after a peripheral re-connect
local reconnect_reactor = function (reactor) public.reconnect_reactor = function (reactor)
self.reactor = reactor self.reactor = reactor
end end
-- report a PLC comms timeout -- trip for lost peripheral
local trip_timeout = function () public.trip_fault = function ()
_set_fault()
end
-- trip for a PLC comms timeout
public.trip_timeout = function ()
self.state[state_keys.timed_out] = true self.state[state_keys.timed_out] = true
end end
-- manually SCRAM the reactor -- manually SCRAM the reactor
local trip_manual = function () public.trip_manual = function ()
self.state[state_keys.manual] = true self.state[state_keys.manual] = true
end end
-- SCRAM the reactor now -- SCRAM the reactor now
local scram = function () ---@return boolean success
public.scram = function ()
log.info("RPS: reactor SCRAM") log.info("RPS: reactor SCRAM")
self.reactor.scram() self.reactor.scram()
@ -165,7 +177,8 @@ plc.rps_init = function (reactor)
end end
-- start the reactor -- start the reactor
local activate = function () ---@return boolean success
public.activate = function ()
if not self.tripped then if not self.tripped then
log.info("RPS: reactor start") log.info("RPS: reactor start")
@ -182,7 +195,8 @@ plc.rps_init = function (reactor)
end end
-- check all safety conditions -- check all safety conditions
local check = function () ---@return boolean tripped, rps_status_t trip_status, boolean first_trip
public.check = function ()
local status = rps_status_t.ok local status = rps_status_t.ok
local was_tripped = self.tripped local was_tripped = self.tripped
local first_trip = false local first_trip = false
@ -237,38 +251,37 @@ plc.rps_init = function (reactor)
self.tripped = true self.tripped = true
self.trip_cause = status self.trip_cause = status
scram() public.scram()
end end
return self.tripped, status, first_trip return self.tripped, status, first_trip
end end
-- get the RPS status public.status = function () return self.state end
local status = function () return self.state end public.is_tripped = function () return self.tripped end
local is_tripped = function () return self.tripped end public.is_active = function () return self.reactor_enabled end
local is_active = function () return self.reactor_enabled end
-- reset the RPS -- reset the RPS
local reset = function () public.reset = function ()
self.tripped = false self.tripped = false
self.trip_cause = rps_status_t.ok self.trip_cause = rps_status_t.ok
for i = 1, #self.state do
self.state[i] = false
end
end end
return { return public
reconnect_reactor = reconnect_reactor,
trip_timeout = trip_timeout,
trip_manual = trip_manual,
scram = scram,
activate = activate,
check = check,
status = status,
is_tripped = is_tripped,
is_active = is_active,
reset = reset
}
end end
-- reactor PLC communications -- Reactor PLC Communications
---@param id integer
---@param modem table
---@param local_port integer
---@param server_port integer
---@param reactor table
---@param rps rps
---@param conn_watchdog watchdog
plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_watchdog) plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_watchdog)
local self = { local self = {
id = id, id = id,
@ -286,6 +299,9 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
max_burn_rate = nil max_burn_rate = nil
} }
---@class plc_comms
local public = {}
-- open modem -- open modem
if not self.modem.isOpen(self.l_port) then if not self.modem.isOpen(self.l_port) then
self.modem.open(self.l_port) self.modem.open(self.l_port)
@ -293,6 +309,9 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
-- PRIVATE FUNCTIONS -- -- PRIVATE FUNCTIONS --
-- send an RPLC packet
---@param msg_type RPLC_TYPES
---@param msg string
local _send = function (msg_type, msg) local _send = function (msg_type, msg)
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
local r_pkt = comms.rplc_packet() local r_pkt = comms.rplc_packet()
@ -304,6 +323,9 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
self.seq_num = self.seq_num + 1 self.seq_num = self.seq_num + 1
end end
-- send a SCADA management packet
---@param msg_type SCADA_MGMT_TYPES
---@param msg string
local _send_mgmt = function (msg_type, msg) local _send_mgmt = function (msg_type, msg)
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
local m_pkt = comms.mgmt_packet() local m_pkt = comms.mgmt_packet()
@ -316,6 +338,7 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
end end
-- variable reactor status information, excluding heating rate -- variable reactor status information, excluding heating rate
---@return table data_table, boolean faulted
local _reactor_status = function () local _reactor_status = function ()
local coolant = nil local coolant = nil
local hcoolant = nil local hcoolant = nil
@ -373,6 +396,8 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
return data_table, self.reactor.__p_is_faulted() return data_table, self.reactor.__p_is_faulted()
end end
-- update the status cache if changed
---@return boolean changed
local _update_status_cache = function () local _update_status_cache = function ()
local status, faulted = _reactor_status() local status, faulted = _reactor_status()
local changed = false local changed = false
@ -398,11 +423,14 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
end end
-- keep alive ack -- keep alive ack
---@param srv_time integer
local _send_keep_alive_ack = function (srv_time) local _send_keep_alive_ack = function (srv_time)
_send(SCADA_MGMT_TYPES.KEEP_ALIVE, { srv_time, util.time() }) _send(SCADA_MGMT_TYPES.KEEP_ALIVE, { srv_time, util.time() })
end end
-- general ack -- general ack
---@param msg_type RPLC_TYPES
---@param succeeded boolean
local _send_ack = function (msg_type, succeeded) local _send_ack = function (msg_type, succeeded)
_send(msg_type, { succeeded }) _send(msg_type, { succeeded })
end end
@ -434,7 +462,8 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
-- PUBLIC FUNCTIONS -- -- PUBLIC FUNCTIONS --
-- reconnect a newly connected modem -- reconnect a newly connected modem
local reconnect_modem = function (modem) ---@param modem table
public.reconnect_modem = function (modem)
self.modem = modem self.modem = modem
-- open modem -- open modem
@ -444,32 +473,34 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
end end
-- reconnect a newly connected reactor -- reconnect a newly connected reactor
local reconnect_reactor = function (reactor) ---@param reactor table
public.reconnect_reactor = function (reactor)
self.reactor = reactor self.reactor = reactor
self.status_cache = nil self.status_cache = nil
end end
-- unlink from the server -- unlink from the server
local unlink = function () public.unlink = function ()
self.linked = false self.linked = false
self.r_seq_num = nil self.r_seq_num = nil
self.status_cache = nil self.status_cache = nil
end end
-- close the connection to the server -- close the connection to the server
local close = function () public.close = function ()
self.conn_watchdog.cancel() self.conn_watchdog.cancel()
unlink() public.unlink()
_send_mgmt(SCADA_MGMT_TYPES.CLOSE, {}) _send_mgmt(SCADA_MGMT_TYPES.CLOSE, {})
end end
-- attempt to establish link with supervisor -- attempt to establish link with supervisor
local send_link_req = function () public.send_link_req = function ()
_send(RPLC_TYPES.LINK_REQ, { self.id }) _send(RPLC_TYPES.LINK_REQ, { self.id })
end end
-- send live status information -- send live status information
local send_status = function (degraded) ---@param degraded boolean
public.send_status = function (degraded)
if self.linked then if self.linked then
local mek_data = nil local mek_data = nil
@ -495,14 +526,15 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
end end
-- send reactor protection system status -- send reactor protection system status
local send_rps_status = function () public.send_rps_status = function ()
if self.linked then if self.linked then
_send(RPLC_TYPES.RPS_STATUS, rps.status()) _send(RPLC_TYPES.RPS_STATUS, rps.status())
end end
end end
-- send reactor protection system alarm -- send reactor protection system alarm
local send_rps_alarm = function (cause) ---@param cause rps_status_t
public.send_rps_alarm = function (cause)
if self.linked then if self.linked then
local rps_alarm = { local rps_alarm = {
cause, cause,
@ -514,7 +546,13 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
end end
-- parse an RPLC packet -- parse an RPLC packet
local parse_packet = function(side, sender, reply_to, message, distance) ---@param side string
---@param sender integer
---@param reply_to integer
---@param message any
---@param distance integer
---@return rplc_frame|mgmt_frame|nil packet
public.parse_packet = function(side, sender, reply_to, message, distance)
local pkt = nil local pkt = nil
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
@ -543,7 +581,10 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
end end
-- handle an RPLC packet -- handle an RPLC packet
local handle_packet = function (packet, plc_state, setpoints) ---@param packet rplc_frame|mgmt_frame
---@param plc_state plc_state
---@param setpoints setpoints
public.handle_packet = function (packet, plc_state, setpoints)
if packet ~= nil then if packet ~= nil then
-- check sequence number -- check sequence number
if self.r_seq_num == nil then if self.r_seq_num == nil then
@ -573,7 +614,7 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
if link_ack == RPLC_LINKING.ALLOW then if link_ack == RPLC_LINKING.ALLOW then
self.status_cache = nil self.status_cache = nil
_send_struct() _send_struct()
send_status(plc_state.degraded) public.send_status(plc_state.degraded)
log.debug("re-sent initial status data") log.debug("re-sent initial status data")
elseif link_ack == RPLC_LINKING.DENY then elseif link_ack == RPLC_LINKING.DENY then
println_ts("received unsolicited link denial, unlinking") println_ts("received unsolicited link denial, unlinking")
@ -593,7 +634,7 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
elseif packet.type == RPLC_TYPES.STATUS then elseif packet.type == RPLC_TYPES.STATUS then
-- request of full status, clear cache first -- request of full status, clear cache first
self.status_cache = nil self.status_cache = nil
send_status(plc_state.degraded) public.send_status(plc_state.degraded)
log.debug("sent out status cache again, did supervisor miss it?") log.debug("sent out status cache again, did supervisor miss it?")
elseif packet.type == RPLC_TYPES.MEK_STRUCT then elseif packet.type == RPLC_TYPES.MEK_STRUCT then
-- request for physical structure -- request for physical structure
@ -659,7 +700,7 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
self.status_cache = nil self.status_cache = nil
_send_struct() _send_struct()
send_status(plc_state.degraded) public.send_status(plc_state.degraded)
log.debug("sent initial status data") log.debug("sent initial status data")
elseif link_ack == RPLC_LINKING.DENY then elseif link_ack == RPLC_LINKING.DENY then
@ -700,7 +741,7 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
elseif packet.type == SCADA_MGMT_TYPES.CLOSE then elseif packet.type == SCADA_MGMT_TYPES.CLOSE then
-- handle session close -- handle session close
self.conn_watchdog.cancel() self.conn_watchdog.cancel()
unlink() public.unlink()
println_ts("server connection closed by remote host") println_ts("server connection closed by remote host")
log.warning("server connection closed by remote host") log.warning("server connection closed by remote host")
else else
@ -713,23 +754,10 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
end end
end end
local is_scrammed = function () return self.scrammed end public.is_scrammed = function () return self.scrammed end
local is_linked = function () return self.linked end public.is_linked = function () return self.linked end
return { return public
reconnect_modem = reconnect_modem,
reconnect_reactor = reconnect_reactor,
unlink = unlink,
close = close,
send_link_req = send_link_req,
send_status = send_status,
send_rps_status = send_rps_status,
send_rps_alarm = send_rps_alarm,
parse_packet = parse_packet,
handle_packet = handle_packet,
is_scrammed = is_scrammed,
is_linked = is_linked
}
end end
return plc return plc

View File

@ -29,11 +29,13 @@ println(">> Reactor PLC " .. R_PLC_VERSION .. " <<")
ppm.mount_all() ppm.mount_all()
-- shared memory across threads -- shared memory across threads
---@class plc_shared_memory
local __shared_memory = { local __shared_memory = {
-- networked setting -- networked setting
networked = config.NETWORKED, networked = config.NETWORKED, ---@type boolean
-- PLC system state flags -- PLC system state flags
---@class plc_state
plc_state = { plc_state = {
init_ok = true, init_ok = true,
shutdown = false, shutdown = false,
@ -42,6 +44,8 @@ local __shared_memory = {
no_modem = false no_modem = false
}, },
-- control setpoints
---@class setpoints
setpoints = { setpoints = {
burn_rate_en = false, burn_rate_en = false,
burn_rate = 0.0 burn_rate = 0.0
@ -55,9 +59,9 @@ local __shared_memory = {
-- system objects -- system objects
plc_sys = { plc_sys = {
rps = nil, rps = nil, ---@type rps
plc_comms = nil, plc_comms = nil, ---@type plc_comms
conn_watchdog = nil conn_watchdog = nil ---@type watchdog
}, },
-- message queues -- message queues

View File

@ -10,8 +10,6 @@ local println = util.println
local print_ts = util.print_ts local print_ts = util.print_ts
local println_ts = util.println_ts local println_ts = util.println_ts
local psleep = util.psleep
local MAIN_CLOCK = 1 -- (1Hz, 20 ticks) local MAIN_CLOCK = 1 -- (1Hz, 20 ticks)
local RPS_SLEEP = 250 -- (250ms, 5 ticks) local RPS_SLEEP = 250 -- (250ms, 5 ticks)
local COMMS_SLEEP = 150 -- (150ms, 3 ticks) local COMMS_SLEEP = 150 -- (150ms, 3 ticks)
@ -30,6 +28,8 @@ local MQ__COMM_CMD = {
} }
-- main thread -- main thread
---@param smem plc_shared_memory
---@param init function
threads.thread__main = function (smem, init) threads.thread__main = function (smem, init)
-- execute thread -- execute thread
local exec = function () local exec = function ()
@ -47,7 +47,7 @@ threads.thread__main = function (smem, init)
local plc_dev = smem.plc_dev local plc_dev = smem.plc_dev
local rps = smem.plc_sys.rps local rps = smem.plc_sys.rps
local plc_comms = smem.plc_sys.plc_comms local plc_comms = smem.plc_sys.plc_comms
local conn_watchdog = smem.plc_sys.conn_watchdog ---@type watchdog local conn_watchdog = smem.plc_sys.conn_watchdog
-- event loop -- event loop
while true do while true do
@ -187,6 +187,7 @@ threads.thread__main = function (smem, init)
end end
-- RPS operation thread -- RPS operation thread
---@param smem plc_shared_memory
threads.thread__rps = function (smem) threads.thread__rps = function (smem)
-- execute thread -- execute thread
local exec = function () local exec = function ()
@ -224,6 +225,7 @@ threads.thread__rps = function (smem)
-- if we tried to SCRAM but failed, keep trying -- if we tried to SCRAM but failed, keep trying
-- in that case, SCRAM won't be called until it reconnects (this is the expected use of this check) -- in that case, SCRAM won't be called until it reconnects (this is the expected use of this check)
---@diagnostic disable-next-line: need-check-nil
if not plc_state.no_reactor and rps.is_tripped() and reactor.getStatus() then if not plc_state.no_reactor and rps.is_tripped() and reactor.getStatus() then
rps.scram() rps.scram()
end end
@ -249,26 +251,28 @@ threads.thread__rps = function (smem)
while rps_queue.ready() and not plc_state.shutdown do while rps_queue.ready() and not plc_state.shutdown do
local msg = rps_queue.pop() local msg = rps_queue.pop()
if msg.qtype == mqueue.TYPE.COMMAND then if msg ~= nil then
-- received a command if msg.qtype == mqueue.TYPE.COMMAND then
if plc_state.init_ok then -- received a command
if msg.message == MQ__RPS_CMD.SCRAM then if plc_state.init_ok then
-- SCRAM if msg.message == MQ__RPS_CMD.SCRAM then
rps.scram() -- SCRAM
elseif msg.message == MQ__RPS_CMD.DEGRADED_SCRAM then rps.scram()
-- lost peripheral(s) elseif msg.message == MQ__RPS_CMD.DEGRADED_SCRAM then
rps.trip_degraded() -- lost peripheral(s)
elseif msg.message == MQ__RPS_CMD.TRIP_TIMEOUT then rps.trip_fault()
-- watchdog tripped elseif msg.message == MQ__RPS_CMD.TRIP_TIMEOUT then
rps.trip_timeout() -- watchdog tripped
println_ts("server timeout") rps.trip_timeout()
log.warning("server timeout") println_ts("server timeout")
log.warning("server timeout")
end
end end
elseif msg.qtype == mqueue.TYPE.DATA then
-- received data
elseif msg.qtype == mqueue.TYPE.PACKET then
-- received a packet
end end
elseif msg.qtype == mqueue.TYPE.DATA then
-- received data
elseif msg.qtype == mqueue.TYPE.PACKET then
-- received a packet
end end
-- quick yield -- quick yield
@ -301,6 +305,7 @@ threads.thread__rps = function (smem)
end end
-- communications sender thread -- communications sender thread
---@param smem plc_shared_memory
threads.thread__comms_tx = function (smem) threads.thread__comms_tx = function (smem)
-- execute thread -- execute thread
local exec = function () local exec = function ()
@ -320,17 +325,19 @@ threads.thread__comms_tx = function (smem)
while comms_queue.ready() and not plc_state.shutdown do while comms_queue.ready() and not plc_state.shutdown do
local msg = comms_queue.pop() local msg = comms_queue.pop()
if msg.qtype == mqueue.TYPE.COMMAND then if msg ~= nil then
-- received a command if msg.qtype == mqueue.TYPE.COMMAND then
if msg.message == MQ__COMM_CMD.SEND_STATUS then -- received a command
-- send PLC/RPS status if msg.message == MQ__COMM_CMD.SEND_STATUS then
plc_comms.send_status(plc_state.degraded) -- send PLC/RPS status
plc_comms.send_rps_status() plc_comms.send_status(plc_state.degraded)
plc_comms.send_rps_status()
end
elseif msg.qtype == mqueue.TYPE.DATA then
-- received data
elseif msg.qtype == mqueue.TYPE.PACKET then
-- received a packet
end end
elseif msg.qtype == mqueue.TYPE.DATA then
-- received data
elseif msg.qtype == mqueue.TYPE.PACKET then
-- received a packet
end end
-- quick yield -- quick yield
@ -352,22 +359,20 @@ threads.thread__comms_tx = function (smem)
end end
-- communications handler thread -- communications handler thread
---@param smem plc_shared_memory
threads.thread__comms_rx = function (smem) threads.thread__comms_rx = function (smem)
-- execute thread -- execute thread
local exec = function () local exec = function ()
log.debug("comms rx thread start") log.debug("comms rx thread start")
-- load in from shared memory -- load in from shared memory
local plc_state = smem.plc_state local plc_state = smem.plc_state
local setpoints = smem.setpoints local setpoints = smem.setpoints
local plc_dev = smem.plc_dev local plc_comms = smem.plc_sys.plc_comms
local rps = smem.plc_sys.rps
local plc_comms = smem.plc_sys.plc_comms
local conn_watchdog = smem.plc_sys.conn_watchdog
local comms_queue = smem.q.mq_comms_rx local comms_queue = smem.q.mq_comms_rx
local last_update = util.time() local last_update = util.time()
-- thread loop -- thread loop
while true do while true do
@ -375,16 +380,17 @@ threads.thread__comms_rx = function (smem)
while comms_queue.ready() and not plc_state.shutdown do while comms_queue.ready() and not plc_state.shutdown do
local msg = comms_queue.pop() local msg = comms_queue.pop()
if msg.qtype == mqueue.TYPE.COMMAND then if msg ~= nil then
-- received a command if msg.qtype == mqueue.TYPE.COMMAND then
elseif msg.qtype == mqueue.TYPE.DATA then -- received a command
-- received data elseif msg.qtype == mqueue.TYPE.DATA then
elseif msg.qtype == mqueue.TYPE.PACKET then -- received data
-- received a packet elseif msg.qtype == mqueue.TYPE.PACKET then
-- handle the packet (setpoints passed to update burn rate setpoint) -- received a packet
-- (plc_state passed to check if degraded) -- handle the packet (setpoints passed to update burn rate setpoint)
-- (conn_watchdog passed to allow feeding the watchdog) -- (plc_state passed to check if degraded)
plc_comms.handle_packet(msg.message, setpoints, plc_state, conn_watchdog) plc_comms.handle_packet(msg.message, setpoints, plc_state)
end
end end
-- quick yield -- quick yield
@ -406,84 +412,90 @@ threads.thread__comms_rx = function (smem)
end end
-- apply setpoints -- apply setpoints
---@param smem plc_shared_memory
threads.thread__setpoint_control = function (smem) threads.thread__setpoint_control = function (smem)
-- execute thread -- execute thread
local exec = function () local exec = function ()
log.debug("setpoint control thread start") log.debug("setpoint control thread start")
-- load in from shared memory -- load in from shared memory
local plc_state = smem.plc_state local plc_state = smem.plc_state
local setpoints = smem.setpoints local setpoints = smem.setpoints
local plc_dev = smem.plc_dev local plc_dev = smem.plc_dev
local rps = smem.plc_sys.rps local rps = smem.plc_sys.rps
local last_update = util.time() local last_update = util.time()
local running = false local running = false
local last_sp_burn = 0 local last_sp_burn = 0.0
-- do not use the actual elapsed time, it could spike
-- we do not want to have big jumps as that is what we are trying to avoid in the first place
local min_elapsed_s = SP_CTRL_SLEEP / 1000.0
-- thread loop -- thread loop
while true do while true do
local reactor = plc_dev.reactor local reactor = plc_dev.reactor
-- check if we should start ramping if plc_state.init_ok and not plc_state.no_reactor then
if setpoints.burn_rate_en and setpoints.burn_rate ~= last_sp_burn then -- check if we should start ramping
if rps.is_active() then if setpoints.burn_rate_en and setpoints.burn_rate ~= last_sp_burn then
if math.abs(setpoints.burn_rate - last_sp_burn) <= 5 then
-- update without ramp if <= 5 mB/t change
log.debug("setting burn rate directly to " .. setpoints.burn_rate .. "mB/t")
reactor.setBurnRate(setpoints.burn_rate)
else
log.debug("starting burn rate ramp from " .. last_sp_burn .. "mB/t to " .. setpoints.burn_rate .. "mB/t")
running = true
end
last_sp_burn = setpoints.burn_rate
else
last_sp_burn = 0
end
end
-- only check I/O if active to save on processing time
if running then
-- do not use the actual elapsed time, it could spike
-- we do not want to have big jumps as that is what we are trying to avoid in the first place
local min_elapsed_s = SP_CTRL_SLEEP / 1000.0
-- clear so we can later evaluate if we should keep running
running = false
-- adjust burn rate (setpoints.burn_rate)
if setpoints.burn_rate_en then
if rps.is_active() then if rps.is_active() then
local current_burn_rate = reactor.getBurnRate() if math.abs(setpoints.burn_rate - last_sp_burn) <= 5 then
-- update without ramp if <= 5 mB/t change
-- we yielded, check enable again log.debug("setting burn rate directly to " .. setpoints.burn_rate .. "mB/t")
if setpoints.burn_rate_en and (current_burn_rate ~= ppm.ACCESS_FAULT) and (current_burn_rate ~= setpoints.burn_rate) then ---@diagnostic disable-next-line: need-check-nil
-- calculate new burn rate reactor.setBurnRate(setpoints.burn_rate)
local new_burn_rate = current_burn_rate else
log.debug("starting burn rate ramp from " .. last_sp_burn .. "mB/t to " .. setpoints.burn_rate .. "mB/t")
if setpoints.burn_rate > current_burn_rate then running = true
-- need to ramp up
local new_burn_rate = current_burn_rate + (BURN_RATE_RAMP_mB_s * min_elapsed_s)
if new_burn_rate > setpoints.burn_rate then
new_burn_rate = setpoints.burn_rate
end
else
-- need to ramp down
local new_burn_rate = current_burn_rate - (BURN_RATE_RAMP_mB_s * min_elapsed_s)
if new_burn_rate < setpoints.burn_rate then
new_burn_rate = setpoints.burn_rate
end
end
-- set the burn rate
reactor.setBurnRate(new_burn_rate)
running = running or (new_burn_rate ~= setpoints.burn_rate)
end end
last_sp_burn = setpoints.burn_rate
else else
last_sp_burn = 0 last_sp_burn = 0.0
end
end
-- only check I/O if active to save on processing time
if running then
-- clear so we can later evaluate if we should keep running
running = false
-- adjust burn rate (setpoints.burn_rate)
if setpoints.burn_rate_en then
if rps.is_active() then
---@diagnostic disable-next-line: need-check-nil
local current_burn_rate = reactor.getBurnRate()
-- we yielded, check enable again
if setpoints.burn_rate_en and (current_burn_rate ~= ppm.ACCESS_FAULT) and (current_burn_rate ~= setpoints.burn_rate) then
-- calculate new burn rate
local new_burn_rate = current_burn_rate
if setpoints.burn_rate > current_burn_rate then
-- need to ramp up
local new_burn_rate = current_burn_rate + (BURN_RATE_RAMP_mB_s * min_elapsed_s)
if new_burn_rate > setpoints.burn_rate then
new_burn_rate = setpoints.burn_rate
end
else
-- need to ramp down
local new_burn_rate = current_burn_rate - (BURN_RATE_RAMP_mB_s * min_elapsed_s)
if new_burn_rate < setpoints.burn_rate then
new_burn_rate = setpoints.burn_rate
end
end
-- set the burn rate
---@diagnostic disable-next-line: need-check-nil
reactor.setBurnRate(new_burn_rate)
running = running or (new_burn_rate ~= setpoints.burn_rate)
end
else
last_sp_burn = 0.0
end
end end
end end
end end