--- /dev/null
+/*
+ calibration support for NI labpc and compatible boards
+
+ copyright (C) 2003 by Frank Mori Hess
+
+ */
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License as *
+ * published by *
+ * the Free Software Foundation; either version 2.1 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "calib.h"
+
+char ni_labpc_id[] = "$Id$";
+
+int ni_labpc_setup( calibration_setup_t *setup , const char *device_name );
+static int cal_ni_labpc( calibration_setup_t *setup );
+
+enum labpc_caldacs
+{
+ DAC0_GAIN = 1,
+ ADC_OFFSET_FINE = 2,
+ DAC1_GAIN = 5,
+ ADC_GAIN = 6,
+ ADC_OFFSET_COARSE_ALT = 7,
+ DAC1_OFFSET = 9,
+ ADC_POSTGAIN_OFFSET = 10,
+ DAC0_OFFSET_ALT = 11,
+ ADC_OFFSET_COARSE = 12,
+ DAC0_OFFSET = 13,
+};
+static inline unsigned int DAC_OFFSET( unsigned int channel )
+{
+ if( channel ) return DAC1_OFFSET;
+ else return DAC0_OFFSET;
+}
+static inline unsigned int DAC_GAIN( unsigned int channel )
+{
+ if( channel ) return DAC1_GAIN;
+ else return DAC0_GAIN;
+}
+
+int ni_labpc_setup( calibration_setup_t *setup , const char *device_name )
+{
+ if( setup->caldac_subdev < 0 )
+ {
+ fprintf( stderr, "no caldac subdevice found\n");
+ return -1;
+ }
+ setup->status = STATUS_DONE;
+ setup->do_cal = cal_ni_labpc;
+ setup_caldacs( setup, setup->caldac_subdev );
+
+ return 0;
+}
+
+
+/* load analog input caldacs from eeprom values (depend on range used) */
+static void labpc_grab_ai_calibration( calibration_setup_t *setup, unsigned int range )
+{
+ comedi_calibration_setting_t *current_cal;
+ /* points to (end of) analog input bipolar calibration values */
+ const int ai_bip_frame = read_eeprom( setup, 127 );
+ enum offset_indices
+ {
+ coarse_offset_index = 0,
+ fine_offset_index = -1,
+ };
+ /* points to (end of) analog input unipolar calibration values */
+ const int ai_unip_frame = read_eeprom( setup, 126 );
+ /* points to (end of) analog input bipolar calibration values */
+ const int bip_gain_frame = read_eeprom( setup, 123 );
+ /* points to (end of) analog input bipolar calibration values */
+ const int unip_gain_frame = read_eeprom( setup, 122 );
+ /* points to (end of) analog input bipolar calibration values */
+ const int bip_offset_frame = read_eeprom( setup, 121 );
+ /* points to (end of) analog input bipolar calibration values */
+ const int unip_offset_frame = read_eeprom( setup, 120 );
+ int ai_frame, gain_frame, offset_frame;
+ /* eeprom offsets by range */
+ int range_to_index[ 14 ] =
+ {
+ 0,
+ -2,
+ -3,
+ -4,
+ -5,
+ -6,
+ -7,
+ 0,
+ -2,
+ -3,
+ -4,
+ -5,
+ -6,
+ -7,
+ };
+ int value;
+
+ if( is_unipolar( setup->dev, setup->ad_subdev, 0, range ) )
+ {
+ ai_frame = ai_unip_frame;
+ gain_frame = unip_gain_frame;
+ offset_frame = unip_offset_frame;
+ }else
+ {
+ ai_frame = ai_bip_frame;
+ gain_frame = bip_gain_frame;
+ offset_frame = bip_offset_frame;
+ }
+ assert( ai_frame >=0 && gain_frame >= 0 && offset_frame >= 0 );
+
+ current_cal = sc_alloc_calibration_setting( setup );
+
+ /* load coarse offset */
+ value = read_eeprom( setup, ai_frame + coarse_offset_index );
+ assert( value >= 0 );
+ update_caldac( setup, ADC_OFFSET_COARSE, value );
+ sc_push_caldac( current_cal, setup->caldacs[ ADC_OFFSET_COARSE ] );
+ update_caldac( setup, ADC_OFFSET_COARSE_ALT, value );
+ sc_push_caldac( current_cal, setup->caldacs[ ADC_OFFSET_COARSE_ALT ] );
+
+ /* load fine offset */
+ value = read_eeprom( setup, ai_frame + fine_offset_index );
+ assert( value >= 0 );
+ update_caldac( setup, ADC_OFFSET_FINE, value );
+ sc_push_caldac( current_cal, setup->caldacs[ ADC_OFFSET_FINE ] );
+
+ /* load postgain offset */
+ value = read_eeprom( setup, offset_frame + range_to_index[ range ] );
+ assert( value >= 0 );
+ update_caldac( setup, ADC_POSTGAIN_OFFSET, value );
+ sc_push_caldac( current_cal, setup->caldacs[ ADC_POSTGAIN_OFFSET ] );
+
+ /* load gain */
+ value = read_eeprom( setup, gain_frame + range_to_index[ range ] );
+ assert( value >= 0 );
+ update_caldac( setup, ADC_GAIN, value );
+ sc_push_caldac( current_cal, setup->caldacs[ ADC_GAIN ] );
+
+ current_cal->subdevice = setup->ad_subdev;
+ sc_push_channel( current_cal, SC_ALL_CHANNELS );
+ sc_push_range( current_cal, range );
+ sc_push_aref( current_cal, SC_ALL_AREFS );
+}
+
+static int ao_offset_index( unsigned int channel )
+{
+ if( channel ) return -2;
+ else return 0;
+}
+
+static int ao_gain_index( unsigned int channel )
+{
+ if( channel ) return -3;
+ else return -1;
+}
+
+/* load analog output caldacs from eeprom values (depend on range used) */
+static void labpc_grab_ao_calibration( calibration_setup_t *setup,
+ unsigned int channel, unsigned int range)
+{
+ comedi_calibration_setting_t *current_cal;
+ /* points to (end of) analog output bipolar calibration values */
+ int ao_bip_frame = read_eeprom( setup, 125 );
+ /* points to (end of) analog output bipolar calibration values */
+ int ao_unip_frame = read_eeprom( setup, 124 );
+ int ao_frame;
+ int value;
+
+ current_cal = sc_alloc_calibration_setting( setup );
+
+ if( is_unipolar( setup->dev, setup->da_subdev, 0, range ) )
+ ao_frame = ao_unip_frame;
+ else
+ ao_frame = ao_bip_frame;
+ assert( ao_frame >= 0 );
+
+ /* load offset */
+ value = read_eeprom( setup, ao_frame + ao_offset_index( channel ) );
+ assert( value >= 0 );
+ update_caldac( setup, DAC_OFFSET( channel ), value );
+ sc_push_caldac( current_cal, setup->caldacs[ DAC_OFFSET( channel ) ] );
+ if( channel == 0 )
+ {
+ update_caldac( setup, DAC0_OFFSET_ALT, value );
+ sc_push_caldac( current_cal, setup->caldacs[ DAC0_OFFSET_ALT ] );
+ }
+
+ // load gain calibration
+ value = read_eeprom( setup, ao_frame + ao_gain_index( channel ) );
+ assert( value >= 0 );
+ update_caldac( setup, DAC_GAIN( channel ), value );
+ sc_push_caldac( current_cal, setup->caldacs[ DAC_GAIN( channel ) ] );
+
+ current_cal->subdevice = setup->da_subdev;
+ sc_push_channel( current_cal, channel );
+ sc_push_range( current_cal, range );
+ sc_push_aref( current_cal, SC_ALL_AREFS );
+}
+
+
+static int cal_ni_labpc( calibration_setup_t *setup )
+{
+ int range, channel, num_ai_ranges, num_ao_ranges;
+
+ if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
+ {
+ DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
+ "for this calibration to work properly\n" );
+ }
+
+ num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
+ assert( num_ai_ranges > 0 );
+ num_ao_ranges = comedi_get_n_ranges( setup->dev, setup->da_subdev, 0 );
+ assert( num_ao_ranges > 0 );
+
+ for( range = 0; range < num_ai_ranges; range++ )
+ labpc_grab_ai_calibration( setup, range );
+
+ if( setup->da_subdev >= 0 && setup->do_output )
+ {
+ for( channel = 0; channel < 2; channel++ )
+ {
+ for( range = 0; range < num_ao_ranges; range++ )
+ labpc_grab_ao_calibration( setup, channel, range );
+ }
+ }
+
+ return write_calibration_file( setup );
+}
+