From ddbbc8ccbd98fbe37039e71d6b77ff679c855e8d Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Thu, 1 Feb 2018 14:26:21 +0100 Subject: [PATCH] Add support to set Rx/TxAntenna Change-Id: I1735e6ab05a05b0312d6d679b16ebd4a2260fa23 --- Transceiver52M/UHDDevice.cpp | 133 +++++++++++++++++++++++++++++++--- Transceiver52M/USRPDevice.cpp | 122 +++++++++++++++++++++---------- Transceiver52M/USRPDevice.h | 17 ++++- Transceiver52M/osmo-trx.cpp | 42 ++++++++++- Transceiver52M/radioDevice.h | 16 +++- 5 files changed, 273 insertions(+), 57 deletions(-) diff --git a/Transceiver52M/UHDDevice.cpp b/Transceiver52M/UHDDevice.cpp index 09317a9d..1cf6cb98 100644 --- a/Transceiver52M/UHDDevice.cpp +++ b/Transceiver52M/UHDDevice.cpp @@ -1,5 +1,5 @@ /* - * Device support for Ettus Research UHD driver + * Device support for Ettus Research UHD driver * * Copyright 2010,2011 Free Software Foundation, Inc. * Copyright (C) 2015 Ettus Research LLC @@ -143,8 +143,8 @@ class smpl_buf { public: /** Sample buffer constructor @param len number of 32-bit samples the buffer should hold - @param rate sample clockrate - @param timestamp + @param rate sample clockrate + @param timestamp */ smpl_buf(size_t len, double rate); ~smpl_buf(); @@ -172,7 +172,7 @@ public: */ std::string str_status(size_t ts) const; - /** Formatted error string + /** Formatted error string @param code an error code @return a formatted error string */ @@ -208,7 +208,9 @@ private: class uhd_device : public RadioDevice { public: uhd_device(size_t tx_sps, size_t rx_sps, InterfaceType type, - size_t chans, double offset); + size_t chans, double offset, + const std::vector& tx_paths, + const std::vector& rx_paths); ~uhd_device(); int open(const std::string &args, int ref, bool swap_channels); @@ -248,6 +250,11 @@ public: double getRxFreq(size_t chan); double getRxFreq(); + bool setRxAntenna(const std::string &ant, size_t chan); + std::string getRxAntenna(size_t chan); + bool setTxAntenna(const std::string &ant, size_t chan); + std::string getTxAntenna(size_t chan); + inline double getSampleRate() { return tx_rate; } inline double numberRead() { return rx_pkt_cnt; } inline double numberWritten() { return 0; } @@ -280,6 +287,7 @@ private: std::vector tx_gains, rx_gains; std::vector tx_freqs, rx_freqs; + std::vector tx_paths, rx_paths; size_t tx_spp, rx_spp; bool started; @@ -295,6 +303,7 @@ private: void init_gains(); void set_channels(bool swap); void set_rates(); + bool set_antennas(); bool parse_dev_type(); bool flush_recv(size_t num_pkts); int check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls); @@ -353,7 +362,9 @@ static void thread_enable_cancel(bool cancel) } uhd_device::uhd_device(size_t tx_sps, size_t rx_sps, - InterfaceType iface, size_t chans, double offset) + InterfaceType iface, size_t chans, double offset, + const std::vector& tx_paths, + const std::vector& rx_paths) : 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), @@ -365,6 +376,8 @@ uhd_device::uhd_device(size_t tx_sps, size_t rx_sps, this->chans = chans; this->offset = offset; this->iface = iface; + this->tx_paths = tx_paths; + this->rx_paths = rx_paths; } uhd_device::~uhd_device() @@ -441,6 +454,33 @@ void uhd_device::set_rates() LOG(INFO) << "Rates configured for " << desc.str; } +bool uhd_device::set_antennas() +{ + unsigned int i; + + for (i = 0; i < tx_paths.size(); i++) { + if (tx_paths[i] == "") + continue; + LOG(DEBUG) << "Configuring channel " << i << " with antenna " << tx_paths[i]; + if (!setTxAntenna(tx_paths[i], i)) { + LOG(ALERT) << "Failed configuring channel " << i << " with antenna " << tx_paths[i]; + return false; + } + } + + for (i = 0; i < rx_paths.size(); i++) { + if (rx_paths[i] == "") + continue; + LOG(DEBUG) << "Configuring channel " << i << " with antenna " << tx_paths[i]; + if (!setRxAntenna(rx_paths[i], i)) { + LOG(ALERT) << "Failed configuring channel " << i << " with antenna " << rx_paths[i]; + return false; + } + } + LOG(INFO) << "Antennas configured successfully"; + return true; +} + double uhd_device::setTxGain(double db, size_t chan) { if (iface == MULTI_ARFCN) @@ -644,6 +684,11 @@ int uhd_device::open(const std::string &args, int ref, bool swap_channels) return -1; } + if (!set_antennas()) { + LOG(ALERT) << "UHD antenna setting failed"; + return -1; + } + tx_freqs.resize(chans); rx_freqs.resize(chans); tx_gains.resize(chans); @@ -705,7 +750,7 @@ int uhd_device::open(const std::string &args, int ref, bool swap_channels) for (size_t i = 0; i < rx_buffers.size(); i++) rx_buffers[i] = new smpl_buf(buf_len, rx_rate); - // Initialize and shadow gain values + // Initialize and shadow gain values init_gains(); // Print configuration @@ -926,7 +971,7 @@ int uhd_device::readSamples(std::vector &bufs, int len, bool *overrun, rx_pkt_cnt++; - // Check for errors + // Check for errors rc = check_rx_md_err(metadata, num_smpls); switch (rc) { case ERROR_UNRECOVERABLE: @@ -1165,6 +1210,72 @@ double uhd_device::getRxFreq(size_t chan) return rx_freqs[chan]; } +bool uhd_device::setRxAntenna(const std::string &ant, size_t chan) +{ + std::vector avail; + if (chan >= rx_paths.size()) { + LOG(ALERT) << "Requested non-existent channel " << chan; + return false; + } + + avail = usrp_dev->get_rx_antennas(chan); + if (std::find(avail.begin(), avail.end(), ant) == avail.end()) { + LOG(ALERT) << "Requested non-existent antenna " << ant << " on channel " << chan; + return false; + } + usrp_dev->set_rx_antenna(ant, chan); + rx_paths[chan] = usrp_dev->get_rx_antenna(chan); + + if (ant != rx_paths[chan]) { + LOG(ALERT) << "Failed setting antenna " << ant << " on channel " << chan << ", got instead " << rx_paths[chan]; + return false; + } + + return true; +} + +std::string uhd_device::getRxAntenna(size_t chan) +{ + if (chan >= rx_paths.size()) { + LOG(ALERT) << "Requested non-existent channel " << chan; + return ""; + } + return usrp_dev->get_rx_antenna(chan); +} + +bool uhd_device::setTxAntenna(const std::string &ant, size_t chan) +{ + std::vector avail; + if (chan >= tx_paths.size()) { + LOG(ALERT) << "Requested non-existent channel " << chan; + return false; + } + + avail = usrp_dev->get_tx_antennas(chan); + if (std::find(avail.begin(), avail.end(), ant) == avail.end()) { + LOG(ALERT) << "Requested non-existent antenna " << ant << " on channel " << chan; + return false; + } + usrp_dev->set_tx_antenna(ant, chan); + tx_paths[chan] = usrp_dev->get_tx_antenna(chan); + + if (ant != tx_paths[chan]) { + LOG(ALERT) << "Failed setting antenna " << ant << " on channel " << chan << ", got instead " << tx_paths[chan]; + return false; + } + + return true; +} + +std::string uhd_device::getTxAntenna(size_t chan) +{ + if (chan >= tx_paths.size()) { + LOG(ALERT) << "Requested non-existent channel " << chan; + return ""; + } + return usrp_dev->get_tx_antenna(chan); +} + /* * Only allow sampling the Rx path lower than Tx and not vice-versa. * Using Tx with 4 SPS and Rx at 1 SPS is the only allowed mixed @@ -1451,7 +1562,9 @@ std::string smpl_buf::str_code(ssize_t code) } RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps, - InterfaceType iface, size_t chans, double offset) + InterfaceType iface, size_t chans, double offset, + const std::vector& tx_paths, + const std::vector& rx_paths) { - return new uhd_device(tx_sps, rx_sps, iface, chans, offset); + return new uhd_device(tx_sps, rx_sps, iface, chans, offset, tx_paths, rx_paths); } diff --git a/Transceiver52M/USRPDevice.cpp b/Transceiver52M/USRPDevice.cpp index e5be58de..f7f24e9b 100644 --- a/Transceiver52M/USRPDevice.cpp +++ b/Transceiver52M/USRPDevice.cpp @@ -27,7 +27,7 @@ Compilation Flags SWLOOPBACK compile for software loopback testing -*/ +*/ #include @@ -80,7 +80,7 @@ USRPDevice::USRPDevice(size_t sps) else pingOffset = 0; -#ifdef SWLOOPBACK +#ifdef SWLOOPBACK samplePeriod = 1.0e6/actualSampleRate; loopbackBufferSize = 0; gettimeofday(&lastReadTime,NULL); @@ -93,9 +93,9 @@ int USRPDevice::open(const std::string &, int, bool) writeLock.unlock(); LOG(INFO) << "opening USRP device.."; -#ifndef SWLOOPBACK +#ifndef SWLOOPBACK string rbf = "std_inband.rbf"; - //string rbf = "inband_1rxhb_1tx.rbf"; + //string rbf = "inband_1rxhb_1tx.rbf"; m_uRx.reset(); if (!skipRx) { try { @@ -144,7 +144,7 @@ int USRPDevice::open(const std::string &, int, bool) if (!skipRx) m_uRx->stop(); m_uTx->stop(); - + #endif switch (dboardConfig) { @@ -175,19 +175,19 @@ int USRPDevice::open(const std::string &, int, bool) samplesRead = 0; samplesWritten = 0; started = false; - + return NORMAL; } -bool USRPDevice::start() +bool USRPDevice::start() { LOG(INFO) << "starting USRP..."; -#ifndef SWLOOPBACK +#ifndef SWLOOPBACK if (!m_uRx && !skipRx) return false; if (!m_uTx) return false; - + if (!skipRx) m_uRx->stop(); m_uTx->stop(); @@ -217,8 +217,8 @@ bool USRPDevice::start() hi32Timestamp = 0; isAligned = false; - - if (!skipRx) + + if (!skipRx) started = (m_uRx->start() && m_uTx->start()); else started = m_uTx->start(); @@ -229,14 +229,14 @@ bool USRPDevice::start() #endif } -bool USRPDevice::stop() +bool USRPDevice::stop() { -#ifndef SWLOOPBACK +#ifndef SWLOOPBACK if (!m_uRx) return false; if (!m_uTx) return false; - + delete[] currData; - + started = !(m_uRx->stop() && m_uTx->stop()); return !started; #else @@ -257,7 +257,7 @@ double USRPDevice::minTxGain() double USRPDevice::maxRxGain() { return m_dbRx->gain_max(); -} +} double USRPDevice::minRxGain() { @@ -313,28 +313,68 @@ double USRPDevice::setRxGain(double dB, size_t chan) return dB; } +bool USRPDevice::setRxAntenna(const std::string &ant, size_t chan) +{ + if (chan >= rx_paths.size()) { + LOG(ALERT) << "Requested non-existent channel " << chan; + return false; + } + LOG(ALERT) << "Not implemented"; + return true; +} + +std::string USRPDevice::getRxAntenna(size_t chan) +{ + if (chan >= rx_paths.size()) { + LOG(ALERT) << "Requested non-existent channel " << chan; + return ""; + } + LOG(ALERT) << "Not implemented"; + return ""; +} + +bool USRPDevice::setTxAntenna(const std::string &ant, size_t chan) +{ + if (chan >= tx_paths.size()) { + LOG(ALERT) << "Requested non-existent channel " << chan; + return false; + } + LOG(ALERT) << "Not implemented"; + return true; +} + +std::string USRPDevice::getTxAntenna(size_t chan) +{ + if (chan >= tx_paths.size()) { + LOG(ALERT) << "Requested non-existent channel " << chan; + return ""; + } + LOG(ALERT) << "Not implemented"; + return ""; +} + // NOTE: Assumes sequential reads int USRPDevice::readSamples(std::vector &bufs, int len, bool *overrun, TIMESTAMP timestamp, bool *underrun, unsigned *RSSI) { -#ifndef SWLOOPBACK +#ifndef SWLOOPBACK if (!m_uRx) return 0; short *buf = bufs[0]; timestamp += timestampOffset; - + if (timestamp + len < timeStart) { memset(buf,0,len*2*sizeof(short)); return len; } if (underrun) *underrun = false; - + uint32_t readBuf[2000]; - + while (1) { //guestimate USB read size int readLen=0; @@ -344,7 +384,7 @@ int USRPDevice::readSamples(std::vector &bufs, int len, bool *overrun, readLen = 512 * ((int) ceil((float) numSamplesNeeded/126.0)); if (readLen > 8000) readLen= (8000/512)*512; } - + // read USRP packets, parse and save A/D data as needed readLen = m_uRx->read((void *)readBuf,readLen,overrun); for(int pktNum = 0; pktNum < (readLen/512); pktNum++) { @@ -381,13 +421,13 @@ int USRPDevice::readSamples(std::vector &bufs, int len, bool *overrun, continue; } if ((word0 >> 28) & 0x04) { - if (underrun) *underrun = true; + if (underrun) *underrun = true; LOG(DEBUG) << "UNDERRUN in TRX->USRP interface"; } if (RSSI) *RSSI = (word0 >> 21) & 0x3f; - + if (!isAligned) continue; - + unsigned cursorStart = pktTimestamp - timeStart + dataStart; while (cursorStart*2 > currDataSize) { cursorStart -= currDataSize/2; @@ -400,17 +440,17 @@ int USRPDevice::readSamples(std::vector &bufs, int len, bool *overrun, else { memcpy(data+cursorStart*2,tmpBuf+2,payloadSz); } - if (pktTimestamp + payloadSz/2/sizeof(short) > timeEnd) + if (pktTimestamp + payloadSz/2/sizeof(short) > timeEnd) timeEnd = pktTimestamp+payloadSz/2/sizeof(short); LOG(DEBUG) << "timeStart: " << timeStart << ", timeEnd: " << timeEnd << ", pktTimestamp: " << pktTimestamp; - } - } - + } + } + // copy desired data to buf unsigned bufStart = dataStart+(timestamp-timeStart); - if (bufStart + len < currDataSize/2) { + if (bufStart + len < currDataSize/2) { LOG(DEBUG) << "bufStart: " << bufStart; memcpy(buf,data+bufStart*2,len*2*sizeof(short)); memset(data+bufStart*2,0,len*2*sizeof(short)); @@ -428,21 +468,21 @@ int USRPDevice::readSamples(std::vector &bufs, int len, bool *overrun, timeStart = timestamp + len; return len; - + #else if (loopbackBufferSize < 2) return 0; int numSamples = 0; struct timeval currTime; gettimeofday(&currTime,NULL); - double timeElapsed = (currTime.tv_sec - lastReadTime.tv_sec)*1.0e6 + + double timeElapsed = (currTime.tv_sec - lastReadTime.tv_sec)*1.0e6 + (currTime.tv_usec - lastReadTime.tv_usec); if (timeElapsed < samplePeriod) {return 0;} int numSamplesToRead = (int) floor(timeElapsed/samplePeriod); if (numSamplesToRead < len) return 0; - + if (numSamplesToRead > len) numSamplesToRead = len; if (numSamplesToRead > loopbackBufferSize/2) { - firstRead =false; + firstRead =false; numSamplesToRead = loopbackBufferSize/2; } memcpy(buf,loopbackBuffer,sizeof(short)*2*numSamplesToRead); @@ -460,7 +500,7 @@ int USRPDevice::readSamples(std::vector &bufs, int len, bool *overrun, firstRead = true; } samplesRead += numSamples; - + return numSamples; #endif } @@ -471,7 +511,7 @@ int USRPDevice::writeSamples(std::vector &bufs, int len, { writeLock.lock(); -#ifndef SWLOOPBACK +#ifndef SWLOOPBACK if (!m_uTx) return 0; @@ -518,14 +558,14 @@ int USRPDevice::writeSamples(std::vector &bufs, int len, memcpy(loopbackBuffer+loopbackBufferSize,buf,sizeof(short)*2*len); samplesWritten += retVal; loopbackBufferSize += retVal*2; - + return retVal; #endif } -bool USRPDevice::updateAlignment(TIMESTAMP timestamp) +bool USRPDevice::updateAlignment(TIMESTAMP timestamp) { -#ifndef SWLOOPBACK +#ifndef SWLOOPBACK short data[] = {0x00,0x02,0x00,0x00}; uint32_t *wordPtr = (uint32_t *) data; *wordPtr = host_to_usrp_u32(*wordPtr); @@ -542,7 +582,7 @@ bool USRPDevice::updateAlignment(TIMESTAMP timestamp) #endif } -#ifndef SWLOOPBACK +#ifndef SWLOOPBACK bool USRPDevice::setTxFreq(double wFreq, size_t chan) { usrp_tune_result result; @@ -600,7 +640,9 @@ bool USRPDevice::setRxFreq(double wFreq) { return true;}; #endif RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps, - RadioDevice::InterfaceType, size_t chans, double) + InterfaceType iface, size_t chans, double offset, + const std::vector& tx_paths, + const std::vector& rx_paths) { return new USRPDevice(tx_sps); } diff --git a/Transceiver52M/USRPDevice.h b/Transceiver52M/USRPDevice.h index b5603391..f5fbe85e 100644 --- a/Transceiver52M/USRPDevice.h +++ b/Transceiver52M/USRPDevice.h @@ -83,10 +83,10 @@ private: double rxGain; -#ifdef SWLOOPBACK +#ifdef SWLOOPBACK short loopbackBuffer[1000000]; int loopbackBufferSize; - double samplePeriod; + double samplePeriod; struct timeval startTime; struct timeval lastReadTime; @@ -179,6 +179,18 @@ private: /** return minimum Rx Gain **/ double minTxGain(void); + /** sets the RX path to use, returns true if successful and false otherwise */ + bool setRxAntenna(const std::string &ant, size_t chan = 0); + + /* return the used RX path */ + std::string getRxAntenna(size_t chan = 0); + + /** sets the RX path to use, returns true if successful and false otherwise */ + bool setTxAntenna(const std::string &ant, size_t chan = 0); + + /* return the used RX path */ + std::string getTxAntenna(size_t chan = 0); + /** Return internal status values */ inline double getTxFreq(size_t chan = 0) { return 0; } inline double getRxFreq(size_t chan = 0) { return 0; } @@ -189,4 +201,3 @@ private: }; #endif // _USRP_DEVICE_H_ - diff --git a/Transceiver52M/osmo-trx.cpp b/Transceiver52M/osmo-trx.cpp index 44da6382..f1e41ee0 100644 --- a/Transceiver52M/osmo-trx.cpp +++ b/Transceiver52M/osmo-trx.cpp @@ -28,6 +28,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -79,6 +83,8 @@ struct trx_config { bool swap_channels; bool edge; int sched_rr; + std::vector rx_paths; + std::vector tx_paths; }; volatile bool gshutdown = false; @@ -241,6 +247,21 @@ static void setup_signal_handlers() } } + +static std::vector comma_delimited_to_vector(char* opt) { + std::string str = std::string(opt); + std::vector result; + std::stringstream ss(str); + + while( ss.good() ) + { + std::string substr; + getline(ss, substr, ','); + result.push_back(substr); + } + return result; +} + static void print_help() { fprintf(stdout, "Options:\n" @@ -263,7 +284,9 @@ static void print_help() " -A Random Access Burst test mode with delay\n" " -R RSSI to dBm offset in dB (default=0)\n" " -S Swap channels (UmTRX only)\n" - " -t SCHED_RR real-time priority (1..32)\n", + " -t SCHED_RR real-time priority (1..32)\n" + " -y comma-delimited list of Tx paths (num elements matches -c)\n" + " -z comma-delimited list of Rx paths (num elements matches -c)\n", "EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG"); } @@ -289,8 +312,10 @@ static void handle_options(int argc, char **argv, struct trx_config *config) config->swap_channels = false; config->edge = false; config->sched_rr = -1; + config->tx_paths = std::vector(DEFAULT_CHANS, ""); + config->rx_paths = std::vector(DEFAULT_CHANS, ""); - while ((option = getopt(argc, argv, "ha:l:i:j:p:c:dmxgfo:s:b:r:A:R:Set:")) != -1) { + while ((option = getopt(argc, argv, "ha:l:i:j:p:c:dmxgfo:s:b:r:A:R:Set:y:z:")) != -1) { switch (option) { case 'h': print_help(); @@ -355,6 +380,11 @@ static void handle_options(int argc, char **argv, struct trx_config *config) case 't': config->sched_rr = atoi(optarg); break; + case 'y': + config->tx_paths = comma_delimited_to_vector(optarg); + case 'z': + config->rx_paths = comma_delimited_to_vector(optarg); + break; default: print_help(); exit(0); @@ -391,6 +421,12 @@ static void handle_options(int argc, char **argv, struct trx_config *config) goto bad_config; } + if(config->tx_paths.size() != config->chans || + config->rx_paths.size() != config->chans) { + printf("Num of channels and num of tx/rx_paths doesn't match\n\n"); + goto bad_config; + } + return; bad_config: @@ -480,7 +516,7 @@ int main(int argc, char *argv[]) ref = RadioDevice::REF_INTERNAL; usrp = RadioDevice::make(config.tx_sps, config.rx_sps, iface, - config.chans, config.offset); + config.chans, config.offset, config.tx_paths, config.rx_paths); type = usrp->open(config.dev_args, ref, config.swap_channels); if (type < 0) { LOG(ALERT) << "Failed to create radio device" << std::endl; diff --git a/Transceiver52M/radioDevice.h b/Transceiver52M/radioDevice.h index 3624c585..8045cf61 100644 --- a/Transceiver52M/radioDevice.h +++ b/Transceiver52M/radioDevice.h @@ -50,7 +50,9 @@ class RadioDevice { }; static RadioDevice *make(size_t tx_sps, size_t rx_sps, InterfaceType type, - size_t chans = 1, double offset = 0.0); + size_t chans = 1, double offset = 0.0, + const std::vector& tx_paths = std::vector(1, ""), + const std::vector& rx_paths = std::vector(1, "")); /** Initialize the USRP */ virtual int open(const std::string &args, int ref, bool swap_channels)=0; @@ -136,6 +138,18 @@ class RadioDevice { /** return minimum Tx Gain **/ virtual double minTxGain(void) = 0; + /** sets the RX path to use, returns true if successful and false otherwise */ + virtual bool setRxAntenna(const std::string &ant, size_t chan = 0) = 0; + + /* return the used RX path */ + virtual std::string getRxAntenna(size_t chan = 0) = 0; + + /** sets the RX path to use, returns true if successful and false otherwise */ + virtual bool setTxAntenna(const std::string &ant, size_t chan = 0) = 0; + + /* return the used RX path */ + virtual std::string getTxAntenna(size_t chan = 0) = 0; + /** Return internal status values */ virtual double getTxFreq(size_t chan = 0) = 0; virtual double getRxFreq(size_t chan = 0) = 0;