blob: bf6499689ada5ed371e208cba9042269b508678f [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
Thomas Tsou711e6af2012-03-07 19:55:59 -05002* Copyright 2008, 2009, 2012 Free Software Foundation, Inc.
dburgessb3a0ca42011-10-12 07:44:40 +00003*
4* This software is distributed under the terms of the GNU Affero Public License.
5* See the COPYING file in the main directory for details.
6*
7* This use of this software may be subject to additional restrictions.
8* See the LEGAL file in the main directory for details.
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU Affero General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Affero General Public License for more details.
19
20 You should have received a copy of the GNU Affero General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22
23*/
24
dburgessb3a0ca42011-10-12 07:44:40 +000025#include "radioInterface.h"
26#include <Logger.h>
Alexander Chemeris1339e422013-08-29 02:52:13 +040027#include "RTMD.h"
dburgessb3a0ca42011-10-12 07:44:40 +000028
kurtis.heimerl9b557832011-11-26 03:18:34 +000029bool started = false;
30
Thomas Tsou03669852013-04-08 14:41:11 -040031/* Device side buffers */
Thomas Tsou48f8fb32013-04-26 19:30:55 -040032static short *rx_buf[CHAN_MAX];
33static short *tx_buf[CHAN_MAX];
Thomas Tsou03669852013-04-08 14:41:11 -040034
35/* Complex float to short conversion */
36static void floatToShort(short *out, float *in, int num)
37{
38 for (int i = 0; i < num; i++) {
39 out[2 * i + 0] = (short) in[2 * i + 0];
40 out[2 * i + 1] = (short) in[2 * i + 1];
41 }
42}
43
44/* Complex short to float conversion */
45static void shortToFloat(float *out, short *in, int num)
46{
47 for (int i = 0; i < num; i++) {
48 out[2 * i + 0] = (float) in[2 * i + 0];
49 out[2 * i + 1] = (float) in[2 * i + 1];
50 }
51}
52
dburgessb3a0ca42011-10-12 07:44:40 +000053RadioInterface::RadioInterface(RadioDevice *wRadio,
Thomas Tsou41c66572012-06-05 20:31:28 -040054 int wChanM,
Thomas Tsou801ce602013-04-08 13:45:55 -040055 int wSPS,
Thomas Tsou48f8fb32013-04-26 19:30:55 -040056 int wReceiveOffset,
dburgessb3a0ca42011-10-12 07:44:40 +000057 GSM::Time wStartTime)
Thomas Tsou41c66572012-06-05 20:31:28 -040058 : mChanM(wChanM), underrun(false), sendCursor(0), rcvCursor(0), mOn(false),
Thomas Tsou48f8fb32013-04-26 19:30:55 -040059 mRadio(wRadio), receiveOffset(wReceiveOffset), samplesPerSymbol(wSPS),
60 powerScaling(1.0), loadTest(false)
dburgessb3a0ca42011-10-12 07:44:40 +000061{
dburgessb3a0ca42011-10-12 07:44:40 +000062 mClock.set(wStartTime);
dburgessb3a0ca42011-10-12 07:44:40 +000063}
64
Thomas Tsou711e6af2012-03-07 19:55:59 -050065RadioInterface::~RadioInterface(void)
66{
Thomas Tsou507e6d42012-03-16 20:26:46 -040067 if (mOn) {
68 mRadio->stop();
69 close();
Thomas Tsoua6ca73c2012-03-17 16:47:01 -040070
Thomas Tsou48f8fb32013-04-26 19:30:55 -040071 for (int i = 0; i < mChanM; i++) {
Thomas Tsou507e6d42012-03-16 20:26:46 -040072 if (rcvBuffer[i] != NULL)
73 delete rcvBuffer[i];
74 if (sendBuffer[i] != NULL)
75 delete sendBuffer[i];
76 }
Thomas Tsou711e6af2012-03-07 19:55:59 -050077 }
dburgessb3a0ca42011-10-12 07:44:40 +000078}
79
80double RadioInterface::fullScaleInputValue(void) {
81 return mRadio->fullScaleInputValue();
82}
83
84double RadioInterface::fullScaleOutputValue(void) {
85 return mRadio->fullScaleOutputValue();
86}
87
88
Thomas Tsou42ade042013-07-13 18:29:08 +020089void RadioInterface::setPowerAttenuation(double atten, int chan)
dburgessb3a0ca42011-10-12 07:44:40 +000090{
kurtis.heimerl16c65402011-11-26 03:18:11 +000091 double rfGain, digAtten;
kurtis.heimerlee5347a2011-11-26 03:18:05 +000092
Thomas Tsou42ade042013-07-13 18:29:08 +020093 rfGain = mRadio->setTxGain(mRadio->maxTxGain() - atten, chan);
kurtis.heimerl16c65402011-11-26 03:18:11 +000094 digAtten = atten - mRadio->maxTxGain() + rfGain;
kurtis.heimerlee5347a2011-11-26 03:18:05 +000095
96 if (digAtten < 1.0)
97 powerScaling = 1.0;
98 else
99 powerScaling = 1.0/sqrt(pow(10, (digAtten/10.0)));
dburgessb3a0ca42011-10-12 07:44:40 +0000100}
101
kurtis.heimerl9b557832011-11-26 03:18:34 +0000102int RadioInterface::radioifyVector(signalVector &wVector,
103 float *retVector,
104 float scale,
105 bool zero)
dburgessb3a0ca42011-10-12 07:44:40 +0000106{
kurtis.heimerl9b557832011-11-26 03:18:34 +0000107 int i;
dburgessb3a0ca42011-10-12 07:44:40 +0000108 signalVector::iterator itr = wVector.begin();
kurtis.heimerl9b557832011-11-26 03:18:34 +0000109
110 if (zero) {
111 memset(retVector, 0, wVector.size() * 2 * sizeof(float));
112 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000113 }
114
kurtis.heimerl9b557832011-11-26 03:18:34 +0000115 for (i = 0; i < wVector.size(); i++) {
116 retVector[2 * i + 0] = itr->real() * scale;
117 retVector[2 * i + 1] = itr->imag() * scale;
118 itr++;
119 }
120
121 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000122}
123
Thomas Tsou711e6af2012-03-07 19:55:59 -0500124int RadioInterface::unRadioifyVector(float *floatVector, int offset,
125 signalVector &newVector)
dburgessb3a0ca42011-10-12 07:44:40 +0000126{
kurtis.heimerl9b557832011-11-26 03:18:34 +0000127 int i;
dburgessb3a0ca42011-10-12 07:44:40 +0000128 signalVector::iterator itr = newVector.begin();
kurtis.heimerl9b557832011-11-26 03:18:34 +0000129
130 for (i = 0; i < newVector.size(); i++) {
Thomas Tsou711e6af2012-03-07 19:55:59 -0500131 *itr++ = Complex<float>(floatVector[offset + 2 * i + 0],
132 floatVector[offset + 2 * i + 1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000133 }
134
kurtis.heimerl9b557832011-11-26 03:18:34 +0000135 return newVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000136}
137
Thomas Tsou48f8fb32013-04-26 19:30:55 -0400138bool RadioInterface::tuneTx(double freq, int chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000139{
Thomas Tsou48f8fb32013-04-26 19:30:55 -0400140 return mRadio->setTxFreq(freq, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000141}
142
Thomas Tsou48f8fb32013-04-26 19:30:55 -0400143bool RadioInterface::tuneRx(double freq, int chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000144{
Thomas Tsou48f8fb32013-04-26 19:30:55 -0400145 return mRadio->setRxFreq(freq, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000146}
147
148
Thomas Tsou711e6af2012-03-07 19:55:59 -0500149bool RadioInterface::start()
dburgessb3a0ca42011-10-12 07:44:40 +0000150{
Thomas Tsou711e6af2012-03-07 19:55:59 -0500151 int i;
152
153 if (mOn)
154 return false;
155
Thomas Tsoua6ca73c2012-03-17 16:47:01 -0400156 mOn = true;
Thomas Tsoued64e792013-04-08 13:35:36 -0400157#ifdef USRP1
Thomas Tsoua6ca73c2012-03-17 16:47:01 -0400158 mAlignRadioServiceLoopThread = new Thread(32768);
159 mAlignRadioServiceLoopThread->start((void * (*)(void*))AlignRadioServiceLoopAdapter,
160 (void*)this);
Thomas Tsoued64e792013-04-08 13:35:36 -0400161#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000162 writeTimestamp = mRadio->initialWriteTimestamp();
163 readTimestamp = mRadio->initialReadTimestamp();
Thomas Tsou41c66572012-06-05 20:31:28 -0400164 for (i = 0; i < mChanM; i++) {
Thomas Tsou711e6af2012-03-07 19:55:59 -0500165 sendBuffer[i] = new float[8*2*INCHUNK];
166 rcvBuffer[i] = new float[8*2*OUTCHUNK];
167 }
168
169 /* Init I/O specific variables if applicable */
170 init();
171
Thomas Tsoua6ca73c2012-03-17 16:47:01 -0400172 mRadio->start();
173 LOG(DEBUG) << "Radio started";
174 mRadio->updateAlignment(writeTimestamp-10000);
175 mRadio->updateAlignment(writeTimestamp-10000);
dburgessb3a0ca42011-10-12 07:44:40 +0000176
Thomas Tsou711e6af2012-03-07 19:55:59 -0500177 return true;
dburgessb3a0ca42011-10-12 07:44:40 +0000178}
179
Thomas Tsou5f133772012-03-17 15:02:32 -0400180bool RadioInterface::stop()
181{
182 if (!mOn)
183 return false;
184
185 mOn = false;
186 mRadio->stop();
187}
188
Thomas Tsoued64e792013-04-08 13:35:36 -0400189#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000190void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface)
191{
Thomas Tsou5f133772012-03-17 15:02:32 -0400192 while (radioInterface->on()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000193 radioInterface->alignRadio();
194 pthread_testcancel();
195 }
196 return NULL;
197}
198
199void RadioInterface::alignRadio() {
200 sleep(60);
201 mRadio->updateAlignment(writeTimestamp+ (TIMESTAMP) 10000);
202}
Thomas Tsoued64e792013-04-08 13:35:36 -0400203#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000204
Thomas Tsou711e6af2012-03-07 19:55:59 -0500205void RadioInterface::driveTransmitRadio(signalVector **radioBurst, bool *zeroBurst)
206{
207 int i;
Alexander Chemeris4c192002013-08-29 13:19:12 +0400208 RTMD_SET("drvTxRadio");
dburgessb3a0ca42011-10-12 07:44:40 +0000209
Alexander Chemeris4c192002013-08-29 13:19:12 +0400210 if (!mOn) {
211 RTMD_VAL("drvTxRadio", -1);
212 RTMD_CLEAR("drvTxRadio");
Thomas Tsou711e6af2012-03-07 19:55:59 -0500213 return;
Alexander Chemeris4c192002013-08-29 13:19:12 +0400214 }
dburgessb3a0ca42011-10-12 07:44:40 +0000215
Thomas Tsou41c66572012-06-05 20:31:28 -0400216 for (i = 0; i < mChanM; i++) {
Thomas Tsou48f8fb32013-04-26 19:30:55 -0400217 radioifyVector(*radioBurst[i], sendBuffer[i] + 2 * sendCursor,
218 powerScaling, zeroBurst[i]);
Thomas Tsou711e6af2012-03-07 19:55:59 -0500219 }
dburgessb3a0ca42011-10-12 07:44:40 +0000220
Thomas Tsou711e6af2012-03-07 19:55:59 -0500221 /*
222 * All bursts should be the same size since all transceivers are
223 * tied with a single clock in the radio interface.
224 */
225 sendCursor += radioBurst[0]->size();
dburgessb3a0ca42011-10-12 07:44:40 +0000226
227 pushBuffer();
Alexander Chemeris4c192002013-08-29 13:19:12 +0400228 RTMD_CLEAR("drvTxRadio");
dburgessb3a0ca42011-10-12 07:44:40 +0000229}
230
Thomas Tsou48f8fb32013-04-26 19:30:55 -0400231static inline void shiftRxBuffers(float **buf, int offset, int len, int chanM)
Thomas Tsou711e6af2012-03-07 19:55:59 -0500232{
Thomas Tsou48f8fb32013-04-26 19:30:55 -0400233 for (int i = 0; i < chanM; i++)
Thomas Tsou711e6af2012-03-07 19:55:59 -0500234 memmove(buf[i], buf[i] + offset, sizeof(float) * len);
Thomas Tsou711e6af2012-03-07 19:55:59 -0500235}
dburgessb3a0ca42011-10-12 07:44:40 +0000236
Thomas Tsou711e6af2012-03-07 19:55:59 -0500237void RadioInterface::loadVectors(unsigned tN, int samplesPerBurst,
238 int idx, GSM::Time rxClock)
239{
240 int i;
241
Thomas Tsou41c66572012-06-05 20:31:28 -0400242 for (i = 0; i < mChanM; i++) {
Thomas Tsou48f8fb32013-04-26 19:30:55 -0400243 signalVector rxVector(samplesPerBurst);
244 unRadioifyVector(rcvBuffer[i], idx * 2, rxVector);
245 radioVector *rxBurst = new radioVector(rxVector, rxClock);
246 mReceiveFIFO[i].write(rxBurst);
Thomas Tsou711e6af2012-03-07 19:55:59 -0500247 }
248}
249
250void RadioInterface::driveReceiveRadio()
251{
Alexander Chemeris9fb1c0b2013-09-01 03:15:32 +0400252 RTMD_SET("drvRxRadio");
Alexander Chemeris1339e422013-08-29 02:52:13 +0400253 if (!mOn) {
Alexander Chemeris9fb1c0b2013-09-01 03:15:32 +0400254 RTMD_VAL("drvRxRadio", -1);
255 RTMD_CLEAR("drvRxRadio");
Thomas Tsou711e6af2012-03-07 19:55:59 -0500256 return;
Alexander Chemeris1339e422013-08-29 02:52:13 +0400257 }
Thomas Tsou711e6af2012-03-07 19:55:59 -0500258
Alexander Chemeris1339e422013-08-29 02:52:13 +0400259 if (mReceiveFIFO[0].size() > 8) {
Alexander Chemeris9fb1c0b2013-09-01 03:15:32 +0400260 RTMD_VAL("drvRxRadio", 2);
261 RTMD_CLEAR("drvRxRadio");
Thomas Tsou711e6af2012-03-07 19:55:59 -0500262 return;
Alexander Chemeris1339e422013-08-29 02:52:13 +0400263 }
dburgessb3a0ca42011-10-12 07:44:40 +0000264
265 pullBuffer();
266
267 GSM::Time rcvClock = mClock.get();
268 rcvClock.decTN(receiveOffset);
269 unsigned tN = rcvClock.TN();
kurtis.heimerl9b557832011-11-26 03:18:34 +0000270 int rcvSz = rcvCursor;
dburgessb3a0ca42011-10-12 07:44:40 +0000271 int readSz = 0;
272 const int symbolsPerSlot = gSlotLen + 8;
Thomas Tsou711e6af2012-03-07 19:55:59 -0500273 int samplesPerBurst = (symbolsPerSlot + (tN % 4 == 0)) * samplesPerSymbol;
dburgessb3a0ca42011-10-12 07:44:40 +0000274
275 // while there's enough data in receive buffer, form received
276 // GSM bursts and pass up to Transceiver
277 // Using the 157-156-156-156 symbols per timeslot format.
Thomas Tsou711e6af2012-03-07 19:55:59 -0500278 while (rcvSz >= samplesPerBurst) {
dburgessb3a0ca42011-10-12 07:44:40 +0000279 if (rcvClock.FN() >= 0) {
Thomas Tsou711e6af2012-03-07 19:55:59 -0500280 loadVectors(tN, samplesPerBurst, readSz, rcvClock);
dburgessb3a0ca42011-10-12 07:44:40 +0000281 }
Thomas Tsou711e6af2012-03-07 19:55:59 -0500282
283 mClock.incTN();
dburgessb3a0ca42011-10-12 07:44:40 +0000284 rcvClock.incTN();
Thomas Tsou711e6af2012-03-07 19:55:59 -0500285
286 readSz += samplesPerBurst;
287 rcvSz -= samplesPerBurst;
dburgessb3a0ca42011-10-12 07:44:40 +0000288
289 tN = rcvClock.TN();
Thomas Tsou711e6af2012-03-07 19:55:59 -0500290 samplesPerBurst = (symbolsPerSlot + (tN % 4 == 0)) * samplesPerSymbol;
dburgessb3a0ca42011-10-12 07:44:40 +0000291 }
292
kurtis.heimerl9b557832011-11-26 03:18:34 +0000293 if (readSz > 0) {
294 rcvCursor -= readSz;
Thomas Tsou48f8fb32013-04-26 19:30:55 -0400295 shiftRxBuffers(rcvBuffer, 2 * readSz, 2 * rcvCursor, mChanM);
dburgessb3a0ca42011-10-12 07:44:40 +0000296 }
Alexander Chemeris9fb1c0b2013-09-01 03:15:32 +0400297 RTMD_CLEAR("drvRxRadio");
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000298}
299
Thomas Tsou42ade042013-07-13 18:29:08 +0200300double RadioInterface::setRxGain(double dB, int chan)
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000301{
302 if (mRadio)
Thomas Tsou42ade042013-07-13 18:29:08 +0200303 return mRadio->setRxGain(dB, chan);
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000304 else
305 return -1;
306}
307
Thomas Tsou42ade042013-07-13 18:29:08 +0200308double RadioInterface::getRxGain(int chan)
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000309{
310 if (mRadio)
Thomas Tsou42ade042013-07-13 18:29:08 +0200311 return mRadio->getRxGain(chan);
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000312 else
313 return -1;
314}
Thomas Tsou03669852013-04-08 14:41:11 -0400315
Thomas Tsou48f8fb32013-04-26 19:30:55 -0400316bool RadioInterface::init()
317{
318 for (int i = 0; i < CHAN_MAX; i++) {
319 rx_buf[i] = new short[2 * OUTCHUNK];
320 tx_buf[i] = new short[4 * 2 * INCHUNK];
321 }
322}
323
324void RadioInterface::close()
325{
326 for (int i = 0; i < CHAN_MAX; i++) {
327 delete rx_buf[i];
328 delete tx_buf[i];
329 }
330}
331
Thomas Tsou03669852013-04-08 14:41:11 -0400332/* Receive a timestamped chunk from the device */
333void RadioInterface::pullBuffer()
334{
335 bool local_underrun;
Alexander Chemeris9fb1c0b2013-09-01 03:15:32 +0400336 RTMD_SET("RI-PullBuff");
Thomas Tsou03669852013-04-08 14:41:11 -0400337
338 /* Read samples. Fail if we don't get what we want. */
Thomas Tsou48f8fb32013-04-26 19:30:55 -0400339 int num_rd = mRadio->readSamples(rx_buf, mChanM, OUTCHUNK, readTimestamp);
Thomas Tsou03669852013-04-08 14:41:11 -0400340
341 LOG(DEBUG) << "Rx read " << num_rd << " samples from device";
342 assert(num_rd == OUTCHUNK);
343
344 underrun |= local_underrun;
345 readTimestamp += (TIMESTAMP) num_rd;
346
Thomas Tsou48f8fb32013-04-26 19:30:55 -0400347 for (int i = 0; i < mChanM; i++)
348 shortToFloat(rcvBuffer[i] + 2 * rcvCursor, rx_buf[i], num_rd);
349
Thomas Tsou03669852013-04-08 14:41:11 -0400350 rcvCursor += num_rd;
Alexander Chemeris9fb1c0b2013-09-01 03:15:32 +0400351 RTMD_CLEAR("RI-PullBuff");
Thomas Tsou03669852013-04-08 14:41:11 -0400352}
353
354/* Send timestamped chunk to the device with arbitrary size */
355void RadioInterface::pushBuffer()
356{
Alexander Chemeris9fb1c0b2013-09-01 03:15:32 +0400357 RTMD_SET("RI-PushBuff");
Alexander Chemeris4c192002013-08-29 13:19:12 +0400358 if (sendCursor < INCHUNK) {
Alexander Chemeris9fb1c0b2013-09-01 03:15:32 +0400359 RTMD_VAL("RI-PushBuff", -1);
360 RTMD_CLEAR("RI-PushBuff");
Thomas Tsou03669852013-04-08 14:41:11 -0400361 return;
Alexander Chemeris4c192002013-08-29 13:19:12 +0400362 }
Thomas Tsou03669852013-04-08 14:41:11 -0400363
Thomas Tsou48f8fb32013-04-26 19:30:55 -0400364 for (int i = 0; i < mChanM; i++)
365 floatToShort(tx_buf[i], sendBuffer[i], sendCursor);
Thomas Tsou03669852013-04-08 14:41:11 -0400366
367 /* Write samples. Fail if we don't get what we want. */
Thomas Tsou48f8fb32013-04-26 19:30:55 -0400368 int num_smpls = mRadio->writeSamples(tx_buf, mChanM, sendCursor,
369 writeTimestamp, &underrun);
Thomas Tsou03669852013-04-08 14:41:11 -0400370 assert(num_smpls == sendCursor);
371
372 writeTimestamp += (TIMESTAMP) num_smpls;
373 sendCursor = 0;
Alexander Chemeris9fb1c0b2013-09-01 03:15:32 +0400374 RTMD_CLEAR("RI-PushBuff");
Thomas Tsou03669852013-04-08 14:41:11 -0400375}