Split up comedi_calibrate.c, additional hacking
authorDavid Schleef <ds@schleef.org>
Tue, 9 Oct 2001 23:45:16 +0000 (23:45 +0000)
committerDavid Schleef <ds@schleef.org>
Tue, 9 Oct 2001 23:45:16 +0000 (23:45 +0000)
comedi_calibrate/Makefile
comedi_calibrate/calib.h [new file with mode: 0644]
comedi_calibrate/comedi_calibrate.c
comedi_calibrate/ni.c [new file with mode: 0644]

index 4ec6ff59f941069eda0eb65f1b82b036aa708662..49c0aeec55322b516aa287685a26cfe850544464 100644 (file)
@@ -7,11 +7,12 @@ LDFLAGS += -L../lib/ -lcomedi -lm
 
 
 BINS=comedi_calibrate
+objs = comedi_calibrate.o ni.o
 
 all: $(BINS)
 
-comedi_calibrate: comedi_calibrate.o
-       $(CC) -o comedi_calibrate comedi_calibrate.o $(LDFLAGS)
+comedi_calibrate: $(objs)
+       $(CC) -o $@ $(objs) $(LDFLAGS)
 
 clean:
        -rm -f *.o $(BINS)
diff --git a/comedi_calibrate/calib.h b/comedi_calibrate/calib.h
new file mode 100644 (file)
index 0000000..897e1c0
--- /dev/null
@@ -0,0 +1,181 @@
+
+#ifndef __CALIB_H_
+#define __CALIB_H_
+
+#include <comedilib.h>
+#if 0
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#define DPRINT(level,fmt,args...) do{if(verbose>=level)printf(fmt, ## args);}while(0)
+
+#define N_CALDACS 32
+#define N_OBSERVABLES 32
+
+typedef struct{
+       int subdev;
+       int chan;
+
+       int maxdata;
+       int current;
+
+       int type;
+       double gain;
+}caldac;
+
+typedef struct{
+       char *name;
+
+       comedi_insn preobserve_insn;
+       lsampl_t preobserve_data;
+
+       comedi_insn observe_insn;
+
+       //comedi_range *range;
+       //int maxdata;
+
+       double target;
+}observable;
+
+extern caldac caldacs[N_CALDACS];
+extern int n_caldacs;
+
+extern observable observables[N_OBSERVABLES];
+extern int n_observables;
+
+extern comedi_t *dev;
+
+extern int ad_subdev;
+extern int da_subdev;
+extern int eeprom_subdev;
+extern int caldac_subdev;
+
+extern char *devicename;
+extern char *drivername;
+
+extern int verbose;
+
+enum {
+       STATUS_UNKNOWN = 0,
+       STATUS_GUESS,
+       STATUS_SOME,
+       STATUS_DONE
+};
+extern int device_status;
+
+extern int do_output;
+
+/* high level */
+
+void observe(void);
+void preobserve(int obs);
+void observable_dependence(int obs);
+void measure_observable(int obs);
+void reset_caldacs(void);
+
+/* drivers */
+
+void ni_setup(void);
+
+/* low level */
+
+void set_target(int obs,double target);
+void update_caldac(int i);
+void setup_caldacs(void);
+void postgain_cal(int obs1, int obs2, int dac);
+void cal1(int obs, int dac);
+
+/* misc and temp */
+
+void channel_dependence(int adc,int range);
+void caldac_dependence(int caldac);
+void dump_curve(int adc,int caldac);
+void chan_cal(int adc,int caldac,int range,double target);
+int read_eeprom(int addr);
+
+double read_chan(int adc,int range);
+int read_chan2(char *s,int adc,int range);
+void set_ao(comedi_t *dev,int subdev,int chan,int range,double value);
+void check_gain(int ad_chan,int range);
+double check_gain_chan(int ad_chan,int range,int cdac);
+
+void (*do_cal)(void);
+void cal_ni_results(void);
+
+/* helper functions */
+
+int get_bipolar_lowgain(comedi_t *dev,int subdev);
+int get_bipolar_highgain(comedi_t *dev,int subdev);
+int get_unipolar_lowgain(comedi_t *dev,int subdev);
+
+/* printing scientific numbers */
+
+int sci_sprint(char *s,double x,double y);
+int sci_sprint_alt(char *s,double x,double y);
+
+/* linear fitting */
+
+typedef struct {
+       int n;
+
+       double *y_data;
+       double *yerr_data;
+       double *x_data;
+
+       double x0;
+       double dx;
+       double yerr;
+
+       /* stats */
+       double s1,sx,sy,sxy,sxx;
+
+       double min,max;
+
+       /* results */
+       double ave_x;
+       double ave_y;
+       double slope;
+       double err_slope;
+       double err_ave_y;
+       double S_min;
+       double dof;
+
+}linear_fit_t;
+int linear_fit_monotonic(linear_fit_t *l);
+double linear_fit_func_y(linear_fit_t *l,double x);
+double check_gain_chan_x(linear_fit_t *l,unsigned int ad_chanspec,int cdac);
+
+/* slowly varying measurements */
+
+typedef struct{
+       comedi_t *dev;
+
+       int maxdata;
+       int order;
+       int aref;
+       int range;
+       int subd;
+       int chan;
+
+       comedi_range *rng;
+
+       int n;
+       double average;
+       double stddev;
+       double error;
+}new_sv_t;
+
+int new_sv_measure(new_sv_t *sv);
+int new_sv_init(new_sv_t *sv,comedi_t *dev,int subdev,int chan,int range,int aref);
+
+
+#endif
+
index 8414af81d75eacaba3b0a74152ad789a0a26c8ed..c93e2d9ecea6f404d2422d210fadd739438c9fe5 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-#define DPRINT(level,fmt,args...) do{if(verbose>=level)printf(fmt, ## args);}while(0)
+#include "calib.h"
 
-#define N_CALDACS 32
-#define N_OBSERVABLES 32
+/* global variables */
 
-typedef struct{
-       int subdev;
-       int chan;
+caldac caldacs[N_CALDACS];
+int n_caldacs;
 
-       int maxdata;
-       int current;
+observable observables[N_OBSERVABLES];
+int n_observables;
 
-       int type;
-       double gain;
-}caldac;
-
-typedef struct{
-       char *name;
-
-       comedi_insn preobserve_insn;
-       lsampl_t preobserve_data;
+comedi_t *dev;
 
-       comedi_insn observe_insn;
-
-       //comedi_range *range;
-       //int maxdata;
-
-       double target;
-}observable;
+int ad_subdev;
+int da_subdev;
+int eeprom_subdev;
+int caldac_subdev;
 
-static caldac caldacs[N_CALDACS];
-static observable observables[N_OBSERVABLES];
-
-static int n_caldacs;
-static int n_observables;
-
-static comedi_t *dev;
-
-static int ad_subdev;
-static int da_subdev;
-static int eeprom_subdev;
-static int caldac_subdev;
-
-double read_chan(int adc,int range);
-int read_chan2(char *s,int adc,int range);
-void set_ao(comedi_t *dev,int subdev,int chan,int range,double value);
-void check_gain(int ad_chan,int range);
-double check_gain_chan(int ad_chan,int range,int cdac);
+char *drivername = NULL;
+char *devicename = NULL;
 
 int verbose = 0;
 
-enum {
-       STATUS_UNKNOWN = 0,
-       STATUS_SOME,
-       STATUS_DONE
-};
 int device_status = STATUS_UNKNOWN;
 
-/* tmep */
-void do_cal(void);
-
-void observe(void);
-void preobserve(int obs);
-void observable_dependence(int obs);
-void measure_observable(int obs);
-void ni_setup(void);
-void set_target(int obs,double target);
-
-void cal_ni_results(void);
-
-void update_caldac(int i);
-void reset_caldacs(void);
-void setup_caldacs(void);
-void cal_ni_mio_E(void);
-void ni_mio_ai_postgain_cal(void);
-void ni_mio_ai_postgain_cal_2(int chan,int dac,int range_lo,int range_hi,double gain);
-void channel_dependence(int adc,int range);
-void caldac_dependence(int caldac);
-void dump_curve(int adc,int caldac);
-void chan_cal(int adc,int caldac,int range,double target);
-int read_eeprom(int addr);
-
-int get_bipolar_lowgain(comedi_t *dev,int subdev);
-int get_bipolar_highgain(comedi_t *dev,int subdev);
-int get_unipolar_lowgain(comedi_t *dev,int subdev);
-
-int sci_sprint(char *s,double x,double y);
-int sci_sprint_alt(char *s,double x,double y);
-
-
-typedef struct {
-       int n;
-
-       double *y_data;
-       double *yerr_data;
-       double *x_data;
-
-       double x0;
-       double dx;
-       double yerr;
-
-       /* stats */
-       double s1,sx,sy,sxy,sxx;
-
-       double min,max;
-
-       /* results */
-       double ave_x;
-       double ave_y;
-       double slope;
-       double err_slope;
-       double err_ave_y;
-       double S_min;
-       double dof;
-
-}linear_fit_t;
-int linear_fit_monotonic(linear_fit_t *l);
-double linear_fit_func_y(linear_fit_t *l,double x);
-double check_gain_chan_x(linear_fit_t *l,unsigned int ad_chanspec,int cdac);
+/* */
 
-typedef struct{
-       comedi_t *dev;
-
-       int maxdata;
-       int order;
-       int aref;
-       int range;
-       int subd;
-       int chan;
-
-       comedi_range *rng;
-
-       int n;
-       double average;
-       double stddev;
-       double error;
-}new_sv_t;
-
-int new_sv_measure(new_sv_t *sv);
-int new_sv_init(new_sv_t *sv,comedi_t *dev,int subdev,int chan,int range,int aref);
 
 struct board_struct{
        char *name;
        void (*setup)(void);
 };
 
-#if 0
-void cal_ni_16e_1(void);
-void cal_ni_16e_10(void);
-void cal_ni_16xe_50(void);
-void cal_ni_16xe_10(void);
-void cal_ni_6023e(void);
-void cal_ni_6071e(void);
-void cal_ni_daqcard_ai_16xe_50(void);
-void cal_ni_unknown(void);
-
-struct board_struct boards[]={
-       { "at-mio-16e-1",       cal_ni_16e_1 },
-       { "at-mio-16e-2",       cal_ni_16e_1 },
-       { "at-mio-16e-10",      cal_ni_16e_10 },
-//     { "at-mio-16de-10",     cal_ni_unknown },
-       { "at-mio-64e-3",       cal_ni_16e_1 },
-//     { "at-mio-16xe-50",     cal_ni_unknown },
-//     { "at-mio-16xe-10",     cal_ni_unknown },
-//     { "at-ai-16xe-10",      cal_ni_unknown },
-       { "pci-mio-16xe-50",    cal_ni_16xe_50 },
-       { "pci-mio-16xe-10",    cal_ni_16xe_10 },
-//     { "pxi-6030e",          cal_ni_unknown },
-       { "pci-mio-16e-1",      cal_ni_16e_1 },
-//     { "pci-mio-16e-4",      cal_ni_unknown },
-//     { "pxi-6040e",          cal_ni_unknown },
-//     { "pci-6031e",          cal_ni_unknown },
-//     { "pci-6032e",          cal_ni_unknown },
-//     { "pci-6033e",          cal_ni_unknown },
-//     { "pci-6071e",          cal_ni_unknown },
-       { "pci-6023e",          cal_ni_6023e },
-       { "pci-6024e",          cal_ni_6023e }, // guess
-       { "pci-6025e",          cal_ni_6023e }, // guess
-       { "pxi-6025e",          cal_ni_6023e }, // guess
-       { "pci-6034e",          cal_ni_6023e }, // guess
-       { "pci-6035e",          cal_ni_6023e },
-//     { "pci-6052e",          cal_ni_unknown },
-//     { "pci-6110e",          cal_ni_unknown },
-//     { "pci-6111e",          cal_ni_unknown },
-//     { "pci-6711",           cal_ni_unknown },
-//     { "pci-6713",           cal_ni_unknown },
-       { "pxi-6071e",          cal_ni_6071e },
-//     { "pxi-6070e",          cal_ni_unknown },
-//     { "pxi-6052e",          cal_ni_unknown },
-       { "DAQCard-ai-16xe-50", cal_ni_daqcard_ai_16xe_50 },
-//     { "DAQCard-ai-16e-4",   cal_ni_unknown },
-//     { "DAQCard-6062e",      cal_ni_unknown },
-//     { "DAQCard-6024e",      cal_ni_unknown },
-};
-#define n_boards (sizeof(boards)/sizeof(boards[0]))
-#endif
-
 struct board_struct drivers[] = {
        { "ni_pcimio",          ni_setup },
        { "ni_atmio",           ni_setup },
@@ -240,7 +75,7 @@ struct board_struct drivers[] = {
 int do_dump = 0;
 int do_reset = 1;
 int do_calibrate = 1;
-int do_results = 1;
+int do_results = 0;
 int do_output = 1;
 
 struct option options[] = {
@@ -257,6 +92,8 @@ struct option options[] = {
        { "no-dump", 0, &do_dump, 0 },
        { "results", 0, &do_results, 1 },
        { "no-results", 0, &do_results, 0 },
+       { "output", 0, &do_output, 1 },
+       { "no-output", 0, &do_output, 0 },
        { 0 },
 };
 
@@ -264,8 +101,6 @@ int main(int argc, char *argv[])
 {
        char *fn = NULL;
        int c;
-       char *drivername = NULL;
-       char *devicename = NULL;
        int i;
        struct board_struct *this_board;
        int index;
@@ -353,147 +188,12 @@ ok:
 
        if(do_reset)reset_caldacs();
        if(do_dump)observe();
-       if(do_calibrate)do_cal();
+       if(do_calibrate && do_cal)do_cal();
        if(do_results)observe();
 
        return 0;
 }
 
-enum {
-       ni_zero_offset_low = 0,
-       ni_zero_offset_high,
-       ni_reference_low,
-       ni_unip_offset_low,
-       ni_ao0_zero_offset,
-       ni_ao0_reference,
-       ni_ao1_zero_offset,
-       ni_ao1_reference,
-};
-
-void ni_setup(void)
-{
-       comedi_insn tmpl;
-       int bipolar_lowgain;
-       int bipolar_highgain;
-       int unipolar_lowgain;
-       double voltage_reference;
-       observable *o;
-
-       bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
-       bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
-       unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
-
-       voltage_reference = 5.000;
-
-       memset(&tmpl,0,sizeof(tmpl));
-       tmpl.insn = INSN_READ;
-       tmpl.n = 1;
-       tmpl.subdev = ad_subdev;
-
-       /* 0 offset, low gain */
-       o = observables + ni_zero_offset_low;
-       o->name = "ai, bipolar zero offset, low gain";
-       o->observe_insn = tmpl;
-       o->observe_insn.chanspec = CR_PACK(0,bipolar_lowgain,AREF_OTHER);
-       o->target = 0;
-
-       /* 0 offset, high gain */
-       o = observables + ni_zero_offset_high;
-       o->name = "ai, bipolar zero offset, high gain";
-       o->observe_insn = tmpl;
-       o->observe_insn.chanspec = CR_PACK(0,bipolar_highgain,AREF_OTHER);
-       o->target = 0;
-
-       /* voltage reference */
-       o = observables + ni_reference_low;
-       o->name = "ai, bipolar voltage reference, low gain";
-       o->observe_insn = tmpl;
-       o->observe_insn.chanspec = CR_PACK(5,bipolar_lowgain,AREF_OTHER);
-       o->target = voltage_reference;
-
-       if(unipolar_lowgain>=0){
-               /* unip/bip offset */
-               o = observables + ni_unip_offset_low;
-               o->name = "ai, unipolar zero offset, low gain";
-               o->observe_insn = tmpl;
-               o->observe_insn.chanspec =
-                       CR_PACK(0,unipolar_lowgain,AREF_OTHER);
-               o->target = 0;
-
-#if 0
-               /* unip gain */
-               o = observables + ni_unip_reference_low;
-               o->name = "ai, unipolar voltage reference, low gain";
-               o->observe_insn = tmpl;
-               o->observe_insn.chanspec =
-                       CR_PACK(5,unipolar_lowgain,AREF_OTHER);
-               o->target = voltage_reference;
-               i++;
-#endif
-       }
-
-       if(da_subdev>=0){
-               comedi_insn po_tmpl;
-
-               memset(&po_tmpl,0,sizeof(po_tmpl));
-               po_tmpl.insn = INSN_WRITE;
-               po_tmpl.n = 1;
-               po_tmpl.subdev = da_subdev;
-
-               /* ao 0, zero offset */
-               o = observables + ni_ao0_zero_offset;
-               o->name = "ao 0, zero offset, low gain";
-               o->preobserve_insn = po_tmpl;
-               o->preobserve_insn.chanspec = CR_PACK(0,0,0);
-               o->preobserve_insn.data = &o->preobserve_data;
-               o->observe_insn = tmpl;
-               o->observe_insn.chanspec =
-                       CR_PACK(2,bipolar_lowgain,AREF_OTHER);
-               set_target(ni_ao0_zero_offset,0.0);
-
-               /* ao 0, gain */
-               o = observables + ni_ao0_reference;
-               o->name = "ao 0, reference voltage, low gain";
-               o->preobserve_insn = po_tmpl;
-               o->preobserve_insn.chanspec = CR_PACK(0,0,0);
-               o->preobserve_insn.data = &o->preobserve_data;
-               o->observe_insn = tmpl;
-               o->observe_insn.chanspec =
-                       CR_PACK(6,bipolar_lowgain,AREF_OTHER);
-               set_target(ni_ao0_reference,5.0);
-               o->target -= voltage_reference;
-
-               /* ao 1, zero offset */
-               o = observables + ni_ao1_zero_offset;
-               o->name = "ao 1, zero offset, low gain";
-               o->preobserve_insn = po_tmpl;
-               o->preobserve_insn.chanspec = CR_PACK(1,0,0);
-               o->preobserve_insn.data = &o->preobserve_data;
-               o->observe_insn = tmpl;
-               o->observe_insn.chanspec =
-                       CR_PACK(3,bipolar_lowgain,AREF_OTHER);
-               set_target(ni_ao1_zero_offset,0.0);
-
-               /* ao 1, gain */
-               o = observables + ni_ao1_reference;
-               o->name = "ao 1, reference voltage, low gain";
-               o->preobserve_insn = po_tmpl;
-               o->preobserve_insn.chanspec = CR_PACK(1,0,0);
-               o->preobserve_insn.data = &o->preobserve_data;
-               o->observe_insn = tmpl;
-               o->observe_insn.chanspec =
-                       CR_PACK(7,bipolar_lowgain,AREF_OTHER);
-               set_target(ni_ao1_reference,5.0);
-               o->target -= voltage_reference;
-
-       }
-       n_observables = ni_ao1_reference + 1;
-
-       setup_caldacs();
-
-
-}
-
 void set_target(int obs,double target)
 {
        comedi_range *range;
@@ -641,264 +341,6 @@ void cal1(int obs, int dac)
        }
 }
 
-void do_cal(void)
-{
-#if 0
-       // daqcard
-       postgain_cal(ni_zero_offset_low,ni_zero_offset_high,2);
-       cal1(ni_zero_offset_high,8);
-       cal1(ni_reference_low,0);
-#endif
-
-       // 16e-2
-       postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
-       cal1(ni_zero_offset_high,0);
-       cal1(ni_reference_low,3);
-       cal1(ni_unip_offset_low,2);
-       if(do_output){
-               cal1(ni_ao0_zero_offset,5);
-               cal1(ni_ao0_reference,6);
-               cal1(ni_ao1_zero_offset,8);
-               cal1(ni_ao1_reference,9);
-       }
-
-#if 0
-       // 16e-10 (old)
-       postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
-       cal1(ni_zero_offset_high,10);
-       cal1(ni_zero_offset_high,0);
-       cal1(ni_reference_low,3);
-       cal1(ni_unip_offset_low,2);
-       if(do_output){
-               cal1(ni_ao0_zero_offset,5); // guess
-               cal1(ni_ao0_reference,6); // guess
-               cal1(ni_ao0_zero_offset,8); // guess
-               cal1(ni_ao0_reference,9); // guess
-       }
-#endif
-
-#if 0
-       // 16xe-50 (old) (same as daqcard?)
-       postgain_cal(ni_zero_offset_low,ni_zero_offset_high,2);
-       cal1(ni_zero_offset_high,8);
-       cal1(ni_reference_low,0);
-       if(do_output){
-               // unknown
-       }
-#endif
-
-#if 0
-       // 6035e (old)
-       postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
-       cal1(ni_zero_offset_high,0);
-       cal1(ni_reference_low,3);
-       if(do_output){
-               // unknown
-       }
-#endif
-
-#if 0
-       // 6071e (old)
-       postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
-       cal1(ni_zero_offset_high,0);
-       cal1(ni_reference_low,3);
-       if(do_output){
-               // unknown
-       }
-#endif
-}
-
-
-double ni_get_reference(int lsb_loc,int msb_loc)
-{
-       int lsb,msb;
-       int uv;
-       double ref;
-
-       lsb=read_eeprom(lsb_loc);
-       msb=read_eeprom(msb_loc);
-       printf("lsb=%d msb=%d\n",read_eeprom(425),read_eeprom(426));
-
-       uv=lsb | (msb<<8);
-       if(uv>=0x8000)uv-=0x10000;
-       ref=5.000+1.0e-6*uv;
-       printf("ref=%g\n",ref);
-
-       return ref;
-}
-
-void cal_ni_unknown(void)
-{
-       comedi_range *range;
-       int bipolar_lowgain;
-       int bipolar_highgain;
-       int unipolar_lowgain;
-       int have_ao = 1;
-
-       reset_caldacs();
-       printf("Warning: device not calibrated due to insufficient information\n");
-       printf("Please send this output to <ds@schleef.org>\n");
-       printf("$Id$\n");
-       printf("Device name: %s\n",comedi_get_board_name(dev));
-       printf("Comedi version: %d.%d.%d\n",
-               (comedi_get_version_code(dev)>>16)&0xff,
-               (comedi_get_version_code(dev)>>8)&0xff,
-               (comedi_get_version_code(dev))&0xff);
-
-       bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
-       bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
-       unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
-
-       /* 0 offset, low gain */
-       range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
-       DPRINT(0,"bipolar zero offset, low gain [%g,%g]\n",
-               range->min,range->max);
-       channel_dependence(0,bipolar_lowgain);
-
-       /* 0 offset, high gain */
-       range = comedi_get_range(dev,ad_subdev,0,bipolar_highgain);
-       DPRINT(0,"bipolar zero offset, high gain [%g,%g]\n",
-               range->min,range->max);
-       channel_dependence(0,bipolar_highgain);
-
-       /* unip/bip offset */
-       range = comedi_get_range(dev,ad_subdev,0,unipolar_lowgain);
-       DPRINT(0,"unipolar zero offset, low gain [%g,%g]\n",
-               range->min,range->max);
-       channel_dependence(0,unipolar_lowgain);
-
-       /* voltage reference */
-       range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
-       DPRINT(0,"bipolar voltage reference, low gain [%g,%g]\n",
-               range->min,range->max);
-       channel_dependence(5,bipolar_lowgain);
-
-       have_ao = (comedi_get_subdevice_type(dev,da_subdev)==COMEDI_SUBD_AO);
-       if(have_ao){
-               int ao_chan;
-
-               /* ao 0, zero offset */
-               ao_chan = 0;
-               set_ao(dev,da_subdev,ao_chan,0,0.0);
-               range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
-               DPRINT(0,"ao 0, zero offset, low gain [%g,%g]\n",
-                       range->min,range->max);
-               channel_dependence(2,bipolar_lowgain);
-
-               /* ao 0, gain */
-               ao_chan = 0;
-               set_ao(dev,da_subdev,ao_chan,0,5.0);
-               range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
-               DPRINT(0,"ao 0, gain, low gain [%g,%g]\n",
-                       range->min,range->max);
-               channel_dependence(6,bipolar_lowgain);
-
-               /* ao 1, zero offset */
-               ao_chan = 1;
-               set_ao(dev,da_subdev,ao_chan,0,0.0);
-               range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
-               DPRINT(0,"ao 1, zero offset, low gain [%g,%g]\n",
-                       range->min,range->max);
-               channel_dependence(3,bipolar_lowgain);
-
-               /* ao 1, gain */
-               ao_chan = 1;
-               set_ao(dev,da_subdev,ao_chan,0,5.0);
-               range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
-               DPRINT(0,"ao 1, gain, low gain [%g,%g]\n",
-                       range->min,range->max);
-               channel_dependence(7,bipolar_lowgain);
-       }
-
-       cal_ni_results();
-}
-
-void cal_ni_results(void)
-{
-       comedi_range *range;
-       int bipolar_lowgain;
-       int bipolar_highgain;
-       int unipolar_lowgain;
-       //int have_ao;
-       char s[32];
-
-       bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
-       bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
-       unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
-
-       /* 0 offset, low gain */
-       range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
-       read_chan2(s,0,bipolar_lowgain);
-       DPRINT(0,"bipolar zero offset, low gain [%g,%g]: %s\n",
-               range->min,range->max,s);
-
-       /* 0 offset, high gain */
-       range = comedi_get_range(dev,ad_subdev,0,bipolar_highgain);
-       read_chan2(s,0,bipolar_highgain);
-       DPRINT(0,"bipolar zero offset, high gain [%g,%g]: %s\n",
-               range->min,range->max,s);
-
-       /* unip/bip offset */
-       range = comedi_get_range(dev,ad_subdev,0,unipolar_lowgain);
-       read_chan2(s,0,unipolar_lowgain);
-       DPRINT(0,"unipolar zero offset, low gain [%g,%g]: %s\n",
-               range->min,range->max,s);
-
-}
-
-void ni_mio_ai_postgain_cal(void)
-{
-       linear_fit_t l;
-       double offset_r0;
-       double offset_r7;
-       double gain;
-       double a;
-
-       check_gain_chan_x(&l,CR_PACK(0,0,AREF_OTHER),1);
-       offset_r0=linear_fit_func_y(&l,caldacs[1].current);
-       printf("offset r0 %g\n",offset_r0);
-
-       check_gain_chan_x(&l,CR_PACK(0,7,AREF_OTHER),1);
-       offset_r7=linear_fit_func_y(&l,caldacs[1].current);
-       printf("offset r7 %g\n",offset_r7);
-
-       gain=l.slope;
-       
-       a=(offset_r0-offset_r7)/(200.0-1.0);
-       a=caldacs[1].current-a/gain;
-
-       printf("%g\n",a);
-
-       caldacs[1].current=rint(a);
-       update_caldac(1);
-}
-
-void ni_mio_ai_postgain_cal_2(int chan,int dac,int range_lo,int range_hi,double gain)
-{
-       double offset_lo,offset_hi;
-       linear_fit_t l;
-       double slope;
-       double a;
-
-       check_gain_chan_x(&l,CR_PACK(chan,range_lo,AREF_OTHER),dac);
-       offset_lo=linear_fit_func_y(&l,caldacs[dac].current);
-       printf("offset lo %g\n",offset_lo);
-
-       check_gain_chan_x(&l,CR_PACK(chan,range_hi,AREF_OTHER),dac);
-       offset_hi=linear_fit_func_y(&l,caldacs[dac].current);
-       printf("offset hi %g\n",offset_hi);
-
-       slope=l.slope;
-       
-       a=(offset_lo-offset_hi)/(gain-1.0);
-       a=caldacs[dac].current-a/slope;
-
-       printf("%g\n",a);
-
-       caldacs[dac].current=rint(a);
-       update_caldac(dac);
-}
-
 void chan_cal(int adc,int cdac,int range,double target)
 {
        linear_fit_t l;
diff --git a/comedi_calibrate/ni.c b/comedi_calibrate/ni.c
new file mode 100644 (file)
index 0000000..f5ae51b
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+   A little auto-calibration utility, for boards
+   that support it.
+
+   Right now, it only supports NI E series boards,
+   but it should be easily portable.
+
+   A few things need improvement here:
+    - current system gets "close", but doesn't
+      do any fine-tuning
+    - no pre/post gain discrimination for the
+      A/D zero offset.
+    - should read (and use) the actual reference
+      voltage value from eeprom
+    - statistics would be nice, to show how good
+      the calibration is.
+    - doesn't check unipolar ranges
+    - "alternate calibrations" would be cool--to
+      accurately measure 0 in a unipolar range
+    - more portable
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <comedilib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "calib.h"
+
+
+struct board_struct{
+       char *name;
+       int status;
+       void (*cal)(void);
+};
+
+void ni_setup_board(void);
+void ni_setup_observables(void);
+
+void cal_ni_16e_1(void);
+void cal_ni_daqcard_ai_16xe_50(void);
+void cal_ni_6035e(void);
+void cal_ni_6071e(void);
+void cal_ni_16e_10(void);
+void cal_ni_16xe_50(void);
+
+struct board_struct boards[]={
+       { "at-mio-16e-2",       STATUS_DONE,    cal_ni_16e_1 },
+       { "DAQCard-ai-16xe-50", STATUS_DONE,    cal_ni_daqcard_ai_16xe_50 },
+       { "at-mio-16e-1",       STATUS_SOME,    cal_ni_16e_1 },
+       { "pci-mio-16e-1",      STATUS_SOME,    cal_ni_16e_1 },
+       { "pci-6035e",          STATUS_GUESS,   cal_ni_6035e },
+       { "pci-6071e",          STATUS_GUESS,   cal_ni_6071e },
+       { "pxi-6071e",          STATUS_GUESS,   cal_ni_6071e },
+       { "at-mio-16e-10",      STATUS_GUESS,   cal_ni_16e_10 },
+       { "pci-mio-16xe-50",    STATUS_GUESS,   cal_ni_16xe_50 },
+       { "pci-6023e",          STATUS_GUESS,   cal_ni_6035e },
+#if 0
+//     { "at-mio-16de-10",     cal_ni_unknown },
+       { "at-mio-64e-3",       cal_ni_16e_1 },
+//     { "at-mio-16xe-50",     cal_ni_unknown },
+//     { "at-mio-16xe-10",     cal_ni_unknown },
+//     { "at-ai-16xe-10",      cal_ni_unknown },
+       { "pci-mio-16xe-10",    cal_ni_16xe_10 },
+//     { "pxi-6030e",          cal_ni_unknown },
+//     { "pci-mio-16e-4",      cal_ni_unknown },
+//     { "pxi-6040e",          cal_ni_unknown },
+//     { "pci-6031e",          cal_ni_unknown },
+//     { "pci-6032e",          cal_ni_unknown },
+//     { "pci-6033e",          cal_ni_unknown },
+//     { "pci-6071e",          cal_ni_unknown },
+       { "pci-6024e",          cal_ni_6023e }, // guess
+       { "pci-6025e",          cal_ni_6023e }, // guess
+       { "pxi-6025e",          cal_ni_6023e }, // guess
+       { "pci-6034e",          cal_ni_6023e }, // guess
+       { "pci-6035e",          cal_ni_6023e },
+//     { "pci-6052e",          cal_ni_unknown },
+//     { "pci-6110e",          cal_ni_unknown },
+//     { "pci-6111e",          cal_ni_unknown },
+//     { "pci-6711",           cal_ni_unknown },
+//     { "pci-6713",           cal_ni_unknown },
+//     { "pxi-6070e",          cal_ni_unknown },
+//     { "pxi-6052e",          cal_ni_unknown },
+//     { "DAQCard-ai-16e-4",   cal_ni_unknown },
+//     { "DAQCard-6062e",      cal_ni_unknown },
+//     { "DAQCard-6024e",      cal_ni_unknown },
+#endif
+};
+#define n_boards (sizeof(boards)/sizeof(boards[0]))
+
+enum {
+       ni_zero_offset_low = 0,
+       ni_zero_offset_high,
+       ni_reference_low,
+       ni_unip_offset_low,
+       ni_ao0_zero_offset,
+       ni_ao0_reference,
+       ni_ao1_zero_offset,
+       ni_ao1_reference,
+};
+
+void ni_setup(void)
+{
+       ni_setup_board();
+       ni_setup_observables();
+       setup_caldacs();
+}
+
+void ni_setup_board(void)
+{
+       int i;
+
+       for(i=0;i<n_boards;i++){
+               if(!strcmp(devicename,boards[i].name)){
+                       device_status = boards[i].status;
+                       do_cal = boards[i].cal;
+                       return;
+               }
+       }
+
+}
+
+void ni_setup_observables(void)
+{
+       comedi_insn tmpl;
+       int bipolar_lowgain;
+       int bipolar_highgain;
+       int unipolar_lowgain;
+       double voltage_reference;
+       observable *o;
+
+       bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
+       bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
+       unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
+
+       voltage_reference = 5.000;
+
+       memset(&tmpl,0,sizeof(tmpl));
+       tmpl.insn = INSN_READ;
+       tmpl.n = 1;
+       tmpl.subdev = ad_subdev;
+
+       /* 0 offset, low gain */
+       o = observables + ni_zero_offset_low;
+       o->name = "ai, bipolar zero offset, low gain";
+       o->observe_insn = tmpl;
+       o->observe_insn.chanspec = CR_PACK(0,bipolar_lowgain,AREF_OTHER);
+       o->target = 0;
+
+       /* 0 offset, high gain */
+       o = observables + ni_zero_offset_high;
+       o->name = "ai, bipolar zero offset, high gain";
+       o->observe_insn = tmpl;
+       o->observe_insn.chanspec = CR_PACK(0,bipolar_highgain,AREF_OTHER);
+       o->target = 0;
+
+       /* voltage reference */
+       o = observables + ni_reference_low;
+       o->name = "ai, bipolar voltage reference, low gain";
+       o->observe_insn = tmpl;
+       o->observe_insn.chanspec = CR_PACK(5,bipolar_lowgain,AREF_OTHER);
+       o->target = voltage_reference;
+
+       if(unipolar_lowgain>=0){
+               /* unip/bip offset */
+               o = observables + ni_unip_offset_low;
+               o->name = "ai, unipolar zero offset, low gain";
+               o->observe_insn = tmpl;
+               o->observe_insn.chanspec =
+                       CR_PACK(0,unipolar_lowgain,AREF_OTHER);
+               o->target = 0;
+
+#if 0
+               /* unip gain */
+               o = observables + ni_unip_reference_low;
+               o->name = "ai, unipolar voltage reference, low gain";
+               o->observe_insn = tmpl;
+               o->observe_insn.chanspec =
+                       CR_PACK(5,unipolar_lowgain,AREF_OTHER);
+               o->target = voltage_reference;
+               i++;
+#endif
+       }
+
+       if(da_subdev>=0){
+               comedi_insn po_tmpl;
+
+               memset(&po_tmpl,0,sizeof(po_tmpl));
+               po_tmpl.insn = INSN_WRITE;
+               po_tmpl.n = 1;
+               po_tmpl.subdev = da_subdev;
+
+               /* ao 0, zero offset */
+               o = observables + ni_ao0_zero_offset;
+               o->name = "ao 0, zero offset, low gain";
+               o->preobserve_insn = po_tmpl;
+               o->preobserve_insn.chanspec = CR_PACK(0,0,0);
+               o->preobserve_insn.data = &o->preobserve_data;
+               o->observe_insn = tmpl;
+               o->observe_insn.chanspec =
+                       CR_PACK(2,bipolar_lowgain,AREF_OTHER);
+               set_target(ni_ao0_zero_offset,0.0);
+
+               /* ao 0, gain */
+               o = observables + ni_ao0_reference;
+               o->name = "ao 0, reference voltage, low gain";
+               o->preobserve_insn = po_tmpl;
+               o->preobserve_insn.chanspec = CR_PACK(0,0,0);
+               o->preobserve_insn.data = &o->preobserve_data;
+               o->observe_insn = tmpl;
+               o->observe_insn.chanspec =
+                       CR_PACK(6,bipolar_lowgain,AREF_OTHER);
+               set_target(ni_ao0_reference,5.0);
+               o->target -= voltage_reference;
+
+               /* ao 1, zero offset */
+               o = observables + ni_ao1_zero_offset;
+               o->name = "ao 1, zero offset, low gain";
+               o->preobserve_insn = po_tmpl;
+               o->preobserve_insn.chanspec = CR_PACK(1,0,0);
+               o->preobserve_insn.data = &o->preobserve_data;
+               o->observe_insn = tmpl;
+               o->observe_insn.chanspec =
+                       CR_PACK(3,bipolar_lowgain,AREF_OTHER);
+               set_target(ni_ao1_zero_offset,0.0);
+
+               /* ao 1, gain */
+               o = observables + ni_ao1_reference;
+               o->name = "ao 1, reference voltage, low gain";
+               o->preobserve_insn = po_tmpl;
+               o->preobserve_insn.chanspec = CR_PACK(1,0,0);
+               o->preobserve_insn.data = &o->preobserve_data;
+               o->observe_insn = tmpl;
+               o->observe_insn.chanspec =
+                       CR_PACK(7,bipolar_lowgain,AREF_OTHER);
+               set_target(ni_ao1_reference,5.0);
+               o->target -= voltage_reference;
+
+       }
+       n_observables = ni_ao1_reference + 1;
+}
+
+void cal_ni_daqcard_ai_16xe_50(void)
+{
+       // daqcard
+       postgain_cal(ni_zero_offset_low,ni_zero_offset_high,2);
+       cal1(ni_zero_offset_high,8);
+       cal1(ni_reference_low,0);
+}
+
+void cal_ni_16e_1(void)
+{
+       // 16e-2
+       postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
+       cal1(ni_zero_offset_high,0);
+       cal1(ni_reference_low,3);
+       cal1(ni_unip_offset_low,2);
+       if(do_output){
+               cal1(ni_ao0_zero_offset,5);
+               cal1(ni_ao0_reference,6);
+               cal1(ni_ao1_zero_offset,8);
+               cal1(ni_ao1_reference,9);
+       }
+}
+
+void cal_ni_16e_10(void)
+{
+       // 16e-10 (old)
+       postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
+       cal1(ni_zero_offset_high,10);
+       cal1(ni_zero_offset_high,0);
+       cal1(ni_reference_low,3);
+       cal1(ni_unip_offset_low,2);
+       if(do_output){
+               cal1(ni_ao0_zero_offset,5); // guess
+               cal1(ni_ao0_reference,6); // guess
+               cal1(ni_ao0_zero_offset,8); // guess
+               cal1(ni_ao0_reference,9); // guess
+       }
+}
+
+void cal_ni_16xe_50(void)
+{
+       // 16xe-50 (old) (same as daqcard?)
+       postgain_cal(ni_zero_offset_low,ni_zero_offset_high,2);
+       cal1(ni_zero_offset_high,8);
+       cal1(ni_reference_low,0);
+       if(do_output){
+               // unknown
+       }
+}
+
+void cal_ni_6035e(void)
+{
+       // 6035e (old)
+       postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
+       cal1(ni_zero_offset_high,0);
+       cal1(ni_reference_low,3);
+       if(do_output){
+               // unknown
+       }
+}
+
+void cal_ni_6071e(void)
+{
+       // 6071e (old)
+       postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
+       cal1(ni_zero_offset_high,0);
+       cal1(ni_reference_low,3);
+       if(do_output){
+               // unknown
+       }
+}
+
+
+double ni_get_reference(int lsb_loc,int msb_loc)
+{
+       int lsb,msb;
+       int uv;
+       double ref;
+
+       lsb=read_eeprom(lsb_loc);
+       msb=read_eeprom(msb_loc);
+       printf("lsb=%d msb=%d\n",read_eeprom(425),read_eeprom(426));
+
+       uv=lsb | (msb<<8);
+       if(uv>=0x8000)uv-=0x10000;
+       ref=5.000+1.0e-6*uv;
+       printf("ref=%g\n",ref);
+
+       return ref;
+}
+
+void cal_ni_unknown(void)
+{
+       comedi_range *range;
+       int bipolar_lowgain;
+       int bipolar_highgain;
+       int unipolar_lowgain;
+       int have_ao = 1;
+
+       reset_caldacs();
+       printf("Warning: device not calibrated due to insufficient information\n");
+       printf("Please send this output to <ds@schleef.org>\n");
+       printf("$Id$\n");
+       printf("Device name: %s\n",comedi_get_board_name(dev));
+       printf("Comedi version: %d.%d.%d\n",
+               (comedi_get_version_code(dev)>>16)&0xff,
+               (comedi_get_version_code(dev)>>8)&0xff,
+               (comedi_get_version_code(dev))&0xff);
+
+       bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
+       bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
+       unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
+
+       /* 0 offset, low gain */
+       range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
+       DPRINT(0,"bipolar zero offset, low gain [%g,%g]\n",
+               range->min,range->max);
+       channel_dependence(0,bipolar_lowgain);
+
+       /* 0 offset, high gain */
+       range = comedi_get_range(dev,ad_subdev,0,bipolar_highgain);
+       DPRINT(0,"bipolar zero offset, high gain [%g,%g]\n",
+               range->min,range->max);
+       channel_dependence(0,bipolar_highgain);
+
+       /* unip/bip offset */
+       range = comedi_get_range(dev,ad_subdev,0,unipolar_lowgain);
+       DPRINT(0,"unipolar zero offset, low gain [%g,%g]\n",
+               range->min,range->max);
+       channel_dependence(0,unipolar_lowgain);
+
+       /* voltage reference */
+       range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
+       DPRINT(0,"bipolar voltage reference, low gain [%g,%g]\n",
+               range->min,range->max);
+       channel_dependence(5,bipolar_lowgain);
+
+       have_ao = (comedi_get_subdevice_type(dev,da_subdev)==COMEDI_SUBD_AO);
+       if(have_ao){
+               int ao_chan;
+
+               /* ao 0, zero offset */
+               ao_chan = 0;
+               set_ao(dev,da_subdev,ao_chan,0,0.0);
+               range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
+               DPRINT(0,"ao 0, zero offset, low gain [%g,%g]\n",
+                       range->min,range->max);
+               channel_dependence(2,bipolar_lowgain);
+
+               /* ao 0, gain */
+               ao_chan = 0;
+               set_ao(dev,da_subdev,ao_chan,0,5.0);
+               range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
+               DPRINT(0,"ao 0, gain, low gain [%g,%g]\n",
+                       range->min,range->max);
+               channel_dependence(6,bipolar_lowgain);
+
+               /* ao 1, zero offset */
+               ao_chan = 1;
+               set_ao(dev,da_subdev,ao_chan,0,0.0);
+               range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
+               DPRINT(0,"ao 1, zero offset, low gain [%g,%g]\n",
+                       range->min,range->max);
+               channel_dependence(3,bipolar_lowgain);
+
+               /* ao 1, gain */
+               ao_chan = 1;
+               set_ao(dev,da_subdev,ao_chan,0,5.0);
+               range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
+               DPRINT(0,"ao 1, gain, low gain [%g,%g]\n",
+                       range->min,range->max);
+               channel_dependence(7,bipolar_lowgain);
+       }
+
+       cal_ni_results();
+}
+
+void cal_ni_results(void)
+{
+       comedi_range *range;
+       int bipolar_lowgain;
+       int bipolar_highgain;
+       int unipolar_lowgain;
+       //int have_ao;
+       char s[32];
+
+       bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
+       bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
+       unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
+
+       /* 0 offset, low gain */
+       range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
+       read_chan2(s,0,bipolar_lowgain);
+       DPRINT(0,"bipolar zero offset, low gain [%g,%g]: %s\n",
+               range->min,range->max,s);
+
+       /* 0 offset, high gain */
+       range = comedi_get_range(dev,ad_subdev,0,bipolar_highgain);
+       read_chan2(s,0,bipolar_highgain);
+       DPRINT(0,"bipolar zero offset, high gain [%g,%g]: %s\n",
+               range->min,range->max,s);
+
+       /* unip/bip offset */
+       range = comedi_get_range(dev,ad_subdev,0,unipolar_lowgain);
+       read_chan2(s,0,unipolar_lowgain);
+       DPRINT(0,"unipolar zero offset, low gain [%g,%g]: %s\n",
+               range->min,range->max,s);
+
+}
+
+#if 0
+void ni_mio_ai_postgain_cal(void)
+{
+       linear_fit_t l;
+       double offset_r0;
+       double offset_r7;
+       double gain;
+       double a;
+
+       check_gain_chan_x(&l,CR_PACK(0,0,AREF_OTHER),1);
+       offset_r0=linear_fit_func_y(&l,caldacs[1].current);
+       printf("offset r0 %g\n",offset_r0);
+
+       check_gain_chan_x(&l,CR_PACK(0,7,AREF_OTHER),1);
+       offset_r7=linear_fit_func_y(&l,caldacs[1].current);
+       printf("offset r7 %g\n",offset_r7);
+
+       gain=l.slope;
+       
+       a=(offset_r0-offset_r7)/(200.0-1.0);
+       a=caldacs[1].current-a/gain;
+
+       printf("%g\n",a);
+
+       caldacs[1].current=rint(a);
+       update_caldac(1);
+}
+
+void ni_mio_ai_postgain_cal_2(int chan,int dac,int range_lo,int range_hi,double gain)
+{
+       double offset_lo,offset_hi;
+       linear_fit_t l;
+       double slope;
+       double a;
+
+       check_gain_chan_x(&l,CR_PACK(chan,range_lo,AREF_OTHER),dac);
+       offset_lo=linear_fit_func_y(&l,caldacs[dac].current);
+       printf("offset lo %g\n",offset_lo);
+
+       check_gain_chan_x(&l,CR_PACK(chan,range_hi,AREF_OTHER),dac);
+       offset_hi=linear_fit_func_y(&l,caldacs[dac].current);
+       printf("offset hi %g\n",offset_hi);
+
+       slope=l.slope;
+       
+       a=(offset_lo-offset_hi)/(gain-1.0);
+       a=caldacs[dac].current-a/slope;
+
+       printf("%g\n",a);
+
+       caldacs[dac].current=rint(a);
+       update_caldac(dac);
+}
+#endif
+