mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
reactor control and safety system attempting server connection
This commit is contained in:
parent
0dac25d9e7
commit
26cce3a46a
157
common/comms.lua
Normal file
157
common/comms.lua
Normal file
@ -0,0 +1,157 @@
|
||||
|
||||
function server_comms()
|
||||
local self = {
|
||||
reactor_struct_cache = nil
|
||||
}
|
||||
|
||||
local record_struct = function (id, mek_data)
|
||||
end
|
||||
|
||||
-- send the structure data by request to pocket computers
|
||||
local send_struct = function ()
|
||||
end
|
||||
|
||||
local command_waste = function ()
|
||||
end
|
||||
end
|
||||
|
||||
function rcass_comms(id, modem, local_port, server_port, reactor)
|
||||
local self = {
|
||||
_id = id,
|
||||
_modem = modem,
|
||||
_server = server_port,
|
||||
_local = local_port,
|
||||
_reactor = reactor,
|
||||
_status_cache = nil,
|
||||
|
||||
_send = function (msg)
|
||||
self._modem.transmit(self._server, self._local, msg)
|
||||
end
|
||||
}
|
||||
|
||||
local _send = function (msg)
|
||||
self._modem.transmit(self._server, self._local, msg)
|
||||
end
|
||||
|
||||
-- variable reactor status information, excluding heating rate
|
||||
local _reactor_status = function ()
|
||||
return {
|
||||
status = self._reactor.getStatus(),
|
||||
burn_rate = self._reactor.getBurnRate(),
|
||||
act_burn_r = self._reactor.getActualBurnRate(),
|
||||
temp = self._reactor.getTemperature(),
|
||||
damage = self._reactor.getDamagePercent(),
|
||||
boil_eff = self._reactor.getBoilEfficiency(),
|
||||
env_loss = self._reactor.getEnvironmentalLoss(),
|
||||
|
||||
fuel = self._reactor.getFuel(),
|
||||
fuel_need = self._reactor.getFuelNeeded(),
|
||||
fuel_fill = self._reactor.getFuelFilledPercentage(),
|
||||
waste = self._reactor.getWaste(),
|
||||
waste_need = self._reactor.getWasteNeeded(),
|
||||
waste_fill = self._reactor.getWasteFilledPercentage(),
|
||||
cool_type = self._reactor.getCoolant()['name'],
|
||||
cool_amnt = self._reactor.getCoolant()['amount'],
|
||||
cool_need = self._reactor.getCoolantNeeded(),
|
||||
cool_fill = self._reactor.getCoolantFilledPercentage(),
|
||||
hcool_type = self._reactor.getHeatedCoolant()['name'],
|
||||
hcool_amnt = self._reactor.getHeatedCoolant()['amount'],
|
||||
hcool_need = self._reactor.getHeatedCoolantNeeded(),
|
||||
hcool_fill = self._reactor.getHeatedCoolantFilledPercentage()
|
||||
}
|
||||
end
|
||||
|
||||
local _status_changed = function ()
|
||||
local status = self._reactor_status()
|
||||
local changed = false
|
||||
|
||||
for key, value in pairs() do
|
||||
if value ~= _status_cache[key] then
|
||||
changed = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return changed
|
||||
end
|
||||
|
||||
-- attempt to establish link with
|
||||
local send_link_req = function ()
|
||||
local linking_data = {
|
||||
id = self._id,
|
||||
type = "link_req"
|
||||
}
|
||||
|
||||
_send(linking_data)
|
||||
end
|
||||
|
||||
-- send structure properties (these should not change)
|
||||
-- server will cache these
|
||||
local send_struct = function ()
|
||||
local mek_data = {
|
||||
heat_cap = self._reactor.getHeatCapacity(),
|
||||
fuel_asm = self._reactor.getFuelAssemblies(),
|
||||
fuel_sa = self._reactor.getFuelSurfaceArea(),
|
||||
fuel_cap = self._reactor.getFuelCapacity(),
|
||||
waste_cap = self._reactor.getWasteCapacity(),
|
||||
cool_cap = self._reactor.getCoolantCapacity(),
|
||||
hcool_cap = self._reactor.getHeatedCoolantCapacity(),
|
||||
max_burn = self._reactor.getMaxBurnRate()
|
||||
}
|
||||
|
||||
local struct_packet = {
|
||||
id = self._id,
|
||||
type = "struct_data",
|
||||
mek_data = mek_data
|
||||
}
|
||||
|
||||
_send(struct_packet)
|
||||
end
|
||||
|
||||
-- send live status information
|
||||
local send_status = function ()
|
||||
local mek_data = self._reactor_status()
|
||||
|
||||
local sys_data = {
|
||||
timestamp = os.time(),
|
||||
control_state = false,
|
||||
overridden = false,
|
||||
faults = {},
|
||||
waste_production = "antimatter" -- "plutonium", "polonium", "antimatter"
|
||||
}
|
||||
end
|
||||
|
||||
local send_keep_alive = function ()
|
||||
-- heating rate is volatile, so it is skipped in status
|
||||
-- send it with keep alive packets
|
||||
local mek_data = {
|
||||
heating_rate = self._reactor.getHeatingRate()
|
||||
}
|
||||
|
||||
-- basic keep alive packet to server
|
||||
local keep_alive_packet = {
|
||||
id = self._id,
|
||||
type = "keep_alive",
|
||||
timestamp = os.time(),
|
||||
mek_data = mek_data
|
||||
}
|
||||
|
||||
_send(keep_alive_packet)
|
||||
end
|
||||
|
||||
local handle_link = function (packet)
|
||||
if packet.type == "link_response" then
|
||||
return packet.accepted
|
||||
else
|
||||
return "wrong_type"
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
send_link_req = send_link_req,
|
||||
send_struct = send_struct,
|
||||
send_status = send_status,
|
||||
send_keep_alive = send_keep_alive,
|
||||
handle_link = handle_link
|
||||
}
|
||||
end
|
29
common/util.lua
Normal file
29
common/util.lua
Normal file
@ -0,0 +1,29 @@
|
||||
-- timestamped print
|
||||
function print_ts(message)
|
||||
term.write(os.date("[%H:%M:%S] ") .. message)
|
||||
end
|
||||
|
||||
-- ComputerCraft OS Timer based Watchdog
|
||||
-- triggers a timer event if not fed within 'timeout' seconds
|
||||
function new_watchdog(timeout)
|
||||
local self = {
|
||||
_timeout = timeout,
|
||||
_wd_timer = os.startTimer(_timeout)
|
||||
}
|
||||
|
||||
local get_timer = function ()
|
||||
return self._wd_timer
|
||||
end
|
||||
|
||||
local feed = function ()
|
||||
if self._wd_timer ~= nil then
|
||||
os.cancelTimer(self._wd_timer)
|
||||
end
|
||||
self._wd_timer = os.startTimer(self._timeout)
|
||||
end
|
||||
|
||||
return {
|
||||
get_timer = get_timer,
|
||||
feed = feed
|
||||
}
|
||||
end
|
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
|
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")
|
Loading…
Reference in New Issue
Block a user