#106 fixes to reactor isFormed support

This commit is contained in:
Mikayla Fischler 2022-10-25 23:40:36 -04:00
parent 57bac57e3f
commit 004c960e4d
5 changed files with 94 additions and 76 deletions

View File

@ -230,16 +230,21 @@ function plc.rps_init(reactor, is_formed)
local was_tripped = self.tripped local was_tripped = self.tripped
local first_trip = false local first_trip = false
-- update state if self.formed then
parallel.waitForAll( -- update state
_is_formed, parallel.waitForAll(
_damage_critical, _is_formed,
_high_temp, _damage_critical,
_no_coolant, _high_temp,
_excess_waste, _no_coolant,
_excess_heated_coolant, _excess_waste,
_insufficient_fuel _excess_heated_coolant,
) _insufficient_fuel
)
else
-- check to see if its now formed
_is_formed()
end
-- check system states in order of severity -- check system states in order of severity
if self.tripped then if self.tripped then
@ -284,7 +289,11 @@ function plc.rps_init(reactor, is_formed)
self.tripped = true self.tripped = true
self.trip_cause = status self.trip_cause = status
public.scram() if self.formed then
public.scram()
else
log.warning("RPS: skipping SCRAM due to not being formed")
end
end end
return self.tripped, status, first_trip return self.tripped, status, first_trip
@ -322,19 +331,16 @@ end
---@param conn_watchdog watchdog ---@param conn_watchdog watchdog
function plc.comms(id, version, modem, local_port, server_port, reactor, rps, conn_watchdog) function plc.comms(id, version, modem, local_port, server_port, reactor, rps, conn_watchdog)
local self = { local self = {
id = id,
version = version,
seq_num = 0, seq_num = 0,
r_seq_num = nil, r_seq_num = nil,
modem = modem, modem = modem,
s_port = server_port, s_port = server_port,
l_port = local_port, l_port = local_port,
reactor = reactor, reactor = reactor,
rps = rps,
conn_watchdog = conn_watchdog,
scrammed = false, scrammed = false,
linked = false, linked = false,
status_cache = nil, status_cache = nil,
resend_build = false,
max_burn_rate = nil max_burn_rate = nil
} }
@ -358,7 +364,7 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
local r_pkt = comms.rplc_packet() local r_pkt = comms.rplc_packet()
r_pkt.make(self.id, msg_type, msg) r_pkt.make(id, msg_type, msg)
s_pkt.make(self.seq_num, PROTOCOLS.RPLC, r_pkt.raw_sendable()) s_pkt.make(self.seq_num, PROTOCOLS.RPLC, r_pkt.raw_sendable())
self.modem.transmit(self.s_port, self.l_port, s_pkt.raw_sendable()) self.modem.transmit(self.s_port, self.l_port, s_pkt.raw_sendable())
@ -514,6 +520,7 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co
if not self.reactor.__p_is_faulted() then if not self.reactor.__p_is_faulted() then
_send(RPLC_TYPES.MEK_STRUCT, mek_data) _send(RPLC_TYPES.MEK_STRUCT, mek_data)
self.resend_build = false
else else
log.error("failed to send structure: PPM fault") log.error("failed to send structure: PPM fault")
end end
@ -535,6 +542,7 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co
function public.reconnect_reactor(reactor) function public.reconnect_reactor(reactor)
self.reactor = reactor self.reactor = reactor
self.status_cache = nil self.status_cache = nil
self.resend_build = true
end end
-- unlink from the server -- unlink from the server
@ -546,30 +554,27 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co
-- close the connection to the server -- close the connection to the server
function public.close() function public.close()
self.conn_watchdog.cancel() conn_watchdog.cancel()
public.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
function public.send_link_req() function public.send_link_req()
_send(RPLC_TYPES.LINK_REQ, { self.id, self.version }) _send(RPLC_TYPES.LINK_REQ, { id, version })
end end
-- send live status information -- send live status information
---@param no_reactor boolean PLC lost reactor connection ---@param no_reactor boolean PLC lost reactor connection
---@param formed boolean reactor formed ---@param formed boolean reactor formed (from PLC state)
function public.send_status(no_reactor, formed) function public.send_status(no_reactor, formed)
if self.linked then if self.linked then
local mek_data = nil ---@type table local mek_data = nil ---@type table
local heating_rate = nil ---@type number local heating_rate = 0.0 ---@type number
if (not no_reactor) and formed then if (not no_reactor) and rps.is_formed() then
if _update_status_cache() then if _update_status_cache() then
mek_data = self.status_cache mek_data = self.status_cache
log.debug("sent updated status")
else
log.debug("sent cached status")
end end
heating_rate = self.reactor.getHeatingRate() heating_rate = self.reactor.getHeatingRate()
@ -586,6 +591,10 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co
} }
_send(RPLC_TYPES.STATUS, sys_status) _send(RPLC_TYPES.STATUS, sys_status)
if self.resend_build then
_send_struct()
end
end end
end end
@ -661,7 +670,7 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co
end end
-- feed the watchdog first so it doesn't uhh...eat our packets :) -- feed the watchdog first so it doesn't uhh...eat our packets :)
self.conn_watchdog.feed() conn_watchdog.feed()
local protocol = packet.scada_frame.protocol() local protocol = packet.scada_frame.protocol()
@ -739,11 +748,11 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co
elseif packet.type == RPLC_TYPES.RPS_ENABLE then elseif packet.type == RPLC_TYPES.RPS_ENABLE then
-- enable the reactor -- enable the reactor
self.scrammed = false self.scrammed = false
_send_ack(packet.type, self.rps.activate()) _send_ack(packet.type, rps.activate())
elseif packet.type == RPLC_TYPES.RPS_SCRAM then elseif packet.type == RPLC_TYPES.RPS_SCRAM then
-- disable the reactor -- disable the reactor
self.scrammed = true self.scrammed = true
self.rps.trip_manual() rps.trip_manual()
_send_ack(packet.type, true) _send_ack(packet.type, true)
elseif packet.type == RPLC_TYPES.RPS_RESET then elseif packet.type == RPLC_TYPES.RPS_RESET then
-- reset the RPS status -- reset the RPS status
@ -809,7 +818,7 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co
end end
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() conn_watchdog.cancel()
public.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")

View File

@ -13,7 +13,7 @@ local config = require("reactor-plc.config")
local plc = require("reactor-plc.plc") local plc = require("reactor-plc.plc")
local threads = require("reactor-plc.threads") local threads = require("reactor-plc.threads")
local R_PLC_VERSION = "beta-v0.9.0" local R_PLC_VERSION = "beta-v0.9.1"
local print = util.print local print = util.print
local println = util.println local println = util.println

View File

@ -84,6 +84,7 @@ function threads.thread__main(smem, init)
-- push a connect event and unmount it from the PPM -- push a connect event and unmount it from the PPM
local iface = ppm.get_iface(plc_dev.reactor) local iface = ppm.get_iface(plc_dev.reactor)
if iface then if iface then
log.info("unmounting and remounting unformed reactor")
ppm.unmount(plc_dev.reactor) ppm.unmount(plc_dev.reactor)
local type, device = ppm.mount(iface) local type, device = ppm.mount(iface)
@ -91,27 +92,32 @@ function threads.thread__main(smem, init)
if type ~= "fissionReactorLogicAdapter" and device ~= nil then if type ~= "fissionReactorLogicAdapter" and device ~= nil then
-- reconnect reactor -- reconnect reactor
plc_dev.reactor = device plc_dev.reactor = device
smem.q.mq_rps.push_command(MQ__RPS_CMD.SCRAM)
println_ts("reactor reconnected as formed.")
log.info("reactor reconnected as formed")
plc_state.reactor_formed = device.isFormed() plc_state.reactor_formed = device.isFormed()
rps.reconnect_reactor(plc_dev.reactor) if plc_state.reactor_formed then
if networked then println_ts("reactor reconnected as formed.")
plc_comms.reconnect_reactor(plc_dev.reactor) log.info("reactor reconnected as formed")
-- SCRAM newly connected reactor
smem.q.mq_rps.push_command(MQ__RPS_CMD.SCRAM)
else
println_ts("reactor reconnected but still not formed.")
log.info("reactor reconnected but still not formed")
end end
-- determine if we are still in a degraded state -- determine if we are still in a degraded state
if not networked or not plc_state.no_modem then if not networked or not plc_state.no_modem then
plc_state.degraded = false plc_state.degraded = false
end end
rps.reconnect_reactor(plc_dev.reactor)
if networked then
plc_comms.reconnect_reactor(plc_dev.reactor)
end
else else
-- fully lost the reactor now :( -- fully lost the reactor now :(
println_ts("reactor lost (failed reconnect)!") println_ts("reactor lost (failed reconnect)!")
log.error("reactor lost (failed reconnect!") log.error("reactor lost (failed reconnect)")
plc_state.no_reactor = true plc_state.no_reactor = true
plc_state.degraded = true plc_state.degraded = true
@ -141,7 +147,7 @@ function threads.thread__main(smem, init)
if type ~= nil and device ~= nil then if type ~= nil and device ~= nil then
if type == "fissionReactorLogicAdapter" then if type == "fissionReactorLogicAdapter" then
println_ts("reactor disconnected!") println_ts("reactor disconnected!")
log.error("reactor disconnected!") log.error("reactor logic adapter disconnected")
plc_state.no_reactor = true plc_state.no_reactor = true
plc_state.degraded = true plc_state.degraded = true
@ -149,7 +155,7 @@ function threads.thread__main(smem, init)
-- we only care if this is our wireless modem -- we only care if this is our wireless modem
if device == plc_dev.modem then if device == plc_dev.modem then
println_ts("comms modem disconnected!") println_ts("comms modem disconnected!")
log.error("comms modem disconnected!") log.error("comms modem disconnected")
plc_state.no_modem = true plc_state.no_modem = true
@ -173,25 +179,27 @@ function threads.thread__main(smem, init)
-- reconnected reactor -- reconnected reactor
plc_dev.reactor = device plc_dev.reactor = device
smem.q.mq_rps.push_command(MQ__RPS_CMD.SCRAM)
println_ts("reactor reconnected.") println_ts("reactor reconnected.")
log.info("reactor reconnected") log.info("reactor reconnected")
plc_state.no_reactor = false plc_state.no_reactor = false
plc_state.reactor_formed = device.isFormed() plc_state.reactor_formed = device.isFormed()
-- determine if we are still in a degraded state
if (not networked or not plc_state.no_modem) and plc_state.reactor_formed then
plc_state.degraded = false
end
if plc_state.init_ok then if plc_state.init_ok then
if plc_state.reactor_formed then
smem.q.mq_rps.push_command(MQ__RPS_CMD.SCRAM)
end
rps.reconnect_reactor(plc_dev.reactor) rps.reconnect_reactor(plc_dev.reactor)
if networked then if networked then
plc_comms.reconnect_reactor(plc_dev.reactor) plc_comms.reconnect_reactor(plc_dev.reactor)
end end
end end
-- determine if we are still in a degraded state
if (not networked or not plc_state.no_modem) and plc_state.reactor_formed then
plc_state.degraded = false
end
elseif networked and type == "modem" then elseif networked and type == "modem" then
if device.isWireless() then if device.isWireless() then
-- reconnected modem -- reconnected modem
@ -302,7 +310,7 @@ function threads.thread__rps(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 ---@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_formed() and rps.is_tripped() and reactor.getStatus() then
rps.scram() rps.scram()
end end

View File

@ -115,35 +115,35 @@ local function peri_init(iface)
-- add default index function to catch undefined indicies -- add default index function to catch undefined indicies
local mt = {} local mt = {
__index = function (_, key)
function mt.__index(_, key) -- this will continuously be counting calls here as faults
-- this will continuously be counting calls here as faults -- unlike other functions, faults here can't be cleared as it is just not defined
-- unlike other functions, faults here can't be cleared as it is just not defined if self.fault_counts[key] == nil then
if self.fault_counts[key] == nil then self.fault_counts[key] = 0
self.fault_counts[key] = 0
end
-- function failed
self.faulted = true
self.last_fault = UNDEFINED_FIELD
_ppm_sys.faulted = true
_ppm_sys.last_fault = UNDEFINED_FIELD
if not _ppm_sys.mute and (self.fault_counts[key] % REPORT_FREQUENCY == 0) then
local count_str = ""
if self.fault_counts[key] > 0 then
count_str = " [" .. self.fault_counts[key] .. " total calls]"
end end
log.error(util.c("PPM: caught undefined function ", key, "()", count_str)) -- function failed
self.faulted = true
self.last_fault = UNDEFINED_FIELD
_ppm_sys.faulted = true
_ppm_sys.last_fault = UNDEFINED_FIELD
if not _ppm_sys.mute and (self.fault_counts[key] % REPORT_FREQUENCY == 0) then
local count_str = ""
if self.fault_counts[key] > 0 then
count_str = " [" .. self.fault_counts[key] .. " total calls]"
end
log.error(util.c("PPM: caught undefined function ", key, "()", count_str))
end
self.fault_counts[key] = self.fault_counts[key] + 1
return (function () return ACCESS_FAULT end)
end end
}
self.fault_counts[key] = self.fault_counts[key] + 1
return ACCESS_FAULT
end
setmetatable(self.device, mt) setmetatable(self.device, mt)

View File

@ -105,7 +105,8 @@ types.rps_status_t = {
no_fuel = "no_fuel", no_fuel = "no_fuel",
fault = "fault", fault = "fault",
timeout = "timeout", timeout = "timeout",
manual = "manual" manual = "manual",
sys_fail = "sys_fail"
} }
-- turbine steam dumping modes -- turbine steam dumping modes