plugins/canfestival/config_utils.py
changeset 34 2721e6910f5a
parent 27 1db681d34579
child 35 4d7861fc34d4
equal deleted inserted replaced
33:59b84ab7bf8b 34:2721e6910f5a
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
    24 
    24 
    25 from types import *
    25 from types import *
    26 
    26 
    27 # Translation between IEC types and Can Open types
    27 # Translation between IEC types and Can Open types
    28 DicoTypes = {"BOOL":0x01, "SINT":0x02, "INT":0x03,"DINT":0x04,"LINT":0x10,
    28 IECToCOType = {"BOOL":0x01, "SINT":0x02, "INT":0x03,"DINT":0x04,"LINT":0x10,
    29              "USINT":0x05,"UINT":0x06,"UDINT":0x07,"ULINT":0x1B,"REAL":0x08,
    29                "USINT":0x05,"UINT":0x06,"UDINT":0x07,"ULINT":0x1B,"REAL":0x08,
    30              "LREAL":0x11,"STRING":0x09,"BYTE":0x05,"WORD":0x06,"DWORD":0x07,
    30                "LREAL":0x11,"STRING":0x09,"BYTE":0x05,"WORD":0x06,"DWORD":0x07,
    31              "LWORD":0x1B,"WSTRING":0x0B}
    31                "LWORD":0x1B,"WSTRING":0x0B}
    32 
       
    33 DictNameVariable = { "" : 1, "X": 2, "B": 3, "W": 4, "D": 5, "L": 6, "increment": 0x100, 1:("__I", 0x2000), 2:("__Q", 0x4000)}
       
    34 
    32 
    35 # Constants for PDO types 
    33 # Constants for PDO types 
    36 RPDO = 1
    34 RPDO = 1
    37 TPDO = 2
    35 TPDO = 2
       
    36 
    38 SlavePDOType = {"I" : TPDO, "Q" : RPDO}
    37 SlavePDOType = {"I" : TPDO, "Q" : RPDO}
    39 InvertPDOType = {RPDO : TPDO, TPDO : RPDO}
    38 InvertPDOType = {RPDO : TPDO, TPDO : RPDO}
    40 
    39 
    41 GenerateMasterMapping = lambda x:[None] + [(loc_infos["type"], name) for name, loc_infos in x]
    40 VariableIncrement = 0x100
    42 
    41 VariableStartIndex = {TPDO : 0x2000, RPDO : 0x4000}
    43 TrashVariableSizes = {1 : 0x01, 8 : 0x05, 16 : 0x06, 32 : 0x07, 64 : 0x1B}
    42 VariableDirText = {TPDO : "__I", RPDO : "__Q"}
       
    43 VariableTypeOffset = dict(zip(["","X","B","W","D","L"], range(6)))
       
    44 
       
    45 TrashVariables = [(1, 0x01), (8, 0x05), (16, 0x06), (32, 0x07), (64, 0x1B)]
    44 
    46 
    45 def LE_to_BE(value, size):
    47 def LE_to_BE(value, size):
    46     """
    48     """
    47     Convert Little Endian to Big Endian
    49     Convert Little Endian to Big Endian
    48     @param value: value expressed in integer
    50     @param value: value expressed in integer
    52     
    54     
    53     data = ("%" + str(size * 2) + "." + str(size * 2) + "X") % value
    55     data = ("%" + str(size * 2) + "." + str(size * 2) + "X") % value
    54     list_car = [data[i:i+2] for i in xrange(0, len(data), 2)]
    56     list_car = [data[i:i+2] for i in xrange(0, len(data), 2)]
    55     list_car.reverse()
    57     list_car.reverse()
    56     return "".join([chr(int(car, 16)) for car in list_car])
    58     return "".join([chr(int(car, 16)) for car in list_car])
       
    59 
    57 
    60 
    58 def GetNodePDOIndexes(node, type, parameters = False):
    61 def GetNodePDOIndexes(node, type, parameters = False):
    59     """
    62     """
    60     Find the PDO indexes of a node
    63     Find the PDO indexes of a node
    61     @param node: node 
    64     @param node: node 
    72     if not parameters:
    75     if not parameters:
    73         return [idx + 0x200 for idx in indexes]
    76         return [idx + 0x200 for idx in indexes]
    74     else:
    77     else:
    75         return indexes
    78         return indexes
    76 
    79 
       
    80 
    77 def SearchNodePDOMapping(loc_infos, node):
    81 def SearchNodePDOMapping(loc_infos, node):
    78     """
    82     """
    79     Find the PDO indexes of a node
    83     Find the PDO indexes of a node
    80     @param node: node 
    84     @param node: node 
    81     @param type: type of PDO searched (RPDO or TPDO or both)
    85     @param type: type of PDO searched (RPDO or TPDO or both)
    92             for subindex, mapping in enumerate(values):
    96             for subindex, mapping in enumerate(values):
    93                 if subindex != 0 and mapping == model:
    97                 if subindex != 0 and mapping == model:
    94                     return PDOidx, subindex
    98                     return PDOidx, subindex
    95     return None
    99     return None
    96 
   100 
       
   101 
       
   102 def GeneratePDOMappingDCF(idx, cobid, transmittype, pdomapping):
       
   103     """
       
   104     Build concise DCF value for configuring a PDO
       
   105     @param idx: index of PDO parameters
       
   106     @param cobid: PDO generated COB ID
       
   107     @param transmittype : PDO transmit type
       
   108     @param pdomapping: list of PDO mappings
       
   109     @return: a tuple of value and number of parameters to add to DCF 
       
   110     """
       
   111     
       
   112     # Create entry for RPDO or TPDO parameters and Disable PDO
       
   113     dcfdata = LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE((0x80000000 + cobid), 4)
       
   114     # Set Transmit type synchrone
       
   115     dcfdata += LE_to_BE(idx, 2) + LE_to_BE(0x02, 1) + LE_to_BE(0x01, 4) + LE_to_BE(transmittype, 1)
       
   116     # Re-Enable PDO
       
   117     #         ---- INDEX -----   --- SUBINDEX ----   ----- SIZE ------   ------ DATA ------
       
   118     dcfdata += LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE(0x00000000 + cobid, 4)
       
   119     nbparams = 3
       
   120     # Map Variables
       
   121     for subindex, (name, loc_infos) in enumerate(pdomapping):
       
   122         value = (loc_infos["index"] << 16) + (loc_infos["subindex"] << 8) + loc_infos["size"]
       
   123         dcfdata += LE_to_BE(idx + 0x200, 2) + LE_to_BE(subindex + 1, 1) + LE_to_BE(0x04, 4) + LE_to_BE(value, 4)
       
   124         nbparams += 1
       
   125     return dcfdata, nbparams
       
   126 
    97 class ConciseDCFGenerator:
   127 class ConciseDCFGenerator:
    98 
   128 
    99     def __init__(self, nodelist):
   129     def __init__(self, nodelist):
   100         # Dictionary of location informations classed by name
   130         # Dictionary of location informations classed by name
   101         self.DictLocations = {}
   131         self.IECLocations = {}
       
   132         # Dictionary of location that have not been mapped yet
       
   133         self.LocationsNotMapped = {}
   102         # Dictionary of location informations classed by name
   134         # Dictionary of location informations classed by name
   103         self.DictCobID = {}
   135         self.MasterMapping = {}
   104         # Dictionary of location that have not been mapped yet
       
   105         self.DictLocationsNotMapped = {}
       
   106         # List of COB IDs available
   136         # List of COB IDs available
   107         self.ListCobIDAvailable = range(0x180, 0x580)
   137         self.ListCobIDAvailable = range(0x180, 0x580)
   108         self.SlavesPdoNumber = {}
   138         self.SlavesPdoNumber = {}
   109         # Dictionary of mapping value where unexpected variables are stored
   139         # Dictionary of mapping value where unexpected variables are stored
   110         TrashVariableValue = {}
   140         self.TrashVariables = {}
   111         
   141         
   112         self.NodeList = nodelist
   142         self.NodeList = nodelist
   113         self.Manager = self.NodeList.Manager
   143         self.Manager = self.NodeList.Manager
   114         self.MasterNode = self.Manager.GetCurrentNodeCopy()
   144         self.MasterNode = self.Manager.GetCurrentNodeCopy()
   115         self.PrepareMasterNode()
   145         self.PrepareMasterNode()
   116 
   146 
       
   147     
   117     def RemoveUsedNodeCobId(self, node):
   148     def RemoveUsedNodeCobId(self, node):
   118         """
   149         """
   119         Remove all PDO COB ID used by the given node from the list of available COB ID
   150         Remove all PDO COB ID used by the given node from the list of available COB ID
   120         @param node: node
   151         @param node: node
   121         @return: a tuple of number of RPDO and TPDO for the node
   152         @return: a tuple of number of RPDO and TPDO for the node
   135             if pdo_cobid in self.ListCobIDAvailable:
   166             if pdo_cobid in self.ListCobIDAvailable:
   136                 self.ListCobIDAvailable.remove(pdo_cobid)
   167                 self.ListCobIDAvailable.remove(pdo_cobid)
   137         
   168         
   138         return len(nodeRpdoIndexes), len(nodeTpdoIndexes)
   169         return len(nodeRpdoIndexes), len(nodeTpdoIndexes)
   139 
   170 
       
   171     
   140     def PrepareMasterNode(self):
   172     def PrepareMasterNode(self):
   141         """
   173         """
   142         Add mandatory entries for DCF generation into MasterNode.
   174         Add mandatory entries for DCF generation into MasterNode.
   143         """
   175         """
   144         
   176         
   145         # Adding DCF entry into Master node
   177         # Adding DCF entry into Master node
   146         if not self.MasterNode.IsEntry(0x1F22):
   178         if not self.MasterNode.IsEntry(0x1F22):
   147             self.MasterNode.AddEntry(0x1F22, 1, "")
   179             self.MasterNode.AddEntry(0x1F22, 1, "")
   148         self.Manager.AddSubentriesToCurrent(0x1F22, 127, masternode)
   180         self.Manager.AddSubentriesToCurrent(0x1F22, 127, self.MasterNode)
   149         
   181         
   150         # Adding trash mappable variables for unused mapped datas
   182         # Adding trash mappable variables for unused mapped datas
   151         idxTrashVariables = 0x2000 + masternode.GetNodeID()
   183         idxTrashVariables = 0x2000 + self.MasterNode.GetNodeID()
   152         # Add an entry for storing unexpected all variable
   184         # Add an entry for storing unexpected all variable
   153         self.Manager.AddMapVariableToCurrent(idxTrashVariables, "trashvariables", 3, len(TrashVariableSizes), self.MasterNode)
   185         self.Manager.AddMapVariableToCurrent(idxTrashVariables, "trashvariables", 3, len(TrashVariables), self.MasterNode)
   154         for subidx, (size, typeidx) in enumerate(TrashVariableSizes.items()):
   186         for subidx, (size, typeidx) in enumerate(TrashVariables):
   155             # Add a subentry for storing unexpected variable of this size
   187             # Add a subentry for storing unexpected variable of this size
   156             self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, "TRASH%d" % size, "name", None, self.MasterNode)
   188             self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, "TRASH%d" % size, "name", None, self.MasterNode)
   157             self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, typeidx, "type", None, self.MasterNode)
   189             self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, typeidx, "type", None, self.MasterNode)
   158             # Store the mapping value for this entry
   190             # Store the mapping value for this entry
   159             self.TrashVariableValue[size] = (idxTrashVariables << 16) + ((subidx + 1) << 8) + size
   191             self.TrashVariables[size] = (idxTrashVariables << 16) + ((subidx + 1) << 8) + size
   160         
   192         
   161         RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(self.MasterNode)
   193         RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(self.MasterNode)
   162         
   194         
   163         # Store the indexes of the first RPDO and TPDO available for MasterNode
   195         # Store the indexes of the first RPDO and TPDO available for MasterNode
   164         self.CurrentPDOParamsIdx = {RPDO : 0x1400 + RPDOnumber, TPDO : 0x1800 + TPDOnumber}
   196         self.CurrentPDOParamsIdx = {RPDO : 0x1400 + RPDOnumber, TPDO : 0x1800 + TPDOnumber}
   165 
   197 
   166         # Prepare MasterNode with all nodelist slaves
   198         # Prepare MasterNode with all nodelist slaves
   167         for nodeid, nodeinfos in self.NodeList.SlaveNodes.items():
   199         for idx, (nodeid, nodeinfos) in enumerate(self.NodeList.SlaveNodes.items()):
   168             node = nodeinfos["Node"]
   200             node = nodeinfos["Node"]
   169             node.SetNodeID(nodeid)
   201             node.SetNodeID(nodeid)
   170             
   202             
   171             RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(node)
   203             RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(node)
   172             
   204             
   180             TSDO_cobid = node.GetEntry(0x1200,0x02)
   212             TSDO_cobid = node.GetEntry(0x1200,0x02)
   181             if not TSDO_cobid:
   213             if not TSDO_cobid:
   182                 TSDO_cobid = 0x580 + nodeid
   214                 TSDO_cobid = 0x580 + nodeid
   183             
   215             
   184             # Configure Master's SDO parameters entries
   216             # Configure Master's SDO parameters entries
   185             self.Manager.ManageEntriesOfCurrent([0x1280 + nodeid], [], self.MasterNode)
   217             self.Manager.ManageEntriesOfCurrent([0x1280 + idx], [], self.MasterNode)
   186             self.MasterNode.SetEntry(0x1280 + nodeid, 0x01, RSDO_cobid)
   218             self.MasterNode.SetEntry(0x1280 + idx, 0x01, RSDO_cobid)
   187             self.MasterNode.SetEntry(0x1280 + nodeid, 0x02, TSDO_cobid)
   219             self.MasterNode.SetEntry(0x1280 + idx, 0x02, TSDO_cobid)
   188             self.MasterNode.SetEntry(0x1280 + nodeid, 0x03, nodeid)        
   220             self.MasterNode.SetEntry(0x1280 + idx, 0x03, nodeid)        
   189         
   221         
       
   222     
   190     def GetMasterNode(self):
   223     def GetMasterNode(self):
   191         """
   224         """
   192         Return MasterNode.
   225         Return MasterNode.
   193         """
   226         """
   194         return self.MasterNode
   227         return self.MasterNode
   195 
   228 
   196     # Build concise DCF
   229     
   197     def GenerateMappingDCF(cobid, idx, pdomapping, mapped):
       
   198         
       
   199         # Create entry for RPDO or TPDO parameters and Disable PDO
       
   200         dcfdata = LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE((0x80000000 + cobid), 4)
       
   201         # Set Transmit type synchrone
       
   202         dcfdata += LE_to_BE(idx, 2) + LE_to_BE(0x02, 1) + LE_to_BE(0x01, 4) + LE_to_BE(DefaultTransmitTypeSlave, 1)
       
   203         # Re-Enable PDO
       
   204         #         ---- INDEX -----   --- SUBINDEX ----   ----- SIZE ------   ------ DATA ------
       
   205         dcfdata += LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE(0x00000000 + cobid, 4)
       
   206         nbparams = 3
       
   207         if mapped == False and pdomapping != None:
       
   208         # Map Variables
       
   209             for subindex, (name, loc_infos) in enumerate(pdomapping):
       
   210                 value = (loc_infos["index"] << 16) + (loc_infos["subindex"] << 8) + loc_infos["size"]
       
   211                 dcfdata += LE_to_BE(idx + 0x200, 2) + LE_to_BE(subindex + 1, 1) + LE_to_BE(0x04, 4) + LE_to_BE(value, 4)
       
   212                 nbparams += 1
       
   213         return dcfdata, nbparams
       
   214 
       
   215     # Return a cobid not used
       
   216     def GetNewCobID(self, nodeid, type):
   230     def GetNewCobID(self, nodeid, type):
   217         """
   231         """
   218         Select a COB ID from the list of those available
   232         Select a COB ID from the list of those available
   219         @param nodeid: id of the slave node
   233         @param nodeid: id of the slave (int)
   220         @param type: type of PDO (RPDO or TPDO)
   234         @param type: type of PDO (RPDO or TPDO)
   221         @return: a tuple of the COD ID and PDO index or None
   235         @return: a tuple of the COD ID and PDO index or None
   222         """
   236         """
   223         # Verify that there is still some cobid available
   237         # Verify that there is still some cobid available
   224         if len(self.ListCobIDAvailable) == 0:
   238         if len(self.ListCobIDAvailable) == 0:
   247                     return newcobid, 0x1800 + nbSlavePDO
   261                     return newcobid, 0x1800 + nbSlavePDO
   248             # Return the first cobid available if no cobid found
   262             # Return the first cobid available if no cobid found
   249             return self.ListCobIDAvailable.pop(0), 0x1800 + nbSlavePDO
   263             return self.ListCobIDAvailable.pop(0), 0x1800 + nbSlavePDO
   250         
   264         
   251         return None
   265         return None
   252         
   266     
       
   267     
       
   268     def AddParamsToDCF(self, nodeid, data, nbparams):
       
   269         """
       
   270         Select a COB ID from the list of those available
       
   271         @param nodeid: id of the slave (int)
       
   272         @param data: data to add to slave DCF (string)
       
   273         @param nbparams: number of params added to slave DCF (int)
       
   274         """
       
   275         # Get current DCF for slave
       
   276         nodeDCF = self.MasterNode.GetEntry(0x1F22, nodeid)
       
   277         
       
   278         # Extract data and number of params in current DCF
       
   279         if nodeDCF != None and nodeDCF != '':
       
   280             tmpnbparams = [i for i in nodeDCF[:4]]
       
   281             tmpnbparams.reverse()
       
   282             nbparams += int(''.join(["%2.2x"%ord(i) for i in tmpnbparams]), 16)
       
   283             data = nodeDCF[4:] + data
       
   284         
       
   285         # Build new DCF
       
   286         dcf = LE_to_BE(nbparams, 0x04) + data
       
   287         # Set new DCF for slave
       
   288         self.MasterNode.SetEntry(0x1F22, nodeid, dcf)
       
   289     
       
   290     def AddPDOMapping(self, nodeid, pdotype, pdomapping, sync_TPDOs):
       
   291         """
       
   292         Select a COB ID from the list of those available
       
   293         @param nodeid: id of the slave (int)
       
   294         @param pdotype: type of PDO to generated (RPDO or TPDO)
       
   295         @param pdomapping: list od variables to map with PDO
       
   296         """
       
   297         # Get a new cob id
       
   298         result = self.GetNewCobID(nodeid, pdotype)
       
   299         if result:
       
   300             new_cobid, new_idx = result
       
   301             
       
   302             # Increment the number of PDO of this type for node
       
   303             self.SlavesPdoNumber[nodeid][pdotype] += 1
       
   304             
       
   305             # Add an entry to MasterMapping
       
   306             self.MasterMapping[new_cobid] = {"type" : InvertPDOType[pdotype], 
       
   307                 "mapping" : [None] + [(loc_infos["type"], name) for name, loc_infos in pdomapping]}
       
   308             
       
   309             # Return the data to add to DCF
       
   310             if sync_TPDOs:
       
   311                 return GeneratePDOMappingDCF(new_idx, new_cobid, 0x01, pdomapping)
       
   312             else:
       
   313                 return GeneratePDOMappingDCF(new_idx, new_cobid, 0xFF, pdomapping)
       
   314         return 0, ""
       
   315     
   253     def GenerateDCF(self, locations, current_location, sync_TPDOs):
   316     def GenerateDCF(self, locations, current_location, sync_TPDOs):
   254         """
   317         """
   255         Generate Concise DCF of MasterNode for the locations list given
   318         Generate Concise DCF of MasterNode for the locations list given
   256         @param locations: list of locations to be mapped
   319         @param locations: list of locations to be mapped
   257         @param current_location: tuple of the located prefixes not to be considered
   320         @param current_location: tuple of the located prefixes not to be considered
   258         @param sync_TPDOs: indicate if TPDO must be synchronous
   321         @param sync_TPDOs: indicate if TPDO must be synchronous
   259         """
   322         """
   260         
   323         
   261         # Get list of locations check if exists and mappables -> put them in DictLocations
   324         # Get list of locations check if exists and mappables -> put them in IECLocations
   262         for location in locations:
   325         for location in locations:
   263             COlocationtype = DicoTypes[location["IEC_TYPE"]]
   326             COlocationtype = IECToCOType[location["IEC_TYPE"]]
   264             name = location["NAME"]
   327             name = location["NAME"]
   265             if name in DictLocations:
   328             if name in self.IECLocations:
   266                 if DictLocations[name]["type"] != COlocationtype:
   329                 if self.IECLocations[name]["type"] != COlocationtype:
   267                     raise ValueError, "Conflict type for location \"%s\"" % name 
   330                     raise ValueError, "Conflict type for location \"%s\"" % name 
   268             else:
   331             else:
   269                 # Get only the part of the location that concern this node
   332                 # Get only the part of the location that concern this node
   270                 loc = location["LOC"][len(current_location):]
   333                 loc = location["LOC"][len(current_location):]
   271                 # loc correspond to (ID, INDEX, SUBINDEX [,BIT])
   334                 # loc correspond to (ID, INDEX, SUBINDEX [,BIT])
   278                 
   341                 
   279                 # Extract and check nodeid
   342                 # Extract and check nodeid
   280                 nodeid, index, subindex = loc[:3]
   343                 nodeid, index, subindex = loc[:3]
   281                 
   344                 
   282                 # Check Id is in slave node list
   345                 # Check Id is in slave node list
   283                 if nodeid not in nodelist.SlaveNodes.keys():
   346                 if nodeid not in self.NodeList.SlaveNodes.keys():
   284                     raise ValueError, "Non existing node ID : %d (variable %s)" % (nodeid,name)
   347                     raise ValueError, "Non existing node ID : %d (variable %s)" % (nodeid,name)
   285                 
   348                 
   286                 # Get the model for this node (made from EDS)
   349                 # Get the model for this node (made from EDS)
   287                 node = nodelist.SlaveNodes[nodeid]["Node"]
   350                 node = self.NodeList.SlaveNodes[nodeid]["Node"]
   288                 
   351                 
   289                 # Extract and check index and subindex
   352                 # Extract and check index and subindex
   290                 if not node.IsEntry(index, subindex):
   353                 if not node.IsEntry(index, subindex):
   291                     raise ValueError, "No such index/subindex (%x,%x) in ID : %d (variable %s)" % (index,subindex,nodeid,name)
   354                     raise ValueError, "No such index/subindex (%x,%x) in ID : %d (variable %s)" % (index,subindex,nodeid,name)
   292                 
   355                 
   305                     entryinfos = node.GetSubentryInfos(index, subindex)
   368                     entryinfos = node.GetSubentryInfos(index, subindex)
   306                     if entryinfos["type"] != COlocationtype:
   369                     if entryinfos["type"] != COlocationtype:
   307                         raise ValueError, "Invalid type \"%s\"-> %d != %d  for location\"%s\"" % (location["IEC_TYPE"], COlocationtype, entryinfos["type"] , name)
   370                         raise ValueError, "Invalid type \"%s\"-> %d != %d  for location\"%s\"" % (location["IEC_TYPE"], COlocationtype, entryinfos["type"] , name)
   308                     
   371                     
   309                     typeinfos = node.GetEntryInfos(COlocationtype)
   372                     typeinfos = node.GetEntryInfos(COlocationtype)
   310                     DictLocations[name] = {"type":COlocationtype, "pdotype":SlavePDOType[direction],
   373                     self.IECLocations[name] = {"type":COlocationtype, "pdotype":SlavePDOType[direction],
   311                                            "nodeid": nodeid, "index": index,"subindex": subindex,
   374                                                 "nodeid": nodeid, "index": index,"subindex": subindex,
   312                                            "bit": numbit, "size": typeinfos["size"], "sizelocation": sizelocation}
   375                                                 "bit": numbit, "size": typeinfos["size"], "sizelocation": sizelocation}
   313                 else:
   376                 else:
   314                     raise ValueError, "Not PDO mappable variable : '%s' (ID:%d,Idx:%x,sIdx:%x))" % (name,nodeid,index,subindex)
   377                     raise ValueError, "Not PDO mappable variable : '%s' (ID:%d,Idx:%x,sIdx:%x))" % (name,nodeid,index,subindex)
   315                 
   378         
   316         # Create DictCobID with variables already mapped and add them in DictValidLocations
   379         #-------------------------------------------------------------------------------
   317         for name, locationinfos in DictLocations.items():
   380         #                         Search for locations already mapped
       
   381         #-------------------------------------------------------------------------------
       
   382         
       
   383         for name, locationinfos in self.IECLocations.items():
   318             node = self.NodeList.SlaveNodes[locationinfos["nodeid"]]["Node"]
   384             node = self.NodeList.SlaveNodes[locationinfos["nodeid"]]["Node"]
       
   385             
       
   386             # Search if slave has a PDO mapping this locations
   319             result = SearchNodePDOMapping(locationinfos, node)
   387             result = SearchNodePDOMapping(locationinfos, node)
   320             if result != None:
   388             if result != None:
   321                 index, subindex = result
   389                 index, subindex = result
   322                 cobid = nodelist.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 1)
   390                 # Get COB ID of the PDO
   323                 
   391                 cobid = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 1)
   324                 transmittype = nodelist.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 2)
   392                 
   325                 
   393                 # Verify that PDO transmit type is conform to sync_TPDOs
   326                 if transmittype != sync_TPDOs:
   394                 transmittype = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 2)
   327                     if sync_TPDOs : # Change TransmitType to ASYCHRONE
   395                 if sync_TPDOs and transmittype != 0x01 or transmittype != 0xFF:
   328                         node = nodelist.SlaveNodes[nodeid]["Node"]
   396                     if sync_TPDOs:
   329                         nodeDCF = masternode.GetEntry(0x1F22, nodeid)
   397                         # Change TransmitType to SYNCHRONE
   330             
   398                         data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0x01, [])
   331                         if nodeDCF != None and nodeDCF != '':
   399                     else:
   332                             tmpnbparams = [i for i in nodeDCF[:4]]
   400                         # Change TransmitType to ASYCHRONE
   333                             tmpnbparams.reverse()
   401                         data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0xFF, [])
   334                             nbparams = int(''.join(["%2.2x"%ord(i) for i in tmpnbparams]), 16)
       
   335                             dataparams = nodeDCF[4:]
       
   336                         else:
       
   337                             nbparams = 0
       
   338                             dataparams = ""
       
   339                     
   402                     
   340                     else: # Change TransmitType to SYNCHRONE  
   403                     # Add entry to slave dcf to change transmit type of 
   341                         pass
   404                     self.AddParamsToDCF(locationinfos["nodeid"], data, nbparams)
   342             
   405                 
   343             
   406                 # Add PDO to MasterMapping
   344                 if cobid not in DictCobID.keys():
   407                 if cobid not in self.MasterMapping.keys():
   345                     mapping = [None]
   408                     mapping = [None]
   346                     values = node.GetEntry(index)
   409                     values = node.GetEntry(index)
       
   410                     # Store the size of each entry mapped in PDO
   347                     for value in values[1:]:
   411                     for value in values[1:]:
   348                         mapping.append(value % 0x100)
   412                         mapping.append(value % 0x100)
   349                     DictCobID[cobid] = {"type" : InvertPDOType[locationinfos["pdotype"]], "mapping" : mapping}
   413                     self.MasterMapping[cobid] = {"type" : InvertPDOType[locationinfos["pdotype"]], "mapping" : mapping}
   350             
   414             
   351                 DictCobID[cobid]["mapping"][subindex] = (locationinfos["type"], name)
   415                 # Indicate that this PDO entry must be saved
       
   416                 self.MasterMapping[cobid]["mapping"][subindex] = (locationinfos["type"], name)
   352                 
   417                 
   353             else:
   418             else:
   354                 if locationinfos["nodeid"] not in DictLocationsNotMapped.keys():
   419                 # Add location to those that haven't been mapped yet
   355                     DictLocationsNotMapped[locationinfos["nodeid"]] = {TPDO : [], RPDO : []}
   420                 if locationinfos["nodeid"] not in self.LocationsNotMapped.keys():
   356                 DictLocationsNotMapped[locationinfos["nodeid"]][locationinfos["pdotype"]].append((name, locationinfos))
   421                     self.LocationsNotMapped[locationinfos["nodeid"]] = {TPDO : [], RPDO : []}
       
   422                 self.LocationsNotMapped[locationinfos["nodeid"]][locationinfos["pdotype"]].append((name, locationinfos))
   357     
   423     
   358         #-------------------------------------------------------------------------------
   424         #-------------------------------------------------------------------------------
   359         #                         Build concise DCF for the others locations
   425         #                         Build concise DCF for the others locations
   360         #-------------------------------------------------------------------------------
   426         #-------------------------------------------------------------------------------
   361         
   427         
   362         for nodeid, locations in DictLocationsNotMapped.items():
   428         for nodeid, locations in self.LocationsNotMapped.items():
   363             # Get current concise DCF
       
   364             node = nodelist.SlaveNodes[nodeid]["Node"]
   429             node = nodelist.SlaveNodes[nodeid]["Node"]
   365             nodeDCF = masternode.GetEntry(0x1F22, nodeid)
   430             
   366             
   431             # Initialize number of params and data to add to node DCF
   367             if nodeDCF != None and nodeDCF != '':
   432             nbparams = 0
   368                 tmpnbparams = [i for i in nodeDCF[:4]]
   433             dataparams = ""
   369                 tmpnbparams.reverse()
   434             
   370                 nbparams = int(''.join(["%2.2x"%ord(i) for i in tmpnbparams]), 16)
   435             # Generate the best PDO mapping for each type of PDO
   371                 dataparams = nodeDCF[4:]
       
   372             else:
       
   373                 nbparams = 0
       
   374                 dataparams = ""
       
   375             
       
   376             for pdotype in (TPDO, RPDO):
   436             for pdotype in (TPDO, RPDO):
   377                 pdosize = 0
   437                 pdosize = 0
   378                 pdomapping = []
   438                 pdomapping = []
   379                 for name, loc_infos in locations[pdotype]:
   439                 for name, loc_infos in locations[pdotype]:
   380                     pdosize += loc_infos["size"]
   440                     pdosize += loc_infos["size"]
   381                     # If pdo's size > 64 bits
   441                     # If pdo's size > 64 bits
   382                     if pdosize > 64:
   442                     if pdosize > 64:
   383                         result = GetNewCobID(nodeid, pdotype)
   443                         # Generate a new PDO Mapping
   384                         if result:
   444                         data, nbaddedparams = self.AddPDOMapping(nodeid, pdotype, pdomapping, sync_TPDOs)
   385                             SlavesPdoNumber[nodeid][pdotype] += 1
   445                         dataparams += data
   386                             new_cobid, new_idx = result
   446                         nbparams += nbaddedparams
   387                             data, nbaddedparams = GenerateMappingDCF(new_cobid, new_idx, pdomapping, False)
       
   388                             dataparams += data
       
   389                             nbparams += nbaddedparams
       
   390                             DictCobID[new_cobid] = {"type" : InvertPDOType[pdotype], "mapping" : GenerateMasterMapping(pdomapping)}
       
   391                         pdosize = loc_infos["size"]
   447                         pdosize = loc_infos["size"]
   392                         pdomapping = [(name, loc_infos)]
   448                         pdomapping = [(name, loc_infos)]
   393                     else:
   449                     else:
   394                         pdomapping.append((name, loc_infos))
   450                         pdomapping.append((name, loc_infos))
       
   451                 # If there isn't locations yet but there is still a PDO to generate
   395                 if len(pdomapping) > 0:
   452                 if len(pdomapping) > 0:
   396                     result = GetNewCobID(nodeid, pdotype)
   453                     # Generate a new PDO Mapping
   397                     if result:
   454                     data, nbaddedparams = self.AddPDOMapping(nodeid, pdotype, pdomapping, sync_TPDOs)
   398                         SlavesPdoNumber[nodeid][pdotype] += 1
   455                     dataparams += data
   399                         new_cobid, new_idx = result
   456                     nbparams += nbaddedparams
   400                         data, nbaddedparams = GenerateMappingDCF(new_cobid, new_idx, pdomapping, False)
   457             
   401                         dataparams += data
   458             # Add number of params and data to node DCF
   402                         nbparams += nbaddedparams
   459             self.AddParamsToDCF(nodeid, dataparams, nbparams)
   403                         DictCobID[new_cobid] = {"type" : InvertPDOType[pdotype], "mapping" : GenerateMasterMapping(pdomapping)}
   460         
   404             
       
   405             dcf = LE_to_BE(nbparams, 0x04) + dataparams
       
   406             masternode.SetEntry(0x1F22, nodeid, dcf)
       
   407     
       
   408             
       
   409         #-------------------------------------------------------------------------------
   461         #-------------------------------------------------------------------------------
   410         #                         Master Node Configuration
   462         #                         Master Node Configuration
   411         #-------------------------------------------------------------------------------
   463         #-------------------------------------------------------------------------------
   412         
   464         
   413     
   465         # Generate Master's Configuration from informations stored in MasterMapping
   414         
   466         for cobid, pdo_infos in self.MasterMapping.items():
   415         # Configure Master's PDO parameters entries and set cobid, transmit type
   467             # Get next PDO index in MasterNode for this PDO type
   416         for cobid, pdo_infos in DictCobID.items():
   468             current_idx = self.CurrentPDOParamsIdx[pdo_infos["type"]]
   417             current_idx = CurrentPDOParamsIdx[pdo_infos["type"]]
   469             
   418             addinglist = [current_idx, current_idx + 0x200]
   470             # Search if there is already a PDO in MasterNode with this cob id
   419             manager.ManageEntriesOfCurrent(addinglist, [], masternode)
   471             for idx in GetNodePDOIndexes(self.MasterNode, pdo_infos["type"], True):
   420             masternode.SetEntry(current_idx, 0x01, cobid)
   472                 if self.MasterNode.GetEntry(idx, 1) == cobid:
   421             masternode.SetEntry(current_idx, 0x02, DefaultTransmitTypeMaster)
   473                     current_idx = idx
       
   474             
       
   475             # Add a PDO to MasterNode if not PDO have been found
       
   476             if current_idx == self.CurrentPDOParamsIdx[pdo_infos["type"]]:
       
   477                 addinglist = [current_idx, current_idx + 0x200]
       
   478                 self.Manager.ManageEntriesOfCurrent(addinglist, [], self.MasterNode)
       
   479                 self.MasterNode.SetEntry(current_idx, 0x01, cobid)
       
   480                 
       
   481                 # Increment the number of PDO for this PDO type
       
   482                 self.CurrentPDOParamsIdx[pdo_infos["type"]] += 1
       
   483             
       
   484             # Change the transmit type of the PDO
       
   485             if sync_TPDOs:
       
   486                 self.MasterNode.SetEntry(current_idx, 0x02, 0x01)
       
   487             else:
       
   488                 self.MasterNode.SetEntry(current_idx, 0x02, 0xFF)
       
   489             
       
   490             # Add some subentries to PDO mapping if there is not enough
   422             if len(pdo_infos["mapping"]) > 2:
   491             if len(pdo_infos["mapping"]) > 2:
   423                 manager.AddSubentriesToCurrent(current_idx + 0x200, len(pdo_infos["mapping"]) - 2, masternode)
   492                 self.Manager.AddSubentriesToCurrent(current_idx + 0x200, len(pdo_infos["mapping"]) - 2, self.MasterNode)
   424             
   493             
   425             # Create Master's PDO mapping
   494             # Generate MasterNode's PDO mapping
   426             for subindex, variable in enumerate(pdo_infos["mapping"]):
   495             for subindex, variable in enumerate(pdo_infos["mapping"]):
   427                 if subindex == 0:
   496                 if subindex == 0:
   428                     continue
   497                     continue
   429                 new_index = False
   498                 new_index = False
   430                 
   499                 
   431                 if type(variable) != IntType:
   500                 if type(variable) == IntType:
       
   501                     # If variable is an integer then variable is unexpected
       
   502                     self.MasterNode.SetEntry(current_idx + 0x200, subindex, self.TrashVariables[variable])
       
   503                 else:
       
   504                     typeidx, varname = variable
       
   505                     variable_infos = self.IECLocations[varname]
   432                     
   506                     
   433                     typeidx, varname = variable
   507                     # Calculate base index for storing variable
   434                     indexname = \
   508                     mapvariableidx = VariableStartIndex[variable_infos["pdotype"]] + \
   435                         DictNameVariable[DictLocations[variable[1]]["pdotype"]][0] + \
   509                                      VariableTypeOffset[variable_infos["sizelocation"]] * VariableIncrement + \
   436                         DictLocations[variable[1]]["sizelocation"] + \
   510                                      variable_infos["nodeid"]
   437                         '_'.join(map(str,current_location)) + \
       
   438                         "_" + \
       
   439                         str(DictLocations[variable[1]]["nodeid"])
       
   440                     mapvariableidx = DictNameVariable[DictLocations[variable[1]]["pdotype"]][1] +  DictNameVariable[DictLocations[variable[1]]["sizelocation"]] * DictNameVariable["increment"]
       
   441     
       
   442                     #indexname = DictNameVariable[DictLocations[variable[1]]["pdotype"]][0] + DictLocations[variable[1]]["sizelocation"] + str(DictLocations[variable[1]]["prefix"]) + "_" + str(DictLocations[variable[1]]["nodeid"])
       
   443                     #mapvariableidx = DictNameVariable[DictLocations[variable[1]]["pdotype"]][1] +  DictNameVariable[DictLocations[variable[1]]["sizelocation"]] * DictNameVariable["increment"]
       
   444                     
   511                     
   445                     if not masternode.IsEntry(mapvariableidx):
   512                     # Search for an entry that has an empty subindex 
   446                         manager.AddMapVariableToCurrent(mapvariableidx, indexname, 3, 1, masternode)
   513                     while mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000:
   447                         new_index = True
   514                         # Entry doesn't exist
   448                         nbsubentries = masternode.GetEntry(mapvariableidx, 0x00)
   515                         if not self.MasterNode.IsEntry(mapvariableidx):    
   449                     else:
   516                             # Generate entry name
   450                         nbsubentries = masternode.GetEntry(mapvariableidx, 0x00)
   517                             indexname = "%s%s%s_%d"%(VariableDirText[variable_infos["pdotype"]],
   451                         mapvariableidxbase = mapvariableidx 
   518                                                      variable_infos["sizelocation"],
   452                         while mapvariableidx < (mapvariableidxbase + 0x1FF) and nbsubentries == 0xFF:
   519                                                      '_'.join(map(str,current_location)),
   453                             mapvariableidx += 0x800
   520                                                      variable_infos["nodeid"])
   454                             if not manager.IsCurrentEntry(mapvariableidx):
   521                             # Add entry to MasterNode
   455                                 manager.AddMapVariableToCurrent(mapvariableidx, indexname, 3, 1, masternode)
   522                             self.Manager.AddMapVariableToCurrent(mapvariableidx, indexname, 3, 1, self.MasterNode)
   456                                 new_index = True
   523                             new_index = True
   457                             nbsubentries = masternode.GetEntry(mapvariableidx, 0x00)
   524                             nbsubentries = self.MasterNode.GetEntry(mapvariableidx, 0x00)
   458                     
       
   459                     if mapvariableidx < 0x6000:
       
   460                         if DictLocations[variable[1]]["bit"] != None:
       
   461                             subindexname = str(DictLocations[variable[1]]["index"]) + "_" + str(DictLocations[variable[1]]["subindex"]) + "_" + str(DictLocations[variable[1]]["bit"])
       
   462                         else:
   525                         else:
   463                             subindexname = str(DictLocations[variable[1]]["index"]) + "_" + str(DictLocations[variable[1]]["subindex"])
   526                             # Get Number of subentries already defined
       
   527                             nbsubentries = self.MasterNode.GetEntry(mapvariableidx, 0x00)
       
   528                             # if entry is full, go to next entry possible or stop now
       
   529                             if nbsubentries == 0xFF:
       
   530                                 mapvariableidx += 8 * VariableIncrement
       
   531                             else:
       
   532                                 break
       
   533                                 
       
   534                     # Verify that a not full entry has been found
       
   535                     if mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000:
       
   536                         # Generate subentry name
       
   537                         if variable_infos["bit"] != None:
       
   538                             subindexname = "%(index)d_%(subindex)d_%(bit)d"%variable_infos
       
   539                         else:
       
   540                             subindexname = "%(index)d_%(subindex)d"%variable_infos
       
   541                         # If entry have just been created, no subentry have to be added
   464                         if not new_index:
   542                         if not new_index:
   465                             manager.AddSubentriesToCurrent(mapvariableidx, 1, masternode)
   543                             self.Manager.AddSubentriesToCurrent(mapvariableidx, 1, self.MasterNode)
   466                             nbsubentries += 1
   544                             nbsubentries += 1
   467                         masternode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"name" : subindexname})
   545                         # Add informations to the new subentry created
   468                         masternode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"type" : typeidx})
   546                         self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"name" : subindexname})
       
   547                         self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"type" : typeidx})
   469                         
   548                         
   470                         # Map Variable
   549                         # Set value of the PDO mapping
   471                         typeinfos = manager.GetEntryInfos(typeidx)
   550                         typeinfos = self.Manager.GetEntryInfos(typeidx)
   472                         if typeinfos != None:
   551                         if typeinfos != None:
   473                             value = (mapvariableidx << 16) + ((nbsubentries) << 8) + typeinfos["size"]
   552                             value = (mapvariableidx << 16) + ((nbsubentries) << 8) + typeinfos["size"]
   474                             masternode.SetEntry(current_idx + 0x200, subindex, value)
   553                             self.MasterNode.SetEntry(current_idx + 0x200, subindex, value)
   475                 else:
       
   476                     masternode.SetEntry(current_idx + 0x200, subindex, TrashVariableValue[variable])
       
   477             
       
   478             CurrentPDOParamsIdx[pdo_infos["type"]] += 1
       
   479         
       
   480 
   554 
   481 def GenerateConciseDCF(locations, current_location, nodelist, sync_TPDOs):
   555 def GenerateConciseDCF(locations, current_location, nodelist, sync_TPDOs):
   482     """
   556     """
   483     Fills a CanFestival network editor model, with DCF with requested PDO mappings.
   557     Fills a CanFestival network editor model, with DCF with requested PDO mappings.
   484     @param locations: List of complete variables locations \
   558     @param locations: List of complete variables locations \
   494     
   568     
   495     dcfgenerator = ConciseDCFGenerator(nodelist)
   569     dcfgenerator = ConciseDCFGenerator(nodelist)
   496     dcfgenerator.GenerateDCF(locations, current_location, sync_TPDOs)
   570     dcfgenerator.GenerateDCF(locations, current_location, sync_TPDOs)
   497     return dcfgenerator.GetMasterNode()
   571     return dcfgenerator.GetMasterNode()
   498 
   572 
   499 if __name__ == "__main__": 
   573 if __name__ == "__main__":
       
   574     import os, sys
       
   575 
       
   576     base_folder = sys.path[0]
       
   577     for i in xrange(3):
       
   578         base_folder = os.path.split(base_folder)[0]
       
   579     sys.path.append(os.path.join(base_folder, "CanFestival-3", "objdictgen"))
       
   580     
   500     from nodemanager import *
   581     from nodemanager import *
   501     from nodelist import *
   582     from nodelist import *
   502     import sys
   583     
   503     
   584     manager = NodeManager()
   504     manager = NodeManager(sys.path[0])
       
   505     nodelist = NodeList(manager)
   585     nodelist = NodeList(manager)
   506     result = nodelist.LoadProject("/home/deobox/Desktop/TestMapping")
   586     result = nodelist.LoadProject("test_config")
   507    
   587     
   508 ##    if result != None:
   588     locations = [{"IEC_TYPE":"BYTE","NAME":"__IB0_1_64_24576_1","DIR":"I","SIZE":"B","LOC":(0,1,64,24576,1)},
   509 ##        print result
   589                  {"IEC_TYPE":"INT","NAME":"__IW0_1_64_25601_2","DIR":"I","SIZE":"W","LOC":(0,1,64,25601,2)},
   510 ##    else:
   590                  {"IEC_TYPE":"INT","NAME":"__IW0_1_64_25601_3","DIR":"I","SIZE":"W","LOC":(0,1,64,25601,3)},
   511 ##        print "MasterNode :"
   591                  {"IEC_TYPE":"INT","NAME":"__QW0_1_64_25617_2","DIR":"Q","SIZE":"W","LOC":(0,1,64,25617,1)},
   512 ##        manager.CurrentNode.Print()
   592                  {"IEC_TYPE":"BYTE","NAME":"__IB0_1_64_24578_1","DIR":"I","SIZE":"B","LOC":(0,1,64,24578,1)},
   513 ##        for nodeid, node in nodelist.SlaveNodes.items():
   593                  {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_1","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,1)},
   514 ##            print "SlaveNode name=%s id=0x%2.2X :"%(node["Name"], nodeid)
   594                  {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_2","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,2)},
   515 ##            node["Node"].Print()
   595                  {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_3","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,3)},
   516             
   596                  {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_4","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,4)}]
   517     #filepath = "/home/deobox/beremiz/test_nodelist/listlocations.txt"
   597     
   518     filepath = "/home/deobox/Desktop/TestMapping/listlocations.txt"
   598     masternode = GenerateConciseDCF(locations, (0, 1), nodelist, True)
   519     
   599     #masternode.Print()
   520     file = open(filepath,'r')
   600     result = [line.rstrip() for line in masternode.PrintString().splitlines()]
   521     locations = [location.split(' ') for location in [line.strip() for line in file.readlines() if len(line) > 0]] 
   601     
       
   602     file = open("test_config/result.txt", "r")
       
   603     model = [line.rstrip() for line in file.readlines()]
   522     file.close()
   604     file.close()
   523     GenerateConciseDCF(locations, 32, nodelist)
   605     
   524     print "MasterNode :"
   606     errors = 0
   525     manager.CurrentNode.Print()
   607     for i, line in enumerate(model):
   526     #masternode.Print()
   608         if i >= len(result):
       
   609             errors += 1
       
   610             print "Line %d disappear :"%(i + 1)
       
   611             print line
       
   612         elif line != result[i]:
       
   613             errors += 1
       
   614             print "Error on line %d :"%(i + 1)
       
   615             print "\t%s"%result[i]
       
   616             print "Instead of :\n\t%s"%line
       
   617     for i in xrange(len(model), len(result)):
       
   618         errors += 1
       
   619         print "Line %d appear :"%(i + 1)
       
   620         print result[i]
       
   621     
       
   622     if errors > 0:
       
   623         print "Test Failed!"
       
   624     else:
       
   625         print "Test Successful!"