Project

General

Profile

radioInterface.cpp

Vladimir, 08/10/2017 02:33 PM

 
1
/*
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

    
25
#include "radioInterface.h"
26
#include "Resampler.h"
27
#include <Logger.h>
28

    
29
extern "C" {
30
#include "convert.h"
31
}
32

    
33
#define CHUNK                625
34
#define NUMCHUNKS        4
35

    
36
RadioInterface::RadioInterface(RadioDevice *wRadio,
37
                               size_t sps_rx, size_t sps_tx,
38
                               size_t chans, size_t diversity,
39
                               int wReceiveOffset, GSM::Time wStartTime)
40
  : mRadio(wRadio), mSPSTx(sps_tx), mSPSRx(sps_rx), mChans(chans),
41
    mMIMO(diversity), sendCursor(0), recvCursor(0), underrun(false),
42
    overrun(false), receiveOffset(wReceiveOffset), mOn(false)
43
{
44
  mClock.set(wStartTime);
45
}
46

    
47
RadioInterface::~RadioInterface(void)
48
{
49
  close();
50
}
51

    
52
bool RadioInterface::init(int type)
53
{
54
  if ((type != RadioDevice::NORMAL) || (mMIMO > 1) || !mChans) {
55
    LOG(ALERT) << "Invalid configuration";
56
    return false;
57
  }
58

    
59
  close();
60

    
61
  sendBuffer.resize(mChans);
62
  recvBuffer.resize(mChans);
63
  convertSendBuffer.resize(mChans);
64
  convertRecvBuffer.resize(mChans);
65
  mReceiveFIFO.resize(mChans);
66
  powerScaling.resize(mChans);
67

    
68
  for (size_t i = 0; i < mChans; i++) {
69
    sendBuffer[i] = new signalVector(CHUNK * mSPSTx);
70
    recvBuffer[i] = new signalVector(NUMCHUNKS * CHUNK * mSPSRx);
71

    
72
    convertSendBuffer[i] = new short[sendBuffer[i]->size() * 2];
73
    convertRecvBuffer[i] = new short[recvBuffer[i]->size() * 2];
74
  }
75

    
76
  sendCursor = 0;
77
  recvCursor = 0;
78

    
79
  return true;
80
}
81

    
82
void RadioInterface::close()
83
{
84
  for (size_t i = 0; i < sendBuffer.size(); i++)
85
    delete sendBuffer[i];
86

    
87
  for (size_t i = 0; i < recvBuffer.size(); i++)
88
    delete recvBuffer[i];
89

    
90
  for (size_t i = 0; i < convertSendBuffer.size(); i++)
91
    delete convertSendBuffer[i];
92

    
93
  for (size_t i = 0; i < convertRecvBuffer.size(); i++)
94
    delete convertRecvBuffer[i];
95

    
96
  sendBuffer.resize(0);
97
  recvBuffer.resize(0);
98
  convertSendBuffer.resize(0);
99
  convertRecvBuffer.resize(0);
100
}
101

    
102
double RadioInterface::fullScaleInputValue(void) {
103
  return mRadio->fullScaleInputValue();
104
}
105

    
106
double RadioInterface::fullScaleOutputValue(void) {
107
  return mRadio->fullScaleOutputValue();
108
}
109

    
110
int RadioInterface::setPowerAttenuation(int atten, size_t chan)
111
{
112
  double rfGain, digAtten;
113

    
114
  if (chan >= mChans) {
115
    LOG(ALERT) << "Invalid channel requested";
116
    return -1;
117
  }
118

    
119
  if (atten < 0.0)
120
    atten = 0.0;
121

    
122
  rfGain = mRadio->setTxGain(mRadio->maxTxGain() - (double) atten, chan);
123
  digAtten = (double) atten - mRadio->maxTxGain() + rfGain;
124

    
125
  if (digAtten < 1.0)
126
    powerScaling[chan] = 1.0;
127
  else
128
    powerScaling[chan] = 1.0 / sqrt(pow(10, digAtten / 10.0));
129

    
130
  return atten;
131
}
132

    
133
int RadioInterface::radioifyVector(signalVector &wVector,
134
                                   float *retVector,
135
                                   bool zero)
136
{
137
  if (zero) {
138
    memset(retVector, 0, wVector.size() * 2 * sizeof(float));
139
    return wVector.size();
140
  }
141

    
142
  memcpy(retVector, wVector.begin(), wVector.size() * 2 * sizeof(float));
143

    
144
  return wVector.size();
145
}
146

    
147
int RadioInterface::unRadioifyVector(float *floatVector,
148
                                     signalVector& newVector)
149
{
150
  signalVector::iterator itr = newVector.begin();
151

    
152
  if (newVector.size() > recvCursor) {
153
    LOG(ALERT) << "Insufficient number of samples in receive buffer";
154
    return -1;
155
  }
156

    
157
  for (size_t i = 0; i < newVector.size(); i++) {
158
    *itr++ = Complex<float>(floatVector[2 * i + 0],
159
                            floatVector[2 * i + 1]);
160
  }
161

    
162
  return newVector.size();
163
}
164

    
165
bool RadioInterface::tuneTx(double freq, size_t chan)
166
{
167
  return mRadio->setTxFreq(freq, chan);
168
}
169

    
170
bool RadioInterface::tuneRx(double freq, size_t chan)
171
{
172
  return mRadio->setRxFreq(freq, chan);
173
}
174

    
175
bool RadioInterface::start()
176
{
177
  if (mOn)
178
    return true;
179

    
180
  LOG(INFO) << "Starting radio device";
181
#if defined(USRP1) || defined(USE_BLADERF)
182
  mAlignRadioServiceLoopThread.start((void * (*)(void*))AlignRadioServiceLoopAdapter,
183
                                     (void*)this);
184
#endif
185

    
186
  if (!mRadio->start())
187
    return false;
188

    
189
  writeTimestamp = mRadio->initialWriteTimestamp();
190
  readTimestamp = mRadio->initialReadTimestamp();
191

    
192
  mRadio->updateAlignment(writeTimestamp-10000);
193
  mRadio->updateAlignment(writeTimestamp-10000);
194

    
195
  mOn = true;
196
  LOG(INFO) << "Radio started";
197
  return true;
198
}
199

    
200
/*
201
 * Stop the radio device
202
 *
203
 * This is a pass-through call to the device interface. Because the underlying
204
 * stop command issuance generally doesn't return confirmation on device status,
205
 * this call will only return false if the device is already stopped.
206
 */
207
bool RadioInterface::stop()
208
{
209
  if (!mOn || !mRadio->stop())
210
    return false;
211

    
212
  mOn = false;
213
  return true;
214
}
215

    
216
#if defined(USRP1) || defined(USE_BLADERF)
217
void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface)
218
{
219
  while (1) {
220
    radioInterface->alignRadio();
221
    pthread_testcancel();
222
  }
223
  return NULL;
224
}
225

    
226
void RadioInterface::alignRadio() {
227
  sleep(60);
228
  mRadio->updateAlignment(writeTimestamp+ (TIMESTAMP) 10000);
229
}
230
#endif
231

    
232
void RadioInterface::driveTransmitRadio(std::vector<signalVector *> &bursts,
233
                                        std::vector<bool> &zeros)
234
{
235
  if (!mOn)
236
    return;
237

    
238
  for (size_t i = 0; i < mChans; i++) {
239
    radioifyVector(*bursts[i],
240
                   (float *) (sendBuffer[i]->begin() + sendCursor), zeros[i]);
241
  }
242

    
243
  sendCursor += bursts[0]->size();
244

    
245
  pushBuffer();
246
}
247

    
248
bool RadioInterface::driveReceiveRadio()
249
{
250
  radioVector *burst = NULL;
251

    
252
  if (!mOn)
253
    return false;
254

    
255
  pullBuffer();
256

    
257
  GSM::Time rcvClock = mClock.get();
258
  rcvClock.decTN(receiveOffset);
259
  unsigned tN = rcvClock.TN();
260
  int recvSz = recvCursor;
261
  int readSz = 0;
262
  const int symbolsPerSlot = gSlotLen + 8;
263
  int burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx;
264

    
265
  /* 
266
   * Pre-allocate head room for the largest correlation size
267
   * so we can later avoid a re-allocation and copy
268
   * */
269
  size_t head = GSM::gRACHSynchSequence.size();
270

    
271
  /*
272
   * Form receive bursts and pass up to transceiver. Use repeating
273
   * pattern of 157-156-156-156 symbols per timeslot
274
   */
275
  while (recvSz > burstSize) {
276
    for (size_t i = 0; i < mChans; i++) {
277
      burst = new radioVector(rcvClock, burstSize, head, mMIMO);
278

    
279
      for (size_t n = 0; n < mMIMO; n++) {
280
        unRadioifyVector((float *)
281
                         (recvBuffer[mMIMO * i + n]->begin() + readSz),
282
                         *burst->getVector(n));
283
      }
284

    
285
      if (mReceiveFIFO[i].size() < 32)
286
        mReceiveFIFO[i].write(burst);
287
      else
288
        delete burst;
289
    }
290

    
291
    mClock.incTN();
292
    rcvClock.incTN();
293
    readSz += burstSize;
294
    recvSz -= burstSize;
295

    
296
    tN = rcvClock.TN();
297

    
298
    burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx;
299
  }
300

    
301
  if (readSz > 0) {
302
    for (size_t i = 0; i < recvBuffer.size(); i++) {
303
      memmove(recvBuffer[i]->begin(),
304
              recvBuffer[i]->begin() + readSz,
305
              (recvCursor - readSz) * 2 * sizeof(float));
306
    }
307

    
308
    recvCursor -= readSz;
309
  }
310

    
311
  return true;
312
}
313

    
314
bool RadioInterface::isUnderrun()
315
{
316
  bool retVal = underrun;
317
  underrun = false;
318

    
319
  return retVal;
320
}
321

    
322
VectorFIFO* RadioInterface::receiveFIFO(size_t chan)
323
{
324
  if (chan >= mReceiveFIFO.size())
325
    return NULL;
326

    
327
  return &mReceiveFIFO[chan];
328
}
329

    
330
double RadioInterface::setRxGain(double dB, size_t chan)
331
{
332
  if (mRadio)
333
    return mRadio->setRxGain(dB, chan);
334
  else
335
    return -1;
336
}
337

    
338
double RadioInterface::getRxGain(size_t chan)
339
{
340
  if (mRadio)
341
    return mRadio->getRxGain(chan);
342
  else
343
    return -1;
344
}
345

    
346
/* Receive a timestamped chunk from the device */
347
void RadioInterface::pullBuffer()
348
{
349
  bool local_underrun;
350
  int num_recv;
351
  float *output;
352

    
353
  if (recvCursor > recvBuffer[0]->size() - CHUNK)
354
    return;
355

    
356
  /* Outer buffer access size is fixed */
357
  num_recv = mRadio->readSamples(convertRecvBuffer,
358
                                 CHUNK,
359
                                 &overrun,
360
                                 readTimestamp,
361
                                 &local_underrun);
362
  if (num_recv != CHUNK) {
363
          LOG(ALERT) << "Receive error " << num_recv;
364
          return;
365
  }
366

    
367
  for (size_t i = 0; i < mChans; i++) {
368
    output = (float *) (recvBuffer[i]->begin() + recvCursor);
369
    convert_short_float(output, convertRecvBuffer[i], 2 * num_recv);
370
  }
371

    
372
  underrun |= local_underrun;
373

    
374
  readTimestamp += num_recv;
375
  recvCursor += num_recv;
376
}
377

    
378
/* Send timestamped chunk to the device with arbitrary size */
379
void RadioInterface::pushBuffer()
380
{
381
  int num_sent;
382

    
383
  if (sendCursor < CHUNK)
384
    return;
385

    
386
  if (sendCursor > sendBuffer[0]->size())
387
    LOG(ALERT) << "Send buffer overflow";
388

    
389
  for (size_t i = 0; i < mChans; i++) {
390
    convert_float_short(convertSendBuffer[i],
391
                        (float *) sendBuffer[i]->begin(),
392
                        powerScaling[i], 2 * sendCursor);
393
  }
394

    
395
  /* Send the all samples in the send buffer */ 
396
  num_sent = mRadio->writeSamples(convertSendBuffer,
397
                                  sendCursor,
398
                                  &underrun,
399
                                  writeTimestamp);
400
  writeTimestamp += num_sent;
401
  sendCursor = 0;
402
}
Add picture from clipboard (Maximum size: 48.8 MB)