blob: f39a470df89746cdb92896cc2729d630e818e7ff [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
Thomas Tsou9471d762013-08-20 21:24:24 -040028extern "C" {
29#include "convert.h"
30}
31
kurtis.heimerl9b557832011-11-26 03:18:34 +000032bool started = false;
33
dburgessb3a0ca42011-10-12 07:44:40 +000034RadioInterface::RadioInterface(RadioDevice *wRadio,
kurtis.heimerl54354042011-11-26 03:18:49 +000035 int wReceiveOffset,
Thomas Tsou312e3872013-04-08 13:45:55 -040036 int wSPS,
dburgessb3a0ca42011-10-12 07:44:40 +000037 GSM::Time wStartTime)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040038 : underrun(false), sendCursor(0), recvCursor(0), mOn(false),
kurtis.heimerl54354042011-11-26 03:18:49 +000039 mRadio(wRadio), receiveOffset(wReceiveOffset),
Thomas Tsoud24cc2c2013-08-20 15:41:45 -040040 sps(wSPS), powerScaling(1.0),
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040041 loadTest(false), sendBuffer(NULL), recvBuffer(NULL),
42 convertRecvBuffer(NULL), convertSendBuffer(NULL)
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 Tsou03e6ecf2013-08-20 20:54:54 -040052bool RadioInterface::init()
53{
54 close();
55
56 sendBuffer = new signalVector(OUTCHUNK * 20);
57 recvBuffer = new signalVector(INCHUNK * 20);
58
59 convertSendBuffer = new short[OUTCHUNK * 2 * 20];
60 convertRecvBuffer = new short[OUTCHUNK * 2 * 2];
61
62 sendCursor = 0;
63 recvCursor = 0;
64
65 return true;
66}
67
68void RadioInterface::close()
69{
70 delete sendBuffer;
71 delete recvBuffer;
72 delete convertSendBuffer;
73 delete convertRecvBuffer;
74
75 sendBuffer = NULL;
76 recvBuffer = NULL;
77 convertRecvBuffer = NULL;
78 convertSendBuffer = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000079}
80
Thomas Tsou9471d762013-08-20 21:24:24 -040081
dburgessb3a0ca42011-10-12 07:44:40 +000082double RadioInterface::fullScaleInputValue(void) {
83 return mRadio->fullScaleInputValue();
84}
85
86double RadioInterface::fullScaleOutputValue(void) {
87 return mRadio->fullScaleOutputValue();
88}
89
90
kurtis.heimerl58d6a012011-11-26 03:17:38 +000091void RadioInterface::setPowerAttenuation(double atten)
dburgessb3a0ca42011-10-12 07:44:40 +000092{
kurtis.heimerl16c65402011-11-26 03:18:11 +000093 double rfGain, digAtten;
kurtis.heimerlee5347a2011-11-26 03:18:05 +000094
kurtis.heimerl16c65402011-11-26 03:18:11 +000095 rfGain = mRadio->setTxGain(mRadio->maxTxGain() - atten);
96 digAtten = atten - mRadio->maxTxGain() + rfGain;
kurtis.heimerlee5347a2011-11-26 03:18:05 +000097
98 if (digAtten < 1.0)
99 powerScaling = 1.0;
100 else
101 powerScaling = 1.0/sqrt(pow(10, (digAtten/10.0)));
dburgessb3a0ca42011-10-12 07:44:40 +0000102}
103
kurtis.heimerl9b557832011-11-26 03:18:34 +0000104int RadioInterface::radioifyVector(signalVector &wVector,
105 float *retVector,
kurtis.heimerl9b557832011-11-26 03:18:34 +0000106 bool zero)
dburgessb3a0ca42011-10-12 07:44:40 +0000107{
kurtis.heimerl9b557832011-11-26 03:18:34 +0000108 if (zero) {
109 memset(retVector, 0, wVector.size() * 2 * sizeof(float));
110 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000111 }
112
Thomas Tsou9471d762013-08-20 21:24:24 -0400113 memcpy(retVector, wVector.begin(), wVector.size() * 2 * sizeof(float));
kurtis.heimerl9b557832011-11-26 03:18:34 +0000114
115 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000116}
117
kurtis.heimerl9b557832011-11-26 03:18:34 +0000118int RadioInterface::unRadioifyVector(float *floatVector,
119 signalVector& newVector)
dburgessb3a0ca42011-10-12 07:44:40 +0000120{
dburgessb3a0ca42011-10-12 07:44:40 +0000121 signalVector::iterator itr = newVector.begin();
kurtis.heimerl9b557832011-11-26 03:18:34 +0000122
Thomas Tsou9471d762013-08-20 21:24:24 -0400123 if (newVector.size() > recvCursor) {
124 LOG(ALERT) << "Insufficient number of samples in receive buffer";
125 return -1;
126 }
127
128 for (int i = 0; i < newVector.size(); i++) {
kurtis.heimerl9b557832011-11-26 03:18:34 +0000129 *itr++ = Complex<float>(floatVector[2 * i + 0],
130 floatVector[2 * i + 1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000131 }
132
kurtis.heimerl9b557832011-11-26 03:18:34 +0000133 return newVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000134}
135
136bool RadioInterface::tuneTx(double freq)
137{
138 return mRadio->setTxFreq(freq);
139}
140
141bool RadioInterface::tuneRx(double freq)
142{
143 return mRadio->setRxFreq(freq);
144}
145
146
147void RadioInterface::start()
148{
149 LOG(INFO) << "starting radio interface...";
Thomas Tsouf2293b82013-04-08 13:35:36 -0400150#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000151 mAlignRadioServiceLoopThread.start((void * (*)(void*))AlignRadioServiceLoopAdapter,
152 (void*)this);
Thomas Tsouf2293b82013-04-08 13:35:36 -0400153#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000154 writeTimestamp = mRadio->initialWriteTimestamp();
155 readTimestamp = mRadio->initialReadTimestamp();
156 mRadio->start();
157 LOG(DEBUG) << "Radio started";
158 mRadio->updateAlignment(writeTimestamp-10000);
159 mRadio->updateAlignment(writeTimestamp-10000);
160
dburgessb3a0ca42011-10-12 07:44:40 +0000161 mOn = true;
162
163}
164
Thomas Tsouf2293b82013-04-08 13:35:36 -0400165#ifdef USRP1
dburgessb3a0ca42011-10-12 07:44:40 +0000166void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface)
167{
168 while (1) {
169 radioInterface->alignRadio();
170 pthread_testcancel();
171 }
172 return NULL;
173}
174
175void RadioInterface::alignRadio() {
176 sleep(60);
177 mRadio->updateAlignment(writeTimestamp+ (TIMESTAMP) 10000);
178}
Thomas Tsouf2293b82013-04-08 13:35:36 -0400179#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000180
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400181void RadioInterface::driveTransmitRadio(signalVector &radioBurst, bool zeroBurst)
182{
183 if (!mOn)
184 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000185
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400186 radioifyVector(radioBurst,
Thomas Tsou9471d762013-08-20 21:24:24 -0400187 (float *) (sendBuffer->begin() + sendCursor), zeroBurst);
dburgessb3a0ca42011-10-12 07:44:40 +0000188
kurtis.heimerl9b557832011-11-26 03:18:34 +0000189 sendCursor += radioBurst.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000190
191 pushBuffer();
192}
193
194void RadioInterface::driveReceiveRadio() {
195
196 if (!mOn) return;
197
198 if (mReceiveFIFO.size() > 8) return;
199
200 pullBuffer();
201
202 GSM::Time rcvClock = mClock.get();
203 rcvClock.decTN(receiveOffset);
204 unsigned tN = rcvClock.TN();
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400205 int rcvSz = recvCursor;
dburgessb3a0ca42011-10-12 07:44:40 +0000206 int readSz = 0;
207 const int symbolsPerSlot = gSlotLen + 8;
208
209 // while there's enough data in receive buffer, form received
210 // GSM bursts and pass up to Transceiver
211 // Using the 157-156-156-156 symbols per timeslot format.
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400212 while (rcvSz > (symbolsPerSlot + (tN % 4 == 0)) * sps) {
213 signalVector rxVector((symbolsPerSlot + (tN % 4 == 0)) * sps);
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400214 unRadioifyVector((float *) (recvBuffer->begin() + readSz), rxVector);
dburgessb3a0ca42011-10-12 07:44:40 +0000215 GSM::Time tmpTime = rcvClock;
216 if (rcvClock.FN() >= 0) {
217 //LOG(DEBUG) << "FN: " << rcvClock.FN();
218 radioVector *rxBurst = NULL;
219 if (!loadTest)
220 rxBurst = new radioVector(rxVector,tmpTime);
221 else {
222 if (tN % 4 == 0)
223 rxBurst = new radioVector(*finalVec9,tmpTime);
224 else
225 rxBurst = new radioVector(*finalVec,tmpTime);
226 }
227 mReceiveFIFO.put(rxBurst);
228 }
229 mClock.incTN();
230 rcvClock.incTN();
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400231 readSz += (symbolsPerSlot+(tN % 4 == 0)) * sps;
232 rcvSz -= (symbolsPerSlot+(tN % 4 == 0)) * sps;
dburgessb3a0ca42011-10-12 07:44:40 +0000233
234 tN = rcvClock.TN();
235 }
236
kurtis.heimerl9b557832011-11-26 03:18:34 +0000237 if (readSz > 0) {
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400238 memmove(recvBuffer->begin(),
239 recvBuffer->begin() + readSz,
240 (recvCursor - readSz) * 2 * sizeof(float));
241
242 recvCursor -= readSz;
dburgessb3a0ca42011-10-12 07:44:40 +0000243 }
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000244}
245
246bool RadioInterface::isUnderrun()
247{
248 bool retVal = underrun;
249 underrun = false;
250
251 return retVal;
252}
253
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000254double RadioInterface::setRxGain(double dB)
255{
256 if (mRadio)
257 return mRadio->setRxGain(dB);
258 else
259 return -1;
260}
261
262double RadioInterface::getRxGain()
263{
264 if (mRadio)
265 return mRadio->getRxGain();
266 else
267 return -1;
268}
Thomas Tsoucb69f082013-04-08 14:18:26 -0400269
270/* Receive a timestamped chunk from the device */
271void RadioInterface::pullBuffer()
272{
273 bool local_underrun;
Thomas Tsou9471d762013-08-20 21:24:24 -0400274 int num_recv;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400275
Thomas Tsou9471d762013-08-20 21:24:24 -0400276 /* Outer buffer access size is fixed */
277 num_recv = mRadio->readSamples(convertRecvBuffer,
278 OUTCHUNK,
279 &overrun,
280 readTimestamp,
281 &local_underrun);
282 if (num_recv != OUTCHUNK) {
283 LOG(ALERT) << "Receive error " << num_recv;
284 return;
285 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400286
Thomas Tsou9471d762013-08-20 21:24:24 -0400287 convert_short_float((float *) (recvBuffer->begin() + recvCursor),
288 convertRecvBuffer, 2 * OUTCHUNK);
Thomas Tsoucb69f082013-04-08 14:18:26 -0400289
290 underrun |= local_underrun;
Thomas Tsou9471d762013-08-20 21:24:24 -0400291 readTimestamp += num_recv;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400292
Thomas Tsou9471d762013-08-20 21:24:24 -0400293 recvCursor += num_recv;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400294}
295
296/* Send timestamped chunk to the device with arbitrary size */
297void RadioInterface::pushBuffer()
298{
Thomas Tsou9471d762013-08-20 21:24:24 -0400299 int num_sent;
300
Thomas Tsoucb69f082013-04-08 14:18:26 -0400301 if (sendCursor < INCHUNK)
302 return;
303
Thomas Tsou9471d762013-08-20 21:24:24 -0400304 convert_float_short(convertSendBuffer,
305 (float *) sendBuffer->begin(),
306 powerScaling, 2 * sendCursor);
Thomas Tsoucb69f082013-04-08 14:18:26 -0400307
Thomas Tsou9471d762013-08-20 21:24:24 -0400308 /* Send the all samples in the send buffer */
309 num_sent = mRadio->writeSamples(convertSendBuffer,
310 sendCursor,
311 &underrun,
312 writeTimestamp);
313 if (num_sent != sendCursor) {
314 LOG(ALERT) << "Transmit error " << num_sent;
315 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400316
Thomas Tsou9471d762013-08-20 21:24:24 -0400317 writeTimestamp += num_sent;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400318 sendCursor = 0;
319}