diff --git a/CMakeLists.txt b/CMakeLists.txt
index 364e85a473b1dd70bf690c96f56da001d9ea6b26..af8ca29bda7815bc59318047f6106c6c0ebcaade 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,6 +9,7 @@ find_package(OpenSSL REQUIRED)
 pkg_check_modules(MULTIPLEXER REQUIRED eismuliplexer)
 pkg_check_modules(COINCELLHELL REQUIRED libcoincellhell)
 pkg_check_modules(EISGEN REQUIRED libeisgenerator)
+pkg_check_modules(READLINE readline)
 
 if(WIN32)
 	set(COINCELLHELL_LIBRARIES -lws2_32 -L/home/philipp/programing/kiss/coincellhell/libcoincellhell/build-w64/ -l:libcoincellhell.dll.a)
@@ -34,6 +35,7 @@ set(SRC_FILES
 	multiplexers.cpp
 	heater.cpp
 	coincell.cpp
+	coincells.cpp
 	biocontrol.cpp
 	tokenize.cpp
 	expirament.cpp
@@ -47,3 +49,27 @@ target_include_directories(${PROJECT_NAME} PUBLIC ${MULTIPLEXER_INCLUDE_DIRS}
 	${SERIALPORT_INCLUDE_DIRS} ${COINCELLHELL_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIRS} ${EISGEN_LIBRARIES_INCLUDE_DIRS})
 target_compile_definitions(${PROJECT_NAME} PUBLIC SMTP_OPENSSL)
 install(TARGETS ${PROJECT_NAME} DESTINATION bin)
+
+
+if(READLINE_FOUND)
+	message("Readline found, will build testing application")
+	set(SRC_FILES_TEST
+		test.cpp
+		log.cpp
+		multiplexers.cpp
+		smtp/smtp.c
+		smtp/SMTPMail.cpp
+		biocontrol.cpp
+		vcpps.cpp
+		heater.cpp
+		coincell.cpp
+		coincells.cpp
+		tokenize.cpp
+		randomgen.cpp)
+	add_executable(${PROJECT_NAME}_test ${SRC_FILES_TEST})
+	target_link_libraries(${PROJECT_NAME}_test ${READLINE_LIBRARIES} ${MULTIPLEXER_LIBRARIES} ${SERIALPORT_LIBRARIES}
+		${COINCELLHELL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EISGEN_LIBRARIES})
+	target_include_directories(${PROJECT_NAME}_test PUBLIC ${READLINE_INCLUDE_DIRS} ${MULTIPLEXER_INCLUDE_DIRS}
+		${SERIALPORT_INCLUDE_DIRS} ${COINCELLHELL_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIRS} ${EISGEN_LIBRARIES_INCLUDE_DIRS})
+	target_compile_definitions(${PROJECT_NAME}_test PUBLIC SMTP_OPENSSL)
+endif(READLINE_FOUND)
diff --git a/coincells.cpp b/coincells.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e7c45851b9ed7df52b586aba43df44e4b425aa6c
--- /dev/null
+++ b/coincells.cpp
@@ -0,0 +1,62 @@
+#include "coincells.h"
+
+#include "log.h"
+
+std::vector<std::unique_ptr<CoinCell>> asign_coincells(std::vector<uint16_t> cellids, Heaters* heaters, Multiplexers* multiplexers)
+{
+	CoinCell cell(heaters, multiplexers, 0, {3});
+	std::vector<std::unique_ptr<CoinCell>> coinCells;
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 0, std::vector<int>({3, 10})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 1, std::vector<int>({2, 9})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 2, std::vector<int>({1, 8})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 3, std::vector<int>({0, 7})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 4, std::vector<int>({6, 13})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 5, std::vector<int>({5, 12})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 6, std::vector<int>({4, 11})));
+
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 8, std::vector<int>({24, 17})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 9, std::vector<int>({23, 16})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 10, std::vector<int>({22, 15})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 11, std::vector<int>({21, 14})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 12, std::vector<int>({27, 20})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 13, std::vector<int>({26, 19})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 14, std::vector<int>({25, 18})));
+
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 16, std::vector<int>({31})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 17, std::vector<int>({30})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 18, std::vector<int>({29})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 19, std::vector<int>({28})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 20, std::vector<int>({34})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 21, std::vector<int>({33})));
+	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 22, std::vector<int>({32})));
+
+	if(!cellids.empty())
+	{
+		for(ssize_t i = coinCells.size()-1; i >= 0; --i)
+		{
+			auto search = std::find(cellids.begin(), cellids.end(), i);
+			if(search == cellids.end())
+				coinCells.erase(coinCells.begin()+i);
+		}
+	}
+
+	Log(Log::INFO)<<"Connections:";
+	for(std::unique_ptr<CoinCell>& cell : coinCells)
+	{
+		int heater = cell->getHeaterId();
+		const std::vector<int>& muliplexerchs = cell->getMulitplexerChannels();
+
+		std::pair<int, int> heaterAddr = heaters->getAddress(heater);
+
+		Log(Log::INFO, false)<<"CoincellHell "<<heaterAddr.first<<" unit "<<heaterAddr.second<<" is connected to: ";
+
+		for(int id : muliplexerchs)
+		{
+			std::pair<int, channel_t> addr = multiplexers->getAddress(id);
+			Log(Log::INFO, false, false)<<" Mulitplexer "<<addr.first<<" channel "<<Multiplexers::chToString(addr.second)<<", ";
+		}
+		Log(Log::INFO, false)<<'\n';
+	}
+
+	return coinCells;
+}
diff --git a/coincells.h b/coincells.h
new file mode 100644
index 0000000000000000000000000000000000000000..668cc05087620e410aaa9713b69454e8fab96086
--- /dev/null
+++ b/coincells.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "coincell.h"
+#include "multiplexers.h"
+#include "heaters.h"
+
+std::vector<std::unique_ptr<CoinCell>> asign_coincells(std::vector<uint16_t> cellids, Heaters* heaters, Multiplexers* multiplexers);
diff --git a/log.cpp b/log.cpp
index 285016010859c8984bdfc37a5d20a91feef7d82a..f59aa2e213a21df247124baa05f9f9b010ef10c7 100644
--- a/log.cpp
+++ b/log.cpp
@@ -19,6 +19,7 @@
 
 #include "log.h"
 #include "smtp/smtp.h"
+#include <cassert>
 
 Log::Log()
 {
@@ -77,6 +78,9 @@ std::string Log::getLabel(Level level)
 		case ERROR: 
 			label = "ERROR"; 
 			break;
+		case NEVER:
+			assert(false);
+			break;
 	}
 	return label;
 }
diff --git a/log.h b/log.h
index 73f971feec689b065b63740d6a778083d477f65e..695a841833fa39099441119aaf78acedade8d819 100644
--- a/log.h
+++ b/log.h
@@ -34,7 +34,8 @@ public:
 		DEBUG,
 		INFO,
 		WARN,
-		ERROR
+		ERROR,
+		NEVER
 	};
 
 private:
diff --git a/main.cpp b/main.cpp
index 786ffb74d0e22b97b52fe0d74a24905e53d8ecc8..a1a4612e02fd879f487378c81f4d27e80d68f402 100644
--- a/main.cpp
+++ b/main.cpp
@@ -13,8 +13,10 @@
 #include <sys/stat.h>
 #include <fstream>
 
+
 #include "biocontrol.h"
 #include "coincell.h"
+#include "coincells.h"
 #include "log.h"
 #include "heaters.h"
 #include "multiplexers.h"
@@ -171,65 +173,6 @@ bool listSerialPorts()
 	return true;
 }
 
-std::vector<std::unique_ptr<CoinCell>> asign_coincells(std::vector<uint16_t> cellids, Heaters* heaters, Multiplexers* multiplexers)
-{
-	CoinCell cell(heaters, multiplexers, 0, {3});
-	std::vector<std::unique_ptr<CoinCell>> coinCells;
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 0, std::vector<int>({3, 10})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 1, std::vector<int>({2, 9})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 2, std::vector<int>({1, 8})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 3, std::vector<int>({0, 7})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 4, std::vector<int>({6, 13})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 5, std::vector<int>({5, 12})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 6, std::vector<int>({4, 11})));
-
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 8, std::vector<int>({24, 17})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 9, std::vector<int>({23, 16})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 10, std::vector<int>({22, 15})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 11, std::vector<int>({21, 14})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 12, std::vector<int>({27, 20})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 13, std::vector<int>({26, 19})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 14, std::vector<int>({25, 18})));
-
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 16, std::vector<int>({31})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 17, std::vector<int>({30})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 18, std::vector<int>({29})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 19, std::vector<int>({28})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 20, std::vector<int>({34})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 21, std::vector<int>({33})));
-	coinCells.push_back(std::make_unique<CoinCell>(heaters, multiplexers, 22, std::vector<int>({32})));
-
-	if(!cellids.empty())
-	{
-		for(ssize_t i = coinCells.size()-1; i >= 0; --i)
-		{
-			auto search = std::find(cellids.begin(), cellids.end(), i);
-			if(search == cellids.end())
-				coinCells.erase(coinCells.begin()+i);
-		}
-	}
-
-	Log(Log::INFO)<<"Connections:";
-	for(std::unique_ptr<CoinCell>& cell : coinCells)
-	{
-		int heater = cell->getHeaterId();
-		const std::vector<int>& muliplexerchs = cell->getMulitplexerChannels();
-
-		std::pair<int, int> heaterAddr = heaters->getAddress(heater);
-
-		Log(Log::INFO, false)<<"CoincellHell "<<heaterAddr.first<<" unit "<<heaterAddr.second<<" is connected to: ";
-
-		for(int id : muliplexerchs)
-		{
-			std::pair<int, channel_t> addr = multiplexers->getAddress(id);
-			Log(Log::INFO, false, false)<<" Mulitplexer "<<addr.first<<" channel "<<Multiplexers::chToString(addr.second)<<", ";
-		}
-		Log(Log::INFO, false)<<'\n';
-	}
-
-	return coinCells;
-}
-
 int main(int argc, char** argv)
 {
 	umask(0);
diff --git a/test.cpp b/test.cpp
index 6f2d1ef812a7c479cf39c7d5730396203b6adc99..a38ace51a71437cd657bf0da2fc7ffd967eeee6c 100644
--- a/test.cpp
+++ b/test.cpp
@@ -1,45 +1,195 @@
 #include <thread>
+#include <readline/readline.h>
+#include <readline/history.h>
 
+#include "coincell.h"
 #include "log.h"
+#include "options.h"
 
-static void logThread()
+#include "tokenize.h"
+#include "vcpps.h"
+#include "heaters.h"
+#include "multiplexers.h"
+#include "coincells.h"
+#include "startupfailure.h"
+
+void devicefailed(Vcpps& psu, int device, uint16_t serial, int code)
 {
-	static int a = 42;
+	std::stringstream ss;
+	Log(Log::WARN)<<"Heater device "<<device<<" with serial number "<<serial<<" has "
+	<<(code == Heaters::ERR_RECOVERED ? "recovered" : "failed")<<" with code "<<code;
+}
 
-	while(true)
-	{
-		Log(Log::INFO)<<"DEBUG"<<' '<<++a;
-		std::this_thread::sleep_for(std::chrono::microseconds(10));
-	}
+void heaterfailed(int heater, int device)
+{
+	Log(Log::WARN)<<"Heater "<<heater<<" on device "<<device<<" has failed";
 }
 
-static void logThreadTwo()
+bool preparePsu(Vcpps* psu, float voltage, float current)
 {
-	static unsigned int a = 0;
+	Vcpps::Status status;
+	Log(Log::INFO)<<"Setting psu voltage to "<<voltage;
+	bool ret = psu->setVoltage(voltage);
+	if(!ret)
+	{
+		Log(Log::ERROR)<<"Unable to set psu voltage";
+		return false;
+	}
+	Log(Log::INFO)<<"Setting psu current to "<<current;
+	ret = psu->setCurrent(current);
+	if(!ret)
+	{
+		Log(Log::ERROR)<<"Unable to set psu current";
+		return false;
+	}
+	ret = psu->setEnabled(true);
+	if(!ret)
+	{
+		Log(Log::ERROR)<<"Unable to enable psu output";
+		return false;
+	}
 
+	Log(Log::INFO)<<"Waiting for psu to stablize";
+	std::this_thread::sleep_for(std::chrono::seconds(2));
 
-	while(true)
+	ret = psu->getStatus(status);
+	if(!ret || status.curent_limited)
 	{
-		a+=2;
-		Log(Log::INFO)<<"DEBUG 2"<<' '<<a;
-		std::this_thread::sleep_for(std::chrono::microseconds(1));
+		Log(Log::ERROR)<<"Psu is overcurrent, abort";
+		psu->setEnabled(false);
+		return false;
 	}
+
+	Log(Log::INFO)<<"PSU voltage: "<<status.voltage<<" current: "<<status.current
+	<<" is currently "<<(status.curent_limited ? "" : "not")<<" current limited";
+	return true;
+}
+
+void print_cmd_help(const std::string& line)
+{
+	Log(Log::INFO)<<line<<" is not a valid command. Valid commands: connect (c), disconnect (d), set (s), get (g), clear."<<
+		"all commands except clear require a number containing the id of the coincell after the command";
 }
 
-int main()
+int main(int argc, char** argv)
 {
 	Log::level = Log::INFO;
+	Log::sendmailLevel = Log::NEVER;
+	Log::headers = false;
 
-	Log(Log::INFO)<<"Starting thread";
+	Config config;
+	argp_parse(&argp, argc, argv, 0, 0, &config);
 
-	std::thread threadA(logThread);
-	std::thread threadB(logThreadTwo);
+	try
+	{
+		Log(Log::INFO)<<"Geting PSU";
+		Vcpps psu(config.psuPort);
+		psu.setEnabled(false);
+
+		Log(Log::INFO)<<"Aquireing heaters and multiplexers";
+		Heaters heaters(config.heaterSerials,
+						[&psu](int device, uint16_t serial, int code){devicefailed(psu, device, serial, code);},
+						&heaterfailed);
+		Multiplexers multiplexers(config.multiplexerSerials);
+
+		std::vector<std::unique_ptr<CoinCell>> coinCells = asign_coincells(config.cells, &heaters, &multiplexers);
+
+		bool ret = preparePsu(&psu, 10, 10);
+		if(!ret)
+			return 2;
+
+		while(true)
+		{
+			std::string line = std::string(readline("> "));
+
+			if(line.empty())
+				continue;
+
+			std::vector<std::string> tokens = tokenize(line, ' ');
 
-	while(true)
+			int coincellId = 0;
+
+			if(tokens.size() < 2 && tokens[0] != "clear")
+			{
+				print_cmd_help(line);
+				continue;
+			}
+			else if(tokens[0] != "clear" && tokens[0] != "get" && tokens.size() >= 2)
+			{
+				coincellId = std::stol(tokens[1]);
+				if(coincellId < 0 || coincellId > coinCells.size())
+					Log(Log::ERROR)<<"Invalid coin cell id: "<<tokens[1];
+			}
+			else if(tokens.size() < 2 && tokens[0] != "clear" && tokens[0] != "get")
+			{
+				print_cmd_help(line);
+			}
+
+			if(tokens[0] == "connect" || tokens[0] == "c")
+			{
+				bool ret = coinCells[coincellId]->setConnected(true);
+				if(!ret)
+					Log(Log::ERROR)<<"unable to connect coin cell "<<coincellId;
+				else
+					Log(Log::ERROR)<<"connected coin cell "<<coincellId;
+			}
+			else if(tokens[0] == "disconnect" || tokens[0] == "d")
+			{
+				bool ret = coinCells[coincellId]->setConnected(false);
+				if(!ret)
+					Log(Log::ERROR)<<"unable to disconnect coin cell "<<coincellId;
+				else
+					Log(Log::ERROR)<<"disconnected coin cell "<<coincellId;
+			}
+			else if(tokens[0] == "set" || tokens[0] == "s")
+			{
+				if(tokens.size() < 3)
+				{
+					Log(Log::ERROR)<<"This command requires a temperature";
+					continue;
+				}
+
+				float temperature = std::stod(tokens[2]);
+				if(temperature < 10 || temperature > 100)
+				{
+					Log(Log::ERROR)<<"Temperature "<<tokens[2]<<" is invalid";
+					continue;
+				}
+				coinCells[coincellId]->setEnabled(true);
+				coinCells[coincellId]->setTemperature(temperature);
+
+			}
+			else if(tokens[0] == "get" || tokens[0] == "g")
+			{
+				for(size_t i = 0; i < coinCells.size(); ++i)
+				{
+					std::unique_ptr<CoinCell>& cell = coinCells[i];
+					float temperature;
+					bool ret = cell->getTemperature(temperature);
+
+					if(!ret)
+						Log(Log::ERROR)<<"Cell "<<i<<" UNABLE TO READ";
+					else
+						Log(Log::INFO)<<"Cell "<<i<<" temperature "<<temperature;
+				}
+
+				auto connected = multiplexers.getConnected();
+				for(size_t i = 0; i < connected.size(); ++i)
+					Log(Log::INFO)<<"multiplexer channel "<<i<<' '<<(connected[i] ? "connected" : "disconnected");
+			}
+			else if(tokens[0] == "clear")
+			{
+				multiplexers.disconnectAll();
+				for(std::unique_ptr<CoinCell>& cell :coinCells)
+					cell->setEnabled(false);
+			}
+			add_history(line.c_str());
+		}
+	}
+	catch(const startup_failure& err)
 	{
-		Log(Log::INFO)<<"MAIN"<<" Thread";
-		std::this_thread::sleep_for(std::chrono::microseconds(1));
+		Log(Log::ERROR)<<err.what();
+		return 1;
 	}
 
-	return 0;
 }
diff --git a/vcpps.cpp b/vcpps.cpp
index aca109af88b2cb261d349614990bd78aa0fddabf..8172225b283ae1510df8790a751ff5ef42a5c31d 100644
--- a/vcpps.cpp
+++ b/vcpps.cpp
@@ -13,7 +13,7 @@ Vcpps::Vcpps(const std::string& portName)
 	std::lock_guard<std::mutex> guard(portMutex);
 	sp_return ret = sp_get_port_by_name(portName.c_str(), &port);
 	if(ret != SP_OK)
-		throw startup_failure("No serial port with the name " + portName + "found");
+		throw startup_failure("No serial port with the name " + portName + " found");
 	ret = sp_open(port, SP_MODE_READ_WRITE);
 	if(ret != SP_OK)
 	{