objdictgen/xml_in.py
changeset 279 9b69f2fabafe
parent 278 9d41c53dadac
child 280 d9b232ec7057
equal deleted inserted replaced
278:9d41c53dadac 279:9b69f2fabafe
     1 #!/usr/bin/env python
       
     2 # -*- coding: utf-8 -*-
       
     3 
       
     4 #This file is part of CanFestival, a library implementing CanOpen Stack. 
       
     5 #
       
     6 #Copyright (C): Edouard TISSERANT, Francis DUPIN and Laurent BESSARD
       
     7 #
       
     8 #See COPYING file for copyrights details.
       
     9 #
       
    10 #This library is free software; you can redistribute it and/or
       
    11 #modify it under the terms of the GNU Lesser General Public
       
    12 #License as published by the Free Software Foundation; either
       
    13 #version 2.1 of the License, or (at your option) any later version.
       
    14 #
       
    15 #This library is distributed in the hope that it will be useful,
       
    16 #but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    17 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    18 #Lesser General Public License for more details.
       
    19 #
       
    20 #You should have received a copy of the GNU Lesser General Public
       
    21 #License along with this library; if not, write to the Free Software
       
    22 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    23 
       
    24 from xml.parsers import expat
       
    25 
       
    26 import node
       
    27 from node import *
       
    28 
       
    29 maxObjects = 8
       
    30 
       
    31 currentPDOIndex = 0
       
    32 currentBitsMapped = 0
       
    33 currentMaxObjects = 0
       
    34 currentNbMappedObjects = 0
       
    35 
       
    36 nextPdoIndex = {"rx":0x1400,"tx":0x1800}
       
    37 
       
    38 valid_elements = ["node","heartbeat_consumers","sdo_clients","pdo","mapped_object",
       
    39     "pdo_param","pdo_receive","pdo_transmit","mapped_variable","mapped_table",
       
    40     "mapped_string_variable","mapped_string_table"]
       
    41 
       
    42 #-------------------------------------------------------------------------------
       
    43 #                       Callback method of parse
       
    44 #-------------------------------------------------------------------------------
       
    45 
       
    46 def StartElement(name, attrs):
       
    47     if name in valid_elements:
       
    48         if name == "node":
       
    49             startNode(attrs)
       
    50         elif name == "heartbeat_consumers":
       
    51             startHeartBeatConsumers(attrs)
       
    52         elif name == "sdo_clients":
       
    53             startSdoClients(attrs)
       
    54         elif name in ["pdo_param","pdo_receive","pdo_transmit"]:
       
    55             raise ValueError, """!!! The XML grammar has changed.
       
    56 Please, open your xml file, delete the tags pdo_param, pdo_receive and pdo_transmit.
       
    57 Use instead the tag pdo for each pdo to create, and (optional) use the tag mapped_object (menu pdo/map and object ...)."""
       
    58         elif name == "pdo":
       
    59             startPdo(attrs)
       
    60         elif name == "mapped_object":
       
    61             startMappedObject(attrs)
       
    62         elif name == "mapped_variable":
       
    63             startMappedVariable(attrs)
       
    64         elif name == "mapped_table":
       
    65             startMappedTable(attrs)
       
    66         elif name == "mapped_string_variable":
       
    67             startMappedVariable(attrs)
       
    68         elif name == "mapped_string_table":
       
    69             startMappedTable(attrs)
       
    70 
       
    71 def EndElement(name):
       
    72     if name in valid_elements:
       
    73        if name == "node":
       
    74            stopNode()
       
    75 
       
    76 def CharacterData(data):
       
    77     pass
       
    78 
       
    79 #-------------------------------------------------------------------------------
       
    80 #                          Creation of Node
       
    81 #-------------------------------------------------------------------------------
       
    82 
       
    83 def startNode(attrs):
       
    84     name = attrs["name"]
       
    85     Node.SetNodeName(name)
       
    86     
       
    87     if "node_id" in attrs and len(attrs["node_id"]) > 0:
       
    88         node_id = eval(attrs["node_id"])
       
    89     else:
       
    90         node_id = 0x01  # We define here a default node_id. 
       
    91     Node.SetNodeID(node_id)
       
    92     
       
    93     typeNode = attrs["type_node"]
       
    94     Node.SetNodeType(typeNode)
       
    95     
       
    96     if "device_type_1000" in attrs:
       
    97         device_type = eval(attrs["device_type_1000"])
       
    98     else:
       
    99         device_type = 0
       
   100     Node.AddEntry(0x1000, 0, device_type)
       
   101     Node.AddEntry(0x1001, 0, 0)
       
   102     Node.AddEntry(0x1005, 0, 0x00000080)
       
   103     Node.AddEntry(0x1006, 0, 0)
       
   104     Node.AddEntry(0x1007, 0, 0)
       
   105 
       
   106     if "manufacturer_device_name_1008" in attrs:
       
   107         manufacturer_device_name = attrs["manufacturer_device_name_1008"]
       
   108     else:
       
   109         manufacturer_device_name = ""
       
   110     Node.AddEntry(0x1008, 0, manufacturer_device_name)
       
   111     
       
   112     if "manufacturer_hardware_version_1009" in attrs:
       
   113         manufacturer_hardware_version = attrs["manufacturer_hardware_version_1009"]
       
   114     else:
       
   115         manufacturer_hardware_version = "__DATE__"
       
   116     Node.AddEntry(0x1009, 0, manufacturer_hardware_version)
       
   117 
       
   118     if "manufacturer_software_version_100A" in attrs:
       
   119         manufacturer_software_version = attrs["manufacturer_software_version_100A"]
       
   120     else:
       
   121         manufacturer_software_version = 0
       
   122     Node.AddEntry(0x100A, 0,  manufacturer_software_version)
       
   123 
       
   124     if "vendor_id_1018" in attrs:
       
   125         vendor_id = eval(attrs["vendor_id_1018"])
       
   126     else:
       
   127         vendor_id = 0
       
   128     if "product_code_1018" in attrs:
       
   129         product_code = eval(attrs["product_code_1018"])
       
   130     else:
       
   131         product_code = 0
       
   132     if "revision_number_1018" in attrs:
       
   133         revision_number = eval(attrs["revision_number_1018"])
       
   134     else:
       
   135         revision_number = 0
       
   136     if "serial_number_1018" in attrs:
       
   137         serial_number = eval(attrs["serial_number_1018"])
       
   138     else:
       
   139         serial_number = 0
       
   140     Node.AddEntry(0x1018, 1, vendor_id)
       
   141     Node.AddEntry(0x1018, 2, product_code)
       
   142     Node.AddEntry(0x1018, 3, revision_number)
       
   143     Node.AddEntry(0x1018, 4, serial_number)
       
   144 
       
   145 def stopNode():
       
   146     heartBeatProducer()
       
   147     sdoServer()
       
   148 
       
   149 #-------------------------------------------------------------------------------
       
   150 #                      Creation of PDO in Object Dictionary
       
   151 #-------------------------------------------------------------------------------
       
   152 
       
   153 def startPdo(attrs):
       
   154     global currentPdoIndex
       
   155     global currentMaxObjects
       
   156     global currentNbMappedObjects
       
   157     global currentBitsMapped
       
   158     global maxObjects
       
   159     
       
   160     cobId = 0
       
   161     transmissionType = 253 # Default is on request. Why not ?
       
   162 
       
   163     # Find the type of the PDO and search the index of the last added
       
   164     type = attrs["type_rx_tx"]
       
   165     index = nextPdoIndex[type]
       
   166     
       
   167     # If the index of the PDO is define, verify that it has a good index
       
   168     if "index_communication_parameter" in attrs:
       
   169         index = eval(attrs["index_communication_parameter"])
       
   170     if type == "rx" and not 0x1400 <= index <= 0x15FF:
       
   171         raise ValueError, """!!! Abort because Index PDO receive : 0x%04X not valid.
       
   172 Valid index is 0x1400 ... 0x15FF"""%index
       
   173     if type == "tx" and not 0x1800 <= index <= 0x19FF:
       
   174         raise ValueError, """!!! Abort because Index PDO transmit : 0x%04X not valid.
       
   175 Valid index is 0x1800 ... 0x19FF"""%index
       
   176     
       
   177     # Extract the PDO communication parameters
       
   178     if "cob_id" == attrs:
       
   179         cobId = eval(attrs["cob_id"])
       
   180     if "max_objects_in_pdo" == attrs:
       
   181         maxObjects = eval(attrs["max_objects_in_pdo"])
       
   182     if "transmission_type" in attrs:
       
   183         transmissionType = eval(attrs["transmission_type"])
       
   184 
       
   185     if Node.IsEntry(index):
       
   186         raise ValueError, """!!! Abort because the PDO at index : 0x%04X have been already defined."""%index
       
   187 
       
   188     # Communication parameters
       
   189     Node.AddEntry(index, 1, cobId)
       
   190     Node.AddEntry(index, 2, transmissionType)
       
   191     
       
   192     # Mapping parameters
       
   193     mapping_index = index + 0x200
       
   194     for i in xrange(1, maxObjects + 1):
       
   195         Node.AddEntry(mapping_index, i, 0x0)
       
   196 
       
   197     currentPdoIndex = index
       
   198     currentMaxObjects = maxObjects
       
   199     currentBitsMapped = 0
       
   200     currentNbMappedObjects = 0
       
   201     
       
   202     nextPdoIndex[type] = index + 1
       
   203 
       
   204 def startMappedObject(attrs):
       
   205     global currentPdoIndex
       
   206     global currentMaxObjects
       
   207     global currentNbMappedObjects
       
   208     global currentBitsMapped
       
   209     
       
   210     index = currentPdoIndex
       
   211     mapping_index = index + 0x200
       
   212     
       
   213     indexObject = eval(attrs["index"])
       
   214     subIndexObject = eval(attrs["sub_index"])
       
   215     sizeInBitsObject = eval(attrs["size_in_bits"])
       
   216 
       
   217     if currentMaxObjects == 0:
       
   218         raise ValueError, """!!! Abort because of a bogue for mapped object (defined at index 0x%04X, subIndex 0x%025X)
       
   219 in PDO. index : 0x%04X is undefined."""%(indexObject,subindexObject,mapping_index)
       
   220     if currentNbMappedObjects >= currentMaxObjects:
       
   221         raise ValueError, """!!! Abort mapping object (defined at index 0x%04X, subIndex 0x%02X)
       
   222 in PDO index 0x%04X. max objects (%d) reached."""%(IndexObject,subIndexObject,mapping_index,pdo[mapping_index]["maxObjects"])
       
   223     if currentBitsMapped + sizeInBitsObject > 64:
       
   224         raise ValueError, """!!! Abort mapping object (defined at index 0x%04X, subIndex 0x%02X)
       
   225 in PDO index 0x%04X. No room to put %d bits in the PDO."""%(IndexObject,subIndexObject,mapping_index,sizeInBitsObject)
       
   226 
       
   227     value = eval("0x%04X%02X%02X"%(indexObject,subIndexObject,sizeInBitsObject))
       
   228     Node.SetEntry(mapping_index, currentNbMappedObjects + 1, value)
       
   229     
       
   230     currentNbMappedObjects += 1
       
   231     currentBitsMapped += sizeInBitsObject
       
   232 
       
   233 #-------------------------------------------------------------------------------
       
   234 #                    Creation of mapped variable and table 
       
   235 #-------------------------------------------------------------------------------
       
   236 
       
   237 def startMappedVariable(attrs):
       
   238     name = attrs["name"]
       
   239     index = eval(attrs["index"])
       
   240     subIndex = eval(attrs["sub_index"])
       
   241     
       
   242     if "size_in_bits" in attrs:
       
   243         size = eval(attrs["size_in_bits"]) # Numeric variable
       
   244         if "type" in attrs:
       
   245             type = attrs["type"]
       
   246             if (type == "UNS"):
       
   247                 type = "UNSIGNED"
       
   248         else: # Default type
       
   249             type = "UNSIGNED"
       
   250         typename = "%s%d"%(type,size)
       
   251 
       
   252         type_index = Manager.GetTypeIndex(typename, False)
       
   253         if type_index == None:
       
   254             raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : Unrecognized type : %s"""%(name,index,subIndex,typename)
       
   255         
       
   256         # Begin ValueRange support
       
   257         if "min_value" in attrs or "max_value" in attrs:
       
   258             if "min_value" in attrs and "max_value" in attrs:
       
   259                 minValue = eval(attrs["min_value"])
       
   260                 maxValue = eval(attrs["max_value"])
       
   261                 if (minValue > maxValue):
       
   262                     raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : error in value-range : min > max"""%(name,index,subIndex)
       
   263             else:
       
   264                 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)
       
   265         
       
   266             type_index = findRangeType(type_index, minValue, maxValue)
       
   267             if type_index == None:
       
   268                 raise ValueError, """!!! Sorry, too many different value range have been defined"""
       
   269         # End ValueRange support    
       
   270 
       
   271     if "size_in_byte" in attrs:
       
   272         size = eval(attrs["size_in_byte"]) # String variable
       
   273         type_index = findStringType(Manager.GetTypeIndex("VISIBLE_STRING", False), size)
       
   274         if type_index == None:
       
   275             raise ValueError, """!!! Sorry, too many different string length have been defined"""
       
   276           
       
   277     if "access" in attrs:
       
   278         access = attrs["access"].lower()
       
   279     else: 
       
   280         access = "rw" # default value
       
   281  
       
   282     if index < 0x2000 or index > 0xBFFF:
       
   283         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)
       
   284 
       
   285     if subIndex == 0:
       
   286         Node.AddMappingEntry(index, name = name, struct = 1)
       
   287     elif subIndex == 1:
       
   288         Node.AddMappingEntry(index, struct = 3)
       
   289         Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False})    
       
   290     result = Node.AddMappingEntry(index, subIndex, values = {"name" : name, "type" : type_index, "access" : access, "pdo" : True})
       
   291     
       
   292     if result:
       
   293         Node.AddEntry(index, subIndex, 0)
       
   294     else:
       
   295         raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : Unable to map"""%(name,index,subIndex)
       
   296 
       
   297 def startMappedTable(attrs):
       
   298     name = attrs["name"]
       
   299     number_elements = eval(attrs["number_elements"])
       
   300     index = eval(attrs["index"])
       
   301 
       
   302     if "size_in_bits" in attrs:
       
   303         size = eval(attrs["size_in_bits"]) # Numeric variable
       
   304         if "type" in attrs:
       
   305             type = attrs["type"]
       
   306             if (type == "UNS"):
       
   307                 type = "UNSIGNED"
       
   308         else: # Default type
       
   309             type = "UNSIGNED"
       
   310         typename = "%s%d"%(type,size)
       
   311 
       
   312         type_index = Manager.GetTypeIndex(typename, False)
       
   313         if type_index == None:
       
   314             raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : Unrecognized type : %s"""%(name,index,typename)
       
   315         
       
   316         # Begin ValueRange support
       
   317         if "min_value" in attrs or "max_value" in attrs:
       
   318             if "min_value" in attrs and "max_value" in attrs:
       
   319                 minValue = eval(attrs["min_value"])
       
   320                 maxValue = eval(attrs["max_value"])
       
   321                 if (minValue > maxValue):
       
   322                     raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : error in value-range : min > max"""%(name,index)
       
   323             else:
       
   324                 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)
       
   325         
       
   326             type_index = findRangeType(type_index, minValue, maxValue)
       
   327             if type_index == None:
       
   328                 raise ValueError, """!!! Sorry, too many different value range have been defined"""
       
   329         # End ValueRange support
       
   330 
       
   331     if "size_in_byte" in attrs:
       
   332         size = eval(attrs["size_in_byte"]) # String variable
       
   333         type_index = findStringType(Manager.GetTypeIndex("VISIBLE_STRING", False), size)
       
   334         if type_index == None:
       
   335             raise ValueError, """!!! Sorry, too many different string length have been defined"""
       
   336 	      
       
   337     if "access" in attrs:
       
   338         access = attrs["access"].lower()
       
   339     else:
       
   340         access = "rw" # default value    
       
   341 
       
   342     if index < 0x2000 or index > 0xBFFF:
       
   343         raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : Variable can't be defined using this index-subindex."""%(name,index)
       
   344 
       
   345     result = Node.AddMappingEntry(index, name = name, struct = 7)
       
   346     if not result:
       
   347         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)
       
   348     Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False})
       
   349     Node.AddMappingEntry(index, 1, values = {"name" : name, "type" : type_index, "access" : access, "pdo" : True, "nbmax" : number_elements})
       
   350     
       
   351     for subIndex in xrange(1,number_elements+1):
       
   352         Node.AddEntry(index, subIndex, 0)
       
   353 
       
   354 def findRangeType(type, minValue, maxValue):
       
   355     index = 0xA0
       
   356     while index < 0x100 and Node.IsEntry(index):
       
   357         current_type = Node.GetEntry(index, 1)
       
   358         if current_type == type:
       
   359             current_minValue = Node.GetEntry(index, 2)
       
   360             current_maxValue = Node.GetEntry(index, 3)
       
   361             if current_minValue == minValue and current_maxValue == maxValue:
       
   362                 return index
       
   363         index += 1
       
   364     if index < 0x100:
       
   365         infos = Manager.GetEntryInfos(type, False)
       
   366         name = "%s[%d-%d]"%(infos["name"], minValue, maxValue)
       
   367         Node.AddMappingEntry(index, name = name, struct = 3, size = infos["size"], default = infos["default"])
       
   368         Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False})
       
   369         Node.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x02, "access" : "ro", "pdo" : False})
       
   370         Node.AddMappingEntry(index, 2, values = {"name" : "Minimum Value", "type" : type, "access" : "ro", "pdo" : False})
       
   371         Node.AddMappingEntry(index, 3, values = {"name" : "Maximum Value", "type" : type, "access" : "ro", "pdo" : False})
       
   372         Node.AddEntry(index, 1, type)
       
   373         Node.AddEntry(index, 2, minValue)
       
   374         Node.AddEntry(index, 3, maxValue)
       
   375         return index
       
   376     return None
       
   377 
       
   378 def findStringType(type, length):
       
   379     index = 0xA0
       
   380     while index < 0x100 and Node.IsEntry(index):
       
   381         current_type = Node.GetEntry(index, 1)
       
   382         if current_type == type:
       
   383             current_length = Node.GetEntry(index, 2)
       
   384             if current_length == length:
       
   385                 return index
       
   386         index += 1
       
   387     if index < 0x100:
       
   388         infos = Manager.GetEntryInfos(type, False)
       
   389         name = "%s%d"%(Manager.GetTypeName(type), length)
       
   390         Node.AddMappingEntry(index, name = name, struct = 3, size = infos["size"], default = infos["default"])
       
   391         Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False})
       
   392         Node.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x02, "access" : "ro", "pdo" : False})
       
   393         Node.AddMappingEntry(index, 2, values = {"name" : "Length", "type" : 0x02, "access" : "ro", "pdo" : False})
       
   394         Node.AddEntry(index, 1, type)
       
   395         Node.AddEntry(index, 2, length)
       
   396         return index
       
   397     return None
       
   398 
       
   399 #-------------------------------------------------------------------------------
       
   400 #                   Creation HeartBeat Producer & Consumers
       
   401 #-------------------------------------------------------------------------------
       
   402 
       
   403 def heartBeatProducer():
       
   404     Node.AddEntry(0x1017, 0, 0)
       
   405     
       
   406 def startHeartBeatConsumers(attrs):
       
   407     nombre = eval(attrs["nombre"])
       
   408     for i in xrange(nombre):
       
   409         Node.AddEntry(0x1016, i + 1, 0)		    
       
   410 
       
   411 #-------------------------------------------------------------------------------
       
   412 #                       Creation of SDO Server & Clients
       
   413 #-------------------------------------------------------------------------------
       
   414 
       
   415 def sdoServer():
       
   416     Node.AddEntry(0x1200, 1, 0x600 + Node.GetNodeID())
       
   417     Node.AddEntry(0x1200, 2, 0x580 + Node.GetNodeID())
       
   418     
       
   419 def startSdoClients(attrs):
       
   420     nombre = eval(attrs["nombre"])
       
   421     for i in xrange(nombre):
       
   422         Node.AddEntry(0x1280 + i, 1, 0x600)
       
   423         Node.AddEntry(0x1280 + i, 2, 0x580)
       
   424         Node.AddEntry(0x1280 + i, 3, 0)
       
   425     
       
   426 #-------------------------------------------------------------------------------
       
   427 #                           Parse file with Saxe
       
   428 #-------------------------------------------------------------------------------
       
   429 
       
   430 def ParseFile(filepath):
       
   431     xmlfile = open(filepath,"r")
       
   432     Parser = expat.ParserCreate()
       
   433     Parser.StartElementHandler = StartElement
       
   434     Parser.EndElementHandler = EndElement
       
   435     Parser.CharacterDataHandler = CharacterData
       
   436     ParserStatus = Parser.ParseFile(xmlfile)
       
   437     xmlfile.close()    
       
   438 
       
   439 def GenerateNode(filepath, manager):
       
   440     global Node
       
   441     global Manager
       
   442     Manager = manager
       
   443     Node = node.Node()
       
   444     ParseFile(filepath)
       
   445     return Node
       
   446 
       
   447 #-------------------------------------------------------------------------------
       
   448 #                             Main Function
       
   449 #-------------------------------------------------------------------------------
       
   450 
       
   451 if __name__ == '__main__':
       
   452     ParseFile("test.xml")
       
   453