blob: ff9f4936c2fe48a0efec50d186e7b81b1a631ec0 [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,
Thomas Tsoue90a42b2013-11-13 23:38:09 -050037 size_t sps, size_t chans, size_t diversity,
38 int wReceiveOffset, GSM::Time wStartTime)
39 : mRadio(wRadio), mSPSTx(sps), mSPSRx(1), mChans(chans), mMIMO(diversity),
Thomas Tsou204a9f12013-10-29 18:34:16 -040040 sendCursor(0), recvCursor(0), underrun(false), overrun(false),
41 receiveOffset(wReceiveOffset), mOn(false), powerScaling(1.0),
42 loadTest(false)
dburgessb3a0ca42011-10-12 07:44:40 +000043{
dburgessb3a0ca42011-10-12 07:44:40 +000044 mClock.set(wStartTime);
dburgessb3a0ca42011-10-12 07:44:40 +000045}
46
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040047RadioInterface::~RadioInterface(void)
48{
49 close();
50}
kurtis.heimerl54354042011-11-26 03:18:49 +000051
Thomas Tsoufe269fe2013-10-14 23:56:51 -040052bool RadioInterface::init(int type)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040053{
Thomas Tsoue90a42b2013-11-13 23:38:09 -050054 if ((type != RadioDevice::NORMAL) || (mMIMO > 1) || !mChans) {
55 LOG(ALERT) << "Invalid configuration";
Thomas Tsou204a9f12013-10-29 18:34:16 -040056 return false;
57 }
58
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040059 close();
60
Thomas Tsou204a9f12013-10-29 18:34:16 -040061 sendBuffer.resize(mChans);
62 recvBuffer.resize(mChans);
63 convertSendBuffer.resize(mChans);
64 convertRecvBuffer.resize(mChans);
65 mReceiveFIFO.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
109
Thomas Tsou204a9f12013-10-29 18:34:16 -0400110void RadioInterface::setPowerAttenuation(double atten, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000111{
kurtis.heimerl16c65402011-11-26 03:18:11 +0000112 double rfGain, digAtten;
kurtis.heimerlee5347a2011-11-26 03:18:05 +0000113
Thomas Tsou204a9f12013-10-29 18:34:16 -0400114 if (chan >= mChans) {
115 LOG(ALERT) << "Invalid channel requested";
116 return;
117 }
118
119 rfGain = mRadio->setTxGain(mRadio->maxTxGain() - atten, chan);
kurtis.heimerl16c65402011-11-26 03:18:11 +0000120 digAtten = atten - mRadio->maxTxGain() + rfGain;
kurtis.heimerlee5347a2011-11-26 03:18:05 +0000121
122 if (digAtten < 1.0)
123 powerScaling = 1.0;
124 else
125 powerScaling = 1.0/sqrt(pow(10, (digAtten/10.0)));
dburgessb3a0ca42011-10-12 07:44:40 +0000126}
127
kurtis.heimerl9b557832011-11-26 03:18:34 +0000128int RadioInterface::radioifyVector(signalVector &wVector,
129 float *retVector,
kurtis.heimerl9b557832011-11-26 03:18:34 +0000130 bool zero)
dburgessb3a0ca42011-10-12 07:44:40 +0000131{
kurtis.heimerl9b557832011-11-26 03:18:34 +0000132 if (zero) {
133 memset(retVector, 0, wVector.size() * 2 * sizeof(float));
134 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000135 }
136
Thomas Tsou9471d762013-08-20 21:24:24 -0400137 memcpy(retVector, wVector.begin(), wVector.size() * 2 * sizeof(float));
kurtis.heimerl9b557832011-11-26 03:18:34 +0000138
139 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000140}
141
kurtis.heimerl9b557832011-11-26 03:18:34 +0000142int RadioInterface::unRadioifyVector(float *floatVector,
143 signalVector& newVector)
dburgessb3a0ca42011-10-12 07:44:40 +0000144{
dburgessb3a0ca42011-10-12 07:44:40 +0000145 signalVector::iterator itr = newVector.begin();
kurtis.heimerl9b557832011-11-26 03:18:34 +0000146
Thomas Tsou9471d762013-08-20 21:24:24 -0400147 if (newVector.size() > recvCursor) {
148 LOG(ALERT) << "Insufficient number of samples in receive buffer";
149 return -1;
150 }
151
152 for (int i = 0; i < newVector.size(); i++) {
kurtis.heimerl9b557832011-11-26 03:18:34 +0000153 *itr++ = Complex<float>(floatVector[2 * i + 0],
154 floatVector[2 * i + 1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000155 }
156
kurtis.heimerl9b557832011-11-26 03:18:34 +0000157 return newVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000158}
159
Thomas Tsou204a9f12013-10-29 18:34:16 -0400160bool RadioInterface::tuneTx(double freq, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000161{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400162 return mRadio->setTxFreq(freq, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000163}
164
Thomas Tsou204a9f12013-10-29 18:34:16 -0400165bool RadioInterface::tuneRx(double freq, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000166{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400167 return mRadio->setRxFreq(freq, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000168}
169
170
171void RadioInterface::start()
172{
173 LOG(INFO) << "starting radio interface...";
Thomas Tsouf2293b82013-04-08 13:35:36 -0400174#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000175 mAlignRadioServiceLoopThread.start((void * (*)(void*))AlignRadioServiceLoopAdapter,
176 (void*)this);
Thomas Tsouf2293b82013-04-08 13:35:36 -0400177#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000178 writeTimestamp = mRadio->initialWriteTimestamp();
179 readTimestamp = mRadio->initialReadTimestamp();
180 mRadio->start();
181 LOG(DEBUG) << "Radio started";
182 mRadio->updateAlignment(writeTimestamp-10000);
183 mRadio->updateAlignment(writeTimestamp-10000);
184
dburgessb3a0ca42011-10-12 07:44:40 +0000185 mOn = true;
186
187}
188
Thomas Tsouf2293b82013-04-08 13:35:36 -0400189#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000190void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface)
191{
192 while (1) {
193 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 Tsouf2293b82013-04-08 13:35:36 -0400203#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000204
Thomas Tsou204a9f12013-10-29 18:34:16 -0400205void RadioInterface::driveTransmitRadio(std::vector<signalVector *> &bursts,
206 std::vector<bool> &zeros)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400207{
208 if (!mOn)
209 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000210
Thomas Tsou204a9f12013-10-29 18:34:16 -0400211 for (size_t i = 0; i < mChans; i++) {
212 radioifyVector(*bursts[i],
213 (float *) (sendBuffer[i]->begin() + sendCursor), zeros[i]);
214 }
dburgessb3a0ca42011-10-12 07:44:40 +0000215
Thomas Tsou204a9f12013-10-29 18:34:16 -0400216 sendCursor += bursts[0]->size();
dburgessb3a0ca42011-10-12 07:44:40 +0000217
218 pushBuffer();
219}
220
Thomas Tsou204a9f12013-10-29 18:34:16 -0400221bool RadioInterface::driveReceiveRadio()
222{
223 radioVector *burst = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000224
Thomas Tsou204a9f12013-10-29 18:34:16 -0400225 if (!mOn)
226 return false;
dburgessb3a0ca42011-10-12 07:44:40 +0000227
228 pullBuffer();
229
230 GSM::Time rcvClock = mClock.get();
231 rcvClock.decTN(receiveOffset);
232 unsigned tN = rcvClock.TN();
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500233 int recvSz = recvCursor;
dburgessb3a0ca42011-10-12 07:44:40 +0000234 int readSz = 0;
235 const int symbolsPerSlot = gSlotLen + 8;
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500236 int burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx;
dburgessb3a0ca42011-10-12 07:44:40 +0000237
Thomas Tsoud0f3ca32013-11-09 22:05:23 -0500238 /*
239 * Pre-allocate head room for the largest correlation size
240 * so we can later avoid a re-allocation and copy
241 * */
242 size_t head = GSM::gRACHSynchSequence.size();
243
244 /*
245 * Form receive bursts and pass up to transceiver. Use repeating
246 * pattern of 157-156-156-156 symbols per timeslot
247 */
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500248 while (recvSz > burstSize) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400249 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500250 burst = new radioVector(rcvClock, burstSize, head, mMIMO);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400251
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500252 for (size_t n = 0; n < mMIMO; n++) {
253 unRadioifyVector((float *)
254 (recvBuffer[mMIMO * i + n]->begin() + readSz),
255 *burst->getVector(n));
256 }
257
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500258
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500259 if (mReceiveFIFO[i].size() < 32)
Thomas Tsou204a9f12013-10-29 18:34:16 -0400260 mReceiveFIFO[i].write(burst);
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500261 else
Thomas Tsou204a9f12013-10-29 18:34:16 -0400262 delete burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000263 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400264
265 mClock.incTN();
dburgessb3a0ca42011-10-12 07:44:40 +0000266 rcvClock.incTN();
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500267 readSz += burstSize;
268 recvSz -= burstSize;
dburgessb3a0ca42011-10-12 07:44:40 +0000269
270 tN = rcvClock.TN();
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500271
272 burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx;
dburgessb3a0ca42011-10-12 07:44:40 +0000273 }
274
kurtis.heimerl9b557832011-11-26 03:18:34 +0000275 if (readSz > 0) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400276 for (size_t i = 0; i < recvBuffer.size(); i++) {
277 memmove(recvBuffer[i]->begin(),
278 recvBuffer[i]->begin() + readSz,
279 (recvCursor - readSz) * 2 * sizeof(float));
280 }
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400281
282 recvCursor -= readSz;
dburgessb3a0ca42011-10-12 07:44:40 +0000283 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400284
285 return true;
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000286}
287
288bool RadioInterface::isUnderrun()
289{
290 bool retVal = underrun;
291 underrun = false;
292
293 return retVal;
294}
295
Thomas Tsou204a9f12013-10-29 18:34:16 -0400296VectorFIFO* RadioInterface::receiveFIFO(size_t chan)
297{
298 if (chan >= mReceiveFIFO.size())
299 return NULL;
300
301 return &mReceiveFIFO[chan];
302}
303
304double RadioInterface::setRxGain(double dB, size_t chan)
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000305{
306 if (mRadio)
Thomas Tsou204a9f12013-10-29 18:34:16 -0400307 return mRadio->setRxGain(dB, chan);
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000308 else
309 return -1;
310}
311
Thomas Tsou204a9f12013-10-29 18:34:16 -0400312double RadioInterface::getRxGain(size_t chan)
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000313{
314 if (mRadio)
Thomas Tsou204a9f12013-10-29 18:34:16 -0400315 return mRadio->getRxGain(chan);
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000316 else
317 return -1;
318}
Thomas Tsoucb69f082013-04-08 14:18:26 -0400319
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400320/* Receive a timestamped chunk from the device */
Thomas Tsoucb69f082013-04-08 14:18:26 -0400321void RadioInterface::pullBuffer()
322{
323 bool local_underrun;
Thomas Tsou3952d802013-10-15 15:12:24 -0400324 int num_recv;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400325 float *output;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400326
Thomas Tsou204a9f12013-10-29 18:34:16 -0400327 if (recvCursor > recvBuffer[0]->size() - CHUNK)
Thomas Tsou3952d802013-10-15 15:12:24 -0400328 return;
329
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400330 /* Outer buffer access size is fixed */
Thomas Tsou9471d762013-08-20 21:24:24 -0400331 num_recv = mRadio->readSamples(convertRecvBuffer,
Thomas Tsou3952d802013-10-15 15:12:24 -0400332 CHUNK,
Thomas Tsou9471d762013-08-20 21:24:24 -0400333 &overrun,
334 readTimestamp,
335 &local_underrun);
Thomas Tsou3952d802013-10-15 15:12:24 -0400336 if (num_recv != CHUNK) {
Thomas Tsou9471d762013-08-20 21:24:24 -0400337 LOG(ALERT) << "Receive error " << num_recv;
338 return;
339 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400340
Thomas Tsou204a9f12013-10-29 18:34:16 -0400341 for (size_t i = 0; i < mChans; i++) {
342 output = (float *) (recvBuffer[i]->begin() + recvCursor);
343 convert_short_float(output, convertRecvBuffer[i], 2 * num_recv);
344 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400345
346 underrun |= local_underrun;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400347
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400348 readTimestamp += num_recv;
Thomas Tsou9471d762013-08-20 21:24:24 -0400349 recvCursor += num_recv;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400350}
351
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400352/* Send timestamped chunk to the device with arbitrary size */
Thomas Tsoucb69f082013-04-08 14:18:26 -0400353void RadioInterface::pushBuffer()
354{
Thomas Tsou9471d762013-08-20 21:24:24 -0400355 int num_sent;
356
Thomas Tsou3952d802013-10-15 15:12:24 -0400357 if (sendCursor < CHUNK)
Thomas Tsoucb69f082013-04-08 14:18:26 -0400358 return;
359
Thomas Tsou204a9f12013-10-29 18:34:16 -0400360 if (sendCursor > sendBuffer[0]->size())
Thomas Tsou3952d802013-10-15 15:12:24 -0400361 LOG(ALERT) << "Send buffer overflow";
362
Thomas Tsou204a9f12013-10-29 18:34:16 -0400363 for (size_t i = 0; i < mChans; i++) {
364 convert_float_short(convertSendBuffer[i],
365 (float *) sendBuffer[i]->begin(),
366 powerScaling, 2 * sendCursor);
367 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400368
Thomas Tsou9471d762013-08-20 21:24:24 -0400369 /* Send the all samples in the send buffer */
370 num_sent = mRadio->writeSamples(convertSendBuffer,
371 sendCursor,
372 &underrun,
373 writeTimestamp);
Thomas Tsou9471d762013-08-20 21:24:24 -0400374 writeTimestamp += num_sent;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400375 sendCursor = 0;
376}