blob: 7256b9b2c009ffe65f3ac28fbd879d4c81ca25e6 [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
2* Copyright 2008, 2009 Free Software Foundation, Inc.
3*
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"
Thomas Tsouc1f7c422013-10-11 13:49:55 -040026#include "Resampler.h"
dburgessb3a0ca42011-10-12 07:44:40 +000027#include <Logger.h>
28
Thomas Tsou9471d762013-08-20 21:24:24 -040029extern "C" {
30#include "convert.h"
31}
32
Thomas Tsou3952d802013-10-15 15:12:24 -040033#define CHUNK 625
34#define NUMCHUNKS 4
kurtis.heimerl9b557832011-11-26 03:18:34 +000035
Tom Tsou5cd70dc2016-03-06 01:28:40 -080036RadioInterface::RadioInterface(RadioDevice *wRadio, size_t tx_sps,
37 size_t rx_sps, size_t chans, size_t diversity,
Thomas Tsoue90a42b2013-11-13 23:38:09 -050038 int wReceiveOffset, GSM::Time wStartTime)
Tom Tsou5cd70dc2016-03-06 01:28:40 -080039 : mRadio(wRadio), mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans),
40 mMIMO(diversity), sendCursor(0), recvCursor(0), underrun(false),
41 overrun(false), receiveOffset(wReceiveOffset), mOn(false)
dburgessb3a0ca42011-10-12 07:44:40 +000042{
dburgessb3a0ca42011-10-12 07:44:40 +000043 mClock.set(wStartTime);
dburgessb3a0ca42011-10-12 07:44:40 +000044}
45
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040046RadioInterface::~RadioInterface(void)
47{
48 close();
49}
kurtis.heimerl54354042011-11-26 03:18:49 +000050
Thomas Tsoufe269fe2013-10-14 23:56:51 -040051bool RadioInterface::init(int type)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040052{
Thomas Tsoue90a42b2013-11-13 23:38:09 -050053 if ((type != RadioDevice::NORMAL) || (mMIMO > 1) || !mChans) {
54 LOG(ALERT) << "Invalid configuration";
Thomas Tsou204a9f12013-10-29 18:34:16 -040055 return false;
56 }
57
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040058 close();
59
Thomas Tsou204a9f12013-10-29 18:34:16 -040060 sendBuffer.resize(mChans);
61 recvBuffer.resize(mChans);
62 convertSendBuffer.resize(mChans);
63 convertRecvBuffer.resize(mChans);
64 mReceiveFIFO.resize(mChans);
Thomas Tsoucb269a32013-11-15 14:15:47 -050065 powerScaling.resize(mChans);
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040066
Thomas Tsou204a9f12013-10-29 18:34:16 -040067 for (size_t i = 0; i < mChans; i++) {
68 sendBuffer[i] = new signalVector(CHUNK * mSPSTx);
69 recvBuffer[i] = new signalVector(NUMCHUNKS * CHUNK * mSPSRx);
70
71 convertSendBuffer[i] = new short[sendBuffer[i]->size() * 2];
72 convertRecvBuffer[i] = new short[recvBuffer[i]->size() * 2];
73 }
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040074
75 sendCursor = 0;
76 recvCursor = 0;
77
78 return true;
79}
80
81void RadioInterface::close()
82{
Thomas Tsou204a9f12013-10-29 18:34:16 -040083 for (size_t i = 0; i < sendBuffer.size(); i++)
84 delete sendBuffer[i];
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040085
Thomas Tsou204a9f12013-10-29 18:34:16 -040086 for (size_t i = 0; i < recvBuffer.size(); i++)
87 delete recvBuffer[i];
88
89 for (size_t i = 0; i < convertSendBuffer.size(); i++)
90 delete convertSendBuffer[i];
91
92 for (size_t i = 0; i < convertRecvBuffer.size(); i++)
93 delete convertRecvBuffer[i];
94
95 sendBuffer.resize(0);
96 recvBuffer.resize(0);
97 convertSendBuffer.resize(0);
98 convertRecvBuffer.resize(0);
dburgessb3a0ca42011-10-12 07:44:40 +000099}
100
101double RadioInterface::fullScaleInputValue(void) {
102 return mRadio->fullScaleInputValue();
103}
104
105double RadioInterface::fullScaleOutputValue(void) {
106 return mRadio->fullScaleOutputValue();
107}
108
Tom Tsoua4d1a412014-11-25 15:46:56 -0800109int RadioInterface::setPowerAttenuation(int atten, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000110{
kurtis.heimerl16c65402011-11-26 03:18:11 +0000111 double rfGain, digAtten;
kurtis.heimerlee5347a2011-11-26 03:18:05 +0000112
Thomas Tsou204a9f12013-10-29 18:34:16 -0400113 if (chan >= mChans) {
114 LOG(ALERT) << "Invalid channel requested";
Tom Tsoua4d1a412014-11-25 15:46:56 -0800115 return -1;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400116 }
117
Tom Tsoua4d1a412014-11-25 15:46:56 -0800118 if (atten < 0.0)
119 atten = 0.0;
120
121 rfGain = mRadio->setTxGain(mRadio->maxTxGain() - (double) atten, chan);
122 digAtten = (double) atten - mRadio->maxTxGain() + rfGain;
kurtis.heimerlee5347a2011-11-26 03:18:05 +0000123
124 if (digAtten < 1.0)
Thomas Tsoucb269a32013-11-15 14:15:47 -0500125 powerScaling[chan] = 1.0;
kurtis.heimerlee5347a2011-11-26 03:18:05 +0000126 else
Thomas Tsoucb269a32013-11-15 14:15:47 -0500127 powerScaling[chan] = 1.0 / sqrt(pow(10, digAtten / 10.0));
Tom Tsoua4d1a412014-11-25 15:46:56 -0800128
129 return atten;
dburgessb3a0ca42011-10-12 07:44:40 +0000130}
131
kurtis.heimerl9b557832011-11-26 03:18:34 +0000132int RadioInterface::radioifyVector(signalVector &wVector,
133 float *retVector,
kurtis.heimerl9b557832011-11-26 03:18:34 +0000134 bool zero)
dburgessb3a0ca42011-10-12 07:44:40 +0000135{
kurtis.heimerl9b557832011-11-26 03:18:34 +0000136 if (zero) {
137 memset(retVector, 0, wVector.size() * 2 * sizeof(float));
138 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000139 }
140
Thomas Tsou9471d762013-08-20 21:24:24 -0400141 memcpy(retVector, wVector.begin(), wVector.size() * 2 * sizeof(float));
kurtis.heimerl9b557832011-11-26 03:18:34 +0000142
143 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000144}
145
kurtis.heimerl9b557832011-11-26 03:18:34 +0000146int RadioInterface::unRadioifyVector(float *floatVector,
147 signalVector& newVector)
dburgessb3a0ca42011-10-12 07:44:40 +0000148{
dburgessb3a0ca42011-10-12 07:44:40 +0000149 signalVector::iterator itr = newVector.begin();
kurtis.heimerl9b557832011-11-26 03:18:34 +0000150
Thomas Tsou9471d762013-08-20 21:24:24 -0400151 if (newVector.size() > recvCursor) {
152 LOG(ALERT) << "Insufficient number of samples in receive buffer";
153 return -1;
154 }
155
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500156 for (size_t i = 0; i < newVector.size(); i++) {
kurtis.heimerl9b557832011-11-26 03:18:34 +0000157 *itr++ = Complex<float>(floatVector[2 * i + 0],
158 floatVector[2 * i + 1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000159 }
160
kurtis.heimerl9b557832011-11-26 03:18:34 +0000161 return newVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000162}
163
Thomas Tsou204a9f12013-10-29 18:34:16 -0400164bool RadioInterface::tuneTx(double freq, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000165{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400166 return mRadio->setTxFreq(freq, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000167}
168
Thomas Tsou204a9f12013-10-29 18:34:16 -0400169bool RadioInterface::tuneRx(double freq, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000170{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400171 return mRadio->setRxFreq(freq, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000172}
173
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800174bool RadioInterface::start()
dburgessb3a0ca42011-10-12 07:44:40 +0000175{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800176 if (mOn)
177 return true;
178
179 LOG(INFO) << "Starting radio device";
Thomas Tsouf2293b82013-04-08 13:35:36 -0400180#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000181 mAlignRadioServiceLoopThread.start((void * (*)(void*))AlignRadioServiceLoopAdapter,
182 (void*)this);
Thomas Tsouf2293b82013-04-08 13:35:36 -0400183#endif
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800184
185 if (!mRadio->start())
186 return false;
187
Tom Tsoud7610cf2015-05-07 17:39:49 -0700188 recvCursor = 0;
189 sendCursor = 0;
190
dburgessb3a0ca42011-10-12 07:44:40 +0000191 writeTimestamp = mRadio->initialWriteTimestamp();
192 readTimestamp = mRadio->initialReadTimestamp();
Thomas Tsou18d3b832014-02-13 14:55:23 -0500193
194 mRadio->updateAlignment(writeTimestamp-10000);
dburgessb3a0ca42011-10-12 07:44:40 +0000195 mRadio->updateAlignment(writeTimestamp-10000);
196
dburgessb3a0ca42011-10-12 07:44:40 +0000197 mOn = true;
Thomas Tsou18d3b832014-02-13 14:55:23 -0500198 LOG(INFO) << "Radio started";
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800199 return true;
200}
201
202/*
203 * Stop the radio device
204 *
205 * This is a pass-through call to the device interface. Because the underlying
206 * stop command issuance generally doesn't return confirmation on device status,
207 * this call will only return false if the device is already stopped.
208 */
209bool RadioInterface::stop()
210{
211 if (!mOn || !mRadio->stop())
212 return false;
213
214 mOn = false;
215 return true;
dburgessb3a0ca42011-10-12 07:44:40 +0000216}
217
Thomas Tsouf2293b82013-04-08 13:35:36 -0400218#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000219void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface)
220{
221 while (1) {
222 radioInterface->alignRadio();
223 pthread_testcancel();
224 }
225 return NULL;
226}
227
228void RadioInterface::alignRadio() {
229 sleep(60);
230 mRadio->updateAlignment(writeTimestamp+ (TIMESTAMP) 10000);
231}
Thomas Tsouf2293b82013-04-08 13:35:36 -0400232#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000233
Thomas Tsou204a9f12013-10-29 18:34:16 -0400234void RadioInterface::driveTransmitRadio(std::vector<signalVector *> &bursts,
235 std::vector<bool> &zeros)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400236{
237 if (!mOn)
238 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000239
Thomas Tsou204a9f12013-10-29 18:34:16 -0400240 for (size_t i = 0; i < mChans; i++) {
241 radioifyVector(*bursts[i],
242 (float *) (sendBuffer[i]->begin() + sendCursor), zeros[i]);
243 }
dburgessb3a0ca42011-10-12 07:44:40 +0000244
Thomas Tsou204a9f12013-10-29 18:34:16 -0400245 sendCursor += bursts[0]->size();
dburgessb3a0ca42011-10-12 07:44:40 +0000246
247 pushBuffer();
248}
249
Thomas Tsou204a9f12013-10-29 18:34:16 -0400250bool RadioInterface::driveReceiveRadio()
251{
252 radioVector *burst = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000253
Thomas Tsou204a9f12013-10-29 18:34:16 -0400254 if (!mOn)
255 return false;
dburgessb3a0ca42011-10-12 07:44:40 +0000256
257 pullBuffer();
258
259 GSM::Time rcvClock = mClock.get();
260 rcvClock.decTN(receiveOffset);
261 unsigned tN = rcvClock.TN();
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500262 int recvSz = recvCursor;
dburgessb3a0ca42011-10-12 07:44:40 +0000263 int readSz = 0;
264 const int symbolsPerSlot = gSlotLen + 8;
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800265 int burstSize;
266
267 if (mSPSRx == 4)
268 burstSize = 625;
269 else
270 burstSize = symbolsPerSlot + (tN % 4 == 0);
dburgessb3a0ca42011-10-12 07:44:40 +0000271
Thomas Tsoud0f3ca32013-11-09 22:05:23 -0500272 /*
273 * Pre-allocate head room for the largest correlation size
274 * so we can later avoid a re-allocation and copy
275 * */
276 size_t head = GSM::gRACHSynchSequence.size();
277
278 /*
279 * Form receive bursts and pass up to transceiver. Use repeating
280 * pattern of 157-156-156-156 symbols per timeslot
281 */
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500282 while (recvSz > burstSize) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400283 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500284 burst = new radioVector(rcvClock, burstSize, head, mMIMO);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400285
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500286 for (size_t n = 0; n < mMIMO; n++) {
287 unRadioifyVector((float *)
288 (recvBuffer[mMIMO * i + n]->begin() + readSz),
289 *burst->getVector(n));
290 }
291
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500292 if (mReceiveFIFO[i].size() < 32)
Thomas Tsou204a9f12013-10-29 18:34:16 -0400293 mReceiveFIFO[i].write(burst);
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500294 else
Thomas Tsou204a9f12013-10-29 18:34:16 -0400295 delete burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000296 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400297
298 mClock.incTN();
dburgessb3a0ca42011-10-12 07:44:40 +0000299 rcvClock.incTN();
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500300 readSz += burstSize;
301 recvSz -= burstSize;
dburgessb3a0ca42011-10-12 07:44:40 +0000302
303 tN = rcvClock.TN();
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500304
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800305 if (mSPSRx != 4)
306 burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx;
dburgessb3a0ca42011-10-12 07:44:40 +0000307 }
308
kurtis.heimerl9b557832011-11-26 03:18:34 +0000309 if (readSz > 0) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400310 for (size_t i = 0; i < recvBuffer.size(); i++) {
311 memmove(recvBuffer[i]->begin(),
312 recvBuffer[i]->begin() + readSz,
313 (recvCursor - readSz) * 2 * sizeof(float));
314 }
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400315
316 recvCursor -= readSz;
dburgessb3a0ca42011-10-12 07:44:40 +0000317 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400318
319 return true;
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000320}
321
322bool RadioInterface::isUnderrun()
323{
324 bool retVal = underrun;
325 underrun = false;
326
327 return retVal;
328}
329
Thomas Tsou204a9f12013-10-29 18:34:16 -0400330VectorFIFO* RadioInterface::receiveFIFO(size_t chan)
331{
332 if (chan >= mReceiveFIFO.size())
333 return NULL;
334
335 return &mReceiveFIFO[chan];
336}
337
338double RadioInterface::setRxGain(double dB, size_t chan)
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000339{
340 if (mRadio)
Thomas Tsou204a9f12013-10-29 18:34:16 -0400341 return mRadio->setRxGain(dB, chan);
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000342 else
343 return -1;
344}
345
Thomas Tsou204a9f12013-10-29 18:34:16 -0400346double RadioInterface::getRxGain(size_t chan)
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000347{
348 if (mRadio)
Thomas Tsou204a9f12013-10-29 18:34:16 -0400349 return mRadio->getRxGain(chan);
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000350 else
351 return -1;
352}
Thomas Tsoucb69f082013-04-08 14:18:26 -0400353
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400354/* Receive a timestamped chunk from the device */
Thomas Tsoucb69f082013-04-08 14:18:26 -0400355void RadioInterface::pullBuffer()
356{
357 bool local_underrun;
Thomas Tsou3952d802013-10-15 15:12:24 -0400358 int num_recv;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400359 float *output;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400360
Thomas Tsou204a9f12013-10-29 18:34:16 -0400361 if (recvCursor > recvBuffer[0]->size() - CHUNK)
Thomas Tsou3952d802013-10-15 15:12:24 -0400362 return;
363
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400364 /* Outer buffer access size is fixed */
Thomas Tsou9471d762013-08-20 21:24:24 -0400365 num_recv = mRadio->readSamples(convertRecvBuffer,
Thomas Tsou3952d802013-10-15 15:12:24 -0400366 CHUNK,
Thomas Tsou9471d762013-08-20 21:24:24 -0400367 &overrun,
368 readTimestamp,
369 &local_underrun);
Thomas Tsou3952d802013-10-15 15:12:24 -0400370 if (num_recv != CHUNK) {
Thomas Tsou9471d762013-08-20 21:24:24 -0400371 LOG(ALERT) << "Receive error " << num_recv;
372 return;
373 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400374
Thomas Tsou204a9f12013-10-29 18:34:16 -0400375 for (size_t i = 0; i < mChans; i++) {
376 output = (float *) (recvBuffer[i]->begin() + recvCursor);
377 convert_short_float(output, convertRecvBuffer[i], 2 * num_recv);
378 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400379
380 underrun |= local_underrun;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400381
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400382 readTimestamp += num_recv;
Thomas Tsou9471d762013-08-20 21:24:24 -0400383 recvCursor += num_recv;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400384}
385
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400386/* Send timestamped chunk to the device with arbitrary size */
Thomas Tsoucb69f082013-04-08 14:18:26 -0400387void RadioInterface::pushBuffer()
388{
Thomas Tsou9471d762013-08-20 21:24:24 -0400389 int num_sent;
390
Thomas Tsou3952d802013-10-15 15:12:24 -0400391 if (sendCursor < CHUNK)
Thomas Tsoucb69f082013-04-08 14:18:26 -0400392 return;
393
Thomas Tsou204a9f12013-10-29 18:34:16 -0400394 if (sendCursor > sendBuffer[0]->size())
Thomas Tsou3952d802013-10-15 15:12:24 -0400395 LOG(ALERT) << "Send buffer overflow";
396
Thomas Tsou204a9f12013-10-29 18:34:16 -0400397 for (size_t i = 0; i < mChans; i++) {
398 convert_float_short(convertSendBuffer[i],
399 (float *) sendBuffer[i]->begin(),
Thomas Tsoucb269a32013-11-15 14:15:47 -0500400 powerScaling[i], 2 * sendCursor);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400401 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400402
Thomas Tsou9471d762013-08-20 21:24:24 -0400403 /* Send the all samples in the send buffer */
404 num_sent = mRadio->writeSamples(convertSendBuffer,
405 sendCursor,
406 &underrun,
407 writeTimestamp);
Thomas Tsou9471d762013-08-20 21:24:24 -0400408 writeTimestamp += num_sent;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400409 sendCursor = 0;
410}