diff --git a/90-eismultiplexer.rules b/90-eismultiplexer.rules
deleted file mode 100644
index 0a7412b0e9a339ae08ed44d8accb4f928d67dcbc..0000000000000000000000000000000000000000
--- a/90-eismultiplexer.rules
+++ /dev/null
@@ -1 +0,0 @@
-SUBSYSTEM=="usb", ATTRS{idVendor}=="fe17", GROUP="uucp"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 19cc3a106a8d904c02fe4a6912c4c231fddc8957..481cb3d50913ef8bca5ae0dbfcad55a960559b96 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.0)
 
-project(eismultiplexer)
+project(coincellhell)
 
 find_package(PkgConfig REQUIRED)
 find_package(Doxygen)
@@ -10,7 +10,7 @@ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
 	set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "..." FORCE)
 endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
 
-set(SRC_FILES eismultiplexer.c usbshm.c)
+set(SRC_FILES coincellhell.c usbshm.c)
 
 message("Platform " ${CMAKE_SYSTEM_NAME})
 if(WIN32)
@@ -27,7 +27,7 @@ target_link_libraries(${PROJECT_NAME} ${LIBUSB_LIBRARIES})
 target_include_directories(${PROJECT_NAME} PUBLIC ${LIBUSB_INCLUDE_DIRS})
 add_definitions("-std=c17 -Wall -O2 -fno-strict-aliasing")
 install(TARGETS ${PROJECT_NAME} DESTINATION lib)
-install(FILES ./eismultiplexer.h DESTINATION include)
+install(FILES ./coincellhell.c DESTINATION include)
 
 link_directories(${CMAKE_CURRENT_BINARY_DIR})
 add_executable(${PROJECT_NAME}_cli main.c)
@@ -56,5 +56,5 @@ endif (DOXYGEN_FOUND)
 
 if(CMAKE_SYSTEM_NAME MATCHES "^Linux")
 	set(UDEV_RULES_INSTALL_DIR /lib/udev/rules.d CACHE PATH "install directory for linux udev config")
-	install(FILES 90-eismultiplexer.rules DESTINATION ${UDEV_RULES_INSTALL_DIR})
+	install(FILES 90-coincellhell.rules DESTINATION ${UDEV_RULES_INSTALL_DIR})
 endif()
diff --git a/EisMultiplexerWinDriver/7ZDP_LZMA.sfx b/EisMultiplexerWinDriver/7ZDP_LZMA.sfx
deleted file mode 100755
index 51982ec7e9a8d561209f14816d3b96bc8f995e18..0000000000000000000000000000000000000000
Binary files a/EisMultiplexerWinDriver/7ZDP_LZMA.sfx and /dev/null differ
diff --git a/EisMultiplexerWinDriver/7zDP_LZMA.cfg b/EisMultiplexerWinDriver/7zDP_LZMA.cfg
deleted file mode 100755
index 2edad7cfa87baad8008e23b30d4899d65169a24b..0000000000000000000000000000000000000000
--- a/EisMultiplexerWinDriver/7zDP_LZMA.cfg
+++ /dev/null
@@ -1,6 +0,0 @@
-;!@Install@!UTF-8!
-RunProgram="dpscat.exe"
-RunProgram="x86:dpinst32.exe"
-RunProgram="x64:dpinst64.exe"
-GUIMode="2"
-;!@InstallEnd@!
\ No newline at end of file
diff --git a/EisMultiplexerWinDriver/7za.exe b/EisMultiplexerWinDriver/7za.exe
deleted file mode 100755
index 7f6bf86bc43ed71decf8b03f54dcb9b2be143a24..0000000000000000000000000000000000000000
Binary files a/EisMultiplexerWinDriver/7za.exe and /dev/null differ
diff --git a/EisMultiplexerWinDriver/EisMultiplexerWinDriver.inf b/EisMultiplexerWinDriver/EisMultiplexerWinDriver.inf
deleted file mode 100755
index cc92de8ef1b595cbd4e0a7b63db0407dbaf65b73..0000000000000000000000000000000000000000
Binary files a/EisMultiplexerWinDriver/EisMultiplexerWinDriver.inf and /dev/null differ
diff --git a/EisMultiplexerWinDriver/InstallDriver.exe b/EisMultiplexerWinDriver/InstallDriver.exe
deleted file mode 100755
index 53ffd16342c59a2a9701df65edc5b8e54482fafc..0000000000000000000000000000000000000000
Binary files a/EisMultiplexerWinDriver/InstallDriver.exe and /dev/null differ
diff --git a/EisMultiplexerWinDriver/_DriverFiles.7z b/EisMultiplexerWinDriver/_DriverFiles.7z
deleted file mode 100755
index 32adf29e50bf53a54e6ab9c899c735a576040ffb..0000000000000000000000000000000000000000
Binary files a/EisMultiplexerWinDriver/_DriverFiles.7z and /dev/null differ
diff --git a/EisMultiplexerWinDriver/amd64/WdfCoInstaller01009.dll b/EisMultiplexerWinDriver/amd64/WdfCoInstaller01009.dll
deleted file mode 100755
index 1731b962d68d52030b32b19d6f0f913cbc47729e..0000000000000000000000000000000000000000
Binary files a/EisMultiplexerWinDriver/amd64/WdfCoInstaller01009.dll and /dev/null differ
diff --git a/EisMultiplexerWinDriver/amd64/libusbK.dll b/EisMultiplexerWinDriver/amd64/libusbK.dll
deleted file mode 100755
index 4497c2ac373522899d4047ce3aa72a089b717ea8..0000000000000000000000000000000000000000
Binary files a/EisMultiplexerWinDriver/amd64/libusbK.dll and /dev/null differ
diff --git a/EisMultiplexerWinDriver/amd64/winusbcoinstaller2.dll b/EisMultiplexerWinDriver/amd64/winusbcoinstaller2.dll
deleted file mode 100755
index 30e55025b2fb6455a18165ad9df1ba1a3aa90566..0000000000000000000000000000000000000000
Binary files a/EisMultiplexerWinDriver/amd64/winusbcoinstaller2.dll and /dev/null differ
diff --git a/EisMultiplexerWinDriver/dpinst.xml b/EisMultiplexerWinDriver/dpinst.xml
deleted file mode 100755
index cc2988e669c6585798b3b01e6806089eec3b716b..0000000000000000000000000000000000000000
--- a/EisMultiplexerWinDriver/dpinst.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<!--
-Summary of the DPInst XML Elements:
-  http://msdn.microsoft.com/en-us/library/windows/hardware/ff553383%28v=vs.85%29.aspx
-  
-Enabling Language Customization:
-  http://msdn.microsoft.com/en-us/library/windows/hardware/ff544886%28v=vs.85%29.aspx
-
-Customizing the Items That Appear on the Wizard Pages:
-  http://msdn.microsoft.com/en-us/library/windows/hardware/ff540265%28v=vs.85%29.aspx
-  
-Dpinst.xml Example:
-  http://msdn.microsoft.com/en-us/library/windows/hardware/ff544778%28v=vs.85%29.aspx
--->
-
-<?xml version="1.0"?>
-<dpinst>
-	<forceIfDriverIsNotBetter>1</forceIfDriverIsNotBetter>
-	<installAllOrNone>1</installAllOrNone>
-</dpinst>
diff --git a/EisMultiplexerWinDriver/dpinst32.exe b/EisMultiplexerWinDriver/dpinst32.exe
deleted file mode 100755
index 410a135a5d3b0ef0e018d9fc0cdd84475a5fe5f2..0000000000000000000000000000000000000000
Binary files a/EisMultiplexerWinDriver/dpinst32.exe and /dev/null differ
diff --git a/EisMultiplexerWinDriver/dpinst64.exe b/EisMultiplexerWinDriver/dpinst64.exe
deleted file mode 100755
index 00964418a06b9e4e066b6831f8f1ee986b21af89..0000000000000000000000000000000000000000
Binary files a/EisMultiplexerWinDriver/dpinst64.exe and /dev/null differ
diff --git a/EisMultiplexerWinDriver/dpscat.exe b/EisMultiplexerWinDriver/dpscat.exe
deleted file mode 100755
index 848a16e097d4b0e9fe787d6629f80cf21ed61bf6..0000000000000000000000000000000000000000
Binary files a/EisMultiplexerWinDriver/dpscat.exe and /dev/null differ
diff --git a/EisMultiplexerWinDriver/re-pack-files.cmd b/EisMultiplexerWinDriver/re-pack-files.cmd
deleted file mode 100755
index dff6c747c3761bab3a28903e6c2e429ad6955167..0000000000000000000000000000000000000000
--- a/EisMultiplexerWinDriver/re-pack-files.cmd
+++ /dev/null
@@ -1,73 +0,0 @@
-@ECHO OFF
-SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
-
-SET FILES_TO_PACK=*.inf dpinst* dpscat.* .\data* .\x86* .\amd64*
-SET SFX_MODULE=7zDP_LZMA.sfx
-SET SFX_MODULE_CFG=7zDP_LZMA.cfg
-SET INSTALL_DRIVER_EXE=InstallDriver.exe
-SET DRIVER_FILES_7Z=_DriverFiles.7z
-SET 7Z_SWITCHES=-air0 -mx
-
-SET CMD_EXIT_CODE=0
-
-IF EXIST "!7ZA_EXE!" (SET 7Z_RUN="!7ZA_EXE!") ELSE CALL :Find7Zip 7za.exe 7z.exe 7zan.exe
-IF !7Z_RUN! EQU "" (
-	ECHO 7Zip is required to re-pack this installer.
-	ECHO 1] Download and install 7Zip. http://www.7-zip.org/
-	ECHO 2] Add the bin folder to the PATH environment variable.
-	ECHO    "Control Panel->System->Advanced->Environment Variables..."
-	SET CMD_EXIT_CODE=1
-	GOTO Error
-)
-
-IF EXIST "!INSTALL_DRIVER_EXE!" DEL /Q "!INSTALL_DRIVER_EXE!"
-IF NOT "!ERRORLEVEL!" EQU "0" (
-	ECHO Access denied or file in-use "!INSTALL_DRIVER_EXE!"
-	SET CMD_EXIT_CODE=2
-	GOTO Error
-)
-
-IF EXIST "!DRIVER_FILES_7Z!" DEL /Q "!DRIVER_FILES_7Z!"
-IF NOT "!ERRORLEVEL!" EQU "0" (
-	ECHO Access denied or file in-use "!DRIVER_FILES_7Z!"
-	SET CMD_EXIT_CODE=3
-	GOTO Error
-)
-
-!7Z_RUN! a "!DRIVER_FILES_7Z!" !FILES_TO_PACK! !7Z_SWITCHES!
-IF NOT "!ERRORLEVEL!" EQU "0" (
-	ECHO Failed re-packing.  Check your 7Zip installation at
-	ECHO !7Z_RUN!
-	SET CMD_EXIT_CODE=4
-	GOTO Error
-)
-
-COPY /B "!SFX_MODULE!"+"!SFX_MODULE_CFG!"+"!DRIVER_FILES_7Z!" "!INSTALL_DRIVER_EXE!"
-
-ECHO. 
-ECHO Done.
-ECHO "!INSTALL_DRIVER_EXE!" re-packed!
-GOTO :EOF
-
-:Find7Zip
-	IF EXIST "%~dp0\%~1" (
-		SET 7Z_RUN="%~dp0\%~1"
-		ECHO 7Zip found at: !7Z_RUN!
-		GOTO :EOF
-	)
-
-	SET 7Z_RUN="%~$PATH:1"
-	IF NOT !7Z_RUN! EQU "" (
-		ECHO 7Zip found at: !7Z_RUN!
-		SET 7Z_RUN="%~1"
-		GOTO :EOF
-	)
-	SHIFT /1
-	IF "%~1" EQU "" GOTO :EOF
-	GOTO Find7Zip
-GOTO :EOF
-
-:Error
-	IF NOT DEFINED NO_REPACK_ERROR_WAIT PAUSE
-	EXIT %CMD_EXIT_CODE%
-GOTO :EOF
\ No newline at end of file
diff --git a/EisMultiplexerWinDriver/x86/WdfCoInstaller01009.dll b/EisMultiplexerWinDriver/x86/WdfCoInstaller01009.dll
deleted file mode 100755
index 30e81af6202448f1f81fb8423af5fa97fa4a110a..0000000000000000000000000000000000000000
Binary files a/EisMultiplexerWinDriver/x86/WdfCoInstaller01009.dll and /dev/null differ
diff --git a/EisMultiplexerWinDriver/x86/libusbK_x86.dll b/EisMultiplexerWinDriver/x86/libusbK_x86.dll
deleted file mode 100755
index 0a9b1c89b23402072ed4c2ca7a1df6e2fec64904..0000000000000000000000000000000000000000
Binary files a/EisMultiplexerWinDriver/x86/libusbK_x86.dll and /dev/null differ
diff --git a/EisMultiplexerWinDriver/x86/winusbcoinstaller2.dll b/EisMultiplexerWinDriver/x86/winusbcoinstaller2.dll
deleted file mode 100755
index fc450d2b25d0f8069454cc0bde5ba9c13927fe4d..0000000000000000000000000000000000000000
Binary files a/EisMultiplexerWinDriver/x86/winusbcoinstaller2.dll and /dev/null differ
diff --git a/coincellhell.c b/coincellhell.c
new file mode 100644
index 0000000000000000000000000000000000000000..bec0af7bb21d05268c54566fd4407c8cd722f167
--- /dev/null
+++ b/coincellhell.c
@@ -0,0 +1,171 @@
+/* * Copyright (c) 2023 Carl Klemm <carl@uvos.xyz>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *  * Neither the name of %ORGANIZATION% nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define _POSIX_C_SOURCE 199309L
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <time.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "coincellhell.h"
+#include "usbshm.h"
+#include "usbcommands.h"
+
+#define VID 0xfe17
+#define PID 0x08dc
+
+static void usleep(uint64_t microseconds)
+{
+	struct timespec ts;
+	ts.tv_sec = microseconds / 1000000;
+	ts.tv_nsec = (microseconds % 1000000) * 1000;
+	nanosleep(&ts, NULL);
+}
+
+int coincellhell_connect(struct coincellhell* hell, uint16_t serial)
+{
+	int ret;
+	hell->priv = malloc(sizeof(*hell->priv));
+	if(!hell->priv)
+		return -1;
+	
+	ret = usbshm_init(hell->priv, NULL, hell);
+	if(ret)
+		return -2;
+
+	unsigned char serialStr[5];
+	snprintf((char*)serialStr, sizeof(serialStr), "%04hu", serial);
+
+	ret = usbshm_open(hell->priv, VID, PID , serial == 0 ? NULL : serialStr);
+	if(ret)
+		return -3;
+	return 0;
+}
+
+int coincellhell_get_temperature(struct coincellhell* hell, uint8_t heater, temperature_sensor_location_t location, float* temperature)
+{
+	int16_t temperatureRaw = 0;
+	uint8_t *dataPtr = (uint8_t*)&temperatureRaw;
+	int ret;
+	while((ret = usbshm_readControlTransferSync(hell->priv, COMMAND_GET_TEMPERATURE, location, heater, dataPtr, 2)) == USBSHM_ERROR_AGAIN)
+		usleep(1000000);
+	*temperature = temperatureRaw/10.0f;
+	return ret;
+}
+
+int coincellhell_set_temperature(struct coincellhell* hell, uint8_t heater, float temperature)
+{
+	if(temperature*10.0f > INT16_MAX || temperature*10.0f < INT16_MIN)
+		return -6;
+	int ret;
+	while((ret = usbshm_writeControlTransfer(hell->priv, COMMAND_SET_TEMPERATURE, NULL, 0, temperature*10.0f, heater)) == USBSHM_ERROR_AGAIN)
+		usleep(100000);
+	return ret;
+}
+
+int coincellhell_get_temperature_setpoint(struct coincellhell* hell, uint8_t heater, float* temperature)
+{
+	int16_t temperatureRaw = 0;
+	uint8_t *dataPtr = (uint8_t*)&temperatureRaw;
+	int ret;
+	while((ret = usbshm_readControlTransferSync(hell->priv, COMMAND_GET_TEMPERATURE_SETPOINT, 0, heater, dataPtr, 2)) == USBSHM_ERROR_AGAIN)
+		usleep(100000);
+	*temperature = temperatureRaw/10.0f;
+	return ret;
+}
+
+int coincellhell_check_ready(struct coincellhell* hell, bool* ready)
+{
+	*ready = false;
+	int ret;
+	while((ret = usbshm_readControlTransferSync(hell->priv, COMMAND_READY, 0, 0, (uint8_t*)ready, 1)) == USBSHM_ERROR_AGAIN)
+		usleep(100000);
+	return ret;
+}
+
+int coincellhell_set_temperature_ramp(struct coincellhell* hell, uint8_t heater, time_t end_time, float temperature)
+{
+	return -1;
+}
+
+int coincellhell_cancle_ramp(struct coincellhell* hell, uint8_t heater)
+{
+	return -1;
+}
+
+int coincellhell_get_ramping(struct coincellhell* hell, uint8_t heater, bool* ramping)
+{
+	return -1;
+}
+
+int coincellhell_set_led(struct coincellhell* hell, bool on)
+{
+	int ret;
+	while((ret = usbshm_writeControlTransfer(hell->priv, on ? COMMAND_LED_ON : COMMAND_LED_OFF, NULL, 0, 0, 0)) == USBSHM_ERROR_AGAIN)
+		usleep(100000);
+	return ret;
+}
+
+int coincellhell_write_eeprom(struct coincellhell* hell, uint16_t addr, uint16_t value)
+{
+	int ret;
+	while((ret = usbshm_writeControlTransfer(hell->priv, COMMAND_WRITE_EEPROM, NULL, 0, value, addr)) == USBSHM_ERROR_AGAIN)
+		usleep(100000);
+	return ret;
+}
+
+uint16_t coincellhell_read_eeprom(struct coincellhell* hell, uint16_t addr)
+{
+	uint8_t buffer[2] = {};
+	usbshm_readControlTransferSync(hell->priv, COMMAND_READ_EEPROM, 0, addr, buffer, 2);
+	return *((uint16_t*)buffer);
+}
+
+
+uint8_t coincellhell_read_oscal(struct coincellhell* hell)
+{
+	uint8_t oscal;
+	usbshm_readControlTransferSync(hell->priv, COMMAND_READ_OSCAL, 0, 0, &oscal, 1);
+	return oscal;
+}
+
+uint32_t coincellhell_get_seconds(struct coincellhell* hell)
+{
+	uint32_t seconds;
+	usbshm_readControlTransferSync(hell->priv, COMMAND_GET_SECONDS, 0, 0, (uint8_t*)&seconds, 4);
+	return seconds;
+}
+
+void coincellhell_disconnect(struct coincellhell* hell)
+{
+	usbshm_distroy(hell->priv);
+	free(hell->priv);
+	hell->priv = NULL;
+}
+
diff --git a/coincellhell.h b/coincellhell.h
new file mode 100644
index 0000000000000000000000000000000000000000..da3e85aab430358f1eb09dfad44504453329decf
--- /dev/null
+++ b/coincellhell.h
@@ -0,0 +1,139 @@
+/* * Copyright (c) 2023 Carl Klemm <carl@uvos.xyz>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *  * Neither the name of %ORGANIZATION% nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <semaphore.h>
+#include <stdbool.h>
+
+#include "usbcommands.h"
+
+/**
+Api to controll EISmultiplexer devices.
+* @defgroup API User API
+* This api allows you to controll the EISmultiplexer device.
+* @{
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct coincellhell {
+	struct usbshm* priv;
+};
+
+/**
+ * @brief Attempts to connect to a EISmultiplexer device and initalizes a coincellhell struct
+ * @param hell pointer to a coincellhell struct to initalize
+ * @param serial The serial number of the device to connect to, or 0 for any
+ * @return 0 on sucess and < 0 on failure
+ */
+int coincellhell_connect(struct coincellhell* hell, uint16_t serial);
+
+/**
+ * @brief Reads the current temperature of the given heater at given location
+ * @param heater heater from which to get the temperature
+ * @param location Place where temperature shal be mesured
+ * @param temperature A float where the temperature in degrees celcius will be stored
+ * @return 0 on sucess and < 0 on failure
+ */
+int coincellhell_get_temperature(struct coincellhell* hell, uint8_t heater, temperature_sensor_location_t location, float* temperature);
+
+/**
+ * @brief Sets the target temperature of the given heater
+ * @param heater heater for which to set the temperature
+ * @param temperature temperature to set
+ * @return 0 on sucess and < 0 on failure
+ */
+int coincellhell_set_temperature(struct coincellhell* hell, uint8_t heater, float temperature);
+
+/**
+ * @brief Gets the target temperature of the given heater
+ * @param heater heater for which to set the temperature
+ * @param temperature A float where the temperature in degrees celcius will be stored
+ * @return 0 on sucess and < 0 on failure
+ */
+int coincellhell_get_temperature_setpoint(struct coincellhell* hell, uint8_t heater, float* temperature);
+
+/**
+ * @brief Checks if all temperatures are close to thair setpoins and all ramps have compleated
+ * @param ready a pointer to a bool where the result will be stored, true if all temperatures have been reatch, false otherwise
+ * @return 0 on sucess and < 0 on failure
+ */
+int coincellhell_check_ready(struct coincellhell* hell, bool* ready);
+
+/**
+ * @brief Will linearly ramp the temperature to the one provided from now until end_time
+ * @param heater heater for which to set the ramp
+ * @param temperature temperature to ramp to
+ * @return 0 on sucess and < 0 on failure
+ */
+int coincellhell_set_temperature_ramp(struct coincellhell* hell, uint8_t heater, time_t end_time, float temperature);
+
+/**
+ * @brief Cancles any previously set ramp, the setpoint of the heater will hold the current temperature
+ * @param heater heater for which to cancle the ramp
+ * @return 0 on sucess and < 0 on failure
+ */
+int coincellhell_cancle_ramp(struct coincellhell* hell, uint8_t heater);
+
+/**
+ * @brief Checks wather the the given heater is currenly executeing a ramp
+ * @param ramping a pointer to a bool where the ramping state will be stored
+ * @param heater heater for which to cancle the ramp
+ * @return 0 on sucess and < 0 on failure
+ */
+int coincellhell_get_ramping(struct coincellhell* hell, uint8_t heater, bool* ramping);
+
+/**
+ * @brief Turns the led on the pcb on or off
+ * @param hell pointer to a coincellhell struct
+ * @param on true to turn the led on, false to turn it off
+ * @return 0 on sucess and < 0 on failure
+ */
+int coincellhell_set_led(struct coincellhell* hell, bool on);
+
+/**
+ * @brief Disconnects from the coincellhell
+ */
+void coincellhell_disconnect(struct coincellhell* hell);
+
+int coincellhell_write_eeprom(struct coincellhell* hell, uint16_t addr, uint16_t value);
+uint16_t coincellhell_read_eeprom(struct coincellhell* hell, uint16_t addr);
+uint8_t coincellhell_read_oscal(struct coincellhell* hell);
+uint32_t coincellhell_get_seconds(struct coincellhell* hell);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+....
+* @}
+*/
diff --git a/doc/mainpage.txt.bak b/doc/mainpage.txt.bak
new file mode 100644
index 0000000000000000000000000000000000000000..e0cdde23dfc56adf77f24eb800d8da243e9f2ad1
--- /dev/null
+++ b/doc/mainpage.txt.bak
@@ -0,0 +1,44 @@
+/*! \mainpage libeismultiplexer manual
+
+libeismultiplexer is a shared library that allows you to control EISmultiplexer devices
+
+An API reference can be found here: \subpage API
+
+## Example usage:
+
+_______
+
+@code
+#include <stdio.h>
+#include "eismultiplexer.h"
+
+int main(int argc, char* argv[])
+{
+	// Each connection to a device is required to have a corresponding eismultiplexer struct
+	struct eismultiplexer multiplexer;
+
+	// Connect to the first device found
+	int ret = eismultiplexer_connect(&multiplexer, 0);
+	if(ret != 0)
+	{
+		printf("Can not connect to EISmultiplexer device\n");
+		return 1;
+	}
+
+	// Connect channels A and C to the common output
+	ret = eismultiplexer_connect_channel(&multiplexer, CHANNEL_A | CHANNEL_C);
+	if(ret != 0)
+	{
+		printf("Failure to communicate with the device\n");
+		return 1;
+	}
+
+	// Disconnect from device
+	eismultiplexer_disconnect(&multiplexer);
+	return 0;
+}
+@endcode
+//-----------------------------------------------------------
+
+librelaxisloader is licenced to you under the Apache License, Version 2.0
+*/
diff --git a/eismultiplexer.c b/eismultiplexer.c
deleted file mode 100644
index 1a0eec7bc59a51096b1a6db93cac7bb3c630dc65..0000000000000000000000000000000000000000
--- a/eismultiplexer.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/* * Copyright (c) 2023 Carl Klemm <carl@uvos.xyz>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- *  * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation and/or
- * other materials provided with the distribution.
- *  * Neither the name of %ORGANIZATION% nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define _POSIX_C_SOURCE 199309L
-
-#include <stdint.h>
-#include "eismultiplexer.h"
-#include "usbshm.h"
-#include <stdlib.h>
-#include <time.h>
-#include <stdio.h>
-
-static void usleep(uint64_t microseconds)
-{
-	struct timespec ts;
-	ts.tv_sec = microseconds / 1000000;
-	ts.tv_nsec = (microseconds % 1000000) * 1000;
-	nanosleep(&ts, NULL);
-}
-
-int eismultiplexer_connect(struct eismultiplexer* muliplexer, uint16_t serial)
-{
-	int ret;
-	muliplexer->priv = malloc(sizeof(*muliplexer->priv));
-	if(!muliplexer->priv)
-		return -1;
-	
-	ret = usbshm_init(muliplexer->priv, NULL, muliplexer);
-	if(ret)
-		return -2;
-
-	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;
-}
-
-int eismultiplexer_connect_channel_exclusive(struct eismultiplexer* muliplexer, channel_t channel)
-{
-	uint16_t wValue;
-	// we compile with fno-strict-aliasing
-	uint8_t* wValChar = (uint8_t*)&wValue;
-	wValChar[0] = channel;
-	wValChar[1] = 0;
-	int ret;
-	while((ret = usbshm_writeControlTransfer(muliplexer->priv, 2, NULL, 0, wValue, 0)) == USBSHM_ERROR_AGAIN)
-		usleep(1000000);
-	return ret;
-}
-
-int eismultiplexer_connect_channel(struct eismultiplexer* muliplexer, channel_t channel)
-{
-	channel_t channels = eismultiplexer_get_connected(muliplexer);
-	channels |= channel;
-	return eismultiplexer_connect_channel_exclusive(muliplexer, channels);
-}
-
-int eismultiplexer_disconnect_channel(struct eismultiplexer* muliplexer, channel_t channel)
-{
-	channel_t channels = CHANNEL_NONE;
-	if(channel != CHANNEL_NONE)
-	{
-		channels = eismultiplexer_get_connected(muliplexer);
-		channels &= ~channel;
-	}
-	return eismultiplexer_connect_channel_exclusive(muliplexer, channels);
-}
-
-channel_t eismultiplexer_get_connected(struct eismultiplexer* muliplexer)
-{
-	uint8_t buffer[2] = {};
-	usbshm_readControlTransferSync(muliplexer->priv, 3, 0, 0, buffer, 1);
-	return buffer[0];
-}
-
-int eismultiplexer_set_led(struct eismultiplexer* muliplexer, bool on)
-{
-	int ret;
-	while((ret = usbshm_writeControlTransfer(muliplexer->priv, on, NULL, 0, 0, 0)) == USBSHM_ERROR_AGAIN)
-		usleep(1000000);
-	return ret;
-}
-
-int eismultiplexer_write_eeprom(struct eismultiplexer* muliplexer, uint16_t addr, uint16_t value)
-{
-	int ret;
-	while((ret = usbshm_writeControlTransfer(muliplexer->priv, 5, NULL, 0, value, addr)) == USBSHM_ERROR_AGAIN)
-		usleep(1000000);
-	return ret;
-}
-
-uint16_t eismultiplexer_read_eeprom(struct eismultiplexer* muliplexer, uint16_t addr)
-{
-	uint8_t buffer[2] = {};
-	usbshm_readControlTransferSync(muliplexer->priv, 4, 0, addr, buffer, 2);
-	return *((uint16_t*)buffer);
-}
-
-void eismultiplexer_disconnect(struct eismultiplexer* muliplexer)
-{
-	usbshm_distroy(muliplexer->priv);
-	free(muliplexer->priv);
-	muliplexer->priv = NULL;
-}
diff --git a/eismultiplexer.h b/eismultiplexer.h
deleted file mode 100644
index a6a9f7fe5703fbe55c64c50960bfee835fc60227..0000000000000000000000000000000000000000
--- a/eismultiplexer.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/* * Copyright (c) 2023 Carl Klemm <carl@uvos.xyz>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- *  * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation and/or
- * other materials provided with the distribution.
- *  * Neither the name of %ORGANIZATION% nor the names of its contributors may be
- * used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <semaphore.h>
-#include <stdbool.h>
-
-/**
-Api to controll EISmultiplexer devices.
-* @defgroup API User API
-* This api allows you to controll the EISmultiplexer device.
-* @{
-*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
-	CHANNEL_A = (1 << 0),
-	CHANNEL_B = (1 << 1),
-	CHANNEL_C = (1 << 2),
-	CHANNEL_D = (1 << 3),
-	CHANNEL_E = (1 << 4),
-	CHANNEL_F = (1 << 5),
-	CHANNEL_G = (1 << 6),
-	CHANNEL_NONE = 0,
-} channel_t;
-
-struct eismultiplexer {
-	struct usbshm* priv;
-};
-
-/**
- * @brief Attempts to connect to a EISmultiplexer device and initalizes a eismultiplexer struct
- * @param muliplexer pointer to a eismultiplexer struct to initalize
- * @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, uint16_t serial);
-
-/**
- * @brief Conects the given channel(s) to the common inputs
- * @param muliplexer pointer to a eismultiplexer struct
- * @param channel A channel to connect, multiple channels can be specified by or'ing together the chanel flags e.g. (CHANNEL_A | CHANNEL_B)
- * @return 0 on sucess and < 0 on failure
- */
-int eismultiplexer_connect_channel(struct eismultiplexer* muliplexer, channel_t channel);
-
-/**
- * @brief Conects the given channel(s) to the common inputs disconnecting all others
- * @param muliplexer pointer to a eismultiplexer struct
- * @param channel A channel to connect, multiple channels can be specified by or'ing together the chanel flags e.g. (CHANNEL_A | CHANNEL_B)
- * @return 0 on sucess and < 0 on failure
- */
-int eismultiplexer_connect_channel_exclusive(struct eismultiplexer* muliplexer, channel_t channel);
-
-/**
- * @brief Disconnect the given channel(s) to the common inputs disconnecting all others
- * @param muliplexer pointer to a eismultiplexer struct
- * @param channel A channel to connect, multiple channels can be specified by or'ing together the chanel flags e.g. (CHANNEL_A | CHANNEL_B)
- * All channels can be dissconnected by passing CHANNEL_NONE
- * @return 0 on sucess and < 0 on failure
- */
-int eismultiplexer_disconnect_channel(struct eismultiplexer* muliplexer, channel_t channel);
-
-/**
- * @brief Returns the channels currently connected
- * @param muliplexer pointer to a eismultiplexer struct
- * @return channels connected as a bitfield
- */
-channel_t eismultiplexer_get_connected(struct eismultiplexer* muliplexer);
-
-/**
- * @brief Turns the led on the pcb on or off
- * @param muliplexer pointer to a eismultiplexer struct
- * @param on true to turn the led on, false to turn it off
- * @return 0 on sucess and < 0 on failure
- */
-int eismultiplexer_set_led(struct eismultiplexer* muliplexer, bool on);
-
-/**
- * @brief Disconnects from the eismultiplexer
- */
-void eismultiplexer_disconnect(struct eismultiplexer* muliplexer);
-
-int eismultiplexer_write_eeprom(struct eismultiplexer* muliplexer, uint16_t addr, uint16_t value);
-uint16_t eismultiplexer_read_eeprom(struct eismultiplexer* muliplexer, uint16_t addr);
-
-#ifdef __cplusplus
-}
-#endif
-
-/**
-....
-* @}
-*/
diff --git a/main.c b/main.c
index 2544d3841f4c69a2629cd29e0c7c914d24ee100f..2a77a90945e9005b252adee141ec69c88327c846 100644
--- a/main.c
+++ b/main.c
@@ -30,67 +30,169 @@
 #include <stdlib.h>
 #include <string.h>
 #include <signal.h>
-#include "eismultiplexer.h"
+
+#include "coincellhell.h"
 #include "options.h"
+#include "float.h"
+#include "usbcommands.h"
 
-static channel_t char_to_channel(char ch)
+static void print_commands(void)
 {
-	switch(ch)
+	puts("Valid commands:");
+	puts("set [HEATER] [TEMPERATURE]\t | set the temperature setpoint of the given heater");
+	puts("get [HEATER] [LOCATION]\t | get the temperature of the given heater");
+	puts("get_setpoint [HEATER]\t | get the temperature setpoint of the given heater");
+	puts("ready\t | check the ready state of all heaters");
+	puts("read [ADDRESS] [LENGTH]\t | read from the device eeprom at address");
+	puts("write [ADDRESS] [LENGTH] | write to the device eeprom at address");
+}
+
+static int convert_string_to_heater_id(const char* str)
+{
+	char* str_end;
+	long id = strtol(str, &str_end, 10);
+	if(str == str_end || id < 0 || id > 0)
 	{
-		case 'a':
-		case 'A':
-		case '1':
-			return CHANNEL_A;
-		case 'b':
-		case 'B':
-		case '2':
-			return CHANNEL_B;
-		case 'c':
-		case 'C':
-		case '3':
-			return CHANNEL_C;
-		case 'd':
-		case 'D':
-		case '4':
-			return CHANNEL_D;
-		case 'e':
-		case 'E':
-		case '5':
-			return CHANNEL_E;
-		case 'f':
-		case 'F':
-		case '6':
-			return CHANNEL_F;
-		case 'g':
-		case 'G':
-		case '7':
-			return CHANNEL_G;
-		default:
-			return CHANNEL_NONE;
+		puts("HEATER must be a whole nummber between 0 and 3");
+		return -1;
 	}
+	return id;
 }
 
-void print_commands(void)
+static float convert_string_to_temperature(const char* str)
 {
-	puts("Valid commands:");
-	puts("connect [CHANNEL]\t | connect a channels");
-	puts("disconnect [CHANNEL]\t | disconnect a channels");
-	puts("clear\t\t\t | disconnect all channels");
-	puts("connect_all\t\t | connect all channels");
-	puts("get\t\t\t | get the state of all channels");
-	puts("read [ADDRESS] [LENGTH]\t | read from the device eeprom at address");
-	puts("write [ADDRESS] [LENGTH] | write to the device eeprom at address");
+	char* str_end;
+	float temperature = strtof(str, &str_end);
+	if(str == str_end || temperature < 0 || temperature > 100)
+	{
+		puts("TEMPERATURE must be a float between 0 and 100");
+		return FLT_MIN;
+	}
+	return temperature;
+}
+
+static temperature_sensor_location_t convert_string_to_location(const char* str)
+{
+	if(strcmp(str, "both") == 0)
+		return TEMP_LOCATION_BOTH;
+	if(strcmp(str, "front") == 0)
+		return TEMP_LOCATION_FRONT;
+	if(strcmp(str, "side") == 0)
+		return TEMP_LOCATION_SIDE;
+	return TEMP_LOCATION_INVALID;
 }
 
-static int process_commands(char** commands, size_t command_count, struct eismultiplexer* multiplexer, char* name)
+static int process_commands(char** commands, size_t command_count, struct coincellhell* hell, char* name)
 {
-	if(strcmp(commands[0], "clear") == 0)
+	int ret = 0;
+
+	if(strcmp(commands[0], "help") == 0)
 	{
-		eismultiplexer_disconnect_channel(multiplexer, CHANNEL_NONE);
+		print_commands();
 	}
-	else if(strcmp(commands[0], "help") == 0)
+	else if(strcmp(commands[0], "set") == 0)
 	{
-		print_commands();
+		if(command_count < 3)
+			printf("Usage %s %s [HEATER] [TEMPERATURE]\n", name, commands[0]);
+
+		int id = convert_string_to_heater_id(commands[1]);
+		if(id < 0)
+			return 1;
+
+		float temperature = convert_string_to_temperature(commands[2]);
+		if(temperature == FLT_MIN)
+			return 2;
+
+		ret = coincellhell_set_temperature(hell, id, temperature);
+	}
+	else if(strcmp(commands[0], "get") == 0)
+	{
+		if(command_count == 1)
+		{
+			for(uint8_t i = 0; i < 4; ++i)
+			{
+				float front = 0;
+				float side = 0;
+				int err = 0;
+				err |= coincellhell_get_temperature(hell, i, TEMP_LOCATION_FRONT, &front);
+				err |= coincellhell_get_temperature(hell, i, TEMP_LOCATION_SIDE, &side);
+
+				if(!err)
+					printf("Heater %i: front temperature %f, side temperature %f, avg temperature %f\n", i, front, side, (front+side)/2);
+				else
+					printf("Heater %i: UNABLE TO READ\n", i);
+
+			}
+		}
+		else if(command_count < 3)
+		{
+			printf("Usage %s %s [HEATER] [LOCATION]\n", name, commands[0]);
+			ret = 1;
+		}
+		else
+		{
+			int id = convert_string_to_heater_id(commands[1]);
+			if(id < 0)
+				return 1;
+			temperature_sensor_location_t location = convert_string_to_location(commands[2]);
+			if(location == TEMP_LOCATION_INVALID)
+				return 2;
+
+			float temperature;
+			ret = coincellhell_get_temperature(hell, id, location, &temperature);
+			if(ret == 0)
+				printf("%f\n", temperature);
+		}
+	}
+	else if(strcmp(commands[0], "get_setpoint") == 0)
+	{
+		if(command_count == 1)
+		{
+			for(uint8_t i = 0; i < 4; ++i)
+			{
+				float setpoint = 0;
+				int err = coincellhell_get_temperature_setpoint(hell, i, &setpoint);
+				if(!err)
+					printf("Heater %i: setpoint %f\n", i, setpoint);
+				else
+					printf("Heater %i: UNABLE TO READ\n", i);
+
+			}
+		}
+		else
+		{
+			int id = convert_string_to_heater_id(commands[1]);
+			if(id < 0)
+				return 1;
+
+			float temperature;
+			ret = coincellhell_get_temperature_setpoint(hell, id, &temperature);
+			if(ret == 0)
+				printf("%f\n", temperature);
+		}
+	}
+	else if(strcmp(commands[0], "ready") == 0)
+	{
+		if(command_count == 1)
+		{
+			for(uint8_t i = 0; i < 4; ++i)
+			{
+				float setpoint = 0;
+				coincellhell_get_temperature_setpoint(hell, i, &setpoint);
+				printf("Heater %i: setpoint %f", i, setpoint);
+			}
+		}
+		else
+		{
+			int id = convert_string_to_heater_id(commands[1]);
+			if(id < 0)
+				return 1;
+
+			float temperature;
+			ret = coincellhell_get_temperature_setpoint(hell, id, &temperature);
+			if(ret == 0)
+				printf("%f\n", temperature);
+		}
 	}
 	else if(strcmp(commands[0], "write") == 0)
 	{
@@ -111,7 +213,7 @@ static int process_commands(char** commands, size_t command_count, struct eismul
 			puts("Address must be a even number, 16 bits are written at a time");
 			return 2;
 		}
-		eismultiplexer_write_eeprom(multiplexer, address, value);
+		coincellhell_write_eeprom(hell, address, value);
 	}
 	else if(strcmp(commands[0], "read") == 0)
 	{
@@ -126,8 +228,8 @@ static int process_commands(char** commands, size_t command_count, struct eismul
 			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");
+			return 2;
 		}
 		if(address % 2 == 1)
 		{
@@ -142,62 +244,24 @@ static int process_commands(char** commands, size_t command_count, struct eismul
 
 		for(uint16_t i = address; i - address < length; i+=2)
 		{
-			uint16_t value = eismultiplexer_read_eeprom(multiplexer, i);
+			uint16_t value = coincellhell_read_eeprom(hell, i);
 			printf("%u: %u\n", i, value);
 		}
 	}
-	else if(strcmp(commands[0], "connect_all") == 0)
+	else if(strcmp(commands[0], "oscal") == 0)
 	{
-		eismultiplexer_connect_channel(multiplexer, 0xff);
+		printf("OSCAL: %u\n", coincellhell_read_oscal(hell));
 	}
-	else if(strcmp(commands[0], "get") == 0)
+	else if(strcmp(commands[0], "seconds") == 0)
 	{
-		channel_t channels = eismultiplexer_get_connected(multiplexer);
-		for(size_t i = 0; i < 7; ++i)
-		{
-			bool connected = channels & (1 << i);
-			printf("Channel %c: %s\n", (char)('A'+i), connected ? "on" : "off");
-		}
+		printf("Seconds: %u\n", coincellhell_get_seconds(hell));
 	}
 	else
 	{
-		if(command_count != 2)
-		{
-			puts("A channel is required");
-			return 2;
-		}
-
-		channel_t channel =  char_to_channel(commands[1][0]);
-		if(channel == CHANNEL_NONE)
-		{
-			printf("%c is not a valid channel\n", commands[1][0]);
-			return 2;
-		}
-
-		if(strcmp(commands[0], "connect") == 0)
-		{
-			if(eismultiplexer_connect_channel(multiplexer, channel))
-			{
-				printf("could not connect channel %c\n", commands[1][0]);
-				return 3;
-			}
-		}
-		else if(strcmp(commands[0], "disconnect") == 0)
-		{
-			if(eismultiplexer_disconnect_channel(multiplexer, channel))
-			{
-				printf("could not disconnect channel %c\n", commands[1][0]);
-				return 3;
-			}
-		}
-		else
-		{
-			printf("%s is not a valid command\n", commands[0]);
-			print_commands();
-			return 3;
-		}
+		printf("%s is not a valid command!", commands[0]);
+		print_commands();
 	}
-	return 0;
+	return ret;
 }
 
 enum
@@ -249,12 +313,12 @@ int main(int argc, char* argv[])
 		return 2;
 	}
 	
-	struct eismultiplexer multiplexer;
-	if(eismultiplexer_connect(&multiplexer, config.serialSet ? config.serial : 0))
+	struct coincellhell hell;
+	if(coincellhell_connect(&hell, 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",
+		printf("Can not connect to EIShell device%s%s\n",
 			   config.serialSet ? " with serial " : "", config.serialSet ? serialStr : "");
 		return 1;
 	}
@@ -287,9 +351,9 @@ int main(int argc, char* argv[])
 				++i;
 			}
 
-			eismultiplexer_set_led(&multiplexer, true);
-			int cmdRet = process_commands(commands, i, &multiplexer, "");
-			eismultiplexer_set_led(&multiplexer, false);
+			coincellhell_set_led(&hell, true);
+			int cmdRet = process_commands(commands, i, &hell, "");
+			coincellhell_set_led(&hell, false);
 			if(cmdRet == 0)
 				puts("OK");
 			else
@@ -298,11 +362,9 @@ int main(int argc, char* argv[])
 	}
 	else
 	{
-		eismultiplexer_set_led(&multiplexer, true);
-		ret = process_commands(config.commands, config.command_count, &multiplexer, argv[0]);
-		eismultiplexer_set_led(&multiplexer, false);
+		ret = process_commands(config.commands, config.command_count, &hell, argv[0]);
 	}
 
-	eismultiplexer_disconnect(&multiplexer);
+	coincellhell_disconnect(&hell);
 	return ret;
 }
diff --git a/options.h b/options.h
new file mode 100644
index 0000000000000000000000000000000000000000..ba047114e0690c85a5ee6bb8f9344163208b4c24
--- /dev/null
+++ b/options.h
@@ -0,0 +1,109 @@
+/* * Copyright (c) 2023 Carl Klemm <carl@uvos.xyz>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *  * Neither the name of %ORGANIZATION% nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+#include <argp.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define MAX_COMMANDS 8
+
+const char *argp_program_version = "eismulitplexer_cli";
+const char *argp_program_bug_address = "<carl@uvos.xyz>";
+static char doc[] = "Applicaion to control eismultiplexer devices";
+static char args_doc[] = "COMMAND";
+
+static struct argp_option options[] =
+{
+  {"interactive",	'i', 0,				0,	"run in interactive mode" },
+  {"pipe",			'p', 0,				0,	"run in pipe mode" },
+  {"serial",		's', "[NUMMBER]",	0,	"serial number of device to connect to"},
+  {"serial",		'l', 0,	0,	"list commands"},
+  {0}
+};
+
+struct command
+{
+	char* command;
+};
+
+struct config
+{
+	bool interactive;
+	bool pipe;
+	uint16_t serial;
+	bool serialSet;
+	char* commands[MAX_COMMANDS];
+	size_t command_count;
+	bool list_commands;
+};
+
+static error_t parse_opt (int key, char *arg, struct argp_state *state)
+{
+	struct config *config = (struct config*)(state->input);
+	switch (key)
+	{
+	case 'i':
+		config->interactive = true;
+		break;
+	case 's':
+	{
+		int serial = atoi(arg);
+		if(serial < 0 || serial > UINT16_MAX )
+		{
+			argp_usage(state);
+			break;
+		}
+		config->serial = serial;
+		config->serialSet = true;
+		break;
+	}
+	case 'p':
+		config->pipe = true;
+		break;
+	case 'l':
+		config->list_commands = true;
+		break;
+	case ARGP_KEY_ARG:
+	{
+		if(config->command_count+1 > MAX_COMMANDS)
+		{
+			argp_usage(state);
+			break;
+		}
+		config->commands[config->command_count] = arg;
+		++config->command_count;
+		break;
+	}
+	default:
+		return ARGP_ERR_UNKNOWN;
+	}
+	return 0;
+}
+
+static struct argp argp = {options, parse_opt, args_doc, doc};
diff --git a/pkgconfig/eismuliplexer.pc.in b/pkgconfig/eismuliplexer.pc.in
index c181acff60ba40257e1f6a590f94e6f1e2e68248..176b49fe0a2ca7250db8eae3a4e89b4651ecead4 100644
--- a/pkgconfig/eismuliplexer.pc.in
+++ b/pkgconfig/eismuliplexer.pc.in
@@ -1,7 +1,7 @@
 includedir=@CMAKE_INSTALL_PREFIX@/include
 
 Name: libeismuliplexer
-Description: C lib to control EISmultiplexer devices
+Description: C lib to control CoincellHell devices
 Version: 1.0
-Libs: -L${libdir} -leismultiplexer
+Libs: -L${libdir} -lcoincellhell
 Cflags: -I${includedir}
diff --git a/usbcommands.h b/usbcommands.h
new file mode 100644
index 0000000000000000000000000000000000000000..0c8dff4c7ec86fb8d4b0bb5d9a33c585960bab81
--- /dev/null
+++ b/usbcommands.h
@@ -0,0 +1,24 @@
+#pragma once
+
+typedef enum {
+	COMMAND_LED_ON = 0,
+	COMMAND_LED_OFF,
+	COMMAND_SET_TEMPERATURE,
+	COMMAND_GET_TEMPERATURE,
+	COMMAND_GET_TEMPERATURE_SETPOINT,
+	COMMAND_READY,
+	COMMAND_RAMP,
+	COMMAND_RAMP_RUNNING,
+	COMMAND_RAMP_CANCLE,
+	COMMAND_GET_SECONDS = 200,
+	COMMAND_READ_EEPROM,
+	COMMAND_WRITE_EEPROM,
+	COMMAND_READ_OSCAL,
+} usb_command_t;
+
+typedef enum {
+	TEMP_LOCATION_BOTH = 0,
+	TEMP_LOCATION_FRONT,
+	TEMP_LOCATION_SIDE,
+	TEMP_LOCATION_INVALID,
+} temperature_sensor_location_t;