blob: 6e82c8a67ae09ff976c9fa40acac67d7a20dcdea [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
dburgessb3a0ca42011-10-12 07:44:40 +000036RadioInterface::RadioInterface(RadioDevice *wRadio,
kurtis.heimerl54354042011-11-26 03:18:49 +000037 int wReceiveOffset,
Thomas Tsou204a9f12013-10-29 18:34:16 -040038 size_t sps, size_t chans,
dburgessb3a0ca42011-10-12 07:44:40 +000039 GSM::Time wStartTime)
Thomas Tsou204a9f12013-10-29 18:34:16 -040040 : mRadio(wRadio), mSPSTx(sps), mSPSRx(1), mChans(chans),
41 sendCursor(0), recvCursor(0), underrun(false), overrun(false),
42 receiveOffset(wReceiveOffset), mOn(false), powerScaling(1.0),
43 loadTest(false)
dburgessb3a0ca42011-10-12 07:44:40 +000044{
dburgessb3a0ca42011-10-12 07:44:40 +000045 mClock.set(wStartTime);
dburgessb3a0ca42011-10-12 07:44:40 +000046}
47
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040048RadioInterface::~RadioInterface(void)
49{
50 close();
51}
kurtis.heimerl54354042011-11-26 03:18:49 +000052
Thomas Tsoufe269fe2013-10-14 23:56:51 -040053bool RadioInterface::init(int type)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040054{
Thomas Tsoufe269fe2013-10-14 23:56:51 -040055 if (type != RadioDevice::NORMAL)
56 return false;
57
Thomas Tsou204a9f12013-10-29 18:34:16 -040058 if (!mChans) {
59 LOG(ALERT) << "Invalid number of channels " << mChans;
60 return false;
61 }
62
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040063 close();
64
Thomas Tsou204a9f12013-10-29 18:34:16 -040065 sendBuffer.resize(mChans);
66 recvBuffer.resize(mChans);
67 convertSendBuffer.resize(mChans);
68 convertRecvBuffer.resize(mChans);
69 mReceiveFIFO.resize(mChans);
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040070
Thomas Tsou204a9f12013-10-29 18:34:16 -040071 for (size_t i = 0; i < mChans; i++) {
72 sendBuffer[i] = new signalVector(CHUNK * mSPSTx);
73 recvBuffer[i] = new signalVector(NUMCHUNKS * CHUNK * mSPSRx);
74
75 convertSendBuffer[i] = new short[sendBuffer[i]->size() * 2];
76 convertRecvBuffer[i] = new short[recvBuffer[i]->size() * 2];
77 }
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040078
79 sendCursor = 0;
80 recvCursor = 0;
81
82 return true;
83}
84
85void RadioInterface::close()
86{
Thomas Tsou204a9f12013-10-29 18:34:16 -040087 for (size_t i = 0; i < sendBuffer.size(); i++)
88 delete sendBuffer[i];
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040089
Thomas Tsou204a9f12013-10-29 18:34:16 -040090 for (size_t i = 0; i < recvBuffer.size(); i++)
91 delete recvBuffer[i];
92
93 for (size_t i = 0; i < convertSendBuffer.size(); i++)
94 delete convertSendBuffer[i];
95
96 for (size_t i = 0; i < convertRecvBuffer.size(); i++)
97 delete convertRecvBuffer[i];
98
99 sendBuffer.resize(0);
100 recvBuffer.resize(0);
101 convertSendBuffer.resize(0);
102 convertRecvBuffer.resize(0);
dburgessb3a0ca42011-10-12 07:44:40 +0000103}
104
105double RadioInterface::fullScaleInputValue(void) {
106 return mRadio->fullScaleInputValue();
107}
108
109double RadioInterface::fullScaleOutputValue(void) {
110 return mRadio->fullScaleOutputValue();
111}
112
113
Thomas Tsou204a9f12013-10-29 18:34:16 -0400114void RadioInterface::setPowerAttenuation(double atten, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000115{
kurtis.heimerl16c65402011-11-26 03:18:11 +0000116 double rfGain, digAtten;
kurtis.heimerlee5347a2011-11-26 03:18:05 +0000117
Thomas Tsou204a9f12013-10-29 18:34:16 -0400118 if (chan >= mChans) {
119 LOG(ALERT) << "Invalid channel requested";
120 return;
121 }
122
123 rfGain = mRadio->setTxGain(mRadio->maxTxGain() - atten, chan);
kurtis.heimerl16c65402011-11-26 03:18:11 +0000124 digAtten = atten - mRadio->maxTxGain() + rfGain;
kurtis.heimerlee5347a2011-11-26 03:18:05 +0000125
126 if (digAtten < 1.0)
127 powerScaling = 1.0;
128 else
129 powerScaling = 1.0/sqrt(pow(10, (digAtten/10.0)));
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
156 for (int 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
174
175void RadioInterface::start()
176{
177 LOG(INFO) << "starting radio interface...";
Thomas Tsouf2293b82013-04-08 13:35:36 -0400178#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000179 mAlignRadioServiceLoopThread.start((void * (*)(void*))AlignRadioServiceLoopAdapter,
180 (void*)this);
Thomas Tsouf2293b82013-04-08 13:35:36 -0400181#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000182 writeTimestamp = mRadio->initialWriteTimestamp();
183 readTimestamp = mRadio->initialReadTimestamp();
184 mRadio->start();
185 LOG(DEBUG) << "Radio started";
186 mRadio->updateAlignment(writeTimestamp-10000);
187 mRadio->updateAlignment(writeTimestamp-10000);
188
dburgessb3a0ca42011-10-12 07:44:40 +0000189 mOn = true;
190
191}
192
Thomas Tsouf2293b82013-04-08 13:35:36 -0400193#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000194void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface)
195{
196 while (1) {
197 radioInterface->alignRadio();
198 pthread_testcancel();
199 }
200 return NULL;
201}
202
203void RadioInterface::alignRadio() {
204 sleep(60);
205 mRadio->updateAlignment(writeTimestamp+ (TIMESTAMP) 10000);
206}
Thomas Tsouf2293b82013-04-08 13:35:36 -0400207#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000208
Thomas Tsou204a9f12013-10-29 18:34:16 -0400209void RadioInterface::driveTransmitRadio(std::vector<signalVector *> &bursts,
210 std::vector<bool> &zeros)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400211{
212 if (!mOn)
213 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000214
Thomas Tsou204a9f12013-10-29 18:34:16 -0400215 for (size_t i = 0; i < mChans; i++) {
216 radioifyVector(*bursts[i],
217 (float *) (sendBuffer[i]->begin() + sendCursor), zeros[i]);
218 }
dburgessb3a0ca42011-10-12 07:44:40 +0000219
Thomas Tsou204a9f12013-10-29 18:34:16 -0400220 sendCursor += bursts[0]->size();
dburgessb3a0ca42011-10-12 07:44:40 +0000221
222 pushBuffer();
223}
224
Thomas Tsou204a9f12013-10-29 18:34:16 -0400225bool RadioInterface::driveReceiveRadio()
226{
227 radioVector *burst = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000228
Thomas Tsou204a9f12013-10-29 18:34:16 -0400229 if (!mOn)
230 return false;
dburgessb3a0ca42011-10-12 07:44:40 +0000231
232 pullBuffer();
233
234 GSM::Time rcvClock = mClock.get();
235 rcvClock.decTN(receiveOffset);
236 unsigned tN = rcvClock.TN();
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500237 int recvSz = recvCursor;
dburgessb3a0ca42011-10-12 07:44:40 +0000238 int readSz = 0;
239 const int symbolsPerSlot = gSlotLen + 8;
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500240 int burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx;
dburgessb3a0ca42011-10-12 07:44:40 +0000241
242 // while there's enough data in receive buffer, form received
243 // GSM bursts and pass up to Transceiver
244 // Using the 157-156-156-156 symbols per timeslot format.
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500245 while (recvSz > burstSize) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400246 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500247 burst = new radioVector(burstSize, rcvClock);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400248
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500249 unRadioifyVector((float *) (recvBuffer[i]->begin() + readSz), *burst);
250 if (mReceiveFIFO[i].size() < 32)
Thomas Tsou204a9f12013-10-29 18:34:16 -0400251 mReceiveFIFO[i].write(burst);
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500252 else
Thomas Tsou204a9f12013-10-29 18:34:16 -0400253 delete burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000254 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400255
256 mClock.incTN();
dburgessb3a0ca42011-10-12 07:44:40 +0000257 rcvClock.incTN();
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500258 readSz += burstSize;
259 recvSz -= burstSize;
dburgessb3a0ca42011-10-12 07:44:40 +0000260
261 tN = rcvClock.TN();
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500262
263 burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx;
dburgessb3a0ca42011-10-12 07:44:40 +0000264 }
265
kurtis.heimerl9b557832011-11-26 03:18:34 +0000266 if (readSz > 0) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400267 for (size_t i = 0; i < recvBuffer.size(); i++) {
268 memmove(recvBuffer[i]->begin(),
269 recvBuffer[i]->begin() + readSz,
270 (recvCursor - readSz) * 2 * sizeof(float));
271 }
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400272
273 recvCursor -= readSz;
dburgessb3a0ca42011-10-12 07:44:40 +0000274 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400275
276 return true;
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000277}
278
279bool RadioInterface::isUnderrun()
280{
281 bool retVal = underrun;
282 underrun = false;
283
284 return retVal;
285}
286
Thomas Tsou204a9f12013-10-29 18:34:16 -0400287VectorFIFO* RadioInterface::receiveFIFO(size_t chan)
288{
289 if (chan >= mReceiveFIFO.size())
290 return NULL;
291
292 return &mReceiveFIFO[chan];
293}
294
295double RadioInterface::setRxGain(double dB, size_t chan)
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000296{
297 if (mRadio)
Thomas Tsou204a9f12013-10-29 18:34:16 -0400298 return mRadio->setRxGain(dB, chan);
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000299 else
300 return -1;
301}
302
Thomas Tsou204a9f12013-10-29 18:34:16 -0400303double RadioInterface::getRxGain(size_t chan)
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000304{
305 if (mRadio)
Thomas Tsou204a9f12013-10-29 18:34:16 -0400306 return mRadio->getRxGain(chan);
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000307 else
308 return -1;
309}
Thomas Tsoucb69f082013-04-08 14:18:26 -0400310
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400311/* Receive a timestamped chunk from the device */
Thomas Tsoucb69f082013-04-08 14:18:26 -0400312void RadioInterface::pullBuffer()
313{
314 bool local_underrun;
Thomas Tsou3952d802013-10-15 15:12:24 -0400315 int num_recv;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400316 float *output;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400317
Thomas Tsou204a9f12013-10-29 18:34:16 -0400318 if (recvCursor > recvBuffer[0]->size() - CHUNK)
Thomas Tsou3952d802013-10-15 15:12:24 -0400319 return;
320
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400321 /* Outer buffer access size is fixed */
Thomas Tsou9471d762013-08-20 21:24:24 -0400322 num_recv = mRadio->readSamples(convertRecvBuffer,
Thomas Tsou3952d802013-10-15 15:12:24 -0400323 CHUNK,
Thomas Tsou9471d762013-08-20 21:24:24 -0400324 &overrun,
325 readTimestamp,
326 &local_underrun);
Thomas Tsou3952d802013-10-15 15:12:24 -0400327 if (num_recv != CHUNK) {
Thomas Tsou9471d762013-08-20 21:24:24 -0400328 LOG(ALERT) << "Receive error " << num_recv;
329 return;
330 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400331
Thomas Tsou204a9f12013-10-29 18:34:16 -0400332 for (size_t i = 0; i < mChans; i++) {
333 output = (float *) (recvBuffer[i]->begin() + recvCursor);
334 convert_short_float(output, convertRecvBuffer[i], 2 * num_recv);
335 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400336
337 underrun |= local_underrun;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400338
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400339 readTimestamp += num_recv;
Thomas Tsou9471d762013-08-20 21:24:24 -0400340 recvCursor += num_recv;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400341}
342
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400343/* Send timestamped chunk to the device with arbitrary size */
Thomas Tsoucb69f082013-04-08 14:18:26 -0400344void RadioInterface::pushBuffer()
345{
Thomas Tsou9471d762013-08-20 21:24:24 -0400346 int num_sent;
347
Thomas Tsou3952d802013-10-15 15:12:24 -0400348 if (sendCursor < CHUNK)
Thomas Tsoucb69f082013-04-08 14:18:26 -0400349 return;
350
Thomas Tsou204a9f12013-10-29 18:34:16 -0400351 if (sendCursor > sendBuffer[0]->size())
Thomas Tsou3952d802013-10-15 15:12:24 -0400352 LOG(ALERT) << "Send buffer overflow";
353
Thomas Tsou204a9f12013-10-29 18:34:16 -0400354 for (size_t i = 0; i < mChans; i++) {
355 convert_float_short(convertSendBuffer[i],
356 (float *) sendBuffer[i]->begin(),
357 powerScaling, 2 * sendCursor);
358 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400359
Thomas Tsou9471d762013-08-20 21:24:24 -0400360 /* Send the all samples in the send buffer */
361 num_sent = mRadio->writeSamples(convertSendBuffer,
362 sendCursor,
363 &underrun,
364 writeTimestamp);
365 if (num_sent != sendCursor) {
366 LOG(ALERT) << "Transmit error " << num_sent;
367 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400368
Thomas Tsou9471d762013-08-20 21:24:24 -0400369 writeTimestamp += num_sent;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400370 sendCursor = 0;
371}