258 lines
6.9 KiB
C#
258 lines
6.9 KiB
C#
enum AirlockState {
|
|
Off,
|
|
DoorsClosing,
|
|
Cycling,
|
|
DoorOpening,
|
|
Cooldown,
|
|
}
|
|
|
|
enum AirlockLightState {
|
|
Off,
|
|
Cycling,
|
|
Cooldown,
|
|
Error,
|
|
}
|
|
|
|
string airlockName;
|
|
IEnumerator<bool> state;
|
|
float targetOxygenLevel = 0.0F;
|
|
|
|
// Blocks we need to track
|
|
IMyDoor innerDoor;
|
|
IMyDoor outerDoor;
|
|
List<IMyLightingBlock> lights;
|
|
IMyAirVent airVent;
|
|
IMyAirVent airSensor; // TODO: we don't use this yet
|
|
IMyGasTank oxygenTank;
|
|
|
|
public Program()
|
|
{
|
|
airlockName = Me.CustomName.Split(' ')[0];
|
|
state = null;
|
|
|
|
// Find the correct objects
|
|
InitDoors();
|
|
InitVents();
|
|
InitLights();
|
|
InitOxygen();
|
|
}
|
|
|
|
private void InitDoors() {
|
|
List<IMyDoor> onlyDoors = new List<IMyDoor>();
|
|
GridTerminalSystem.GetBlocksOfType(onlyDoors);
|
|
foreach (IMyDoor door in onlyDoors) {
|
|
if (door.CustomName.StartsWith(airlockName)) {
|
|
if (door.CustomName.Contains("Inner")) {
|
|
innerDoor = door;
|
|
}
|
|
else if (door.CustomName.Contains("Outer")) {
|
|
outerDoor = door;
|
|
}
|
|
}
|
|
|
|
if (innerDoor != null && outerDoor != null) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void InitVents() {
|
|
List<IMyAirVent> onlyFans = new List<IMyAirVent>();
|
|
GridTerminalSystem.GetBlocksOfType(onlyFans);
|
|
foreach (IMyAirVent vent in onlyFans) {
|
|
if (vent.CustomName.StartsWith(airlockName)) {
|
|
if (vent.CustomName.Contains("Main")) {
|
|
airVent = vent;
|
|
}
|
|
else if (vent.CustomName.Contains("Reference")) {
|
|
airSensor = vent;
|
|
}
|
|
}
|
|
|
|
// A global reference vent will be used if we don't have one specific to our airlock.
|
|
// A specific vent found later will overwrite this assignment.
|
|
if(vent.CustomName.StartsWith("Airlock Reference") && airSensor == null) {
|
|
airSensor = vent;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void InitLights() {
|
|
lights = new List<IMyLightingBlock>();
|
|
List<IMyLightingBlock> allLights = new List<IMyLightingBlock>();
|
|
GridTerminalSystem.GetBlocksOfType(allLights);
|
|
foreach (IMyLightingBlock light in allLights) {
|
|
if (light.CustomName.StartsWith(airlockName)) {
|
|
lights.Add(light);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void InitOxygen() {
|
|
List<IMyGasTank> allTanks = new List<IMyGasTank>();
|
|
GridTerminalSystem.GetBlocksOfType(allTanks);
|
|
foreach (IMyGasTank tank in allTanks) {
|
|
if (tank.CustomName.StartsWith(airlockName)) {
|
|
oxygenTank = tank;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Main(string argument, UpdateType updateSource)
|
|
{
|
|
if (state == null) {
|
|
state = CycleAirlock();
|
|
Runtime.UpdateFrequency = UpdateFrequency.Update1;
|
|
return;
|
|
}
|
|
|
|
if (!state.MoveNext()) {
|
|
state.Dispose();
|
|
state = null;
|
|
Runtime.UpdateFrequency = UpdateFrequency.None;
|
|
}
|
|
}
|
|
|
|
private IEnumerator<bool> CycleAirlock() {
|
|
SetLights(AirlockLightState.Cycling);
|
|
|
|
CloseDoors();
|
|
while(!DoorsClosed()) { yield return true; }
|
|
LockDoors();
|
|
|
|
if (!airVent.CanPressurize) {
|
|
Error("Airlock is not airtight.");
|
|
yield return false;
|
|
}
|
|
|
|
PressurizeDepressurize();
|
|
while(!PressureStabilized()) { yield return true; }
|
|
airVent.Enabled = false;
|
|
|
|
OpenDoor();
|
|
while(!DoorOpened()) { yield return true; }
|
|
LockDoors();
|
|
|
|
// Balance oxygen storage
|
|
SetLights(AirlockLightState.Cooldown);
|
|
if (BalanceOxygen()) {
|
|
while(!OxygenBalanced()) { yield return true; }
|
|
}
|
|
airVent.Enabled = false;
|
|
|
|
// Cooldown period
|
|
Runtime.UpdateFrequency = UpdateFrequency.Update100;
|
|
yield return true;
|
|
Runtime.UpdateFrequency = UpdateFrequency.Update1;
|
|
|
|
SetLights(AirlockLightState.Off);
|
|
}
|
|
|
|
private void CloseDoors() {
|
|
Echo("DEBUG: Closing Doors");
|
|
|
|
// close the doors
|
|
innerDoor.Enabled = true;
|
|
outerDoor.Enabled = true;
|
|
innerDoor.CloseDoor();
|
|
outerDoor.CloseDoor();
|
|
}
|
|
|
|
private bool DoorsClosed() {
|
|
return innerDoor.Status == DoorStatus.Closed && outerDoor.Status == DoorStatus.Closed;
|
|
}
|
|
|
|
private void PressurizeDepressurize() {
|
|
Echo("DEBUG: Cycling");
|
|
|
|
// toggle the current state
|
|
airVent.Depressurize = !airVent.Depressurize;
|
|
airVent.Enabled = true;
|
|
|
|
// When depressurizing, check the external pressure and only depressurize to that value.
|
|
// TODO: test this for floating point errors
|
|
if (airVent.Depressurize && airSensor != null) {
|
|
targetOxygenLevel = airSensor.GetOxygenLevel();
|
|
Echo($"Set depressurization target to {targetOxygenLevel}");
|
|
}
|
|
}
|
|
|
|
// TODO: this should check for depressurizing to the *reference* amount
|
|
private bool PressureStabilized() {
|
|
return ((airVent.Depressurize && airVent.GetOxygenLevel() <= targetOxygenLevel) ||
|
|
(!airVent.Depressurize && airVent.Status == VentStatus.Pressurized));
|
|
}
|
|
|
|
// Open the appropriate door based on pressure state.
|
|
private void OpenDoor() {
|
|
Echo("DEBUG: Opening Door");
|
|
|
|
if (airVent.Status == VentStatus.Pressurized) {
|
|
innerDoor.Enabled = true;
|
|
innerDoor.OpenDoor();
|
|
} else {
|
|
outerDoor.Enabled = true;
|
|
outerDoor.OpenDoor();
|
|
}
|
|
}
|
|
|
|
private bool DoorOpened() {
|
|
return innerDoor.Status == DoorStatus.Open || outerDoor.Status == DoorStatus.Open;
|
|
}
|
|
|
|
// Returns false if we are in a state where we can't or don't need to balance
|
|
private bool BalanceOxygen() {
|
|
if (innerDoor.Status == DoorStatus.Closed || outerDoor.Status == DoorStatus.Open || OxygenBalanced()) { return false; }
|
|
|
|
Echo("DEBUG: Balancing Oxygen Tank");
|
|
|
|
// Configure the vent to suck in Oxygen.
|
|
airVent.Depressurize = true;
|
|
airVent.Enabled = true;
|
|
return true;
|
|
}
|
|
|
|
private bool OxygenBalanced() {
|
|
return oxygenTank.FilledRatio > 0.25;
|
|
}
|
|
|
|
// TODO: blinkenlights are unsatisfying right now...
|
|
private void SetLights(AirlockLightState lightState) {
|
|
float blinkLength = 1.0F;
|
|
float blinkInterval = 0.0F;
|
|
Color color = Color.Red;
|
|
|
|
switch(lightState) {
|
|
case AirlockLightState.Off:
|
|
color = Color.Green;
|
|
break;
|
|
case AirlockLightState.Cycling:
|
|
blinkInterval = 1.0F;
|
|
blinkLength = 0.75F;
|
|
break;
|
|
case AirlockLightState.Cooldown:
|
|
color = Color.Yellow;
|
|
break;
|
|
case AirlockLightState.Error:
|
|
// the defaults already set this correctly
|
|
break;
|
|
}
|
|
|
|
foreach (IMyLightingBlock light in lights) {
|
|
light.Enabled = true;
|
|
light.BlinkIntervalSeconds = blinkInterval;
|
|
light.BlinkLength = blinkLength;
|
|
light.Color = color;
|
|
}
|
|
}
|
|
|
|
private void LockDoors() {
|
|
innerDoor.Enabled = false;
|
|
outerDoor.Enabled = false;
|
|
}
|
|
|
|
private void Error(string error) {
|
|
Echo(error);
|
|
SetLights(AirlockLightState.Error);
|
|
} |