aboutsummaryrefslogtreecommitdiffstats
path: root/Transceiver52M/UHDDevice.cpp
diff options
context:
space:
mode:
authorThomas Tsou <tom@tsou.cc>2013-10-29 18:34:16 -0400
committerThomas Tsou <tom@tsou.cc>2013-11-15 14:45:20 -0500
commit204a9f135ac2408dd62b55462ebe4b2d10be4f56 (patch)
tree80de459f10c23a103bf80172ba762f2577da0859 /Transceiver52M/UHDDevice.cpp
parent0169b310de2789cbe2ec9a447caae494fbea13d0 (diff)
Transceiver52M: Add multi channel transceiver support
This patch primarily addresses devices with multiple RF front end support. Currently device support is limited to UmTRX. Vectorize transceiver variables to allow multiple asynchronous threads on the upper layer with single downlink and uplink threads driving the UHD I/O interface synchronously. Signed-off-by: Thomas Tsou <tom@tsou.cc>
Diffstat (limited to 'Transceiver52M/UHDDevice.cpp')
-rw-r--r--Transceiver52M/UHDDevice.cpp263
1 files changed, 174 insertions, 89 deletions
diff --git a/Transceiver52M/UHDDevice.cpp b/Transceiver52M/UHDDevice.cpp
index 7a1a74d..224ebd0 100644
--- a/Transceiver52M/UHDDevice.cpp
+++ b/Transceiver52M/UHDDevice.cpp
@@ -211,7 +211,7 @@ private:
*/
class uhd_device : public RadioDevice {
public:
- uhd_device(int sps, bool skip_rx);
+ uhd_device(size_t sps, size_t chans);
~uhd_device();
int open(const std::string &args, bool extref);
@@ -221,16 +221,16 @@ public:
void setPriority();
enum TxWindowType getWindowType() { return tx_window; }
- int readSamples(short *buf, int len, bool *overrun,
+ int readSamples(std::vector<short *> &bufs, int len, bool *overrun,
TIMESTAMP timestamp, bool *underrun, unsigned *RSSI);
- int writeSamples(short *buf, int len, bool *underrun,
+ int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
TIMESTAMP timestamp, bool isControl);
bool updateAlignment(TIMESTAMP timestamp);
- bool setTxFreq(double wFreq);
- bool setRxFreq(double wFreq);
+ bool setTxFreq(double wFreq, size_t chan);
+ bool setRxFreq(double wFreq, size_t chan);
inline TIMESTAMP initialWriteTimestamp() { return 0; }
inline TIMESTAMP initialReadTimestamp() { return 0; }
@@ -238,17 +238,18 @@ public:
inline double fullScaleInputValue() { return 32000 * TX_AMPL; }
inline double fullScaleOutputValue() { return 32000; }
- double setRxGain(double db);
- double getRxGain(void) { return rx_gain; }
+ double setRxGain(double db, size_t chan);
+ double getRxGain(size_t chan);
double maxRxGain(void) { return rx_gain_max; }
double minRxGain(void) { return rx_gain_min; }
- double setTxGain(double db);
+ double setTxGain(double db, size_t chan);
double maxTxGain(void) { return tx_gain_max; }
double minTxGain(void) { return tx_gain_min; }
- double getTxFreq() { return tx_freq; }
- double getRxFreq() { return rx_freq; }
+ double getTxFreq(size_t chan);
+ double getRxFreq(size_t chan);
+ double getRxFreq();
inline double getSampleRate() { return tx_rate; }
inline double numberRead() { return rx_pkt_cnt; }
@@ -272,25 +273,25 @@ private:
enum TxWindowType tx_window;
enum uhd_dev_type dev_type;
- int sps;
+ size_t sps, chans;
double tx_rate, rx_rate;
- double tx_gain, tx_gain_min, tx_gain_max;
- double rx_gain, rx_gain_min, rx_gain_max;
+ double tx_gain_min, tx_gain_max;
+ double rx_gain_min, rx_gain_max;
- double tx_freq, rx_freq;
+ std::vector<double> tx_gains, rx_gains;
+ std::vector<double> tx_freqs, rx_freqs;
size_t tx_spp, rx_spp;
bool started;
bool aligned;
- bool skip_rx;
size_t rx_pkt_cnt;
size_t drop_cnt;
uhd::time_spec_t prev_ts;
TIMESTAMP ts_offset;
- smpl_buf *rx_smpl_buf;
+ std::vector<smpl_buf *> rx_buffers;
void init_gains();
int set_master_clk(double rate);
@@ -335,23 +336,23 @@ void uhd_msg_handler(uhd::msg::type_t type, const std::string &msg)
}
}
-uhd_device::uhd_device(int sps, bool skip_rx)
- : tx_gain(0.0), tx_gain_min(0.0), tx_gain_max(0.0),
- rx_gain(0.0), rx_gain_min(0.0), rx_gain_max(0.0),
- tx_freq(0.0), rx_freq(0.0), tx_spp(0), rx_spp(0),
+uhd_device::uhd_device(size_t sps, size_t chans)
+ : tx_gain_min(0.0), tx_gain_max(0.0),
+ rx_gain_min(0.0), rx_gain_max(0.0),
+ tx_spp(0), rx_spp(0),
started(false), aligned(false), rx_pkt_cnt(0), drop_cnt(0),
- prev_ts(0,0), ts_offset(0), rx_smpl_buf(NULL)
+ prev_ts(0,0), ts_offset(0)
{
this->sps = sps;
- this->skip_rx = skip_rx;
+ this->chans = chans;
}
uhd_device::~uhd_device()
{
stop();
- if (rx_smpl_buf)
- delete rx_smpl_buf;
+ for (size_t i = 0; i < rx_buffers.size(); i++)
+ delete rx_buffers[i];
}
void uhd_device::init_gains()
@@ -366,13 +367,18 @@ void uhd_device::init_gains()
rx_gain_min = range.start();
rx_gain_max = range.stop();
- usrp_dev->set_tx_gain((tx_gain_min + tx_gain_max) / 2);
- usrp_dev->set_rx_gain((rx_gain_min + rx_gain_max) / 2);
+ for (size_t i = 0; i < tx_gains.size(); i++) {
+ usrp_dev->set_tx_gain((tx_gain_min + tx_gain_max) / 2, i);
+ tx_gains[i] = usrp_dev->get_tx_gain(i);
+ }
- tx_gain = usrp_dev->get_tx_gain();
- rx_gain = usrp_dev->get_rx_gain();
+ for (size_t i = 0; i < rx_gains.size(); i++) {
+ usrp_dev->set_rx_gain((rx_gain_min + rx_gain_max) / 2, i);
+ rx_gains[i] = usrp_dev->get_rx_gain(i);
+ }
return;
+
}
int uhd_device::set_master_clk(double clk_rate)
@@ -435,24 +441,44 @@ int uhd_device::set_rates(double tx_rate, double rx_rate)
return 0;
}
-double uhd_device::setTxGain(double db)
+double uhd_device::setTxGain(double db, size_t chan)
{
- usrp_dev->set_tx_gain(db);
- tx_gain = usrp_dev->get_tx_gain();
+ if (chan >= tx_gains.size()) {
+ LOG(ALERT) << "Requested non-existent channel" << chan;
+ return 0.0f;
+ }
+
+ usrp_dev->set_tx_gain(db, chan);
+ tx_gains[chan] = usrp_dev->get_tx_gain(chan);
- LOG(INFO) << "Set TX gain to " << tx_gain << "dB";
+ LOG(INFO) << "Set TX gain to " << tx_gains[chan] << "dB";
- return tx_gain;
+ return tx_gains[chan];
}
-double uhd_device::setRxGain(double db)
+double uhd_device::setRxGain(double db, size_t chan)
{
- usrp_dev->set_rx_gain(db);
- rx_gain = usrp_dev->get_rx_gain();
+ if (chan >= rx_gains.size()) {
+ LOG(ALERT) << "Requested non-existent channel " << chan;
+ return 0.0f;
+ }
- LOG(INFO) << "Set RX gain to " << rx_gain << "dB";
+ usrp_dev->set_rx_gain(db, chan);
+ rx_gains[chan] = usrp_dev->get_rx_gain(chan);
- return rx_gain;
+ LOG(INFO) << "Set RX gain to " << rx_gains[chan] << "dB";
+
+ return rx_gains[chan];
+}
+
+double uhd_device::getRxGain(size_t chan)
+{
+ if (chan >= rx_gains.size()) {
+ LOG(ALERT) << "Requested non-existent channel " << chan;
+ return 0.0f;
+ }
+
+ return rx_gains[chan];
}
/*
@@ -533,11 +559,30 @@ int uhd_device::open(const std::string &args, bool extref)
if (!parse_dev_type())
return -1;
+ // Verify and set channels
+ if ((dev_type == UMTRX) && (chans == 2)) {
+ uhd::usrp::subdev_spec_t subdev_spec("A:0 B:0");
+ usrp_dev->set_tx_subdev_spec(subdev_spec);
+ usrp_dev->set_rx_subdev_spec(subdev_spec);
+ } else if (chans != 1) {
+ LOG(ALERT) << "Invalid channel combination for device";
+ return -1;
+ }
+
+ tx_freqs.resize(chans);
+ rx_freqs.resize(chans);
+ tx_gains.resize(chans);
+ rx_gains.resize(chans);
+ rx_buffers.resize(chans);
+
if (extref)
usrp_dev->set_clock_source("external");
// Create TX and RX streamers
uhd::stream_args_t stream_args("sc16");
+ for (size_t i = 0; i < chans; i++)
+ stream_args.channels.push_back(i);
+
tx_stream = usrp_dev->get_tx_stream(stream_args);
rx_stream = usrp_dev->get_rx_stream(stream_args);
@@ -553,7 +598,8 @@ int uhd_device::open(const std::string &args, bool extref)
// Create receive buffer
size_t buf_len = SAMPLE_BUF_SZ / sizeof(uint32_t);
- rx_smpl_buf = new smpl_buf(buf_len, rx_rate);
+ for (size_t i = 0; i < rx_buffers.size(); i++)
+ rx_buffers[i] = new smpl_buf(buf_len, rx_rate);
// Set receive chain sample offset
double offset = get_dev_offset(dev_type, sps);
@@ -608,16 +654,13 @@ bool uhd_device::flush_recv(size_t num_pkts)
void uhd_device::restart(uhd::time_spec_t ts)
{
- uhd::stream_cmd_t cmd = uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS;
- usrp_dev->issue_stream_cmd(cmd);
-
- flush_recv(50);
-
usrp_dev->set_time_now(ts);
aligned = false;
- cmd = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
- cmd.stream_now = true;
+ uhd::stream_cmd_t cmd = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
+ cmd.time_spec = uhd::time_spec_t(0.1);
+ cmd.stream_now = false;
+
usrp_dev->issue_stream_cmd(cmd);
}
@@ -707,16 +750,17 @@ int uhd_device::check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls)
return 0;
}
-int uhd_device::readSamples(short *buf, int len, bool *overrun,
- TIMESTAMP timestamp, bool *underrun, unsigned *RSSI)
+int uhd_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
+ TIMESTAMP timestamp, bool *underrun, unsigned *RSSI)
{
ssize_t rc;
uhd::time_spec_t ts;
uhd::rx_metadata_t metadata;
- uint32_t pkt_buf[rx_spp];
- if (skip_rx)
- return 0;
+ if (bufs.size() != chans) {
+ LOG(ALERT) << "Invalid channel combination " << bufs.size();
+ return -1;
+ }
*overrun = false;
*underrun = false;
@@ -728,21 +772,25 @@ int uhd_device::readSamples(short *buf, int len, bool *overrun,
LOG(DEBUG) << "Requested timestamp = " << ts.get_real_secs();
// Check that timestamp is valid
- rc = rx_smpl_buf->avail_smpls(timestamp);
+ rc = rx_buffers[0]->avail_smpls(timestamp);
if (rc < 0) {
- LOG(ERR) << rx_smpl_buf->str_code(rc);
- LOG(ERR) << rx_smpl_buf->str_status();
+ LOG(ERR) << rx_buffers[0]->str_code(rc);
+ LOG(ERR) << rx_buffers[0]->str_status();
return 0;
}
+ // Create vector buffer
+ std::vector<std::vector<short> >
+ pkt_bufs(chans, std::vector<short>(2 * rx_spp));
+
+ std::vector<short *> pkt_ptrs;
+ for (size_t i = 0; i < pkt_bufs.size(); i++)
+ pkt_ptrs.push_back(&pkt_bufs[i].front());
+
// Receive samples from the usrp until we have enough
- while (rx_smpl_buf->avail_smpls(timestamp) < len) {
- size_t num_smpls = rx_stream->recv(
- (void*)pkt_buf,
- rx_spp,
- metadata,
- 0.1,
- true);
+ while (rx_buffers[0]->avail_smpls(timestamp) < len) {
+ size_t num_smpls = rx_stream->recv(pkt_ptrs, rx_spp,
+ metadata, 0.1, true);
rx_pkt_cnt++;
// Check for errors
@@ -758,36 +806,39 @@ int uhd_device::readSamples(short *buf, int len, bool *overrun,
continue;
}
-
ts = metadata.time_spec;
LOG(DEBUG) << "Received timestamp = " << ts.get_real_secs();
- rc = rx_smpl_buf->write(pkt_buf,
- num_smpls,
- metadata.time_spec);
-
- // Continue on local overrun, exit on other errors
- if ((rc < 0)) {
- LOG(ERR) << rx_smpl_buf->str_code(rc);
- LOG(ERR) << rx_smpl_buf->str_status();
- if (rc != smpl_buf::ERROR_OVERFLOW)
- return 0;
+ for (size_t i = 0; i < rx_buffers.size(); i++) {
+ rc = rx_buffers[i]->write((short *) &pkt_bufs[i].front(),
+ num_smpls,
+ metadata.time_spec);
+
+ // Continue on local overrun, exit on other errors
+ if ((rc < 0)) {
+ LOG(ERR) << rx_buffers[i]->str_code(rc);
+ LOG(ERR) << rx_buffers[i]->str_status();
+ if (rc != smpl_buf::ERROR_OVERFLOW)
+ return 0;
+ }
}
}
// We have enough samples
- rc = rx_smpl_buf->read(buf, len, timestamp);
- if ((rc < 0) || (rc != len)) {
- LOG(ERR) << rx_smpl_buf->str_code(rc);
- LOG(ERR) << rx_smpl_buf->str_status();
- return 0;
+ for (size_t i = 0; i < rx_buffers.size(); i++) {
+ rc = rx_buffers[i]->read(bufs[i], len, timestamp);
+ if ((rc < 0) || (rc != len)) {
+ LOG(ERR) << rx_buffers[i]->str_code(rc);
+ LOG(ERR) << rx_buffers[i]->str_status();
+ return 0;
+ }
}
return len;
}
-int uhd_device::writeSamples(short *buf, int len, bool *underrun,
- unsigned long long timestamp,bool isControl)
+int uhd_device::writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
+ unsigned long long timestamp,bool isControl)
{
uhd::tx_metadata_t metadata;
metadata.has_time_spec = true;
@@ -803,6 +854,11 @@ int uhd_device::writeSamples(short *buf, int len, bool *underrun,
return 0;
}
+ if (bufs.size() != chans) {
+ LOG(ALERT) << "Invalid channel combination " << bufs.size();
+ return -1;
+ }
+
// Drop a fixed number of packets (magic value)
if (!aligned) {
drop_cnt++;
@@ -822,8 +878,7 @@ int uhd_device::writeSamples(short *buf, int len, bool *underrun,
}
}
- size_t num_smpls = tx_stream->send(buf, len, metadata);
-
+ size_t num_smpls = tx_stream->send(bufs, len, metadata);
if (num_smpls != (unsigned) len) {
LOG(ALERT) << "UHD: Device send timed out";
LOG(ALERT) << "UHD: Version " << uhd::get_version_string();
@@ -839,24 +894,54 @@ bool uhd_device::updateAlignment(TIMESTAMP timestamp)
return true;
}
-bool uhd_device::setTxFreq(double wFreq)
+bool uhd_device::setTxFreq(double wFreq, size_t chan)
{
- uhd::tune_result_t tr = usrp_dev->set_tx_freq(wFreq);
+ if (chan >= tx_freqs.size()) {
+ LOG(ALERT) << "Requested non-existent channel " << chan;
+ return false;
+ }
+
+ uhd::tune_result_t tr = usrp_dev->set_tx_freq(wFreq, chan);
LOG(INFO) << "\n" << tr.to_pp_string();
- tx_freq = usrp_dev->get_tx_freq();
+ tx_freqs[chan] = usrp_dev->get_tx_freq(chan);
return true;
}
-bool uhd_device::setRxFreq(double wFreq)
+bool uhd_device::setRxFreq(double wFreq, size_t chan)
{
- uhd::tune_result_t tr = usrp_dev->set_rx_freq(wFreq);
+ if (chan >= rx_freqs.size()) {
+ LOG(ALERT) << "Requested non-existent channel " << chan;
+ return false;
+ }
+
+ uhd::tune_result_t tr = usrp_dev->set_rx_freq(wFreq, chan);
LOG(INFO) << "\n" << tr.to_pp_string();
- rx_freq = usrp_dev->get_rx_freq();
+ rx_freqs[chan] = usrp_dev->get_rx_freq(chan);
return true;
}
+double uhd_device::getTxFreq(size_t chan)
+{
+ if (chan >= tx_freqs.size()) {
+ LOG(ALERT) << "Requested non-existent channel " << chan;
+ return 0.0;
+ }
+
+ return tx_freqs[chan];
+}
+
+double uhd_device::getRxFreq(size_t chan)
+{
+ if (chan >= rx_freqs.size()) {
+ LOG(ALERT) << "Requested non-existent channel " << chan;
+ return 0.0;
+ }
+
+ return rx_freqs[chan];
+}
+
bool uhd_device::recv_async_msg()
{
uhd::async_metadata_t md;
@@ -1085,7 +1170,7 @@ std::string smpl_buf::str_code(ssize_t code)
}
}
-RadioDevice *RadioDevice::make(int sps, bool skip_rx)
+RadioDevice *RadioDevice::make(size_t sps, size_t chans)
{
- return new uhd_device(sps, skip_rx);
+ return new uhd_device(sps, chans);
}