3 * Copyright 2004,2008 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 3, 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.
23 //#define MSDD_DEBUG_TRUE
24 //#define MSDD_DEBUG2_TRUE
30 #include <msdd_source_base.h>
31 #include <gr_io_signature.h>
33 #include <omnithread.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 #include <sys/socket.h>
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
48 #ifdef MSDD_DEBUG_TRUE
49 #define MSDD_DEBUG(x) std::cout << x << std::endl;
55 #ifdef MSDD_DEBUG2_TRUE
56 #define MSDD_DEBUG2(x) std::cout << x << std::endl;
58 #define MSDD_DEBUG2(x)
63 const int OUTPUT_MAX((1 << 15)*8);
64 const double PGA_MAX(75);
65 const double PGA_MIN(10);
66 const double PGA_STEP(.5);
67 const double DEFAULT_RX_FREQ(2.417e6);
68 const double DEFAULT_GAIN(32);
69 const msdd_source_base::msdd_fft_mode_t DEFAULT_FFT_MODE(msdd_source_base::MODE_MAG);
70 const msdd_source_base::msdd_fft_points_t DEFAULT_FFT_POINTS(msdd_source_base::S8192);
71 const msdd_source_base::msdd_decimation_t DEFAULT_DECIMATION_RATE(msdd_source_base::D2);
74 class msdd_source_base::Impl {
79 d_deci_rate (DEFAULT_DECIMATION_RATE),
80 d_rx_freq ((unsigned long) DEFAULT_RX_FREQ),
84 d_msdd_command_type((msdd_command_type_t) opp_mode),
85 d_msdd_fft_mode(DEFAULT_FFT_MODE),
86 d_desired_sample_size(2^15),
87 d_fft_points (DEFAULT_FFT_POINTS)
93 msdd_decimation_t d_deci_rate;
94 unsigned long d_rx_freq;
98 msdd_command_type_t d_msdd_command_type;
99 msdd_fft_mode_t d_msdd_fft_mode;
100 unsigned long d_desired_sample_size;
102 int d_socket; // handle to socket
103 int d_socket_rcv; // handle to socket retuned in the accept call
104 struct in_addr d_ip_src; // store the source IP address to use
105 unsigned short d_port_src; // the port number to open for connections to this service
106 sockaddr_in d_sockaddr_src; // store the source sockaddr data (formatted IP address and port number)
107 std::auto_ptr<unsigned char> d_temp_buff; // hold buffer between calls
110 msdd_fft_points_t d_fft_points;
112 struct msdd_request_fft_packet {
113 msdd_command_type_t command_type;
115 unsigned int center_freq_mhz;
118 msdd_fft_window_type_t window_type;
119 msdd_fft_points_t fft_points;
120 msdd_decimation_t decimation;
121 msdd_fft_mode_t fft_mode;
123 } __attribute__((__packed__));
125 struct msdd_request_iq_packet {
126 msdd_command_type_t command_type;
128 unsigned int center_freq_mhz;
132 msdd_decimation_t decimation;
134 } __attribute__((__packed__));
136 void make_request_fft_packet(msdd_request_fft_packet& packet);
138 void make_request_iq_packet(msdd_request_iq_packet& packet, unsigned int number_samples);
140 msdd_request_fft_packet d_fft_request_packet; // fft request packet
141 msdd_request_iq_packet d_iq_request_packet; // fft request packet
145 msdd_source_base::msdd_source_base (const std::string &name,
146 gr_io_signature_sptr output_signature,
150 unsigned short port_src
151 ) throw (std::runtime_error)
152 : gr_sync_block (name,
153 gr_make_io_signature (0, 0, 0),
155 pimpl( new Impl(opp_mode))
160 // Set up the address stucture for the source address and port numbers
161 // Get the source IP address from the host name
162 struct hostent *hsrc (gethostbyname(src));
164 if(hsrc) { // if the source was provided as a host namex
165 pimpl->d_ip_src = *(struct in_addr*)hsrc->h_addr_list[0];
167 else { // assume it was specified as an IP address
168 if((ret=inet_aton(src, &pimpl->d_ip_src)) == 0) { // format IP address
169 perror("Not a valid source IP address or host name");
170 throw std::runtime_error("can't initialize source socket");
174 pimpl->d_port_src = htons(port_src); // format port number
176 pimpl->d_sockaddr_src.sin_family = AF_INET;
177 pimpl->d_sockaddr_src.sin_addr = pimpl->d_ip_src;
178 pimpl->d_sockaddr_src.sin_port = pimpl->d_port_src;
180 pimpl->d_temp_buff.reset(new unsigned char[OUTPUT_MAX +
181 std::max(sizeof(Impl::msdd_request_iq_packet),
182 sizeof(Impl::msdd_request_fft_packet))]); // allow it to hold up to payload_size bytes
184 set_output_multiple (OUTPUT_MAX / output_signature->sizeof_stream_item (0));
189 msdd_source_base::open()
191 omni_mutex_lock l(pimpl->d_mutex); // hold mutex for duration of this function
193 MSDD_DEBUG2("MSDD: Before socket ")
194 pimpl->d_socket = socket(PF_INET, SOCK_STREAM, 0);
195 if(pimpl->d_socket == -1) {
196 perror("socket open");
197 throw std::runtime_error("can't open socket");
200 // Turn on reuse address
202 if(setsockopt(pimpl->d_socket, SOL_SOCKET, SO_REUSEADDR, (void*)&opt_val, sizeof(int)) == -1) {
203 perror("SO_REUSEADDR");
204 throw std::runtime_error("can't set socket option SO_REUSEADDR");
207 // Don't wait when shutting down
211 if(setsockopt(pimpl->d_socket, SOL_SOCKET, SO_LINGER, (void*)&lngr, sizeof(linger)) == -1) {
213 throw std::runtime_error("can't set socket option SO_LINGER");
216 // Set a timeout on the receive function to not block indefinitely
217 // This value can (and probably should) be changed
219 // timeout.tv_sec = 1;
220 // timeout.tv_usec = 0;
221 // if(setsockopt(d_socket, SOL_SOCKET, SO_RCVTIMEO, (void*)&timeout, sizeof(timeout)) == -1) {
222 // perror("SO_RCVTIMEO");
223 // throw std::runtime_error("can't set socket option SO_RCVTIMEO");
226 // bind socket to an address and port number to listen on
227 MSDD_DEBUG2("MSDD: Before socket bind to " << pimpl->d_sockaddr_src.sin_port)
228 if(::connect(pimpl->d_socket, (struct sockaddr*)&pimpl->d_sockaddr_src, sizeof(pimpl->d_sockaddr_src)) == -1) {
229 perror("socket bind");
230 throw std::runtime_error("can't bind socket");
233 MSDD_DEBUG2("MSDD: Socket open")
234 pimpl->d_updated = true;
235 return pimpl->d_socket != 0;
238 /* read n bytes from a socket descriptor */
240 msdd_source_base::readsock(int sockfd, unsigned char* buf, int nbytes) {
245 MSDD_DEBUG2("MSDD: Before socket read: " << nleft)
246 if ((nread = ::read(sockfd, buf, nleft)) < 0) {
247 return(nread); /* error, nread < 0 */
248 } else if (nread == 0) {
255 return(nbytes - nleft);
259 msdd_source_base::close()
261 omni_mutex_lock l(pimpl->d_mutex); // hold mutex for duration of this function
263 if (pimpl->d_socket){
264 shutdown(pimpl->d_socket, SHUT_RDWR);
267 pimpl->d_updated = true;
272 msdd_source_base::~msdd_source_base ()
274 msdd_source_base::close();
278 msdd_source_base::sizeof_basic_sample() const
280 switch (pimpl->d_msdd_command_type) {
281 case SAMPLES_REALTIME:
284 switch (pimpl->d_msdd_fft_mode) {
291 assert (false); // bad mode
294 assert (false); // bad mode
299 msdd_source_base::start()
301 return msdd_source_base::open();
305 msdd_source_base::stop()
307 return msdd_source_base::close();
311 msdd_source_base::make_request_packet(unsigned int& size, unsigned int number_samples) {
312 switch (pimpl->d_msdd_command_type) {
313 case SAMPLES_REALTIME:
314 pimpl->make_request_iq_packet(pimpl->d_iq_request_packet, number_samples);
315 size = sizeof (pimpl->d_iq_request_packet);
316 return &pimpl->d_iq_request_packet;
318 pimpl->make_request_fft_packet(pimpl->d_fft_request_packet);
319 size = sizeof (pimpl->d_fft_request_packet);
320 return &pimpl->d_fft_request_packet;
322 assert (false); // bad mode
327 msdd_source_base::Impl::make_request_fft_packet(msdd_request_fft_packet& packet)
329 packet.command_type = SAMPLES_FFT; // FFT samples Command
330 packet.foo_x20 = 0x20;
331 packet.center_freq_mhz = d_rx_freq;
332 packet.offset_freq_hz = 0;
333 packet.gain = (int) d_gain; // gain
334 packet.window_type = WINDOW_HANNING; // magic number
335 packet.fft_points = d_fft_points;
336 packet.decimation = d_deci_rate;
337 packet.fft_mode = MODE_MAGDB;
338 packet.number_sets = 1;
342 msdd_source_base::Impl::make_request_iq_packet(msdd_request_iq_packet& packet, unsigned int number_samples)
344 packet.command_type = SAMPLES_REALTIME; // FFT samples Command
345 packet.foo0x18 = 0x18; // magic number
346 packet.center_freq_mhz = d_rx_freq;
347 packet.offset_freq_hz = 0;
348 packet.gain = (int) d_gain; // gain
349 packet.number = number_samples * 4;
350 packet.decimation = d_deci_rate;
351 packet.number_sets = 1;
355 msdd_source_base::work (int noutput_items,
356 gr_vector_const_void_star &input_items,
357 gr_vector_void_star &output_items)
359 int output_index (0);
360 int output_items_produced;
363 unsigned int packet_size;
365 MSDD_DEBUG("MSDD: requested items: " << noutput_items)
366 int noutput_items_desired = std::min (noutput_items, (int) pimpl->d_desired_sample_size);
367 MSDD_DEBUG("MSDD: desired items: " << noutput_items_desired)
369 while (output_index < noutput_items_desired){
371 int nbytes = (pimpl->d_msdd_command_type == SAMPLES_REALTIME) ?
372 ninput_bytes_reqd_for_noutput_items (noutput_items_desired - output_index) :
373 ninput_bytes_reqd_for_noutput_items (msdd_source_base::fft_points());
375 void* request_packet = msdd_source_base::make_request_packet(packet_size, noutput_items_desired);
377 nbytes = std::min (nbytes, OUTPUT_MAX);
378 MSDD_DEBUG2("MSDD: payload sizes: nbytes1: " << nbytes )
381 int result_nbytes = ::write(pimpl->d_socket, request_packet, packet_size);
382 //assert (result_nbytes == sizeof(msdd_request_packet));
385 result_nbytes = ::read (pimpl->d_socket, (unsigned char*) request_packet, packet_size);
386 MSDD_DEBUG2("MSDD: response: " << result_nbytes)
387 //assert (result_nbytes == sizeof(msdd_request_packet));
390 result_nbytes = msdd_source_base::readsock (pimpl->d_socket, pimpl->d_temp_buff.get(), nbytes);
391 MSDD_DEBUG("MSDD: reading bytes: " << nbytes << " received: " << result_nbytes)
392 if (result_nbytes > (int) nbytes){
393 // fprintf (stderr, "msdd_source: overrun\n");
394 fputs ("uO", stderr);
395 pimpl->d_noverruns++;
396 result_nbytes = nbytes; // truncate
399 if (result_nbytes < 0) // We've got a problem. Usually board unplugged or powered down.
400 return -1; // Indicate we're done.
402 if (result_nbytes != nbytes){ // not really an error, but unexpected
403 fprintf (stderr, "msdd_source: short read. Expected %d, got %d\n",
404 nbytes, result_nbytes);
407 copy_from_msdd_buffer (output_items,
409 noutput_items_desired - output_index, // output_items_available
410 output_items_produced, // [out]
411 pimpl->d_temp_buff.get(), // usrp_buffer
413 bytes_read); // [out]
415 output_index += output_items_produced;
417 if (pimpl->d_msdd_command_type == SAMPLES_FFT) break;
420 MSDD_DEBUG("MSDD: items produced: " << output_items_produced << " index: " << output_index)
428 msdd_source_base::set_decim_rate (unsigned int rate)
433 pimpl->d_deci_rate = D0;
436 pimpl->d_deci_rate = D1;
439 pimpl->d_deci_rate = D2;
442 pimpl->d_deci_rate = D3;
445 pimpl->d_deci_rate = D4;
448 pimpl->d_deci_rate = D5;
451 pimpl->d_deci_rate = D6;
454 pimpl->d_deci_rate = D7;
457 pimpl->d_deci_rate = D8;
467 //msdd_source_base::set_nchannels (int nchan)
469 // // return d_usrp->set_nchannels (nchan);
474 //msdd_source_base::set_mux (int mux)
476 // return d_usrp->set_mux (mux);
480 msdd_source_base::set_rx_freq (int channel, double freq)
482 assert (channel == 0);
485 if (freq >= 30e6 && freq <= 6e9) {
486 pimpl->d_rx_freq = (unsigned long) freq / 1000000;
495 msdd_source_base::set_fft_size (int channel, unsigned long fft_size)
497 assert (channel == 1);
501 pimpl->d_fft_points = S256;
504 pimpl->d_fft_points = S512;
507 pimpl->d_fft_points = S1024;
510 pimpl->d_fft_points = S2048;
513 pimpl->d_fft_points = S4096;
516 pimpl->d_fft_points = S8192;
519 pimpl->d_fft_points = S16384;
522 pimpl->d_fft_points = S32768;
526 return msdd_source_base::fft_points();
531 //msdd_source_base::fpga_master_clock_freq() const
533 // return d_usrp->fpga_master_clock_freq();
537 //msdd_source_base::converter_rate() const
539 // // return d_usrp->converter_rate();
544 msdd_source_base::decim_rate () const
546 return 1 << pimpl->d_deci_rate;
550 //msdd_source_base::nchannels () const
552 // return d_usrp->nchannels ();
556 //msdd_source_base::mux () const
558 // return d_usrp->mux ();
562 msdd_source_base::rx_freq (int channel) const
564 assert (channel == 0);
566 return pimpl->d_rx_freq;
570 msdd_source_base::fft_points() const
572 return (1 << pimpl->d_fft_points);
576 msdd_source_base::noverruns () const
578 return pimpl->d_noverruns;
582 //msdd_source_base::set_fpga_mode (int mode)
584 // return d_usrp->set_fpga_mode (mode);
588 //msdd_source_base::set_ddc_phase (int channel, int phase)
590 // return d_usrp->set_ddc_phase(channel, phase);
594 //msdd_source_base::set_dc_offset_cl_enable(int bits, int mask)
596 // return d_usrp->set_dc_offset_cl_enable(bits, mask);
600 msdd_source_base::set_verbose (bool verbose)
602 pimpl->d_verbose = verbose;
606 //msdd_source_base::write_aux_dac (int which_dboard, int which_dac, int value)
608 // return d_usrp->write_aux_dac (which_dboard, which_dac, value);
612 //msdd_source_base::read_aux_adc (int which_dboard, int which_adc)
614 // return d_usrp->read_aux_adc (which_dboard, which_adc);
618 //msdd_source_base::write_eeprom (int i2c_addr, int eeprom_offset, const std::string buf)
620 // return d_usrp->write_eeprom (i2c_addr, eeprom_offset, buf);
624 //msdd_source_base::read_eeprom (int i2c_addr, int eeprom_offset, int len)
626 // return d_usrp->read_eeprom (i2c_addr, eeprom_offset, len);
630 //msdd_source_base::write_i2c (int i2c_addr, const std::string buf)
632 // return d_usrp->write_i2c (i2c_addr, buf);
636 //msdd_source_base::read_i2c (int i2c_addr, int len)
638 // return d_usrp->read_i2c (i2c_addr, len);
642 msdd_source_base::set_pga (int which, double gain)
644 if (gain >= PGA_MIN && gain <= PGA_MAX) {
645 pimpl->d_gain = gain;
652 msdd_source_base::pga (int which) const
654 return pimpl->d_gain;
658 msdd_source_base::pga_min () const
664 msdd_source_base::pga_max () const
670 msdd_source_base::pga_db_per_step () const
676 //msdd_source_base::daughterboard_id (int which) const
678 // return d_usrp->daughterboard_id (which);
683 //msdd_source_base::set_adc_offset (int which, int offset)
685 // return d_usrp->set_adc_offset (which, offset);
689 //msdd_source_base::set_dac_offset (int which, int offset, int offset_pin)
691 // return d_usrp->set_dac_offset (which, offset, offset_pin);
695 //msdd_source_base::set_adc_buffer_bypass (int which, bool bypass)
697 // return d_usrp->set_adc_buffer_bypass (which, bypass);
701 msdd_source_base::serial_number()
703 return "SoftTronics MSDD 6000";
707 //msdd_source_base::_write_oe (int which_dboard, int value, int mask)
709 // return d_usrp->_write_oe (which_dboard, value, mask);
713 //msdd_source_base::write_io (int which_dboard, int value, int mask)
715 // return d_usrp->write_io (which_dboard, value, mask);
719 //msdd_source_base::read_io (int which_dboard)
721 // return d_usrp->read_io (which_dboard);
727 //// internal routines...
730 //msdd_source_base::_write_fpga_reg (int regno, int value)
732 // return d_usrp->_write_fpga_reg (regno, value);
736 //msdd_source_base::_write_fpga_reg_masked (int regno, int value, int mask)
738 // return d_usrp->_write_fpga_reg_masked (regno, value, mask);
742 //msdd_source_base::_read_fpga_reg (int regno)
744 // return d_usrp->_read_fpga_reg (regno);
748 //msdd_source_base::_write_9862 (int which_codec, int regno, unsigned char value)
750 // return d_usrp->_write_9862 (which_codec, regno, value);
754 //msdd_source_base::_read_9862 (int which_codec, int regno) const
756 // return d_usrp->_read_9862 (which_codec, regno);
760 //msdd_source_base::_write_spi (int optional_header, int enables,
761 // int format, std::string buf)
763 // return d_usrp->_write_spi (optional_header, enables, format, buf);
767 //msdd_source_base::_read_spi (int optional_header, int enables, int format, int len)
769 // return d_usrp->_read_spi (optional_header, enables, format, len);
773 //msdd_source_base::set_format(unsigned int format)
775 // return d_usrp->set_format(format);
779 //msdd_source_base::format() const
781 // return d_usrp->format();
785 //msdd_source_base::make_format(int width, int shift, bool want_q, bool bypass_halfband)
787 // return usrp_standard_rx::make_format(width, shift, want_q, bypass_halfband);
791 //msdd_source_base::format_width(unsigned int format)
793 // return usrp_standard_rx::format_width(format);
797 //msdd_source_base::format_shift(unsigned int format)
799 // return usrp_standard_rx::format_shift(format);
803 //msdd_source_base::format_want_q(unsigned int format)
805 // return usrp_standard_rx::format_want_q(format);
809 //msdd_source_base::format_bypass_halfband(unsigned int format)
811 // return usrp_standard_rx::format_bypass_halfband(format);
814 bool msdd_source_base::set_desired_packet_size (int which, unsigned long packet_size) {
817 //if (pimpl->d_desired_sample_size < 2^32) { // FIXME: find maximum sample request for MSDD check if greater than
818 if (pimpl->d_desired_sample_size < LONG_MAX) { // FIXME: find maximum sample request for MSDD check if greater than
819 pimpl->d_desired_sample_size = packet_size;
825 unsigned long msdd_source_base::desired_packet_size (int which) const {
826 return pimpl->d_desired_sample_size;