From 98ce9856efefa250bfccce9bbbaaee46ab9335a4 Mon Sep 17 00:00:00 2001
From: "m.marn" <matic.marn@cosylab.com>
Date: Wed, 27 Sep 2023 07:52:22 +0200
Subject: [PATCH] Refactor lower level classes. From PLC down without changing
 the interfaces too much.

---
 .../src/silecs-cli-client/main.cpp            |  19 +-
 .../src/xml/fesa/fesa_3_0_0/fesaTemplates.py  |  33 +-
 .../xml/test/generated_correct/AllTypes.cpp   | 232 +++---
 .../src/xml/test/generated_correct/AllTypes.h |   1 +
 .../interface/communication/MBConnection.cpp  |   4 +-
 .../communication/SNAP7Connection.cpp         |   2 +-
 .../communication/SilecsConnection.h          |   3 +-
 .../interface/core/Context.cpp                |  34 -
 .../interface/core/Context.h                  |  64 --
 .../interface/core/SilecsService.h            |   4 +-
 .../interface/equipment/PLCBlock.cpp          | 780 ++++--------------
 .../interface/equipment/PLCBlock.h            |  29 +-
 .../interface/equipment/PLCRegister.cpp       |  62 +-
 .../interface/equipment/PLCRegister.h         |  14 +-
 .../interface/equipment/SilecsBlock.cpp       |  55 +-
 .../interface/equipment/SilecsBlock.h         |  56 +-
 .../interface/equipment/SilecsCluster.cpp     |  51 +-
 .../interface/equipment/SilecsCluster.h       |   6 -
 .../interface/equipment/SilecsDevice.cpp      | 207 ++---
 .../interface/equipment/SilecsDevice.h        | 113 ++-
 .../interface/equipment/SilecsPLC.cpp         | 612 +++++++-------
 .../interface/equipment/SilecsPLC.h           | 361 +-------
 .../interface/equipment/SilecsParamConfig.h   |  43 +
 .../interface/equipment/SilecsRegister.cpp    |  21 +-
 .../interface/equipment/SilecsRegister.h      |  38 +-
 .../interface/utility/Definitions.h           | 106 +++
 .../interface/utility/StringUtilities.h       |   1 -
 .../diagnostictoolmainview.cpp                |   4 +-
 .../diagnostictoolmainview.h                  |   2 +
 .../src/silecs-diagnostic/silecsmodule.cpp    |  10 +-
 .../src/silecs-diagnostic/utils.cpp           |  43 +-
 31 files changed, 1167 insertions(+), 1843 deletions(-)
 delete mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/Context.cpp
 delete mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/Context.h
 create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsParamConfig.h
 create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/Definitions.h

diff --git a/silecs-cli-client/src/silecs-cli-client/main.cpp b/silecs-cli-client/src/silecs-cli-client/main.cpp
index 7aa8763..4945c0e 100755
--- a/silecs-cli-client/src/silecs-cli-client/main.cpp
+++ b/silecs-cli-client/src/silecs-cli-client/main.cpp
@@ -27,6 +27,7 @@
 #include <silecs-communication/interface/equipment/SilecsCluster.h>
 #include <silecs-communication/interface/equipment/SilecsDevice.h>
 #include <silecs-communication/interface/equipment/SilecsRegister.h>
+#include <silecs-communication/interface/equipment/SilecsPLC.h>
 
 const std::string startbold = "\e[1m";
 const std::string endbold = "\e[0m";
@@ -256,13 +257,12 @@ void printRegister(Silecs::Device *device, Silecs::Register *reg)
 void printBlock(Silecs::Device *device, std::string blockName, Silecs::XMLParser &paramParser)
 {
     device->recv(blockName);
-    std::vector<Silecs::Register*> regCol = device->getRegisterCollection(blockName);
-    std::vector<Silecs::Register*>::iterator reg;
-    for (reg = regCol.begin(); reg != regCol.end(); reg++)
+    auto& regCol = device->getRegisterCollection(blockName);
+    for (auto reg = regCol.begin(); reg != regCol.end(); reg++)
     {
         if (isRegisterInBlock( (*reg)->getName(), blockName, paramParser))
         {
-            printRegister(device, *reg);
+            printRegister(device, (*reg).get());
         }
     }
 }
@@ -274,11 +274,10 @@ void printDevice(Silecs::Device *device, Silecs::XMLParser &paramParser)
     for (blockName = blockNames.begin(); blockName != blockNames.end(); blockName++)
     {
         device->recv(*blockName);
-        std::vector<Silecs::Register*> regCol = device->getRegisterCollection(*blockName);
-        std::vector<Silecs::Register*>::iterator reg;
-        for (reg = regCol.begin(); reg != regCol.end(); reg++)
+        auto& regCol = device->getRegisterCollection(*blockName);
+        for (auto reg = regCol.begin(); reg != regCol.end(); reg++)
         {
-            printRegister(device, *reg);
+            printRegister(device, (*reg).get());
         }
     }
 }
@@ -353,7 +352,7 @@ int connectInteractive(Silecs::Service *service, Silecs::XMLParser &paramParser)
                 if (index == -1)
                     break;
                 arg_registerName = registers[index];
-                reg = device->getRegister(arg_registerName);
+                reg = device->getRegister(arg_registerName).get();
                 break;
             }
             case 3:
@@ -433,7 +432,7 @@ int connectNonInteractive(Silecs::Service *service, Silecs::XMLParser &paramPars
     Silecs::Register *reg = NULL;
     if (!arg_registerName.empty())
     {
-        reg = device->getRegister(arg_registerName);
+        reg = device->getRegister(arg_registerName).get();
         arg_blockName = getSilecsBlockNamebyRegisterName(arg_registerName, paramParser);
     }
 
diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py b/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py
index 972516c..0a23fa1 100644
--- a/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py
+++ b/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py
@@ -108,6 +108,7 @@ htop = string.Template("""/*
 #define ${className}_${className}_H_
 
 #include <silecs-communication/interface/core/SilecsService.h>
+#include <silecs-communication/interface/equipment/SilecsPLC.h>
 #include <fesa-core/Synchronization/MultiplexingContext.h>
 #include <${className}/GeneratedCode/ServiceLocator.h>
 """)
@@ -471,14 +472,14 @@ cRecv = """        if (recvNow) pPLCDevice -> recv(blockName_);
 
 cGetStringReg = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             pDevice->${fesaFieldName}.set(pRegister->getVal<std::string>().c_str(), pContext);
         }
 """)
 
 cGetStringArrayReg = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             uint32_t dim1 = pRegister->getDimension1();
             const std::string** stdStringArray = pRegister->getRefArray<const std::string*>(dim1);
             for (unsigned int i=0; i<dim1; i++)
@@ -493,14 +494,14 @@ cGetScalarReg = string.Template("""
         
 cGetArrayReg = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             uint32_t dim1 = pRegister->getDimension1();
             pDevice->${fesaFieldName}.set(pRegister->getRefArray<${regType}>(dim1), dim1, pContext);
         }
         """)
 cGetArray2DReg = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             pDevice->${fesaFieldName}.set(pRegister->getRefArray2D<${regType}>(dim1, dim2), dim1, dim2, pContext);
@@ -508,7 +509,7 @@ cGetArray2DReg = string.Template("""
 """)
 cGetUnsignedArray2DReg = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             uint32_t dim1;
             uint32_t dim2;
             ${regType}* data = pRegister->getRefArray2D<${regType}>(dim1, dim2);
@@ -519,7 +520,7 @@ cGetUnsignedArray2DReg = string.Template("""
 
 cGetUnsignedArrayReg = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             uint32_t dim1;
             ${regType}* data = pRegister->getRefArray<${regType}>(dim1);
             std::vector<${fesaType}> ${regName}(data, data + dim1);
@@ -555,7 +556,7 @@ cSetStringReg = string.Template("""
 
 cSetStringArrayReg = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             uint32_t dim1 = pRegister->getDimension1();
             std::string stdStringArray[dim1];
             uint32_t fesaDim1;
@@ -570,7 +571,7 @@ cSetScalarReg = string.Template("""
             
 cSetArrayReg = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             pRegister->setValArray<${regType}>(pDevice->${fesaFieldName}.get(fesaDim1${context}), dim1);
@@ -579,7 +580,7 @@ cSetArrayReg = string.Template("""
 
 cSetUnsignedArrayReg = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             uint32_t fesaDim1;
             const ${fesaType}* ${regName} = pDevice->${fesaFieldName}.get(fesaDim1${context});
             uint32_t dim1 = pRegister->getDimension1();
@@ -590,7 +591,7 @@ cSetUnsignedArrayReg = string.Template("""
 
 cSetArray2DReg = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -600,7 +601,7 @@ cSetArray2DReg = string.Template("""
                                  
 cSetUnsignedArray2DReg = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -616,7 +617,7 @@ cSetStringRegData = string.Template("""
                                     
 cSetStringArrayRegData = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             uint32_t dim1 = pRegister->getDimension1();
             std::string stdStringArray[dim1];
             uint32_t fesaDim1;
@@ -631,7 +632,7 @@ cSetScalarRegData = string.Template("""
                                           pPLCDevice->getRegister("${regName}")->setVal<${regType}>( ${cCast}pDevice->${fesaFieldName}.get(${context}));""")
 cSetArrayRegData = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             (data.is${fesaFieldName_upper}Available()) ? pRegister->setValArray<${regType}>( data.${fesaFieldName}.get(fesaDim1), dim1) :
@@ -641,7 +642,7 @@ cSetArrayRegData = string.Template("""
 
 cSetUnsignedArrayRegData = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             const ${fesaType}* ${regName};
@@ -654,7 +655,7 @@ cSetUnsignedArrayRegData = string.Template("""
 
 cSetArray2DRegData = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -665,7 +666,7 @@ cSetArray2DRegData = string.Template("""
 
 cSetUnsignedArray2DRegData = string.Template("""
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            auto& pRegister = pPLCDevice->getRegister("${regName}");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
diff --git a/silecs-codegen/src/xml/test/generated_correct/AllTypes.cpp b/silecs-codegen/src/xml/test/generated_correct/AllTypes.cpp
index 491da01..a73c35e 100644
--- a/silecs-codegen/src/xml/test/generated_correct/AllTypes.cpp
+++ b/silecs-codegen/src/xml/test/generated_correct/AllTypes.cpp
@@ -213,7 +213,7 @@ namespace AllTypes
         pDevice->RO_uint32_fesa.set( pPLCDevice->getRegister("RO_uint32")->getVal<uint32_t>(), pContext);
         pDevice->RO_float32_fesa.set( pPLCDevice->getRegister("RO_float32")->getVal<float>(), pContext);
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RO_string");
+            auto& pRegister = pPLCDevice->getRegister("RO_string");
             pDevice->RO_string_fesa.set(pRegister->getVal<std::string>().c_str(), pContext);
         }
 
@@ -244,7 +244,7 @@ namespace AllTypes
         pDevice->RW_uint32_fesa.set( pPLCDevice->getRegister("RW_uint32")->getVal<uint32_t>(), pContext);
         pDevice->RW_float32_fesa.set( pPLCDevice->getRegister("RW_float32")->getVal<float>(), pContext);
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW_string");
+            auto& pRegister = pPLCDevice->getRegister("RW_string");
             pDevice->RW_string_fesa.set(pRegister->getVal<std::string>().c_str(), pContext);
         }
 
@@ -258,14 +258,14 @@ namespace AllTypes
         pDevice->RW_real_fesa.set( pPLCDevice->getRegister("RW_real")->getVal<float>(), pContext);
         pDevice->RW_dt_fesa.set( pPLCDevice->getRegister("RW_dt")->getVal<double>(), pContext);
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int8");
+            auto& pRegister = pPLCDevice->getRegister("RW2_int8");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             pDevice->RW2_int8.set(pRegister->getRefArray2D<int8_t>(dim1, dim2), dim1, dim2, pContext);
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint8");
+            auto& pRegister = pPLCDevice->getRegister("RW2_uint8");
             uint32_t dim1;
             uint32_t dim2;
             uint8_t* data = pRegister->getRefArray2D<uint8_t>(dim1, dim2);
@@ -274,14 +274,14 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int16");
+            auto& pRegister = pPLCDevice->getRegister("RW2_int16");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             pDevice->RW2_int16_fesa.set(pRegister->getRefArray2D<int16_t>(dim1, dim2), dim1, dim2, pContext);
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint16");
+            auto& pRegister = pPLCDevice->getRegister("RW2_uint16");
             uint32_t dim1;
             uint32_t dim2;
             uint16_t* data = pRegister->getRefArray2D<uint16_t>(dim1, dim2);
@@ -290,14 +290,14 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int32");
+            auto& pRegister = pPLCDevice->getRegister("RW2_int32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             pDevice->RW2_int32_fesa.set(pRegister->getRefArray2D<int32_t>(dim1, dim2), dim1, dim2, pContext);
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint32");
+            auto& pRegister = pPLCDevice->getRegister("RW2_uint32");
             uint32_t dim1;
             uint32_t dim2;
             uint32_t* data = pRegister->getRefArray2D<uint32_t>(dim1, dim2);
@@ -306,28 +306,28 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_float32");
+            auto& pRegister = pPLCDevice->getRegister("RW2_float32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             pDevice->RW2_float32_fesa.set(pRegister->getRefArray2D<float>(dim1, dim2), dim1, dim2, pContext);
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_date");
+            auto& pRegister = pPLCDevice->getRegister("RW2_date");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             pDevice->RW2_date_fesa.set(pRegister->getRefArray2D<double>(dim1, dim2), dim1, dim2, pContext);
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_char");
+            auto& pRegister = pPLCDevice->getRegister("RW2_char");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             pDevice->RW2_char_fesa.set(pRegister->getRefArray2D<int8_t>(dim1, dim2), dim1, dim2, pContext);
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_byte");
+            auto& pRegister = pPLCDevice->getRegister("RW2_byte");
             uint32_t dim1;
             uint32_t dim2;
             uint8_t* data = pRegister->getRefArray2D<uint8_t>(dim1, dim2);
@@ -336,7 +336,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_word");
+            auto& pRegister = pPLCDevice->getRegister("RW2_word");
             uint32_t dim1;
             uint32_t dim2;
             uint16_t* data = pRegister->getRefArray2D<uint16_t>(dim1, dim2);
@@ -345,7 +345,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dword");
+            auto& pRegister = pPLCDevice->getRegister("RW2_dword");
             uint32_t dim1;
             uint32_t dim2;
             uint32_t* data = pRegister->getRefArray2D<uint32_t>(dim1, dim2);
@@ -354,28 +354,28 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int");
+            auto& pRegister = pPLCDevice->getRegister("RW2_int");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             pDevice->RW2_int_fesa.set(pRegister->getRefArray2D<int16_t>(dim1, dim2), dim1, dim2, pContext);
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dint");
+            auto& pRegister = pPLCDevice->getRegister("RW2_dint");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             pDevice->RW2_dint_fesa.set(pRegister->getRefArray2D<int32_t>(dim1, dim2), dim1, dim2, pContext);
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_real");
+            auto& pRegister = pPLCDevice->getRegister("RW2_real");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             pDevice->RW2_real_fesa.set(pRegister->getRefArray2D<float>(dim1, dim2), dim1, dim2, pContext);
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dt");
+            auto& pRegister = pPLCDevice->getRegister("RW2_dt");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             pDevice->RW2_dt_fesa.set(pRegister->getRefArray2D<double>(dim1, dim2), dim1, dim2, pContext);
@@ -408,7 +408,7 @@ namespace AllTypes
         pPLCDevice->getRegister("RW_real")->setVal<float>( pDevice->RW_real_fesa.get(pContext));
         pPLCDevice->getRegister("RW_dt")->setVal<double>( pDevice->RW_dt_fesa.get(pContext));
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int8");
+            auto& pRegister = pPLCDevice->getRegister("RW2_int8");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -416,7 +416,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint8");
+            auto& pRegister = pPLCDevice->getRegister("RW2_uint8");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -426,7 +426,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int16");
+            auto& pRegister = pPLCDevice->getRegister("RW2_int16");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -434,7 +434,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint16");
+            auto& pRegister = pPLCDevice->getRegister("RW2_uint16");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -444,7 +444,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int32");
+            auto& pRegister = pPLCDevice->getRegister("RW2_int32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -452,7 +452,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint32");
+            auto& pRegister = pPLCDevice->getRegister("RW2_uint32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -462,7 +462,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_float32");
+            auto& pRegister = pPLCDevice->getRegister("RW2_float32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -470,7 +470,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_date");
+            auto& pRegister = pPLCDevice->getRegister("RW2_date");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -478,7 +478,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_char");
+            auto& pRegister = pPLCDevice->getRegister("RW2_char");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -486,7 +486,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_byte");
+            auto& pRegister = pPLCDevice->getRegister("RW2_byte");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -496,7 +496,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_word");
+            auto& pRegister = pPLCDevice->getRegister("RW2_word");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -506,7 +506,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dword");
+            auto& pRegister = pPLCDevice->getRegister("RW2_dword");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -516,7 +516,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int");
+            auto& pRegister = pPLCDevice->getRegister("RW2_int");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -524,7 +524,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dint");
+            auto& pRegister = pPLCDevice->getRegister("RW2_dint");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -532,7 +532,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_real");
+            auto& pRegister = pPLCDevice->getRegister("RW2_real");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -540,7 +540,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dt");
+            auto& pRegister = pPLCDevice->getRegister("RW2_dt");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -591,7 +591,7 @@ namespace AllTypes
         (data.isRW_dt_fesaAvailable()) ? pPLCDevice->getRegister("RW_dt")->setVal<double>( data.RW_dt_fesa.get()) :
                                           pPLCDevice->getRegister("RW_dt")->setVal<double>( pDevice->RW_dt_fesa.get(pContext));
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int8");
+            auto& pRegister = pPLCDevice->getRegister("RW2_int8");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -600,7 +600,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint8");
+            auto& pRegister = pPLCDevice->getRegister("RW2_uint8");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -612,7 +612,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int16");
+            auto& pRegister = pPLCDevice->getRegister("RW2_int16");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -621,7 +621,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint16");
+            auto& pRegister = pPLCDevice->getRegister("RW2_uint16");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -633,7 +633,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int32");
+            auto& pRegister = pPLCDevice->getRegister("RW2_int32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -642,7 +642,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint32");
+            auto& pRegister = pPLCDevice->getRegister("RW2_uint32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -654,7 +654,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_float32");
+            auto& pRegister = pPLCDevice->getRegister("RW2_float32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -663,7 +663,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_date");
+            auto& pRegister = pPLCDevice->getRegister("RW2_date");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -672,7 +672,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_char");
+            auto& pRegister = pPLCDevice->getRegister("RW2_char");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -681,7 +681,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_byte");
+            auto& pRegister = pPLCDevice->getRegister("RW2_byte");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -693,7 +693,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_word");
+            auto& pRegister = pPLCDevice->getRegister("RW2_word");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -705,7 +705,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dword");
+            auto& pRegister = pPLCDevice->getRegister("RW2_dword");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -717,7 +717,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int");
+            auto& pRegister = pPLCDevice->getRegister("RW2_int");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -726,7 +726,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dint");
+            auto& pRegister = pPLCDevice->getRegister("RW2_dint");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -735,7 +735,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_real");
+            auto& pRegister = pPLCDevice->getRegister("RW2_real");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -744,7 +744,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dt");
+            auto& pRegister = pPLCDevice->getRegister("RW2_dt");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -763,14 +763,14 @@ namespace AllTypes
         Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get());
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int8");
+            auto& pRegister = pPLCDevice->getRegister("WO_int8");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             pRegister->setValArray<int8_t>(pDevice->WO_int8.get(fesaDim1, pContext), dim1);
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_uint8");
+            auto& pRegister = pPLCDevice->getRegister("WO_uint8");
             uint32_t fesaDim1;
             const int16_t* WO_uint8 = pDevice->WO_uint8_fesa.get(fesaDim1, pContext);
             uint32_t dim1 = pRegister->getDimension1();
@@ -779,14 +779,14 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int16");
+            auto& pRegister = pPLCDevice->getRegister("WO_int16");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             pRegister->setValArray<int16_t>(pDevice->WO_int16_fesa.get(fesaDim1, pContext), dim1);
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_uint16");
+            auto& pRegister = pPLCDevice->getRegister("WO_uint16");
             uint32_t fesaDim1;
             const int32_t* WO_uint16 = pDevice->WO_uint16_fesa.get(fesaDim1, pContext);
             uint32_t dim1 = pRegister->getDimension1();
@@ -795,14 +795,14 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int32");
+            auto& pRegister = pPLCDevice->getRegister("WO_int32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             pRegister->setValArray<int32_t>(pDevice->WO_int32_fesa.get(fesaDim1, pContext), dim1);
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_uint32");
+            auto& pRegister = pPLCDevice->getRegister("WO_uint32");
             uint32_t fesaDim1;
             const int64_t* WO_uint32 = pDevice->WO_uint32_fesa.get(fesaDim1, pContext);
             uint32_t dim1 = pRegister->getDimension1();
@@ -811,14 +811,14 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_float32");
+            auto& pRegister = pPLCDevice->getRegister("WO_float32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             pRegister->setValArray<float>(pDevice->WO_float32_fesa.get(fesaDim1, pContext), dim1);
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_string");
+            auto& pRegister = pPLCDevice->getRegister("WO_string");
             uint32_t dim1 = pRegister->getDimension1();
             std::string stdStringArray[dim1];
             uint32_t fesaDim1;
@@ -828,21 +828,21 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_date");
+            auto& pRegister = pPLCDevice->getRegister("WO_date");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             pRegister->setValArray<double>(pDevice->WO_date_fesa.get(fesaDim1, pContext), dim1);
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_char");
+            auto& pRegister = pPLCDevice->getRegister("WO_char");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             pRegister->setValArray<int8_t>(pDevice->WO_char_fesa.get(fesaDim1, pContext), dim1);
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_byte");
+            auto& pRegister = pPLCDevice->getRegister("WO_byte");
             uint32_t fesaDim1;
             const int16_t* WO_byte = pDevice->WO_byte_fesa.get(fesaDim1, pContext);
             uint32_t dim1 = pRegister->getDimension1();
@@ -851,7 +851,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_word");
+            auto& pRegister = pPLCDevice->getRegister("WO_word");
             uint32_t fesaDim1;
             const int32_t* WO_word = pDevice->WO_word_fesa.get(fesaDim1, pContext);
             uint32_t dim1 = pRegister->getDimension1();
@@ -860,7 +860,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_dword");
+            auto& pRegister = pPLCDevice->getRegister("WO_dword");
             uint32_t fesaDim1;
             const int64_t* WO_dword = pDevice->WO_dword_fesa.get(fesaDim1, pContext);
             uint32_t dim1 = pRegister->getDimension1();
@@ -869,28 +869,28 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int");
+            auto& pRegister = pPLCDevice->getRegister("WO_int");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             pRegister->setValArray<int16_t>(pDevice->WO_int_fesa.get(fesaDim1, pContext), dim1);
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_dint");
+            auto& pRegister = pPLCDevice->getRegister("WO_dint");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             pRegister->setValArray<int32_t>(pDevice->WO_dint_fesa.get(fesaDim1, pContext), dim1);
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_real");
+            auto& pRegister = pPLCDevice->getRegister("WO_real");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             pRegister->setValArray<float>(pDevice->WO_real_fesa.get(fesaDim1, pContext), dim1);
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_dt");
+            auto& pRegister = pPLCDevice->getRegister("WO_dt");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             pRegister->setValArray<double>(pDevice->WO_dt_fesa.get(fesaDim1, pContext), dim1);
@@ -906,7 +906,7 @@ namespace AllTypes
         Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get());
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int8");
+            auto& pRegister = pPLCDevice->getRegister("WO_int8");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             (data.isWO_int8Available()) ? pRegister->setValArray<int8_t>( data.WO_int8.get(fesaDim1), dim1) :
@@ -914,7 +914,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_uint8");
+            auto& pRegister = pPLCDevice->getRegister("WO_uint8");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             const int16_t* WO_uint8;
@@ -925,7 +925,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int16");
+            auto& pRegister = pPLCDevice->getRegister("WO_int16");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             (data.isWO_int16_fesaAvailable()) ? pRegister->setValArray<int16_t>( data.WO_int16_fesa.get(fesaDim1), dim1) :
@@ -933,7 +933,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_uint16");
+            auto& pRegister = pPLCDevice->getRegister("WO_uint16");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             const int32_t* WO_uint16;
@@ -944,7 +944,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int32");
+            auto& pRegister = pPLCDevice->getRegister("WO_int32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             (data.isWO_int32_fesaAvailable()) ? pRegister->setValArray<int32_t>( data.WO_int32_fesa.get(fesaDim1), dim1) :
@@ -952,7 +952,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_uint32");
+            auto& pRegister = pPLCDevice->getRegister("WO_uint32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             const int64_t* WO_uint32;
@@ -963,7 +963,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_float32");
+            auto& pRegister = pPLCDevice->getRegister("WO_float32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             (data.isWO_float32_fesaAvailable()) ? pRegister->setValArray<float>( data.WO_float32_fesa.get(fesaDim1), dim1) :
@@ -971,7 +971,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_string");
+            auto& pRegister = pPLCDevice->getRegister("WO_string");
             uint32_t dim1 = pRegister->getDimension1();
             std::string stdStringArray[dim1];
             uint32_t fesaDim1;
@@ -981,7 +981,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_date");
+            auto& pRegister = pPLCDevice->getRegister("WO_date");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             (data.isWO_date_fesaAvailable()) ? pRegister->setValArray<double>( data.WO_date_fesa.get(fesaDim1), dim1) :
@@ -989,7 +989,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_char");
+            auto& pRegister = pPLCDevice->getRegister("WO_char");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             (data.isWO_char_fesaAvailable()) ? pRegister->setValArray<int8_t>( data.WO_char_fesa.get(fesaDim1), dim1) :
@@ -997,7 +997,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_byte");
+            auto& pRegister = pPLCDevice->getRegister("WO_byte");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             const int16_t* WO_byte;
@@ -1008,7 +1008,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_word");
+            auto& pRegister = pPLCDevice->getRegister("WO_word");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             const int32_t* WO_word;
@@ -1019,7 +1019,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_dword");
+            auto& pRegister = pPLCDevice->getRegister("WO_dword");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             const int64_t* WO_dword;
@@ -1030,7 +1030,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int");
+            auto& pRegister = pPLCDevice->getRegister("WO_int");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             (data.isWO_int_fesaAvailable()) ? pRegister->setValArray<int16_t>( data.WO_int_fesa.get(fesaDim1), dim1) :
@@ -1038,7 +1038,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_dint");
+            auto& pRegister = pPLCDevice->getRegister("WO_dint");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             (data.isWO_dint_fesaAvailable()) ? pRegister->setValArray<int32_t>( data.WO_dint_fesa.get(fesaDim1), dim1) :
@@ -1046,7 +1046,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_real");
+            auto& pRegister = pPLCDevice->getRegister("WO_real");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             (data.isWO_real_fesaAvailable()) ? pRegister->setValArray<float>( data.WO_real_fesa.get(fesaDim1), dim1) :
@@ -1054,7 +1054,7 @@ namespace AllTypes
         }
     
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("WO_dt");
+            auto& pRegister = pPLCDevice->getRegister("WO_dt");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t fesaDim1;
             (data.isWO_dt_fesaAvailable()) ? pRegister->setValArray<double>( data.WO_dt_fesa.get(fesaDim1), dim1) :
@@ -1072,7 +1072,7 @@ namespace AllTypes
         Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get());
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_int8");
+            auto& pRegister = pPLCDevice->getRegister("C_int8");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1080,7 +1080,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_uint8");
+            auto& pRegister = pPLCDevice->getRegister("C_uint8");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1090,7 +1090,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_int16");
+            auto& pRegister = pPLCDevice->getRegister("C_int16");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1098,7 +1098,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_uint16");
+            auto& pRegister = pPLCDevice->getRegister("C_uint16");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1108,7 +1108,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_int32");
+            auto& pRegister = pPLCDevice->getRegister("C_int32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1116,7 +1116,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_uint32");
+            auto& pRegister = pPLCDevice->getRegister("C_uint32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1126,7 +1126,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_float32");
+            auto& pRegister = pPLCDevice->getRegister("C_float32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1134,7 +1134,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_date");
+            auto& pRegister = pPLCDevice->getRegister("C_date");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1142,7 +1142,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_char");
+            auto& pRegister = pPLCDevice->getRegister("C_char");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1150,7 +1150,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_byte");
+            auto& pRegister = pPLCDevice->getRegister("C_byte");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1160,7 +1160,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_word");
+            auto& pRegister = pPLCDevice->getRegister("C_word");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1170,7 +1170,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_dword");
+            auto& pRegister = pPLCDevice->getRegister("C_dword");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1180,7 +1180,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_int");
+            auto& pRegister = pPLCDevice->getRegister("C_int");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1188,7 +1188,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_dint");
+            auto& pRegister = pPLCDevice->getRegister("C_dint");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1196,7 +1196,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_real");
+            auto& pRegister = pPLCDevice->getRegister("C_real");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1204,7 +1204,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_dt");
+            auto& pRegister = pPLCDevice->getRegister("C_dt");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1221,7 +1221,7 @@ namespace AllTypes
         Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get());
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_int8");
+            auto& pRegister = pPLCDevice->getRegister("C_int8");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1230,7 +1230,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_uint8");
+            auto& pRegister = pPLCDevice->getRegister("C_uint8");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1242,7 +1242,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_int16");
+            auto& pRegister = pPLCDevice->getRegister("C_int16");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1251,7 +1251,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_uint16");
+            auto& pRegister = pPLCDevice->getRegister("C_uint16");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1263,7 +1263,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_int32");
+            auto& pRegister = pPLCDevice->getRegister("C_int32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1272,7 +1272,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_uint32");
+            auto& pRegister = pPLCDevice->getRegister("C_uint32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1284,7 +1284,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_float32");
+            auto& pRegister = pPLCDevice->getRegister("C_float32");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1293,7 +1293,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_date");
+            auto& pRegister = pPLCDevice->getRegister("C_date");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1302,7 +1302,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_char");
+            auto& pRegister = pPLCDevice->getRegister("C_char");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1311,7 +1311,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_byte");
+            auto& pRegister = pPLCDevice->getRegister("C_byte");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1323,7 +1323,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_word");
+            auto& pRegister = pPLCDevice->getRegister("C_word");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1335,7 +1335,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_dword");
+            auto& pRegister = pPLCDevice->getRegister("C_dword");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1347,7 +1347,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_int");
+            auto& pRegister = pPLCDevice->getRegister("C_int");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1356,7 +1356,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_dint");
+            auto& pRegister = pPLCDevice->getRegister("C_dint");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1365,7 +1365,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_real");
+            auto& pRegister = pPLCDevice->getRegister("C_real");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
@@ -1374,7 +1374,7 @@ namespace AllTypes
         }
 
         {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("C_dt");
+            auto& pRegister = pPLCDevice->getRegister("C_dt");
             uint32_t dim1 = pRegister->getDimension1();
             uint32_t dim2 = pRegister->getDimension2();
             uint32_t fesaDim1,fesaDim2;
diff --git a/silecs-codegen/src/xml/test/generated_correct/AllTypes.h b/silecs-codegen/src/xml/test/generated_correct/AllTypes.h
index f7dc771..a3afcef 100644
--- a/silecs-codegen/src/xml/test/generated_correct/AllTypes.h
+++ b/silecs-codegen/src/xml/test/generated_correct/AllTypes.h
@@ -8,6 +8,7 @@
 #define AllTypes_AllTypes_H_
 
 #include <silecs-communication/interface/core/SilecsService.h>
+#include <silecs-communication/interface/equipment/SilecsPLC.h>
 #include <fesa-core/Synchronization/MultiplexingContext.h>
 #include <AllTypes/GeneratedCode/ServiceLocator.h>
 
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp b/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp
index 8804a66..ddc7c7f 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp
+++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp
@@ -292,7 +292,7 @@ int MBConnection::readBits(long address, unsigned long offset, unsigned long siz
         // connection is established then acquire data
         // addr is a byte address, therefore we don't need to convert to a word address
         // However, we need to calculate the coil address from the register address 
-        long addr = (address - thePLC_->getDIBaseAddress()) + offset;
+        long addr = (address - thePLC_->getParamConfig().baseDIAddr) + offset;
 
         // Coils address is a bit address, but in our case we only address the first bit of the byte
         // addr should me a multiple of 8
@@ -318,7 +318,7 @@ int MBConnection::writeBits(long address, unsigned long offset, unsigned long si
         // connection is established then send data
         // addr is a byte address, therefore we don't need to convert to a word address
         // However, we need to calculate the coil address from the register address 
-        long addr = (address - thePLC_->getDOBaseAddress()) + offset;
+        long addr = (address - thePLC_->getParamConfig().baseDOAddr) + offset;
 
         // Coils address is a bit address, but in our case we only address the first bit of the byte
         // addr should me a multiple of 8
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp b/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp
index 9675b40..ce365d8 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp
+++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp
@@ -53,7 +53,7 @@ bool SNAP7Connection::open()
     int slotsDefault[4] = {2, 3, 4, 1}; //slot scan - most common layout S7-other (S7-300, ET200S)
     int nbMaxSlot = ( (slotNb_ == -1) ? 4 : 1); //slots scan only the first time (slotNb_ == -1)
 
-    switch (thePLC_->getModelID())
+    switch (thePLC_->getParamConfig().modelID)
     {
         case S7400:
             slotsScan = slotsS7400;
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h b/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h
index 2b33aef..da8dde6 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h
@@ -16,7 +16,8 @@ Contributors:
 
 #include <mutex>
 
-#include <silecs-communication/interface/equipment/PLCRegister.h>
+#include <silecs-communication/interface/utility/Definitions.h>
+#include <silecs-communication/interface/utility/SilecsException.h>
 #include <silecs-communication/interface/utility/TimeStamp.h>
 
 namespace Silecs
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/Context.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/Context.cpp
deleted file mode 100644
index e09e683..0000000
--- a/silecs-communication-cpp/src/silecs-communication/interface/core/Context.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-Copyright (c) 2017 European Organization for Nuclear Research (CERN).
-All rights reserved. This program and the accompanying materials
-are made available under the terms of the GNU Public License v3.0
-which accompanies this distribution, and is available at
-http://www.gnu.org/licenses/gpl.html
-
-Contributors:
-    .European Organization for Nuclear Research    (CERN) - initial API and implementation
-    .GSI Helmholtzzentrum für Schwerionenforschung (GSI)  - features and bugfixes
-*/
-
-
-#include <silecs-communication/interface/core/SilecsService.h>
-#include <silecs-communication/interface/core/Context.h>
-#include <silecs-communication/interface/equipment/SilecsDevice.h>
-#include <silecs-communication/interface/utility/SilecsLog.h>
-
-namespace Silecs
-{
-Context::Context(Device* pDev, bool isForSynchronization) :
-                pDevice_(pDev),
-                isForSynchro_(isForSynchronization)
-{
-    //LOG(ALLOC) << "Context (create) for Device: " << pDevice_->getLabel() << ", isForSynchronization: " <<  (isForSynchro_ ? "yes" : "no");
-}
-
-Context::~Context()
-{
-    //LOG(ALLOC) << "Context (delete) for Device: " << pDevice_->getLabel()  << ", isForSynchronization: " <<  (isForSynchro_ ? "yes" : "no");
-}
-
-} // namespace
-
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/Context.h b/silecs-communication-cpp/src/silecs-communication/interface/core/Context.h
deleted file mode 100644
index 2c0582f..0000000
--- a/silecs-communication-cpp/src/silecs-communication/interface/core/Context.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-Copyright (c) 2017 European Organization for Nuclear Research (CERN).
-All rights reserved. This program and the accompanying materials
-are made available under the terms of the GNU Public License v3.0
-which accompanies this distribution, and is available at
-http://www.gnu.org/licenses/gpl.html
-
-Contributors:
-    .European Organization for Nuclear Research    (CERN) - initial API and implementation
-    .GSI Helmholtzzentrum für Schwerionenforschung (GSI)  - features and bugfixes
-*/
-
-
-#ifndef _CONTEXT_H_
-#define _CONTEXT_H_
-
-namespace Silecs
-{
-class Device;
-
-/*!
- * \class Context
- * \brief This class defines the context of the Silecs Transaction.
- * A transaction can be done from Cluster or PLC levels for all-devices
- * and from Device level for a particular device.
- * A transaction can be executed by the client process (normal transaction) or
- * can be executed at the Cluster set-up for retentive registers synchronization.
- */
-class Context
-{
-public:
-    Context(Device* pDev, bool isForSynchronization);
-    virtual ~Context();
-
-    inline bool isForAllDevices()
-    {
-        return pDevice_ == NULL;
-    }
-    inline bool isForOneDevice()
-    {
-        return pDevice_ != NULL;
-    }
-    inline Device* getDevice()
-    {
-        return pDevice_;
-    }
-
-    inline bool isForSynchronization()
-    {
-        return isForSynchro_;
-    }
-
-private:
-    /// Device reference used for Device context
-    Device* pDevice_;
-
-    /// true for synchronization transaction.
-    /// In this case only retentive registers will be updated (Master & Slave).
-    bool isForSynchro_;
-};
-
-} // namespace
-
-#endif // _USER_CONTEXT_H_
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h
index b82230f..f90f2f9 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h
@@ -44,9 +44,7 @@ enum class AccessArea
 }
 
 #include <silecs-communication/interface/equipment/SilecsCluster.h>
-#include <silecs-communication/interface/equipment/SilecsPLC.h>
-#include <silecs-communication/interface/equipment/SilecsDevice.h>
-#include <silecs-communication/interface/equipment/SilecsRegister.h>
+#include <string>
 
 namespace Silecs
 {
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp
index b76832a..c6271e1 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp
@@ -21,22 +21,59 @@ Contributors:
 #include <silecs-communication/interface/utility/SilecsLog.h>
 #include <silecs-communication/interface/utility/StringUtilities.h>
 #include <silecs-communication/interface/equipment/PLCBlock.h>
-#include <silecs-communication/interface/core/Context.h>
 #include <silecs-communication/interface/communication/SilecsConnection.h>
+#include <silecs-communication/interface/equipment/PLCRegister.h>
 
 namespace Silecs
 {
 
-PLCBlock::PLCBlock(PLC* thePLC, const ElementXML& blockNode, AccessType accessType) :
-                Block(thePLC, blockNode, accessType)
+PLCBlock::PLCBlock(const ElementXML& blockNode, const std::vector<ElementXML>& registerNodes, AccessType accessType, long deviceInputAddress, long deviceOutputAddress, Connection& plcConnection_, const SilecsParamConfig& paramConfig) :
+                Block(blockNode, accessType, plcConnection_),
+                deviceInputAddress_(deviceInputAddress),
+                deviceOutputAddress_(deviceOutputAddress),
+                paramConfig_(paramConfig)
 {
+    for (auto registerIter = registerNodes.begin(); registerIter != registerNodes.end(); registerIter++)
+    {
+        std::string registerName = registerIter->getAttribute("name");
+        std::unique_ptr<Register> reg;
+        switch (paramConfig.brandID)
+        {
+            // SIEMENS PLCs use Motorola memory convention (BigEndianRegister)
+            case Siemens:
+                reg = std::unique_ptr<Register>(new S7Register(*registerIter, paramConfig));
+                break;
+                // SCHNEIDER PLCs use Intel memory convention (LittleEndianRegister)
+                // RABBIT microcontrollers use Intel memory convention (LittleEndianRegister)
+            case Schneider:
+            case Digi:
+                reg = std::unique_ptr<Register>(new UnityRegister(*registerIter, paramConfig));
+                break;
+                // BECKHOFF PLCs use different memory convention depending on PLC type:
+                // . CX model: same convention than Unity
+                // . BC model: special convention for 64 bits data (float, ..): swap only the two 16bits words together (no bytes swap).
+            case Beckhoff:
+                reg = std::unique_ptr<Register>(new TwinCATRegister(*registerIter, paramConfig));
+                break;
+            default:
+                throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_PLC_MANUFACTURER, paramConfig.brand);
+
+        }
+
+        AccessArea accessArea = AccessArea::Memory;
+        if (blockNode.hasAttribute("ioType")) // only IO-Blocks have this attribute
+        {
+            accessArea = Block::whichAccessArea(blockNode.getAttribute("ioType"));
+        }
+
+        reg->setAccessArea(accessArea);
+        reg->setAccessType(accessType);
+        reg->setBlockName(blockNode.getAttribute("name"));
+        registers_.emplace_back(std::move(reg));
+    }
+
     // Create buffer for the block exchanges
     bufferSize_ = memSize_; //size of one block type (including alignements)
-    if (thePLC_->getProtocolModeID() == BlockMode)
-    { //BlockMode ==> access all devices in once
-        unsigned int devicesWithBlock = getPLC()->getNrDevicesWithBlock(blockNode.getAttribute("name"));
-        bufferSize_ *= devicesWithBlock;
-    }
     pBuffer_ = (unsigned char*)calloc(bufferSize_, sizeof(unsigned char));
 }
 
@@ -48,712 +85,203 @@ PLCBlock::~PLCBlock()
     pBuffer_ = NULL;
 }
 
-int PLCBlock::recvBlockMode(Context* context)
+int PLCBlock::recvBlockMode()
 {
-    timeval tod; //Time-of-day for register time-stamping
-    int errorCode = 0;
-
-    Connection* pConn = thePLC_->getConnection();
-    AccessArea area = accessArea_;
+    unsigned long usedAddress = address_;
+    unsigned long usedSize = memSize_;
+    unsigned long usedDeviceOffset = deviceInputAddress_ * usedSize;
 
-    try
+    // Overwrite device-block address, offset & size in case user wants to resize the block dynamically
+    if (withCustomAttributes() == true)
     {
-        //if transaction is for one device only, context contains its reference
-        if (context->isForOneDevice())
-        {
-            //Device context: get block of one device only ====================================
-            Device* pDev = context->getDevice();
-
-            //Base attributes of the device within the complete data block containing all devices.
-            unsigned long usedAddress = address_;
-            unsigned long usedSize = memSize_;
-            unsigned long usedDeviceOffset = pDev->getInputAddress(area) * usedSize;
-            unsigned char* pBuffer = ((unsigned char*)pBuffer_) + usedDeviceOffset;
-
-            // Overwrite device-block address, offset & size in case user wants to resize the block dynamically
-            if (withCustomAttributes() == true)
-            {
-                usedAddress = customAddress_;
-                usedSize = customSize_;
-                usedDeviceOffset = customOffset_;
-            }
-
-            if (RECV & Log::topics_)
-            {
-                if (pConn->isEnabled())
-                {
-                    Log(RECV).getLog() << "RecvAction (execute/ BlockMode): " << ", device: " << pDev->getLabel() << ", block: " << name_;
-                }
-            }
-            // Try to open the connection, if it fails. Throw an exception. On success all the
-            // PLC blocks will be updated this function will be called recursively within doOpen.
-            // Once all blocks are updated continue from here.
-            if (!pConn->doOpen())
-            {
-                throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE};
-            }
-
-            //begin critical section
-            std::lock_guard<std::mutex> lock(bufferMux_);
-            switch (accessArea_)
-            {
-                case AccessArea::Digital:
-                    errorCode = pConn->readDIO(usedAddress, //Base address (or DBn) of the block
-                    usedDeviceOffset, //Device data address within the block
-                    usedSize, //Get one device-block only
-                    pBuffer //Buffer to store the data
-                    );
-                    break;
-                case AccessArea::Analog:
-                {
-                    errorCode = pConn->readAIO(usedAddress, //Base address (or DBn) of the block
-                    usedDeviceOffset, //Device data address within the block
-                    usedSize, //Get one device-block only
-                    pBuffer //Buffer to store the data
-                    );
-                    break;
-                }
-                case AccessArea::Memory:
-                default:
-                {
-                    errorCode = pConn->readMemory(usedAddress, //Base address (or DBn) of the block
-                    usedDeviceOffset, //Device data address within the block
-                    usedSize, //Get one device-block only
-                    pBuffer //Buffer to store the data
-                    );
-                    break;
-                }
-            }
-
-            if (pConn->isConnected() && (errorCode == 0))
-            { //Data have just been received: get time-of-day to time-stamp the registers
-                gettimeofday(&tod, 0);
-
-                //Device context: Extract all the device registers from that block
-                pDev->importRegisters(this, pBuffer, tod, context);
-
-                LOG_DELAY(RECV) << "done for block: " << name_;
-            }
-            //end critical section
-        }
-        else
-        {
-            //Dynamic resizing of the block is not possible in BLOCK_MODE
-            if (withCustomAttributes() == true)
-                throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED);
-
-            deviceVectorType::iterator pDeviceIter;
-            deviceVectorType& deviceCol = thePLC_->getDeviceMap();
-
-            //Cluster/PLC context: get block of all devices in one go =========================
-            if (RECV & Log::topics_)
-            {
-                if (pConn->isEnabled())
-                {
-                    Log(RECV).getLog() << "RecvAction (execute/ BlockMode): " << name_ << ", " << deviceCol.size() << " device(s)";
-                }
-            }
+        usedAddress = customAddress_;
+        usedSize = customSize_;
+        usedDeviceOffset = customOffset_;
+    }
 
-            // Try to open the connection, if it fails. Throw an exception. On success all the
-            // PLC blocks will be updated this function will be called recursively within doOpen.
-            // Once all blocks are updated continue from here.
-            if (!pConn->doOpen())
-            {
-                throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE};
-            }
+    return readBlock(usedAddress, usedDeviceOffset, usedSize, (unsigned char*)pBuffer_);
+}
 
-            //begin critical section
-            std::lock_guard<std::mutex> lock(bufferMux_);
-            switch (area)
-            {
-                case AccessArea::Digital:
-                    errorCode = pConn->readDIO(address_, //Base address (or DBn) of the block
-                    0, //Get all devices from the first one
-                    bufferSize_, //Get blocks of all devices (full buffer size)
-                    (unsigned char*)pBuffer_ //Buffer to store the data (full buffer)
-                    );
-                    break;
-                case AccessArea::Analog:
-                {
-                    errorCode = pConn->readAIO(address_, //Base address (or DBn) of the block
-                    0, //Get all devices from the first one
-                    bufferSize_, //Get blocks of all devices (full buffer size)
-                    (unsigned char*)pBuffer_ //Buffer to store the data (full buffer)
-                    );
-                    break;
-                }
-                case AccessArea::Memory:
-                default:
-                {
-                    errorCode = pConn->readMemory(address_, //Base address (or DBn) of the block
-                    0, //Get all devices from the first one
-                    bufferSize_, //Get blocks of all devices (full buffer size)
-                    (unsigned char*)pBuffer_ //Buffer to store the data (full buffer)
-                    );
-                    break;
-                }
-            }
+int PLCBlock::recvDeviceMode()
+{
+    unsigned long usedDeviceAddress = deviceInputAddress_;
+    unsigned long usedBlockAddress = address_;
+    unsigned long usedSize = memSize_;
 
-            if (pConn->isConnected() && (errorCode == 0))
-            { //Data have just been received: get time-of-day to time-stamp the registers
-                gettimeofday(&tod, 0);
-
-                //PLC context: Extract all registers value of all devices of the PLC from that block
-                for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter)
-                {
-                    Device* pDev = pDeviceIter->second;
-
-                    // Only extract if this device actually contains this block, otherwise skip it.
-                    if (!pDev->hasBlock(name_))
-                    {
-                        continue;
-                    }
-                    unsigned long deviceOffset = pDev->getInputAddress(area) * memSize_;
-                    unsigned char* pBuffer = ((unsigned char*)pBuffer_) + deviceOffset;
-                    pDev->importRegisters(this, pBuffer, tod, context);
-                }
-
-                LOG_DELAY(RECV) << "done for block: " << name_;
-            }
-        }
-    }
-    catch(const SilecsException& ex)
+    // Overwrite device-block address, offset & size in case user wants to resize the block dynamically
+    if (withCustomAttributes() == true)
     {
-        LOG(ERROR) << ex.what();
-        LOG(ERROR) << "RecvAction (execute/ BlockMode) for block " << name_ << " has failed.";
-        return ex.getCode();
+        usedDeviceAddress = customAddress_;
+        usedBlockAddress = customOffset_;
+        usedSize = customSize_;
     }
-    return 0;
+    return readBlock(usedDeviceAddress, usedBlockAddress, usedSize, (unsigned char*)pBuffer_);
 }
 
-int PLCBlock::recvDeviceMode(Context* context)
+int PLCBlock::sendBlockMode()
 {
-    timeval tod; //Time-of-day for register time-stamping
-    int errorCode = 0;
-    Connection* pConn = thePLC_->getConnection();
+    unsigned long usedAddress = address_;
+    unsigned long usedSize = memSize_;
+    unsigned long usedDeviceOffset = deviceOutputAddress_ * usedSize;
 
-    try
+    // Overwrite device-block address, offset & size in case user wants to resize the block dynamically
+    if (withCustomAttributes() == true)
     {
-        //if transaction is for one device only, context contains its reference
-        if (context->isForOneDevice())
-        {
-            //Device context: get block of one device only ====================================
-            Device* pDev = context->getDevice();
-
-            //Set base attributes of the device blocks
-            unsigned long usedDeviceAddress = pDev->getInputAddress(accessArea_);
-            unsigned long usedBlockAddress = address_;
-            unsigned long usedSize = memSize_;
-
-            // Overwrite device-block address, offset & size in case user wants to resize the block dynamically
-            if (withCustomAttributes() == true)
-            {
-                usedDeviceAddress = customAddress_;
-                usedBlockAddress = customOffset_;
-                usedSize = customSize_;
-            }
-
-            if (RECV & Log::topics_)
-            {
-                if (pConn->isEnabled())
-                {
-                    Log(RECV).getLog() << "RecvAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << name_;
-                }
-            }
-
-            // Try to open the connection, if it fails. Throw an exception. On success all the
-            // PLC blocks will be updated this function will be called recursively within doOpen.
-            // Once all blocks are updated continue from here.
-            if (!pConn->doOpen())
-            {
-                throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE};
-            }
-
-            //begin critical section
-            std::lock_guard<std::mutex> lock(bufferMux_);
-            switch (accessArea_)
-            {
-                case AccessArea::Digital:
-                    errorCode = pConn->readDIO(usedDeviceAddress, //Base address (or DBn) of the device
-                    usedBlockAddress, //Block data address within the device
-                    usedSize, //Get one device-block only
-                    (unsigned char*)pBuffer_ //Buffer to store the data
-                    );
-                    break;
-                case AccessArea::Analog:
-                {
-                    errorCode = pConn->readAIO(usedDeviceAddress, //Base address (or DBn) of the device
-                    usedBlockAddress, //Block data address within the device
-                    usedSize, //Get one device-block only
-                    (unsigned char*)pBuffer_ //Buffer to store the data
-                    );
-                    break;
-                }
-                case AccessArea::Memory:
-                default:
-                {
-                    errorCode = pConn->readMemory(usedDeviceAddress, //Base address (or DBn) of the device
-                    usedBlockAddress, //Block data address within the device
-                    usedSize, //Get one device-block only
-                    (unsigned char*)pBuffer_ //Buffer to store the data
-                    );
-                    break;
-                }
-            }
-
-            if (pConn->isConnected() && (errorCode == 0))
-            { //Data have just been received: get time-of-day to time-stamp the registers
-                gettimeofday(&tod, 0);
+        usedAddress = customAddress_;
+        usedSize = customSize_;
+        usedDeviceOffset = customOffset_;
+    }
+    return sendBlock(usedAddress, usedDeviceOffset, usedSize, (unsigned char*)pBuffer_);
+}
 
-                //Device context: Extract all the device registers from that block
-                pDev->importRegisters(this, (unsigned char*)pBuffer_, tod, context);
+int PLCBlock::sendDeviceMode()
+{
+    unsigned long usedDeviceAddress = deviceOutputAddress_;
+    unsigned long usedBlockAddress = address_;
+    unsigned long usedSize = memSize_;
 
-                LOG_DELAY(RECV) << "done for block: " << name_;
-            }
-        }
-        else
-        {
-            //Dynamic resizing of the block is not possible in multiple access
-            if (withCustomAttributes() == true)
-                throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED);
-
-            //Cluster/PLC context: get block of all devices one by one =========================
-            deviceVectorType::iterator pDeviceIter;
-            deviceVectorType& deviceCol = thePLC_->getDeviceMap();
-            for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter)
-            {
-                Device* pDev = pDeviceIter->second;
-                if (!pDev->hasBlock(name_))
-                {
-                    continue;
-                }
-
-                if (RECV & Log::topics_)
-                {
-                    if (pConn->isEnabled())
-                    {
-                        Log(RECV).getLog() << "RecvAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << name_;
-                    }
-                }
-
-                // Try to open the connection, if it fails. Throw an exception. On success all the
-                // PLC blocks will be updated this function will be called recursively within doOpen.
-                // Once all blocks are updated continue from here.
-                if (!pConn->doOpen())
-                {
-                    throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE};
-                }
-                //begin critical section
-                std::lock_guard<std::mutex> lock(bufferMux_);
-                switch (accessArea_)
-                {
-                    case AccessArea::Digital:
-                        errorCode = pConn->readDIO(pDev->getInputAddress(accessArea_), //Base address (or DBn) of the device
-                        address_, //Block data address within the device
-                        memSize_, //Get one device-block only
-                        (unsigned char*)pBuffer_ //Buffer to store the data
-                        );
-                        break;
-                    case AccessArea::Analog:
-                    {
-                        errorCode = pConn->readAIO(pDev->getInputAddress(accessArea_), //Base address (or DBn) of the device
-                        address_, //Block data address within the device
-                        memSize_, //Get one device-block only
-                        (unsigned char*)pBuffer_ //Buffer to store the data
-                        );
-                        break;
-                    }
-                    case AccessArea::Memory:
-                    default:
-                    {
-                        errorCode = pConn->readMemory(pDev->getInputAddress(accessArea_), //Base address (or DBn) of the device
-                        address_, //Block data address within the device
-                        memSize_, //Get one device-block only
-                        (unsigned char*)pBuffer_ //Buffer to store the data
-                        );
-                        break;
-                    }
-                }
-
-                if (pConn->isConnected() && (errorCode == 0))
-                { //Data have just been received: get time-of-day to time-stamp the registers
-                    gettimeofday(&tod, 0);
-
-                    //PLC context: Extract all registers value of the current device of the PLC from that block
-                    pDev->importRegisters(this, (unsigned char*)pBuffer_, tod, context);
-
-                    LOG_DELAY(RECV) << "done for block: " << name_;
-                }
-            }
-        }
-    }
-    catch(const SilecsException& ex)
+    // Overwrite device-block address, offset & size in case user wants to resize the block dynamically
+    if (withCustomAttributes() == true)
     {
-        LOG(ERROR) << ex.what();
-        LOG(ERROR) << "RecvAction (execute/ DeviceMode) failed.";
-        return ex.getCode();
+        usedDeviceAddress = customAddress_;
+        usedBlockAddress = customOffset_;
+        usedSize = customSize_;
     }
-    return 0;
+    return sendBlock(usedDeviceAddress, usedBlockAddress, usedSize, (unsigned char*)pBuffer_);
 }
 
-int PLCBlock::sendBlockMode(Context* context)
+int PLCBlock::readBlock(long address, unsigned long offset, unsigned long size, unsigned char* pBuffer)
 {
+    timeval tod; //Time-of-day for register time-stamping
     int errorCode = 0;
-    Connection* pConn = thePLC_->getConnection();
 
     try
     {
-        //if transaction is for one device only, context contains its reference
-        if (context->isForOneDevice())
+        // Try to open the connection, if it fails. Throw an exception. On success all the
+        // PLC blocks will be updated this function will be called recursively within doOpen.
+        // Once all blocks are updated continue from here.
+        if (!plcConnection_.doOpen())
         {
-            //Device context: send block of one device only ====================================
-            Device* pDev = context->getDevice();
-
-            //Base attributes of the device within the complete data block containing all devices.
-            unsigned long usedAddress = address_;
-            unsigned long usedSize = memSize_;
-            AccessArea area = accessArea_;
-            unsigned long usedDeviceOffset = pDev->getOutputAddress(area) * usedSize;
-            unsigned char* pBuffer = ((unsigned char*)pBuffer_) + usedDeviceOffset;
-
-            // Overwrite device-block address, offset & size in case user wants to resize the block dynamically
-            if (withCustomAttributes() == true)
-            {
-                usedAddress = customAddress_;
-                usedSize = customSize_;
-                usedDeviceOffset = customOffset_;
-            }
-
-            // Try to open the connection, if it fails. Throw an exception. On success all the
-            // PLC blocks will be updated this function will be called recursively within doOpen.
-            // Once all blocks are updated continue from here.
-            if (!pConn->doOpen())
+            throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE};
+        }
+        switch (accessArea_)
+        {
+            case AccessArea::Digital:
+                errorCode = plcConnection_.readDIO(address, offset, size, pBuffer);
+                break;
+            case AccessArea::Analog:
             {
-                throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE};
-            }
-            { //critical section
-                std::lock_guard<std::mutex> lock(bufferMux_);
-                if (pConn->isEnabled())
-                {
-                    LOG(SEND) << "SendAction (execute/ BlockMode): device: " << pDev->getLabel() << ", block: " << name_;
-
-                    //Device context: Export all the device registers to that block
-                    pDev->exportRegisters(this, pBuffer, context);
-                }
-
-                switch (area)
-                {
-                    case AccessArea::Digital:
-                        errorCode = pConn->writeDIO(usedAddress, //Base address (or DBn) of the block
-                            usedDeviceOffset, //Device data address within the block
-                            usedSize, //Set one device-block only
-                            pBuffer //Buffer which contain the data
-                            );
-                        break;
-                    case AccessArea::Analog:
-                    {
-                        errorCode = pConn->writeAIO(usedAddress, //Base address (or DBn) of the block
-                            usedDeviceOffset, //Device data address within the block
-                            usedSize, //Set one device-block only
-                            pBuffer //Buffer which contain the data
-                            );
-                        break;
-                    }
-                    case AccessArea::Memory:
-                    default:
-                        errorCode = pConn->writeMemory(usedAddress, //Base address (or DBn) of the block
-                            usedDeviceOffset, //Device data address within the block
-                            usedSize, //Set one device-block only
-                            pBuffer //Buffer which contain the data
-                            );
-                        break;
-                }
+                errorCode = plcConnection_.readAIO(address, offset, size, pBuffer);
+                break;
             }
-
-            if (SEND & Log::topics_)
+            case AccessArea::Memory:
+            default:
             {
-                if (pConn->isEnabled())
-                {
-                    Log(SEND).getLogDelay() << "done for block: " << name_;
-                }
+                errorCode = plcConnection_.readMemory(address, offset, size, pBuffer);
+                break;
             }
         }
-        else
-        {
-            //Dynamic resizing of the block is not possible in BLOCK_MODE
-            if (withCustomAttributes() == true)
-                throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED);
-
-            // Try to open the connection, if it fails. Throw an exception. On success all the
-            // PLC blocks will be updated this function will be called recursively within doOpen.
-            // Once all blocks are updated continue from here.
-            if (!pConn->doOpen())
-            {
-                throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE};
-            }
 
-            { //critical section
-                std::lock_guard<std::mutex> lock(bufferMux_);
-                if (pConn->isEnabled())
-                {
-                    deviceVectorType::iterator pDeviceIter;
-                    deviceVectorType& deviceCol = thePLC_->getDeviceMap();
-
-                    //Cluster/PLC context: set block of all devices in one go ===========================
-                    LOG(SEND) << "SendAction (execute/ BlockMode): block: " << name_ << ", " << deviceCol.size() << " device(s)";
-
-                    //PLC context: Export all registers value of all devices of the PLC to that block
-                    for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter)
-                    {
-                        Device* pDev = pDeviceIter->second;
-                        AccessArea area = accessArea_;
-                        unsigned long deviceOffset = pDev->getOutputAddress(area) * memSize_;
-                        unsigned char* pBuffer = ((unsigned char*)pBuffer_) + deviceOffset;
-                        pDev->exportRegisters(this, pBuffer, context);
-                    }
-                }
-
-                switch (accessArea_)
-                {
-                    case AccessArea::Digital:
-                        errorCode = pConn->writeDIO(address_, //Base address (or DBn) of the block
-                            0, //Set all devices from the first one
-                            bufferSize_, //Set blocks of all devices (full buffer size)
-                            (unsigned char*)pBuffer_ //Buffer which contain the data (full buffer)
-                            );
-                        break;
-                    case AccessArea::Analog:
-                    {
-                        errorCode = pConn->writeAIO(address_, //Base address (or DBn) of the block
-                            0, //Set all devices from the first one
-                            bufferSize_, //Set blocks of all devices (full buffer size)
-                            (unsigned char*)pBuffer_ //Buffer which contain the data (full buffer)
-                            );
-                        break;
-                    }
-                    case AccessArea::Memory:
-                    default:
-                        errorCode = pConn->writeMemory(address_, //Base address (or DBn) of the block
-                            0, //Set all devices from the first one
-                            bufferSize_, //Set blocks of all devices (full buffer size)
-                            (unsigned char*)pBuffer_ //Buffer which contain the data (full buffer)
-                            );
-                        break;
-                }
-            }
+        if (plcConnection_.isConnected() && (errorCode == 0))
+        { //Data have just been received: get time-of-day to time-stamp the registers
+            gettimeofday(&tod, 0);
 
-            if (SEND & Log::topics_)
-            {
-                if (pConn->isEnabled())
-                {
-                    Log(SEND).getLogDelay() << "done for block: " << name_;
-                }
-            }
+            importRegisters(pBuffer, tod);
+
+            LOG_DELAY(RECV) << "done for block: " << name_;
         }
     }
     catch(const SilecsException& ex)
     {
         LOG(ERROR) << ex.what();
-        LOG(ERROR) << "SendAction (execute/ DeviceMode) on block: " << name_ << " has failed";
+        LOG(ERROR) << "RecvAction (execute) for block " << name_ << " has failed.";
         return ex.getCode();
     }
     return errorCode;
 }
 
-int PLCBlock::sendDeviceMode(Context* context)
+int PLCBlock::sendBlock(long address, unsigned long offset, unsigned long size, unsigned char* pBuffer)
 {
-    Connection* pConn = thePLC_->getConnection();
     int errorCode = 0;
     try
     {
-        //if transaction is for one device only, context contains its reference
-        if (context->isForOneDevice())
+        // Try to open the connection, if it fails. Throw an exception. On success all the
+        // PLC blocks will be updated this function will be called recursively within doOpen.
+        // Once all blocks are updated continue from here.
+        if (!plcConnection_.doOpen())
         {
-            //Device context: set block of one device only ====================================
-            Device* pDev = context->getDevice();
-
-            //Set base attributes of the device blocks
-            AccessArea area = accessArea_;
-            unsigned long usedDeviceAddress = pDev->getOutputAddress(area);
-            unsigned long usedBlockAddress = address_;
-            unsigned long usedSize = memSize_;
-
-            // Overwrite device-block address, offset & size in case user wants to resize the block dynamically
-            if (withCustomAttributes() == true)
-            {
-                usedDeviceAddress = customAddress_;
-                usedBlockAddress = customOffset_;
-                usedSize = customSize_;
-            }
-
-            // Try to open the connection, if it fails. Throw an exception. On success all the
-            // PLC blocks will be updated this function will be called recursively within doOpen.
-            // Once all blocks are updated continue from here.
-            if (!pConn->doOpen())
-            {
-                throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE};
-            }
+            throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE};
+        }
 
-            { //critical section
-                std::lock_guard<std::mutex> lock(bufferMux_);
-                if (pConn->isEnabled())
-                {
-                    LOG(SEND) << "SendAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << name_;
-
-                    //Device context: Export all the device registers to that block
-                    pDev->exportRegisters(this, (unsigned char*)pBuffer_, context);
-                }
-
-                switch (area)
-                {
-                    case AccessArea::Digital:
-                        errorCode = pConn->writeDIO(usedDeviceAddress, //Base address (or DBn) of the device
-                            usedBlockAddress, //Block data address within the device
-                            usedSize, //Set one device-block only
-                            (unsigned char*)pBuffer_ //Buffer which contain the data
-                            );
-                        break;
-                    case AccessArea::Analog:
-                    {
-                        errorCode = pConn->writeAIO(usedDeviceAddress, //Base address (or DBn) of the device
-                            usedBlockAddress, //Block data address within the device
-                            usedSize, //Set one device-block only
-                            (unsigned char*)pBuffer_ //Buffer which contain the data
-                            );
-                        break;
-                    }
-                    case AccessArea::Memory:
-                    default:
-                        errorCode = pConn->writeMemory(usedDeviceAddress, //Base address (or DBn) of the device
-                            usedBlockAddress, //Block data address within the device
-                            usedSize, //Set one device-block only
-                            (unsigned char*)pBuffer_ //Buffer which contain the data
-                            );
-                        break;
-                }
-            }
+        if (plcConnection_.isEnabled())
+        {
+            exportRegisters(pBuffer);
+        }
 
-            if (SEND & Log::topics_)
+        switch (accessArea_)
+        {
+            case AccessArea::Digital:
+                errorCode = plcConnection_.writeDIO(address, offset, size, pBuffer);
+                break;
+            case AccessArea::Analog:
             {
-                if (pConn->isEnabled())
-                {
-                    Log(SEND).getLogDelay() << "done for block: " << name_;
-                }
+                errorCode = plcConnection_.writeAIO(address, offset, size, pBuffer);
+                break;
             }
+            case AccessArea::Memory:
+            default:
+                errorCode = plcConnection_.writeMemory(address, offset, size, pBuffer);
+                break;
         }
-        else
+
+        if (SEND & Log::topics_)
         {
-            //Dynamic resizing of the block is not possible in multiple access
-            if (withCustomAttributes() == true)
-                throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED);
-
-            //Cluster/PLC context: set block of all devices one by one =========================
-            deviceVectorType::iterator pDeviceIter;
-            deviceVectorType& deviceCol = thePLC_->getDeviceMap();
-            for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter)
+            if (plcConnection_.isEnabled())
             {
-                Device* pDev = pDeviceIter->second;
-                if (!pDev->hasBlock(name_))
-                {
-                    continue;
-                }
-                // Try to open the connection, if it fails. Throw an exception. On success all the
-                // PLC blocks will be updated this function will be called recursively within doOpen.
-                // Once all blocks are updated continue from here.
-                if (!pConn->doOpen())
-                {
-                    throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE};
-                }
-                { //critical section
-                    std::lock_guard<std::mutex> lock(bufferMux_);
-                    if (pConn->isEnabled())
-                    {
-                        LOG(SEND) << "SendAction (execute/ DeviceMode):  device: " << pDev->getLabel() << ", block: " << name_;
-
-                        //PLC context: Export all registers value of the current device of the PLC to that block
-                        pDev->exportRegisters(this, (unsigned char*)pBuffer_, context);
-                    }
-
-                    AccessArea area = accessArea_;
-                    switch (area)
-                    {
-                        case AccessArea::Digital:
-                            errorCode = pConn->writeDIO(pDev->getOutputAddress(area), //Base address (or DBn) of the device
-                                address_, //Block data address within the device
-                                memSize_, //Set one device-block only
-                                (unsigned char*)pBuffer_ //Buffer which contain the data
-                                );
-                            break;
-                        case AccessArea::Analog:
-                        {
-                            errorCode = pConn->writeAIO(pDev->getOutputAddress(area), //Base address (or DBn) of the device
-                                address_, //Block data address within the device
-                                memSize_, //Set one device-block only
-                                (unsigned char*)pBuffer_ //Buffer which contain the data
-                                );
-                            break;
-                        }
-                        case AccessArea::Memory:
-                        default:
-                            errorCode = pConn->writeMemory(pDev->getOutputAddress(area), //Base address (or DBn) of the device
-                                address_, //Block data address within the device
-                                memSize_, //Set one device-block only
-                                (unsigned char*)pBuffer_ //Buffer which contain the data
-                                );
-                            break;
-                    }
-                }
-
-                if (SEND & Log::topics_)
-                {
-                    if (pConn->isEnabled())
-                    {
-                        Log(SEND).getLogDelay() << "done for block: " << name_;
-                    }
-                }
+                Log(SEND).getLogDelay() << "done for block: " << name_;
             }
         }
     }
     catch(const SilecsException& ex)
     {
         LOG(ERROR) << ex.what();
-        LOG(ERROR) << "SendAction (execute/ DeviceMode) failed";
+        LOG(ERROR) << "SendAction (execute) failed";
         return ex.getCode();
     }
     return errorCode;
 }
 
-int PLCBlock::send(Context* context)
+int PLCBlock::send()
 {
     if (accessType_ == AccessType::Acquisition)
     {
         throw SilecsException(__FILE__, __LINE__, DATA_WRITE_ACCESS_TYPE_MISMATCH);
     }
     
-    if (thePLC_->getProtocolModeID() == BlockMode)
+    if (paramConfig_.protocolModeID == BlockMode)
     {
-        return sendBlockMode(context);
+        return sendBlockMode();
     }
     else
     {
-        return sendDeviceMode(context);
+        return sendDeviceMode();
     }
 }
 
-int PLCBlock::receive(Context* context)
+int PLCBlock::receive()
 {
     if (accessType_ == AccessType::Command)
     {
         throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH);
     }
 
-    if (thePLC_->getProtocolModeID() == BlockMode)
+    if (paramConfig_.protocolModeID == BlockMode)
     {
-        return recvBlockMode(context);
+        return recvBlockMode();
     }
     else
     {
-        return recvDeviceMode(context);
+        return recvDeviceMode();
     }
 }
 
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h
index ebf452b..6f4068e 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h
@@ -16,6 +16,7 @@ Contributors:
 
 #include <silecs-communication/interface/core/SilecsService.h>
 #include <silecs-communication/interface/equipment/SilecsBlock.h>
+#include <silecs-communication/interface/equipment/SilecsParamConfig.h>
 
 namespace Silecs
 {
@@ -26,27 +27,31 @@ class PLCBlock : public Block
 {
 
 public:
-    PLCBlock(PLC* thePLC, const ElementXML& blockNode, AccessType accessType);
+    PLCBlock(const ElementXML& blockNode, const std::vector<ElementXML>& registerNodes, AccessType accessType, long deviceInputAddress, long deviceOutputAddress, Connection& plcConnection, const SilecsParamConfig& paramConfig);
     virtual ~PLCBlock();
 
-    int send(Context* context) override;
-    int receive(Context* context) override;
+    // TODO: Receive and send functions can be made void and exceptions instead thrown.
+    int send() override;
+    int receive() override;
 
-protected:
+private:
     friend class Device;
 
-    int recvBlockMode(Context* context);
-    int recvDeviceMode(Context* context);
-    int sendBlockMode(Context* context);
-    int sendDeviceMode(Context* context);
+    int recvBlockMode();
+    int recvDeviceMode();
+    int sendBlockMode();
+    int sendDeviceMode();
+
+    int readBlock(long address, unsigned long offset, unsigned long size, unsigned char* pBuffer);
+    int sendBlock(long address, unsigned long offset, unsigned long size, unsigned char* pBuffer);
 
     /// Send/Receive data size (size of block * nb of device)
     unsigned long bufferSize_;
 
-private:
-    //The frame buffer update (import/export registers) and related read/write data must be done
-    //in a critical section (the same buffer is used to send/recv data to all devices).
-    std::mutex bufferMux_;
+    long deviceInputAddress_;
+    long deviceOutputAddress_;
+
+    SilecsParamConfig paramConfig_;
 };
 
 } // namespace
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp
index d066ad6..6e7d980 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp
@@ -21,48 +21,49 @@ namespace Silecs
 
 constexpr int kDtlSize = 12;
 
-PLCRegister::PLCRegister(Device* theDevice, const ElementXML& registerNode) :
-                Register(theDevice, registerNode)
+PLCRegister::PLCRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig) :
+                Register(registerNode),
+                paramConfig_(paramConfig)
 {
 }
 PLCRegister::~PLCRegister()
 {
 }
 
-BigEndianRegister::BigEndianRegister(Device* theDevice, const ElementXML& registerNode) :
-                PLCRegister(theDevice, registerNode)
+BigEndianRegister::BigEndianRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig) :
+                PLCRegister(registerNode, paramConfig)
 {
 }
 BigEndianRegister::~BigEndianRegister()
 {
 }
 
-LittleEndianRegister::LittleEndianRegister(Device* theDevice, const ElementXML& registerNode) :
-                PLCRegister(theDevice, registerNode)
+LittleEndianRegister::LittleEndianRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig) :
+                PLCRegister(registerNode, paramConfig)
 {
 }
 LittleEndianRegister::~LittleEndianRegister()
 {
 }
 
-S7Register::S7Register(Device* theDevice, const ElementXML& registerNode) :
-                BigEndianRegister(theDevice, registerNode)
+S7Register::S7Register(const ElementXML& registerNode, const SilecsParamConfig& paramConfig) :
+                BigEndianRegister(registerNode, paramConfig)
 {
 }
 S7Register::~S7Register()
 {
 }
 
-UnityRegister::UnityRegister(Device* theDevice, const ElementXML& registerNode) :
-                LittleEndianRegister(theDevice, registerNode)
+UnityRegister::UnityRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig) :
+                LittleEndianRegister(registerNode, paramConfig)
 {
 }
 UnityRegister::~UnityRegister()
 {
 }
 
-TwinCATRegister::TwinCATRegister(Device* theDevice, const ElementXML& registerNode) :
-                UnityRegister(theDevice, registerNode)
+TwinCATRegister::TwinCATRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig) :
+                UnityRegister(registerNode, paramConfig)
 {
 }
 TwinCATRegister::~TwinCATRegister()
@@ -93,7 +94,7 @@ uint32_t TwinCATRegister::_swapl(uint32_t l)
     void *pl = &l;
     void *pul = &ul;
 
-    if ( (getPLC()->getModelID() == BC9xxx) && (getFormat() == Silecs::Float32))
+    if ( (paramConfig_.modelID == BC9xxx) && (getFormat() == Silecs::Float32))
     { //Particular case for BC9020 PLC:  swap only bytes together (not the words)
         * ((uint16_t *)pul) = _swaps(* ((uint16_t *)pl));
         * ((uint16_t *)pul + 1) = _swaps(* ((uint16_t *)pl + 1));
@@ -285,6 +286,7 @@ void LittleEndianRegister::swapBytesHToN(unsigned char *data, unsigned long size
 // ----------------------------------------------------------------------------------------
 void PLCRegister::importValue(void* pBuffer, timeval ts)
 {
+    std::lock_guard<std::mutex> lock(mutex_);
     //Compute the register address within the block: block-address + register-offset
     unsigned char* pDataBase = ((unsigned char*)pBuffer) + address_;
     unsigned char* pData = pDataBase;
@@ -339,14 +341,14 @@ void PLCRegister::importValue(void* pBuffer, timeval ts)
             {
                 for (unsigned int j = 0; j < dimension2_; j++) // works also for 1d, in this case j is always 0 and points to the element on the array
                 {
-                    if (getPLC()->getBrandID() == Beckhoff)
+                    if (paramConfig_.brandID == Beckhoff)
                     { //Beckhoff controller implement the standard EPOCH on 32bits word
                         dtSize = sizeof(uint32_t);
                         uint32_t *timeVal = (uint32_t *)pData;
                         swapBytesNToH((unsigned char *)& (timeVal[0]), sizeof(uint32_t));
                         ((double *)pRecvValue_)[i * dimension2_ + j] = static_cast<double>(timeVal[0]);
                     }
-                    else if (getPLC()->getProtocolTypeID() == S7Protocol)
+                    else if (paramConfig_.protocolTypeID == S7Protocol)
                     {
                         if (dtSize == kDtlSize)
                         {
@@ -359,13 +361,13 @@ void PLCRegister::importValue(void* pBuffer, timeval ts)
                             reinterpret_cast<double *>(pRecvValue_)[i * dimension2_ + j] = IeRfcGetTime(pData);
                         }
                     }
-                    else if (getPLC()->getProtocolTypeID() == MBProtocol)
+                    else if (paramConfig_.protocolTypeID == MBProtocol)
                     {
 #ifdef MODBUS_SUPPORT_ENABLED
                         ((double *)pRecvValue_)[i*dimension2_+j] = IeMdbGetTime(pData);
 #endif //MODBUS_SUPPORT_ENABLED
                     }
-                    else if (getPLC()->getProtocolTypeID() == CNVProtocol)
+                    else if (paramConfig_.protocolTypeID == CNVProtocol)
                     { //TODO for NI
                     }
                     else
@@ -383,14 +385,15 @@ void PLCRegister::importValue(void* pBuffer, timeval ts)
 
     //DATA topic makes sense with RECV one
     if (RECV & Log::topics_)
-        LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", ts: " << getTimeStampAsString() << ", value: " << getValAsByteString(pRecvValue_, 10);
+        LOG(DATA) << paramConfig_.plcName << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", ts: " << getTimeStampAsString() << ", value: " << getValAsByteString(pRecvValue_, 10);
 }
 
 void PLCRegister::exportValue(void* pBuffer)
 {
+    std::lock_guard<std::mutex> lock(mutex_);
     //DATA topic makes sense with SEND one
     if (SEND & Log::topics_)
-        LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", value: " << getValAsByteString(pSendValue_, 10);
+        LOG(DATA) << paramConfig_.plcName << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", value: " << getValAsByteString(pSendValue_, 10);
 
     //Compute the register address within the block: block-address + register-offset
     unsigned char* pData = ((unsigned char*)pBuffer) + address_;
@@ -440,14 +443,14 @@ void PLCRegister::exportValue(void* pBuffer)
             {
                 time_t epoch = static_cast<time_t>((double) ((double *)pSendValue_)[i]);
 
-                if (getPLC()->getBrandID() == Beckhoff)
+                if (paramConfig_.brandID == Beckhoff)
                 { //Beckhoff controller implement the standard EPOCH on 32bits word
                     dtSize = sizeof(uint32_t);
                     uint32_t *timeVal = (uint32_t *)pData;
                     timeVal[0] = static_cast<uint32_t>(epoch);
                     swapBytesHToN((unsigned char *)& (timeVal[0]), sizeof(uint32_t));
                 }
-                else if (getPLC()->getProtocolTypeID() == S7Protocol)
+                else if (paramConfig_.protocolTypeID == S7Protocol)
                 {
                     if (dtSize == kDtlSize)
                     {
@@ -460,13 +463,13 @@ void PLCRegister::exportValue(void* pBuffer)
                         IeRfcSetTime(pData, epoch);
                     }
                 }
-                else if (getPLC()->getProtocolTypeID() == MBProtocol)
+                else if (paramConfig_.protocolTypeID == MBProtocol)
                 {
 #ifdef MODBUS_SUPPORT_ENABLED
                     IeMdbSetTime(pData, epoch);
 #endif //MODBUS_SUPPORT_ENABLED
                 }
-                else if (getPLC()->getProtocolTypeID() == CNVProtocol)
+                else if (paramConfig_.protocolTypeID == CNVProtocol)
                 { //TODO for NI
                 }
                 else
@@ -481,6 +484,7 @@ void PLCRegister::exportValue(void* pBuffer)
 
 void PLCRegister::copyValue()
 {
+    std::lock_guard<std::mutex> lock(mutex_);
     //Transfer the value of the recvBuffer to to the sendBuffer
     if (type_ == String)
     {
@@ -500,6 +504,7 @@ void PLCRegister::copyValue()
 // S7 METHODS -------------------------------------------------------------------------------
 void S7Register::importString(void* pBuffer, timeval ts)
 {
+    std::lock_guard<std::mutex> lock(mutex_);
     // Compute the register address within the block: block-address + register-offset
     unsigned char* pDataBase = ((unsigned char*)pBuffer) + address_;
     std::string** pRecvStringValue_ = static_cast<std::string**>(pRecvValue_);
@@ -518,14 +523,15 @@ void S7Register::importString(void* pBuffer, timeval ts)
 
     //DATA topic makes sense with RECV one
     if (RECV & Log::topics_)
-        LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", ts: " << getTimeStampAsString() << ", value: " << getValAsByteString(pRecvValue_, 10);
+        LOG(DATA) << paramConfig_.plcName << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", ts: " << getTimeStampAsString() << ", value: " << getValAsByteString(pRecvValue_, 10);
 }
 
 void S7Register::exportString(void* pBuffer)
 {
+    std::lock_guard<std::mutex> lock(mutex_);
     //DATA topic makes sense with SEND one
     if (SEND & Log::topics_)
-        LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", value: " << getValAsByteString(pSendValue_, 10);
+        LOG(DATA) << paramConfig_.plcName << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", value: " << getValAsByteString(pSendValue_, 10);
 
     //Compute the register address within the block: block-address + register-offset
     unsigned char* pData = ((unsigned char*)pBuffer) + address_;
@@ -551,6 +557,7 @@ void S7Register::exportString(void* pBuffer)
 // TwinCAT object inherit from the same methods than UNITY.
 void UnityRegister::importString(void* pBuffer, timeval ts)
 {
+    std::lock_guard<std::mutex> lock(mutex_);
     // Compute the register address within the block: block-address + register-offset
     unsigned char* pDataBase = ((unsigned char*)pBuffer) + address_;
     std::string** pRecvStringValue_ = static_cast<std::string**>(pRecvValue_);
@@ -569,14 +576,15 @@ void UnityRegister::importString(void* pBuffer, timeval ts)
 
     //DATA topic makes sense with RECV one
     if (RECV & Log::topics_)
-        LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", ts: " << getTimeStampAsString() << ", value: " << getValAsByteString(pRecvValue_, 10);
+        LOG(DATA) << paramConfig_.plcName << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", ts: " << getTimeStampAsString() << ", value: " << getValAsByteString(pRecvValue_, 10);
 }
 
 void UnityRegister::exportString(void* pBuffer)
 {
+    std::lock_guard<std::mutex> lock(mutex_);
     //DATA topic makes sense with SEND one
     if (SEND & Log::topics_)
-        LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", value: " << getValAsByteString(pSendValue_, 10);
+        LOG(DATA) << paramConfig_.plcName << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", value: " << getValAsByteString(pSendValue_, 10);
 
     //Compute the register address within the block: block-address + register-offset
     unsigned char* pData = ((unsigned char*)pBuffer) + address_;
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.h
index c7c7200..5521075 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.h
@@ -22,6 +22,7 @@ Contributors:
 #include <silecs-communication/interface/utility/SilecsException.h>
 #include <silecs-communication/interface/utility/SilecsLog.h>
 #include <silecs-communication/interface/utility/StringUtilities.h>
+#include <silecs-communication/interface/equipment/SilecsParamConfig.h>
 
 #ifdef __x86_64__
 #include <endian.h>
@@ -35,7 +36,7 @@ class PLCRegister : public Register
 private:
 
 protected:
-    PLCRegister(Device* theDevice, const ElementXML& registerNode);
+    PLCRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig);
     virtual ~PLCRegister();
 
     // export register extraction methods
@@ -76,6 +77,7 @@ protected:
     virtual void swapBytesNToH(unsigned char *data, unsigned long size) = 0;
     virtual void swapBytesHToN(unsigned char *data, unsigned long size) = 0;
 
+    SilecsParamConfig paramConfig_;
 };
 
 /*!
@@ -86,7 +88,7 @@ class BigEndianRegister : public PLCRegister
 {
 
 public:
-    BigEndianRegister(Silecs::Device* theDevice, const ElementXML& registerNode);
+    BigEndianRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig);
     virtual ~BigEndianRegister();
 
 protected:
@@ -103,7 +105,7 @@ class LittleEndianRegister : public PLCRegister
 {
 
 public:
-    LittleEndianRegister(Silecs::Device* theDevice, const ElementXML& registerNode);
+    LittleEndianRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig);
     virtual ~LittleEndianRegister();
 
 protected:
@@ -119,7 +121,7 @@ protected:
 class S7Register : public BigEndianRegister
 {
 public:
-    S7Register(Silecs::Device* theDevice, const ElementXML& registerNode);
+    S7Register(const ElementXML& registerNode, const SilecsParamConfig& paramConfig);
     virtual ~S7Register();
 
 private:
@@ -147,7 +149,7 @@ private:
 class UnityRegister : public LittleEndianRegister
 {
 public:
-    UnityRegister(Silecs::Device* theDevice, const ElementXML& registerNode);
+    UnityRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig);
     virtual ~UnityRegister();
 
 private:
@@ -177,7 +179,7 @@ private:
 class TwinCATRegister : public UnityRegister
 {
 public:
-    TwinCATRegister(Silecs::Device* theDevice, const ElementXML& registerNode);
+    TwinCATRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig);
     virtual ~TwinCATRegister();
 
 protected:
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp
index 10e521c..deb4651 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp
@@ -24,15 +24,14 @@ Contributors:
 namespace Silecs
 {
 
-Block::Block(PLC* thePLC, const ElementXML& blockNode, AccessType accessType) :
-                thePLC_(thePLC), configuration_(false)
+Block::Block(const ElementXML& blockNode, AccessType accessType, Connection& plcConnection) :
+            plcConnection_(plcConnection),
+            configuration_(false)
 {
-    std::string designName = blockNode.getAttribute("name");
-
+    name_ = blockNode.getAttribute("name");;
     if(blockNode.getName() == "Configuration-Block")
         configuration_ = true;
 
-    name_ = designName;
     StringUtilities::fromString(size_, blockNode.getAttribute("size"));
     StringUtilities::fromString(memSize_, blockNode.getAttribute("mem-size"));
     StringUtilities::fromString(address_, blockNode.getAttribute("address"));
@@ -134,4 +133,50 @@ void Block::resetCustomAttributes()
     LOG(DEBUG) << "Reset custom attributes of block: " << name_;
 }
 
+void Block::importRegisters(void* pBuffer, timeval ts)
+{
+    for (auto& reg : registers_)
+    {
+        if (reg->getFormat() == String)
+        {
+            reg->importString(pBuffer, ts);
+        }
+        else
+        {
+            reg->importValue(pBuffer, ts);
+        }
+    }
+}
+
+void Block::exportRegisters(void* pBuffer)
+{
+    for (auto& reg : registers_)
+    {
+        if (reg->getFormat() == String)
+        {
+            reg->exportString(pBuffer);
+        }
+        else
+        {
+            reg->exportValue(pBuffer);
+        }
+    }
+}
+
+void Block::copyInToOut()
+{
+    for (auto& reg : registers_)
+    {
+        if (reg->isReadable() && reg->isWritable())
+        {
+            reg->copyValue();
+        }
+    }
+}
+
+const std::vector<std::unique_ptr<Register>>& Block::getRegisters() const
+{
+    return registers_;
+}
+
 } // namespace
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h
index 722a74a..e9a6371 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h
@@ -16,7 +16,10 @@ Contributors:
 
 #include <silecs-communication/interface/core/SilecsAction.h>
 #include <silecs-communication/interface/core/SilecsService.h>
+#include <silecs-communication/interface/communication/SilecsConnection.h>
+#include <silecs-communication/interface/equipment/SilecsRegister.h>
 
+#include <memory>
 namespace Silecs
 {
 class Action;
@@ -33,13 +36,13 @@ class ElementXML;
  */
 class Block
 {
-
+friend class PLC;
 public:
-    Block(PLC* thePLC, const ElementXML& blockNode, AccessType accessType);
+    Block(const ElementXML& blockNode, AccessType accessType, Connection& plcConnection);
     virtual ~Block();
 
-    virtual int receive(Context* context) = 0;
-    virtual int send(Context* context) = 0;
+    virtual int receive() = 0;
+    virtual int send() = 0;
 
     /*!
      * \fn whichAccessType
@@ -67,10 +70,6 @@ public:
     {
         return configuration_;
     }
-    PLC* getPLC() const
-    {
-        return thePLC_;
-    }
     std::string getName() const
     {
         return name_;
@@ -84,6 +83,16 @@ public:
         return (accessArea_);
     }
 
+    unsigned long getMemSize() const
+    {
+        return memSize_;
+    }
+
+    unsigned long getAddress() const
+    {
+        return address_;
+    }
+
     /// @cond
     void setCustomAttributes(const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize);
     void resetCustomAttributes();
@@ -93,10 +102,35 @@ public:
     }
     /// @endcond
 
+    /*!
+     * \brief Copies input buffer in output buffer
+     * The method copies the input buffer in the output buffer for each READ-WRITE register for the block passed as parameter
+     * \param blockName name of the block for which the copy must be performed
+     */
+    void copyInToOut();
+
+    const std::vector<std::unique_ptr<Register>>& getRegisters() const;
+
 protected:
 
-    /// Parent PLC reference of that device
-    PLC* thePLC_;
+    /*!
+     * \fn importRegisters
+     * \brief Extract all the concerned registers data of that device from a given block and set the registers value.
+     * \param pBlock: block which contain list of registers to be imported
+     * \param pBuffer: direct pointer on the buffer which contain the registers data
+     * \param ts is the time-of-day to time-stamp each register
+     */
+    void importRegisters(void* pBuffer, timeval ts);
+
+    /*!
+     * \fn exportRegisters
+     * \brief Export all the concerned registers value of that device to a given block.
+     * \param pBlock: block which contain list of registers to be exported
+     * \param pBuffer: direct pointer on the buffer which will contain the registers data
+     */
+    void exportRegisters(void* pBuffer);
+
+    Connection& plcConnection_;
 
     /// Block attributes
     std::string name_;
@@ -130,6 +164,8 @@ protected:
 
     unsigned long address_;
 
+    std::vector<std::unique_ptr<Register>> registers_;
+
     // Send/Receive data buffer
     void *pBuffer_;
 };
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp
index 2ec9ed1..0e112b0 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp
@@ -97,47 +97,54 @@ bool Cluster::getAddressByHostName(const std::string hostName, std::string& IPAd
     return false;
 }
 
-Block* Cluster::getBlock(const std::string blockName)
-{ // Retrieve the block from the first PLC (same for each of them)
-    return plcMap_.begin()->second->getBlock(blockName);
-}
-
 std::string Cluster::getBlockList(AccessType accessType)
 {
-    std::string blockList = "";
+    std::set<std::string> uniqueBlocks;
     //At first, check this class/version is already deployed (one PLC in the Cluster at least)
-    if (plcMap_.size() > 0)
+    if (!plcMap_.empty())
     { // Retrieve the block-map from the first PLC (same for each of them)
-        blockVectorType blockCol = plcMap_.begin()->second->getBlockCol();
-
-        blockVectorType::iterator block;
-        for (block = blockCol.begin(); block != blockCol.end(); ++block)
+        auto& devices = plcMap_.begin()->second->getDevices();
+        for (auto& device : devices)
         {
-            if ( (*block)->getAccessType() == accessType)
+            auto& blockCol = device.getBlocks();
+            for (auto& block : blockCol)
             {
-                std::string blockName = (*block)->getName();
-                blockList.append(blockName + " ");
+                if (block->getAccessType() == accessType)
+                {
+                    uniqueBlocks.insert(block->getName());
+                }
             }
         }
     }
+    std::string blockList = "";
+    for (auto& block : uniqueBlocks)
+    {
+        blockList.append(block + " ");
+    }
     return blockList;
 }
 
 std::string Cluster::getBlockList()
 {
-    std::string blockList = "";
+    std::set<std::string> uniqueBlocks;
     //At first, check this class/version is already deployed (one PLC in the Cluster at least)
-    if (plcMap_.size() > 0)
+    if (!plcMap_.empty())
     { // Retrieve the block-map from the first PLC (same for each of them)
-        blockVectorType blockCol = plcMap_.begin()->second->getBlockCol();
-
-        blockVectorType::iterator block;
-        for (block = blockCol.begin(); block != blockCol.end(); ++block)
+        auto& devices = plcMap_.begin()->second->getDevices();
+        for (auto& device : devices)
         {
-            std::string blockName = (*block)->getName();
-            blockList.append(blockName + " ");
+            auto& blockCol = device.getBlocks();
+            for (auto& block : blockCol)
+            {
+                uniqueBlocks.insert(block->getName());
+            }
         }
     }
+    std::string blockList = "";
+    for (auto& block : uniqueBlocks)
+    {
+        blockList.append(block + " ");
+    }
     return blockList;
 }
 
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h
index aa68187..f19c1e5 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h
@@ -140,12 +140,6 @@ private:
     bool getHostNameByAddress(const std::string IPAddress, std::string& hostName);
     bool getAddressByHostName(const std::string hostName, std::string& IPAddress);
 
-    /*!
-     * \fn getBlock
-     * \brief returns instance of the requested block
-     */
-    Block* getBlock(const std::string blockName);
-
     /// Store the current FEC name
     std::string hostName_;
 
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp
index d324d6d..e1fa081 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp
@@ -13,7 +13,6 @@ Contributors:
 
 #include <silecs-communication/interface/equipment/SilecsDevice.h>
 
-#include <silecs-communication/interface/core/Context.h>
 #include <silecs-communication/interface/core/SilecsService.h>
 #include <silecs-communication/interface/equipment/SilecsBlock.h>
 #include <silecs-communication/interface/equipment/SilecsCluster.h>
@@ -23,6 +22,7 @@ Contributors:
 #include <silecs-communication/interface/utility/SilecsException.h>
 #include <silecs-communication/interface/utility/SilecsLog.h>
 #include <silecs-communication/interface/utility/XMLParser.h>
+#include <silecs-communication/interface/equipment/PLCBlock.h>
 
 #include <silecs-communication/interface/equipment/CNVRegister.h>
 
@@ -30,27 +30,17 @@ Contributors:
 
 namespace Silecs
 {
-Device::Device(PLC* thePLC, const ElementXML& deviceNode, const std::vector<ElementXML>& blockNodes) :
-                thePLC_(thePLC)
+Device::Device(const ElementXML& deviceNode, const std::vector<ElementXML>& blockNodes, Connection& plcConnection, const SilecsParamConfig& paramConfig) :
+        paramConfig_(paramConfig)
 {
     // Update Device ElementXML attributes
     label_ = deviceNode.getAttribute("label");
     StringUtilities::fromString(address_, deviceNode.getAttribute("address"));
 
-    //For backward compatibility (IO addresses are not defined in Silecs version <1.4.0)
-    //Undefined address = -1 by default.
-    ai_address_ = -1;
-    ao_address_ = -1;
-    di_address_ = -1;
-    do_address_ = -1;
-    if (deviceNode.hasAttribute("AI-address"))
-        StringUtilities::fromString(ai_address_, deviceNode.getAttribute("AI-address"));
-    if (deviceNode.hasAttribute("AO-address"))
-        StringUtilities::fromString(ao_address_, deviceNode.getAttribute("AO-address"));
-    if (deviceNode.hasAttribute("DI-address"))
-        StringUtilities::fromString(di_address_, deviceNode.getAttribute("DI-address"));
-    if (deviceNode.hasAttribute("DO-address"))
-        StringUtilities::fromString(do_address_, deviceNode.getAttribute("DO-address"));
+    StringUtilities::fromString(ai_address_, deviceNode.getAttribute("AI-address"));
+    StringUtilities::fromString(ao_address_, deviceNode.getAttribute("AO-address"));
+    StringUtilities::fromString(di_address_, deviceNode.getAttribute("DI-address"));
+    StringUtilities::fromString(do_address_, deviceNode.getAttribute("DO-address"));
 
     LOG(ALLOC) << "Creating SilecsDevice: " << label_;
 
@@ -63,79 +53,66 @@ Device::Device(PLC* thePLC, const ElementXML& deviceNode, const std::vector<Elem
         if (blockIter->hasAttribute("ioType")) // only IO-Blocks have this attribute
             accessArea = Block::whichAccessArea(blockIter->getAttribute("ioType"));
         auto& registerNodes = blockIter->getChildNodes();
-        instantiateRegisters(blockName, accessType, accessArea, registerNodes);
+
+        blocks_.emplace_back(new PLCBlock(*blockIter, registerNodes, accessType, getInputAddress(accessArea),
+            getOutputAddress(accessArea), plcConnection, paramConfig));
     }
 }
 
 Device::~Device()
 {
     LOG(ALLOC) << "Device (delete): " << label_;
-
-    // Remove the register instances related to this Device
-    registerVectorType::iterator pRegisterIter;
-    for (pRegisterIter = registerCol_.begin(); pRegisterIter != registerCol_.end(); ++pRegisterIter)
-        delete pRegisterIter->second;
-    registerCol_.clear();
-
-    // Register instances have been deleted before, just clear the block-register Map.
-    blockRegisterMap_.clear();
 }
 
-PLC* Device::getPLC() const
+const std::vector<std::unique_ptr<Block>>& Device::getBlocks() const
 {
-    return thePLC_;
+    return blocks_;
 }
 
-Register* Device::getRegister(const std::string& registerName) const
+const std::unique_ptr<Register>& Device::getRegister(const std::string& registerName) const
 {
-    for (auto iter = registerCol_.begin(); iter != registerCol_.end(); ++iter)
+    for (auto& block : blocks_)
     {
-        if (iter->first == registerName)
+        for (auto& reg : block->getRegisters())
         {
-            return iter->second;
+            if (reg->getName() == registerName)
+            {
+                return reg;
+            }
         }
     }
     throw SilecsException(__FILE__, __LINE__, PARAM_UNKNOWN_REGISTER_NAME, registerName);
-    return NULL; // to suppress warning
 }
 
-std::vector<Register*>& Device::getRegisterCollection(const std::string& blockName)
+const std::vector<std::unique_ptr<Register>>& Device::getRegisterCollection(const std::string& blockName) const
 {
-    blockRegisterMapType::iterator iter = blockRegisterMap_.find(blockName);
-    if (iter == blockRegisterMap_.end())
+    auto blockIt = std::find_if(blocks_.begin(), blocks_.end(),
+        [&blockName](const std::unique_ptr<Block>& block)
+    {
+        return block->getName() == blockName;
+    });
+    if (blockIt == blocks_.end())
     {
         throw SilecsException(__FILE__, __LINE__, PARAM_UNKNOWN_BLOCK_NAME, blockName);
     }
-    return iter->second;
+    return (*blockIt)->getRegisters();
 }
 
 int Device::recv(const std::string& blockName)
 {
     //Synchronous device data receive
-
-    //Context of the transaction:
-    //this = the device to be treated,
-    //false = is not for registers synchronization (normal transaction)
-    Context context(this, false);
-
     //Execute the receive action for the required device (from the current thread)
-    return getBlock(blockName)->receive(&context);
+    return getBlock(blockName)->receive();
 }
 
 int Device::send(const std::string& blockName)
 {
     //Synchronous device data send
-
-    //Context of the transaction:
-    //this = the device to be treated,
-    //false = is not for registers synchronization (normal transaction)
-    Context context(this, false);
-
     //Execute the receive action for the required device (from the current thread)
-    return getBlock(blockName)->send(&context);
+    return getBlock(blockName)->send();
 }
 
-std::string Device::getLabel() const
+const std::string& Device::getLabel() const
 {
     return label_;
 }
@@ -143,126 +120,44 @@ std::string Device::getLabel() const
 std::string Device::getRegisterList() const
 {
     std::string registerList = "";
-    for (auto pRegisterIter = registerCol_.begin(); pRegisterIter != registerCol_.end(); ++pRegisterIter)
+    for (auto& block : blocks_)
     {
-        if (!registerList.empty())
-            registerList.append(" ");
-        registerList.append(pRegisterIter->second->getName());
+        for (auto& reg : block->getRegisters())
+        {
+            if (!registerList.empty())
+            {
+                registerList.append(" ");
+            }
+            registerList.append(reg->getName());
+        }
     }
     return registerList;
 }
 
-Register* Device::instantiateRegister(const ElementXML& registerNode)
-{
-    switch (getPLC()->getBrandID())
-    {
-        // SIEMENS PLCs use Motorola memory convention (BigEndianRegister)
-        case Siemens:
-            return new S7Register(this, registerNode);
-
-            // SCHNEIDER PLCs use Intel memory convention (LittleEndianRegister)
-            // RABBIT microcontrollers use Intel memory convention (LittleEndianRegister)
-        case Schneider:
-        case Digi:
-            return new UnityRegister(this, registerNode);
-
-            // BECKHOFF PLCs use different memory convention depending on PLC type:
-            // . CX model: same convention than Unity
-            // . BC model: special convention for 64 bits data (float, ..): swap only the two 16bits words together (no bytes swap).
-        case Beckhoff:
-            return new TwinCATRegister(this, registerNode);
-
-#ifdef NI_SUPPORT_ENABLED
-            //NI Shared variables use specific convention
-            case Ni:
-            return new CNVRegister(this, registerNode);
-#endif
-
-        default:
-            throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_PLC_MANUFACTURER, getPLC()->getBrand());
-
-    } //switch
-}
-
-void Device::instantiateRegisters(const std::string& blockName, AccessType accessType, AccessArea accessArea, const std::vector<ElementXML>& registerNodes)
+const std::unique_ptr<Block>& Device::getBlock(const std::string& blockName)
 {
-    std::vector<Register*> registerCol;
-
-    //LOG(SETUP) << "Ordering registers for block: " <<  blockName << " on Device: " << getLabel();
-
-    for (auto registerIter = registerNodes.begin(); registerIter != registerNodes.end(); registerIter++)
+    auto blockIt = std::find_if(blocks_.begin(), blocks_.end(),
+        [&blockName](const std::unique_ptr<Block>& block)
     {
-        std::string registerName = registerIter->getAttribute("name");
-        Register* pReg = instantiateRegister(*registerIter);
-        pReg->setAccessArea(accessArea);
-        pReg->setAccessType(accessType);
-        pReg->setBlockName(blockName);
-        registerCol.push_back(pReg);
-        registerCol_.push_back(std::make_pair(registerName, pReg));
-    }
-    blockRegisterMap_.insert(std::make_pair(blockName, registerCol));
-}
-
-Block* Device::getBlock(const std::string& blockName)
-{
-    if (!hasBlock(blockName))
+        return block->getName() == blockName;
+    });
+    if (blockIt == blocks_.end())
     {
         std::ostringstream errorMessage;
         errorMessage << "Block not found! The block '" << blockName << "' does not exist on the device '" << label_ << "'.";
         throw SilecsException(__FILE__, __LINE__, errorMessage.str());
     }
-    return thePLC_->getBlock(blockName);
+    return *blockIt;
 }
 
 bool Device::hasBlock(const std::string& blockName)
 {
-    blockRegisterMapType::iterator iter;
-    iter = blockRegisterMap_.find(blockName);
-    return (iter != blockRegisterMap_.end());
-}
-
-void Device::importRegisters(Block* pBlock, void* pBuffer, timeval ts, Context* pContext)
-{
-    std::vector<Register*>& registerCol = getRegisterCollection(pBlock->getName());
-    std::vector<Register*>::iterator pReg;
-    for (pReg = registerCol.begin(); pReg < registerCol.end(); pReg++)
-    {
-        if (!pContext->isForSynchronization())
-        {
-            if ( (*pReg)->getFormat() == String)
-                (*pReg)->importString(pBuffer, ts);
-            else
-                (*pReg)->importValue(pBuffer, ts);
-        }
-    }
-}
-
-void Device::exportRegisters(Block* pBlock, void* pBuffer, Context* pContext)
-{
-    std::vector<Register*>& registerCol = getRegisterCollection(pBlock->getName());
-    std::vector<Register*>::iterator pReg;
-    for (pReg = registerCol.begin(); pReg < registerCol.end(); pReg++)
+    auto blockIt = std::find_if(blocks_.begin(), blocks_.end(),
+        [&blockName](const std::unique_ptr<Block>& block)
     {
-        if (!pContext->isForSynchronization())
-        {
-            if ( (*pReg)->getFormat() == String)
-                (*pReg)->exportString(pBuffer);
-            else
-                (*pReg)->exportValue(pBuffer);
-        }
-    }
-}
-
-void Device::copyInToOut(const std::string& blockName)
-{
-    std::vector<Register*>& registerCol = getRegisterCollection(blockName);
-    for (unsigned int i = 0; i < registerCol.size(); i++)
-    {
-        Register* pReg = registerCol[i];
-        if (pReg->isReadable() && pReg->isWritable())
-            pReg->copyValue();
-    }
-
+        return block->getName() == blockName;
+    });
+    return blockIt != blocks_.end();
 }
 
 } // namespace
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h
index 2eb7916..4610506 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h
@@ -15,15 +15,19 @@ Contributors:
 #define _SILECS_DEVICE_H_
 
 #include <silecs-communication/interface/core/SilecsService.h>
+#include <silecs-communication/interface/equipment/SilecsBlock.h>
+#include <silecs-communication/interface/communication/SilecsConnection.h>
+#include <silecs-communication/interface/equipment/SilecsParamConfig.h>
 
 #include <string>
 #include <vector>
 #include <map>
+#include <memory>
+#include <iostream>
 
 namespace Silecs
 {
 class PLC;
-class Block;
 class ElementXML;
 class Register;
 class Context;
@@ -43,12 +47,6 @@ class Device
 {
 public:
 
-    /*!
-     * \brief Returns reference of the PLC where the device is instantiated
-     * \return Reference of the PLC object
-     */
-    PLC* getPLC() const;
-
     /*!
      * \brief Returns the label of the device as defined in the Deployment document.
      *  A device label is not visible from the supervision. It's the device identifier within
@@ -56,14 +54,14 @@ public:
      *  corresponding index [1..n] in the device collection.
      * \return label or index of the device as string
      */
-    std::string getLabel() const;
+    const std::string& getLabel() const;
 
     /*!
      * \brief Returns one register instance of the device by its name
      * \param registerName name of the register
      * \return Reference of the register object
      */
-    Register* getRegister(const std::string& registerName) const;
+    const std::unique_ptr<Register>& getRegister(const std::string& registerName) const;
 
     /*!
      * \brief Acquires one particular registers block of the device.
@@ -88,13 +86,13 @@ public:
      * The method copies the input buffer in the output buffer for each READ-WRITE register for the block passed as parameter
      * \param blockName name of the block for which the copy must be performed
      */
-    void copyInToOut(const std::string& blockName);
+    // void copyInToOut(const std::string& blockName);
 
     /// @cond
     /*!
      * \return all registers of the device for a given block
      */
-    std::vector<Register*>& getRegisterCollection(const std::string& blockName);
+    const std::vector<std::unique_ptr<Register>>& getRegisterCollection(const std::string& blockName) const;
 
     /*!
      * \return String list (space separated value) of the Device registers
@@ -102,73 +100,71 @@ public:
     std::string getRegisterList() const;
     /// @endcond
 
-private:
-    // export device attributes to the Actions
-    friend class PLC;
-    friend class Register;
-    friend class PLCRegister;
-    friend class PLCBlock;
-    friend class Context;
+    Device(const ElementXML& deviceNode, const std::vector<ElementXML>& blockNodes, Connection& plcConnection, const SilecsParamConfig& paramConfig);
+    ~Device();
+
+    Device(Device&& other) :
+        label_(std::move(other.label_)),
+        address_(other.address_),
+        ai_address_(other.ai_address_),
+        ao_address_(other.ao_address_),
+        di_address_(other.di_address_),
+        do_address_(other.do_address_),
+        blocks_(std::move(other.blocks_))
+    {
+        address_ = -1;
+        ai_address_ = -1;
+        ao_address_ = -1;
+        di_address_ = -1;
+        do_address_ = -1;
+    };
 
-    friend class CNVRegister;
-    friend class CNVRecvBlockMode;
-    friend class CNVRecvDeviceMode;
-    friend class CNVSendBlockMode;
-    friend class CNVSendDeviceMode;
+    const std::vector<std::unique_ptr<Block>>& getBlocks() const;
 
-    Device(PLC* thePLC, const ElementXML& deviceNode, const std::vector<ElementXML>& blockNodes);
-    virtual ~Device();
+    /*!
+     * \fn getBlock
+     * \brief returns one instance of the requested block checking its access-type
+     */
+    const std::unique_ptr<Block>& getBlock(const std::string& blockName);
 
-    inline long& getInputAddress(AccessArea area)
+    long getInputAddress(AccessArea area)
     {
         if (area == AccessArea::Digital)
+        {
             return di_address_;
+        }
         else if (area == AccessArea::Analog)
+        {
             return ai_address_;
+        }
         return address_;
     }
 
-    inline long& getOutputAddress(AccessArea area)
+    long getOutputAddress(AccessArea area)
     {
         if (area == AccessArea::Digital)
+        {
             return do_address_;
+        }
         else if (area == AccessArea::Analog)
+        {
             return ao_address_;
+        }
         return address_;
     }
 
-    Register* instantiateRegister(const ElementXML& registerNode);
-
-    void instantiateRegisters(const std::string& blockName, AccessType accessType, AccessArea accessArea, const std::vector<ElementXML>& registerNodes);
+private:
+    // export device attributes to the Actions
+    friend class PLC;
 
-    /*!
-     * \fn getBlock
-     * \brief returns one instance of the requested block checking its access-type
-     */
-    Block* getBlock(const std::string& blockName);
+    friend class CNVRegister;
+    friend class CNVRecvBlockMode;
+    friend class CNVRecvDeviceMode;
+    friend class CNVSendBlockMode;
+    friend class CNVSendDeviceMode;
 
     bool hasBlock(const std::string& blockName);
 
-    /*!
-     * \fn importRegisters
-     * \brief Extract all the concerned registers data of that device from a given block and set the registers value.
-     * \param pBlock: block which contain list of registers to be imported
-     * \param pBuffer: direct pointer on the buffer which contain the registers data
-     * \param ts is the time-of-day to time-stamp each register
-     */
-    void importRegisters(Block* pBlock, void* pBuffer, timeval ts, Context* pContext);
-
-    /*!
-     * \fn exportRegisters
-     * \brief Export all the concerned registers value of that device to a given block.
-     * \param pBlock: block which contain list of registers to be exported
-     * \param pBuffer: direct pointer on the buffer which will contain the registers data
-     */
-    void exportRegisters(Block* pBlock, void* pBuffer, Context* pContext);
-
-    /// Parent PLC reference of that device
-    PLC* thePLC_;
-
     /// Device attributes
     std::string label_;
     long address_;
@@ -177,12 +173,9 @@ private:
     long di_address_;
     long do_address_;
 
-    /// Register collection of that device
-    registerVectorType registerCol_;
-
-    /// Collections of the device registers by block
-    blockRegisterMapType blockRegisterMap_;
+    SilecsParamConfig paramConfig_;
 
+    std::vector<std::unique_ptr<Block>> blocks_;
 };
 
 } // namespace
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp
index 69ef6e6..25c63a0 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp
@@ -44,6 +44,7 @@ PLC::PLC(Cluster* theCluster, std::string plcName, std::string plcIPaddr, std::s
     //Force PLC hostname lower-case
     name_ = plcName;
     StringUtilities::toLower(name_);
+    paramConfig_.plcName = name_;
 
     LOG(ALLOC) << "PLC (create): " << name_ << "/ " << IPaddr_;
 
@@ -53,12 +54,10 @@ PLC::PLC(Cluster* theCluster, std::string plcName, std::string plcIPaddr, std::s
     // Upload the parameters file and build the PLC configuration
     extractDatabase();
 
-    // create default contexts for all-devices transaction (normal and for synchronization)
-    allDevicesTransaction_ = new Context(NULL/*no Device: for all devices)*/, false);
-    allDevicesSynchronization_ = new Context(NULL/*no Device: for all devices)*/, true);
-
     // Instantiate the communication interface
-    plcConn_ = NULL;
+    createConnection();
+
+    createDevices();
 }
 
 PLC::~PLC()
@@ -67,39 +66,12 @@ PLC::~PLC()
 
     //Before removing the PLC resources, we need to interrupt all the related accesses (if connection is not shared)
     disconnect();
-
-    // Remove PLC communication resources
-    if (plcConn_ != NULL)
-    {
-        delete plcConn_;
-        plcConn_ = NULL;
-    }
-
-    //theHeader object must not be delete from the PLC since it is shared between all the PLC
-    //instances. It will be removed by the Service destructor at the end.
-
-    delete allDevicesTransaction_;
-    delete allDevicesSynchronization_;
-
-    // Remove the Device instances related to this PLC
-    deviceVectorType::iterator pDeviceIter;
-    for (pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter)
-        delete pDeviceIter->second;
-    deviceCol_.clear();
-
-    // Remove the Block instances related to this PLC
-    blockVectorType::iterator pBlockIter;
-    for (pBlockIter = blockCol_.begin(); pBlockIter != blockCol_.end(); ++pBlockIter)
-    {
-        delete *pBlockIter;
-    }
 }
 
 void PLC::connect(bool connectNow, bool compareChecksums)
 {
     //At first, Instantiate the PLC connection object if needed
     LOG((COMM|DIAG)) << "Attempt to establish connection ... ";
-    /*plcConn_ =*/getConnection();
     //Check PLC is not already Enabled
     std::string connStr = name_ + "(" + IPaddr_ + ")" + ":" + theCluster_->getClassName() + "/v" + theCluster_->getClassVersion();
     LOG(COMM) << connStr;
@@ -113,58 +85,69 @@ void PLC::connect(bool connectNow, bool compareChecksums)
     
     LOG(COMM) << (connectNow ? "Open" : "Enable") << " Connection request for " << connStr;
 
-    if (getTypeID() == BusCoupler)
+    if (paramConfig_.typeID == BusCoupler)
     { //This is an Ethernet coupler (pure RIO) => immediate connection without SilecsHeader check
         plcConn_->enable(connectNow);
         return;
     }
     
     // Whatever the outcome of the connection that will follow, the PLC must be Enabled in any case.
-    // Thus, even if the PLC is off and rejects the first connection to upload the Header (see updateHeader),
+    // Thus, even if the PLC is off and rejects the first connection to upload the Header,
     // we will automatically attempt to reconnect later at the next PLC accesses (send/recv) ... again and again.
     plcConn_->enable(connectNow);
     
-    if (getTypeID() != BusCoupler && compareChecksums)
+    auto headerIt = std::find_if(devices_.begin(), devices_.end(),
+        [](const Device& dev)
+    {
+        return dev.getLabel() == "SilecsHeader";
+    });
+
+    if (paramConfig_.typeID != BusCoupler && compareChecksums)
     {
         /* PLC memory could have change during a disconnection time (downloading or other).
          The Header registers must be reloaded for consistency checking.
          Do not continue the connection sequence if it is not even possible to load the header.
          */
         LOG(COMM) << "getting checksum";
-        remoteChecksum_ = theHeader_->getRegister("_checksum")->getVal<std::uint32_t>();
-        if (remoteChecksum_ != localChecksum_)
+        if (headerIt == devices_.end())
+        {
+            throw SilecsException(__FILE__, __LINE__, UNEXPECTED_ERROR, "Missing SilecsHeader.");
+        }
+
+        remoteChecksum_ = headerIt->getRegister("_checksum")->getVal<std::uint32_t>();
+        if (remoteChecksum_ != paramConfig_.localChecksum)
         { //Client and PLC mapping are not consistent ... no transaction are possible!
             disconnect();
             std::ostringstream message;
-            message << "Checksum comparison failed. Checksum in parameter file: '" << localChecksum_ << "' Checksum in PLC: '" << remoteChecksum_ << "' Disconnecting PLC now.";
+            message << "Checksum comparison failed. Checksum in parameter file: '" << paramConfig_.localChecksum << "' Checksum in PLC: '" << remoteChecksum_ << "' Disconnecting PLC now.";
             throw SilecsException(__FILE__, __LINE__, CONFIG_CLIENT_PLC_NOT_CONSISTENT, message.str());
         }
     }
 
     //Warn ACET service that a new connection is established (except for SilecsHeader)
-    if (theHeader_ != NULL)
+    if (headerIt == devices_.end())
     {
-        TRACE("info") << "Connection setup: ClassName=" << theCluster_->getClassName() << ", " << "ClassVersion=" << theCluster_->getClassVersion() << ", " << "Owner=" << localOwner_ << ", " << "GenerationRelease=" << localRelease_ << ", " << "GenerationDate=" << localDate_ << ", " << "PlcChecksum=" << localChecksum_ << ", " << "PlcDomain=" << domain_ << ", " << "PlcHostname=" << name_ << ", " << "PlcBrand=" << brand_ << ", " << "PlcSystem=" << system_ << ", " << "PlcModel=" << model_ << ", " << "ProtocolAddress=" << baseMemAddr_ << ", " << "ProtocolMode=" << protocolMode_ << ", " << "InstanceNumber=" << deviceCol_.size();
+        return;
     }
+
+    TRACE("info") << "Connection setup: ClassName=" << theCluster_->getClassName() << ", " << "ClassVersion=" << theCluster_->getClassVersion() << ", " << "Owner=" << paramConfig_.localOwner << ", " << "GenerationRelease=" << paramConfig_.localRelease << ", " << "GenerationDate=" << paramConfig_.localDate << ", " << "PlcChecksum=" << paramConfig_.localChecksum << ", " << "PlcDomain=" << paramConfig_.domain << ", " << "PlcHostname=" << name_ << ", " << "PlcBrand=" << paramConfig_.brand << ", " << "PlcSystem=" << paramConfig_.system << ", " << "PlcModel=" << paramConfig_.model << ", " << "ProtocolAddress=" << paramConfig_.baseMemAddr << ", " << "ProtocolMode=" << paramConfig_.protocolMode << ", " << "InstanceNumber=" << devices_.size();
 }
-;
 
 void PLC::disconnect()
 {
     if (DEBUG & Log::topics_)
         LOG(COMM) << "Disconnection request for " << name_ << ":" << theCluster_->getClassName() << "/v" << theCluster_->getClassVersion();
-    //close the connection (also close the connection if shared with other cluster on the same PLC!)
-    getConnection()->disable();
+    //close the connection
+    plcConn_->disable();
 }
-;
 
 bool PLC::isEnabled()
 {
-    return ( (plcConn_ == NULL) ? false : plcConn_->isEnabled()); /*do not use getConnection() here*/
+    return plcConn_->isEnabled();
 }
 bool PLC::isConnected(bool connectNow)
 {
-    return (connectNow ? getConnection()->doOpen() : getConnection()->isConnected());
+    return (connectNow ? plcConn_->doOpen() : plcConn_->isConnected());
 }
 
 std::string PLC::getParamsFileName() const
@@ -175,11 +158,9 @@ std::string PLC::getParamsFileName() const
 unsigned int PLC::getNrDevicesWithBlock(const std::string& blockName)
 {
     unsigned int devicesWithBlock = 0;
-    deviceVectorType::iterator pDeviceIter;
-    for (pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter)
+    for (auto& device : devices_)
     {
-        Device* pDev = pDeviceIter->second;
-        if (pDev->hasBlock(blockName))
+        if (device.hasBlock(blockName))
         {
             devicesWithBlock++;
         }
@@ -197,31 +178,25 @@ const Cluster& PLC::getCluster() const
     return *theCluster_;
 }
 
-bool PLC::hasHeader() const
-{
-    return theHeader_ != nullptr;
-}
-
-Device* PLC::getDevice(const std::string& deviceName) const
+Device* PLC::getDevice(const std::string& deviceName)
 {
-    for (auto iter = deviceCol_.begin(); iter != deviceCol_.end(); ++iter)
+    for (auto& device : devices_)
     {
-        if (iter->first == deviceName)
+        if (device.getLabel() == deviceName)
         {
-            return iter->second;
+            return &device;
         }
     }
 
     throw SilecsException(__FILE__, __LINE__, PARAM_UNKNOWN_DEVICE_NAME, deviceName + "/" + name_);
-    return NULL; //to suppress warning
 }
 
 std::vector<std::string> PLC::getDeviceList() const
 {
     std::vector<std::string> deviceList;
-    for (auto pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter)
+    for (auto& device : devices_)
     {
-        deviceList.push_back(pDeviceIter->first);
+        deviceList.push_back(device.getLabel());
     }
     return deviceList;
 }
@@ -234,100 +209,22 @@ std::string PLC::getIPAddress() const
 {
     return IPaddr_;
 }
-std::string PLC::getDomain() const
-{
-    return domain_;
-}
-std::string PLC::getBrand() const
-{
-    return brand_;
-}
-std::string PLC::getSystem() const
-{
-    return system_;
-}
-std::string PLC::getModel() const
-{
-    return model_;
-}
-PLCType PLC::getPLCType() const
-{
-    return typeID_;
-}
-std::string PLC::getProtocolType() const
-{
-    return protocolType_;
-}
-std::string PLC::getProtocolMode() const
-{
-    return protocolMode_;
-}
-unsigned long PLC::getBaseAddress() const
-{
-    return baseMemAddr_;
-}
-
-long PLC::getMemBaseAddress() const
-{
-    return baseMemAddr_;
-}
-
-long PLC::getDIBaseAddress() const
-{
-    return baseDIAddr_;
-}
-
-long PLC::getDOBaseAddress() const
-{
-    return baseDOAddr_;
-}
-
-long PLC::getAIBaseAddress() const
-{
-    return baseAIAddr_;
-}
-
-long PLC::getAOBaseAddress() const
-{
-    return baseAOAddr_;
-}
 
-deviceVectorType& PLC::getDeviceMap()
-{
-    return deviceCol_;
-}
-std::string PLC::getLocalRelease() const
+const SilecsParamConfig& PLC::getParamConfig() const
 {
-    return localRelease_;
-}
-std::string PLC::getLocalOwner() const
-{
-    return localOwner_;
-}
-std::string PLC::getLocalDate() const
-{
-    return localDate_;
-}
-unsigned long PLC::getLocalChecksum() const
-{
-    return localChecksum_;
+    return paramConfig_;
 }
 
 void PLC::updateLocalData()
 {
-    blockVectorType::iterator blockIter;
-    for (blockIter = blockCol_.begin(); blockIter != blockCol_.end(); blockIter++)
+    for (auto& device : devices_)
     {
-        deviceVectorType::iterator pDeviceIter;
-        for (pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter)
+        for (auto& block : device.getBlocks())
         {
-            if (pDeviceIter->second->hasBlock( (*blockIter)->getName()))
+            if (block->isReadable())
             {
-                if ( (*blockIter)->isReadable())
-                {
-                    LOG(COMM) << "Updating block '" << (*blockIter)->getName() << "' for device '" << pDeviceIter->second->getLabel() << "'";
-                    pDeviceIter->second->recv( (*blockIter)->getName());
-                }
+                LOG(COMM) << "Updating block '" << block->getName() << "' for device '" << device.getLabel() << "'";
+                block->receive();
             }
         }
     }
@@ -335,66 +232,232 @@ void PLC::updateLocalData()
 
 int PLC::recvUnitCode(UnitCodeType& dataStruct)
 {
-    return getConnection()->readUnitCode(dataStruct);
+    return plcConn_->readUnitCode(dataStruct);
 }
 
 int PLC::recvUnitStatus(UnitStatusType& dataStruct)
 {
-    return getConnection()->readUnitStatus(dataStruct);
+    return plcConn_->readUnitStatus(dataStruct);
 }
 
 bool PLC::isRunning()
 {
-    return getConnection()->isRunning();
+    return plcConn_->isRunning();
 }
 
 int PLC::recvCPUInfo(CPUInfoType& dataStruct)
 {
-    return getConnection()->readCPUInfo(dataStruct);
+    return plcConn_->readCPUInfo(dataStruct);
 }
 
 int PLC::recvCPInfo(CPInfoType& dataStruct)
 {
-    return getConnection()->readCPInfo(dataStruct);
+    return plcConn_->readCPInfo(dataStruct);
 }
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //
 //Puts the CPU in RUN mode performing a COLD START.
 int PLC::sendColdRestart()
 {
-    return getConnection()->coldRestart();
+    return plcConn_->coldRestart();
 }
 
 int PLC::sendPlcStop()
 {
-    return getConnection()->plcStop();
+    return plcConn_->plcStop();
 }
 //
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+int PLC::recvAllBlockMode(const std::string& blockName)
+{
+    // TODO: When devices will be structured by classes, make sure that same block name in two classes does not cause problems.
+    auto& block = getOneDeviceBlock(blockName); // Get first device's block.
+    
+    unsigned long address = block->getAddress();
+    unsigned long memSize = block->getMemSize();
+    unsigned long bufferSize = memSize * getNrDevicesWithBlock(blockName);
+    unsigned long offset = 0;
+
+    AccessArea area = block->getAccessArea();
+
+    std::vector<unsigned char> buffer(bufferSize, 0);
+
+    int errorCode = 0;
+
+    // Try to open the connection, if it fails. Throw an exception. On success all the
+    // PLC blocks will be updated this function will be called recursively within doOpen.
+    // Once all blocks are updated continue from here.
+    if (!plcConn_->doOpen())
+    {
+        throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE};
+    }
+
+    switch (area)
+    {
+    case AccessArea::Digital:
+        errorCode = plcConn_->readDIO(address, offset, bufferSize, buffer.data());
+        break;
+    case AccessArea::Analog:
+    {
+        errorCode = plcConn_->readAIO(address, offset, bufferSize, buffer.data());
+        break;
+    }
+    case AccessArea::Memory:
+    default:
+        errorCode = plcConn_->readMemory(address, offset, bufferSize, buffer.data());
+        break;
+    }
+
+    if (plcConn_->isConnected() && (errorCode == 0))
+    {
+        timeval tod;
+        gettimeofday(&tod, 0);
+
+        //PLC context: Extract all registers value of all devices of the PLC from that block
+        for (auto& device : devices_)
+        {
+            // Only extract if this device actually contains this block, otherwise skip it.
+            if (!device.hasBlock(blockName))
+            {
+                continue;
+            }
+            auto& devBlock = device.getBlock(blockName);
+            unsigned long deviceOffset = device.getInputAddress(area) * memSize;
+            unsigned char* pBuffer = buffer.data() + deviceOffset;
+            devBlock->importRegisters(pBuffer, tod);
+        }
+    }
+    return errorCode;
+}
+
+int PLC::sendAllBlockMode(const std::string& blockName)
+{
+    // TODO: When devices will be structured by classes, make sure that same block name in two classes does not cause problems.
+    auto& block = getOneDeviceBlock(blockName); // Get first device's block.
+    
+    unsigned long address = block->getAddress();
+    unsigned long memSize = block->getMemSize();
+    unsigned long bufferSize = memSize * getNrDevicesWithBlock(blockName);
+    unsigned long offset = 0;
+
+    AccessArea area = block->getAccessArea();
+
+    std::vector<unsigned char> buffer(bufferSize, 0);
+
+    int errorCode = 0;
+
+    // Try to open the connection, if it fails. Throw an exception. On success all the
+    // PLC blocks will be updated this function will be called recursively within doOpen.
+    // Once all blocks are updated continue from here.
+    if (!plcConn_->doOpen())
+    {
+        throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE};
+    }
+
+    if (plcConn_->isEnabled())
+    {
+        //PLC context: Export all registers value of all devices of the PLC to that block
+        for (auto& device : devices_)
+        {
+            // Only if this device actually contains this block, otherwise skip it.
+            if (!device.hasBlock(blockName))
+            {
+                continue;
+            }
+            auto& devBlock = device.getBlock(blockName);
+            unsigned long deviceOffset = device.getOutputAddress(area) * memSize;
+            unsigned char* pBuffer = buffer.data() + deviceOffset;
+            devBlock->exportRegisters(pBuffer);
+        }
+    }
+    switch (area)
+    {
+    case AccessArea::Digital:
+        errorCode = plcConn_->writeDIO(address, offset, bufferSize, buffer.data());
+        break;
+    case AccessArea::Analog:
+    {
+        errorCode = plcConn_->writeAIO(address, offset, bufferSize, buffer.data());
+        break;
+    }
+    case AccessArea::Memory:
+    default:
+        errorCode = plcConn_->writeMemory(address, offset, bufferSize, buffer.data());
+        break;
+    }
+
+    return errorCode;
+}
+
+int PLC::receiveForAllDevices(const std::string& blockName)
+{
+    int status = 0;
+    if (paramConfig_.protocolModeID == ProtocolMode::DeviceMode)
+    {
+        for (auto& device : devices_)
+        {
+            if (device.hasBlock(blockName))
+            {
+                auto ret = device.recv(blockName);
+                status = (ret != 0) ? ret : status;
+            }
+        }
+    }
+    else
+    {
+        return recvAllBlockMode(blockName);
+    }
+
+    return status;
+}
+
+int PLC::sendForAllDevices(const std::string& blockName)
+{
+    int status = 0;
+    if (paramConfig_.protocolModeID == ProtocolMode::DeviceMode)
+    {
+        for (auto& device : devices_)
+        {
+            if (device.hasBlock(blockName))
+            {
+                auto ret = device.send(blockName);
+                status = (ret != 0) ? ret : status;
+            }
+        }
+    }
+    else
+    {
+        return sendAllBlockMode(blockName);
+    }
+
+    return status;
+}
+
 int PLC::recv(const std::string& blockName)
 {
     //Synchronous data receive
     //Execute the receive action for all the PLC devices (from the current thread)
-    return getBlock(blockName)->receive(allDevicesTransaction_);
+    return receiveForAllDevices(blockName);
 }
 
 int PLC::send(const std::string& blockName)
 {
     //Synchronous data send
     //Execute the send action for all the PLC devices (from the current thread)
-    return getBlock(blockName)->send(allDevicesTransaction_);
+    return sendForAllDevices(blockName);
 }
 
 std::future<int> PLC::recvAsync(const std::string& blockName)
 {
     //Schedule task using asynchronous call
-    return std::async(std::launch::async, &Block::receive, getBlock(blockName), allDevicesTransaction_);
+    return std::async(std::launch::async, &PLC::receiveForAllDevices, this, blockName);
 }
 
 std::future<int> PLC::sendAsync(const std::string& blockName)
 {
     //Schedule task using asynchronous call
-    return std::async(std::launch::async, &Block::send, getBlock(blockName), allDevicesTransaction_);
+    return std::async(std::launch::async, &PLC::sendForAllDevices, this, blockName);
 }
 
 void PLC::extractDatabase()
@@ -404,69 +467,65 @@ void PLC::extractDatabase()
 
     // Extract general information ===========================================
     ElementXML rootNode = xmlParser.getSingleElementFromXPath("/SILECS-Param");
-    localRelease_ = rootNode.getAttribute("silecs-version");
-    if( !Service::isVersionSupported(localRelease_) )
+    paramConfig_.localRelease = rootNode.getAttribute("silecs-version");
+    if( !Service::isVersionSupported(paramConfig_.localRelease) )
     {
       std::ostringstream message;
-      message << "The version of the parameter-file: '" << localRelease_ << "' is not compartible with the version of the silecs-library: '" << Service::getVersion() << "'";
+      message << "The version of the parameter-file: '" << paramConfig_.localRelease << "' is not compartible with the version of the silecs-library: '" << Service::getVersion() << "'";
       throw SilecsException(__FILE__, __LINE__, message.str().c_str());
     }
     ElementXML ownerNode = xmlParser.getSingleElementFromXPath("/SILECS-Param/Mapping-Info/Owner");
-    localOwner_ = ownerNode.getAttribute("user-login");
+    paramConfig_.localOwner = ownerNode.getAttribute("user-login");
 
     ElementXML generationNode = xmlParser.getSingleElementFromXPath("/SILECS-Param/Mapping-Info/Generation");
-    localDate_ = generationNode.getAttribute("date");
+    paramConfig_.localDate = generationNode.getAttribute("date");
 
     ElementXML deploymentNode = xmlParser.getSingleElementFromXPath("/SILECS-Param/Mapping-Info/Deployment");
-    StringUtilities::fromString(localChecksum_, deploymentNode.getAttribute("checksum"));
+    StringUtilities::fromString(paramConfig_.localChecksum, deploymentNode.getAttribute("checksum"));
 
     // Extract PLC general configuration ======================================
     ElementXML mappingNode = xmlParser.getSingleElementFromXPath("/SILECS-Param/SILECS-Mapping");
     //name_ = pEl->getStringAttribute("name"); already done before
-    domain_ = mappingNode.getAttribute("domain");
-    brand_ = mappingNode.getAttribute("plc-brand");
-    system_ = mappingNode.getAttribute("plc-system");
-    protocolMode_ = mappingNode.getAttribute("protocol");
-    model_ = mappingNode.getAttribute("plc-model");
-
-    StringUtilities::fromString(baseMemAddr_, mappingNode.getAttribute("address"));
-    //For backward compatibility (IO addresses are not defined in Silecs version <1.4.0)
-    //Undefined address = -1 by default.
-    baseDIAddr_ = -1;
-    baseDOAddr_ = -1;
-    baseAIAddr_ = -1;
-    baseAOAddr_ = -1;
-    if (mappingNode.hasAttribute("AI-address"))
-        StringUtilities::fromString(baseAIAddr_, mappingNode.getAttribute("AI-address"));
-    if (mappingNode.hasAttribute("AO-address"))
-        StringUtilities::fromString(baseAOAddr_, mappingNode.getAttribute("AO-address"));
-    if (mappingNode.hasAttribute("DI-address"))
-        StringUtilities::fromString(baseDIAddr_, mappingNode.getAttribute("DI-address"));
-    if (mappingNode.hasAttribute("DO-address"))
-        StringUtilities::fromString(baseDOAddr_, mappingNode.getAttribute("DO-address"));
-    usedMem_ = mappingNode.getAttribute("used-mem");
-
-    typeID_ = BusCoupler; //by default, we consider the controller won't use Memory access
-
-    brandID_ = whichPLCBrand(brand_);
-    modelID_ = whichPLCModel(model_);
-    systemID_ = whichPLCSystem(system_);
-    protocolModeID_ = whichProtocolMode(protocolMode_);
-    protocolTypeID_ = whichProtocolType(system_);
-
-    switch (protocolTypeID_)
+    paramConfig_.domain = mappingNode.getAttribute("domain");
+    paramConfig_.brand = mappingNode.getAttribute("plc-brand");
+    paramConfig_.system = mappingNode.getAttribute("plc-system");
+    paramConfig_.protocolMode = mappingNode.getAttribute("protocol");
+    paramConfig_.model = mappingNode.getAttribute("plc-model");
+
+    StringUtilities::fromString(paramConfig_.baseMemAddr, mappingNode.getAttribute("address"));
+    StringUtilities::fromString(paramConfig_.baseAIAddr, mappingNode.getAttribute("AI-address"));
+    StringUtilities::fromString(paramConfig_.baseAOAddr, mappingNode.getAttribute("AO-address"));
+    StringUtilities::fromString(paramConfig_.baseDIAddr, mappingNode.getAttribute("DI-address"));
+    StringUtilities::fromString(paramConfig_.baseDOAddr, mappingNode.getAttribute("DO-address"));
+    paramConfig_.usedMem = mappingNode.getAttribute("used-mem");
+
+    paramConfig_.typeID = BusCoupler; //by default, we consider the controller won't use Memory access
+
+    paramConfig_.brandID = whichPLCBrand(paramConfig_.brand);
+    paramConfig_.modelID = whichPLCModel(paramConfig_.model);
+    paramConfig_.systemID = whichPLCSystem(paramConfig_.system);
+    paramConfig_.protocolModeID = whichProtocolMode(paramConfig_.protocolMode);
+    paramConfig_.protocolTypeID = whichProtocolType(paramConfig_.system);
+
+    switch (paramConfig_.protocolTypeID)
     {
         case MBProtocol:
-            protocolType_ = "MODBUS-TCP";
+            paramConfig_.protocolType = "MODBUS-TCP";
             break;
         case S7Protocol:
-            protocolType_ = "SNAP7-TCP";
+            paramConfig_.protocolType = "SNAP7-TCP";
             break;
         case CNVProtocol:
-            protocolType_ = "CNV-TCP";
+            paramConfig_.protocolType = "CNV-TCP";
             break;
     };
+}
 
+void PLC::createDevices()
+{
+    XMLParser xmlParser(parameterFile_, true);
+    ElementXML mappingNode = xmlParser.getSingleElementFromXPath("/SILECS-Param/SILECS-Mapping");
+    
     const std::vector<ElementXML>& classNodes = mappingNode.getChildNodes();
     for (auto& classNode : classNodes)
     {
@@ -476,99 +535,68 @@ void PLC::extractDatabase()
         std::vector<ElementXML> instanceNodes = xmlParser.getElementsFromXPath("/SILECS-Param/SILECS-Mapping/SILECS-Class[@name='" + className + "']/Instance");
         for (auto instanceIter = instanceNodes.begin(); instanceIter != instanceNodes.end(); instanceIter++)
         {
-            Device* pDevice = new Device(this, *instanceIter, blockNodes);
-            deviceCol_.push_back(std::make_pair(pDevice->getLabel(), pDevice));
-            if (pDevice->getLabel() == "SilecsHeader")
-                theHeader_ = pDevice;
-        }
-
-        for (auto blockIter = blockNodes.begin(); blockIter != blockNodes.end(); blockIter++)
-        {
-            std::string blockName = (*blockIter).getAttribute("name");
-            AccessType accessType = Block::whichAccessType( (*blockIter).getName());
-            LOG((DIAG)) << "The block '" << blockName << " of type '" << (*blockIter).getName() << "' will be created.";
-
-            if (brandID_ == Ni)
+            devices_.emplace_back(*instanceIter, blockNodes, *plcConn_, paramConfig_);
+            for (auto& block : devices_.back().getBlocks())
             {
-#ifdef NI_SUPPORT_ENABLED
-                // TODO: Implement blocks in the same way as done for PLCBlock.
-                throw SilecsException(__FILE__, __LINE__, "CNV Blocks not implemented");
-#else
-                throw SilecsException(__FILE__, __LINE__, "Support for NI-Devices is disabled");
-#endif
+                //Force BusController type (with SilecsHeader check), if there is at least one Memory block defined
+                if (block->getAccessArea() == AccessArea::Memory)
+                {
+                    paramConfig_.typeID = BusController;
+                }
             }
-
-            Block* pBlock = new PLCBlock(this, *blockIter, accessType);
-            blockCol_.push_back(pBlock);
-
-            //Force BusController type (with SilecsHeader check), if there is at least one Memory block defined
-            if (pBlock->getAccessArea() == AccessArea::Memory)
-                typeID_ = BusController;
-
-        } //for blocks
-    } //for classes
+        }
+    }
 }
 
-Connection* PLC::createConnection()
+void PLC::createConnection()
 {
-    Connection* theConn = NULL;
-    try
+    switch (paramConfig_.protocolTypeID)
     {
-        switch (protocolTypeID_)
-        {
-            case S7Protocol:
-                theConn = new SNAP7Connection(this);
-                break;
-            case MBProtocol:
+        case S7Protocol:
+            plcConn_ = std::unique_ptr<Connection>(new SNAP7Connection(this));
+            break;
+        case MBProtocol:
 #ifdef MODBUS_SUPPORT_ENABLED
-                theConn = new MBConnection(this); break;
+            plcConn_ = std::unique_ptr<Connection>(new MBConnection(this));
+            break;
+#else
+            throw SilecsException(__FILE__, __LINE__, "Support for Modbus-Devices is disabled");
 #endif
-            case CNVProtocol:
+        case CNVProtocol:
 #ifdef NI_SUPPORT_ENABLED
-                theConn = new CNVConnection(this);break;
+            plcConn_ = std::unique_ptr<Connection>(new CNVConnection(this));
+            break;
 #else
-                throw SilecsException(__FILE__, __LINE__, "Support for NI-Devices is disabled");
+            throw SilecsException(__FILE__, __LINE__, "Support for NI-Devices is disabled");
 #endif
-            default:
-                throw SilecsException(__FILE__, __LINE__, "Unknown protocolTypeID_");
-        }
-    }
-    catch(const SilecsException& ex)
-    { //Something has failed. Nothing to do, we trust the re-open mechanism from now.
-        LOG(ERROR) << ex.what();
-        throw ex;
+        default:
+            throw SilecsException(__FILE__, __LINE__, "Unknown protocolTypeID");
     }
 
     if (DEBUG & Log::topics_)
         LOG(COMM) << "PLC::createConnection()";
-    return theConn;
 }
 
-Connection* PLC::getConnection()
+const std::unique_ptr<Block>& PLC::getOneDeviceBlock(const std::string& blockName) const
 {
-    if (plcConn_ == NULL)
+    for (auto& device : devices_)
     {
-        LOG((COMM|DIAG)) << "No connection found. Attempt to establish connection ... ";
-        plcConn_ = createConnection();
-    }
-    return plcConn_;
-}
-
-Block* PLC::getBlock(const std::string& blockName) const
-{
-    for (auto block = blockCol_.begin(); block != blockCol_.end(); block++)
-    {
-        if ( (*block)->getName() == blockName)
-            return *block;
+        for (auto& block : device.getBlocks())
+        {
+            if (block->getName() == blockName)
+            {
+                return block;
+            }
+        }
     }
     std::ostringstream error;
     error << "The block '" << blockName << "' was not found.";
     throw SilecsException(__FILE__, __LINE__, error.str());
 }
 
-blockVectorType& PLC::getBlockCol()
+const std::vector<Device>& PLC::getDevices() const
 {
-    return blockCol_;
+    return devices_;
 }
 
 PLCBrand PLC::whichPLCBrand(std::string brand)
@@ -694,33 +722,47 @@ ProtocolMode PLC::whichProtocolMode(std::string mode)
 
 void PLC::copyInToOut(const std::string& blockName)
 {
-    deviceVectorType::iterator pDeviceIter;
-    for (pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter)
-        pDeviceIter->second->copyInToOut(blockName);
+    for (auto& device : devices_)
+    {
+        device.getBlock(blockName)->copyInToOut();
+    }
 }
 
-void PLC::setReadBlockAttributes(const std::string& blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize)
+void PLC::setBlockAttributes(const std::string& blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize)
 {
     //Set the custom offset/size of the referred Input block if any.
     //Will throw an exception if that block-name does not exist.
-    getBlock(blockName)->setCustomAttributes(customAddress, customOffset, customSize);
-}
-
-void PLC::resetReadBlockAttributes(const std::string& blockName)
-{
-    getBlock(blockName)->resetCustomAttributes();
-}
-
-void PLC::setWriteBlockAttributes(const std::string& blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize)
-{
-    //Set the custom address/offset/size of the referred Output block if any.
-    //Will throw an exception if that block-name does not exist.
-    getBlock(blockName)->setCustomAttributes(customAddress, customOffset, customSize);
+    for (auto& device : devices_)
+    {
+        for (auto& block : device.getBlocks())
+        {
+            if (block->getName() == blockName)
+            {
+                return block->setCustomAttributes(customAddress, customOffset, customSize);
+            }
+        }
+    }
+    
+    std::ostringstream error;
+    error << "The block '" << blockName << "' was not found.";
+    throw SilecsException(__FILE__, __LINE__, error.str());
 }
 
-void PLC::resetWriteBlockAttributes(const std::string& blockName)
+void PLC::resetBlockAttributes(const std::string& blockName)
 {
-    getBlock(blockName)->resetCustomAttributes();
+    for (auto& device : devices_)
+    {
+        for (auto& block : device.getBlocks())
+        {
+            if (block->getName() == blockName)
+            {
+                return block->resetCustomAttributes();
+            }
+        }
+    }
+    std::ostringstream error;
+    error << "The block '" << blockName << "' was not found.";
+    throw SilecsException(__FILE__, __LINE__, error.str());
 }
 
 } // namespace
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h
index 062606c..464bce4 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h
@@ -15,7 +15,9 @@ Contributors:
 #define _SILECS_PLC_H_
 
 #include <silecs-communication/interface/core/SilecsService.h>
-#include <silecs-communication/interface/core/Context.h>
+#include <silecs-communication/interface/utility/Definitions.h>
+#include <silecs-communication/interface/equipment/SilecsParamConfig.h>
+#include <silecs-communication/interface/equipment/SilecsDevice.h>
 
 #include <future>
 #include <string>
@@ -34,103 +36,6 @@ typedef std::vector<std::pair<std::string, Device*> > deviceVectorType;
 typedef std::vector<Block*> blockVectorType;
 typedef std::map<std::string, Connection*> connMapType;
 
-// PLC type, brand, system, protocol type and mode
-typedef enum
-{
-    BusController,
-    BusCoupler
-} PLCType;
-
-// PLC brand, system, protocol type and mode
-typedef enum
-{
-    Siemens,
-    Schneider,
-    Ni,
-    Digi,
-    Beckhoff
-} PLCBrand;
-
-typedef enum
-{
-    ET200S,
-    S7300,
-    S7400,
-    S71200,
-    S71500,
-    S7VIRTUAL,
-    Premium,
-    Quantum,
-    M340,
-    BC9xxx,
-    CX9xxx,
-    BK9xxx,
-    RCM4010,
-    RCM2000,
-    CompactRIO,
-    PXIRT,
-    PXIWindows,
-    PCWindows,
-    OtherSupportCNV
-} PLCModel;
-
-typedef enum
-{
-    Step7,
-    TiaPortal,
-    Unity,
-    TwinCat,
-    StdC,
-    ServerS7,
-    Labview
-} PLCSystem;
-
-typedef enum
-{
-    MBProtocol,
-    S7Protocol,
-    CNVProtocol
-} ProtocolType;
-
-typedef enum
-{
-    BlockMode,
-    DeviceMode
-} ProtocolMode;
-/// @endcond
-
-// PLC unit status
-typedef struct
-{
-    int status; //bit-pattern hardware specific (look at the related documentation)
-} UnitStatusType;
-
-// Order code
-typedef struct
-{
-    std::string code;
-    std::string version;
-} UnitCodeType;
-
-// CPU Info
-typedef struct
-{
-    std::string moduleName;
-    std::string moduleTypeName;
-    std::string serialNumber;
-    std::string asName;
-    std::string copyright;
-} CPUInfoType;
-
-// CP Info
-typedef struct
-{
-    int maxPduLength;
-    int maxConnections;
-    int maxMPIRate;
-    int maxBusRate;
-} CPInfoType;
-
 /*!
  * \class PLC
  * \brief This object provides all services related to a PLC. It provides the information
@@ -147,8 +52,6 @@ public:
      * \return List of the related Cluster instances (Class/Version) for the PLC.
      */
     std::vector<std::string> getDeviceList() const;
-
-    deviceVectorType& getDeviceMap();
     /// @endcond
 
     // Diagnostic features ----------------------------------------
@@ -165,127 +68,6 @@ public:
      */
     std::string getIPAddress() const;
 
-    /*!
-     * \brief Returns the PLC configuration domain: CPS, PSB, ADE, .., TST
-     * \return Accelerator domain
-     */
-    std::string getDomain() const;
-
-    /*!
-     * \brief Returns the PLC manufacturer: SIEMENS, SCHNEIDER, BECKHOFF, RABBIT, NI
-     * \return PLC brand
-     */
-    std::string getBrand() const;
-
-    /*!
-     * \brief Returns the PLC development system: STEP-7, TIA-PORTAL, UNITY Pro, TWINCat, Standard-C, Standard-Cpp, Labview
-     * \return PLC development system
-     */
-    std::string getSystem() const;
-
-    /*!
-     * \brief Returns PLC hardware model: UNITY_Premium, SIMATIC_S7-300, ..
-     * \return PLC hardware model
-     */
-    std::string getModel() const;
-
-    /*!
-     * \brief Returns PLC type: bus coupler or bus controller
-     * \return PLC type
-     */
-    PLCType getPLCType() const;
-
-    /*!
-     * \brief Returns the protocol type used for the PLC communication: MODBUS-TCP, S7-TCP, CNV-TCP
-     * \return PLC protocol type
-     */
-    std::string getProtocolType() const;
-
-    /*!
-     * \brief Returns the SILECS mode used to map the data within the PLC memory: DEVICE_MODE, BLOCK_MODE
-     * \return PLC protocol mode
-     */
-    std::string getProtocolMode() const;
-
-    /*!
-     * \deprecated Use getMemBaseAddress() instead
-     * \brief Returns the memory base address of the SILECS configuration within the PLC
-     * \return DB number for SIMATIC-S7
-     * \return 16bits absolute memory address for UNITY Premium/Quantum
-     * \return 32bits absolute memory address for UNITY M340
-     */
-    unsigned long getBaseAddress() const __attribute__ ((deprecated));
-
-    /*!
-     * \brief Returns the memory base address of the SILECS configuration within the PLC
-     * \return DB number for SIMATIC-S7
-     * \return 16bits absolute memory address for UNITY Premium/Quantum
-     * \return 32bits absolute memory address for UNITY M340
-     */
-    long getMemBaseAddress() const;
-
-    /*!
-     * \brief Returns the digital input base address of the SILECS configuration within the PLC
-     * \return byte address for SIMATIC-S7
-     * \return byte address for MODBUS TCP
-     * \return -1 in case of non existent address
-     */
-    long getDIBaseAddress() const;
-
-    /*!
-     * \brief Returns the digital output base address of the SILECS configuration within the PLC
-     * \return byte address for SIMATIC-S7
-     * \return byte address for MODBUS TCP
-     * \return -1 in case of non existent address
-     */
-    long getDOBaseAddress() const;
-
-    /*!
-     * \brief Returns the analog input base address of the SILECS configuration within the PLC
-     * \return byte address for SIMATIC-S7
-     * \return byte address for MODBUS TCP
-     * \return -1 in case of non existent address
-     */
-    long getAIBaseAddress() const;
-
-    /*!
-     * \brief Returns the analog output base address of the SILECS configuration within the PLC
-     * \return byte address for SIMATIC-S7
-     * \return byte address for MODBUS TCP
-     * \return -1 in case of non existent address
-     */
-    long getAOBaseAddress() const;
-
-    /*!
-     * \brief Extracts SILECS release information from the client configuration parameters.
-     * Provides detail about SILECS software used to generate the client documents.
-     * \return SILECS release number
-     */
-    std::string getLocalRelease() const;
-
-    /*!
-     * \brief Extracts Owner information from the client configuration parameters.
-     * Owner of the deployment document is not necessary responsible for the 'Generate' action
-     * who can be done by any Editor of the document.
-     * \return Owner name
-     */
-    std::string getLocalOwner() const;
-
-    /*!
-     * \brief Extracts the Date information from the client configuration parameters.
-     * Date of the client parameters file generation.
-     * \return Coordinate Universal Time (UTC)
-     */
-    std::string getLocalDate() const;
-
-    /*!
-     * \brief Extracts the Checksum information from the client configuration parameters.
-     * CRC-32 Checksum relies on Classes and Deployment documents that have been used to
-     * design the client configuration.
-     * \return CRC32 checksum
-     */
-    unsigned long getLocalChecksum() const;
-
     // Miscellaneous features ----------------------------------------
 
     /*!
@@ -293,13 +75,7 @@ public:
      * \param deviceName label or index of the device
      * \return Reference of the device object
      */
-    Device* getDevice(const std::string& deviceName) const;
-
-    /*!
-     * \fn getBlock
-     * \brief returns instance of the requested block
-     */
-    Block* getBlock(const std::string& blockName) const;
+    Device* getDevice(const std::string& deviceName);
 
     /*!
      * \brief Used to Enable the Client/PLC connection and connect the PLC immediately if needed (connectNow=true).
@@ -377,31 +153,13 @@ public:
      * \param customOffset offset (in byte) of the data block to be received
      * \param customSize real size (in byte) of the data block to be received
      */
-    void setReadBlockAttributes(const std::string& blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize);
+    void setBlockAttributes(const std::string& blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize);
 
     /*!
      * \brief Sets back the default attributes of the data block (the ones defined by the design)
      * \param blockName name of the related block
      */
-    void resetReadBlockAttributes(const std::string& blockName);
-
-    /*!
-     * \brief Used to change designed attributes of a data block.
-     * In that version, can be used to limit dynamically size of data to be sent (send).
-     * Interesting for specific application that uses general purpose data block with maximum size and adjusts the real data size at communication time.
-     * Caution! This option can be used only with single device access (using DEVICE_MODE or send/recv from the Device level).
-     * \param blockName name of the related block
-     * \param customAddress base address (DBn or absolute in byte) of the data block to be sent
-     * \param customOffset offset (in byte) of the data block to be sent
-     * \param customSize real size (in byte) of the data block to be sent
-     */
-    void setWriteBlockAttributes(const std::string& blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize);
-
-    /*!
-     * \brief Sets back the default attributes of the data block (the ones defined by the design)
-     * \param blockName name of the related block
-     */
-    void resetWriteBlockAttributes(const std::string& blockName);
+    void resetBlockAttributes(const std::string& blockName);
 
     /// @cond
     /*!
@@ -411,47 +169,16 @@ public:
      *  Allow sharing connection pipe between different classes if required (from mapping configuration)
      * \return reference to the [shared-]connection instance of this PLC instance
      */
-    Connection* createConnection(); //just to instantiate the object
-    Connection* getConnection();
+    void createConnection(); //just to instantiate the object
     /// @endcond
 
     std::string getParamsFileName() const;
 
-    /*!
-     * \brief Used for detemining the required block buffer size in case of BLOCK_MODE. In BLOCK_MODE a single block contains a specific register for all the devices,
-     * hence when calculating the required buffer size, we need to only reserve the space for the devices which actually contain this block.
-     * \param blockName name of the block which should be used to count the devices
-     */
-    unsigned int getNrDevicesWithBlock(const std::string& blockName);
-
-    PLCType getTypeID() const
-    {
-        return typeID_;
-    }
-    PLCBrand getBrandID() const
-    {
-        return brandID_;
-    }
-    PLCModel getModelID() const
-    {
-        return modelID_;
-    }
-    PLCSystem getSystemID() const
-    {
-        return systemID_;
-    }
-    ProtocolMode getProtocolModeID() const
-    {
-        return protocolModeID_;
-    }
-    ProtocolType getProtocolTypeID() const
-    {
-        return protocolTypeID_;
-    }
+    const SilecsParamConfig& getParamConfig() const;
 
     const Cluster& getCluster() const;
 
-    bool hasHeader() const;
+    const std::vector<Device>& getDevices() const;
 
 private:
     friend class Cluster;
@@ -460,16 +187,20 @@ private:
     PLC(Cluster* theCluster, std::string plcName, std::string plcIPaddr, std::string parameterFile = "");
     virtual ~PLC();
 
-    void updateLocalData();
+    /*!
+     * \brief Used for detemining the required block buffer size in case of BLOCK_MODE. In BLOCK_MODE a single block contains a specific register for all the devices,
+     * hence when calculating the required buffer size, we need to only reserve the space for the devices which actually contain this block.
+     * \param blockName name of the block which should be used to count the devices
+     */
+    unsigned int getNrDevicesWithBlock(const std::string& blockName);
 
     /*!
-     * \fn updateHeader
-     * \brief This method is used to update the unique 'SilecsHeader' Device data of the PLC config.
-     * It consists to create the corresponding Cluster if needed, connect the current PLC,
-     * upload the diagnostic block registers ('hdrBlk') then disconnect the PLC.
-     * \return True if uploading was correctly done.
+     * \fn getBlock
+     * \brief returns instance of the first found block of the first device
      */
-    bool updateHeader();
+    const std::unique_ptr<Block>& getOneDeviceBlock(const std::string& blockName) const;
+
+    void updateLocalData();
 
     /*!
      * \fn recvAsync/ recvWait
@@ -483,6 +214,12 @@ private:
      */
     std::future<int> sendAsync(const std::string& blockName);
 
+    int receiveForAllDevices(const std::string& blockName);
+    int sendForAllDevices(const std::string& blockName);
+
+    int recvAllBlockMode(const std::string& blockName);
+    int sendAllBlockMode(const std::string& blockName);
+
     /*!
      * \fn whichPLC, whichProtocol...
      * \return the enumeration value of the given Protocol type/mode string
@@ -500,11 +237,7 @@ private:
      */
     void extractDatabase();
 
-    /*!
-     * \brief Provides the  map of the Block objects attached to the underlying PLC(s)
-     * \return Block object map
-     */
-    blockVectorType& getBlockCol();
+    void createDevices();
 
     /// Parent cluster reference of that PLC
     Cluster* theCluster_;
@@ -512,62 +245,28 @@ private:
     /// PLC attributes
     std::string name_;
     std::string IPaddr_;
-    std::string domain_; //TST, ADE, PSB, CPS, ..
-    std::string brand_; //SIEMENS, SCHNEIDER, ..
-    std::string system_; //STEP-7, UNITY, TWINCAT, ..
-    std::string model_; //SIMATIC S7-300, Premium, ..
-    std::string protocolMode_; //Device, Block
-    std::string protocolType_; //MODBUS-TCP, S7-TCP, ..
-
-    PLCType typeID_; //BusController (with CPU), BusCoupler (pure IO)
-    PLCBrand brandID_; //Siemens, Schneider, ... enumeration
-    PLCModel modelID_; //S7-400, S7-300, ... enumeration
-    PLCSystem systemID_; //Step7, Unity, TwinCat, ... enumeration
-    ProtocolMode protocolModeID_; //BlockMode, DeviceMode enumeration
-    ProtocolType protocolTypeID_; //Modbus, S7 enumeration
-
-    long baseMemAddr_;
-    long baseDIAddr_;
-    long baseDOAddr_;
-    long baseAIAddr_;
-    long baseAOAddr_;
-    std::string usedMem_;
 
     std::string parameterFile_;
 
-    // Unique instance of the Header Device for diagnostic purpose
-    Device* theHeader_;
-
     /* Diagnostic registers are used to check the consistency between the
      * PLC memory (remote data) and the client parameters (local data).
      */
-    //Local data, extracted from the parameters file
-    std::string localRelease_; //Release number of the SILECS software
-    std::string localOwner_; //Owner of the deployment document
-    std::string localDate_; //Date of the Generation (Client parameters and PLC Sources)
-    uint32_t localChecksum_; //Checksum of the deployed configuration
-
     //Remote data, uploaded from the PLC memory
     std::string remoteVersion_;
     std::string remoteOwner_;
     std::string remoteDate_;
     uint32_t remoteChecksum_;
 
-    Context* allDevicesTransaction_;
-    Context* allDevicesSynchronization_;
-
-    /// Device collection of the PLC
-    deviceVectorType deviceCol_;
+    SilecsParamConfig paramConfig_;
 
-    /// Block collection of the PLC listed by name.
-    blockVectorType blockCol_;
+    std::vector<Device> devices_;
 
     /// Object to manage the plc communication
     /* By default, we instantiate 1 connection (2 channels: r/w) per PLC/Cluster
      * In order to safe PLC resources it's possible to share 1 connection between clusters of the same PLC.
      * A connection ID is used to define if the connection is shared or not.
      */
-    Connection* plcConn_; // the connection object that can be individual per PLC/Cluster or shared
+    std::unique_ptr<Connection> plcConn_; // the connection object that can be individual per PLC/Cluster or shared
 };
 
 } // namespace
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsParamConfig.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsParamConfig.h
new file mode 100644
index 0000000..c7c5071
--- /dev/null
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsParamConfig.h
@@ -0,0 +1,43 @@
+#ifndef _SILECS_PARAM_CONFIG_H_
+#define _SILECS_PARAM_CONFIG_H_
+
+#include <silecs-communication/interface/utility/Definitions.h>
+
+#include <string>
+#include <vector>
+
+namespace Silecs
+{
+
+struct SilecsParamConfig
+{
+    std::string plcName;
+    std::string localRelease; //Release number of the SILECS software
+    std::string localOwner; //Owner of the deployment document
+    std::string localDate; //Date of the Generation (Client parameters and PLC Sources)
+    uint32_t localChecksum; //Checksum of the deployed configuration
+    std::string domain; //TST, ADE, PSB, CPS, ..
+    std::string brand; //SIEMENS, SCHNEIDER, ..
+    std::string system; //STEP-7, UNITY, TWINCAT, ..
+    std::string model; //SIMATIC S7-300, Premium, ..
+    std::string protocolMode; //Device, Block
+    std::string protocolType; //MODBUS-TCP, S7-TCP, ..
+
+    long baseMemAddr;
+    long baseDIAddr;
+    long baseDOAddr;
+    long baseAIAddr;
+    long baseAOAddr;
+    std::string usedMem;
+
+    PLCType typeID; //BusController (with CPU), BusCoupler (pure IO)
+    PLCBrand brandID; //Siemens, Schneider, ... enumeration
+    PLCModel modelID; //S7-400, S7-300, ... enumeration
+    PLCSystem systemID; //Step7, Unity, TwinCat, ... enumeration
+    ProtocolMode protocolModeID; //BlockMode, DeviceMode enumeration
+    ProtocolType protocolTypeID; //Modbus, S7 enumeration
+};
+
+} // namespace Silecs
+
+#endif // _SILECS_PARAM_CONFIG_H_
\ No newline at end of file
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp
index b1bf784..1cb6a07 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp
@@ -26,8 +26,8 @@ Contributors:
 namespace Silecs
 {
 
-Register::Register(Device* theDevice, const ElementXML& registerNode) :
-                theDevice_(theDevice), isConfiguration_(false)
+Register::Register(const ElementXML& registerNode) :
+                isConfiguration_(false)
 {
     name_ = registerNode.getAttribute("name");
     length_ = 1;
@@ -111,17 +111,6 @@ Register::~Register()
     }
 }
 
-PLC* Register::getPLC()
-{
-    return theDevice_->getPLC();
-}
-
-Device* Register::getDevice()
-{
-    return theDevice_;
-}
-
-
 // SET methods =============================================================
 
 void Register::setAccessArea(AccessArea accessArea)
@@ -133,6 +122,7 @@ void Register::setAccessType(AccessType accessType)
 {
     accessType_ = accessType;
 
+    std::lock_guard<std::mutex> lock(mutex_);
     // By knowing the register type we can allocate 1 or 2 buffers for data exchanges.
     pRecvValue_ = pSendValue_ = NULL;
 
@@ -945,6 +935,7 @@ std::string Register::getInputValAsString(unsigned long i)
 ;
 std::string Register::getInputValAsString(unsigned long i, unsigned long j)
 {
+    std::lock_guard<std::mutex> lock(mutex_);
     if (isReadable())
     {
         return getValAsString(pRecvValue_, i, j);
@@ -965,6 +956,7 @@ std::string Register::getOutputValAsString(unsigned long i)
 ;
 std::string Register::getOutputValAsString(unsigned long i, unsigned long j)
 {
+    std::lock_guard<std::mutex> lock(mutex_);
     if (isWritable())
     {
         return getValAsString(pSendValue_, i, j);
@@ -975,6 +967,7 @@ std::string Register::getOutputValAsString(unsigned long i, unsigned long j)
 
 std::string Register::dumpInputVal(bool asAsciiChar)
 {
+    std::lock_guard<std::mutex> lock(mutex_);
     std::ostringstream os;
     unsigned long byteSize = dimension1_ * dimension2_ * size_;
     for (unsigned int i = 0; i < byteSize; i++)
@@ -995,6 +988,7 @@ std::string Register::dumpInputVal(bool asAsciiChar)
 
 std::string Register::dumpOutputVal(bool asAsciiChar)
 {
+    std::lock_guard<std::mutex> lock(mutex_);
     std::ostringstream os;
     unsigned long byteSize = dimension1_ * dimension2_ * size_;
     for (unsigned int i = 0; i < byteSize; i++)
@@ -1043,6 +1037,7 @@ std::string Register::getTimeStampAsString()
 
 void Register::printVal()
 {
+    std::lock_guard<std::mutex> lock(mutex_);
     std::ostringstream os;
     os << getName() << " " << getFormatAsString() << "[" << dimension1_ << "][" << dimension2_ << "] ";
     if (getFormat() == String)
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h
index f7b8fad..25d8eec 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h
@@ -17,6 +17,7 @@ Contributors:
 #include <stdint.h>
 #include <cstring>
 #include <string>
+#include <mutex>
 
 #include <silecs-communication/interface/utility/SilecsException.h>
 
@@ -95,12 +96,6 @@ class Register
 {
 public:
 
-    /*!
-     * \brief Returns reference of the Device where the register is instantiated
-     * \return Reference of the Device object
-     */
-    Device* getDevice();
-
     /*!
      * \brief Returns the register name as defined in the Class design
      * \return Register name
@@ -338,14 +333,17 @@ public:
     template<typename T> void setValArray(const T* pVal, uint32_t dim);
     template<typename T> void setValArray2D(const T* pVal, uint32_t dim1, uint32_t dim2);
 
+    virtual ~Register();
+
     /// @cond
 protected:
-    Register(Device* theDevice, const ElementXML& registerNode);
-    virtual ~Register();
+    Register(const ElementXML& registerNode);
 
     // export register extraction methods
     friend class PLC;
     friend class Device;
+    friend class Block;
+    friend class PLCBlock;
 
     /*!
      * \brief Set access type.
@@ -418,9 +416,6 @@ protected:
     
     void setDoubleArrayFromString(const std::vector<std::string>& data);
 
-    /// Parent reference of that register
-    Device* theDevice_;
-
     /// Register name
     std::string name_;
 
@@ -465,6 +460,9 @@ protected:
     void* pRecvValue_;
     void* pSendValue_;
 
+    /// Mutex for synchronizing access to pRecvValue_ and pSendValue_ from import/export functions and get/set functions.
+    std::mutex mutex_;
+
     /// Name of the "parent" Block name (for general information)
     std::string blockName_;
 
@@ -476,7 +474,6 @@ protected:
     // FEC clock and Timing are synchronized using SNTP (common GPS source)
     timeval tod_;
 
-    PLC* getPLC();
     /// @endcond
 
     //private:
@@ -491,6 +488,7 @@ inline bool Register::getVal<bool>()
     if ( !isValidType<bool>() || !isScalar())
         throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName());
 
+    std::lock_guard<std::mutex> lock(mutex_);
     if (* ((int8_t*)pRecvValue_) == 0)
         return false;
     else
@@ -505,6 +503,7 @@ inline std::string Register::getVal<std::string>()
     if (!isValidType<std::string>() || (dimension1_ != 1) || (dimension2_ != 1))
         throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName());
     // TODO: Fix this string casting.
+    std::lock_guard<std::mutex> lock(mutex_);
     std::string** pRecvStringValue = static_cast<std::string**>(pRecvValue_);
     return * (pRecvStringValue[0]);
 }
@@ -516,6 +515,7 @@ T Register::getVal()
         throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName());
     if (!isValidType<T>() || !isScalar())
         throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName());
+    std::lock_guard<std::mutex> lock(mutex_);
     return * ((T*)pRecvValue_);
 }
 
@@ -529,6 +529,7 @@ inline void Register::getValArray<std::string>(std::string* pVal, uint32_t dim)
     if ( (dimension1_ != dim) || (dimension2_ > 1))
         throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName());
     // TODO: Fix this string casting.
+    std::lock_guard<std::mutex> lock(mutex_);
     std::string** pRecvStringValue = static_cast<std::string**>(pRecvValue_);
     for (unsigned long i = 0; i < dimension1_; i++)
     {
@@ -546,6 +547,7 @@ inline void Register::getValArray2D<std::string>(std::string* pVal, uint32_t dim
     if ( (dimension1_ != dim1) || (dimension2_ != dim2))
         throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName());
     // TODO: Fix this string casting.
+    std::lock_guard<std::mutex> lock(mutex_);
     std::string** pRecvStringValue = static_cast<std::string**>(pRecvValue_);
     for (unsigned long i = 0; i < dimension1_; i++)
     {
@@ -565,6 +567,7 @@ void Register::getValArray(T* pValue, uint32_t dim)
         throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName());
     if (dimension1_ != dim)
         throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName());
+    std::lock_guard<std::mutex> lock(mutex_);
     memcpy((void *)pValue, pRecvValue_, size_ * dimension1_);
 }
 
@@ -577,6 +580,7 @@ void Register::getValArray2D(T* pValue, uint32_t dim1, uint32_t dim2)
         throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName());
     if ( (dimension1_ != dim1) || (dimension2_ != dim2))
         throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName());
+    std::lock_guard<std::mutex> lock(mutex_);
     memcpy((void *)pValue, pRecvValue_, size_ * dimension1_ * dimension2_);
 }
 
@@ -589,6 +593,7 @@ inline const std::string** Register::getRefArray(uint32_t& dim)
         throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName());
     dim = dimension1_;
     // TODO: Fix this string casting.
+    std::lock_guard<std::mutex> lock(mutex_);
     return (const std::string**)pRecvValue_;
 }
 
@@ -602,6 +607,7 @@ inline const std::string** Register::getRefArray2D(uint32_t& dim1, uint32_t& dim
     dim1 = dimension1_;
     dim2 = dimension2_;
     // TODO: Fix this string casting.
+    std::lock_guard<std::mutex> lock(mutex_);
     return (const std::string**)pRecvValue_;
 }
 
@@ -613,6 +619,7 @@ T* Register::getRefArray(uint32_t& dim)
     if (!isValidType<T>() || !isSingleArray())
         throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName());
     dim = dimension1_;
+    std::lock_guard<std::mutex> lock(mutex_);
     return (T*)pRecvValue_;
 }
 
@@ -625,6 +632,7 @@ T* Register::getRefArray2D(uint32_t& dim1, uint32_t& dim2)
         throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName());
     dim1 = dimension1_;
     dim2 = dimension2_;
+    std::lock_guard<std::mutex> lock(mutex_);
     return (T*)pRecvValue_;
 }
 
@@ -637,6 +645,7 @@ inline void Register::setVal<std::string>(std::string val)
         throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName());
 
     // TODO: Fix this string casting.
+    std::lock_guard<std::mutex> lock(mutex_);
     std::string** pSendStringValue = static_cast<std::string**>(pSendValue_);
     * (pSendStringValue[0]) = val;
     isInitialized_ = true; //the register value has been set once at least
@@ -649,6 +658,7 @@ void Register::setVal(T val)
         throw SilecsException(__FILE__, __LINE__, DATA_WRITE_ACCESS_TYPE_MISMATCH, getName());
     if (!isValidType<T>() || (dimension1_ != 1))
         throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName());
+    std::lock_guard<std::mutex> lock(mutex_);
     * ((T*)pSendValue_) = val;
     isInitialized_ = true; //the register value has been set once at least
 }
@@ -664,6 +674,7 @@ inline void Register::setValArray<std::string>(const std::string* pVal, uint32_t
         throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName());
 
     // TODO: Fix this string casting.
+    std::lock_guard<std::mutex> lock(mutex_);
     std::string** pSendStringValue = static_cast<std::string**>(pSendValue_);
     for (unsigned long i = 0; i < dimension1_; i++)
     {
@@ -681,6 +692,7 @@ void Register::setValArray(const T* pVal, uint32_t dim)
         throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName());
     if (dimension1_ != dim)
         throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName());
+    std::lock_guard<std::mutex> lock(mutex_);
     memcpy(pSendValue_, (void *)pVal, size_ * dimension1_);
     isInitialized_ = true; //the register value has been set once at least
 }
@@ -696,6 +708,7 @@ inline void Register::setValArray2D<std::string>(const std::string* pVal, uint32
         throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName());
 
     // TODO: Fix this string casting.
+    std::lock_guard<std::mutex> lock(mutex_);
     std::string** pSendStringValue = static_cast<std::string**>(pSendValue_);
     for (unsigned long i = 0; i < dimension1_; i++)
     {
@@ -716,6 +729,7 @@ void Register::setValArray2D(const T* pVal, uint32_t dim1, uint32_t dim2)
         throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName());
     if ( (dimension1_ != dim1) || (dimension2_ != dim2))
         throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName());
+    std::lock_guard<std::mutex> lock(mutex_);
     memcpy(pSendValue_, (void *)pVal, size_ * dimension1_ * dimension2_);
     isInitialized_ = true; //the register value has been set once at least
 }
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/Definitions.h b/silecs-communication-cpp/src/silecs-communication/interface/utility/Definitions.h
new file mode 100644
index 0000000..eba119c
--- /dev/null
+++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/Definitions.h
@@ -0,0 +1,106 @@
+#ifndef _SILECS_UTILITY_DEFINITIONS_H_
+#define _SILECS_UTILITY_DEFINITIONS_H_
+
+namespace Silecs
+{
+
+// PLC type, brand, system, protocol type and mode
+typedef enum
+{
+    BusController,
+    BusCoupler
+} PLCType;
+
+// PLC brand, system, protocol type and mode
+typedef enum
+{
+    Siemens,
+    Schneider,
+    Ni,
+    Digi,
+    Beckhoff
+} PLCBrand;
+
+typedef enum
+{
+    ET200S,
+    S7300,
+    S7400,
+    S71200,
+    S71500,
+    S7VIRTUAL,
+    Premium,
+    Quantum,
+    M340,
+    BC9xxx,
+    CX9xxx,
+    BK9xxx,
+    RCM4010,
+    RCM2000,
+    CompactRIO,
+    PXIRT,
+    PXIWindows,
+    PCWindows,
+    OtherSupportCNV
+} PLCModel;
+
+typedef enum
+{
+    Step7,
+    TiaPortal,
+    Unity,
+    TwinCat,
+    StdC,
+    ServerS7,
+    Labview
+} PLCSystem;
+
+typedef enum
+{
+    MBProtocol,
+    S7Protocol,
+    CNVProtocol
+} ProtocolType;
+
+typedef enum
+{
+    BlockMode,
+    DeviceMode
+} ProtocolMode;
+/// @endcond
+
+// PLC unit status
+typedef struct
+{
+    int status; //bit-pattern hardware specific (look at the related documentation)
+} UnitStatusType;
+
+// Order code
+typedef struct
+{
+    std::string code;
+    std::string version;
+} UnitCodeType;
+
+// CPU Info
+typedef struct
+{
+    std::string moduleName;
+    std::string moduleTypeName;
+    std::string serialNumber;
+    std::string asName;
+    std::string copyright;
+} CPUInfoType;
+
+// CP Info
+typedef struct
+{
+    int maxPduLength;
+    int maxConnections;
+    int maxMPIRate;
+    int maxBusRate;
+} CPInfoType;
+
+} // namespace Silecs
+
+#endif // _SILECS_UTILITY_DEFINITIONS_H_
\ No newline at end of file
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.h b/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.h
index e5079cc..cba3307 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.h
@@ -48,7 +48,6 @@ public:
     static std::string toString(const void * ptr);
     static void toLower(std::string& str);
     static bool evalStringToBool(std::string stringVal);
-    // TODO: Merge both fromString methods ( std::ios_base argument is anyhwo always the same )
     /*!
      * \brief transform a string into any integer-type
      * \param str the string to transform
diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.cpp
index 7d40311..89ea6ed 100755
--- a/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.cpp
+++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.cpp
@@ -24,6 +24,8 @@ Contributors:
 
 #include <silecs-communication/interface/utility/XMLParser.h>
 #include <silecs-communication/interface/utility/SilecsException.h>
+#include <silecs-communication/interface/equipment/SilecsDevice.h>
+#include <silecs-communication/interface/equipment/SilecsPLC.h>
 
 #include <exception>
 extern silecsModule *mysilecs;
@@ -996,7 +998,7 @@ void diagnosticToolMainView::on_copyButton_clicked()
                                      "You are trying to copy all the input value to the output values.\nThe copy will effect all the register of the block "+ui->copyComboBox->currentText()+" in the device "+QString::fromStdString(device->getLabel())+".\nDo you confirm this operation?",
                                      QMessageBox::Yes,QMessageBox::No)==QMessageBox::Yes)
             {
-                device->copyInToOut(blockName);
+                device->getBlock(blockName)->copyInToOut();
                 mysilecs->updateDeviceItem(currentItem,false);
             }
         }
diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.h b/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.h
index dbc00fe..f4e64ed 100755
--- a/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.h
+++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.h
@@ -21,6 +21,8 @@ Contributors:
 #include <silecs-diagnostic/silecsmodule.h>
 #include <silecs-diagnostic/stderrredirect.h>
 
+#include <silecs-communication/interface/equipment/SilecsRegister.h>
+
 #include <iostream>
 #include <typeinfo>
 #include <map>
diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.cpp
index 691a886..84b887d 100755
--- a/silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.cpp
+++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.cpp
@@ -15,6 +15,8 @@ Contributors:
 #include <silecs-diagnostic/silecsmodule.h>
 #include <silecs-communication/interface/utility/XMLParser.h>
 #include <silecs-communication/interface/utility/StringUtilities.h>
+#include <silecs-communication/interface/equipment/SilecsDevice.h>
+#include <silecs-communication/interface/equipment/SilecsPLC.h>
 
 extern std::string UserName;
 
@@ -182,9 +184,9 @@ Item *silecsModule::generateTree(const std::string& className, const std::string
                 if(registerName.compare("")==0) break;
 
                 Utils::logInfo(messageConsole_,"found Register: '" + registerName + "' in parameter file");
-                Silecs::Register *reg = device->getRegister(registerName);
+                auto& reg = device->getRegister(registerName);
 
-                Item *registerItem = Utils::addTreeItem(deviceItem,QString::fromStdString(registerName),"",QString::fromStdString(REGISTER_TYPE),reg,":/Images/REG.png" );
+                Item *registerItem = Utils::addTreeItem(deviceItem,QString::fromStdString(registerName),"",QString::fromStdString(REGISTER_TYPE),reg.get(),":/Images/REG.png" );
 
                 // Set the block name
                 registerItem->setText(1 , QString::fromStdString(reg->getBlockName()));
@@ -226,7 +228,7 @@ void silecsModule::setScalarDataInDeviceFromItem(Item *currentItem, const std::s
 
         if(registerName.compare("")==0) break;
 
-        Silecs::Register *reg = device->getRegister(registerName);
+        auto& reg = device->getRegister(registerName);
 
         // analyse just the register within the selected block
         if(reg->getBlockName().compare(blockName)!=0)
@@ -288,7 +290,7 @@ void silecsModule::updateDeviceItem(Item *deviceItem,bool updateInputBufferOnly)
     {
         // Get the register Item in the tree view
         Item *regItem = dynamic_cast<Item*>(deviceItem->child(regIndex));
-        Silecs::Register *reg = device->getRegister(regItem->text(0).toStdString());
+        auto& reg = device->getRegister(regItem->text(0).toStdString());
         Utils::logInfo(messageConsole_,"updating register: '" + reg->getName() + "'of device: '" + device-> getLabel() + "'" );
 
         // PLC values
diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp
index 8da767a..a5e66ab 100755
--- a/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp
+++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp
@@ -17,6 +17,9 @@ Contributors:
 #include <silecs-diagnostic/silecsmodule.h>
 #include <iomanip>
 
+#include <silecs-communication/interface/equipment/SilecsDevice.h>
+#include <silecs-communication/interface/equipment/SilecsPLC.h>
+
 
 extern silecsModule *mysilecs;
 
@@ -130,11 +133,13 @@ void Utils::displayPLCInformation(Silecs::PLC *plc, QTextEdit *console)
 {
     std::string text = "";
 
+    auto& paramConfig = plc->getParamConfig();
+
     if (plc->isConnected(false))
     {
         text.append("<h3><font color ='green'>This PLC is currently connected</font></h3><hr/>");
 
-        if (plc->getPLCType() == BusCoupler)
+        if (paramConfig.typeID == BusCoupler)
         {
             text.append("<h3><font color ='green'>PLC Runtime information</font></h3>");
             text.append("<ul>");
@@ -162,38 +167,38 @@ void Utils::displayPLCInformation(Silecs::PLC *plc, QTextEdit *console)
     text.append("<ul>");
     text.append("<li>Name:    " + plc->getName() + "</li>");
     text.append("<li>Address: " + plc->getIPAddress() + "</li>");
-    text.append("<li>Brand:   " + plc->getBrand() + "</li>");
-    text.append("<li>Model:   " + plc->getModel() + "</li>");
-    text.append("<li>Owner:   " + plc->getLocalOwner() + "</li>");
+    text.append("<li>Brand:   " + paramConfig.brand + "</li>");
+    text.append("<li>Model:   " + paramConfig.model + "</li>");
+    text.append("<li>Owner:   " + paramConfig.localOwner + "</li>");
     text.append("</ul><hr/>");
 
     text.append("<h3>PLC configuration information</h3>");
     text.append("<ul>");
-    text.append("<li>Protocol type: " + plc->getProtocolType() + "</li>");
-    text.append("<li>Protocol mode: " + plc->getProtocolMode() + "</li>");
+    text.append("<li>Protocol type: " + paramConfig.protocolType + "</li>");
+    text.append("<li>Protocol mode: " + paramConfig.protocolMode + "</li>");
 
-    if (plc->getMemBaseAddress() > -1)
-        text.append("<li>Memory Base address:  " + toString(plc->getMemBaseAddress()) + " (0x" + toString(plc->getMemBaseAddress(), 16) + ")" + "</li>");
+    if (paramConfig.baseMemAddr > -1)
+        text.append("<li>Memory Base address:  " + toString(paramConfig.baseMemAddr) + " (0x" + toString(paramConfig.baseMemAddr, 16) + ")" + "</li>");
     else
         text.append("<li>Memory Base address:  Not applicable</li>");
 
-    if (plc->getDIBaseAddress() > -1)
-        text.append("<li>DI Base address:  " + toString(plc->getDIBaseAddress()) + " (0x" + toString(plc->getDIBaseAddress(), 16) + ")" + "</li>");
+    if (paramConfig.baseDIAddr > -1)
+        text.append("<li>DI Base address:  " + toString(paramConfig.baseDIAddr) + " (0x" + toString(paramConfig.baseDIAddr, 16) + ")" + "</li>");
     else
         text.append("<li>DI Base address:  Not applicable</li>");
 
-    if (plc->getDOBaseAddress() > -1)
-        text.append("<li>DO Base address:  " + toString(plc->getDOBaseAddress()) + " (0x" + toString(plc->getDOBaseAddress(), 16) + ")" + "</li>");
+    if (paramConfig.baseDOAddr > -1)
+        text.append("<li>DO Base address:  " + toString(paramConfig.baseDOAddr) + " (0x" + toString(paramConfig.baseDOAddr, 16) + ")" + "</li>");
     else
         text.append("<li>DO Base address:  Not applicable</li>");
 
-    if (plc->getAIBaseAddress() > -1)
-        text.append("<li>AI Base address:  " + toString(plc->getAIBaseAddress()) + " (0x" + toString(plc->getAIBaseAddress(), 16) + ")" + "</li>");
+    if (paramConfig.baseAIAddr > -1)
+        text.append("<li>AI Base address:  " + toString(paramConfig.baseAIAddr) + " (0x" + toString(paramConfig.baseAIAddr, 16) + ")" + "</li>");
     else
         text.append("<li>AI Base address:  Not applicable</li>");
 
-    if (plc->getAOBaseAddress() > -1)
-        text.append("<li>AO Base address:  " + toString(plc->getAOBaseAddress()) + " (0x" + toString(plc->getAOBaseAddress(), 16) + ")" + "</li>");
+    if (paramConfig.baseAOAddr > -1)
+        text.append("<li>AO Base address:  " + toString(paramConfig.baseAOAddr) + " (0x" + toString(paramConfig.baseAOAddr, 16) + ")" + "</li>");
     else
         text.append("<li>AO Base address:  Not applicable</li>");
 
@@ -201,9 +206,9 @@ void Utils::displayPLCInformation(Silecs::PLC *plc, QTextEdit *console)
 
     text.append("<h3>PLC generation information</h3>");
     text.append("<ul>");
-    text.append("<li>Release:  " + plc->getLocalRelease() + "</li>");
-    text.append("<li>Date:     " + plc->getLocalDate() + "</li>");
-    text.append("<li>Checksum: " + toString(plc->getLocalChecksum()) + "</li>");
+    text.append("<li>Release:  " + paramConfig.localRelease + "</li>");
+    text.append("<li>Date:     " + paramConfig.localDate + "</li>");
+    text.append("<li>Checksum: " + toString(paramConfig.localChecksum) + "</li>");
     text.append("</ul><hr/>");
 
     console->setText(QString::fromStdString(text));
-- 
GitLab