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