reactor control and safety system attempting server connection
This commit is contained in:
6
rcass/config.lua
Normal file
6
rcass/config.lua
Normal file
@@ -0,0 +1,6 @@
|
||||
-- unique reactor ID
|
||||
REACTOR_ID = 1
|
||||
-- port to send packets TO server
|
||||
SERVER_PORT = 1000
|
||||
-- port to listen to incoming packets FROM server
|
||||
LISTEN_PORT = 1001
|
||||
122
rcass/rcass.lua
Normal file
122
rcass/rcass.lua
Normal file
@@ -0,0 +1,122 @@
|
||||
--
|
||||
-- RCaSS: Reactor Controller and Safety Subsystem
|
||||
--
|
||||
|
||||
os.loadAPI("common/util.lua")
|
||||
os.loadAPI("common/comms.lua")
|
||||
os.loadAPI("rcass/config.lua")
|
||||
os.loadAPI("rcass/safety.lua")
|
||||
|
||||
local RCASS_VERSION = "alpha-v0.1"
|
||||
|
||||
local print_ts = util.print_ts
|
||||
|
||||
local reactor = peripheral.find("fissionReactor")
|
||||
local modem = peripheral.find("modem")
|
||||
|
||||
print(">> RCaSS " .. RCASS_VERSION .. " <<")
|
||||
|
||||
-- we need a reactor and a modem
|
||||
if reactor == nil then
|
||||
print("Fission reactor not found, exiting...");
|
||||
return
|
||||
elseif modem == nil then
|
||||
print("No modem found, disabling reactor and exiting...")
|
||||
reactor.scram()
|
||||
return
|
||||
end
|
||||
|
||||
-- just booting up, no fission allowed (neutrons stay put thanks)
|
||||
reactor.scram()
|
||||
|
||||
-- init internal safety system
|
||||
local iss = safety.iss_init(reactor)
|
||||
local iss_status = "ok"
|
||||
local iss_tripped = false
|
||||
|
||||
-- read config
|
||||
|
||||
-- start comms
|
||||
if not modem.isOpen(config.LISTEN_PORT) then
|
||||
modem.open(config.LISTEN_PORT)
|
||||
end
|
||||
|
||||
local comms = comms.rcass_comms(config.REACTOR_ID, modem, config.LISTEN_PORT, config.SERVER_PORT, reactor)
|
||||
|
||||
-- attempt server connection
|
||||
local linked = false
|
||||
local link_timeout = os.startTimer(5)
|
||||
comms.send_link_req()
|
||||
print_ts("sent link request")
|
||||
repeat
|
||||
local event, param1, param2, param3, param4, param5 = os.pullEvent()
|
||||
|
||||
-- handle event
|
||||
if event == "timer" and param1 == link_timeout then
|
||||
-- no response yet
|
||||
print("...no response");
|
||||
comms.send_link_req()
|
||||
print_ts("sent link request")
|
||||
link_timeout = os.startTimer(5)
|
||||
elseif event == "modem_message" then
|
||||
-- server response? cancel timeout
|
||||
if link_timeout ~= nil then
|
||||
os.cancelTimer(link_timeout)
|
||||
end
|
||||
|
||||
local packet = {
|
||||
side = param1,
|
||||
sender = param2,
|
||||
reply_to = param3,
|
||||
message = param4,
|
||||
distance = param5
|
||||
}
|
||||
|
||||
-- handle response
|
||||
response = comms.handle_link(packet)
|
||||
if response == "wrong_type" then
|
||||
print_ts("invalid link response, bad channel?\n")
|
||||
return
|
||||
elseif response == true then
|
||||
print_ts("...linked!\n")
|
||||
linked = true
|
||||
else
|
||||
print_ts("...denied, exiting\n")
|
||||
return
|
||||
end
|
||||
end
|
||||
until linked
|
||||
|
||||
-- comms watchdog, 3 second timeout
|
||||
local conn_watchdog = watchdog.new_watchdog(3)
|
||||
|
||||
-- loop clock (10Hz, 2 ticks)
|
||||
-- send status updates at 4Hz (every 5 ticks)
|
||||
local loop_tick = os.startTimer(0.05)
|
||||
local ticks_to_update = 5
|
||||
|
||||
-- event loop
|
||||
while true do
|
||||
local event, param1, param2, param3, param4, param5 = os.pullEvent()
|
||||
|
||||
-- check safety (SCRAM occurs if tripped)
|
||||
iss_status, iss_tripped = iss.check()
|
||||
|
||||
-- handle event
|
||||
if event == "timer" and param1 == loop_tick then
|
||||
-- basic event tick, send updated data if it is time
|
||||
ticks_to_update = ticks_to_update - 1
|
||||
if ticks_to_update == 0 then
|
||||
ticks_to_update = 5
|
||||
end
|
||||
elseif event == "modem_message" then
|
||||
-- got a packet
|
||||
-- feed the watchdog first so it doesn't eat our packets
|
||||
conn_watchdog.feed()
|
||||
|
||||
elseif event == "timer" and param1 == conn_watchdog.get_timer() then
|
||||
-- haven't heard from server recently? shutdown
|
||||
reactor.scram()
|
||||
print_ts("[alert] server timeout, reactor disabled\n")
|
||||
end
|
||||
end
|
||||
80
rcass/safety.lua
Normal file
80
rcass/safety.lua
Normal file
@@ -0,0 +1,80 @@
|
||||
-- Internal Safety System
|
||||
-- identifies dangerous states and SCRAMs reactor if warranted
|
||||
-- autonomous from main control
|
||||
function iss_init(reactor)
|
||||
local self = {
|
||||
_reactor = reactor,
|
||||
_tripped = false,
|
||||
_trip_cause = ""
|
||||
}
|
||||
|
||||
local check = function ()
|
||||
local status = "ok"
|
||||
|
||||
-- check system states in order of severity
|
||||
if self.damage_critical() then
|
||||
status = "dmg_crit"
|
||||
elseif self.high_temp() then
|
||||
status = "high_temp"
|
||||
elseif self.excess_heated_coolant() then
|
||||
status = "heated_coolant_backup"
|
||||
elseif self.excess_waste() then
|
||||
status = "full_waste"
|
||||
elseif self.insufficient_fuel() then
|
||||
status = "no_fuel"
|
||||
elseif self._tripped then
|
||||
status = self._trip_cause
|
||||
else
|
||||
self._tripped = false
|
||||
end
|
||||
|
||||
if status ~= "ok" then
|
||||
self._tripped = true
|
||||
self._trip_cause = status
|
||||
self._reactor.scram()
|
||||
end
|
||||
|
||||
return self._tripped, status
|
||||
end
|
||||
|
||||
local reset = function ()
|
||||
self._tripped = false
|
||||
self._trip_cause = ""
|
||||
end
|
||||
|
||||
local damage_critical = function ()
|
||||
return self._reactor.getDamagePercent() >= 100
|
||||
end
|
||||
|
||||
local excess_heated_coolant = function ()
|
||||
return self._reactor.getHeatedCoolantNeeded() == 0
|
||||
end
|
||||
|
||||
local excess_waste = function ()
|
||||
return self._reactor.getWasteNeeded() == 0
|
||||
end
|
||||
|
||||
local high_temp = function ()
|
||||
-- mekanism: MAX_DAMAGE_TEMPERATURE = 1_200
|
||||
return self._reactor.getTemperature() >= 1200
|
||||
end
|
||||
|
||||
local insufficient_fuel = function ()
|
||||
return self._reactor.getFuel() == 0
|
||||
end
|
||||
|
||||
local no_coolant = function()
|
||||
return self._reactor.getCoolantFilledPercentage() < 2
|
||||
end
|
||||
|
||||
return {
|
||||
check = check,
|
||||
reset = reset,
|
||||
damage_critical = damage_critical,
|
||||
excess_heated_coolant = excess_heated_coolant,
|
||||
excess_waste = excess_waste,
|
||||
high_temp = high_temp,
|
||||
insufficient_fuel = insufficient_fuel,
|
||||
no_coolant = no_coolant
|
||||
}
|
||||
end
|
||||
159
rcass/signal-router.lua
Normal file
159
rcass/signal-router.lua
Normal file
@@ -0,0 +1,159 @@
|
||||
-- reactor signal router
|
||||
-- transmits status information and controls enable state
|
||||
|
||||
-- bundeled redstone key
|
||||
-- top:
|
||||
-- black (in): insufficent fuel
|
||||
-- brown (in): excess waste
|
||||
-- orange (in): overheat
|
||||
-- red (in): damage critical
|
||||
-- right:
|
||||
-- cyan (out): plutonium/plutonium pellet pipe
|
||||
-- green (out): polonium pipe
|
||||
-- magenta (out): polonium pellet pipe
|
||||
-- purple (out): antimatter pipe
|
||||
-- white (out): reactor enable
|
||||
|
||||
-- constants
|
||||
REACTOR_ID = 1
|
||||
DEST_PORT = 1000
|
||||
|
||||
local state = {
|
||||
id = REACTOR_ID,
|
||||
run = false,
|
||||
no_fuel = false,
|
||||
full_waste = false,
|
||||
high_temp = false,
|
||||
damage_crit = false
|
||||
}
|
||||
|
||||
local waste_production = "antimatter"
|
||||
|
||||
local listen_port = 1000 + REACTOR_ID
|
||||
local modem = peripheral.wrap("left")
|
||||
|
||||
print("Reactor Signal Router v1.0")
|
||||
print("Configured for Reactor #" .. REACTOR_ID)
|
||||
|
||||
if not modem.isOpen(listen_port) then
|
||||
modem.open(listen_port)
|
||||
end
|
||||
|
||||
-- greeting
|
||||
modem.transmit(DEST_PORT, listen_port, REACTOR_ID)
|
||||
|
||||
-- queue event to read initial state and make sure reactor starts off
|
||||
os.queueEvent("redstone")
|
||||
rs.setBundledOutput("right", colors.white)
|
||||
rs.setBundledOutput("right", 0)
|
||||
re_eval_output = true
|
||||
|
||||
local connection_timeout = os.startTimer(3)
|
||||
|
||||
-- event loop
|
||||
while true do
|
||||
local event, param1, param2, param3, param4, param5 = os.pullEvent()
|
||||
|
||||
if event == "redstone" then
|
||||
-- redstone state change
|
||||
input = rs.getBundledInput("top")
|
||||
|
||||
if state.no_fuel ~= colors.test(input, colors.black) then
|
||||
state.no_fuel = colors.test(input, colors.black)
|
||||
if state.no_fuel then
|
||||
print("insufficient fuel")
|
||||
end
|
||||
end
|
||||
|
||||
if state.full_waste ~= colors.test(input, colors.brown) then
|
||||
state.full_waste = colors.test(input, colors.brown)
|
||||
if state.full_waste then
|
||||
print("waste tank full")
|
||||
end
|
||||
end
|
||||
|
||||
if state.high_temp ~= colors.test(input, colors.orange) then
|
||||
state.high_temp = colors.test(input, colors.orange)
|
||||
if state.high_temp then
|
||||
print("high temperature")
|
||||
end
|
||||
end
|
||||
|
||||
if state.damage_crit ~= colors.test(input, colors.red) then
|
||||
state.damage_crit = colors.test(input, colors.red)
|
||||
if state.damage_crit then
|
||||
print("damage critical")
|
||||
end
|
||||
end
|
||||
elseif event == "modem_message" then
|
||||
-- got data, reset timer
|
||||
if connection_timeout ~= nil then
|
||||
os.cancelTimer(connection_timeout)
|
||||
end
|
||||
connection_timeout = os.startTimer(3)
|
||||
|
||||
if type(param4) == "number" and param4 == 0 then
|
||||
print("[info] controller server startup detected")
|
||||
modem.transmit(DEST_PORT, listen_port, REACTOR_ID)
|
||||
elseif type(param4) == "number" and param4 == 1 then
|
||||
-- keep-alive, do nothing, just had to reset timer
|
||||
elseif type(param4) == "boolean" then
|
||||
state.run = param4
|
||||
|
||||
if state.run then
|
||||
print("[alert] reactor enabled")
|
||||
else
|
||||
print("[alert] reactor disabled")
|
||||
end
|
||||
|
||||
re_eval_output = true
|
||||
elseif type(param4) == "string" then
|
||||
if param4 == "plutonium" then
|
||||
print("[alert] switching to plutonium production")
|
||||
waste_production = param4
|
||||
re_eval_output = true
|
||||
elseif param4 == "polonium" then
|
||||
print("[alert] switching to polonium production")
|
||||
waste_production = param4
|
||||
re_eval_output = true
|
||||
elseif param4 == "antimatter" then
|
||||
print("[alert] switching to antimatter production")
|
||||
waste_production = param4
|
||||
re_eval_output = true
|
||||
end
|
||||
else
|
||||
print("[error] got unknown packet (" .. param4 .. ")")
|
||||
end
|
||||
elseif event == "timer" and param1 == connection_timeout then
|
||||
-- haven't heard from server in 3 seconds? shutdown
|
||||
-- timer won't be restarted until next packet, so no need to do anything with it
|
||||
print("[alert] server timeout, reactor disabled")
|
||||
state.run = false
|
||||
re_eval_output = true
|
||||
end
|
||||
|
||||
-- check for control state changes
|
||||
if re_eval_output then
|
||||
re_eval_output = false
|
||||
|
||||
local run_color = 0
|
||||
if state.run then
|
||||
run_color = colors.white
|
||||
end
|
||||
|
||||
-- values are swapped, as on disables and off enables
|
||||
local waste_color
|
||||
if waste_production == "plutonium" then
|
||||
waste_color = colors.green
|
||||
elseif waste_production == "polonium" then
|
||||
waste_color = colors.cyan + colors.purple
|
||||
else
|
||||
-- antimatter (default)
|
||||
waste_color = colors.cyan + colors.magenta
|
||||
end
|
||||
|
||||
rs.setBundledOutput("right", run_color + waste_color)
|
||||
end
|
||||
|
||||
modem.transmit(DEST_PORT, listen_port, state)
|
||||
end
|
||||
13
rcass/startup.lua
Normal file
13
rcass/startup.lua
Normal file
@@ -0,0 +1,13 @@
|
||||
print(">>RCASS LOADER START<<")
|
||||
print(">>CHECKING SETTINGS...")
|
||||
loaded = settings.load("rcass.settings")
|
||||
if loaded then
|
||||
print(">>SETTINGS FOUND, VERIFIYING INTEGRITY...")
|
||||
settings.getNames()
|
||||
else
|
||||
print(">>SETTINGS NOT FOUND")
|
||||
print(">>LAUNCHING CONFIGURATOR...")
|
||||
shell.run("config")
|
||||
end
|
||||
print(">>LAUNCHING RCASS...")
|
||||
shell.run("rcass")
|
||||
Reference in New Issue
Block a user