]> rtime.felk.cvut.cz Git - CanFestival-3.git/blob - objdictgen/gen_cfile.py
Bug corrected on gen_cfile
[CanFestival-3.git] / objdictgen / gen_cfile.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 copyright_notice="""/*
4 This file is part of CanFestival, a library implementing CanOpen Stack. 
5
6 Copyright (C): Edouard TISSERANT and Francis DUPIN
7
8 See COPYING file for copyrights details.
9
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.
14
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.
19
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
23 */
24 """
25
26 from node import *
27 from types import *
28
29 import re, os
30
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]*)\]')
34
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"]
39
40 generated_tag = """\n/* File generated by gen_cfile.py. Should not be modified. */\n"""
41
42 # Format a string for making a C++ variable
43 def FormatName(name):
44     wordlist = [word for word in word_model.findall(name) if word != '']
45     result = ''
46     sep = ''
47     for word in wordlist:
48         result += "%s%s"%(sep,word)
49         sep = '_'
50     return result
51
52 # Extract the informations from a given type name
53 def GetValidTypeInfos(typename):
54     result = type_model.match(typename)
55     if result:
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":
62             if values[1] == "":
63                 return "UNS8", "[10]", "visible_string"
64             else:
65                 return "UNS8", "[%s]"%values[1], "visible_string"
66     return None
67
68 def WriteFile(filepath, content):
69     cfile = open(filepath,"w")
70     cfile.write(content)
71     cfile.close()
72
73 def GenerateFileContent(Manager, headerfilepath):
74     global type
75     texts = {}
76     texts["maxPDOtransmit"] = 0
77     texts["NodeName"], texts["NodeID"], texts["NodeType"] = Manager.GetCurrentNodeInfos()
78     internal_types = {}
79     texts["iam_a_slave"] = 0
80     if (texts["NodeType"] == "slave"):
81         texts["iam_a_slave"] = 1
82     
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)]
90
91 #-------------------------------------------------------------------------------
92 #                       Declaration of the value range types
93 #-------------------------------------------------------------------------------    
94     
95     valueRangeContent = ""
96     strDefine = ""
97     strSwitch = ""
98     num = 0
99     for index in rangelist:
100         rangename = Manager.GetEntryName(index)
101         result = range_model.match(rangename)
102         if result:
103             num += 1
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)
118
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"
124
125 #-------------------------------------------------------------------------------
126 #            Creation of the mapped variables and object dictionary
127 #-------------------------------------------------------------------------------
128
129     mappedVariableContent = ""
130     strDeclareHeader = ""
131     strDeclareCallback = ""
132     indexContents = {}
133     indexCallbacks = {}
134     for index in listIndex:
135         texts["index"] = index
136         strIndex = ""
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
143         else:
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
148         
149         # Entry type is VAR
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"] = ""
163             else:
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
169                 if callbacks:
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
172             else:
173                 strIndex += "                    %(subIndexType)s %(NodeName)s_obj%(index)04X%(suffixe)s = %(value)s;%(comment)s\n"%texts
174             values = [values]
175         else:
176             
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 += "extern %(subIndexType)s %(name)s[%(length)d]%(suffixe)s;\t\t// Mapped at index 0x%(index)04X, subindex 0x01 - 0x%(length)02X\n"%texts
192                     if callbacks:
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):
196                         sep = ","
197                         comment = ""
198                         if subIndex > 0:
199                             if subIndex == len(values)-1:
200                                 sep = ""
201                             if typeinfos[2] == "visible_string":
202                                 value = "\"%s\""%value
203                             else:
204                                 comment = "\t// %s"%str(value)
205                                 value = "0x%X"%value
206                             mappedVariableContent += "    %s%s%s\n"%(value, sep, comment)
207                     mappedVariableContent += "  };\n"
208                 else:
209                     strIndex += "                    %(subIndexType)s %(NodeName)s_obj%(index)04X[] = \n                    {\n"%texts
210                     for subIndex, value in enumerate(values):
211                         sep = ","
212                         comment = ""
213                         if subIndex > 0:
214                             if subIndex == len(values)-1:
215                                 sep = ""
216                             if typeinfos[2] == "visible_string":
217                                 value = "\"%s\""%value
218                             else:
219                                 comment = "\t// %s"%str(value)
220                                 value = "0x%X"%value
221                             strIndex += "                      %s%s%s\n"%(value, sep, comment)
222                     strIndex += "                    };\n"
223             else:
224                 
225                 texts["parent"] = FormatName(entry_infos["name"])
226                 # Entry type is ARRAY
227                 for subIndex, value in enumerate(values):
228                     texts["subIndex"] = subIndex
229                     if subIndex > 0:
230                         subentry_infos = Manager.GetSubentryInfos(index, subIndex)
231                         typename = Manager.GetTypeName(subentry_infos["type"])
232                         typeinfos = GetValidTypeInfos(typename)
233                         if typeinfos == None:
234                             raise ValueError, """!!! %s isn't a valid type for CanFestival."""%typename
235                         if typename not in internal_types:
236                             internal_types[typename] = typeinfos[2]
237                         texts["subIndexType"] = typeinfos[0]
238                         texts["suffixe"] = typeinfos[1]
239                         if typeinfos[2] == "visible_string":
240                             texts["value"] = "\"%s\""%value
241                             texts["comment"] = ""
242                         else:
243                             texts["value"] = "0x%X"%value
244                             texts["comment"] = "\t// %s"%str(value)
245                         texts["name"] = FormatName(subentry_infos["name"])
246                         if index in variablelist:
247                             strDeclareHeader += "extern %(subIndexType)s %(parent)s_%(name)s%(suffixe)s;\t\t// Mapped at index 0x%(index)04X, subindex 0x%(subIndex)02X\n"%texts
248                             mappedVariableContent += "%(subIndexType)s %(parent)s_%(name)s%(suffixe)s = %(value)s;\t\t// Mapped at index 0x%(index)04X, subindex 0x%(subIndex)02X\n"%texts
249                         else:
250                             strIndex += "                    %(subIndexType)s %(NodeName)s_obj%(index)04X_%(name)s%(suffixe)s = %(value)s;%(comment)s\n"%texts
251                 if callbacks:
252                     strDeclareHeader += "extern ODCallback_t %(parent)s_callbacks[];\t\t// Callbacks of index0x%(index)04X\n"%texts
253         
254         # Generating Dictionary C++ entry
255         if callbacks:
256             if index in variablelist:
257                 name = FormatName(entry_infos["name"])
258             else:
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"
263             strIndex += "                     };\n"
264             indexCallbacks[index] = "*callbacks = %s_callbacks; "%name
265         else:
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:
271                 sep = ","
272             else:
273                 sep = ""
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]
280             else:
281                 subIndexType = typename
282             if subIndex == 0:
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"])
287                 else:
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)
292                 else:
293                     name = "%s_obj%04X[%d]"%(texts["NodeName"], texts["index"], subIndex - 1)
294             else:
295                 if index in variablelist:
296                     name = FormatName("%s_%s"%(entry_infos["name"],subentry_infos["name"]))
297                 else:
298                     name = "%s_obj%04X_%s"%(texts["NodeName"], texts["index"], FormatName(subentry_infos["name"]))
299             if subIndexType == "visible_string":
300                 sizeof = name
301             else:
302                 sizeof = typeinfos[0]
303             params = Manager.GetCurrentParamsEntry(index, subIndex)
304             if params["save"]:
305                 save = "|TO_BE_SAVE"
306             else:
307                 save = ""
308             strIndex += "                       { %s%s, %s, sizeof (%s), (void*)&%s }%s\n"%(subentry_infos["access"].upper(),save,subIndexType,sizeof,name,sep)
309         strIndex += "                     };\n"
310         indexContents[index] = strIndex
311
312 #-------------------------------------------------------------------------------
313 #                     Declaration of Particular Parameters
314 #-------------------------------------------------------------------------------
315
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
321 """%texts
322
323     if 0x1016 in communicationlist:
324         texts["nombre"] = Manager.GetCurrentEntry(0x1016, 0)
325     else:
326         texts["nombre"] = 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];
333 """%texts
334     if texts["nombre"] > 0:
335         strTimers = "TIMER_HANDLE %(NodeName)s_heartBeatTimers[%(nombre)d] = {TIMER_NONE,};\n"%texts
336     else:
337         strTimers = "TIMER_HANDLE %(NodeName)s_heartBeatTimers[0];\n"%texts
338
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
344 """%texts
345
346 #-------------------------------------------------------------------------------
347 #               Declaration of navigation in the Object Dictionary
348 #-------------------------------------------------------------------------------
349
350     strDeclareIndex = ""
351     strDeclareSwitch = ""
352     strQuickIndex = ""
353     quick_index = {}
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
358     maxPDOtransmit = 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
368                 if cat == "PDO_TRS":
369                     maxPDOtransmit += 1
370     texts["maxPDOtransmit"] = max(1, maxPDOtransmit)
371     for index_cat in index_categories:
372         strQuickIndex += "\nquick_index %s_%s = {\n"%(texts["NodeName"], index_cat)
373         sep = ","
374         for i, (cat, idx_min, idx_max) in enumerate(categories):
375             if i == len(categories) - 1:
376                 sep = ""
377             strQuickIndex += "  %s : %d%s\n"%(cat, quick_index[index_cat][cat], sep)
378         strQuickIndex += "};\n"
379
380 #-------------------------------------------------------------------------------
381 #                            Write File Content
382 #-------------------------------------------------------------------------------
383
384     fileContent = copyright_notice + generated_tag + """
385 #include "%s"
386 """%(headerfilepath)
387
388     fileContent += """
389 /**************************************************************************/
390 /* Declaration of the mapped variables                                    */
391 /**************************************************************************/
392 """ + mappedVariableContent
393
394     fileContent += """
395 /**************************************************************************/
396 /* Declaration of the value range types                                   */
397 /**************************************************************************/
398 """ + valueRangeContent
399
400     fileContent += """
401 /**************************************************************************/
402 /* The node id                                                            */
403 /**************************************************************************/
404 /* node_id default value.*/
405 UNS8 %(NodeName)s_bDeviceNodeId = 0x%(NodeID)02X;
406
407 //*****************************************************************************/
408 /* Array of message processing information */
409
410 const UNS8 %(NodeName)s_iam_a_slave = %(iam_a_slave)d;
411
412 """%texts
413     fileContent += strTimers
414     
415     fileContent += """
416 //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
417 //
418 //                             OBJECT DICTIONARY
419 //
420 //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
421 """%texts
422     contentlist = indexContents.keys()
423     contentlist.sort()
424     for index in contentlist:
425         fileContent += indexContents[index]
426
427     fileContent += """
428 const indextable %(NodeName)s_objdict[] = 
429 {
430 """%texts
431     fileContent += strDeclareIndex
432     fileContent += """};
433
434 const indextable * %(NodeName)s_scanIndexOD (UNS16 wIndex, UNS32 * errorCode, ODCallback_t **callbacks)
435 {
436         int i;
437         *callbacks = NULL;
438         switch(wIndex){
439 """%texts
440     fileContent += strDeclareSwitch
441     fileContent += """          default:
442                         *errorCode = OD_NO_SUCH_OBJECT;
443                         return NULL;
444         }
445         *errorCode = OD_SUCCESSFUL;
446         return &%(NodeName)s_objdict[i];
447 }
448
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,};
453 """%texts
454     fileContent += strQuickIndex
455     fileContent += """
456 UNS16 %(NodeName)s_ObjdictSize = sizeof(%(NodeName)s_objdict)/sizeof(%(NodeName)s_objdict[0]); 
457
458 CO_Data %(NodeName)s_Data = CANOPEN_NODE_DATA_INITIALIZER(%(NodeName)s);
459
460 """%texts
461
462 #-------------------------------------------------------------------------------
463 #                          Write Header File Content
464 #-------------------------------------------------------------------------------
465
466     HeaderFileContent = copyright_notice + generated_tag + """
467 #include "data.h"
468
469 // prototypes of function provided by object dictionnary
470 UNS32 %(NodeName)s_valueRangeTest (UNS8 typeValue, void * value);
471 const indextable * %(NodeName)s_scanIndexOD (UNS16 wIndex, UNS32 * errorCode, ODCallback_t **callbacks);
472
473 // prototypes of function to be filled by app
474 void %(NodeName)s_SDOtimeoutError(UNS8 line);
475 void %(NodeName)s_heartbeatError(UNS8);
476
477 UNS8 %(NodeName)s_canSend(Message *);
478
479 void %(NodeName)s_initialisation(void);
480 void %(NodeName)s_preOperational(void);
481 void %(NodeName)s_operational(void);
482 void %(NodeName)s_stopped(void);
483
484 void %(NodeName)s_post_sync(void);
485 void %(NodeName)s_post_TPDO(void);
486
487 // Master node data struct
488 extern CO_Data %(NodeName)s_Data;
489
490 """%texts
491     HeaderFileContent += strDeclareHeader
492     
493     return fileContent,HeaderFileContent
494
495 #-------------------------------------------------------------------------------
496 #                             Main Function
497 #-------------------------------------------------------------------------------
498
499 def GenerateFile(filepath, manager):
500     headerfilepath = os.path.splitext(filepath)[0]+".h"
501     content, header = GenerateFileContent(manager, os.path.split(headerfilepath)[1])
502     WriteFile(filepath, content)
503     WriteFile(headerfilepath, header)
504     return True