made sv order adjustable
[comedilib.git] / comedi_calibrate / ni.c
1 /*
2    A little auto-calibration utility, for boards
3    that support it.
4
5    copyright (C) 1999,2000,2001,2002 by David Schleef
6    copyright (C) 2003 by Frank Mori Hess
7
8  */
9
10 /***************************************************************************
11  *                                                                         *
12  *   This program is free software; you can redistribute it and/or modify  *
13  *   it under the terms of the GNU Lesser General Public License as        *
14  *   published by                                                          *
15  *   the Free Software Foundation; either version 2.1 of the License, or   *
16  *   (at your option) any later version.                                   *
17  *                                                                         *
18  ***************************************************************************/
19
20 #define _GNU_SOURCE
21
22 #include <stdio.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <getopt.h>
27 #include <ctype.h>
28 #include <math.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <assert.h>
32
33 #include "calib.h"
34
35
36 char ni_id[] = "$Id$";
37
38 struct board_struct{
39         char *name;
40         int status;
41         int (*cal)( calibration_setup_t *setup);
42         void (*setup_observables)( calibration_setup_t *setup );
43         int ref_eeprom_lsb;
44         int ref_eeprom_msb;
45 };
46
47 static int ni_setup_board( calibration_setup_t *setup , const char *device_name );
48 static void ni_setup_observables( calibration_setup_t *setup );
49 static void ni_setup_observables_611x( calibration_setup_t *setup );
50
51 static int cal_ni_at_mio_16e_2(calibration_setup_t *setup);
52 static int cal_ni_daqcard_ai_16xe_50(calibration_setup_t *setup);
53 static int cal_ni_at_mio_16e_1(calibration_setup_t *setup);
54 static int cal_ni_pci_mio_16e_1(calibration_setup_t *setup);
55 static int cal_ni_pci_6024e(calibration_setup_t *setup);
56 static int cal_ni_pci_6025e(calibration_setup_t *setup);
57 static int cal_ni_pci_6035e(calibration_setup_t *setup);
58 static int cal_ni_pci_6071e(calibration_setup_t *setup);
59 static int cal_ni_pxi_6071e(calibration_setup_t *setup);
60 static int cal_ni_at_mio_16e_10(calibration_setup_t *setup);
61 static int cal_ni_pci_mio_16xe_50(calibration_setup_t *setup);
62 static int cal_ni_pci_6023e(calibration_setup_t *setup);
63 static int cal_ni_at_mio_16xe_50(calibration_setup_t *setup);
64 static int cal_ni_pci_mio_16xe_10(calibration_setup_t *setup);
65 static int cal_ni_pci_6052e(calibration_setup_t *setup);
66 static int cal_ni_pci_6032e(calibration_setup_t *setup);
67 static int cal_ni_daqcard_ai_16e_4(calibration_setup_t *setup);
68 static int cal_ni_pci_611x(calibration_setup_t *setup);
69 static int cal_ni_pci_mio_16e_4(calibration_setup_t *setup);
70 static int cal_ni_daqcard_6062e(calibration_setup_t *setup);
71 static int cal_ni_daqcard_6024e(calibration_setup_t *setup);
72
73 static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc);
74
75 static struct board_struct boards[]={
76         { "at-mio-16e-2", STATUS_DONE, cal_ni_at_mio_16e_2, ni_setup_observables, 0x1a9, 0x1aa },
77         { "DAQCard-ai-16xe-50", STATUS_DONE, cal_ni_daqcard_ai_16xe_50, ni_setup_observables, 0x1be, 0x1bf },
78         { "at-mio-16xe-50", STATUS_SOME, cal_ni_at_mio_16xe_50, ni_setup_observables, 0x1b5, 0x1b6 },
79         { "at-mio-16e-1", STATUS_SOME, cal_ni_at_mio_16e_1, ni_setup_observables, 0x1a9, 0x1aa },
80         { "pci-mio-16e-1", STATUS_DONE, cal_ni_pci_mio_16e_1, ni_setup_observables, 0x1a9, 0x1aa },
81         { "pci-6025e", STATUS_SOME, cal_ni_pci_6025e, ni_setup_observables, 0x1af, 0x1b0 },
82         { "pci-6035e", STATUS_DONE, cal_ni_pci_6035e, ni_setup_observables, 0x1af, 0x1b0 },
83         { "pci-6071e", STATUS_SOME, cal_ni_pci_6071e, ni_setup_observables, 0x1a9, 0x1aa },
84         { "pxi-6071e", STATUS_GUESS, cal_ni_pxi_6071e, ni_setup_observables, -1, -1 },
85         { "at-mio-16e-10", STATUS_GUESS, cal_ni_at_mio_16e_10, ni_setup_observables, 0x1a7, 0x1a8 },
86         { "pci-mio-16xe-50", STATUS_SOME, cal_ni_pci_mio_16xe_50, ni_setup_observables, 0x1b5, 0x1b6 },
87         { "pci-6023e", STATUS_DONE, cal_ni_pci_6023e, ni_setup_observables, 0x1bb, 0x1bc },
88         { "pci-mio-16xe-10", STATUS_DONE,       cal_ni_pci_mio_16xe_10, ni_setup_observables, 0x1ae, 0x1af },
89         { "pci-6052e", STATUS_DONE, cal_ni_pci_6052e, ni_setup_observables, 0x19f, 0x1a0 },
90         { "pci-6024e", STATUS_SOME, cal_ni_pci_6024e, ni_setup_observables, 0x1af, 0x1b0 },
91         { "pci-mio-16e-4", STATUS_SOME, cal_ni_pci_mio_16e_4, ni_setup_observables, 0x1a9, 0x1aa },
92         { "pci-6032e", STATUS_DONE, cal_ni_pci_6032e, ni_setup_observables, 0x1ae, 0x1af },
93         { "DAQCard-ai-16e-4", STATUS_DONE, cal_ni_daqcard_ai_16e_4, ni_setup_observables, 0x1b5, 0x1b6 },
94         { "pci-6110", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
95         { "pci-6111", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
96         { "DAQCard-6062E", STATUS_DONE, cal_ni_daqcard_6062e, ni_setup_observables, 0x1a9, 0x1aa },
97         { "DAQCard-6024E", STATUS_SOME, cal_ni_daqcard_6024e, ni_setup_observables, -1, -1 },
98         { "at-mio-16de-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1a7, 0x1a8 },
99         { "at-mio-16xe-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1b7, 0x1b8 },
100         { "at-ai-16xe-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1b7, 0x1b8 },
101         { "pci-6031e", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1ae, 0x1af },
102         { "pci-6033e", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1ae, 0x1af },
103 #if 0
104         { "at-mio-64e-3",       cal_ni_16e_1 },
105 //      { "at-mio-16xe-50",     cal_ni_unknown },
106 //      { "pxi-6030e",          cal_ni_unknown },
107 //      { "pxi-6040e",          cal_ni_unknown },
108         { "pxi-6025e",          cal_ni_6023e }, // guess
109         { "pci-6034e",          cal_ni_6023e }, // guess
110 //      { "pci-6711",           cal_ni_unknown },
111 //      { "pci-6713",           cal_ni_unknown },
112 //      { "pxi-6070e",          cal_ni_unknown },
113 //      { "pxi-6052e",          cal_ni_unknown },
114 #endif
115 };
116 #define n_boards (sizeof(boards)/sizeof(boards[0]))
117
118 static const int ni_num_observables = 18;
119 enum observables{
120         ni_zero_offset_low = 0,
121         ni_zero_offset_high,
122         ni_reference_low,
123         ni_unip_zero_offset_low,
124         ni_unip_zero_offset_high,
125         ni_unip_reference_low,
126         ni_ao0_zero_offset,
127         ni_ao0_reference,
128         ni_ao0_linearity,
129         ni_ao1_zero_offset,
130         ni_ao1_reference,
131         ni_ao1_linearity,
132         ni_ao0_unip_zero_offset,
133         ni_ao0_unip_reference,
134         ni_ao0_unip_linearity,
135         ni_ao1_unip_zero_offset,
136         ni_ao1_unip_reference,
137         ni_ao1_unip_linearity,
138 };
139 static inline unsigned int ni_ao_zero_offset( unsigned int channel )
140 {
141         if( channel ) return ni_ao1_zero_offset;
142         else return ni_ao0_zero_offset;
143 }
144 static inline unsigned int ni_ao_reference( unsigned int channel )
145 {
146         if( channel ) return ni_ao1_reference;
147         else return ni_ao0_reference;
148 }
149 static inline unsigned int ni_ao_linearity( unsigned int channel )
150 {
151         if( channel ) return ni_ao1_linearity;
152         else return ni_ao0_linearity;
153 }
154 static inline unsigned int ni_ao_unip_zero_offset( unsigned int channel )
155 {
156         if( channel ) return ni_ao1_unip_zero_offset;
157         else return ni_ao0_unip_zero_offset;
158 }
159 static inline unsigned int ni_ao_unip_reference( unsigned int channel )
160 {
161         if( channel ) return ni_ao1_unip_reference;
162         else return ni_ao0_unip_reference;
163 }
164 static inline unsigned int ni_ao_unip_linearity( unsigned int channel )
165 {
166         if( channel ) return ni_ao1_unip_linearity;
167         else return ni_ao0_unip_linearity;
168 }
169
170 static const int num_ao_observables_611x = 4;
171 static int ni_ao_zero_offset_611x( const calibration_setup_t *setup,
172         unsigned int channel, unsigned int range ) {
173         assert( range == 0 );
174         return 2 * channel;
175 };
176 static int ni_ao_reference_611x( const calibration_setup_t *setup,
177         unsigned int channel, unsigned int range ) {
178         assert( range == 0 );
179         return 2 * channel + 1;
180 };
181 static int ni_zero_offset_611x( const calibration_setup_t *setup,
182         unsigned int channel, unsigned int range ) {
183         return num_ao_observables_611x + 8 * range + 2 * channel;
184 };
185 static int ni_reference_611x( const calibration_setup_t *setup,
186         unsigned int channel, unsigned int range ) {
187         return num_ao_observables_611x + 8 * range + 2 * channel + 1;
188 };
189
190 enum reference_sources {
191         REF_GND_GND = 0,
192         REF_AOGND_AIGND = 1,
193         REF_DAC0_GND = 2,
194         REF_DAC1_GND = 3,
195         REF_CALSRC_CALSRC = 4,
196         REF_CALSRC_GND = 5,
197         REF_DAC0_CALSRC = 6,
198         REF_DAC1_CALSRC = 7,
199 };
200 static inline unsigned int REF_DAC_GND( unsigned int channel )
201 {
202         if( channel ) return REF_DAC1_GND;
203         else return REF_DAC0_GND;
204 }
205 static inline unsigned int REF_DAC_CALSRC( unsigned int channel )
206 {
207         if( channel ) return REF_DAC1_CALSRC;
208         else return REF_DAC0_CALSRC;
209 }
210
211 static struct board_struct* ni_board( calibration_setup_t *setup )
212 {
213         return setup->private_data;
214 }
215
216 typedef struct
217 {
218         int adc_pregain_offset;
219         int adc_postgain_offset;
220         int adc_gain;
221         int adc_pregain_offset_fine;
222         int adc_postgain_offset_fine;
223         int adc_gain_fine;
224         int adc_unip_offset;
225         int dac_offset[ 2 ];
226         int dac_gain[ 2 ];
227         int dac_gain_fine[ 2 ];
228         int dac_linearity[ 2 ];
229 } ni_caldac_layout_t;
230
231 static int cal_ni_generic( calibration_setup_t *setup,
232         const ni_caldac_layout_t *layout );
233
234 static inline void init_ni_caldac_layout( ni_caldac_layout_t *layout )
235 {
236         int i;
237
238         layout->adc_pregain_offset = -1;
239         layout->adc_postgain_offset = -1;
240         layout->adc_gain = -1;
241         layout->adc_unip_offset = -1;
242         layout->adc_pregain_offset_fine = -1;
243         layout->adc_postgain_offset_fine = -1;
244         layout->adc_gain_fine = -1;
245         for( i = 0; i < 2; i++ )
246         {
247                 layout->dac_offset[ i ] = -1;
248                 layout->dac_gain[ i ] = -1;
249                 layout->dac_gain_fine[ i ] = -1;
250                 layout->dac_linearity[ i ] = -1;
251         }
252 }
253
254 int ni_setup( calibration_setup_t *setup , const char *device_name )
255 {
256         int retval;
257
258         retval = ni_setup_board( setup, device_name );
259         if( retval < 0 ) return retval;
260         setup_caldacs( setup, setup->caldac_subdev );
261
262         return 0;
263 }
264
265 static int ni_setup_board( calibration_setup_t *setup, const char *device_name )
266 {
267         int i;
268
269         for(i = 0; i < n_boards; i++ ){
270                 if(!strcmp( device_name, boards[i].name )){
271                         setup->status = boards[i].status;
272                         setup->do_cal = boards[i].cal;
273                         setup->private_data = &boards[ i ];
274                         boards[i].setup_observables( setup );
275                         break;
276                 }
277         }
278         if( i == n_boards ) return -1;
279         return 0;
280 }
281
282 static void ni_setup_ao_observables( calibration_setup_t *setup )
283 {
284         observable *o;
285         comedi_insn tmpl, po_tmpl;
286         unsigned int channel;
287         int ai_bipolar_lowgain;
288         int ao_bipolar_lowgain;
289         int ao_unipolar_lowgain;
290
291         ai_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
292         ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev);
293         ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev);
294
295         memset(&tmpl,0,sizeof(tmpl));
296         tmpl.insn = INSN_READ;
297         tmpl.n = 1;
298         tmpl.subdev = setup->ad_subdev;
299
300         memset(&po_tmpl, 0, sizeof(po_tmpl));
301         po_tmpl.insn = INSN_WRITE;
302         po_tmpl.n = 1;
303         po_tmpl.subdev = setup->da_subdev;
304
305         for( channel = 0; channel < 2; channel++ )
306         {
307                 /* ao zero offset */
308                 o = setup->observables + ni_ao_zero_offset( channel );
309                 assert( o->name == NULL );
310                 asprintf( &o->name, "ao %i, zero offset, low gain", channel );
311                 o->preobserve_insn = po_tmpl;
312                 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
313                 o->preobserve_insn.data = o->preobserve_data;
314                 o->observe_insn = tmpl;
315                 o->observe_insn.chanspec =
316                         CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
317                         | CR_ALT_SOURCE | CR_ALT_FILTER;
318                 o->reference_source = REF_DAC_GND( channel );
319                 set_target( setup, ni_ao_zero_offset( channel ),0.0);
320
321                 /* ao gain */
322                 o = setup->observables + ni_ao_reference( channel );
323                 assert( o->name == NULL );
324                 asprintf( &o->name, "ao %i, reference voltage, low gain", channel );
325                 o->preobserve_insn = po_tmpl;
326                 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
327                 o->preobserve_insn.data = o->preobserve_data;
328                 o->observe_insn = tmpl;
329                 o->observe_insn.chanspec =
330                         CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
331                         | CR_ALT_SOURCE | CR_ALT_FILTER;
332                 o->reference_source = REF_DAC_GND( channel );
333                 set_target( setup, ni_ao_reference( channel ),5.0);
334
335                 /* ao linearity, negative */
336                 o = setup->observables + ni_ao_linearity( channel );
337                 assert( o->name == NULL );
338                 asprintf( &o->name, "ao %i, linearity (negative), low gain", channel );
339                 o->preobserve_insn = po_tmpl;
340                 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
341                 o->preobserve_insn.data = o->preobserve_data;
342                 o->observe_insn = tmpl;
343                 o->observe_insn.chanspec =
344                         CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
345                         | CR_ALT_SOURCE | CR_ALT_FILTER;
346                 o->reference_source = REF_DAC_GND( channel );
347                 set_target( setup, ni_ao_linearity( channel ),-5.0);
348
349                 if( ao_unipolar_lowgain >= 0 )
350                 {
351                         /* ao unipolar zero offset */
352                         o = setup->observables + ni_ao_unip_zero_offset( channel );
353                         assert( o->name == NULL );
354                         asprintf( &o->name, "ao %i, unipolar zero offset, low gain", channel );
355                         o->preobserve_insn = po_tmpl;
356                         o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
357                         o->preobserve_insn.data = o->preobserve_data;
358                         o->observe_insn = tmpl;
359                         o->observe_insn.chanspec =
360                                 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
361                                 | CR_ALT_SOURCE | CR_ALT_FILTER;
362                         o->reference_source = REF_DAC_GND( channel );
363                         set_target( setup, ni_ao_zero_offset( channel ),0.0);
364
365                         /* ao unipolar gain */
366                         o = setup->observables + ni_ao_unip_reference( channel );
367                         assert( o->name == NULL );
368                         asprintf( &o->name, "ao %i, unipolar high, low gain", channel );
369                         o->preobserve_insn = po_tmpl;
370                         o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
371                         o->preobserve_insn.data = o->preobserve_data;
372                         o->observe_insn = tmpl;
373                         o->observe_insn.chanspec =
374                                 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
375                                 | CR_ALT_SOURCE | CR_ALT_FILTER;
376                         o->reference_source = REF_DAC_GND( channel );
377                         set_target( setup, ni_ao_reference( channel ),8.0);
378
379                         /* ao unipolar linearity, negative */
380                         o = setup->observables + ni_ao_unip_linearity( channel );
381                         assert( o->name == NULL );
382                         asprintf( &o->name, "ao %i, unipolar linearity (mid), low gain", channel );
383                         o->preobserve_insn = po_tmpl;
384                         o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
385                         o->preobserve_insn.data = o->preobserve_data;
386                         o->observe_insn = tmpl;
387                         o->observe_insn.chanspec =
388                                 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
389                                 | CR_ALT_SOURCE | CR_ALT_FILTER;
390                         o->reference_source = REF_DAC_GND( channel );
391                         set_target( setup, ni_ao_linearity( channel ),4.0);
392                 }
393         }
394 }
395
396 static void ni_setup_observables( calibration_setup_t *setup )
397 {
398         comedi_insn tmpl;
399         int bipolar_lowgain;
400         int bipolar_highgain;
401         int unipolar_lowgain;
402         int unipolar_highgain;
403         double voltage_reference;
404         observable *o;
405
406         bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
407         bipolar_highgain = get_bipolar_highgain( setup->dev, setup->ad_subdev);
408         unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->ad_subdev);
409         unipolar_highgain = get_unipolar_highgain( setup->dev, setup->ad_subdev);
410
411         if( ni_board( setup )->ref_eeprom_lsb >= 0 &&
412                 ni_board( setup )->ref_eeprom_msb >= 0 )
413         {
414                 voltage_reference = ni_get_reference( setup,
415                         ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
416         }else
417         {
418                 DPRINT( 0, "WARNING: unknown eeprom address for reference voltage\n"
419                         "correction.  This might be fixable if you send us an eeprom dump\n"
420                         "(see the demo/eeprom_dump program).\n");
421                 voltage_reference = 5.0;
422         }
423
424         memset(&tmpl,0,sizeof(tmpl));
425         tmpl.insn = INSN_READ;
426         tmpl.n = 1;
427         tmpl.subdev = setup->ad_subdev;
428
429         setup->n_observables = ni_num_observables;
430
431         /* 0 offset, low gain */
432         o = setup->observables + ni_zero_offset_low;
433         o->name = "ai, bipolar zero offset, low gain";
434         o->observe_insn = tmpl;
435         o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_lowgain,AREF_OTHER)
436                 | CR_ALT_SOURCE | CR_ALT_FILTER;
437         o->reference_source = REF_GND_GND;
438         o->target = 0;
439
440         /* 0 offset, high gain */
441         o = setup->observables + ni_zero_offset_high;
442         o->name = "ai, bipolar zero offset, high gain";
443         o->observe_insn = tmpl;
444         o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_highgain,AREF_OTHER)
445                 | CR_ALT_SOURCE | CR_ALT_FILTER;
446         o->reference_source = REF_GND_GND;
447         o->target = 0;
448
449         /* voltage reference */
450         o = setup->observables + ni_reference_low;
451         o->name = "ai, bipolar voltage reference, low gain";
452         o->observe_insn = tmpl;
453         o->observe_insn.chanspec = CR_PACK(REF_CALSRC_GND,bipolar_lowgain,AREF_OTHER)
454                 | CR_ALT_SOURCE | CR_ALT_FILTER;
455         o->reference_source = REF_CALSRC_GND;
456         o->target = voltage_reference;
457
458         if(unipolar_lowgain>=0){
459                 o = setup->observables + ni_unip_zero_offset_low;
460                 o->name = "ai, unipolar zero offset, low gain";
461                 o->observe_insn = tmpl;
462                 o->observe_insn.chanspec =
463                         CR_PACK(REF_GND_GND,unipolar_lowgain,AREF_OTHER)
464                         | CR_ALT_SOURCE | CR_ALT_FILTER;
465                 o->reference_source = REF_GND_GND;
466                 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_lowgain );
467
468                 o = setup->observables + ni_unip_reference_low;
469                 o->name = "ai, unipolar voltage reference, low gain";
470                 o->observe_insn = tmpl;
471                 o->observe_insn.chanspec =
472                         CR_PACK(REF_CALSRC_GND,unipolar_lowgain,AREF_OTHER)
473                         | CR_ALT_SOURCE | CR_ALT_FILTER;
474                 o->reference_source = REF_CALSRC_GND;
475                 o->target = voltage_reference;
476         }
477
478         if(unipolar_highgain >= 0)
479         {
480                 o = setup->observables + ni_unip_zero_offset_high;
481                 o->name = "ai, unipolar zero offset, high gain";
482                 o->observe_insn = tmpl;
483                 o->observe_insn.chanspec =
484                         CR_PACK(REF_GND_GND,unipolar_highgain,AREF_OTHER)
485                         | CR_ALT_SOURCE | CR_ALT_FILTER;
486                 o->reference_source = REF_GND_GND;
487                 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_highgain );
488         }
489
490         if(setup->da_subdev >= 0)
491                 ni_setup_ao_observables( setup );
492 }
493
494 /* for +-50V and +-20V ranges, the reference source goes 0V
495  * to 50V instead of 0V to 5V */
496 static unsigned int cal_gain_register_bits_611x( double reference, double *voltage )
497 {
498         int bits;
499
500         bits = 200.0 * ( *voltage / reference );
501         if( bits > 200 ) bits = 200;
502         if( bits < 0 ) bits = 0;
503
504         *voltage = reference * ( bits / 200.0 );
505         return bits;
506 }
507
508 static unsigned int ref_source_611x( unsigned int ref_source, unsigned int cal_gain_bits )
509 {
510         return ( ref_source & 0xf ) | ( ( cal_gain_bits << 4 ) & 0xff0 );
511 }
512
513 static void reference_target_611x( calibration_setup_t *setup,
514         observable *o, double master_reference, unsigned int range )
515 {
516         int cal_gain_reg_bits;
517         double reference;
518         double target;
519         comedi_range *range_ptr;
520
521         range_ptr = comedi_get_range( setup->dev, setup->ad_subdev, 0, range );
522         assert( range_ptr != NULL );
523         if( range_ptr->max > 19.0 ) reference = 10 * master_reference;
524         else reference = master_reference;
525         target = range_ptr->max * 0.8;
526
527         cal_gain_reg_bits = cal_gain_register_bits_611x( reference, &target );
528
529         o->reference_source = ref_source_611x( REF_CALSRC_GND, cal_gain_reg_bits );
530         o->target = target;
531 }
532
533 static void ni_setup_observables_611x( calibration_setup_t *setup )
534 {
535         comedi_insn tmpl;
536         comedi_insn po_tmpl;
537         int range, channel;
538         double master_reference;
539         observable *o;
540         int num_ai_channels, num_ai_ranges;
541         static const int num_ao_channels = 2;
542
543         setup->sv_settling_time_ns = 10000000;
544         setup->sv_order = 14;
545
546         master_reference = ni_get_reference( setup,
547                 ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
548
549         memset(&tmpl,0,sizeof(tmpl));
550         tmpl.insn = INSN_READ;
551         tmpl.n = 1;
552         tmpl.subdev = setup->ad_subdev;
553
554         num_ai_channels = comedi_get_n_channels( setup->dev, setup->ad_subdev );
555         assert( num_ai_channels >= 0 );
556         num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
557         assert( num_ai_ranges >= 0 );
558
559         for( channel = 0; channel < num_ai_channels; channel++ )
560         {
561                 for( range = 0; range < num_ai_ranges; range++ )
562                 {
563                         /* 0 offset */
564                         o = setup->observables + ni_zero_offset_611x( setup, channel, range );
565                         assert( o->name == NULL );
566                         asprintf( &o->name, "ai, ch %i, range %i, zero offset",
567                                 channel, range );
568                         o->observe_insn = tmpl;
569                         o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
570                                 | CR_ALT_SOURCE | CR_ALT_FILTER;
571                         o->reference_source = REF_GND_GND;
572                         o->target = 0.0;
573
574                         /* voltage reference */
575                         o = setup->observables + ni_reference_611x( setup, channel, range );
576                         assert( o->name == NULL );
577                         asprintf( &o->name, "ai, ch %i, range %i, voltage reference",
578                                 channel, range );
579                         o->observe_insn = tmpl;
580                         o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
581                                 | CR_ALT_SOURCE | CR_ALT_FILTER;
582                         reference_target_611x( setup, o, master_reference, range );
583                 }
584         }
585
586         memset(&po_tmpl,0,sizeof(po_tmpl));
587         po_tmpl.insn = INSN_WRITE;
588         po_tmpl.n = 1;
589         po_tmpl.subdev = setup->da_subdev;
590
591         for( channel = 0; channel < num_ao_channels; channel ++ )
592         {
593                 static const int ai_range_for_ao = 2;
594
595                 /* ao zero offset */
596                 o = setup->observables + ni_ao_zero_offset_611x( setup, channel, 0 );
597                 assert( o->name == NULL );
598                 asprintf( &o->name, "ao ch %i, zero offset", channel );
599                 o->preobserve_insn = po_tmpl;
600                 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
601                 o->preobserve_insn.data = o->preobserve_data;
602                 o->observe_insn = tmpl;
603                 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
604                         | CR_ALT_SOURCE | CR_ALT_FILTER;
605                 o->reference_source = REF_DAC_GND( channel );
606                 set_target( setup, ni_ao_zero_offset_611x( setup, channel, 0 ), 0.0 );
607
608                 /* ao gain */
609                 o = setup->observables + ni_ao_reference_611x( setup, channel, 0 );
610                 assert( o->name == NULL );
611                 asprintf( &o->name, "ao ch %i, reference voltage", channel );
612                 o->preobserve_insn = po_tmpl;
613                 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
614                 o->preobserve_insn.data = o->preobserve_data;
615                 o->observe_insn = tmpl;
616                 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
617                         | CR_ALT_SOURCE | CR_ALT_FILTER;
618                 o->reference_source = REF_DAC_GND( channel );
619                 set_target( setup, ni_ao_reference_611x( setup, channel, 0 ), 5.0 );
620         }
621
622         setup->n_observables = num_ao_observables_611x + 2 * num_ai_ranges * num_ai_channels;
623 }
624
625 static int cal_ni_at_mio_16e_2(calibration_setup_t *setup)
626 {
627         ni_caldac_layout_t layout;
628
629         init_ni_caldac_layout( &layout );
630         layout.adc_pregain_offset = 0;
631         layout.adc_postgain_offset = 1;
632         layout.adc_gain = 3;
633         layout.adc_unip_offset = 2;
634         layout.dac_offset[ 0 ] = 5;
635         layout.dac_gain[ 0 ] = 6;
636         layout.dac_offset[ 1 ] = 8;
637         layout.dac_gain[ 1 ] = 9;
638
639         return cal_ni_generic( setup, &layout );
640 }
641
642 static int cal_ni_daqcard_ai_16xe_50(calibration_setup_t *setup)
643 {
644         ni_caldac_layout_t layout;
645
646         init_ni_caldac_layout( &layout );
647         layout.adc_pregain_offset = 8;
648         layout.adc_postgain_offset = 2;
649         layout.adc_gain = 0;
650         layout.adc_gain_fine = 1;
651
652         return cal_ni_generic( setup, &layout );
653 }
654
655 static int cal_ni_at_mio_16xe_50(calibration_setup_t *setup)
656 {
657         ni_caldac_layout_t layout;
658
659         init_ni_caldac_layout( &layout );
660         layout.adc_pregain_offset = 8;
661         layout.adc_postgain_offset = 2;
662         layout.adc_gain = 0;
663         layout.adc_gain_fine = 1;
664         layout.dac_offset[ 0 ] = 6;
665         layout.dac_gain[ 0 ] = 4;
666         layout.dac_offset[ 1 ] = 7;
667         layout.dac_gain[ 1 ] = 5;
668
669         return cal_ni_generic( setup, &layout );
670 }
671
672 static int cal_ni_pci_mio_16xe_10(calibration_setup_t *setup)
673 {
674         ni_caldac_layout_t layout;
675
676         init_ni_caldac_layout( &layout );
677         layout.adc_pregain_offset = 8;
678         layout.adc_postgain_offset = 2;
679         layout.adc_postgain_offset_fine = 3;
680         layout.adc_gain = 0;
681         layout.adc_gain_fine = 1;
682         layout.dac_offset[ 0 ] = 6;
683         layout.dac_gain[ 0 ] = 4;
684         layout.dac_offset[ 1 ] = 7;
685         layout.dac_gain[ 1 ] = 5;
686
687         return cal_ni_generic( setup, &layout );
688 }
689
690 static int cal_ni_at_mio_16e_1(calibration_setup_t *setup)
691 {
692         return cal_ni_at_mio_16e_2( setup );
693 }
694
695 static int cal_ni_pci_mio_16e_1(calibration_setup_t *setup)
696 {
697         ni_caldac_layout_t layout;
698
699         init_ni_caldac_layout( &layout );
700         layout.adc_pregain_offset = 0;
701         layout.adc_postgain_offset = 1;
702         layout.adc_unip_offset = 2;
703         layout.adc_gain = 3;
704         layout.dac_offset[ 0 ] = 5;
705         layout.dac_gain[ 0 ] = 6;
706         layout.dac_linearity[ 0 ] = 4;
707         layout.dac_offset[ 1 ] = 8;
708         layout.dac_gain[ 1 ] = 9;
709         layout.dac_linearity[ 1 ] = 7;
710
711         return cal_ni_generic( setup, &layout );
712 }
713
714 static int cal_ni_pci_6032e(calibration_setup_t *setup)
715 {
716         ni_caldac_layout_t layout;
717
718         init_ni_caldac_layout( &layout );
719         layout.adc_pregain_offset = 8;
720         layout.adc_postgain_offset = 2;
721         layout.adc_postgain_offset_fine = 3;
722         layout.adc_gain = 0;
723         layout.adc_gain_fine = 1;
724
725         return cal_ni_generic( setup, &layout );
726 }
727
728 static int cal_ni_pci_6035e(calibration_setup_t *setup)
729 {
730         /* this is for the ad8804_debug caldac */
731         ni_caldac_layout_t layout;
732
733         init_ni_caldac_layout( &layout );
734         layout.adc_pregain_offset = 0;
735         layout.adc_pregain_offset_fine = 8;
736         layout.adc_postgain_offset = 4;
737         layout.adc_gain = 2;
738         layout.dac_offset[ 0 ] = 6;
739         layout.dac_gain[ 0 ] = 11;
740         layout.dac_linearity[ 0 ] = 10;
741         layout.dac_offset[ 1 ] = 9;
742         layout.dac_gain[ 1 ] = 5;
743         layout.dac_linearity[ 1 ] = 1;
744
745         return cal_ni_generic( setup, &layout );
746 }
747
748 static int cal_ni_pci_6071e(calibration_setup_t *setup)
749 {
750         ni_caldac_layout_t layout;
751
752         if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
753         {
754                 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
755                  "for this calibration to work properly\n" );
756         }
757
758         init_ni_caldac_layout( &layout );
759         layout.adc_pregain_offset = 0;
760         layout.adc_pregain_offset_fine = 8;
761         layout.adc_postgain_offset = 4;
762         layout.adc_gain = 2;
763         layout.dac_offset[ 0 ] = 6;
764         layout.dac_gain[ 0 ] = 11;
765         layout.dac_linearity[ 0 ] = 10;
766         layout.dac_offset[ 1 ] = 9;
767         layout.dac_gain[ 1 ] = 5;
768         layout.dac_linearity[ 1 ] = 1;
769         return cal_ni_generic( setup, &layout );
770 }
771
772 static int cal_ni_pxi_6071e(calibration_setup_t *setup)
773 {
774         ni_caldac_layout_t layout;
775
776         if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
777         {
778                 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
779                  "for this calibration to work properly\n" );
780         }
781
782         init_ni_caldac_layout( &layout );
783         layout.adc_pregain_offset = 0;
784         layout.adc_pregain_offset_fine = 8;
785         layout.adc_postgain_offset = 4;
786         layout.adc_gain = 2;
787         layout.dac_offset[ 0 ] = 6;
788         layout.dac_gain[ 0 ] = 11;
789         layout.dac_linearity[ 0 ] = 10;
790         layout.dac_offset[ 1 ] = 9;
791         layout.dac_gain[ 1 ] = 5;
792         layout.dac_linearity[ 1 ] = 1;
793         return cal_ni_generic( setup, &layout );
794 }
795
796 static int cal_ni_at_mio_16e_10(calibration_setup_t *setup)
797 {
798         // 16e-10 (old)
799         ni_caldac_layout_t layout;
800
801         init_ni_caldac_layout( &layout );
802         layout.adc_pregain_offset = 10;
803         layout.adc_pregain_offset_fine = 0;
804         layout.adc_postgain_offset = 1;
805         layout.adc_gain = 3;
806         layout.adc_unip_offset = 2;
807         layout.dac_offset[ 0 ] = 5; /* guess */
808         layout.dac_gain[ 0 ] = 6; /* guess */
809         layout.dac_offset[ 1 ] = 8; /* guess */
810         layout.dac_gain[ 1 ] = 9; /* guess */
811
812         return cal_ni_generic( setup, &layout );
813 }
814
815 static int cal_ni_pci_mio_16xe_50(calibration_setup_t *setup)
816 {
817         ni_caldac_layout_t layout;
818
819         init_ni_caldac_layout( &layout );
820         layout.adc_pregain_offset = 8;
821         layout.adc_postgain_offset = 2;
822         layout.adc_gain = 0;
823         layout.adc_gain_fine = 1;
824         layout.adc_unip_offset = 7;
825         layout.dac_offset[ 0 ] = 6;
826         layout.dac_gain[ 0 ] = 4;
827         layout.dac_offset[ 1 ] = 7;
828         layout.dac_gain[ 1 ] = 5;
829
830         return cal_ni_generic( setup, &layout );
831 }
832
833 static int cal_ni_pci_6023e(calibration_setup_t *setup)
834 {
835         /* for comedi-0.7.65 */
836         ni_caldac_layout_t layout;
837
838         init_ni_caldac_layout( &layout );
839         layout.adc_pregain_offset = 8; /* possibly wrong */
840         layout.adc_pregain_offset_fine = 0;
841         layout.adc_postgain_offset = 4;
842         layout.adc_gain = 2;
843
844         return cal_ni_generic( setup, &layout );
845 }
846
847 static int cal_ni_pci_6024e(calibration_setup_t *setup)
848 {
849         ni_caldac_layout_t layout;
850
851         init_ni_caldac_layout( &layout );
852         layout.adc_pregain_offset = 8;
853         layout.adc_postgain_offset = 4;
854         layout.adc_pregain_offset_fine = 0;
855         layout.adc_gain = 2;
856         layout.dac_offset[ 0 ] = 6;
857         layout.dac_gain[ 0 ] = 11;
858         layout.dac_linearity[ 0 ] = 10;
859         layout.dac_offset[ 1 ] = 9;
860         layout.dac_gain[ 1 ] = 5;
861         layout.dac_linearity[ 1 ] = 1;
862
863         return cal_ni_generic( setup, &layout );
864 }
865
866 static int cal_ni_pci_6025e(calibration_setup_t *setup)
867 {
868         ni_caldac_layout_t layout;
869
870         init_ni_caldac_layout( &layout );
871         layout.adc_pregain_offset = 8;
872         layout.adc_postgain_offset = 4;
873         layout.adc_pregain_offset_fine = 0;
874         layout.adc_gain = 2;
875         layout.dac_offset[ 0 ] = 6;
876         layout.dac_gain[ 0 ] = 11;
877         layout.dac_linearity[ 0 ] = 10;
878         layout.dac_offset[ 1 ] = 9;
879         layout.dac_gain[ 1 ] = 5;
880         layout.dac_linearity[ 1 ] = 1;
881
882         return cal_ni_generic( setup, &layout );
883 }
884
885 static int cal_ni_pci_6052e(calibration_setup_t *setup)
886 {
887         /*
888          * This board has noisy caldacs
889          *
890          * The NI documentation says (true mb88341 addressing):
891          *   0, 8   AI pregain  (coarse, fine)
892          *   4, 12  AI postgain
893          *   2, 10  AI reference
894          *   14, 7  AI unipolar offset
895          *
896          *   0      AO0 linearity
897          *   8, 4   AO0 reference
898          *   12     AO0 offset
899          *   2      AO1 linearity
900          *   10, 6  AO1 reference
901          *   14     AO1 offset
902          *
903          *  For us, these map to (ad8804 channels)
904          *
905          *   0, 1   AI pregain  (coarse, fine)
906          *   2, 3  AI postgain
907          *   4, 5  AI reference
908          *   7  AI unipolar offset
909          *
910          *   0      AO0 linearity
911          *   1, 2   AO0 reference
912          *   3      AO0 offset
913          *   4      AO1 linearity
914          *   5, 6   AO1 reference
915          *   7      AO1 offset
916          *
917          *  or, with mb88341 channels
918          *
919          *   xxx    AO0 linearity
920          *   7, 3   AO0 reference
921          *   11     AO0 offset
922          *   1      AO1 linearity
923          *   9, 5   AO1 reference
924          *   xxx    AO1 offset
925          *
926          */
927         ni_caldac_layout_t layout;
928
929         init_ni_caldac_layout( &layout );
930         layout.adc_pregain_offset = 0;
931         layout.adc_postgain_offset = 2;
932         layout.adc_gain = 4;
933         layout.adc_unip_offset = 6;
934         layout.adc_pregain_offset_fine = 1;
935         layout.adc_postgain_offset_fine = 3;
936         layout.adc_gain_fine = 5;
937 #if 1
938 /* this seems broken, i think we need to change
939  * second caldac in driver to ad8804_debug */
940         layout.dac_offset[ 0 ] = 12 + 11;
941         layout.dac_gain[ 0 ] = 12 + 7;
942         layout.dac_gain_fine[ 0 ] = 12 + 3;
943         layout.dac_offset[ 1 ] = 12 + 1;
944         layout.dac_gain[ 1 ] = 12 + 9;
945         layout.dac_gain_fine[ 1 ] = 12 + 5;
946 #else
947 /* this should work if the first two caldacs were ad8804_debug */
948         layout.dac_offset[ 0 ] = 16 + 3;
949         layout.dac_gain[ 0 ] = 16 + 1;
950         layout.dac_gain_fine[ 0 ] = 16 + 2;
951         layout.dac_linearity[ 0 ] = 16 + 0;
952         layout.dac_offset[ 1 ] = 16 + 7;
953         layout.dac_gain[ 1 ] = 16 + 5;
954         layout.dac_gain_fine[ 1 ] = 16 + 6;
955         layout.dac_linearity[ 1 ] = 16 + 4;
956 #endif
957         return cal_ni_generic( setup, &layout );
958 }
959
960 static int cal_ni_daqcard_ai_16e_4(calibration_setup_t *setup)
961 {
962         ni_caldac_layout_t layout;
963
964         init_ni_caldac_layout( &layout );
965         layout.adc_pregain_offset = 0;
966         layout.adc_postgain_offset = 1;
967         layout.adc_gain = 3;
968         layout.adc_unip_offset = 2;
969
970         return cal_ni_generic( setup, &layout );
971 }
972
973 static int adc_offset_611x( unsigned int channel )
974 {
975         return 2 * channel + 2;
976 }
977 static int adc_gain_611x( unsigned int channel )
978 {
979         return 2 * channel + 1;
980 }
981 static int dac_offset_611x( unsigned int channel )
982 {
983         return 12 + 2 + 2 * channel;
984 }
985 static int dac_gain_611x( unsigned int channel )
986 {
987         return 12 + 1 + 2 * channel;
988 }
989 static int cal_ni_pci_611x( calibration_setup_t *setup )
990 {
991         generic_layout_t layout;
992
993         init_generic_layout( &layout );
994         layout.adc_offset = adc_offset_611x;
995         layout.adc_gain = adc_gain_611x;
996         layout.dac_offset = dac_offset_611x;
997         layout.dac_gain = dac_gain_611x;
998         layout.adc_high_observable = ni_reference_611x;
999         layout.adc_ground_observable = ni_zero_offset_611x;
1000         layout.dac_high_observable = ni_ao_reference_611x;
1001         layout.dac_ground_observable = ni_ao_zero_offset_611x;
1002
1003         return generic_cal_by_channel_and_range( setup, &layout );
1004 }
1005
1006 static int cal_ni_pci_mio_16e_4( calibration_setup_t *setup )
1007 {
1008         ni_caldac_layout_t layout;
1009
1010         init_ni_caldac_layout( &layout );
1011         layout.adc_pregain_offset = 8;
1012         layout.adc_postgain_offset = 4;
1013         layout.adc_gain = 2;
1014         layout.adc_unip_offset = 7;
1015         layout.dac_offset[ 0 ] = 6;
1016         layout.dac_gain[ 0 ] = 11;
1017         layout.dac_linearity[ 0 ] = 10;
1018         layout.dac_offset[ 1 ] = 9;
1019         layout.dac_gain[ 1 ] = 5;
1020         layout.dac_linearity[ 1 ] = 1;
1021
1022         return cal_ni_generic( setup, &layout );
1023 }
1024
1025 static int cal_ni_daqcard_6062e( calibration_setup_t *setup )
1026 {
1027         ni_caldac_layout_t layout;
1028
1029         if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
1030         {
1031                 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
1032                  "for this calibration to work properly\n" );
1033         }
1034         init_ni_caldac_layout( &layout );
1035         layout.adc_pregain_offset = 8;
1036         layout.adc_postgain_offset = 4;
1037         layout.adc_gain = 2;
1038         layout.adc_unip_offset = 7;
1039         layout.dac_offset[ 0 ] = 6;
1040         layout.dac_gain[ 0 ] = 11;
1041         layout.dac_linearity[ 0 ] = 10;
1042         layout.dac_offset[ 1 ] = 9;
1043         layout.dac_gain[ 1 ] = 5;
1044         layout.dac_linearity[ 1 ] = 1;
1045
1046         return cal_ni_generic( setup, &layout );
1047 }
1048
1049 static int cal_ni_daqcard_6024e( calibration_setup_t *setup )
1050 {
1051         ni_caldac_layout_t layout;
1052
1053         init_ni_caldac_layout( &layout );
1054
1055         layout.adc_pregain_offset = 0;
1056         layout.adc_postgain_offset = 4;
1057         layout.adc_gain = 2;
1058         //layout.adc_unip_offset = 7;
1059         layout.dac_offset[ 0 ] = 6;
1060         layout.dac_gain[ 0 ] = 3;
1061         //layout.dac_linearity[ 0 ] = 10;
1062         layout.dac_offset[ 1 ] = 1;
1063         layout.dac_gain[ 1 ] = 5;
1064         //layout.dac_linearity[ 1 ] = 1;
1065
1066         return cal_ni_generic( setup, &layout );
1067 }
1068
1069 static void prep_adc_caldacs_generic( calibration_setup_t *setup,
1070         const ni_caldac_layout_t *layout )
1071 {
1072         int retval;
1073
1074         if( setup->old_calibration == NULL )
1075         {
1076                 reset_caldac( setup, layout->adc_pregain_offset );
1077                 reset_caldac( setup, layout->adc_postgain_offset );
1078                 reset_caldac( setup, layout->adc_gain );
1079                 reset_caldac( setup, layout->adc_pregain_offset_fine );
1080                 reset_caldac( setup, layout->adc_postgain_offset_fine );
1081                 reset_caldac( setup, layout->adc_gain_fine );
1082                 reset_caldac( setup, layout->adc_unip_offset );
1083         }else
1084         {
1085                 retval = comedi_apply_parsed_calibration( setup->dev, setup->ad_subdev,
1086                         0, 0, AREF_GROUND, setup->old_calibration );
1087                 if( retval < 0 )
1088                 {
1089                         DPRINT( 0, "Failed to apply existing calibration, reseting adc caldacs.\n" );
1090                         reset_caldac( setup, layout->adc_pregain_offset );
1091                         reset_caldac( setup, layout->adc_postgain_offset );
1092                         reset_caldac( setup, layout->adc_gain );
1093                         reset_caldac( setup, layout->adc_pregain_offset_fine );
1094                         reset_caldac( setup, layout->adc_postgain_offset_fine );
1095                         reset_caldac( setup, layout->adc_gain_fine );
1096                         reset_caldac( setup, layout->adc_unip_offset );
1097                 }
1098         }
1099 }
1100
1101 static void prep_dac_caldacs_generic( calibration_setup_t *setup,
1102         const ni_caldac_layout_t *layout, unsigned int channel, unsigned int range )
1103 {
1104         int retval;
1105
1106         if( setup->da_subdev < 0 ) return;
1107
1108         if( setup->old_calibration == NULL )
1109         {
1110                 reset_caldac( setup, layout->dac_offset[ channel ] );
1111                 reset_caldac( setup, layout->dac_gain[ channel ] );
1112                 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1113                 reset_caldac( setup, layout->dac_linearity[ channel ] );
1114         }else
1115         {
1116                 retval = comedi_apply_parsed_calibration( setup->dev, setup->da_subdev,
1117                         channel, range, AREF_GROUND, setup->old_calibration );
1118                 if( retval < 0 )
1119                 {
1120                         DPRINT( 0, "Failed to apply existing calibration, reseting dac caldacs.\n" );
1121                         reset_caldac( setup, layout->dac_offset[ channel ] );
1122                         reset_caldac( setup, layout->dac_gain[ channel ] );
1123                         reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1124                         reset_caldac( setup, layout->dac_linearity[ channel ] );
1125                 }
1126         }
1127 }
1128
1129 static int cal_ni_generic( calibration_setup_t *setup, const ni_caldac_layout_t *layout )
1130 {
1131         comedi_calibration_setting_t *current_cal;
1132         int retval;
1133
1134         prep_adc_caldacs_generic( setup, layout );
1135
1136         current_cal = sc_alloc_calibration_setting( setup );
1137         current_cal->subdevice = setup->ad_subdev;
1138         generic_do_relative( setup, current_cal, ni_zero_offset_low,
1139                 ni_reference_low, layout->adc_gain );
1140         generic_do_relative( setup, current_cal, ni_zero_offset_low,
1141                 ni_zero_offset_high, layout->adc_postgain_offset );
1142         generic_do_cal( setup, current_cal, ni_zero_offset_high, layout->adc_pregain_offset );
1143         generic_do_relative( setup, current_cal, ni_zero_offset_low,
1144                 ni_reference_low, layout->adc_gain_fine );
1145         generic_do_relative( setup, current_cal, ni_zero_offset_low,
1146                 ni_zero_offset_high, layout->adc_postgain_offset_fine );
1147         generic_do_cal( setup, current_cal, ni_zero_offset_high,
1148                 layout->adc_pregain_offset_fine );
1149         generic_do_cal( setup, current_cal, ni_unip_zero_offset_high, layout->adc_unip_offset );
1150         sc_push_channel( current_cal, SC_ALL_CHANNELS );
1151         sc_push_range( current_cal, SC_ALL_RANGES );
1152         sc_push_aref( current_cal, SC_ALL_AREFS );
1153
1154         if( setup->da_subdev >= 0 && setup->do_output )
1155         {
1156                 unsigned int channel, range;
1157                 int ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev );
1158                 int ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev );
1159                 int num_ao_ranges;
1160
1161                 for( channel = 0; channel < 2; channel++ )
1162                 {
1163                         num_ao_ranges = comedi_get_n_ranges( setup->dev, setup->da_subdev, channel );
1164                         prep_dac_caldacs_generic( setup, layout, channel, ao_bipolar_lowgain );
1165
1166                         current_cal = sc_alloc_calibration_setting( setup );
1167                         current_cal->subdevice = setup->da_subdev;
1168                         generic_do_linearity( setup, current_cal, ni_ao_linearity( channel ),
1169                                 ni_ao_zero_offset( channel ), ni_ao_reference( channel ),
1170                                 layout->dac_linearity[ channel ] );
1171                         generic_do_cal( setup, current_cal, ni_ao_zero_offset( channel ),
1172                                 layout->dac_offset[ channel ] );
1173                         generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1174                                 layout->dac_gain[ channel ] );
1175                         generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1176                                 layout->dac_gain_fine[ channel ] );
1177                         sc_push_channel( current_cal, channel );
1178                         for( range = 0; range < num_ao_ranges; range++ )
1179                         {
1180                                 if( is_bipolar( setup->dev, setup->da_subdev, channel, range ) )
1181                                         sc_push_range( current_cal, range );
1182                         }
1183                         sc_push_aref( current_cal, SC_ALL_AREFS );
1184
1185                         if( ao_unipolar_lowgain >= 0 )
1186                         {
1187                                 prep_dac_caldacs_generic( setup, layout, channel, ao_unipolar_lowgain );
1188
1189                                 current_cal = sc_alloc_calibration_setting( setup );
1190                                 current_cal->subdevice = setup->da_subdev;
1191                                 generic_do_linearity( setup, current_cal, ni_ao_unip_zero_offset( channel ),
1192                                         ni_ao_unip_linearity( channel ), ni_ao_unip_reference( channel ),
1193                                         layout->dac_linearity[ channel ] );
1194                                 generic_do_cal( setup, current_cal, ni_ao_unip_zero_offset( channel),
1195                                         layout->dac_offset[ channel ] );
1196                                 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1197                                         layout->dac_gain[ channel ] );
1198                                 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1199                                         layout->dac_gain_fine[ channel ] );
1200                                 sc_push_channel( current_cal, channel );
1201                                 for( range = 0; range < num_ao_ranges; range++ )
1202                                 {
1203                                         if( is_unipolar( setup->dev, setup->da_subdev, channel, range ) )
1204                                                 sc_push_range( current_cal, range );
1205                                 }
1206                                 sc_push_aref( current_cal, SC_ALL_AREFS );
1207                         }
1208                 }
1209         }
1210
1211         retval = write_calibration_file( setup );
1212
1213         return retval;
1214 }
1215
1216 static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc)
1217 {
1218         int lsb,msb;
1219         int16_t uv;
1220         double ref;
1221
1222         lsb=read_eeprom( setup, lsb_loc );
1223         msb=read_eeprom( setup, msb_loc );
1224         assert( lsb >=0 && msb >= 0 );
1225         DPRINT(0,"eeprom reference lsb=%d msb=%d\n", lsb, msb);
1226
1227         uv = ( lsb & 0xff ) | ( ( msb << 8 ) & 0xff00 );
1228         ref=5.000+1.0e-6*uv;
1229         DPRINT(0, "resulting reference voltage: %g\n", ref );
1230         if( fabs( ref - 5.0 ) > 0.005 )
1231                 DPRINT( 0, "WARNING: eeprom indicates reference is more than 5mV away\n"
1232                         "from 5V.  Possible bad eeprom address?\n" );
1233
1234         return ref;
1235 }
1236