From 1b85212093162435ce190702729706323b0fede8 Mon Sep 17 00:00:00 2001
From: aschwinn <al.schwinn@gsi.de>
Date: Tue, 30 Jan 2018 12:05:44 +0100
Subject: [PATCH] - #2 Dont overwrite all PLC Registers of a Block if only one
 Register is set

---
 .../src/xml/fesa/fesa_3_0_0/fesaTemplates.py  | 150 ++++++++----------
 .../xml/fesa/fesa_3_0_0/generateFesaDesign.py |  24 ++-
 .../xml/fesa/fesa_3_0_0/generateSourceCode.py |  19 +--
 silecs-codegen/src/xml/model/Class/Block.py   |  15 +-
 silecs-codegen/src/xml/model/Class/Class.py   |   2 +-
 .../src/xml/model/Class/Register.py           |  13 +-
 .../interface/equipment/SilecsBlock.cpp       |   8 +-
 .../interface/equipment/SilecsBlock.h         |   8 +-
 .../interface/equipment/SilecsDevice.cpp      |   7 +-
 .../interface/equipment/SilecsPLC.cpp         |  10 +-
 .../interface/equipment/SilecsRegister.cpp    |  14 +-
 .../interface/equipment/SilecsRegister.h      |  20 +--
 .../interface/utility/StringUtilities.h       |   4 +-
 .../src/silecs-diagnostic/utils.cpp           |   7 -
 silecs-model/src/xml/DesignSchema.xsd         |  26 ++-
 15 files changed, 164 insertions(+), 163 deletions(-)

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 ef0b4b6..413183c 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
@@ -158,8 +158,9 @@ namespace ${className}
             static void setup(const ServiceLocator* serviceLocator);
             static void cleanup();
             static bool isInitialized(){ return Abstract${className}::isInitialized_; }
-            static void setPLCSlaveRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator);
-            static void getPLCMasterRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator);
+            static void updatePLCRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator);
+            static void updateFesaFields(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator);
+
 
             Abstract${className}(std::string blockName);
             virtual ~Abstract${className}();
@@ -274,7 +275,6 @@ namespace ${className}
     Silecs::Service* Abstract${className}::pService_ = NULL;
     Silecs::Cluster* Abstract${className}::pCluster_ = NULL;
     bool Abstract${className}::isInitialized_ = false;
-
     """
 
 cGlobal = """${blockName}_Type\t${className}::${blockName}("${blockName}");
@@ -321,16 +321,14 @@ cPart2 = """
                 // (from 'plcHostName' FESA field defined on that purpose).
                 Silecs::PLC* pPLC = pCluster_->getPLC(pDevice->plcHostName.get());
 
-                // Update the PLC Slave registers from related FESA fields just before synchronising done at connection time
-                setPLCSlaveRegisters(pPLC, serviceLocator);
+                // Update PLC registers from related FESA fields just before synchronising done at connection time
+                updatePLCRegisters(pPLC, serviceLocator);
 
                 // Connect the PLC if not already connected
                 if (!pPLC->isEnabled())
                 {   pPLC->connect(/*synchroMode=*/Silecs::FULL_SYNCHRO, /*connectNow=*/true);
                     if (pPLC->isConnected())
-                    {   // Update FESA fields from related PLC Master registers just after synchronising done at connection time
-                        getPLCMasterRegisters(pPLC, serviceLocator);
-                    }
+                        updateFesaFields(pPLC, serviceLocator);
                 }
             }
         }
@@ -350,30 +348,35 @@ cPart2 = """
         //
         Silecs::Service::deleteInstance();
     }
+"""
 
+updatePLCRegisters_start = """
     //---------------------------------------------------------------------------------------------------------
-    // Synchronise PLC SLAVE/MASTER registers and related FESA fields (automatically called by the setup method @connection time)
-    void Abstract${className}::setPLCSlaveRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator)
+    //automatically called by the setup method at connection time)
+    void Abstract${className}::updatePLCRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator)
     {
         fesa::NoneContext noneContext;
     """
-
-cSetPLC = """
+updatePLCRegisters_body = """
         ${className}::${blockName}.setPLCDevices(pPLC, serviceLocator, false, &noneContext);"""
-
-cPart3 = """
+updatePLCRegisters_end = """
     }
+"""
 
-    void Abstract${className}::getPLCMasterRegisters(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator)
+updateFesaFields_start = """
+    //---------------------------------------------------------------------------------------------------------
+    //automatically called by the setup method at connection time)
+    void Abstract${className}::updateFesaFields(Silecs::PLC* pPLC, const ServiceLocator* serviceLocator)
     {
-        fesa::NoneContext noneContext;    //MASTER acquisition fields are not consistent, can be set with none-context
+        fesa::NoneContext noneContext;
     """
-
-cGetPLC = """
+updateFesaFields_body = """
         ${className}::${blockName}.getPLCDevices(pPLC, serviceLocator, false, &noneContext);"""
+updateFesaFields_end = """
+    }
+"""
 
 cPart4 = """
-    }
     
     //---------------------------------------------------------------------------------------------------------
     // General methods to synchronize the FESA fields and related PLC registers of the FESA server
@@ -485,7 +488,7 @@ cGetStringArrayReg = """
 
 cGetScalarReg = """
         pDevice->${fesaFieldName}.set( pPLCDevice->getRegister("${regName}")->getVal${regType}(), pContext);"""
-
+        
 cGetArrayReg = """
         {
             Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
@@ -501,6 +504,17 @@ cGetArray2DReg = """
             pDevice->${fesaFieldName}.set(pRegister->getRef${regType}Array2D(dim1, dim2), dim1, dim2, pContext);
         }
 """
+cGetUnsignedArray2DReg = """
+        {
+            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
+            uint32_t dim1 = pRegister->getDimension1();
+            uint32_t dim2 = pRegister->getDimension2();
+            ${fesaType}* ${regName} = (${fesaType}*)calloc(dim1*dim2, sizeof(${fesaType}));
+            pRegister->getVal${regType}Array2D(${regName}, dim1, dim2);\t//use automatic conversion for JAVA non-supported type
+            pDevice->${fesaFieldName}.set(${regName}, dim1, dim2, pContext);
+            free(${regName});
+        }
+"""
 
 cGetUnsignedArrayReg = """
         {
@@ -513,17 +527,7 @@ cGetUnsignedArrayReg = """
         }
     """
 
-cGetUnsignedArray2DReg = """
-        {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
-            uint32_t dim1 = pRegister->getDimension1();
-            uint32_t dim2 = pRegister->getDimension2();
-            ${fesaType}* ${regName} = (${fesaType}*)calloc(dim1*dim2, sizeof(${fesaType}));
-            pRegister->getVal${regType}Array2D(${regName}, dim1, dim2);\t//use automatic conversion for JAVA non-supported type
-            pDevice->${fesaFieldName}.set(${regName}, dim1, dim2, pContext);
-            free(${regName});
-        }
-"""
+
 
 cCommonSet = """    
     void ${blockName}_Type::setOneDevice(Device* pDevice, const bool sendNow, MultiplexingContext* pContext)
@@ -568,11 +572,8 @@ cSetStringArrayReg = """
 """
 
 cSetScalarReg = """
-        pPLCDevice->getRegister("${regName}")->setVal${regType}( pDevice->${fesaFieldName}.get(pContext));"""
+        pPLCDevice->getRegister("${regName}")->setVal${regType}( ${cCast}pDevice->${fesaFieldName}.get(${context}));"""
             
-cSetScalarUReg = """
-        pPLCDevice->getRegister("${regName}")->setVal${regType}( (${cType})pDevice->${fesaFieldName}.get(pContext));"""
-
 cSetArrayReg = """
         {
             Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
@@ -592,25 +593,6 @@ cSetArray2DReg = """
         }
 """
 
-cSetUnsignedArrayReg = """
-        {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
-            uint32_t dim1 = pRegister->getDimension1();
-            uint32_t fesaDim1;
-            pRegister->setVal${regType}Array(pDevice->${fesaFieldName}.get(fesaDim1, pContext), dim1);\t//use automatic conversion for JAVA non-supported type
-        }
-"""
-
-cSetUnsignedArray2DReg = """
-        {
-            Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
-            uint32_t dim1 = pRegister->getDimension1();
-            dim2 = pRegister->getDimension2();
-            uint32_t fesaDim1,fesaDim2;
-            pRegister->setVal${regType}Array2D( pDevice->${fesaFieldName}.get(fesaDim1, fesaDim2, pContext), dim1, dim2);\t//use automatic conversion for JAVA non-supported type
-        }
-"""
-
 cSetStringRegData = """
         (data.is${fesaFieldName_upper}Available()) ? pPLCDevice->getRegister("${regName}")->setValString(data.${fesaFieldName}.get()) :
                                      pPLCDevice->getRegister("${regName}")->setValString(pDevice->${fesaFieldName}.get(pContext));"""
@@ -628,12 +610,8 @@ cSetStringArrayRegData = """
 """
 
 cSetScalarRegData = """
-        (data.is${fesaFieldName_upper}Available()) ? pPLCDevice->getRegister("${regName}")->setVal${regType}( data.${fesaFieldName}.get()) :
-                                          pPLCDevice->getRegister("${regName}")->setVal${regType}( pDevice->${fesaFieldName}.get(pContext));"""
-
-cSetScalarURegData = """
-        (data.is${fesaFieldName_upper}Available()) ? pPLCDevice->getRegister("${regName}")->setVal${regType}( (${cType})data.${fesaFieldName}.get()) :
-                                          pPLCDevice->getRegister("${regName}")->setVal${regType}( (${cType})pDevice->${fesaFieldName}.get(pContext));"""
+        (data.is${fesaFieldName_upper}Available()) ? pPLCDevice->getRegister("${regName}")->setVal${regType}( ${cCast}data.${fesaFieldName}.get()) :
+                                          pPLCDevice->getRegister("${regName}")->setVal${regType}( ${cCast}pDevice->${fesaFieldName}.get(${context}));"""
 cSetArrayRegData = """
         {
             Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}");
@@ -746,17 +724,24 @@ def genCBlockConstr(blockName, className):
 def genCPart2(className):
     return cPart2.replace('${className}', className)
 
-def genCSetPLC(className, blockName):
-    return cSetPLC.replace('${className}', className).replace('${blockName}', blockName)
-
 def genCCommonGet(blockName,className):
     return cCommonGet.replace('${className}', className).replace('${blockName}', blockName)
 
-def genCPart3(className):
-    return cPart3.replace('${className}', className)
-
-def genCGetPLC(className, blockName):
-    return cGetPLC.replace('${className}', className).replace('${blockName}', blockName)
+def updatePLCRegisters(className, blockList):
+    code = updatePLCRegisters_start.replace('${className}', className)
+    for block in blockList:
+        if block.isConfiguration(): # only config Blocks are updated on PLC during startup !
+            code += updatePLCRegisters_body.replace('${className}', className).replace('${blockName}', block.name)
+    code += updatePLCRegisters_end
+    return code
+
+def updateFesaFields(className, blockList):
+    code = updateFesaFields_start.replace('${className}', className)
+    for block in blockList:
+        if block.isReadable() and not block.isConfiguration():
+            code += updateFesaFields_body.replace('${className}', className).replace('${blockName}', block.name)
+    code += updateFesaFields_end
+    return code
 
 def genCPart4(className):
     return cPart4.replace('${className}', className)
@@ -795,23 +780,19 @@ def genCSetStringArrayReg(register):
     return cSetStringArrayReg.replace('${regName}', register.name).replace('${fesaFieldName}', register.getFesaFieldName())
 
 def genCSetScalarReg(register):
+    cCast = ""
+    context = "pContext"
     if register.isUnsigned():
-        return cSetScalarUReg.replace('${regName}', register.name).replace('${regType}', register.getSilecsTypeCapitalized()).replace('${cType}', register.getCType()).replace('${fesaFieldName}', register.getFesaFieldName())
-    else:
-        return cSetScalarReg.replace('${regName}', register.name).replace('${regType}', register.getSilecsTypeCapitalized()).replace('${fesaFieldName}', register.getFesaFieldName())
-        
+        cCast = "(" + register.getCType() + ")"
+    if register.isConfiguration():
+        context = ""
+    return cSetScalarReg.replace('${regName}', register.name).replace('${regType}', register.getSilecsTypeCapitalized()).replace('${cCast}', cCast ).replace('${fesaFieldName}', register.getFesaFieldName()).replace('${context}', context)
 
 def genCSetArrayReg(register):
-    if register.isUnsigned():
-        return cSetUnsignedArrayReg.replace('${regName}', register.name).replace('${regType}', register.getSilecsTypeCapitalized()).replace('${fesaFieldName}', register.getFesaFieldName())
-    else:
-        return cSetArrayReg.replace('${regName}', register.name).replace('${regType}', register.getSilecsTypeCapitalized()).replace('${fesaFieldName}', register.getFesaFieldName())
+    return cSetArrayReg.replace('${regName}', register.name).replace('${regType}', register.getSilecsTypeCapitalized()).replace('${fesaFieldName}', register.getFesaFieldName())
 
 def genCSetArray2DReg(register):
-    if register.isUnsigned():
-        return cSetUnsignedArray2DReg.replace('${regName}', register.name).replace('${regType}', register.getSilecsTypeCapitalized()).replace('${fesaFieldName}', register.getFesaFieldName())
-    else:
-        return cSetArray2DReg.replace('${regName}', register.name).replace('${regType}', register.getSilecsTypeCapitalized()).replace('${fesaFieldName}', register.getFesaFieldName())
+    return cSetArray2DReg.replace('${regName}', register.name).replace('${regType}', register.getSilecsTypeCapitalized()).replace('${fesaFieldName}', register.getFesaFieldName())
         
 def genCSetStringRegData(register):
     return cSetStringRegData.replace('${regName}', register.name).replace('${fesaFieldName_upper}', register.getFesaFieldNameCapitalized()).replace('${fesaFieldName}', register.getFesaFieldName())
@@ -820,10 +801,13 @@ def genCSetStringArrayRegData(register):
     return cSetStringArrayRegData.replace('${regName}', register.name).replace('${fesaFieldName_upper}', register.getFesaFieldNameCapitalized()).replace('${fesaFieldName}', register.getFesaFieldName())
 
 def genCSetScalarRegData(register):
+    cCast = ""
+    context = "pContext"
     if register.isUnsigned():
-	    return cSetScalarURegData.replace('${regName}', register.name).replace('${fesaFieldName_upper}', register.getFesaFieldNameCapitalized()).replace('${regType}', register.getSilecsTypeCapitalized()).replace('${fesaFieldName}', register.getFesaFieldName()).replace('${cType}', register.getCType())
-    else:
-        return cSetScalarRegData.replace('${regName}', register.name).replace('${fesaFieldName_upper}', register.getFesaFieldNameCapitalized()).replace('${regType}', register.getSilecsTypeCapitalized()).replace('${fesaFieldName}', register.getFesaFieldName())
+        cCast = "(" + register.getCType() + ")"
+    if register.isConfiguration():
+        context = ""
+    return cSetScalarRegData.replace('${regName}', register.name).replace('${fesaFieldName_upper}', register.getFesaFieldNameCapitalized()).replace('${regType}', register.getSilecsTypeCapitalized()).replace('${fesaFieldName}', register.getFesaFieldName()).replace('${cCast}', cCast).replace('${context}', context)
 
 def genCSetArrayRegData(register):
     return cSetArrayRegData.replace('${regName}', register.name).replace('${fesaFieldName_upper}', register.getFesaFieldNameCapitalized()).replace('${regType}', register.getSilecsTypeCapitalized()).replace('${fesaFieldName}', register.getFesaFieldName())
diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign.py b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign.py
index 43b972e..9974923 100644
--- a/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign.py
+++ b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign.py
@@ -197,6 +197,10 @@ class FESADesignGenerator3_0_0(object):
         else:
             return getOrCreateNamedChildElement(parent,'field',register.getFesaFieldName())
 
+    def addDefaultNode(self, fieldNode, defaultValue):
+        defaultNode = getOrCreateChildElement(fieldNode,'default')
+        defaultNode.setContent(defaultValue)
+        
     def getOrCreatePLCHostNameField(self,configurationNode):
         fieldNode = getOrCreateNamedFirstChild(configurationNode,'field','plcHostName')
         descriptionNode = getOrCreateChildElement(fieldNode,'description')
@@ -224,9 +228,8 @@ class FESADesignGenerator3_0_0(object):
         array = getOrCreateChildElement(fieldNode,'array')
         fillAttributes(array, {'type': 'char'})
         dim = getOrCreateChildElement(array,'dim')
-        defaultNode = getOrCreateChildElement(fieldNode,'default')
-        defaultNode.setContent(plcClassVersion)
-        dim.setContent(str(len(defaultNode.getContent())))
+        self.addDefaultNode(fieldNode, plcClassVersion)
+        dim.setContent(str(len(plcClassVersion)))
         return fieldNode
                 
     def getOrCreateRegisterValueItems(self,prop,block,direction):
@@ -331,6 +334,8 @@ class FESADesignGenerator3_0_0(object):
                     raise Exception("Error: Please use '@generateFesaProperty=false' for the GSI-Version-Property and connect silecs-fields manually")
                 else:
                     return self.getOrCreateGSIAcquisitionProperty(parent,actionsNode,block)
+            elif block.isConfiguration():
+                return self.getOrCreateGSIAcquisitionProperty(parent,actionsNode,block);
             else:
                 raise Exception( "Cannot identify FESA GSI Property-type to use for block:" + block.name )
         else:
@@ -340,6 +345,8 @@ class FESADesignGenerator3_0_0(object):
                 return self.getOrCreateCommandProperty(parent,actionsNode,block)
             elif block.isAcquisition():
                 return self.getOrCreateAcquisitionProperty(parent,actionsNode,block)
+            elif block.isConfiguration():
+                return self.getOrCreateAcquisitionProperty(parent,actionsNode,block);
             else:
                 raise Exception( "Cannot identify FESA Property-type to use for block:" + block.name )
 
@@ -381,10 +388,13 @@ class FESADesignGenerator3_0_0(object):
                 elif reg.isAcquisition():
                     fieldNode = self.getOrCreateFieldNode(acquisitionNode,reg)
                     fillAttributes(fieldNode, {'multiplexed': 'false', 'persistent': 'false'})
-                else: #volatile#
-                    fieldNode = self.getOrCreateFieldNode(settingNode,reg)
-                    fillAttributes(fieldNode, {'multiplexed': 'false', 'persistent': 'false'})
+                elif reg.isConfiguration():
+                    fieldNode = self.getOrCreateFieldNode(configurationNode,reg)
+                else:
+                    raise Exception( "Cannot identify register-type to use for register:" + reg.name )
                 self.getOrCreateType(fieldNode,reg)
+                if reg.hasDefaultValue():
+                    self.addDefaultNode(fieldNode, reg.default)
 
         globalDataNode = getOrCreateChildElement(dataNode,'global-data')
         globalConfigurationNode = ""
@@ -412,7 +422,7 @@ class FESADesignGenerator3_0_0(object):
         for block in designClass.getDesignBlocks():
             if not block.generateFesaProperty:
                 continue #skip this block
-            if block.isWritable():
+            if block.isSetting():
                 propertyNode = self.getOrCreateFESAProperty(settingNode, actionsNode, block)
             else:
                 propertyNode = self.getOrCreateFESAProperty(acquisitionNode,actionsNode,block)
diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateSourceCode.py b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateSourceCode.py
index a5af449..a8fc547 100644
--- a/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateSourceCode.py
+++ b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateSourceCode.py
@@ -49,7 +49,7 @@ def genHSource(className, silecsRoot, fesaRoot, sourcePath,logTopics):
     source =  fesaTemplates.genHTop(className)
     
     for block in designClass.getDesignFesaBlocks():
-        if block.isWritable():
+        if block.isSetting():
             serverActionName = findBlockServerSetActionName(fesaRoot,block.getFesaName())
             source += fesaTemplates.genHTopBlock(className, serverActionName)
         
@@ -58,7 +58,7 @@ def genHSource(className, silecsRoot, fesaRoot, sourcePath,logTopics):
     for block in designClass.getDesignFesaBlocks():
         if block.isAcquisition():
             source += fesaTemplates.genHBlock('RO', block.name,block.getFesaName() )
-        elif block.isCommand():
+        elif block.isCommand() or block.isConfiguration():
             source += fesaTemplates.genHBlock('WO', block.name,block.getFesaName())
         else:   # Setting
             source += fesaTemplates.genHBlock('RW', block.name,block.getFesaName())
@@ -104,23 +104,14 @@ def genCppSource(className, silecsRoot, fesaRoot, sourcePath,logTopics):
         finalSource += fesaTemplates.genCBlockConstr(block.name, className)
         
     finalSource += fesaTemplates.genCPart2(className)
-    
-    for block in blockList:
-        if (block.isWritable()):
-            # WARNING: In order to have multiplexed FESA fields, the corresponding SILECS registers' synchro mode must be 'NONE' 
-            finalSource += fesaTemplates.genCSetPLC(className, block.name)
         
-    finalSource += fesaTemplates.genCPart3(className)
-    
-    for block in blockList:
-        if (block.isReadable()):
-            # WARNING: In order to have multiplexed FESA fields, the corresponding SILECS registers' synchro mode must be 'NONE'
-            finalSource += fesaTemplates.genCGetPLC(className, block.name)
+    finalSource += fesaTemplates.updatePLCRegisters(className, blockList)
+    finalSource += fesaTemplates.updateFesaFields(className, blockList)
     
     finalSource += fesaTemplates.genCPart4(className)
     
     for block in blockList:
-        if block.isReadable():
+        if block.isSetting() or block.isAcquisition(): #configuration-fields in fesa are not writable, so no setter to generate for them !
             finalSource += fesaTemplates.genCCommonGet(block.name,className)
             finalSource += '\n'
             finalSource += fesaTemplates.cRecv
diff --git a/silecs-codegen/src/xml/model/Class/Block.py b/silecs-codegen/src/xml/model/Class/Block.py
index 05ed43f..681cc6e 100644
--- a/silecs-codegen/src/xml/model/Class/Block.py
+++ b/silecs-codegen/src/xml/model/Class/Block.py
@@ -30,6 +30,7 @@ class Block(object):
     ___settingBlockName = "Setting-Block"
     ___acquisitionBlockName = "Acquisition-Block"
     ___commandBlockName = "Command-Block"
+    ___configurationBlockName = "Configuration-Block"
     ___settingIOBlockName = "Setting-IO-Block"
     ___acquisitionIOBlockName = "Acquisition-IO-Block"
     ___commandIOBlockName = "Command-IO-Block"
@@ -44,7 +45,7 @@ class Block(object):
             self.ioType = IOType.MEMORY
         self.___name = xmlNode.get_name()
         self.type = None
-        if self.___name == self.___settingBlockName or self.___name == self.___acquisitionBlockName or self.___name == self.___commandBlockName:
+        if self.___name == self.___settingBlockName or self.___name == self.___acquisitionBlockName or self.___name == self.___commandBlockName or self.___name == self.___configurationBlockName:
             self.type = MEM_TYPE
         elif self.___name == self.___acquisitionIOBlockName and self.ioType == IOType.DIGITAL:
             self.type = DI_TYPE
@@ -62,10 +63,11 @@ class Block(object):
         return  iecommon.capitalizeString(self.name)
     
     def isReadable(self):
-        return self.___name == self.___settingBlockName or self.___name == self.___acquisitionBlockName
+        return self.___name == self.___settingBlockName or self.___name == self.___acquisitionBlockName or self.___name == self.___configurationBlockName
     
+    # note that configuration-blocks need to be writable, since they need to be sent to plc at least once, at startup
     def isWritable(self):
-        return self.___name == self.___settingBlockName or self.___name == self.___commandBlockName
+        return self.___name == self.___settingBlockName or self.___name == self.___commandBlockName or self.___name == self.___configurationBlockName
 
     def isIOBlock(self):
         return not self.isMEMBlock()
@@ -73,7 +75,6 @@ class Block(object):
     def isMEMBlock(self):
         return self.type == MEM_TYPE
     
-    
     def isAnanlogIO(self):
         return self.ioType == IOType.ANALOG
     
@@ -89,8 +90,11 @@ class Block(object):
     def isCommand(self):
         return self.___name == self.___commandBlockName or self.___name == self.___commandIOBlockName
     
+    def isConfiguration(self):
+        return self.___name == self.___configurationBlockName
+    
     def getMEMRegisterNodes(self):
-        return self.xmlNode.xpathEval("*[name()='Acquisition-Register' or name()='Setting-Register' or name()='Volatile-Register']")
+        return self.xmlNode.xpathEval("*[name()='Acquisition-Register' or name()='Setting-Register' or name()='Configuration-Register']")
     
     def getIORegisterNodes(self):
         return self.xmlNode.xpathEval("*[name()='Acquisition-IO-Register' or name()='Setting-IO-Register']")
@@ -104,7 +108,6 @@ class ParamBlock(Block):
         self.size = 0
         self.address = 0
         self.memSize = 0
-
             
     def initWithParamBlockNode(self, xmlNode):
         super(ParamBlock, self).__init__(xmlNode)
diff --git a/silecs-codegen/src/xml/model/Class/Class.py b/silecs-codegen/src/xml/model/Class/Class.py
index 20f8e0e..4938887 100644
--- a/silecs-codegen/src/xml/model/Class/Class.py
+++ b/silecs-codegen/src/xml/model/Class/Class.py
@@ -37,7 +37,7 @@ class Class(object):
         return self.xmlNode.xpathEval("*[name()='Acquisition-IO-Block' or name()='Setting-IO-Block' or name()='Command-IO-Block']")
     
     def getMemoryBlockNodes(self):
-        return self.xmlNode.xpathEval("*[name()='Acquisition-Block' or name()='Setting-Block' or name()='Command-Block']")
+        return self.xmlNode.xpathEval("*[name()='Acquisition-Block' or name()='Setting-Block' or name()='Command-Block' or name()='Configuration-Block']")
     
 class ParamClass(Class):
     ___addressAttribute = { MEM_TYPE: "address", DI_TYPE: "DI-address", DO_TYPE: "DO-address", AI_TYPE: "AI-address", AO_TYPE: "AO-address" }
diff --git a/silecs-codegen/src/xml/model/Class/Register.py b/silecs-codegen/src/xml/model/Class/Register.py
index dd1b299..840bf23 100644
--- a/silecs-codegen/src/xml/model/Class/Register.py
+++ b/silecs-codegen/src/xml/model/Class/Register.py
@@ -20,7 +20,7 @@ import libxml2
 class Register(object):
     ___settingRegisterType = "Setting-Register"
     ___acquisitionRegisterType = "Acquisition-Register"
-    ___volatileRegisterType = "Volatile-Register"
+    ___configurationRegisterType = "Configuration-Register"
     ___settingIORegisterType = "Setting-IO-Register"
     ___acquisitionIORegisterType = "Acquisition-IO-Register"
     
@@ -37,7 +37,11 @@ class Register(object):
         self.dim2 = 1
         self.stringLength = 1 # ... currently needs to be default because of some old convention
         self.format = ""
+        self.default= "" # default value, if any
     
+        if self.xmlNode.hasProp("default"):
+            self.default = xmlNode.prop("default")
+
         valueTypes = xmlNode.xpathEval("*[name()='scalar' or name()='array' or name()='array2D' or name()='string' or name()='stringArray' or name()='stringArray2D']")
         if not valueTypes:
             iecommon.logError('ERROR: The register '+ self.name +' has no valueTypes.', True, {'errorlog': True})
@@ -61,6 +65,9 @@ class Register(object):
             
         self.format = self.valueTypeNode.prop("format")
             
+    def hasDefaultValue(self):
+        return self.default != ""
+
     def getNameCapitalized(self):
         return  iecommon.capitalizeString(self.name)
     
@@ -100,8 +107,8 @@ class Register(object):
     def isSetting(self):
         return self.___type == self.___settingRegisterType or self.___type == self.___settingIORegisterType
     
-    def isVolatile(self):
-        return self.___type == self.___volatileRegisterType
+    def isConfiguration(self):
+        return self.___type == self.___configurationRegisterType
     
     def getCType(self):
         return  {
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 0a21be6..d1e901f 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp
@@ -27,10 +27,14 @@ namespace Silecs
 {
 
 Block::Block(PLC* thePLC, ElementXML blockNode, AccessType accessType) :
-                thePLC_(thePLC)
+                thePLC_(thePLC), configuration_(false)
 {
     std::string designName = blockNode.getAttribute("name");
 
+
+    if(blockNode.name_ == "Configuration-Block")
+        configuration_ = true;
+
     name_ = designName;
     StringUtilities::fromString(size_, blockNode.getAttribute("size"));
     StringUtilities::fromString(memSize_, blockNode.getAttribute("mem-size"));
@@ -65,6 +69,8 @@ AccessType Block::whichAccessType(std::string type)
         return Input;
     else if (type == "Command-Block")
         return Output;
+    else if (type == "Configuration-Block")
+        return InOut;
     else if (type == "Setting-Block")
         return InOut;
     else if (type == "Setting-IO-Block")
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 dbca8a5..f392928 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h
@@ -71,7 +71,10 @@ public:
     {
         return (accessType_ != Input);
     }
-
+    inline bool isConfiguration()
+    {
+        return configuration_;
+    }
     inline PLC* getPLC()
     {
         return thePLC_;
@@ -141,6 +144,9 @@ protected:
     /// Block access-type: Memory, Digital or Analog
     AccessArea accessArea_;
 
+    /// Block only consists of configuration registers (write once to controller at startup, afterwards only read from controller)
+    bool configuration_;
+
     /// Block size
     unsigned long size_;
 
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 7a4cbfd..e9e035c 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp
@@ -232,8 +232,7 @@ void Device::importRegisters(Block* pBlock, void* pBuffer, timeval ts, Context*
     std::vector<Register*>::iterator pReg;
     for (pReg = registerCol.begin(); pReg < registerCol.end(); pReg++)
     {
-        // do not update volatile registers for sync (client has to force a transaction himself if required).
-        if (! (*pReg)->isVolatile() || !pContext->isForSynchronization())
+        if (!pContext->isForSynchronization())
         {
             if ( (*pReg)->getFormat() == String)
                 (*pReg)->importString(pBuffer, ts);
@@ -241,7 +240,6 @@ void Device::importRegisters(Block* pBlock, void* pBuffer, timeval ts, Context*
                 (*pReg)->importValue(pBuffer, ts);
         }
     }
-
 }
 
 void Device::exportRegisters(Block* pBlock, void* pBuffer, Context* pContext)
@@ -250,8 +248,7 @@ void Device::exportRegisters(Block* pBlock, void* pBuffer, Context* pContext)
     std::vector<Register*>::iterator pReg;
     for (pReg = registerCol.begin(); pReg < registerCol.end(); pReg++)
     {
-        // do not update volatile registers for sync (client has to force a transaction himself if required).
-        if (! (*pReg)->isVolatile() || !pContext->isForSynchronization())
+        if (!pContext->isForSynchronization())
         {
             if ( (*pReg)->getFormat() == String)
                 (*pReg)->exportString(pBuffer);
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 a023059..f30ecf4 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp
@@ -322,12 +322,12 @@ void PLC::updateLocalData()
     blockVectorType::iterator blockIter;
     for (blockIter = blockCol_.begin(); blockIter != blockCol_.end(); blockIter++)
     {
-        if ( (*blockIter)->isReadable())
+        deviceVectorType::iterator pDeviceIter;
+        for (pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter)
         {
-            deviceVectorType::iterator pDeviceIter;
-            for (pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter)
+            if (pDeviceIter->second->hasBlock( (*blockIter)->getName()))
             {
-                if (pDeviceIter->second->hasBlock( (*blockIter)->getName()))
+                if ( (*blockIter)->isReadable())
                 {
                     LOG(COMM) << "Updating block '" << (*blockIter)->getName() << "' for device '" << pDeviceIter->second->getLabel() << "'";
                     pDeviceIter->second->recv( (*blockIter)->getName());
@@ -489,7 +489,7 @@ void PLC::extractDatabase()
     for (classIter = classNodes.begin(); classIter != classNodes.end(); classIter++)
     {
         std::string className = (*classIter)->getAttribute("name");
-        boost::ptr_vector<ElementXML> blockNodes = xmlParser.getElementsFromXPath_throwIfEmpty("/SILECS-Param/SILECS-Mapping/SILECS-Class[@name='" + className + "']/*[ name()='Acquisition-Block' or name()='Setting-Block' or name()='Command-Block' or name()='Setting-IO-Block' or name()='Acquisition-IO-Block' or name()='Command-IO-Block']");
+        boost::ptr_vector<ElementXML> blockNodes = xmlParser.getElementsFromXPath_throwIfEmpty("/SILECS-Param/SILECS-Mapping/SILECS-Class[@name='" + className + "']/*[ name()='Acquisition-Block' or name()='Setting-Block' or name()='Command-Block' or name()='Configuration-Block' or name()='Setting-IO-Block' or name()='Acquisition-IO-Block' or name()='Command-IO-Block']");
         boost::ptr_vector<ElementXML>::const_iterator blockIter;
 
         boost::ptr_vector<ElementXML> instanceNodes = xmlParser.getElementsFromXPath_throwIfEmpty("/SILECS-Param/SILECS-Mapping/SILECS-Class[@name='" + className + "']/Instance");
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 82c8fd7..321fde7 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp
@@ -28,7 +28,7 @@ namespace Silecs
 {
 
 Register::Register(Device* theDevice, ElementXML* registerNode) :
-                theDevice_(theDevice)
+                theDevice_(theDevice), isConfiguration_(false)
 {
     name_ = registerNode->getAttribute("name");
     length_ = 1;
@@ -52,6 +52,10 @@ Register::Register(Device* theDevice, ElementXML* registerNode) :
     StringUtilities::fromString(size_, registerNode->getAttribute("size"));
     StringUtilities::fromString(memSize_, registerNode->getAttribute("mem-size"));
     StringUtilities::fromString(address_, registerNode->getAttribute("address"));
+
+    if(registerNode->name_ == "Configuration-Register")
+        isConfiguration_ = true;
+
     isInitialized_ = false; //register not initialized yet (used for output registers)
 
     if (length_ > 1)
@@ -1198,13 +1202,9 @@ bool Register::isMemoryRegister()
 {
     return (accessArea_ == Memory);
 }
-bool Register::isRetentive()
-{
-    return !isVolatile_;
-}
-bool Register::isVolatile()
+bool Register::isConfiguration()
 {
-    return isVolatile_;
+    return isConfiguration_;
 }
 bool Register::isScalar()
 {
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 a474991..2b0e2b6 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h
@@ -200,20 +200,11 @@ public:
     bool isMemoryRegister();
 
     /*!
-     * \brief A retentive register can be a persistent or a constant data.
-     * Its value must be initialized at the system start-up.
-     * - From the client side if the synchro register is 'Slave'
-     * - From the PLC side if the synchro register is 'Master'
-     * \return true if the register has Master or Slave synchro as defined in the Class design
+     * \brief A register that has constant value is a configuration.
+     * Its given default-value is set to the controller at start-up.
+     * \return if the register is a configuration register
      */
-    bool isRetentive();
-
-    /*!
-     * \brief A register that has not persistent or constant value is Volatile.
-     * Its value is not initialized at the system start-up.
-     * \return true if the register has 'No' synchro as defined in the Class design
-     */
-    bool isVolatile();
+    bool isConfiguration();
 
     /*!
      * \brief A scalar is a single value register (dimension1_ and dimension2_ attributes == 1)
@@ -1762,7 +1753,8 @@ protected:
     /// Name of the "parent" Block name (for general information)
     std::string blockName_;
 
-    bool isVolatile_;
+    // True if this register is a configuration register ( sent to controller only once suring startup, than only read )
+    bool isConfiguration_;
 
     // Time-of-day: number of seconds and microseconds since the POSIX.1 Epoch (00:00:00 UTC, January 1, 1970)
     // Use to time-stamp the register coming from PLC (no time-stamping on send).
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 b6ad4fb..385600d 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.h
@@ -49,11 +49,11 @@ public:
      * \param str the string to transform
      * \param value that will receive the conversion
      */
-    template<typename T> static void fromString(T& value, const std::string& str);
+    template <typename T> static void fromString(T& value, const std::string& str);
 
 };
 
-template<typename T>
+template <typename T>
 inline void StringUtilities::fromString(T& value, const std::string& str)
 {
     std::istringstream iss(str);
diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp
index 845f5e6..1c52f32 100755
--- a/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp
+++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp
@@ -251,13 +251,6 @@ void Utils::displayRegisterInformation(Silecs::Register *reg, QTextEdit *console
     }
 
     text.append("<li>Access area: " + reg->whichAccessArea(reg->getAccessArea()) + "</li>");
-
-    // Retentive volatile
-    if (reg->isRetentive())
-        text.append("<li>Storage method: Retentive</li>");
-    else
-        text.append("<li>Storage method: Volatile</li>");
-
     text.append("</ul>");
 
     console->setText(QString::fromStdString(text));
diff --git a/silecs-model/src/xml/DesignSchema.xsd b/silecs-model/src/xml/DesignSchema.xsd
index 5c6f329..deda552 100644
--- a/silecs-model/src/xml/DesignSchema.xsd
+++ b/silecs-model/src/xml/DesignSchema.xsd
@@ -82,6 +82,7 @@
                             <xs:choice minOccurs="1" maxOccurs="unbounded">
                                 <xs:element name="Setting-Block" type="Setting-BlockType" />
                                 <xs:element name="Acquisition-Block" type="Acquisition-BlockType" />
+                                <xs:element name="Configuration-Block" type="Configuration-BlockType" />
                                 <xs:element name="Command-Block" type="Command-BlockType" />
                                 <xs:element name="Setting-IO-Block" type="Setting-IO-BlockType" />
                                 <xs:element name="Acquisition-IO-Block" type="Acquisition-IO-BlockType" />
@@ -214,14 +215,25 @@
                         <xs:element name="Setting-Register" type="Memory-RegisterType">
                             <xs:annotation>
                                 <xs:appinfo>
-                                    <doc>PLC Register which can be setted and read back by Silecs. The PLC should not modify it's value.</doc>
+                                    <doc>Controller register which can be setted and read back by Silecs. The controller should not modify it's value.</doc>
                                 </xs:appinfo>
                             </xs:annotation>
                         </xs:element>
-                        <xs:element name="Volatile-Register" type="Memory-RegisterType">
+                    </xs:choice>
+                </xs:sequence>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    
+    <xs:complexType name="Configuration-BlockType">
+        <xs:complexContent>
+            <xs:extension base="BlockType">
+                <xs:sequence>
+                    <xs:choice minOccurs="1" maxOccurs="unbounded">
+                        <xs:element name="Configuration-Register" type="Memory-RegisterType">
                             <xs:annotation>
                                 <xs:appinfo>
-                                    <doc>PLC Register which can be set by both, Silecs and the PLC</doc>
+                                    <doc>Controller register which is set to the controller at Silecs startup. Later only readout is possible.</doc>
                                 </xs:appinfo>
                             </xs:annotation>
                         </xs:element>
@@ -239,7 +251,7 @@
                         <xs:element name="Acquisition-Register" type="Memory-RegisterType">
                             <xs:annotation>
                                 <xs:appinfo>
-                                    <doc>PLC Register which is only read out by Silecs</doc>
+                                    <doc>Controller register which is only read out by Silecs</doc>
                                 </xs:appinfo>
                             </xs:annotation>
                         </xs:element>
@@ -257,7 +269,7 @@
                         <xs:element name="Setting-IO-Register" type="IO-RegisterType">
                             <xs:annotation>
                                 <xs:appinfo>
-                                    <doc>PLC Register which is only read out by Silecs, which connects directly to Hardware</doc>
+                                    <doc>Controller register which is only set by Silecs and cannot be read. It connects directly to Hardware</doc>
                                 </xs:appinfo>
                             </xs:annotation>
                         </xs:element>
@@ -275,7 +287,7 @@
                         <xs:element name="Acquisition-IO-Register" type="IO-RegisterType">
                             <xs:annotation>
                                 <xs:appinfo>
-                                    <doc>PLC Register which is only read out by Silecs, which connects directly to Hardware</doc>
+                                    <doc>Controller register which is only read out by Silecs and cannot be set. It connects directly to Hardware</doc>
                                 </xs:appinfo>
                             </xs:annotation>
                         </xs:element>
@@ -293,7 +305,7 @@
                         <xs:element name="Setting-Register" type="Memory-RegisterType">
                             <xs:annotation>
                                 <xs:appinfo>
-                                    <doc>PLC Register which can be setted by Silecs. The PLC should not modify it's value.</doc>
+                                    <doc>Controller register which can be setted by Silecs. The controller should not modify it's value.</doc>
                                 </xs:appinfo>
                             </xs:annotation>
                         </xs:element>
-- 
GitLab