diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e7e9d11d4bf243bffe4bb60b4ac1f9392297f4bf
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,2 @@
+# Default ignored files
+/workspace.xml
diff --git a/.idea/TPBlockChain.iml b/.idea/TPBlockChain.iml
new file mode 100644
index 0000000000000000000000000000000000000000..8b8c395472a5a6b3598af42086e590417ace9933
--- /dev/null
+++ b/.idea/TPBlockChain.iml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="PYTHON_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+  <component name="PyDocumentationSettings">
+    <option name="format" value="PLAIN" />
+    <option name="myDocStringFormat" value="Plain" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..105ce2da2d6447d11dfe32bfb846c3d5b199fc99
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <settings>
+    <option name="USE_PROJECT_PROFILE" value="false" />
+    <version value="1.0" />
+  </settings>
+</component>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2d83d70ff8b2e7835f3dbc08bb4481dda6e86665
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (2)" project-jdk-type="Python SDK" />
+</project>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6fc7816c0da56e737083e3e383904371902517ac
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/TPBlockChain.iml" filepath="$PROJECT_DIR$/.idea/TPBlockChain.iml" />
+    </modules>
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000000000000000000000000000000000000..94a25f7f4cb416c083d265558da75d457237d671
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/TP2/.gitkeep b/TP2/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/TP2/Armoire5.py b/TP2/Armoire5.py
new file mode 100644
index 0000000000000000000000000000000000000000..605eba6bc77ff33300ddd8780fb5c1e82b0b0656
--- /dev/null
+++ b/TP2/Armoire5.py
@@ -0,0 +1,154 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Mon Jun 22 16:40:33 2020
+
+@author: chevrier6
+"""
+from bitManip import *
+from easymodbus.modbusClient import ModbusClient
+from easymodbus.modbusClient import convert_registers_to_float
+
+
+class AutomateException(Exception):
+    def __init__(self, message):
+        self.message = message
+
+
+class Armoire5():
+    # ici les adresse des mesure commence  a ZERO (pas UN comme en java)
+
+    def __init__(self):
+        self.nbCharge = 7  # de 0 a 6
+        self.ipAdresse = "100.75.155.115"
+        self.adresseMesure = 2
+        self.adresseTOR = 32000
+        self.adresseMesureSecteur1 = 7  # attention  vraie adresse ()
+        self.adresseMesureSecteur2 = 8  # attention  vraie adresse
+
+        self.debutAdrCharge = 9
+        self.debutAdrSource = 0
+
+    def okCharge(self, i):
+        return 0 <= i <= self.nbCharge - 1 ###########♦ MODIF
+
+    def resetAll(self):
+        self.writeTOR(0)
+
+    def resetSource(self):
+        for i in range(self.nbCharge):
+            self.setSource1(i)
+
+    def resetCharge(self):
+        for i in range(self.nbCharge):
+            self.unsetCharge(i)
+
+    def setCharge(self, charge: int):
+        if not self.okCharge(charge):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        val = self.readTOR()
+        val = setBit(val, charge + self.debutAdrCharge)
+        self.writeTOR(val)
+
+    def unsetCharge(self, charge):
+        if not self.okCharge(charge):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        val = self.readTOR()
+        val = clearBit(val, charge + self.debutAdrCharge)
+        self.writeTOR(val)
+
+    def toggleCharge(self, charge):
+        if not self.okCharge(charge):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        val = self.readTOR()
+        val = toggleBit(val, charge + self.debutAdrCharge)
+        self.writeTOR(val)
+
+    def setSource1(self, charge):
+        if not self.okCharge(charge):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        val = self.readTOR()
+        val = clearBit(val, charge + self.debutAdrSource)
+        self.writeTOR(val)
+
+    def setSource2(self, charge):
+        if not self.okCharge(charge):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        val = self.readTOR()
+        val = setBit(val, charge + self.debutAdrSource)
+        self.writeTOR(val)
+
+    def togglesource(self, charge):
+        if not self.okCharge(charge):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        val = self.readTOR()
+        val = toggleBit(val, charge + self.debutAdrSource)
+        self.writeTOR(val)
+
+    ################################
+
+    def writeTOR(self, val):
+        modbusclient = ModbusClient(self.ipAdresse, 502)
+        modbusclient.connect()
+        modbusclient.write_single_register(self.adresseTOR, val)
+        modbusclient.close()
+        # some tempo to wait measure to stabilize
+        from time import sleep
+        sleep(2.)
+
+    def readTOR(self):
+        modbusclient = ModbusClient(self.ipAdresse, 502)
+        modbusclient.connect()
+        inputRegisters = modbusclient.read_inputregisters(self.adresseTOR, 1)
+        modbusclient.close()
+        return (int)(inputRegisters[0])
+
+    ###############################################
+    def readSecteur1(self):
+        addr = self.adresseMesure + (self.adresseMesureSecteur1) * 8
+        return self.lireValeurAdresse(addr + 2), self.lireValeurAdresse(addr), self.lireValeurAdresse(
+            addr + 4), self.lireValeurAdresse(addr + 6)
+
+    def readSecteur2(self):
+        addr = self.adresseMesure + (self.adresseMesureSecteur2) * 8
+        return self.lireValeurAdresse(addr + 2), self.lireValeurAdresse(addr), self.lireValeurAdresse(
+            addr + 4), self.lireValeurAdresse(addr + 6)
+
+    def readMesureCourant(self, source: int):
+        if not self.okCharge(source):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        return self.lireValeur(source, 0)
+
+    def readMesureTension(self, source: int):
+        if not self.okCharge(source):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        return self.lireValeur(source, 2)
+
+    def readMesurePactive(self, source: int):
+        if not self.okCharge(source):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        return self.lireValeur(source, 4)
+
+    def readMesurePreactive(self, source: int):
+        if not self.okCharge(source):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        return self.lireValeur(source, 6)
+
+    def readMesure(self, source):
+        return self.readMesureTension(source), self.readMesureCourant(source), self.readMesurePactive(
+            source), self.readMesurePreactive(source)
+
+    def lireValeur(self, source, offset):
+
+        addr = self.adresseMesure + (source) * 8 + offset
+        return self.lireValeurAdresse(addr)
+
+    def lireValeurAdresse(self, addr):
+
+        modbusclient = ModbusClient(self.ipAdresse, 502)
+        modbusclient.connect()
+        data = modbusclient.read_holdingregisters(addr, 2)
+        modbusclient.close()
+        res = convert_registers_to_float(data)
+
+        return res[0]
+
diff --git a/TP2/Armoire6.py b/TP2/Armoire6.py
new file mode 100644
index 0000000000000000000000000000000000000000..3063525959492caf4166c676316e20a795149b51
--- /dev/null
+++ b/TP2/Armoire6.py
@@ -0,0 +1,157 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Mon Jun 22 16:40:33 2020
+
+@author: chevrier6
+"""
+from bitManip import *
+from easymodbus.modbusClient import ModbusClient
+from easymodbus.modbusClient import convert_registers_to_float
+
+class AutomateException(Exception):
+    def __init__(self, message):
+        self.message = message
+
+
+
+
+
+class Armoire6():
+    # ici les adresse des mesure commence  a ZERO (pas UN comme en java)
+
+
+    def __init__(self):
+        self.nbCharge=7 # de 0 a 6
+        self.ipAdresse="100.75.155.116"
+        self.adresseMesure=0
+        self.adresseTOR=32000
+        self.adresseMesureSecteur1=7 # attention  vraie adresse ()
+        self.adresseMesureSecteur2=8 # attention  vraie adresse
+
+        self.debutAdrCharge=0
+        self.debutAdrSource=7
+
+    def okCharge(self,i):
+        return 0 <= i <= self.nbCharge-1
+    
+    def resetAll(self):
+        self.writeTOR(0)
+    
+    def resetSource(self):
+        for i in range(self.nbCharge):
+            self.setSource1(i)
+    
+    def resetCharge(self):
+        for i in range(self.nbCharge):
+            self.unsetCharge(i)
+            
+    def setCharge(self, charge : int ):
+        if not self.okCharge(charge):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        val=self.readTOR()
+        val=setBit(val,charge+self.debutAdrCharge)
+        self.writeTOR(val)
+    
+
+    def unsetCharge(self,charge):
+        if not self.okCharge(charge):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        val=self.readTOR()
+        val=clearBit(val,charge+self.debutAdrCharge)
+        self.writeTOR(val)
+
+    def toggleCharge(self, charge):
+        if not self.okCharge(charge):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        val = self.readTOR()
+        val = toggleBit(val, charge+self.debutAdrCharge)
+        self.writeTOR(val)
+    
+    def setSource1(self,charge):
+        if not self.okCharge(charge):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        val=self.readTOR()
+        val=clearBit(val,charge+self.debutAdrSource)
+        self.writeTOR(val)
+
+    def setSource2(self, charge):
+        if not self.okCharge(charge):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        val = self.readTOR()
+        val = setBit(val, charge +self.debutAdrSource)
+        self.writeTOR(val)
+
+
+  
+    def togglesource(self,charge):
+        if not self.okCharge(charge):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        val=self.readTOR()
+        val=toggleBit(val,charge+self.debutAdrSource)
+        self.writeTOR(val)
+    
+    ################################
+    
+    
+    def writeTOR(self,val):
+        modbusclient =ModbusClient(self.ipAdresse,502)
+        modbusclient.connect()
+        modbusclient.write_single_register(self.adresseTOR,val)
+        modbusclient.close()
+        # some tempo to wait measure to stabilize
+        from time import sleep
+        sleep(2.)
+    
+    
+    def readTOR(self):
+        modbusclient =ModbusClient(self.ipAdresse,502)
+        modbusclient.connect()
+        inputRegisters = modbusclient.read_inputregisters(self.adresseTOR, 1)
+        modbusclient.close()
+        return (int)(inputRegisters[0])
+        
+###############################################
+    def readSecteur1(self):
+        from time import sleep
+        addr = self.adresseMesure  + (self.adresseMesureSecteur1 ) * 8
+        return self.lireValeurAdresse(addr + 2), self.lireValeurAdresse(addr), self.lireValeurAdresse(addr + 4), self.lireValeurAdresse(addr + 6)
+    def readSecteur2(self):
+        addr = self.adresseMesure  + (self.adresseMesureSecteur2 ) * 8
+        return self.lireValeurAdresse(addr+2),self.lireValeurAdresse(addr),self.lireValeurAdresse(addr+4),self.lireValeurAdresse(addr+6)
+        
+    def readMesureCourant(self,source :int):
+        if not self.okCharge(source):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        return self.lireValeur(source,0 )
+    def readMesureTension(self,source :int):
+        if not self.okCharge(source):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        return self.lireValeur(source,2 )
+    def readMesurePactive(self,source :int):
+        if not self.okCharge(source):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        return self.lireValeur(source,4 )
+    def readMesurePreactive(self,source :int):
+        if not self.okCharge(source):
+            raise AutomateException("numero charge pas compris entre 0 et 6")
+        return self.lireValeur(source,6 )
+
+    def readMesure(self,source):
+        return self.readMesureTension(source),self.readMesureCourant(source),self.readMesurePactive(source),self.readMesurePreactive(source)
+   
+    def lireValeur(self,source,offset):
+
+        addr=  self.adresseMesure  + (source ) *8+offset
+        return self.lireValeurAdresse(addr)
+    def lireValeurAdresse(self,addr):
+
+
+        modbusclient =ModbusClient(self.ipAdresse,502)
+        modbusclient.connect()
+        data=modbusclient.read_holdingregisters(addr,2)
+        modbusclient.close()
+        res =convert_registers_to_float(data)
+       
+        return res[0]
+        
+        
\ No newline at end of file
diff --git a/TP2/__pycache__/Armoire5.cpython-38.pyc b/TP2/__pycache__/Armoire5.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..dc0c29328822cc7d2ab02fa499ac18483c67c216
Binary files /dev/null and b/TP2/__pycache__/Armoire5.cpython-38.pyc differ
diff --git a/TP2/__pycache__/Armoire5.cpython-39.pyc b/TP2/__pycache__/Armoire5.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..750a157ccd1c8ff5791bae08ab9b2a2cd5680ab4
Binary files /dev/null and b/TP2/__pycache__/Armoire5.cpython-39.pyc differ
diff --git a/TP2/__pycache__/Armoire6.cpython-38.pyc b/TP2/__pycache__/Armoire6.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b54c26efa12a459cc6a298cb10fb4044e8f975d8
Binary files /dev/null and b/TP2/__pycache__/Armoire6.cpython-38.pyc differ
diff --git a/TP2/__pycache__/Armoire6.cpython-39.pyc b/TP2/__pycache__/Armoire6.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f9cc62dd27f5c43adea4b6064ad935f7c989130b
Binary files /dev/null and b/TP2/__pycache__/Armoire6.cpython-39.pyc differ
diff --git a/TP2/__pycache__/bitManip.cpython-38.pyc b/TP2/__pycache__/bitManip.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..57fc49c64a676aabb5e2291b23cca6cb93d92c66
Binary files /dev/null and b/TP2/__pycache__/bitManip.cpython-38.pyc differ
diff --git a/TP2/__pycache__/bitManip.cpython-39.pyc b/TP2/__pycache__/bitManip.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..2da8f09a8e9dbcb2193a38cc1d2dfc191a8a9410
Binary files /dev/null and b/TP2/__pycache__/bitManip.cpython-39.pyc differ
diff --git a/TP2/bitManip.py b/TP2/bitManip.py
new file mode 100644
index 0000000000000000000000000000000000000000..2f8ceb26ce056109e127d98f179d807daf0acc0f
--- /dev/null
+++ b/TP2/bitManip.py
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Mon Jun 22 16:43:58 2020
+
+@author: chevrier6
+"""
+
+######################
+def mask16(v):
+    "same as setBit(v,0)"
+    b=1
+    for i in range(v):
+        b*=2
+    return b
+
+# 4 next functions from https://wiki.python.org/moin/BitManipulation
+# testBit() returns a nonzero result, 2**offset, if the bit at 'offset' is one.
+def testBit(int_type, offset):
+    mask = 1 << offset
+    return(int_type & mask)
+
+  # setBit() returns an integer with the bit at 'offset' set to 1.
+
+def setBit(int_type, offset):
+    mask = 1 << offset
+    return(int_type | mask)
+
+ # clearBit() returns an integer with the bit at 'offset' cleared.
+
+def clearBit(int_type, offset):
+    mask = ~(1 << offset)
+    return(int_type & mask)
+
+ # toggleBit() returns an integer with the bit at 'offset' inverted, 0 -> 1 and 1 -> 0.
+
+def toggleBit(int_type, offset):
+    mask = 1 << offset
+    return(int_type ^ mask)
\ No newline at end of file
diff --git a/TP2/docArmoirePython.md b/TP2/docArmoirePython.md
new file mode 100644
index 0000000000000000000000000000000000000000..95dcaa37bce4bb21c22dbbf1a0cdd999900f58d4
--- /dev/null
+++ b/TP2/docArmoirePython.md
@@ -0,0 +1,43 @@
+# Une armoire c'est quoi ?
+
+- c'est un appareil électrique commandable à distance
+- il dispose de 7 charges différentes (numérotées de 0 à 6)  et de deux source d'alimentation 
+(source1 et source2)
+
+- chaque charge peut être en marche ou pas et soit sur source 1 soit sur source 2 indépendament des autres
+- on peut connaitre des infos sur chaque charges (U,I,P,PR) et sur chaque source (i.e. le cumul des charges en marche sur la source concernée)
+# Documentation code python de manipulation des armoires
+
+
+## Prerequis logiciel
+
+- utilisation de la librairie EasyModbus.py
+- utilisation d'un code bitManip.py
+
+## Code disponible
+
+### Note
+Actuellemnt seul le code pour l'armoire 6 est opérationnel
+
+### Utilisation
+
+- charger le fichier correspondant à l'armoire à utiliser (exemple Armoire6.py) et ses dépendances
+
+**Méthodes**
+
+* Constructeur *ArmoireX()* où X vaut 6
+
+* actions générales
+    - **resetAll**: remet tout à l'état d'origine
+    - **resetSource** / **resetCharge**: remet la partie source/charge à l'état d'origine
+ * actions sur les charges  
+    - **setCharge** / **unsetCharge** / **toggleCharge**(*n°charge*): met sur ON/OFF/état inverse la charge. *N°charge* doit être compris entre 0 et 6
+* Actions sur les sources
+    - **setSource1** / **setSource2** / **togglesource**(*n°charge*): met sur l'alimentaion 1/l'alimentation 2/inverse la source. *N°charge* doit être compris entre 0 et 6
+* Actions sur les sources
+   
+* lecture de valeurs (
+retourne une liste de valeurs  [U,I,PA,PR])
+    - **readSecteur1**: mesure pour la source 1
+    - **readSecteur2**: mesure pour la source 2
+    - **readMesure**(*n°charge*): mesure pour la charge paramètre (compris en 0 et 6)
\ No newline at end of file
diff --git a/TP2/easymodbus/__init__.py b/TP2/easymodbus/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..5f434bb496ed6a57a145aba0d9dad799cb91861c
--- /dev/null
+++ b/TP2/easymodbus/__init__.py
@@ -0,0 +1,3 @@
+#Only required for Python 2:
+#We Make an empty file called __init__.py in the same directory as the files.
+#That will signify to Python that it's "ok to import from this directory".
diff --git a/TP2/easymodbus/__pycache__/__init__.cpython-38.pyc b/TP2/easymodbus/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..793146fc0b6713b49233b6cc0dc4fc92f3c85bd2
Binary files /dev/null and b/TP2/easymodbus/__pycache__/__init__.cpython-38.pyc differ
diff --git a/TP2/easymodbus/__pycache__/modbusClient.cpython-38.pyc b/TP2/easymodbus/__pycache__/modbusClient.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c2e7f7cbf118af50ede25a74b3a23406cf228087
Binary files /dev/null and b/TP2/easymodbus/__pycache__/modbusClient.cpython-38.pyc differ
diff --git a/TP2/easymodbus/__pycache__/modbusException.cpython-38.pyc b/TP2/easymodbus/__pycache__/modbusException.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0dee22613bc74e0574fbf40c102b00e23c6f30c1
Binary files /dev/null and b/TP2/easymodbus/__pycache__/modbusException.cpython-38.pyc differ
diff --git a/TP2/easymodbus/easyModbusGUI.py b/TP2/easymodbus/easyModbusGUI.py
new file mode 100644
index 0000000000000000000000000000000000000000..fedeb5e5db2ac3142f01cc62c15616630a177b71
--- /dev/null
+++ b/TP2/easymodbus/easyModbusGUI.py
@@ -0,0 +1,308 @@
+#!/usr/bin/env python
+
+import sys
+
+if sys.version_info[0] < 3:                 #The Module "Tkinter" is named "tkinter" in Python 3.
+    from Tkinter import *
+    import tkMessageBox as messagebox       #We import tkMessageBos as messagebox, because thats the name in Python 3
+
+else:
+    from tkinter import *
+    from builtins import int
+    from future.moves import tkinter
+    import tkinter.messagebox as messagebox
+from easymodbus.modbusClient import *
+
+class EasyModbusGUI(Frame):
+    def __init__(self, master=None):
+        Frame.__init__(self)
+        master.title("EasyModbusPython Client")
+        self.pack()
+        self.createWidgets()
+        
+        
+    def createWidgets(self):
+        self.pack(fill=BOTH, expand=True)
+                
+        self.columnconfigure(1, weight=1)
+        self.columnconfigure(3, pad=7)
+        self.rowconfigure(3, weight=1)
+        self.rowconfigure(5, pad=7)
+        
+        #label Read operations
+        readOperationsLabel = Label(self, text="Read Operations", font = 15)
+        readOperationsLabel.config(font=15)
+        readOperationsLabel.grid(row = 0, column = 0)
+        
+        #Button Read Coils
+        self.readCoils = Button(self, text="Read Coils (FC1)", width=25, command=self.__ReadCoils)
+        self.readCoils.grid(row = 4, column = 0, padx = 20, pady = 6, columnspan=2)
+        
+        #Button Read Discrete Inputs
+        self.readDiscreteInputs = Button(self, text="Read Discrete Inputs (FC2)", width=25, command=self.__ReadDiscreteInputs)
+        self.readDiscreteInputs.grid(row = 5, column = 0, padx = 20, pady = 6, columnspan=2)
+        
+        #Button Read Holding Registers
+        self.readHoldingRegisters = Button(self, text="Read Holding Registers (FC3)", width=25, command=self.__ReadHoldingRegisters)
+        self.readHoldingRegisters.grid(row = 6, column = 0, padx = 20, pady = 6, columnspan=2)
+ 
+        #Button Read Input Registers
+        self.readInputRegisters = Button(self, text="Read Input Registers (FC4)", width=25, command=self.__ReadInputRegisters)
+        self.readInputRegisters.grid(row = 7, column = 0, padx = 20, pady = 6, columnspan=2)       
+        
+        #label for IP Addresses
+        label = Label(self, text="IP-Address:")
+        label.grid(row = 2, column = 0, sticky=W)
+        
+        #Entry for IPAddress
+        self.ipAddressEntry = Entry(self, width=15)
+        self.ipAddressEntry.insert(END, "127.0.0.1")
+        self.ipAddressEntry.grid(row = 3, column = 0, sticky=W)
+        
+        #label for Display Port
+        labelPort = Label(self, text="Port:")
+        labelPort.grid(row = 2, column = 1, sticky=W)
+        
+        #Text Field for Port
+        self.portEntry = Entry(self, width=10)
+        self.portEntry.insert(END, "502")
+        self.portEntry.grid(row = 3, column = 1, sticky=W)
+
+        #label for Display Starting Address
+        labelStartingAddress = Label(self, text="Starting Address:")
+        labelStartingAddress.grid(row = 4, column = 3, sticky=W)
+        
+        #Text Field for starting Address
+        self.startingAddress = Entry(self, width=10)
+        self.startingAddress.insert(END, "1")
+        self.startingAddress.grid(row = 4, column = 4, sticky=W)
+
+        #label for Display Number of values
+        labelStartingAddress = Label(self, text="Number of values:")
+        labelStartingAddress.grid(row = 5, column = 3, sticky=W)
+        
+        #Text Field for number of Values
+        self.quantity = Entry(self, width=10)
+        self.quantity.insert(END, "1")
+        self.quantity.grid(row = 5, column = 4, sticky=W)
+
+        #label for Response from server
+        labelResponse = Label(self, text="Response from Server")
+        labelResponse.grid(row = 2, column = 5, sticky=W, padx = 10)        
+    
+        #Text Field for response from server
+        self.response = StringVar
+        self.responseTextField = Text(self,  width=35, height = 10)
+        scroll = Scrollbar(self, command=self.responseTextField.yview)
+        self.responseTextField.configure(yscrollcommand=scroll.set)
+        self.responseTextField.insert(END, "")
+        self.responseTextField.grid(row = 2, column = 5, rowspan=8, padx = 10) 
+        scroll.grid(row = 3, column = 6, rowspan=5, sticky=N+S+E)
+        
+        #Empty row between Read and Write operations
+        self.rowconfigure(15, minsize=20)
+        
+        #label Write operations
+        readOperationsLabel = Label(self, text="Write Operations", font = 15)
+        readOperationsLabel.config(font=15)
+        readOperationsLabel.grid(row = 20, column = 0)
+        
+        #Label select datatye to write
+        datatype = Label(self, text="Select datatype to write")
+        datatype.grid(row = 25, column = 0,  sticky=W)       
+
+        #Combobox to selct the type of variable to write 
+        lst1 = ['Coils (bool)','Holding Registers (word)']
+        self.variableDatatype = StringVar(self)
+        self.variableDatatype.set('Coils (bool)')
+        self.variableDatatype.trace('w',self.datatypeChanged)
+        dropdown = OptionMenu(self,self.variableDatatype,*lst1)
+        dropdown.grid(row = 25, column = 1,columnspan = 3,  sticky=W)
+
+        #Label select value to write
+        datatype = Label(self, text="Select value to write")
+        datatype.grid(row = 26, column = 0, sticky=W)   #
+        
+        #Combobox to selct true or false in case "coils" has been selcted
+        lst1 = ['FALSE', 'TRUE']
+        self.variableData = StringVar(self)
+        self.variableData.set('FALSE')
+        self.dropdownData = OptionMenu(self,self.variableData,*lst1)
+        self.dropdownData.grid(row = 26, column = 1, sticky=W)
+        
+        #TextField for the Register Values to write
+        self.registerValueToWrite = Entry(self, width=10)
+        self.registerValueToWrite.insert(END, "1")
+        
+        #label for Display startingAddress
+        labelStartingAddress = Label(self, text="Starting Address:")
+        labelStartingAddress.grid(row = 27, column = 0, sticky=W)
+        
+        #Text Field for starting Address
+        self.startingAddressWrite = Entry(self, width=10)
+        self.startingAddressWrite.insert(END, "1")
+        self.startingAddressWrite.grid(row = 27, column = 1, sticky=W)
+        
+        #label for Request to Server
+        labelResponse = Label(self, text="Request to Server")
+        labelResponse.grid(row = 24, column = 5, sticky=W, padx = 10)     
+        
+        #Text Field containing data to write to server
+        self.request = StringVar
+        self.requestTextField = Text(self,  width=35, height = 10)
+        scroll = Scrollbar(self, command=self.requestTextField.yview)
+        self.requestTextField.configure(yscrollcommand=scroll.set)
+        self.requestTextField.insert(END, "")
+        self.requestTextField.grid(row = 25, column = 5, rowspan=8, padx = 10) 
+        scroll.grid(row = 25, column = 6, rowspan=8, sticky=N+S+E)
+        
+        #Button Add Entry to request list
+        self.addEntryToRequestList = Button(self, text="Add Value to \n request list", width=15, command=self.addValueToRequestList)
+        self.addEntryToRequestList.grid(row = 26, column = 3,columnspan = 2)
+        
+        #Button Delete Entry from request list
+        self.addEntryToRequestList = Button(self, text="Delete Value from \n request list", width=15, command=self.deleteValueToRequestList)
+        self.addEntryToRequestList.grid(row = 28, column = 3,columnspan = 2)
+                
+        
+        #Button Write values to server
+        writeValuesToServerButton = Button(self, text="Write Requested Values to Server", width=25, command=self.__writeValuesToServer)
+        writeValuesToServerButton.grid(row = 30, column = 0, padx = 20, pady = 6, columnspan=2)
+        
+    def addValueToRequestList(self):
+        if (self.variableDatatype.get()  == 'Coils (bool)'):
+            self.requestTextField.insert(END, self.variableData.get())  
+            self.requestTextField.insert(END, "\n")
+        else:
+            self.requestTextField.insert(END, self.registerValueToWrite.get())  
+            self.requestTextField.insert(END, "\n")          
+        
+        
+    def datatypeChanged(self,a,b,c):
+        self.requestTextField.delete('1.0', END)
+        if (self.variableDatatype.get()  == 'Coils (bool)'):
+            self.registerValueToWrite.grid_remove()
+            self.dropdownData.grid(row = 26, column = 1, sticky=W)
+        else:
+            self.registerValueToWrite.grid(row = 26, column = 1, sticky=W)
+            self.dropdownData.grid_remove()
+           
+    def onReverse(self):
+        self.name.set(self.name.get()[::-1])
+      
+    def __ReadCoils(self):
+        try:
+            modbusClient = ModbusClient(self.ipAddressEntry.get(), int(self.portEntry.get()))
+            if (not modbusClient.is_connected()):
+                modbusClient.connect()
+            coils = modbusClient.read_coils(int(self.startingAddress.get()) - 1, int(self.quantity.get()))
+            self.responseTextField.delete('1.0', END)
+            for coil in coils:
+                if (coil == FALSE):
+                    response = "FALSE"
+                else:
+                    response = "TRUE"
+                
+                self.responseTextField.insert(END, response  + "\n")
+        except Exception as e:
+            messagebox.showerror('Exception Reading coils from Server', str(e))
+        finally:
+            modbusClient.close()
+        
+    def __ReadDiscreteInputs(self):
+        try:
+            modbusClient = ModbusClient(self.ipAddressEntry.get(), int(self.portEntry.get()))
+            if (not modbusClient.is_connected()):
+                modbusClient.connect()
+            discrInputs = modbusClient.read_discreteinputs(int(self.startingAddress.get()) - 1, int(self.quantity.get()))
+            self.responseTextField.delete('1.0', END)
+            for inp in discrInputs:
+                if (inp == FALSE):
+                    response = "FALSE"
+                else:
+                    response = "TRUE"
+                
+                self.responseTextField.insert(END, response  + "\n")
+        except Exception as e:
+            messagebox.showerror('Exception Reading discrete inputs from Server', str(e))
+        finally:
+            modbusClient.close() 
+   
+    def __ReadHoldingRegisters(self):
+        try:
+            modbusClient = ModbusClient(self.ipAddressEntry.get(), int(self.portEntry.get()))
+            if (not modbusClient.is_connected()):
+                modbusClient.connect()
+            holdingRegisters = modbusClient.read_holdingregisters(int(self.startingAddress.get()) - 1, int(self.quantity.get()))
+            self.responseTextField.delete('1.0', END)
+            for register in holdingRegisters:
+     
+                
+                self.responseTextField.insert(END, str(register)  + "\n")
+        except Exception as e:
+            messagebox.showerror('Exception Reading holding registers from Server', str(e))
+        
+        finally:
+            modbusClient.close()   
+        
+    def __ReadInputRegisters(self):
+        try:
+            modbusClient = ModbusClient(self.ipAddressEntry.get(), int(self.portEntry.get()))
+            if (not modbusClient.is_connected()):
+                modbusClient.connect()
+            inputRegisters = modbusClient.read_inputregisters(int(self.startingAddress.get()) - 1, int(self.quantity.get()))
+            self.responseTextField.delete('1.0', END)
+            for register in inputRegisters:
+                
+                self.responseTextField.insert(END, str(register)  + "\n")
+            
+            modbusClient.close()   
+        except Exception as e:
+            messagebox.showerror('Exception Reading input Registers from Server', str(e))
+      
+    def __writeValuesToServer(self):
+        try:
+            modbusClient = ModbusClient(self.ipAddressEntry.get(), int(self.portEntry.get()))
+            if (not modbusClient.is_connected()):
+                modbusClient.connect()
+            numberOfLines = (int(self.requestTextField.index('end').split('.')[0]) - 2)
+            if (self.variableDatatype.get()  == 'Coils (bool)'):
+                if (numberOfLines > 1):
+                    valueToWrite = list()
+                    for i in range(1, numberOfLines+1):
+                        textFieltValues = str(self.requestTextField.get(str(i)+".0", str(i+1)+".0")[:-1])
+                        if "TRUE" in textFieltValues:           #String comparison contains some ""Null" symbol
+                            valueToWrite.append(1)
+                        else:
+                            valueToWrite.append(0)
+                    modbusClient.write_multiple_coils(int(self.startingAddressWrite.get()) - 1, valueToWrite)
+                else:              
+                    textFieltValues = str(self.requestTextField.get('1.0', END)[:-1])
+                    if "TRUE" in textFieltValues:               #String comparison contains some ""Null" symbol
+                        dataToSend = 1
+                    else:
+                        dataToSend = 0
+                    modbusClient.write_single_coil(int(self.startingAddressWrite.get()) - 1, dataToSend)
+            else:
+                if (numberOfLines > 1):
+                    valueToWrite = list()
+                    for i in range(1, numberOfLines+1):
+                        textFieltValues = int(self.requestTextField.get(str(i)+".0", str(i+1)+".0")[:-1])
+                        valueToWrite.append(textFieltValues)
+                    modbusClient.write_multiple_registers(int(self.startingAddressWrite.get()) - 1, valueToWrite)
+                else:              
+                    textFieltValues = int(self.requestTextField.get('1.0', END)[:-1])
+                    modbusClient.write_single_register(int(self.startingAddressWrite.get()) - 1, textFieltValues)
+        except Exception as e:
+            messagebox.showerror('Exception writing values to Server', str(e))
+        modbusClient.close()
+        
+    def deleteValueToRequestList(self):
+        numberOfLines = (int(self.requestTextField.index('end').split('.')[0]) - 2)
+        cursorPos = int(self.requestTextField.index(INSERT)[0])                     #Find the current Cursorposition e.g. 1.0 -> First line
+        if (cursorPos-1 != numberOfLines):            #don't delete the last line, because the last line contains only a "newline"
+            self.requestTextField.delete(str(cursorPos)+".0",str(cursorPos+1)+".0")     #Delete the whole line using e.g. delete("1.0","2.0) deletes the first line
+      
+root = Tk()
+app = EasyModbusGUI(root)
+app.mainloop()
\ No newline at end of file
diff --git a/TP2/easymodbus/modbusClient.py b/TP2/easymodbus/modbusClient.py
new file mode 100644
index 0000000000000000000000000000000000000000..8801033441781b4ccaa90a16dbb43c2bc4889c1d
--- /dev/null
+++ b/TP2/easymodbus/modbusClient.py
@@ -0,0 +1,1048 @@
+'''
+Created on 12.09.2016
+
+@author: Stefan Rossmann
+'''
+import importlib
+import easymodbus.modbusException as Exceptions
+import socket
+import struct
+import threading
+
+
+class ModbusClient(object):
+    """
+    Implementation of a Modbus TCP Client and a Modbus RTU Master
+    """
+
+    def __init__(self, *params):
+        """
+        Constructor for Modbus RTU (serial line):
+        modbusClient = ModbusClient.ModbusClient('COM1')
+        First Parameter is the serial Port 
+        
+        Constructor for Modbus TCP:
+        modbusClient = ModbusClient.ModbusClient('127.0.0.1', 502)
+        First Parameter ist the IP-Address of the Server to connect to
+        Second Parameter is the Port the Server listens to
+        """
+        self.__receivedata = bytearray()
+        self.__transactionIdentifier = 0
+        self.__unitIdentifier = 1
+        self.__timeout = 5
+        self.__ser = None
+        self.__tcpClientSocket = None
+        self.__connected = False
+        # Constructor for RTU
+        if len(params) == 1 & isinstance(params[0], str):
+            serial = importlib.import_module("serial")
+            self.serialPort = params[0]
+            self.__baudrate = 9600
+            self.__parity = Parity.even
+            self.__stopbits = Stopbits.one
+            self.__transactionIdentifier = 0
+            self.__ser = serial.Serial()
+
+        # Constructor for TCP
+        elif (len(params) == 2) & isinstance(params[0], str) & isinstance(params[1], int):
+            self.__tcpClientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            self.__ipAddress = params[0]
+            self.__port = params[1]
+
+    def connect(self):
+        """
+        Connects to a Modbus-TCP Server or a Modbus-RTU Slave with the given Parameters
+        """
+        if self.__ser is not None:
+            serial = importlib.import_module("serial")
+            if self.__stopbits == 0:
+                self.__ser.stopbits = serial.STOPBITS_ONE
+            elif self.__stopbits == 1:
+                self.__ser.stopbits = serial.STOPBITS_TWO
+            elif self.__stopbits == 2:
+                self.__ser.stopbits = serial.STOPBITS_ONE_POINT_FIVE
+            if self.__parity == 0:
+                self.__ser.parity = serial.PARITY_EVEN
+            elif self.__parity == 1:
+                self.__ser.parity = serial.PARITY_ODD
+            elif self.__parity == 2:
+                self.__ser.parity = serial.PARITY_NONE
+
+            self.__ser = serial.Serial(self.serialPort, self.__baudrate, timeout=self.__timeout,
+                                       parity=self.__ser.parity, stopbits=self.__ser.stopbits, xonxoff=0, rtscts=0)
+            self.__ser.writeTimeout = self.__timeout
+        # print (self.ser)
+        if self.__tcpClientSocket is not None:
+            self.__tcpClientSocket.settimeout(5)
+            self.__tcpClientSocket.connect((self.__ipAddress, self.__port))
+
+            self.__connected = True
+            self.__thread = threading.Thread(target=self.__listen, args=())
+            self.__thread.start()
+
+    def __listen(self):
+        self.__stoplistening = False
+        self.__receivedata = bytearray()
+        try:
+            while not self.__stoplistening:
+                if len(self.__receivedata) == 0:
+                    self.__receivedata = bytearray()
+                    self.__timeout = 500
+                    if self.__tcpClientSocket is not None:
+                        self.__receivedata = self.__tcpClientSocket.recv(256)
+        except socket.timeout:
+            self.__receivedata = None
+
+    def close(self):
+        """
+        Closes Serial port, or TCP-Socket connection
+        """
+        if self.__ser is not None:
+            self.__ser.close()
+        if self.__tcpClientSocket is not None:
+            self.__stoplistening = True
+            self.__tcpClientSocket.shutdown(socket.SHUT_RDWR)
+            self.__tcpClientSocket.close()
+        self.__connected = False
+
+    def read_discreteinputs(self, starting_address, quantity):
+        """
+        Read Discrete Inputs from Master device (Function code 2)
+        starting_address: First discrete input to be read
+        quantity: Numer of discrete Inputs to be read
+        returns: Boolean Array [0..quantity-1] which contains the discrete Inputs
+        """
+        self.__transactionIdentifier += 1
+        if self.__ser is not None:
+            if self.__ser.closed:
+                raise Exception.SerialPortNotOpenedException("serial port not opened")
+        if (starting_address > 65535) | (quantity > 2000):
+            raise ValueError("Starting address must be 0 - 65535; quantity must be 0 - 2000")
+        function_code = 2
+        length = 6
+        transaction_identifier_lsb = self.__transactionIdentifier & 0xFF
+        transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8)
+        length_lsb = length & 0xFF
+        length_msb = (length & 0xFF00) >> 8
+        starting_address_lsb = starting_address & 0xFF
+        starting_address_msb = (starting_address & 0xFF00) >> 8
+        quantity_lsb = quantity & 0xFF
+        quantity_msb = (quantity & 0xFF00) >> 8
+        if self.__ser is not None:
+            data = bytearray(
+                [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, quantity_msb,
+                 quantity_lsb, 0, 0])
+            crc = self.__calculateCRC(data, len(data) - 2, 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            data[6] = crcLSB
+            data[7] = crcMSB
+            self.__ser.write(data)
+            if quantity % 8 != 0:
+                bytes_to_read = 6 + int(quantity / 8)
+            else:
+                bytes_to_read = 5 + int(quantity / 8)
+            data = self.__ser.read(bytes_to_read)
+            b = bytearray(data)
+            data = b
+            if len(data) < bytes_to_read:
+                raise Exceptions.TimeoutError('Read timeout Exception')
+            if (data[1] == 0x82) & (data[2] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1] == 0x82) & (data[2] == 0x02):
+                raise Exceptions.starting_addressInvalidException(
+                    "Starting address invalid or starting address + quantity invalid")
+            if (data[1] == 0x82) & (data[2] == 0x03):
+                raise Exceptions.QuantityInvalidException("quantity invalid")
+            if (data[1] == 0x82) & (data[2] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+            crc = self.__calculateCRC(data, len(data) - 2, 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]):
+                raise Exceptions.CRCCheckFailedException("CRC check failed")
+            myList = list()
+            for i in range(0, quantity):
+                myList.append(bool((data[int(i / 8) + 3] >> int(i % 8)) & 0x1))
+            return myList
+        else:
+            protocolIdentifierLSB = 0x00
+            protocolIdentifierMSB = 0x00
+            length_lsb = 0x06
+            length_msb = 0x00
+            data = bytearray(
+                [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB,
+                 length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb,
+                 starting_address_lsb, quantity_msb, quantity_lsb])
+            self.__tcpClientSocket.send(data)
+            self.__receivedata = bytearray()
+            if quantity % 8 != 0:
+                bytes_to_read = 9 + int(quantity / 8)
+            else:
+                bytes_to_read = 8 + int(quantity / 8)
+            try:
+                while len(self.__receivedata) == 0:
+                    pass
+            except Exception:
+                raise Exception('Read Timeout')
+
+            data = bytearray(self.__receivedata)
+
+            if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x02):
+                raise Exceptions.starting_addressInvalidException(
+                    "Starting address invalid or starting address + quantity invalid")
+            if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x03):
+                raise Exceptions.QuantityInvalidException("quantity invalid")
+            if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+            myList = list()
+            for i in range(0, quantity):
+                myList.append(bool((data[int(i / 8) + 3 + 6] >> int(i % 8)) & 0x1))
+            return myList
+
+    def read_coils(self, starting_address, quantity):
+        """
+        Read Coils from Master device (Function code 1)
+        starting_address:  First coil to be read
+        quantity: Numer of coils to be read
+        returns:  Boolean Array [0..quantity-1] which contains the coils
+        """
+        self.__transactionIdentifier += 1
+        if self.__ser is not None:
+            if self.__ser.closed:
+                raise Exception.SerialPortNotOpenedException("serial port not opened")
+        if (starting_address > 65535) | (quantity > 2000):
+            raise ValueError("Starting address must be 0 - 65535; quantity must be 0 - 2000")
+        function_code = 1
+        length = 6
+        transaction_identifier_lsb = self.__transactionIdentifier & 0xFF
+        transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8)
+        length_lsb = length & 0xFF
+        length_msb = (length & 0xFF00) >> 8
+        starting_address_lsb = starting_address & 0xFF
+        starting_address_msb = (starting_address & 0xFF00) >> 8
+        quantity_lsb = quantity & 0xFF
+        quantity_msb = (quantity & 0xFF00) >> 8
+        if self.__ser is not None:
+            data = bytearray(
+                [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, quantity_msb,
+                 quantity_lsb, 0, 0])
+            crc = self.__calculateCRC(data, len(data) - 2, 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            data[6] = crcLSB
+            data[7] = crcMSB
+            self.__ser.write(data)
+            if quantity % 8 != 0:
+                bytes_to_read = 6 + int(quantity / 8)
+            else:
+                bytes_to_read = 5 + int(quantity / 8)
+            data = self.__ser.read(bytes_to_read)
+            b = bytearray(data)
+            data = b
+            if len(data) < bytes_to_read:
+                raise Exceptions.TimeoutError('Read timeout Exception')
+            if (data[1] == 0x81) & (data[2] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1] == 0x81) & (data[2] == 0x02):
+                raise Exceptions.starting_addressInvalidException(
+                    "Starting address invalid or starting address + quantity invalid")
+            if (data[1] == 0x81) & (data[2] == 0x03):
+                raise Exceptions.QuantityInvalidException("quantity invalid")
+            if (data[1] == 0x81) & (data[2] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+            crc = self.__calculateCRC(data, len(data) - 2, 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]):
+                raise Exceptions.CRCCheckFailedException("CRC check failed")
+            myList = list()
+            for i in range(0, quantity):
+                myList.append(bool((data[int(i / 8) + 3] >> int(i % 8)) & 0x1))
+            return myList
+        else:
+            protocolIdentifierLSB = 0x00
+            protocolIdentifierMSB = 0x00
+            length_lsb = 0x06
+            length_msb = 0x00
+            data = bytearray(
+                [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB,
+                 length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb,
+                 starting_address_lsb, quantity_msb, quantity_lsb])
+            self.__tcpClientSocket.send(data)
+            self.__receivedata = bytearray()
+            if (quantity % 8 != 0):
+                bytes_to_read = 10 + int(quantity / 8)
+            else:
+                bytes_to_read = 9 + int(quantity / 8)
+            try:
+                while len(self.__receivedata) == 0:
+                    pass
+            except Exception:
+                raise Exception('Read Timeout')
+            data = bytearray(self.__receivedata)
+            if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x02):
+                raise Exceptions.starting_addressInvalidException(
+                    "Starting address invalid or starting address + quantity invalid")
+            if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x03):
+                raise Exceptions.QuantityInvalidException("quantity invalid")
+            if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+            myList = list()
+            for i in range(0, quantity):
+                myList.append(bool((data[int(i / 8) + 3 + 6] >> int(i % 8)) & 0x1))
+            return myList
+
+    def read_holdingregisters(self, starting_address, quantity):
+        """
+        Read Holding Registers from Master device (Function code 3)
+        starting_address: First holding register to be read
+        quantity:  Number of holding registers to be read
+        returns:  Int Array [0..quantity-1] which contains the holding registers
+        """
+        self.__transactionIdentifier += 1
+        if self.__ser is not None:
+            if self.__ser.closed:
+                raise Exception.SerialPortNotOpenedException("serial port not opened")
+        if (starting_address > 65535) | (quantity > 125):
+            raise ValueError("Starting address must be 0 - 65535; quantity must be 0 - 125")
+        function_code = 3
+        length = 6
+        transaction_identifier_lsb = self.__transactionIdentifier & 0xFF
+        transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8)
+        length_lsb = length & 0xFF
+        length_msb = (length & 0xFF00) >> 8
+        starting_address_lsb = starting_address & 0xFF
+        starting_address_msb = (starting_address & 0xFF00) >> 8
+        quantity_lsb = quantity & 0xFF
+        quantity_msb = (quantity & 0xFF00) >> 8
+        if self.__ser is not None:
+            data = bytearray(
+                [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, quantity_msb,
+                 quantity_lsb, 0, 0])
+
+            crc = self.__calculateCRC(data, len(data) - 2, 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            data[6] = crcLSB
+            data[7] = crcMSB
+
+            self.__ser.write(data)
+            bytes_to_read = 5 + int(quantity * 2)
+            data = self.__ser.read(bytes_to_read)
+            b = bytearray(data)
+            data = b
+
+            if len(data) < bytes_to_read:
+                raise Exceptions.TimeoutError('Read timeout Exception')
+            if (data[1] == 0x83) & (data[2] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1] == 0x83) & (data[2] == 0x02):
+                raise Exceptions.starting_addressInvalidException(
+                    "Starting address invalid or starting address + quantity invalid")
+            if (data[1] == 0x83) & (data[2] == 0x03):
+                raise Exceptions.QuantityInvalidException("quantity invalid")
+            if (data[1] == 0x83) & (data[2] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+            crc = self.__calculateCRC(data, len(data) - 2, 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]):
+                raise Exceptions.CRCCheckFailedException("CRC check failed")
+
+            myList = list()
+            for i in range(0, quantity):
+                myList.append((data[i * 2 + 3] << 8) + data[i * 2 + 4])
+            return myList
+        else:
+            protocolIdentifierLSB = 0x00
+            protocolIdentifierMSB = 0x00
+            length_lsb = 0x06
+            length_msb = 0x00
+            data = bytearray(
+                [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB,
+                 length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb,
+                 starting_address_lsb, quantity_msb, quantity_lsb])
+            self.__tcpClientSocket.send(data)
+            bytes_to_read = 9 + int(quantity * 2)
+            self.__receivedata = bytearray()
+            try:
+                while len(self.__receivedata) == 0:
+                    pass
+            except Exception:
+                raise Exception('Read Timeout')
+            data = bytearray(self.__receivedata)
+            if (data[1 + 6] == 0x83) & (data[2 + 6] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1 + 6] == 0x83) & (data[2 + 6] == 0x02):
+                raise Exceptions.starting_addressInvalidException(
+                    "Starting address invalid or starting address + quantity invalid")
+            if (data[1 + 6] == 0x83) & (data[2 + 6] == 0x03):
+                raise Exceptions.QuantityInvalidException("quantity invalid")
+            if (data[1 + 6] == 0x83) & (data[2 + 6] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+            myList = list()
+            for i in range(0, quantity):
+                myList.append((data[i * 2 + 3 + 6] << 8) + data[i * 2 + 4 + 6])
+            return myList
+
+    def read_inputregisters(self, starting_address, quantity):
+        """
+        Read Input Registers from Master device (Function code 4)
+        starting_address :  First input register to be read
+        quantity:  Number of input registers to be read
+        returns:  Int Array [0..quantity-1] which contains the input registers
+        """
+        self.__transactionIdentifier += 1
+        if self.__ser is not None:
+            if self.__ser.closed:
+                raise Exception.SerialPortNotOpenedException("serial port not opened")
+        if (starting_address > 65535) | (quantity > 125):
+            raise ValueError("Starting address must be 0 - 65535 quantity must be 0 - 125")
+        function_code = 4
+        length = 6
+        transaction_identifier_lsb = self.__transactionIdentifier & 0xFF
+        transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8)
+        length_lsb = length & 0xFF
+        length_msb = (length & 0xFF00) >> 8
+        starting_address_lsb = starting_address & 0xFF
+        starting_address_msb = (starting_address & 0xFF00) >> 8
+        quantity_lsb = quantity & 0xFF
+        quantity_msb = (quantity & 0xFF00) >> 8
+        if self.__ser is not None:
+            data = bytearray(
+                [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, quantity_msb,
+                 quantity_lsb, 0, 0])
+            crc = self.__calculateCRC(data, len(data) - 2, 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            data[6] = crcLSB
+            data[7] = crcMSB
+
+            self.__ser.write(data)
+            bytes_to_read = 5 + int(quantity * 2)
+
+            data = self.__ser.read(bytes_to_read)
+
+            b = bytearray(data)
+            data = b
+
+            if len(data) < bytes_to_read:
+                raise Exceptions.TimeoutError("Read timeout Exception")
+            if (data[1] == 0x84) & (data[2] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1] == 0x84) & (data[2] == 0x02):
+                raise Exceptions.starting_addressInvalidException(
+                    "Starting address invalid or starting address + quantity invalid")
+            if (data[1] == 0x84) & (data[2] == 0x03):
+                raise Exceptions.QuantityInvalidException("quantity invalid")
+            if (data[1] == 0x84) & (data[2] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+            crc = self.__calculateCRC(data, len(data) - 2, 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]):
+                raise Exceptions.CRCCheckFailedException("CRC check failed")
+            myList = list()
+            for i in range(0, quantity):
+                myList.append((data[i * 2 + 3] << 8) + data[i * 2 + 4])
+            return myList
+        else:
+            protocolIdentifierLSB = 0x00
+            protocolIdentifierMSB = 0x00
+            length_lsb = 0x06
+            length_msb = 0x00
+            data = bytearray(
+                [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB,
+                 length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb,
+                 starting_address_lsb, quantity_msb, quantity_lsb])
+            self.__tcpClientSocket.send(data)
+            bytes_to_read = 9 + int(quantity * 2)
+            self.__receivedata = bytearray()
+            try:
+                while len(self.__receivedata) == 0:
+                    pass
+            except Exception:
+                raise Exception('Read Timeout')
+            data = bytearray(self.__receivedata)
+            if (data[1 + 6] == 0x84) & (data[2 + 6] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1 + 6] == 0x84) & (data[2 + 6] == 0x02):
+                raise Exceptions.starting_addressInvalidException(
+                    "Starting address invalid or starting address + quantity invalid")
+            if (data[1 + 6] == 0x84) & (data[2 + 6] == 0x03):
+                raise Exceptions.QuantityInvalidException("quantity invalid")
+            if (data[1 + 6] == 0x84) & (data[2 + 6] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+            myList = list()
+            for i in range(0, quantity):
+                myList.append((data[i * 2 + 3 + 6] << 8) + data[i * 2 + 4 + 6])
+            return myList
+
+    def write_single_coil(self, starting_address, value):
+        """
+        Write single Coil to Master device (Function code 5)
+        starting_address: Coil to be written
+        value:  Coil Value to be written
+        """
+        self.__transactionIdentifier += 1
+        if self.__ser is not None:
+            if self.__ser.closed:
+                raise Exception.SerialPortNotOpenedException("serial port not opened")
+        function_code = 5
+        length = 6
+        transaction_identifier_lsb = self.__transactionIdentifier & 0xFF
+        transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8)
+        length_lsb = length & 0xFF
+        length_msb = (length & 0xFF00) >> 8
+        starting_address_lsb = starting_address & 0xFF
+        starting_address_msb = (starting_address & 0xFF00) >> 8
+        if value:
+            valueLSB = 0x00
+            valueMSB = (0xFF00) >> 8
+        else:
+            valueLSB = 0x00
+            valueMSB = (0x00) >> 8
+        if self.__ser is not None:
+            data = bytearray(
+                [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, valueMSB, valueLSB,
+                 0, 0])
+            crc = self.__calculateCRC(data, len(data) - 2, 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            data[6] = crcLSB
+            data[7] = crcMSB
+            self.__ser.write(data)
+            bytes_to_read = 8
+            data = self.__ser.read(bytes_to_read)
+            b = bytearray(data)
+            data = b
+            if len(data) < bytes_to_read:
+                raise Exceptions.TimeoutError('Read timeout Exception')
+            if (data[1] == 0x85) & (data[2] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1] == 0x85) & (data[2] == 0x02):
+                raise Exceptions.starting_addressInvalidException("Address invalid")
+            if (data[1] == 0x85) & (data[2] == 0x03):
+                raise Exceptions.QuantityInvalidException("Value invalid")
+            if (data[1] == 0x85) & (data[2] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+            crc = self.__calculateCRC(data, len(data) - 2, 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]):
+                raise Exceptions.CRCCheckFailedException("CRC check failed")
+            if data[1] == self.__unitIdentifier:
+                return True
+            else:
+                return False
+        else:
+            protocolIdentifierLSB = 0x00
+            protocolIdentifierMSB = 0x00
+            length_lsb = 0x06
+            length_msb = 0x00
+            data = bytearray(
+                [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB,
+                 length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb,
+                 starting_address_lsb, valueMSB, valueLSB])
+            self.__tcpClientSocket.send(data)
+            bytes_to_read = 12
+            self.__receivedata = bytearray()
+            try:
+                while len(self.__receivedata) == 0:
+                    pass
+            except Exception:
+                raise Exception('Read Timeout')
+            data = bytearray(self.__receivedata)
+            if (data[1 + 6] == 0x85) & (data[2 + 6] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1 + 6] == 0x85) & (data[2 + 6] == 0x02):
+                raise Exceptions.starting_addressInvalidException("Address invalid")
+            if (data[1 + 6] == 0x85) & (data[2 + 6] == 0x03):
+                raise Exceptions.QuantityInvalidException("Value invalid")
+            if (data[1 + 6] == 0x85) & (data[2 + 6] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+
+                return True
+
+    def write_single_register(self, starting_address, value):
+        """
+        Write single Register to Master device (Function code 6)
+        starting_address:  Register to be written
+        value: Register Value to be written
+        """
+        self.__transactionIdentifier += 1
+        if self.__ser is not None:
+            if self.__ser.closed:
+                raise Exception.SerialPortNotOpenedException("serial port not opened")
+        function_code = 6
+        length = 6
+        transaction_identifier_lsb = self.__transactionIdentifier & 0xFF
+        transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8)
+        length_lsb = length & 0xFF
+        length_msb = (length & 0xFF00) >> 8
+        starting_address_lsb = starting_address & 0xFF
+        starting_address_msb = (starting_address & 0xFF00) >> 8
+        valueLSB = value & 0xFF
+        valueMSB = (value & 0xFF00) >> 8
+        if self.__ser is not None:
+            data = bytearray(
+                [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, valueMSB, valueLSB,
+                 0, 0])
+            crc = self.__calculateCRC(data, len(data) - 2, 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            data[6] = crcLSB
+            data[7] = crcMSB
+            self.__ser.write(data)
+            bytes_to_read = 8
+            data = self.__ser.read(bytes_to_read)
+            b = bytearray(data)
+            data = b
+            # Check for Exception
+            if len(data) < bytes_to_read:
+                raise Exceptions.TimeoutError('Read timeout Exception')
+            if (data[1] == 0x86) & (data[2] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1] == 0x86) & (data[2] == 0x02):
+                raise Exceptions.starting_addressInvalidException("Register address invalid")
+            if (data[1] == 0x86) & (data[2] == 0x03):
+                raise Exceptions.QuantityInvalidException("Invalid Register Value")
+            if (data[1] == 0x86) & (data[2] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+            crc = self.__calculateCRC(data, len(data) - 2, 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]):
+                raise Exceptions.CRCCheckFailedException("CRC check failed")
+
+            if data[1] == self.__unitIdentifier:
+                return True
+            else:
+                return False
+        else:
+            protocolIdentifierLSB = 0x00
+            protocolIdentifierMSB = 0x00
+            length_lsb = 0x06
+            length_msb = 0x00
+            data = bytearray(
+                [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB,
+                 length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb,
+                 starting_address_lsb, valueMSB, valueLSB])
+            self.__tcpClientSocket.send(data)
+            bytes_to_read = 12
+            self.__receivedata = bytearray()
+            try:
+                while (len(self.__receivedata) == 0):
+                    pass
+            except Exception:
+                raise Exception('Read Timeout')
+            data = bytearray(self.__receivedata)
+            if (data[1 + 6] == 0x86) & (data[2 + 6] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1 + 6] == 0x86) & (data[2 + 6] == 0x02):
+                raise Exceptions.starting_addressInvalidException("Register address invalid")
+            if (data[1 + 6] == 0x86) & (data[2 + 6] == 0x03):
+                raise Exceptions.QuantityInvalidException("Invalid Register Value")
+            if (data[1 + 6] == 0x86) & (data[2 + 6] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+
+                return True
+
+    def write_multiple_coils(self, starting_address, values):
+        """
+        Write multiple coils to Master device (Function code 15)
+        starting_address :  First coil to be written
+        values:  Coil Values [0..quantity-1] to be written
+        """
+        self.__transactionIdentifier += 1
+        if self.__ser is not None:
+            if self.__ser.closed:
+                raise Exception.SerialPortNotOpenedException("serial port not opened")
+        function_code = 15
+        length = 6
+        transaction_identifier_lsb = self.__transactionIdentifier & 0xFF
+        transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8)
+        length_lsb = length & 0xFF
+        length_msb = (length & 0xFF00) >> 8
+        starting_address_lsb = starting_address & 0xFF
+        starting_address_msb = (starting_address & 0xFF00) >> 8
+        quantityLSB = len(values) & 0xFF
+        quantityMSB = (len(values) & 0xFF00) >> 8
+        valueToWrite = list()
+        singleCoilValue = 0
+        for i in range(0, len(values)):
+            if ((i % 8) == 0):
+                if i > 0:
+                    valueToWrite.append(singleCoilValue)
+                singleCoilValue = 0
+
+            if values[i] == True:
+                coilValue = 1
+            else:
+                coilValue = 0
+            singleCoilValue = ((coilValue) << (i % 8) | (singleCoilValue))
+
+        valueToWrite.append(singleCoilValue)
+        if self.__ser is not None:
+            data = bytearray(
+                [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, quantityMSB,
+                 quantityLSB])
+            data.append(len(valueToWrite))  # Bytecount
+            for i in range(0, len(valueToWrite)):
+                data.append(valueToWrite[i] & 0xFF)
+
+            crc = self.__calculateCRC(data, len(data), 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            data.append(crcLSB)
+            data.append(crcMSB)
+            self.__ser.write(data)
+            bytes_to_read = 8
+            data = self.__ser.read(bytes_to_read)
+            b = bytearray(data)
+            data = b
+            if len(data) < bytes_to_read:
+                raise Exceptions.TimeoutError('Read timeout Exception')
+            if (data[1] == 0x8F) & (data[2] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1] == 0x8F) & (data[2] == 0x02):
+                raise Exceptions.starting_addressInvalidException(
+                    "Starting address invalid or starting address + quantity invalid")
+            if (data[1] == 0x8F) & (data[2] == 0x03):
+                raise Exceptions.QuantityInvalidException("quantity invalid")
+            if (data[1] == 0x8F) & (data[2] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+            crc = self.__calculateCRC(data, len(data) - 2, 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]):
+                raise Exceptions.CRCCheckFailedException("CRC check failed")
+            if data[1] == self.__unitIdentifier:
+                return True
+            else:
+                return False
+        else:
+            protocolIdentifierLSB = 0x00
+            protocolIdentifierMSB = 0x00
+            length_lsb = 0x06
+            length_msb = 0x00
+            data = bytearray(
+                [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB,
+                 length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb,
+                 starting_address_lsb, quantityMSB, quantityLSB])
+            data.append(len(valueToWrite))  # Bytecount
+            for i in range(0, len(valueToWrite)):
+                data.append(valueToWrite[i] & 0xFF)
+            self.__tcpClientSocket.send(data)
+            bytes_to_read = 12
+            self.__receivedata = bytearray()
+            try:
+                while (len(self.__receivedata) == 0):
+                    pass
+            except Exception:
+                raise Exception('Read Timeout')
+            data = bytearray(self.__receivedata)
+            if (data[1] == 0x8F) & (data[2] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1] == 0x8F) & (data[2] == 0x02):
+                raise Exceptions.starting_addressInvalidException(
+                    "Starting address invalid or starting address + quantity invalid")
+            if (data[1] == 0x8F) & (data[2] == 0x03):
+                raise Exceptions.QuantityInvalidException("quantity invalid")
+            if (data[1] == 0x8F) & (data[2] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+
+            return True
+
+    def write_multiple_registers(self, starting_address, values):
+        """
+        Write multiple registers to Master device (Function code 16)
+        starting_address: First register to be written
+        values:  Register Values [0..quantity-1] to be written
+        """
+        self.__transactionIdentifier += 1
+        if self.__ser is not None:
+            if self.__ser.closed:
+                raise Exception.SerialPortNotOpenedException("serial port not opened")
+        function_code = 16
+        length = 6
+        transaction_identifier_lsb = self.__transactionIdentifier & 0xFF
+        transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8)
+        length_lsb = length & 0xFF
+        length_msb = (length & 0xFF00) >> 8
+        starting_address_lsb = starting_address & 0xFF
+        starting_address_msb = (starting_address & 0xFF00) >> 8
+        quantityLSB = len(values) & 0xFF
+        quantityMSB = (len(values) & 0xFF00) >> 8
+        valueToWrite = list()
+        for i in range(0, len(values)):
+            valueToWrite.append(values[i])
+        if self.__ser is not None:
+            data = bytearray(
+                [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, quantityMSB,
+                 quantityLSB])
+            data.append(len(valueToWrite) * 2)  # Bytecount
+            for i in range(0, len(valueToWrite)):
+                data.append((valueToWrite[i] & 0xFF00) >> 8)
+                data.append(valueToWrite[i] & 0xFF)
+            crc = self.__calculateCRC(data, len(data), 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            data.append(crcLSB)
+            data.append(crcMSB)
+            self.__ser.write(data)
+            bytes_to_read = 8
+            data = self.__ser.read(bytes_to_read)
+            b = bytearray(data)
+            data = b
+            if len(data) < bytes_to_read:
+                raise Exceptions.TimeoutError('Read timeout Exception')
+            if (data[1] == 0x90) & (data[2] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1] == 0x90) & (data[2] == 0x02):
+                raise Exceptions.starting_addressInvalidException(
+                    "Starting address invalid or starting address + quantity invalid")
+            if (data[1] == 0x90) & (data[2] == 0x03):
+                raise Exceptions.QuantityInvalidException("quantity invalid")
+            if (data[1] == 0x90) & (data[2] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+            crc = self.__calculateCRC(data, len(data) - 2, 0)
+            crcLSB = crc & 0xFF
+            crcMSB = (crc & 0xFF00) >> 8
+            if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]):
+                raise Exceptions.CRCCheckFailedException("CRC check failed")
+            if data[1] == self.__unitIdentifier:
+                return True
+            else:
+                return False
+        else:
+            protocolIdentifierLSB = 0x00
+            protocolIdentifierMSB = 0x00
+            length_lsb = 0x06
+            length_msb = 0x00
+            data = bytearray(
+                [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB,
+                 length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb,
+                 starting_address_lsb, quantityMSB, quantityLSB])
+            data.append(len(valueToWrite) * 2)  # Bytecount
+            for i in range(0, len(valueToWrite)):
+                data.append((valueToWrite[i] & 0xFF00) >> 8)
+                data.append(valueToWrite[i] & 0xFF)
+
+            self.__tcpClientSocket.send(data)
+            bytes_to_read = 12
+            self.__receivedata = bytearray()
+            try:
+                while len(self.__receivedata) == 0:
+                    pass
+            except Exception:
+                raise Exception('Read Timeout')
+            data = bytearray(self.__receivedata)
+            if (data[1] == 0x90) & (data[2] == 0x01):
+                raise Exceptions.function_codeNotSupportedException("Function code not supported by master")
+            if (data[1] == 0x90) & (data[2] == 0x02):
+                raise Exceptions.starting_addressInvalidException(
+                    "Starting address invalid or starting address + quantity invalid")
+            if (data[1] == 0x90) & (data[2] == 0x03):
+                raise Exceptions.QuantityInvalidException("quantity invalid")
+            if (data[1] == 0x90) & (data[2] == 0x04):
+                raise Exceptions.ModbusException("error reading")
+            return True
+
+    def __calculateCRC(self, data, numberOfBytes, startByte):
+        crc = 0xFFFF
+        for x in range(0, numberOfBytes):
+            crc = crc ^ data[x]
+            for _ in range(0, 8):
+                if (crc & 0x0001) != 0:
+                    crc = crc >> 1
+                    crc = crc ^ 0xA001
+                else:
+                    crc = crc >> 1
+        return crc
+
+    @property
+    def port(self):
+        """
+        Gets the Port were the Modbus-TCP Server is reachable (Standard is 502)
+        """
+        return self.__port
+
+    @port.setter
+    def port(self, port):
+        """
+        Sets the Port were the Modbus-TCP Server is reachable (Standard is 502)
+        """
+        self.__port = port
+
+    @property
+    def ipaddress(self):
+        """
+        Gets the IP-Address of the Server to be connected
+        """
+        return self.__ipAddress
+
+    @ipaddress.setter
+    def ipaddress(self, ipAddress):
+        """
+        Sets the IP-Address of the Server to be connected
+        """
+        self.__ipAddress = ipAddress
+
+    @property
+    def unitidentifier(self):
+        """
+        Gets the Unit identifier in case of serial connection (Default = 1)
+        """
+        return self.__unitIdentifier
+
+    @unitidentifier.setter
+    def unitidentifier(self, unitIdentifier):
+        """
+        Sets the Unit identifier in case of serial connection (Default = 1)
+        """
+        self.__unitIdentifier = unitIdentifier
+
+    @property
+    def baudrate(self):
+        """
+        Gets the Baudrate for serial connection (Default = 9600)
+        """
+        return self.__baudrate
+
+    @baudrate.setter
+    def baudrate(self, baudrate):
+        """
+        Sets the Baudrate for serial connection (Default = 9600)
+        """
+        self.__baudrate = baudrate
+
+    @property
+    def parity(self):
+        """
+        Gets the of Parity in case of serial connection
+        """
+        return self.__parity
+
+    @parity.setter
+    def parity(self, parity):
+        """
+        Sets the of Parity in case of serial connection
+        Example modbusClient.Parity = Parity.even
+        """
+        self.__parity = parity
+
+    @property
+    def stopbits(self):
+        """
+        Gets the number of stopbits in case of serial connection
+        """
+        return self.__stopbits
+
+    @stopbits.setter
+    def stopbits(self, stopbits):
+        """
+        Sets the number of stopbits in case of serial connection
+        Example: modbusClient.Stopbits = Stopbits.one
+        """
+        self.__stopbits = stopbits
+
+    @property
+    def timeout(self):
+        """
+        Gets the Timeout
+        """
+        return self.__timeout
+
+    @timeout.setter
+    def timeout(self, timeout):
+        """
+        Sets the Timeout
+        """
+        self.__timeout = timeout
+
+    def is_connected(self):
+        """
+        Returns true if a connection has been established
+        """
+        return self.__connected
+
+
+class Parity():
+    even = 0
+    odd = 1
+    none = 2
+
+
+class Stopbits():
+    one = 0
+    two = 1
+    onePointFive = 2
+
+
+def convert_double_to_two_registers(doubleValue):
+    """
+    Convert 32 Bit Value to two 16 Bit Value to send as Modbus Registers
+    doubleValue: Value to be converted
+    return: 16 Bit Register values int[]
+    """
+    myList = list()
+    myList.append(int(doubleValue & 0x0000FFFF))  # Append Least Significant Word
+    myList.append(int((doubleValue & 0xFFFF0000) >> 16))  # Append Most Significant Word
+    return myList
+
+
+def convert_float_to_two_registers(floatValue):
+    """
+    Convert 32 Bit real Value to two 16 Bit Value to send as Modbus Registers
+    floatValue: Value to be converted
+    return: 16 Bit Register values int[]
+    """
+    myList = list()
+    s = bytearray(struct.pack('<f', floatValue))  # little endian
+    myList.append(s[0] | (s[1] << 8))  # Append Least Significant Word
+    myList.append(s[2] | (s[3] << 8))  # Append Most Significant Word
+
+    return myList
+
+
+def convert_registers_to_double(registers):
+    """
+    Convert two 16 Bit Registers to 32 Bit long value - Used to receive 32 Bit values from Modbus (Modbus Registers are 16 Bit long)
+    registers: 16 Bit Registers
+    return: 32 bit value
+    """
+    returnValue = (int(registers[0]) & 0x0000FFFF) | (int((registers[1]) << 16) & 0xFFFF0000)
+    return returnValue
+
+
+def convert_registers_to_float(registers):
+    """
+    Convert two 16 Bit Registers to 32 Bit real value - Used to receive float values from Modbus (Modbus Registers are 16 Bit long)
+    registers: 16 Bit Registers
+    return: 32 bit value real
+    """
+    b = bytearray(4)
+    b[0] = registers[0] & 0xff
+    b[1] = (registers[0] & 0xff00) >> 8
+    b[2] = (registers[1] & 0xff)
+    b[3] = (registers[1] & 0xff00) >> 8
+    returnValue = struct.unpack('<f', b)  # little Endian
+    return returnValue
+
+
+if __name__ == "__main__":
+    modbus_client = ModbusClient("192.168.178.33", 502)
+    modbus_client.connect()
+    counter = 0
+    while (1):
+        counter = counter + 1
+        modbus_client.unitidentifier = 200
+        modbus_client.write_single_register(1, counter)
+        print(modbus_client.read_holdingregisters(1, 1))
+    modbus_client.close()
diff --git a/TP2/easymodbus/modbusException.py b/TP2/easymodbus/modbusException.py
new file mode 100644
index 0000000000000000000000000000000000000000..af4d59459ca9474b76643fc83cbfeda03faece6e
--- /dev/null
+++ b/TP2/easymodbus/modbusException.py
@@ -0,0 +1,110 @@
+'''
+Created on 14.09.2016
+
+@author: Stefan Rossmann
+'''
+
+
+class ModbusException(Exception):
+    '''
+    classdocs
+    '''
+
+    def __init__(self, expression, message):
+        """ Exception to be thrown if Modbus Server returns error code "Function Code not executed (0x04)"
+        Attributes:
+            expression -- input expression in which the error occurred
+            message -- explanation of the error
+        """
+        self.expression = expression
+        self.message = message
+
+
+class SerialPortNotOpenedException(ModbusException):
+    '''
+    classdocs
+    '''
+
+    def __init__(self, expression, message):
+        """ Exception to be thrown if serial port is not opened
+        Attributes:
+            expression -- input expression in which the error occurred
+            message -- explanation of the error
+        """
+        self.expression = expression
+        self.message = message
+
+
+class ConnectionException(ModbusException):
+    '''
+    classdocs
+    '''
+
+    def __init__(self, expression, message):
+        """ Exception to be thrown if Connection to Modbus device failed
+        Attributes:
+            expression -- input expression in which the error occurred
+            message -- explanation of the error
+        """
+        self.expression = expression
+        self.message = message
+
+
+class FunctionCodeNotSupportedException(ModbusException):
+    '''
+    classdocs
+    '''
+
+    def __init__(self, expression, message):
+        """ Exception to be thrown if Modbus Server returns error code "Function code not supported"
+        Attributes:
+            expression -- input expression in which the error occurred
+            message -- explanation of the error
+        """
+        self.expression = expression
+        self.message = message
+
+
+class QuantityInvalidException(ModbusException):
+    '''
+    classdocs
+    '''
+
+    def __init__(self, expression, message):
+        """ Exception to be thrown if Modbus Server returns error code "quantity invalid"
+        Attributes:
+            expression -- input expression in which the error occurred
+            message -- explanation of the error
+        """
+        self.expression = expression
+        self.message = message
+
+
+class StartingAddressInvalidException(ModbusException):
+    '''
+    classdocs
+    '''
+
+    def __init__(self, expression, message):
+        """ Exception to be thrown if Modbus Server returns error code "starting adddress and quantity invalid"
+        Attributes:
+            expression -- input expression in which the error occurred
+            message -- explanation of the error
+        """
+        self.expression = expression
+        self.message = message
+
+
+class CRCCheckFailedException(ModbusException):
+    '''
+    classdocs
+    '''
+
+    def __init__(self, expression, message):
+        """ Exception to be thrown if CRC Check failed
+        Attributes:
+            expression -- input expression in which the error occurred
+            message -- explanation of the error
+        """
+        self.expression = expression
+        self.message = message
diff --git a/TP2/easymodbus/run.py b/TP2/easymodbus/run.py
new file mode 100644
index 0000000000000000000000000000000000000000..84b0e76386b340c73d86d1b8ef38f25a18a3d333
--- /dev/null
+++ b/TP2/easymodbus/run.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+'''
+Created on 12.09.2016
+
+@author: Stefan Rossmann
+'''
+
+# @UnresolvedImport
+from easymodbus.modbusClient import *
+# @UnresolvedImport
+    
+modbusClient = ModbusClient('127.0.0.1', 502)
+#modbusClient = ModbusClient('COM4')
+modbusClient.parity = Parity.even
+modbusClient.unitidentifier = 2
+modbusClient.baudrate = 9600
+modbusClient.stopbits = Stopbits.one
+modbusClient.connect()
+discreteInputs = modbusClient.read_discreteinputs(0, 8)
+print (discreteInputs)
+
+holdingRegisters = convert_registers_to_float(modbusClient.read_holdingregisters(0, 2))
+print (holdingRegisters)
+inputRegisters = modbusClient.read_inputregisters(0, 8)
+print (inputRegisters)
+coils = modbusClient.read_coils(0, 8)
+print (coils)
+
+modbusClient.write_single_coil(0, True)
+modbusClient.write_single_register(0, 777)
+modbusClient.write_multiple_coils(0, [True,True,True,True,True,False,True,True])
+modbusClient.write_multiple_registers(0, convert_float_to_two_registers(3.141517))
+modbusClient.close()
\ No newline at end of file
diff --git a/TP2/test5.py b/TP2/test5.py
new file mode 100644
index 0000000000000000000000000000000000000000..70ef3be131ceb282098aa9ad4d4b6f2f02dec95d
--- /dev/null
+++ b/TP2/test5.py
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+"""
+Seule Test est à utiliser
+
+@author: chevrier6
+"""
+
+from Armoire5 import *
+#
+# a=Armoire6()
+# a.resetAll()
+# i=0
+# a.setCharge(i)
+# s=a.readMesure(i)
+# print(s)
+#
+# def chenillard():
+#     a=Armoire6()
+#     for i in range(a.nbCharge):
+#         a.setCharge(i)
+#         s=a.readMesure(i)
+#         print(s)
+
+def pprint(mesure):
+    output="U={:.2f} I={:.2f} PA={:.2f} PR={:.2f}"
+    return output.format(mesure[0],mesure[1],mesure[2],mesure[3])
+
+def test(charge):
+
+    a=Armoire5()
+    a.resetAll()
+    print("charge ",charge)
+    a.setCharge(charge)
+    s=a.readMesure(charge)
+    print(pprint(s), "\nS1" ,pprint(a.readSecteur1()),"\nS2", pprint(a.readSecteur2()),"\n")
+    a.setSource2(charge)
+    s=a.readMesure(charge)
+    print(pprint(s), "\nS1" ,pprint(a.readSecteur1()),"\nS2", pprint(a.readSecteur2()),"\n")
+    a.unsetCharge(charge)
+
+#
+# def chenillard2():
+#     a=Armoire6()
+#     a.resetAll()
+#     for i in range(a.nbCharge):
+#         print("charge ",i)
+#         a.setCharge(i)
+#         s=a.readMesure(i)
+#         print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2())
+#         a.setSource2(i)
+#         s=a.readMesure(i)
+#         print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2())
+#         a.unsetCharge(i)
+#
+#
+# def chenillard3():
+#     a=Armoire6()
+#     a.resetAll()
+#     for charge in range(a.nbCharge):
+#         print("charge ",charge)
+#         a.setCharge(charge)
+#         u,i,pa,pr=a.readMesure(charge)
+#         u1,i1,pa1,pr1=a.readSecteur1()
+#         u2,i2,pa2,pr2=a.readSecteur2()
+#         print((u,i,pa,pr), "S1" ,a.readSecteur1(),"S2", a.readSecteur2())
+#         print(u-u1,i-i1,pa-pa1,pr-pr1)
+#         print(u-u2,i-i2,pa-pa2,pr-pr2)
+#         a.setSource2(charge)
+#         u,i,pa,pr=a.readMesure(charge)
+#         u1,i1,pa1,pr1=a.readSecteur1()
+#         u2,i2,pa2,pr2=a.readSecteur2()
+#         print((u,i,pa,pr), "S1" ,a.readSecteur1(),"S2", a.readSecteur2())
+#         print(u-u1,i-i1,pa-pa1,pr-pr1)
+#         print(u-u2,i-i2,pa-pa2,pr-pr2)
+#         a.unsetCharge(charge)
+#
+# def chenillard2b():
+#     a=Armoire6()
+#     a.resetAll()
+#     for i in range(a.nbCharge):
+#         print("charge ",i)
+#         a.toggleCharge(i)
+#         s=a.readMesure(i)
+#         print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2())
+#         a.setSource2(i)
+#         s=a.readMesure(i)
+#         print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2())
+#         a.unsetCharge(i)
+
+#chenillard2b()
\ No newline at end of file
diff --git a/TP2/test6.py b/TP2/test6.py
new file mode 100644
index 0000000000000000000000000000000000000000..89615be8205fc2ab1109e9fac713b1f5151a06e4
--- /dev/null
+++ b/TP2/test6.py
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+"""
+
+
+@author: chevrier6
+"""
+
+from Armoire6 import *
+#
+# a=Armoire6()
+# a.resetAll()
+# i=0
+# a.setCharge(i)
+# s=a.readMesure(i)
+# print(s)
+#
+# def chenillard():
+#     a=Armoire6()
+#     for i in range(a.nbCharge):
+#         a.setCharge(i)
+#         s=a.readMesure(i)
+#         print(s)
+
+def pprint(mesure):
+    output="U={:.2f} I={:.2f} PA={:.2f} PR={:.2f}"
+    return output.format(mesure[0],mesure[1],mesure[2],mesure[3])
+
+def test(charge):
+
+    a=Armoire6()
+    a.resetAll()
+    print("charge ",charge)
+    a.setCharge(charge)
+    s=a.readMesure(charge)
+    print(pprint(s), "\nS1" ,pprint(a.readSecteur1()),"\nS2", pprint(a.readSecteur2()),"\n")
+    a.setSource2(charge)
+    s=a.readMesure(charge)
+    print(pprint(s), "\nS1" ,pprint(a.readSecteur1()),"\nS2", pprint(a.readSecteur2()),"\n")
+    a.unsetCharge(charge)
+
+
+def chenillard2():
+    a=Armoire6()
+    a.resetAll()
+    for i in range(a.nbCharge):
+        print("charge ",i)
+        a.setCharge(i)
+        s=a.readMesure(i)
+        print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2())
+        a.setSource2(i)
+        s=a.readMesure(i)
+        print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2())
+        a.unsetCharge(i)
+
+#
+# def chenillard3():
+#     a=Armoire6()
+#     a.resetAll()
+#     for charge in range(a.nbCharge):
+#         print("charge ",charge)
+#         a.setCharge(charge)
+#         u,i,pa,pr=a.readMesure(charge)
+#         u1,i1,pa1,pr1=a.readSecteur1()
+#         u2,i2,pa2,pr2=a.readSecteur2()
+#         print((u,i,pa,pr), "S1" ,a.readSecteur1(),"S2", a.readSecteur2())
+#         print(u-u1,i-i1,pa-pa1,pr-pr1)
+#         print(u-u2,i-i2,pa-pa2,pr-pr2)
+#         a.setSource2(charge)
+#         u,i,pa,pr=a.readMesure(charge)
+#         u1,i1,pa1,pr1=a.readSecteur1()
+#         u2,i2,pa2,pr2=a.readSecteur2()
+#         print((u,i,pa,pr), "S1" ,a.readSecteur1(),"S2", a.readSecteur2())
+#         print(u-u1,i-i1,pa-pa1,pr-pr1)
+#         print(u-u2,i-i2,pa-pa2,pr-pr2)
+#         a.unsetCharge(charge)
+#
+# def chenillard2b():
+#     a=Armoire6()
+#     a.resetAll()
+#     for i in range(a.nbCharge):
+#         print("charge ",i)
+#         a.toggleCharge(i)
+#         s=a.readMesure(i)
+#         print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2())
+#         a.setSource2(i)
+#         s=a.readMesure(i)
+#         print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2())
+#         a.unsetCharge(i)
+
+#chenillard2b()
\ No newline at end of file