1 <!-- <!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V3.1//EN" "docbook/dtd/3.1/docbook.dtd"> -->
3 <section id="writingprograms">
5 Writing &comedi; programs
8 This Section describes how a well-installed and configured &comedi;
9 package can be used in an application, to communicate data with a set
11 <xref linkend="acquisitionfunctions"> gives more details about
12 the various acquisition functions with which the application
13 programmer can perform data acquisition in &comedi;.
16 Also don't forget to take a good look at the
17 <filename class=directory>demo</filename>
18 directory of the Comedilib source code. It contains lots of examples
19 for the basic functionalities of &comedi;.
22 <section id="firstprogram">
24 Your first &comedi; program
28 This example requires a card that has analog or digital input. This
29 progam opens the device, gets the data, and prints it out:
31 #include <![CDATA[<stdio.h>]]> /* for printf() */
32 #include <![CDATA[<]]><link linkend="comedi-comedilib-h">comedilib.h</link><![CDATA[>]]>
34 int subdev = 0; /* change this to your input subdevice */
35 int chan = 0; /* change this to your channel */
36 int range = 0; /* more on this later */
37 int aref = <link linkend="aref-ground">AREF_GROUND</link>; /* more on this later */
39 int main(int argc,char *argv[])
41 <link linkend="ref-type-comedi-t">comedi_t</link> *it;
42 <link linkend="ref-type-lsampl-t">lsampl_t</link> data;
44 it=<link linkend="func-ref-comedi-open">comedi_open</link>("/dev/comedi0");
46 <link linkend="func-ref-comedi-data-read">comedi_data_read</link>(it,subdev,chan,range,aref, & data);
55 <link linkend="func-ref-comedi-open">comedi_open()</link>
56 </function> can only be successful if the
57 <filename>comedi0</filename> device file is configured to point to a
58 valid &comedi; driver. <xref linkend="cardconfiguration"> explains
59 how this driver is linked to the <quote>device file</quote>.
61 The code above is basically the guts of
62 <filename>demo/inp.c</filename>, without error checking or fancy
63 options. Compile the program using
67 cc tut1.c -lcomedi -o tut1
70 (Replace <literal>cc</literal> by your favourite C compiler command.)
74 The <parameter class=function>range</parameter> variable tells
75 &comedi; which gain to use when measuring an analog voltage. Since we
76 don't know (yet) which numbers are valid, or what each means, we'll
77 use <literal>0</literal>, because it won't cause errors. Likewise
78 with <parameter class=function>aref</parameter>, which determines the
79 analog reference used.
84 <section id="convertingsamples">
86 Converting samples to voltages
90 If you selected an analog input subdevice, you probably noticed
91 that the output of <command>tut1</command> is a number between
92 <literal>0</literal> and <literal>4095</literal>, or
93 <literal>0</literal> and <literal>65535</literal>, depending on the
94 number of bits in the A/D converter. &comedi; samples are
95 <emphasis>always</emphasis> unsigned,
96 with <literal>0</literal> representing the lowest voltage of the ADC,
97 and <literal>4095</literal>
98 the highest. &comedi; compensates for anything else the manual for
99 your device says. However, you probably prefer to have this number
100 translated to a voltage. Naturally, as a good programmer, your first
101 question is: <quote>How do I do this in a device-independent
106 Most devices give you a choice of gain and unipolar/bipolar
107 input, and &comedi; allows you to select which of these to use. This
108 parameter is called the <quote>range parameter,</quote> since it
109 specifies the <quote>input range</quote> for analog input (or
110 <quote>output range</quote> for analog output.) The range parameter
111 represents both the gain and the unipolar/bipolar aspects.
115 &comedi; keeps the number of available ranges and the largest
116 sample value for each subdevice/channel combination. (Some
117 devices allow different input/output ranges for different
118 channels in a subdevice.)
122 The largest sample value can be found using the function
124 <link linkend="ref-type-lsampl-t">lsampl_t</link> <link linkend="func-ref-comedi-get-maxdata">comedi_get_maxdata</link>(<link linkend="ref-type-comedi-t">comedi_t</link> * device, unsigned int subdevice, unsigned int channel))
126 The number of available ranges can be found using the function:
128 int <link linkend="func-ref-comedi-get-n-ranges">comedi_get_n_ranges</link>(<link linkend="ref-type-comedi-t">comedi_t</link> * device, unsigned int subdevice, unsigned int channel);
133 For each value of the range parameter for a particular
134 subdevice/channel, you can get range information using:
136 <link linkend="ref-type-comedi-range">comedi_range</link> * <link linkend="func-ref-comedi-get-range">comedi_get_range</link>(<link linkend="ref-type-comedi-t">comedi_t</link> * device,
137 unsigned int subdevice, unsigned int channel, unsigned int range);
139 which returns a pointer to a
140 <link linkend="ref-type-comedi-range">comedi_range</link>
141 structure, which has the following contents:
149 The structure element <parameter class=function>min</parameter>
150 represents the voltage corresponding to
151 <link linkend="func-ref-comedi-data-read">comedi_data_read()</link>
152 returning <literal>0</literal>,
153 and <parameter class=function>max</parameter> represents
154 <link linkend="func-ref-comedi-data-read">comedi_data_read()</link>
155 returning <parameter class=function>maxdata</parameter>,
156 (i.e., <literal>4095</literal> for <literal>12</literal> bit A/C
157 converters, <literal>65535</literal> for <literal>16</literal> bit,
158 or, <literal>1</literal> for digital input; more on this in a bit.)
159 The <parameter class=function>unit</parameter> entry tells you if
160 <parameter class=function>min</parameter> and
161 <parameter class=function>max</parameter> refer to voltage, current,
162 or are dimensionless (e.g., for digital I/O).
166 <quote>Could it get easier?</quote> you say. Well, yes. Use
167 the function <function>comedi_to_phys()</function>
168 <link linkend="func-ref-comedi-to-phys">comedi_to_phys()</link>, which
169 converts data values to physical units. Call it using something like
173 volts=<link linkend="func-ref-comedi-to-phys">comedi_to_phys</link>(it,data,range,maxdata);
181 data=<link linkend="func-ref-comedi-from-phys">comedi_from_phy</link>s(it,volts,range,maxdata);
186 <section id="usingfileinterface">
188 Using the file interface
193 In addition to providing low level routines for data
194 access, the &comedi; library provides higher-level access,
195 much like the standard <acronym>C</acronym> library provides
196 <function>fopen()</function>, etc. as a high-level (and portable)
197 alternative to the direct <acronym>UNIX</acronym> system calls
198 <function>open()</function>, etc. Similarily to
199 <function>fopen()</function>, we have
200 <link linkend="func-ref-comedi-open">comedi_open()</link>:
204 file=<link linkend="func-ref-comedi-open">comedi_open</link>("/dev/comedi0");
208 where <parameter class=function>file</parameter> is of type
209 <parameter>(<link linkend="ref-type-comedi-t">comedi_t</link> *)</parameter>.
210 This function calls <function>open()</function>, as done explicitly in
211 a previous section, but also fills the
212 <link linkend="ref-type-comedi-t">comedi_t</link>
213 structure with lots of goodies; this information will be useful soon.
217 Specifically, you need to know
218 <parameter class=function>maxdata</parameter> for a specific
219 subdevice/channel. How about:
222 maxdata=<link linkend="func-ref-comedi-get-maxdata">comedi_get_maxdata</link>(file,subdevice,channel);
225 Wow! How easy. And the range information?
228 <link linkend="ref-type-comedi-range">comedi_range</link> * <link linkend="func-ref-comedi-get-range">comedi_get_range(<link linkend="ref-type-comedi-t">comedi_t</link>comedi_t</link> *it,unsigned int subdevice,unsigned int chan,unsigned int range);
236 <section id="secondprogram">
238 Your second &comedi; program: simple acquisition
243 Actually, this is the first &comedi; program again, just
244 that we've added what we've learned.
249 #include <stdio.h> /* for printf() */
250 #include <![CDATA[<]]><link linkend="comedi-comedilib-h">comedilib.h</link><![CDATA[>]]>
252 int subdev = 0; /* change this to your input subdevice */
253 int chan = 0; /* change this to your channel */
254 int range = 0; /* more on this later */
255 int aref = 0; /* more on this later */
257 int main(int argc,char *argv[])
259 <link linkend="ref-type-comedi-t">comedi_t</link> *cf;
261 <link linkend="ref-type-lsampl-t">lsampl_t</link> data;
262 int maxdata,rangetype;
265 cf=<link linkend="func-ref-comedi-open">comedi_open</link>("/dev/comedi0");
267 maxdata=<link linkend="func-ref-comedi-get-maxdata">comedi_get_maxdata</link>(cf,subdev,chan);
269 rangetype=comedi_get_rangetype(cf,subdev,chan);
271 <link linkend="func-ref-comedi-data-read">comedi_data_read</link>(cf->fd,subdev,chan,range,aref,&data);
273 volts=<link linkend="func-ref-comedi-to-phys">comedi_to_phys</link>(data,rangetype,range,maxdata);
275 printf("%d %g\n",data,volts);
283 <section id="thirdprogram">
285 Your third &comedi; program: instructions
288 This program (taken from the set of demonstration examples that come
289 with &comedi;) shows how to use a somewhat more flexible acquisition
290 function, the so-called <link linkend="instructions">instruction</link>.
294 #include <]]><link linkend="comedi-comedilib-h">comedilib.h</link><![CDATA[>
298 #include <sys/time.h>
300 #include "examples.h"
304 * This example does 3 instructions in one system call. It does
305 * a gettimeofday() call, then reads N_SAMPLES samples from an
306 * analog input, and the another gettimeofday() call.
309 #define MAX_SAMPLES 128
311 <link linkend="ref-type-comedi-t">comedi_t</link> *device;
313 int main(int argc, char *argv[])
316 <link linkend="ref-type-comedi-insn">comedi_insn</link> insn[3];
317 <link linkend="ref-type-comedi-insnlist">comedi_insnlist</link> il;
318 struct timeval t1,t2;
319 <link linkend="ref-type-lsampl-t">lsampl_t</link> data[MAX_SAMPLES];
321 parse_options(argc,argv);
324 device=<link linkend="func-ref-comedi-open">comedi_open</link>(filename);
326 <link linkend="func-ref-comedi-perror">comedi_perror</link>(filename);
331 printf("measuring device=%s subdevice=%d channel=%d range=%d analog reference=%d\n",
332 filename,subdevice,channel,range,aref);
335 /* Set up a the "instruction list", which is just a pointer
336 * to the array of instructions and the number of instructions.
341 /* Instruction 0: perform a gettimeofday() */
342 insn[0].insn=<link linkend="insn-gtod">INSN_GTOD</link>;
344 insn[0].data=(void *)&t1;
346 /* Instruction 1: do 10 analog input reads */
347 insn[1].insn=<link linkend="insn-read">INSN_READ</link>;
350 insn[1].subdev=subdevice;
351 insn[1].chanspec=<link linkend="ref-macro-CR-PACK">CR_PACK</link>(channel,range,aref);
353 /* Instruction 2: perform a gettimeofday() */
354 insn[2].insn=<link linkend="insn-gtod">INSN_GTOD</link>;
356 insn[2].data=(void *)&t2;
358 ret=<link linkend="func-ref-comedi-do-insnlist">comedi_do_insnlist</link>(device,&il);
359 if(ret<![CDATA[<]]>0){
360 <link linkend="func-ref-comedi-perror">comedi_perror</link>(filename);
364 printf("initial time: %ld.%06ld\n",t1.tv_sec,t1.tv_usec);
365 for(i=0;i<![CDATA[<]]>n_scan;i++){
366 printf("%d\n",data[i]);
368 printf("final time: %ld.%06ld\n",t2.tv_sec,t2.tv_usec);
370 printf("difference (us): %ld\n",(t2.tv_sec-t1.tv_sec)*1000000+
371 (t2.tv_usec-t1.tv_usec));
380 <section id="fourthprogram">
382 Your fourth &comedi; program: commands
386 This example programs an analog output subdevice with &comedi;'s most
387 powerful acquisition function, the asynchronous
388 <link linkend="commandsstreaming">command</link>, to generate a waveform.
392 The waveform in this example is a sine wave, but this can be easily
393 changed to make a generic function generator.
397 The function generation algorithm is the same as what is typically
398 used in digital function generators. A 32-bit accumulator is
399 incremented by a phase factor, which is the amount (in radians) that
400 the generator advances each time step. The accumulator is then
401 shifted right by 20 bits, to get a 12 bit offset into a lookup table.
402 The value in the lookup table at that offset is then put into a buffer
403 for output to the DAC.
408 issued the command, &comedi; expects you to keep the buffer full of
409 data to output to the acquisition card. This is done by
410 <function>write()</function>. Since there may be a delay between the
411 <link linkend="func-ref-comedi-command">comedi_command()</link>
412 and a subsequent <function>write()</function>, you
413 should fill the buffer using <function>write()</function> before you call
414 <link linkend="func-ref-comedi-command">comedi_command()</link>,
419 #include <]]><link linkend="comedi-comedilib-h">comedilib.h</link><![CDATA[>
427 #include "examples.h"
430 double waveform_frequency = 10.0; /* frequency of the sine wave to output */
431 double amplitude = 4000; /* peak-to-peak amplitude, in DAC units (i.e., 0-4095) */
432 double offset = 2048; /* offset, in DAC units */
434 /* This is the size of chunks we deal with when creating and
435 outputting data. This *could* be 1, but that would be
440 int external_trigger_number = 0;
442 sampl_t data[BUF_LEN];
444 void <link linkend="dds-output">dds_output</link>(sampl_t *buf,int n);
445 void <link linkend="dds-init">dds_init</link>(void);
447 /* This define determines which waveform to use. */
448 #define <anchor id="dds-init-function">dds_init_function <link linkend="dds-init-sine">dds_init_sine</link>
450 void <link linkend="dds-init-sine">dds_init_sine</link>(void);
451 void <link linkend="dds-init-pseudocycloid">dds_init_pseudocycloid</link>(void);
452 void <link linkend="dds-init-sawtooth">dds_init_sawtooth</link>(void);
454 int <anchor id="comedi-internal-trigger">comedi_internal_trigger(<link linkend="ref-type-comedi-t">comedi_t</link> *dev, unsigned int subd, unsigned int trignum)
456 <link linkend="ref-type-comedi-insn">comedi_insn</link> insn;
457 <link linkend="ref-type-lsampl-t">lsampl_t</link> data[1];
459 memset(<![CDATA[&insn]]>, 0, sizeof(<link linkend="ref-type-comedi-insn">comedi_insn</link>));
460 insn.insn = <link linkend="insn-inttrig">INSN_INTTRIG</link>;
467 return <link linkend="func-ref-comedi-do-insn">comedi_do_insn</link>(dev, <![CDATA[&insn]]>);
471 int main(int argc, char *argv[])
473 <link linkend="ref-type-comedi-cmd">comedi_cmd</link> cmd;
477 <link linkend="ref-type-comedi-t">comedi_t</link> *dev;
478 unsigned int chanlist[16];
479 unsigned int maxdata;
480 <link linkend="ref-type-comedi-range">comedi_range</link> *rng;
482 <link linkend="ref-type-lsampl-t">lsampl_t</link> insn_data = 0;
484 parse_options(argc,argv);
486 /* Force n_chan to be 1 */
489 if(value){ waveform_frequency = value; }
491 dev = <link linkend="func-ref-comedi-open">comedi_open</link>(filename);
493 fprintf(stderr, "error opening %s\n", filename);
496 subdevice = <link linkend="func-ref-comedi-find-subdevice-by-type">comedi_find_subdevice_by_type</link>(dev,COMEDI_SUBD_AO,0);
498 maxdata = <link linkend="func-ref-comedi-get-maxdata">comedi_get_maxdata</link>(dev,subdevice,0);
499 rng = <link linkend="func-ref-comedi-get-range">comedi_get_range</link>(dev,subdevice,0,0);
500 offset = (double)<link linkend="func-ref-comedi-from-phys">comedi_from_phys</link>(0.0,rng,maxdata);
501 amplitude = (double)<link linkend="func-ref-comedi-from-phys">comedi_from_phys</link>(1.0,rng,maxdata) - offset;
503 memset(<![CDATA[&cmd]]>,0,sizeof(cmd));
504 /* fill in the <link linkend="ref-type-comedi-cmd">command data structure</link>: */
505 cmd.subdev = subdevice;
507 cmd.start_src = <link linkend="trig-int-start-src">TRIG_INT</link>;
509 cmd.scan_begin_src = <link linkend="trig-timer">TRIG_TIMER</link>;
510 cmd.scan_begin_arg = 1e9/freq;
511 cmd.convert_src = <link linkend="trig-now">TRIG_NOW</link>;
513 cmd.scan_end_src = <link linkend="trig-count">TRIG_COUNT</link>;
514 cmd.scan_end_arg = n_chan;
515 cmd.stop_src = <link linkend="trig-none">TRIG_NONE</link>;
518 cmd.chanlist = chanlist;
519 cmd.chanlist_len = n_chan;
521 chanlist[0] = <link linkend="ref-macro-CR-PACK">CR_PACK</link>(channel,range,aref);
522 chanlist[1] = <link linkend="ref-macro-CR-PACK">CR_PACK</link>(channel+1,range,aref);
524 <link linkend="dds-init">dds_init</link>();
526 <link linkend="dds-output">dds_output</link>(data,BUF_LEN);
527 <link linkend="dds-output">dds_output</link>(data,BUF_LEN);
529 dump_cmd(stdout,<![CDATA[&cmd]]>);
531 if ((err = <link linkend="func-ref-comedi-command">comedi_command</link>(dev, <![CDATA[&cmd]]>)) < 0) {
532 <link linkend="func-ref-comedi-perror">comedi_perror</link>("comedi_command");
536 m=write(comedi_fileno(dev),data,BUF_LEN*sizeof(sampl_t));
543 ret = <link linkend="comedi-internal-trigger">comedi_internal_trigger</link>(dev, subdevice, 0);
547 perror("comedi_internal_trigger\n");
552 <link linkend="dds-output">dds_output</link>(data,BUF_LEN);
553 n=BUF_LEN*sizeof(sampl_t);
555 m=write(comedi_fileno(dev),(void *)data+(BUF_LEN*sizeof(sampl_t)-n),n);
571 #define WAVEFORM_SHIFT 16
573 #define WAVEFORM_LEN (1<<WAVEFORM_SHIFT)
575 #define WAVEFORM_MASK (WAVEFORM_LEN-1)
577 sampl_t waveform[WAVEFORM_LEN];
582 void <anchor id="dds-init">dds_init(void)
585 adder=waveform_frequency/freq*(1<<16)*(1<<WAVEFORM_SHIFT);
588 <link linkend="dds-init-function">dds_init_function</link>();
591 void <anchor id="dds-output">dds_output(sampl_t *buf,int n)
598 *p=waveform[(acc>>16)&WAVEFORM_MASK];
606 void <anchor id="dds-init-sine">dds_init_sine(void)
611 for(i=0;i<WAVEFORM_LEN;i++){
612 waveform[i]=rint(offset+0.5*amplitude*cos(i*2*M_PI/WAVEFORM_LEN));
617 /* Yes, I know this is not the proper equation for a cycloid. Fix it. */
618 void <anchor id="dds-init-pseudocycloid">dds_init_pseudocycloid(void)
624 for(i=0;i<WAVEFORM_LEN/2;i++){
625 t=2*((double)i)/WAVEFORM_LEN;
626 waveform[i]=rint(offset+amplitude*sqrt(1-4*t*t));
628 for(i=WAVEFORM_LEN/2;i<WAVEFORM_LEN;i++){
629 t=2*(1-((double)i)/WAVEFORM_LEN);
630 waveform[i]=rint(offset+amplitude*sqrt(1-t*t));
635 void <anchor id="dds-init-sawtooth">dds_init_sawtooth(void)
640 for(i=0;i<WAVEFORM_LEN;i++){
641 waveform[i]=rint(offset+amplitude*((double)i)/WAVEFORM_LEN);