From f1d87926828d1c6deccf82c50f1cfb1841c3e954 Mon Sep 17 00:00:00 2001
From: Frank Mori Hess <fmhess@speakeasy.net>
Date: Sun, 4 May 2003 02:16:31 +0000
Subject: [PATCH] converted all remaining boards (except mc pci-das1602/16) to
 use generic calibration support

---
 comedi_calibrate/cal_common.c |  22 +-
 comedi_calibrate/calib.h      |   3 +
 comedi_calibrate/cb.c         | 446 ++++++----------------------------
 comedi_calibrate/cb64.c       | 206 ++++------------
 4 files changed, 146 insertions(+), 531 deletions(-)

diff --git a/comedi_calibrate/cal_common.c b/comedi_calibrate/cal_common.c
index 6545937..de93e57 100644
--- a/comedi_calibrate/cal_common.c
+++ b/comedi_calibrate/cal_common.c
@@ -64,8 +64,10 @@ void generic_prep_adc_caldacs( calibration_setup_t *setup,
 		reset_caldac( setup, layout->adc_gain( channel ) );
 		reset_caldac( setup, layout->adc_offset_fine( channel ) );
 		reset_caldac( setup, layout->adc_gain_fine( channel ) );
+		// don't reset postgain offset here
 	}else
 	{
+		// need to preserve postgain offset? XXX
 		retval = comedi_apply_calibration( setup->dev, setup->ad_subdev,
 			channel, range, AREF_GROUND, setup->cal_save_file_path);
 		if( retval < 0 )
@@ -75,6 +77,7 @@ void generic_prep_adc_caldacs( calibration_setup_t *setup,
 			reset_caldac( setup, layout->adc_gain( channel ) );
 			reset_caldac( setup, layout->adc_offset_fine( channel ) );
 			reset_caldac( setup, layout->adc_gain_fine( channel ) );
+			// don't reset postgain offset here
 		}
 	}
 }
@@ -90,6 +93,8 @@ void generic_prep_dac_caldacs( calibration_setup_t *setup,
 	{
 		reset_caldac( setup, layout->dac_offset( channel ) );
 		reset_caldac( setup, layout->dac_gain( channel ) );
+		reset_caldac( setup, layout->dac_offset_fine( channel ) );
+		reset_caldac( setup, layout->dac_gain_fine( channel ) );
 	}else
 	{
 		retval = comedi_apply_calibration( setup->dev, setup->da_subdev,
@@ -99,6 +104,8 @@ void generic_prep_dac_caldacs( calibration_setup_t *setup,
 			DPRINT( 0, "Failed to apply existing calibration, reseting dac caldacs.\n" );
 			reset_caldac( setup, layout->dac_offset( channel ) );
 			reset_caldac( setup, layout->dac_gain( channel ) );
+			reset_caldac( setup, layout->dac_offset_fine( channel ) );
+			reset_caldac( setup, layout->dac_gain_fine( channel ) );
 		}
 	}
 }
@@ -179,12 +186,15 @@ static void generic_do_dac_channel( calibration_setup_t *setup, const generic_la
 
 	generic_prep_adc_for_dac( setup, layout, saved_cals, saved_cals_length,
 		layout->dac_ground_observable( setup, channel, range ) );
-		
+
 	generic_do_relative( setup, current_cal, layout->dac_ground_observable( setup, channel, range ),
 		layout->dac_high_observable( setup, channel, range ), layout->dac_gain( channel ) );
-
 	generic_do_cal( setup, current_cal, layout->dac_ground_observable( setup, channel, range ),
 		layout->dac_offset( channel ) );
+	generic_do_relative( setup, current_cal, layout->dac_ground_observable( setup, channel, range ),
+		layout->dac_high_observable( setup, channel, range ), layout->dac_gain_fine( channel ) );
+	generic_do_cal( setup, current_cal, layout->dac_ground_observable( setup, channel, range ),
+		layout->dac_offset_fine( channel ) );
 
 	current_cal->subdevice = setup->da_subdev;
 	sc_push_channel( current_cal, channel );
@@ -192,20 +202,17 @@ static void generic_do_dac_channel( calibration_setup_t *setup, const generic_la
 	sc_push_aref( current_cal, SC_ALL_AREFS );
 }
 
-static void generic_do_adc_channel( calibration_setup_t *setup, const generic_layout_t *layout ,
+static void generic_do_adc_channel( calibration_setup_t *setup, const generic_layout_t *layout,
 	saved_calibration_t *current_cal, unsigned int channel, unsigned int range )
 {
 	generic_prep_adc_caldacs( setup, layout, channel, range );
 
 	generic_do_relative( setup, current_cal, layout->adc_high_observable( setup, channel, range ),
 		layout->adc_ground_observable( setup, channel, range ), layout->adc_gain( channel ) );
-
 	generic_do_cal( setup, current_cal, layout->adc_ground_observable( setup, channel, range ),
 		layout->adc_offset( channel ) );
-
 	generic_do_relative( setup, current_cal, layout->adc_high_observable( setup, channel, range ),
 		layout->adc_ground_observable( setup, channel, range ), layout->adc_gain_fine( channel ) );
-
 	generic_do_cal( setup, current_cal, layout->adc_ground_observable( setup, channel, range ),
 		layout->adc_offset_fine( channel ) );
 
@@ -344,7 +351,10 @@ void init_generic_layout( generic_layout_t *layout )
 	layout->adc_offset_fine = dummy_caldac;
 	layout->adc_gain_fine = dummy_caldac;
 	layout->dac_offset = dummy_caldac;
+	layout->adc_postgain_offset = dummy_caldac;
 	layout->dac_gain = dummy_caldac;
+	layout->dac_offset_fine = dummy_caldac;
+	layout->dac_gain_fine = dummy_caldac;
 	layout->adc_high_observable = dummy_observable;
 	layout->adc_ground_observable = dummy_observable;
 	layout->dac_high_observable = dummy_observable;
diff --git a/comedi_calibrate/calib.h b/comedi_calibrate/calib.h
index 3cf1253..07c793b 100644
--- a/comedi_calibrate/calib.h
+++ b/comedi_calibrate/calib.h
@@ -251,10 +251,13 @@ typedef struct
 {
 	int (*adc_offset)( unsigned int channel );
 	int (*adc_offset_fine)( unsigned int channel );
+	int (*adc_postgain_offset)( unsigned int channel );
 	int (*adc_gain)( unsigned int channel );
 	int (*adc_gain_fine)( unsigned int channel );
 	int (*dac_offset)( unsigned int channel );
+	int (*dac_offset_fine)( unsigned int channel );
 	int (*dac_gain)( unsigned int channel );
+	int (*dac_gain_fine)( unsigned int channel );
 	int (*adc_high_observable)( const calibration_setup_t *setup,
 		unsigned int channel, unsigned int range );
 	int (*adc_ground_observable)( const calibration_setup_t *setup,
diff --git a/comedi_calibrate/cb.c b/comedi_calibrate/cb.c
index 15dcb49..11f6296 100644
--- a/comedi_calibrate/cb.c
+++ b/comedi_calibrate/cb.c
@@ -44,20 +44,17 @@ struct board_struct{
 };
 
 static int setup_cb_pci_1xxx( calibration_setup_t *setup );
-static int setup_cb_pci_1001( calibration_setup_t *setup );
 static int setup_cb_pci_1602_16( calibration_setup_t *setup );
 
 static int cal_cb_pci_1xxx( calibration_setup_t *setup );
-static int cal_cb_pci_1001( calibration_setup_t *setup );
 static int cal_cb_pci_1602_16( calibration_setup_t *setup );
 
 static int init_observables_1xxx( calibration_setup_t *setup );
-static int init_observables_1001( calibration_setup_t *setup );
 static int init_observables_1602_16( calibration_setup_t *setup );
 
 static struct board_struct boards[]={
 	{ "pci-das1000",	STATUS_GUESS,	setup_cb_pci_1xxx },
-	{ "pci-das1001",	STATUS_GUESS,	setup_cb_pci_1001 },
+	{ "pci-das1001",	STATUS_GUESS,	setup_cb_pci_1xxx },
 	{ "pci-das1002",	STATUS_GUESS,	setup_cb_pci_1xxx },
 	{ "pci-das1200",	STATUS_DONE,	setup_cb_pci_1xxx },
 	{ "pci-das1200/jr",	STATUS_GUESS,	setup_cb_pci_1xxx },
@@ -68,15 +65,6 @@ static struct board_struct boards[]={
 
 static const int num_boards = ( sizeof(boards) / sizeof(boards[0]) );
 
-enum observables_1xxx {
-	OBS_0V_RANGE_10V_BIP_1XXX = 0,
-	OBS_7V_RANGE_10V_BIP_1XXX,
-	OBS_DAC0_GROUND_1XXX,
-	OBS_DAC0_HIGH_1XXX,
-	OBS_DAC1_GROUND_1XXX,
-	OBS_DAC1_HIGH_1XXX,
-};
-
 enum observables_1602_16 {
 	OBS_0V_RANGE_10V_BIP_1602_16 = 0,
 	OBS_7V_RANGE_10V_BIP_1602_16,
@@ -86,10 +74,12 @@ enum calibration_source_1xxx
 {
 	CS_1XXX_GROUND = 0,
 	CS_1XXX_7V = 1,
-	CS_1XXX_3500mV = 2,
-	CS_1XXX_1750mV = 3,
+	CS_1002_3500mV = 2,
+	CS_1002_1750mV = 3,
+	CS_1001_88600uV = 3,
 	CS_1XXX_875mV = 4,
 	CS_1XXX_8600uV = 5,
+	CS_1602_16_minus_10V = 5,
 	CS_1XXX_DAC0 = 6,
 	CS_1XXX_DAC1 = 7,
 };
@@ -101,40 +91,6 @@ static inline int CS_1XXX_DAC( unsigned int channel )
 		return CS_1XXX_DAC0;
 }
 
-enum cal_knobs_1xxx
-{
-	DAC0_GAIN_FINE_1XXX = 0,
-	DAC0_GAIN_COARSE_1XXX = 1,
-	DAC0_OFFSET_1XXX = 2,
-	DAC1_OFFSET_1XXX = 3,
-	DAC1_GAIN_FINE_1XXX = 4,
-	DAC1_GAIN_COARSE_1XXX = 5,
-	ADC_OFFSET_COARSE_1XXX = 6,
-	ADC_OFFSET_FINE_1XXX = 7,
-	ADC_GAIN_1XXX = 8,
-};
-static inline unsigned int DAC_OFFSET_1XXX( unsigned int channel )
-{
-	if( channel )
-		return DAC1_OFFSET_1XXX;
-	else
-		return DAC0_OFFSET_1XXX;
-}
-static inline unsigned int DAC_GAIN_FINE_1XXX( unsigned int channel )
-{
-	if( channel )
-		return DAC1_GAIN_FINE_1XXX;
-	else
-		return DAC0_GAIN_FINE_1XXX;
-}
-static inline unsigned int DAC_GAIN_COARSE_1XXX( unsigned int channel )
-{
-	if( channel )
-		return DAC1_GAIN_COARSE_1XXX;
-	else
-		return DAC0_GAIN_COARSE_1XXX;
-}
-
 int cb_setup( calibration_setup_t *setup, const char *device_name )
 {
 	unsigned int i;
@@ -165,18 +121,6 @@ static int setup_cb_pci_1xxx( calibration_setup_t *setup )
 	return 0;
 }
 
-static int setup_cb_pci_1001( calibration_setup_t *setup )
-{
-	static const int caldac_subdev = 4;
-	static const int calpot_subdev = 5;
-
-	init_observables_1001( setup );
-	setup_caldacs( setup, caldac_subdev );
-	setup_caldacs( setup, calpot_subdev );
-	setup->do_cal = cal_cb_pci_1001;
-	return 0;
-}
-
 static int setup_cb_pci_1602_16( calibration_setup_t *setup )
 {
 	static const int caldac_subdev = 4;
@@ -191,17 +135,19 @@ static int setup_cb_pci_1602_16( calibration_setup_t *setup )
 	return 0;
 }
 
-static unsigned int ai_low_observable_1xxx( unsigned int range )
+static int ai_ground_observable_1xxx( const calibration_setup_t *setup,
+	unsigned int channel, unsigned int range )
 {
 	return 2 * range;
 }
 
-static unsigned int ai_high_observable_1xxx( unsigned int range )
+static int ai_high_observable_1xxx( const calibration_setup_t *setup,
+	unsigned int channel, unsigned int range )
 {
-	return ai_low_observable_1xxx( range ) + 1;
+	return ai_ground_observable_1xxx( setup, channel, range ) + 1;
 }
 
-static unsigned int ao_low_observable_1xxx( calibration_setup_t *setup,
+static int ao_ground_observable_1xxx( const calibration_setup_t *setup,
 	unsigned int channel, unsigned int range )
 {
 	int num_ai_ranges, num_ao_ranges;
@@ -214,10 +160,10 @@ static unsigned int ao_low_observable_1xxx( calibration_setup_t *setup,
 	return 2 * num_ai_ranges + 2 * num_ao_ranges * channel + 2 * range;
 }
 
-static unsigned int ao_high_observable_1xxx( calibration_setup_t *setup,
+static int ao_high_observable_1xxx( const calibration_setup_t *setup,
 	unsigned int channel, unsigned int range )
 {
-	return ao_low_observable_1xxx( setup, channel, range ) + 1;
+	return ao_ground_observable_1xxx( setup, channel, range ) + 1;
 }
 
 static double ai_low_target_1xxx( calibration_setup_t *setup,
@@ -234,8 +180,9 @@ static int source_eeprom_addr_1xxx( calibration_setup_t *setup, unsigned int ran
 	enum source_eeprom_addr
 	{
 		EEPROM_7V_CHAN = 0x80,
-		EEPROM_3500mV_CHAN = 0x84,
-		EEPROM_1750mV_CHAN = 0x88,
+		EEPROM_3500mV_CHAN_1002 = 0x84,
+		EEPROM_1750mV_CHAN_1002 = 0x88,
+		EEPROM_88600uV_CHAN_1001 = 0x88,
 		EEPROM_875mV_CHAN = 0x8c,
 		EEPROM_8600uV_CHAN = 0x90,
 	};
@@ -247,11 +194,13 @@ static int source_eeprom_addr_1xxx( calibration_setup_t *setup, unsigned int ran
 	if( range->max > 7.0 )
 		return EEPROM_7V_CHAN;
 	else if( range->max > 3.5 )
-		return EEPROM_3500mV_CHAN;
+		return EEPROM_3500mV_CHAN_1002;
 	else if( range->max > 1.750 )
-		return EEPROM_1750mV_CHAN;
+		return EEPROM_1750mV_CHAN_1002;
 	else if( range->max > 0.875 )
 		return EEPROM_875mV_CHAN;
+	else if( range->max > .0886 )
+		return EEPROM_88600uV_CHAN_1001;
 	else if( range->max > 0.0086 )
 		return EEPROM_8600uV_CHAN;
 
@@ -268,11 +217,13 @@ static int ai_high_cal_source_1xxx( calibration_setup_t *setup, unsigned int ran
 	if( range->max > 7.0 )
 		return CS_1XXX_7V;
 	else if( range->max > 3.5 )
-		return CS_1XXX_3500mV;
+		return CS_1002_3500mV;
 	else if( range->max > 1.750 )
-		return CS_1XXX_1750mV;
+		return CS_1002_1750mV;
 	else if( range->max > 0.875 )
 		return CS_1XXX_875mV;
+	else if( range->max > .0886 )
+		return CS_1001_88600uV;
 	else if( range->max > 0.0086 )
 		return CS_1XXX_8600uV;
 
@@ -314,7 +265,7 @@ static int init_observables_1xxx( calibration_setup_t *setup )
 
 	for( range = 0; range < num_ai_ranges; range++ )
 	{
-		o = setup->observables + ai_low_observable_1xxx( range );
+		o = setup->observables + ai_ground_observable_1xxx( setup, 0, range );
 		o->reference_source = CS_1XXX_GROUND;
 		assert( o->name == NULL );
 		asprintf( &o->name, "calibration source %i, range %i, ground referenced",
@@ -325,7 +276,7 @@ static int init_observables_1xxx( calibration_setup_t *setup )
 		o->target = ai_low_target_1xxx( setup, range );
 		setup->n_observables++;
 
-		o = setup->observables + ai_high_observable_1xxx( range );;
+		o = setup->observables + ai_high_observable_1xxx( setup, 0, range );;
 		retval = ai_high_cal_source_1xxx( setup, range );
 		if( retval < 0 ) return -1;
 		o->reference_source = retval;
@@ -362,7 +313,7 @@ static int init_observables_1xxx( calibration_setup_t *setup )
 		{
 			for( channel = 0; channel < num_channels; channel++ )
 			{
-				o = setup->observables + ao_low_observable_1xxx( setup, channel, range );
+				o = setup->observables + ao_ground_observable_1xxx( setup, channel, range );
 				o->reference_source = CS_1XXX_DAC( channel );
 				assert( o->name == NULL );
 				asprintf( &o->name, "DAC ground calibration source, ch %i, range %i",
@@ -373,7 +324,7 @@ static int init_observables_1xxx( calibration_setup_t *setup )
 				o->observe_insn = tmpl;
 				o->observe_insn.chanspec = CR_PACK( 0, ai_for_ao_range, AREF_GROUND) |
 					CR_ALT_SOURCE | CR_ALT_FILTER;
-				set_target( setup, ao_low_observable_1xxx( setup, channel, range ), 0.0 );
+				set_target( setup, ao_ground_observable_1xxx( setup, channel, range ), 0.0 );
 				setup->n_observables++;
 
 				o = setup->observables + ao_high_observable_1xxx( setup, channel, range );
@@ -397,125 +348,6 @@ static int init_observables_1xxx( calibration_setup_t *setup )
 	return 0;
 }
 
-static int init_observables_1001( calibration_setup_t *setup )
-{
-	comedi_insn tmpl, po_tmpl;
-	observable *o;
-	int retval;
-	float target;
-	enum source_eeprom_addr
-	{
-		EEPROM_7V_CHAN = 0x80,
-		EEPROM_88600uV_CHAN = 0x88,
-		EEPROM_875mV_CHAN = 0x8c,
-		EEPROM_8600uV_CHAN = 0x90,
-	};
-	enum calibration_source
-	{
-		CAL_SRC_GROUND = 0,
-		CAL_SRC_7V = 1,
-		CAL_SRC_88600uV = 3,
-		CAL_SRC_875mV = 4,
-		CAL_SRC_8600uV = 5,
-		CAL_SRC_DAC0 = 6,
-		CAL_SRC_DAC1 = 7,
-	};
-	enum ai_ranges
-	{
-		AI_RNG_BIP_10V = 0
-	};
-	enum ao_ranges
-	{
-		AO_RNG_BIP_10V = 1,
-	};
-
-	setup->n_observables = 0;
-
-	memset( &tmpl, 0, sizeof(tmpl) );
-	tmpl.insn = INSN_READ;
-	tmpl.n = 1;
-	tmpl.subdev = setup->ad_subdev;
-
-	o = setup->observables + OBS_0V_RANGE_10V_BIP_1XXX;
-	o->name = "ground calibration source, 10V bipolar range, ground referenced";
-	o->reference_source = CAL_SRC_GROUND;
-	o->observe_insn = tmpl;
-	o->observe_insn.chanspec = CR_PACK( 0, AI_RNG_BIP_10V, AREF_GROUND) |
-		CR_ALT_SOURCE | CR_ALT_FILTER;
-	o->target = 0.0;
-	setup->n_observables++;
-
-	o = setup->observables + OBS_7V_RANGE_10V_BIP_1XXX;
-	o->name = "7V calibration source, 10V bipolar range, ground referenced";
-	o->reference_source = CAL_SRC_7V;
-	o->observe_insn = tmpl;
-	o->observe_insn.chanspec = CR_PACK( 0, AI_RNG_BIP_10V, AREF_GROUND) |
-		CR_ALT_SOURCE | CR_ALT_FILTER;
-	o->target = 7.0;
-	retval = cb_actual_source_voltage( setup->dev, setup->eeprom_subdev, EEPROM_7V_CHAN, &target );
-	if( retval == 0 )
-		o->target = target;
-	setup->n_observables++;
-
-	if( setup->da_subdev >= 0 )
-	{
-		memset( &po_tmpl, 0, sizeof(po_tmpl) );
-		po_tmpl.insn = INSN_WRITE;
-		po_tmpl.n = 1;
-		po_tmpl.subdev = setup->da_subdev;
-
-		o = setup->observables + OBS_DAC0_GROUND_1XXX;
-		o->name = "DAC0 ground calibration source, 10V bipolar input range";
-		o->reference_source = CAL_SRC_DAC0;
-		o->preobserve_insn = po_tmpl;
-		o->preobserve_insn.chanspec = CR_PACK( 0, AO_RNG_BIP_10V, AREF_GROUND );
-		o->preobserve_insn.data = o->preobserve_data;
-		o->observe_insn = tmpl;
-		o->observe_insn.chanspec = CR_PACK( 0, AI_RNG_BIP_10V, AREF_GROUND) |
-			CR_ALT_SOURCE | CR_ALT_FILTER;
-		set_target( setup, OBS_DAC0_GROUND_1XXX, 0.0 );
-		setup->n_observables++;
-
-		o = setup->observables + OBS_DAC0_HIGH_1XXX;
-		o->name = "DAC0 high calibration source, 10V bipolar input range";
-		o->reference_source = CAL_SRC_DAC0;
-		o->preobserve_insn = po_tmpl;
-		o->preobserve_insn.chanspec = CR_PACK( 0 , AO_RNG_BIP_10V, AREF_GROUND );
-		o->preobserve_insn.data = o->preobserve_data;
-		o->observe_insn = tmpl;
-		o->observe_insn.chanspec = CR_PACK( 0, AI_RNG_BIP_10V, AREF_GROUND) |
-			CR_ALT_SOURCE | CR_ALT_FILTER;
-		set_target( setup, OBS_DAC0_HIGH_1XXX, 8.0 );
-		setup->n_observables++;
-
-		o = setup->observables + OBS_DAC1_GROUND_1XXX;
-		o->name = "DAC1 ground calibration source, 10V bipolar input range";
-		o->reference_source = CAL_SRC_DAC1;
-		o->preobserve_insn = po_tmpl;
-		o->preobserve_insn.chanspec = CR_PACK( 1, AO_RNG_BIP_10V, AREF_GROUND );
-		o->preobserve_insn.data = o->preobserve_data;
-		o->observe_insn = tmpl;
-		o->observe_insn.chanspec = CR_PACK( 0, AI_RNG_BIP_10V, AREF_GROUND) |
-			CR_ALT_SOURCE | CR_ALT_FILTER;
-		set_target( setup, OBS_DAC1_GROUND_1XXX, 0.0 );
-		setup->n_observables++;
-
-		o = setup->observables + OBS_DAC1_HIGH_1XXX;
-		o->name = "DAC1 high calibration source, 10V bipolar input range";
-		o->reference_source = CAL_SRC_DAC1;
-		o->preobserve_insn = po_tmpl;
-		o->preobserve_insn.chanspec = CR_PACK( 1 , AO_RNG_BIP_10V, AREF_GROUND );
-		o->preobserve_insn.data = o->preobserve_data;
-		o->observe_insn = tmpl;
-		o->observe_insn.chanspec = CR_PACK( 0, AI_RNG_BIP_10V, AREF_GROUND) |
-			CR_ALT_SOURCE | CR_ALT_FILTER;
-		set_target( setup, OBS_DAC1_HIGH_1XXX, 8.0 );
-		setup->n_observables++;
-	}
-
-	return 0;
-}
-
 static int init_observables_1602_16( calibration_setup_t *setup )
 {
 	comedi_insn tmpl;//, po_tmpl;
@@ -578,186 +410,68 @@ static int init_observables_1602_16( calibration_setup_t *setup )
 	return 0;
 }
 
-static void prep_adc_caldacs_1xxx( calibration_setup_t *setup,
-	unsigned int range )
+enum cal_knobs_1xxx
 {
-	int retval;
-
-	if( setup->do_reset )
-	{
-		reset_caldac( setup, ADC_OFFSET_COARSE_1XXX );
-		reset_caldac( setup, ADC_OFFSET_FINE_1XXX );
-		reset_caldac( setup, ADC_GAIN_1XXX );
-	}else
-	{
-		retval = comedi_apply_calibration( setup->dev, setup->ad_subdev,
-			0, range, AREF_GROUND, setup->cal_save_file_path);
-		if( retval < 0 )
-		{
-			reset_caldac( setup, ADC_OFFSET_COARSE_1XXX );
-			reset_caldac( setup, ADC_OFFSET_FINE_1XXX );
-			reset_caldac( setup, ADC_GAIN_1XXX );
-		}
-	}
+	DAC0_GAIN_FINE_1XXX = 0,
+	DAC0_GAIN_COARSE_1XXX = 1,
+	DAC0_OFFSET_1XXX = 2,
+	DAC1_OFFSET_1XXX = 3,
+	DAC1_GAIN_FINE_1XXX = 4,
+	DAC1_GAIN_COARSE_1XXX = 5,
+	ADC_OFFSET_COARSE_1XXX = 6,
+	ADC_OFFSET_FINE_1XXX = 7,
+	ADC_GAIN_1XXX = 8,
+};
+static int adc_offset_coarse_1xxx( unsigned int channel )
+{
+	return ADC_OFFSET_COARSE_1XXX;
 }
-
-static void prep_dac_caldacs_1xxx( calibration_setup_t *setup,
-	unsigned int channel, unsigned int range )
+static int adc_offset_fine_1xxx( unsigned int channel )
 {
-	int retval;
-
-	if( setup->do_reset )
-	{
-		reset_caldac( setup, DAC_OFFSET_1XXX( channel ) );
-		reset_caldac( setup, DAC_GAIN_FINE_1XXX( channel ) );
-		reset_caldac( setup, DAC_GAIN_COARSE_1XXX( channel ) );
-	}else
-	{
-		retval = comedi_apply_calibration( setup->dev, setup->da_subdev,
-			channel, range, AREF_GROUND, setup->cal_save_file_path);
-		if( retval < 0 )
-		{
-			reset_caldac( setup, DAC_OFFSET_1XXX( channel ) );
-			reset_caldac( setup, DAC_GAIN_FINE_1XXX( channel ) );
-			reset_caldac( setup, DAC_GAIN_COARSE_1XXX( channel ) );
-		}
-	}
+	return ADC_OFFSET_FINE_1XXX;
 }
-
-static int prep_ai_for_ao_1xxx( calibration_setup_t *setup,
-	saved_calibration_t *saved_cals, unsigned int ao_range )
+static int adc_gain_1xxx( unsigned int channel )
 {
-	int retval, ai_range, i, num_caldacs;
-	caldac_t *dacs;
-
-	retval = ao_low_observable_1xxx( setup, 0, ao_range );
-	if( retval < 0 ) return -1;
-	ai_range = CR_RANGE( setup->observables[ retval ].observe_insn.chanspec );
-
-	dacs = saved_cals[ ai_range ].caldacs;
-	num_caldacs = saved_cals[ ai_range ].caldacs_length;
-	for( i = 0; i < num_caldacs; i++ )
-	{
-		retval = comedi_data_write( setup->dev, dacs[ i ].subdev, dacs[ i ].chan,
-			0, 0, dacs[ i ].current );
-		assert( retval >= 0 );
-	}
-	return 0;
+	return ADC_GAIN_1XXX;
+}
+static int dac_offset_1xxx( unsigned int channel )
+{
+	if( channel )
+		return DAC1_OFFSET_1XXX;
+	else
+		return DAC0_OFFSET_1XXX;
+}
+static int dac_gain_fine_1xxx( unsigned int channel )
+{
+	if( channel )
+		return DAC1_GAIN_FINE_1XXX;
+	else
+		return DAC0_GAIN_FINE_1XXX;
+}
+static int dac_gain_coarse_1xxx( unsigned int channel )
+{
+	if( channel )
+		return DAC1_GAIN_COARSE_1XXX;
+	else
+		return DAC0_GAIN_COARSE_1XXX;
 }
 
 static int cal_cb_pci_1xxx( calibration_setup_t *setup )
 {
-	saved_calibration_t *saved_cals, *current_cal;
-	int range, num_ai_ranges, num_ao_ranges, num_calibrations,
-		retval, channel, i;
+	generic_layout_t layout;
 
-	comedi_set_global_oor_behavior( COMEDI_OOR_NUMBER );
-
-	num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
-	if( num_ai_ranges < 1 ) return -1;
-
-	if( setup->da_subdev >= 0 )
-	{
-		num_ao_ranges = comedi_get_n_ranges( setup->dev, setup->da_subdev, 0 );
-		if( num_ai_ranges < 1 ) return -1;
-	}else
-		num_ao_ranges = 0;
-
-	num_calibrations = num_ai_ranges + 2 * num_ao_ranges;
-
-	saved_cals = malloc( num_calibrations * sizeof( saved_calibration_t ) );
-	if( saved_cals == NULL ) return -1;
-	memset( saved_cals, 0, num_calibrations * sizeof( saved_calibration_t ) );
-
-	current_cal = saved_cals;
-
-	for( range = 0; range < num_ai_ranges; range++ )
-	{
-		prep_adc_caldacs_1xxx( setup, range );
-
-		cal_binary( setup, ai_low_observable_1xxx( range ), ADC_OFFSET_COARSE_1XXX );
-		cal_binary( setup, ai_low_observable_1xxx( range ), ADC_OFFSET_FINE_1XXX );
-		cal_binary( setup, ai_high_observable_1xxx( range ), ADC_GAIN_1XXX );
-
-		current_cal->subdevice = setup->ad_subdev;
-		sc_push_caldac( current_cal, setup->caldacs[ ADC_OFFSET_COARSE_1XXX ] );
-		sc_push_caldac( current_cal, setup->caldacs[ ADC_OFFSET_FINE_1XXX ] );
-		sc_push_caldac( current_cal, setup->caldacs[ ADC_GAIN_1XXX ] );
-		sc_push_channel( current_cal, SC_ALL_CHANNELS );
-		sc_push_range( current_cal, range );
-		sc_push_aref( current_cal, SC_ALL_AREFS );
-
-		current_cal++;
-	}
-
-	if( setup->da_subdev >= 0 && setup->do_output)
-	{
-		for( range = 0; range < num_ao_ranges; range++ )
-		{
-			for( channel = 0; channel < 2; channel++ )
-			{
-				prep_ai_for_ao_1xxx( setup, saved_cals, range );
-
-				prep_dac_caldacs_1xxx( setup, channel, range );
-
-				cal_binary( setup, ao_low_observable_1xxx( setup, channel, range ),
-					DAC_OFFSET_1XXX( channel ) );
-				cal_binary( setup, ao_high_observable_1xxx( setup, channel, range ),
-					DAC_GAIN_COARSE_1XXX( channel ) );
-				cal_binary( setup, ao_high_observable_1xxx( setup, channel, range ),
-					DAC_GAIN_FINE_1XXX( channel ) );
-
-				current_cal->subdevice = setup->da_subdev;
-				sc_push_caldac( current_cal, setup->caldacs[ DAC_OFFSET_1XXX( channel ) ] );
-				sc_push_caldac( current_cal, setup->caldacs[ DAC_GAIN_COARSE_1XXX( channel ) ] );
-				sc_push_caldac( current_cal, setup->caldacs[ DAC_GAIN_FINE_1XXX( channel ) ] );
-				sc_push_channel( current_cal, channel );
-				sc_push_range( current_cal, range );
-				sc_push_aref( current_cal, SC_ALL_AREFS );
-
-				current_cal++;
-			}
-		}
-	}
-
-	retval = write_calibration_file( setup, saved_cals, num_calibrations );
-	for( i = 0; i < num_calibrations; i++ )
-		clear_saved_calibration( &saved_cals[ i ] );
-	free( saved_cals );
-	return retval;
-}
-
-static int cal_cb_pci_1001( calibration_setup_t *setup )
-{
-	enum cal_knobs_1xxx
-	{
-		DAC0_GAIN_FINE = 0,
-		DAC0_GAIN_COARSE,
-		DAC0_OFFSET,
-		DAC1_OFFSET,
-		DAC1_GAIN_FINE,
-		DAC1_GAIN_COARSE,
-		ADC_OFFSET_COARSE,
-		ADC_OFFSET_FINE,
-		ADC_GAIN,
-	};
-
-	cal_binary( setup, OBS_0V_RANGE_10V_BIP_1XXX, ADC_OFFSET_COARSE );
-	cal_binary( setup, OBS_0V_RANGE_10V_BIP_1XXX, ADC_OFFSET_FINE );
-	cal_binary( setup, OBS_7V_RANGE_10V_BIP_1XXX, ADC_GAIN );
-
-	if( setup->da_subdev >= 0 && setup->do_output )
-	{
-		cal_binary( setup, OBS_DAC0_GROUND_1XXX, DAC0_OFFSET );
-		cal_binary( setup, OBS_DAC0_HIGH_1XXX, DAC0_GAIN_COARSE );
-		cal_binary( setup, OBS_DAC0_HIGH_1XXX, DAC0_GAIN_FINE );
-
-		cal_binary( setup, OBS_DAC1_GROUND_1XXX, DAC1_OFFSET );
-		cal_binary( setup, OBS_DAC1_HIGH_1XXX, DAC1_GAIN_COARSE );
-		cal_binary( setup, OBS_DAC1_HIGH_1XXX, DAC1_GAIN_FINE );
-	}
-
-	return 0;
+	init_generic_layout( &layout );
+	layout.adc_gain = adc_gain_1xxx;
+	layout.adc_offset = adc_offset_coarse_1xxx;
+	layout.adc_offset_fine = adc_offset_fine_1xxx;
+	layout.dac_gain = dac_gain_coarse_1xxx;
+	layout.dac_gain_fine = dac_gain_fine_1xxx;
+	layout.dac_offset = dac_offset_1xxx;
+	layout.adc_high_observable = ai_high_observable_1xxx;
+	layout.adc_ground_observable = ai_ground_observable_1xxx;
+	layout.dac_high_observable = ao_high_observable_1xxx;
+	layout.dac_ground_observable = ao_ground_observable_1xxx;
+	return generic_cal_by_range( setup, &layout );
 }
 
 static int cal_cb_pci_1602_16( calibration_setup_t *setup )
diff --git a/comedi_calibrate/cb64.c b/comedi_calibrate/cb64.c
index b156e0d..8d06676 100644
--- a/comedi_calibrate/cb64.c
+++ b/comedi_calibrate/cb64.c
@@ -177,17 +177,19 @@ static int setup_cb_pci_4020( calibration_setup_t *setup )
 	return 0;
 }
 
-static int ai_ground_observable_index_64xx( unsigned int range )
+static int ai_ground_observable_index_64xx( const calibration_setup_t *setup,
+	unsigned int channel, unsigned int range )
 {
 	return 2 * range;
 }
 
-static int ai_high_observable_index_64xx( unsigned int range )
+static int ai_high_observable_index_64xx( const calibration_setup_t *setup,
+	unsigned int channel, unsigned int range )
 {
 	return 2 * range + 1;
 }
 
-static unsigned int ao_low_observable_index_64xx( const calibration_setup_t *setup,
+static int ao_ground_observable_index_64xx( const calibration_setup_t *setup,
 	unsigned int channel, unsigned int ao_range )
 {
 	int num_ai_ranges;
@@ -198,7 +200,7 @@ static unsigned int ao_low_observable_index_64xx( const calibration_setup_t *set
 	return 2 * num_ai_ranges + 2 * channel + 4 * ao_range;
 }
 
-static unsigned int ao_high_observable_index_64xx( const calibration_setup_t *setup,
+static int ao_high_observable_index_64xx( const calibration_setup_t *setup,
 	unsigned int channel, unsigned int ao_range )
 {
 	int num_ai_ranges;
@@ -318,7 +320,7 @@ static int init_observables_64xx( calibration_setup_t *setup )
 
 	for( range = 0; range < num_ai_ranges; range++ )
 	{
-		o = setup->observables + ai_ground_observable_index_64xx( range );
+		o = setup->observables + ai_ground_observable_index_64xx( setup, 0, range );
 		retval = ai_low_cal_source_64xx( setup, range );
 		if( retval < 0 ) return -1;
 		o->reference_source = retval;
@@ -330,7 +332,7 @@ static int init_observables_64xx( calibration_setup_t *setup )
 		o->target = 0.0;
 		setup->n_observables++;
 
-		o = setup->observables + ai_high_observable_index_64xx( range );
+		o = setup->observables + ai_high_observable_index_64xx( setup, 0, range );
 		retval = ai_high_cal_source_64xx( setup, range );
 		if( retval < 0 ) return -1;
 		o->reference_source = retval;
@@ -366,7 +368,7 @@ static int init_observables_64xx( calibration_setup_t *setup )
 
 			for( dac_chan = 0; dac_chan < 2; dac_chan++ )
 			{
-				o = setup->observables + ao_low_observable_index_64xx( setup,
+				o = setup->observables + ao_ground_observable_index_64xx( setup,
 					dac_chan, range );
 				o->reference_source = ao_cal_src_64xx( dac_chan );
 				assert( o->name == NULL );
@@ -376,7 +378,7 @@ static int init_observables_64xx( calibration_setup_t *setup )
 				o->preobserve_insn.data = o->preobserve_data;
 				o->observe_insn = tmpl;
 				o->observe_insn.chanspec = CR_PACK( 0, ai_range, AREF_GROUND) | CR_ALT_SOURCE | CR_ALT_FILTER;
-				set_target( setup, ao_low_observable_index_64xx( setup, dac_chan, range ), 0.0 );
+				set_target( setup, ao_ground_observable_index_64xx( setup, dac_chan, range ), 0.0 );
 				setup->n_observables++;
 
 				o = setup->observables + ao_high_observable_index_64xx( setup, dac_chan, range );
@@ -709,164 +711,50 @@ static int init_observables_4020( calibration_setup_t *setup )
 	return 0;
 }
 
-static void prep_adc_caldacs_64xx( calibration_setup_t *setup, unsigned int range )
+static int adc_offset_64xx( unsigned int channel )
 {
-	int retval;
-
-	if( setup->do_reset )
-	{
-		reset_caldac( setup, ADC_OFFSET_64XX );
-		reset_caldac( setup, ADC_GAIN_64XX );
-	}else
-	{
-		retval = comedi_apply_calibration( setup->dev, setup->ad_subdev,
-			0, range, AREF_GROUND, setup->cal_save_file_path);
-		if( retval < 0 )
-		{
-			reset_caldac( setup, ADC_OFFSET_64XX );
-			reset_caldac( setup, ADC_GAIN_64XX );
-		}
-	}
+	return ADC_OFFSET_64XX;
 }
-
-static void prep_dac_caldacs_64xx( calibration_setup_t *setup,
-	unsigned int channel, unsigned int range )
+static int adc_gain_64xx( unsigned int channel )
 {
-	int retval;
-
-	if( setup->do_reset )
-	{
-		if( channel == 0 )
-		{
-			reset_caldac( setup, DAC0_OFFSET_COARSE_64XX );
-			reset_caldac( setup, DAC0_GAIN_COARSE_64XX );
-			reset_caldac( setup, DAC0_OFFSET_FINE_64XX );
-			reset_caldac( setup, DAC0_GAIN_FINE_64XX );
-		}else
-		{
-			reset_caldac( setup, DAC1_OFFSET_COARSE_64XX );
-			reset_caldac( setup, DAC1_GAIN_COARSE_64XX );
-			reset_caldac( setup, DAC1_OFFSET_FINE_64XX );
-			reset_caldac( setup, DAC1_GAIN_FINE_64XX );
-		}
-	}else
-	{
-		retval = comedi_apply_calibration( setup->dev, setup->da_subdev,
-			channel, range, AREF_GROUND, setup->cal_save_file_path);
-		if( retval < 0 )
-		{
-			if( channel == 0 )
-			{
-				reset_caldac( setup, DAC0_OFFSET_COARSE_64XX );
-				reset_caldac( setup, DAC0_GAIN_COARSE_64XX );
-				reset_caldac( setup, DAC0_OFFSET_FINE_64XX );
-				reset_caldac( setup, DAC0_GAIN_FINE_64XX );
-			}else
-			{
-				reset_caldac( setup, DAC1_OFFSET_COARSE_64XX );
-				reset_caldac( setup, DAC1_GAIN_COARSE_64XX );
-				reset_caldac( setup, DAC1_OFFSET_FINE_64XX );
-				reset_caldac( setup, DAC1_GAIN_FINE_64XX );
-			}
-		}
-	}
+	return ADC_GAIN_64XX;
+}
+static int dac_gain_coarse_64xx( unsigned int channel )
+{
+	if( channel ) return DAC1_GAIN_COARSE_64XX;
+	else return DAC0_GAIN_COARSE_64XX;
+}
+static int dac_gain_fine_64xx( unsigned int channel )
+{
+	if( channel ) return DAC1_GAIN_FINE_64XX;
+	else return DAC0_GAIN_FINE_64XX;
+}
+static int dac_offset_coarse_64xx( unsigned int channel )
+{
+	if( channel ) return DAC1_OFFSET_COARSE_64XX;
+	else return DAC0_OFFSET_COARSE_64XX;
+}
+static int dac_offset_fine_64xx( unsigned int channel )
+{
+	if( channel ) return DAC1_OFFSET_FINE_64XX;
+	else return DAC0_OFFSET_FINE_64XX;
 }
-
 static int cal_cb_pci_64xx( calibration_setup_t *setup )
 {
-	saved_calibration_t *saved_cals, *current_cal;
-	int i, num_ai_ranges, num_ao_ranges, num_calibrations, retval;
-	int adc_offset_for_ao = -1, adc_gain_for_ao = -1;
-	int ai_range_for_ao;
+	generic_layout_t layout;
 
-	num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
-	if( num_ai_ranges < 1 ) return -1;
-	if( setup->da_subdev >= 0 )
-	{
-		num_ao_ranges = comedi_get_n_ranges( setup->dev, setup->da_subdev, 0 );
-		if( num_ai_ranges < 1 ) return -1;
-	}else
-		num_ao_ranges = 0;
-
-	ai_range_for_ao = get_bipolar_lowgain( setup->dev, setup->ad_subdev );
-	if( ai_range_for_ao < 0 ) return -1;
-
-	num_calibrations = num_ai_ranges + 2 * num_ao_ranges;
-
-	saved_cals = malloc( num_calibrations * sizeof( saved_calibration_t ) );
-	if( saved_cals == NULL ) return -1;
-	memset( saved_cals, 0, num_calibrations * sizeof( saved_calibration_t ) );
-
-	current_cal = saved_cals;
-	for( i = 0; i < num_ai_ranges ; i++ )
-	{
-		prep_adc_caldacs_64xx( setup, i );
-
-		cal_binary( setup, ai_ground_observable_index_64xx( i ), ADC_OFFSET_64XX );
-		cal_binary( setup, ai_high_observable_index_64xx( i ), ADC_GAIN_64XX );
-
-		current_cal->subdevice = setup->ad_subdev;
-		sc_push_caldac( current_cal, setup->caldacs[ ADC_OFFSET_64XX ] );
-		sc_push_caldac( current_cal, setup->caldacs[ ADC_GAIN_64XX ] );
-		sc_push_channel( current_cal, SC_ALL_CHANNELS );
-		sc_push_range( current_cal, i );
-		sc_push_aref( current_cal, SC_ALL_AREFS );
-
-		current_cal++;
-
-		if( i == ai_range_for_ao )
-		{
-			adc_offset_for_ao = setup->caldacs[ ADC_OFFSET_64XX ].current;
-			adc_gain_for_ao = setup->caldacs[ ADC_GAIN_64XX ].current;
-		}
-	}
-
-	update_caldac( setup, ADC_OFFSET_64XX, adc_offset_for_ao );
-	update_caldac( setup, ADC_GAIN_64XX, adc_gain_for_ao );
-	for( i = 0; i < num_ao_ranges && setup->do_output; i++ )
-	{
-		prep_dac_caldacs_64xx( setup, 0, i );
-
-		cal_binary( setup, ao_low_observable_index_64xx( setup, 0, i ), DAC0_OFFSET_COARSE_64XX );
-		cal_binary( setup, ao_high_observable_index_64xx( setup, 0, i ), DAC0_GAIN_COARSE_64XX );
-		cal_binary( setup, ao_low_observable_index_64xx( setup, 0, i ), DAC0_OFFSET_FINE_64XX );
-		cal_binary( setup, ao_high_observable_index_64xx( setup, 0, i ), DAC0_GAIN_FINE_64XX );
-
-		current_cal->subdevice = setup->da_subdev;
-		sc_push_caldac( current_cal, setup->caldacs[ DAC0_OFFSET_COARSE_64XX ] );
-		sc_push_caldac( current_cal, setup->caldacs[ DAC0_GAIN_COARSE_64XX ] );
-		sc_push_caldac( current_cal, setup->caldacs[ DAC0_OFFSET_FINE_64XX ] );
-		sc_push_caldac( current_cal, setup->caldacs[ DAC0_GAIN_FINE_64XX ] );
-		sc_push_channel( current_cal, 0 );
-		sc_push_range( current_cal, i );
-		sc_push_aref( current_cal, SC_ALL_AREFS );
-
-		current_cal++;
-
-		prep_dac_caldacs_64xx( setup, 1, i );
-
-		cal_binary( setup, ao_low_observable_index_64xx( setup, 1, i ), DAC1_OFFSET_COARSE_64XX );
-		cal_binary( setup, ao_high_observable_index_64xx( setup, 1, i ), DAC1_GAIN_COARSE_64XX );
-		cal_binary( setup, ao_low_observable_index_64xx( setup, 1, i ), DAC1_OFFSET_FINE_64XX );
-		cal_binary( setup, ao_high_observable_index_64xx( setup, 1, i ), DAC1_GAIN_FINE_64XX );
-
-		current_cal->subdevice = setup->da_subdev;
-		sc_push_caldac( current_cal, setup->caldacs[ DAC1_OFFSET_COARSE_64XX ] );
-		sc_push_caldac( current_cal, setup->caldacs[ DAC1_GAIN_COARSE_64XX ] );
-		sc_push_caldac( current_cal, setup->caldacs[ DAC1_OFFSET_FINE_64XX ] );
-		sc_push_caldac( current_cal, setup->caldacs[ DAC1_GAIN_FINE_64XX ] );
-		sc_push_channel( current_cal, 1 );
-		sc_push_range( current_cal, i );
-		sc_push_aref( current_cal, SC_ALL_AREFS );
-
-		current_cal++;
-	}
-
-	retval = write_calibration_file( setup, saved_cals, num_calibrations );
-	for( i = 0; i < num_calibrations; i++ )
-		clear_saved_calibration( &saved_cals[ i ] );
-	free( saved_cals );
-	return retval;
+	init_generic_layout( &layout );
+	layout.adc_gain = adc_gain_64xx;
+	layout.adc_offset = adc_offset_64xx;
+	layout.dac_gain = dac_gain_coarse_64xx;
+	layout.dac_gain_fine = dac_gain_fine_64xx;
+	layout.dac_offset = dac_offset_coarse_64xx;
+	layout.dac_offset_fine = dac_offset_fine_64xx;
+	layout.adc_high_observable = ai_high_observable_index_64xx;
+	layout.adc_ground_observable = ai_ground_observable_index_64xx;
+	layout.dac_high_observable = ao_high_observable_index_64xx;
+	layout.dac_ground_observable = ao_ground_observable_index_64xx;
+	return generic_cal_by_range( setup, &layout );
 }
 
 static int adc_gain_coarse_60xx( unsigned int channel )