summaryrefslogtreecommitdiff
path: root/usrp2/host
diff options
context:
space:
mode:
Diffstat (limited to 'usrp2/host')
-rw-r--r--usrp2/host/apps/Makefile.am5
-rwxr-xr-xusrp2/host/apps/stdin_int32_fft.py4
-rw-r--r--usrp2/host/apps/tx_samples.cc4
-rw-r--r--usrp2/host/include/usrp2/usrp2.h69
-rw-r--r--usrp2/host/lib/Makefile.am9
-rw-r--r--usrp2/host/lib/control.cc23
-rw-r--r--usrp2/host/lib/control.h34
-rw-r--r--usrp2/host/lib/ring.cc14
-rw-r--r--usrp2/host/lib/ring.h8
-rw-r--r--usrp2/host/lib/usrp2.cc62
-rw-r--r--usrp2/host/lib/usrp2_impl.cc379
-rw-r--r--usrp2/host/lib/usrp2_impl.h40
-rw-r--r--usrp2/host/lib/usrp2_thread.cc64
-rw-r--r--usrp2/host/lib/usrp2_thread.h47
-rw-r--r--usrp2/host/usrp2.pc.in2
15 files changed, 441 insertions, 323 deletions
diff --git a/usrp2/host/apps/Makefile.am b/usrp2/host/apps/Makefile.am
index db7660196..4a26898fa 100644
--- a/usrp2/host/apps/Makefile.am
+++ b/usrp2/host/apps/Makefile.am
@@ -24,9 +24,8 @@ AM_CPPFLAGS = \
$(GRUEL_INCLUDES)
LDADD = \
- $(USRP2_LA) \
- $(GRUEL_LA) \
- $(OMNITHREAD_LA)
+ $(USRP2_LA) \
+ $(GRUEL_LA)
bin_PROGRAMS = \
find_usrps \
diff --git a/usrp2/host/apps/stdin_int32_fft.py b/usrp2/host/apps/stdin_int32_fft.py
index 5391863a5..1596fa00d 100755
--- a/usrp2/host/apps/stdin_int32_fft.py
+++ b/usrp2/host/apps/stdin_int32_fft.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2004,2005,2007,2008 Free Software Foundation, Inc.
+# Copyright 2004,2005,2007,2008,2010 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -152,7 +152,7 @@ class app_top_block(stdgui2.std_top_block):
if True:
self.myform['freq'].set_value(target_freq) # update displayed value
if not self.options.waterfall and not self.options.oscilloscope:
- self.scope.win.set_baseband_freq(target_freq)
+ self.scope.set_baseband_freq(target_freq)
return True
return False
diff --git a/usrp2/host/apps/tx_samples.cc b/usrp2/host/apps/tx_samples.cc
index 5c3728fb1..3e41bbf8d 100644
--- a/usrp2/host/apps/tx_samples.cc
+++ b/usrp2/host/apps/tx_samples.cc
@@ -150,6 +150,10 @@ main(int argc, char **argv)
interp = strtol(optarg, 0, 0);
break;
+ case 'g':
+ gain = strtod(optarg, 0);
+ break;
+
case 'S':
if (!strtod_si(optarg, &tmp)){
std::cerr << "invalid number: " << optarg << std::endl;
diff --git a/usrp2/host/include/usrp2/usrp2.h b/usrp2/host/include/usrp2/usrp2.h
index 7a612f945..7069507cf 100644
--- a/usrp2/host/include/usrp2/usrp2.h
+++ b/usrp2/host/include/usrp2/usrp2.h
@@ -60,7 +60,7 @@ namespace usrp2 {
*
* \returns a vector of properties, 1 entry for each matching USRP2 found.
*/
- props_vector_t find(const std::string &ifc, const std::string &mac_addr="");
+ props_vector_t find(const std::string &ifc, const std::string &mac_addr="");
class tune_result;
@@ -79,10 +79,10 @@ namespace usrp2 {
/*!
* Shared pointer to this class
- */
+ */
typedef boost::shared_ptr<usrp2> sptr;
-
- /*!
+
+ /*!
* Static function to return an instance of usrp2 as a shared pointer
*
* \param ifc Network interface name, e.g., "eth0"
@@ -96,7 +96,7 @@ namespace usrp2 {
/*!
* Class destructor
*/
- ~usrp2();
+ ~usrp2();
/*!
* Returns the MAC address associated with this USRP
@@ -115,15 +115,20 @@ namespace usrp2 {
*/
/*!
+ * Set the rx antenna
+ */
+ bool set_rx_antenna(int ant);
+
+ /*!
* Set receiver gain
* \param gain in dB (more or less)
*/
bool set_rx_gain(double gain);
- //! return minimum Rx gain
+ //! return minimum Rx gain
double rx_gain_min();
- //! return maximum Rx gain
+ //! return maximum Rx gain
double rx_gain_max();
//! return Rx gain db_per_step
@@ -160,7 +165,7 @@ namespace usrp2 {
/*!
* Set received sample format
- *
+ *
* domain: complex or real
* type: floating, fixed point, or raw
* depth: bits per sample
@@ -172,12 +177,33 @@ namespace usrp2 {
/*!
* Start streaming receive mode. USRP2 will send a continuous stream of
* DSP pipeline samples to host. Call rx_samples(...) to access.
- *
+ *
* \param channel Stream channel number (0-30)
* \param items_per_frame Number of 32-bit items per frame.
*/
bool start_rx_streaming(unsigned int channel=0, unsigned int items_per_frame=0);
-
+
+ /*!
+ * Start streaming receive mode at specified timestamp. USRP2 will send a
+ * continuous stream of DSP pipeline samples to host. Call rx_samples(...)
+ * to access.
+ *
+ * \param channel Stream channel number (0-30)
+ * \param items_per_frame Number of 32-bit items per frame.
+ * \param time Timestamp to start streaming at
+ */
+ bool start_rx_streaming_at(unsigned int channel=0, unsigned int items_per_frame=0, unsigned int time=0);
+
+ /*!
+ * Sync to PPS and start streaming receive mode at specified timestamp.
+ * Just like calling sync_to_pps() and start_rx_streaming_at().
+ *
+ * \param channel Stream channel number (0-30)
+ * \param items_per_frame Number of 32-bit items per frame.
+ * \param time Timestamp to start streaming at
+ */
+ bool sync_and_start_rx_streaming_at(unsigned int channel=0, unsigned int items_per_frame=0, uint32_t time=0);
+
/*!
* Stop streaming receive mode.
*/
@@ -193,7 +219,7 @@ namespace usrp2 {
* Returns number of times receive overruns have occurred
*/
unsigned int rx_overruns();
-
+
/*!
* Returns total number of missing frames from overruns.
*/
@@ -206,14 +232,19 @@ namespace usrp2 {
*/
/*!
+ * Set the tx antenna
+ */
+ bool set_tx_antenna(int ant);
+
+ /*!
* Set transmitter gain
*/
bool set_tx_gain(double gain);
- //! return minimum Tx gain
+ //! return minimum Tx gain
double tx_gain_min();
- //! return maximum Tx gain
+ //! return maximum Tx gain
double tx_gain_max();
//! return Tx gain db_per_step
@@ -255,7 +286,7 @@ namespace usrp2 {
/*!
* Set transmit sample format
- *
+ *
* domain: complex or real
* type: floating, fixed point, or raw
* depth: bits per sample
@@ -272,7 +303,7 @@ namespace usrp2 {
* \param nsamples is the number of samples to transmit
* \param metadata provides the timestamp and flags
*
- * The complex<float> samples are converted to the appropriate
+ * The complex<float> samples are converted to the appropriate
* "on the wire" representation, depending on the current USRP2
* configuration. Typically, this is big-endian 16-bit I & Q.
*/
@@ -400,12 +431,12 @@ namespace usrp2 {
*
* \param addr 32-bit aligned address. Only the lower 16-bits are significant.
* \param words Number of 32-bit words
- *
+ *
* \returns Vector of 32-bit read values
*
* WARNING: Attempts to read memory from addresses that do not correspond to RAM or
* memory-mapped peripherals may cause the USRP2 to hang, requiring a power cycle.
- *
+ *
*/
std::vector<uint32_t> peek32(uint32_t addr, uint32_t words);
@@ -419,7 +450,7 @@ namespace usrp2 {
*
* WARNING: Attempts to read memory from addresses that do not correspond to RAM or
* memory-mapped peripherals may cause the USRP2 to hang, requiring a power cycle.
- *
+ *
*/
bool poke32(uint32_t addr, const std::vector<uint32_t> &data);
@@ -587,7 +618,7 @@ namespace usrp2 {
// Only class members can instantiate this class
usrp2(const std::string &ifc, props *p, size_t rx_bufsize);
-
+
// All private state is held in opaque pointer
std::auto_ptr<impl> d_impl;
};
diff --git a/usrp2/host/lib/Makefile.am b/usrp2/host/lib/Makefile.am
index 772cf1446..cda051bb0 100644
--- a/usrp2/host/lib/Makefile.am
+++ b/usrp2/host/lib/Makefile.am
@@ -1,5 +1,5 @@
#
-# Copyright 2007,2008 Free Software Foundation, Inc.
+# Copyright 2007,2008,2010 Free Software Foundation, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -45,11 +45,9 @@ libusrp2_la_SOURCES = \
rx_sample_handler.cc \
strtod_si.c \
usrp2.cc \
- usrp2_impl.cc \
- usrp2_thread.cc
+ usrp2_impl.cc
libusrp2_la_LIBADD = \
- $(OMNITHREAD_LA) \
$(GRUEL_LA) \
$(BOOST_LDFLAGS) $(BOOST_THREAD_LIB)
@@ -63,5 +61,4 @@ noinst_HEADERS = \
pktfilter.h \
ring.h \
usrp2_bytesex.h \
- usrp2_impl.h \
- usrp2_thread.h
+ usrp2_impl.h \ No newline at end of file
diff --git a/usrp2/host/lib/control.cc b/usrp2/host/lib/control.cc
index bb71f79c2..33a95c078 100644
--- a/usrp2/host/lib/control.cc
+++ b/usrp2/host/lib/control.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2008 Free Software Foundation, Inc.
+ * Copyright 2008,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -23,14 +23,14 @@
#include <config.h>
#endif
-#include <gnuradio/omni_time.h>
#include "control.h"
#include <iostream>
+#include <gruel/thread.h>
namespace usrp2 {
pending_reply::pending_reply(unsigned int rid, void *buffer, size_t len)
- : d_rid(rid), d_buffer(buffer), d_len(len), d_mutex(), d_cond(&d_mutex),
+ : d_rid(rid), d_buffer(buffer), d_len(len), d_mutex(), d_cond(),
d_complete(false)
{
}
@@ -43,22 +43,23 @@ namespace usrp2 {
int
pending_reply::wait_for_completion(double secs)
{
- omni_time abs_timeout = omni_time::time(omni_time(secs));
- omni_mutex_lock l(d_mutex);
- while (!d_complete){
- int r = d_cond.timedwait(abs_timeout.d_secs, abs_timeout.d_nsecs);
- if (r == 0) // timed out
- return 0;
+ gruel::scoped_lock l(d_mutex);
+ boost::system_time to(gruel::get_new_timeout(secs));
+
+ while (!d_complete) {
+ if (!d_cond.timed_wait(l, to))
+ return 0; // timed out
}
+
return 1;
}
void
pending_reply::notify_completion()
{
- omni_mutex_lock l(d_mutex);
+ gruel::scoped_lock l(d_mutex);
d_complete = true;
- d_cond.signal();
+ d_cond.notify_one();
}
} // namespace usrp2
diff --git a/usrp2/host/lib/control.h b/usrp2/host/lib/control.h
index 8769e4522..3515ba10f 100644
--- a/usrp2/host/lib/control.h
+++ b/usrp2/host/lib/control.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2008,2009 Free Software Foundation, Inc.
+ * Copyright 2008,2009,2010 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
#ifndef INCLUDED_CONTROL_H
#define INCLUDED_CONTROL_H
-#include <gnuradio/omnithread.h>
+#include <gruel/thread.h>
#include <usrp2_eth_packet.h>
namespace usrp2 {
@@ -33,27 +33,35 @@ namespace usrp2 {
/*!
* OP_CONFIG_RX_V2 command packet
*/
- struct op_config_rx_v2_cmd
+ struct op_config_rx_v2_cmd
{
u2_eth_packet_t h;
op_config_rx_v2_t op;
op_generic_t eop;
};
- struct op_start_rx_streaming_cmd
+ struct op_start_rx_streaming_cmd
{
u2_eth_packet_t h;
op_start_rx_streaming_t op;
op_generic_t eop;
};
-
+
+ struct op_sync_and_start_rx_streaming_cmd
+ {
+ u2_eth_packet_t h;
+ op_generic_t sync_op;
+ op_start_rx_streaming_t rx_op;
+ op_generic_t eop;
+ };
+
struct op_stop_rx_cmd {
u2_eth_packet_t h;
op_generic_t op;
op_generic_t eop;
};
- struct op_config_tx_v2_cmd
+ struct op_config_tx_v2_cmd
{
u2_eth_packet_t h;
op_config_tx_v2_t op;
@@ -67,7 +75,7 @@ namespace usrp2 {
op_generic_t eop;
};
- struct op_burn_mac_addr_cmd
+ struct op_burn_mac_addr_cmd
{
u2_eth_packet_t h;
op_burn_mac_addr_t op;
@@ -113,20 +121,20 @@ namespace usrp2 {
/*!
* Control mechanism to allow API calls to block waiting for reply packets
- */
+ */
class pending_reply
{
private:
unsigned int d_rid;
void *d_buffer;
size_t d_len;
-
+
// d_mutex is used with d_cond and also protects d_complete
- omni_mutex d_mutex;
- omni_condition d_cond;
+ gruel::mutex d_mutex;
+ gruel::condition_variable d_cond;
bool d_complete;
- public:
+ public:
/*!
* Construct a pending reply from the reply ID, response packet
* buffer, and buffer length.
@@ -165,7 +173,7 @@ namespace usrp2 {
*/
size_t len() const { return d_len; }
};
-
+
} // namespace usrp2
#endif /* INCLUDED_CONTROL_H */
diff --git a/usrp2/host/lib/ring.cc b/usrp2/host/lib/ring.cc
index 3c45821f8..d0048418c 100644
--- a/usrp2/host/lib/ring.cc
+++ b/usrp2/host/lib/ring.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2008 Free Software Foundation, Inc.
+ * Copyright 2008,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -29,7 +29,7 @@ namespace usrp2 {
ring::ring(unsigned int entries)
: d_max(entries), d_read_ind(0), d_write_ind(0), d_ring(entries),
- d_mutex(), d_not_empty(&d_mutex)
+ d_mutex(), d_not_empty()
{
for (unsigned int i = 0; i < entries; i++) {
d_ring[i].d_base = 0;
@@ -40,15 +40,15 @@ namespace usrp2 {
void
ring::wait_for_not_empty()
{
- omni_mutex_lock l(d_mutex);
+ gruel::scoped_lock l(d_mutex);
while (empty())
- d_not_empty.wait();
+ d_not_empty.wait(l);
}
bool
ring::enqueue(void *p, size_t len)
{
- omni_mutex_lock l(d_mutex);
+ gruel::scoped_lock l(d_mutex);
if (full())
return false;
@@ -56,14 +56,14 @@ namespace usrp2 {
d_ring[d_write_ind].d_base = p;
inc_write_ind();
- d_not_empty.signal();
+ d_not_empty.notify_one();
return true;
}
bool
ring::dequeue(void **p, size_t *len)
{
- omni_mutex_lock l(d_mutex);
+ gruel::scoped_lock l(d_mutex);
if (empty())
return false;
diff --git a/usrp2/host/lib/ring.h b/usrp2/host/lib/ring.h
index 19ae9ae97..fd0ad0a9f 100644
--- a/usrp2/host/lib/ring.h
+++ b/usrp2/host/lib/ring.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2008 Free Software Foundation, Inc.
+ * Copyright 2008,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -21,10 +21,10 @@
#ifndef INCLUDED_RING_H
#define INCLUDED_RING_H
-#include <gnuradio/omnithread.h>
#include <stddef.h>
#include <vector>
#include <boost/shared_ptr.hpp>
+#include <gruel/thread.h>
namespace usrp2 {
@@ -46,8 +46,8 @@ namespace usrp2 {
};
std::vector<ring_desc> d_ring;
- omni_mutex d_mutex;
- omni_condition d_not_empty;
+ gruel::mutex d_mutex;
+ gruel::condition_variable d_not_empty;
void inc_read_ind()
{
diff --git a/usrp2/host/lib/usrp2.cc b/usrp2/host/lib/usrp2.cc
index a2a9ecc11..f0ee564be 100644
--- a/usrp2/host/lib/usrp2.cc
+++ b/usrp2/host/lib/usrp2.cc
@@ -62,7 +62,7 @@ namespace usrp2 {
else {
if (key == p->key) // found it
return usrp2::sptr(p->value);
- else
+ else
++p; // keep looking
}
}
@@ -90,15 +90,15 @@ namespace usrp2 {
p.addr[3] = 0x85;
p.addr[4] = 0x30;
p.addr[5] = 0x00;
-
+
int len = s.size();
switch (len) {
-
+
case 5:
if (sscanf(s.c_str(), "%hhx:%hhx", &p.addr[4], &p.addr[5]) != 2)
return false;
break;
-
+
case 17:
if (sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&p.addr[0], &p.addr[1], &p.addr[2],
@@ -109,7 +109,7 @@ namespace usrp2 {
default:
return false;
}
-
+
char buf[128];
snprintf(buf, sizeof(buf),
"%02x:%02x:%02x:%02x:%02x:%02x",
@@ -148,13 +148,13 @@ namespace usrp2 {
{
// NOP
}
-
+
// Public class destructor. d_impl will auto-delete.
usrp2::~usrp2()
{
// NOP
}
-
+
std::string
usrp2::mac_addr()
{
@@ -169,12 +169,17 @@ namespace usrp2 {
// Receive
- bool
+ bool
+ usrp2::set_rx_antenna(int ant){
+ return d_impl->set_rx_antenna(ant);
+ }
+
+ bool
usrp2::set_rx_gain(double gain)
{
return d_impl->set_rx_gain(gain);
}
-
+
double
usrp2::rx_gain_min()
{
@@ -204,7 +209,7 @@ namespace usrp2 {
{
return d_impl->set_rx_center_freq(frequency, result);
}
-
+
double
usrp2::rx_freq_min()
{
@@ -222,7 +227,7 @@ namespace usrp2 {
{
return d_impl->set_rx_decim(decimation_factor);
}
-
+
int
usrp2::rx_decim()
{
@@ -234,13 +239,25 @@ namespace usrp2 {
{
return d_impl->set_rx_scale_iq(scale_i, scale_q);
}
-
+
bool
usrp2::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
{
return d_impl->start_rx_streaming(channel, items_per_frame);
}
-
+
+ bool
+ usrp2::start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time)
+ {
+ return d_impl->start_rx_streaming_at(channel, items_per_frame,time);
+ }
+
+ bool
+ usrp2::sync_and_start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time)
+ {
+ return d_impl->sync_and_start_rx_streaming_at(channel, items_per_frame, time);
+ }
+
bool
usrp2::rx_samples(unsigned int channel, rx_sample_handler *handler)
{
@@ -258,7 +275,7 @@ namespace usrp2 {
{
return d_impl->rx_overruns();
}
-
+
unsigned int
usrp2::rx_missing()
{
@@ -267,12 +284,17 @@ namespace usrp2 {
// Transmit
- bool
+ bool
+ usrp2::set_tx_antenna(int ant){
+ return d_impl->set_tx_antenna(ant);
+ }
+
+ bool
usrp2::set_tx_gain(double gain)
{
return d_impl->set_tx_gain(gain);
}
-
+
double
usrp2::tx_gain_min()
{
@@ -302,7 +324,7 @@ namespace usrp2 {
{
return d_impl->set_tx_center_freq(frequency, result);
}
-
+
double
usrp2::tx_freq_min()
{
@@ -321,7 +343,7 @@ namespace usrp2 {
{
return d_impl->set_tx_interp(interpolation_factor);
}
-
+
int
usrp2::tx_interp()
{
@@ -339,7 +361,7 @@ namespace usrp2 {
{
return d_impl->set_tx_scale_iq(scale_i, scale_q);
}
-
+
bool
usrp2::tx_32fc(unsigned int channel,
const std::complex<float> *samples,
@@ -404,7 +426,7 @@ namespace usrp2 {
{
return d_impl->rx_daughterboard_id(dbid);
}
-
+
// low level methods
diff --git a/usrp2/host/lib/usrp2_impl.cc b/usrp2/host/lib/usrp2_impl.cc
index 3d0304324..333e2d1e7 100644
--- a/usrp2/host/lib/usrp2_impl.cc
+++ b/usrp2/host/lib/usrp2_impl.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2008,2009 Free Software Foundation, Inc.
+ * Copyright 2008,2009,2010 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,9 +24,10 @@
#include <usrp2/tune_result.h>
#include <usrp2/copiers.h>
#include <gruel/inet.h>
+#include <gruel/realtime.h>
+#include <boost/bind.hpp>
#include <usrp2_types.h>
#include "usrp2_impl.h"
-#include "usrp2_thread.h"
#include "eth_buffer.h"
#include "pktfilter.h"
#include "control.h"
@@ -106,7 +107,7 @@ namespace usrp2 {
//assert((((uintptr_t) p) % 4) == 0); // must be 4-byte aligned
u2_fixed_hdr_t *fh = static_cast<u2_fixed_hdr_t *>(p);
-
+
// FIXME unaligned loads!
md->word0 = u2p_word0(fh);
md->timestamp = u2p_timestamp(fh);
@@ -129,15 +130,15 @@ namespace usrp2 {
usrp2::impl::impl(const std::string &ifc, props *p, size_t rx_bufsize)
- : d_eth_buf(new eth_buffer(rx_bufsize)), d_interface_name(ifc), d_pf(0), d_bg_thread(0),
+ : d_eth_buf(new eth_buffer(rx_bufsize)), d_interface_name(ifc), d_pf(0),
d_bg_running(false), d_rx_seqno(-1), d_tx_seqno(0), d_next_rid(0),
- d_num_rx_frames(0), d_num_rx_missing(0), d_num_rx_overruns(0), d_num_rx_bytes(0),
- d_num_enqueued(0), d_enqueued_mutex(), d_bg_pending_cond(&d_enqueued_mutex),
+ d_num_rx_frames(0), d_num_rx_missing(0), d_num_rx_overruns(0), d_num_rx_bytes(0),
+ d_num_enqueued(0), d_enqueued_mutex(), d_bg_pending_cond(),
d_channel_rings(NCHANS), d_tx_interp(0), d_rx_decim(0), d_dont_enqueue(true)
{
if (!d_eth_buf->open(ifc, htons(U2_ETHERTYPE)))
throw std::runtime_error("Unable to register USRP2 protocol");
-
+
d_addr = p->addr;
// Create a packet filter for U2_ETHERTYPE packets sourced from target USRP2
@@ -146,14 +147,14 @@ namespace usrp2 {
d_pf = pktfilter::make_ethertype_inbound_target(U2_ETHERTYPE, (const unsigned char*)&(usrp_mac.addr));
if (!d_pf || !d_eth_buf->attach_pktfilter(d_pf))
throw std::runtime_error("Unable to attach packet filter.");
-
+
if (USRP2_IMPL_DEBUG)
std::cerr << "usrp2 constructor: using USRP2 at " << d_addr << std::endl;
memset(d_pending_replies, 0, sizeof(d_pending_replies));
- d_bg_thread = new usrp2_thread(this);
- d_bg_thread->start();
+ // Kick off receive thread
+ start_bg();
// In case the USRP2 was left streaming RX
// FIXME: only one channel right now
@@ -199,30 +200,29 @@ namespace usrp2 {
if (!set_rx_decim(12))
std::cerr << "usrp2::ctor set_rx_decim failed\n";
-
+
// set workable defaults for scaling
if (!set_rx_scale_iq(DEFAULT_RX_SCALE, DEFAULT_RX_SCALE))
std::cerr << "usrp2::ctor set_rx_scale_iq failed\n";
}
-
+
usrp2::impl::~impl()
{
stop_bg();
- d_bg_thread = 0; // thread class deletes itself
delete d_pf;
d_eth_buf->close();
delete d_eth_buf;
-
+
if (USRP2_IMPL_DEBUG) {
std::cerr << std::endl
- << "usrp2 destructor: received " << d_num_rx_frames
+ << "usrp2 destructor: received " << d_num_rx_frames
<< " frames, with " << d_num_rx_missing << " lost ("
<< (d_num_rx_frames == 0 ? 0 : (int)(100.0*d_num_rx_missing/d_num_rx_frames))
<< "%), totaling " << d_num_rx_bytes
<< " bytes" << std::endl;
}
}
-
+
bool
usrp2::impl::parse_mac_addr(const std::string &s, u2_mac_addr_t *p)
{
@@ -232,14 +232,14 @@ namespace usrp2 {
p->addr[3] = 0x85;
p->addr[4] = 0x30;
p->addr[5] = 0x00;
-
+
int len = s.size();
-
+
switch (len){
-
+
case 5:
return sscanf(s.c_str(), "%hhx:%hhx", &p->addr[4], &p->addr[5]) == 2;
-
+
case 17:
return sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&p->addr[0], &p->addr[1], &p->addr[2],
@@ -248,36 +248,36 @@ namespace usrp2 {
return false;
}
}
-
+
void
usrp2::impl::init_et_hdrs(u2_eth_packet_t *p, const std::string &dst)
{
p->ehdr.ethertype = htons(U2_ETHERTYPE);
- parse_mac_addr(dst, &p->ehdr.dst);
+ parse_mac_addr(dst, &p->ehdr.dst);
memcpy(&p->ehdr.src, d_eth_buf->mac(), 6);
p->thdr.flags = 0; // FIXME transport header values?
p->thdr.seqno = d_tx_seqno++;
p->thdr.ack = 0;
}
-
- void
+
+ void
usrp2::impl::init_etf_hdrs(u2_eth_packet_t *p, const std::string &dst,
int word0_flags, int chan, uint32_t timestamp)
{
init_et_hdrs(p, dst);
u2p_set_word0(&p->fixed, word0_flags, chan);
u2p_set_timestamp(&p->fixed, timestamp);
-
+
if (chan == CONTROL_CHAN) { // no sequence numbers, back it out
p->thdr.seqno = 0;
d_tx_seqno--;
}
}
-
+
void
usrp2::impl::init_config_rx_v2_cmd(op_config_rx_v2_cmd *cmd)
{
- memset(cmd, 0, sizeof(*cmd));
+ memset(cmd, 0, sizeof(*cmd));
init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
cmd->op.opcode = OP_CONFIG_RX_V2;
cmd->op.len = sizeof(cmd->op);
@@ -289,7 +289,7 @@ namespace usrp2 {
void
usrp2::impl::init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd)
{
- memset(cmd, 0, sizeof(*cmd));
+ memset(cmd, 0, sizeof(*cmd));
init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
cmd->op.opcode = OP_CONFIG_TX_V2;
cmd->op.len = sizeof(cmd->op);
@@ -320,7 +320,7 @@ namespace usrp2 {
usrp2::impl::transmit_cmd_and_wait(void *cmd, size_t len, pending_reply *p, double secs)
{
d_pending_replies[p->rid()] = p;
-
+
if (!transmit_cmd(cmd, len)){
d_pending_replies[p->rid()] = 0;
return false;
@@ -336,18 +336,24 @@ namespace usrp2 {
// ----------------------------------------------------------------
void
+ usrp2::impl::start_bg()
+ {
+ d_rx_tg.create_thread(boost::bind(&usrp2::impl::bg_loop, this));
+ }
+
+ void
usrp2::impl::stop_bg()
{
d_bg_running = false;
- d_bg_pending_cond.signal();
-
- void *dummy_status;
- d_bg_thread->join(&dummy_status);
+ d_bg_pending_cond.notify_one(); // FIXME: check if needed
+ d_rx_tg.join_all();
}
-
+
void
usrp2::impl::bg_loop()
{
+ gruel::enable_realtime_scheduling();
+
d_bg_running = true;
while(d_bg_running) {
DEBUG_LOG(":");
@@ -356,20 +362,20 @@ namespace usrp2 {
// rings, and signal blocked API threads
int res = d_eth_buf->rx_frames(this, 100); // FIXME magic timeout
if (res == eth_buffer::EB_ERROR)
- break;
+ break;
// Wait for user API thread(s) to process all enqueued packets.
- // The channel ring thread that decrements d_num_enqueued to zero
+ // The channel ring thread that decrements d_num_enqueued to zero
// will signal this thread to continue.
{
- omni_mutex_lock l(d_enqueued_mutex);
+ gruel::scoped_lock l(d_enqueued_mutex);
while(d_num_enqueued > 0 && d_bg_running)
- d_bg_pending_cond.wait();
+ d_bg_pending_cond.wait(l);
}
}
d_bg_running = false;
}
-
+
//
// passed to eth_buffer::rx_frames
//
@@ -401,11 +407,11 @@ namespace usrp2 {
{
// point to beginning of payload (subpackets)
unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t);
-
+
// FIXME (p % 4) == 2. Not good. Must watch for unaligned loads.
// FIXME iterate over payload, handling more than a single subpacket.
-
+
int opcode = p[0];
unsigned int oplen = p[1];
unsigned int rid = p[2];
@@ -417,8 +423,8 @@ namespace usrp2 {
std::cerr << "usrp2: mismatched command reply length (expected: "
<< buflen << " got: " << oplen << "). "
<< "op = " << opcode_to_string(opcode) << std::endl;
- }
-
+ }
+
// Copy reply into caller's buffer
memcpy(rp->buffer(), p, std::min(oplen, buflen));
rp->notify_completion();
@@ -430,26 +436,26 @@ namespace usrp2 {
DEBUG_LOG("l");
return data_handler::RELEASE;
}
-
+
data_handler::result
usrp2::impl::handle_data_packet(const void *base, size_t len)
{
u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
d_num_rx_frames++;
d_num_rx_bytes += len;
-
+
/* --- FIXME start of fake transport layer handler --- */
if (d_rx_seqno != -1) {
int expected_seqno = (d_rx_seqno + 1) & 0xFF;
- int seqno = pkt->hdrs.thdr.seqno;
-
+ int seqno = pkt->hdrs.thdr.seqno;
+
if (seqno != expected_seqno) {
::write(2, "S", 1); // missing sequence number
int missing = seqno - expected_seqno;
if (missing < 0)
missing += 256;
-
+
d_num_rx_overruns++;
d_num_rx_missing += missing;
}
@@ -463,15 +469,15 @@ namespace usrp2 {
unsigned int chan = u2p_chan(&pkt->hdrs.fixed);
{
- omni_mutex_lock l(d_channel_rings_mutex);
+ gruel::scoped_lock l(d_channel_rings_mutex);
if (!d_channel_rings[chan]) {
DEBUG_LOG("!");
return data_handler::RELEASE; // discard packet, no channel handler
}
-
+
// Strip off ethernet header and transport header and enqueue the rest
-
+
size_t offset = offsetof(u2_eth_samples_t, hdrs.fixed);
if (d_channel_rings[chan]->enqueue(&pkt->hdrs.fixed, len-offset)) {
inc_enqueued();
@@ -481,7 +487,7 @@ namespace usrp2 {
else {
DEBUG_LOG("!");
return data_handler::RELEASE; // discard, no room in channel ring
- }
+ }
return data_handler::RELEASE;
}
}
@@ -491,7 +497,28 @@ namespace usrp2 {
// Receive
// ----------------------------------------------------------------
- bool
+ bool
+ usrp2::impl::set_rx_antenna(int ant){
+ op_config_mimo_cmd cmd;
+ op_generic_t reply;
+
+ memset(&cmd, 0, sizeof(cmd));
+ init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
+ cmd.op.opcode = OP_RX_ANTENNA;
+ cmd.op.len = sizeof(cmd.op);
+ cmd.op.rid = d_next_rid++;
+ cmd.op.flags = ant;
+ cmd.eop.opcode = OP_EOP;
+ cmd.eop.len = sizeof(cmd.eop);
+
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ return false;
+
+ return ntohx(reply.ok) == 1;
+ }
+
+ bool
usrp2::impl::set_rx_gain(double gain)
{
op_config_rx_v2_cmd cmd;
@@ -500,7 +527,7 @@ namespace usrp2 {
init_config_rx_v2_cmd(&cmd);
cmd.op.valid = htons(CFGV_GAIN);
cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -508,7 +535,7 @@ namespace usrp2 {
bool success = (ntohx(reply.ok) == 1);
return success;
}
-
+
bool
usrp2::impl::set_rx_lo_offset(double frequency)
{
@@ -527,7 +554,7 @@ namespace usrp2 {
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -547,7 +574,7 @@ namespace usrp2 {
u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -555,18 +582,18 @@ namespace usrp2 {
bool success = (ntohx(reply.ok) == 1);
if (result && success) {
result->baseband_freq =
- u2_fxpt_freq_to_double(
- u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
ntohl(reply.baseband_freq_lo)));
result->dxc_freq =
- u2_fxpt_freq_to_double(
- u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi),
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi),
ntohl(reply.ddc_freq_lo)));
result->residual_freq =
- u2_fxpt_freq_to_double(
- u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
ntohl(reply.residual_freq_lo)));
result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
@@ -574,7 +601,7 @@ namespace usrp2 {
return success;
}
-
+
bool
usrp2::impl::set_rx_decim(int decimation_factor)
{
@@ -584,7 +611,7 @@ namespace usrp2 {
init_config_rx_v2_cmd(&cmd);
cmd.op.valid = htons(CFGV_INTERP_DECIM);
cmd.op.decim = htonl(decimation_factor);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -594,7 +621,7 @@ namespace usrp2 {
d_rx_decim = decimation_factor;
return success;
}
-
+
bool
usrp2::impl::set_rx_scale_iq(int scale_i, int scale_q)
{
@@ -604,7 +631,7 @@ namespace usrp2 {
init_config_rx_v2_cmd(&cmd);
cmd.op.valid = htons(CFGV_SCALE_IQ);
cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -612,7 +639,7 @@ namespace usrp2 {
bool success = (ntohx(reply.ok) == 1);
return success;
}
-
+
bool
usrp2::impl::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
{
@@ -629,16 +656,16 @@ namespace usrp2 {
}
{
- omni_mutex_lock l(d_channel_rings_mutex);
+ gruel::scoped_lock l(d_channel_rings_mutex);
if (d_channel_rings[channel]) {
std::cerr << "usrp2: channel " << channel
<< " already streaming" << std::endl;
return false;
}
-
+
if (items_per_frame == 0)
items_per_frame = U2_MAX_SAMPLES; // minimize overhead
-
+
op_start_rx_streaming_cmd cmd;
op_generic_t reply;
@@ -650,13 +677,13 @@ namespace usrp2 {
cmd.op.items_per_frame = htonl(items_per_frame);
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
d_dont_enqueue = false;
bool success = false;
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
success = success && (ntohx(reply.ok) == 1);
-
+
if (success)
d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
else
@@ -666,7 +693,117 @@ namespace usrp2 {
return success;
}
}
-
+
+ bool
+ usrp2::impl::start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time)
+ {
+ if (channel > MAX_CHAN) {
+ std::cerr << "usrp2: invalid channel number (" << channel
+ << ")" << std::endl;
+ return false;
+ }
+
+ if (channel > 0) { // until firmware supports multiple streams
+ std::cerr << "usrp2: channel " << channel
+ << " not implemented" << std::endl;
+ return false;
+ }
+
+ {
+ gruel::scoped_lock guard(d_channel_rings_mutex);
+ if (d_channel_rings[channel]) {
+ std::cerr << "usrp2: channel " << channel
+ << " already streaming" << std::endl;
+ return false;
+ }
+
+ if (items_per_frame == 0)
+ items_per_frame = U2_MAX_SAMPLES; // minimize overhead
+
+ op_start_rx_streaming_cmd cmd;
+ op_generic_t reply;
+
+ memset(&cmd, 0, sizeof(cmd));
+ init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, time);
+ cmd.op.opcode = OP_START_RX_STREAMING;
+ cmd.op.len = sizeof(cmd.op);
+ cmd.op.rid = d_next_rid++;
+ cmd.op.items_per_frame = htonl(items_per_frame);
+ cmd.eop.opcode = OP_EOP;
+ cmd.eop.len = sizeof(cmd.eop);
+
+ d_dont_enqueue = false;
+ bool success = false;
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
+ success = success && (ntohx(reply.ok) == 1);
+
+ if (success)
+ d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
+ else
+ d_dont_enqueue = true;
+
+ return success;
+ }
+ }
+
+ bool
+ usrp2::impl::sync_and_start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time)
+ {
+
+ if (channel > MAX_CHAN) {
+ std::cerr << "usrp2: invalid channel number (" << channel
+ << ")" << std::endl;
+ return false;
+ }
+
+ if (channel > 0) { // until firmware supports multiple streams
+ std::cerr << "usrp2: channel " << channel
+ << " not implemented" << std::endl;
+ return false;
+ }
+
+ {
+ gruel::scoped_lock guard(d_channel_rings_mutex);
+ if (d_channel_rings[channel]) {
+ std::cerr << "usrp2: channel " << channel
+ << " already streaming" << std::endl;
+ return false;
+ }
+
+ if (items_per_frame == 0)
+ items_per_frame = U2_MAX_SAMPLES; // minimize overhead
+
+ op_sync_and_start_rx_streaming_cmd cmd;
+ op_generic_t reply;
+
+ memset(&cmd, 0, sizeof(cmd));
+ init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, time);
+ cmd.sync_op.opcode = OP_SYNC_TO_PPS;
+ cmd.sync_op.len = sizeof(cmd.sync_op);
+ cmd.sync_op.rid = d_next_rid++;
+ cmd.rx_op.opcode = OP_START_RX_STREAMING;
+ cmd.rx_op.len = sizeof(cmd.rx_op);
+ cmd.rx_op.rid = d_next_rid++;
+ cmd.rx_op.items_per_frame = htonl(items_per_frame);
+ cmd.eop.opcode = OP_EOP;
+ cmd.eop.len = sizeof(cmd.eop);
+
+ d_dont_enqueue = false;
+ bool success = false;
+ pending_reply p(cmd.sync_op.rid, &reply, sizeof(reply));
+ success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
+ success = success && (ntohx(reply.ok) == 1);
+
+ if (success)
+ d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
+ else
+ d_dont_enqueue = true;
+
+ return success;
+ }
+ }
+
bool
usrp2::impl::stop_rx_streaming(unsigned int channel)
{
@@ -689,7 +826,7 @@ namespace usrp2 {
op_generic_t reply;
{
- omni_mutex_lock l(d_channel_rings_mutex);
+ gruel::scoped_lock l(d_channel_rings_mutex);
memset(&cmd, 0, sizeof(cmd));
init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
@@ -698,12 +835,13 @@ namespace usrp2 {
cmd.op.rid = d_next_rid++;
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
bool success = false;
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
success = success && (ntohx(reply.ok) == 1);
d_channel_rings[channel].reset();
+ d_rx_seqno = -1;
//fprintf(stderr, "usrp2::stop_rx_streaming: success = %d\n", success);
return success;
}
@@ -717,25 +855,25 @@ namespace usrp2 {
<< " )" << std::endl;
return false;
}
-
+
if (channel > 0) {
std::cerr << "usrp2: channel " << channel
<< " not implemented" << std::endl;
return false;
}
-
+
ring_sptr rp = d_channel_rings[channel];
if (!rp){
std::cerr << "usrp2: channel " << channel
<< " not receiving" << std::endl;
return false;
}
-
+
// Wait for frames available in channel ring
DEBUG_LOG("W");
rp->wait_for_not_empty();
DEBUG_LOG("s");
-
+
// Iterate through frames and present to user
void *p;
size_t frame_len_in_bytes;
@@ -791,7 +929,28 @@ namespace usrp2 {
// Transmit
// ----------------------------------------------------------------
- bool
+ bool
+ usrp2::impl::set_tx_antenna(int ant){
+ op_config_mimo_cmd cmd;
+ op_generic_t reply;
+
+ memset(&cmd, 0, sizeof(cmd));
+ init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
+ cmd.op.opcode = OP_TX_ANTENNA;
+ cmd.op.len = sizeof(cmd.op);
+ cmd.op.rid = d_next_rid++;
+ cmd.op.flags = ant;
+ cmd.eop.opcode = OP_EOP;
+ cmd.eop.len = sizeof(cmd.eop);
+
+ pending_reply p(cmd.op.rid, &reply, sizeof(reply));
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ return false;
+
+ return ntohx(reply.ok) == 1;
+ }
+
+ bool
usrp2::impl::set_tx_gain(double gain)
{
op_config_tx_v2_cmd cmd;
@@ -800,7 +959,7 @@ namespace usrp2 {
init_config_tx_v2_cmd(&cmd);
cmd.op.valid = htons(CFGV_GAIN);
cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -808,7 +967,7 @@ namespace usrp2 {
bool success = (ntohx(reply.ok) == 1);
return success;
}
-
+
bool
usrp2::impl::set_tx_lo_offset(double frequency)
{
@@ -827,7 +986,7 @@ namespace usrp2 {
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -847,7 +1006,7 @@ namespace usrp2 {
u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -855,18 +1014,18 @@ namespace usrp2 {
bool success = (ntohx(reply.ok) == 1);
if (result && success) {
result->baseband_freq =
- u2_fxpt_freq_to_double(
- u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
ntohl(reply.baseband_freq_lo)));
result->dxc_freq =
- u2_fxpt_freq_to_double(
- u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi),
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi),
ntohl(reply.duc_freq_lo)));
result->residual_freq =
- u2_fxpt_freq_to_double(
- u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
+ u2_fxpt_freq_to_double(
+ u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
ntohl(reply.residual_freq_lo)));
result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
@@ -874,7 +1033,7 @@ namespace usrp2 {
return success;
}
-
+
bool
usrp2::impl::set_tx_interp(int interpolation_factor)
{
@@ -884,7 +1043,7 @@ namespace usrp2 {
init_config_tx_v2_cmd(&cmd);
cmd.op.valid = htons(CFGV_INTERP_DECIM);
cmd.op.interp = htonl(interpolation_factor);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -901,7 +1060,7 @@ namespace usrp2 {
return success;
}
-
+
void
usrp2::impl::default_tx_scale_iq(int interpolation_factor, int *scale_i, int *scale_q)
{
@@ -914,7 +1073,7 @@ namespace usrp2 {
// Calculate dsp_core_tx gain absent scale multipliers
float gain = (1.65*i*i*i)/(4096*pow(2, ceil(log2(i*i*i))));
-
+
// Calculate closest multiplier constant to reverse gain
int scale = (int)rint(1.0/gain);
// fprintf(stderr, "if=%i i=%i gain=%f scale=%i\n", interpolation_factor, i, gain, scale);
@@ -935,7 +1094,7 @@ namespace usrp2 {
init_config_tx_v2_cmd(&cmd);
cmd.op.valid = htons(CFGV_SCALE_IQ);
cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1063,7 +1222,7 @@ namespace usrp2 {
cmd.op.flags = flags;
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1137,10 +1296,10 @@ namespace usrp2 {
dst->dbid = ntohl(src->dbid);
dst->freq_min =
- u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_min_hi),
+ u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_min_hi),
ntohl(src->freq_min_lo)));
dst->freq_max =
- u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_max_hi),
+ u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_max_hi),
ntohl(src->freq_max_lo)));
dst->gain_min = u2_fxpt_gain_to_double(ntohs(src->gain_min));
@@ -1161,7 +1320,7 @@ namespace usrp2 {
cmd.op.rid = d_next_rid++;
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1188,7 +1347,7 @@ namespace usrp2 {
cmd.op.rid = d_next_rid++;
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1210,7 +1369,7 @@ namespace usrp2 {
cmd.op.ok = enable ? 1 : 0;
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1225,7 +1384,7 @@ namespace usrp2 {
// fprintf(stderr, "usrp2::peek: addr=%08X words=%u\n", addr, words);
if (addr % 4 != 0) {
- fprintf(stderr, "usrp2::peek: addr (=%08X) must be 32-bit word aligned\n", addr);
+ fprintf(stderr, "usrp2::peek: addr (=%08X) must be 32-bit word aligned\n", addr);
return result;
}
@@ -1267,7 +1426,7 @@ namespace usrp2 {
usrp2::impl::poke32(uint32_t addr, const std::vector<uint32_t> &data)
{
if (addr % 4 != 0) {
- fprintf(stderr, "usrp2::poke32: addr (=%08X) must be 32-bit word aligned\n", addr);
+ fprintf(stderr, "usrp2::poke32: addr (=%08X) must be 32-bit word aligned\n", addr);
return false;
}
@@ -1339,7 +1498,7 @@ namespace usrp2 {
cmd.op.rid = d_next_rid++;
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1368,7 +1527,7 @@ namespace usrp2 {
cmd.op.mask = htons(mask);
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1401,7 +1560,7 @@ namespace usrp2 {
memcpy(&cmd.op.sels, sels.c_str(), 16);
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1430,7 +1589,7 @@ namespace usrp2 {
cmd.op.mask = htons(mask);
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1459,7 +1618,7 @@ namespace usrp2 {
cmd.op.mask = 0; // not used
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
@@ -1496,7 +1655,7 @@ namespace usrp2 {
cmd.op.mask = 0; // not used
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
-
+
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
diff --git a/usrp2/host/lib/usrp2_impl.h b/usrp2/host/lib/usrp2_impl.h
index ed71a6ba3..eee26358e 100644
--- a/usrp2/host/lib/usrp2_impl.h
+++ b/usrp2/host/lib/usrp2_impl.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2008,2009 Free Software Foundation, Inc.
+ * Copyright 2008,2009,2010 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,6 +22,7 @@
#include <usrp2/usrp2.h>
#include <usrp2/data_handler.h>
#include <usrp2_eth_packet.h>
+#include <gruel/thread.h>
#include <boost/scoped_ptr.hpp>
#include "control.h"
#include "ring.h"
@@ -30,7 +31,7 @@
#define MAX_SUBPKT_LEN 252
namespace usrp2 {
-
+
class eth_buffer;
class pktfilter;
class usrp2_thread;
@@ -60,9 +61,10 @@ namespace usrp2 {
std::string d_interface_name;
pktfilter *d_pf;
std::string d_addr; // FIXME: use u2_mac_addr_t instead
- usrp2_thread *d_bg_thread;
+
+ boost::thread_group d_rx_tg;
volatile bool d_bg_running; // TODO: multistate if needed
-
+
int d_rx_seqno;
int d_tx_seqno;
int d_next_rid;
@@ -72,38 +74,39 @@ namespace usrp2 {
unsigned int d_num_rx_bytes;
unsigned int d_num_enqueued;
- omni_mutex d_enqueued_mutex;
- omni_condition d_bg_pending_cond;
+ gruel::mutex d_enqueued_mutex;
+ gruel::condition_variable d_bg_pending_cond;
// all pending_replies are stack allocated, thus no possibility of leaking these
pending_reply *d_pending_replies[NRIDS]; // indexed by 8-bit reply id
std::vector<ring_sptr> d_channel_rings; // indexed by 5-bit channel number
- omni_mutex d_channel_rings_mutex;
+ gruel::mutex d_channel_rings_mutex;
db_info d_tx_db_info;
db_info d_rx_db_info;
- int d_tx_interp; // shadow tx interp
+ int d_tx_interp; // shadow tx interp
int d_rx_decim; // shadow rx decim
bool d_dont_enqueue;
void inc_enqueued() {
- omni_mutex_lock l(d_enqueued_mutex);
+ gruel::scoped_lock l(d_enqueued_mutex);
d_num_enqueued++;
}
-
+
void dec_enqueued() {
- omni_mutex_lock l(d_enqueued_mutex);
+ gruel::scoped_lock l(d_enqueued_mutex);
if (--d_num_enqueued == 0)
- d_bg_pending_cond.signal();
+ d_bg_pending_cond.notify_one();
}
-
+
static bool parse_mac_addr(const std::string &s, u2_mac_addr_t *p);
void init_et_hdrs(u2_eth_packet_t *p, const std::string &dst);
void init_etf_hdrs(u2_eth_packet_t *p, const std::string &dst,
int word0_flags, int chan, uint32_t timestamp);
+ void start_bg();
void stop_bg();
void init_config_rx_v2_cmd(op_config_rx_v2_cmd *cmd);
void init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd);
@@ -118,14 +121,13 @@ namespace usrp2 {
public:
impl(const std::string &ifc, props *p, size_t rx_bufsize);
~impl();
-
- void bg_loop();
std::string mac_addr() const { return d_addr; } // FIXME: convert from u2_mac_addr_t
std::string interface_name() const { return d_interface_name; }
// Rx
+ bool set_rx_antenna(int ant);
bool set_rx_gain(double gain);
double rx_gain_min() { return d_rx_db_info.gain_min; }
double rx_gain_max() { return d_rx_db_info.gain_max; }
@@ -143,6 +145,8 @@ namespace usrp2 {
bool write_gpio(int bank, uint16_t value, uint16_t mask);
bool read_gpio(int bank, uint16_t *value);
bool start_rx_streaming(unsigned int channel, unsigned int items_per_frame);
+ bool start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time);
+ bool sync_and_start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time);
bool rx_samples(unsigned int channel, rx_sample_handler *handler);
bool flush_rx_samples(unsigned int channel);
bool stop_rx_streaming(unsigned int channel);
@@ -151,6 +155,7 @@ namespace usrp2 {
// Tx
+ bool set_tx_antenna(int ant);
bool set_tx_gain(double gain);
double tx_gain_min() { return d_tx_db_info.gain_min; }
double tx_gain_max() { return d_tx_db_info.gain_max; }
@@ -195,8 +200,11 @@ namespace usrp2 {
bool sync_every_pps(bool enable);
std::vector<uint32_t> peek32(uint32_t addr, uint32_t words);
bool poke32(uint32_t addr, const std::vector<uint32_t> &data);
+
+ // Receive thread, need to be public for boost::bind
+ void bg_loop();
};
-
+
} // namespace usrp2
#endif /* INCLUDED_USRP2_IMPL_H */
diff --git a/usrp2/host/lib/usrp2_thread.cc b/usrp2/host/lib/usrp2_thread.cc
deleted file mode 100644
index d14770395..000000000
--- a/usrp2/host/lib/usrp2_thread.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2008 Free Software Foundation, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "usrp2_thread.h"
-#include "usrp2_impl.h"
-#include <gruel/realtime.h>
-#include <gruel/sys_pri.h>
-#include <iostream>
-
-#define USRP2_THREAD_DEBUG 1
-
-namespace usrp2 {
-
- usrp2_thread::usrp2_thread(usrp2::impl *u2) :
- omni_thread(NULL, PRIORITY_HIGH),
- d_u2(u2)
- {
- }
-
- usrp2_thread::~usrp2_thread()
- {
- // we don't own this, just forget it
- d_u2 = 0;
- }
-
- void
- usrp2_thread::start()
- {
- start_undetached();
- }
-
- void *
- usrp2_thread::run_undetached(void *arg)
- {
- if (gruel::enable_realtime_scheduling(gruel::sys_pri::usrp2_backend()) != gruel::RT_OK)
- std::cerr << "usrp2: failed to enable realtime scheduling" << std::endl;
-
- // This is the first code to run in the new thread context.
- d_u2->bg_loop();
-
- return 0;
- }
-
-} // namespace usrp2
-
diff --git a/usrp2/host/lib/usrp2_thread.h b/usrp2/host/lib/usrp2_thread.h
deleted file mode 100644
index 12723e947..000000000
--- a/usrp2/host/lib/usrp2_thread.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2008 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef INCLUDED_USRP2_THREAD_H
-#define INCLUDED_USRP2_THREAD_H
-
-#include <gnuradio/omnithread.h>
-#include <usrp2_impl.h>
-
-namespace usrp2 {
-
- class usrp2_thread : public omni_thread
- {
- private:
- usrp2::impl *d_u2;
-
- public:
- usrp2_thread(usrp2::impl *u2);
- ~usrp2_thread();
-
- void start();
-
- virtual void *run_undetached(void *arg);
- };
-
-} // namespace usrp2
-
-#endif /* INCLUDED_USRP2_THREAD_H */
diff --git a/usrp2/host/usrp2.pc.in b/usrp2/host/usrp2.pc.in
index eaef5f41d..e0c2b1986 100644
--- a/usrp2/host/usrp2.pc.in
+++ b/usrp2/host/usrp2.pc.in
@@ -5,7 +5,7 @@ includedir=@includedir@
Name: usrp2
Description: Universal Software Radio Peripheral 2
-Requires: gnuradio-omnithread gruel
+Requires: gruel
Version: @VERSION@
Libs: -L${libdir} -lusrp2
Cflags: -I${includedir} @DEFINES@