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