2 # -*- coding: utf-8 -*-
4 This file is part of CanFestival, a library implementing CanOpen Stack.
6 Copyright (C): Edouard TISSERANT and Francis DUPIN
8 See COPYING file for copyrights details.
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2.1 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 word_model = re.compile('([a-zA-Z_0-9]*)')
32 type_model = re.compile('([\_A-Z]*)([0-9]*)')
33 range_model = re.compile('([\_A-Z]*)([0-9]*)\[([\-0-9]*)-([\-0-9]*)\]')
35 categories = [("SDO_SVR", 0x1200, 0x127F), ("SDO_CLT", 0x1280, 0x12FF),
36 ("PDO_RCV", 0x1400, 0x15FF), ("PDO_RCV_MAP", 0x1600, 0x17FF),
37 ("PDO_TRS", 0x1800, 0x19FF), ("PDO_TRS_MAP", 0x1A00, 0x1BFF)]
38 index_categories = ["firstIndex", "lastIndex"]
40 generated_tag = """\n/* File generated by gen_cfile.py. Should not be modified. */\n"""
42 # Format a string for making a C++ variable
44 wordlist = [word for word in word_model.findall(name) if word != '']
48 result += "%s%s"%(sep,word)
52 # Extract the informations from a given type name
53 def GetValidTypeInfos(typename):
54 result = type_model.match(typename)
56 values = result.groups()
57 if values[0] in ("UNSIGNED", "INTEGER") and eval(values[1]) in [i * 8 for i in xrange(1, 9)]:
58 return "UNS%s"%values[1], "", "uint%s"%values[1]
59 elif values[0] == "REAL" and eval(values[1]) in (32, 64):
60 return "%s%s"%(values[0], values[1]), "", "real%s"%values[1]
61 elif values[0] == "VISIBLE_STRING":
63 return "UNS8", "[10]", "visible_string"
65 return "UNS8", "[%s]"%values[1], "visible_string"
68 def WriteFile(filepath, content):
69 cfile = open(filepath,"w")
73 def GenerateFileContent(Manager, headerfilepath):
76 texts["maxPDOtransmit"] = 0
77 texts["NodeName"], texts["NodeID"], texts["NodeType"] = Manager.GetCurrentNodeInfos()
79 texts["iam_a_slave"] = 0
80 if (texts["NodeType"] == "slave"):
81 texts["iam_a_slave"] = 1
83 # Compiling lists of indexes
84 rangelist = [idx for name,idx in Manager.GetCurrentValidIndexes(0, 0x260)]
85 listIndex = [idx for name,idx in Manager.GetCurrentValidIndexes(0x1000, 0xFFFF)]
86 communicationlist = [idx for name,idx in Manager.GetCurrentValidIndexes(0x1000, 0x11FF)]
87 sdolist = [idx for name,idx in Manager.GetCurrentValidIndexes(0x1200, 0x12FF)]
88 pdolist = [idx for name,idx in Manager.GetCurrentValidIndexes(0x1400, 0x1BFF)]
89 variablelist = [idx for name,idx in Manager.GetCurrentValidIndexes(0x2000, 0xBFFF)]
91 #-------------------------------------------------------------------------------
92 # Declaration of the value range types
93 #-------------------------------------------------------------------------------
95 valueRangeContent = ""
99 for index in rangelist:
100 rangename = Manager.GetEntryName(index)
101 result = range_model.match(rangename)
104 internal_types[rangename] = "valueRange_%d"%num
105 typeindex = Manager.GetCurrentEntry(index, 1)
106 typename = Manager.GetTypeName(typeindex)
107 typeinfos = GetValidTypeInfos(typename)
108 if typeinfos == None:
109 raise ValueError, """!!! %s isn't a valid type for CanFestival."""%typename
110 typename = typeinfos[0]
111 minvalue = str(Manager.GetCurrentEntry(index, 2))
112 maxvalue = str(Manager.GetCurrentEntry(index, 3))
113 strDefine += "\n#define valueRange_%d 0x%02X /* Type %s, %s < value < %s */"%(num,index,typename,minvalue,maxvalue)
114 strSwitch += """ case valueRange_%d:
115 if (*(%s*)Value < (%s)%s) return OD_VALUE_TOO_LOW;
116 if (*(%s*)Value > (%s)%s) return OD_VALUE_TOO_HIGH;
117 break;\n"""%(num,typename,typename,minvalue,typename,typename,maxvalue)
119 valueRangeContent += strDefine
120 valueRangeContent += "\nUNS32 %(NodeName)s_valueRangeTest (UNS8 typeValue, void * value)\n{"%texts
121 valueRangeContent += "\n switch (typeValue) {\n"
122 valueRangeContent += strSwitch
123 valueRangeContent += " }\n return 0;\n}\n"
125 #-------------------------------------------------------------------------------
126 # Creation of the mapped variables and object dictionary
127 #-------------------------------------------------------------------------------
129 mappedVariableContent = ""
130 strDeclareHeader = ""
131 strDeclareCallback = ""
134 for index in listIndex:
135 texts["index"] = index
137 entry_infos = Manager.GetEntryInfos(index)
138 texts["EntryName"] = entry_infos["name"]
139 values = Manager.GetCurrentEntry(index)
140 callbacks = Manager.HasCurrentEntryCallbacks(index)
141 if index in variablelist:
142 strIndex += "\n/* index 0x%(index)04X : Mapped variable %(EntryName)s */\n"%texts
144 strIndex += "\n/* index 0x%(index)04X : %(EntryName)s. */\n"%texts
145 if type(values) == ListType:
146 texts["value"] = values[0]
147 strIndex += " UNS8 %(NodeName)s_highestSubIndex_obj%(index)04X = %(value)d; // number of subindex - 1\n"%texts
150 if type(values) != ListType:
151 subentry_infos = Manager.GetSubentryInfos(index, 0)
152 typename = Manager.GetTypeName(subentry_infos["type"])
153 typeinfos = GetValidTypeInfos(typename)
154 if typeinfos == None:
155 raise ValueError, """!!! %s isn't a valid type for CanFestival."""%typename
156 if typename not in internal_types:
157 internal_types[typename] = typeinfos[2]
158 texts["subIndexType"] = typeinfos[0]
159 texts["suffixe"] = typeinfos[1]
160 if typeinfos[2] == "visible_string":
161 texts["value"] = "\"%s\""%values
162 texts["comment"] = ""
164 texts["value"] = "0x%X"%values
165 texts["comment"] = "\t// %s"%str(values)
166 if index in variablelist:
167 texts["name"] = FormatName(subentry_infos["name"])
168 strDeclareHeader += "extern %(subIndexType)s %(name)s%(suffixe)s;\t\t// Mapped at index 0x%(index)04X, subindex 0x00\n"%texts
170 strDeclareHeader += "extern ODCallback_t %(name)s_callbacks[];\t\t// Callbacks of index0x%(index)04X\n"%texts
171 mappedVariableContent += "%(subIndexType)s %(name)s%(suffixe)s = %(value)s;\t\t// Mapped at index 0x%(index)04X, subindex 0x00\n"%texts
173 strIndex += " %(subIndexType)s %(NodeName)s_obj%(index)04X%(suffixe)s = %(value)s;%(comment)s\n"%texts
177 # Entry type is RECORD
178 if entry_infos["struct"] & OD_IdenticalSubindexes:
179 subentry_infos = Manager.GetSubentryInfos(index, 1)
180 typename = Manager.GetTypeName(subentry_infos["type"])
181 typeinfos = GetValidTypeInfos(typename)
182 if typeinfos == None:
183 raise ValueError, """!!! %s isn't a valid type for CanFestival."""%typename
184 if typename not in internal_types:
185 internal_types[typename] = typeinfos[2]
186 texts["subIndexType"] = typeinfos[0]
187 texts["suffixe"] = typeinfos[1]
188 texts["length"] = values[0]
189 if index in variablelist:
190 texts["name"] = FormatName(entry_infos["name"])
191 strDeclareHeader += "%(subIndexType)s %(name)s[%(length)d]%(suffixe)s;\t\t// Mapped at index 0x%(index)04X, subindex 0x01 - 0x%(length)02X\n"%texts
193 strDeclareHeader += "extern ODCallback_t %(name)s_callbacks[];\t\t// Callbacks of index0x%(index)04X\n"%texts
194 mappedVariableContent = "%(subIndexType)s %(name)s[] =\t\t// Mapped at index 0x%(index)04X, subindex 0x01 - 0x%(length)02X\n {\n"%texts
195 for subIndex, value in enumerate(values):
199 if subIndex == len(values)-1:
201 if typeinfos[2] == "visible_string":
202 value = "\"%s\""%value
204 comment = "\t// %s"%str(value)
206 mappedVariableContent += " %s%s%s\n"%(value, sep, comment)
207 mappedVariableContent += " };\n"
209 strIndex += " %(subIndexType)s %(NodeName)s_obj%(index)04X[] = \n {\n"%texts
210 for subIndex, value in enumerate(values):
214 if subIndex == len(values)-1:
216 if typeinfos[2] == "visible_string":
217 value = "\"%s\""%value
219 comment = "\t// %s"%str(value)
221 strIndex += " %s%s%s\n"%(value, sep, comment)
225 # Entry type is ARRAY
226 for subIndex, value in enumerate(values):
227 texts["subIndex"] = subIndex
229 subentry_infos = Manager.GetSubentryInfos(index, subIndex)
230 typename = Manager.GetTypeName(subentry_infos["type"])
231 typeinfos = GetValidTypeInfos(typename)
232 if typeinfos == None:
233 raise ValueError, """!!! %s isn't a valid type for CanFestival."""%typename
234 if typename not in internal_types:
235 internal_types[typename] = typeinfos[2]
236 texts["subIndexType"] = typeinfos[0]
237 texts["suffixe"] = typeinfos[1]
238 if typeinfos[2] == "visible_string":
239 texts["value"] = "\"%s\""%value
240 texts["comment"] = ""
242 texts["value"] = "0x%X"%value
243 texts["comment"] = "\t// %s"%str(value)
244 texts["name"] = FormatName(subentry_infos["name"])
245 if index in variablelist:
246 strDeclareHeader += "extern %(subIndexType)s %(name)s%(suffixe)s;\t\t// Mapped at index 0x%(index)04X, subindex 0x%(subIndex)02X\n"%texts
247 mappedVariableContent += "%(subIndexType)s %(name)s%(suffixe)s = %(value)s;\t\t// Mapped at index 0x%(index)04X, subindex 0x%(subIndex)02X\n"%texts
249 strIndex += " %(subIndexType)s %(NodeName)s_obj%(index)04X_%(name)s%(suffixe)s = %(value)s;%(comment)s\n"%texts
251 texts["name"] = FormatName(entry_infos["name"])
252 strDeclareHeader += "extern ODCallback_t %(name)s_callbacks[];\t\t// Callbacks of index0x%(index)04X\n"%texts
254 # Generating Dictionary C++ entry
256 if index in variablelist:
257 name = FormatName(entry_infos["name"])
259 name = "%(NodeName)s_Index%(index)04X"%texts
260 strIndex += " ODCallback_t %s_callbacks[] = \n {\n"%name
261 for subIndex in xrange(len(values)):
262 strIndex += " NULL,\n"
264 indexCallbacks[index] = "*callbacks = %s_callbacks; "%name
266 indexCallbacks[index] = ""
267 strIndex += " subindex %(NodeName)s_Index%(index)04X[] = \n {\n"%texts
268 for subIndex in xrange(len(values)):
269 subentry_infos = Manager.GetSubentryInfos(index, subIndex)
270 if subIndex < len(values) - 1:
274 typename = Manager.GetTypeName(subentry_infos["type"])
275 typeinfos = GetValidTypeInfos(typename)
276 if typename.startswith("VISIBLE_STRING"):
277 subIndexType = "visible_string"
278 elif typename in internal_types:
279 subIndexType = internal_types[typename]
281 subIndexType = typename
283 if entry_infos["struct"] & OD_MultipleSubindexes:
284 name = "%(NodeName)s_highestSubIndex_obj%(index)04X"%texts
285 elif index in variablelist:
286 name = FormatName(subentry_infos["name"])
288 name = FormatName("%s_obj%04X"%(texts["NodeName"], texts["index"]))
289 elif entry_infos["struct"] & OD_IdenticalSubindexes:
290 if index in variablelist:
291 name = "%s[%d]"%(FormatName(entry_infos["name"]), subIndex - 1)
293 name = "%s_obj%04X[%d]"%(texts["NodeName"], texts["index"], subIndex - 1)
295 if index in variablelist:
296 name = FormatName(subentry_infos["name"])
298 name = "%s_obj%04X_%s"%(texts["NodeName"], texts["index"], FormatName(subentry_infos["name"]))
299 if subIndexType == "visible_string":
302 sizeof = typeinfos[0]
303 params = Manager.GetCurrentParamsEntry(index, subIndex)
308 strIndex += " { %s%s, %s, sizeof (%s), (void*)&%s }%s\n"%(subentry_infos["access"].upper(),save,subIndexType,sizeof,name,sep)
310 indexContents[index] = strIndex
312 #-------------------------------------------------------------------------------
313 # Declaration of Particular Parameters
314 #-------------------------------------------------------------------------------
316 if 0x1006 not in communicationlist:
317 entry_infos = Manager.GetEntryInfos(0x1006)
318 texts["EntryName"] = entry_infos["name"]
319 indexContents[0x1006] = """\n/* index 0x1006 : %(EntryName)s */
320 UNS32 %(NodeName)s_obj1006 = 0x0; // 0
323 if 0x1016 in communicationlist:
324 texts["nombre"] = Manager.GetCurrentEntry(0x1016, 0)
327 entry_infos = Manager.GetEntryInfos(0x1016)
328 texts["EntryName"] = entry_infos["name"]
329 indexContents[0x1016] = """\n/* index 0x1016 : %(EntryName)s */
330 UNS8 %(NodeName)s_highestSubIndex_obj1016 = 0;
331 UNS32 %(NodeName)s_obj1016[0];
332 subindex %(NodeName)s_Index1016[0];
334 if texts["nombre"] > 0:
335 strTimers = "TIMER_HANDLE %(NodeName)s_heartBeatTimers[%(nombre)d] = {TIMER_NONE,};\n"%texts
337 strTimers = "TIMER_HANDLE %(NodeName)s_heartBeatTimers[0];\n"%texts
339 if 0x1017 not in communicationlist:
340 entry_infos = Manager.GetEntryInfos(0x1017)
341 texts["EntryName"] = entry_infos["name"]
342 indexContents[0x1017] = """\n/* index 0x1017 : %(EntryName)s */
343 UNS16 %(NodeName)s_obj1017 = 0x0; // 0
346 #-------------------------------------------------------------------------------
347 # Declaration of navigation in the Object Dictionary
348 #-------------------------------------------------------------------------------
351 strDeclareSwitch = ""
354 for index_cat in index_categories:
355 quick_index[index_cat] = {}
356 for cat, idx_min, idx_max in categories:
357 quick_index[index_cat][cat] = 0
359 for i, index in enumerate(listIndex):
360 texts["index"] = index
361 strDeclareIndex += " { (subindex*)%(NodeName)s_Index%(index)04X,sizeof(%(NodeName)s_Index%(index)04X)/sizeof(%(NodeName)s_Index%(index)04X[0]), 0x%(index)04X},\n"%texts
362 strDeclareSwitch += " case 0x%04X: i = %d;%sbreak;\n"%(index, i, indexCallbacks[index])
363 for cat, idx_min, idx_max in categories:
364 if idx_min <= index <= idx_max:
365 quick_index["lastIndex"][cat] = i
366 if quick_index["firstIndex"][cat] == 0:
367 quick_index["firstIndex"][cat] = i
370 texts["maxPDOtransmit"] = max(1, maxPDOtransmit)
371 for index_cat in index_categories:
372 strQuickIndex += "\nquick_index %s_%s = {\n"%(texts["NodeName"], index_cat)
374 for i, (cat, idx_min, idx_max) in enumerate(categories):
375 if i == len(categories) - 1:
377 strQuickIndex += " %s : %d%s\n"%(cat, quick_index[index_cat][cat], sep)
378 strQuickIndex += "};\n"
380 #-------------------------------------------------------------------------------
382 #-------------------------------------------------------------------------------
384 fileContent = copyright_notice + generated_tag + """
389 /**************************************************************************/
390 /* Declaration of the mapped variables */
391 /**************************************************************************/
392 """ + mappedVariableContent
395 /**************************************************************************/
396 /* Declaration of the value range types */
397 /**************************************************************************/
398 """ + valueRangeContent
401 /**************************************************************************/
403 /**************************************************************************/
404 /* node_id default value.*/
405 UNS8 %(NodeName)s_bDeviceNodeId = 0x%(NodeID)02X;
407 //*****************************************************************************/
408 /* Array of message processing information */
410 const UNS8 %(NodeName)s_iam_a_slave = %(iam_a_slave)d;
413 fileContent += strTimers
416 //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
420 //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
422 contentlist = indexContents.keys()
424 for index in contentlist:
425 fileContent += indexContents[index]
428 const indextable %(NodeName)s_objdict[] =
431 fileContent += strDeclareIndex
434 const indextable * %(NodeName)s_scanIndexOD (UNS16 wIndex, UNS32 * errorCode, ODCallback_t **callbacks)
440 fileContent += strDeclareSwitch
441 fileContent += """ default:
442 *errorCode = OD_NO_SUCH_OBJECT;
445 *errorCode = OD_SUCCESSFUL;
446 return &%(NodeName)s_objdict[i];
449 // To count at which received SYNC a PDO must be sent.
450 // Even if no pdoTransmit are defined, at least one entry is computed
451 // for compilations issues.
452 UNS8 %(NodeName)s_count_sync[%(maxPDOtransmit)d] = {0,};
454 fileContent += strQuickIndex
456 UNS16 %(NodeName)s_ObjdictSize = sizeof(%(NodeName)s_objdict)/sizeof(%(NodeName)s_objdict[0]);
458 CO_Data %(NodeName)s_Data = CANOPEN_NODE_DATA_INITIALIZER(%(NodeName)s);
462 #-------------------------------------------------------------------------------
463 # Write Header File Content
464 #-------------------------------------------------------------------------------
466 HeaderFileContent = copyright_notice + generated_tag + """
469 // prototypes of function to be filled by app
470 void %(NodeName)s_SDOtimeoutError(UNS8 line);
471 void %(NodeName)s_heartbeatError(UNS8);
473 UNS8 %(NodeName)s_canSend(Message *);
475 void %(NodeName)s_initialisation();
476 void %(NodeName)s_preOperational();
477 void %(NodeName)s_operational();
478 void %(NodeName)s_stopped();
480 void %(NodeName)s_post_sync();
481 void %(NodeName)s_post_TPDO();
483 // Master node data struct
484 extern CO_Data %(NodeName)s_Data;
487 HeaderFileContent += strDeclareHeader
489 return fileContent,HeaderFileContent
491 #-------------------------------------------------------------------------------
493 #-------------------------------------------------------------------------------
495 def GenerateFile(filepath, manager):
496 headerfilepath = os.path.splitext(filepath)[0]+".h"
497 content, header = GenerateFileContent(manager, os.path.split(headerfilepath)[1])
498 WriteFile(filepath, content)
499 WriteFile(headerfilepath, header)