for all sorts of entries use in CAN Open specification
"""
nosub = 0 # Entry without subindex (only for type declaration)
-var = 1
-array = 3
-rec = 7
+var = OD_Subindex
+array = OD_Subindex | OD_MultipleSubindexes
+rec = OD_Subindex | OD_MultipleSubindexes | OD_IdenticalSubindexes
# Entries identical on multiple indexes
-plurivar = 9
-pluriarray = 11 # Example : PDO Parameters
-plurirec = 15 # Example : PDO Mapping
+plurivar = OD_Subindex | OD_IdenticalIndexes
+pluriarray = OD_Subindex | OD_MultipleSubindexes | OD_IdenticalIndexes # Example : PDO Parameters
+plurirec = OD_Subindex | OD_MultipleSubindexes | OD_IdenticalSubindexes |OD_IdenticalIndexes # Example : PDO Mapping
"""
MappingDictionary is the structure used for writing a good organised Object
[{"name" : "Error Register", "type" : 0x05, "access": 'ro', "pdo" : True}]},
0x1002 : {"name" : "Manufacturer Status Register", "struct" : var, "need" : False, "values" :
[{"name" : "Manufacturer Status Register", "type" : 0x07, "access" : 'ro', "pdo" : True}]},
- 0x1003 : {"name" : "Pre-defined Error Field", "struct" : rec, "need" : False, "values" :
+ 0x1003 : {"name" : "Pre-defined Error Field", "struct" : rec, "need" : False, "callback" : True, "values" :
[{"name" : "Number of Errors", "type" : 0x05, "access" : 'rw', "pdo" : False},
{"name" : "Standard Error Field", "type" : 0x07, "access" : 'ro', "pdo" : False, "nbmax" : 0xFE}]},
0x1005 : {"name" : "SYNC COB ID", "struct" : var, "need" : False, "callback" : True, "values" :
{"name" : "Save All Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False},
{"name" : "Save Communication Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False},
{"name" : "Save Application Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False},
- {"name" : "Save Manufacturer Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmax" : 0x7C}]},
+ {"name" : "Save Manufacturer Parameters %d[(sub - 3)]", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmax" : 0x7C}]},
0x1011 : {"name" : "Restore Default Parameters", "struct" : array, "need" : False, "values" :
[{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
{"name" : "Restore All Default Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False},
{"name" : "Restore Communication Default Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False},
{"name" : "Restore Application Default Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False},
- {"name" : "Restore Manufacturer Default Parameters", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmax" : 0x7C}]},
+ {"name" : "Restore Manufacturer Defined Default Parameters %d[(sub - 3)]", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmax" : 0x7C}]},
0x1012 : {"name" : "TIME COB ID", "struct" : var, "need" : False, "values" :
[{"name" : "TIME COB ID", "type" : 0x07, "access" : 'rw', "pdo" : False}]},
0x1013 : {"name" : "High Resolution Timestamp", "struct" : var, "need" : False, "values" :
[{"name" : "High Resolution Time Stamp", "type" : 0x07, "access" : 'rw', "pdo" : True}]},
0x1014 : {"name" : "Emergency COB ID", "struct" : var, "need" : False, "values" :
- [{"name" : "Emergency COB ID", "type" : 0x07, "access" : 'rw', "pdo" : False}]},
+ [{"name" : "Emergency COB ID", "type" : 0x07, "access" : 'rw', "pdo" : False, "default" : "\"$NODEID+0x80\""}]},
0x1015 : {"name" : "Inhibit Time Emergency", "struct" : var, "need" : False, "values" :
[{"name" : "Inhibit Time Emergency", "type" : 0x06, "access" : 'rw', "pdo" : False}]},
0x1016 : {"name" : "Consumer Heartbeat Time", "struct" : rec, "need" : False, "values" :
[{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
- {"name" : "Consumer Heartbeat Time", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmax" : 0x7F}]},
+ {"name" : "Consumer Heartbeat Time", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmin" : 1, "nbmax" : 0x7F}]},
0x1017 : {"name" : "Producer Heartbeat Time", "struct" : var, "need" : False, "callback" : True, "values" :
[{"name" : "Producer Heartbeat Time", "type" : 0x06, "access" : 'rw', "pdo" : False}]},
0x1018 : {"name" : "Identity", "struct" : array, "need" : True, "values" :
{"name" : "StdErr", "type" : 0x05, "access" : 'ro', "pdo" : True}]},
0x1027 : {"name" : "Module List", "struct" : rec, "need" : False, "values" :
[{"name" : "Number of Connected Modules", "type" : 0x05, "access" : 'ro', "pdo" : False},
- {"name" : "Module %d[(sub)]", "type" : 0x06, "access" : 'ro', "pdo" : False, "nbmax" : 0xFE}]},
+ {"name" : "Module %d[(sub)]", "type" : 0x06, "access" : 'ro', "pdo" : False, "nbmin" : 1, "nbmax" : 0xFE}]},
0x1028 : {"name" : "Emergency Consumer", "struct" : rec, "need" : False, "values" :
[{"name" : "Number of Consumed Emergency Objects", "type" : 0x05, "access" : 'ro', "pdo" : False},
- {"name" : "Emergency Consumer", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmax" : 0x7E}]},
+ {"name" : "Emergency Consumer", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmin" : 1, "nbmax" : 0x7E}]},
0x1029 : {"name" : "Error Behavior", "struct" : array, "need" : False, "values" :
[{"name" : "Number of Error Classes", "type" : 0x05, "access" : 'ro', "pdo" : False},
{"name" : "Communication Error", "type" : 0x05, "access" : 'rw', "pdo" : False},
{"name" : "Device Profile", "type" : 0x05, "access" : 'rw', "pdo" : False, "nbmax" : 0xFE}]},
0x1200 : {"name" : "Server SDO Parameter", "struct" : array, "need" : False, "values" :
[{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
- {"name" : "COB ID Client to Server (Receive SDO)", "type" : 0x07, "access" : 'ro', "pdo" : False},
- {"name" : "COB ID Server to Client (Transmit SDO)", "type" : 0x07, "access" : 'ro', "pdo" : False}]},
+ {"name" : "COB ID Client to Server (Receive SDO)", "type" : 0x07, "access" : 'ro', "pdo" : False, "default" : "\"$NODEID+0x600\""},
+ {"name" : "COB ID Server to Client (Transmit SDO)", "type" : 0x07, "access" : 'ro', "pdo" : False, "default" : "\"$NODEID+0x580\""}]},
0x1201 : {"name" : "Additional Server SDO %d Parameter[(idx)]", "struct" : pluriarray, "incr" : 1, "nbmax" : 0x7F, "need" : False, "values" :
[{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
{"name" : "COB ID Client to Server (Receive SDO)", "type" : 0x07, "access" : 'ro', "pdo" : False},
[{"name" : "Number of Entries", "type" : 0x05, "access" : 'ro', "pdo" : False},
{"name" : "COB ID Client to Server (Transmit SDO)", "type" : 0x07, "access" : 'rw', "pdo" : False},
{"name" : "COB ID Server to Client (Receive SDO)", "type" : 0x07, "access" : 'rw', "pdo" : False},
- {"name" : "Node ID of the SDO Server", "type" : 0x04, "access" : 'rw', "pdo" : False}]},
+ {"name" : "Node ID of the SDO Server", "type" : 0x05, "access" : 'rw', "pdo" : False}]},
0x1400 : {"name" : "Receive PDO %d Parameter[(idx)]", "struct" : pluriarray, "incr" : 1, "nbmax" : 0x200, "need" : False, "values" :
[{"name" : "Highest SubIndex Supported", "type" : 0x05, "access" : 'ro', "pdo" : False},
- {"name" : "COB ID used by PDO", "type" : 0x07, "access" : 'rw', "pdo" : False, "default" : "{True:self.ID+(base+2)*0x100,False:0}[base<4]"},
+ {"name" : "COB ID used by PDO", "type" : 0x07, "access" : 'rw', "pdo" : False, "default" : "{True:\"$NODEID+0x%X00\"%(base+2),False:0x80000000}[base<4]"},
{"name" : "Transmission Type", "type" : 0x05, "access" : 'rw', "pdo" : False},
{"name" : "Inhibit Time", "type" : 0x06, "access" : 'rw', "pdo" : False},
{"name" : "Compatibility Entry", "type" : 0x05, "access" : 'rw', "pdo" : False},
{"name" : "Event Timer", "type" : 0x06, "access" : 'rw', "pdo" : False}]},
0x1600 : {"name" : "Receive PDO %d Mapping[(idx)]", "struct" : plurirec, "incr" : 1, "nbmax" : 0x200, "need" : False, "values" :
[{"name" : "Number of Entries", "type" : 0x05, "access" : 'rw', "pdo" : False},
- {"name" : "PDO %d Mapping for an application object %d[(idx,sub)]", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmax" : 0x40}]},
+ {"name" : "PDO %d Mapping for an application object %d[(idx,sub)]", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmin" : 0, "nbmax" : 0x40}]},
0x1800 : {"name" : "Transmit PDO %d Parameter[(idx)]", "struct" : pluriarray, "incr" : 1, "nbmax" : 0x200, "need" : False, "callback" : True, "values" :
[{"name" : "Highest SubIndex Supported", "type" : 0x05, "access" : 'ro', "pdo" : False},
- {"name" : "COB ID used by PDO", "type" : 0x07, "access" : 'rw', "pdo" : False, "default" : "{True:self.ID+(base+1)*0x100+0x80,False:0}[base<4]"},
+ {"name" : "COB ID used by PDO", "type" : 0x07, "access" : 'rw', "pdo" : False, "default" : "{True:\"$NODEID+0x%X80\"%(base+1),False:0x80000000}[base<4]"},
{"name" : "Transmission Type", "type" : 0x05, "access" : 'rw', "pdo" : False},
{"name" : "Inhibit Time", "type" : 0x06, "access" : 'rw', "pdo" : False},
{"name" : "Compatibility Entry", "type" : 0x05, "access" : 'rw', "pdo" : False},
{"name" : "Event Timer", "type" : 0x06, "access" : 'rw', "pdo" : False}]},
0x1A00 : {"name" : "Transmit PDO %d Mapping[(idx)]", "struct" : plurirec, "incr" : 1, "nbmax" : 0x200, "need" : False, "values" :
[{"name" : "Number of Entries", "type" : 0x05, "access" : 'rw', "pdo" : False},
- {"name" : "PDO %d Mapping for a process data variable %d[(idx,sub)]", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmax" : 0x40}]},
+ {"name" : "PDO %d Mapping for a process data variable %d[(idx,sub)]", "type" : 0x07, "access" : 'rw', "pdo" : False, "nbmin" : 0, "nbmax" : 0x40}]},
}
#-------------------------------------------------------------------------------
base_index = FindIndex(index, mappingdictionary)
if base_index:
struct = mappingdictionary[base_index]["struct"]
+ if struct & OD_IdenticalIndexes:
+ incr = mappingdictionary[base_index]["incr"]
+ else:
+ incr = 1
if struct & OD_Subindex:
+ infos = None
if struct & OD_IdenticalSubindexes:
- if struct & OD_IdenticalIndexes:
- incr = mappingdictionary[base_index]["incr"]
- else:
- incr = 1
if subIndex == 0:
- return mappingdictionary[base_index]["values"][0].copy()
+ infos = mappingdictionary[base_index]["values"][0].copy()
elif 0 < subIndex <= mappingdictionary[base_index]["values"][1]["nbmax"]:
- copy = mappingdictionary[base_index]["values"][1].copy()
- copy["name"] = StringFormat(copy["name"], (index - base_index) / incr + 1, subIndex)
- return copy
- elif struct & OD_MultipleSubindexes and 0 <= subIndex < len(mappingdictionary[base_index]["values"]):
- return mappingdictionary[base_index]["values"][subIndex].copy()
+ infos = mappingdictionary[base_index]["values"][1].copy()
+ elif struct & OD_MultipleSubindexes:
+ idx = 0
+ for subindex_infos in mappingdictionary[base_index]["values"]:
+ if "nbmax" in subindex_infos:
+ if idx <= subIndex < idx + subindex_infos["nbmax"]:
+ infos = subindex_infos.copy()
+ break;
+ idx += subindex_infos["nbmax"]
+ else:
+ if subIndex == idx:
+ infos = subindex_infos.copy()
+ break;
+ idx += 1
elif subIndex == 0:
- return mappingdictionary[base_index]["values"][0].copy()
+ infos = mappingdictionary[base_index]["values"][0].copy()
+ if infos is not None:
+ infos["name"] = StringFormat(infos["name"], (index - base_index) / incr + 1, subIndex)
+ return infos
return None
"""
class Node:
+ DefaultStringSize = 10
+
def __init__(self, name = "", type = "slave", id = 0, description = "", profilename = "DS-301", profile = {}, specificmenu = []):
self.Name = name
self.Type = type
def SetProfile(self, profile):
self.Profile = profile
+ """
+ Return the default string size
+ """
+ def GetDefaultStringSize(self):
+ return self.DefaultStringSize
+
+ """
+ Define the default string size
+ """
+ def SetDefaultStringSize(self, size):
+ self.DefaultStringSize = size
+
"""
Define the DS-302 Profile
"""
elif subIndex == 1:
self.Dictionary[index] = [value]
return True
- elif subIndex > 1 and type(self.Dictionary[index]) == ListType and subIndex == len(self.Dictionary[index]) + 1:
+ elif subIndex > 0 and type(self.Dictionary[index]) == ListType and subIndex == len(self.Dictionary[index]) + 1:
self.Dictionary[index].append(value)
return True
return False
Returns the value of the entry asked. If the entry has the value "count", it
returns the number of subIndex in the entry except the first.
"""
- def GetEntry(self, index, subIndex = None):
+ def GetEntry(self, index, subIndex = None, compute = True):
if index in self.Dictionary:
if subIndex == None:
if type(self.Dictionary[index]) == ListType:
values = [len(self.Dictionary[index])]
for value in self.Dictionary[index]:
- values.append(self.CompileValue(value, index))
+ values.append(self.CompileValue(value, index, compute))
return values
else:
- return self.CompileValue(self.Dictionary[index], index)
+ return self.CompileValue(self.Dictionary[index], index, compute)
elif subIndex == 0:
if type(self.Dictionary[index]) == ListType:
return len(self.Dictionary[index])
else:
- return self.CompileValue(self.Dictionary[index], index)
+ return self.CompileValue(self.Dictionary[index], index, compute)
elif type(self.Dictionary[index]) == ListType and 0 < subIndex <= len(self.Dictionary[index]):
- return self.CompileValue(self.Dictionary[index][subIndex - 1], index)
+ return self.CompileValue(self.Dictionary[index][subIndex - 1], index, compute)
return None
"""
self.UserMapping[index]["values"] = values
return True
elif 0 <= subIndex < len(self.UserMapping[index]["values"]) and values != None:
+ if "type" in values:
+ if self.UserMapping[index]["struct"] & OD_IdenticalSubindexes:
+ if self.IsStringType(self.UserMapping[index]["values"][subIndex]["type"]):
+ if self.IsRealType(values["type"]):
+ for i in xrange(len(self.Dictionary[index])):
+ self.SetEntry(index, i + 1, 0.)
+ elif not self.IsStringType(values["type"]):
+ for i in xrange(len(self.Dictionary[index])):
+ self.SetEntry(index, i + 1, 0)
+ elif self.IsRealType(self.UserMapping[index]["values"][subIndex]["type"]):
+ if self.IsStringType(values["type"]):
+ for i in xrange(len(self.Dictionary[index])):
+ self.SetEntry(index, i + 1, "")
+ elif not self.IsRealType(values["type"]):
+ for i in xrange(len(self.Dictionary[index])):
+ self.SetEntry(index, i + 1, 0)
+ elif self.IsStringType(values["type"]):
+ for i in xrange(len(self.Dictionary[index])):
+ self.SetEntry(index, i + 1, "")
+ elif self.IsRealType(values["type"]):
+ for i in xrange(len(self.Dictionary[index])):
+ self.SetEntry(index, i + 1, 0.)
+ else:
+ if self.IsStringType(self.UserMapping[index]["values"][subIndex]["type"]):
+ if self.IsRealType(values["type"]):
+ self.SetEntry(index, subIndex, 0.)
+ elif not self.IsStringType(values["type"]):
+ self.SetEntry(index, subIndex, 0)
+ elif self.IsRealType(self.UserMapping[index]["values"][subIndex]["type"]):
+ if self.IsStringType(values["type"]):
+ self.SetEntry(index, subIndex, "")
+ elif not self.IsRealType(values["type"]):
+ self.SetEntry(index, subIndex, 0)
+ elif self.IsStringType(values["type"]):
+ self.SetEntry(index, subIndex, "")
+ elif self.IsRealType(values["type"]):
+ self.SetEntry(index, subIndex, 0.)
self.UserMapping[index]["values"][subIndex].update(values)
return True
return False
mask = 0xFFFF << 16
if subIndex:
model += subIndex << 8
- mask = 0xFF << 8
+ mask += 0xFF << 8
for i in self.Dictionary.iterkeys():
if 0x1600 <= i <= 0x17FF or 0x1A00 <= i <= 0x1BFF:
for j,value in enumerate(self.Dictionary[i]):
Print the Dictionary values
"""
def Print(self):
+ print self.PrintString()
+
+ def PrintString(self):
+ result = ""
listindex = self.Dictionary.keys()
listindex.sort()
for index in listindex:
+ name = self.GetEntryName(index)
values = self.Dictionary[index]
- if index != 0x1F22 and type(values) != IntType:
- values = [i for i in values]
- for i, value in enumerate(values):
- if type(value) == IntType:
- values[i] = "%X"%value
- values = "[" + ",".join(values) + "]"
- print "%04X : %s"%(index, values)
-
- def CompileValue(self, value, index):
- if type(value) == StringType and value.find("self.ID") != -1:
+ if isinstance(values, ListType):
+ result += "%04X (%s):\n"%(index, name)
+ for subidx, value in enumerate(values):
+ subentry_infos = self.GetSubentryInfos(index, subidx + 1)
+ if index == 0x1F22 and value:
+ nb_params = BE_to_LE(value[:4])
+ data = value[4:]
+ value = "%d arg defined"%nb_params
+ i = 0
+ count = 1
+ while i < len(data):
+ value += "\n%04X %02X, arg %d: "%(index, subidx+1, count)
+ value += "%04X"%BE_to_LE(data[i:i+2])
+ value += " %02X"%BE_to_LE(data[i+2:i+3])
+ size = BE_to_LE(data[i+3:i+7])
+ value += " %08X"%size
+ value += (" %0"+"%d"%(size * 2)+"X")%BE_to_LE(data[i+7:i+7+size])
+ i += 7 + size
+ count += 1
+ elif isinstance(value, IntType):
+ value = "%X"%value
+ result += "%04X %02X (%s): %s\n"%(index, subidx+1, subentry_infos["name"], value)
+ else:
+ if isinstance(values, IntType):
+ values = "%X"%values
+ result += "%04X (%s): %s\n"%(index, name, values)
+ return result
+
+ def CompileValue(self, value, index, compute = True):
+ if isinstance(value, (StringType, UnicodeType)) and value.upper().find("$NODEID") != -1:
base = self.GetBaseIndex(index)
try:
- return eval(value)
+ raw = eval(value)
+ if compute:
+ return eval(raw.upper().replace("$NODEID","self.ID"))
+ return raw
except:
return 0
else:
dic[index] = [name, valuetype]
return dic
+#-------------------------------------------------------------------------------
+# Type helper functions
+#-------------------------------------------------------------------------------
+
+ def IsStringType(self, index):
+ if index in (0x9, 0xA, 0xB, 0xF):
+ return True
+ elif 0xA0 <= index < 0x100:
+ result = self.GetEntry(index, 1)
+ if result is not None and result in (0x9, 0xA, 0xB):
+ return True
+ return False
+
+ def IsRealType(self, index):
+ if index in (0x8, 0x11):
+ return True
+ elif 0xA0 <= index < 0x100:
+ result = self.GetEntry(index, 1)
+ if result is not None and result in (0x8, 0x11):
+ return True
+ return False
+
#-------------------------------------------------------------------------------
# Type and Map Variable Lists
#-------------------------------------------------------------------------------
list.sort()
return ",".join(list)
+ def GenerateMapName(self, name, index, subindex):
+ return "%s (0x%4.4X)" % (name, index)
+
"""
Generate the list of variables that can be mapped for the current node
"""
for index, subIndex, size, name in list:
self.MapList += ",%s"%name
map = "%04X%02X%02X"%(index,subIndex,size)
- self.NameTranslation[name] = map
- self.MapTranslation[map] = name
+ mapname = self.GenerateMapName(name, index, subIndex)
+ self.NameTranslation[mapname] = map
+ self.MapTranslation[map] = mapname
def GetMapValue(self, mapname):
if mapname == "None":
else:
list = self.GetMapVariableList()
for index, subIndex, size, name in list:
- if mapname == name:
+ if mapname == self.GenerateMapName(name, index, subIndex):
return (index << 16) + (subIndex << 8) + size
return None
subindex = (value >> 8) % (1 << 8)
result = self.GetSubentryInfos(index, subindex)
if result:
- return result["name"]
+ return self.GenerateMapName(result["name"], index, subindex)
return "None"
"""
Return the list of variables that can be mapped for the current node
"""
def GetMapList(self):
- list = ["None"] + [name for index, subIndex, size, name in self.GetMapVariableList()]
+ list = ["None"] + [self.GenerateMapName(name, index, subIndex) for index, subIndex, size, name in self.GetMapVariableList()]
return ",".join(list)
+
+def BE_to_LE(value):
+ """
+ Convert Big Endian to Little Endian
+ @param value: value expressed in Big Endian
+ @param size: number of bytes generated
+ @return: a string containing the value converted
+ """
+
+ data = [char for char in value]
+ data.reverse()
+ return int("".join(["%2.2X"%ord(char) for char in data]), 16)
+
+def LE_to_BE(value, size):
+ """
+ Convert Little Endian to Big Endian
+ @param value: value expressed in integer
+ @param size: number of bytes generated
+ @return: a string containing the value converted
+ """
+
+ data = ("%" + str(size * 2) + "." + str(size * 2) + "X") % value
+ list_car = [data[i:i+2] for i in xrange(0, len(data), 2)]
+ list_car.reverse()
+ return "".join([chr(int(car, 16)) for car in list_car])
+