3 * Copyright 2005 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
29 #include <comedi_source_s.h>
30 #include <gr_io_signature.h>
35 #include <gri_comedi.h>
38 // FIXME these should query some kind of user preference
42 default_device_name ()
44 return "/dev/comedi0";
47 // ----------------------------------------------------------------
50 comedi_make_source_s (int sampling_freq, const std::string dev)
52 return comedi_source_s_sptr (new comedi_source_s (sampling_freq, dev));
55 comedi_source_s::comedi_source_s (int sampling_freq,
56 const std::string device_name)
57 : gr_sync_block ("comedi_source_s",
58 gr_make_io_signature (0, 0, 0),
59 gr_make_io_signature (0, 0, 0)),
60 d_sampling_freq (sampling_freq),
61 d_device_name (device_name.empty() ? default_device_name() : device_name),
63 d_subdevice (0/*COMEDI_SUBD_AI*/),
64 d_n_chan (1), // number of input channels
73 d_dev = comedi_open(d_device_name.c_str());
75 comedi_perror(d_device_name.c_str());
76 throw std::runtime_error ("comedi_source_s");
79 unsigned int chanlist[256];
81 for(int i=0; i<d_n_chan; i++){
82 chanlist[i]=CR_PACK(i,range,aref);
88 ret = comedi_get_cmd_generic_timed(d_dev,d_subdevice,&cmd,(unsigned int)(1e9/sampling_freq));
90 bail ("comedi_get_cmd_generic_timed", comedi_errno());
92 // TODO: check period_ns is not to far off sampling_freq
94 d_buffer_size = comedi_get_buffer_size(d_dev, d_subdevice);
95 if (d_buffer_size <= 0)
96 bail ("comedi_get_buffer_size", comedi_errno());
98 d_map = mmap(NULL,d_buffer_size,PROT_READ,MAP_SHARED,comedi_fileno(d_dev),0);
99 if (d_map == MAP_FAILED)
100 bail ("mmap", errno);
102 cmd.chanlist = chanlist;
103 cmd.chanlist_len = d_n_chan;
104 cmd.scan_end_arg = d_n_chan;
106 cmd.stop_src=TRIG_NONE;
109 /* comedi_command_test() tests a command to see if the
110 * trigger sources and arguments are valid for the subdevice.
111 * If a trigger source is invalid, it will be logically ANDed
112 * with valid values (trigger sources are actually bitmasks),
113 * which may or may not result in a valid trigger source.
114 * If an argument is invalid, it will be adjusted to the
115 * nearest valid value. In this way, for many commands, you
116 * can test it multiple times until it passes. Typically,
117 * if you can't get a valid command in two tests, the original
118 * command wasn't specified very well. */
119 ret = comedi_command_test(d_dev,&cmd);
122 bail ("comedi_command_test", comedi_errno());
124 ret = comedi_command_test(d_dev,&cmd);
127 bail ("comedi_command_test", comedi_errno());
129 /* start the command */
130 ret = comedi_command(d_dev,&cmd);
133 bail ("comedi_command", comedi_errno());
135 set_output_multiple (d_n_chan*sizeof(sampl_t));
137 assert(sizeof(sampl_t) == sizeof(short));
138 set_output_signature (gr_make_io_signature (1, 1, sizeof (sampl_t)));
142 comedi_source_s::check_topology (int ninputs, int noutputs)
144 if (noutputs > d_n_chan)
145 throw std::runtime_error ("comedi_source_s");
150 comedi_source_s::~comedi_source_s ()
153 munmap(d_map, d_buffer_size);
161 comedi_source_s::work (int noutput_items,
162 gr_vector_const_void_star &input_items,
163 gr_vector_void_star &output_items)
167 int work_left = noutput_items * sizeof(sampl_t) * d_n_chan;
168 sampl_t *pbuf = (sampl_t*)d_map;
173 ret = comedi_get_buffer_contents(d_dev,d_subdevice);
175 bail ("comedi_get_buffer_contents", comedi_errno());
177 assert(ret % sizeof(sampl_t) == 0);
178 assert(work_left % sizeof(sampl_t) == 0);
180 ret = std::min(ret, work_left);
183 assert(d_buffer_size%d_n_chan == 0);
184 if (d_buf_front-d_buf_back > (unsigned)d_buffer_size) {
185 d_buf_front+=d_buffer_size;
186 d_buf_back +=d_buffer_size;
189 if(d_buf_front==d_buf_back){
190 usleep(1000000*std::min(work_left,d_buffer_size/2)/(d_sampling_freq*sizeof(sampl_t)*d_n_chan));
193 } while (d_buf_front==d_buf_back);
195 for(unsigned i=d_buf_back/sizeof(sampl_t);i<d_buf_front/sizeof(sampl_t);i++){
196 int chan = i%d_n_chan;
197 int o_idx = noutput_items-work_left/d_n_chan/sizeof(sampl_t)+(i-d_buf_back/sizeof(sampl_t))/d_n_chan;
199 if (output_items[chan])
200 ((short*)(output_items[chan]))[o_idx] =
201 (int)pbuf[i%(d_buffer_size/sizeof(sampl_t))] - 32767;
204 ret = comedi_mark_buffer_read(d_dev,d_subdevice,d_buf_front-d_buf_back);
206 bail ("comedi_mark_buffer_read", comedi_errno());
208 work_left -= d_buf_front-d_buf_back;
210 d_buf_back = d_buf_front;
212 } while(work_left>0);
214 return noutput_items;
218 comedi_source_s::output_error_msg (const char *msg, int err)
220 fprintf (stderr, "comedi_source_s[%s]: %s: %s\n",
221 d_device_name.c_str(), msg, comedi_strerror(err));
225 comedi_source_s::bail (const char *msg, int err) throw (std::runtime_error)
227 output_error_msg (msg, err);
228 throw std::runtime_error ("comedi_source_s");