blob: a8a54a5c7667cf643fc16f251290d5ce6cee8957 [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 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 Tsoufe269fe2013-10-14 23:56:51 -040054bool RadioInterface::init(int type)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040055{
Thomas Tsoufe269fe2013-10-14 23:56:51 -040056 if (type != RadioDevice::NORMAL)
57 return false;
58
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040059 close();
60
Thomas Tsou3952d802013-10-15 15:12:24 -040061 sendBuffer = new signalVector(CHUNK * mSPSTx);
62 recvBuffer = new signalVector(NUMCHUNKS * CHUNK * mSPSRx);
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040063
Thomas Tsou3952d802013-10-15 15:12:24 -040064 convertSendBuffer = new short[sendBuffer->size() * 2];
65 convertRecvBuffer = new short[recvBuffer->size() * 2];
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040066
67 sendCursor = 0;
68 recvCursor = 0;
69
70 return true;
71}
72
73void RadioInterface::close()
74{
75 delete sendBuffer;
76 delete recvBuffer;
77 delete convertSendBuffer;
78 delete convertRecvBuffer;
79
80 sendBuffer = NULL;
81 recvBuffer = NULL;
82 convertRecvBuffer = NULL;
83 convertSendBuffer = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000084}
85
Thomas Tsou9471d762013-08-20 21:24:24 -040086
dburgessb3a0ca42011-10-12 07:44:40 +000087double RadioInterface::fullScaleInputValue(void) {
88 return mRadio->fullScaleInputValue();
89}
90
91double RadioInterface::fullScaleOutputValue(void) {
92 return mRadio->fullScaleOutputValue();
93}
94
95
kurtis.heimerl58d6a012011-11-26 03:17:38 +000096void RadioInterface::setPowerAttenuation(double atten)
dburgessb3a0ca42011-10-12 07:44:40 +000097{
kurtis.heimerl16c65402011-11-26 03:18:11 +000098 double rfGain, digAtten;
kurtis.heimerlee5347a2011-11-26 03:18:05 +000099
kurtis.heimerl16c65402011-11-26 03:18:11 +0000100 rfGain = mRadio->setTxGain(mRadio->maxTxGain() - atten);
101 digAtten = atten - mRadio->maxTxGain() + rfGain;
kurtis.heimerlee5347a2011-11-26 03:18:05 +0000102
103 if (digAtten < 1.0)
104 powerScaling = 1.0;
105 else
106 powerScaling = 1.0/sqrt(pow(10, (digAtten/10.0)));
dburgessb3a0ca42011-10-12 07:44:40 +0000107}
108
kurtis.heimerl9b557832011-11-26 03:18:34 +0000109int RadioInterface::radioifyVector(signalVector &wVector,
110 float *retVector,
kurtis.heimerl9b557832011-11-26 03:18:34 +0000111 bool zero)
dburgessb3a0ca42011-10-12 07:44:40 +0000112{
kurtis.heimerl9b557832011-11-26 03:18:34 +0000113 if (zero) {
114 memset(retVector, 0, wVector.size() * 2 * sizeof(float));
115 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000116 }
117
Thomas Tsou9471d762013-08-20 21:24:24 -0400118 memcpy(retVector, wVector.begin(), wVector.size() * 2 * sizeof(float));
kurtis.heimerl9b557832011-11-26 03:18:34 +0000119
120 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000121}
122
kurtis.heimerl9b557832011-11-26 03:18:34 +0000123int RadioInterface::unRadioifyVector(float *floatVector,
124 signalVector& newVector)
dburgessb3a0ca42011-10-12 07:44:40 +0000125{
dburgessb3a0ca42011-10-12 07:44:40 +0000126 signalVector::iterator itr = newVector.begin();
kurtis.heimerl9b557832011-11-26 03:18:34 +0000127
Thomas Tsou9471d762013-08-20 21:24:24 -0400128 if (newVector.size() > recvCursor) {
129 LOG(ALERT) << "Insufficient number of samples in receive buffer";
130 return -1;
131 }
132
133 for (int i = 0; i < newVector.size(); i++) {
kurtis.heimerl9b557832011-11-26 03:18:34 +0000134 *itr++ = Complex<float>(floatVector[2 * i + 0],
135 floatVector[2 * i + 1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000136 }
137
kurtis.heimerl9b557832011-11-26 03:18:34 +0000138 return newVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000139}
140
141bool RadioInterface::tuneTx(double freq)
142{
143 return mRadio->setTxFreq(freq);
144}
145
146bool RadioInterface::tuneRx(double freq)
147{
148 return mRadio->setRxFreq(freq);
149}
150
151
152void RadioInterface::start()
153{
154 LOG(INFO) << "starting radio interface...";
Thomas Tsouf2293b82013-04-08 13:35:36 -0400155#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000156 mAlignRadioServiceLoopThread.start((void * (*)(void*))AlignRadioServiceLoopAdapter,
157 (void*)this);
Thomas Tsouf2293b82013-04-08 13:35:36 -0400158#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000159 writeTimestamp = mRadio->initialWriteTimestamp();
160 readTimestamp = mRadio->initialReadTimestamp();
161 mRadio->start();
162 LOG(DEBUG) << "Radio started";
163 mRadio->updateAlignment(writeTimestamp-10000);
164 mRadio->updateAlignment(writeTimestamp-10000);
165
dburgessb3a0ca42011-10-12 07:44:40 +0000166 mOn = true;
167
168}
169
Thomas Tsouf2293b82013-04-08 13:35:36 -0400170#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000171void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface)
172{
173 while (1) {
174 radioInterface->alignRadio();
175 pthread_testcancel();
176 }
177 return NULL;
178}
179
180void RadioInterface::alignRadio() {
181 sleep(60);
182 mRadio->updateAlignment(writeTimestamp+ (TIMESTAMP) 10000);
183}
Thomas Tsouf2293b82013-04-08 13:35:36 -0400184#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000185
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400186void RadioInterface::driveTransmitRadio(signalVector &radioBurst, bool zeroBurst)
187{
188 if (!mOn)
189 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000190
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400191 radioifyVector(radioBurst,
Thomas Tsou9471d762013-08-20 21:24:24 -0400192 (float *) (sendBuffer->begin() + sendCursor), zeroBurst);
dburgessb3a0ca42011-10-12 07:44:40 +0000193
kurtis.heimerl9b557832011-11-26 03:18:34 +0000194 sendCursor += radioBurst.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000195
196 pushBuffer();
197}
198
199void RadioInterface::driveReceiveRadio() {
200
201 if (!mOn) return;
202
203 if (mReceiveFIFO.size() > 8) return;
204
205 pullBuffer();
206
207 GSM::Time rcvClock = mClock.get();
208 rcvClock.decTN(receiveOffset);
209 unsigned tN = rcvClock.TN();
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400210 int rcvSz = recvCursor;
dburgessb3a0ca42011-10-12 07:44:40 +0000211 int readSz = 0;
212 const int symbolsPerSlot = gSlotLen + 8;
213
214 // while there's enough data in receive buffer, form received
215 // GSM bursts and pass up to Transceiver
216 // Using the 157-156-156-156 symbols per timeslot format.
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400217 while (rcvSz > (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx) {
218 signalVector rxVector((symbolsPerSlot + (tN % 4 == 0)) * mSPSRx);
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400219 unRadioifyVector((float *) (recvBuffer->begin() + readSz), rxVector);
dburgessb3a0ca42011-10-12 07:44:40 +0000220 GSM::Time tmpTime = rcvClock;
221 if (rcvClock.FN() >= 0) {
222 //LOG(DEBUG) << "FN: " << rcvClock.FN();
223 radioVector *rxBurst = NULL;
224 if (!loadTest)
225 rxBurst = new radioVector(rxVector,tmpTime);
226 else {
227 if (tN % 4 == 0)
228 rxBurst = new radioVector(*finalVec9,tmpTime);
229 else
230 rxBurst = new radioVector(*finalVec,tmpTime);
231 }
232 mReceiveFIFO.put(rxBurst);
233 }
234 mClock.incTN();
235 rcvClock.incTN();
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400236 readSz += (symbolsPerSlot+(tN % 4 == 0)) * mSPSRx;
237 rcvSz -= (symbolsPerSlot+(tN % 4 == 0)) * mSPSRx;
dburgessb3a0ca42011-10-12 07:44:40 +0000238
239 tN = rcvClock.TN();
240 }
241
kurtis.heimerl9b557832011-11-26 03:18:34 +0000242 if (readSz > 0) {
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400243 memmove(recvBuffer->begin(),
244 recvBuffer->begin() + readSz,
245 (recvCursor - readSz) * 2 * sizeof(float));
246
247 recvCursor -= readSz;
dburgessb3a0ca42011-10-12 07:44:40 +0000248 }
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000249}
250
251bool RadioInterface::isUnderrun()
252{
253 bool retVal = underrun;
254 underrun = false;
255
256 return retVal;
257}
258
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000259double RadioInterface::setRxGain(double dB)
260{
261 if (mRadio)
262 return mRadio->setRxGain(dB);
263 else
264 return -1;
265}
266
267double RadioInterface::getRxGain()
268{
269 if (mRadio)
270 return mRadio->getRxGain();
271 else
272 return -1;
273}
Thomas Tsoucb69f082013-04-08 14:18:26 -0400274
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400275/* Receive a timestamped chunk from the device */
Thomas Tsoucb69f082013-04-08 14:18:26 -0400276void RadioInterface::pullBuffer()
277{
278 bool local_underrun;
Thomas Tsou3952d802013-10-15 15:12:24 -0400279 int num_recv;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400280 float *output;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400281
Thomas Tsou3952d802013-10-15 15:12:24 -0400282 if (recvCursor > recvBuffer->size() - CHUNK)
283 return;
284
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400285 /* Outer buffer access size is fixed */
Thomas Tsou9471d762013-08-20 21:24:24 -0400286 num_recv = mRadio->readSamples(convertRecvBuffer,
Thomas Tsou3952d802013-10-15 15:12:24 -0400287 CHUNK,
Thomas Tsou9471d762013-08-20 21:24:24 -0400288 &overrun,
289 readTimestamp,
290 &local_underrun);
Thomas Tsou3952d802013-10-15 15:12:24 -0400291 if (num_recv != CHUNK) {
Thomas Tsou9471d762013-08-20 21:24:24 -0400292 LOG(ALERT) << "Receive error " << num_recv;
293 return;
294 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400295
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400296 output = (float *) (recvBuffer->begin() + recvCursor);
297
Thomas Tsou3952d802013-10-15 15:12:24 -0400298 convert_short_float(output, convertRecvBuffer, 2 * num_recv);
Thomas Tsoucb69f082013-04-08 14:18:26 -0400299
300 underrun |= local_underrun;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400301
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400302 readTimestamp += num_recv;
Thomas Tsou9471d762013-08-20 21:24:24 -0400303 recvCursor += num_recv;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400304}
305
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400306/* Send timestamped chunk to the device with arbitrary size */
Thomas Tsoucb69f082013-04-08 14:18:26 -0400307void RadioInterface::pushBuffer()
308{
Thomas Tsou9471d762013-08-20 21:24:24 -0400309 int num_sent;
310
Thomas Tsou3952d802013-10-15 15:12:24 -0400311 if (sendCursor < CHUNK)
Thomas Tsoucb69f082013-04-08 14:18:26 -0400312 return;
313
Thomas Tsou3952d802013-10-15 15:12:24 -0400314 if (sendCursor > sendBuffer->size())
315 LOG(ALERT) << "Send buffer overflow";
316
Thomas Tsou9471d762013-08-20 21:24:24 -0400317 convert_float_short(convertSendBuffer,
318 (float *) sendBuffer->begin(),
319 powerScaling, 2 * sendCursor);
Thomas Tsoucb69f082013-04-08 14:18:26 -0400320
Thomas Tsou9471d762013-08-20 21:24:24 -0400321 /* Send the all samples in the send buffer */
322 num_sent = mRadio->writeSamples(convertSendBuffer,
323 sendCursor,
324 &underrun,
325 writeTimestamp);
326 if (num_sent != sendCursor) {
327 LOG(ALERT) << "Transmit error " << num_sent;
328 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400329
Thomas Tsou9471d762013-08-20 21:24:24 -0400330 writeTimestamp += num_sent;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400331 sendCursor = 0;
332}