doc/dio_funcref.txt: Some DocBook mark-up changes.
[comedilib.git] / lib / calib.c
index d5068880018c45ce3ce4a7c81cdae9e33f1ee134..ee823bc0f6acd1a39a08f881c108230c96b3c636 100644 (file)
 
 #define _GNU_SOURCE
 
+#include <assert.h>
+#include <math.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/stat.h>
 #include "libinternal.h"
 
 static int set_calibration( comedi_t *dev, const comedi_calibration_t *parsed_file,
@@ -154,6 +157,7 @@ int _comedi_apply_parsed_calibration( comedi_t *dev, unsigned int subdev, unsign
 {
        int retval;
 
+       if(!valid_dev(dev)) return -1;
        retval = check_cal_file( dev, calibration );
        if( retval < 0 ) return retval;
 
@@ -165,7 +169,13 @@ int _comedi_apply_parsed_calibration( comedi_t *dev, unsigned int subdev, unsign
 static void fixup_board_name( char *name )
 {
        while( ( name = strchr( name, '/' ) ) )
-               if( name ) *name = '-';
+       {
+               if( name )
+               {
+                       *name = '-';
+                       name++;
+               }
+       }
 }
 
 EXPORT_ALIAS_DEFAULT(_comedi_get_default_calibration_path,comedi_get_default_calibration_path,0.7.20);
@@ -173,9 +183,12 @@ char* _comedi_get_default_calibration_path( comedi_t *dev )
 {
        struct stat file_stats;
        char *file_path;
-       char *board_name, *temp;
-       char *driver_name;
+       const char *temp;
+       char *board_name;
+       const char *driver_name;
+       int err;
 
+       if(!valid_dev(dev)) return NULL;
        if( fstat( comedi_fileno( dev ), &file_stats ) < 0 )
        {
                COMEDILIB_DEBUG( 3, "failed to get file stats of comedi device file\n" );
@@ -195,10 +208,14 @@ char* _comedi_get_default_calibration_path( comedi_t *dev )
        board_name = strdup( temp );
 
        fixup_board_name( board_name );
-       asprintf( &file_path, "/etc/comedi/calibrations/%s_%s_comedi%li",
+       err = 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 );
+       if( err < 0 )
+       {
+               return NULL;
+       }
        return file_path;
 }
 
@@ -236,3 +253,101 @@ int _comedi_apply_calibration( comedi_t *dev, unsigned int subdev, unsigned int
 
        return retval;
 }
+
+EXPORT_ALIAS_DEFAULT(_comedi_get_hardcal_converter, comedi_get_hardcal_converter, 0.8.0);
+int _comedi_get_hardcal_converter(
+       comedi_t *dev, unsigned subdevice, unsigned channel, unsigned range,
+       enum comedi_conversion_direction direction,
+       comedi_polynomial_t* polynomial)
+{
+       comedi_range *range_ptr = comedi_get_range(dev, subdevice, channel, range);
+       lsampl_t maxdata;
+
+       if(range_ptr == NULL)
+       {
+               return -1;
+       }
+       maxdata = comedi_get_maxdata(dev, subdevice, channel);
+       if(maxdata == 0)
+       {
+               return -1;
+       }
+       polynomial->order = 1;
+       switch(direction)
+       {
+       case COMEDI_TO_PHYSICAL:
+               polynomial->expansion_origin = 0.;
+               polynomial->coefficients[0] = range_ptr->min;
+               polynomial->coefficients[1] = (range_ptr->max - range_ptr->min) / maxdata;
+               break;
+       case COMEDI_FROM_PHYSICAL:
+               polynomial->expansion_origin = range_ptr->min;
+               polynomial->coefficients[0] = 0.;
+               polynomial->coefficients[1] =  maxdata / (range_ptr->max - range_ptr->min);
+               break;
+       }
+       return 0;
+}
+
+EXPORT_ALIAS_DEFAULT(_comedi_get_softcal_converter, comedi_get_softcal_converter, 0.8.0);
+int _comedi_get_softcal_converter(
+       unsigned subdevice, unsigned channel, unsigned range,
+       enum comedi_conversion_direction direction,
+       const comedi_calibration_t *calibration, comedi_polynomial_t* polynomial)
+{
+       unsigned i;
+
+       for(i = 0; i < calibration->num_settings; ++i)
+       {
+               if(calibration->settings[i].subdevice != subdevice) continue;
+               if(valid_channel(calibration, i, channel) == 0) continue;
+               if(valid_range(calibration, i, range) == 0) continue;
+               switch(direction)
+               {
+               case COMEDI_TO_PHYSICAL:
+                       if(calibration->settings[i].soft_calibration.to_phys == NULL)
+                       {
+                               continue;
+                       }
+                       *polynomial = *calibration->settings[i].soft_calibration.to_phys;
+                       break;
+               case COMEDI_FROM_PHYSICAL:
+                       if(calibration->settings[i].soft_calibration.from_phys == NULL)
+                       {
+                               continue;
+                       }
+                       *polynomial = *calibration->settings[i].soft_calibration.from_phys;
+                       break;
+               }
+               return 0;
+       }
+       return -1;
+}
+
+static double apply_polynomial(const comedi_polynomial_t *polynomial, double input)
+{
+       double value = 0.;
+       double term = 1.;
+       unsigned i;
+       assert(polynomial->order < COMEDI_MAX_NUM_POLYNOMIAL_COEFFICIENTS);
+       for(i = 0; i <= polynomial->order; ++i)
+       {
+               value += polynomial->coefficients[i] * term;
+               term *= input - polynomial->expansion_origin;
+       }
+       return value;
+}
+
+EXPORT_ALIAS_DEFAULT(_comedi_to_physical, comedi_to_physical, 0.8.0);
+double _comedi_to_physical(lsampl_t data,
+       const comedi_polynomial_t *conversion_polynomial)
+{
+       return apply_polynomial(conversion_polynomial, data);
+}
+
+EXPORT_ALIAS_DEFAULT(_comedi_from_physical, comedi_from_physical, 0.8.0);
+lsampl_t _comedi_from_physical(double data,
+       const comedi_polynomial_t *conversion_polynomial)
+{
+       return nearbyint(apply_polynomial(conversion_polynomial, data));
+}