increased BUF_LEN, so demo works better with ni boards
[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       = 10.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         8192    
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 comedi_internal_trigger(comedi_t *dev, unsigned int subd, unsigned int trignum)
88 {
89         comedi_insn insn;
90         lsampl_t data[1];
91
92         memset(&insn, 0, sizeof(comedi_insn));
93         insn.insn = INSN_INTTRIG;
94         insn.subdev = subd;
95         insn.data = data;
96         insn.n = 1;
97
98         data[0] = trignum;
99
100         return comedi_do_insn(dev, &insn);
101 }
102
103
104 int main(int argc, char *argv[])
105 {
106         comedi_cmd cmd;
107         int err;
108         int n,m;
109         int total=0;
110         comedi_t *dev;
111         unsigned int chanlist[16];
112         unsigned int maxdata;
113         comedi_range *rng;
114         int ret;
115         lsampl_t insn_data = 0;
116
117         parse_options(argc,argv);
118
119         /* Force n_chan to be 1 */
120         n_chan = 1;
121
122         if(value){
123                 waveform_frequency = value;
124         }
125
126         dev = comedi_open(filename);
127         if(dev == NULL){
128                 fprintf(stderr, "error opening %s\n", filename);
129                 return -1;
130         }
131         subdevice = comedi_find_subdevice_by_type(dev,COMEDI_SUBD_AO,0);
132
133         maxdata = comedi_get_maxdata(dev,subdevice,0);
134         rng = comedi_get_range(dev,subdevice,0,0);
135
136         offset = (double)comedi_from_phys(0.0,rng,maxdata);
137         amplitude = (double)comedi_from_phys(1.0,rng,maxdata) - offset;
138
139         memset(&cmd,0,sizeof(cmd));
140         cmd.subdev = subdevice;
141         cmd.flags = 0;
142         cmd.start_src = TRIG_INT;
143         cmd.start_arg = 0;
144         cmd.scan_begin_src = TRIG_TIMER;
145         cmd.scan_begin_arg = 1e9/freq;
146         cmd.convert_src = TRIG_NOW;
147         cmd.convert_arg = 0;
148         cmd.scan_end_src = TRIG_COUNT;
149         cmd.scan_end_arg = n_chan;
150         cmd.stop_src = TRIG_NONE;
151         cmd.stop_arg = 0;
152
153         cmd.chanlist = chanlist;
154         cmd.chanlist_len = n_chan;
155
156         chanlist[0] = CR_PACK(channel,range,aref);
157         chanlist[1] = CR_PACK(channel+1,range,aref);
158
159         dds_init();
160
161         dds_output(data,BUF_LEN);
162         dds_output(data,BUF_LEN);
163
164         dump_cmd(stdout,&cmd);
165
166         err = comedi_command_test(dev, &cmd);
167         if (err < 0) {
168                 comedi_perror("comedi_command_test");
169                 exit(1);
170         }
171
172         err = comedi_command_test(dev, &cmd);
173         if (err < 0) {
174                 comedi_perror("comedi_command_test");
175                 exit(1);
176         }
177
178         if ((err = comedi_command(dev, &cmd)) < 0) {
179                 comedi_perror("comedi_command");
180                 exit(1);
181         }
182
183         m=write(comedi_fileno(dev),data,BUF_LEN*sizeof(sampl_t));
184         if(m<0){
185                 perror("write");
186                 exit(1);
187         }
188         printf("m=%d\n",m);
189         
190         ret = comedi_internal_trigger(dev, subdevice, 0);
191         if(ret<0){
192                 perror("comedi_internal_trigger\n");
193                 exit(1);
194         }
195
196         while(1){
197                 dds_output(data,BUF_LEN);
198                 n=BUF_LEN*sizeof(sampl_t);
199                 while(n>0){
200                         m=write(comedi_fileno(dev),(void *)data+(BUF_LEN*sizeof(sampl_t)-n),n);
201                         if(m<0){
202                                 perror("write");
203                                 exit(0);
204                         }
205                         printf("m=%d\n",m);
206                         n-=m;
207                 }
208                 total+=BUF_LEN;
209                 //printf("%d\n",total);
210         }
211
212         return 0;
213 }
214
215
216
217 #define WAVEFORM_SHIFT 16
218 #define WAVEFORM_LEN (1<<WAVEFORM_SHIFT)
219 #define WAVEFORM_MASK (WAVEFORM_LEN-1)
220
221
222 sampl_t waveform[WAVEFORM_LEN];
223
224 unsigned int acc;
225 unsigned int adder;
226
227 void dds_init(void)
228 {
229         adder=waveform_frequency/freq*(1<<16)*(1<<WAVEFORM_SHIFT);
230
231         dds_init_function();
232 }
233
234 void dds_output(sampl_t *buf,int n)
235 {
236         int i;
237         sampl_t *p=buf;
238
239         for(i=0;i<n;i++){
240                 *p=waveform[(acc>>16)&WAVEFORM_MASK];
241                 p++;
242                 acc+=adder;
243         }
244 }
245
246
247 void dds_init_sine(void)
248 {
249         int i;
250
251         for(i=0;i<WAVEFORM_LEN;i++){
252                 waveform[i]=rint(offset+0.5*amplitude*cos(i*2*M_PI/WAVEFORM_LEN));
253         }
254 }
255
256 /* Yes, I know this is not the proper equation for a
257    cycloid.  Fix it. */
258 void dds_init_pseudocycloid(void)
259 {
260         int i;
261         double t;
262
263         for(i=0;i<WAVEFORM_LEN/2;i++){
264                 t=2*((double)i)/WAVEFORM_LEN;
265                 waveform[i]=rint(offset+amplitude*sqrt(1-4*t*t));
266         }
267         for(i=WAVEFORM_LEN/2;i<WAVEFORM_LEN;i++){
268                 t=2*(1-((double)i)/WAVEFORM_LEN);
269                 waveform[i]=rint(offset+amplitude*sqrt(1-t*t));
270         }
271 }
272
273 void dds_init_sawtooth(void)
274 {
275         int i;
276
277         for(i=0;i<WAVEFORM_LEN;i++){
278                 waveform[i]=rint(offset+amplitude*((double)i)/WAVEFORM_LEN);
279         }
280 }
281