]> rtime.felk.cvut.cz Git - CanFestival-3.git/blob - objdictgen/gen_cfile.py
Commit a new cvs repo.
[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             else:
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
167                 if callbacks:
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
170             else:
171                 strIndex += "                    %(subIndexType)s %(NodeName)s_obj%(index)04X%(suffixe)s = %(value)s;\n"%texts
172             values = [values]
173         else:
174             
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
190                     if callbacks:
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):
194                         sep = ","
195                         if subIndex > 0:
196                             if subIndex == len(values)-1:
197                                 sep = ""
198                             if typeinfos[2] == "visible_string":
199                                 value = "\"%s\""%value
200                             else:
201                                 value = "0x%X"%value
202                             mappedVariableContent += "    %s%s\n"%(value, sep)
203                     mappedVariableContent += "  }\n"
204                 else:
205                     strIndex += "                    %(subIndexType)s %(NodeName)s_obj%(index)04X[] = \n                    {\n"%texts
206                     for subIndex, value in enumerate(values):
207                         sep = ","
208                         if subIndex > 0:
209                             if subIndex == len(values)-1:
210                                 sep = ""
211                             if typeinfos[2] == "visible_string":
212                                 value = "\"%s\""%value
213                             else:
214                                 value = str(value)
215                             strIndex += "                      %s%s\n"%(value, sep)
216                     strIndex += "                    };\n"
217             else:
218                 
219                 # Entry type is ARRAY
220                 for subIndex, value in enumerate(values):
221                     texts["subIndex"] = subIndex
222                     if subIndex > 0:
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
234                         else:
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
240                         else:
241                             strIndex += "                    %(subIndexType)s %(NodeName)s_obj%(index)04X_%(name)s%(suffixe)s = %(value)s;\n"%texts
242                 if callbacks:
243                     texts["name"] = FormatName(entry_infos["name"])
244                     strDeclareHeader += "extern ODCallback_t %(name)s_callbacks[];\t\t// Callbacks of index0x%(index)04X\n"%texts
245         
246         # Generating Dictionary C++ entry
247         if callbacks:
248             if index in variablelist:
249                 name = FormatName(entry_infos["name"])
250             else:
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"
255             strIndex += "                     };\n"
256             indexCallbacks[index] = "*callbacks = %s_callbacks; "%name
257         else:
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:
263                 sep = ","
264             else:
265                 sep = ""
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]
272             else:
273                 subIndexType = typename
274             if subIndex == 0:
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"])
279                 else:
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)
284                 else:
285                     name = "%s_obj%04X[%d]"%(texts["NodeName"], texts["index"], subIndex - 1)
286             else:
287                 if index in variablelist:
288                     name = FormatName(subentry_infos["name"])
289                 else:
290                     name = "%s_obj%04X_%s"%(texts["NodeName"], texts["index"], FormatName(subentry_infos["name"]))
291             if subIndexType == "visible_string":
292                 sizeof = name
293             else:
294                 sizeof = typeinfos[0]
295             params = Manager.GetCurrentParamsEntry(index, subIndex)
296             if params["save"]:
297                 save = "|TO_BE_SAVE"
298             else:
299                 save = ""
300             strIndex += "                       { %s%s, %s, sizeof (%s), (void*)&%s }%s\n"%(subentry_infos["access"].upper(),save,subIndexType,sizeof,name,sep)
301         strIndex += "                     };\n"
302         indexContents[index] = strIndex
303
304 #-------------------------------------------------------------------------------
305 #                     Declaration of Particular Parameters
306 #-------------------------------------------------------------------------------
307
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;
313 """%texts
314
315     if 0x1016 in communicationlist:
316         texts["nombre"] = Manager.GetCurrentEntry(0x1016, 0)
317     else:
318         texts["nombre"] = 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];
325 """%texts
326     if texts["nombre"] > 0:
327         strTimers = "TIMER_HANDLE %(NodeName)s_heartBeatTimers[%(nombre)d] = {TIMER_NONE,};\n"%texts
328     else:
329         strTimers = "TIMER_HANDLE %(NodeName)s_heartBeatTimers[0];\n"%texts
330
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;
336 """%texts
337
338 #-------------------------------------------------------------------------------
339 #               Declaration of navigation in the Object Dictionary
340 #-------------------------------------------------------------------------------
341
342     strDeclareIndex = ""
343     strDeclareSwitch = ""
344     strQuickIndex = ""
345     quick_index = {}
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
350     maxPDOtransmit = 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
360                 if cat == "PDO_TRS":
361                     maxPDOtransmit += 1
362     texts["maxPDOtransmit"] = max(1, maxPDOtransmit)
363     for index_cat in index_categories:
364         strQuickIndex += "\nquick_index %s_%s = {\n"%(texts["NodeName"], index_cat)
365         sep = ","
366         for i, (cat, idx_min, idx_max) in enumerate(categories):
367             if i == len(categories) - 1:
368                 sep = ""
369             strQuickIndex += "  %s : %d%s\n"%(cat, quick_index[index_cat][cat], sep)
370         strQuickIndex += "};\n"
371
372 #-------------------------------------------------------------------------------
373 #                            Write File Content
374 #-------------------------------------------------------------------------------
375
376     fileContent = copyright_notice + generated_tag + """
377 #include "%s"
378 """%(headerfilepath)
379
380     fileContent += """
381 /**************************************************************************/
382 /* Declaration of the mapped variables                                    */
383 /**************************************************************************/
384 """ + mappedVariableContent
385
386     fileContent += """
387 /**************************************************************************/
388 /* Declaration of the value range types                                   */
389 /**************************************************************************/
390 """ + valueRangeContent
391
392     fileContent += """
393 /**************************************************************************/
394 /* The node id                                                            */
395 /**************************************************************************/
396 /* node_id default value.*/
397 UNS8 %(NodeName)s_bDeviceNodeId = 0x%(NodeID)02X;
398
399 //*****************************************************************************/
400 /* Array of message processing information */
401
402 const UNS8 %(NodeName)s_iam_a_slave = %(iam_a_slave)d;
403
404 """%texts
405     fileContent += strTimers
406     
407     fileContent += """
408 //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
409 //
410 //                       OBJECT DICTIONARY
411 //                   
412 //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
413 """%texts
414     contentlist = indexContents.keys()
415     contentlist.sort()
416     for index in contentlist:
417         fileContent += indexContents[index]
418
419     fileContent += """
420 const indextable %(NodeName)s_objdict[] = 
421 {
422 """%texts
423     fileContent += strDeclareIndex
424     fileContent += """};
425
426 const indextable * %(NodeName)s_scanIndexOD (UNS16 wIndex, UNS32 * errorCode, ODCallback_t **callbacks)
427 {
428         int i;
429         *callbacks = NULL;
430         switch(wIndex){
431 """%texts
432     fileContent += strDeclareSwitch
433     fileContent += """          default:
434                         *errorCode = OD_NO_SUCH_OBJECT;
435                         return NULL;
436         }
437         *errorCode = OD_SUCCESSFUL;
438         return &%(NodeName)s_objdict[i];
439 }
440
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,};
445 """%texts
446     fileContent += strQuickIndex
447     fileContent += """
448 UNS16 %(NodeName)s_ObjdictSize = sizeof(%(NodeName)s_objdict)/sizeof(%(NodeName)s_objdict[0]); 
449
450 CO_Data %(NodeName)s_Data = CANOPEN_NODE_DATA_INITIALIZER(%(NodeName)s);
451
452 """%texts
453
454 #-------------------------------------------------------------------------------
455 #                          Write Header File Content
456 #-------------------------------------------------------------------------------
457
458     HeaderFileContent = copyright_notice + generated_tag + """
459 #include "data.h"
460
461 // prototypes of function to be filled by app
462 void %(NodeName)s_SDOtimeoutError(UNS8 line);
463 void %(NodeName)s_heartbeatError(UNS8);
464
465 UNS8 %(NodeName)s_canSend(Message *);
466
467 void %(NodeName)s_initialisation();
468 void %(NodeName)s_preOperational();
469 void %(NodeName)s_operational();
470 void %(NodeName)s_stopped();
471
472 void %(NodeName)s_post_sync();
473 void %(NodeName)s_post_TPDO();
474
475 // Master node data struct
476 extern CO_Data %(NodeName)s_Data;
477
478 """%texts
479     HeaderFileContent += strDeclareHeader
480     
481     return fileContent,HeaderFileContent
482
483 #-------------------------------------------------------------------------------
484 #                             Main Function
485 #-------------------------------------------------------------------------------
486
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)
492     return True