#define _GNU_SOURCE
#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
#include <comedilib.h>
#include <libinternal.h>
-static int ph_extract_element( const char *file_path, const char *element,
- char *result, unsigned int result_size )
+static int extract_ph_element( const char *file_path, const char *hash_ref,
+ const char *element, char *result, unsigned int result_size )
{
char perl_prog[ 1024 ];
FILE *perl_stdout;
int retval;
snprintf( perl_prog, sizeof( perl_prog ),
- "perl -e '"
- "use strict;"
- "use warnings;"
- "my $hash;"
- "my $cal;"
- "$hash = `cat %s`;"
- "eval \"\\$cal = $hash;\";"
- "print $cal->%s;"
- "'",
- file_path, element );
+ "perl -e '
+ use strict;
+ use warnings;
+ my $hash;
+ my $%s;
+ $hash = `cat %s`;
+ eval \"\\$%s = $hash;\";
+ print %s;
+ '",
+ hash_ref, file_path, hash_ref, element );
perl_stdout = popen( perl_prog, "r");
if( perl_stdout == NULL )
return 0;
}
-//EXPORT_SYMBOL(comedi_set_calibration,0.7.20);
-int comedi_set_calibration( comedi_t *dev, const char *cal_file_path,
- unsigned int subdev, unsigned int channel, unsigned int range, unsigned int aref )
+static int check_cal_file( comedi_t *dev, const char *file_path )
+{
+ char result[ 100 ];
+ int retval;
+
+ retval = extract_ph_element( file_path, "cal", "cal->{driver_name}",
+ result, sizeof( result ) );
+ if( retval < 0 ) return retval;
+
+ if( strcmp( comedi_get_driver_name( dev ), result ) )
+ {
+ fprintf( stderr, "driver name does not match calibration file\n" );
+ return -1;
+ }
+
+ retval = extract_ph_element( file_path, "cal", "cal->{board_name}",
+ result, sizeof( result ) );
+ if( retval < 0 ) return retval;
+
+ if( strcmp( comedi_get_board_name( dev ), result ) )
+ {
+ fprintf( stderr, "board name does not match calibration file\n" );
+ return -1;
+ }
+
+ return 0;
+}
+
+static int num_calibrations( const char *file_path )
+{
+ int retval;
+ char result[ 100 ];
+
+ retval = extract_ph_element( file_path, "cal", "scalar( @{$cal->{calibrations}} )",
+ result, sizeof( result ) );
+ if( retval < 0 ) return retval;
+
+ return strtol( result, NULL, 0 );
+}
+
+static int extract_array_element( const char *file_path, unsigned int cal_index,
+ const char *array_name, unsigned int array_index )
+{
+ char element[ 100 ];
+ char result[ 100 ];
+ int retval;
+
+ snprintf( element, sizeof( element ),
+ "cal->{ calibrations }[ %i ]->{ %s }[ %i ]", cal_index, array_name, array_index );
+ retval = extract_ph_element( file_path, "cal", element, result, sizeof( result ) );
+ if( retval < 0 ) return retval;
+
+ return strtol( result, NULL, 0 );
+}
+
+static int extract_array_length( const char *file_path, unsigned int cal_index,
+ const char *array_name )
+{
+ char result[ 100 ];
+ char element[ 100 ];
+ int retval;
+
+ snprintf( element, sizeof( element ),
+ "scalar( @{ cal->{ calibrations }[ %i ]->{ %s } } )", cal_index, array_name );
+ retval = extract_ph_element( file_path, "cal", element, result, sizeof( result ) );
+ if( retval < 0 ) return 0;
+
+ return strtol( result, NULL, 0 );
+}
+
+static int valid_item( const char *file_path, unsigned int cal_index,
+ const char *item_type, unsigned int item )
+{
+ int num_items, i;
+
+ num_items = extract_array_length( file_path, cal_index, item_type );
+ if( num_items < 0 ) return 0;
+ if( num_items == 0 ) return 1;
+ for( i = 0; i < num_items; i++ )
+ {
+ if( extract_array_element( file_path, cal_index, item_type, i ) == item )
+ return 1;
+ }
+
+ return 0;
+}
+
+static inline int valid_range( const char *file_path, unsigned int cal_index,
+ unsigned int range )
+{
+ return valid_item( file_path, cal_index, "ranges", range );
+}
+
+static inline int valid_channel( const char *file_path, unsigned int cal_index,
+ unsigned int channel )
+{
+ return valid_item( file_path, cal_index, "channels", channel );
+}
+
+static inline int valid_aref( const char *file_path, unsigned int cal_index,
+ unsigned int aref )
+{
+ return valid_item( file_path, cal_index, "arefs", aref );
+}
+
+static int find_calibration( const char *file_path, unsigned int channel,
+ unsigned int range, unsigned int aref )
+{
+ int num_cals, i;
+
+ num_cals = num_calibrations( file_path );
+ if( num_cals < 0 ) return num_cals;
+
+ for( i = 0; i < num_cals; i++ )
+ {
+ if( valid_range( file_path, i, range ) == 0 ) continue;
+ if( valid_channel( file_path, i, channel ) == 0 ) continue;
+ if( valid_aref( file_path, i, aref ) == 0 ) continue;
+ break;
+ }
+ if( i == num_cals ) return -1;
+
+ return i;
+}
+
+EXPORT_SYMBOL(comedi_set_calibration,0.7.20);
+int comedi_set_calibration( comedi_t *dev, unsigned int subdev, unsigned int channel,
+ unsigned int range, unsigned int aref, const char *cal_file_path )
{
struct stat file_stats;
- FILE *cal_file;
+ char file_path[ 1024 ];
+ int retval;
+ int cal_index;
if( cal_file_path )
- cal_file = fopen( cal_file_path, "r" );
- else
{
- char *file_path;
-
+ strncpy( file_path, cal_file_path, sizeof( file_path ) );
+ }else
+ {
if( fstat( comedi_fileno( dev ), &file_stats ) < 0 )
{
fprintf( stderr, "failed to get file stats of comedi device file\n" );
return -1;
}
- asprintf( &file_path, "/etc/comedi/calibrations/%s_0x%lx",
+ snprintf( file_path, sizeof( file_path ), "/etc/comedi/calibrations/%s_0x%lx",
comedi_get_board_name( dev ),
( unsigned long ) file_stats.st_ino );
- cal_file = fopen( file_path, "r" );
- free( file_path );
}
- if( cal_file == NULL )
- {
- fprintf( stderr, "failed to open calibration file\n" );
- return -1;
- }
+ retval = check_cal_file( dev, file_path );
+ if( retval < 0 ) return retval;
+
+ cal_index = find_calibration( file_path, channel, range, aref );
return 0;
}