From b950e1c63c454f350124c126b656791cafc63456 Mon Sep 17 00:00:00 2001 From: Frank Mori Hess Date: Wed, 5 Mar 2003 00:30:00 +0000 Subject: [PATCH] removed libperl dependency by switching to bison/flex to parse calibration file. --- lib/Makefile | 16 +-- lib/calib.c | 250 +++++++++----------------------------- lib/calib_lex.l | 81 +++++++++++++ lib/calib_yacc.y | 301 ++++++++++++++++++++++++++++++++++++++++++++++ lib/libinternal.h | 38 +++++- 5 files changed, 487 insertions(+), 199 deletions(-) create mode 100644 lib/calib_lex.l create mode 100644 lib/calib_yacc.y diff --git a/lib/Makefile b/lib/Makefile index dea449b..7da559b 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -2,23 +2,25 @@ include ../Config include ../version -PERL_LDFLAGS := -lperl $(shell perl -MConfig -e 'print $$Config{perllibs}') -PERL_INC := $(shell perl -MConfig -e 'print $$Config{archlib}')/CORE - -CFLAGS += -fPIC -I../include -I. -I$(PERL_INC) +CFLAGS += -fPIC -I../include -I. OBJS=comedi.o timer.o sv.o range.o ioctl.o filler.o timed.o error.o \ - dio.o data.o get.o cmd.o buffer.o calib.o + dio.o data.o get.o cmd.o buffer.o calib.o calib_lex.o calib_yacc.o SONAME=libcomedi$(SONAME_SUFFIX).so.0 libcomedi.a: $(OBJS) version_script #$(CC) -shared -Wl,-soname,libcomedi.so,-T,version_script -o libcomedi.so.${VERSION_CODE} $(OBJS) -lm - $(CC) -shared -Wl,-soname,$(SONAME) -Wl,--version-script,version_script -o libcomedi.so.${version} $(OBJS) -lm $(PERL_LDFLAGS) + $(CC) -shared -Wl,-soname,$(SONAME) -Wl,--version-script,version_script -o libcomedi.so.${version} $(OBJS) -lm $(AR) rs libcomedi.a $(OBJS) ln -sf libcomedi.so.${version} libcomedi.so ln -sf libcomedi.so.${version} libcomedi.so.0 clean: - rm -f libcomedi.a libcomedi.so* *.o + rm -f libcomedi.a libcomedi.so* *.o calib_lex.c calib_yacc.c calib_yacc.h + +calib_lex.c: calib_lex.l calib_yacc.h + flex -Pcalib_yy -o$@ $< +calib_yacc.c + calib_yacc.h: calib_yacc.y + bison -d -y -p calib_yy -o calib_yacc.c calib_yacc.y diff --git a/lib/calib.c b/lib/calib.c index c99433a..c6cce94 100644 --- a/lib/calib.c +++ b/lib/calib.c @@ -27,50 +27,16 @@ #include #include #include -#include -#include -static int extract_ph_string( PerlInterpreter *my_perl, const char *perl_statement, - char *result, unsigned int result_size ) +static int check_cal_file( comedi_t *dev, const struct calibration_file_contents *parsed_file ) { - SV *perl_retval; - STRLEN len; - - perl_retval = eval_pv( perl_statement, FALSE ); - strncpy( result, SvPV( perl_retval, len ), result_size ); - return 0; -} - -static int extract_ph_integer( PerlInterpreter *my_perl, const char *perl_statement ) -{ - SV *perl_retval; - int result; - - perl_retval = eval_pv( perl_statement, FALSE ); - result = SvIV( perl_retval ); - return result; -} - -static int check_cal_file( comedi_t *dev, PerlInterpreter *my_perl ) -{ - char result[ 100 ]; - int retval; - - retval = extract_ph_string( my_perl, "$cal->{driver_name};", - result, sizeof( result ) ); - if( retval < 0 ) return retval; - - if( strcmp( comedi_get_driver_name( dev ), result ) ) + if( strcmp( comedi_get_driver_name( dev ), parsed_file->driver_name ) ) { fprintf( stderr, "driver name does not match calibration file\n" ); return -1; } - retval = extract_ph_string( my_perl, "$cal->{board_name};", - result, sizeof( result ) ); - if( retval < 0 ) return retval; - - if( strcmp( comedi_get_board_name( dev ), result ) ) + if( strcmp( comedi_get_board_name( dev ), parsed_file->board_name ) ) { fprintf( stderr, "board name does not match calibration file\n" ); return -1; @@ -79,89 +45,67 @@ static int check_cal_file( comedi_t *dev, PerlInterpreter *my_perl ) return 0; } -static inline int num_calibrations( PerlInterpreter *my_perl ) +static inline int valid_channel( const struct calibration_file_contents *parsed_file, + unsigned int cal_index, unsigned int channel ) { - return extract_ph_integer( my_perl, "scalar( @{$cal->{calibrations}} );" ); -} - -static int extract_array_element( PerlInterpreter *my_perl, unsigned int cal_index, - const char *array_name, unsigned int array_index ) -{ - char element[ 100 ]; - - snprintf( element, sizeof( element ), - "$cal->{ calibrations }[ %i ]->{ %s }[ %i ];", cal_index, array_name, array_index ); - return extract_ph_integer( my_perl, element ); -} + int num_channels, i; -static int extract_array_length( PerlInterpreter *my_perl, unsigned int cal_index, - const char *array_name ) -{ - char element[ 100 ]; - - snprintf( element, sizeof( element ), - "scalar( @{ $cal->{ calibrations }[ %i ]->{ %s } } );", cal_index, array_name ); - return extract_ph_integer( my_perl, element ); -} - -static int extract_subdevice( PerlInterpreter *my_perl, unsigned int cal_index ) -{ - char element[ 100 ]; + num_channels = parsed_file->calibrations[ cal_index ].num_channels; + if( num_channels == 0 ) return 1; + for( i = 0; i < num_channels; i++ ) + { + if( parsed_file->calibrations[ cal_index ].channels[ i ] == channel ) + return 1; + } - snprintf( element, sizeof( element ), - "$cal->{ calibrations }[ %i ]->{ subdevice };", cal_index ); - return extract_ph_integer( my_perl, element ); + return 0; } -static int valid_item( PerlInterpreter *my_perl, unsigned int cal_index, - const char *item_type, unsigned int item ) +static inline int valid_range( const struct calibration_file_contents *parsed_file, + unsigned int cal_index, unsigned int range ) { - int num_items, i; + int num_ranges, i; - num_items = extract_array_length( my_perl, cal_index, item_type ); - if( num_items < 0 ) return 0; - if( num_items == 0 ) return 1; - for( i = 0; i < num_items; i++ ) + num_ranges = parsed_file->calibrations[ cal_index ].num_ranges; + if( num_ranges == 0 ) return 1; + for( i = 0; i < num_ranges; i++ ) { - if( extract_array_element( my_perl, cal_index, item_type, i ) == item ) + if( parsed_file->calibrations[ cal_index ].ranges[ i ] == range ) return 1; } return 0; } -static inline int valid_range( PerlInterpreter *my_perl, unsigned int cal_index, - unsigned int range ) +static inline int valid_aref( const struct calibration_file_contents *parsed_file, + unsigned int cal_index, unsigned int aref ) { - return valid_item( my_perl, cal_index, "ranges", range ); -} + int num_arefs, i; -static inline int valid_channel( PerlInterpreter *my_perl, unsigned int cal_index, - unsigned int channel ) -{ - return valid_item( my_perl, cal_index, "channels", channel ); -} + num_arefs = parsed_file->calibrations[ cal_index ].num_arefs; + if( num_arefs == 0 ) return 1; + for( i = 0; i < num_arefs; i++ ) + { + if( parsed_file->calibrations[ cal_index ].arefs[ i ] == aref ) + return 1; + } -static inline int valid_aref( PerlInterpreter *my_perl, unsigned int cal_index, - unsigned int aref ) -{ - return valid_item( my_perl, cal_index, "arefs", aref ); + return 0; } -static int find_calibration( PerlInterpreter *my_perl, unsigned int subdev, - unsigned int channel, unsigned int range, unsigned int aref ) +static int find_calibration( const struct calibration_file_contents *parsed_file, + unsigned int subdev, unsigned int channel, unsigned int range, unsigned int aref ) { int num_cals, i; - num_cals = num_calibrations( my_perl ); - if( num_cals < 0 ) return num_cals; + num_cals = parsed_file->num_calibrations; for( i = 0; i < num_cals; i++ ) { - if( extract_subdevice( my_perl, i ) != subdev ) continue; - if( valid_range( my_perl, i, range ) == 0 ) continue; - if( valid_channel( my_perl, i, channel ) == 0 ) continue; - if( valid_aref( my_perl, i, aref ) == 0 ) continue; + if( parsed_file->calibrations[ i ].subdevice != subdev ) continue; + if( valid_range( parsed_file, i, range ) == 0 ) continue; + if( valid_channel( parsed_file, i, channel ) == 0 ) continue; + if( valid_aref( parsed_file, i, aref ) == 0 ) continue; break; } if( i == num_cals ) return -1; @@ -169,101 +113,27 @@ static int find_calibration( PerlInterpreter *my_perl, unsigned int subdev, return i; } -static int set_calibration( comedi_t *dev, PerlInterpreter *my_perl, +static int set_calibration( comedi_t *dev, const struct calibration_file_contents *parsed_file, unsigned int cal_index ) { int i, retval, num_caldacs; - num_caldacs = extract_array_length( my_perl, cal_index, "caldacs" ); - if( num_caldacs < 0 ) return num_caldacs; + num_caldacs = parsed_file->calibrations[ cal_index ].num_caldacs; for( i = 0; i < num_caldacs; i++ ) { - int subdev, channel, value; - char *element; - - asprintf( &element, "$cal->{calibrations}[ %i ]->{caldacs}[ %i ]->{subdevice};", - cal_index, i ); - subdev = extract_ph_integer( my_perl, element ); - free( element ); - if( subdev < 0 ) - { - fprintf( stderr, "failed to extract subdev\n" ); - return subdev; - } + struct caldac_setting caldac; - asprintf( &element, "$cal->{calibrations}[ %i ]->{caldacs}[ %i ]->{channel};", - cal_index, i ); - channel = extract_ph_integer( my_perl, element ); - free( element ); - if( channel < 0 ) - { - fprintf( stderr, "failed to extract channel\n" ); - return channel; - } + caldac = parsed_file->calibrations[ cal_index ].caldacs[ i ]; - asprintf( &element, "$cal->{calibrations}[ %i ]->{caldacs}[ %i ]->{value};", - cal_index, i ); - value = extract_ph_integer( my_perl, element ); - free( element ); - if( value < 0 ) - { - fprintf( stderr, "failed to extract value\n" ); - return value; - } - - retval = comedi_data_write( dev, subdev, channel, 0, 0, value ); + retval = comedi_data_write( dev, caldac.subdevice, caldac.channel, + 0, 0, caldac.value ); if( retval < 0 ) return retval; } return 0; } -static PerlInterpreter* alloc_my_perl( void ) -{ - PerlInterpreter *my_perl; - char *embedding[] = { "", "-e", "0" }; - - my_perl = perl_alloc(); - if( my_perl == NULL ) - { - fprintf( stderr, "failed to alloc perl interpreter\n"); - return my_perl; - } - perl_construct( my_perl ); - perl_parse(my_perl, NULL, 3, embedding, NULL); - - return my_perl; -} - -static int startup_my_perl( PerlInterpreter *my_perl, const char *file_path ) -{ - int retval; - char perl_prog[ 1024 ]; - - snprintf( perl_prog, sizeof( perl_prog ), - " - my $hash = `cat '%s'`; - eval \"\\$cal = $hash;\"; - ", file_path ); - - retval = perl_run( my_perl ); - if( retval ) - { - fprintf( stderr, "nonzero exit from perl_run\n"); - return -1; - } - eval_pv( perl_prog, FALSE ); - - return 0; -} - -static void cleanup_my_perl( PerlInterpreter *my_perl ) -{ - perl_destruct( my_perl ); - perl_free( my_perl ); -} - EXPORT_SYMBOL(comedi_apply_calibration,0.7.20); int comedi_apply_calibration( comedi_t *dev, unsigned int subdev, unsigned int channel, unsigned int range, unsigned int aref, const char *cal_file_path ) @@ -272,7 +142,8 @@ int comedi_apply_calibration( comedi_t *dev, unsigned int subdev, unsigned int c char file_path[ 1024 ]; int retval; int cal_index; - PerlInterpreter *my_perl; + FILE *cal_file; + const struct calibration_file_contents *parsed_file; if( cal_file_path ) { @@ -290,35 +161,32 @@ int comedi_apply_calibration( comedi_t *dev, unsigned int subdev, unsigned int c ( unsigned long ) file_stats.st_ino ); } - my_perl = alloc_my_perl(); - if( my_perl == NULL ) - return -1; + cal_file = fopen( file_path, "r" ); + if( cal_file == NULL ) return -1; - retval = startup_my_perl( my_perl, file_path ); - if( retval < 0 ) - { - cleanup_my_perl( my_perl ); - return retval; - } + parsed_file = parse_calibration_file( cal_file ); + if( parsed_file == NULL ) return -1; + + fclose( cal_file ); - retval = check_cal_file( dev, my_perl ); + retval = check_cal_file( dev, parsed_file ); if( retval < 0 ) { - cleanup_my_perl( my_perl ); + cleanup_calibration_parse(); return retval; } - cal_index = find_calibration( my_perl, subdev, channel, range, aref ); + cal_index = find_calibration( parsed_file, subdev, channel, range, aref ); if( cal_index < 0 ) { - cleanup_my_perl( my_perl ); + cleanup_calibration_parse(); return cal_index; } - retval = set_calibration( dev, my_perl, cal_index ); + retval = set_calibration( dev, parsed_file, cal_index ); if( retval < 0 ); { - cleanup_my_perl( my_perl ); + cleanup_calibration_parse(); return retval; } diff --git a/lib/calib_lex.l b/lib/calib_lex.l new file mode 100644 index 0000000..9e2dab4 --- /dev/null +++ b/lib/calib_lex.l @@ -0,0 +1,81 @@ +%option noyywrap + +%{ + +/* + lib/calib_lex.l + code for parsing calibration file, generated by flex + + Copyright (C) 2003 Frank Mori Hess \n { yylloc.first_line++; } + +"#" BEGIN(COMMENT); +\n { yylloc.first_line++; BEGIN(INITIAL); } + +\" { string_buf_ptr = string_buf; BEGIN(STRING); } +\" { + *string_buf_ptr = 0; + BEGIN(INITIAL); + calib_yylval.sval = string_buf; + return ( T_STRING ); + } +[^\n\"]+ { + char *yptr = yytext; + + while ( *yptr && ( string_buf_ptr - string_buf ) < sizeof( string_buf ) - 1 ) + *string_buf_ptr++ = *yptr++; + } + +driver_name { return ( T_DRIVER_NAME ); } +board_name { return ( T_BOARD_NAME ); } +calibrations { return ( T_CALIBRATIONS ); } +subdevice { return ( T_SUBDEVICE); } +channels { return (T_CHANNELS); } +ranges { return ( T_RANGES ); } +arefs { return ( T_AREFS ); } +caldacs { return ( T_CALDACS ); } +channel { return ( T_CHANNEL ); } +value { return ( T_VALUE ); } +=> { return ( T_ASSIGN ); }; + +(0x)?(00)?[0-9a-fA-F]+ { calib_yylval.ival = strtol( calib_yytext, NULL, 0 ); + return( T_NUMBER ); } + +[ \t] + +. { return( calib_yytext[0] ); } + + +%% + diff --git a/lib/calib_yacc.y b/lib/calib_yacc.y new file mode 100644 index 0000000..b7f7657 --- /dev/null +++ b/lib/calib_yacc.y @@ -0,0 +1,301 @@ +%{ +/* + lib/calib_yacc.y + code for parsing calibration file, generated by bison + + Copyright (C) 2003 Frank Mori Hess +#include "libinternal.h" +#include +#include + +#define YYERROR_VERBOSE + +struct calibration_file_contents file_contents; +static struct caldac_setting caldac; +static int cal_index; + +static void free_calibration_setting( struct calibration_setting *setting ) +{ + if( setting->channels ); + { + free( setting->channels ); + setting->channels = NULL; + setting->num_channels = 0; + } + if( setting->ranges ); + { + free( setting->ranges ); + setting->ranges = NULL; + setting->num_ranges = 0; + } + setting->num_arefs = 0; + if( setting->caldacs ); + { + free( setting->caldacs ); + setting->caldacs = NULL; + setting->num_caldacs = 0; + } +} + +static void free_calibrations( struct calibration_file_contents *file_contents ) +{ + int i; + + if( file_contents->calibrations == NULL ) return; + + for( i = 0; i < file_contents->num_calibrations; i++ ) + { + free_calibration_setting( &file_contents->calibrations[ i ] ); + } + file_contents->calibrations = NULL; +} + +static int add_calibration_setting( struct calibration_file_contents *file_contents ) +{ + struct calibration_setting *temp; + + temp = realloc( file_contents->calibrations, + ( file_contents->num_calibrations + 1 ) * sizeof( struct calibration_setting ) ); + if( temp == NULL ) return -1; + file_contents->calibrations = temp; + memset( &file_contents->calibrations[ file_contents->num_calibrations ], + 0, sizeof( struct calibration_setting ) ); + + file_contents->num_calibrations++; + return 0; +} + +static struct calibration_setting* current_setting( struct calibration_file_contents *file_contents ) +{ + int retval; + + while( cal_index >= file_contents->num_calibrations ) + { + retval = add_calibration_setting( file_contents ); + if( retval < 0 ) return NULL; + } + return &file_contents->calibrations[ cal_index ]; +} + +static int add_channel( struct calibration_file_contents *file_contents, int channel ) +{ + int *temp; + struct calibration_setting *setting; + + setting = current_setting( file_contents ); + if( setting == NULL ) return -1; + + temp = realloc( setting->channels, ( setting->num_channels + 1 ) * sizeof( int ) ); + if( temp == NULL ) return -1; + setting->channels = temp; + setting->channels[ setting->num_channels++ ] = channel; + return 0; +} + +static int add_range( struct calibration_file_contents *file_contents, int range ) +{ + int *temp; + struct calibration_setting *setting; + + setting = current_setting( file_contents ); + if( setting == NULL ) return -1; + + temp = realloc( setting->ranges, ( setting->num_ranges + 1 ) * sizeof( int ) ); + if( temp == NULL ) return -1; + setting->ranges = temp; + setting->ranges[ setting->num_ranges++ ] = range; + return 0; +} + +static int add_aref( struct calibration_file_contents *file_contents, int aref ) +{ + struct calibration_setting *setting; + + setting = current_setting( file_contents ); + if( setting == NULL ) return -1; + + if( setting->num_arefs >= sizeof( setting->arefs ) / + sizeof( setting->arefs[ 0 ] ) ) + return -1; + setting->arefs[ setting->num_arefs++ ] = aref; + return 0; +} + +static int add_caldac( struct calibration_file_contents *file_contents, + struct caldac_setting caldac ) +{ + struct caldac_setting *temp; + struct calibration_setting *setting; + + setting = current_setting( file_contents ); + if( setting == NULL ) return -1; + + temp = realloc( setting->caldacs, ( setting->num_caldacs + 1 ) * + sizeof( struct caldac_setting ) ); + if( temp == NULL ) return -1; + setting->caldacs = temp; + setting->caldacs[ setting->num_caldacs++ ] = caldac; + return 0; +} + +static void init_calib_parse( void ) +{ + memset( &file_contents, 0, sizeof( file_contents ) ); + cal_index = 0; +} + +extern void cleanup_calibration_parse( void ) +{ + if( file_contents.driver_name ) + { + free( file_contents.driver_name ); + file_contents.driver_name = NULL; + } + if( file_contents.board_name ) + { + free( file_contents.board_name ); + file_contents.board_name = NULL; + } + free_calibrations( &file_contents ); +} + +extern const struct calibration_file_contents* parse_calibration_file( FILE *file ) +{ + calib_yyrestart( file ); + init_calib_parse(); + if( calib_yyparse() ) return NULL; + return &file_contents; +} + +%} + +%union +{ + int ival; + char *sval; +} + +%token T_DRIVER_NAME T_BOARD_NAME T_CALIBRATIONS T_SUBDEVICE T_CHANNELS +%token T_RANGES T_AREFS T_CALDACS T_CHANNEL T_VALUE T_NUMBER T_STRING +%token T_ASSIGN + +%type T_NUMBER +%type T_STRING + +%% + + input: '{' hash '}' + | error + { + fprintf(stderr, "input error on line %i\n", @1.first_line ); + return -1; + } + ; + + hash: /* empty */ + | hash_element + | hash_element ',' hash + ; + + hash_element: T_DRIVER_NAME T_ASSIGN T_STRING + { + if( file_contents.driver_name != NULL ) YYABORT; + file_contents.driver_name = strdup( $3 ); + } + | T_BOARD_NAME T_ASSIGN T_STRING + { + if( file_contents.board_name != NULL ) YYABORT; + file_contents.board_name = strdup( $3 ); + } + | T_CALIBRATIONS T_ASSIGN '[' calibrations_array ']' + ; + + calibrations_array: /* empty */ + | '{' calibration_setting '}' + | '{' calibration_setting '}' ',' calibrations_array + ; + + calibration_setting: /* empty */ { cal_index++; } + | calibration_setting_element + | calibration_setting_element ',' calibration_setting + ; + + calibration_setting_element: T_SUBDEVICE T_ASSIGN T_NUMBER + { + struct calibration_setting *setting; + setting = current_setting( &file_contents ); + if( setting == NULL ) YYABORT; + setting->subdevice = $3; + } + | T_CHANNELS T_ASSIGN '[' channels_array ']' + | T_RANGES T_ASSIGN '[' ranges_array ']' + | T_AREFS T_ASSIGN '[' arefs_array ']' + | T_CALDACS T_ASSIGN '[' caldacs_array ']' + ; + + channels_array: /* empty */ + | channel + | channel ',' channels_array + ; + + channel: T_NUMBER { add_channel( &file_contents, $1 ); } + ; + + ranges_array: /* empty */ + | range + | range ',' ranges_array + ; + + range: T_NUMBER { add_range( &file_contents, $1 ); } + ; + + arefs_array: /* empty */ + | aref + | aref ',' arefs_array + ; + + aref: T_NUMBER { add_aref( &file_contents, $1 ); } + ; + + caldacs_array: /* empty */ + | '{' caldac '}' + | '{' caldac '}' ',' caldacs_array + ; + + caldac: /* empty */ { add_caldac( &file_contents, caldac ); } + | caldac_element + | caldac_element ',' caldac + ; + + caldac_element: T_SUBDEVICE T_ASSIGN T_NUMBER { caldac.subdevice = $3; } + | T_CHANNEL T_ASSIGN T_NUMBER { caldac.channel = $3; } + | T_VALUE T_ASSIGN T_NUMBER { caldac.value = $3; } + ; + +%% + +void calib_yyerror(char *s) +{ + fprintf(stderr, "%s\n", s); +} + + + diff --git a/lib/libinternal.h b/lib/libinternal.h index 139ba55..9c1bcb0 100644 --- a/lib/libinternal.h +++ b/lib/libinternal.h @@ -151,8 +151,44 @@ enum{ COMEDILIB_BADCHAN, }; -// used by range.c, was in comedilib.h but apparently deprecated so I put it here - fmhess +/* used by range.c, was in comedilib.h but apparently deprecated so I put it here - fmhess */ int comedi_get_rangetype(comedi_t *it,unsigned int subdevice,unsigned int chan); +/* structs and functions used for parsing calibration files */ +struct caldac_setting +{ + unsigned int subdevice; + unsigned int channel; + unsigned int value; +}; + +struct calibration_setting +{ + unsigned int subdevice; + unsigned int *channels; + unsigned int num_channels; + unsigned int *ranges; + unsigned int num_ranges; + unsigned int arefs[ 4 ]; + unsigned int num_arefs; + struct caldac_setting *caldacs; + unsigned int num_caldacs; +}; + +struct calibration_file_contents +{ + char *driver_name; + char *board_name; + struct calibration_setting *calibrations; + unsigned int num_calibrations; +}; + +int calib_yylex( void ); +void calib_yyerror( char *s ); +int calib_yyparse( void ); +void calib_yyrestart( FILE *calibration_file ); +const struct calibration_file_contents* parse_calibration_file( FILE *file ); +void cleanup_calibration_parse( void ); + #endif -- 2.26.2