added memory mapped ao waveform demo (untested)
[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         int n,m;
74         int total=0;
75         comedi_t *dev;
76         unsigned int chanlist[16];
77         unsigned int maxdata;
78         comedi_range *rng;
79         int ret;
80         int size;
81         sampl_t *map;
82         /* peak-to-peak amplitude, in DAC units (i.e., 0-4095) */
83         double amplitude;
84         /* offset, in DAC units */
85         double offset;
86         int subdevice;
87
88         
89         parse_options(argc,argv);
90
91         /* Force n_chan to be 1 */
92         n_chan = 1;
93
94         dev = comedi_open(filename);
95         if(dev == NULL){
96                 fprintf(stderr, "error opening %s\n", filename);
97                 return -1;
98         }
99         subdevice = comedi_find_subdevice_by_type(dev,COMEDI_SUBD_AO,0);
100
101         maxdata = comedi_get_maxdata(dev,subdevice,0);
102         rng = comedi_get_range(dev,subdevice,0,0);
103
104         offset = (double)comedi_from_phys(0.0, rng, maxdata);
105         amplitude = (double)comedi_from_phys(1.0, rng, maxdata) - offset;
106
107         memset(&cmd,0,sizeof(cmd));
108         cmd.subdev = subdevice;
109         cmd.flags = 0;
110         cmd.start_src = TRIG_INT;
111         cmd.start_arg = 0;
112         cmd.scan_begin_src = TRIG_TIMER;
113         cmd.scan_begin_arg = 1e9/freq;
114         cmd.convert_src = TRIG_NOW;
115         cmd.convert_arg = 0;
116         cmd.scan_end_src = TRIG_COUNT;
117         cmd.scan_end_arg = n_chan;
118         cmd.stop_src = TRIG_NONE;
119         cmd.stop_arg = 0;
120
121         cmd.chanlist = chanlist;
122         cmd.chanlist_len = n_chan;
123
124         chanlist[0] = CR_PACK(channel,range,aref);
125
126         dump_cmd(stdout,&cmd);
127
128         err = comedi_command_test(dev, &cmd);
129         if (err < 0) {
130                 comedi_perror("comedi_command_test");
131                 exit(1);
132         }
133
134         err = comedi_command_test(dev, &cmd);
135         if (err < 0) {
136                 comedi_perror("comedi_command_test");
137                 exit(1);
138         }
139
140         if ((err = comedi_command(dev, &cmd)) < 0) {
141                 comedi_perror("comedi_command");
142                 exit(1);
143         }
144         
145         size = comedi_get_buffer_size(dev, subdevice);
146         fprintf(stderr, "buffer size is %d\n", size);
147         map = mmap(NULL, size, PROT_WRITE, MAP_SHARED, comedi_fileno(dev), 0);
148         if(map == MAP_FAILED)
149         {
150                 perror("mmap");
151                 exit(1);
152         }
153         write_waveform(map, size, amplitude, offset, maxdata);
154         if(msync(map, size, MS_SYNC) < 0)
155         {
156                 perror("msync");
157                 exit(1);
158         }
159         ret = comedi_internal_trigger(dev, subdevice, 0);
160         if(ret<0){
161                 comedi_perror("comedi_internal_trigger\n");
162                 exit(1);
163         }
164         while(1){
165                 int bytes_marked = comedi_get_buffer_contents(dev,subdevice);
166                 if(bytes_marked < 1)
167                 {
168                         comedi_perror("comedi_get_buffer_contents");
169                         exit(1);
170                 }
171                 int bytes_unmarked = size - bytes_marked;
172                 // this keeps comedi from reporting a buffer underrun
173                 if(comedi_mark_buffer_written(dev, subdevice, bytes_unmarked) < 0)
174                 {
175                         comedi_perror("comedi_mark_buffer_written");
176                         exit(1);
177                 }
178         }
179         return 0;
180 }
181