From cb210056111b9192067260d616181f7634dc3695 Mon Sep 17 00:00:00 2001 From: TO Date: Sun, 25 Dec 2022 16:57:55 +0100 Subject: [PATCH] close Safety Rules #1 Auto inj safety rules #9 --- fissionControler.lua | 197 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 187 insertions(+), 10 deletions(-) diff --git a/fissionControler.lua b/fissionControler.lua index 71e6822..5493b38 100644 --- a/fissionControler.lua +++ b/fissionControler.lua @@ -1,13 +1,22 @@ +-- Gist get => pastebin get t4RjeKsw gist + local reactor, monitor local data = {} local buttons = {} local computerTerm = term.current() -local wButtons, wStats, wGraph +local wButtons, wStats, wGraph, wInfos, wRules local injRate = 0.1 local maxBurnRate -local last_reactor_heatedCoolent +local last_reactor_heatedCoolent, last_reactor_coolant local auto = false +local state, startAsked, stopAsked +local STATES = { + READY = 1, -- Reactor is off and can be started + RUNNING = 2, -- Reactor is running and all rules are met + ESTOP = 3, -- Reactor is stopped due to rule(s) being violated + UNKNOWN = 4, -- Reactor peripherals are missing +} local function round(val, decimal) if (decimal) then return math.floor((val * 10 ^ decimal) + 0.5) / (10 ^ decimal) @@ -86,6 +95,7 @@ local function updateButtons() buttons["+inj"]["color"] = colors.green buttons["-inj"]["active"] = true buttons["-inj"]["color"] = colors.red + buttons["auto"]["active"] = true buttons["auto"]["color"] = colors.orange if auto then buttons["+inj"]["active"] = false @@ -93,6 +103,7 @@ local function updateButtons() buttons["-inj"]["active"] = false buttons["-inj"]["color"] = colors.gray buttons["auto"]["color"] = colors.green + buttons["auto"]["active"] = true end if data.reactor_burn_rate == 0 then buttons["-inj"]["active"] = false @@ -101,7 +112,16 @@ local function updateButtons() buttons["+inj"]["active"] = false buttons["+inj"]["color"] = colors.gray end - if data.reactor_on then + if state == STATES.ESTOP then + buttons["startstop"]["title"] = "RESET" + buttons["startstop"]["color"] = colors.yellow + buttons["+inj"]["active"] = false + buttons["+inj"]["color"] = colors.gray + buttons["-inj"]["active"] = false + buttons["-inj"]["color"] = colors.gray + buttons["auto"]["active"] = false + buttons["auto"]["color"] = colors.gray + elseif data.reactor_on then buttons["startstop"]["title"] = "S.C.R.A.M." buttons["startstop"]["color"] = colors.red else @@ -159,13 +179,16 @@ local function autoInj() if auto and data.reactor_on then update_data() last_reactor_heatedCoolent = last_reactor_heatedCoolent or data.reactor_heatedCoolent - if data.reactor_heatedCoolent == 0 then + last_reactor_coolant = last_reactor_coolant or data.reactor_coolant + if (data.reactor_heatedCoolent == 0) and (data.reactor_coolant > 0.9) then addInj() - elseif data.reactor_heatedCoolent > last_reactor_heatedCoolent then + elseif (data.reactor_heatedCoolent > last_reactor_heatedCoolent) or (data.reactor_coolant < last_reactor_coolant) then delInj() last_reactor_heatedCoolent = data.reactor_heatedCoolent + last_reactor_coolant = data.reactor_coolant else last_reactor_heatedCoolent = data.reactor_heatedCoolent + last_reactor_coolant = data.reactor_coolant end end sleep(1) @@ -173,10 +196,12 @@ local function autoInj() end local function startStop() - if data.reactor_on then - reactor.scram() + if state == STATES.ESTOP then + state = STATES.READY + elseif data.reactor_on then + stopAsked = true else - reactor.activate() + startAsked = true end end @@ -268,7 +293,7 @@ local function drawGraphs() local nbGraph = 6 local hGraph = round(h / (nbGraph + 3)) - 1 local spaceBetween = round(hGraph / (nbGraph - 1)) + 2 - drawGraph("DAMAGE", 1, 1, w, hGraph, data.reactor_damage, colors.gray, colors.red) + drawGraph("DAMAGE", 1, 1, w, hGraph, data.reactor_damage / 100, colors.gray, colors.red) drawGraph("INJ-RATE", 1, 1 + (hGraph + spaceBetween), w, hGraph, data.reactor_burn_rate / data.reactor_max_burn_rate, colors.gray, colors.pink) drawGraph("COOLANT", 1, 1 + (hGraph + spaceBetween) * 2, w, hGraph, data.reactor_coolant, colors.gray, colors.blue) @@ -289,11 +314,163 @@ local function drawAll() end end +local rules = {} + +local function add_rule(name, fn) + table.insert(rules, function() + local ok, rule_met, value = pcall(fn) + if ok then + return rule_met, string.format("%s (%s)", name, value) + else + return false, name + end + end) +end + +add_rule("REACTOR TEMPERATURE <= 745K", function() + local value = string.format("%3dK", math.ceil(data.reactor_temp)) + return data.reactor_temp <= 745, value +end) + +add_rule("REACTOR DAMAGE <= 10%", function() + local value = string.format("%3d%%", math.ceil(data.reactor_damage)) + return data.reactor_damage / 100 <= 0.10, value +end) + +add_rule("REACTOR COOLANT LEVEL >= 80%", function() + local value = string.format("%3d%%", math.floor(data.reactor_coolant * 100)) + return data.reactor_coolant >= 0.80, value +end) + +add_rule("REACTOR HCOOLANT LEVEL<= 95%", function() + local value = string.format("%3d%%", math.floor(data.reactor_heatedCoolent * 100)) + return data.reactor_heatedCoolent <= 0.95, value +end) + +add_rule("REACTOR WASTE LEVEL <= 90%", function() + local value = string.format("%3d%%", math.ceil(data.reactor_waste * 100)) + return data.reactor_waste <= 0.90, value +end) + +local function all_rules_met() + for i, rule in ipairs(rules) do + if not rule() then + return false + end + end + -- Allow manual emergency stop with SCRAM button + return state ~= STATES.RUNNING or data.reactor_on +end + +local function update_info() + local prev_term = term.redirect(wInfos) + + term.clear() + term.setCursorPos(1, 1) + + if state == STATES.UNKNOWN then + colored("ERROR RETRIEVING DATA", colors.red) + return + end + + colored("REACTOR: ") + colored(data.reactor_on and "ON " or "OFF", data.reactor_on and colors.green or colors.red) + colored(" R. LIMIT: ") + colored(string.format("%4.1f", data.reactor_burn_rate), colors.blue) + colored("/", colors.lightGray) + colored(string.format("%4.1f", data.reactor_max_burn_rate), colors.blue) + + term.setCursorPos(1, 3) + + colored("STATUS: ") + if state == STATES.READY then + colored("READY, press TURN ON to start", colors.blue) + elseif state == STATES.RUNNING then + colored("RUNNING, press S.C.R.A.M. to stop", colors.green) + elseif state == STATES.ESTOP and not all_rules_met() then + colored("EMERGENCY STOP, safety rules violated", colors.red) + elseif state == STATES.ESTOP then + colored("EMERGENCY STOP, press RESET", colors.red) + end -- STATES.UNKNOWN cases handled above + + term.redirect(prev_term) +end + +local estop_reasons = {} + +local function update_rules() + local prev_term = term.redirect(wRules) + + term.clear() + + if state ~= STATES.ESTOP then + estop_reasons = {} + end + + for i, rule in ipairs(rules) do + local ok, text = rule() + term.setCursorPos(1, i) + if ok and not estop_reasons[i] then + colored("[ OK ] ", colors.green) + colored(text, colors.lightGray) + else + colored("[ FAIL ] ", colors.red) + colored(text, colors.red) + estop_reasons[i] = true + end + end + + term.redirect(prev_term) +end + +local function updateSafetyLoop() + while true do + if data.reactor_on == nil then + -- Reactor is not connected + state = STATES.UNKNOWN + elseif not state then + -- Program just started, get current state from lever + state = STATES.READY + elseif (state == STATES.READY and startAsked) or (state == STATES.READY and reactor.getStatus()) then + -- READY -> RUNNING + state = STATES.RUNNING + -- Activate reactor + pcall(reactor.activate) + startAsked = false + data.reactor_on = true + elseif (state == STATES.RUNNING and stopAsked) or (state == STATES.RUNNING and not reactor.getStatus()) then + -- RUNNING -> READY + state = STATES.READY + pcall(reactor.scram) + stopAsked = false + data.reactor_on = false + end + -- Always enter ESTOP if safety rules are not met + if state ~= STATES.UNKNOWN and not all_rules_met() then + state = STATES.ESTOP + end + + -- SCRAM reactor if not running + if state ~= STATES.RUNNING and reactor then + pcall(reactor.scram) + end + + -- Update info and rules windows + pcall(update_info) + pcall(update_rules) + sleep(1) + end +end + local function main() getPeripherals() + term.clear() + local width = term.getSize() monitor.setTextScale(0.5) local w, h = monitor.getSize() update_data() + wInfos = makeSection("INFORMATION", 2, 2, width - 2, 7, computerTerm) + wRules = makeSection("SAFETY RULES", 2, 10, width - 2, 9, computerTerm) wStats = makeSection("Infos", 1, 1, round(w / 3) - 1, round(h / 2) - 1, monitor) wButtons = makeSection("Buttons", 1, round(h / 2) + 1, round(w / 3) - 1, round(h / 2), monitor) wGraph = makeSection("Graphics", round(w / 3) + 1, 1, round(w / 3 * 2), h, monitor) @@ -305,7 +482,7 @@ local function main() setButton("-inj", "- Inj", delInj, 1, 1 + hButton + spaceBetween, w, hButton, colors.gray, colors.white) setButton("auto", "Auto Inj", toggleAuto, 1, 1 + (spaceBetween + hButton) * 2, w, hButton, colors.gray, colors.white) setButton("startstop", "Start", startStop, 1, 1 + (spaceBetween + hButton) * 3, w, hButton, colors.green, colors.white) - parallel.waitForAny(autoInj, clickEvent, drawAll) + parallel.waitForAny(autoInj, clickEvent, drawAll, updateSafetyLoop) end main()