doc/reference.xml: Added CR_PACK_FLAGS()
[comedilib.git] / demo / cmd.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  *
7  * This file may be freely modified, distributed, and combined with
8  * other software, as long as proper attribution is given in the
9  * source code.
10  */
11
12 /*
13  * An example for directly using Comedi commands.  Comedi commands
14  * are used for asynchronous acquisition, with the timing controlled
15  * by on-board timers or external events.
16  */
17
18 #include <stdio.h>
19 #include <comedilib.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <sys/time.h>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include "examples.h"
27
28 #define BUFSZ 10000
29 char buf[BUFSZ];
30
31 #define N_CHANS 256
32 static unsigned int chanlist[N_CHANS];
33 static comedi_range * range_info[N_CHANS];
34 static lsampl_t maxdata[N_CHANS];
35
36
37 int prepare_cmd_lib(comedi_t *dev, int subdevice, int n_scan, int n_chan, unsigned period_nanosec, comedi_cmd *cmd);
38
39 void do_cmd(comedi_t *dev,comedi_cmd *cmd);
40
41 void print_datum(lsampl_t raw, int channel_index, short physical);
42
43 char *cmdtest_messages[]={
44         "success",
45         "invalid source",
46         "source conflict",
47         "invalid argument",
48         "argument conflict",
49         "invalid chanlist",
50 };
51
52 int main(int argc, char *argv[])
53 {
54         comedi_t *dev;
55         comedi_cmd c,*cmd=&c;
56         int ret;
57         int total=0;
58         int i;
59         struct timeval start,end;
60         int subdev_flags;
61         lsampl_t raw;
62         struct parsed_options options;
63
64         init_parsed_options(&options);
65         parse_options(&options, argc, argv);
66
67         /* The following variables used in this demo
68          * can be modified by command line
69          * options.  When modifying this demo, you may want to
70          * change them here. */
71         //options.filename = "/dev/comedi0";
72         //options.subdevice = 0;
73         //options.channel = 0;
74         //options.range = 0;
75         //options.aref = AREF_GROUND;
76         //options.n_chan = 4;
77         //options.n_scan = 1000;
78         //options.freq = 1000.0;
79
80         /* open the device */
81         dev = comedi_open(options.filename);
82         if(!dev){
83                 comedi_perror(options.filename);
84                 exit(1);
85         }
86
87         // Print numbers for clipped inputs
88         comedi_set_global_oor_behavior(COMEDI_OOR_NUMBER);
89
90         /* Set up channel list */
91         for(i = 0; i < options.n_chan; i++){
92                 chanlist[i] = CR_PACK(options.channel + i, options.range, options.aref);
93                 range_info[i] = comedi_get_range(dev, options.subdevice, options.channel, options.range);
94                 maxdata[i] = comedi_get_maxdata(dev, options.subdevice, options.channel);
95         }
96
97         /* prepare_cmd_lib() uses a Comedilib routine to find a
98          * good command for the device.  prepare_cmd() explicitly
99          * creates a command, which may not work for your device. */
100         prepare_cmd_lib(dev, options.subdevice, options.n_scan, options.n_chan, 1e9 / options.freq, cmd);
101         //prepare_cmd(dev, options.subdevice, options.n_scan, options.n_chan, 1e9 / options.freq, cmd);
102
103         fprintf(stderr, "command before testing:\n");
104         dump_cmd(stderr, cmd);
105
106         /* comedi_command_test() tests a command to see if the
107          * trigger sources and arguments are valid for the subdevice.
108          * If a trigger source is invalid, it will be logically ANDed
109          * with valid values (trigger sources are actually bitmasks),
110          * which may or may not result in a valid trigger source.
111          * If an argument is invalid, it will be adjusted to the
112          * nearest valid value.  In this way, for many commands, you
113          * can test it multiple times until it passes.  Typically,
114          * if you can't get a valid command in two tests, the original
115          * command wasn't specified very well. */
116         ret = comedi_command_test(dev, cmd);
117         if(ret < 0){
118                 comedi_perror("comedi_command_test");
119                 if(errno == EIO){
120                         fprintf(stderr,"Ummm... this subdevice doesn't support commands\n");
121                 }
122                 exit(1);
123         }
124         fprintf(stderr,"first test returned %d (%s)\n", ret,
125                         cmdtest_messages[ret]);
126         dump_cmd(stderr, cmd);
127
128         ret = comedi_command_test(dev, cmd);
129         if(ret < 0){
130                 comedi_perror("comedi_command_test");
131                 exit(1);
132         }
133         fprintf(stderr,"second test returned %d (%s)\n", ret,
134                         cmdtest_messages[ret]);
135         if(ret!=0){
136                 dump_cmd(stderr, cmd);
137                 fprintf(stderr, "Error preparing command\n");
138                 exit(1);
139         }
140
141         /* this is only for informational purposes */
142         gettimeofday(&start, NULL);
143         fprintf(stderr,"start time: %ld.%06ld\n", start.tv_sec, start.tv_usec);
144
145         /* start the command */
146         ret = comedi_command(dev, cmd);
147         if(ret < 0){
148                 comedi_perror("comedi_command");
149                 exit(1);
150         }
151         subdev_flags = comedi_get_subdevice_flags(dev, options.subdevice);
152         while(1){
153                 ret = read(comedi_fileno(dev),buf,BUFSZ);
154                 if(ret < 0){
155                         /* some error occurred */
156                         perror("read");
157                         break;
158                 }else if(ret == 0){
159                         /* reached stop condition */
160                         break;
161                 }else{
162                         static int col = 0;
163                         int bytes_per_sample;
164                         total += ret;
165                         if(options.verbose)fprintf(stderr, "read %d %d\n", ret, total);
166                         if(subdev_flags & SDF_LSAMPL)
167                                 bytes_per_sample = sizeof(lsampl_t);
168                         else
169                                 bytes_per_sample = sizeof(sampl_t);
170                         for(i = 0; i < ret / bytes_per_sample; i++){
171                                 if(subdev_flags & SDF_LSAMPL) {
172                                         raw = ((lsampl_t *)buf)[i];
173                                 } else {
174                                         raw = ((sampl_t *)buf)[i];
175                                 }
176                                 print_datum(raw, col, options.physical);
177                                 col++;
178                                 if(col == options.n_chan){
179                                         printf("\n");
180                                         col=0;
181                                 }
182                         }
183                 }
184         }
185
186         /* this is only for informational purposes */
187         gettimeofday(&end,NULL);
188         fprintf(stderr,"end time: %ld.%06ld\n", end.tv_sec, end.tv_usec);
189
190         end.tv_sec -= start.tv_sec;
191         if(end.tv_usec < start.tv_usec){
192                 end.tv_sec--;
193                 end.tv_usec += 1000000;
194         }
195         end.tv_usec -= start.tv_usec;
196         fprintf(stderr,"time: %ld.%06ld\n", end.tv_sec, end.tv_usec);
197
198         return 0;
199 }
200
201 /*
202  * This prepares a command in a pretty generic way.  We ask the
203  * library to create a stock command that supports periodic
204  * sampling of data, then modify the parts we want. */
205 int prepare_cmd_lib(comedi_t *dev, int subdevice, int n_scan, int n_chan, unsigned scan_period_nanosec, comedi_cmd *cmd)
206 {
207         int ret;
208
209         memset(cmd,0,sizeof(*cmd));
210
211         /* This comedilib function will get us a generic timed
212          * command for a particular board.  If it returns -1,
213          * that's bad. */
214         ret = comedi_get_cmd_generic_timed(dev, subdevice, cmd, n_chan, scan_period_nanosec);
215         if(ret<0){
216                 printf("comedi_get_cmd_generic_timed failed\n");
217                 return ret;
218         }
219
220         /* Modify parts of the command */
221         cmd->chanlist = chanlist;
222         cmd->chanlist_len = n_chan;
223         if(cmd->stop_src == TRIG_COUNT) cmd->stop_arg = n_scan;
224
225         return 0;
226 }
227
228 /*
229  * Set up a command by hand.  This will not work on some devices.
230  * There is no single command that will work on all devices.
231  */
232 int prepare_cmd(comedi_t *dev, int subdevice, int n_scan, int n_chan, unsigned period_nanosec, comedi_cmd *cmd)
233 {
234         memset(cmd,0,sizeof(*cmd));
235
236         /* the subdevice that the command is sent to */
237         cmd->subdev =   subdevice;
238
239         /* flags */
240         cmd->flags = 0;
241
242         /* Wake up at the end of every scan */
243         //cmd->flags |= TRIG_WAKE_EOS;
244
245         /* Use a real-time interrupt, if available */
246         //cmd->flags |= TRIG_RT;
247
248         /* each event requires a trigger, which is specified
249            by a source and an argument.  For example, to specify
250            an external digital line 3 as a source, you would use
251            src=TRIG_EXT and arg=3. */
252
253         /* The start of acquisition is controlled by start_src.
254          * TRIG_NOW:     The start_src event occurs start_arg nanoseconds
255          *               after comedi_command() is called.  Currently,
256          *               only start_arg=0 is supported.
257          * TRIG_FOLLOW:  (For an output device.)  The start_src event occurs
258          *               when data is written to the buffer.
259          * TRIG_EXT:     start event occurs when an external trigger
260          *               signal occurs, e.g., a rising edge of a digital
261          *               line.  start_arg chooses the particular digital
262          *               line.
263          * TRIG_INT:     start event occurs on a Comedi internal signal,
264          *               which is typically caused by an INSN_TRIG
265          *               instruction.
266          */
267         cmd->start_src =        TRIG_NOW;
268         cmd->start_arg =        0;
269
270         /* The timing of the beginning of each scan is controlled by
271          * scan_begin.
272          * TRIG_TIMER:   scan_begin events occur periodically.
273          *               The time between scan_begin events is
274          *               convert_arg nanoseconds.
275          * TRIG_EXT:     scan_begin events occur when an external trigger
276          *               signal occurs, e.g., a rising edge of a digital
277          *               line.  scan_begin_arg chooses the particular digital
278          *               line.
279          * TRIG_FOLLOW:  scan_begin events occur immediately after a scan_end
280          *               event occurs.
281          * The scan_begin_arg that we use here may not be supported exactly
282          * by the device, but it will be adjusted to the nearest supported
283          * value by comedi_command_test(). */
284         cmd->scan_begin_src =   TRIG_TIMER;
285         cmd->scan_begin_arg = period_nanosec;           /* in ns */
286
287         /* The timing between each sample in a scan is controlled by convert.
288          * TRIG_TIMER:   Conversion events occur periodically.
289          *               The time between convert events is
290          *               convert_arg nanoseconds.
291          * TRIG_EXT:     Conversion events occur when an external trigger
292          *               signal occurs, e.g., a rising edge of a digital
293          *               line.  convert_arg chooses the particular digital
294          *               line.
295          * TRIG_NOW:     All conversion events in a scan occur simultaneously.
296          * Even though it is invalid, we specify 1 ns here.  It will be
297          * adjusted later to a valid value by comedi_command_test() */
298         cmd->convert_src =      TRIG_TIMER;
299         cmd->convert_arg =      1;              /* in ns */
300
301         /* The end of each scan is almost always specified using
302          * TRIG_COUNT, with the argument being the same as the
303          * number of channels in the chanlist.  You could probably
304          * find a device that allows something else, but it would
305          * be strange. */
306         cmd->scan_end_src =     TRIG_COUNT;
307         cmd->scan_end_arg =     n_chan;         /* number of channels */
308
309         /* The end of acquisition is controlled by stop_src and
310          * stop_arg.
311          * TRIG_COUNT:  stop acquisition after stop_arg scans.
312          * TRIG_NONE:   continuous acquisition, until stopped using
313          *              comedi_cancel()
314          * */
315         cmd->stop_src =         TRIG_COUNT;
316         cmd->stop_arg =         n_scan;
317
318         /* the channel list determined which channels are sampled.
319            In general, chanlist_len is the same as scan_end_arg.  Most
320            boards require this.  */
321         cmd->chanlist =         chanlist;
322         cmd->chanlist_len =     n_chan;
323
324         return 0;
325 }
326
327 void print_datum(lsampl_t raw, int channel_index, short physical) {
328         double physical_value;
329         if(!physical) {
330                 printf("%d ",raw);
331         } else {
332                 physical_value = comedi_to_phys(raw, range_info[channel_index], maxdata[channel_index]);
333                 printf("%#8.6g ",physical_value);
334         }
335 }