diff --git a/eismultiplexer.c b/eismultiplexer.c
index e83aad97a03e4b6aeae97636062bf5853dba0367..1a0eec7bc59a51096b1a6db93cac7bb3c630dc65 100644
--- a/eismultiplexer.c
+++ b/eismultiplexer.c
@@ -42,7 +42,7 @@ static void usleep(uint64_t microseconds)
 	nanosleep(&ts, NULL);
 }
 
-int eismultiplexer_connect(struct eismultiplexer* muliplexer, int serial)
+int eismultiplexer_connect(struct eismultiplexer* muliplexer, uint16_t serial)
 {
 	int ret;
 	muliplexer->priv = malloc(sizeof(*muliplexer->priv));
@@ -52,8 +52,11 @@ int eismultiplexer_connect(struct eismultiplexer* muliplexer, int serial)
 	ret = usbshm_init(muliplexer->priv, NULL, muliplexer);
 	if(ret)
 		return -2;
-	
-	ret = usbshm_open(muliplexer->priv, 0xfe17, 0x07dc , NULL);
+
+	unsigned char serialStr[5];
+	snprintf((char*)serialStr, sizeof(serialStr), "%04hu", serial);
+
+	ret = usbshm_open(muliplexer->priv, 0xfe17, 0x07dc , serial == 0 ? NULL : serialStr);
 	if(ret)
 		return -3;
 	return 0;
@@ -93,7 +96,7 @@ int eismultiplexer_disconnect_channel(struct eismultiplexer* muliplexer, channel
 channel_t eismultiplexer_get_connected(struct eismultiplexer* muliplexer)
 {
 	uint8_t buffer[2] = {};
-	usbshm_readControlTransferSync(muliplexer->priv, 3, buffer, 1);
+	usbshm_readControlTransferSync(muliplexer->priv, 3, 0, 0, buffer, 1);
 	return buffer[0];
 }
 
@@ -108,7 +111,7 @@ int eismultiplexer_set_led(struct eismultiplexer* muliplexer, bool on)
 int eismultiplexer_write_eeprom(struct eismultiplexer* muliplexer, uint16_t addr, uint16_t value)
 {
 	int ret;
-	while((ret = usbshm_writeControlTransfer(muliplexer->priv, 4, NULL, 0, value, addr)) == USBSHM_ERROR_AGAIN)
+	while((ret = usbshm_writeControlTransfer(muliplexer->priv, 5, NULL, 0, value, addr)) == USBSHM_ERROR_AGAIN)
 		usleep(1000000);
 	return ret;
 }
@@ -116,7 +119,7 @@ int eismultiplexer_write_eeprom(struct eismultiplexer* muliplexer, uint16_t addr
 uint16_t eismultiplexer_read_eeprom(struct eismultiplexer* muliplexer, uint16_t addr)
 {
 	uint8_t buffer[2] = {};
-	usbshm_readControlTransferSync(muliplexer->priv, 5, buffer, 2);
+	usbshm_readControlTransferSync(muliplexer->priv, 4, 0, addr, buffer, 2);
 	return *((uint16_t*)buffer);
 }
 
diff --git a/eismultiplexer.h b/eismultiplexer.h
index 81e103a243d1071ea601877fab1d07cb54d7d3a4..a6a9f7fe5703fbe55c64c50960bfee835fc60227 100644
--- a/eismultiplexer.h
+++ b/eismultiplexer.h
@@ -63,7 +63,7 @@ struct eismultiplexer {
  * @param serial The serial number of the device to connect to, or 0 for any
  * @return 0 on sucess and < 0 on failure
  */
-int eismultiplexer_connect(struct eismultiplexer* muliplexer, int serial);
+int eismultiplexer_connect(struct eismultiplexer* muliplexer, uint16_t serial);
 
 /**
  * @brief Conects the given channel(s) to the common inputs
diff --git a/main.c b/main.c
index 846676dd86468f3438c6961f179ff58c4be4176c..87c2f58414c2692b0a73d618ad615a55ce9d7844 100644
--- a/main.c
+++ b/main.c
@@ -29,15 +29,11 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <signal.h>
 #include "eismultiplexer.h"
+#include "options.h"
 
-void print_help(const char* progname)
-{
-	printf("usage: %s [OPERATION] [CHANNEL] [VALUE]\n", progname);
-	printf("available operations: connect disconnect clear connect_all get help\n");
-}
-
-channel_t char_to_channel(char ch)
+static channel_t char_to_channel(char ch)
 {
 	switch(ch)
 	{
@@ -74,53 +70,73 @@ channel_t char_to_channel(char ch)
 	}
 }
 
-
-void disconnect(struct eismultiplexer* multiplexer)
+static int process_commands(char** commands, size_t command_count, struct eismultiplexer* multiplexer, char* name)
 {
-	eismultiplexer_set_led(multiplexer, false);
-	eismultiplexer_disconnect(multiplexer);
-}
-
-
-int main(int argc, char* argv[])
-{
-	if(argc < 2 || strcmp(argv[1], "help") == 0)
-	{
-		print_help(argv[0]);
-		return 0;
-	} 
-	
-	struct eismultiplexer multiplexer;
-	
-	if(eismultiplexer_connect(&multiplexer, 0))
+	if(strcmp(commands[0], "clear") == 0)
 	{
-		printf("Can not connect to EISmultiplexer device\n");
-		return 1;
+		eismultiplexer_disconnect_channel(multiplexer, CHANNEL_NONE);
 	}
-
-	eismultiplexer_set_led(&multiplexer, true);
-
-	if(strcmp(argv[1], "clear") == 0)
+	else if(strcmp(commands[0], "write") == 0)
 	{
-		eismultiplexer_disconnect_channel(&multiplexer, CHANNEL_NONE);
-	}
-	else if(strcmp(argv[1], "write") == 0)
-	{
-		eismultiplexer_write_eeprom(&multiplexer, 0, 42);
+		if(command_count < 3)
+		{
+			printf("Usage %s %s [ADDRESS] [VALUE]\n", name, commands[0]);
+			return 2;
+		}
+		long address = strtol(commands[1], NULL, 10);
+		long value = strtol(commands[2], NULL, 10);
+		if(address > UINT16_MAX || address < 0 || value < 0 || value > UINT16_MAX)
+		{
+			puts("Value or address is out of range");
+			return 2;
+		}
+		if(address % 2 == 1)
+		{
+			puts("Address must be a even number, 16 bits are written at a time");
+			return 2;
+		}
+		eismultiplexer_write_eeprom(multiplexer, address, value);
 	}
-	else if(strcmp(argv[1], "read") == 0)
+	else if(strcmp(commands[0], "read") == 0)
 	{
-		uint16_t value = eismultiplexer_read_eeprom(&multiplexer, 0);
-		printf("0: %u\n", value);
+		if(command_count < 2)
+		{
+			printf("Usage %s %s [ADDRESS] [LENGTH]\n", name, commands[0]);
+			return 2;
+		}
+		long address = strtol(commands[1], NULL, 10);
+		long length = 2;
+		if(command_count > 2)
+			length = strtol(commands[2], NULL, 10);
+		if(address > UINT16_MAX || address < 0 || length < 0 || length > UINT16_MAX)
+		{
+			return 2;
+			puts("Value or address is out of range");
+		}
+		if(address % 2 == 1)
+		{
+			puts("Address must be a even number, 16 bits are read at a time");
+			return 2;
+		}
+		if(length % 2 == 1)
+		{
+			puts("Length must be a even number, 16 bits are read at a time");
+			return 2;
+		}
+
+		for(uint16_t i = address; i - address < length; i+=2)
+		{
+			uint16_t value = eismultiplexer_read_eeprom(multiplexer, i);
+			printf("%u: %u\n", i, value);
+		}
 	}
-	else if(strcmp(argv[1], "connect_all") == 0)
+	else if(strcmp(commands[0], "connect_all") == 0)
 	{
-		eismultiplexer_connect_channel(&multiplexer, 0xff);
+		eismultiplexer_connect_channel(multiplexer, 0xff);
 	}
-	else if(strcmp(argv[1], "get") == 0)
+	else if(strcmp(commands[0], "get") == 0)
 	{
-		channel_t channels = eismultiplexer_get_connected(&multiplexer);
-		printf("%d\n", channels);
+		channel_t channels = eismultiplexer_get_connected(multiplexer);
 		for(size_t i = 0; i < 7; ++i)
 		{
 			bool connected = channels & (1 << i);
@@ -129,41 +145,134 @@ int main(int argc, char* argv[])
 	}
 	else
 	{
-		if(argc != 3)
+		if(command_count != 2)
 		{
-			printf("Usage %s %s [CHANNEL]\n", argv[0], argv[1]);
-			disconnect(&multiplexer);
+			printf("Usage %s %s [CHANNEL]\n", name, commands[0]);
 			return 2;
 		}
 
-		channel_t channel =  char_to_channel(argv[2][0]);
+		channel_t channel =  char_to_channel(commands[1][0]);
 		if(channel == CHANNEL_NONE)
 		{
-			printf("%c is not a valid channel\n", argv[2][0]);
-			disconnect(&multiplexer);
+			printf("%c is not a valid channel\n", commands[1][0]);
 			return 2;
 		}
 
-		if(strcmp(argv[1], "connect") == 0)
+		if(strcmp(commands[0], "connect") == 0)
 		{
-			if(eismultiplexer_connect_channel(&multiplexer, channel))
+			if(eismultiplexer_connect_channel(multiplexer, channel))
 			{
-				printf("could not connect channel %c\n", argv[2][0]);
-				disconnect(&multiplexer);
+				printf("could not connect channel %c\n", commands[1][0]);
 				return 3;
 			}
 		}
-		else if(strcmp(argv[1], "disconnect") == 0)
+		else if(strcmp(commands[0], "disconnect") == 0)
 		{
-			if(eismultiplexer_disconnect_channel(&multiplexer, channel))
+			if(eismultiplexer_disconnect_channel(multiplexer, channel))
 			{
-				printf("could not disconnect channel %c\n", argv[2][0]);
-				disconnect(&multiplexer);
+				printf("could not disconnect channel %c\n", commands[1][0]);
 				return 3;
 			}
 		}
 	}
-
-	disconnect(&multiplexer);
 	return 0;
 }
+
+enum
+{
+	INPUT_SUCESS = 0,
+	INPUT_NO_INPUT,
+	INPUT_TOO_LONG
+};
+
+static int get_input(char *prompt, char *buffer, size_t length)
+{
+	int ch, extra;
+
+	if(prompt != NULL)
+	{
+		fputs(prompt, stdout);
+		fflush(stdout);
+	}
+	if(fgets (buffer, length, stdin) == NULL)
+		return INPUT_NO_INPUT;
+
+	if(buffer[strlen(buffer)-1] != '\n')
+	{
+		extra = 0;
+		while((ch = getchar()) != '\n' && ch != EOF)
+			extra = 1;
+		return (extra == 1) ? INPUT_TOO_LONG : INPUT_SUCESS;
+	}
+
+	buffer[strlen(buffer)-1] = '\0';
+	return INPUT_SUCESS;
+}
+
+
+int main(int argc, char* argv[])
+{
+	struct config config = {};
+	argp_parse(&argp, argc, argv, 0, 0, &config);
+
+	if(config.command_count < 1 && !(config.interactive || config.pipe))
+	{
+		printf("A command is required\n");
+		return 2;
+	}
+	
+	struct eismultiplexer multiplexer;
+	if(eismultiplexer_connect(&multiplexer, config.serialSet ? config.serial : 0))
+	{
+		char serialStr[5];
+		snprintf(serialStr, sizeof(serialStr), "%04hu", config.serial);
+		printf("Can not connect to EISmultiplexer device%s%s\n",
+			   config.serialSet ? " with serial " : "", config.serialSet ? serialStr : "");
+		return 1;
+	}
+
+	int ret = 0;
+
+	if(config.interactive || config.pipe)
+	{
+		char buffer[256];
+		while(true)
+		{
+			int ret = get_input(config.pipe ? NULL : "> ", buffer, sizeof(buffer));
+			if(ret == INPUT_NO_INPUT)
+			{
+				break;
+			}
+			else if(ret != INPUT_SUCESS)
+			{
+				puts("Invalid command");
+				continue;
+			}
+
+			char* commands[MAX_COMMANDS];
+			char* command = strtok(buffer, " \t");
+			size_t i = 0;
+			while(command  && i < MAX_COMMANDS)
+			{
+				commands[i] = command;
+				command = strtok(NULL, " \t");
+				++i;
+			}
+
+			int cmdRet = process_commands(commands, i, &multiplexer, "");
+			if(cmdRet == 0)
+				puts("OK");
+			else
+				printf("ERR %i\n", cmdRet);
+		}
+	}
+	else
+	{
+		eismultiplexer_set_led(&multiplexer, true);
+		ret = process_commands(config.commands, config.command_count, &multiplexer, argv[0]);
+		eismultiplexer_set_led(&multiplexer, false);
+	}
+
+	eismultiplexer_disconnect(&multiplexer);
+	return ret;
+}
diff --git a/usbshm.c b/usbshm.c
index ae2516ec22d0aca852803b8c1a3b8aaa42e46368..81f932ce433569df66e0ffb32c3c549753d30ca2 100644
--- a/usbshm.c
+++ b/usbshm.c
@@ -59,7 +59,6 @@ void usbshm_distroy(struct usbshm* instance)
 	free(instance->priv->transfer);
 	libusb_close(instance->priv->handle);
 	free(instance->priv->buffer);
-	free(instance->productName);
 	free(instance->priv);
 	if(--objectCounter == 0)
 	{
@@ -94,7 +93,6 @@ int usbshm_init(struct usbshm* instance, void (*dataCallback)(uint8_t request, u
 	instance->priv->buffer = NULL;
 	instance->vendorID = 0;
 	instance->productID = 0;
-	instance->productName = NULL;
 	instance->dataCallback = dataCallback;
 	instance->user_data = user_data;
 	if(objectCounter == 0)
@@ -114,7 +112,7 @@ bool usbshm_ready(struct usbshm* instance)
 	return instance->priv->transfer == NULL;
 }
 
-int usbshm_open(struct usbshm* instance, int vendorID, int productID, const char* productName)
+int usbshm_open(struct usbshm* instance, int vendorID, int productID, const unsigned char* serial)
 {
 	instance->priv->handle = NULL;
 	pthread_mutex_lock(libusbDataMutex);
@@ -130,6 +128,21 @@ int usbshm_open(struct usbshm* instance, int vendorID, int productID, const char
 			if(desc.idVendor == vendorID && desc.idProduct == productID)
 			{
 				errorCode = libusb_open(list[i], &instance->priv->handle) < 0 ? USBSHM_ERROR_ERR : 0;
+				if(serial)
+				{
+					size_t len = strlen((const char*)serial)+1;
+					unsigned char* buffer = malloc(len);
+					buffer[0] = '\0';
+					libusb_get_string_descriptor_ascii(instance->priv->handle, desc.iSerialNumber, buffer, len);
+					int cmp = strcmp((const char*)serial, (const char*)buffer);
+					free(buffer);
+					if(cmp != 0)
+					{
+						libusb_close(instance->priv->handle);
+						instance->priv->handle = NULL;
+						continue;
+					}
+				}
 				break;
 			}
 		}
@@ -145,15 +158,6 @@ int usbshm_open(struct usbshm* instance, int vendorID, int productID, const char
 	{
 		instance->vendorID = vendorID;
 		instance->productID = productID;
-		if(productName)
-		{
-			instance->productName = malloc(strlen(productName)+1);
-			strcpy(instance->productName, productName);
-		}
-		else
-		{
-			instance->productName = NULL;
-		}
 		libusb_set_auto_detach_kernel_driver(instance->priv->handle, true);
 	}
 	else
@@ -181,7 +185,7 @@ void usbshm_reset(struct usbshm* instance)
 void usbshm_reopen(struct usbshm* instance)
 {
 	libusb_close(instance->priv->handle);
-	usbshm_open(instance, instance->vendorID, instance->productID, instance->productName);
+	usbshm_open(instance, instance->vendorID, instance->productID, NULL);
 }
 
 int usbshm_writeControlTransfer(struct usbshm* instance, const uint8_t request,
@@ -219,7 +223,7 @@ int usbshm_writeControlTransfer(struct usbshm* instance, const uint8_t request,
 	else return USBSHM_ERROR_AGAIN;
 }
 
-int usbshm_readControlTransfer(struct usbshm* instance, const uint8_t request, const uint16_t length)
+int usbshm_readControlTransfer(struct usbshm* instance, const uint8_t request, const uint16_t wValue, const uint16_t wIndex, const uint16_t length)
 {
 	if(!usbshm_isOpen(instance))
 		return USBSHM_ERROR_NOT_CONNECTED;
@@ -230,7 +234,7 @@ int usbshm_readControlTransfer(struct usbshm* instance, const uint8_t request, c
 		pthread_mutex_lock(libusbDataMutex);
 		instance->priv->buffer = malloc(length+8);
 		libusb_fill_control_setup(instance->priv->buffer, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
-			request, request, request, length);
+			request, wValue, wIndex, length);
 		instance->priv->transfer = libusb_alloc_transfer(0);
 		libusb_fill_control_transfer(instance->priv->transfer, instance->priv->handle, instance->priv->buffer, &usbshm_transferCallBack, instance, 100);
 		int ret = libusb_submit_transfer(instance->priv->transfer);
@@ -265,8 +269,8 @@ static void usbshm_transferCallBack(struct libusb_transfer *transfer)
 	context->priv->transfer = NULL;
 }
 
-int usbshm_readControlTransferSync(struct usbshm* instance, const uint8_t request, uint8_t* buffer, const uint16_t length)
+int usbshm_readControlTransferSync(struct usbshm* instance, const uint8_t request, const uint16_t wValue, const uint16_t wIndex, uint8_t* buffer, const uint16_t length)
 {
 	return libusb_control_transfer(instance->priv->handle, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
-		request, request, request, buffer, length, 2000);
+		request, wValue, wIndex, buffer, length, 2000);
 }
diff --git a/usbshm.h b/usbshm.h
index add9a7ff34c4da5acfd58ea8228f43be5354a5f3..d03ad2decb928da656653b8042ed295623c9534d 100644
--- a/usbshm.h
+++ b/usbshm.h
@@ -45,7 +45,6 @@ struct usbshm {
 	struct usbshm_priv* priv;
 	int vendorID;
 	int productID;
-	char* productName;
 	void* user_data;
 	void (*dataCallback)(uint8_t request, unsigned char* data, size_t length, void* user_data);
 };
@@ -56,7 +55,7 @@ int usbshm_init(struct usbshm* instance, void (*dataCallback)(uint8_t request, u
 
 bool usbshm_ready(struct usbshm* instance);
 
-int usbshm_open(struct usbshm* instance, int vendorID, int productID, const char* productName);
+int usbshm_open(struct usbshm* instance, int vendorID, int productID, const unsigned char* serial);
 
 bool usbshm_isOpen(struct usbshm* instance);
 
@@ -68,7 +67,7 @@ int usbshm_writeControlTransfer(struct usbshm* instance, const uint8_t request,
 								char* buffer, const uint8_t length, 
 								const uint16_t wValue, const uint16_t wIndex);
 
-int usbshm_readControlTransfer(struct usbshm* instance, const uint8_t request, const uint16_t length);
+int usbshm_readControlTransfer(struct usbshm* instance, const uint8_t request, const uint16_t wValue, const uint16_t wIndex, const uint16_t length);
 
-int usbshm_readControlTransferSync(struct usbshm* instance, const uint8_t request, uint8_t* buffer, const uint16_t length);
+int usbshm_readControlTransferSync(struct usbshm* instance, const uint8_t request, const uint16_t wValue, const uint16_t wIndex, uint8_t* buffer, const uint16_t length);