mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#47 reactor plc docs and bugfixes
This commit is contained in:
parent
22a6159520
commit
faac421b63
@ -1,3 +1,4 @@
|
||||
---@diagnostic disable: redefined-local
|
||||
local comms = require("scada-common.comms")
|
||||
local log = require("scada-common.log")
|
||||
local ppm = require("scada-common.ppm")
|
||||
@ -18,9 +19,11 @@ local println = util.println
|
||||
local print_ts = util.print_ts
|
||||
local println_ts = util.println_ts
|
||||
|
||||
-- Reactor Protection System
|
||||
-- identifies dangerous states and SCRAMs reactor if warranted
|
||||
-- autonomous from main SCADA supervisor/coordinator control
|
||||
--- RPS: Reactor Protection System
|
||||
---
|
||||
--- identifies dangerous states and SCRAMs reactor if warranted
|
||||
---
|
||||
--- autonomous from main SCADA supervisor/coordinator control
|
||||
plc.rps_init = function (reactor)
|
||||
local state_keys = {
|
||||
dmg_crit = 1,
|
||||
@ -42,6 +45,9 @@ plc.rps_init = function (reactor)
|
||||
trip_cause = ""
|
||||
}
|
||||
|
||||
---@class rps
|
||||
local public = {}
|
||||
|
||||
-- PRIVATE FUNCTIONS --
|
||||
|
||||
-- set reactor access fault flag
|
||||
@ -136,22 +142,28 @@ plc.rps_init = function (reactor)
|
||||
-- PUBLIC FUNCTIONS --
|
||||
|
||||
-- re-link a reactor after a peripheral re-connect
|
||||
local reconnect_reactor = function (reactor)
|
||||
public.reconnect_reactor = function (reactor)
|
||||
self.reactor = reactor
|
||||
end
|
||||
|
||||
-- report a PLC comms timeout
|
||||
local trip_timeout = function ()
|
||||
-- trip for lost peripheral
|
||||
public.trip_fault = function ()
|
||||
_set_fault()
|
||||
end
|
||||
|
||||
-- trip for a PLC comms timeout
|
||||
public.trip_timeout = function ()
|
||||
self.state[state_keys.timed_out] = true
|
||||
end
|
||||
|
||||
-- manually SCRAM the reactor
|
||||
local trip_manual = function ()
|
||||
public.trip_manual = function ()
|
||||
self.state[state_keys.manual] = true
|
||||
end
|
||||
|
||||
-- SCRAM the reactor now
|
||||
local scram = function ()
|
||||
---@return boolean success
|
||||
public.scram = function ()
|
||||
log.info("RPS: reactor SCRAM")
|
||||
|
||||
self.reactor.scram()
|
||||
@ -165,7 +177,8 @@ plc.rps_init = function (reactor)
|
||||
end
|
||||
|
||||
-- start the reactor
|
||||
local activate = function ()
|
||||
---@return boolean success
|
||||
public.activate = function ()
|
||||
if not self.tripped then
|
||||
log.info("RPS: reactor start")
|
||||
|
||||
@ -182,7 +195,8 @@ plc.rps_init = function (reactor)
|
||||
end
|
||||
|
||||
-- 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 was_tripped = self.tripped
|
||||
local first_trip = false
|
||||
@ -237,38 +251,37 @@ plc.rps_init = function (reactor)
|
||||
self.tripped = true
|
||||
self.trip_cause = status
|
||||
|
||||
scram()
|
||||
public.scram()
|
||||
end
|
||||
|
||||
return self.tripped, status, first_trip
|
||||
end
|
||||
|
||||
-- get the RPS status
|
||||
local status = function () return self.state end
|
||||
local is_tripped = function () return self.tripped end
|
||||
local is_active = function () return self.reactor_enabled end
|
||||
public.status = function () return self.state end
|
||||
public.is_tripped = function () return self.tripped end
|
||||
public.is_active = function () return self.reactor_enabled end
|
||||
|
||||
-- reset the RPS
|
||||
local reset = function ()
|
||||
public.reset = function ()
|
||||
self.tripped = false
|
||||
self.trip_cause = rps_status_t.ok
|
||||
|
||||
for i = 1, #self.state do
|
||||
self.state[i] = false
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
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
|
||||
}
|
||||
return public
|
||||
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)
|
||||
local self = {
|
||||
id = id,
|
||||
@ -286,6 +299,9 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
|
||||
max_burn_rate = nil
|
||||
}
|
||||
|
||||
---@class plc_comms
|
||||
local public = {}
|
||||
|
||||
-- open modem
|
||||
if not self.modem.isOpen(self.l_port) then
|
||||
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 --
|
||||
|
||||
-- send an RPLC packet
|
||||
---@param msg_type RPLC_TYPES
|
||||
---@param msg string
|
||||
local _send = function (msg_type, msg)
|
||||
local s_pkt = comms.scada_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
|
||||
end
|
||||
|
||||
-- send a SCADA management packet
|
||||
---@param msg_type SCADA_MGMT_TYPES
|
||||
---@param msg string
|
||||
local _send_mgmt = function (msg_type, msg)
|
||||
local s_pkt = comms.scada_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
|
||||
|
||||
-- variable reactor status information, excluding heating rate
|
||||
---@return table data_table, boolean faulted
|
||||
local _reactor_status = function ()
|
||||
local coolant = 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()
|
||||
end
|
||||
|
||||
-- update the status cache if changed
|
||||
---@return boolean changed
|
||||
local _update_status_cache = function ()
|
||||
local status, faulted = _reactor_status()
|
||||
local changed = false
|
||||
@ -398,11 +423,14 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
|
||||
end
|
||||
|
||||
-- keep alive ack
|
||||
---@param srv_time integer
|
||||
local _send_keep_alive_ack = function (srv_time)
|
||||
_send(SCADA_MGMT_TYPES.KEEP_ALIVE, { srv_time, util.time() })
|
||||
end
|
||||
|
||||
-- general ack
|
||||
---@param msg_type RPLC_TYPES
|
||||
---@param succeeded boolean
|
||||
local _send_ack = function (msg_type, succeeded)
|
||||
_send(msg_type, { succeeded })
|
||||
end
|
||||
@ -434,7 +462,8 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
|
||||
-- PUBLIC FUNCTIONS --
|
||||
|
||||
-- reconnect a newly connected modem
|
||||
local reconnect_modem = function (modem)
|
||||
---@param modem table
|
||||
public.reconnect_modem = function (modem)
|
||||
self.modem = modem
|
||||
|
||||
-- open modem
|
||||
@ -444,32 +473,34 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
|
||||
end
|
||||
|
||||
-- reconnect a newly connected reactor
|
||||
local reconnect_reactor = function (reactor)
|
||||
---@param reactor table
|
||||
public.reconnect_reactor = function (reactor)
|
||||
self.reactor = reactor
|
||||
self.status_cache = nil
|
||||
end
|
||||
|
||||
-- unlink from the server
|
||||
local unlink = function ()
|
||||
public.unlink = function ()
|
||||
self.linked = false
|
||||
self.r_seq_num = nil
|
||||
self.status_cache = nil
|
||||
end
|
||||
|
||||
-- close the connection to the server
|
||||
local close = function ()
|
||||
public.close = function ()
|
||||
self.conn_watchdog.cancel()
|
||||
unlink()
|
||||
public.unlink()
|
||||
_send_mgmt(SCADA_MGMT_TYPES.CLOSE, {})
|
||||
end
|
||||
|
||||
-- attempt to establish link with supervisor
|
||||
local send_link_req = function ()
|
||||
public.send_link_req = function ()
|
||||
_send(RPLC_TYPES.LINK_REQ, { self.id })
|
||||
end
|
||||
|
||||
-- send live status information
|
||||
local send_status = function (degraded)
|
||||
---@param degraded boolean
|
||||
public.send_status = function (degraded)
|
||||
if self.linked then
|
||||
local mek_data = nil
|
||||
|
||||
@ -495,14 +526,15 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
|
||||
end
|
||||
|
||||
-- send reactor protection system status
|
||||
local send_rps_status = function ()
|
||||
public.send_rps_status = function ()
|
||||
if self.linked then
|
||||
_send(RPLC_TYPES.RPS_STATUS, rps.status())
|
||||
end
|
||||
end
|
||||
|
||||
-- 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
|
||||
local rps_alarm = {
|
||||
cause,
|
||||
@ -514,7 +546,13 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
|
||||
end
|
||||
|
||||
-- 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 s_pkt = comms.scada_packet()
|
||||
|
||||
@ -543,7 +581,10 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
|
||||
end
|
||||
|
||||
-- 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
|
||||
-- check sequence number
|
||||
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
|
||||
self.status_cache = nil
|
||||
_send_struct()
|
||||
send_status(plc_state.degraded)
|
||||
public.send_status(plc_state.degraded)
|
||||
log.debug("re-sent initial status data")
|
||||
elseif link_ack == RPLC_LINKING.DENY then
|
||||
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
|
||||
-- request of full status, clear cache first
|
||||
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?")
|
||||
elseif packet.type == RPLC_TYPES.MEK_STRUCT then
|
||||
-- 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
|
||||
|
||||
_send_struct()
|
||||
send_status(plc_state.degraded)
|
||||
public.send_status(plc_state.degraded)
|
||||
|
||||
log.debug("sent initial status data")
|
||||
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
|
||||
-- handle session close
|
||||
self.conn_watchdog.cancel()
|
||||
unlink()
|
||||
public.unlink()
|
||||
println_ts("server connection closed by remote host")
|
||||
log.warning("server connection closed by remote host")
|
||||
else
|
||||
@ -713,23 +754,10 @@ plc.comms = function (id, modem, local_port, server_port, reactor, rps, conn_wat
|
||||
end
|
||||
end
|
||||
|
||||
local is_scrammed = function () return self.scrammed end
|
||||
local is_linked = function () return self.linked end
|
||||
public.is_scrammed = function () return self.scrammed end
|
||||
public.is_linked = function () return self.linked end
|
||||
|
||||
return {
|
||||
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
|
||||
}
|
||||
return public
|
||||
end
|
||||
|
||||
return plc
|
||||
|
@ -29,11 +29,13 @@ println(">> Reactor PLC " .. R_PLC_VERSION .. " <<")
|
||||
ppm.mount_all()
|
||||
|
||||
-- shared memory across threads
|
||||
---@class plc_shared_memory
|
||||
local __shared_memory = {
|
||||
-- networked setting
|
||||
networked = config.NETWORKED,
|
||||
networked = config.NETWORKED, ---@type boolean
|
||||
|
||||
-- PLC system state flags
|
||||
---@class plc_state
|
||||
plc_state = {
|
||||
init_ok = true,
|
||||
shutdown = false,
|
||||
@ -42,6 +44,8 @@ local __shared_memory = {
|
||||
no_modem = false
|
||||
},
|
||||
|
||||
-- control setpoints
|
||||
---@class setpoints
|
||||
setpoints = {
|
||||
burn_rate_en = false,
|
||||
burn_rate = 0.0
|
||||
@ -55,9 +59,9 @@ local __shared_memory = {
|
||||
|
||||
-- system objects
|
||||
plc_sys = {
|
||||
rps = nil,
|
||||
plc_comms = nil,
|
||||
conn_watchdog = nil
|
||||
rps = nil, ---@type rps
|
||||
plc_comms = nil, ---@type plc_comms
|
||||
conn_watchdog = nil ---@type watchdog
|
||||
},
|
||||
|
||||
-- message queues
|
||||
|
@ -10,8 +10,6 @@ local println = util.println
|
||||
local print_ts = util.print_ts
|
||||
local println_ts = util.println_ts
|
||||
|
||||
local psleep = util.psleep
|
||||
|
||||
local MAIN_CLOCK = 1 -- (1Hz, 20 ticks)
|
||||
local RPS_SLEEP = 250 -- (250ms, 5 ticks)
|
||||
local COMMS_SLEEP = 150 -- (150ms, 3 ticks)
|
||||
@ -30,6 +28,8 @@ local MQ__COMM_CMD = {
|
||||
}
|
||||
|
||||
-- main thread
|
||||
---@param smem plc_shared_memory
|
||||
---@param init function
|
||||
threads.thread__main = function (smem, init)
|
||||
-- execute thread
|
||||
local exec = function ()
|
||||
@ -47,7 +47,7 @@ threads.thread__main = function (smem, init)
|
||||
local plc_dev = smem.plc_dev
|
||||
local rps = smem.plc_sys.rps
|
||||
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
|
||||
while true do
|
||||
@ -187,6 +187,7 @@ threads.thread__main = function (smem, init)
|
||||
end
|
||||
|
||||
-- RPS operation thread
|
||||
---@param smem plc_shared_memory
|
||||
threads.thread__rps = function (smem)
|
||||
-- execute thread
|
||||
local exec = function ()
|
||||
@ -224,6 +225,7 @@ threads.thread__rps = function (smem)
|
||||
|
||||
-- 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)
|
||||
---@diagnostic disable-next-line: need-check-nil
|
||||
if not plc_state.no_reactor and rps.is_tripped() and reactor.getStatus() then
|
||||
rps.scram()
|
||||
end
|
||||
@ -249,26 +251,28 @@ threads.thread__rps = function (smem)
|
||||
while rps_queue.ready() and not plc_state.shutdown do
|
||||
local msg = rps_queue.pop()
|
||||
|
||||
if msg.qtype == mqueue.TYPE.COMMAND then
|
||||
-- received a command
|
||||
if plc_state.init_ok then
|
||||
if msg.message == MQ__RPS_CMD.SCRAM then
|
||||
-- SCRAM
|
||||
rps.scram()
|
||||
elseif msg.message == MQ__RPS_CMD.DEGRADED_SCRAM then
|
||||
-- lost peripheral(s)
|
||||
rps.trip_degraded()
|
||||
elseif msg.message == MQ__RPS_CMD.TRIP_TIMEOUT then
|
||||
-- watchdog tripped
|
||||
rps.trip_timeout()
|
||||
println_ts("server timeout")
|
||||
log.warning("server timeout")
|
||||
if msg ~= nil then
|
||||
if msg.qtype == mqueue.TYPE.COMMAND then
|
||||
-- received a command
|
||||
if plc_state.init_ok then
|
||||
if msg.message == MQ__RPS_CMD.SCRAM then
|
||||
-- SCRAM
|
||||
rps.scram()
|
||||
elseif msg.message == MQ__RPS_CMD.DEGRADED_SCRAM then
|
||||
-- lost peripheral(s)
|
||||
rps.trip_fault()
|
||||
elseif msg.message == MQ__RPS_CMD.TRIP_TIMEOUT then
|
||||
-- watchdog tripped
|
||||
rps.trip_timeout()
|
||||
println_ts("server timeout")
|
||||
log.warning("server timeout")
|
||||
end
|
||||
end
|
||||
elseif msg.qtype == mqueue.TYPE.DATA then
|
||||
-- received data
|
||||
elseif msg.qtype == mqueue.TYPE.PACKET then
|
||||
-- received a packet
|
||||
end
|
||||
elseif msg.qtype == mqueue.TYPE.DATA then
|
||||
-- received data
|
||||
elseif msg.qtype == mqueue.TYPE.PACKET then
|
||||
-- received a packet
|
||||
end
|
||||
|
||||
-- quick yield
|
||||
@ -301,6 +305,7 @@ threads.thread__rps = function (smem)
|
||||
end
|
||||
|
||||
-- communications sender thread
|
||||
---@param smem plc_shared_memory
|
||||
threads.thread__comms_tx = function (smem)
|
||||
-- execute thread
|
||||
local exec = function ()
|
||||
@ -320,17 +325,19 @@ threads.thread__comms_tx = function (smem)
|
||||
while comms_queue.ready() and not plc_state.shutdown do
|
||||
local msg = comms_queue.pop()
|
||||
|
||||
if msg.qtype == mqueue.TYPE.COMMAND then
|
||||
-- received a command
|
||||
if msg.message == MQ__COMM_CMD.SEND_STATUS then
|
||||
-- send PLC/RPS status
|
||||
plc_comms.send_status(plc_state.degraded)
|
||||
plc_comms.send_rps_status()
|
||||
if msg ~= nil then
|
||||
if msg.qtype == mqueue.TYPE.COMMAND then
|
||||
-- received a command
|
||||
if msg.message == MQ__COMM_CMD.SEND_STATUS then
|
||||
-- send PLC/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
|
||||
elseif msg.qtype == mqueue.TYPE.DATA then
|
||||
-- received data
|
||||
elseif msg.qtype == mqueue.TYPE.PACKET then
|
||||
-- received a packet
|
||||
end
|
||||
|
||||
-- quick yield
|
||||
@ -352,22 +359,20 @@ threads.thread__comms_tx = function (smem)
|
||||
end
|
||||
|
||||
-- communications handler thread
|
||||
---@param smem plc_shared_memory
|
||||
threads.thread__comms_rx = function (smem)
|
||||
-- execute thread
|
||||
local exec = function ()
|
||||
log.debug("comms rx thread start")
|
||||
|
||||
-- load in from shared memory
|
||||
local plc_state = smem.plc_state
|
||||
local setpoints = smem.setpoints
|
||||
local plc_dev = smem.plc_dev
|
||||
local rps = smem.plc_sys.rps
|
||||
local plc_comms = smem.plc_sys.plc_comms
|
||||
local conn_watchdog = smem.plc_sys.conn_watchdog
|
||||
local plc_state = smem.plc_state
|
||||
local setpoints = smem.setpoints
|
||||
local plc_comms = smem.plc_sys.plc_comms
|
||||
|
||||
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
|
||||
while true do
|
||||
@ -375,16 +380,17 @@ threads.thread__comms_rx = function (smem)
|
||||
while comms_queue.ready() and not plc_state.shutdown do
|
||||
local msg = comms_queue.pop()
|
||||
|
||||
if msg.qtype == mqueue.TYPE.COMMAND then
|
||||
-- received a command
|
||||
elseif msg.qtype == mqueue.TYPE.DATA then
|
||||
-- received data
|
||||
elseif msg.qtype == mqueue.TYPE.PACKET then
|
||||
-- received a packet
|
||||
-- handle the packet (setpoints passed to update burn rate setpoint)
|
||||
-- (plc_state passed to check if degraded)
|
||||
-- (conn_watchdog passed to allow feeding the watchdog)
|
||||
plc_comms.handle_packet(msg.message, setpoints, plc_state, conn_watchdog)
|
||||
if msg ~= nil then
|
||||
if msg.qtype == mqueue.TYPE.COMMAND then
|
||||
-- received a command
|
||||
elseif msg.qtype == mqueue.TYPE.DATA then
|
||||
-- received data
|
||||
elseif msg.qtype == mqueue.TYPE.PACKET then
|
||||
-- received a packet
|
||||
-- handle the packet (setpoints passed to update burn rate setpoint)
|
||||
-- (plc_state passed to check if degraded)
|
||||
plc_comms.handle_packet(msg.message, setpoints, plc_state)
|
||||
end
|
||||
end
|
||||
|
||||
-- quick yield
|
||||
@ -406,84 +412,90 @@ threads.thread__comms_rx = function (smem)
|
||||
end
|
||||
|
||||
-- apply setpoints
|
||||
---@param smem plc_shared_memory
|
||||
threads.thread__setpoint_control = function (smem)
|
||||
-- execute thread
|
||||
local exec = function ()
|
||||
log.debug("setpoint control thread start")
|
||||
|
||||
-- load in from shared memory
|
||||
local plc_state = smem.plc_state
|
||||
local setpoints = smem.setpoints
|
||||
local plc_dev = smem.plc_dev
|
||||
local rps = smem.plc_sys.rps
|
||||
local plc_state = smem.plc_state
|
||||
local setpoints = smem.setpoints
|
||||
local plc_dev = smem.plc_dev
|
||||
local rps = smem.plc_sys.rps
|
||||
|
||||
local last_update = util.time()
|
||||
local running = false
|
||||
local last_update = util.time()
|
||||
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
|
||||
while true do
|
||||
local reactor = plc_dev.reactor
|
||||
|
||||
-- check if we should start ramping
|
||||
if setpoints.burn_rate_en and setpoints.burn_rate ~= last_sp_burn then
|
||||
if rps.is_active() 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 plc_state.init_ok and not plc_state.no_reactor then
|
||||
-- check if we should start ramping
|
||||
if setpoints.burn_rate_en and setpoints.burn_rate ~= last_sp_burn then
|
||||
if rps.is_active() then
|
||||
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
|
||||
reactor.setBurnRate(new_burn_rate)
|
||||
|
||||
running = running or (new_burn_rate ~= setpoints.burn_rate)
|
||||
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")
|
||||
---@diagnostic disable-next-line: need-check-nil
|
||||
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
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user