diff --git a/reactor-plc/config.lua b/reactor-plc/config.lua index f3cf0f6..0555b54 100644 --- a/reactor-plc/config.lua +++ b/reactor-plc/config.lua @@ -5,6 +5,10 @@ config.NETWORKED = true -- unique reactor ID config.REACTOR_ID = 1 +-- for offline mode, this redstone interface will turn off (open a valve) +-- when emergency coolant is needed due to low coolant +config.EMERGENCY_COOL = { side = "right", color = nil } + -- port to send packets TO server config.SERVER_PORT = 16000 -- port to listen to incoming packets FROM server diff --git a/reactor-plc/plc.lua b/reactor-plc/plc.lua index dce6a73..6c2b066 100644 --- a/reactor-plc/plc.lua +++ b/reactor-plc/plc.lua @@ -2,6 +2,7 @@ local comms = require("scada-common.comms") local const = require("scada-common.constants") local log = require("scada-common.log") local ppm = require("scada-common.ppm") +local rsio = require("scada-common.rsio") local types = require("scada-common.types") local util = require("scada-common.util") @@ -34,7 +35,8 @@ local PCALL_START_MSG = "pcall: Reactor is already active." ---@nodiscard ---@param reactor table ---@param is_formed boolean -function plc.rps_init(reactor, is_formed) +---@param emer_cool nil|table emergency coolant configuration +function plc.rps_init(reactor, is_formed, emer_cool) local state_keys = { high_dmg = 1, high_temp = 2, @@ -54,6 +56,7 @@ function plc.rps_init(reactor, is_formed) state = { false, false, false, false, false, false, false, false, false, false, false, false }, reactor_enabled = false, enabled_at = 0, + emer_cool_active = nil, ---@type boolean formed = is_formed, force_disabled = false, tripped = false, @@ -74,6 +77,41 @@ function plc.rps_init(reactor, is_formed) self.state[state_keys.fault] = false end + -- set emergency coolant control (if configured) + ---@param state boolean true to enable emergency coolant, false to disable + local function _set_emer_cool(state) + -- check if this was configured: if it's a table, fields have already been validated. + if type(emer_cool) == "table" then + local level = rsio.digital_write_active(rsio.IO.U_EMER_COOL, state) + + if level ~= false then + if rsio.is_color(emer_cool.color) then + local output = rs.getBundledOutput(emer_cool.side) + + if rsio.digital_write(level) then + output = colors.combine(output, emer_cool.color) + else + output = colors.subtract(output, emer_cool.color) + end + + rs.setBundledOutput(emer_cool.side, output) + else + rs.setOutput(emer_cool.side, rsio.digital_write(level)) + end + + if state ~= self.emer_cool_active then + if state then + log.info("RPS: emergency coolant valve OPENED") + else + log.info("RPS: emergency coolant valve CLOSED") + end + + self.emer_cool_active = state + end + end + end + end + -- check if the reactor is formed local function _is_formed() local formed = reactor.isFormed() @@ -348,6 +386,9 @@ function plc.rps_init(reactor, is_formed) end end + -- update emergency coolant control if configured + _set_emer_cool(self.state[state_keys.low_coolant]) + return self.tripped, status, first_trip end @@ -358,6 +399,8 @@ function plc.rps_init(reactor, is_formed) function public.is_tripped() return self.tripped end ---@nodiscard function public.get_trip_cause() return self.trip_cause end + ---@nodiscard + function public.is_low_coolant() return self.states[state_keys.low_coolant] end ---@nodiscard function public.is_active() return self.reactor_enabled end diff --git a/reactor-plc/startup.lua b/reactor-plc/startup.lua index 5ad5ca4..dc9d3ce 100644 --- a/reactor-plc/startup.lua +++ b/reactor-plc/startup.lua @@ -8,13 +8,14 @@ local crash = require("scada-common.crash") local log = require("scada-common.log") local mqueue = require("scada-common.mqueue") local ppm = require("scada-common.ppm") +local rsio = require("scada-common.rsio") local util = require("scada-common.util") local config = require("reactor-plc.config") local plc = require("reactor-plc.plc") local threads = require("reactor-plc.threads") -local R_PLC_VERSION = "v1.0.0" +local R_PLC_VERSION = "v1.0.1" local print = util.print local println = util.println @@ -39,6 +40,15 @@ cfv.assert_type_int(config.LOG_MODE) assert(cfv.valid(), "bad config file: missing/invalid fields") +-- check emergency coolant configuration +if type(config.EMERGENCY_COOL) == "table" then + if not rsio.is_valid_side(config.EMERGENCY_COOL.side) then + assert(false, "bad config file: emergency coolant side unrecognized") + elseif config.EMERGENCY_COOL.color ~= nil and not rsio.is_color(config.EMERGENCY_COOL.color) then + assert(false, "bad config file: emergency coolant invalid redstone channel color provided") + end +end + ---------------------------------------- -- log init ---------------------------------------- @@ -155,7 +165,7 @@ local function main() end -- init reactor protection system - smem_sys.rps = plc.rps_init(smem_dev.reactor, plc_state.reactor_formed) + smem_sys.rps = plc.rps_init(smem_dev.reactor, plc_state.reactor_formed, config.EMERGENCY_COOL) log.debug("init> rps init") if __shared_memory.networked then @@ -172,6 +182,12 @@ local function main() log.info("init> running without networking") end + -- notify user of emergency coolant configuration status + if config.EMERGENCY_COOL ~= nil then + println("init> emergency coolant control ready") + log.info("init> running with emergency coolant control available") + end + util.push_event("clock_start") println("init> completed") diff --git a/reactor-plc/threads.lua b/reactor-plc/threads.lua index d2708fd..c288281 100644 --- a/reactor-plc/threads.lua +++ b/reactor-plc/threads.lua @@ -314,7 +314,6 @@ function threads.thread__rps(smem) rps.trip_timeout() end else - -- would do elseif not networked but there is no reason to do that extra operation was_linked = true end