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