diff --git a/baystation12.dme b/baystation12.dme
index 9ef6c90239f..4ad917169d6 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -392,6 +392,7 @@
#include "code\game\machinery\embedded_controller\airlock_controller.dm"
#include "code\game\machinery\embedded_controller\embedded_controller_base.dm"
#include "code\game\machinery\embedded_controller\simple_vent_controller.dm"
+#include "code\game\machinery\embedded_controller\smart_airlock_controller.dm"
#include "code\game\machinery\kitchen\gibber.dm"
#include "code\game\machinery\kitchen\juicer.dm"
#include "code\game\machinery\kitchen\microwave.dm"
diff --git a/code/game/machinery/embedded_controller/smart_airlock_controller.dm b/code/game/machinery/embedded_controller/smart_airlock_controller.dm
new file mode 100644
index 00000000000..3d5fe5a01ef
--- /dev/null
+++ b/code/game/machinery/embedded_controller/smart_airlock_controller.dm
@@ -0,0 +1,369 @@
+//States for airlock_control
+#define AIRLOCK_STATE_WAIT 0
+#define AIRLOCK_STATE_DEPRESSURIZE 1
+#define AIRLOCK_STATE_PRESSURIZE 2
+
+#define AIRLOCK_TARGET_INOPEN -1
+#define AIRLOCK_TARGET_NONE 0
+#define AIRLOCK_TARGET_OUTOPEN 1
+
+datum/computer/file/embedded_program/smart_airlock_controller
+ var/id_tag
+ var/tag_exterior_door
+ var/tag_interior_door
+ var/tag_airpump
+ var/tag_chamber_sensor
+ var/tag_exterior_sensor
+ var/tag_interior_sensor
+ //var/sanitize_external
+
+ state = AIRLOCK_STATE_WAIT
+ var/target_state = AIRLOCK_TARGET_NONE
+
+datum/computer/file/embedded_program/smart_airlock_controller/New()
+ ..()
+ memory["chamber_sensor_pressure"] = ONE_ATMOSPHERE
+ memory["external_sensor_pressure"] = ONE_ATMOSPHERE
+ memory["internal_sensor_pressure"] = ONE_ATMOSPHERE
+ memory["exterior_status"] = "unknown"
+ memory["interior_status"] = "unknown"
+ memory["pump_status"] = "unknown"
+ memory["target_pressure"] = ONE_ATMOSPHERE
+
+datum/computer/file/embedded_program/smart_airlock_controller/receive_signal(datum/signal/signal, receive_method, receive_param)
+ var/receive_tag = signal.data["tag"]
+ if(!receive_tag) return
+
+ if(receive_tag==tag_chamber_sensor)
+ if(signal.data["pressure"])
+ memory["chamber_sensor_pressure"] = text2num(signal.data["pressure"])
+
+ else if(receive_tag==tag_exterior_sensor)
+ if(signal.data["pressure"])
+ memory["external_sensor_pressure"] = text2num(signal.data["pressure"])
+
+ else if(receive_tag==tag_interior_sensor)
+ if(signal.data["pressure"])
+ memory["internal_sensor_pressure"] = text2num(signal.data["pressure"])
+
+ else if(receive_tag==tag_exterior_door)
+ memory["exterior_status"] = signal.data["door_status"]
+
+ else if(receive_tag==tag_interior_door)
+ memory["interior_status"] = signal.data["door_status"]
+
+ else if(receive_tag==tag_airpump)
+ if(signal.data["power"])
+ memory["pump_status"] = signal.data["direction"]
+ else
+ memory["pump_status"] = "off"
+
+ else if(receive_tag==id_tag)
+ switch(signal.data["command"])
+ if("cycle_exterior")
+ state = AIRLOCK_STATE_WAIT
+ target_state = AIRLOCK_TARGET_OUTOPEN
+ if("cycle_interior")
+ state = AIRLOCK_STATE_WAIT
+ target_state = AIRLOCK_TARGET_INOPEN
+
+ master.updateDialog()
+
+datum/computer/file/embedded_program/smart_airlock_controller/receive_user_command(command)
+ var/shutdown_pump = 0
+ switch(command)
+ if("cycle_closed")
+ state = AIRLOCK_STATE_WAIT
+ target_state = AIRLOCK_TARGET_NONE
+ if(memory["interior_status"] != "closed")
+ var/datum/signal/signal = new
+ signal.data["tag"] = tag_interior_door
+ signal.data["command"] = "secure_close"
+ post_signal(signal)
+ if(memory["exterior_status"] != "closed")
+ var/datum/signal/signal = new
+ signal.data["tag"] = tag_exterior_door
+ signal.data["command"] = "secure_close"
+ post_signal(signal)
+ shutdown_pump = 1
+ if("open_interior")
+ state = AIRLOCK_STATE_WAIT
+ target_state = AIRLOCK_TARGET_NONE
+ if(memory["interior_status"] != "open")
+ var/datum/signal/signal = new
+ signal.data["tag"] = tag_interior_door
+ signal.data["command"] = "secure_open"
+ post_signal(signal)
+ if("close_interior")
+ if(memory["interior_status"] != "closed")
+ var/datum/signal/signal = new
+ signal.data["tag"] = tag_interior_door
+ signal.data["command"] = "secure_close"
+ post_signal(signal)
+ shutdown_pump = 1
+ if("close_exterior")
+ if(memory["exterior_status"] != "closed")
+ var/datum/signal/signal = new
+ signal.data["tag"] = tag_exterior_door
+ signal.data["command"] = "secure_close"
+ post_signal(signal)
+ shutdown_pump = 1
+ if("open_exterior")
+ state = AIRLOCK_STATE_WAIT
+ target_state = AIRLOCK_TARGET_NONE
+ if(memory["exterior_status"] != "open")
+ var/datum/signal/signal = new
+ signal.data["tag"] = tag_exterior_door
+ signal.data["command"] = "secure_open"
+ post_signal(signal)
+ if("cycle_exterior")
+ state = AIRLOCK_STATE_WAIT
+ target_state = AIRLOCK_TARGET_OUTOPEN
+ if("cycle_interior")
+ state = AIRLOCK_STATE_WAIT
+ target_state = AIRLOCK_TARGET_INOPEN
+
+ if(shutdown_pump)
+ //send a signal to stop pressurizing
+ if(memory["pump_status"] != "off")
+ var/datum/signal/signal = new
+ signal.data = list(
+ "tag" = tag_airpump,
+ "power" = 0,
+ "sigtype"="command"
+ )
+ post_signal(signal)
+ master.updateDialog()
+
+datum/computer/file/embedded_program/smart_airlock_controller/process()
+ var/process_again = 1
+ while(process_again)
+ process_again = 0
+
+ if(!state && target_state)
+ //we're ready to do stuff, now what do we want to do?
+ switch(target_state)
+ if(AIRLOCK_TARGET_INOPEN)
+ memory["target_pressure"] = memory["internal_sensor_pressure"]
+ if(AIRLOCK_TARGET_OUTOPEN)
+ memory["target_pressure"] = memory["external_sensor_pressure"]
+
+ //work out whether we need to pressurize or depressurize the chamber (5% leeway with target pressure)
+ var/chamber_pressure = memory["chamber_sensor_pressure"]
+ var/target_pressure = memory["target_pressure"]
+ if(chamber_pressure <= target_pressure)
+ state = AIRLOCK_STATE_PRESSURIZE
+
+ //send a signal to start pressurizing
+ var/datum/signal/signal = new
+ signal.data = list(
+ "tag" = tag_airpump,
+ "sigtype"="command",
+ "power"=1,
+ "direction"=1,
+ "set_external_pressure"=target_pressure
+ )
+ post_signal(signal)
+
+ else if(chamber_pressure > target_pressure)
+ state = AIRLOCK_STATE_DEPRESSURIZE
+
+ //send a signal to start depressurizing
+ var/datum/signal/signal = new
+ signal.transmission_method = 1 //radio signal
+ signal.data = list(
+ "tag" = tag_airpump,
+ "sigtype"="command",
+ "power"=1,
+ "direction"=0,
+ "set_external_pressure"=target_pressure
+ )
+ post_signal(signal)
+
+ //actually do stuff
+ //override commands are handled elsewhere, otherwise everything proceeds automatically
+ switch(state)
+ if(AIRLOCK_STATE_PRESSURIZE)
+ if(memory["chamber_sensor_pressure"] >= memory["target_pressure"] * 0.95)
+ if(target_state < 0)
+ if(memory["interior_status"] != "open")
+ var/datum/signal/signal = new
+ signal.data["tag"] = tag_interior_door
+ signal.data["command"] = "secure_open"
+ post_signal(signal)
+ else if(target_state > 0)
+ if(memory["exterior_status"] != "open")
+ var/datum/signal/signal = new
+ signal.data["tag"] = tag_exterior_door
+ signal.data["command"] = "secure_open"
+ post_signal(signal)
+ state = AIRLOCK_STATE_WAIT
+ target_state = AIRLOCK_TARGET_NONE
+
+ //send a signal to stop pumping
+ if(memory["pump_status"] != "off")
+ var/datum/signal/signal = new
+ signal.data = list(
+ "tag" = tag_airpump,
+ "sigtype"="command",
+ "power" = 0
+ )
+ post_signal(signal)
+ master.updateDialog()
+
+ if(AIRLOCK_STATE_DEPRESSURIZE)
+ if(memory["chamber_sensor_pressure"] <= memory["target_pressure"] * 1.05)
+ if(target_state > 0)
+ if(memory["exterior_status"] != "open")
+ var/datum/signal/signal = new
+ signal.data["tag"] = tag_exterior_door
+ signal.data["command"] = "secure_open"
+ post_signal(signal)
+ else if(target_state < 0)
+ if(memory["interior_status"] != "open")
+ var/datum/signal/signal = new
+ signal.data["tag"] = tag_interior_door
+ signal.data["command"] = "secure_open"
+ post_signal(signal)
+ state = AIRLOCK_STATE_WAIT
+ target_state = AIRLOCK_TARGET_NONE
+
+ //send a signal to stop pumping
+ if(memory["pump_status"] != "off")
+ var/datum/signal/signal = new
+ signal.data = list(
+ "tag" = tag_airpump,
+ "sigtype"="command",
+ "power" = 0
+ )
+ post_signal(signal)
+ master.updateDialog()
+
+ //memory["sensor_pressure"] = sensor_pressure
+ memory["processing"] = state != target_state
+ //sensor_pressure = null //not sure if we can comment this out. Uncomment in case of problems -rastaf0
+
+ return 1
+
+
+obj/machinery/embedded_controller/radio/smart_airlock_controller
+ icon = 'icons/obj/airlock_machines.dmi'
+ icon_state = "airlock_control_standby"
+
+ name = "Cycling Airlock Console"
+ density = 0
+
+ frequency = 1449
+ power_channel = ENVIRON
+
+ // Setup parameters only
+ var/id_tag
+ var/tag_exterior_door
+ var/tag_interior_door
+ var/tag_airpump
+ var/tag_chamber_sensor
+ var/tag_exterior_sensor
+ var/tag_interior_sensor
+ //var/sanitize_external
+
+ initialize()
+ ..()
+
+ var/datum/computer/file/embedded_program/smart_airlock_controller/new_prog = new
+
+ new_prog.id_tag = id_tag
+ new_prog.tag_exterior_door = tag_exterior_door
+ new_prog.tag_interior_door = tag_interior_door
+ new_prog.tag_airpump = tag_airpump
+ new_prog.tag_chamber_sensor = tag_chamber_sensor
+ new_prog.tag_exterior_sensor = tag_exterior_sensor
+ new_prog.tag_interior_sensor = tag_interior_sensor
+ //new_prog.sanitize_external = sanitize_external
+
+ new_prog.master = src
+ program = new_prog
+
+ update_icon()
+ if(on && program)
+ if(program.memory["processing"])
+ icon_state = "airlock_control_process"
+ else
+ icon_state = "airlock_control_standby"
+ else
+ icon_state = "airlock_control_off"
+
+
+ return_text()
+ var/state_options = ""
+
+ var/state = 0
+ var/chamber_sensor_pressure = "----"
+ var/external_sensor_pressure = "----"
+ var/internal_sensor_pressure = "----"
+ var/exterior_status = "----"
+ var/interior_status = "----"
+ var/pump_status = "----"
+ var/target_pressure = "----"
+ if(program)
+ state = program.state
+ chamber_sensor_pressure = program.memory["chamber_sensor_pressure"]
+ external_sensor_pressure = program.memory["external_sensor_pressure"]
+ internal_sensor_pressure = program.memory["internal_sensor_pressure"]
+ exterior_status = program.memory["exterior_status"]
+ interior_status = program.memory["interior_status"]
+ pump_status = program.memory["pump_status"]
+ target_pressure = program.memory["target_pressure"]
+
+ var/exterior_closed = 0
+ if(exterior_status == "closed")
+ exterior_closed = 1
+ var/interior_closed = 0
+ if(interior_status == "closed")
+ interior_closed = 1
+
+ state_options += "Exterior status: [exterior_status] ([external_sensor_pressure] kPa)
"
+ if(exterior_closed)
+ state_options += "Open exterior airlock "
+ if(abs(chamber_sensor_pressure - external_sensor_pressure) > ONE_ATMOSPHERE * 0.05)
+ state_options += "WARNING"
+ state_options += "
"
+ if(!state && exterior_closed && interior_closed)
+ state_options += "Cycle to Exterior Airlock
"
+ else
+ state_options += "
"
+ else
+ state_options += "Close exterior airlock
"
+ state_options += "
"
+
+ state_options += "Interior status: [interior_status] ([internal_sensor_pressure] kPa)
"
+ if(interior_closed)
+ state_options += "Open interior airlock "
+ if(abs(chamber_sensor_pressure - internal_sensor_pressure) > ONE_ATMOSPHERE * 0.05)
+ state_options += "WARNING"
+ state_options += "
"
+ if(!state && exterior_closed && interior_closed)
+ state_options += "Cycle to Interior Airlock
"
+ else
+ state_options += "
"
+ else
+ state_options += "Close interior airlock
"
+ state_options += "
"
+
+ state_options += "
"
+ state_options += "Chamber Pressure: [chamber_sensor_pressure] kPa
"
+ state_options += "Target Chamber Pressure: [target_pressure] kPa
"
+ state_options += "Control Pump: [pump_status]
"
+ if(state)
+ state_options += "Abort Cycling
"
+ else
+ state_options += "
"
+
+ return state_options
+
+#undef AIRLOCK_STATE_PRESSURIZE
+#undef AIRLOCK_STATE_WAIT
+#undef AIRLOCK_STATE_DEPRESSURIZE
+
+#undef AIRLOCK_TARGET_INOPEN
+#undef AIRLOCK_TARGET_CLOSED
+#undef AIRLOCK_TARGET_OUTOPEN