demo/tut3.c: memset options to 0 before modifying
[comedilib.git] / demo / tut3.c
1 /*
2  * Example of using commands - asynchronous input
3  * Part of Comedilib
4  *
5  * Copyright (c) 1999,2000,2001 David A. Schleef <ds@schleef.org>
6  *               2008 Bernd Porr <berndporr@f2s.com>
7  *
8  * This file may be freely modified, distributed, and combined with
9  * other software, as long as proper attribution is given in the
10  * source code.
11  */
12
13 /*
14  * The program is used to test the usbdux sigma board
15  */
16
17 #include <stdio.h>
18 #include <comedilib.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <sys/time.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 extern comedi_t *device;
27
28 struct parsed_options
29 {
30         char *filename;
31         double value;
32         int subdevice;
33         int channel;
34         int aref;
35         int range;
36         int verbose;
37         int n_chan;
38         int n_scan;
39         double freq;
40 };
41
42
43
44 #define BUFSZ 10000
45 char buf[BUFSZ];
46
47 #define N_CHANS 256
48 static unsigned int chanlist[N_CHANS];
49 static comedi_range * range_info[N_CHANS];
50 static lsampl_t maxdata[N_CHANS];
51
52
53 int prepare_cmd_lib(comedi_t *dev, int subdevice, int n_scan, int n_chan, unsigned period_nanosec, comedi_cmd *cmd);
54
55 void do_cmd(comedi_t *dev,comedi_cmd *cmd);
56
57 void print_datum(lsampl_t raw, int channel_index);
58
59 char *cmdtest_messages[]={
60         "success",
61         "invalid source",
62         "source conflict",
63         "invalid argument",
64         "argument conflict",
65         "invalid chanlist",
66 };
67
68 int main(int argc, char *argv[])
69 {
70         comedi_t *dev;
71         comedi_cmd c,*cmd=&c;
72         int ret;
73         int total=0;
74         int i;
75         int subdev_flags;
76         lsampl_t raw;
77
78         struct parsed_options options;
79
80         memset(&options, 0, sizeof(options));
81         /* The following variables used in this demo
82          * can be modified by command line
83          * options.  When modifying this demo, you may want to
84          * change them here. */
85         options.filename = "/dev/comedi0";
86         options.subdevice = 0;
87         options.channel = 0;
88         options.range = 0;
89         options.aref = AREF_GROUND;
90         options.n_chan = 2;
91         options.n_scan = 10000;
92         options.freq = 1000.0;
93
94         /* open the device */
95         dev = comedi_open(options.filename);
96         if(!dev){
97                 comedi_perror(options.filename);
98                 exit(1);
99         }
100
101         // Print numbers for clipped inputs
102         comedi_set_global_oor_behavior(COMEDI_OOR_NUMBER);
103
104         /* Set up channel list */
105         for(i = 0; i < options.n_chan; i++){
106                 chanlist[i] = CR_PACK(options.channel + i, options.range, options.aref);
107                 range_info[i] = comedi_get_range(dev, options.subdevice, options.channel, options.range);
108                 maxdata[i] = comedi_get_maxdata(dev, options.subdevice, options.channel);
109         }
110
111         /* prepare_cmd_lib() uses a Comedilib routine to find a
112          * good command for the device.  prepare_cmd() explicitly
113          * creates a command, which may not work for your device. */
114         prepare_cmd_lib(dev, options.subdevice, options.n_scan, options.n_chan, 1e9 / options.freq, cmd);
115
116         /* comedi_command_test() tests a command to see if the
117          * trigger sources and arguments are valid for the subdevice.
118          * If a trigger source is invalid, it will be logically ANDed
119          * with valid values (trigger sources are actually bitmasks),
120          * which may or may not result in a valid trigger source.
121          * If an argument is invalid, it will be adjusted to the
122          * nearest valid value.  In this way, for many commands, you
123          * can test it multiple times until it passes.  Typically,
124          * if you can't get a valid command in two tests, the original
125          * command wasn't specified very well. */
126         ret = comedi_command_test(dev, cmd);
127         if(ret < 0){
128                 comedi_perror("comedi_command_test");
129                 if(errno == EIO){
130                         fprintf(stderr,"Ummm... this subdevice doesn't support commands\n");
131                 }
132                 exit(1);
133         }
134         ret = comedi_command_test(dev, cmd);
135         if(ret < 0){
136                 comedi_perror("comedi_command_test");
137                 exit(1);
138         }
139         fprintf(stderr,"second test returned %d (%s)\n", ret,
140                         cmdtest_messages[ret]);
141         if(ret!=0){
142                 fprintf(stderr, "Error preparing command\n");
143                 exit(1);
144         }
145
146         /* start the command */
147         ret = comedi_command(dev, cmd);
148         if(ret < 0){
149                 comedi_perror("comedi_command");
150                 exit(1);
151         }
152         subdev_flags = comedi_get_subdevice_flags(dev, options.subdevice);
153         while(1){
154                 ret = read(comedi_fileno(dev),buf,BUFSZ);
155                 if(ret < 0){
156                         /* some error occurred */
157                         perror("read");
158                         break;
159                 }else if(ret == 0){
160                         /* reached stop condition */
161                         break;
162                 }else{
163                         static int col = 0;
164                         int bytes_per_sample;
165                         total += ret;
166                         if(options.verbose)fprintf(stderr, "read %d %d\n", ret, total);
167                         if(subdev_flags & SDF_LSAMPL)
168                                 bytes_per_sample = sizeof(lsampl_t);
169                         else
170                                 bytes_per_sample = sizeof(sampl_t);
171                         for(i = 0; i < ret / bytes_per_sample; i++){
172                                 if(subdev_flags & SDF_LSAMPL) {
173                                         raw = ((lsampl_t *)buf)[i];
174                                 } else {
175                                         raw = ((sampl_t *)buf)[i];
176                                 }
177                                 print_datum(raw, col);
178                                 col++;
179                                 if(col == options.n_chan){
180                                         printf("\n");
181                                         col=0;
182                                 }
183                         }
184                 }
185         }
186
187 }
188
189 /*
190  * This prepares a command in a pretty generic way.  We ask the
191  * library to create a stock command that supports periodic
192  * sampling of data, then modify the parts we want. */
193 int prepare_cmd_lib(comedi_t *dev, int subdevice, int n_scan, int n_chan, unsigned scan_period_nanosec, comedi_cmd *cmd)
194 {
195         int ret;
196
197         memset(cmd,0,sizeof(*cmd));
198
199         /* This comedilib function will get us a generic timed
200          * command for a particular board.  If it returns -1,
201          * that's bad. */
202         ret = comedi_get_cmd_generic_timed(dev, subdevice, cmd, n_chan, scan_period_nanosec);
203         if(ret<0){
204                 printf("comedi_get_cmd_generic_timed failed\n");
205                 return ret;
206         }
207
208         /* Modify parts of the command */
209         cmd->chanlist = chanlist;
210         cmd->chanlist_len = n_chan;
211         if(cmd->stop_src == TRIG_COUNT) cmd->stop_arg = n_scan;
212
213         return 0;
214 }
215
216 void print_datum(lsampl_t raw, int channel_index) {
217         double physical_value;
218         physical_value = comedi_to_phys(raw, range_info[channel_index], maxdata[channel_index]);
219         printf("%#8.6g ",physical_value);
220 }