canfestival/config_utils.py
changeset 1730 64d8f52bc8c8
parent 1722 89824afffef2
child 1732 94ffe74e6895
equal deleted inserted replaced
1726:d51af006fa6b 1730:64d8f52bc8c8
    28 IECToCOType = {"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 
    32 
    33 # Constants for PDO types 
    33 # Constants for PDO types
    34 RPDO = 1
    34 RPDO = 1
    35 TPDO = 2
    35 TPDO = 2
    36 
    36 
    37 SlavePDOType = {"I" : TPDO, "Q" : RPDO}
    37 SlavePDOType = {"I" : TPDO, "Q" : RPDO}
    38 InvertPDOType = {RPDO : TPDO, TPDO : RPDO}
    38 InvertPDOType = {RPDO : TPDO, TPDO : RPDO}
    59     Convert Little Endian to Big Endian
    59     Convert Little Endian to Big Endian
    60     @param value: value expressed in integer
    60     @param value: value expressed in integer
    61     @param size: number of bytes generated
    61     @param size: number of bytes generated
    62     @return: a string containing the value converted
    62     @return: a string containing the value converted
    63     """
    63     """
    64     
    64 
    65     data = ("%" + str(size * 2) + "." + str(size * 2) + "X") % value
    65     data = ("%" + str(size * 2) + "." + str(size * 2) + "X") % value
    66     list_car = [data[i:i+2] for i in xrange(0, len(data), 2)]
    66     list_car = [data[i:i+2] for i in xrange(0, len(data), 2)]
    67     list_car.reverse()
    67     list_car.reverse()
    68     return "".join([chr(int(car, 16)) for car in list_car])
    68     return "".join([chr(int(car, 16)) for car in list_car])
    69 
    69 
    70 
    70 
    71 def GetNodePDOIndexes(node, type, parameters = False):
    71 def GetNodePDOIndexes(node, type, parameters = False):
    72     """
    72     """
    73     Find the PDO indexes of a node
    73     Find the PDO indexes of a node
    74     @param node: node 
    74     @param node: node
    75     @param type: type of PDO searched (RPDO or TPDO or both)
    75     @param type: type of PDO searched (RPDO or TPDO or both)
    76     @param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False)
    76     @param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False)
    77     @return: a list of indexes found
    77     @return: a list of indexes found
    78     """
    78     """
    79     
    79 
    80     indexes = []
    80     indexes = []
    81     if type & RPDO:
    81     if type & RPDO:
    82         indexes.extend([idx for idx in node.GetIndexes() if 0x1400 <= idx <= 0x15FF])
    82         indexes.extend([idx for idx in node.GetIndexes() if 0x1400 <= idx <= 0x15FF])
    83     if type & TPDO:
    83     if type & TPDO:
    84         indexes.extend([idx for idx in node.GetIndexes() if 0x1800 <= idx <= 0x19FF])
    84         indexes.extend([idx for idx in node.GetIndexes() if 0x1800 <= idx <= 0x19FF])
    89 
    89 
    90 
    90 
    91 def SearchNodePDOMapping(loc_infos, node):
    91 def SearchNodePDOMapping(loc_infos, node):
    92     """
    92     """
    93     Find the PDO indexes of a node
    93     Find the PDO indexes of a node
    94     @param node: node 
    94     @param node: node
    95     @param type: type of PDO searched (RPDO or TPDO or both)
    95     @param type: type of PDO searched (RPDO or TPDO or both)
    96     @param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False)
    96     @param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False)
    97     @return: a list of indexes found
    97     @return: a list of indexes found
    98     """
    98     """
    99     
    99 
   100     model = (loc_infos["index"] << 16) + (loc_infos["subindex"] << 8)
   100     model = (loc_infos["index"] << 16) + (loc_infos["subindex"] << 8)
   101     
   101 
   102     for PDOidx in GetNodePDOIndexes(node, loc_infos["pdotype"]):
   102     for PDOidx in GetNodePDOIndexes(node, loc_infos["pdotype"]):
   103         values = node.GetEntry(PDOidx)
   103         values = node.GetEntry(PDOidx)
   104         if values != None:
   104         if values != None:
   105             for subindex, mapping in enumerate(values):
   105             for subindex, mapping in enumerate(values):
   106                 if subindex != 0 and mapping & 0xFFFFFF00 == model:
   106                 if subindex != 0 and mapping & 0xFFFFFF00 == model:
   113     Build concise DCF value for configuring a PDO
   113     Build concise DCF value for configuring a PDO
   114     @param idx: index of PDO parameters
   114     @param idx: index of PDO parameters
   115     @param cobid: PDO generated COB ID
   115     @param cobid: PDO generated COB ID
   116     @param transmittype : PDO transmit type
   116     @param transmittype : PDO transmit type
   117     @param pdomapping: list of PDO mappings
   117     @param pdomapping: list of PDO mappings
   118     @return: a tuple of value and number of parameters to add to DCF 
   118     @return: a tuple of value and number of parameters to add to DCF
   119     """
   119     """
   120     
   120 
   121     dcfdata=[]
   121     dcfdata=[]
   122     # Create entry for RPDO or TPDO parameters and Disable PDO
   122     # Create entry for RPDO or TPDO parameters and Disable PDO
   123     #           ---- INDEX -----   --- SUBINDEX ----   ----- SIZE ------   ------ DATA ------
   123     #           ---- INDEX -----   --- SUBINDEX ----   ----- SIZE ------   ------ DATA ------
   124     dcfdata += [LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE(0x80000000 + cobid, 4)]
   124     dcfdata += [LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE(0x80000000 + cobid, 4)]
   125     # Set Transmit type
   125     # Set Transmit type
   150         self.ListCobIDAvailable = range(0x180, 0x580)
   150         self.ListCobIDAvailable = range(0x180, 0x580)
   151         # Dictionary of mapping value where unexpected variables are stored
   151         # Dictionary of mapping value where unexpected variables are stored
   152         self.TrashVariables = {}
   152         self.TrashVariables = {}
   153         # Dictionary of pointed variables
   153         # Dictionary of pointed variables
   154         self.PointedVariables = {}
   154         self.PointedVariables = {}
   155         
   155 
   156         self.NodeList = nodelist
   156         self.NodeList = nodelist
   157         self.Manager = self.NodeList.Manager
   157         self.Manager = self.NodeList.Manager
   158         self.MasterNode = self.Manager.GetCurrentNodeCopy()
   158         self.MasterNode = self.Manager.GetCurrentNodeCopy()
   159         self.MasterNode.SetNodeName(nodename)
   159         self.MasterNode.SetNodeName(nodename)
   160         self.PrepareMasterNode()
   160         self.PrepareMasterNode()
   161 
   161 
   162     def GetPointedVariables(self):
   162     def GetPointedVariables(self):
   163         return self.PointedVariables
   163         return self.PointedVariables
   164     
   164 
   165     def RemoveUsedNodeCobId(self, node):
   165     def RemoveUsedNodeCobId(self, node):
   166         """
   166         """
   167         Remove all PDO COB ID used by the given node from the list of available COB ID
   167         Remove all PDO COB ID used by the given node from the list of available COB ID
   168         @param node: node
   168         @param node: node
   169         @return: a tuple of number of RPDO and TPDO for the node
   169         @return: a tuple of number of RPDO and TPDO for the node
   170         """
   170         """
   171         
   171 
   172         # Get list of all node TPDO and RPDO indexes
   172         # Get list of all node TPDO and RPDO indexes
   173         nodeRpdoIndexes = GetNodePDOIndexes(node, RPDO, True)
   173         nodeRpdoIndexes = GetNodePDOIndexes(node, RPDO, True)
   174         nodeTpdoIndexes = GetNodePDOIndexes(node, TPDO, True)
   174         nodeTpdoIndexes = GetNodePDOIndexes(node, TPDO, True)
   175         
   175 
   176         # Mark all the COB ID of the node already mapped PDO as not available
   176         # Mark all the COB ID of the node already mapped PDO as not available
   177         for PdoIdx in nodeRpdoIndexes + nodeTpdoIndexes:
   177         for PdoIdx in nodeRpdoIndexes + nodeTpdoIndexes:
   178             pdo_cobid = node.GetEntry(PdoIdx, 0x01)
   178             pdo_cobid = node.GetEntry(PdoIdx, 0x01)
   179             # Extract COB ID, if PDO isn't active
   179             # Extract COB ID, if PDO isn't active
   180             if pdo_cobid > 0x600 :
   180             if pdo_cobid > 0x600 :
   181                 pdo_cobid -= 0x80000000
   181                 pdo_cobid -= 0x80000000
   182             # Remove COB ID from the list of available COB ID
   182             # Remove COB ID from the list of available COB ID
   183             if pdo_cobid in self.ListCobIDAvailable:
   183             if pdo_cobid in self.ListCobIDAvailable:
   184                 self.ListCobIDAvailable.remove(pdo_cobid)
   184                 self.ListCobIDAvailable.remove(pdo_cobid)
   185         
   185 
   186         return len(nodeRpdoIndexes), len(nodeTpdoIndexes)
   186         return len(nodeRpdoIndexes), len(nodeTpdoIndexes)
   187 
   187 
   188     
   188 
   189     def PrepareMasterNode(self):
   189     def PrepareMasterNode(self):
   190         """
   190         """
   191         Add mandatory entries for DCF generation into MasterNode.
   191         Add mandatory entries for DCF generation into MasterNode.
   192         """
   192         """
   193         
   193 
   194         # Adding DCF entry into Master node
   194         # Adding DCF entry into Master node
   195         if not self.MasterNode.IsEntry(0x1F22):
   195         if not self.MasterNode.IsEntry(0x1F22):
   196             self.MasterNode.AddEntry(0x1F22, 1, "")
   196             self.MasterNode.AddEntry(0x1F22, 1, "")
   197         self.Manager.AddSubentriesToCurrent(0x1F22, 127, self.MasterNode)
   197         self.Manager.AddSubentriesToCurrent(0x1F22, 127, self.MasterNode)
   198         
   198 
   199         # Adding trash mappable variables for unused mapped datas
   199         # Adding trash mappable variables for unused mapped datas
   200         idxTrashVariables = 0x2000 + self.MasterNode.GetNodeID()
   200         idxTrashVariables = 0x2000 + self.MasterNode.GetNodeID()
   201         # Add an entry for storing unexpected all variable
   201         # Add an entry for storing unexpected all variable
   202         self.Manager.AddMapVariableToCurrent(idxTrashVariables, self.MasterNode.GetNodeName()+"_trashvariables", 3, len(TrashVariables), self.MasterNode)
   202         self.Manager.AddMapVariableToCurrent(idxTrashVariables, self.MasterNode.GetNodeName()+"_trashvariables", 3, len(TrashVariables), self.MasterNode)
   203         for subidx, (size, typeidx) in enumerate(TrashVariables):
   203         for subidx, (size, typeidx) in enumerate(TrashVariables):
   204             # Add a subentry for storing unexpected variable of this size
   204             # Add a subentry for storing unexpected variable of this size
   205             self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, "TRASH%d" % size, "name", None, self.MasterNode)
   205             self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, "TRASH%d" % size, "name", None, self.MasterNode)
   206             self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, typeidx, "type", None, self.MasterNode)
   206             self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, typeidx, "type", None, self.MasterNode)
   207             # Store the mapping value for this entry
   207             # Store the mapping value for this entry
   208             self.TrashVariables[size] = (idxTrashVariables << 16) + ((subidx + 1) << 8) + size
   208             self.TrashVariables[size] = (idxTrashVariables << 16) + ((subidx + 1) << 8) + size
   209         
   209 
   210         RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(self.MasterNode)
   210         RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(self.MasterNode)
   211         
   211 
   212         # Store the indexes of the first RPDO and TPDO available for MasterNode
   212         # Store the indexes of the first RPDO and TPDO available for MasterNode
   213         self.CurrentPDOParamsIdx = {RPDO : 0x1400 + RPDOnumber, TPDO : 0x1800 + TPDOnumber}
   213         self.CurrentPDOParamsIdx = {RPDO : 0x1400 + RPDOnumber, TPDO : 0x1800 + TPDOnumber}
   214 
   214 
   215         # Prepare MasterNode with all nodelist slaves
   215         # Prepare MasterNode with all nodelist slaves
   216         for idx, (nodeid, nodeinfos) in enumerate(self.NodeList.SlaveNodes.items()):
   216         for idx, (nodeid, nodeinfos) in enumerate(self.NodeList.SlaveNodes.items()):
   217             node = nodeinfos["Node"]
   217             node = nodeinfos["Node"]
   218             node.SetNodeID(nodeid)
   218             node.SetNodeID(nodeid)
   219             
   219 
   220             RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(node)
   220             RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(node)
   221             
   221 
   222             # Get Slave's default SDO server parameters
   222             # Get Slave's default SDO server parameters
   223             RSDO_cobid = node.GetEntry(0x1200,0x01)
   223             RSDO_cobid = node.GetEntry(0x1200,0x01)
   224             if not RSDO_cobid:
   224             if not RSDO_cobid:
   225                 RSDO_cobid = 0x600 + nodeid
   225                 RSDO_cobid = 0x600 + nodeid
   226             TSDO_cobid = node.GetEntry(0x1200,0x02)
   226             TSDO_cobid = node.GetEntry(0x1200,0x02)
   227             if not TSDO_cobid:
   227             if not TSDO_cobid:
   228                 TSDO_cobid = 0x580 + nodeid
   228                 TSDO_cobid = 0x580 + nodeid
   229             
   229 
   230             # Configure Master's SDO parameters entries
   230             # Configure Master's SDO parameters entries
   231             self.Manager.ManageEntriesOfCurrent([0x1280 + idx], [], self.MasterNode)
   231             self.Manager.ManageEntriesOfCurrent([0x1280 + idx], [], self.MasterNode)
   232             self.MasterNode.SetEntry(0x1280 + idx, 0x01, RSDO_cobid)
   232             self.MasterNode.SetEntry(0x1280 + idx, 0x01, RSDO_cobid)
   233             self.MasterNode.SetEntry(0x1280 + idx, 0x02, TSDO_cobid)
   233             self.MasterNode.SetEntry(0x1280 + idx, 0x02, TSDO_cobid)
   234             self.MasterNode.SetEntry(0x1280 + idx, 0x03, nodeid)        
   234             self.MasterNode.SetEntry(0x1280 + idx, 0x03, nodeid)
   235         
   235 
   236     
   236 
   237     def GetMasterNode(self):
   237     def GetMasterNode(self):
   238         """
   238         """
   239         Return MasterNode.
   239         Return MasterNode.
   240         """
   240         """
   241         return self.MasterNode
   241         return self.MasterNode
   242     
   242 
   243     def AddParamsToDCF(self, nodeid, data, nbparams):
   243     def AddParamsToDCF(self, nodeid, data, nbparams):
   244         """
   244         """
   245         Add entry to DCF, for the requested nodeID
   245         Add entry to DCF, for the requested nodeID
   246         @param nodeid: id of the slave (int)
   246         @param nodeid: id of the slave (int)
   247         @param data: data to add to slave DCF (string)
   247         @param data: data to add to slave DCF (string)
   248         @param nbparams: number of params added to slave DCF (int)
   248         @param nbparams: number of params added to slave DCF (int)
   249         """
   249         """
   250         # Get current DCF for slave
   250         # Get current DCF for slave
   251         nodeDCF = self.MasterNode.GetEntry(0x1F22, nodeid)
   251         nodeDCF = self.MasterNode.GetEntry(0x1F22, nodeid)
   252         
   252 
   253         # Extract data and number of params in current DCF
   253         # Extract data and number of params in current DCF
   254         if nodeDCF != None and nodeDCF != '':
   254         if nodeDCF != None and nodeDCF != '':
   255             tmpnbparams = [i for i in nodeDCF[:4]]
   255             tmpnbparams = [i for i in nodeDCF[:4]]
   256             tmpnbparams.reverse()
   256             tmpnbparams.reverse()
   257             nbparams += int(''.join(["%2.2x"%ord(i) for i in tmpnbparams]), 16)
   257             nbparams += int(''.join(["%2.2x"%ord(i) for i in tmpnbparams]), 16)
   258             data = nodeDCF[4:] + data
   258             data = nodeDCF[4:] + data
   259         
   259 
   260         # Build new DCF
   260         # Build new DCF
   261         dcf = LE_to_BE(nbparams, 0x04) + data
   261         dcf = LE_to_BE(nbparams, 0x04) + data
   262         # Set new DCF for slave
   262         # Set new DCF for slave
   263         self.MasterNode.SetEntry(0x1F22, nodeid, dcf)
   263         self.MasterNode.SetEntry(0x1F22, nodeid, dcf)
   264     
   264 
   265     def GetEmptyPDO(self, nodeid, pdotype, start_index=None):
   265     def GetEmptyPDO(self, nodeid, pdotype, start_index=None):
   266         """
   266         """
   267         Search a not configured PDO for a slave
   267         Search a not configured PDO for a slave
   268         @param node: the slave node object
   268         @param node: the slave node object
   269         @param pdotype: type of PDO to generated (RPDO or TPDO)
   269         @param pdotype: type of PDO to generated (RPDO or TPDO)
   273         # If no start_index defined, start with PDOtype base index
   273         # If no start_index defined, start with PDOtype base index
   274         if start_index is None:
   274         if start_index is None:
   275             index = PDOTypeBaseIndex[pdotype]
   275             index = PDOTypeBaseIndex[pdotype]
   276         else:
   276         else:
   277             index = start_index
   277             index = start_index
   278         
   278 
   279         # Search for all PDO possible index until find a configurable PDO
   279         # Search for all PDO possible index until find a configurable PDO
   280         # starting from start_index
   280         # starting from start_index
   281         while index < PDOTypeBaseIndex[pdotype] + 0x200:
   281         while index < PDOTypeBaseIndex[pdotype] + 0x200:
   282             values = self.NodeList.GetSlaveNodeEntry(nodeid, index + 0x200)
   282             values = self.NodeList.GetSlaveNodeEntry(nodeid, index + 0x200)
   283             if values != None and values[0] > 0:
   283             if values != None and values[0] > 0:
   294                         if cobid not in self.ListCobIDAvailable:
   294                         if cobid not in self.ListCobIDAvailable:
   295                             cobid = self.ListCobIDAvailable.pop(0)
   295                             cobid = self.ListCobIDAvailable.pop(0)
   296                     return index, cobid, values[0]
   296                     return index, cobid, values[0]
   297             index += 1
   297             index += 1
   298         return None
   298         return None
   299     
   299 
   300     def AddPDOMapping(self, nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs):
   300     def AddPDOMapping(self, nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs):
   301         """
   301         """
   302         Record a new mapping request for a slave, and add related slave config to the DCF
   302         Record a new mapping request for a slave, and add related slave config to the DCF
   303         @param nodeid: id of the slave (int)
   303         @param nodeid: id of the slave (int)
   304         @param pdotype: type of PDO to generated (RPDO or TPDO)
   304         @param pdotype: type of PDO to generated (RPDO or TPDO)
   305         @param pdomapping: list od variables to map with PDO
   305         @param pdomapping: list od variables to map with PDO
   306         """
   306         """
   307         # Add an entry to MasterMapping
   307         # Add an entry to MasterMapping
   308         self.MasterMapping[pdocobid] = {"type" : InvertPDOType[pdotype], 
   308         self.MasterMapping[pdocobid] = {"type" : InvertPDOType[pdotype],
   309             "mapping" : [None] + [(loc_infos["type"], name) for name, loc_infos in pdomapping]}
   309             "mapping" : [None] + [(loc_infos["type"], name) for name, loc_infos in pdomapping]}
   310         
   310 
   311         # Return the data to add to DCF
   311         # Return the data to add to DCF
   312         if sync_TPDOs:
   312         if sync_TPDOs:
   313             return GeneratePDOMappingDCF(pdoindex, pdocobid, 0x01, pdomapping)
   313             return GeneratePDOMappingDCF(pdoindex, pdocobid, 0x01, pdomapping)
   314         else:
   314         else:
   315             return GeneratePDOMappingDCF(pdoindex, pdocobid, 0xFF, pdomapping)
   315             return GeneratePDOMappingDCF(pdoindex, pdocobid, 0xFF, pdomapping)
   316         return 0, ""
   316         return 0, ""
   317     
   317 
   318     def GenerateDCF(self, locations, current_location, sync_TPDOs):
   318     def GenerateDCF(self, locations, current_location, sync_TPDOs):
   319         """
   319         """
   320         Generate Concise DCF of MasterNode for the locations list given
   320         Generate Concise DCF of MasterNode for the locations list given
   321         @param locations: list of locations to be mapped
   321         @param locations: list of locations to be mapped
   322         @param current_location: tuple of the located prefixes not to be considered
   322         @param current_location: tuple of the located prefixes not to be considered
   323         @param sync_TPDOs: indicate if TPDO must be synchronous
   323         @param sync_TPDOs: indicate if TPDO must be synchronous
   324         """
   324         """
   325         
   325 
   326         #-------------------------------------------------------------------------------
   326         #-------------------------------------------------------------------------------
   327         #               Verify that locations correspond to real slave variables
   327         #               Verify that locations correspond to real slave variables
   328         #-------------------------------------------------------------------------------
   328         #-------------------------------------------------------------------------------
   329         
   329 
   330         # Get list of locations check if exists and mappables -> put them in IECLocations
   330         # Get list of locations check if exists and mappables -> put them in IECLocations
   331         for location in locations:
   331         for location in locations:
   332             COlocationtype = IECToCOType[location["IEC_TYPE"]]
   332             COlocationtype = IECToCOType[location["IEC_TYPE"]]
   333             name = location["NAME"]
   333             name = location["NAME"]
   334             if name in self.IECLocations:
   334             if name in self.IECLocations:
   335                 if self.IECLocations[name]["type"] != COlocationtype:
   335                 if self.IECLocations[name]["type"] != COlocationtype:
   336                     raise PDOmappingException, _("Type conflict for location \"%s\"") % name 
   336                     raise PDOmappingException, _("Type conflict for location \"%s\"") % name
   337             else:
   337             else:
   338                 # Get only the part of the location that concern this node
   338                 # Get only the part of the location that concern this node
   339                 loc = location["LOC"][len(current_location):]
   339                 loc = location["LOC"][len(current_location):]
   340                 # loc correspond to (ID, INDEX, SUBINDEX [,BIT])
   340                 # loc correspond to (ID, INDEX, SUBINDEX [,BIT])
   341                 if len(loc) not in (2, 3, 4):
   341                 if len(loc) not in (2, 3, 4):
   342                     raise PDOmappingException, _("Bad location size : %s") % str(loc)
   342                     raise PDOmappingException, _("Bad location size : %s") % str(loc)
   343                 elif len(loc) == 2:
   343                 elif len(loc) == 2:
   344                     continue
   344                     continue
   345                 
   345 
   346                 direction = location["DIR"]
   346                 direction = location["DIR"]
   347                 
   347 
   348                 sizelocation = location["SIZE"]
   348                 sizelocation = location["SIZE"]
   349                 
   349 
   350                 # Extract and check nodeid
   350                 # Extract and check nodeid
   351                 nodeid, index, subindex = loc[:3]
   351                 nodeid, index, subindex = loc[:3]
   352                 
   352 
   353                 # Check Id is in slave node list
   353                 # Check Id is in slave node list
   354                 if nodeid not in self.NodeList.SlaveNodes.keys():
   354                 if nodeid not in self.NodeList.SlaveNodes.keys():
   355                     raise PDOmappingException, _("Non existing node ID : {a1} (variable {a2})").format(a1 = nodeid, a2 = name)
   355                     raise PDOmappingException, _("Non existing node ID : {a1} (variable {a2})").format(a1 = nodeid, a2 = name)
   356                 
   356 
   357                 # Get the model for this node (made from EDS)
   357                 # Get the model for this node (made from EDS)
   358                 node = self.NodeList.SlaveNodes[nodeid]["Node"]
   358                 node = self.NodeList.SlaveNodes[nodeid]["Node"]
   359                 
   359 
   360                 # Extract and check index and subindex
   360                 # Extract and check index and subindex
   361                 if not node.IsEntry(index, subindex):
   361                 if not node.IsEntry(index, subindex):
   362                     msg = _("No such index/subindex ({a1},{a2}) in ID : {a3} (variable {a4})").\
   362                     msg = _("No such index/subindex ({a1},{a2}) in ID : {a3} (variable {a4})").\
   363                           format(a1 = "%x" % index, a2 ="%x" % subindex, a3 = nodeid, a4 = name)
   363                           format(a1 = "%x" % index, a2 ="%x" % subindex, a3 = nodeid, a4 = name)
   364                     raise PDOmappingException, msg
   364                     raise PDOmappingException, msg
   365                 
   365 
   366                 # Get the entry info
   366                 # Get the entry info
   367                 subentry_infos = node.GetSubentryInfos(index, subindex)
   367                 subentry_infos = node.GetSubentryInfos(index, subindex)
   368                 
   368 
   369                 # If a PDO mappable
   369                 # If a PDO mappable
   370                 if subentry_infos and subentry_infos["pdo"]:
   370                 if subentry_infos and subentry_infos["pdo"]:
   371                     if sizelocation == "X" and len(loc) > 3:
   371                     if sizelocation == "X" and len(loc) > 3:
   372                         numbit = loc[3]
   372                         numbit = loc[3]
   373                     elif sizelocation != "X" and len(loc) > 3:
   373                     elif sizelocation != "X" and len(loc) > 3:
   374                         msg = _("Cannot set bit offset for non bool '{a1}' variable (ID:{a2},Idx:{a3},sIdx:{a4}))").\
   374                         msg = _("Cannot set bit offset for non bool '{a1}' variable (ID:{a2},Idx:{a3},sIdx:{a4}))").\
   375                               format(a1 = name, a2 = nodeid, a3 = "%x" % index, a4 = "%x" % subindex)
   375                               format(a1 = name, a2 = nodeid, a3 = "%x" % index, a4 = "%x" % subindex)
   376                         raise PDOmappingException, msg
   376                         raise PDOmappingException, msg
   377                     else:
   377                     else:
   378                         numbit = None
   378                         numbit = None
   379                     
   379 
   380                     if location["IEC_TYPE"] != "BOOL" and subentry_infos["type"] != COlocationtype:
   380                     if location["IEC_TYPE"] != "BOOL" and subentry_infos["type"] != COlocationtype:
   381                         raise PDOmappingException, _("Invalid type \"{a1}\"-> {a2} != {a3}  for location \"{a4}\"").\
   381                         raise PDOmappingException, _("Invalid type \"{a1}\"-> {a2} != {a3}  for location \"{a4}\"").\
   382                             format(a1 = location["IEC_TYPE"], a2 = COlocationtype, a3 = subentry_infos["type"] , a4 = name)
   382                             format(a1 = location["IEC_TYPE"], a2 = COlocationtype, a3 = subentry_infos["type"] , a4 = name)
   383                     
   383 
   384                     typeinfos = node.GetEntryInfos(COlocationtype)
   384                     typeinfos = node.GetEntryInfos(COlocationtype)
   385                     self.IECLocations[name] = {"type":COlocationtype, "pdotype":SlavePDOType[direction],
   385                     self.IECLocations[name] = {"type":COlocationtype, "pdotype":SlavePDOType[direction],
   386                                                 "nodeid": nodeid, "index": index,"subindex": subindex,
   386                                                 "nodeid": nodeid, "index": index,"subindex": subindex,
   387                                                 "bit": numbit, "size": typeinfos["size"], "sizelocation": sizelocation}
   387                                                 "bit": numbit, "size": typeinfos["size"], "sizelocation": sizelocation}
   388                 else:
   388                 else:
   389                     raise PDOmappingException, _("Not PDO mappable variable : '{a1}' (ID:{a2},Idx:{a3},sIdx:{a4}))").\
   389                     raise PDOmappingException, _("Not PDO mappable variable : '{a1}' (ID:{a2},Idx:{a3},sIdx:{a4}))").\
   390                         format(a1 = name, a2 = nodeid, a3 = "%x" % index, a4 = "%x" % subindex)
   390                         format(a1 = name, a2 = nodeid, a3 = "%x" % index, a4 = "%x" % subindex)
   391         
   391 
   392         #-------------------------------------------------------------------------------
   392         #-------------------------------------------------------------------------------
   393         #                         Search for locations already mapped
   393         #                         Search for locations already mapped
   394         #-------------------------------------------------------------------------------
   394         #-------------------------------------------------------------------------------
   395         
   395 
   396         for name, locationinfos in self.IECLocations.items():
   396         for name, locationinfos in self.IECLocations.items():
   397             node = self.NodeList.SlaveNodes[locationinfos["nodeid"]]["Node"]
   397             node = self.NodeList.SlaveNodes[locationinfos["nodeid"]]["Node"]
   398             
   398 
   399             # Search if slave has a PDO mapping this locations
   399             # Search if slave has a PDO mapping this locations
   400             result = SearchNodePDOMapping(locationinfos, node)
   400             result = SearchNodePDOMapping(locationinfos, node)
   401             if result != None:
   401             if result != None:
   402                 index, subindex = result
   402                 index, subindex = result
   403                 # Get COB ID of the PDO
   403                 # Get COB ID of the PDO
   404                 cobid = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 1)
   404                 cobid = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 1)
   405                 
   405 
   406                 # Add PDO to MasterMapping
   406                 # Add PDO to MasterMapping
   407                 if cobid not in self.MasterMapping.keys():
   407                 if cobid not in self.MasterMapping.keys():
   408                     # Verify that PDO transmit type is conform to sync_TPDOs
   408                     # Verify that PDO transmit type is conform to sync_TPDOs
   409                     transmittype = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 2)
   409                     transmittype = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 2)
   410                     if sync_TPDOs and transmittype != 0x01 or transmittype != 0xFF:
   410                     if sync_TPDOs and transmittype != 0x01 or transmittype != 0xFF:
   412                             # Change TransmitType to SYNCHRONE
   412                             # Change TransmitType to SYNCHRONE
   413                             data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0x01, [])
   413                             data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0x01, [])
   414                         else:
   414                         else:
   415                             # Change TransmitType to ASYCHRONE
   415                             # Change TransmitType to ASYCHRONE
   416                             data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0xFF, [])
   416                             data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0xFF, [])
   417                         
   417 
   418                         # Add entry to slave dcf to change transmit type of 
   418                         # Add entry to slave dcf to change transmit type of
   419                         self.AddParamsToDCF(locationinfos["nodeid"], data, nbparams)
   419                         self.AddParamsToDCF(locationinfos["nodeid"], data, nbparams)
   420                                     
   420 
   421                     mapping = [None]
   421                     mapping = [None]
   422                     values = node.GetEntry(index)
   422                     values = node.GetEntry(index)
   423                     # Store the size of each entry mapped in PDO
   423                     # Store the size of each entry mapped in PDO
   424                     for value in values[1:]:
   424                     for value in values[1:]:
   425                         if value != 0:
   425                         if value != 0:
   426                             mapping.append(value % 0x100)
   426                             mapping.append(value % 0x100)
   427                     self.MasterMapping[cobid] = {"type" : InvertPDOType[locationinfos["pdotype"]], "mapping" : mapping}
   427                     self.MasterMapping[cobid] = {"type" : InvertPDOType[locationinfos["pdotype"]], "mapping" : mapping}
   428             
   428 
   429                 # Indicate that this PDO entry must be saved
   429                 # Indicate that this PDO entry must be saved
   430                 if locationinfos["bit"] is not None:
   430                 if locationinfos["bit"] is not None:
   431                     if not isinstance(self.MasterMapping[cobid]["mapping"][subindex], ListType):
   431                     if not isinstance(self.MasterMapping[cobid]["mapping"][subindex], ListType):
   432                         self.MasterMapping[cobid]["mapping"][subindex] = [1] * self.MasterMapping[cobid]["mapping"][subindex]
   432                         self.MasterMapping[cobid]["mapping"][subindex] = [1] * self.MasterMapping[cobid]["mapping"][subindex]
   433                     if locationinfos["bit"] < len(self.MasterMapping[cobid]["mapping"][subindex]):
   433                     if locationinfos["bit"] < len(self.MasterMapping[cobid]["mapping"][subindex]):
   434                         self.MasterMapping[cobid]["mapping"][subindex][locationinfos["bit"]] = (locationinfos["type"], name)
   434                         self.MasterMapping[cobid]["mapping"][subindex][locationinfos["bit"]] = (locationinfos["type"], name)
   435                 else:
   435                 else:
   436                     self.MasterMapping[cobid]["mapping"][subindex] = (locationinfos["type"], name)
   436                     self.MasterMapping[cobid]["mapping"][subindex] = (locationinfos["type"], name)
   437                 
   437 
   438             else:
   438             else:
   439                 # Add location to those that haven't been mapped yet
   439                 # Add location to those that haven't been mapped yet
   440                 if locationinfos["nodeid"] not in self.LocationsNotMapped.keys():
   440                 if locationinfos["nodeid"] not in self.LocationsNotMapped.keys():
   441                     self.LocationsNotMapped[locationinfos["nodeid"]] = {TPDO : [], RPDO : []}
   441                     self.LocationsNotMapped[locationinfos["nodeid"]] = {TPDO : [], RPDO : []}
   442                 self.LocationsNotMapped[locationinfos["nodeid"]][locationinfos["pdotype"]].append((name, locationinfos))
   442                 self.LocationsNotMapped[locationinfos["nodeid"]][locationinfos["pdotype"]].append((name, locationinfos))
   443     
   443 
   444         #-------------------------------------------------------------------------------
   444         #-------------------------------------------------------------------------------
   445         #                         Build concise DCF for the others locations
   445         #                         Build concise DCF for the others locations
   446         #-------------------------------------------------------------------------------
   446         #-------------------------------------------------------------------------------
   447         
   447 
   448         for nodeid, locations in self.LocationsNotMapped.items():
   448         for nodeid, locations in self.LocationsNotMapped.items():
   449             node = self.NodeList.SlaveNodes[nodeid]["Node"]
   449             node = self.NodeList.SlaveNodes[nodeid]["Node"]
   450             
   450 
   451             # Initialize number of params and data to add to node DCF
   451             # Initialize number of params and data to add to node DCF
   452             nbparams = 0
   452             nbparams = 0
   453             dataparams = ""
   453             dataparams = ""
   454             
   454 
   455             # Generate the best PDO mapping for each type of PDO
   455             # Generate the best PDO mapping for each type of PDO
   456             for pdotype in (TPDO, RPDO):
   456             for pdotype in (TPDO, RPDO):
   457                 if len(locations[pdotype]) > 0:
   457                 if len(locations[pdotype]) > 0:
   458                     pdosize = 0
   458                     pdosize = 0
   459                     pdomapping = []
   459                     pdomapping = []
   481                     if len(pdomapping) > 0:
   481                     if len(pdomapping) > 0:
   482                         # Generate a new PDO Mapping
   482                         # Generate a new PDO Mapping
   483                         data, nbaddedparams = self.AddPDOMapping(nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs)
   483                         data, nbaddedparams = self.AddPDOMapping(nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs)
   484                         dataparams += data
   484                         dataparams += data
   485                         nbparams += nbaddedparams
   485                         nbparams += nbaddedparams
   486                 
   486 
   487             # Add number of params and data to node DCF
   487             # Add number of params and data to node DCF
   488             self.AddParamsToDCF(nodeid, dataparams, nbparams)
   488             self.AddParamsToDCF(nodeid, dataparams, nbparams)
   489         
   489 
   490         #-------------------------------------------------------------------------------
   490         #-------------------------------------------------------------------------------
   491         #                         Master Node Configuration
   491         #                         Master Node Configuration
   492         #-------------------------------------------------------------------------------
   492         #-------------------------------------------------------------------------------
   493         
   493 
   494         # Generate Master's Configuration from informations stored in MasterMapping
   494         # Generate Master's Configuration from informations stored in MasterMapping
   495         for cobid, pdo_infos in self.MasterMapping.items():
   495         for cobid, pdo_infos in self.MasterMapping.items():
   496             # Get next PDO index in MasterNode for this PDO type
   496             # Get next PDO index in MasterNode for this PDO type
   497             current_idx = self.CurrentPDOParamsIdx[pdo_infos["type"]]
   497             current_idx = self.CurrentPDOParamsIdx[pdo_infos["type"]]
   498             
   498 
   499             # Search if there is already a PDO in MasterNode with this cob id
   499             # Search if there is already a PDO in MasterNode with this cob id
   500             for idx in GetNodePDOIndexes(self.MasterNode, pdo_infos["type"], True):
   500             for idx in GetNodePDOIndexes(self.MasterNode, pdo_infos["type"], True):
   501                 if self.MasterNode.GetEntry(idx, 1) == cobid:
   501                 if self.MasterNode.GetEntry(idx, 1) == cobid:
   502                     current_idx = idx
   502                     current_idx = idx
   503             
   503 
   504             # Add a PDO to MasterNode if not PDO have been found
   504             # Add a PDO to MasterNode if not PDO have been found
   505             if current_idx == self.CurrentPDOParamsIdx[pdo_infos["type"]]:
   505             if current_idx == self.CurrentPDOParamsIdx[pdo_infos["type"]]:
   506                 addinglist = [current_idx, current_idx + 0x200]
   506                 addinglist = [current_idx, current_idx + 0x200]
   507                 self.Manager.ManageEntriesOfCurrent(addinglist, [], self.MasterNode)
   507                 self.Manager.ManageEntriesOfCurrent(addinglist, [], self.MasterNode)
   508                 self.MasterNode.SetEntry(current_idx, 0x01, cobid)
   508                 self.MasterNode.SetEntry(current_idx, 0x01, cobid)
   509                 
   509 
   510                 # Increment the number of PDO for this PDO type
   510                 # Increment the number of PDO for this PDO type
   511                 self.CurrentPDOParamsIdx[pdo_infos["type"]] += 1
   511                 self.CurrentPDOParamsIdx[pdo_infos["type"]] += 1
   512             
   512 
   513             # Change the transmit type of the PDO
   513             # Change the transmit type of the PDO
   514             if sync_TPDOs:
   514             if sync_TPDOs:
   515                 self.MasterNode.SetEntry(current_idx, 0x02, 0x01)
   515                 self.MasterNode.SetEntry(current_idx, 0x02, 0x01)
   516             else:
   516             else:
   517                 self.MasterNode.SetEntry(current_idx, 0x02, 0xFF)
   517                 self.MasterNode.SetEntry(current_idx, 0x02, 0xFF)
   518             
   518 
   519             mapping = []
   519             mapping = []
   520             for item in pdo_infos["mapping"]:
   520             for item in pdo_infos["mapping"]:
   521                 if isinstance(item, ListType):
   521                 if isinstance(item, ListType):
   522                     mapping.extend(item)
   522                     mapping.extend(item)
   523                 else:
   523                 else:
   524                     mapping.append(item)
   524                     mapping.append(item)
   525             
   525 
   526             # Add some subentries to PDO mapping if there is not enough
   526             # Add some subentries to PDO mapping if there is not enough
   527             if len(mapping) > 1:
   527             if len(mapping) > 1:
   528                 self.Manager.AddSubentriesToCurrent(current_idx + 0x200, len(mapping) - 1, self.MasterNode)
   528                 self.Manager.AddSubentriesToCurrent(current_idx + 0x200, len(mapping) - 1, self.MasterNode)
   529             
   529 
   530             # Generate MasterNode's PDO mapping
   530             # Generate MasterNode's PDO mapping
   531             for subindex, variable in enumerate(mapping):
   531             for subindex, variable in enumerate(mapping):
   532                 if subindex == 0:
   532                 if subindex == 0:
   533                     continue
   533                     continue
   534                 new_index = False
   534                 new_index = False
   535                 
   535 
   536                 if isinstance(variable, (IntType, LongType)):
   536                 if isinstance(variable, (IntType, LongType)):
   537                     # If variable is an integer then variable is unexpected
   537                     # If variable is an integer then variable is unexpected
   538                     self.MasterNode.SetEntry(current_idx + 0x200, subindex, self.TrashVariables[variable])
   538                     self.MasterNode.SetEntry(current_idx + 0x200, subindex, self.TrashVariables[variable])
   539                 else:
   539                 else:
   540                     typeidx, varname = variable
   540                     typeidx, varname = variable
   541                     variable_infos = self.IECLocations[varname]
   541                     variable_infos = self.IECLocations[varname]
   542                     
   542 
   543                     # Calculate base index for storing variable
   543                     # Calculate base index for storing variable
   544                     mapvariableidx = VariableStartIndex[variable_infos["pdotype"]] + \
   544                     mapvariableidx = VariableStartIndex[variable_infos["pdotype"]] + \
   545                                      VariableTypeOffset[variable_infos["sizelocation"]] * VariableIncrement + \
   545                                      VariableTypeOffset[variable_infos["sizelocation"]] * VariableIncrement + \
   546                                      variable_infos["nodeid"]
   546                                      variable_infos["nodeid"]
   547                     
   547 
   548                     # Generate entry name
   548                     # Generate entry name
   549                     indexname = "%s%s%s_%d"%(VariableDirText[variable_infos["pdotype"]],
   549                     indexname = "%s%s%s_%d"%(VariableDirText[variable_infos["pdotype"]],
   550                                                  variable_infos["sizelocation"],
   550                                                  variable_infos["sizelocation"],
   551                                                  '_'.join(map(str,current_location)),
   551                                                  '_'.join(map(str,current_location)),
   552                                                  variable_infos["nodeid"])    
   552                                                  variable_infos["nodeid"])
   553                     
   553 
   554                     # Search for an entry that has an empty subindex 
   554                     # Search for an entry that has an empty subindex
   555                     while mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000:
   555                     while mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000:
   556                         # Entry doesn't exist
   556                         # Entry doesn't exist
   557                         if not self.MasterNode.IsEntry(mapvariableidx):    
   557                         if not self.MasterNode.IsEntry(mapvariableidx):
   558                             # Add entry to MasterNode
   558                             # Add entry to MasterNode
   559                             self.Manager.AddMapVariableToCurrent(mapvariableidx, "beremiz"+indexname, 3, 1, self.MasterNode)
   559                             self.Manager.AddMapVariableToCurrent(mapvariableidx, "beremiz"+indexname, 3, 1, self.MasterNode)
   560                             new_index = True
   560                             new_index = True
   561                             nbsubentries = self.MasterNode.GetEntry(mapvariableidx, 0x00)
   561                             nbsubentries = self.MasterNode.GetEntry(mapvariableidx, 0x00)
   562                         else:
   562                         else:
   565                             # if entry is full, go to next entry possible or stop now
   565                             # if entry is full, go to next entry possible or stop now
   566                             if nbsubentries == 0xFF:
   566                             if nbsubentries == 0xFF:
   567                                 mapvariableidx += 8 * VariableIncrement
   567                                 mapvariableidx += 8 * VariableIncrement
   568                             else:
   568                             else:
   569                                 break
   569                                 break
   570                                 
   570 
   571                     # Verify that a not full entry has been found
   571                     # Verify that a not full entry has been found
   572                     if mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000:
   572                     if mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000:
   573                         # Generate subentry name
   573                         # Generate subentry name
   574                         if variable_infos["bit"] != None:
   574                         if variable_infos["bit"] != None:
   575                             subindexname = "%(index)d_%(subindex)d_%(bit)d"%variable_infos
   575                             subindexname = "%(index)d_%(subindex)d_%(bit)d"%variable_infos
   580                             self.Manager.AddSubentriesToCurrent(mapvariableidx, 1, self.MasterNode)
   580                             self.Manager.AddSubentriesToCurrent(mapvariableidx, 1, self.MasterNode)
   581                             nbsubentries += 1
   581                             nbsubentries += 1
   582                         # Add informations to the new subentry created
   582                         # Add informations to the new subentry created
   583                         self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"name" : subindexname})
   583                         self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"name" : subindexname})
   584                         self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"type" : typeidx})
   584                         self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"type" : typeidx})
   585                         
   585 
   586                         # Set value of the PDO mapping
   586                         # Set value of the PDO mapping
   587                         typeinfos = self.Manager.GetEntryInfos(typeidx)
   587                         typeinfos = self.Manager.GetEntryInfos(typeidx)
   588                         if typeinfos != None:
   588                         if typeinfos != None:
   589                             value = (mapvariableidx << 16) + ((nbsubentries) << 8) + typeinfos["size"]
   589                             value = (mapvariableidx << 16) + ((nbsubentries) << 8) + typeinfos["size"]
   590                             self.MasterNode.SetEntry(current_idx + 0x200, subindex, value)
   590                             self.MasterNode.SetEntry(current_idx + 0x200, subindex, value)
   591                         
   591 
   592                         # Add variable to pointed variables
   592                         # Add variable to pointed variables
   593                         self.PointedVariables[(mapvariableidx, nbsubentries)] = "%s_%s"%(indexname, subindexname)
   593                         self.PointedVariables[(mapvariableidx, nbsubentries)] = "%s_%s"%(indexname, subindexname)
   594 
   594 
   595 def GenerateConciseDCF(locations, current_location, nodelist, sync_TPDOs, nodename):
   595 def GenerateConciseDCF(locations, current_location, nodelist, sync_TPDOs, nodename):
   596     """
   596     """
   603         "LOC" : tuple of interger for IEC location (0,1,2,...)
   603         "LOC" : tuple of interger for IEC location (0,1,2,...)
   604         }, ...]
   604         }, ...]
   605     @param nodelist: CanFestival network editor model
   605     @param nodelist: CanFestival network editor model
   606     @return: a modified copy of the given CanFestival network editor model
   606     @return: a modified copy of the given CanFestival network editor model
   607     """
   607     """
   608     
   608 
   609     dcfgenerator = ConciseDCFGenerator(nodelist, nodename)
   609     dcfgenerator = ConciseDCFGenerator(nodelist, nodename)
   610     dcfgenerator.GenerateDCF(locations, current_location, sync_TPDOs)
   610     dcfgenerator.GenerateDCF(locations, current_location, sync_TPDOs)
   611     masternode,pointers = dcfgenerator.GetMasterNode(), dcfgenerator.GetPointedVariables()
   611     masternode,pointers = dcfgenerator.GetMasterNode(), dcfgenerator.GetPointedVariables()
   612     # allow access to local OD from Master PLC
   612     # allow access to local OD from Master PLC
   613     pointers.update(LocalODPointers(locations, current_location, masternode))
   613     pointers.update(LocalODPointers(locations, current_location, masternode))
   619     for location in locations:
   619     for location in locations:
   620         COlocationtype = IECToCOType[location["IEC_TYPE"]]
   620         COlocationtype = IECToCOType[location["IEC_TYPE"]]
   621         name = location["NAME"]
   621         name = location["NAME"]
   622         if name in IECLocations:
   622         if name in IECLocations:
   623             if IECLocations[name] != COlocationtype:
   623             if IECLocations[name] != COlocationtype:
   624                 raise PDOmappingException, _("Type conflict for location \"%s\"") % name 
   624                 raise PDOmappingException, _("Type conflict for location \"%s\"") % name
   625         else:
   625         else:
   626             # Get only the part of the location that concern this node
   626             # Get only the part of the location that concern this node
   627             loc = location["LOC"][len(current_location):]
   627             loc = location["LOC"][len(current_location):]
   628             # loc correspond to (ID, INDEX, SUBINDEX [,BIT])
   628             # loc correspond to (ID, INDEX, SUBINDEX [,BIT])
   629             if len(loc) not in (2, 3, 4):
   629             if len(loc) not in (2, 3, 4):
   630                 raise PDOmappingException, _("Bad location size : %s") % str(loc)
   630                 raise PDOmappingException, _("Bad location size : %s") % str(loc)
   631             elif len(loc) != 2:
   631             elif len(loc) != 2:
   632                 continue
   632                 continue
   633             
   633 
   634             # Extract and check nodeid
   634             # Extract and check nodeid
   635             index, subindex = loc[:2]
   635             index, subindex = loc[:2]
   636             
   636 
   637             # Extract and check index and subindex
   637             # Extract and check index and subindex
   638             if not slave.IsEntry(index, subindex):
   638             if not slave.IsEntry(index, subindex):
   639                 raise PDOmappingException, _("No such index/subindex ({a1},{a2}) (variable {a3})").\
   639                 raise PDOmappingException, _("No such index/subindex ({a1},{a2}) (variable {a3})").\
   640                     format(a1 = "%x" % index, a2 = "%x" % subindex, a3 = name)
   640                     format(a1 = "%x" % index, a2 = "%x" % subindex, a3 = name)
   641             
   641 
   642             # Get the entry info
   642             # Get the entry info
   643             subentry_infos = slave.GetSubentryInfos(index, subindex)    
   643             subentry_infos = slave.GetSubentryInfos(index, subindex)
   644             if subentry_infos["type"] != COlocationtype:
   644             if subentry_infos["type"] != COlocationtype:
   645                 raise PDOmappingException, _("Invalid type \"{a1}\"-> {a2} != {a3} for location \"{a4}\"").\
   645                 raise PDOmappingException, _("Invalid type \"{a1}\"-> {a2} != {a3} for location \"{a4}\"").\
   646                     format( a1 = location["IEC_TYPE"], a2 = COlocationtype, a3 = subentry_infos["type"] , a4 = name)
   646                     format( a1 = location["IEC_TYPE"], a2 = COlocationtype, a3 = subentry_infos["type"] , a4 = name)
   647             
   647 
   648             IECLocations[name] = COlocationtype
   648             IECLocations[name] = COlocationtype
   649             pointers[(index, subindex)] = name
   649             pointers[(index, subindex)] = name
   650     return pointers
   650     return pointers
   651         
   651 
   652 if __name__ == "__main__":
   652 if __name__ == "__main__":
   653     import os, sys, getopt
   653     import os, sys, getopt
   654 
   654 
   655     def usage():
   655     def usage():
   656         print """
   656         print """
   665     --reset (-r)
   665     --reset (-r)
   666             Reset the reference result of config_utils test.
   666             Reset the reference result of config_utils test.
   667             Use with caution. Be sure that config_utils
   667             Use with caution. Be sure that config_utils
   668             is currently working properly.
   668             is currently working properly.
   669 """%sys.argv[0]
   669 """%sys.argv[0]
   670     
   670 
   671     # Boolean that indicate if reference result must be redefined
   671     # Boolean that indicate if reference result must be redefined
   672     reset = False
   672     reset = False
   673 
   673 
   674     # Extract command options
   674     # Extract command options
   675     try:
   675     try:
   691     base_folder = sys.path[0]
   691     base_folder = sys.path[0]
   692     for i in xrange(3):
   692     for i in xrange(3):
   693         base_folder = os.path.split(base_folder)[0]
   693         base_folder = os.path.split(base_folder)[0]
   694     # Add CanFestival folder to search pathes
   694     # Add CanFestival folder to search pathes
   695     sys.path.append(os.path.join(base_folder, "CanFestival-3", "objdictgen"))
   695     sys.path.append(os.path.join(base_folder, "CanFestival-3", "objdictgen"))
   696     
   696 
   697     from nodemanager import *
   697     from nodemanager import *
   698     from nodelist import *
   698     from nodelist import *
   699     
   699 
   700     # Open the test nodelist contained into test_config folder
   700     # Open the test nodelist contained into test_config folder
   701     manager = NodeManager()
   701     manager = NodeManager()
   702     nodelist = NodeList(manager)
   702     nodelist = NodeList(manager)
   703     result = nodelist.LoadProject("test_config")
   703     result = nodelist.LoadProject("test_config")
   704     
   704 
   705     # List of locations, we try to map for test
   705     # List of locations, we try to map for test
   706     locations = [{"IEC_TYPE":"BYTE","NAME":"__IB0_1_64_24576_1","DIR":"I","SIZE":"B","LOC":(0,1,64,24576,1)},
   706     locations = [{"IEC_TYPE":"BYTE","NAME":"__IB0_1_64_24576_1","DIR":"I","SIZE":"B","LOC":(0,1,64,24576,1)},
   707                  {"IEC_TYPE":"INT","NAME":"__IW0_1_64_25601_2","DIR":"I","SIZE":"W","LOC":(0,1,64,25601,2)},
   707                  {"IEC_TYPE":"INT","NAME":"__IW0_1_64_25601_2","DIR":"I","SIZE":"W","LOC":(0,1,64,25601,2)},
   708                  {"IEC_TYPE":"INT","NAME":"__IW0_1_64_25601_3","DIR":"I","SIZE":"W","LOC":(0,1,64,25601,3)},
   708                  {"IEC_TYPE":"INT","NAME":"__IW0_1_64_25601_3","DIR":"I","SIZE":"W","LOC":(0,1,64,25601,3)},
   709                  {"IEC_TYPE":"INT","NAME":"__QW0_1_64_25617_2","DIR":"Q","SIZE":"W","LOC":(0,1,64,25617,1)},
   709                  {"IEC_TYPE":"INT","NAME":"__QW0_1_64_25617_2","DIR":"Q","SIZE":"W","LOC":(0,1,64,25617,1)},
   711                  {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_1","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,1)},
   711                  {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_1","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,1)},
   712                  {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_2","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,2)},
   712                  {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_2","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,2)},
   713                  {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_3","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,3)},
   713                  {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_3","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,3)},
   714                  {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_4","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,4)},
   714                  {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_4","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,4)},
   715                  {"IEC_TYPE":"UDINT","NAME":"__ID0_1_4096_0","DIR":"I","SIZE":"D","LOC":(0,1,4096,0)}]
   715                  {"IEC_TYPE":"UDINT","NAME":"__ID0_1_4096_0","DIR":"I","SIZE":"D","LOC":(0,1,4096,0)}]
   716     
   716 
   717     # Generate MasterNode configuration
   717     # Generate MasterNode configuration
   718     try:
   718     try:
   719         masternode, pointedvariables = GenerateConciseDCF(locations, (0, 1), nodelist, True, "TestNode")
   719         masternode, pointedvariables = GenerateConciseDCF(locations, (0, 1), nodelist, True, "TestNode")
   720     except ValueError, message:
   720     except ValueError, message:
   721         print "%s\nTest Failed!"%message
   721         print "%s\nTest Failed!"%message
   722         sys.exit()
   722         sys.exit()
   723     
   723 
   724     import pprint
   724     import pprint
   725     # Get Text corresponding to MasterNode 
   725     # Get Text corresponding to MasterNode
   726     result_node = masternode.PrintString()
   726     result_node = masternode.PrintString()
   727     result_vars = pprint.pformat(pointedvariables)
   727     result_vars = pprint.pformat(pointedvariables)
   728     result = result_node + "\n********POINTERS*********\n" + result_vars + "\n"
   728     result = result_node + "\n********POINTERS*********\n" + result_vars + "\n"
   729     
   729 
   730     # If reset has been choosen
   730     # If reset has been choosen
   731     if reset:
   731     if reset:
   732         # Write Text into reference result file
   732         # Write Text into reference result file
   733         testfile = open("test_config/result.txt", "w")
   733         testfile = open("test_config/result.txt", "w")
   734         testfile.write(result)
   734         testfile.write(result)
   735         testfile.close()
   735         testfile.close()
   736         
   736 
   737         print "Reset Successful!"
   737         print "Reset Successful!"
   738     else:
   738     else:
   739         import os
   739         import os
   740         
   740 
   741         testfile = open("test_config/result_tmp.txt", "w")
   741         testfile = open("test_config/result_tmp.txt", "w")
   742         testfile.write(result)
   742         testfile.write(result)
   743         testfile.close()
   743         testfile.close()
   744         
   744 
   745         os.system("diff test_config/result.txt test_config/result_tmp.txt")
   745         os.system("diff test_config/result.txt test_config/result_tmp.txt")
   746         os.remove("test_config/result_tmp.txt")
   746         os.remove("test_config/result_tmp.txt")