~ubuntu-branches/ubuntu/feisty/comedilib/feisty

« back to all changes in this revision

Viewing changes to doc/tutorial.sgml

  • Committer: Bazaar Package Importer
  • Author(s): David Schleef
  • Date: 2003-09-23 18:11:12 UTC
  • Revision ID: james.westby@ubuntu.com-20030923181112-sat05jyh702rb1at
Tags: upstream-0.7.21
ImportĀ upstreamĀ versionĀ 0.7.21

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<!-- <!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V3.1//EN" "docbook/dtd/3.1/docbook.dtd">  -->
 
2
 
 
3
<section id="writingprograms">
 
4
<title>
 
5
Writing &comedi; programs
 
6
</title>
 
7
<para>
 
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
 
10
of &comedi; devices.
 
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;.
 
14
</para>
 
15
<para>
 
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;.
 
20
</para>
 
21
 
 
22
<section id="firstprogram">
 
23
<title>
 
24
Your first &comedi; program
 
25
</title>
 
26
 
 
27
<para>
 
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:
 
30
<programlisting>
 
31
#include <![CDATA[<stdio.h>]]>   /* for printf() */
 
32
#include <![CDATA[<]]><link linkend="comedi-comedilib-h">comedilib.h</link><![CDATA[>]]>
 
33
 
 
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 */
 
38
 
 
39
int main(int argc,char *argv[])
 
40
{
 
41
  <link linkend="ref-type-comedi-t">comedi_t</link> *it;
 
42
  <link linkend="ref-type-lsampl-t">lsampl_t</link> data;
 
43
 
 
44
  it=<link linkend="func-ref-comedi-open">comedi_open</link>("/dev/comedi0");
 
45
 
 
46
  <link linkend="func-ref-comedi-data-read">comedi_data_read</link>(it,subdev,chan,range,aref, & data);
 
47
 
 
48
  printf("%d\n",data);
 
49
 
 
50
  return 0;
 
51
}
 
52
</programlisting>
 
53
The
 
54
<function>
 
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>.
 
60
<para>
 
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
 
64
</para>
 
65
 
 
66
<screen>
 
67
cc tut1.c -lcomedi -o tut1
 
68
</screen>
 
69
<para>
 
70
(Replace <literal>cc</literal> by your favourite C compiler command.)
 
71
</para>
 
72
 
 
73
<para>
 
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.
 
80
</para>
 
81
</section>
 
82
 
 
83
 
 
84
<section id="convertingsamples">
 
85
<title>
 
86
Converting samples to voltages
 
87
</title>
 
88
 
 
89
<para>
 
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
 
102
manner?</quote>
 
103
</para>
 
104
 
 
105
<para>
 
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.
 
112
</para>
 
113
 
 
114
<para>
 
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.)
 
119
</para>
 
120
 
 
121
<para>
 
122
The largest sample value can be found using the function
 
123
<programlisting>
 
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))
 
125
</programlisting>
 
126
The number of available ranges can be found using the function:
 
127
<programlisting>
 
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);
 
129
</programlisting>
 
130
</para>
 
131
 
 
132
<para>
 
133
For each value of the range parameter for a particular
 
134
subdevice/channel, you can get range information using:
 
135
<programlisting>
 
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);
 
138
</programlisting>
 
139
which returns a pointer to a
 
140
<link linkend="ref-type-comedi-range">comedi_range</link>
 
141
structure, which has the following contents:
 
142
<programlisting>
 
143
typedef struct{
 
144
        double min;
 
145
        double max;
 
146
        unsigned int unit;
 
147
}comedi_range;
 
148
</programlisting>
 
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).
 
163
</para>
 
164
 
 
165
<para>
 
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
 
170
</para>
 
171
 
 
172
<programlisting>
 
173
volts=<link linkend="func-ref-comedi-to-phys">comedi_to_phys</link>(it,data,range,maxdata);
 
174
</programlisting>
 
175
 
 
176
<para>
 
177
and the opposite
 
178
</para>
 
179
 
 
180
<programlisting>
 
181
data=<link linkend="func-ref-comedi-from-phys">comedi_from_phy</link>s(it,volts,range,maxdata);
 
182
</programlisting>
 
183
 
 
184
</section>
 
185
 
 
186
<section id="usingfileinterface">
 
187
<title>
 
188
Using the file interface
 
189
</title>
 
190
 
 
191
 
 
192
<para>
 
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>:
 
201
</para>
 
202
 
 
203
<programlisting>
 
204
file=<link linkend="func-ref-comedi-open">comedi_open</link>("/dev/comedi0");
 
205
</programlisting>
 
206
 
 
207
<para>
 
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.  
 
214
</para>
 
215
 
 
216
<para>
 
217
Specifically, you need to know
 
218
<parameter class=function>maxdata</parameter> for a specific
 
219
subdevice/channel. How about:
 
220
 
 
221
<programlisting>
 
222
maxdata=<link linkend="func-ref-comedi-get-maxdata">comedi_get_maxdata</link>(file,subdevice,channel);
 
223
</programlisting>
 
224
 
 
225
Wow! How easy. And the range information?
 
226
 
 
227
<programlisting>
 
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);
 
229
</programlisting>
 
230
 
 
231
</para>
 
232
 
 
233
</section>
 
234
 
 
235
 
 
236
<section id="secondprogram">
 
237
<title>
 
238
Your second &comedi; program: simple acquisition
 
239
</title>
 
240
 
 
241
 
 
242
<para>
 
243
Actually, this is the first &comedi; program again, just
 
244
that we've added what we've learned.
 
245
</para>
 
246
 
 
247
 
 
248
<programlisting>
 
249
#include &lt;stdio.h&gt;      /* for printf() */
 
250
#include <![CDATA[<]]><link linkend="comedi-comedilib-h">comedilib.h</link><![CDATA[>]]>
 
251
 
 
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 */
 
256
 
 
257
int main(int argc,char *argv[])
 
258
{
 
259
  <link linkend="ref-type-comedi-t">comedi_t</link> *cf;
 
260
  int chan=0;
 
261
  <link linkend="ref-type-lsampl-t">lsampl_t</link> data;
 
262
  int maxdata,rangetype;
 
263
  double volts;
 
264
 
 
265
  cf=<link linkend="func-ref-comedi-open">comedi_open</link>("/dev/comedi0");
 
266
 
 
267
  maxdata=<link linkend="func-ref-comedi-get-maxdata">comedi_get_maxdata</link>(cf,subdev,chan);
 
268
 
 
269
  rangetype=comedi_get_rangetype(cf,subdev,chan);
 
270
 
 
271
  <link linkend="func-ref-comedi-data-read">comedi_data_read</link>(cf->fd,subdev,chan,range,aref,&amp;data);
 
272
 
 
273
  volts=<link linkend="func-ref-comedi-to-phys">comedi_to_phys</link>(data,rangetype,range,maxdata);
 
274
 
 
275
  printf("%d %g\n",data,volts);
 
276
 
 
277
 return 0;
 
278
}
 
279
</programlisting>
 
280
 
 
281
</section>
 
282
 
 
283
<section id="thirdprogram">
 
284
<title>
 
285
Your third &comedi; program: instructions
 
286
</title>
 
287
<para>
 
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>.
 
291
<programlisting>
 
292
<![CDATA[
 
293
#include <stdio.h>
 
294
#include <]]><link linkend="comedi-comedilib-h">comedilib.h</link><![CDATA[>
 
295
#include <fcntl.h>
 
296
#include <unistd.h>
 
297
#include <errno.h>
 
298
#include <sys/time.h>
 
299
#include <unistd.h>
 
300
#include "examples.h"
 
301
]]>
 
302
 
 
303
/*
 
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.
 
307
 */
 
308
 
 
309
#define MAX_SAMPLES 128
 
310
 
 
311
<link linkend="ref-type-comedi-t">comedi_t</link> *device;
 
312
 
 
313
int main(int argc, char *argv[])
 
314
{
 
315
  int ret,i;
 
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];
 
320
 
 
321
  parse_options(argc,argv);
 
322
 
 
323
 
 
324
  device=<link linkend="func-ref-comedi-open">comedi_open</link>(filename);
 
325
  if(!device){
 
326
    <link linkend="func-ref-comedi-perror">comedi_perror</link>(filename);
 
327
    exit(0);
 
328
  }
 
329
 
 
330
  if(verbose){
 
331
    printf("measuring device=%s subdevice=%d channel=%d range=%d analog reference=%d\n",
 
332
      filename,subdevice,channel,range,aref);
 
333
  }
 
334
 
 
335
  /* Set up a the "instruction list", which is just a pointer
 
336
   * to the array of instructions and the number of instructions.
 
337
   */
 
338
  il.n_insns=3;
 
339
  il.insns=insn;
 
340
 
 
341
  /* Instruction 0: perform a gettimeofday() */
 
342
  insn[0].insn=<link linkend="insn-gtod">INSN_GTOD</link>;
 
343
  insn[0].n=2;
 
344
  insn[0].data=(void *)&amp;t1;
 
345
 
 
346
  /* Instruction 1: do 10 analog input reads */
 
347
  insn[1].insn=<link linkend="insn-read">INSN_READ</link>;
 
348
  insn[1].n=n_scan;
 
349
  insn[1].data=data;
 
350
  insn[1].subdev=subdevice;
 
351
  insn[1].chanspec=<link linkend="ref-macro-CR-PACK">CR_PACK</link>(channel,range,aref);
 
352
 
 
353
  /* Instruction 2: perform a gettimeofday() */
 
354
  insn[2].insn=<link linkend="insn-gtod">INSN_GTOD</link>;
 
355
  insn[2].n=2;
 
356
  insn[2].data=(void *)&amp;t2;
 
357
 
 
358
  ret=<link linkend="func-ref-comedi-do-insnlist">comedi_do_insnlist</link>(device,&amp;il);
 
359
  if(ret<![CDATA[<]]>0){
 
360
    <link linkend="func-ref-comedi-perror">comedi_perror</link>(filename);
 
361
    exit(0);
 
362
  }
 
363
 
 
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]);
 
367
  }
 
368
  printf("final time: %ld.%06ld\n",t2.tv_sec,t2.tv_usec);
 
369
 
 
370
  printf("difference (us): %ld\n",(t2.tv_sec-t1.tv_sec)*1000000+
 
371
      (t2.tv_usec-t1.tv_usec));
 
372
 
 
373
  return 0;
 
374
}
 
375
</programlisting>
 
376
</para>
 
377
 
 
378
</section>
 
379
 
 
380
<section id="fourthprogram">
 
381
<title>
 
382
Your fourth &comedi; program: commands
 
383
</title>
 
384
 
 
385
<para>
 
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. 
 
389
</para>
 
390
 
 
391
<para>
 
392
The waveform in this example is a sine wave, but this can be easily
 
393
changed to make a generic function generator.
 
394
</para>
 
395
 
 
396
<para>
 
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.
 
404
</para>
 
405
 
 
406
<para>
 
407
Once you have
 
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>,
 
415
as is done here.
 
416
<programlisting>
 
417
<![CDATA[
 
418
#include <stdio.h>
 
419
#include <]]><link linkend="comedi-comedilib-h">comedilib.h</link><![CDATA[>
 
420
#include <fcntl.h>
 
421
#include <stdlib.h>
 
422
#include <unistd.h>
 
423
#include <errno.h>
 
424
#include <getopt.h>
 
425
#include <ctype.h>
 
426
#include <math.h>
 
427
#include "examples.h"
 
428
]]>
 
429
 
 
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 */
 
433
 
 
434
/* This is the size of chunks we deal with when creating and
 
435
   outputting data.  This *could* be 1, but that would be
 
436
   inefficient */
 
437
#define BUF_LEN 4096
 
438
 
 
439
int subdevice;
 
440
int external_trigger_number = 0;
 
441
 
 
442
sampl_t data[BUF_LEN];
 
443
 
 
444
void <link linkend="dds-output">dds_output</link>(sampl_t *buf,int n);
 
445
void <link linkend="dds-init">dds_init</link>(void);
 
446
 
 
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>
 
449
 
 
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);
 
453
 
 
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)
 
455
{
 
456
  <link linkend="ref-type-comedi-insn">comedi_insn</link> insn;
 
457
  <link linkend="ref-type-lsampl-t">lsampl_t</link> data[1];
 
458
 
 
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>;
 
461
  insn.subdev = subd;
 
462
  insn.data = data;
 
463
  insn.n = 1;
 
464
 
 
465
  data[0] = trignum;
 
466
 
 
467
  return <link linkend="func-ref-comedi-do-insn">comedi_do_insn</link>(dev, <![CDATA[&insn]]>);
 
468
}
 
469
 
 
470
 
 
471
int main(int argc, char *argv[])
 
472
{
 
473
  <link linkend="ref-type-comedi-cmd">comedi_cmd</link> cmd;
 
474
  int err;
 
475
  int n,m;
 
476
  int total=0;
 
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;
 
481
  int ret;
 
482
  <link linkend="ref-type-lsampl-t">lsampl_t</link> insn_data = 0; 
 
483
 
 
484
  parse_options(argc,argv);
 
485
 
 
486
  /* Force n_chan to be 1 */
 
487
  n_chan = 2;
 
488
 
 
489
  if(value){ waveform_frequency = value; }
 
490
 
 
491
  dev = <link linkend="func-ref-comedi-open">comedi_open</link>(filename);
 
492
  if(dev == NULL){
 
493
    fprintf(stderr, "error opening %s\n", filename);
 
494
    return -1;
 
495
  }
 
496
  subdevice = <link linkend="func-ref-comedi-find-subdevice-by-type">comedi_find_subdevice_by_type</link>(dev,COMEDI_SUBD_AO,0);
 
497
 
 
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;
 
502
 
 
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;
 
506
  cmd.flags          = 0;
 
507
  cmd.start_src      = <link linkend="trig-int-start-src">TRIG_INT</link>;
 
508
  cmd.start_arg      = 0;
 
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>;
 
512
  cmd.convert_arg    = 0;
 
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>;
 
516
  cmd.stop_arg       = 0;
 
517
 
 
518
  cmd.chanlist       = chanlist;
 
519
  cmd.chanlist_len   = n_chan;
 
520
 
 
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);
 
523
 
 
524
  <link linkend="dds-init">dds_init</link>();
 
525
 
 
526
  <link linkend="dds-output">dds_output</link>(data,BUF_LEN);
 
527
  <link linkend="dds-output">dds_output</link>(data,BUF_LEN);
 
528
 
 
529
  dump_cmd(stdout,<![CDATA[&cmd]]>);
 
530
 
 
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");
 
533
    exit(1);
 
534
  }
 
535
 
 
536
  m=write(comedi_fileno(dev),data,BUF_LEN*sizeof(sampl_t));
 
537
  if(<![CDATA[m<0]]>){
 
538
    perror("write");
 
539
    exit(1);
 
540
  }
 
541
  printf("m=%d\n",m);
 
542
  
 
543
  ret = <link linkend="comedi-internal-trigger">comedi_internal_trigger</link>(dev, subdevice, 0);
 
544
<![CDATA[
 
545
  if(ret<0){
 
546
]]>
 
547
    perror("comedi_internal_trigger\n");
 
548
    exit(1);
 
549
  }
 
550
 
 
551
  while(1){
 
552
    <link linkend="dds-output">dds_output</link>(data,BUF_LEN);
 
553
    n=BUF_LEN*sizeof(sampl_t);
 
554
    while(n>0){
 
555
      m=write(comedi_fileno(dev),(void *)data+(BUF_LEN*sizeof(sampl_t)-n),n);
 
556
<![CDATA[
 
557
      if(m<0){
 
558
]]>
 
559
        perror("write");
 
560
        exit(0);
 
561
      }
 
562
      printf("m=%d\n",m);
 
563
      n-=m;
 
564
    }
 
565
    total+=BUF_LEN;
 
566
  }
 
567
 
 
568
  return 0;
 
569
}
 
570
 
 
571
#define WAVEFORM_SHIFT 16
 
572
<![CDATA[
 
573
#define WAVEFORM_LEN (1<<WAVEFORM_SHIFT)
 
574
]]>
 
575
#define WAVEFORM_MASK (WAVEFORM_LEN-1)
 
576
 
 
577
sampl_t waveform[WAVEFORM_LEN];
 
578
 
 
579
unsigned int acc;
 
580
unsigned int adder;
 
581
 
 
582
void <anchor id="dds-init">dds_init(void)
 
583
{
 
584
<![CDATA[
 
585
  adder=waveform_frequency/freq*(1<<16)*(1<<WAVEFORM_SHIFT);
 
586
]]>
 
587
 
 
588
  <link linkend="dds-init-function">dds_init_function</link>();
 
589
}
 
590
 
 
591
void <anchor id="dds-output">dds_output(sampl_t *buf,int n)
 
592
{
 
593
  int i;
 
594
  sampl_t *p=buf;
 
595
 
 
596
  <![CDATA[
 
597
  for(i=0;i<n;i++){
 
598
  *p=waveform[(acc>>16)&WAVEFORM_MASK];
 
599
  ]]>
 
600
  p++;
 
601
  acc+=adder;
 
602
  }
 
603
}
 
604
 
 
605
 
 
606
void <anchor id="dds-init-sine">dds_init_sine(void)
 
607
{
 
608
  int i;
 
609
 
 
610
  <![CDATA[
 
611
  for(i=0;i<WAVEFORM_LEN;i++){
 
612
  waveform[i]=rint(offset+0.5*amplitude*cos(i*2*M_PI/WAVEFORM_LEN));
 
613
  ]]>
 
614
  }
 
615
}
 
616
 
 
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)
 
619
{
 
620
  int i;
 
621
  double t;
 
622
 
 
623
  <![CDATA[
 
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));
 
627
  }
 
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));
 
631
  }
 
632
  ]]>
 
633
}
 
634
 
 
635
void <anchor id="dds-init-sawtooth">dds_init_sawtooth(void)
 
636
{
 
637
  int i;
 
638
 
 
639
  <![CDATA[
 
640
  for(i=0;i<WAVEFORM_LEN;i++){
 
641
  waveform[i]=rint(offset+amplitude*((double)i)/WAVEFORM_LEN);
 
642
  ]]>
 
643
  }
 
644
}
 
645
</programlisting>
 
646
</para>
 
647
 
 
648
</section>
 
649
 
 
650
</section>
 
651