Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • silecs/opensilecs
  • k.fugiel/opensilecs
  • s.kupiecki/opensilecs
3 results
Show changes
Showing
with 1733 additions and 962 deletions
......@@ -14,13 +14,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from test.testBase import *
import unittest
import libxml2
from migration.migration_0_9_0to0_10_0.migrateDeployDomain import *
from migration.migration_0_9_0to0_10_0.migrateDeployDeviceNumber import *
import inspect #get caller name
SilecsDeployOld = '''<?xml version="1.0" encoding="UTF-8"?>
<SILECS-Deploy silecs-version="0.9.0" created="03/04/16" updated="03/04/16"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
......@@ -59,33 +58,32 @@ SilecsDeployOld = '''<?xml version="1.0" encoding="UTF-8"?>
</SILECS-Deploy>
'''
def testMigrateDeployDeviceNumber(deployDoc):
migrator = DeployDeviceNumberMigrator()
migrator.migrate(deployDoc)
deviceNumbers = deployDoc.xpathEval("/SILECS-Deploy/Deploy-Classes/Class/device-number")
assertEqual(len(deviceNumbers),0)
deviceLists = deployDoc.xpathEval("/SILECS-Deploy/Deploy-Classes/Class/device-list")
assertEqual(len(deviceLists),3)
newHeader = deployDoc.xpathEval('/SILECS-Deploy/Deploy-Classes/Class/device-list/Device[@label="SilecsHeader"]')
assertEqual(len(newHeader),1)
test123 = deployDoc.xpathEval('/SILECS-Deploy/Deploy-Classes/Class/name[text()="Test123"]')
assertEqual(len(test123),1)
class TestMigration0_9_0to0_10_0(unittest.TestCase):
deviceListOnFirstPosition = test123[0].xpathEval('../*')[0]
assertTrue(deviceListOnFirstPosition.get_name() == 'device-list')
def setUp(self):
self.deployDoc = libxml2.parseDoc(SilecsDeployOld)
genericDevices = test123[0].xpathEval('../device-list/Device')
assertEqual(len(genericDevices),5)
def test_migrateDeployDeviceNumber(self):
migrator = DeployDeviceNumberMigrator()
migrator.migrate(self.deployDoc)
deviceNumbers = self.deployDoc.xpathEval("/SILECS-Deploy/Deploy-Classes/Class/device-number")
self.assertEqual(len(deviceNumbers),0)
deviceLists = self.deployDoc.xpathEval("/SILECS-Deploy/Deploy-Classes/Class/device-list")
self.assertEqual(len(deviceLists),3)
newHeader = self.deployDoc.xpathEval('/SILECS-Deploy/Deploy-Classes/Class/device-list/Device[@label="SilecsHeader"]')
self.assertEqual(len(newHeader),1)
test123 = self.deployDoc.xpathEval('/SILECS-Deploy/Deploy-Classes/Class/name[text()="Test123"]')
self.assertEqual(len(test123),1)
def testMigrateDeployDomain(deployDoc):
migrator = DeployDomainMigrator()
migrator.migrate(deployDoc)
controllers = deployDoc.xpathEval("/SILECS-Deploy/Deploy-Instances/Controller")
for controller in controllers:
assertFalse(controller.hasProp('domain'))
deviceListOnFirstPosition = test123[0].xpathEval('../*')[0]
self.assertTrue(deviceListOnFirstPosition.get_name() == 'device-list')
def runTests():
deployDoc = libxml2.parseDoc(SilecsDeployOld)
testMigrateDeployDomain(deployDoc)
testMigrateDeployDeviceNumber(deployDoc)
# print deployDoc # for debugging
genericDevices = test123[0].xpathEval('../device-list/Device')
self.assertEqual(len(genericDevices),5)
def test_MigrateDeployDomain(self):
migrator = DeployDomainMigrator()
migrator.migrate(self.deployDoc)
controllers = self.deployDoc.xpathEval("/SILECS-Deploy/Deploy-Instances/Controller")
for controller in controllers:
self.assertFalse(controller.hasProp('domain'))
......@@ -16,41 +16,92 @@
from iecommon import *
from model.Class.Register import *
from Mapping import *
import libxml2
class IOType(object):
ANALOG = "ANALOG-IO"
DIGITAL = "DIGITAL-IO"
MEMORY = "MEMORY"
class Block(object):
___settingBlockType = "Setting-Block"
___acquisitionBlockType = "Acquisition-Block"
___commandBlockType = "Command-Block"
___settingBlockName = "Setting-Block"
___acquisitionBlockName = "Acquisition-Block"
___commandBlockName = "Command-Block"
___configurationBlockName = "Configuration-Block"
___settingIOBlockName = "Setting-IO-Block"
___acquisitionIOBlockName = "Acquisition-IO-Block"
___commandIOBlockName = "Command-IO-Block"
def __init__(self, xmlNode):
def __init__(self, xmlNode, customTypesXmlNode):
self.xmlNode = xmlNode
self.customTypesXmlNode = customTypesXmlNode
self.ioType = ""
self.name = xmlNode.prop("name")
self.___type = xmlNode.get_name()
if xmlNode.hasProp("ioType"):
self.ioType = xmlNode.prop("ioType") #only available on io-blocks
else:
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 or self.___name == self.___configurationBlockName:
self.type = MEM_TYPE
elif self.___name == self.___acquisitionIOBlockName and self.ioType == IOType.DIGITAL:
self.type = DI_TYPE
elif ( self.___name == self.___settingIOBlockName or self.___name == self.___commandIOBlockName) and self.ioType == IOType.DIGITAL:
self.type = DO_TYPE
elif self.___name == self.___acquisitionIOBlockName and self.ioType == IOType.ANALOG:
self.type = AI_TYPE
elif ( self.___name == self.___settingIOBlockName or self.___name == self.___commandIOBlockName ) and self.ioType == IOType.ANALOG:
self.type = AO_TYPE
else:
raise Exception( "Cannot identify block-type of block:" + self.name )
#xmlNode.shellPrintNode()
def getNameCapitalized(self):
return iecommon.capitalizeString(self.name)
def isReadable(self):
return self.___type == self.___settingBlockType or self.___type == self.___acquisitionBlockType
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.___type == self.___settingBlockType or self.___type == self.___commandBlockType
return self.___name == self.___settingBlockName or self.___name == self.___commandBlockName or self.___name == self.___configurationBlockName
def isIOBlock(self):
return not self.isMEMBlock()
def isMEMBlock(self):
return self.type == MEM_TYPE
def isAnanlogIO(self):
return self.ioType == IOType.ANALOG
def isDigitalIO(self):
return self.ioType == IOType.DIGITAL
def isAcquisition(self):
return self.___type == self.___acquisitionBlockType
return self.___name == self.___acquisitionBlockName or self.___name == self.___acquisitionIOBlockName
def isSetting(self):
return self.___type == self.___settingBlockType
return self.___name == self.___settingBlockName or self.___name == self.___settingIOBlockName
def isCommand(self):
return self.___type == self.___commandBlockType
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()='Configuration-Register']")
def getIORegisterNodes(self):
return self.xmlNode.xpathEval("*[name()='Acquisition-IO-Register' or name()='Setting-IO-Register']")
def getRegisterNodes(self):
return self.xmlNode.xpathEval("*[name()='Acquisition-Register' or name()='Setting-Register' or name()='Volatile-Register']")
return self.getMEMRegisterNodes() + self.getIORegisterNodes()
#has some additionalValues
class ParamBlock(Block):
......@@ -58,47 +109,57 @@ class ParamBlock(Block):
self.size = 0
self.address = 0
self.memSize = 0
def initWithParamBlockNode(self, xmlNode):
super(ParamBlock, self).__init__(xmlNode)
self.size = long(self.xmlNode.prop("size"))
self.address = long(self.xmlNode.prop("address"))
self.memSize = long(self.xmlNode.prop("mem-size"))
def initWithParamBlockNode(self, xmlNode, customTypesXmlNode):
super(ParamBlock, self).__init__(xmlNode, customTypesXmlNode)
self.size = int(self.xmlNode.prop("size"))
self.address = int(self.xmlNode.prop("address"))
self.memSize = int(self.xmlNode.prop("mem-size"))
def initWithDesignBlock(self, designBlock):
newNode = libxml2.newNode(designBlock.xmlNode.get_name())
newNode.newProp("name", designBlock.name)
super(ParamBlock, self).__init__(newNode)
if designBlock.xmlNode.hasProp("ioType"):
newNode.newProp("ioType", designBlock.xmlNode.prop("ioType"))
print(newNode.get_name())
super(ParamBlock, self).__init__(newNode, designBlock.customTypesXmlNode)
newNode.newProp("size", str(self.size))
newNode.newProp("address", str(self.address))
newNode.newProp("mem-size", str(self.memSize))
def setSize(self,size):
self.xmlNode.setProp("size", str(size))
self.xmlNode.setProp("size", str(int(size)))
self.size = size
def setAddress(self,address):
self.xmlNode.setProp("address", str(address))
self.xmlNode.setProp("address", str(int(address)))
self.address = address
def setMemSize(self,memSize):
self.xmlNode.setProp("mem-size", str(memSize))
self.xmlNode.setProp("mem-size", str(int(memSize)))
self.memSize = memSize
def getParamRegisters(self):
paramRegisters = []
for registerNode in self.getRegisterNodes():
paramRegister = ParamRegister()
paramRegister.initWithParamRegisterNode(registerNode)
paramRegister.initWithParamRegisterNode(registerNode, self.customTypesXmlNode)
paramRegisters.append(paramRegister)
return paramRegisters
def getParamIORegisters(self):
paramIORegisters = []
for registerNode in self.getIORegisterNodes():
paramRegister = ParamIORegister()
paramRegister.initWithParamIORegisterNode(registerNode)
paramIORegisters.append(paramRegister)
return paramIORegisters
class DesignBlock(Block):
def __init__(self, xmlNode):
super(DesignBlock, self).__init__(xmlNode)
def __init__(self, xmlNode, customTypesXmlNode):
super(DesignBlock, self).__init__(xmlNode, customTypesXmlNode)
self.generateFesaProperty = False
self.fesaPropertyName = ""
self.fesaGetServerActionName = ""
......@@ -125,8 +186,17 @@ class DesignBlock(Block):
def getFesaName(self):
return self.fesaPropertyName
def getDesignRegisters(self):
def getDesignMEMRegisters(self):
designRegisters = []
for registerNode in self.getRegisterNodes():
designRegisters.append(DesignRegister(registerNode))
for registerNode in self.getMEMRegisterNodes():
designRegisters.append(DesignRegister(registerNode, self.customTypesXmlNode))
return designRegisters
def getDesignIORegisters(self):
designIORegisters = []
for registerNode in self.getIORegisterNodes():
designIORegisters.append(DesignRegister(registerNode, self.customTypesXmlNode))
return designIORegisters
def getDesignRegisters(self):
return self.getDesignMEMRegisters() + self.getDesignIORegisters()
......@@ -16,12 +16,20 @@
from iecommon import *
from model.Class.Block import *
from Mapping import *
import libxml2
from model.Class.Types import Enum
class Class(object):
def __init__(self, xmlNode):
self.xmlNode = xmlNode
customTypes = self.xmlNode.xpathEval("custom-types")
if customTypes is not None and len(customTypes) == 1:
self.customTypesXmlNode = customTypes[0]
else:
self.customTypesXmlNode = None
self.name = xmlNode.prop("name")
self.version = xmlNode.prop("version")
#xmlNode.shellPrintNode()
......@@ -30,59 +38,73 @@ class Class(object):
return iecommon.capitalizeString(self.name)
def getBlockNodes(self):
return self.xmlNode.xpathEval("*[name()='Acquisition-Block' or name()='Setting-Block' or name()='Command-Block']")
return self.getIOBlockNodes() + self.getMemoryBlockNodes()
def getIOBlockNodes(self):
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' or name()='Configuration-Block']")
def getEnumNodes(self):
return self.xmlNode.xpathEval("custom-types/enum")
class ParamClass(Class):
def __init__(self):
self.address = 0
self.usedMemory = ""
___addressAttribute = { MEM_TYPE: "address", DI_TYPE: "DI-address", DO_TYPE: "DO-address", AI_TYPE: "AI-address", AO_TYPE: "AO-address" }
___usedDataAttribute = { MEM_TYPE: "used-mem", DI_TYPE: "used-DI", DO_TYPE: "used-DO", AI_TYPE: "used-AI", AO_TYPE: "used-AO" }
def __init__(self):
self.address = { MEM_TYPE: int(-1), DI_TYPE: int(-1), DO_TYPE: int(-1), AI_TYPE: int(-1), AO_TYPE: int(-1) }
self.usedData = { MEM_TYPE: "", DI_TYPE: "", DO_TYPE: "", AI_TYPE: "", AO_TYPE: "" }
def initWithParamClassNode(self, xmlNode):
super(ParamClass, self).__init__(xmlNode)
self.address = long(self.xmlNode.prop("address"))
self.usedMemory = self.xmlNode.prop("usedMemory")
for index, address in enumerate(self.address):
self.address[index] = int(self.xmlNode.prop(self.___addressAttribute[index]))
for index, usedData in enumerate(self.usedData):
self.usedData[index] = self.xmlNode.prop(self.___usedDataAttribute[index])
def initWithDesignClass(self, designClass):
newNode = libxml2.newNode(designClass.xmlNode.get_name())
newNode.newProp("name", designClass.name)
newNode.newProp("version", designClass.version)
if designClass.customTypesXmlNode is not None:
customNode = designClass.customTypesXmlNode.copyNode(1)
newNode.addChild(customNode)
super(ParamClass, self).__init__(newNode)
newNode.newProp("address", str(self.address))
newNode.newProp("usedMemory", self.usedMemory)
def setAddress(self,address):
self.xmlNode.setProp("address", str(address))
self.address = address
def setUsedMemory(self,usedMemory):
self.xmlNode.setProp("usedMemory", usedMemory)
self.usedMemory = usedMemory
for index, address in enumerate(self.address):
newNode.newProp(self.___addressAttribute[index], str(self.address[index]))
for index, usedData in enumerate(self.usedData):
newNode.newProp(self.___usedDataAttribute[index], str(self.usedData[index]))
def setAddress(self,address,type):
self.xmlNode.setProp(self.___addressAttribute[type], str(int(address)))
self.address[type] = address
def setUsedData(self,usedData,type):
self.xmlNode.setProp(self.___usedDataAttribute[type], usedData)
self.usedData[type] = usedData
def getParamBlocks(self):
paramBlocks = []
for blockNode in self.getBlockNodes():
paramBlock = ParamBlock()
paramBlock.initWithParamBlockNode(blockNode)
paramBlock.initWithParamBlockNode(blockNode, self.customTypesXmlNode)
paramBlocks.append(paramBlock)
return paramBlocks
def getParamMemoryBlocks(self):
paramMemBlocks = []
for blockNode in self.getMemoryBlockNodes():
paramBlock = ParamBlock()
paramBlock.initWithParamBlockNode(blockNode, self.customTypesXmlNode)
paramMemBlocks.append(paramBlock)
return paramMemBlocks
def getDeviceInstanceNodes(self):
deviceNodes = self.xmlNode.xpathEval("Instance")
return deviceNodes
@staticmethod
def getParamClassesFromRootNode(silecsRoot):
classNodes = silecsRoot.xpathEval("/SILECS-Param/SILECS-Mapping/SILECS-Class")
if len(classNodes) < 1:
raise BaseException("Error: no class-node found in design-document")
paramClasses = []
for classNode in classNodes:
paramClass = ParamClass()
paramClass.initWithParamClassNode(classNode)
paramClasses.append(paramClass)
return paramClasses
class DesignClass(Class):
def __init__(self, xmlNode):
......@@ -92,12 +114,31 @@ class DesignClass(Class):
def getFesaName(self):
return self.fesaPropertyName
def getDesignFesaBlocks(self):
designFesaBlocks = []
for block in self.getDesignBlocks():
if block.generateFesaProperty:
designFesaBlocks.append(block)
return designFesaBlocks
def getDesignBlocks(self):
designBlocks = []
for blockNode in self.getBlockNodes():
designBlocks.append(DesignBlock(blockNode))
designBlocks.append(DesignBlock(blockNode, self.customTypesXmlNode))
return designBlocks
def getDesignMemoryBlocks(self):
designBlocks = []
for blockNode in self.getMemoryBlockNodes():
designBlocks.append(DesignBlock(blockNode, self.customTypesXmlNode))
return designBlocks
def getEnums(self):
enums = []
for node in self.getEnumNodes():
enums.append(Enum(node))
return enums
@staticmethod
def getDesignClassFromRootNode(silecsRoot):
classNodes = silecsRoot.xpathEval('/SILECS-Design/SILECS-Class')
......
......@@ -20,12 +20,14 @@ 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"
def __init__(self, xmlNode):
def __init__(self, xmlNode, customTypesXmlNode):
self.xmlNode = xmlNode
self.customTypesXmlNode = customTypesXmlNode
#xmlNode.shellPrintNode()
self.name = xmlNode.prop("name")
self.___type = xmlNode.get_name()
......@@ -35,8 +37,9 @@ class Register(object):
self.dim2 = 1
self.stringLength = 1 # ... currently needs to be default because of some old convention
self.format = ""
valueTypes = xmlNode.xpathEval("*[name()='scalar' or name()='array' or name()='array2D' or name()='string' or name()='stringArray' or name()='stringArray2D']")
self.custom_type_name = ""
valueTypes = xmlNode.xpathEval("*[name()='scalar' or name()='array' or name()='array2D' or name()='string' or name()='stringArray' or name()='stringArray2D' or name()='custom-type-scalar' or name()='custom-type-array' or name()='custom-type-array2D']")
if not valueTypes:
iecommon.logError('ERROR: The register '+ self.name +' has no valueTypes.', True, {'errorlog': True})
if len(valueTypes) < 1:
......@@ -47,18 +50,27 @@ class Register(object):
self.valueType = self.valueTypeNode.get_name()
if self.valueTypeNode.hasProp("dim1"):
self.dim1 = long(self.valueTypeNode.prop("dim1"))
self.dim1 = int(self.valueTypeNode.prop("dim1"))
elif self.valueTypeNode.hasProp("dim"):
self.dim1 = long(self.valueTypeNode.prop("dim"))
self.dim1 = int(self.valueTypeNode.prop("dim"))
if self.valueTypeNode.hasProp("dim2"):
self.dim2 = long(self.valueTypeNode.prop("dim2"))
self.dim2 = int(self.valueTypeNode.prop("dim2"))
if self.valueTypeNode.hasProp("string-length"):
self.stringLength = long(self.valueTypeNode.prop("string-length"))
self.format = self.valueTypeNode.prop("format")
self.stringLength = int(self.valueTypeNode.prop("string-length"))
if self.isCustomType():
self.custom_type_name = self.valueTypeNode.prop("custom-type-name-ref")
if self.isEnumType():
self.format = "int32"
else:
raise Exception("Custom types other than 'enum' are not yet supported.")
else:
self.format = self.valueTypeNode.prop("format")
def getNameCapitalized(self):
return iecommon.capitalizeString(self.name)
......@@ -68,9 +80,6 @@ class Register(object):
return True
return False
def getSilecsTypeCapitalized(self):
return self.getSilecsDataTypeUpperCase()
def isScalar(self):
return self.valueType == 'scalar'
......@@ -89,20 +98,44 @@ class Register(object):
def isStringType(self):
return self.valueType == 'string' or self.valueType == 'stringArray' or self.valueType == 'stringArray2D'
def isCustomScalar(self):
return self.valueType == 'custom-type-scalar'
def isCustomArray(self):
return self.valueType == 'custom-type-array'
def isCustomArray2D(self):
return self.valueType == 'custom-type-array2D'
def isCustomType(self):
return self.isCustomScalar() or self.isCustomArray() or self.isCustomArray2D()
def isEnumType(self):
if self.customTypesXmlNode is None:
return False
enums = self.customTypesXmlNode.xpathEval("enum")
for e in enums:
if e.prop("name") == self.custom_type_name:
return True
return False
def isArrayType(self):
return self.isArray() or self.isArray2D()
def isAcquisition(self):
return self.___type == self.___acquisitionRegisterType
return self.___type == self.___acquisitionRegisterType or self.___type == self.___acquisitionIORegisterType
def isSetting(self):
return self.___type == self.___settingRegisterType
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 {
'bool' :'bool',
'int8' :'int8_t',
'uint8' :'uint8_t',
'int16' :'int16_t',
......@@ -122,6 +155,7 @@ class Register(object):
'dint' :'int32_t',
'real' :'float',
'dt' :'double',
'dtl' :'double',
'string' :'std::string'
}[self.getSilecsDataType()]
......@@ -146,6 +180,7 @@ class Register(object):
'dint' :'int32',
'real' :'float32',
'dt' :'date',
'dtl' :'date',
'uint8' :'uint8',
'int8' :'int8',
'uint16' :'uint16',
......@@ -157,21 +192,39 @@ class Register(object):
'float32' :'float32',
'float64' :'float64',
'date' :'date',
'string' : 'string'
'string' : 'string',
'bool' : 'bool'
}[self.format]
#Needed for SilecsMethodNames
def getSilecsDataTypeUpperCase(self):
silecsType = self.getSilecsDataType()
typeUpperCase = ""
if silecsType[0] == 'u':
typeUpperCase = silecsType[:2].upper() + silecsType[2:] # first two characters if unsigned
elif silecsType == 'date':
typeUpperCase = 'Date'
else:
typeUpperCase = silecsType[:1].upper() + silecsType[1:] # only first character if not unsigned
return typeUpperCase
def getDataSize(self):
return {
'bool' : 1,
'uint8' : 1,
'int8' : 1,
'uint16' : 2,
'int16' : 2,
'uint32' : 4,
'int32' : 4,
'float32' : 4,
'uint64' : 8,
'int64' : 8,
'float64' : 8,
'string' : 1,
'date' : 8,
'dtl' : 12,
# deprecated formats
'char' : 1,
'byte' : 1,
'word' : 2,
'dword' : 4,
'int' : 2,
'dint' : 4,
'real' : 4,
'dt' : 8
}[self.format]
#has some additionalValues
class ParamRegister(Register):
......@@ -180,44 +233,59 @@ class ParamRegister(Register):
self.size = 0
self.address = 0
self.memSize = 0
self.bitNumber = 0
def initWithParamRegisterNode(self, xmlNode, customTypesXmlNode):
super(ParamRegister, self).__init__(xmlNode, customTypesXmlNode)
self.size = int(self.xmlNode.prop("size"))
self.address = int(self.xmlNode.prop("address"))
self.memSize = int(self.xmlNode.prop("mem-size"))
def initWithParamRegisterNode(self, xmlNode):
super(ParamRegister, self).__init__(xmlNode)
self.size = long(self.xmlNode.prop("size"))
self.address = long(self.xmlNode.prop("address"))
self.memSize = long(self.xmlNode.prop("mem-size"))
if self.xmlNode.prop("bit-number"):
self.bitNumber = int(self.xmlNode.prop("bit-number"))
def initWithDesignRegister(self, designRegister,size,address,memSize):
def initWithDesignRegister(self, designRegister,address,memSize,bitNumber=None):
newNodeTree = designRegister.xmlNode.copyNode(1) # 1 is for recursive copy
if ( newNodeTree == None ):
iecommon.logError('ERROR: Failed to copy register node: '+ designRegister.name +'.', True, {'errorlog': True})
super(ParamRegister, self).__init__(designRegister.xmlNode)
super(ParamRegister, self).__init__(designRegister.xmlNode, designRegister.customTypesXmlNode)
self.xmlNode = newNodeTree
newNodeTree.newProp("size", size)
self.size = long(size)
self.size = self.getDataSize()
newNodeTree.newProp("size", str(self.size))
newNodeTree.newProp("address", str(address))
self.address = address
newNodeTree.newProp("mem-size", str(memSize))
self.memSize = memSize
#self.xmlNode.shellPrintNode()
if bitNumber is not None:
newNodeTree.newProp("bit-number", str(bitNumber))
self.bitNumber = bitNumber
# Add an attribute to facilitate detecting the type of the custom-type.
if self.isEnumType():
for elem in self.xmlNode:
if elem.hasProp("custom-type-name-ref"):
elem.newProp("type", "enum")
def setSize(self,size):
self.xmlNode.setProp("size", str(size))
self.size = size
def setAddress(self,address):
self.xmlNode.setProp("address", str(address))
self.xmlNode.setProp("address", str(int(address)))
self.address = address
def setMemSize(self,memSize):
self.xmlNode.setProp("mem-size", str(memSize))
self.memSize = memSize
class DesignRegister(Register):
def __init__(self, xmlNode):
super(DesignRegister, self).__init__(xmlNode)
def __init__(self, xmlNode, customTypesXmlNode):
super(DesignRegister, self).__init__(xmlNode, customTypesXmlNode)
self.fesaFieldName = self.name
self.generateFesaValueItem=True
if self.xmlNode.hasProp("fesaFieldName"):
......@@ -243,7 +311,7 @@ class DesignRegister(Register):
'int32' :'int32_t',
'uint32' :'int64_t',
'int64' :'int64_t',
'uint64' :'uint64_t', # only for PXI, but not supported from Java! Not possible to use it in FESA properties
'uint64' :'uint64_t', #for PXI and Beckhoff, but not supported from Java! Not possible to use it in FESA properties
'float32' :'float',
'float64' :'double',
'date' :'double',
......@@ -255,7 +323,8 @@ class DesignRegister(Register):
'dint' :'int32_t',
'real' :'float',
'dt' :'double',
'string' :'char'
'string' :'char',
'bool' :'bool'
}[self.getSilecsDataType()]
def getFesaFieldNameCapitalized(self):
......@@ -282,6 +351,6 @@ class DesignRegister(Register):
'dint' :'int32_t',
'real' :'float',
'dt' :'double',
'string' :'char'
'string' :'char',
'bool' :'bool'
}[silecsDataType]
class EnumItem(object):
def __init__(self, xmlNode) -> None:
self.xmlNode = xmlNode
self.access = xmlNode.prop("access")
self.symbol = xmlNode.prop("symbol")
self.value = xmlNode.prop("value")
def __str__(self) -> str:
return f"EnumItem: {self.access}, {self.symbol}, {self.value}"
class Enum(object):
def __init__(self, xmlNode) -> None:
self.xmlNode = xmlNode
self.name: str = xmlNode.prop("name")
self.items: EnumItem = []
items = xmlNode.xpathEval("item")
for item in items:
self.items.append(EnumItem(item))
def __str__(self) -> str:
items = ""
for item in self.items:
items += "\t"+ str(item) + "\n"
return f"Enum {self.name}.\nItems:\n {items}"
\ No newline at end of file
......@@ -16,10 +16,24 @@
from model.Deploy.Device import *
from model.Deploy.SilecsDesign import *
from model.Class.Block import *
from Mapping import *
import libxml2
#-------------------------------------------------------------------------
# Return the highest bit-alignment of the given address
def whichDataAlignment(value):
if (value % 2 != 0): return 8
if (value % 4 != 0): return 16
if (value % 8 != 0): return 32
if (value % 16 != 0): return 64
return 128
class Controller(object):
BLOCK_MODE = "BLOCK_MODE"
DEVICE_MODE = "DEVICE_MODE"
def __init__(self, xmlNode):
self.hostName = ""
self.domain = ""
......@@ -27,12 +41,28 @@ class Controller(object):
self.model = ""
self.protocol = ""
self.brand = ""
self.baseAddress = long(0)
self.xmlNode = None
self._baseAddress = { MEM_TYPE: None, DI_TYPE: None, DO_TYPE: None, AI_TYPE: None, AO_TYPE: None }
self.address = { MEM_TYPE: int(-1), DI_TYPE: int(-1), DO_TYPE: int(-1), AI_TYPE: int(-1), AO_TYPE: int(-1) }
self.offset = { MEM_TYPE: int(0), DI_TYPE: int(0), DO_TYPE: int(0), AI_TYPE: int(0), AO_TYPE: int(0) }
self.addressFactor = 1
# some variable used to calculate class/block/register-memory
self.memSize = 0
self.memLast = 0
self.msize = 0
self.regCounter = 0
self.blockCounter = 0
# The following constant are used to align the address of a device block {set of registers}.
# With SCHNEIDER PLC, block is aligned depending on his 'worst-case' alignement {16bits or 32bits}.
# This logic allows having a unique adress computing whatever the mode {DEVICE/BLOCK} and the PLC model.
# Concerning SIEMENS PLC, block alignment should respect the 16bits alignement constraint for Struct&Array.
self.baseAlignment = int(16) # the default
self.alligment = { IOType.MEMORY: int(16), IOType.DIGITAL: int(8), IOType.ANALOG: int(16) } # the default
self.xmlNode = xmlNode
self.plcNode = None
self.devices = []
self.xmlNode = xmlNode
self.hostName = xmlNode.prop("host-name")
if xmlNode.hasProp("domain"):
self.domain = xmlNode.prop("domain")
......@@ -41,6 +71,19 @@ class Controller(object):
self.model = self.plcNode.prop('model')
self.protocol = self.plcNode.prop('protocol')
if self.plcNode.hasProp("base-address"):
self._baseAddress[MEM_TYPE] = int(self.plcNode.prop('base-address'))
if self.plcNode.hasProp("base-DB-number"):
self._baseAddress[MEM_TYPE] = int(self.plcNode.prop('base-DB-number'))
if self.plcNode.hasProp("DI-base-address"):
self._baseAddress[DI_TYPE] = int(self.plcNode.prop("DI-base-address"))
if self.plcNode.hasProp("DO-base-address"):
self._baseAddress[DO_TYPE] = int(self.plcNode.prop("DO-base-address"))
if self.plcNode.hasProp("AI-base-address"):
self._baseAddress[AI_TYPE] = int(self.plcNode.prop("AI-base-address"))
if self.plcNode.hasProp("AO-base-address"):
self._baseAddress[AO_TYPE] = int(self.plcNode.prop("AO-base-address"))
silecsHeader = Device()
silecsHeader.silecsDeviceLabel = "SilecsHeader"
silecsHeader.silecsDesignRef = "SilecsHeader"
......@@ -51,6 +94,11 @@ class Controller(object):
device.initFromXMLNode(deviceNode)
self.devices.append(device)
def computeAddresses(self):
for index, baseAddress in enumerate(self._baseAddress):
if self._baseAddress[index] != None:
self.address[index] = ( self._baseAddress[index] + self.offset[index] ) * self.addressFactor
def connectDesignObjects(self,silecsDesigns):
for device in self.devices:
for design in silecsDesigns:
......@@ -92,60 +140,470 @@ class Controller(object):
elif type == "Beckhoff-PLC":
return BeckhoffController(controllerNode)
elif type == "Rabbit-uC":
return DigiController(controllerNode)
return RabbitController(controllerNode)
elif type == "NI-Controller":
return NIController(controllerNode)
elif type == "Virtual-Controller":
return SiemensController(controllerNode)
return SiemensController(controllerNode)#currently there is only S7-virtual
else:
raise Exception( "Controller-Type " + type + " not supported" )
def hasMappingFor(self,type):
return self._baseAddress[type] != None
def computeInstAddress(self, mapping):
if self.protocol == self.BLOCK_MODE:
return self.computeBlockInstAddress(mapping)
elif self.protocol == self.DEVICE_MODE:
return self.computeDeviceInstAddress(mapping)
else:
raise Exception("The protocol '" + self.protocol + "' of controller '" + self.hostName + "is not known.")
def computeBlockInstAddress(self, mapping):
raise NotImplementedError()
def computeDeviceInstAddress(self, mapping):
raise NotImplementedError()
def computeBlockInstAddressDefault(self, mapping):
if not mapping.isDefined:
return mapping.instanceAddress
tmpInstAddr = mapping.instanceAddress
mapping.instanceAddress += 1 #device-index
return tmpInstAddr
def computeDeviceInstAddressDefault(self, mapping):
if not mapping.isDefined:
return mapping.instanceAddress
tmpInstAddr = mapping.instanceAddress
mapping.instanceAddress = mapping.instanceAddress + mapping.deviceDataSize #absolute address
return tmpInstAddr + mapping.classBaseAddress
def computeNextBaseAddress(self, mapping, nbDev):
raise NotImplementedError()
# Compute the base-address of the next class
# DEVICE or BLOCK mode use the same memory size: next base address should be the same
# 'used-mem' info is expressed in words (/2) but address is computed in bytes
def computeNextBaseAddressDefault(self, mapping, nbDev):
mapping.usedData = "0 word"
if not mapping.isDefined or ( mapping.nbBlock == 0 ) or not self.hasMappingFor(mapping.type):
return mapping.classBaseAddress
wordSize = (nbDev * mapping.deviceDataSize) / self.addressFactor
self.memSize += wordSize # global size of the plc configuration
startAddr = (mapping.classBaseAddress - self.offset[mapping.type] * self.addressFactor) / self.addressFactor # first word address used for this class
self.memLast = startAddr + wordSize - 1 # last word address used for this class
mapping.usedData = "MW%d..MW%d/%d words" % (startAddr, self.memLast, wordSize);
mapping.classBaseAddress = (mapping.classBaseAddress + (wordSize * self.addressFactor)) # next word address expressed in bytes
def alignRegAddress(self, block, register, regAddress):
raise NotImplementedError()
# Adjust the register address relying on the SCHNEIDER Premium/Quantum and/or Beckhoff alignment constraints
# Unity Premium/Quantum is 16bits processor and base-address is interpreted as 16bit address
# Byte elements of array (including STRING) use 8bit alignment.
def alignRegAddressDefault(self, block, register, regAddress):
algnt = 16
while(whichDataAlignment(regAddress) < algnt):
regAddress += 1
self.msize = register.dim1 * register.dim2 * register.stringLength * register.getDataSize() # compute memory data size
if register.format == 'int8' or register.format == 'char':# 8bit signed type use word alignment (16bit)
self.msize = self.msize * 2 # while string and uint8-array use 8bit alignment
return regAddress
def computeNextRegAddress(self, block, register, regAddress ):
raise NotImplementedError()
#-------------------------------------------------------------------------
# Compute the next register address relying on the data start-address and size.
def computeNextRegAddressDefault(self, block, register, regAddress ):
regAddress = regAddress + self.msize;
return regAddress
def computeBlkAddress(self, block, mapping, regAddr, nbDev):
if self.protocol == self.BLOCK_MODE:
return self.computeBlockBlkAddress(block, mapping, regAddr, nbDev)
elif self.protocol == self.DEVICE_MODE:
return self.computeDeviceBlkAddress(block, mapping, regAddr, nbDev)
else:
raise Exception("The protocol '" + self.protocol + "' of controller '" + self.hostName + "is not known.")
def computeBlockBlkAddress(self, block, mapping, regAddr, nbDev):
raise NotImplementedError()
def computeDeviceBlkAddress(self, block, mapping, regAddr, nbDev):
raise NotImplementedError()
# Block-address = absolute address in the PLC memory
def computeBlockBlkAddressDefault(self, block, mapping, regAddr, nbDev):
# Compute block mem-size at first:
# It corresponds to the next potential address that is 16bits or 32bits.
nextBlockAddr = regAddr
# Adjust the next block-address by respecting the alignment depending on the area
while int(whichDataAlignment(nextBlockAddr)) < self.alligment[block.ioType]:
nextBlockAddr += 1
mapping.blockDataSize = nextBlockAddr
# then compute the next block DB-number and return the current one
tmpblockAddress = mapping.blockAddress
# next absolute address: relies on the global class-address
mapping.blockAddress += (nbDev * mapping.blockDataSize)
# Count the number of block per area type,
# accumulate the block data size to compute the total device data size
mapping.nbBlock += 1
mapping.deviceDataSize += mapping.blockDataSize
return mapping.classBaseAddress + tmpblockAddress
# Block-address = offset in the device memory
def computeDeviceBlkAddressDefault(self, block, mapping, regAddr, nbDev):
# Compute block mem-size at first:
# it corresponds to the next potential address that is 16bits or 32bits
nextBlockAddr = regAddr
# Adjust the next block-address by respecting the alignment depending on the area
while int(whichDataAlignment(nextBlockAddr)) < self.alligment[block.ioType]:
nextBlockAddr += 1
mapping.blockDataSize = nextBlockAddr
# then compute the next block DB-number and return the current one
tmpblockAddress = mapping.blockAddress
# next relative address: independent from the global class-address
mapping.blockAddress += mapping.blockDataSize
# Count the number of block per area type,
# accumulate the block data size to compute the total device data size
mapping.nbBlock += 1
mapping.deviceDataSize += mapping.blockDataSize
return tmpblockAddress
class SiemensController(Controller):
def __init__(self, xmlNode):
super(SiemensController, self).__init__(xmlNode)
self.brand = "SIEMENS"
self.baseAddress = long(self.plcNode.prop('base-DB-number'))
self.computeAddresses()
def computeDeviceInstAddress(self, mapping):
if not mapping.isDefined:
return mapping.instanceAddress
tmpInstAddr = mapping.instanceAddress
mapping.instanceAddress += 1 #device DB-number
return tmpInstAddr + mapping.classBaseAddress
def computeBlockInstAddress(self, mapping):
return self.computeBlockInstAddressDefault(mapping)
def computeNextBaseAddress(self, mapping, nbDev):
mapping.usedData = "0 byte"
if not mapping.isDefined or ( mapping.nbBlock == 0 ) or not self.hasMappingFor(mapping.type):
return mapping.classBaseAddress
if mapping.type != MEM_TYPE:
return self.computeIONextBaseAddress(mapping, nbDev)
if self.protocol == self.BLOCK_MODE:
return self.computeBlockNextBaseAddress(mapping, nbDev)
elif self.protocol == self.DEVICE_MODE:
return self.computeDeviceNextBaseAddress(mapping, nbDev)
else:
raise Exception("The protocol '" + self.protocol + "' of controller '" + self.hostName + "is not known.")
# Compute the base DB-number of the next instance in the SIEMENS PLC memory
# BLOCK mode requires 1 DB per class block
def computeBlockNextBaseAddress(self, mapping, nbDev):
byteSize = nbDev * mapping.deviceDataSize
self.memSize = self.memSize + byteSize # global size of the plc configuration
startDB = mapping.classBaseAddress # first DB used for this class
self.memLast = mapping.classBaseAddress + mapping.nbBlock - 1 # last DB used
mapping.usedData = "DB%d..DB%d/%d bytes" % (startDB, self.memLast, byteSize)
mapping.classBaseAddress = self.memLast + 1 # next DB number
# Compute the base DB-number of the next instance in the SIEMENS PLC memory
# DEVICE mode requires 1 DB per class instance
def computeDeviceNextBaseAddress(self, mapping, nbDev):
byteSize = nbDev * mapping.deviceDataSize
self.memSize = self.memSize + byteSize # global size of the plc configuration
startDB = mapping.classBaseAddress # first DB used for this class
self.memLast = mapping.classBaseAddress + nbDev - 1 # last DB used
mapping.usedData = "DB%d..DB%d/%d bytes" % (startDB, self.memLast, byteSize)
mapping.classBaseAddress = self.memLast + 1 # next DB number
# Compute the base-address of the next class in the SIEMENS PLC IO area
# DEVICE or BLOCK mode use the same data size: next base address should be the same
# 'used-IO' info is expressed in bytes
def computeIONextBaseAddress(self, mapping, nbDev):
byteSize = nbDev * mapping.deviceDataSize
self.memSize += byteSize # global size of the plc configuration
startAddr = mapping.classBaseAddress # first byte address used for this class
self.memLast = startAddr + byteSize - 1 # last byte address used for this class
if mapping.type == DI_TYPE or mapping.type == AI_TYPE:
mapping.usedData = "IB%d..IB%d/%d bytes" % (startAddr, self.memLast, byteSize);
else: #in ['DO-', 'AO-']
mapping.usedData = "QB%d..QB%d/%d bytes" % (startAddr, self.memLast, byteSize);
mapping.classBaseAddress = (mapping.classBaseAddress + byteSize) # next byte address expressed in bytes
# Adjust the register relying on the SIEMENS Simatic alignment constraints
# MEMORY area: uses 8bits alignment except for array and >8bits data (16bits alignment)
# DIGITAL area: uses 8bit alignment without any exception.
# ANALOG area: uses 16bit alignment.
# In case of string, its length has to be +2 to hold info on string
def alignRegAddress(self, block, register, regAddress):
algnt = 8
if ( block.isAnanlogIO() or ( block.isMEMBlock() and ((register.getDataSize() > 1) or (register.dim1 > 1) or (register.dim2 > 1) or (register.stringLength > 1))) ):
algnt = self.alligment[block.ioType]
while(whichDataAlignment(regAddress) < algnt):
regAddress += 1
if register.stringLength > 1: # register is a string,
if ((register.stringLength % 2) != 0): register.stringLength += 1 # adjusts the global size for byte type (word alignment)
register.stringLength += 2 # add increment to register.stringLength first two bytes for info on string (len, maxlen)
self.msize = register.dim1 * register.dim2 * register.stringLength * register.getDataSize() # compute memory data size
return regAddress
def computeNextRegAddress(self, block, register, regAddress ):
regAddress = regAddress + self.msize; #compute the next address for any case
# SIEMENS requires specific treatment in case of array.
if register.isArrayType():
#SIEMENS array is always followed by 16bits adressing
algnt = 16
while(whichDataAlignment(regAddress) < algnt):
regAddress+=1
# SIEMENS ANALOG-IO area uses 16bit addressing
# SIEMENS MEMORY array is always followed by 16bits address
if block.isAnanlogIO() or ( block.isMEMBlock() and register.isArrayType() ):
while(whichDataAlignment(regAddress) < 16):
regAddress += 1
return regAddress
def computeBlockBlkAddress(self, block, mapping, regAddr, nbDev):
if mapping.type == MEM_TYPE:
return self.computeBlockBlkAddressMemory(block, mapping, regAddr, nbDev)
else:
return self.computeBlockBlkAddressDefault(block, mapping, regAddr, nbDev)
def computeDeviceBlkAddress(self, block, mapping, regAddr, nbDev):
return self.computeDeviceBlkAddressDefault(block, mapping, regAddr, nbDev)
# block-address = block DB-Number
def computeBlockBlkAddressMemory(self, block, mapping, regAddr, nbDev):
# Compute block mem-size at first: each block has a dedicated DB-number which contains an array of devices
# each element of the array is a structure which must be 16bits aligned!
nextBlockAddr = regAddr
# Adjust the next block-address by respecting the alignment depending on the area
while int(whichDataAlignment(nextBlockAddr)) < self.alligment[block.ioType]:
nextBlockAddr += 1
mapping.blockDataSize = nextBlockAddr
# then compute the next block DB-number and return the current one
tmpblockAddress = mapping.blockAddress
mapping.blockAddress += 1
# Count the number of block per area type,
# accumulate the block data size to compute the total device data size
mapping.nbBlock += 1
mapping.deviceDataSize += mapping.blockDataSize
return mapping.classBaseAddress + tmpblockAddress
class BeckhoffController(Controller):
addressFactor_BC9020 = 2 # BC90xx use 16 bit addressing
addressFactor_CX9020 = 1
offset_BC9020 = 32768
offset_CX9020 = 24576
addressFactor_default = 2 # Beckhoff default is 16 bit addressing
addressFactor_CX9020_Twincat2 = 1
addressFactor_CX9020_Twincat3 = 2
offset_mem_BC9020_base = 0x8000 # some controllers use a memory-offset
offset_mem_CX9020_base = 0x6000
offset_output_base = 0x1000 # offset for analog and digital output registers
memoryAlignment_CX9020 = 32
def __init__(self, xmlNode):
super(BeckhoffController, self).__init__(xmlNode)
self.brand = "BECKHOFF"
self.baseAddress = long(self.plcNode.prop('base-address'))
self.brand = "BECKHOFF"
self.addressFactor = self.addressFactor_default
if 'CX90' in self.model:
if self.system == 'TWINCat-2':
self.addressFactor = self.addressFactor_CX9020_Twincat2
elif self.system == 'TWINCat-3':
self.addressFactor = self.addressFactor_CX9020_Twincat3
else:
raise Exception("system '" + self.system + "' of controller '" + self.hostName + "'not supported")
self.offset[MEM_TYPE] = self.offset_mem_CX9020_base / self.addressFactor
self.alligment[IOType.MEMORY] = self.memoryAlignment_CX9020
if self.model == 'BC9020':
self.offset[MEM_TYPE] = self.offset_mem_BC9020_base / self.addressFactor
self.offset[AO_TYPE] = self.offset_output_base / self.addressFactor
self.offset[DO_TYPE] = self.offset_output_base / self.addressFactor
self.computeAddresses()
def computeDeviceInstAddress(self, mapping):
return self.computeDeviceInstAddressDefault(mapping)
def computeBlockInstAddress(self, mapping):
return self.computeBlockInstAddressDefault(mapping)
def computeNextBaseAddress(self, mapping, nbDev):
return self.computeNextBaseAddressDefault(mapping, nbDev)
def alignRegAddress(self, block, register, regAddress):
if self.model == 'BC9020':
self.baseAddress = ( self.baseAddress * self.addressFactor_BC9020 ) + self.offset_BC9020
return self.alignBCxxRegAddress(block, register, regAddress);
elif self.model == 'CX9020':
self.baseAddress = ( self.baseAddress * self.addressFactor_CX9020 ) + self.offset_CX9020
return self.alignCXxxRegAddress(block, register, regAddress);
elif self.model == 'BK9000' or self.model == 'BK9050' or self.model == 'BK9100':
return self.alignRegAddressDefault(block, register, regAddress);
else:
raise Exception( "Unknown beckhoff plc-model:" + self.model )
raise Exception("The plc-model '" + self.model + "' is not yet supported.")
# Adjust the register address relying on the BECKHOFF Twincat BC9020 alignment constraints.
# TwinCAT BCxx PLCs are 16bits processor and base-address is interpreted as 16bit address
# 8bits alignment between elements of 8bit-data array (including strings).
# In case of string, its length has to be +1 to hold end-terminator.
def alignBCxxRegAddress(self, block, register, regAddress):
algnt = 16
while(whichDataAlignment(regAddress) < algnt):
regAddress += 1
if register.stringLength > 1: # register is a string,
register.stringLength += 1 # TwinCAT requires '\0' string terminator.
self.msize = register.dim1 * register.dim2 * register.stringLength * register.getDataSize() # compute memory data size
return regAddress
# Adjust the register address relying on the BECKHOFF Twincat CX9020 alignment constraints.
# TwinCAT CXxx PLCs are 32bits processor but base-address is interpreted as 16bit address (required even address in the mapping)
# TWINCAT-2: 32bits alignment except for 8/16bits (16bits alignment).
# TWINCAT-3: 16bits alignment
# BOTH: 8bits alignment between elements of 8bit-data array (including strings).
# In case of string, its length has to be +1 to hold end-terminator.
def alignCXxxRegAddress(self, block, register, regAddress):
algnt = 16
if (register.getDataSize() > 2):
algnt = self.alligment[block.ioType] #depends on TwinCAT platform
while(whichDataAlignment(regAddress) < algnt):
regAddress += 1
if register.stringLength > 1: # register is a string,
register.stringLength += 1 # TwinCAT requires '\0' string terminator.
self.msize = register.dim1 * register.dim2 * register.stringLength * register.getDataSize() # compute memory data size
return regAddress
def computeNextRegAddress(self, block, register, regAddress):
return self.computeNextRegAddressDefault(block, register, regAddress)
def computeBlockBlkAddress(self, block, mapping, regAddr, nbDev):
return self.computeBlockBlkAddressDefault(block, mapping, regAddr, nbDev)
def computeDeviceBlkAddress(self, block, mapping, regAddr, nbDev):
return self.computeDeviceBlkAddressDefault(block, mapping, regAddr, nbDev)
class SchneiderController(Controller):
addressFactor = 2
# Premium/Quantum uses 16bit adressing for 32bit values
# Unity M340 is interpreted as 32bit address
addressFactor_Schneider_default = 2
memoryAlignment_M340 = 32
def __init__(self, xmlNode):
super(SchneiderController, self).__init__(xmlNode)
self.brand = "SCHNEIDER"
self.baseAddress = long(self.plcNode.prop('base-address'))
self.baseAddress = self.baseAddress * self.addressFactor
self.addressFactor = self.addressFactor_Schneider_default
if self.model == 'M340':
self.alligment[IOType.MEMORY] = self.memoryAlignment_M340
self.computeAddresses()
def computeDeviceInstAddress(self, mapping):
return self.computeDeviceInstAddressDefault(mapping)
def computeBlockInstAddress(self, mapping):
return self.computeBlockInstAddressDefault(mapping)
def computeNextBaseAddress(self, mapping, nbDev):
return self.computeNextBaseAddressDefault(mapping, nbDev)
def alignRegAddress(self, block, register, regAddress):
if self.model == 'M340':
return self.alignM340RegAddress(block, register, regAddress);
elif self.model == 'Premium' or self.model == 'Quantum':
return self.alignRegAddressDefault(block, register, regAddress);
else:
raise Exception("The plc-model '" + self.model + "' is not yet supported.")
# Formally known as "Rabbit Controller"
class DigiController(Controller):
addressFactor = 2
# Adjust the register address relying on the SCHNEIDER M340 alignment constraints
# Unity M340 is 32bits processor but base-address is interpreted as 16bit address (required even address in the mapping)
# 32bits alignment except for 8/16bits (16bits alignment)
# Byte elements of array (including STRING) use 8bit alignment.
def alignM340RegAddress(self, block, register, regAddress):
algnt = 16
if (register.getDataSize() > 2):
algnt = self.alligment[block.ioType]
while(whichDataAlignment(regAddress) < algnt):
regAddress += 1
self.msize = register.dim1 * register.dim2 * register.stringLength * register.getDataSize() # compute memory data size
if register.format == 'int8' or register.format == 'char':# 8bit signed type use word alignment (16bit)
self.msize = self.msize * 2 # while string and uint8-array use 8bit alignment
return regAddress
def computeNextRegAddress(self, block, register, regAddress):
return self.computeNextRegAddressDefault(block, register, regAddress)
def computeBlockBlkAddress(self, block, mapping, regAddr, nbDev):
return self.computeBlockBlkAddressDefault(block, mapping, regAddr, nbDev)
def computeDeviceBlkAddress(self, block, mapping, regAddr, nbDev):
return self.computeDeviceBlkAddressDefault(block, mapping, regAddr, nbDev)
class RabbitController(Controller):
addressFactor_DIGI_default = 2
def __init__(self, xmlNode):
super(DigiController, self).__init__(xmlNode)
super(RabbitController, self).__init__(xmlNode)
self.brand = "DIGI"
self.baseAddress = long(self.plcNode.prop('base-address'))
self.baseAddress = self.baseAddress * self.addressFactor
self.addressFactor = self.addressFactor_DIGI_default
self.computeAddresses()
def computeDeviceInstAddress(self, mapping):
return self.computeDeviceInstAddressDefault(mapping)
def computeBlockInstAddress(self, mapping):
return self.computeBlockInstAddressDefault(mapping)
def computeNextBaseAddress(self, mapping, nbDev):
return self.computeNextBaseAddressDefault(mapping, nbDev)
# Adjust the register address relying on the DIGI-Rabbit RCMx alignment constraints
# Use 16bits processor and base-address is interpreted as 16bit address
def alignRegAddress(self, block, register, regAddress):
algnt = 16
while(whichDataAlignment(regAddress) < algnt):
regAddress += 1
self.msize = register.dim1 * register.dim2 * register.stringLength * register.getDataSize() # compute memory data size
if not register.isStringType():
if (register.getDataSize() == 1): # but it's a 8bit type
self.msize = self.msize * 2 # so, it's a word alignment (only string use byte alignment)
return regAddress
def computeNextRegAddress(self, block, register, regAddress):
return self.computeNextRegAddressDefault(block, register, regAddress)
def computeBlockBlkAddress(self, block, mapping, regAddr, nbDev):
return self.computeBlockBlkAddressDefault(block, mapping, regAddr, nbDev)
def computeDeviceBlkAddress(self, block, mapping, regAddr, nbDev):
return self.computeDeviceBlkAddressDefault(block, mapping, regAddr, nbDev)
class NIController(Controller):
def __init__(self, xmlNode):
super(NIController, self).__init__(xmlNode)
self.brand = "NI"
self.baseAddress = 0
self.computeAddresses()
def computeDeviceInstAddress(self, mapping):
return 0
def computeNextBaseAddress(self, mapping, nbDev):
mapping.usedData = "0 byte"
mapping.classBaseAddress = 0
def alignRegAddress(self, block, register, regAddress):
return self.regCounter
def computeNextRegAddress(self, block, register, regAddress):
regAddress = regAddress + self.msize; #compute the next address for any case
self.msize = 0
return regAddress
def computeBlockBlkAddress(self, block, mapping, regAddr, nbDev):
raise Exception("Block-mode not possible for NI-Controllers")
def computeDeviceBlkAddress(self, block, mapping, regAddr, nbDev):
self.blockCounter += 1
# Count the number of block per area type,
# accumulate the block data size to compute the total device data size
mapping.nbBlock += 1
mapping.deviceDataSize += mapping.blockDataSize
return self.blockCounter
#xmlNode.shellPrintNode()
#!/usr/bin/python
# Copyright 2016 CERN and GSI
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from model.Class.Class import ParamClass
from model.Deploy.Controller import Controller
from Mapping import *
import libxml2
class ParamController(object):
def __init__(self):
self.hostName = ""
self.domain = ""
self.system = ""
self.model = ""
self.protocol = ""
self.brand = ""
self.address = { MEM_TYPE: int(-1), DI_TYPE: int(-1), DO_TYPE: int(-1), AI_TYPE: int(-1), AO_TYPE: int(-1) }
self.usedMem = ""
self.xmlNode = None
self.paramClasses = []
def initAttributes(self, xmlNode):
self.xmlNode = xmlNode
self.hostName = xmlNode.prop("plc-name")
self.domain = xmlNode.prop("domain")
self.system = self.xmlNode.prop('plc-system')
self.model = self.xmlNode.prop('plc-model')
self.protocol = self.xmlNode.prop('protocol')
self.brand = self.xmlNode.prop("plc-brand")
self.address[MEM_TYPE] = int(float(self.xmlNode.prop("address")))
self.address[DI_TYPE] = int(float(self.xmlNode.prop("DI-address")))
self.address[DO_TYPE] = int(float(self.xmlNode.prop("DO-address")))
self.address[AI_TYPE] = int(float(self.xmlNode.prop("AI-address")))
self.address[AO_TYPE] = int(float(self.xmlNode.prop("AO-address")))
self.usedMem = self.xmlNode.prop("used-mem")
def initFromXMLNode(self, xmlNode):
self.initAttributes(xmlNode)
for classNode in self.xmlNode.xpathEval('SILECS-Class'):
paramClass = ParamClass()
paramClass.initWithParamClassNode(classNode)
self.paramClasses.append(paramClass)
def initFromDeployController(self, controller):
newNode = libxml2.newNode("SILECS-Mapping")
newNode.newProp("plc-name", controller.hostName)
newNode.newProp("plc-brand", controller.brand)
newNode.newProp("plc-system", str(controller.system))
newNode.newProp("plc-model", controller.model)
newNode.newProp("protocol", controller.protocol)
newNode.newProp("address", str(int(controller.address[MEM_TYPE])))
newNode.newProp("DI-address", str(int(controller.address[DI_TYPE])))
newNode.newProp("DO-address", str(int(controller.address[DO_TYPE])))
newNode.newProp("AI-address", str(int(controller.address[AI_TYPE])))
newNode.newProp("AO-address", str(int(controller.address[AO_TYPE])))
newNode.newProp("domain", controller.domain)
newNode.newProp("used-mem", "TODO")
self.initAttributes(newNode)
def addParamClass(self,paramClass):
self.xmlNode.addChild(paramClass.xmlNode)
self.paramClasses.append(paramClass)
\ No newline at end of file
#!/usr/bin/python
# Copyright 2016 CERN and GSI
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import libxml2
import datetime
from model.Param.Controller import ParamController
class Param(object):
def __init__(self):
self.xmlNode = None
self.mappingNode = None
self.silecsVersion = ""
self.owner = ""
self.genDate = ""
self.checksum = 0
self.controller = None
self.deployName ="" #need to be explicitly set by codegen
self.deployVersion ="" #need to be explicitly set by codegen
def initBaseAttributes(self, paramDOM):
paramNodes = paramDOM.xpathEval('/SILECS-Param')
if len(paramNodes) != 1:
raise Exception( "Error: param-document is corrupt" )
self.xmlNode = paramNodes[0]
ownderNodes = self.xmlNode.xpathEval('Mapping-Info/Owner')
if len(ownderNodes) != 1:
raise Exception( "Error: param-document is corrupt" )
generationNodes = self.xmlNode.xpathEval('Mapping-Info/Generation')
if len(generationNodes) != 1:
raise Exception( "Error: param-document is corrupt" )
deploymentNodes = self.xmlNode.xpathEval('Mapping-Info/Deployment')
if len(deploymentNodes) != 1:
raise Exception( "Error: param-document is corrupt" )
self.silecsVersion = self.xmlNode.prop("silecs-version")
self.owner = ownderNodes[0].prop("user-login")
self.genDate = generationNodes[0].prop("date")
self.checksum = int(deploymentNodes[0].prop('checksum'))
def initFromXMLNode(self,paramDOM):
self.initBaseAttributes(paramDOM)
mappingNodes = self.xmlNode.xpathEval('SILECS-Mapping')
if len(mappingNodes) != 1:
raise Exception( "Error: param-document is corrupt" )
self.mappingNode = mappingNodes[0]
self.controller = ParamController()
self.controller.initFromXMLNode(self.mappingNode)
def addController(self,deployController):
if self.controller != None:
raise Exception("Cannot add controller '" + deployController.hostName + "'. A controller named '" + self.controller.hostName + "' is already registered")
paramController = ParamController()
paramController.initFromDeployController(deployController)
self.xmlNode.addChild(paramController.xmlNode)
self.controller = paramController
@staticmethod
def createParam(silecsVersion, owner, checksum):
paramDOM = libxml2.newDoc(version='1.0')
comment = libxml2.newComment("This file is auto generated by the SILECS framework tools. Code regeneration will overwrite it.")
paramDOM.addChild(comment)
rootNode = libxml2.newNode('SILECS-Param')
rootNode.setProp("silecs-version", silecsVersion)
paramDOM.addChild(rootNode)
paramMappingInfoNode = libxml2.newNode("Mapping-Info")
rootNode.addChild(paramMappingInfoNode)
paramOwnerNode = libxml2.newNode('Owner')
paramOwnerNode.setProp("user-login", owner)
paramMappingInfoNode.addChild(paramOwnerNode)
gen = libxml2.newNode('Generation')
currentDate = str(datetime.datetime.now())
gen.setProp("date",currentDate)
paramMappingInfoNode.addChild(gen)
deploy = libxml2.newNode('Deployment')
deploy.setProp("checksum", str(checksum))
paramMappingInfoNode.addChild(deploy)
param = Param()
param.initBaseAttributes(rootNode)
#param.mappingNode = libxml2.newNode('SILECS-Mapping')
#rootNode.addChild(param.mappingNode)
return param
......@@ -25,10 +25,13 @@
# Global definition
#=========================================================================
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
# Hash-Table
import string
whichSimaticFormat = {
'bool' : 'BOOL',
'uint8' : 'BYTE',
'int8' : 'CHAR',
'uint16' : 'WORD',
......@@ -41,96 +44,106 @@ whichSimaticFormat = {
# 'int64' : '8', not supported with PLC
# 'float64' : '8', not supported with PLC
'date' : 'DT',
'char' :'CHAR',
'byte' :'BYTE',
'word' :'WORD',
'dword' :'DWORD',
'int' :'INT',
'dint' :'DINT',
'real' :'REAL',
'dt' :'DT'}
'char' :'CHAR',
'byte' :'BYTE',
'word' :'WORD',
'dword' :'DWORD',
'int' :'INT',
'dint' :'DINT',
'real' :'REAL',
'dt' :'DT',
'dtl' :'DTL'
}
head = string.Template("""\r
(* ---------------------------------------------------------------------\r
* This file is auto generated by the SILECS framework tools. Code regeneration will overwrite it.\r
* ---------------------------------------------------------------------\r
*)\r
""")
#=========================================================================
# STL Source template (.scl file)
#=========================================================================
firstBlockUDT = """//---------------------------------------------------------------------\r
// %s/ v%s\r
// BLOCK Type definition\r
//---------------------------------------------------------------------\r
"""
blockUDT = """TYPE _%s_%s\r
AUTHOR: %s\r
FAMILY: SILECS\r
NAME: UDTB\r
STRUCT\r
%s
END_STRUCT;\r
#=========================================================================
firstBlockUDT = string.Template("""\r
(* ---------------------------------------------------------------------\r
* ${className}/ v${classVersion}\r
* BLOCK Type definition\r
* ---------------------------------------------------------------------\r
*)\r
""")
blockUDT = string.Template("""TYPE _${className}_${blockName}\r
AUTHOR: ${owner}\r
FAMILY: SILECS\r
NAME: UDTB\r
STRUCT\r
${regList}\r
END_STRUCT;\r
END_TYPE\r
\r
"""
regScalar = """ %s: %s%s;\r
"""
regArray = """ %s: ARRAY[0..%d] OF %s%s;\r
"""
regArray2d = """ %s: ARRAY[0..%d, 0..%d] OF %s%s;\r
"""
regFixedStringLen = """ %s: STRING[16]%s;\r
"""
firstBlock = """//---------------------------------------------------------------------\r
// %s/ v%s\r
// Block instance definition\r
//---------------------------------------------------------------------\r
"""
DB_TIAP = """DATA_BLOCK %s_%s\r
{ S7_Optimized_Access := 'FALSE' }\r
AUTHOR: %s\r
FAMILY: SILECS\r
NAME: %s\r
STRUCT\r %s
END_STRUCT;\r
BEGIN\r
\r
""")
regScalar = string.Template(""" ${regName}: ${len}${value};\r
""")
regArray = string.Template(""" ${regName}: ARRAY[0..${dim}] OF ${len}${value};\r
""")
regArray2d = string.Template(""" ${regName}: ARRAY[0..${dim1}, 0..${dim2}] OF ${len}${value};\r
""")
firstBlock = string.Template("""\r
(* ---------------------------------------------------------------------\r
* ${className}/ v${classVersion}\r
* BLOCK instance definition\r
* ---------------------------------------------------------------------\r
*)\r
""")
DB_TIAP = string.Template("""DATA_BLOCK ${className}_${blockName}${comment}\r
{ S7_Optimized_Access := 'FALSE' }\r
AUTHOR: ${owner}\r
FAMILY: SILECS\r
NAME: ${mode}\r
STRUCT\r
${blockList}\r
END_STRUCT;\r
BEGIN\r
END_DATA_BLOCK\r
\r
"""
\r
""")
DB_STEP7 = """// %s_%s ...........................................\r
DATA_BLOCK DB%s\r
DB_STEP7 = string.Template("""(* ${className}_${blockName} ...........................................*)\r
DATA_BLOCK DB${DBnumber}${comment}\r
{ S7_Optimized_Access := 'FALSE' }\r
AUTHOR: %s\r
AUTHOR: ${owner}\r
FAMILY: SILECS\r
NAME: %s\r
NAME: ${mode}\r
STRUCT\r
%s
${blockList}\r
END_STRUCT;\r
BEGIN\r
END_DATA_BLOCK\r
\r
"""
""")
device = string.Template(""" ${label}: _${className}_${blockName};\r
""")
device = """ %s: _%s_%s;
"""
device_with_comment = string.Template(""" ${label}: _${className}_${blockName}; //${comment}\r
""")
#=========================================================================
# SYMBOLS Source template (.sdf file)
#=========================================================================
diagSymbol = """"SILECS_HEADER",%s
"""
UDTSymbol = string.Template(""""_${className}_${blockName}","UDT ${number}","UDT ${number}","${comment}"
""")
UDTSymbol = """"_%s_%s","UDT %d","UDT %d","%s"
"""
DBSymbol = """"%s_%s","DB %d","DB %d","%s"
"""
DBSymbol = string.Template(""""${className}_${label}","DB ${number}","DB ${number}","${comment}"
""")
#=========================================================================
# Sub-function
......@@ -167,18 +180,18 @@ def stlRegister(regName, regFormat, regDim, regDim2, regVal, regLen=1):
if regLen > 1: # register is a string or an array of strings
strLen = whichSimaticFormat[regFormat]+'['+str(regLen)+']'
if regDim == 1 and regDim2 == 1: # scalar register
return regScalar %(regName, strLen, regVal)
return regScalar.substitute(regName=regName, len=strLen, value=regVal)
elif regDim > 1 and regDim2 == 1: # array register
return regArray %(regName, regDim-1, strLen, regVal)
return regArray.substitute(regName=regName, dim=regDim-1, len=strLen, value=regVal)
else: # dim1>=1 and for whatever dim2, use double array syntax
return regArray2d %(regName, regDim-1, regDim2-1, strLen, regVal)
return regArray2d.substitute(regName=regName, dim1=regDim-1, dim2=regDim2-1, len=strLen, value=regVal)
else:
if regDim == 1 and regDim2 == 1:
return regScalar %(regName, whichSimaticFormat[regFormat], regVal)
return regScalar.substitute(regName=regName, len=whichSimaticFormat[regFormat], value=regVal)
elif regDim > 1 and regDim2 == 1:
return regArray %(regName, regDim-1, whichSimaticFormat[regFormat], regVal)
return regArray.substitute(regName=regName, dim=regDim-1, len=whichSimaticFormat[regFormat], value=regVal)
else: # dim1>=1 and for whatever dim2, use double array syntax
return regArray2d %(regName, regDim-1, regDim2-1, whichSimaticFormat[regFormat], regVal)
return regArray2d.substitute(regName=regName, dim1=regDim-1, dim2=regDim2-1, len=whichSimaticFormat[regFormat], value=regVal)
#This method is used to add default value to the diagnostic registers
def stlRegisterValue(regName, owner, date, checksum, silecsversion):
......@@ -191,37 +204,42 @@ def stlRegisterValue(regName, owner, date, checksum, silecsversion):
# BLOCK type definition (UDT) --------------------------------------------
def stlBlockUDT(owner, className, classVersion, blockName, regList, isFirst):
if isFirst:
return firstBlockUDT %(className, classVersion) + blockUDT %(className, blockName, owner, regList)
return firstBlockUDT.substitute(className=className, classVersion=classVersion) + blockUDT.substitute(className=className, blockName=blockName, owner=owner, regList=regList)
else:
return blockUDT %(className, blockName, owner, regList)
return blockUDT.substitute(className=className, blockName=blockName, owner=owner, regList=regList)
# BLOCK_MODE: data-block instance ----------------------------------------
def stlDevice(devLabel, className, blockName):
return device %(devLabel, className, blockName)
def stlDevice(devLabel, className, blockName, fesaName):
if fesaName == "":
return device.substitute(label=devLabel, className=className, blockName=blockName)
return device_with_comment.substitute(label=devLabel, className=className, blockName=blockName, comment=fesaName)
# DEVICE_MODE: data-block instance ---------------------------------------
def stlBlock(className, blockName):
return device %(blockName, className, blockName)
return device.substitute(label=blockName, className=className, blockName=blockName)
def generateBlock(owner, className, classVersion, system, DBnumber, blockName, blockList, isFirst, protocol):
def generateBlock(owner, className, classVersion, system, DBnumber, blockName, blockList, isFirst, protocol, fesaName):
srcCore = ""
mode = ''
mode = ''
comment = ''
if protocol == 'BLOCK_MODE':
mode = 'BLK_MODE'
elif protocol == 'DEVICE_MODE':
mode = 'DEV_MODE'
if fesaName != "":
comment = " //" + fesaName
else:
raise Exception( "Unknown PLC-protocol defined: " + protocol )
if (system == 'TIA-PORTAL'):
srcCore = DB_TIAP %(className, blockName, owner, mode, blockList)
srcCore = DB_TIAP.substitute(className=className, blockName=blockName, owner=owner, mode=mode, blockList=blockList, comment=comment)
elif (system == 'STEP-7'):
srcCore = DB_STEP7 %(className, blockName, DBnumber, owner, mode, blockList)
srcCore = DB_STEP7.substitute(className=className, blockName=blockName, DBnumber=DBnumber, owner=owner, mode=mode, blockList=blockList, comment=comment)
else:
raise Exception( "Unknown PLC-system defined: " + system )
if isFirst:
return firstBlock %(className, classVersion) + srcCore
return firstBlock.substitute(className=className, classVersion=classVersion) + srcCore
else:
return srcCore
......@@ -237,16 +255,16 @@ def symHeader(baseAddress):
def symBlockUDT(className, classVersion, blockName, number, isFirst):
comment = ''
if isFirst: comment = "[%s/%s] UDT symbol: _<class-name>_<block-name>" %(className, classVersion)
return UDTSymbol %(className, blockName, number, number, comment)
return UDTSymbol.substitute(className=className, blockName=blockName, number=number, comment=comment)
# BLOCK_MODE: data-block symbol ----------------------------
def symBlockDB(className, classVersion, blockName, number, isFirst):
comment = ''
if isFirst: comment = "[%s/%s] DB symbol: <class-name>_<block-name>" %(className, classVersion)
return DBSymbol %(className, blockName, number, number, comment)
return DBSymbol.substitute(className=className, label=blockName, number=number, comment=comment)
# DEVICE_MODE : data-block symbol ----------------------------
def symDeviceDB(className, classVersion, deviceLabel, number, isFirst):
comment = ''
if isFirst: comment = "[%s/%s] DB symbol: <class-name>_<device-label | device-id>" %(className, classVersion)
return DBSymbol %(className, deviceLabel, number, number, comment)
return DBSymbol.substitute(className=className, label=deviceLabel, number=number, comment=comment)
......@@ -5,173 +5,298 @@
<Editor user-login="schwinn"/>
</Information>
<SILECS-Class name="AllTypes" version="0.1.0" domain="OPERATIONAL">
<Acquisition-Block name="MyROBlock" generateFesaProperty="true" fesaPropertyName="MyROBlockProp">
<Acquisition-Register name="RO_int8" generateFesaValueItem="true">
<scalar format="int8"/>
</Acquisition-Register>
<Acquisition-Register name="RO_uint8" generateFesaValueItem="true" fesaFieldName="RO_uint8_fesa">
<scalar format="uint8"/>
</Acquisition-Register>
<Acquisition-Register name="RO_int16" generateFesaValueItem="true" fesaFieldName="RO_int16_fesa">
<scalar format="int16"/>
</Acquisition-Register>
<Acquisition-Register name="RO_uint16" generateFesaValueItem="true" fesaFieldName="RO_uint16_fesa">
<scalar format="uint16"/>
</Acquisition-Register>
<Acquisition-Register name="RO_int32" generateFesaValueItem="true" fesaFieldName="RO_int32_fesa">
<scalar format="int32"/>
</Acquisition-Register>
<Acquisition-Register name="RO_uint32" generateFesaValueItem="true" fesaFieldName="RO_uint32_fesa">
<scalar format="uint32"/>
</Acquisition-Register>
<!--<Register name="RO_int64" format="int64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RO_int64_fesa"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<!--<Register name="RO_uint64" format="uint64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RO_uint64_fesa"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<Acquisition-Register name="RO_float32" generateFesaValueItem="true" fesaFieldName="RO_float32_fesa">
<scalar format="float32"/>
</Acquisition-Register>
<!--<Register name="RO_float64" format="float64" synchro="MASTER" generateFesaValueItem="true" esaFieldName="RO_float64_fesa"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<Acquisition-Register name="RO_string" generateFesaValueItem="true" fesaFieldName="RO_string_fesa">
<string string-length="64" format="string"/>
</Acquisition-Register>
<Acquisition-Register name="RO_date" generateFesaValueItem="true" fesaFieldName="RO_date_fesa">
<scalar format="date"/>
</Acquisition-Register>
<Acquisition-Register name="RO_char" generateFesaValueItem="true" fesaFieldName="RO_char_fesa">
<scalar format="char"/>
</Acquisition-Register>
<Acquisition-Register name="RO_byte" generateFesaValueItem="true" fesaFieldName="RO_byte_fesa">
<scalar format="byte"/>
</Acquisition-Register>
<Acquisition-Register name="RO_word" generateFesaValueItem="true" fesaFieldName="RO_word_fesa">
<scalar format="word"/>
</Acquisition-Register>
<Acquisition-Register name="RO_dword" generateFesaValueItem="true" fesaFieldName="RO_dword_fesa">
<scalar format="dword"/>
</Acquisition-Register>
<Acquisition-Register name="RO_int" generateFesaValueItem="true" fesaFieldName="RO_int_fesa">
<scalar format="int"/>
</Acquisition-Register>
<Acquisition-Register name="RO_dint" generateFesaValueItem="true" fesaFieldName="RO_dint_fesa">
<scalar format="dint"/>
</Acquisition-Register>
<Acquisition-Register name="RO_real" generateFesaValueItem="true" fesaFieldName="RO_real_fesa">
<scalar format="real"/>
</Acquisition-Register>
<Acquisition-Register name="RO_dt" generateFesaValueItem="true" fesaFieldName="RO_dt_fesa">
<scalar format="dt"/>
</Acquisition-Register>
</Acquisition-Block>
<Setting-Block name="MyRWBlock" generateFesaProperty="true" fesaPropertyName="MyRWBlockProp">
<Volatile-Register name="RW_int8" generateFesaValueItem="true">
<array2D dim1="2" dim2="2" format="int8"/>
</Volatile-Register>
<Volatile-Register name="RW_uint8" generateFesaValueItem="true" fesaFieldName="RW_uint8_fesa">
<array2D dim1="2" dim2="2" format="uint8"/>
</Volatile-Register>
<Volatile-Register name="RW_int16" generateFesaValueItem="true" fesaFieldName="RW_int16_fesa">
<array2D dim1="2" dim2="2" format="int16"/>
</Volatile-Register>
<Volatile-Register name="RW_uint16" generateFesaValueItem="true" fesaFieldName="RW_uint16_fesa">
<array2D dim1="2" dim2="2" format="uint16"/>
</Volatile-Register>
<Volatile-Register name="RW_int32" generateFesaValueItem="true" fesaFieldName="RW_int32_fesa">
<array2D dim1="2" dim2="2" format="int32"/>
</Volatile-Register>
<Volatile-Register name="RW_uint32" generateFesaValueItem="true" fesaFieldName="RW_uint32_fesa">
<array2D dim1="2" dim2="2" format="uint32"/>
</Volatile-Register>
<!--<Register name="RW_int64" format="int64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RW_int64_fesa" array-dim1="2" array-dim2="2"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<!--<Register name="RW_uint64" format="uint64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RW_uint64_fesa" array-dim1="2" array-dim2="2"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<Volatile-Register name="RW_float32" generateFesaValueItem="true" fesaFieldName="RW_float32_fesa">
<array2D dim1="2" dim2="2" format="float32"/>
</Volatile-Register>
<!--<Register name="RW_float64" format="float64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RW_float64_fesa" array-dim1="2" array-dim2="2"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<Volatile-Register name="RW_string" generateFesaValueItem="true" fesaFieldName="RW_string_fesa">
<stringArray2D dim1="2" dim2="2" string-length="64" format="string"/>
</Volatile-Register>
<Volatile-Register name="RW_date" generateFesaValueItem="true" fesaFieldName="RW_date_fesa">
<array2D dim1="2" dim2="2" format="date"/>
</Volatile-Register>
<Volatile-Register name="RW_char" generateFesaValueItem="true" fesaFieldName="RW_char_fesa">
<array2D dim1="2" dim2="2" format="char"/>
</Volatile-Register>
<Volatile-Register name="RW_byte" generateFesaValueItem="true" fesaFieldName="RW_byte_fesa">
<array2D dim1="2" dim2="2" format="byte"/>
</Volatile-Register>
<Volatile-Register name="RW_word" generateFesaValueItem="true" fesaFieldName="RW_word_fesa">
<array2D dim1="2" dim2="2" format="word"/>
</Volatile-Register>
<Volatile-Register name="RW_dword" generateFesaValueItem="true" fesaFieldName="RW_dword_fesa">
<array2D dim1="2" dim2="2" format="dword"/>
</Volatile-Register>
<Volatile-Register name="RW_int" generateFesaValueItem="true" fesaFieldName="RW_int_fesa">
<array2D dim1="2" dim2="2" format="int"/>
</Volatile-Register>
<Volatile-Register name="RW_dint" generateFesaValueItem="true" fesaFieldName="RW_dint_fesa">
<array2D dim1="2" dim2="2" format="dint"/>
</Volatile-Register>
<Volatile-Register name="RW_real" generateFesaValueItem="true" fesaFieldName="RW_real_fesa">
<array2D dim1="2" dim2="2" format="real"/>
</Volatile-Register>
<Volatile-Register name="RW_dt" generateFesaValueItem="true" fesaFieldName="RW_dt_fesa">
<array2D dim1="2" dim2="2" format="dt"/>
</Volatile-Register>
</Setting-Block>
<Command-Block name="MyWOBlock" generateFesaProperty="true" fesaPropertyName="MyWOBlockProp">
<Setting-Register name="WO_int8" generateFesaValueItem="true">
<array dim="10" format="int8"/>
</Setting-Register>
<Setting-Register name="WO_uint8" generateFesaValueItem="true" fesaFieldName="WO_uint8_fesa">
<array dim="10" format="uint8"/>
</Setting-Register>
<Setting-Register name="WO_int16" generateFesaValueItem="true" fesaFieldName="WO_int16_fesa">
<array dim="10" format="int16"/>
</Setting-Register>
<Setting-Register name="WO_uint16" generateFesaValueItem="true" fesaFieldName="WO_uint16_fesa">
<array dim="10" format="uint16"/>
</Setting-Register>
<Setting-Register name="WO_int32" generateFesaValueItem="true" fesaFieldName="WO_int32_fesa">
<array dim="10" format="int32"/>
</Setting-Register>
<Setting-Register name="WO_uint32" generateFesaValueItem="true" fesaFieldName="WO_uint32_fesa">
<array dim="10" format="uint32"/>
</Setting-Register>
<!--<Register name="WO_int64" format="int64" synchro="SLAVE" generateFesaValueItem="true" fesaFieldName="WO_int64_fesa" array-dim1="10"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<!--<Register name="WO_uint64" format="uint64" synchro="SLAVE" generateFesaValueItem="true" fesaFieldName="WO_uint64_fesa" array-dim1="10"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<Setting-Register name="WO_float32" generateFesaValueItem="true" fesaFieldName="WO_float32_fesa">
<array dim="10" format="float32"/>
</Setting-Register>
<!--<Register name="WO_float64" format="float64" synchro="SLAVE" generateFesaValueItem="true" fesaFieldName="WO_float64_fesa" array-dim1="10"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<Setting-Register name="WO_string" generateFesaValueItem="true" fesaFieldName="WO_string_fesa">
<stringArray dim="10" string-length="64" format="string"/>
</Setting-Register>
<Setting-Register name="WO_date" generateFesaValueItem="true" fesaFieldName="WO_date_fesa">
<array dim="10" format="date"/>
</Setting-Register>
<Setting-Register name="WO_char" generateFesaValueItem="true" fesaFieldName="WO_char_fesa">
<array dim="10" format="char"/>
</Setting-Register>
<Setting-Register name="WO_byte" generateFesaValueItem="true" fesaFieldName="WO_byte_fesa">
<array dim="10" format="byte"/>
</Setting-Register>
<Setting-Register name="WO_word" generateFesaValueItem="true" fesaFieldName="WO_word_fesa">
<array dim="10" format="word"/>
</Setting-Register>
<Setting-Register name="WO_dword" generateFesaValueItem="true" fesaFieldName="WO_dword_fesa">
<array dim="10" format="dword"/>
</Setting-Register>
<Setting-Register name="WO_int" generateFesaValueItem="true" fesaFieldName="WO_int_fesa">
<array dim="10" format="int"/>
</Setting-Register>
<Setting-Register name="WO_dint" generateFesaValueItem="true" fesaFieldName="WO_dint_fesa">
<array dim="10" format="dint"/>
</Setting-Register>
<Setting-Register name="WO_real" generateFesaValueItem="true" fesaFieldName="WO_real_fesa">
<array dim="10" format="real"/>
</Setting-Register>
<Setting-Register name="WO_dt" generateFesaValueItem="true" fesaFieldName="WO_dt_fesa">
<array dim="10" format="dt"/>
</Setting-Register>
</Command-Block>
<Acquisition-Block name="MyROBlock" generateFesaProperty="true" fesaPropertyName="MyROBlockProp">
<Acquisition-Register name="RO_int8" generateFesaValueItem="true">
<scalar format="int8"/>
</Acquisition-Register>
<Acquisition-Register name="RO_uint8" generateFesaValueItem="true" fesaFieldName="RO_uint8_fesa">
<scalar format="uint8"/>
</Acquisition-Register>
<Acquisition-Register name="RO_int16" generateFesaValueItem="true" fesaFieldName="RO_int16_fesa">
<scalar format="int16"/>
</Acquisition-Register>
<Acquisition-Register name="RO_uint16" generateFesaValueItem="true" fesaFieldName="RO_uint16_fesa">
<scalar format="uint16"/>
</Acquisition-Register>
<Acquisition-Register name="RO_int32" generateFesaValueItem="true" fesaFieldName="RO_int32_fesa">
<scalar format="int32"/>
</Acquisition-Register>
<Acquisition-Register name="RO_uint32" generateFesaValueItem="true" fesaFieldName="RO_uint32_fesa">
<scalar format="uint32"/>
</Acquisition-Register>
<!--<Register name="RO_int64" format="int64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RO_int64_fesa"/> not Supported for Beckhoff, Siemens and Schneider -->
<!--<Register name="RO_uint64" format="uint64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RO_uint64_fesa"/> not Supported for Beckhoff, Siemens and Schneider -->
<Acquisition-Register name="RO_float32" generateFesaValueItem="true" fesaFieldName="RO_float32_fesa">
<scalar format="float32"/>
</Acquisition-Register>
<!--<Register name="RO_float64" format="float64" synchro="MASTER" generateFesaValueItem="true" esaFieldName="RO_float64_fesa"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<Acquisition-Register name="RO_string" generateFesaValueItem="true" fesaFieldName="RO_string_fesa">
<string string-length="64" format="string"/>
</Acquisition-Register>
<Acquisition-Register name="RO_date" generateFesaValueItem="true" fesaFieldName="RO_date_fesa">
<scalar format="date"/>
</Acquisition-Register>
<Acquisition-Register name="RO_char" generateFesaValueItem="true" fesaFieldName="RO_char_fesa">
<scalar format="char"/>
</Acquisition-Register>
<Acquisition-Register name="RO_byte" generateFesaValueItem="true" fesaFieldName="RO_byte_fesa">
<scalar format="byte"/>
</Acquisition-Register>
<Acquisition-Register name="RO_word" generateFesaValueItem="true" fesaFieldName="RO_word_fesa">
<scalar format="word"/>
</Acquisition-Register>
<Acquisition-Register name="RO_dword" generateFesaValueItem="true" fesaFieldName="RO_dword_fesa">
<scalar format="dword"/>
</Acquisition-Register>
<Acquisition-Register name="RO_int" generateFesaValueItem="true" fesaFieldName="RO_int_fesa">
<scalar format="int"/>
</Acquisition-Register>
<Acquisition-Register name="RO_dint" generateFesaValueItem="true" fesaFieldName="RO_dint_fesa">
<scalar format="dint"/>
</Acquisition-Register>
<Acquisition-Register name="RO_real" generateFesaValueItem="true" fesaFieldName="RO_real_fesa">
<scalar format="real"/>
</Acquisition-Register>
<Acquisition-Register name="RO_dt" generateFesaValueItem="true" fesaFieldName="RO_dt_fesa">
<scalar format="dt"/>
</Acquisition-Register>
<Acquisition-Register name="RO_enum" generateFesaValueItem="true" fesaFieldName="RO_enum_fesa">
<custom-type-scalar custom-type-name-ref="TEST_ENUM"/>
</Acquisition-Register>
</Acquisition-Block>
<Setting-Block name="MyRWBlock" generateFesaProperty="true" fesaPropertyName="MyRWBlockProp">
<Setting-Register name="RW_int8" generateFesaValueItem="true">
<scalar format="int8"/>
</Setting-Register>
<Setting-Register name="RW_uint8" generateFesaValueItem="true" fesaFieldName="RW_uint8_fesa">
<scalar format="uint8"/>
</Setting-Register>
<Setting-Register name="RW_int16" generateFesaValueItem="true" fesaFieldName="RW_int16_fesa">
<scalar format="int16"/>
</Setting-Register>
<Setting-Register name="RW_uint16" generateFesaValueItem="true" fesaFieldName="RW_uint16_fesa">
<scalar format="uint16"/>
</Setting-Register>
<Setting-Register name="RW_int32" generateFesaValueItem="true" fesaFieldName="RW_int32_fesa">
<scalar format="int32"/>
</Setting-Register>
<Setting-Register name="RW_uint32" generateFesaValueItem="true" fesaFieldName="RW_uint32_fesa">
<scalar format="uint32"/>
</Setting-Register>
<!--<Register name="RW_int64" format="int64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RW_int64_fesa"/> not Supported for Beckhoff, Siemens and Schneider -->
<!--<Register name="RW_uint64" format="uint64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RW_uint64_fesa"/> not Supported for Beckhoff, Siemens and Schneider -->
<Setting-Register name="RW_float32" generateFesaValueItem="true" fesaFieldName="RW_float32_fesa">
<scalar format="float32"/>
</Setting-Register>
<!--<Register name="RW_float64" format="float64" synchro="MASTER" generateFesaValueItem="true" esaFieldName="RW_float64_fesa"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<Setting-Register name="RW_string" generateFesaValueItem="true" fesaFieldName="RW_string_fesa">
<string string-length="64" format="string"/>
</Setting-Register>
<Setting-Register name="RW_date" generateFesaValueItem="true" fesaFieldName="RW_date_fesa">
<scalar format="date"/>
</Setting-Register>
<Setting-Register name="RW_char" generateFesaValueItem="true" fesaFieldName="RW_char_fesa">
<scalar format="char"/>
</Setting-Register>
<Setting-Register name="RW_byte" generateFesaValueItem="true" fesaFieldName="RW_byte_fesa">
<scalar format="byte"/>
</Setting-Register>
<Setting-Register name="RW_word" generateFesaValueItem="true" fesaFieldName="RW_word_fesa">
<scalar format="word"/>
</Setting-Register>
<Setting-Register name="RW_dword" generateFesaValueItem="true" fesaFieldName="RW_dword_fesa">
<scalar format="dword"/>
</Setting-Register>
<Setting-Register name="RW_int" generateFesaValueItem="true" fesaFieldName="RW_int_fesa">
<scalar format="int"/>
</Setting-Register>
<Setting-Register name="RW_dint" generateFesaValueItem="true" fesaFieldName="RW_dint_fesa">
<scalar format="dint"/>
</Setting-Register>
<Setting-Register name="RW_real" generateFesaValueItem="true" fesaFieldName="RW_real_fesa">
<scalar format="real"/>
</Setting-Register>
<Setting-Register name="RW_dt" generateFesaValueItem="true" fesaFieldName="RW_dt_fesa">
<scalar format="dt"/>
</Setting-Register>
<Setting-Register name="RW2_int8" generateFesaValueItem="true">
<array2D dim1="2" dim2="2" format="int8"/>
</Setting-Register>
<Setting-Register name="RW2_uint8" generateFesaValueItem="true" fesaFieldName="RW2_uint8_fesa">
<array2D dim1="2" dim2="2" format="uint8"/>
</Setting-Register>
<Setting-Register name="RW2_int16" generateFesaValueItem="true" fesaFieldName="RW2_int16_fesa">
<array2D dim1="2" dim2="2" format="int16"/>
</Setting-Register>
<Setting-Register name="RW2_uint16" generateFesaValueItem="true" fesaFieldName="RW2_uint16_fesa">
<array2D dim1="2" dim2="2" format="uint16"/>
</Setting-Register>
<Setting-Register name="RW2_int32" generateFesaValueItem="true" fesaFieldName="RW2_int32_fesa">
<array2D dim1="2" dim2="2" format="int32"/>
</Setting-Register>
<Setting-Register name="RW2_uint32" generateFesaValueItem="true" fesaFieldName="RW2_uint32_fesa">
<array2D dim1="2" dim2="2" format="uint32"/>
</Setting-Register>
<!-- <Register name="RW_int64" format="int64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RW_int64_fesa" array-dim1="2" array-dim2="2"/> not Supported for Beckhoff, Siemens and Schneider -->
<!--<Register name="RW_uint64" format="uint64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RW_uint64_fesa" array-dim1="2" array-dim2="2"/> not Supported for Beckhoff, Siemens and Schneider -->
<Setting-Register name="RW2_float32" generateFesaValueItem="true" fesaFieldName="RW2_float32_fesa">
<array2D dim1="2" dim2="2" format="float32"/>
</Setting-Register>
<!--<Register name="RW_float64" format="float64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RW_float64_fesa" array-dim1="2" array-dim2="2"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<!-- <Register name="RW_string" format="string" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RW_string_fesa" array-dim1="2" array-dim2="2"/> 2d string arrays not supported in FESA -->
<Setting-Register name="RW2_date" generateFesaValueItem="true" fesaFieldName="RW2_date_fesa">
<array2D dim1="2" dim2="2" format="date"/>
</Setting-Register>
<Setting-Register name="RW2_char" generateFesaValueItem="true" fesaFieldName="RW2_char_fesa">
<array2D dim1="2" dim2="2" format="char"/>
</Setting-Register>
<Setting-Register name="RW2_byte" generateFesaValueItem="true" fesaFieldName="RW2_byte_fesa">
<array2D dim1="2" dim2="2" format="byte"/>
</Setting-Register>
<Setting-Register name="RW2_word" generateFesaValueItem="true" fesaFieldName="RW2_word_fesa">
<array2D dim1="2" dim2="2" format="word"/>
</Setting-Register>
<Setting-Register name="RW2_dword" generateFesaValueItem="true" fesaFieldName="RW2_dword_fesa">
<array2D dim1="2" dim2="2" format="dword"/>
</Setting-Register>
<Setting-Register name="RW2_int" generateFesaValueItem="true" fesaFieldName="RW2_int_fesa">
<array2D dim1="2" dim2="2" format="int"/>
</Setting-Register>
<Setting-Register name="RW2_dint" generateFesaValueItem="true" fesaFieldName="RW2_dint_fesa">
<array2D dim1="2" dim2="2" format="dint"/>
</Setting-Register>
<Setting-Register name="RW2_real" generateFesaValueItem="true" fesaFieldName="RW2_real_fesa">
<array2D dim1="2" dim2="2" format="real"/>
</Setting-Register>
<Setting-Register name="RW2_dt" generateFesaValueItem="true" fesaFieldName="RW2_dt_fesa">
<array2D dim1="2" dim2="2" format="dt"/>
</Setting-Register>
<Setting-Register name="RW_enum" generateFesaValueItem="true" fesaFieldName="RW_enum_fesa">
<custom-type-scalar custom-type-name-ref="TEST_ENUM"/>
</Setting-Register>
</Setting-Block>
<Command-Block name="MyWOBlock" generateFesaProperty="true" fesaPropertyName="MyWOBlockProp">
<Setting-Register name="WO_int8" generateFesaValueItem="true">
<array dim="10" format="int8"/>
</Setting-Register>
<Setting-Register name="WO_uint8" generateFesaValueItem="true" fesaFieldName="WO_uint8_fesa">
<array dim="10" format="uint8"/>
</Setting-Register>
<Setting-Register name="WO_int16" generateFesaValueItem="true" fesaFieldName="WO_int16_fesa">
<array dim="10" format="int16"/>
</Setting-Register>
<Setting-Register name="WO_uint16" generateFesaValueItem="true" fesaFieldName="WO_uint16_fesa">
<array dim="10" format="uint16"/>
</Setting-Register>
<Setting-Register name="WO_int32" generateFesaValueItem="true" fesaFieldName="WO_int32_fesa">
<array dim="10" format="int32"/>
</Setting-Register>
<Setting-Register name="WO_uint32" generateFesaValueItem="true" fesaFieldName="WO_uint32_fesa">
<array dim="10" format="uint32"/>
</Setting-Register>
<!--<Register name="WO_int64" format="int64" synchro="SLAVE" generateFesaValueItem="true" fesaFieldName="WO_int64_fesa" array-dim1="10"/> not Supported for Beckhoff, Siemens and Schneider -->
<!--<Register name="WO_uint64" format="uint64" synchro="SLAVE" generateFesaValueItem="true" fesaFieldName="WO_uint64_fesa" array-dim1="10"/> not Supported for Beckhoff, Siemens and Schneider -->
<Setting-Register name="WO_float32" generateFesaValueItem="true" fesaFieldName="WO_float32_fesa">
<array dim="10" format="float32"/>
</Setting-Register>
<!--<Register name="WO_float64" format="float64" synchro="SLAVE" generateFesaValueItem="true" fesaFieldName="WO_float64_fesa" array-dim1="10"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<Setting-Register name="WO_string" generateFesaValueItem="true" fesaFieldName="WO_string_fesa">
<stringArray dim="10" string-length="64" format="string"/>
</Setting-Register>
<Setting-Register name="WO_date" generateFesaValueItem="true" fesaFieldName="WO_date_fesa">
<array dim="10" format="date"/>
</Setting-Register>
<Setting-Register name="WO_char" generateFesaValueItem="true" fesaFieldName="WO_char_fesa">
<array dim="10" format="char"/>
</Setting-Register>
<Setting-Register name="WO_byte" generateFesaValueItem="true" fesaFieldName="WO_byte_fesa">
<array dim="10" format="byte"/>
</Setting-Register>
<Setting-Register name="WO_word" generateFesaValueItem="true" fesaFieldName="WO_word_fesa">
<array dim="10" format="word"/>
</Setting-Register>
<Setting-Register name="WO_dword" generateFesaValueItem="true" fesaFieldName="WO_dword_fesa">
<array dim="10" format="dword"/>
</Setting-Register>
<Setting-Register name="WO_int" generateFesaValueItem="true" fesaFieldName="WO_int_fesa">
<array dim="10" format="int"/>
</Setting-Register>
<Setting-Register name="WO_dint" generateFesaValueItem="true" fesaFieldName="WO_dint_fesa">
<array dim="10" format="dint"/>
</Setting-Register>
<Setting-Register name="WO_real" generateFesaValueItem="true" fesaFieldName="WO_real_fesa">
<array dim="10" format="real"/>
</Setting-Register>
<Setting-Register name="WO_dt" generateFesaValueItem="true" fesaFieldName="WO_dt_fesa">
<array dim="10" format="dt"/>
</Setting-Register>
<Setting-Register name="WO_enum" generateFesaValueItem="true" fesaFieldName="WO_enum_fesa">
<custom-type-array dim="10" custom-type-name-ref="TEST_ENUM"/>
</Setting-Register>
</Command-Block>
<Configuration-Block name="MyCBlock" generateFesaProperty="true" fesaPropertyName="MyCBlockProp">
<Configuration-Register name="C_int8" generateFesaValueItem="true">
<array2D dim1="2" dim2="2" format="int8"/>
</Configuration-Register>
<Configuration-Register name="C_uint8" generateFesaValueItem="true" fesaFieldName="C_uint8_fesa">
<array2D dim1="2" dim2="2" format="uint8"/>
</Configuration-Register>
<Configuration-Register name="C_int16" generateFesaValueItem="true" fesaFieldName="C_int16_fesa">
<array2D dim1="2" dim2="2" format="int16"/>
</Configuration-Register>
<Configuration-Register name="C_uint16" generateFesaValueItem="true" fesaFieldName="C_uint16_fesa">
<array2D dim1="2" dim2="2" format="uint16"/>
</Configuration-Register>
<Configuration-Register name="C_int32" generateFesaValueItem="true" fesaFieldName="C_int32_fesa">
<array2D dim1="2" dim2="2" format="int32"/>
</Configuration-Register>
<Configuration-Register name="C_uint32" generateFesaValueItem="true" fesaFieldName="C_uint32_fesa">
<array2D dim1="2" dim2="2" format="uint32"/>
</Configuration-Register>
<!--<Register name="C_int64" format="int64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="C_int64_fesa" array-dim1="2" array-dim2="2"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<!--<Register name="C_uint64" format="uint64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="C_uint64_fesa" array-dim1="2" array-dim2="2"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<Configuration-Register name="C_float32" generateFesaValueItem="true" fesaFieldName="C_float32_fesa">
<array2D dim1="2" dim2="2" format="float32"/>
</Configuration-Register>
<!--<Register name="C_float64" format="float64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="C_float64_fesa" array-dim1="2" array-dim2="2"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<Configuration-Register name="C_string" generateFesaValueItem="true" fesaFieldName="C_string_fesa">
<stringArray2D dim1="2" dim2="2" string-length="64" format="string"/>
</Configuration-Register>
<Configuration-Register name="C_date" generateFesaValueItem="true" fesaFieldName="C_date_fesa">
<array2D dim1="2" dim2="2" format="date"/>
</Configuration-Register>
<Configuration-Register name="C_char" generateFesaValueItem="true" fesaFieldName="C_char_fesa">
<array2D dim1="2" dim2="2" format="char"/>
</Configuration-Register>
<Configuration-Register name="C_byte" generateFesaValueItem="true" fesaFieldName="C_byte_fesa">
<array2D dim1="2" dim2="2" format="byte"/>
</Configuration-Register>
<Configuration-Register name="C_word" generateFesaValueItem="true" fesaFieldName="C_word_fesa">
<array2D dim1="2" dim2="2" format="word"/>
</Configuration-Register>
<Configuration-Register name="C_dword" generateFesaValueItem="true" fesaFieldName="C_dword_fesa">
<array2D dim1="2" dim2="2" format="dword"/>
</Configuration-Register>
<Configuration-Register name="C_int" generateFesaValueItem="true" fesaFieldName="C_int_fesa">
<array2D dim1="2" dim2="2" format="int"/>
</Configuration-Register>
<Configuration-Register name="C_dint" generateFesaValueItem="true" fesaFieldName="C_dint_fesa">
<array2D dim1="2" dim2="2" format="dint"/>
</Configuration-Register>
<Configuration-Register name="C_real" generateFesaValueItem="true" fesaFieldName="C_real_fesa">
<array2D dim1="2" dim2="2" format="real"/>
</Configuration-Register>
<Configuration-Register name="C_dt" generateFesaValueItem="true" fesaFieldName="C_dt_fesa">
<array2D dim1="2" dim2="2" format="dt"/>
</Configuration-Register>
</Configuration-Block>
<custom-types>
<enum name="TEST_ENUM">
<item access="RW" value="0" symbol="OK" />
<item access="RW" value="1" symbol="WARNING" />
<item access="RW" value="2" symbol="ERROR" />
<item access="RW" value="3" symbol="UNKNOWN" />
</enum>
</custom-types>
</SILECS-Class>
</SILECS-Design>
......@@ -5,21 +5,19 @@
<Editor user-login="schwinn" />
</Information>
<Deploy-Unit name="AllTypesDU" version="0.1.0" />
<SilecsDesign silecs-design-version="0.1.0" silecs-design-name="AllTypes">
<SilecsDesign silecs-design-version="0.1.0" silecs-design-name="AllTypes"/>
</SilecsDesign>
<Controller host-name="Siemens_TiaDevice">
<Siemens-PLC model="SIMATIC_S7-300" system="TIA-PORTAL" base-DB-number="0" protocol="DEVICE_MODE">
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice1" />
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice2" />
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice1" fesa-device-name="FESA_NAME1"/>
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice2" fesa-device-name="FESA_NAME2"/>
</Siemens-PLC>
</Controller>
<Controller host-name="Siemens_TiaBlock">
<Siemens-PLC model="SIMATIC_S7-300" system="TIA-PORTAL" base-DB-number="0" protocol="BLOCK_MODE">
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice1" />
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice2" />
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice1" fesa-device-name="FESA_NAME1" />
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice2" fesa-device-name="FESA_NAME2" />
</Siemens-PLC>
</Controller>
......@@ -37,36 +35,39 @@
</Siemens-PLC>
</Controller>
<Controller host-name="Virtual_SiemensDevice">
<Virtual-Controller model="SIMATIC_S7-VIRTUAL" system="SNAP7 linux32" base-DB-number="0" protocol="DEVICE_MODE">
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice1" />
<Virtual-Controller model="SIMATIC_S7-VIRTUAL" system="SNAP7 linux32" protocol="DEVICE_MODE" base-address="0">
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice1" />
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice2" />
</Virtual-Controller>
</Virtual-Controller>
</Controller>
<Controller host-name="Virtual_SiemensBlock">
<Virtual-Controller model="SIMATIC_S7-VIRTUAL" system="SNAP7 linux32" base-DB-number="0" protocol="BLOCK_MODE">
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice1" />
<Virtual-Controller model="SIMATIC_S7-VIRTUAL" system="SNAP7 linux32" protocol="BLOCK_MODE" base-address="0">
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice1" />
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice2" />
</Virtual-Controller>
</Virtual-Controller>
</Controller>
<Controller host-name="Beckhoff_BC9020">
<Beckhoff-PLC model="BC9020" system="TWINCat" protocol="BLOCK_MODE" base-address="0">
<Beckhoff-PLC model="BC9020" system="TWINCat-2" protocol="BLOCK_MODE" base-address="0">
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice1" />
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice2" />
</Beckhoff-PLC>
</Controller>
<Controller host-name="Beckhoff_CX9020">
<Beckhoff-PLC model="CX9020" system="TWINCat" protocol="BLOCK_MODE" base-address="0">
<Controller host-name="Beckhoff_CX9020_TC2">
<Beckhoff-PLC model="CX9020" system="TWINCat-2" protocol="BLOCK_MODE" base-address="0">
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice1" />
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice2" />
</Beckhoff-PLC>
</Controller>
<Controller host-name="Beckhoff_CX9020_TC3">
<Beckhoff-PLC model="CX9020" system="TWINCat-3" protocol="BLOCK_MODE" base-address="0">
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice1" />
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice2" />
</Beckhoff-PLC>
</Controller>
<Controller host-name="Schneider_PremiumQuantum">
<Schneider-PLC model="Premium" system="UNITY Pro" protocol="BLOCK_MODE" base-address="0">
<Device silecs-design-ref="AllTypes" silecs-device-label="testDevice1" />
......
<?xml version="1.0" encoding="UTF-8"?>
<SILECS-Design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" silecs-version="2.0.0" created="06/27/16" updated="06/27/16" xsi:noNamespaceSchemaLocation="/common/home/bel/schwinn/lnx/git/silecs-model/src/xml/DesignSchema.xsd">
<Information>
<Owner user-login="schwinn"/>
<Editor user-login="schwinn"/>
</Information>
<SILECS-Class name="AllTypesFESA" version="0.1.0" domain="OPERATIONAL">
<Acquisition-Block name="MyROBlock" generateFesaProperty="true" fesaPropertyName="MyROBlockProp">
<Acquisition-Register name="RO_int8" generateFesaValueItem="true">
<scalar format="int8"/>
</Acquisition-Register>
<Acquisition-Register name="RO_uint8" generateFesaValueItem="true" fesaFieldName="RO_uint8_fesa">
<scalar format="uint8"/>
</Acquisition-Register>
<Acquisition-Register name="RO_int16" generateFesaValueItem="true" fesaFieldName="RO_int16_fesa">
<scalar format="int16"/>
</Acquisition-Register>
<Acquisition-Register name="RO_uint16" generateFesaValueItem="true" fesaFieldName="RO_uint16_fesa">
<scalar format="uint16"/>
</Acquisition-Register>
<Acquisition-Register name="RO_int32" generateFesaValueItem="true" fesaFieldName="RO_int32_fesa">
<scalar format="int32"/>
</Acquisition-Register>
<Acquisition-Register name="RO_uint32" generateFesaValueItem="true" fesaFieldName="RO_uint32_fesa">
<scalar format="uint32"/>
</Acquisition-Register>
<!--<Register name="RO_int64" format="int64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RO_int64_fesa"/> not Supported for Beckhoff, Siemens and Schneider -->
<!--<Register name="RO_uint64" format="uint64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RO_uint64_fesa"/> not Supported for Beckhoff, Siemens and Schneider -->
<Acquisition-Register name="RO_float32" generateFesaValueItem="true" fesaFieldName="RO_float32_fesa">
<scalar format="float32"/>
</Acquisition-Register>
<!--<Register name="RO_float64" format="float64" synchro="MASTER" generateFesaValueItem="true" esaFieldName="RO_float64_fesa"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<Acquisition-Register name="RO_string" generateFesaValueItem="true" fesaFieldName="RO_string_fesa">
<string string-length="64" format="string"/>
</Acquisition-Register>
<Acquisition-Register name="RO_date" generateFesaValueItem="true" fesaFieldName="RO_date_fesa">
<scalar format="date"/>
</Acquisition-Register>
<Acquisition-Register name="RO_char" generateFesaValueItem="true" fesaFieldName="RO_char_fesa">
<scalar format="char"/>
</Acquisition-Register>
<Acquisition-Register name="RO_byte" generateFesaValueItem="true" fesaFieldName="RO_byte_fesa">
<scalar format="byte"/>
</Acquisition-Register>
<Acquisition-Register name="RO_word" generateFesaValueItem="true" fesaFieldName="RO_word_fesa">
<scalar format="word"/>
</Acquisition-Register>
<Acquisition-Register name="RO_dword" generateFesaValueItem="true" fesaFieldName="RO_dword_fesa">
<scalar format="dword"/>
</Acquisition-Register>
<Acquisition-Register name="RO_int" generateFesaValueItem="true" fesaFieldName="RO_int_fesa">
<scalar format="int"/>
</Acquisition-Register>
<Acquisition-Register name="RO_dint" generateFesaValueItem="true" fesaFieldName="RO_dint_fesa">
<scalar format="dint"/>
</Acquisition-Register>
<Acquisition-Register name="RO_real" generateFesaValueItem="true" fesaFieldName="RO_real_fesa">
<scalar format="real"/>
</Acquisition-Register>
<Acquisition-Register name="RO_dt" generateFesaValueItem="true" fesaFieldName="RO_dt_fesa">
<scalar format="dt"/>
</Acquisition-Register>
</Acquisition-Block>
<Setting-Block name="MyRWBlock" generateFesaProperty="true" fesaPropertyName="MyRWBlockProp">
<Volatile-Register name="RW_int8" generateFesaValueItem="true">
<array2D dim1="2" dim2="2" format="int8"/>
</Volatile-Register>
<Volatile-Register name="RW_uint8" generateFesaValueItem="true" fesaFieldName="RW_uint8_fesa">
<array2D dim1="2" dim2="2" format="uint8"/>
</Volatile-Register>
<Volatile-Register name="RW_int16" generateFesaValueItem="true" fesaFieldName="RW_int16_fesa">
<array2D dim1="2" dim2="2" format="int16"/>
</Volatile-Register>
<Volatile-Register name="RW_uint16" generateFesaValueItem="true" fesaFieldName="RW_uint16_fesa">
<array2D dim1="2" dim2="2" format="uint16"/>
</Volatile-Register>
<Volatile-Register name="RW_int32" generateFesaValueItem="true" fesaFieldName="RW_int32_fesa">
<array2D dim1="2" dim2="2" format="int32"/>
</Volatile-Register>
<Volatile-Register name="RW_uint32" generateFesaValueItem="true" fesaFieldName="RW_uint32_fesa">
<array2D dim1="2" dim2="2" format="uint32"/>
</Volatile-Register>
<!-- <Register name="RW_int64" format="int64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RW_int64_fesa" array-dim1="2" array-dim2="2"/> not Supported for Beckhoff, Siemens and Schneider -->
<!--<Register name="RW_uint64" format="uint64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RW_uint64_fesa" array-dim1="2" array-dim2="2"/> not Supported for Beckhoff, Siemens and Schneider -->
<Volatile-Register name="RW_float32" generateFesaValueItem="true" fesaFieldName="RW_float32_fesa">
<array2D dim1="2" dim2="2" format="float32"/>
</Volatile-Register>
<!--<Register name="RW_float64" format="float64" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RW_float64_fesa" array-dim1="2" array-dim2="2"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<!-- <Register name="RW_string" format="string" synchro="MASTER" generateFesaValueItem="true" fesaFieldName="RW_string_fesa" array-dim1="2" array-dim2="2"/> 2d string arrays not supported in FESA -->
<Volatile-Register name="RW_date" generateFesaValueItem="true" fesaFieldName="RW_date_fesa">
<array2D dim1="2" dim2="2" format="date"/>
</Volatile-Register>
<Volatile-Register name="RW_char" generateFesaValueItem="true" fesaFieldName="RW_char_fesa">
<array2D dim1="2" dim2="2" format="char"/>
</Volatile-Register>
<Volatile-Register name="RW_byte" generateFesaValueItem="true" fesaFieldName="RW_byte_fesa">
<array2D dim1="2" dim2="2" format="byte"/>
</Volatile-Register>
<Volatile-Register name="RW_word" generateFesaValueItem="true" fesaFieldName="RW_word_fesa">
<array2D dim1="2" dim2="2" format="word"/>
</Volatile-Register>
<Volatile-Register name="RW_dword" generateFesaValueItem="true" fesaFieldName="RW_dword_fesa">
<array2D dim1="2" dim2="2" format="dword"/>
</Volatile-Register>
<Volatile-Register name="RW_int" generateFesaValueItem="true" fesaFieldName="RW_int_fesa">
<array2D dim1="2" dim2="2" format="int"/>
</Volatile-Register>
<Volatile-Register name="RW_dint" generateFesaValueItem="true" fesaFieldName="RW_dint_fesa">
<array2D dim1="2" dim2="2" format="dint"/>
</Volatile-Register>
<Volatile-Register name="RW_real" generateFesaValueItem="true" fesaFieldName="RW_real_fesa">
<array2D dim1="2" dim2="2" format="real"/>
</Volatile-Register>
<Volatile-Register name="RW_dt" generateFesaValueItem="true" fesaFieldName="RW_dt_fesa">
<array2D dim1="2" dim2="2" format="dt"/>
</Volatile-Register>
</Setting-Block>
<Command-Block name="MyWOBlock" generateFesaProperty="true" fesaPropertyName="MyWOBlockProp">
<Setting-Register name="WO_int8" generateFesaValueItem="true">
<array dim="10" format="int8"/>
</Setting-Register>
<Setting-Register name="WO_uint8" generateFesaValueItem="true" fesaFieldName="WO_uint8_fesa">
<array dim="10" format="uint8"/>
</Setting-Register>
<Setting-Register name="WO_int16" generateFesaValueItem="true" fesaFieldName="WO_int16_fesa">
<array dim="10" format="int16"/>
</Setting-Register>
<Setting-Register name="WO_uint16" generateFesaValueItem="true" fesaFieldName="WO_uint16_fesa">
<array dim="10" format="uint16"/>
</Setting-Register>
<Setting-Register name="WO_int32" generateFesaValueItem="true" fesaFieldName="WO_int32_fesa">
<array dim="10" format="int32"/>
</Setting-Register>
<Setting-Register name="WO_uint32" generateFesaValueItem="true" fesaFieldName="WO_uint32_fesa">
<array dim="10" format="uint32"/>
</Setting-Register>
<!--<Register name="WO_int64" format="int64" synchro="SLAVE" generateFesaValueItem="true" fesaFieldName="WO_int64_fesa" array-dim1="10"/> not Supported for Beckhoff, Siemens and Schneider -->
<!--<Register name="WO_uint64" format="uint64" synchro="SLAVE" generateFesaValueItem="true" fesaFieldName="WO_uint64_fesa" array-dim1="10"/> not Supported for Beckhoff, Siemens and Schneider -->
<Setting-Register name="WO_float32" generateFesaValueItem="true" fesaFieldName="WO_float32_fesa">
<array dim="10" format="float32"/>
</Setting-Register>
<!--<Register name="WO_float64" format="float64" synchro="SLAVE" generateFesaValueItem="true" fesaFieldName="WO_float64_fesa" array-dim1="10"/> not Supported for Rabbit, Beckhoff, Siemens and Schneider -->
<Setting-Register name="WO_string" generateFesaValueItem="true" fesaFieldName="WO_string_fesa">
<stringArray dim="10" string-length="64" format="string"/>
</Setting-Register>
<Setting-Register name="WO_date" generateFesaValueItem="true" fesaFieldName="WO_date_fesa">
<array dim="10" format="date"/>
</Setting-Register>
<Setting-Register name="WO_char" generateFesaValueItem="true" fesaFieldName="WO_char_fesa">
<array dim="10" format="char"/>
</Setting-Register>
<Setting-Register name="WO_byte" generateFesaValueItem="true" fesaFieldName="WO_byte_fesa">
<array dim="10" format="byte"/>
</Setting-Register>
<Setting-Register name="WO_word" generateFesaValueItem="true" fesaFieldName="WO_word_fesa">
<array dim="10" format="word"/>
</Setting-Register>
<Setting-Register name="WO_dword" generateFesaValueItem="true" fesaFieldName="WO_dword_fesa">
<array dim="10" format="dword"/>
</Setting-Register>
<Setting-Register name="WO_int" generateFesaValueItem="true" fesaFieldName="WO_int_fesa">
<array dim="10" format="int"/>
</Setting-Register>
<Setting-Register name="WO_dint" generateFesaValueItem="true" fesaFieldName="WO_dint_fesa">
<array dim="10" format="dint"/>
</Setting-Register>
<Setting-Register name="WO_real" generateFesaValueItem="true" fesaFieldName="WO_real_fesa">
<array dim="10" format="real"/>
</Setting-Register>
<Setting-Register name="WO_dt" generateFesaValueItem="true" fesaFieldName="WO_dt_fesa">
<array dim="10" format="dt"/>
</Setting-Register>
</Command-Block>
</SILECS-Class>
</SILECS-Design>
../../../../test/AllTypesFESA/src/AllTypesFESA.silecsdesign
\ No newline at end of file
......@@ -6,29 +6,30 @@
<class-minor-version>1</class-minor-version>
<class-tiny-version>0</class-tiny-version>
<type>Final</type>
<state>development</state>
<description>An Empty design with GSI-specific standard properties</description>
<fesa-version>3.0.0</fesa-version>
<repository-path>undefined</repository-path>
<description>An empty design with GSI-specific standard properties</description>
<fesa-version>7.0.0</fesa-version>
</information>
<ownership>
<responsible name="CSCO"/>
<responsible name="ACO"/>
<creator login="Undefined"/>
</ownership>
<interface>
<device-interface>
<setting>
<GSI-Init-Property multiplexed="false" name="Init" visibility="operational">
<description>Control property, used to initialize the device with default values from the device instantiation file</description>
<set-action partial-setting="true" transaction="true">
<server-action-ref server-action-name-ref="InitSetAction"/>
</set-action>
</GSI-Init-Property>
<GSI-Reset-Property multiplexed="false" name="Reset" visibility="operational">
<description>Control property, used to reset the device while keeping the persistent data.</description>
<set-action partial-setting="true" transaction="true">
<server-action-ref server-action-name-ref="ResetSetAction"/>
</set-action>
</GSI-Reset-Property>
<GSI-Setting-Property multiplexed="false" name="Setting" visibility="operational">
<description>Used for setting hardware parameters for controlling the device.</description>
<update-flag-item direction="OUT" name="updateFlags" optional="true">
<builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/>
</update-flag-item>
......@@ -45,6 +46,7 @@
</get-action>
</GSI-Setting-Property>
<GSI-Power-Property multiplexed="false" name="Power" visibility="operational">
<description>Used to turn the power of a device on or off.</description>
<update-flag-item direction="OUT" name="updateFlags" optional="true">
<builtin-type-scalar data-type-name-ref="NOTIFICATION_UPDATE"/>
</update-flag-item>
......@@ -67,7 +69,9 @@
</GSI-Power-Property>
</setting>
<acquisition>
<GSI-Status-Property multiplexed="false" name="Status" on-change="true" subscribable="true" visibility="operational">
<GSI-Status-Property cycle-bound="false" name="Status" on-change="true" subscribable="true" visibility="operational">
<description>Used to display the (cycle independent) overall status of the device.</description>
<description>Detailed status information may be additionally added to this property.</description>
<acq-stamp-item direction="OUT" name="acqStamp">
<scalar type="int64_t"/>
</acq-stamp-item>
......@@ -91,12 +95,15 @@
<data-field-ref field-name-ref="status"/>
</status-item>
<detailed-status-item direction="OUT" name="detailedStatus">
<description>Detailed status should consist of an array of boolean values considered as detailed status information as well as a
corresponding string array containing keys to illustrate the meaning of the detailed status information.</description>
<array type="bool">
<custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/>
</array>
<data-field-ref field-name-ref="detailedStatus"/>
</detailed-status-item>
<detailed-status-labels-item direction="OUT" name="detailedStatus_labels">
<description>Labels of detailed status bits.</description>
<array2D type="char">
<custom-constant-dim1 constant-name-ref="DETAILED_STATUS_SIZE"/>
<custom-constant-dim2 constant-name-ref="MAX_DETAILED_STATUS_LABEL_LENGTH"/>
......@@ -104,30 +111,34 @@
<data-field-ref field-name-ref="detailedStatus_labels"/>
</detailed-status-labels-item>
<detailed-status-severity-item direction="OUT" name="detailedStatus_severity">
<description>Severities of the detailed status bits</description>
<custom-type-array data-type-name-ref="DETAILED_STATUS_SEVERITY">
<custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/>
</custom-type-array>
<data-field-ref field-name-ref="detailedStatus_severity"/>
</detailed-status-severity-item>
<powerState-item direction="OUT" name="powerState">
<description>Power state of the device (ON, OFF)</description>
<custom-type-scalar data-type-name-ref="DEVICE_POWER_STATE"/>
<data-field-ref field-name-ref="powerState"/>
</powerState-item>
<control-item direction="OUT" name="control">
<custom-type-scalar data-type-name-ref="DEVICE_CONTROL"/>
<data-field-ref field-name-ref="control"/>
</control-item>
<interlock-item direction="OUT" name="interlock">
<description>Interlock state of the device</description>
<scalar type="bool"/>
<data-field-ref field-name-ref="interlock"/>
</interlock-item>
<opReady-item direction="OUT" name="opReady">
<description>Contains the devices state regarding operation</description>
<scalar type="bool"/>
<data-field-ref field-name-ref="opReady"/>
</opReady-item>
<modulesReady-item direction="OUT" name="modulesReady">
<description>Contains the devices module state</description>
<scalar type="bool"/>
<data-field-ref field-name-ref="modulesReady"/>
</modulesReady-item>
......@@ -157,7 +168,8 @@
<error_collection-field-ref field-name-ref="error_collection"/>
</error_collection-item>
</GSI-Status-Property>
<GSI-ModuleStatus-Property visibility="development" subscribable="true" name="ModuleStatus" multiplexed="false">
<GSI-ModuleStatus-Property visibility="operational" subscribable="true" name="ModuleStatus" cycle-bound="false">
<description>Gives detailed information on the state of 3rd party hardware and software components which are required to operate the device.</description>
<acq-stamp-item name="acqStamp" direction="OUT">
<scalar type="int64_t" />
</acq-stamp-item>
......@@ -178,22 +190,19 @@
<module-status-item name="moduleStatus" direction="OUT">
<custom-type-array data-type-name-ref="MODULE_STATUS">
<custom-constant-dim constant-name-ref="MODULE_STATUS_SIZE" />
</custom-type-array>
<data-field-ref field-name-ref="moduleStatus" />
</module-status-item>
<module-status-labels-item name="moduleStatus_labels" direction="OUT">
<array2D type="char">
<custom-constant-dim1 constant-name-ref="MODULE_STATUS_SIZE" />
<custom-constant-dim2 constant-name-ref="MAX_MODULE_STATUS_LABEL_LENGTH" />
</array2D>
<data-field-ref field-name-ref="moduleStatus_labels" />
</module-status-labels-item>
</GSI-ModuleStatus-Property>
<GSI-Acquisition-Property multiplexed="true" name="Acquisition" on-change="true" subscribable="true" visibility="operational">
<GSI-Acquisition-Property cycle-bound="true" name="Acquisition" on-change="true" subscribable="true" visibility="operational">
<description>Used for returning acquisition data which is retrieved from the hardware.</description>
<acq-stamp-item direction="OUT" name="acqStamp">
<scalar type="int64_t"/>
</acq-stamp-item>
......@@ -212,27 +221,41 @@
<server-action-ref server-action-name-ref="AcquisitionGetAction"/>
</get-action>
<acquisition-context-item direction="OUT">
<acqStamp direction="OUT" name="acqStampGSI">
<scalar type="int64_t"/>
</acqStamp>
<cycleStamp direction="OUT" name="cycleStampGSI">
<scalar type="int64_t"/>
</cycleStamp>
<cycleName direction="OUT" name="cycleNameGSI">
<array type="char">
<custom-constant-dim constant-name-ref="MAX_CYCLE_NAME_LENGTH"/>
</array>
</cycleName>
<beamProcessID direction="OUT" name="beamProcessID">
<processIndex direction="OUT" name="processIndex">
<scalar type="int32_t"/>
</processIndex>
<sequenceIndex direction="OUT" name="sequenceIndex">
<scalar type="int32_t"/>
</sequenceIndex>
<chainIndex direction="OUT" name="chainIndex">
<scalar type="int32_t"/>
</beamProcessID>
<sequenceID direction="OUT" name="sequenceID">
</chainIndex>
<eventNumber direction="OUT" name="eventNumber">
<scalar type="int32_t"/>
</sequenceID>
</eventNumber>
<timingGroupID direction="OUT" name="timingGroupID">
<scalar type="int32_t"/>
</timingGroupID>
<acquisitionStamp direction="OUT" name="acquisitionStamp">
<scalar type="int64_t"/>
</acquisitionStamp>
<eventStamp direction="OUT" name="eventStamp">
<scalar type="int64_t"/>
</eventStamp>
<processStartStamp direction="OUT" name="processStartStamp">
<scalar type="int64_t"/>
</processStartStamp>
<sequenceStartStamp direction="OUT" name="sequenceStartStamp">
<scalar type="int64_t"/>
</sequenceStartStamp>
<chainStartStamp direction="OUT" name="chainStartStamp">
<scalar type="int64_t"/>
</chainStartStamp>
<acquisition-context-field-ref field-name-ref="acquisitionContext"/>
</acquisition-context-item>
</GSI-Acquisition-Property>
<GSI-Version-Property multiplexed="false" name="Version" on-change="false" subscribable="false" visibility="operational">
<GSI-Version-Property cycle-bound="false" name="Version" on-change="false" subscribable="false" visibility="operational">
<description>Returns the current software and hardware versions of a piece of equipment.</description>
<acq-stamp-item direction="OUT" name="acqStamp">
<scalar type="int64_t"/>
</acq-stamp-item>
......@@ -276,11 +299,13 @@
<scalar type="bool"/>
</mode-item>
<host-item direction="INOUT" name="hostName">
<description>Host of the FESA class</description>
<array type="char">
<dim>32</dim>
</array>
</host-item>
<port-item direction="INOUT" name="portNumber">
<description>Port used by the FESA class</description>
<scalar type="int32_t"/>
</port-item>
<config-item direction="IN" name="requestConfig">
......@@ -308,7 +333,7 @@
</diagnostic-property>
</setting>
<acquisition>
<GSI-DeviceDescription-Property multiplexed="false" name="DeviceDescription" on-change="false" subscribable="false" visibility="operational">
<GSI-DeviceDescription-Property cycle-bound="false" name="DeviceDescription" on-change="false" subscribable="false" visibility="operational">
<timing-info-item direction="OUT" name="deviceNameTimingReceiver">
<array type="char">
<variable-dim/>
......@@ -509,28 +534,47 @@
</array>
</struct-item>
</struct>
<struct name="GSI_ACQ_CONTEXT">
<!--This struct-item describes all AcquisitionContext items which are relevant for GSI-->
<struct-item name="acqStamp">
<!--The acquisition stamp is used to indicate when a measurement was done -->
<struct name="GSI_ACQ_CONTEXT"><description>WhiteRabbit event specific acquisition information</description>
<struct-item name="processIndex">
<description>Used in order to index process-multiplexed data</description>
<scalar type="int32_t" />
</struct-item>
<struct-item name="sequenceIndex">
<description>Used in order to index sequence-multiplexed data</description>
<scalar type="int32_t" />
</struct-item>
<struct-item name="chainIndex">
<description>Refers to a specific beam production chain</description>
<scalar type="int32_t" />
</struct-item>
<struct-item name="eventNumber">
<description>The number of the event describes it's type</description>
<scalar type="int32_t" />
</struct-item>
<struct-item name="timingGroupID">
<description>ID of the timing group for which the event is relevant</description>
<scalar type="int32_t" />
</struct-item>
<struct-item name="acquisitionStamp" >
<description>The acquisition stamp is used to indicate when a measurement was done</description>
<scalar type="int64_t"/>
</struct-item>
<struct-item name="cycleStamp">
<!--The cycle stamp is used to indicate when a specific cycle has started-->
<scalar type="int64_t"/>
</struct-item>
<struct-item name="cycleName">
<!--The cycle name indicates the cycle which started at time of the cycleStamp -->
<array type="char">
<custom-constant-dim constant-name-ref="MAX_CYCLE_NAME_LENGTH"/>
</array>
</struct-item>
<struct-item name="beamProcessID">
<scalar type="int32_t"/>
</struct-item>
<struct-item name="sequenceID">
<scalar type="int32_t"/>
</struct-item>
<struct-item name="eventStamp">
<description>The event stamp is used to indicate when WhiteRabbit event was triggered on the Timing Receiver</description>
<scalar type="int64_t" />
</struct-item>
<struct-item name="processStartStamp">
<description>The process start stamp indicates when the first event of the current process was triggered</description>
<scalar type="int64_t" />
</struct-item>
<struct-item name="sequenceStartStamp">
<description>The sequence start stamp indicates when the first event of the current sequence was triggered</description>
<scalar type="int64_t" />
</struct-item>
<struct-item name="chainStartStamp">
<description>The chain start stamp indicates when the first event of the current chain was triggered</description>
<scalar type="int64_t" />
</struct-item>
</struct>
<constant name="MAX_ERROR_MESSAGE_LENGTH" type="uint32_t" value="256"/>
<constant name="MAX_NUMBER_OF_ERROR_MESSAGES" type="uint32_t" value="16"/>
......@@ -591,39 +635,38 @@
</GSI-power-field>
</setting>
<acquisition>
<GSI-control-field multiplexed="false" name="control">
<GSI-control-field cycle-bound="false" name="control">
<custom-type-scalar data-type-name-ref="DEVICE_CONTROL"/>
</GSI-control-field>
<GSI-powerState-field multiplexed="false" name="powerState">
<GSI-powerState-field cycle-bound="false" name="powerState">
<custom-type-scalar data-type-name-ref="DEVICE_POWER_STATE"/>
</GSI-powerState-field>
<GSI-status-field multiplexed="false" name="status">
<GSI-status-field cycle-bound="false" name="status">
<custom-type-scalar data-type-name-ref="DEVICE_STATUS"/>
</GSI-status-field>
<GSI-interlock-field multiplexed="false" name="interlock">
<GSI-interlock-field cycle-bound="false" name="interlock">
<scalar type="bool"/>
</GSI-interlock-field>
<GSI-opReady-field multiplexed="false" name="opReady">
<GSI-opReady-field cycle-bound="false" name="opReady">
<scalar type="bool"/>
</GSI-opReady-field>
<GSI-modulesReady-field name="modulesReady" multiplexed="false">
<GSI-modulesReady-field name="modulesReady" cycle-bound="false">
<scalar type="bool" />
</GSI-modulesReady-field>
<GSI-detailed-status-field multiplexed="false" name="detailedStatus">
<GSI-detailed-status-field cycle-bound="false" name="detailedStatus">
<array type="bool">
<custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/>
</array>
</GSI-detailed-status-field>
<GSI-module-status-field name="moduleStatus" multiplexed="false">
<GSI-module-status-field name="moduleStatus" cycle-bound="false">
<custom-type-array data-type-name-ref="MODULE_STATUS">
<custom-constant-dim constant-name-ref="MODULE_STATUS_SIZE" />
</custom-type-array>
</GSI-module-status-field>
<GSI-acquisition-context-field multiplexed="true" name="acquisitionContext">
<GSI-acquisition-context-field cycle-bound="true" name="acquisitionContext">
<custom-type-scalar data-type-name-ref="GSI_ACQ_CONTEXT"/>
</GSI-acquisition-context-field>
<GSI-error_collection-field multiplexed="false" name="error_collection">
<GSI-error_collection-field cycle-bound="false" name="error_collection">
<custom-type-array data-type-name-ref="GSI_ERROR">
<custom-constant-dim constant-name-ref="MAX_NUMBER_OF_ERROR_MESSAGES"/>
</custom-type-array>
......@@ -651,7 +694,21 @@
<get-server-action implementation="default" name="SettingGetAction"/>
<get-server-action implementation="default" name="AcquisitionGetAction"/>
<get-server-action implementation="default" name="StatusGetAction"/>
<get-server-action implementation="default" name="VersionGetAction"/><get-server-action implementation="default" name="ModuleStatusGetAction"></get-server-action>
<get-server-action implementation="default" name="VersionGetAction"/>
<get-server-action implementation="default" name="ModuleStatusGetAction"/>
<rt-action name="StatusUpdateAction"/> <!-- Pre-defined status update action -->
</actions>
<events>
<logical-events>
<logical-event use="required" name="StatusUpdateEvent" type="timer"/>
</logical-events>
</events>
<scheduling-units>
<scheduling-unit name="StatusUpdateSchedulingUnit">
<rt-action-ref rt-action-name-ref="StatusUpdateAction" />
<logical-event-ref logical-event-name-ref="StatusUpdateEvent" />
</scheduling-unit>
</scheduling-units>
</equipment-model>
\ No newline at end of file
</equipment-model>
......@@ -6,10 +6,8 @@
<class-minor-version>1</class-minor-version>
<class-tiny-version>0</class-tiny-version>
<type>Final</type>
<state>development</state>
<description>An Empty design</description>
<fesa-version>0.9.0</fesa-version>
<repository-path>undefined</repository-path>
</information>
<ownership>
<responsible name="Undefined" />
......@@ -55,6 +53,51 @@
</bypass-action-item>
</diagnostic-property>
</setting>
<acquisition>
<metrics-property visibility="expert" name="Metrics" on-change="false" subscribable="false" cycle-bound="false">
<description>Generic property to retrieve deploy-unit's metrics</description>
<cmw-server name="cmwServer" direction="OUT">
<array type="char">
<dim>160</dim>
</array>
</cmw-server>
<concurrency-layers name="concurrencyLayers" direction="OUT">
<array type="char">
<dim>2000</dim>
</array>
</concurrency-layers>
<event-sources name="eventSources" direction="OUT">
<array type="char">
<dim>2000</dim>
</array>
</event-sources>
<logical-events name="logicalEvents" direction="OUT">
<array type="char">
<dim>2000</dim>
</array>
</logical-events>
<notification-queue name="notificationQueue" direction="OUT">
<array type="char">
<dim>50</dim>
</array>
</notification-queue>
<ondemand-queues name="ondemandQueues" direction="OUT">
<array type="char">
<dim>2000</dim>
</array>
</ondemand-queues>
<rt-actions name="rtActions" direction="OUT">
<array type="char">
<dim>5000</dim>
</array>
</rt-actions>
<server-actions name="serverActions" direction="OUT">
<array type="char">
<dim>5000</dim>
</array>
</server-actions>
</metrics-property>
</acquisition>
</global-interface>
</interface>
<builtin-types>
......
......@@ -14,10 +14,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import libxml2
import unittest
from test.testBase import *
import fesa.fesa_3_0_0.fillFESADeployUnit
simpleSilecsDeploy = '''<?xml version="1.0" encoding="UTF-8"?>
......@@ -44,25 +43,23 @@ simpleSilecsDeploy = '''<?xml version="1.0" encoding="UTF-8"?>
simpleSilecsDeployParsed = libxml2.parseDoc(simpleSilecsDeploy)
simpleFesaDeployParsed = libxml2.parseFile("test/fesa/DeploymentUnitTemplateFESA300.xml")
def fillDU_3_0_0(generator):
generator.fillXML(simpleFesaDeployParsed,simpleSilecsDeployParsed,"MyTestDeploy", "some/schema.xsd", "1.2.3")
# check that default class is removed
defaultClassTemplate = simpleFesaDeployParsed.xpathEval('/deploy-unit/class[class-name/text()="class-name"]')
assertEqual( len(defaultClassTemplate), 0 )
class TestFillDeployUnit(unittest.TestCase):
# test 2 classes available
classes = simpleFesaDeployParsed.xpathEval('/deploy-unit/class')
assertEqual( len(classes), 2 )
def setUp(self):
self.generator = fesa.fesa_3_0_0.fillFESADeployUnit.FESADeployUnitGenerator3_0_0()
# test 2 classes available after overwrite
generator.fillXML(simpleFesaDeployParsed,simpleSilecsDeployParsed,"MyTestDeploy", "some/schema.xsd", "1.2.3")
classes = simpleFesaDeployParsed.xpathEval('/deploy-unit/class')
assertEqual( len(classes), 2 )
def test_fillDU_3_0_0(self):
self.generator.fillXML(simpleFesaDeployParsed,simpleSilecsDeployParsed,"MyTestDeploy", "some/schema.xsd", "1.2.3")
def runTests():
generator = fesa.fesa_3_0_0.fillFESADeployUnit.FESADeployUnitGenerator3_0_0()
fillDU_3_0_0(generator)
# No need to test 3.1.0, it uses the same generator than 3.0.0
allTestsOk()
# check that default class is removed
defaultClassTemplate = simpleFesaDeployParsed.xpathEval('/deploy-unit/class[class-name/text()="class-name"]')
self.assertEqual(len(defaultClassTemplate), 0)
# test 2 classes available
classes = simpleFesaDeployParsed.xpathEval('/deploy-unit/class')
self.assertEqual(len(classes), 2)
# test 2 classes available after overwrite
self.generator.fillXML(simpleFesaDeployParsed,simpleSilecsDeployParsed,"MyTestDeploy", "some/schema.xsd", "1.2.3")
classes = simpleFesaDeployParsed.xpathEval('/deploy-unit/class')
self.assertEqual(len(classes), 2)
......@@ -14,13 +14,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import fesa.fesa_7_3_0.generateFesaDesign
from test.testBase import *
import fesa.fesa_3_0_0.generateFesaDesign
import fesa.fesa_3_1_0.generateFesaDesign
fesa_version = "7.5.0"
import libxml2
import unittest
simpleSilecsDesign = '''<?xml version="1.0" encoding="UTF-8"?>
<SILECS-Design silecs-version="0.10.0" created="03/02/16" updated="03/02/16"
......@@ -36,6 +35,11 @@ simpleSilecsDesign = '''<?xml version="1.0" encoding="UTF-8"?>
<scalar format="uint8"/>
</Setting-Register>
</Setting-Block>
<Command-Block name="Command" generateFesaProperty="true">
<Setting-Register name="mySettingRegister" generateFesaValueItem="true">
<scalar format="uint8"/>
</Setting-Register>
</Command-Block>
<Acquisition-Block name="Acquisition" generateFesaProperty="true">
<Acquisition-Register name="myAcqRegister" generateFesaValueItem="true">
<scalar format="uint8"/>
......@@ -45,77 +49,65 @@ simpleSilecsDesign = '''<?xml version="1.0" encoding="UTF-8"?>
</SILECS-Design>'''
simpleSilecsDesignRoot = libxml2.parseDoc(simpleSilecsDesign)
def testFillXML_EmptyTemplate_3_0_0(generator):
fesaRoot = libxml2.parseFile("test/fesa/emptyTemplateFESA300.xml")
generator.fillXML('3.0.0', 'MyClass', fesaRoot,simpleSilecsDesignRoot,logTopics={'errorlog': True})
assertTrue( fesaRoot.xpathEval('/equipment-model/events') != None )
assertTrue( fesaRoot.xpathEval('/equipment-model/scheduling-units') != None )
#etree.tostring(fesaRoot)
def testFillXML_GSITemplate_3_0_0(generator):
fesaRoot = libxml2.parseFile("test/fesa/GSIClassTemplateFESA300.xml")
generator.fillXML('3.0.0', 'MyClass', fesaRoot,simpleSilecsDesignRoot,logTopics={'errorlog': True})
assertTrue( fesaRoot.xpathEval('/equipment-model/events') != None )
assertTrue( fesaRoot.xpathEval('/equipment-model/scheduling-units') != None )
acquisition = fesaRoot.xpathEval('/equipment-model/interface/device-interface/acquisition')[0]
firstGSIAcqProp = acquisition.xpathEval('GSI-Acquisition-Property')[0]
assertTrue( acquisition.xpathEval('*')[0].prop('name') != firstGSIAcqProp.prop('name') ) # check if generated at right position
assertEqual( firstGSIAcqProp.prop('name'),"Acquisition" )
firstGSIAcqProp.shellPrintNode() #for debug
valueItem = firstGSIAcqProp.xpathEval('value-item')[0]
assertTrue( valueItem != None )
setting = fesaRoot.xpathEval('/equipment-model/interface/device-interface/setting')[0]
firstGSISettingProp = setting.xpathEval('GSI-Setting-Property')[0]
assertTrue( acquisition.xpathEval('*')[0].prop('name') != firstGSISettingProp.prop('name') ) # check if generated at right position
#etree.tostring(fesaRoot)
def testFillXML_EmptyTemplate_3_1_0(generator):
fesaRoot = libxml2.parseFile("test/fesa/emptyTemplateFESA300.xml")
generator.fillXML('3.1.0', 'MyClass', fesaRoot,simpleSilecsDesignRoot,logTopics={'errorlog': True})
assertTrue( fesaRoot.xpathEval('/equipment-model/events') != None )
assertTrue( fesaRoot.xpathEval('/equipment-model/scheduling-units') != None )
#etree.tostring(fesaRoot)
def testFillXML_GSITemplate_3_1_0(generator):
fesaRoot = libxml2.parseFile("test/fesa/GSIClassTemplateFESA300.xml")
generator.fillXML('3.1.0', 'MyClass', fesaRoot,simpleSilecsDesignRoot,logTopics={'errorlog': True})
assertTrue( fesaRoot.xpathEval('/equipment-model/events') != None )
assertTrue( fesaRoot.xpathEval('/equipment-model/scheduling-units') != None )
acquisition = fesaRoot.xpathEval('/equipment-model/interface/device-interface/acquisition')[0]
firstGSIAcqProp = acquisition.xpathEval('GSI-Acquisition-Property')[0]
assertTrue( acquisition.xpathEval('*')[0].prop('name') != firstGSIAcqProp.prop('name') ) # check if generated at right position
assertEqual( firstGSIAcqProp.prop('name'),"Acquisition" )
valueItems = firstGSIAcqProp.xpathEval('value-item')
assertTrue( valueItems != None )
setting = fesaRoot.xpathEval('/equipment-model/interface/device-interface/setting')[0]
firstGSISettingProp = setting.xpathEval('GSI-Setting-Property')[0]
assertTrue( acquisition.xpathEval('*')[0].prop('name') != firstGSISettingProp.prop('name') ) # check if generated at right position
#etree.tostring(fesaRoot)
def testFillXML_AllTypes_3_1_0(generator):
fesaRoot = libxml2.parseFile("test/fesa/GSIClassTemplateFESA300.xml")
silecsRoot = libxml2.parseFile("test/AllTypesFESA.silecsdesign")
fesaRoot = generator.fillXML('3.1.0', 'MyClass', fesaRoot,silecsRoot,logTopics={'errorlog': True})
fesaNewDocPath = "test/generated_temp/AllTypesFESA.design"
fesaCompareDocPath = "test/generated_correct/AllTypesFESA.design"
with open(fesaNewDocPath, 'w') as fd:
fesaRoot.saveTo(fd,format = True)
print 'FESA design document saved successfully'
assertFileEqual( fesaNewDocPath, fesaCompareDocPath)
def runTests():
generator = fesa.fesa_3_0_0.generateFesaDesign.FESADesignGenerator3_0_0();
testFillXML_EmptyTemplate_3_0_0(generator)
testFillXML_GSITemplate_3_0_0(generator)
generator = fesa.fesa_3_1_0.generateFesaDesign.FESADesignGenerator3_1_0();
testFillXML_EmptyTemplate_3_1_0(generator)
testFillXML_GSITemplate_3_1_0(generator)
testFillXML_AllTypes_3_1_0(generator)
allTestsOk()
class TestGenerateFesaDesign(unittest.TestCase):
def setUp(self):
self.generator = fesa.fesa_7_3_0.generateFesaDesign.FESADesignGenerator7_3_0()
def test_fillXML_EmptyTemplate(self):
fesaRoot = libxml2.parseFile("test/fesa/emptyTemplate.xml")
self.generator.fillXML(fesa_version, 'AllTypesFESA', fesaRoot, simpleSilecsDesignRoot, logTopics={'errorlog': True})
self.assertTrue(fesaRoot.xpathEval('/equipment-model/events') is not None)
self.assertTrue(fesaRoot.xpathEval('/equipment-model/scheduling-units') is not None)
def test_fillXML_GSITemplate(self):
fesaRoot = libxml2.parseFile("test/fesa/GSIClassTemplate.xml")
self.generator.fillXML(fesa_version, 'AllTypesFESA', fesaRoot, simpleSilecsDesignRoot, logTopics={'errorlog': True})
self.assertTrue(fesaRoot.xpathEval('/equipment-model/events') is not None)
self.assertTrue(fesaRoot.xpathEval('/equipment-model/scheduling-units') is not None)
acquisition = fesaRoot.xpathEval('/equipment-model/interface/device-interface/acquisition')[0]
firstGSIAcqProp = acquisition.xpathEval('GSI-Acquisition-Property')[0]
self.assertTrue(acquisition.xpathEval('*')[0].prop('name') != firstGSIAcqProp.prop('name')) # check if generated at right position
self.assertEqual(firstGSIAcqProp.prop('name'), "Acquisition")
valueItems = firstGSIAcqProp.xpathEval('value-item')
self.assertTrue(valueItems is not None)
setting = fesaRoot.xpathEval('/equipment-model/interface/device-interface/setting')[0]
firstGSISettingProp = setting.xpathEval('GSI-Setting-Property')[0]
self.assertTrue(acquisition.xpathEval('*')[0].prop('name') != firstGSISettingProp.prop('name')) # check if generated at right position
def test_fillXML_GSITemplate_Exceptions(self):
fesaRoot = libxml2.parseFile("test/fesa/GSIClassTemplate.xml")
myRoot = simpleSilecsDesignRoot
commandBlock = myRoot.xpathEval('/SILECS-Design/SILECS-Class/Command-Block')[0]
commandBlock.setProp("name", "Init")
self.assertRaises(Exception, lambda: self.generator.fillXML(fesa_version, 'AllTypesFESA', fesaRoot, myRoot, logTopics={'errorlog': True}))
commandBlock.setProp("name", "Reset")
self.assertRaises(Exception, lambda: self.generator.fillXML(fesa_version, 'AllTypesFESA', fesaRoot, myRoot, logTopics={'errorlog': True}))
def testFillXML_AllTypes(self):
fesaRoot = libxml2.parseFile("test/fesa/GSIClassTemplate.xml")
silecsRoot = libxml2.parseFile("test/AllTypesFESA.silecsdesign")
fesaRoot = self.generator.fillXML(fesa_version, 'AllTypesFESA', fesaRoot, silecsRoot, logTopics={'errorlog': True})
fesaNewDocPath = "test/generated_temp/AllTypesFESA.design"
fesaCompareDocPath = "test/generated_correct/AllTypesFESA.design"
fesaCompareTestDocPath = "test/generated_correct/AllTypesFESA.design.testing"
with open(fesaNewDocPath, 'w') as fd:
fesaRoot.saveTo(fd, format = True)
correct = libxml2.readFile(fesaCompareDocPath, "utf-8", 0)
for node in correct.xpathEval("//*"):
if node.hasProp("id"):
node.unsetProp("id")
if node.name == "equipment-model":
node.setProp("xsi:noNamespaceSchemaLocation", "../design-gsi.xsd")
correct.saveFormatFile(fesaCompareTestDocPath, format=True)
print('FESA design document saved successfully')
# Compare files.
with open(fesaNewDocPath) as a, open(fesaCompareTestDocPath) as b:
self.assertListEqual(list(a), list(b))
......@@ -14,9 +14,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import unittest
from test.testBase import *
import fesa.fesa_3_0_0.generateSourceCode
import fesa.fesa_3_1_0.generateSourceCode
......@@ -30,19 +29,19 @@ generatedCppName = "AllTypes.cpp"
silecsDesignRoot = libxml2.parseFile("test/AllTypesFESA.silecsdesign")
class TestGenerateSourceCode(unittest.TestCase):
def setUp(self):
self.fesaDesignRoot = libxml2.parseFile(generationFolder + "/AllTypesFESA.design" )
def assertFileEqual(self, filePath1, filePath2):
with open(filePath1) as a, open(filePath2) as b:
self.assertListEqual(list(a), list(b))
def testGenHSource():
fesaDesignRoot = libxml2.parseFile(generationFolder + "/AllTypesFESA.design" )
fesa.fesa_3_1_0.generateSourceCode.genHSource('AllTypes', silecsDesignRoot,fesaDesignRoot,generationFolder,logTopics={'errorlog': True})
assertFileEqual( generationFolder + "/" + generatedHeaderName, comparisonFolder + "/" + generatedHeaderName)
def test_genHSource(self):
fesa.fesa_3_1_0.generateSourceCode.genHSource('AllTypes', silecsDesignRoot, self.fesaDesignRoot, generationFolder,logTopics={'errorlog': True})
self.assertFileEqual(generationFolder + "/" + generatedHeaderName, comparisonFolder + "/" + generatedHeaderName)
def testGenCppSource():
fesaDesignRoot = libxml2.parseFile(generationFolder + "/AllTypesFESA.design" )
fesa.fesa_3_1_0.generateSourceCode.genCppSource('AllTypes', silecsDesignRoot,fesaDesignRoot,generationFolder,logTopics={'errorlog': True})
assertFileEqual( generationFolder + "/" + generatedCppName, comparisonFolder + "/" + generatedCppName)
def runTests():
testGenHSource()
testGenCppSource()
allTestsOk()
def test_genCppSource(self):
fesaDesignRoot = libxml2.parseFile(generationFolder + "/AllTypesFESA.design" )
fesa.fesa_3_1_0.generateSourceCode.genCppSource('AllTypes', silecsDesignRoot,fesaDesignRoot,generationFolder,logTopics={'errorlog': True})
self.assertFileEqual(generationFolder + "/" + generatedCppName, comparisonFolder + "/" + generatedCppName)
#!/usr/bin/python
# Copyright 2016 CERN and GSI
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import difflib
import sys
import libxml2
from test.testBase import *
from genparam import *
import iecommon
import iefiles
import libxml2
testFolder = "test"
generationFolder = testFolder + "/generated_temp/client"
comparisonFolder = testFolder + "/generated_correct/client"
def fakeGetSilecsDesignFilePath(workspacePath,designName):
return testFolder + "/AllTypes.silecsdesign"
def fakeGetParameterFile(workspacePath,deployName,controllerName):
return generationFolder + "/" + controllerName + ".silecsparam"
def fakeGetSilecsDeployFilePath(workspacePath,deployName):
return testFolder + "/AllTypesDU.silecsdeploy"
def fakeGetParameterFileDirectory(workspacePath,deployName):
return generationFolder
def CompareGeneratedFiles(hostName,fileExtension):
fileGeneratedPath = generationFolder + "/" + hostName + fileExtension
fileCorrectPath = comparisonFolder + "/" + hostName + fileExtension
print "comparing: " + fileGeneratedPath + " with: " + fileCorrectPath
assertParameterFileEqual( fileGeneratedPath, fileCorrectPath)
def SiemensSourcesTest():
CompareGeneratedFiles("Siemens_TiaDevice",".silecsparam")
CompareGeneratedFiles("Siemens_TiaBlock",".silecsparam")
CompareGeneratedFiles("Siemens_Step7Device",".silecsparam")
CompareGeneratedFiles("Siemens_Step7Block",".silecsparam")
def BeckhoffSourcesTest():
CompareGeneratedFiles("Beckhoff_BC9020",".silecsparam")
CompareGeneratedFiles("Beckhoff_CX9020",".silecsparam")
def SchneiderSourcesTest():
CompareGeneratedFiles("Schneider_M340",".silecsparam")
CompareGeneratedFiles("Schneider_PremiumQuantum",".silecsparam")
def RabbitSourcesTest():
CompareGeneratedFiles("Rabbit_BlockMode",".silecsparam")
CompareGeneratedFiles("Rabbit_DeviceMode",".silecsparam")
def runTests():
genParamBase( fakeGetSilecsDesignFilePath, fakeGetParameterFile, fakeGetSilecsDeployFilePath, fakeGetParameterFileDirectory, "fake", "AllTypesDU", "fake", "DEV")
SiemensSourcesTest()
BeckhoffSourcesTest()
SchneiderSourcesTest()
RabbitSourcesTest()
allTestsOk()