Made parse_options() write options to a struct instead of passing
[comedilib.git] / demo / ao_mmap.c
1 /*
2  * Asynchronous Analog Output Example
3  * Part of Comedilib
4  *
5  * Copyright (c) 1999,2000 David A. Schleef <ds@schleef.org>
6  * Copyright (c) 2005 Frank Mori Hess <fmhess@@users.sourceforge.net>
7  *
8  * This file may be freely modified, distributed, and combined with
9  * other software, as long as proper attribution is given in the
10  * source code.
11  */
12
13 /*
14  * Requirements: Analog output device capable of
15  *    asynchronous commands.
16  *
17  * This demo uses an analog output subdevice with an
18  * asynchronous command to generate a waveform.  The
19  * waveform in this example is a sine wave (surprise!).
20  * The waveform data is passed to comedi through
21  * a memory mapping (as opposed to using write()).
22  * The entire buffer is filled once with one period
23  * of the waveform.
24  */
25
26 #include <stdio.h>
27 #include <comedilib.h>
28 #include <fcntl.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <getopt.h>
33 #include <ctype.h>
34 #include <math.h>
35 #include <string.h>
36 #include <sys/mman.h>
37 #include "examples.h"
38
39
40 static int comedi_internal_trigger(comedi_t *dev, unsigned int subd, unsigned int trignum)
41 {
42         comedi_insn insn;
43         lsampl_t data[1];
44
45         memset(&insn, 0, sizeof(comedi_insn));
46         insn.insn = INSN_INTTRIG;
47         insn.subdev = subd;
48         insn.data = data;
49         insn.n = 1;
50
51         data[0] = trignum;
52
53         return comedi_do_insn(dev, &insn);
54 }
55
56 static void write_waveform(sampl_t *buffer, int size, double amplitude, double offset, int maxdata)
57 {
58         int i;
59
60         for(i = 0; i < size; ++i)
61         {
62                 double temp = (amplitude / 2.) * sin((2. * M_PI * i) / size) + offset;
63                 if(temp < 0.) temp = 0.;
64                 if(temp > maxdata) temp = maxdata;
65                 buffer[i] = (sampl_t)temp;
66         }
67 }
68
69 int main(int argc, char *argv[])
70 {
71         comedi_cmd cmd;
72         int err;
73         comedi_t *dev;
74         unsigned int chanlist[16];
75         unsigned int maxdata;
76         comedi_range *rng;
77         int ret;
78         int size;
79         int num_samples;
80         sampl_t *map;
81         /* peak-to-peak amplitude, in DAC units (i.e., 0-4095) */
82         double amplitude;
83         /* offset, in DAC units */
84         double offset;
85         struct parsed_options options;
86
87         init_parsed_options(&options);
88         options.subdevice = -1;
89         parse_options(&options, argc, argv);
90
91         /* Force n_chan to be 1 */
92         options.n_chan = 1;
93
94         dev = comedi_open(options.filename);
95         if(dev == NULL){
96                 fprintf(stderr, "error opening %s\n", options.filename);
97                 return -1;
98         }
99         if(options.subdevice < 0)
100                 options.subdevice = comedi_find_subdevice_by_type(dev,COMEDI_SUBD_AO, 0);
101
102         maxdata = comedi_get_maxdata(dev, options.subdevice, 0);
103         rng = comedi_get_range(dev, options.subdevice, 0, 0);
104
105         offset = (double)comedi_from_phys(0.0, rng, maxdata);
106         amplitude = (double)comedi_from_phys(1.0, rng, maxdata) - offset;
107
108         memset(&cmd,0,sizeof(cmd));
109         cmd.subdev = options.subdevice;
110         cmd.flags = 0;
111         cmd.start_src = TRIG_INT;
112         cmd.start_arg = 0;
113         cmd.scan_begin_src = TRIG_TIMER;
114         cmd.scan_begin_arg = 1e9 / options.freq;
115         cmd.convert_src = TRIG_NOW;
116         cmd.convert_arg = 0;
117         cmd.scan_end_src = TRIG_COUNT;
118         cmd.scan_end_arg = options.n_chan;
119         cmd.stop_src = TRIG_NONE;
120         cmd.stop_arg = 0;
121
122         cmd.chanlist = chanlist;
123         cmd.chanlist_len = options.n_chan;
124
125         chanlist[0] = CR_PACK(options.channel, options.range, options.aref);
126
127         dump_cmd(stdout, &cmd);
128
129         err = comedi_command_test(dev, &cmd);
130         if (err < 0) {
131                 comedi_perror("comedi_command_test");
132                 exit(1);
133         }
134
135         err = comedi_command_test(dev, &cmd);
136         if (err < 0) {
137                 comedi_perror("comedi_command_test");
138                 exit(1);
139         }
140
141         if ((err = comedi_command(dev, &cmd)) < 0) {
142                 comedi_perror("comedi_command");
143                 exit(1);
144         }
145
146         size = comedi_get_buffer_size(dev, options.subdevice);
147         fprintf(stderr, "buffer size is %d\n", size);
148         map = mmap(NULL, size, PROT_WRITE, MAP_SHARED, comedi_fileno(dev), 0);
149         if(map == MAP_FAILED)
150         {
151                 perror("mmap");
152                 exit(1);
153         }
154         num_samples = size / sizeof(sampl_t);
155         write_waveform(map, num_samples, amplitude, offset, maxdata);
156         if(msync(map, size, MS_SYNC) < 0)
157         {
158                 perror("msync");
159                 exit(1);
160         }
161         printf("marking %i samples as written\n", num_samples);
162         ret = comedi_mark_buffer_written(dev, options.subdevice, size);
163         if(ret < 0)
164         {
165                 comedi_perror("comedi_mark_buffer_written");
166                 exit(1);
167         }
168         ret = comedi_internal_trigger(dev, options.subdevice, 0);
169         if(ret<0){
170                 comedi_perror("comedi_internal_trigger");
171                 exit(1);
172         }
173         while(1)
174         {
175                 int bytes_marked = comedi_get_buffer_contents(dev, options.subdevice);
176                 int bytes_unmarked = size - bytes_marked;
177                 if(bytes_marked < 0)
178                 {
179                         comedi_perror("comedi_get_buffer_contents");
180                         exit(1);
181                 }
182                 if(bytes_unmarked > 0)
183                 {
184                         // this keeps comedi from reporting a buffer underrun
185                         if(comedi_mark_buffer_written(dev, options.subdevice, bytes_unmarked) < 0)
186                         {
187                                 comedi_perror("comedi_mark_buffer_written");
188                                 exit(1);
189                         }
190                         printf("marked %i more samples as written\n", bytes_unmarked / sizeof(sampl_t));
191                 }else
192                         usleep(10000);
193         }
194         return 0;
195 }
196