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