Removed usbdux_firmware.lst because it's just the listing of the assembler which...
[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 <string.h>
56 #include "examples.h"
57
58
59 /* frequency of the sine wave to output */
60 double waveform_frequency       = 10.0;
61
62 /* peak-to-peak amplitude, in DAC units (i.e., 0-4095) */
63 double amplitude                = 4000;
64
65 /* offset, in DAC units */
66 double offset                   = 2048;
67
68 /* This is the size of chunks we deal with when creating and
69    outputting data.  This *could* be 1, but that would be
70    inefficient */
71 #define BUF_LEN 0x8000
72
73 int subdevice;
74 int external_trigger_number = 0;
75
76 sampl_t data[BUF_LEN];
77
78 void dds_output(sampl_t *buf,int n);
79 void dds_init(void);
80
81 /* This define determines which waveform to use. */
82 #define dds_init_function dds_init_sine
83
84 void dds_init_sine(void);
85 void dds_init_pseudocycloid(void);
86 void dds_init_sawtooth(void);
87
88 int comedi_internal_trigger(comedi_t *dev, unsigned int subd, unsigned int trignum)
89 {
90         comedi_insn insn;
91         lsampl_t data[1];
92
93         memset(&insn, 0, sizeof(comedi_insn));
94         insn.insn = INSN_INTTRIG;
95         insn.subdev = subd;
96         insn.data = data;
97         insn.n = 1;
98
99         data[0] = trignum;
100
101         return comedi_do_insn(dev, &insn);
102 }
103
104
105 int main(int argc, char *argv[])
106 {
107         comedi_cmd cmd;
108         int err;
109         int n,m;
110         int total=0;
111         comedi_t *dev;
112         unsigned int chanlist[16];
113         unsigned int maxdata;
114         comedi_range *rng;
115         int ret;
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         dump_cmd(stdout,&cmd);
162
163         err = comedi_command_test(dev, &cmd);
164         if (err < 0) {
165                 comedi_perror("comedi_command_test");
166                 exit(1);
167         }
168
169         err = comedi_command_test(dev, &cmd);
170         if (err < 0) {
171                 comedi_perror("comedi_command_test");
172                 exit(1);
173         }
174
175         if ((err = comedi_command(dev, &cmd)) < 0) {
176                 comedi_perror("comedi_command");
177                 exit(1);
178         }
179
180         dds_output(data,BUF_LEN);
181         n = BUF_LEN * sizeof(sampl_t);
182         m = write(comedi_fileno(dev), (void *)data, n);
183         if(m < 0){
184                 perror("write");
185                 exit(1);
186         }else if(m < n)
187         {
188                 fprintf(stderr, "failed to preload output buffer with %i bytes, is it too small?\n"
189                         "See the --write-buffer option of comedi_config\n", n);
190                 exit(1);
191         }
192         printf("m=%d\n",m);
193
194         ret = comedi_internal_trigger(dev, subdevice, 0);
195         if(ret<0){
196                 perror("comedi_internal_trigger\n");
197                 exit(1);
198         }
199
200         while(1){
201                 dds_output(data,BUF_LEN);
202                 n=BUF_LEN*sizeof(sampl_t);
203                 while(n>0){
204                         m=write(comedi_fileno(dev),(void *)data+(BUF_LEN*sizeof(sampl_t)-n),n);
205                         if(m<0){
206                                 perror("write");
207                                 exit(0);
208                         }
209                         printf("m=%d\n",m);
210                         n-=m;
211                 }
212                 total+=BUF_LEN;
213                 //printf("%d\n",total);
214         }
215
216         return 0;
217 }
218
219
220
221 #define WAVEFORM_SHIFT 16
222 #define WAVEFORM_LEN (1<<WAVEFORM_SHIFT)
223 #define WAVEFORM_MASK (WAVEFORM_LEN-1)
224
225
226 sampl_t waveform[WAVEFORM_LEN];
227
228 unsigned int acc;
229 unsigned int adder;
230
231 void dds_init(void)
232 {
233         adder=waveform_frequency/freq*(1<<16)*(1<<WAVEFORM_SHIFT);
234
235         dds_init_function();
236 }
237
238 void dds_output(sampl_t *buf,int n)
239 {
240         int i;
241         sampl_t *p=buf;
242
243         for(i=0;i<n;i++){
244                 *p=waveform[(acc>>16)&WAVEFORM_MASK];
245                 p++;
246                 acc+=adder;
247         }
248 }
249
250
251 void dds_init_sine(void)
252 {
253         int i;
254
255         for(i=0;i<WAVEFORM_LEN;i++){
256                 waveform[i]=rint(offset+0.5*amplitude*cos(i*2*M_PI/WAVEFORM_LEN));
257         }
258 }
259
260 /* Yes, I know this is not the proper equation for a
261    cycloid.  Fix it. */
262 void dds_init_pseudocycloid(void)
263 {
264         int i;
265         double t;
266
267         for(i=0;i<WAVEFORM_LEN/2;i++){
268                 t=2*((double)i)/WAVEFORM_LEN;
269                 waveform[i]=rint(offset+amplitude*sqrt(1-4*t*t));
270         }
271         for(i=WAVEFORM_LEN/2;i<WAVEFORM_LEN;i++){
272                 t=2*(1-((double)i)/WAVEFORM_LEN);
273                 waveform[i]=rint(offset+amplitude*sqrt(1-t*t));
274         }
275 }
276
277 void dds_init_sawtooth(void)
278 {
279         int i;
280
281         for(i=0;i<WAVEFORM_LEN;i++){
282                 waveform[i]=rint(offset+amplitude*((double)i)/WAVEFORM_LEN);
283         }
284 }
285