blob: 1e25b5d48bca64216d2efceb60660102224b5c89 [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"
26#include <Logger.h>
27
kurtis.heimerl9b557832011-11-26 03:18:34 +000028bool started = false;
29
Thomas Tsoucb69f082013-04-08 14:18:26 -040030/* Device side buffers */
31static short rx_buf[OUTCHUNK * 2 * 2];
32static short tx_buf[INCHUNK * 2 * 2];
33
34/* Complex float to short conversion */
35static void floatToShort(short *out, float *in, int num)
36{
37 for (int i = 0; i < num; i++) {
38 out[2 * i + 0] = (short) in[2 * i + 0];
39 out[2 * i + 1] = (short) in[2 * i + 1];
40 }
41}
42
43/* Complex short to float conversion */
44static void shortToFloat(float *out, short *in, int num)
45{
46 for (int i = 0; i < num; i++) {
47 out[2 * i + 0] = (float) in[2 * i + 0];
48 out[2 * i + 1] = (float) in[2 * i + 1];
49 }
50}
51
dburgessb3a0ca42011-10-12 07:44:40 +000052RadioInterface::RadioInterface(RadioDevice *wRadio,
kurtis.heimerl54354042011-11-26 03:18:49 +000053 int wReceiveOffset,
Thomas Tsou312e3872013-04-08 13:45:55 -040054 int wSPS,
dburgessb3a0ca42011-10-12 07:44:40 +000055 GSM::Time wStartTime)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040056 : underrun(false), sendCursor(0), recvCursor(0), mOn(false),
kurtis.heimerl54354042011-11-26 03:18:49 +000057 mRadio(wRadio), receiveOffset(wReceiveOffset),
Thomas Tsoud24cc2c2013-08-20 15:41:45 -040058 sps(wSPS), powerScaling(1.0),
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040059 loadTest(false), sendBuffer(NULL), recvBuffer(NULL),
60 convertRecvBuffer(NULL), convertSendBuffer(NULL)
dburgessb3a0ca42011-10-12 07:44:40 +000061{
dburgessb3a0ca42011-10-12 07:44:40 +000062 mClock.set(wStartTime);
dburgessb3a0ca42011-10-12 07:44:40 +000063}
64
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040065RadioInterface::~RadioInterface(void)
66{
67 close();
68}
kurtis.heimerl54354042011-11-26 03:18:49 +000069
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040070bool RadioInterface::init()
71{
72 close();
73
74 sendBuffer = new signalVector(OUTCHUNK * 20);
75 recvBuffer = new signalVector(INCHUNK * 20);
76
77 convertSendBuffer = new short[OUTCHUNK * 2 * 20];
78 convertRecvBuffer = new short[OUTCHUNK * 2 * 2];
79
80 sendCursor = 0;
81 recvCursor = 0;
82
83 return true;
84}
85
86void RadioInterface::close()
87{
88 delete sendBuffer;
89 delete recvBuffer;
90 delete convertSendBuffer;
91 delete convertRecvBuffer;
92
93 sendBuffer = NULL;
94 recvBuffer = NULL;
95 convertRecvBuffer = NULL;
96 convertSendBuffer = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000097}
98
99double RadioInterface::fullScaleInputValue(void) {
100 return mRadio->fullScaleInputValue();
101}
102
103double RadioInterface::fullScaleOutputValue(void) {
104 return mRadio->fullScaleOutputValue();
105}
106
107
kurtis.heimerl58d6a012011-11-26 03:17:38 +0000108void RadioInterface::setPowerAttenuation(double atten)
dburgessb3a0ca42011-10-12 07:44:40 +0000109{
kurtis.heimerl16c65402011-11-26 03:18:11 +0000110 double rfGain, digAtten;
kurtis.heimerlee5347a2011-11-26 03:18:05 +0000111
kurtis.heimerl16c65402011-11-26 03:18:11 +0000112 rfGain = mRadio->setTxGain(mRadio->maxTxGain() - atten);
113 digAtten = atten - mRadio->maxTxGain() + rfGain;
kurtis.heimerlee5347a2011-11-26 03:18:05 +0000114
115 if (digAtten < 1.0)
116 powerScaling = 1.0;
117 else
118 powerScaling = 1.0/sqrt(pow(10, (digAtten/10.0)));
dburgessb3a0ca42011-10-12 07:44:40 +0000119}
120
kurtis.heimerl9b557832011-11-26 03:18:34 +0000121int RadioInterface::radioifyVector(signalVector &wVector,
122 float *retVector,
123 float scale,
124 bool zero)
dburgessb3a0ca42011-10-12 07:44:40 +0000125{
kurtis.heimerl9b557832011-11-26 03:18:34 +0000126 int i;
dburgessb3a0ca42011-10-12 07:44:40 +0000127 signalVector::iterator itr = wVector.begin();
kurtis.heimerl9b557832011-11-26 03:18:34 +0000128
129 if (zero) {
130 memset(retVector, 0, wVector.size() * 2 * sizeof(float));
131 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000132 }
133
kurtis.heimerl9b557832011-11-26 03:18:34 +0000134 for (i = 0; i < wVector.size(); i++) {
135 retVector[2 * i + 0] = itr->real() * scale;
136 retVector[2 * i + 1] = itr->imag() * scale;
137 itr++;
138 }
139
140 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000141}
142
kurtis.heimerl9b557832011-11-26 03:18:34 +0000143int RadioInterface::unRadioifyVector(float *floatVector,
144 signalVector& newVector)
dburgessb3a0ca42011-10-12 07:44:40 +0000145{
kurtis.heimerl9b557832011-11-26 03:18:34 +0000146 int i;
dburgessb3a0ca42011-10-12 07:44:40 +0000147 signalVector::iterator itr = newVector.begin();
kurtis.heimerl9b557832011-11-26 03:18:34 +0000148
149 for (i = 0; i < newVector.size(); i++) {
150 *itr++ = Complex<float>(floatVector[2 * i + 0],
151 floatVector[2 * i + 1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000152 }
153
kurtis.heimerl9b557832011-11-26 03:18:34 +0000154 return newVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000155}
156
157bool RadioInterface::tuneTx(double freq)
158{
159 return mRadio->setTxFreq(freq);
160}
161
162bool RadioInterface::tuneRx(double freq)
163{
164 return mRadio->setRxFreq(freq);
165}
166
167
168void RadioInterface::start()
169{
170 LOG(INFO) << "starting radio interface...";
Thomas Tsouf2293b82013-04-08 13:35:36 -0400171#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000172 mAlignRadioServiceLoopThread.start((void * (*)(void*))AlignRadioServiceLoopAdapter,
173 (void*)this);
Thomas Tsouf2293b82013-04-08 13:35:36 -0400174#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000175 writeTimestamp = mRadio->initialWriteTimestamp();
176 readTimestamp = mRadio->initialReadTimestamp();
177 mRadio->start();
178 LOG(DEBUG) << "Radio started";
179 mRadio->updateAlignment(writeTimestamp-10000);
180 mRadio->updateAlignment(writeTimestamp-10000);
181
dburgessb3a0ca42011-10-12 07:44:40 +0000182 mOn = true;
183
184}
185
Thomas Tsouf2293b82013-04-08 13:35:36 -0400186#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000187void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface)
188{
189 while (1) {
190 radioInterface->alignRadio();
191 pthread_testcancel();
192 }
193 return NULL;
194}
195
196void RadioInterface::alignRadio() {
197 sleep(60);
198 mRadio->updateAlignment(writeTimestamp+ (TIMESTAMP) 10000);
199}
Thomas Tsouf2293b82013-04-08 13:35:36 -0400200#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000201
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400202void RadioInterface::driveTransmitRadio(signalVector &radioBurst, bool zeroBurst)
203{
204 if (!mOn)
205 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000206
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400207 radioifyVector(radioBurst,
208 (float *) (sendBuffer->begin() + sendCursor),
209 powerScaling, zeroBurst);
dburgessb3a0ca42011-10-12 07:44:40 +0000210
kurtis.heimerl9b557832011-11-26 03:18:34 +0000211 sendCursor += radioBurst.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000212
213 pushBuffer();
214}
215
216void RadioInterface::driveReceiveRadio() {
217
218 if (!mOn) return;
219
220 if (mReceiveFIFO.size() > 8) return;
221
222 pullBuffer();
223
224 GSM::Time rcvClock = mClock.get();
225 rcvClock.decTN(receiveOffset);
226 unsigned tN = rcvClock.TN();
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400227 int rcvSz = recvCursor;
dburgessb3a0ca42011-10-12 07:44:40 +0000228 int readSz = 0;
229 const int symbolsPerSlot = gSlotLen + 8;
230
231 // while there's enough data in receive buffer, form received
232 // GSM bursts and pass up to Transceiver
233 // Using the 157-156-156-156 symbols per timeslot format.
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400234 while (rcvSz > (symbolsPerSlot + (tN % 4 == 0)) * sps) {
235 signalVector rxVector((symbolsPerSlot + (tN % 4 == 0)) * sps);
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400236 unRadioifyVector((float *) (recvBuffer->begin() + readSz), rxVector);
dburgessb3a0ca42011-10-12 07:44:40 +0000237 GSM::Time tmpTime = rcvClock;
238 if (rcvClock.FN() >= 0) {
239 //LOG(DEBUG) << "FN: " << rcvClock.FN();
240 radioVector *rxBurst = NULL;
241 if (!loadTest)
242 rxBurst = new radioVector(rxVector,tmpTime);
243 else {
244 if (tN % 4 == 0)
245 rxBurst = new radioVector(*finalVec9,tmpTime);
246 else
247 rxBurst = new radioVector(*finalVec,tmpTime);
248 }
249 mReceiveFIFO.put(rxBurst);
250 }
251 mClock.incTN();
252 rcvClock.incTN();
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400253 readSz += (symbolsPerSlot+(tN % 4 == 0)) * sps;
254 rcvSz -= (symbolsPerSlot+(tN % 4 == 0)) * sps;
dburgessb3a0ca42011-10-12 07:44:40 +0000255
256 tN = rcvClock.TN();
257 }
258
kurtis.heimerl9b557832011-11-26 03:18:34 +0000259 if (readSz > 0) {
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400260 memmove(recvBuffer->begin(),
261 recvBuffer->begin() + readSz,
262 (recvCursor - readSz) * 2 * sizeof(float));
263
264 recvCursor -= readSz;
dburgessb3a0ca42011-10-12 07:44:40 +0000265 }
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000266}
267
268bool RadioInterface::isUnderrun()
269{
270 bool retVal = underrun;
271 underrun = false;
272
273 return retVal;
274}
275
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000276double RadioInterface::setRxGain(double dB)
277{
278 if (mRadio)
279 return mRadio->setRxGain(dB);
280 else
281 return -1;
282}
283
284double RadioInterface::getRxGain()
285{
286 if (mRadio)
287 return mRadio->getRxGain();
288 else
289 return -1;
290}
Thomas Tsoucb69f082013-04-08 14:18:26 -0400291
292/* Receive a timestamped chunk from the device */
293void RadioInterface::pullBuffer()
294{
295 bool local_underrun;
296
297 /* Read samples. Fail if we don't get what we want. */
298 int num_rd = mRadio->readSamples(rx_buf, OUTCHUNK, &overrun,
299 readTimestamp, &local_underrun);
300
301 LOG(DEBUG) << "Rx read " << num_rd << " samples from device";
302 assert(num_rd == OUTCHUNK);
303
304 underrun |= local_underrun;
305 readTimestamp += (TIMESTAMP) num_rd;
306
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400307 shortToFloat((float *) recvBuffer->begin() + recvCursor, rx_buf, num_rd);
308 recvCursor += num_rd;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400309}
310
311/* Send timestamped chunk to the device with arbitrary size */
312void RadioInterface::pushBuffer()
313{
314 if (sendCursor < INCHUNK)
315 return;
316
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400317 floatToShort(tx_buf, (float *) sendBuffer->begin(), sendCursor);
Thomas Tsoucb69f082013-04-08 14:18:26 -0400318
319 /* Write samples. Fail if we don't get what we want. */
320 int num_smpls = mRadio->writeSamples(tx_buf,
321 sendCursor,
322 &underrun,
323 writeTimestamp);
324 assert(num_smpls == sendCursor);
325
326 writeTimestamp += (TIMESTAMP) num_smpls;
327 sendCursor = 0;
328}