From 5cd70dc4ec6a658c2835c805a8b941351c90ccb0 Mon Sep 17 00:00:00 2001 From: Tom Tsou Date: Sun, 6 Mar 2016 01:28:40 -0800 Subject: EDGE: Setup variable sampling on receive path Allow setting the device to non single SPS sample rates - mainly running at 4 SPS as the signal processing library does not support other rates. Wider bandwith support is required on the receive path to avoid 8-PSK bandlimiting distortion for EDGE. Signed-off-by: Tom Tsou --- Transceiver52M/Transceiver.cpp | 4 +- Transceiver52M/Transceiver.h | 2 +- Transceiver52M/UHDDevice.cpp | 134 ++++++++++++++++++++++++++------------ Transceiver52M/USRPDevice.cpp | 7 +- Transceiver52M/USRPDevice.h | 2 +- Transceiver52M/osmo-trx.cpp | 44 ++++++++----- Transceiver52M/radioDevice.h | 2 +- Transceiver52M/radioInterface.cpp | 20 ++++-- Transceiver52M/radioInterface.h | 3 +- 9 files changed, 144 insertions(+), 74 deletions(-) diff --git a/Transceiver52M/Transceiver.cpp b/Transceiver52M/Transceiver.cpp index 48f4a19..2be7ab0 100644 --- a/Transceiver52M/Transceiver.cpp +++ b/Transceiver52M/Transceiver.cpp @@ -143,7 +143,7 @@ bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc) Transceiver::Transceiver(int wBasePort, const char *wTRXAddress, - size_t wSPS, size_t wChans, + size_t tx_sps, size_t rx_sps, size_t chans, GSM::Time wTransmitLatency, RadioInterface *wRadioInterface, double wRssiOffset) @@ -151,7 +151,7 @@ Transceiver::Transceiver(int wBasePort, mClockSocket(wBasePort, wTRXAddress, mBasePort + 100), mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface), rssiOffset(wRssiOffset), - mSPSTx(wSPS), mSPSRx(1), mChans(wChans), mOn(false), + mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mOn(false), mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0), mWriteBurstToDiskMask(0) { txFullScale = mRadioInterface->fullScaleInputValue(); diff --git a/Transceiver52M/Transceiver.h b/Transceiver52M/Transceiver.h index 0337aab..2fd1aea 100644 --- a/Transceiver52M/Transceiver.h +++ b/Transceiver52M/Transceiver.h @@ -98,7 +98,7 @@ public: */ Transceiver(int wBasePort, const char *TRXAddress, - size_t wSPS, size_t chans, + size_t tx_sps, size_t rx_sps, size_t chans, GSM::Time wTransmitLatency, RadioInterface *wRadioInterface, double wRssiOffset); diff --git a/Transceiver52M/UHDDevice.cpp b/Transceiver52M/UHDDevice.cpp index 777dab4..af844f6 100644 --- a/Transceiver52M/UHDDevice.cpp +++ b/Transceiver52M/UHDDevice.cpp @@ -68,7 +68,8 @@ enum uhd_dev_type { struct uhd_dev_offset { enum uhd_dev_type type; - int sps; + int tx_sps; + int rx_sps; double offset; const std::string desc; }; @@ -79,9 +80,11 @@ struct uhd_dev_offset { #ifdef USE_UHD_3_9 #define B2XX_TIMING_1SPS 1.7153e-4 #define B2XX_TIMING_4SPS 1.1696e-4 +#define B2XX_TIMING_4_4SPS 5.89578e-5 #else #define B2XX_TIMING_1SPS 9.9692e-5 #define B2XX_TIMING_4SPS 6.9248e-5 +#define B2XX_TIMING_4_4SPS 4.19034e-5 #endif /* @@ -95,24 +98,32 @@ struct uhd_dev_offset { * USRP1 with timestamps is not supported by UHD. */ static struct uhd_dev_offset uhd_offsets[NUM_USRP_TYPES * 2] = { - { USRP1, 1, 0.0, "USRP1 not supported" }, - { USRP1, 4, 0.0, "USRP1 not supported"}, - { USRP2, 1, 1.2184e-4, "N2XX 1 SPS" }, - { USRP2, 4, 8.0230e-5, "N2XX 4 SPS" }, - { B100, 1, 1.2104e-4, "B100 1 SPS" }, - { B100, 4, 7.9307e-5, "B100 4 SPS" }, - { B200, 1, B2XX_TIMING_1SPS, "B200 1 SPS" }, - { B200, 4, B2XX_TIMING_4SPS, "B200 4 SPS" }, - { B210, 1, B2XX_TIMING_1SPS, "B210 1 SPS" }, - { B210, 4, B2XX_TIMING_4SPS, "B210 4 SPS" }, - { E1XX, 1, 9.5192e-5, "E1XX 1 SPS" }, - { E1XX, 4, 6.5571e-5, "E1XX 4 SPS" }, - { E3XX, 1, 1.5000e-4, "E3XX 1 SPS" }, - { E3XX, 4, 1.2740e-4, "E3XX 4 SPS" }, - { X3XX, 1, 1.5360e-4, "X3XX 1 SPS"}, - { X3XX, 4, 1.1264e-4, "X3XX 4 SPS"}, - { UMTRX, 1, 9.9692e-5, "UmTRX 1 SPS" }, - { UMTRX, 4, 7.3846e-5, "UmTRX 4 SPS" }, + { USRP1, 1, 1, 0.0, "USRP1 not supported" }, + { USRP1, 4, 1, 0.0, "USRP1 not supported"}, + { USRP2, 1, 1, 1.2184e-4, "N2XX 1 SPS" }, + { USRP2, 4, 1, 8.0230e-5, "N2XX 4 SPS" }, + { B100, 1, 1, 1.2104e-4, "B100 1 SPS" }, + { B100, 4, 1, 7.9307e-5, "B100 4 SPS" }, + { B200, 1, 1, B2XX_TIMING_1SPS, "B200 1 SPS" }, + { B200, 4, 1, B2XX_TIMING_4SPS, "B200 4 SPS" }, + { B210, 1, 1, B2XX_TIMING_1SPS, "B210 1 SPS" }, + { B210, 4, 1, B2XX_TIMING_4SPS, "B210 4 SPS" }, + { E1XX, 1, 1, 9.5192e-5, "E1XX 1 SPS" }, + { E1XX, 4, 1, 6.5571e-5, "E1XX 4 SPS" }, + { E3XX, 1, 1, 1.5000e-4, "E3XX 1 SPS" }, + { E3XX, 4, 1, 1.2740e-4, "E3XX 4 SPS" }, + { X3XX, 1, 1, 1.5360e-4, "X3XX 1 SPS"}, + { X3XX, 4, 1, 1.1264e-4, "X3XX 4 SPS"}, + { UMTRX, 1, 1, 9.9692e-5, "UmTRX 1 SPS" }, + { UMTRX, 4, 1, 7.3846e-5, "UmTRX 4 SPS" }, +}; + +struct uhd_dev_offset edge_offset = { + .type = B200, + .tx_sps = 4, + .rx_sps = 4, + .offset = B2XX_TIMING_4_4SPS, + .desc = "B200/B210 EDGE mode (4 SPS TX/RX)", }; /* @@ -120,12 +131,12 @@ static struct uhd_dev_offset uhd_offsets[NUM_USRP_TYPES * 2] = { * diversity receiver only. */ static struct uhd_dev_offset special_offsets[] = { - { UMTRX, 1, 8.0875e-5, "UmTRX diversity, 1 SPS" }, - { UMTRX, 4, 5.2103e-5, "UmTRX diversity, 4 SPS" }, + { UMTRX, 1, 1, 8.0875e-5, "UmTRX diversity, 1 SPS" }, + { UMTRX, 4, 1, 5.2103e-5, "UmTRX diversity, 4 SPS" }, }; -static double get_dev_offset(enum uhd_dev_type type, - int sps, bool diversity = false) +static double get_dev_offset(enum uhd_dev_type type, int tx_sps, + bool edge = false, bool diversity = false) { struct uhd_dev_offset *offset = NULL; @@ -135,6 +146,11 @@ static double get_dev_offset(enum uhd_dev_type type, return 0.0; } + if (edge && diversity) { + LOG(ERR) << "Unsupported configuration"; + return 0.0; + } + /* Special cases (e.g. diversity receiver) */ if (diversity) { if (type != UMTRX) { @@ -142,7 +158,7 @@ static double get_dev_offset(enum uhd_dev_type type, return 0.0; } - switch (sps) { + switch (tx_sps) { case 1: offset = &special_offsets[0]; break; @@ -150,11 +166,22 @@ static double get_dev_offset(enum uhd_dev_type type, default: offset = &special_offsets[1]; } + } else if (edge) { + if ((type != B200) && (type != B210)) { + LOG(ALERT) << "EDGE support on B200/B210 only"; + return 0.0; + } + if (tx_sps != 4) { + LOG(ALERT) << "Invalid device configuration"; + return 0.0; + } + + offset = &edge_offset; } else { /* Search for matching offset value */ for (int i = 0; i < NUM_USRP_TYPES * 2; i++) { if ((type == uhd_offsets[i].type) && - (sps == uhd_offsets[i].sps)) { + (tx_sps == uhd_offsets[i].tx_sps)) { offset = &uhd_offsets[i]; break; } @@ -281,7 +308,8 @@ private: */ class uhd_device : public RadioDevice { public: - uhd_device(size_t sps, size_t chans, bool diversity, double offset); + uhd_device(size_t tx_sps, size_t rx_sps, + size_t chans, bool diversity, double offset); ~uhd_device(); int open(const std::string &args, bool extref, bool swap_channels); @@ -302,8 +330,8 @@ public: bool setTxFreq(double wFreq, size_t chan); bool setRxFreq(double wFreq, size_t chan); - inline TIMESTAMP initialWriteTimestamp() { return ts_initial * sps; } - inline TIMESTAMP initialReadTimestamp() { return ts_initial; } + inline TIMESTAMP initialWriteTimestamp(); + inline TIMESTAMP initialReadTimestamp(); double fullScaleInputValue(); double fullScaleOutputValue(); @@ -344,7 +372,7 @@ private: enum TxWindowType tx_window; enum uhd_dev_type dev_type; - size_t sps, chans; + size_t tx_sps, rx_sps, chans; double tx_rate, rx_rate; double tx_gain_min, tx_gain_max; @@ -423,14 +451,16 @@ static void thread_enable_cancel(bool cancel) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); } -uhd_device::uhd_device(size_t sps, size_t chans, bool diversity, double offset) +uhd_device::uhd_device(size_t tx_sps, size_t rx_sps, + size_t chans, bool diversity, double offset) : 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_initial(0), ts_offset(0) { - this->sps = sps; + this->tx_sps = tx_sps; + this->rx_sps = rx_sps; this->chans = chans; this->offset = offset; this->diversity = diversity; @@ -738,12 +768,8 @@ int uhd_device::open(const std::string &args, bool extref, bool swap_channels) usrp_dev->set_clock_source("external"); // Set rates - double _rx_rate; - double _tx_rate = select_rate(dev_type, sps); - if (diversity) - _rx_rate = select_rate(dev_type, 1, true); - else - _rx_rate = _tx_rate / sps; + double _tx_rate = select_rate(dev_type, tx_sps); + double _rx_rate = select_rate(dev_type, rx_sps, diversity); if ((_tx_rate < 0.0) || (_rx_rate < 0.0)) return -1; @@ -777,8 +803,14 @@ int uhd_device::open(const std::string &args, bool extref, bool swap_channels) 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, diversity); + // Set receive chain sample offset. Trigger the EDGE offset + // table by checking for 4 SPS on the receive path. No other + // configuration supports using 4 SPS. + bool edge = false; + if (rx_sps == 4) + edge = true; + + double offset = get_dev_offset(dev_type, tx_sps, edge, diversity); if (offset == 0.0) { LOG(ERR) << "Unsupported configuration, no correction applied"; ts_offset = 0; @@ -1243,6 +1275,24 @@ double uhd_device::getRxFreq(size_t chan) return rx_freqs[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 + * combination. + */ +TIMESTAMP uhd_device::initialWriteTimestamp() +{ + if (rx_sps == tx_sps) + return ts_initial; + else + return ts_initial * tx_sps; +} + +TIMESTAMP uhd_device::initialReadTimestamp() +{ + return ts_initial; +} + double uhd_device::fullScaleInputValue() { if (dev_type == UMTRX) @@ -1508,8 +1558,8 @@ std::string smpl_buf::str_code(ssize_t code) } } -RadioDevice *RadioDevice::make(size_t sps, size_t chans, - bool diversity, double offset) +RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps, + size_t chans, bool diversity, double offset) { - return new uhd_device(sps, chans, diversity, offset); + return new uhd_device(tx_sps, rx_sps, chans, diversity, offset); } diff --git a/Transceiver52M/USRPDevice.cpp b/Transceiver52M/USRPDevice.cpp index 568f0e5..bf6ccca 100644 --- a/Transceiver52M/USRPDevice.cpp +++ b/Transceiver52M/USRPDevice.cpp @@ -59,7 +59,7 @@ const dboardConfigType dboardConfig = TXA_RXB; const double USRPDevice::masterClockRate = 52.0e6; -USRPDevice::USRPDevice(size_t sps, size_t, bool) +USRPDevice::USRPDevice(size_t sps) { LOG(INFO) << "creating USRP device..."; @@ -600,7 +600,8 @@ bool USRPDevice::setTxFreq(double wFreq) { return true;}; bool USRPDevice::setRxFreq(double wFreq) { return true;}; #endif -RadioDevice *RadioDevice::make(size_t sps, size_t chans, bool diversity, double) +RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps, + size_t chans, bool diversity, double) { - return new USRPDevice(sps, chans, diversity); + return new USRPDevice(tx_sps); } diff --git a/Transceiver52M/USRPDevice.h b/Transceiver52M/USRPDevice.h index 3f06c88..6bc5f1d 100644 --- a/Transceiver52M/USRPDevice.h +++ b/Transceiver52M/USRPDevice.h @@ -96,7 +96,7 @@ private: public: /** Object constructor */ - USRPDevice(size_t sps, size_t chans = 1, bool diversity = false); + USRPDevice(size_t sps); /** Instantiate the USRP */ int open(const std::string &, bool, bool); diff --git a/Transceiver52M/osmo-trx.cpp b/Transceiver52M/osmo-trx.cpp index 7b9fd7c..c8fd9a8 100644 --- a/Transceiver52M/osmo-trx.cpp +++ b/Transceiver52M/osmo-trx.cpp @@ -41,11 +41,19 @@ * ARM and non-SIMD enabled architectures. */ #if defined(HAVE_NEON) || !defined(HAVE_SSE3) -#define DEFAULT_SPS 1 +#define DEFAULT_TX_SPS 1 #else -#define DEFAULT_SPS 4 +#define DEFAULT_TX_SPS 4 #endif +/* + * Samples-per-symbol for uplink (receiver) path + * Do not modify this value. EDGE configures 4 sps automatically on + * B200/B210 devices only. Use of 4 sps on the receive path for other + * configurations is not supported. + */ +#define DEFAULT_RX_SPS 1 + /* Default configuration parameters * Note that these values are only used if the particular key does not * exist in the configuration database. IP port and address values will @@ -63,7 +71,8 @@ struct trx_config { std::string addr; std::string dev_args; unsigned port; - unsigned sps; + unsigned tx_sps; + unsigned rx_sps; unsigned chans; unsigned rtsc; bool extref; @@ -182,7 +191,7 @@ bool trx_setup_config(struct trx_config *config) ost << " TRX Base Port........... " << config->port << std::endl; ost << " TRX Address............. " << config->addr << std::endl; ost << " Channels................ " << config->chans << std::endl; - ost << " Samples-per-Symbol...... " << config->sps << std::endl; + ost << " Tx Samples-per-Symbol... " << config->tx_sps << std::endl; ost << " External Reference...... " << refstr << std::endl; ost << " C0 Filler Table......... " << fillstr << std::endl; ost << " Diversity............... " << divstr << std::endl; @@ -208,16 +217,17 @@ RadioInterface *makeRadioInterface(struct trx_config *config, switch (type) { case RadioDevice::NORMAL: - radio = new RadioInterface(usrp, config->sps, config->chans); + radio = new RadioInterface(usrp, config->tx_sps, + config->rx_sps, config->chans); break; case RadioDevice::RESAMP_64M: case RadioDevice::RESAMP_100M: - radio = new RadioInterfaceResamp(usrp, - config->sps, config->chans); + radio = new RadioInterfaceResamp(usrp, config->tx_sps, + config->chans); break; case RadioDevice::DIVERSITY: - radio = new RadioInterfaceDiversity(usrp, - config->sps, config->chans); + radio = new RadioInterfaceDiversity(usrp, config->tx_sps, + config->chans); break; default: LOG(ALERT) << "Unsupported radio interface configuration"; @@ -243,8 +253,9 @@ Transceiver *makeTransceiver(struct trx_config *config, RadioInterface *radio) Transceiver *trx; VectorFIFO *fifo; - trx = new Transceiver(config->port, config->addr.c_str(), config->sps, - config->chans, GSM::Time(3,0), radio, config->rssi_offset); + trx = new Transceiver(config->port, config->addr.c_str(), + config->tx_sps, config->rx_sps, config->chans, + GSM::Time(3,0), radio, config->rssi_offset); if (!trx->init(config->filler, config->rtsc)) { LOG(ALERT) << "Failed to initialize transceiver"; delete trx; @@ -307,7 +318,8 @@ static void handle_options(int argc, char **argv, struct trx_config *config) int option; config->port = 0; - config->sps = DEFAULT_SPS; + config->tx_sps = DEFAULT_TX_SPS; + config->rx_sps = DEFAULT_RX_SPS; config->chans = DEFAULT_CHANS; config->rtsc = 0; config->extref = false; @@ -351,7 +363,7 @@ static void handle_options(int argc, char **argv, struct trx_config *config) config->offset = atof(optarg); break; case 's': - config->sps = atoi(optarg); + config->tx_sps = atoi(optarg); break; case 'r': config->rtsc = atoi(optarg); @@ -369,8 +381,8 @@ static void handle_options(int argc, char **argv, struct trx_config *config) } } - if ((config->sps != 1) && (config->sps != 4)) { - printf("Unsupported samples-per-symbol %i\n\n", config->sps); + if ((config->tx_sps != 1) && (config->tx_sps != 4)) { + printf("Unsupported samples-per-symbol %i\n\n", config->tx_sps); print_help(); exit(0); } @@ -405,7 +417,7 @@ int main(int argc, char *argv[]) srandom(time(NULL)); /* Create the low level device object */ - usrp = RadioDevice::make(config.sps, config.chans, + usrp = RadioDevice::make(config.tx_sps, config.rx_sps, config.chans, config.diversity, config.offset); type = usrp->open(config.dev_args, config.extref, config.swap_channels); if (type < 0) { diff --git a/Transceiver52M/radioDevice.h b/Transceiver52M/radioDevice.h index dd4928c..40f47a5 100644 --- a/Transceiver52M/radioDevice.h +++ b/Transceiver52M/radioDevice.h @@ -37,7 +37,7 @@ class RadioDevice { /* Radio interface types */ enum RadioInterfaceType { NORMAL, RESAMP_64M, RESAMP_100M, DIVERSITY }; - static RadioDevice *make(size_t sps, size_t chans = 1, + static RadioDevice *make(size_t tx_sps, size_t rx_sps = 1, size_t chans = 1, bool diversity = false, double offset = 0.0); /** Initialize the USRP */ diff --git a/Transceiver52M/radioInterface.cpp b/Transceiver52M/radioInterface.cpp index 14a4fc2..7256b9b 100644 --- a/Transceiver52M/radioInterface.cpp +++ b/Transceiver52M/radioInterface.cpp @@ -33,12 +33,12 @@ extern "C" { #define CHUNK 625 #define NUMCHUNKS 4 -RadioInterface::RadioInterface(RadioDevice *wRadio, - size_t sps, size_t chans, size_t diversity, +RadioInterface::RadioInterface(RadioDevice *wRadio, size_t tx_sps, + size_t rx_sps, size_t chans, size_t diversity, int wReceiveOffset, GSM::Time wStartTime) - : mRadio(wRadio), mSPSTx(sps), mSPSRx(1), mChans(chans), mMIMO(diversity), - sendCursor(0), recvCursor(0), underrun(false), overrun(false), - receiveOffset(wReceiveOffset), mOn(false) + : mRadio(wRadio), mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), + mMIMO(diversity), sendCursor(0), recvCursor(0), underrun(false), + overrun(false), receiveOffset(wReceiveOffset), mOn(false) { mClock.set(wStartTime); } @@ -262,7 +262,12 @@ bool RadioInterface::driveReceiveRadio() int recvSz = recvCursor; int readSz = 0; const int symbolsPerSlot = gSlotLen + 8; - int burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx; + int burstSize; + + if (mSPSRx == 4) + burstSize = 625; + else + burstSize = symbolsPerSlot + (tN % 4 == 0); /* * Pre-allocate head room for the largest correlation size @@ -297,7 +302,8 @@ bool RadioInterface::driveReceiveRadio() tN = rcvClock.TN(); - burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx; + if (mSPSRx != 4) + burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx; } if (readSz > 0) { diff --git a/Transceiver52M/radioInterface.h b/Transceiver52M/radioInterface.h index b359cbd..ce06578 100644 --- a/Transceiver52M/radioInterface.h +++ b/Transceiver52M/radioInterface.h @@ -87,7 +87,8 @@ public: /** constructor */ RadioInterface(RadioDevice* wRadio = NULL, - size_t sps = 4, size_t chans = 1, size_t diversity = 1, + size_t tx_sps = 4, size_t rx_sps = 1, + size_t chans = 1, size_t diversity = 1, int receiveOffset = 3, GSM::Time wStartTime = GSM::Time(0)); /** destructor */ -- cgit v1.2.3