modified to work with TRIG_INT, made it use the -F command line option to
[comedilib.git] / demo / ao_waveform.c
1 /*
2  * Asynchronous Analog Output Example
3  * Part of Comedilib
4  *
5  * Copyright (c) 1999,2000 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  * Requirements: Analog output device capable of
14  *    asynchronous commands.
15  *
16  * This demo uses an analog output subdevice with an
17  * asynchronous command to generate a waveform.  The
18  * waveform in this example is a sine wave (surprise!),
19  * but this can be easily changed to make a generic
20  * function generator.
21  *
22  * The function generation algorithm is the same as
23  * what is typically used in digital function generators.
24  * A 32-bit accumulator is incremented by a phase factor,
25  * which is the amount (in radians) that the generator
26  * advances each time step.  The accumulator is then
27  * shifted right by 20 bits, to get a 12 bit offset into
28  * a lookup table.  The value in the lookup table at
29  * that offset is then put into a buffer for output to
30  * the DAC.
31  *
32  * [ Actually, the accumulator is only 26 bits, for some
33  * reason.  I'll fix this sometime. ]
34  *
35  * On the Comedi side of things, the setup for mode 2
36  * is similar to analog input, except for the TRIG_WRITE
37  * flag.  Once you have issued the command, comedi then
38  * expects you to keep the buffer full of data to output
39  * to the DAC.  This is done by write().  Since there
40  * may be a delay between the comedi_command() and a subsequent
41  * write(), you should fill the buffer using write() before
42  * you call comedi_command(), as is done here.
43  *
44  */
45
46 #include <stdio.h>
47 #include <comedilib.h>
48 #include <fcntl.h>
49 #include <stdlib.h>
50 #include <unistd.h>
51 #include <errno.h>
52 #include <getopt.h>
53 #include <ctype.h>
54 #include <math.h>
55 #include "examples.h"
56
57
58 /* frequency of the sine wave to output */
59 double waveform_frequency       = 100.0;
60
61 /* peak-to-peak amplitude, in DAC units (i.e., 0-4095) */
62 double amplitude                = 4000;
63
64 /* offset, in DAC units */
65 double offset                   = 2048;
66
67 /* This is the size of chunks we deal with when creating and
68    outputting data.  This *could* be 1, but that would be
69    inefficient */
70 #define BUF_LEN         4096
71
72 int subdevice;
73 int external_trigger_number = 0;
74
75 sampl_t data[BUF_LEN];
76
77 void dds_output(sampl_t *buf,int n);
78 void dds_init(void);
79
80 /* This define determines which waveform to use. */
81 #define dds_init_function dds_init_sine
82
83 void dds_init_sine(void);
84 void dds_init_pseudocycloid(void);
85 void dds_init_sawtooth(void);
86
87 int main(int argc, char *argv[])
88 {
89         comedi_cmd cmd;
90         comedi_insn insn;
91         int err;
92         int n,m;
93         int total=0;
94         comedi_t *dev;
95         unsigned int chanlist[1];
96
97         parse_options(argc,argv);
98
99         if(value){
100                 waveform_frequency = value;
101         }
102
103         dev = comedi_open(filename);
104         if(dev == NULL){
105                 fprintf(stderr, "error opening %s\n", filename);
106                 return -1;
107         }
108         subdevice = comedi_find_subdevice_by_type(dev,COMEDI_SUBD_AO,0);
109
110         memset(&cmd,0,sizeof(cmd));
111         cmd.subdev = subdevice;
112         cmd.flags = 0;
113         cmd.start_src = TRIG_INT;
114         cmd.start_arg = 0;
115         cmd.scan_begin_src = TRIG_TIMER;
116         cmd.scan_begin_arg = 1e9/freq;
117         cmd.convert_src = TRIG_NOW;
118         cmd.convert_arg = 0;
119         cmd.scan_end_src = TRIG_COUNT;
120         cmd.scan_end_arg = 1;
121         cmd.stop_src = TRIG_NONE;
122         cmd.stop_arg = 0;
123
124         cmd.chanlist = chanlist;
125         cmd.chanlist_len = 1;
126
127         chanlist[0] = CR_PACK(channel,range,aref);
128
129         dds_init();
130
131         dds_output(data,BUF_LEN);
132         dds_output(data,BUF_LEN);
133
134         if ((err = comedi_command(dev, &cmd)) < 0) {
135                 comedi_perror("comedi_command");
136                 exit(1);
137         }
138
139         m=write(comedi_fileno(dev),data,BUF_LEN*sizeof(sampl_t));
140         perror("write");
141         printf("m=%d\n",m);
142         
143         memset(&insn, 0, sizeof(comedi_insn));
144         insn.insn = INSN_INTTRIG;
145         comedi_do_insn(dev, &insn);
146
147         while(1){
148                 dds_output(data,BUF_LEN);
149                 n=BUF_LEN*sizeof(sampl_t);
150                 while(n>0){
151                         m=write(comedi_fileno(dev),(void *)data+(BUF_LEN*sizeof(sampl_t)-n),n);
152                         if(m<0){
153                                 perror("write");
154                                 exit(0);
155                         }
156                         //printf("m=%d\n",m);
157                         n-=m;
158                 }
159                 total+=BUF_LEN;
160                 //printf("%d\n",total);
161         }
162
163         return 0;
164 }
165
166
167
168 #define WAVEFORM_SHIFT 16
169 #define WAVEFORM_LEN (1<<WAVEFORM_SHIFT)
170 #define WAVEFORM_MASK (WAVEFORM_LEN-1)
171
172
173 sampl_t waveform[WAVEFORM_LEN];
174
175 unsigned int acc;
176 unsigned int adder;
177
178 void dds_init(void)
179 {
180         int i;
181
182         adder=waveform_frequency/freq*(1<<16)*(1<<WAVEFORM_SHIFT);
183
184         dds_init_function();
185
186         /* this is due to a bug in the NI-E driver */
187         if(range){
188                 for(i=0;i<WAVEFORM_LEN;i++){
189                         waveform[i]^=0x800;
190                 }
191         }
192 }
193
194 void dds_output(sampl_t *buf,int n)
195 {
196         int i;
197         sampl_t *p=buf;
198
199         for(i=0;i<n;i++){
200                 *p=waveform[(acc>>16)&WAVEFORM_MASK];
201                 p++;
202                 acc+=adder;
203         }
204 }
205
206
207 void dds_init_sine(void)
208 {
209         int i;
210
211         for(i=0;i<WAVEFORM_LEN;i++){
212                 waveform[i]=rint(offset+0.5*amplitude*cos(i*2*M_PI/WAVEFORM_LEN));
213         }
214 }
215
216 /* Yes, I know this is not the proper equation for a
217    cycloid.  Fix it. */
218 void dds_init_pseudocycloid(void)
219 {
220         int i;
221         double t;
222
223         for(i=0;i<WAVEFORM_LEN/2;i++){
224                 t=2*((double)i)/WAVEFORM_LEN;
225                 waveform[i]=rint(offset+amplitude*sqrt(1-4*t*t));
226         }
227         for(i=WAVEFORM_LEN/2;i<WAVEFORM_LEN;i++){
228                 t=2*(1-((double)i)/WAVEFORM_LEN);
229                 waveform[i]=rint(offset+amplitude*sqrt(1-t*t));
230         }
231 }
232
233 void dds_init_sawtooth(void)
234 {
235         int i;
236
237         for(i=0;i<WAVEFORM_LEN;i++){
238                 waveform[i]=rint(offset+amplitude*((double)i)/WAVEFORM_LEN);
239         }
240 }
241