etisserant@0: #!/usr/bin/env python etisserant@0: # -*- coding: utf-8 -*- etisserant@0: etisserant@0: #This file is part of CanFestival, a library implementing CanOpen Stack. etisserant@0: # etisserant@0: #Copyright (C): Edouard TISSERANT, Francis DUPIN and Laurent BESSARD etisserant@0: # etisserant@0: #See COPYING file for copyrights details. etisserant@0: # etisserant@0: #This library is free software; you can redistribute it and/or etisserant@0: #modify it under the terms of the GNU Lesser General Public etisserant@0: #License as published by the Free Software Foundation; either etisserant@0: #version 2.1 of the License, or (at your option) any later version. etisserant@0: # etisserant@0: #This library is distributed in the hope that it will be useful, etisserant@0: #but WITHOUT ANY WARRANTY; without even the implied warranty of etisserant@0: #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU etisserant@0: #Lesser General Public License for more details. etisserant@0: # etisserant@0: #You should have received a copy of the GNU Lesser General Public etisserant@0: #License along with this library; if not, write to the Free Software etisserant@0: #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA etisserant@0: etisserant@0: from xml.parsers import expat etisserant@0: etisserant@0: import node etisserant@0: from node import * etisserant@0: etisserant@0: maxObjects = 8 etisserant@0: etisserant@0: currentPDOIndex = 0 etisserant@0: currentBitsMapped = 0 etisserant@0: currentMaxObjects = 0 etisserant@0: currentNbMappedObjects = 0 etisserant@0: etisserant@0: nextPdoIndex = {"rx":0x1400,"tx":0x1800} etisserant@0: etisserant@0: valid_elements = ["node","heartbeat_consumers","sdo_clients","pdo","mapped_object", etisserant@0: "pdo_param","pdo_receive","pdo_transmit","mapped_variable","mapped_table", etisserant@0: "mapped_string_variable","mapped_string_table"] etisserant@0: etisserant@0: #------------------------------------------------------------------------------- etisserant@0: # Callback method of parse etisserant@0: #------------------------------------------------------------------------------- etisserant@0: etisserant@0: def StartElement(name, attrs): etisserant@0: if name in valid_elements: etisserant@0: if name == "node": etisserant@0: startNode(attrs) etisserant@0: elif name == "heartbeat_consumers": etisserant@0: startHeartBeatConsumers(attrs) etisserant@0: elif name == "sdo_clients": etisserant@0: startSdoClients(attrs) etisserant@0: elif name in ["pdo_param","pdo_receive","pdo_transmit"]: etisserant@0: raise ValueError, """!!! The XML grammar has changed. etisserant@0: Please, open your xml file, delete the tags pdo_param, pdo_receive and pdo_transmit. etisserant@0: Use instead the tag pdo for each pdo to create, and (optional) use the tag mapped_object (menu pdo/map and object ...).""" etisserant@0: elif name == "pdo": etisserant@0: startPdo(attrs) etisserant@0: elif name == "mapped_object": etisserant@0: startMappedObject(attrs) etisserant@0: elif name == "mapped_variable": etisserant@0: startMappedVariable(attrs) etisserant@0: elif name == "mapped_table": etisserant@0: startMappedTable(attrs) etisserant@0: elif name == "mapped_string_variable": etisserant@0: startMappedVariable(attrs) etisserant@0: elif name == "mapped_string_table": etisserant@0: startMappedTable(attrs) etisserant@0: etisserant@0: def EndElement(name): etisserant@0: if name in valid_elements: etisserant@0: if name == "node": etisserant@0: stopNode() etisserant@0: etisserant@0: def CharacterData(data): etisserant@0: pass etisserant@0: etisserant@0: #------------------------------------------------------------------------------- etisserant@0: # Creation of Node etisserant@0: #------------------------------------------------------------------------------- etisserant@0: etisserant@0: def startNode(attrs): etisserant@0: name = attrs["name"] etisserant@0: Node.SetNodeName(name) etisserant@0: etisserant@0: if "node_id" in attrs and len(attrs["node_id"]) > 0: etisserant@0: node_id = eval(attrs["node_id"]) etisserant@0: else: etisserant@0: node_id = 0x01 # We define here a default node_id. etisserant@0: Node.SetNodeID(node_id) etisserant@0: etisserant@0: typeNode = attrs["type_node"] etisserant@0: Node.SetNodeType(typeNode) etisserant@0: etisserant@0: if "device_type_1000" in attrs: etisserant@0: device_type = eval(attrs["device_type_1000"]) etisserant@0: else: etisserant@0: device_type = 0 etisserant@0: Node.AddEntry(0x1000, 0, device_type) etisserant@0: Node.AddEntry(0x1001, 0, 0) etisserant@0: Node.AddEntry(0x1005, 0, 0x00000080) etisserant@0: Node.AddEntry(0x1006, 0, 0) etisserant@0: Node.AddEntry(0x1007, 0, 0) etisserant@0: etisserant@0: if "manufacturer_device_name_1008" in attrs: etisserant@0: manufacturer_device_name = attrs["manufacturer_device_name_1008"] etisserant@0: else: etisserant@0: manufacturer_device_name = "" etisserant@0: Node.AddEntry(0x1008, 0, manufacturer_device_name) etisserant@0: etisserant@0: if "manufacturer_hardware_version_1009" in attrs: etisserant@0: manufacturer_hardware_version = attrs["manufacturer_hardware_version_1009"] etisserant@0: else: etisserant@0: manufacturer_hardware_version = "__DATE__" etisserant@0: Node.AddEntry(0x1009, 0, manufacturer_hardware_version) etisserant@0: etisserant@0: if "manufacturer_software_version_100A" in attrs: etisserant@0: manufacturer_software_version = attrs["manufacturer_software_version_100A"] etisserant@0: else: etisserant@0: manufacturer_software_version = 0 etisserant@0: Node.AddEntry(0x100A, 0, manufacturer_software_version) etisserant@0: etisserant@0: if "vendor_id_1018" in attrs: etisserant@0: vendor_id = eval(attrs["vendor_id_1018"]) etisserant@0: else: etisserant@0: vendor_id = 0 etisserant@0: if "product_code_1018" in attrs: etisserant@0: product_code = eval(attrs["product_code_1018"]) etisserant@0: else: etisserant@0: product_code = 0 etisserant@0: if "revision_number_1018" in attrs: etisserant@0: revision_number = eval(attrs["revision_number_1018"]) etisserant@0: else: etisserant@0: revision_number = 0 etisserant@0: if "serial_number_1018" in attrs: etisserant@0: serial_number = eval(attrs["serial_number_1018"]) etisserant@0: else: etisserant@0: serial_number = 0 etisserant@0: Node.AddEntry(0x1018, 1, vendor_id) etisserant@0: Node.AddEntry(0x1018, 2, product_code) etisserant@0: Node.AddEntry(0x1018, 3, revision_number) etisserant@0: Node.AddEntry(0x1018, 4, serial_number) etisserant@0: etisserant@0: def stopNode(): etisserant@0: heartBeatProducer() etisserant@0: sdoServer() etisserant@0: etisserant@0: #------------------------------------------------------------------------------- etisserant@0: # Creation of PDO in Object Dictionary etisserant@0: #------------------------------------------------------------------------------- etisserant@0: etisserant@0: def startPdo(attrs): etisserant@0: global currentPdoIndex etisserant@0: global currentMaxObjects etisserant@0: global currentNbMappedObjects etisserant@0: global currentBitsMapped etisserant@0: global maxObjects etisserant@0: etisserant@0: cobId = 0 etisserant@0: transmissionType = 253 # Default is on request. Why not ? etisserant@0: etisserant@0: # Find the type of the PDO and search the index of the last added etisserant@0: type = attrs["type_rx_tx"] etisserant@0: index = nextPdoIndex[type] etisserant@0: etisserant@0: # If the index of the PDO is define, verify that it has a good index etisserant@0: if "index_communication_parameter" in attrs: etisserant@0: index = eval(attrs["index_communication_parameter"]) etisserant@0: if type == "rx" and not 0x1400 <= index <= 0x15FF: etisserant@0: raise ValueError, """!!! Abort because Index PDO receive : 0x%04X not valid. etisserant@0: Valid index is 0x1400 ... 0x15FF"""%index etisserant@0: if type == "tx" and not 0x1800 <= index <= 0x19FF: etisserant@0: raise ValueError, """!!! Abort because Index PDO transmit : 0x%04X not valid. etisserant@0: Valid index is 0x1800 ... 0x19FF"""%index etisserant@0: etisserant@0: # Extract the PDO communication parameters etisserant@0: if "cob_id" == attrs: etisserant@0: cobId = eval(attrs["cob_id"]) etisserant@0: if "max_objects_in_pdo" == attrs: etisserant@0: maxObjects = eval(attrs["max_objects_in_pdo"]) etisserant@0: if "transmission_type" in attrs: etisserant@0: transmissionType = eval(attrs["transmission_type"]) etisserant@0: etisserant@0: if Node.IsEntry(index): etisserant@0: raise ValueError, """!!! Abort because the PDO at index : 0x%04X have been already defined."""%index etisserant@0: etisserant@0: # Communication parameters etisserant@0: Node.AddEntry(index, 1, cobId) etisserant@0: Node.AddEntry(index, 2, transmissionType) etisserant@0: etisserant@0: # Mapping parameters etisserant@0: mapping_index = index + 0x200 etisserant@0: for i in xrange(1, maxObjects + 1): etisserant@0: Node.AddEntry(mapping_index, i, 0x0) etisserant@0: etisserant@0: currentPdoIndex = index etisserant@0: currentMaxObjects = maxObjects etisserant@0: currentBitsMapped = 0 etisserant@0: currentNbMappedObjects = 0 etisserant@0: etisserant@0: nextPdoIndex[type] = index + 1 etisserant@0: etisserant@0: def startMappedObject(attrs): etisserant@0: global currentPdoIndex etisserant@0: global currentMaxObjects etisserant@0: global currentNbMappedObjects etisserant@0: global currentBitsMapped etisserant@0: etisserant@0: index = currentPdoIndex etisserant@0: mapping_index = index + 0x200 etisserant@0: etisserant@0: indexObject = eval(attrs["index"]) etisserant@0: subIndexObject = eval(attrs["sub_index"]) etisserant@0: sizeInBitsObject = eval(attrs["size_in_bits"]) etisserant@0: etisserant@0: if currentMaxObjects == 0: etisserant@0: raise ValueError, """!!! Abort because of a bogue for mapped object (defined at index 0x%04X, subIndex 0x%025X) etisserant@0: in PDO. index : 0x%04X is undefined."""%(indexObject,subindexObject,mapping_index) etisserant@0: if currentNbMappedObjects >= currentMaxObjects: etisserant@0: raise ValueError, """!!! Abort mapping object (defined at index 0x%04X, subIndex 0x%02X) etisserant@0: in PDO index 0x%04X. max objects (%d) reached."""%(IndexObject,subIndexObject,mapping_index,pdo[mapping_index]["maxObjects"]) etisserant@0: if currentBitsMapped + sizeInBitsObject > 64: etisserant@0: raise ValueError, """!!! Abort mapping object (defined at index 0x%04X, subIndex 0x%02X) etisserant@0: in PDO index 0x%04X. No room to put %d bits in the PDO."""%(IndexObject,subIndexObject,mapping_index,sizeInBitsObject) etisserant@0: etisserant@0: value = eval("0x%04X%02X%02X"%(indexObject,subIndexObject,sizeInBitsObject)) etisserant@0: Node.SetEntry(mapping_index, currentNbMappedObjects + 1, value) etisserant@0: etisserant@0: currentNbMappedObjects += 1 etisserant@0: currentBitsMapped += sizeInBitsObject etisserant@0: etisserant@0: #------------------------------------------------------------------------------- etisserant@0: # Creation of mapped variable and table etisserant@0: #------------------------------------------------------------------------------- etisserant@0: etisserant@0: def startMappedVariable(attrs): etisserant@0: name = attrs["name"] etisserant@0: index = eval(attrs["index"]) etisserant@0: subIndex = eval(attrs["sub_index"]) etisserant@0: etisserant@0: if "size_in_bits" in attrs: etisserant@0: size = eval(attrs["size_in_bits"]) # Numeric variable etisserant@0: if "type" in attrs: etisserant@0: type = attrs["type"] etisserant@0: if (type == "UNS"): etisserant@0: type = "UNSIGNED" etisserant@0: else: # Default type etisserant@0: type = "UNSIGNED" etisserant@0: typename = "%s%d"%(type,size) etisserant@0: etisserant@0: type_index = Manager.GetTypeIndex(typename, False) etisserant@0: if type_index == None: etisserant@0: raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : Unrecognized type : %s"""%(name,index,subIndex,typename) etisserant@0: etisserant@0: # Begin ValueRange support etisserant@0: if "min_value" in attrs or "max_value" in attrs: etisserant@0: if "min_value" in attrs and "max_value" in attrs: etisserant@0: minValue = eval(attrs["min_value"]) etisserant@0: maxValue = eval(attrs["max_value"]) etisserant@0: if (minValue > maxValue): etisserant@0: raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : error in value-range : min > max"""%(name,index,subIndex) etisserant@0: else: etisserant@0: raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : You have defined only a min or a max value. \nIf you define one, you must define both."""%(name,index,subIndex) etisserant@0: etisserant@0: type_index = findRangeType(type_index, minValue, maxValue) etisserant@0: if type_index == None: etisserant@0: raise ValueError, """!!! Sorry, too many different value range have been defined""" etisserant@0: # End ValueRange support etisserant@0: etisserant@0: if "size_in_byte" in attrs: etisserant@0: size = eval(attrs["size_in_byte"]) # String variable etisserant@0: type_index = findStringType(Manager.GetTypeIndex("VISIBLE_STRING", False), size) etisserant@0: if type_index == None: etisserant@0: raise ValueError, """!!! Sorry, too many different string length have been defined""" etisserant@0: etisserant@0: if "access" in attrs: etisserant@0: access = attrs["access"].lower() etisserant@0: else: etisserant@0: access = "rw" # default value etisserant@0: etisserant@0: if index < 0x2000 or index > 0xBFFF: etisserant@0: raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : Variable can't be defined using this index-subindex."""%(name,index,subIndex) etisserant@0: etisserant@0: if subIndex == 0: etisserant@0: Node.AddMappingEntry(index, name = name, struct = 1) etisserant@0: elif subIndex == 1: etisserant@0: Node.AddMappingEntry(index, struct = 3) etisserant@0: Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False}) etisserant@0: result = Node.AddMappingEntry(index, subIndex, values = {"name" : name, "type" : type_index, "access" : access, "pdo" : True}) etisserant@0: etisserant@0: if result: etisserant@0: Node.AddEntry(index, subIndex, 0) etisserant@0: else: etisserant@0: raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : Unable to map"""%(name,index,subIndex) etisserant@0: etisserant@0: def startMappedTable(attrs): etisserant@0: name = attrs["name"] etisserant@0: number_elements = eval(attrs["number_elements"]) etisserant@0: index = eval(attrs["index"]) etisserant@0: etisserant@0: if "size_in_bits" in attrs: etisserant@0: size = eval(attrs["size_in_bits"]) # Numeric variable etisserant@0: if "type" in attrs: etisserant@0: type = attrs["type"] etisserant@0: if (type == "UNS"): etisserant@0: type = "UNSIGNED" etisserant@0: else: # Default type etisserant@0: type = "UNSIGNED" etisserant@0: typename = "%s%d"%(type,size) etisserant@0: etisserant@0: type_index = Manager.GetTypeIndex(typename, False) etisserant@0: if type_index == None: etisserant@0: raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : Unrecognized type : %s"""%(name,index,typename) etisserant@0: etisserant@0: # Begin ValueRange support etisserant@0: if "min_value" in attrs or "max_value" in attrs: etisserant@0: if "min_value" in attrs and "max_value" in attrs: etisserant@0: minValue = eval(attrs["min_value"]) etisserant@0: maxValue = eval(attrs["max_value"]) etisserant@0: if (minValue > maxValue): etisserant@0: raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : error in value-range : min > max"""%(name,index) etisserant@0: else: etisserant@0: raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : You have defined only a min or a max value. \nIf you define one, you must define both."""%(name,index) etisserant@0: etisserant@0: type_index = findRangeType(type_index, minValue, maxValue) etisserant@0: if type_index == None: etisserant@0: raise ValueError, """!!! Sorry, too many different value range have been defined""" etisserant@0: # End ValueRange support etisserant@0: etisserant@0: if "size_in_byte" in attrs: etisserant@0: size = eval(attrs["size_in_byte"]) # String variable etisserant@0: type_index = findStringType(Manager.GetTypeIndex("VISIBLE_STRING", False), size) etisserant@0: if type_index == None: etisserant@0: raise ValueError, """!!! Sorry, too many different string length have been defined""" etisserant@0: etisserant@0: if "access" in attrs: etisserant@0: access = attrs["access"].lower() etisserant@0: else: etisserant@0: access = "rw" # default value etisserant@0: etisserant@0: if index < 0x2000 or index > 0xBFFF: etisserant@0: raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : Variable can't be defined using this index-subindex."""%(name,index) etisserant@0: etisserant@0: result = Node.AddMappingEntry(index, name = name, struct = 7) etisserant@0: if not result: etisserant@0: raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : Unable to map because a variable or a table is using this index"""%(name,index) etisserant@0: Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False}) etisserant@0: Node.AddMappingEntry(index, 1, values = {"name" : name, "type" : type_index, "access" : access, "pdo" : True, "nbmax" : number_elements}) etisserant@0: etisserant@0: for subIndex in xrange(1,number_elements+1): etisserant@0: Node.AddEntry(index, subIndex, 0) etisserant@0: etisserant@0: def findRangeType(type, minValue, maxValue): etisserant@0: index = 0xA0 etisserant@0: while index < 0x100 and Node.IsEntry(index): etisserant@0: current_type = Node.GetEntry(index, 1) etisserant@0: if current_type == type: etisserant@0: current_minValue = Node.GetEntry(index, 2) etisserant@0: current_maxValue = Node.GetEntry(index, 3) etisserant@0: if current_minValue == minValue and current_maxValue == maxValue: etisserant@0: return index etisserant@0: index += 1 etisserant@0: if index < 0x100: etisserant@0: infos = Manager.GetEntryInfos(type, False) etisserant@0: name = "%s[%d-%d]"%(infos["name"], minValue, maxValue) etisserant@0: Node.AddMappingEntry(index, name = name, struct = 3, size = infos["size"], default = infos["default"]) etisserant@0: Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False}) etisserant@0: Node.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x02, "access" : "ro", "pdo" : False}) etisserant@0: Node.AddMappingEntry(index, 2, values = {"name" : "Minimum Value", "type" : type, "access" : "ro", "pdo" : False}) etisserant@0: Node.AddMappingEntry(index, 3, values = {"name" : "Maximum Value", "type" : type, "access" : "ro", "pdo" : False}) etisserant@0: Node.AddEntry(index, 1, type) etisserant@0: Node.AddEntry(index, 2, minValue) etisserant@0: Node.AddEntry(index, 3, maxValue) etisserant@0: return index etisserant@0: return None etisserant@0: etisserant@0: def findStringType(type, length): etisserant@0: index = 0xA0 etisserant@0: while index < 0x100 and Node.IsEntry(index): etisserant@0: current_type = Node.GetEntry(index, 1) etisserant@0: if current_type == type: etisserant@0: current_length = Node.GetEntry(index, 2) etisserant@0: if current_length == length: etisserant@0: return index etisserant@0: index += 1 etisserant@0: if index < 0x100: etisserant@0: infos = Manager.GetEntryInfos(type, False) etisserant@0: name = "%s%d"%(Manager.GetTypeName(type), length) etisserant@0: Node.AddMappingEntry(index, name = name, struct = 3, size = infos["size"], default = infos["default"]) etisserant@0: Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False}) etisserant@0: Node.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x02, "access" : "ro", "pdo" : False}) etisserant@0: Node.AddMappingEntry(index, 2, values = {"name" : "Length", "type" : 0x02, "access" : "ro", "pdo" : False}) etisserant@0: Node.AddEntry(index, 1, type) etisserant@0: Node.AddEntry(index, 2, length) etisserant@0: return index etisserant@0: return None etisserant@0: etisserant@0: #------------------------------------------------------------------------------- etisserant@0: # Creation HeartBeat Producer & Consumers etisserant@0: #------------------------------------------------------------------------------- etisserant@0: etisserant@0: def heartBeatProducer(): etisserant@0: Node.AddEntry(0x1017, 0, 0) etisserant@0: etisserant@0: def startHeartBeatConsumers(attrs): etisserant@0: nombre = eval(attrs["nombre"]) etisserant@0: for i in xrange(nombre): etisserant@0: Node.AddEntry(0x1016, i + 1, 0) etisserant@0: etisserant@0: #------------------------------------------------------------------------------- etisserant@0: # Creation of SDO Server & Clients etisserant@0: #------------------------------------------------------------------------------- etisserant@0: etisserant@0: def sdoServer(): etisserant@0: Node.AddEntry(0x1200, 1, 0x600 + Node.GetNodeID()) etisserant@0: Node.AddEntry(0x1200, 2, 0x580 + Node.GetNodeID()) etisserant@0: etisserant@0: def startSdoClients(attrs): etisserant@0: nombre = eval(attrs["nombre"]) etisserant@0: for i in xrange(nombre): etisserant@0: Node.AddEntry(0x1280 + i, 1, 0x600) etisserant@0: Node.AddEntry(0x1280 + i, 2, 0x580) etisserant@0: Node.AddEntry(0x1280 + i, 3, 0) etisserant@0: etisserant@0: #------------------------------------------------------------------------------- etisserant@0: # Parse file with Saxe etisserant@0: #------------------------------------------------------------------------------- etisserant@0: etisserant@0: def ParseFile(filepath): etisserant@0: xmlfile = open(filepath,"r") etisserant@0: Parser = expat.ParserCreate() etisserant@0: Parser.StartElementHandler = StartElement etisserant@0: Parser.EndElementHandler = EndElement etisserant@0: Parser.CharacterDataHandler = CharacterData etisserant@0: ParserStatus = Parser.ParseFile(xmlfile) etisserant@0: xmlfile.close() etisserant@0: etisserant@0: def GenerateNode(filepath, manager): etisserant@0: global Node etisserant@0: global Manager etisserant@0: Manager = manager etisserant@0: Node = node.Node() etisserant@0: ParseFile(filepath) etisserant@0: return Node etisserant@0: etisserant@0: #------------------------------------------------------------------------------- etisserant@0: # Main Function etisserant@0: #------------------------------------------------------------------------------- etisserant@0: etisserant@0: if __name__ == '__main__': etisserant@0: ParseFile("test.xml") etisserant@0: