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 ef0b4b69136f81e82a9ec60a04cf237831883ec3..413183cf2a67ed7d79607fe56f71f6b8bcda5ecf 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 43b972eadb21a9916ade572929cb9ddc88402d80..99749236a53c19b24b64a205232c2a128106bbdf 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 a5af44919bf0ca6ea0d21b98bc546ba525e2a483..a8fc5472a9541b1a9e2870a85bb17adff94b7fa4 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 05ed43f1ffa19d4833c4487b44963816ba24b0c9..681cc6e9cb4c38048fa30f125f68bfe0b50173f0 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 20f8e0e0a13f286a81dbac19d6b938bd4b01cb54..49388876d2f38a942de1907a079976aeadaa828a 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 dd1b2999953ab479de23969e7ed063bccc5e6c72..840bf2371bcf66392aaa1ea8aeb2439ea45237a8 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 0a21be68e0ef12126997f20f2161bfb2042bc04e..d1e901f81d62cd38528067c8dff65a48d497699f 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 dbca8a541a9b21ee14c7f9816ee788369113ce64..f3929281fc56b5d26a60ccf2a00a07e3fec701e4 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 7a4cbfd5836305b378aba2fb675ef1d03d92f225..e9e035c41b77e63aa1eefef0f850d5f6d745832c 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 a0230592e133d16cb8069a1acd9a148ddd992f89..f30ecf43b7b23780f92f7de9da5642b77d66fb79 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 82c8fd75c8c49cb21dc0810e233d410bd52ebc21..321fde765e7bc53ca616eeef35cb8d7b703e965c 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 a47499176ee0da1de2f5b5f0961dd4fc3276fc59..2b0e2b6a8ccee3df97d1d873200bb07688300e23 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 b6ad4fbcc1cc9c97bd8bc9c0aacb99ddf9a666d7..385600d72ad0538c85d5d0e5a3b3242ed5b23981 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 845f5e6d0704087289a7940d0a83b385a5b61fd2..1c52f320f213c12774365d42642622b9b227f818 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 5c6f329d23a8b1a6d30ed7e732772aa235bdc4c1..deda5520152bd172dc367872a6f4db222d82951a 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>