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
163 texts["value"] = "0x%X"%values
164 if index in variablelist:
165 texts["name"] = FormatName(subentry_infos["name"])
166 strDeclareHeader += "extern %(subIndexType)s %(name)s%(suffixe)s;\t\t// Mapped at index 0x%(index)04X, subindex 0x00\n"%texts
168 strDeclareHeader += "extern ODCallback_t %(name)s_callbacks[];\t\t// Callbacks of index0x%(index)04X\n"%texts
169 mappedVariableContent += "%(subIndexType)s %(name)s%(suffixe)s = %(value)s;\t\t// Mapped at index 0x%(index)04X, subindex 0x00\n"%texts
171 strIndex += " %(subIndexType)s %(NodeName)s_obj%(index)04X%(suffixe)s = %(value)s;\n"%texts
175 # Entry type is RECORD
176 if entry_infos["struct"] & OD_IdenticalSubindexes:
177 subentry_infos = Manager.GetSubentryInfos(index, 1)
178 typename = Manager.GetTypeName(subentry_infos["type"])
179 typeinfos = GetValidTypeInfos(typename)
180 if typeinfos == None:
181 raise ValueError, """!!! %s isn't a valid type for CanFestival."""%typename
182 if typename not in internal_types:
183 internal_types[typename] = typeinfos[2]
184 texts["subIndexType"] = typeinfos[0]
185 texts["suffixe"] = typeinfos[1]
186 texts["length"] = values[0]
187 if index in variablelist:
188 texts["name"] = FormatName(entry_infos["name"])
189 strDeclareHeader += "%(subIndexType)s %(name)s[%(length)d]%(suffixe)s;\t\t// Mapped at index 0x%(index)04X, subindex 0x01 - 0x%(length)02X\n"%texts
191 strDeclareHeader += "extern ODCallback_t %(name)s_callbacks[];\t\t// Callbacks of index0x%(index)04X\n"%texts
192 mappedVariableContent = "%(subIndexType)s %(name)s[] =\t\t// Mapped at index 0x%(index)04X, subindex 0x01 - 0x%(length)02X\n {\n"%texts
193 for subIndex, value in enumerate(values):
196 if subIndex == len(values)-1:
198 if typeinfos[2] == "visible_string":
199 value = "\"%s\""%value
202 mappedVariableContent += " %s%s\n"%(value, sep)
203 mappedVariableContent += " }\n"
205 strIndex += " %(subIndexType)s %(NodeName)s_obj%(index)04X[] = \n {\n"%texts
206 for subIndex, value in enumerate(values):
209 if subIndex == len(values)-1:
211 if typeinfos[2] == "visible_string":
212 value = "\"%s\""%value
215 strIndex += " %s%s\n"%(value, sep)
219 # Entry type is ARRAY
220 for subIndex, value in enumerate(values):
221 texts["subIndex"] = subIndex
223 subentry_infos = Manager.GetSubentryInfos(index, subIndex)
224 typename = Manager.GetTypeName(subentry_infos["type"])
225 typeinfos = GetValidTypeInfos(typename)
226 if typeinfos == None:
227 raise ValueError, """!!! %s isn't a valid type for CanFestival."""%typename
228 if typename not in internal_types:
229 internal_types[typename] = typeinfos[2]
230 texts["subIndexType"] = typeinfos[0]
231 texts["suffixe"] = typeinfos[1]
232 if typeinfos[2] == "visible_string":
233 texts["value"] = "\"%s\""%value
235 texts["value"] = "0x%X"%value
236 texts["name"] = FormatName(subentry_infos["name"])
237 if index in variablelist:
238 strDeclareHeader += "extern %(subIndexType)s %(name)s%(suffixe)s;\t\t// Mapped at index 0x%(index)04X, subindex 0x%(subIndex)02X\n"%texts
239 mappedVariableContent += "%(subIndexType)s %(name)s%(suffixe)s = %(value)s;\t\t// Mapped at index 0x%(index)04X, subindex 0x%(subIndex)02X\n"%texts
241 strIndex += " %(subIndexType)s %(NodeName)s_obj%(index)04X_%(name)s%(suffixe)s = %(value)s;\n"%texts
243 texts["name"] = FormatName(entry_infos["name"])
244 strDeclareHeader += "extern ODCallback_t %(name)s_callbacks[];\t\t// Callbacks of index0x%(index)04X\n"%texts
246 # Generating Dictionary C++ entry
248 if index in variablelist:
249 name = FormatName(entry_infos["name"])
251 name = "%(NodeName)s_Index%(index)04X"%texts
252 strIndex += " ODCallback_t %s_callbacks[] = \n {\n"%name
253 for subIndex in xrange(len(values)):
254 strIndex += " NULL,\n"
256 indexCallbacks[index] = "*callbacks = %s_callbacks; "%name
258 indexCallbacks[index] = ""
259 strIndex += " subindex %(NodeName)s_Index%(index)04X[] = \n {\n"%texts
260 for subIndex in xrange(len(values)):
261 subentry_infos = Manager.GetSubentryInfos(index, subIndex)
262 if subIndex < len(values) - 1:
266 typename = Manager.GetTypeName(subentry_infos["type"])
267 typeinfos = GetValidTypeInfos(typename)
268 if typename.startswith("VISIBLE_STRING"):
269 subIndexType = "visible_string"
270 elif typename in internal_types:
271 subIndexType = internal_types[typename]
273 subIndexType = typename
275 if entry_infos["struct"] & OD_MultipleSubindexes:
276 name = "%(NodeName)s_highestSubIndex_obj%(index)04X"%texts
277 elif index in variablelist:
278 name = FormatName(subentry_infos["name"])
280 name = FormatName("%s_obj%04X"%(texts["NodeName"], texts["index"]))
281 elif entry_infos["struct"] & OD_IdenticalSubindexes:
282 if index in variablelist:
283 name = "%s[%d]"%(FormatName(entry_infos["name"]), subIndex - 1)
285 name = "%s_obj%04X[%d]"%(texts["NodeName"], texts["index"], subIndex - 1)
287 if index in variablelist:
288 name = FormatName(subentry_infos["name"])
290 name = "%s_obj%04X_%s"%(texts["NodeName"], texts["index"], FormatName(subentry_infos["name"]))
291 if subIndexType == "visible_string":
294 sizeof = typeinfos[0]
295 params = Manager.GetCurrentParamsEntry(index, subIndex)
300 strIndex += " { %s%s, %s, sizeof (%s), (void*)&%s }%s\n"%(subentry_infos["access"].upper(),save,subIndexType,sizeof,name,sep)
302 indexContents[index] = strIndex
304 #-------------------------------------------------------------------------------
305 # Declaration of Particular Parameters
306 #-------------------------------------------------------------------------------
308 if 0x1006 not in communicationlist:
309 entry_infos = Manager.GetEntryInfos(0x1006)
310 texts["EntryName"] = entry_infos["name"]
311 indexContents[0x1006] = """\n/* index 0x1006 : %(EntryName)s */
312 UNS32 %(NodeName)s_obj1006 = 0;
315 if 0x1016 in communicationlist:
316 texts["nombre"] = Manager.GetCurrentEntry(0x1016, 0)
319 entry_infos = Manager.GetEntryInfos(0x1016)
320 texts["EntryName"] = entry_infos["name"]
321 indexContents[0x1016] = """\n/* index 0x1016 : %(EntryName)s */
322 UNS8 %(NodeName)s_highestSubIndex_obj1016 = 0;
323 UNS32 %(NodeName)s_obj1016[0];
324 subindex %(NodeName)s_Index1016[0];
326 if texts["nombre"] > 0:
327 strTimers = "TIMER_HANDLE %(NodeName)s_heartBeatTimers[%(nombre)d] = {TIMER_NONE,};\n"%texts
329 strTimers = "TIMER_HANDLE %(NodeName)s_heartBeatTimers[0];\n"%texts
331 if 0x1017 not in communicationlist:
332 entry_infos = Manager.GetEntryInfos(0x1017)
333 texts["EntryName"] = entry_infos["name"]
334 indexContents[0x1017] = """\n/* index 0x1017 : %(EntryName)s */
335 UNS16 %(NodeName)s_obj1017 = 0;
338 #-------------------------------------------------------------------------------
339 # Declaration of navigation in the Object Dictionary
340 #-------------------------------------------------------------------------------
343 strDeclareSwitch = ""
346 for index_cat in index_categories:
347 quick_index[index_cat] = {}
348 for cat, idx_min, idx_max in categories:
349 quick_index[index_cat][cat] = 0
351 for i, index in enumerate(listIndex):
352 texts["index"] = index
353 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
354 strDeclareSwitch += " case 0x%04X: i = %d;%sbreak;\n"%(index, i, indexCallbacks[index])
355 for cat, idx_min, idx_max in categories:
356 if idx_min <= index <= idx_max:
357 quick_index["lastIndex"][cat] = i
358 if quick_index["firstIndex"][cat] == 0:
359 quick_index["firstIndex"][cat] = i
362 texts["maxPDOtransmit"] = max(1, maxPDOtransmit)
363 for index_cat in index_categories:
364 strQuickIndex += "\nquick_index %s_%s = {\n"%(texts["NodeName"], index_cat)
366 for i, (cat, idx_min, idx_max) in enumerate(categories):
367 if i == len(categories) - 1:
369 strQuickIndex += " %s : %d%s\n"%(cat, quick_index[index_cat][cat], sep)
370 strQuickIndex += "};\n"
372 #-------------------------------------------------------------------------------
374 #-------------------------------------------------------------------------------
376 fileContent = copyright_notice + generated_tag + """
381 /**************************************************************************/
382 /* Declaration of the mapped variables */
383 /**************************************************************************/
384 """ + mappedVariableContent
387 /**************************************************************************/
388 /* Declaration of the value range types */
389 /**************************************************************************/
390 """ + valueRangeContent
393 /**************************************************************************/
395 /**************************************************************************/
396 /* node_id default value.*/
397 UNS8 %(NodeName)s_bDeviceNodeId = 0x%(NodeID)02X;
399 //*****************************************************************************/
400 /* Array of message processing information */
402 const UNS8 %(NodeName)s_iam_a_slave = %(iam_a_slave)d;
405 fileContent += strTimers
408 //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
412 //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
414 contentlist = indexContents.keys()
416 for index in contentlist:
417 fileContent += indexContents[index]
420 const indextable %(NodeName)s_objdict[] =
423 fileContent += strDeclareIndex
426 const indextable * %(NodeName)s_scanIndexOD (UNS16 wIndex, UNS32 * errorCode, ODCallback_t **callbacks)
432 fileContent += strDeclareSwitch
433 fileContent += """ default:
434 *errorCode = OD_NO_SUCH_OBJECT;
437 *errorCode = OD_SUCCESSFUL;
438 return &%(NodeName)s_objdict[i];
441 // To count at which received SYNC a PDO must be sent.
442 // Even if no pdoTransmit are defined, at least one entry is computed
443 // for compilations issues.
444 UNS8 %(NodeName)s_count_sync[%(maxPDOtransmit)d] = {0,};
446 fileContent += strQuickIndex
448 UNS16 %(NodeName)s_ObjdictSize = sizeof(%(NodeName)s_objdict)/sizeof(%(NodeName)s_objdict[0]);
450 CO_Data %(NodeName)s_Data = CANOPEN_NODE_DATA_INITIALIZER(%(NodeName)s);
454 #-------------------------------------------------------------------------------
455 # Write Header File Content
456 #-------------------------------------------------------------------------------
458 HeaderFileContent = copyright_notice + generated_tag + """
461 // prototypes of function to be filled by app
462 void %(NodeName)s_SDOtimeoutError(UNS8 line);
463 void %(NodeName)s_heartbeatError(UNS8);
465 UNS8 %(NodeName)s_canSend(Message *);
467 void %(NodeName)s_initialisation();
468 void %(NodeName)s_preOperational();
469 void %(NodeName)s_operational();
470 void %(NodeName)s_stopped();
472 void %(NodeName)s_post_sync();
473 void %(NodeName)s_post_TPDO();
475 // Master node data struct
476 extern CO_Data %(NodeName)s_Data;
479 HeaderFileContent += strDeclareHeader
481 return fileContent,HeaderFileContent
483 #-------------------------------------------------------------------------------
485 #-------------------------------------------------------------------------------
487 def GenerateFile(filepath, manager):
488 headerfilepath = os.path.splitext(filepath)[0]+".h"
489 content, header = GenerateFileContent(manager, os.path.split(headerfilepath)[1])
490 WriteFile(filepath, content)
491 WriteFile(headerfilepath, header)