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