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