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