mmap works for output waveforms now.
[comedilib.git] / lib / calib.c
index 7bb8fb4b2c667aeafd7580760ca4843bfebd23c3..87fc6340484653692c58ecd8f2791a234de0b348 100644 (file)
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <comedilib.h>
-#include <libinternal.h>
+#include "libinternal.h"
 
-static int extract_ph_string( 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 $%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 )
-       {
-               fprintf( stderr, "popen() failed in ph_extract_element()\n" );
-               return -1;
-       }
+static int set_calibration( comedi_t *dev, const comedi_calibration_t *parsed_file,
+       unsigned int cal_index );
 
-       if( fgets( result, result_size, perl_stdout ) == NULL )
+static int check_cal_file( comedi_t *dev, const comedi_calibration_t *parsed_file )
+{
+       if( strcmp( comedi_get_driver_name( dev ), parsed_file->driver_name ) )
        {
-               fprintf( stderr, "fgets() returned NULL in ph_extract_element()\n" );
+               COMEDILIB_DEBUG( 3, "driver name does not match '%s' from calibration file\n",
+                       parsed_file->driver_name );
                return -1;
        }
 
-       retval = pclose( perl_stdout );
-       if( retval )
+       if( strcmp( comedi_get_board_name( dev ), parsed_file->board_name ) )
        {
-               fprintf( stderr, "perl returned error %i\n in ph_extract_element()", retval );
+               COMEDILIB_DEBUG( 3, "board name does not match '%s' from calibration file\n",
+                       parsed_file->board_name );
                return -1;
        }
 
        return 0;
 }
 
-static int extract_ph_integer( const char *file_path, const char *hash_ref,
-       const char *element )
+static inline int valid_channel( const comedi_calibration_t *parsed_file,
+       unsigned int cal_index, unsigned int channel )
 {
-       char result[ 100 ];
-       int retval;
+       int num_channels, i;
 
-       retval = extract_ph_string( file_path, hash_ref, element, result, sizeof( result ) );
-       if( retval < 0 ) return retval;
+       num_channels = parsed_file->settings[ cal_index ].num_channels;
+       if( num_channels == 0 ) return 1;
+       for( i = 0; i < num_channels; i++ )
+       {
+               if( parsed_file->settings[ cal_index ].channels[ i ] == channel )
+                       return 1;
+       }
 
-       return strtol( result, NULL, 0 );
+       return 0;
 }
 
-static int check_cal_file( comedi_t *dev, const char *file_path )
+static inline int valid_range( const comedi_calibration_t *parsed_file,
+       unsigned int cal_index, unsigned int range )
 {
-       char result[ 100 ];
-       int retval;
+       int num_ranges, i;
 
-       retval = extract_ph_string( file_path, "cal", "$cal->{driver_name}",
-               result, sizeof( result ) );
-       if( retval < 0 ) return retval;
-
-       if( strcmp( comedi_get_driver_name( dev ), result ) )
+       num_ranges = parsed_file->settings[ cal_index ].num_ranges;
+       if( num_ranges == 0 ) return 1;
+       for( i = 0; i < num_ranges; i++ )
        {
-               fprintf( stderr, "driver name does not match calibration file\n" );
-               return -1;
+               if( parsed_file->settings[ cal_index ].ranges[ i ] == range )
+                       return 1;
        }
 
-       retval = extract_ph_string( file_path, "cal", "$cal->{board_name}",
-               result, sizeof( result ) );
-       if( retval < 0 ) return retval;
+       return 0;
+}
+
+static inline int valid_aref( const comedi_calibration_t *parsed_file,
+       unsigned int cal_index, unsigned int aref )
+{
+       int num_arefs, i;
 
-       if( strcmp( comedi_get_board_name( dev ), result ) )
+       num_arefs = parsed_file->settings[ cal_index ].num_arefs;
+       if( num_arefs == 0 ) return 1;
+       for( i = 0; i < num_arefs; i++ )
        {
-               fprintf( stderr, "board name does not match calibration file\n" );
-               return -1;
+               if( parsed_file->settings[ cal_index ].arefs[ i ] == aref )
+                       return 1;
        }
 
        return 0;
 }
 
-static inline int num_calibrations( const char *file_path )
+static int apply_calibration( comedi_t *dev, const comedi_calibration_t *parsed_file,
+       unsigned int subdev, unsigned int channel, unsigned int range, unsigned int aref )
 {
-       return extract_ph_integer( file_path, "cal", "scalar( @{$cal->{calibrations}} )" );
-}
+       int num_cals, i, retval;
+       int found_cal = 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 ];
+       num_cals = parsed_file->num_settings;
 
-       snprintf( element, sizeof( element ),
-               "$cal->{ calibrations }[ %i ]->{ %s }[ %i ]", cal_index, array_name, array_index );
-       return extract_ph_integer( file_path, "cal", element );
-}
+       for( i = 0; i < num_cals; i++ )
+       {
+               if( parsed_file->settings[ 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;
 
-static int extract_array_length( const char *file_path, unsigned int cal_index,
-       const char *array_name )
-{
-       char element[ 100 ];
+               retval = set_calibration( dev, parsed_file, i );
+               if( retval < 0 ) return retval;
+               found_cal = 1;
+       }
+       if( found_cal == 0 )
+       {
+               COMEDILIB_DEBUG( 3, "failed to find matching calibration\n" );
+               return -1;
+       }
 
-       snprintf( element, sizeof( element ),
-               "scalar( @{ $cal->{ calibrations }[ %i ]->{ %s } } )", cal_index, array_name );
-       return extract_ph_integer( file_path, "cal", element );
+       return 0;
 }
 
-static int extract_subdevice( const char *file_path, unsigned int cal_index )
+static int set_calibration( comedi_t *dev, const comedi_calibration_t *parsed_file,
+       unsigned int cal_index )
 {
-       char element[ 100 ];
-
-       snprintf( element, sizeof( element ),
-               "$cal->{ calibrations }[ %i ]->{ subdevice }", cal_index );
-       return extract_ph_integer( file_path, "cal", element );
-}
+       int i, retval, num_caldacs;
 
-static int valid_item( const char *file_path, unsigned int cal_index,
-       const char *item_type, unsigned int item )
-{
-       int num_items, i;
+       num_caldacs = parsed_file->settings[ cal_index ].num_caldacs;
+       COMEDILIB_DEBUG( 4, "num_caldacs %i\n", num_caldacs );
 
-       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++ )
+       for( i = 0; i < num_caldacs; i++ )
        {
-               if( extract_array_element( file_path, cal_index, item_type, i ) == item )
-                       return 1;
+               comedi_caldac_t caldac;
+
+               caldac = parsed_file->settings[ cal_index ].caldacs[ i ];
+               COMEDILIB_DEBUG( 4, "subdev %i, ch %i, val %i\n", caldac.subdevice,
+                       caldac.channel,caldac.value);
+               retval = comedi_data_write( dev, caldac.subdevice, caldac.channel,
+                       0, 0, caldac.value );
+               if( retval < 0 ) return retval;
        }
 
        return 0;
 }
 
-static inline int valid_range( const char *file_path, unsigned int cal_index,
-       unsigned int range )
+EXPORT_ALIAS_DEFAULT(_comedi_apply_parsed_calibration,comedi_apply_parsed_calibration,0.7.20);
+int _comedi_apply_parsed_calibration( comedi_t *dev, unsigned int subdev, unsigned int channel,
+       unsigned int range, unsigned int aref, const comedi_calibration_t *calibration )
 {
-       return valid_item( file_path, cal_index, "ranges", range );
-}
+       int retval;
 
-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 );
-}
+       retval = check_cal_file( dev, calibration );
+       if( retval < 0 ) return retval;
 
-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 );
+       retval = apply_calibration( dev, calibration, subdev, channel, range, aref );
+       return retval;
 }
 
-static int find_calibration( const char *file_path, unsigned int subdev,
-       unsigned int channel, unsigned int range, unsigned int aref )
+/* munge characters in board name that will cause problems with file paths */
+static void fixup_board_name( char *name )
 {
-       int num_cals, i;
-
-       num_cals = num_calibrations( file_path );
-       if( num_cals < 0 ) return num_cals;
-
-       for( i = 0; i < num_cals; i++ )
+       while( ( name = strchr( name, '/' ) ) )
        {
-               if( extract_subdevice( file_path, i ) != subdev ) continue;
-               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( name )
+               {
+                       *name = '-';
+                       name++;
+               }
        }
-       if( i == num_cals ) return -1;
-
-       return i;
 }
 
-static int set_calibration( comedi_t *dev, const char *file_path,
-       unsigned int cal_index )
+EXPORT_ALIAS_DEFAULT(_comedi_get_default_calibration_path,comedi_get_default_calibration_path,0.7.20);
+char* _comedi_get_default_calibration_path( comedi_t *dev )
 {
-       int i, retval, num_caldacs;
-
-       num_caldacs = extract_array_length( file_path, cal_index, "caldacs" );
-       if( num_caldacs < 0 ) return num_caldacs;
+       struct stat file_stats;
+       char *file_path;
+       char *board_name, *temp;
+       char *driver_name;
 
-       for( i = 0; i < num_caldacs; i++ )
+       if( fstat( comedi_fileno( dev ), &file_stats ) < 0 )
        {
-               int subdev, channel, value;
-               char *element;
-
-               asprintf( &element, "$cal->{calibrations}[ %i ]->{caldacs}[ %i ]->{subdevice}",
-                       cal_index, i );
-               subdev = extract_ph_integer( file_path, "cal", element );
-               free( element );
-               if( subdev < 0 )
-               {
-                       fprintf( stderr, "failed to extract subdev\n" );
-                       return subdev;
-               }
-
-               asprintf( &element, "$cal->{calibrations}[ %i ]->{caldacs}[ %i ]->{channel}",
-                       cal_index, i );
-               channel = extract_ph_integer( file_path, "cal", element );
-               free( element );
-               if( channel < 0 )
-               {
-                       fprintf( stderr, "failed to extract channel\n" );
-                       return channel;
-               }
-
-               asprintf( &element, "$cal->{calibrations}[ %i ]->{caldacs}[ %i ]->{value}",
-                       cal_index, i );
-               value = extract_ph_integer( file_path, "cal", element );
-               free( element );
-               if( value < 0 )
-               {
-                       fprintf( stderr, "failed to extract value\n" );
-                       return value;
-               }
+               COMEDILIB_DEBUG( 3, "failed to get file stats of comedi device file\n" );
+               return NULL;
+       }
 
-               retval = comedi_data_write( dev, subdev, channel, 0, 0, value );
-               if( retval < 0 ) return retval;
+       driver_name = comedi_get_driver_name( dev );
+       if( driver_name == NULL )
+       {
+               return NULL;
        }
+       temp = comedi_get_board_name( dev );
+       if( temp == NULL )
+       {
+               return NULL;
+       }
+       board_name = strdup( temp );
 
-       return 0;
+       fixup_board_name( board_name );
+       asprintf( &file_path, LOCALSTATEDIR "/lib/comedi/calibrations/%s_%s_comedi%li",
+               driver_name, board_name, ( unsigned long ) minor( file_stats.st_rdev ) );
+
+       free( board_name );
+       return file_path;
 }
 
-EXPORT_SYMBOL(comedi_set_calibration,0.7.20);
-int comedi_set_calibration( comedi_t *dev, unsigned int subdev, unsigned int channel,
+EXPORT_ALIAS_DEFAULT(_comedi_apply_calibration,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 )
 {
-       struct stat file_stats;
        char file_path[ 1024 ];
        int retval;
-       int cal_index;
+       comedi_calibration_t *parsed_file;
 
        if( cal_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;
-               }
+               char *temp;
 
-               snprintf( file_path, sizeof( file_path ), "/etc/comedi/calibrations/%s_0x%lx",
-                       comedi_get_board_name( dev ),
-                       ( unsigned long ) file_stats.st_ino );
+               temp = comedi_get_default_calibration_path( dev );
+               if( temp == NULL ) return -1;
+               strncpy( file_path, temp, sizeof( file_path ) );
+               free( temp );
        }
 
-       retval = check_cal_file( dev, file_path );
-       if( retval < 0 ) return retval;
+       parsed_file = comedi_parse_calibration_file( file_path );
+       if( parsed_file == NULL )
+       {
+               COMEDILIB_DEBUG( 3, "failed to parse calibration file\n" );
+               return -1;
+       }
 
-       cal_index = find_calibration( file_path, subdev, channel, range, aref );
-       if( cal_index < 0 ) return cal_index;
-       
-       retval = set_calibration( dev, file_path, cal_index );
-       if( retval < 0 ) return retval;
+       retval = comedi_apply_parsed_calibration( dev, subdev, channel, range, aref, parsed_file );
 
-       return 0;
+       comedi_cleanup_calibration( parsed_file );
+
+       return retval;
 }