blob: e9fcd49e96c96208901fcc854af729ba9e2e47d8 [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 Tsouc1f7c422013-10-11 13:49:55 -040033#define INCHUNK (625 * SAMPSPERSYM)
34#define OUTCHUNK (625 * SAMPSPERSYM)
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 Tsou312e3872013-04-08 13:45:55 -040038 int wSPS,
dburgessb3a0ca42011-10-12 07:44:40 +000039 GSM::Time wStartTime)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040040 : underrun(false), sendCursor(0), recvCursor(0), mOn(false),
kurtis.heimerl54354042011-11-26 03:18:49 +000041 mRadio(wRadio), receiveOffset(wReceiveOffset),
Thomas Tsouc1f7c422013-10-11 13:49:55 -040042 mSPSTx(wSPS), mSPSRx(1), powerScaling(1.0),
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040043 loadTest(false), sendBuffer(NULL), recvBuffer(NULL),
44 convertRecvBuffer(NULL), convertSendBuffer(NULL)
dburgessb3a0ca42011-10-12 07:44:40 +000045{
dburgessb3a0ca42011-10-12 07:44:40 +000046 mClock.set(wStartTime);
dburgessb3a0ca42011-10-12 07:44:40 +000047}
48
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040049RadioInterface::~RadioInterface(void)
50{
51 close();
52}
kurtis.heimerl54354042011-11-26 03:18:49 +000053
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040054bool RadioInterface::init()
55{
56 close();
57
58 sendBuffer = new signalVector(OUTCHUNK * 20);
59 recvBuffer = new signalVector(INCHUNK * 20);
60
61 convertSendBuffer = new short[OUTCHUNK * 2 * 20];
62 convertRecvBuffer = new short[OUTCHUNK * 2 * 2];
63
64 sendCursor = 0;
65 recvCursor = 0;
66
67 return true;
68}
69
70void RadioInterface::close()
71{
72 delete sendBuffer;
73 delete recvBuffer;
74 delete convertSendBuffer;
75 delete convertRecvBuffer;
76
77 sendBuffer = NULL;
78 recvBuffer = NULL;
79 convertRecvBuffer = NULL;
80 convertSendBuffer = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000081}
82
Thomas Tsou9471d762013-08-20 21:24:24 -040083
dburgessb3a0ca42011-10-12 07:44:40 +000084double RadioInterface::fullScaleInputValue(void) {
85 return mRadio->fullScaleInputValue();
86}
87
88double RadioInterface::fullScaleOutputValue(void) {
89 return mRadio->fullScaleOutputValue();
90}
91
92
kurtis.heimerl58d6a012011-11-26 03:17:38 +000093void RadioInterface::setPowerAttenuation(double atten)
dburgessb3a0ca42011-10-12 07:44:40 +000094{
kurtis.heimerl16c65402011-11-26 03:18:11 +000095 double rfGain, digAtten;
kurtis.heimerlee5347a2011-11-26 03:18:05 +000096
kurtis.heimerl16c65402011-11-26 03:18:11 +000097 rfGain = mRadio->setTxGain(mRadio->maxTxGain() - atten);
98 digAtten = atten - mRadio->maxTxGain() + rfGain;
kurtis.heimerlee5347a2011-11-26 03:18:05 +000099
100 if (digAtten < 1.0)
101 powerScaling = 1.0;
102 else
103 powerScaling = 1.0/sqrt(pow(10, (digAtten/10.0)));
dburgessb3a0ca42011-10-12 07:44:40 +0000104}
105
kurtis.heimerl9b557832011-11-26 03:18:34 +0000106int RadioInterface::radioifyVector(signalVector &wVector,
107 float *retVector,
kurtis.heimerl9b557832011-11-26 03:18:34 +0000108 bool zero)
dburgessb3a0ca42011-10-12 07:44:40 +0000109{
kurtis.heimerl9b557832011-11-26 03:18:34 +0000110 if (zero) {
111 memset(retVector, 0, wVector.size() * 2 * sizeof(float));
112 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000113 }
114
Thomas Tsou9471d762013-08-20 21:24:24 -0400115 memcpy(retVector, wVector.begin(), wVector.size() * 2 * sizeof(float));
kurtis.heimerl9b557832011-11-26 03:18:34 +0000116
117 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000118}
119
kurtis.heimerl9b557832011-11-26 03:18:34 +0000120int RadioInterface::unRadioifyVector(float *floatVector,
121 signalVector& newVector)
dburgessb3a0ca42011-10-12 07:44:40 +0000122{
dburgessb3a0ca42011-10-12 07:44:40 +0000123 signalVector::iterator itr = newVector.begin();
kurtis.heimerl9b557832011-11-26 03:18:34 +0000124
Thomas Tsou9471d762013-08-20 21:24:24 -0400125 if (newVector.size() > recvCursor) {
126 LOG(ALERT) << "Insufficient number of samples in receive buffer";
127 return -1;
128 }
129
130 for (int i = 0; i < newVector.size(); i++) {
kurtis.heimerl9b557832011-11-26 03:18:34 +0000131 *itr++ = Complex<float>(floatVector[2 * i + 0],
132 floatVector[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
138bool RadioInterface::tuneTx(double freq)
139{
140 return mRadio->setTxFreq(freq);
141}
142
143bool RadioInterface::tuneRx(double freq)
144{
145 return mRadio->setRxFreq(freq);
146}
147
148
149void RadioInterface::start()
150{
151 LOG(INFO) << "starting radio interface...";
Thomas Tsouf2293b82013-04-08 13:35:36 -0400152#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000153 mAlignRadioServiceLoopThread.start((void * (*)(void*))AlignRadioServiceLoopAdapter,
154 (void*)this);
Thomas Tsouf2293b82013-04-08 13:35:36 -0400155#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000156 writeTimestamp = mRadio->initialWriteTimestamp();
157 readTimestamp = mRadio->initialReadTimestamp();
158 mRadio->start();
159 LOG(DEBUG) << "Radio started";
160 mRadio->updateAlignment(writeTimestamp-10000);
161 mRadio->updateAlignment(writeTimestamp-10000);
162
dburgessb3a0ca42011-10-12 07:44:40 +0000163 mOn = true;
164
165}
166
Thomas Tsouf2293b82013-04-08 13:35:36 -0400167#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000168void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface)
169{
170 while (1) {
171 radioInterface->alignRadio();
172 pthread_testcancel();
173 }
174 return NULL;
175}
176
177void RadioInterface::alignRadio() {
178 sleep(60);
179 mRadio->updateAlignment(writeTimestamp+ (TIMESTAMP) 10000);
180}
Thomas Tsouf2293b82013-04-08 13:35:36 -0400181#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000182
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400183void RadioInterface::driveTransmitRadio(signalVector &radioBurst, bool zeroBurst)
184{
185 if (!mOn)
186 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000187
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400188 radioifyVector(radioBurst,
Thomas Tsou9471d762013-08-20 21:24:24 -0400189 (float *) (sendBuffer->begin() + sendCursor), zeroBurst);
dburgessb3a0ca42011-10-12 07:44:40 +0000190
kurtis.heimerl9b557832011-11-26 03:18:34 +0000191 sendCursor += radioBurst.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000192
193 pushBuffer();
194}
195
196void RadioInterface::driveReceiveRadio() {
197
198 if (!mOn) return;
199
200 if (mReceiveFIFO.size() > 8) return;
201
202 pullBuffer();
203
204 GSM::Time rcvClock = mClock.get();
205 rcvClock.decTN(receiveOffset);
206 unsigned tN = rcvClock.TN();
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400207 int rcvSz = recvCursor;
dburgessb3a0ca42011-10-12 07:44:40 +0000208 int readSz = 0;
209 const int symbolsPerSlot = gSlotLen + 8;
210
211 // while there's enough data in receive buffer, form received
212 // GSM bursts and pass up to Transceiver
213 // Using the 157-156-156-156 symbols per timeslot format.
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400214 while (rcvSz > (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx) {
215 signalVector rxVector((symbolsPerSlot + (tN % 4 == 0)) * mSPSRx);
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400216 unRadioifyVector((float *) (recvBuffer->begin() + readSz), rxVector);
dburgessb3a0ca42011-10-12 07:44:40 +0000217 GSM::Time tmpTime = rcvClock;
218 if (rcvClock.FN() >= 0) {
219 //LOG(DEBUG) << "FN: " << rcvClock.FN();
220 radioVector *rxBurst = NULL;
221 if (!loadTest)
222 rxBurst = new radioVector(rxVector,tmpTime);
223 else {
224 if (tN % 4 == 0)
225 rxBurst = new radioVector(*finalVec9,tmpTime);
226 else
227 rxBurst = new radioVector(*finalVec,tmpTime);
228 }
229 mReceiveFIFO.put(rxBurst);
230 }
231 mClock.incTN();
232 rcvClock.incTN();
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400233 readSz += (symbolsPerSlot+(tN % 4 == 0)) * mSPSRx;
234 rcvSz -= (symbolsPerSlot+(tN % 4 == 0)) * mSPSRx;
dburgessb3a0ca42011-10-12 07:44:40 +0000235
236 tN = rcvClock.TN();
237 }
238
kurtis.heimerl9b557832011-11-26 03:18:34 +0000239 if (readSz > 0) {
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400240 memmove(recvBuffer->begin(),
241 recvBuffer->begin() + readSz,
242 (recvCursor - readSz) * 2 * sizeof(float));
243
244 recvCursor -= readSz;
dburgessb3a0ca42011-10-12 07:44:40 +0000245 }
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000246}
247
248bool RadioInterface::isUnderrun()
249{
250 bool retVal = underrun;
251 underrun = false;
252
253 return retVal;
254}
255
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000256double RadioInterface::setRxGain(double dB)
257{
258 if (mRadio)
259 return mRadio->setRxGain(dB);
260 else
261 return -1;
262}
263
264double RadioInterface::getRxGain()
265{
266 if (mRadio)
267 return mRadio->getRxGain();
268 else
269 return -1;
270}
Thomas Tsoucb69f082013-04-08 14:18:26 -0400271
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400272/* Receive a timestamped chunk from the device */
Thomas Tsoucb69f082013-04-08 14:18:26 -0400273void RadioInterface::pullBuffer()
274{
275 bool local_underrun;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400276 int num_recv, len = OUTCHUNK / mSPSTx;
277 float *output;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400278
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400279 /* Outer buffer access size is fixed */
Thomas Tsou9471d762013-08-20 21:24:24 -0400280 num_recv = mRadio->readSamples(convertRecvBuffer,
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400281 len,
Thomas Tsou9471d762013-08-20 21:24:24 -0400282 &overrun,
283 readTimestamp,
284 &local_underrun);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400285 if (num_recv != len) {
Thomas Tsou9471d762013-08-20 21:24:24 -0400286 LOG(ALERT) << "Receive error " << num_recv;
287 return;
288 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400289
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400290 output = (float *) (recvBuffer->begin() + recvCursor);
291
292 convert_short_float(output, convertRecvBuffer, 2 * len);
Thomas Tsoucb69f082013-04-08 14:18:26 -0400293
294 underrun |= local_underrun;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400295
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400296 readTimestamp += num_recv;
Thomas Tsou9471d762013-08-20 21:24:24 -0400297 recvCursor += num_recv;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400298}
299
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400300/* Send timestamped chunk to the device with arbitrary size */
Thomas Tsoucb69f082013-04-08 14:18:26 -0400301void RadioInterface::pushBuffer()
302{
Thomas Tsou9471d762013-08-20 21:24:24 -0400303 int num_sent;
304
Thomas Tsoucb69f082013-04-08 14:18:26 -0400305 if (sendCursor < INCHUNK)
306 return;
307
Thomas Tsou9471d762013-08-20 21:24:24 -0400308 convert_float_short(convertSendBuffer,
309 (float *) sendBuffer->begin(),
310 powerScaling, 2 * sendCursor);
Thomas Tsoucb69f082013-04-08 14:18:26 -0400311
Thomas Tsou9471d762013-08-20 21:24:24 -0400312 /* Send the all samples in the send buffer */
313 num_sent = mRadio->writeSamples(convertSendBuffer,
314 sendCursor,
315 &underrun,
316 writeTimestamp);
317 if (num_sent != sendCursor) {
318 LOG(ALERT) << "Transmit error " << num_sent;
319 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400320
Thomas Tsou9471d762013-08-20 21:24:24 -0400321 writeTimestamp += num_sent;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400322 sendCursor = 0;
323}