diff --git a/demo/cmd.c b/demo/cmd.c index 58b4b0f..3bb922c 100644 --- a/demo/cmd.c +++ b/demo/cmd.c @@ -2,7 +2,7 @@ * Example of using commands - asynchronous input * Part of Comedilib * - * Copyright (c) 1999,2000 David A. Schleef + * Copyright (c) 1999,2000,2001 David A. Schleef * * This file may be freely modified, distributed, and combined with * other software, as long as proper attribution is given in the @@ -19,119 +19,135 @@ #include #include #include +#include #include -#include -#include -#include #include "examples.h" -#define N_SCANS 10 -#define N_CHANS 16 - -int n_chan = 4; -double freq = 1000; - #define BUFSZ 10000 char buf[BUFSZ]; +#define N_CHANS 256 unsigned int chanlist[N_CHANS]; -void prepare_cmd_1(comedi_t *dev,comedi_cmd *cmd); -void prepare_cmd_2(comedi_t *dev,comedi_cmd *cmd); + +int prepare_cmd_lib(comedi_t *dev,int subdevice,comedi_cmd *cmd); +int prepare_cmd(comedi_t *dev,int subdevice,comedi_cmd *cmd); void do_cmd(comedi_t *dev,comedi_cmd *cmd); -void dump_cmd(comedi_cmd *cmd); + +char *cmdtest_messages[]={ + "success", + "invalid source", + "source conflict", + "invalid argument", + "argument conflict", + "invalid chanlist", +}; int main(int argc, char *argv[]) { comedi_t *dev; - comedi_cmd cmd; + comedi_cmd c,*cmd=&c; + int ret; + int total=0; + int i; + struct timeval start,end; parse_options(argc,argv); + /* The following global variables used in this demo are + * defined in main.c, and can be modified by command line + * options. When modifying this demo, you may want to + * change them here. */ + //filename = "/dev/comedi0"; + //subdevice = 0; + //channel = 0; + //range = 0; + //aref = AREF_GROUND; + //n_chan = 4; + //n_scan = 1000; + //freq = 1000.0; + + /* open the device */ dev = comedi_open(filename); if(!dev){ - perror(filename); + comedi_perror(filename); exit(1); } - fcntl(comedi_fileno(dev),F_SETFL,O_NONBLOCK); - - prepare_cmd_1(dev,&cmd); - - do_cmd(dev,&cmd); - - return 0; -} - -void do_cmd(comedi_t *dev,comedi_cmd *cmd) -{ - unsigned int *chanlist; - int n_chans; - int total=0; - int ret; - int go; - - chanlist = cmd->chanlist; - n_chans = cmd->chanlist_len; - - ret=comedi_command_test(dev,cmd); - - printf("test ret=%d\n",ret); - if(ret<0){ - printf("errno=%d\n",errno); - comedi_perror("comedi_command_test"); - return; + /* Set up channel list */ + for(i=0;ichanlist = chanlist; - cmd->chanlist_len = n_chans; -#endif - - ret=comedi_command_test(dev,cmd); - - printf("test ret=%d\n",ret); + /* comedi_command_test() tests a command to see if the + * trigger sources and arguments are valid for the subdevice. + * If a trigger source is invalid, it will be logically ANDed + * with valid values (trigger sources are actually bitmasks), + * which may or may not result in a valid trigger source. + * If an argument is invalid, it will be adjusted to the + * nearest valid value. In this way, for many commands, you + * can test it multiple times until it passes. Typically, + * if you can't get a valid command in two tests, the original + * command wasn't specified very well. */ + ret = comedi_command_test(dev,cmd); if(ret<0){ - printf("errno=%d\n",errno); comedi_perror("comedi_command_test"); - return; + if(errno==EIO){ + fprintf(stderr,"Ummm... this subdevice doesn't support commands\n"); + } + exit(1); + } + fprintf(stderr,"first test returned %d (%s)\n",ret, + cmdtest_messages[ret]); + dump_cmd(stderr,cmd); + + ret = comedi_command_test(dev,cmd); + if(ret<0){ + comedi_perror("comedi_command_test"); + exit(1); + } + fprintf(stderr,"second test returned %d (%s)\n",ret, + cmdtest_messages[ret]); + if(ret!=0){ + dump_cmd(stderr,cmd); + fprintf(stderr,"Error preparing command\n"); + exit(1); } - dump_cmd(cmd); - + /* start the command */ ret=comedi_command(dev,cmd); - - printf("ret=%d\n",ret); if(ret<0){ - printf("errno=%d\n",errno); comedi_perror("comedi_command"); - return; + exit(1); } - go=1; - while(go){ + /* this is only for informational purposes */ + gettimeofday(&start,NULL); + fprintf(stderr,"start time: %ld.%06ld\n",start.tv_sec,start.tv_usec); + + while(1){ ret=read(comedi_fileno(dev),buf,BUFSZ); if(ret<0){ - if(errno==EAGAIN){ - usleep(10000); - }else{ - go = 0; - perror("read"); - } + /* some error occurred */ + perror("read"); + break; }else if(ret==0){ - go = 0; + /* reached stop condition */ + break; }else{ static int col = 0; - int i; total+=ret; - //printf("read %d %d\n",ret,total); -#if 1 + if(verbose)fprintf(stderr,"read %d %d\n",ret,total); for(i=0;ichanlist = chanlist; + cmd->chanlist_len = n_chan; + + cmd->scan_end_arg = n_chan; + if(cmd->stop_src==TRIG_COUNT)cmd->stop_arg = n_scan; + + return 0; +} + +/* + * Set up a command by hand. This will not work on some devices. + * There is no single command that will work on all devices. */ -void prepare_cmd_1(comedi_t *dev,comedi_cmd *cmd) +int prepare_cmd(comedi_t *dev,int subdevice,comedi_cmd *cmd) { memset(cmd,0,sizeof(cmd)); @@ -159,36 +210,66 @@ void prepare_cmd_1(comedi_t *dev,comedi_cmd *cmd) cmd->subdev = subdevice; /* flags */ - cmd->flags = TRIG_WAKE_EOS; - //cmd.flags = 0; + cmd->flags = 0; + + /* Wake up at the end of every scan */ + //cmd->flags |= TRIG_WAKE_EOS; + + /* Use a real-time interrupt, if available */ + //cmd->flags |= TRIG_RT; /* each event requires a trigger, which is specified by a source and an argument. For example, to specify an external digital line 3 as a source, you would use src=TRIG_EXT and arg=3. */ - /* In this case, we specify using TRIG_NOW to start - * acquisition immediately when the command is issued. - * The argument of TRIG_NOW is "number of nsec after - * NOW", but no driver supports it yet. Also, no driver - * currently supports using a start_src other than - * TRIG_NOW. */ - cmd->start_src = TRIG_NOW; - cmd->start_arg = 0; + /* The start of acquisition is controlled by start_src. + * TRIG_NOW: The start_src event occurs start_arg nanoseconds + * after comedi_command() is called. Currently, + * only start_arg=0 is supported. + * TRIG_FOLLOW: (For an output device.) The start_src event occurs + * when data is written to the buffer. + * TRIG_EXT: start event occurs when an external trigger + * signal occurs, e.g., a rising edge of a digital + * line. start_arg chooses the particular digital + * line. + * TRIG_INT: start event occurs on a Comedi internal signal, + * which is typically caused by an INSN_TRIG + * instruction. + */ + cmd->start_src = TRIG_NOW; + cmd->start_arg = 0; - /* The timing of the beginning of each scan is controlled - * by scan_begin. TRIG_TIMER specifies that scan_start - * events occur periodically at a rate of scan_begin_arg - * nanoseconds between scans. */ + /* The timing of the beginning of each scan is controlled by + * scan_begin. + * TRIG_TIMER: scan_begin events occur periodically. + * The time between scan_begin events is + * convert_arg nanoseconds. + * TRIG_EXT: scan_begin events occur when an external trigger + * signal occurs, e.g., a rising edge of a digital + * line. scan_begin_arg chooses the particular digital + * line. + * TRIG_FOLLOW: scan_begin events occur immediately after a scan_end + * event occurs. + * The scan_begin_arg that we use here may not be supported exactly + * by the device, but it will be adjusted to the nearest supported + * value by comedi_command_test(). */ cmd->scan_begin_src = TRIG_TIMER; - cmd->scan_begin_arg = 10000000; + cmd->scan_begin_arg = 1e9/freq; /* in ns */ - /* The timing between each sample in a scan is controlled - * by convert. Like above, TRIG_TIMER specifies that - * convert events occur periodically at a rate of convert_arg - * nanoseconds between scans. */ + /* The timing between each sample in a scan is controlled by convert. + * TRIG_TIMER: Conversion events occur periodically. + * The time between convert events is + * convert_arg nanoseconds. + * TRIG_EXT: Conversion events occur when an external trigger + * signal occurs, e.g., a rising edge of a digital + * line. convert_arg chooses the particular digital + * line. + * TRIG_NOW: All conversion events in a scan occur simultaneously. + * Even though it is invalid, we specify 1 ns here. It will be + * adjusted later to a valid value by comedi_command_test() */ cmd->convert_src = TRIG_TIMER; - cmd->convert_arg = 10000; /* in ns */ + cmd->convert_arg = 1; /* in ns */ /* The end of each scan is almost always specified using * TRIG_COUNT, with the argument being the same as the @@ -199,13 +280,13 @@ void prepare_cmd_1(comedi_t *dev,comedi_cmd *cmd) cmd->scan_end_arg = n_chan; /* number of channels */ /* The end of acquisition is controlled by stop_src and - * stop_arg. The src will typically be TRIG_COUNT or - * TRIG_NONE. Specifying TRIG_COUNT will stop acquisition - * after stop_arg number of scans, or TRIG_NONE will - * cause acquisition to continue until stopped using - * comedi_cancel(). */ + * stop_arg. + * TRIG_COUNT: stop acquisition after stop_arg scans. + * TRIG_NONE: continuous acquisition, until stopped using + * comedi_cancel() + * */ cmd->stop_src = TRIG_COUNT; - cmd->stop_arg = 10000; + cmd->stop_arg = n_scan; /* the channel list determined which channels are sampled. In general, chanlist_len is the same as scan_end_arg. Most @@ -213,44 +294,7 @@ void prepare_cmd_1(comedi_t *dev,comedi_cmd *cmd) cmd->chanlist = chanlist; cmd->chanlist_len = n_chan; - chanlist[0]=CR_PACK(channel+0,range,aref); - chanlist[1]=CR_PACK(channel+1,range,aref); - chanlist[2]=CR_PACK(channel+2,range,aref); - chanlist[3]=CR_PACK(channel+3,range,aref); + return 0; } -/* - */ -void prepare_cmd_2(comedi_t *dev,comedi_cmd *cmd) -{ - memset(cmd,0,sizeof(cmd)); - - cmd->subdev = subdevice; - - //cmd->flags = TRIG_RT|TRIG_WAKE_EOS; - cmd->flags = 0; - - cmd->start_src = TRIG_NOW; - cmd->start_arg = 0; - - cmd->scan_begin_src = TRIG_TIMER; - cmd->scan_begin_arg = 1; - - cmd->convert_src = TRIG_TIMER; - cmd->convert_arg = 1000000; - - cmd->scan_end_src = TRIG_COUNT; - cmd->scan_end_arg = n_chan; - - cmd->stop_src = TRIG_NONE; - cmd->stop_arg = 0; - - cmd->chanlist = chanlist; - cmd->chanlist_len = n_chan; - - chanlist[0]=CR_PACK(channel+0,range,aref); - chanlist[1]=CR_PACK(channel+1,range,aref); - chanlist[2]=CR_PACK(channel+2,range,aref); - chanlist[3]=CR_PACK(channel+3,range,aref); -}