blob: e3fa2a4ad02feff3ea325c83b1af260276964f16 [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)
kurtis.heimerl54354042011-11-26 03:18:49 +000056 : underrun(false), sendCursor(0), rcvCursor(0), mOn(false),
57 mRadio(wRadio), receiveOffset(wReceiveOffset),
Thomas Tsoud24cc2c2013-08-20 15:41:45 -040058 sps(wSPS), powerScaling(1.0),
kurtis.heimerl54354042011-11-26 03:18:49 +000059 loadTest(false)
dburgessb3a0ca42011-10-12 07:44:40 +000060{
dburgessb3a0ca42011-10-12 07:44:40 +000061 mClock.set(wStartTime);
dburgessb3a0ca42011-10-12 07:44:40 +000062}
63
kurtis.heimerl54354042011-11-26 03:18:49 +000064
dburgessb3a0ca42011-10-12 07:44:40 +000065RadioInterface::~RadioInterface(void) {
66 if (rcvBuffer!=NULL) delete rcvBuffer;
67 //mReceiveFIFO.clear();
68}
69
70double RadioInterface::fullScaleInputValue(void) {
71 return mRadio->fullScaleInputValue();
72}
73
74double RadioInterface::fullScaleOutputValue(void) {
75 return mRadio->fullScaleOutputValue();
76}
77
78
kurtis.heimerl58d6a012011-11-26 03:17:38 +000079void RadioInterface::setPowerAttenuation(double atten)
dburgessb3a0ca42011-10-12 07:44:40 +000080{
kurtis.heimerl16c65402011-11-26 03:18:11 +000081 double rfGain, digAtten;
kurtis.heimerlee5347a2011-11-26 03:18:05 +000082
kurtis.heimerl16c65402011-11-26 03:18:11 +000083 rfGain = mRadio->setTxGain(mRadio->maxTxGain() - atten);
84 digAtten = atten - mRadio->maxTxGain() + rfGain;
kurtis.heimerlee5347a2011-11-26 03:18:05 +000085
86 if (digAtten < 1.0)
87 powerScaling = 1.0;
88 else
89 powerScaling = 1.0/sqrt(pow(10, (digAtten/10.0)));
dburgessb3a0ca42011-10-12 07:44:40 +000090}
91
kurtis.heimerl9b557832011-11-26 03:18:34 +000092int RadioInterface::radioifyVector(signalVector &wVector,
93 float *retVector,
94 float scale,
95 bool zero)
dburgessb3a0ca42011-10-12 07:44:40 +000096{
kurtis.heimerl9b557832011-11-26 03:18:34 +000097 int i;
dburgessb3a0ca42011-10-12 07:44:40 +000098 signalVector::iterator itr = wVector.begin();
kurtis.heimerl9b557832011-11-26 03:18:34 +000099
100 if (zero) {
101 memset(retVector, 0, wVector.size() * 2 * sizeof(float));
102 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000103 }
104
kurtis.heimerl9b557832011-11-26 03:18:34 +0000105 for (i = 0; i < wVector.size(); i++) {
106 retVector[2 * i + 0] = itr->real() * scale;
107 retVector[2 * i + 1] = itr->imag() * scale;
108 itr++;
109 }
110
111 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000112}
113
kurtis.heimerl9b557832011-11-26 03:18:34 +0000114int RadioInterface::unRadioifyVector(float *floatVector,
115 signalVector& newVector)
dburgessb3a0ca42011-10-12 07:44:40 +0000116{
kurtis.heimerl9b557832011-11-26 03:18:34 +0000117 int i;
dburgessb3a0ca42011-10-12 07:44:40 +0000118 signalVector::iterator itr = newVector.begin();
kurtis.heimerl9b557832011-11-26 03:18:34 +0000119
120 for (i = 0; i < newVector.size(); i++) {
121 *itr++ = Complex<float>(floatVector[2 * i + 0],
122 floatVector[2 * i + 1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000123 }
124
kurtis.heimerl9b557832011-11-26 03:18:34 +0000125 return newVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000126}
127
128bool RadioInterface::tuneTx(double freq)
129{
130 return mRadio->setTxFreq(freq);
131}
132
133bool RadioInterface::tuneRx(double freq)
134{
135 return mRadio->setRxFreq(freq);
136}
137
138
139void RadioInterface::start()
140{
141 LOG(INFO) << "starting radio interface...";
Thomas Tsouf2293b82013-04-08 13:35:36 -0400142#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000143 mAlignRadioServiceLoopThread.start((void * (*)(void*))AlignRadioServiceLoopAdapter,
144 (void*)this);
Thomas Tsouf2293b82013-04-08 13:35:36 -0400145#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000146 writeTimestamp = mRadio->initialWriteTimestamp();
147 readTimestamp = mRadio->initialReadTimestamp();
148 mRadio->start();
149 LOG(DEBUG) << "Radio started";
150 mRadio->updateAlignment(writeTimestamp-10000);
151 mRadio->updateAlignment(writeTimestamp-10000);
152
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400153 sendBuffer = new float[2*2*INCHUNK*sps];
154 rcvBuffer = new float[2*2*OUTCHUNK*sps];
dburgessb3a0ca42011-10-12 07:44:40 +0000155
156 mOn = true;
157
158}
159
Thomas Tsouf2293b82013-04-08 13:35:36 -0400160#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000161void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface)
162{
163 while (1) {
164 radioInterface->alignRadio();
165 pthread_testcancel();
166 }
167 return NULL;
168}
169
170void RadioInterface::alignRadio() {
171 sleep(60);
172 mRadio->updateAlignment(writeTimestamp+ (TIMESTAMP) 10000);
173}
Thomas Tsouf2293b82013-04-08 13:35:36 -0400174#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000175
176void RadioInterface::driveTransmitRadio(signalVector &radioBurst, bool zeroBurst) {
177
178 if (!mOn) return;
179
kurtis.heimerl9b557832011-11-26 03:18:34 +0000180 radioifyVector(radioBurst, sendBuffer + 2 * sendCursor, powerScaling, zeroBurst);
dburgessb3a0ca42011-10-12 07:44:40 +0000181
kurtis.heimerl9b557832011-11-26 03:18:34 +0000182 sendCursor += radioBurst.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000183
184 pushBuffer();
185}
186
187void RadioInterface::driveReceiveRadio() {
188
189 if (!mOn) return;
190
191 if (mReceiveFIFO.size() > 8) return;
192
193 pullBuffer();
194
195 GSM::Time rcvClock = mClock.get();
196 rcvClock.decTN(receiveOffset);
197 unsigned tN = rcvClock.TN();
kurtis.heimerl9b557832011-11-26 03:18:34 +0000198 int rcvSz = rcvCursor;
dburgessb3a0ca42011-10-12 07:44:40 +0000199 int readSz = 0;
200 const int symbolsPerSlot = gSlotLen + 8;
201
202 // while there's enough data in receive buffer, form received
203 // GSM bursts and pass up to Transceiver
204 // Using the 157-156-156-156 symbols per timeslot format.
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400205 while (rcvSz > (symbolsPerSlot + (tN % 4 == 0)) * sps) {
206 signalVector rxVector((symbolsPerSlot + (tN % 4 == 0)) * sps);
dburgessb3a0ca42011-10-12 07:44:40 +0000207 unRadioifyVector(rcvBuffer+readSz*2,rxVector);
208 GSM::Time tmpTime = rcvClock;
209 if (rcvClock.FN() >= 0) {
210 //LOG(DEBUG) << "FN: " << rcvClock.FN();
211 radioVector *rxBurst = NULL;
212 if (!loadTest)
213 rxBurst = new radioVector(rxVector,tmpTime);
214 else {
215 if (tN % 4 == 0)
216 rxBurst = new radioVector(*finalVec9,tmpTime);
217 else
218 rxBurst = new radioVector(*finalVec,tmpTime);
219 }
220 mReceiveFIFO.put(rxBurst);
221 }
222 mClock.incTN();
223 rcvClock.incTN();
224 //if (mReceiveFIFO.size() >= 16) mReceiveFIFO.wait(8);
225 //LOG(DEBUG) << "receiveFIFO: wrote radio vector at time: " << mClock.get() << ", new size: " << mReceiveFIFO.size() ;
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400226 readSz += (symbolsPerSlot+(tN % 4 == 0)) * sps;
227 rcvSz -= (symbolsPerSlot+(tN % 4 == 0)) * sps;
dburgessb3a0ca42011-10-12 07:44:40 +0000228
229 tN = rcvClock.TN();
230 }
231
kurtis.heimerl9b557832011-11-26 03:18:34 +0000232 if (readSz > 0) {
233 rcvCursor -= readSz;
234 memmove(rcvBuffer,rcvBuffer+2*readSz,sizeof(float) * 2 * rcvCursor);
dburgessb3a0ca42011-10-12 07:44:40 +0000235 }
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000236}
237
238bool RadioInterface::isUnderrun()
239{
240 bool retVal = underrun;
241 underrun = false;
242
243 return retVal;
244}
245
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000246double RadioInterface::setRxGain(double dB)
247{
248 if (mRadio)
249 return mRadio->setRxGain(dB);
250 else
251 return -1;
252}
253
254double RadioInterface::getRxGain()
255{
256 if (mRadio)
257 return mRadio->getRxGain();
258 else
259 return -1;
260}
Thomas Tsoucb69f082013-04-08 14:18:26 -0400261
262/* Receive a timestamped chunk from the device */
263void RadioInterface::pullBuffer()
264{
265 bool local_underrun;
266
267 /* Read samples. Fail if we don't get what we want. */
268 int num_rd = mRadio->readSamples(rx_buf, OUTCHUNK, &overrun,
269 readTimestamp, &local_underrun);
270
271 LOG(DEBUG) << "Rx read " << num_rd << " samples from device";
272 assert(num_rd == OUTCHUNK);
273
274 underrun |= local_underrun;
275 readTimestamp += (TIMESTAMP) num_rd;
276
277 shortToFloat(rcvBuffer + 2 * rcvCursor, rx_buf, num_rd);
278 rcvCursor += num_rd;
279}
280
281/* Send timestamped chunk to the device with arbitrary size */
282void RadioInterface::pushBuffer()
283{
284 if (sendCursor < INCHUNK)
285 return;
286
287 floatToShort(tx_buf, sendBuffer, sendCursor);
288
289 /* Write samples. Fail if we don't get what we want. */
290 int num_smpls = mRadio->writeSamples(tx_buf,
291 sendCursor,
292 &underrun,
293 writeTimestamp);
294 assert(num_smpls == sendCursor);
295
296 writeTimestamp += (TIMESTAMP) num_smpls;
297 sendCursor = 0;
298}