Subversion Repositories Projects

Rev

Rev 260 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
260 dhylands 1
/****************************************************************************
2
*
3
*   Copyright (c) 2010 Dave Hylands     <dhylands@gmail.com>
4
*
5
*   This program is free software; you can redistribute it and/or modify
6
*   it under the terms of the GNU General Public License version 2 as
7
*   published by the Free Software Foundation.
8
*
9
*   Alternatively, this software may be distributed under the terms of BSD
10
*   license.
11
*
12
*   See README and COPYING for more details.
13
*
14
****************************************************************************/
15
/**
16
*
17
*   @file   gen-dev-type.cpp
18
*
19
*   @brief  Reads a bioloid device file and creates a class derived from
20
*           the BioloidDevice class.
21
*
22
*****************************************************************************/
23
 
24
/* ---- Include Files ----------------------------------------------------- */
25
 
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <ctype.h>
30
#include <getopt.h>
31
 
32
#include "Log.h"
33
#include "Str.h"
34
 
35
#include "bioloid-reg.h"
36
 
37
#include "DevTypeParser.h"
38
 
39
/* ---- Public Variables -------------------------------------------------- */
40
 
41
/* ---- Private Constants and Types --------------------------------------- */
42
 
43
/* ---- Private Variables ------------------------------------------------- */
44
 
45
enum
46
{
47
    // Options assigned a single character code can use that charater code
48
    // as a short option.
49
 
50
    OPT_DEBUG       = 'd',
51
    OPT_VERBOSE     = 'v',
52
    OPT_HELP        = 'h',
53
 
54
    // Options from this point onwards don't have any short option equivalents
55
 
56
    OPT_FIRST_LONG_OPT   = 0x80,
57
 
58
};
59
 
60
static struct option gOption[] =
61
{
62
    { "debug",      no_argument,        NULL,       OPT_DEBUG },
63
    { "help",       no_argument,        NULL,       OPT_HELP },
64
    { "verbose",    no_argument,        NULL,       OPT_VERBOSE },
65
    { NULL }
66
};
67
 
68
static  const char *gFileName;
69
 
70
static  char    gSymbolStr[ 100 ];
71
 
72
/* ---- Private Function Prototypes --------------------------------------- */
73
 
74
static const char *CSymbol( const char *str );
75
static const char *CUpperSymbol( const char *str );
76
 
77
/* ---- Functions --------------------------------------------------------- */
78
 
79
/**
80
 * @addtogroup Bioloid
81
 * @{
82
 */
83
 
84
/***************************************************************************/
85
/**
86
*   Given a symbol, make sure that it can be used a C symbol.
87
*/
88
 
89
const char *CSymbol( const char *str )
90
{
91
    char       *dst_s = gSymbolStr;
92
    const char *src_s = str;
93
    int         makeUpper = 1;
94
 
95
    while ( *src_s != '\0' )
96
    {
97
        if ( isalnum( *src_s ))
98
        {
99
            if ( makeUpper )
100
            {
101
                *dst_s = toupper( *src_s );
102
                makeUpper = 0;
103
            }
104
            else
105
            {
106
                *dst_s = *src_s;
107
            }
108
            dst_s++;
109
        }
110
        else
111
        {
112
            makeUpper = 1;
113
        }
114
 
115
        src_s++;
116
    }
117
    *dst_s = '\0';
118
 
119
    return gSymbolStr;
120
}
121
 
122
/***************************************************************************/
123
/**
124
*   Given a symbol, make sure that it can be used as a C symbol and is
125
*   all uppercase.
126
*/
127
 
128
const char *CLowerSymbol( const char *str )
129
{
130
    char *dst_s = gSymbolStr;
131
    const char *src_s = str;
132
 
133
    while ( *src_s != '\0' )
134
    {
135
        if ( isalnum( *src_s ))
136
        {
137
            *dst_s = tolower( *src_s );
138
        }
139
        else
140
        {
141
            *dst_s = '_';
142
        }
143
 
144
        dst_s++;
145
        src_s++;
146
    }
147
    *dst_s = '\0';
148
 
149
    return gSymbolStr;
150
}
151
 
152
/***************************************************************************/
153
/**
154
*   Given a symbol, make sure that it can be used as a C symbol and is
155
*   all uppercase.
156
*/
157
 
158
const char *CUpperSymbol( const char *str )
159
{
160
    char *dst_s = gSymbolStr;
161
    const char *src_s = str;
162
 
163
    while ( *src_s != '\0' )
164
    {
165
        if ( isalnum( *src_s ))
166
        {
167
            *dst_s = toupper( *src_s );
168
        }
169
        else
170
        {
171
            *dst_s = '_';
172
        }
173
 
174
        dst_s++;
175
        src_s++;
176
    }
177
    *dst_s = '\0';
178
 
179
    return gSymbolStr;
180
}
181
 
182
/***************************************************************************/
183
/**
184
*   Given a parsed device type, generate the source file
185
*/
186
 
187
void GenerateDeviceType( BLD_DevType_t *devType )
188
{
189
    char        genFileName[ FILENAME_MAX ];
190
    char        guardStr[ 60 ];
191
    FILE       *genFs;
192
    const char *baseName;
193
    char       *s;
194
 
195
    if (( baseName = strrchr( gFileName, '/' )) == NULL )
196
    {
197
        baseName = genFileName;
198
    }
199
    else
200
    {
201
        baseName++;
202
    }
203
    LogVerbose( "baseName = '%s'\n", baseName );
204
 
205
    StrMaxCpy( genFileName, baseName, sizeof( genFileName ));
206
    if (( s = strrchr( genFileName, '.' )) != NULL )
207
    {
208
        *s = '\0';
209
    }
210
    StrMaxCat( genFileName, ".h", sizeof( genFileName ));
211
 
212
    if (( genFs = fopen( genFileName, "w" )) == NULL )
213
    {
214
        fprintf( stderr, "Unable to open '%s' for writing\n", genFileName );
215
        return;
216
    }
217
 
218
    Log( "Generating %s from %s ...\n", genFileName, gFileName );
219
 
220
    // Figure out the guard symbol
221
 
222
    StrMaxCpy( guardStr, CUpperSymbol( genFileName ), sizeof( guardStr ));
223
 
224
    fprintf( genFs, "/****************************************************************************\n" );
225
    fprintf( genFs, "*\n" );
226
    fprintf( genFs, "* This file was automatically generated from %s\n", gFileName );
227
    fprintf( genFs, "*\n" );
228
    fprintf( genFs, "****************************************************************************/\n" );
229
    fprintf( genFs, "\n" );
230
    fprintf( genFs, "#if !defined( %s )\n", guardStr );
231
    fprintf( genFs, "#define %s\n", guardStr );
232
    fprintf( genFs, "\n" );
233
    fprintf( genFs, "#include \"BioloidDevice.h\"\n" );
234
    fprintf( genFs, "\n" );
235
    fprintf( genFs, "class Bioloid%s : public BioloidDevice\n", CSymbol( devType->devTypeStr ));
236
    fprintf( genFs, "{\n" );
237
    fprintf( genFs, "public:\n" );
238
 
239
    // Generate the constants for the register offsets
240
    fprintf( genFs, "    enum\n" );
241
    fprintf( genFs, "    {\n" );
242
 
243
    for ( unsigned regIdx = 0; regIdx < devType->numRegs; regIdx++ )
244
    {
245
        BLD_Reg_t   *reg = &devType->reg[ regIdx ];
246
 
247
        fprintf( genFs, "        REG_%-24s = 0x%02x, // %2d\n", CUpperSymbol( reg->name ), reg->address, reg->address );
248
    }
249
 
279 dhylands 250
    fprintf( genFs, "    };\n\n" );
260 dhylands 251
 
252
    // Generate the inline get/set methods
253
 
254
    for ( unsigned regIdx = 0; regIdx < devType->numRegs; regIdx++ )
255
    {
256
        BLD_Reg_t   *reg = &devType->reg[ regIdx ];
257
 
258
        const char *typeStr;
259
 
260
        if ( reg->flags & BLD_REG_FLAG_16BIT )
261
        {
262
            typeStr = "uint16_t";
263
        }
264
        else
265
        {
266
            typeStr = "uint8_t";
267
        }
268
 
269
        fprintf( genFs, "    %s get_%s()\n", typeStr, CLowerSymbol( reg->name ));
270
        fprintf( genFs, "    {\n" );
271
        fprintf( genFs, "        %s val;\n", typeStr );
272
        fprintf( genFs, "        if ( Read( REG_%s, &val ) == Bioloid::ERROR_NONE )\n", CUpperSymbol( reg->name ));
273
        fprintf( genFs, "            return val;\n" );
274
        fprintf( genFs, "        return 0;\n" );
275
        fprintf( genFs, "    }\n\n" );
276
 
277
        if (( reg->flags & BLD_REG_FLAG_WR ) != 0 )
278
        {
279
            fprintf( genFs, "    void set_%s( %s val )\n", CLowerSymbol( reg->name ), typeStr );
280
            fprintf( genFs, "    {\n" );
281
            fprintf( genFs, "        Write( REG_%s, &val, sizeof( val ))\n", CUpperSymbol( reg->name ));
282
            fprintf( genFs, "    }\n\n" );
283
        }
284
    }
285
 
286
    fprintf( genFs, "};\n" );
287
    fprintf( genFs, "\n" );
288
    fprintf( genFs, "#endif // %s\n", guardStr );
289
 
290
    fclose( genFs );
291
}
292
 
293
/***************************************************************************/
294
/**
295
*   Print out the program usage.
296
*/
297
 
298
static void ProcessDeviceType( const char *fileName )
299
{
300
    DevTypeParser    dtp;
301
 
302
    gFileName = fileName;
303
 
304
    dtp.ParseFile( fileName, GenerateDeviceType );
305
}
306
 
307
/***************************************************************************/
308
/**
309
*   Print out the program usage.
310
*/
311
 
312
void Usage()
313
{
314
    fprintf( stderr, "Usage: gen-dev-type <option(s)>\n" );
315
    fprintf( stderr, "  Send commands to bioloid devices\n" );
316
    fprintf( stderr, "\n" );
317
    fprintf( stderr, "  -d, --debug       Enable debug features\n" );
318
    fprintf( stderr, "  -h, --help        Display this message\n" );
319
    fprintf( stderr, "  -v, --verbose     Turn on verbose messages\n" );
320
 
321
} // Usage
322
 
323
//***************************************************************************
324
/**
325
*   main
326
*/
327
 
328
int main( int argc, char **argv )
329
{
330
    char                shortOptsStr[ sizeof( gOption ) / sizeof( gOption[ 0 ] ) + 1 ];
331
    char               *shortOpts = shortOptsStr;
332
    struct option      *scanOpt;
333
    int                 opt;
334
 
335
    // Figure out the short options from our options structure
336
 
337
    for ( scanOpt = gOption; scanOpt->name != NULL; scanOpt++ )
338
    {
339
        if (( scanOpt->flag == NULL ) && ( scanOpt->val < OPT_FIRST_LONG_OPT ))
340
        {
341
            *shortOpts++ = (char)scanOpt->val;
342
 
343
            if ( scanOpt->has_arg != no_argument )
344
            {
345
                *shortOpts++ = ':';
346
            }
347
        }
348
    }
349
    *shortOpts++ = '\0';
350
 
351
    // Parse the command line options
352
 
353
    while (( opt = getopt_long( argc, argv, shortOptsStr, gOption, NULL )) != -1 )
354
    {
355
        switch ( opt )
356
        {
357
            case 0:
358
            {
359
                // getopt_long returns 0 for entries where flag is non-NULL
360
 
361
                break;
362
            }
363
 
364
            case OPT_DEBUG:
365
            {
366
                gDebug = 1;
367
                break;
368
            }
369
 
370
            case OPT_VERBOSE:
371
            {
372
                gVerbose = 1;
373
                break;
374
            }
375
 
376
            case '?':
377
            default:
378
            {
379
                fprintf( stderr, "opt:%d\n", opt );
380
            }
381
            case OPT_HELP:
382
            {
383
                Usage();
384
                exit( 1 );
385
            }
386
        }
387
    }
388
    argc -= optind;
389
    argv += optind;
390
 
391
    LogDebug( "Debug enabled\n" );
392
    LogVerbose( "Verbose enabled\n" );
393
 
394
    for ( int arg = 0; arg < argc; arg++ )
395
    {
396
        const char *fileName = argv[ arg ];
397
 
398
        Log( "Processing %s ...\n", fileName );
399
 
400
        ProcessDeviceType( fileName );
401
    }
402
}
403
 
404
/** @} */
405