blob: 01fec5b4abb3e7f03db72e8df2d0ec21ee71e85a [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
2* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
3*
4* This software is distributed under the terms of the GNU 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 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 General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22*/
23
dburgessb3a0ca42011-10-12 07:44:40 +000024#include <stdio.h>
25#include "Transceiver.h"
26#include <Logger.h>
27
ttsou2173abf2012-08-08 00:51:31 +000028#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
dburgessb3a0ca42011-10-12 07:44:40 +000031
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040032using namespace GSM;
33
kurtis.heimerlec842de2012-11-23 08:37:32 +000034#define USB_LATENCY_INTRVL 10,0
ttsou2173abf2012-08-08 00:51:31 +000035
36#if USE_UHD
kurtis.heimerlec842de2012-11-23 08:37:32 +000037# define USB_LATENCY_MIN 6,7
ttsou2173abf2012-08-08 00:51:31 +000038#else
kurtis.heimerlec842de2012-11-23 08:37:32 +000039# define USB_LATENCY_MIN 1,1
ttsou2173abf2012-08-08 00:51:31 +000040#endif
dburgessb3a0ca42011-10-12 07:44:40 +000041
Thomas Tsoufa3a7872013-10-17 21:23:34 -040042/* Number of running values use in noise average */
43#define NOISE_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000044
Thomas Tsouf0782732013-10-29 15:55:47 -040045TransceiverState::TransceiverState()
46{
47 for (int i = 0; i < 8; i++) {
48 chanType[i] = Transceiver::NONE;
49 fillerModulus[i] = 26;
50 chanResponse[i] = NULL;
51 DFEForward[i] = NULL;
52 DFEFeedback[i] = NULL;
53
54 for (int n = 0; n < 102; n++)
55 fillerTable[n][i] = NULL;
56 }
57}
58
59TransceiverState::~TransceiverState()
60{
61 for (int i = 0; i < 8; i++) {
62 delete chanResponse[i];
63 delete DFEForward[i];
64 delete DFEFeedback[i];
65
66 for (int n = 0; n < 102; n++)
67 delete fillerTable[n][i];
68 }
69}
70
71void TransceiverState::init(size_t slot, signalVector *burst)
72{
73 for (int i = 0; i < 102; i++)
74 fillerTable[i][slot] = new signalVector(*burst);
75}
76
dburgessb3a0ca42011-10-12 07:44:40 +000077Transceiver::Transceiver(int wBasePort,
78 const char *TRXAddress,
Thomas Tsou204a9f12013-10-29 18:34:16 -040079 size_t wSPS, size_t wChans,
dburgessb3a0ca42011-10-12 07:44:40 +000080 GSM::Time wTransmitLatency,
81 RadioInterface *wRadioInterface)
Thomas Tsoud647ec52013-10-29 15:17:34 -040082 : mBasePort(wBasePort), mAddr(TRXAddress),
Thomas Tsou204a9f12013-10-29 18:34:16 -040083 mTransmitLatency(wTransmitLatency), mClockSocket(NULL), mRadioInterface(wRadioInterface),
84 mNoiseLev(0.0), mNoises(NOISE_CNT), mSPSTx(wSPS), mSPSRx(1), mChans(wChans),
85 mOn(false), mTxFreq(0.0), mRxFreq(0.0), mPower(-10), mMaxExpectedDelay(0)
dburgessb3a0ca42011-10-12 07:44:40 +000086{
dburgessb3a0ca42011-10-12 07:44:40 +000087 GSM::Time startTime(random() % gHyperframe,0);
88
Thomas Tsou204a9f12013-10-29 18:34:16 -040089 mRxLowerLoopThread = new Thread(32768);
90 mTxLowerLoopThread = new Thread(32768);
dburgessb3a0ca42011-10-12 07:44:40 +000091
dburgessb3a0ca42011-10-12 07:44:40 +000092 mTransmitDeadlineClock = startTime;
93 mLastClockUpdateTime = startTime;
94 mLatencyUpdateTime = startTime;
95 mRadioInterface->getClock()->set(startTime);
dburgessb3a0ca42011-10-12 07:44:40 +000096
dburgessb3a0ca42011-10-12 07:44:40 +000097 txFullScale = mRadioInterface->fullScaleInputValue();
98 rxFullScale = mRadioInterface->fullScaleOutputValue();
dburgessb3a0ca42011-10-12 07:44:40 +000099}
100
101Transceiver::~Transceiver()
102{
dburgessb3a0ca42011-10-12 07:44:40 +0000103 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400104
105 delete mClockSocket;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400106
107 for (size_t i = 0; i < mChans; i++) {
108 mTxPriorityQueues[i].clear();
109 delete mCtrlSockets[i];
110 delete mDataSockets[i];
111 }
dburgessb3a0ca42011-10-12 07:44:40 +0000112}
Thomas Tsou83e06892013-08-20 16:10:01 -0400113
114bool Transceiver::init()
115{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500116 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400117 signalVector *burst;
118
Thomas Tsou204a9f12013-10-29 18:34:16 -0400119 if (!mChans) {
120 LOG(ALERT) << "No channels assigned";
121 return false;
122 }
123
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400124 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400125 LOG(ALERT) << "Failed to initialize signal processing library";
126 return false;
127 }
128
Thomas Tsou204a9f12013-10-29 18:34:16 -0400129 mDataSockets.resize(mChans);
130 mCtrlSockets.resize(mChans);
131
132 mControlServiceLoopThreads.resize(mChans);
133 mTxPriorityQueueServiceLoopThreads.resize(mChans);
134 mRxServiceLoopThreads.resize(mChans);
135
136 mTxPriorityQueues.resize(mChans);
137 mReceiveFIFO.resize(mChans);
138 mStates.resize(mChans);
139
Thomas Tsoud647ec52013-10-29 15:17:34 -0400140 mClockSocket = new UDPSocket(mBasePort, mAddr.c_str(), mBasePort + 100);
Thomas Tsoud647ec52013-10-29 15:17:34 -0400141
Thomas Tsou204a9f12013-10-29 18:34:16 -0400142 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500143 c_srcport = mBasePort + 2 * i + 1;
144 c_dstport = mBasePort + 2 * i + 101;
145 d_srcport = mBasePort + 2 * i + 2;
146 d_dstport = mBasePort + 2 * i + 102;
147
148 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
149 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400150 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400151
Thomas Tsou204a9f12013-10-29 18:34:16 -0400152 for (size_t i = 0; i < mChans; i++) {
153 mControlServiceLoopThreads[i] = new Thread(32768);
154 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
155 mRxServiceLoopThreads[i] = new Thread(32768);
156
157 for (size_t n = 0; n < 8; n++) {
158 burst = modulateBurst(gDummyBurst, 8 + (n % 4 == 0), mSPSTx);
159 scaleVector(*burst, txFullScale);
160 mStates[i].init(n, burst);
161 delete burst;
162 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400163 }
164
165 return true;
166}
dburgessb3a0ca42011-10-12 07:44:40 +0000167
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500168void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400169 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000170{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500171 signalVector *burst;
172 radioVector *radio_burst;
173
Thomas Tsou204a9f12013-10-29 18:34:16 -0400174 if (chan >= mTxPriorityQueues.size()) {
175 LOG(ALERT) << "Invalid channel " << chan;
176 return;
177 }
178
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500179 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
180 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000181
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500182 radio_burst = new radioVector(wTime, burst);
183
184 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000185}
186
dburgessb3a0ca42011-10-12 07:44:40 +0000187void Transceiver::pushRadioVector(GSM::Time &nowTime)
188{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400189 int TN, modFN;
190 radioVector *burst;
191 TransceiverState *state;
192 std::vector<signalVector *> bursts(mChans);
193 std::vector<bool> zeros(mChans);
dburgessb3a0ca42011-10-12 07:44:40 +0000194
Thomas Tsou204a9f12013-10-29 18:34:16 -0400195 for (size_t i = 0; i < mChans; i ++) {
196 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000197
Thomas Tsou204a9f12013-10-29 18:34:16 -0400198 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
199 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
200
201 TN = burst->getTime().TN();
202 modFN = burst->getTime().FN() % state->fillerModulus[TN];
203
204 delete state->fillerTable[modFN][TN];
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500205 state->fillerTable[modFN][TN] = burst->getVector();
206 burst->setVector(NULL);
207 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400208 }
209
210 TN = nowTime.TN();
211 modFN = nowTime.FN() % state->fillerModulus[TN];
212
213 bursts[i] = state->fillerTable[modFN][TN];
214 zeros[i] = state->chanType[TN] == NONE;
215
216 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
217 delete state->fillerTable[modFN][TN];
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500218 state->fillerTable[modFN][TN] = burst->getVector();
219 bursts[i] = burst->getVector();
220 burst->setVector(NULL);
221 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400222 }
dburgessb3a0ca42011-10-12 07:44:40 +0000223 }
224
Thomas Tsou204a9f12013-10-29 18:34:16 -0400225 mRadioInterface->driveTransmitRadio(bursts, zeros);
226
227 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000228}
229
Thomas Tsou204a9f12013-10-29 18:34:16 -0400230void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000231{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400232 TransceiverState *state = &mStates[chan];
233
234 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000235 case NONE:
236 case I:
237 case II:
238 case III:
239 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400240 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000241 break;
242 case IV:
243 case VI:
244 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400245 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000246 break;
247 //case V:
248 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400249 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000250 break;
ttsoufc40a842013-06-09 22:38:18 +0000251 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400252 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000253 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000254 default:
255 break;
256 }
257}
258
259
Thomas Tsou204a9f12013-10-29 18:34:16 -0400260Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
261 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000262{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400263 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000264 unsigned burstTN = currTime.TN();
265 unsigned burstFN = currTime.FN();
266
Thomas Tsou204a9f12013-10-29 18:34:16 -0400267 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000268 case NONE:
269 return OFF;
270 break;
271 case FILL:
272 return IDLE;
273 break;
274 case I:
275 return TSC;
276 /*if (burstFN % 26 == 25)
277 return IDLE;
278 else
279 return TSC;*/
280 break;
281 case II:
ttsou20642972013-03-27 22:00:25 +0000282 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000283 break;
284 case III:
285 return TSC;
286 break;
287 case IV:
288 case VI:
289 return RACH;
290 break;
291 case V: {
292 int mod51 = burstFN % 51;
293 if ((mod51 <= 36) && (mod51 >= 14))
294 return RACH;
295 else if ((mod51 == 4) || (mod51 == 5))
296 return RACH;
297 else if ((mod51 == 45) || (mod51 == 46))
298 return RACH;
299 else
300 return TSC;
301 break;
302 }
303 case VII:
304 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
305 return IDLE;
306 else
307 return TSC;
308 break;
ttsoufc40a842013-06-09 22:38:18 +0000309 case XIII: {
310 int mod52 = burstFN % 52;
311 if ((mod52 == 12) || (mod52 == 38))
312 return RACH;
313 else if ((mod52 == 25) || (mod52 == 51))
314 return IDLE;
315 else
316 return TSC;
317 break;
318 }
dburgessb3a0ca42011-10-12 07:44:40 +0000319 case LOOPBACK:
320 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
321 return IDLE;
322 else
323 return TSC;
324 break;
325 default:
326 return OFF;
327 break;
328 }
dburgessb3a0ca42011-10-12 07:44:40 +0000329}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400330
Thomas Tsou30421a72013-11-13 23:14:48 -0500331/*
332 * Detect RACH synchronization sequence within a burst. No equalization
333 * is used or available on the RACH channel.
334 */
335bool Transceiver::detectRACH(TransceiverState *state,
336 signalVector &burst,
337 complex &amp, float &toa)
338{
339 float threshold = 6.0;
340
341 return detectRACHBurst(burst, threshold, mSPSRx, &amp, &toa);
342}
343
344/*
345 * Detect normal burst training sequence midamble. Update equalization
346 * state information and channel estimate if necessary. Equalization
347 * is currently disabled.
348 */
349bool Transceiver::detectTSC(TransceiverState *state,
350 signalVector &burst,
351 complex &amp, float &toa, GSM::Time &time)
352{
353 int tn = time.TN();
354 float chanOffset, threshold = 5.0;
355 bool needDFE = false, estimateChan = false;
356 double elapsed = time - state->chanEstimateTime[tn];
357 signalVector *chanResp;
358
359 /* Check equalization update state */
360 if ((elapsed > 50) || (!state->chanResponse[tn])) {
361 delete state->DFEForward[tn];
362 delete state->DFEFeedback[tn];
363 state->DFEForward[tn] = NULL;
364 state->DFEFeedback[tn] = NULL;
365
366 estimateChan = true;
367 }
368
369 /* Detect normal burst midambles */
370 if (!analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, &amp,
371 &toa, mMaxExpectedDelay, estimateChan,
372 &chanResp, &chanOffset)) {
373 return false;
374 }
375
376 state->SNRestimate[tn] = amp.norm2() / (mNoiseLev * mNoiseLev + 1.0);
377
378 /* Set equalizer if unabled */
379 if (needDFE && estimateChan) {
380 state->chanResponse[tn] = chanResp;
381 state->chanRespOffset[tn] = chanOffset;
382 state->chanRespAmplitude[tn] = amp;
383
384 scaleVector(*chanResp, complex(1.0, 0.0) / amp);
385
386 designDFE(*chanResp, state->SNRestimate[tn],
387 7, &state->DFEForward[tn], &state->DFEFeedback[tn]);
388
389 state->chanEstimateTime[tn] = time;
390 }
391
392 return true;;
393}
394
395/*
396 * Demodulate GMSK burst using equalization if requested. Otherwise
397 * demodulate by direct rotation and soft slicing.
398 */
399SoftVector *Transceiver::demodulate(TransceiverState *state,
400 signalVector &burst, complex amp,
401 float toa, size_t tn, bool equalize)
402{
403 if (equalize) {
404 scaleVector(burst, complex(1.0, 0.0) / amp);
405 return equalizeBurst(burst,
406 toa - state->chanRespOffset[tn],
407 mSPSRx,
408 *state->DFEForward[tn],
409 *state->DFEFeedback[tn]);
410 }
411
412 return demodulateBurst(burst, mSPSRx, amp, toa);
413}
414
415/*
416 * Pull bursts from the FIFO and handle according to the slot
417 * and burst correlation type. Equalzation is currently disabled.
418 */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400419SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
420 int &timingOffset, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000421{
Thomas Tsou30421a72013-11-13 23:14:48 -0500422 bool success, equalize = false;
423 complex amp;
424 float toa, pow, max = -1.0, avg = 0.0;
425 signalVector *burst;
426 SoftVector *bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000427
Thomas Tsou30421a72013-11-13 23:14:48 -0500428 /* Blocking FIFO read */
429 radioVector *radio_burst = mReceiveFIFO[chan]->read();
430 if (!radio_burst)
431 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000432
Thomas Tsou30421a72013-11-13 23:14:48 -0500433 /* Set time and determine correlation type */
434 GSM::Time time = radio_burst->getTime();
435 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000436
Thomas Tsou30421a72013-11-13 23:14:48 -0500437 if ((type == OFF) || (type == IDLE)) {
438 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000439 return NULL;
440 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000441
Thomas Tsou30421a72013-11-13 23:14:48 -0500442 /* Average noise on diversity paths and update global levels */
443 burst = radio_burst->getVector();
444 avg = avg / radio_burst->chans();
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400445 mNoiseLev = mNoises.avg();
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400446 avg = sqrt(avg);
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400447
Thomas Tsou30421a72013-11-13 23:14:48 -0500448 /* Detect normal or RACH bursts */
449 if (type == TSC)
450 success = detectTSC(&mStates[chan], *burst, amp, toa, time);
451 else
452 success = detectRACH(&mStates[chan], *burst, amp, toa);
Thomas Tsouf0782732013-10-29 15:55:47 -0400453
Thomas Tsou30421a72013-11-13 23:14:48 -0500454 if (!success) {
455 mNoises.insert(avg);
456 delete radio_burst;
457 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000458 }
dburgessb3a0ca42011-10-12 07:44:40 +0000459
Thomas Tsou30421a72013-11-13 23:14:48 -0500460 /* Demodulate and set output info */
461 if (equalize && (type != TSC))
462 equalize = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000463
Thomas Tsou30421a72013-11-13 23:14:48 -0500464 bits = demodulate(&mStates[chan], *burst, amp, toa, time.TN(), equalize);
465 wTime = time;
466 RSSI = (int) floor(20.0 * log10(rxFullScale / avg));
467 timingOffset = (int) round(toa * 256.0 / mSPSRx);
dburgessb3a0ca42011-10-12 07:44:40 +0000468
Thomas Tsou30421a72013-11-13 23:14:48 -0500469 delete radio_burst;
470
471 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000472}
473
474void Transceiver::start()
475{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400476 TransceiverChannel *chan;
477
478 for (size_t i = 0; i < mControlServiceLoopThreads.size(); i++) {
479 chan = new TransceiverChannel(this, i);
480 mControlServiceLoopThreads[i]->start((void * (*)(void*))
481 ControlServiceLoopAdapter, (void*) chan);
482 }
dburgessb3a0ca42011-10-12 07:44:40 +0000483}
484
485void Transceiver::reset()
486{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400487 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
488 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000489}
490
491
Thomas Tsou204a9f12013-10-29 18:34:16 -0400492void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000493{
dburgessb3a0ca42011-10-12 07:44:40 +0000494 int MAX_PACKET_LENGTH = 100;
495
496 // check control socket
497 char buffer[MAX_PACKET_LENGTH];
498 int msgLen = -1;
499 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400500
Thomas Tsou204a9f12013-10-29 18:34:16 -0400501 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000502
503 if (msgLen < 1) {
504 return;
505 }
506
507 char cmdcheck[4];
508 char command[MAX_PACKET_LENGTH];
509 char response[MAX_PACKET_LENGTH];
510
511 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400512
513 if (!chan)
514 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000515
516 if (strcmp(cmdcheck,"CMD")!=0) {
517 LOG(WARNING) << "bogus message on control interface";
518 return;
519 }
520 LOG(INFO) << "command is " << buffer;
521
522 if (strcmp(command,"POWEROFF")==0) {
523 // turn off transmitter/demod
524 sprintf(response,"RSP POWEROFF 0");
525 }
526 else if (strcmp(command,"POWERON")==0) {
527 // turn on transmitter/demod
528 if (!mTxFreq || !mRxFreq)
529 sprintf(response,"RSP POWERON 1");
530 else {
531 sprintf(response,"RSP POWERON 0");
Thomas Tsou204a9f12013-10-29 18:34:16 -0400532 if (!chan && !mOn) {
dburgessb3a0ca42011-10-12 07:44:40 +0000533 // Prepare for thread start
534 mPower = -20;
535 mRadioInterface->start();
dburgessb3a0ca42011-10-12 07:44:40 +0000536
537 // Start radio interface threads.
Thomas Tsou204a9f12013-10-29 18:34:16 -0400538 mTxLowerLoopThread->start((void * (*)(void*))
539 TxLowerLoopAdapter,(void*) this);
540 mRxLowerLoopThread->start((void * (*)(void*))
541 RxLowerLoopAdapter,(void*) this);
dburgessb3a0ca42011-10-12 07:44:40 +0000542
Thomas Tsou204a9f12013-10-29 18:34:16 -0400543 for (size_t i = 0; i < mChans; i++) {
544 TransceiverChannel *chan = new TransceiverChannel(this, i);
545 mRxServiceLoopThreads[i]->start((void * (*)(void*))
546 RxUpperLoopAdapter, (void*) chan);
547
548 chan = new TransceiverChannel(this, i);
549 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
550 TxUpperLoopAdapter, (void*) chan);
551 }
552
553 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000554 mOn = true;
555 }
556 }
557 }
558 else if (strcmp(command,"SETMAXDLY")==0) {
559 //set expected maximum time-of-arrival
560 int maxDelay;
561 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
562 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
563 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
564 }
565 else if (strcmp(command,"SETRXGAIN")==0) {
566 //set expected maximum time-of-arrival
567 int newGain;
568 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400569 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000570 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
571 }
572 else if (strcmp(command,"NOISELEV")==0) {
573 if (mOn) {
574 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400575 (int) round(20.0*log10(rxFullScale/mNoiseLev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000576 }
577 else {
578 sprintf(response,"RSP NOISELEV 1 0");
579 }
580 }
581 else if (strcmp(command,"SETPOWER")==0) {
582 // set output power in dB
583 int dbPwr;
584 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr);
585 if (!mOn)
586 sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
587 else {
588 mPower = dbPwr;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400589 mRadioInterface->setPowerAttenuation(dbPwr, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000590 sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
591 }
592 }
593 else if (strcmp(command,"ADJPOWER")==0) {
594 // adjust power in dB steps
595 int dbStep;
596 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep);
597 if (!mOn)
598 sprintf(response,"RSP ADJPOWER 1 %d",mPower);
599 else {
600 mPower += dbStep;
601 sprintf(response,"RSP ADJPOWER 0 %d",mPower);
602 }
603 }
604#define FREQOFFSET 0//11.2e3
605 else if (strcmp(command,"RXTUNE")==0) {
606 // tune receiver
607 int freqKhz;
608 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
609 mRxFreq = freqKhz*1.0e3+FREQOFFSET;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400610 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000611 LOG(ALERT) << "RX failed to tune";
612 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
613 }
614 else
615 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
616 }
617 else if (strcmp(command,"TXTUNE")==0) {
618 // tune txmtr
619 int freqKhz;
620 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
621 //freqKhz = 890e3;
622 mTxFreq = freqKhz*1.0e3+FREQOFFSET;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400623 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000624 LOG(ALERT) << "TX failed to tune";
625 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
626 }
627 else
628 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
629 }
630 else if (strcmp(command,"SETTSC")==0) {
631 // set TSC
632 int TSC;
633 sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC);
634 if (mOn)
635 sprintf(response,"RSP SETTSC 1 %d",TSC);
636 else {
637 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400638 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400639 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000640 }
641 }
642 else if (strcmp(command,"SETSLOT")==0) {
643 // set TSC
644 int corrCode;
645 int timeslot;
646 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
647 if ((timeslot < 0) || (timeslot > 7)) {
648 LOG(WARNING) << "bogus message on control interface";
649 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
650 return;
651 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400652 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
653 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000654 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
655
656 }
657 else {
658 LOG(WARNING) << "bogus command " << command << " on control interface.";
659 }
660
Thomas Tsou204a9f12013-10-29 18:34:16 -0400661 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000662}
663
Thomas Tsou204a9f12013-10-29 18:34:16 -0400664bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000665{
dburgessb3a0ca42011-10-12 07:44:40 +0000666 char buffer[gSlotLen+50];
667
668 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400669 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000670
671 if (msgLen!=gSlotLen+1+4+1) {
672 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
673 return false;
674 }
675
676 int timeSlot = (int) buffer[0];
677 uint64_t frameNum = 0;
678 for (int i = 0; i < 4; i++)
679 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
680
681 /*
682 if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) {
683 // stale burst
684 //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot);
685 //writeClockInterface();
686 }*/
687
688/*
689 DAB -- Just let these go through the demod.
690 if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) {
691 // stale burst from GSM core
692 LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot);
693 return false;
694 }
695*/
696
697 // periodically update GSM core clock
698 LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
699 << " mLastClockUpdateTime " << mLastClockUpdateTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000700
Thomas Tsou204a9f12013-10-29 18:34:16 -0400701 if (!chan) {
702 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
703 writeClockInterface();
704 }
dburgessb3a0ca42011-10-12 07:44:40 +0000705
706 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
707
708 int RSSI = (int) buffer[5];
709 static BitVector newBurst(gSlotLen);
710 BitVector::iterator itr = newBurst.begin();
711 char *bufferItr = buffer+6;
712 while (itr < newBurst.end())
713 *itr++ = *bufferItr++;
714
715 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400716
717 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000718
719 return true;
720
721
722}
dburgessb3a0ca42011-10-12 07:44:40 +0000723
Thomas Tsou204a9f12013-10-29 18:34:16 -0400724void Transceiver::driveReceiveRadio()
725{
726 if (!mRadioInterface->driveReceiveRadio())
727 usleep(100000);
728}
729
730void Transceiver::driveReceiveFIFO(size_t chan)
731{
dburgessb3a0ca42011-10-12 07:44:40 +0000732 SoftVector *rxBurst = NULL;
733 int RSSI;
734 int TOA; // in 1/256 of a symbol
735 GSM::Time burstTime;
736
Thomas Tsou204a9f12013-10-29 18:34:16 -0400737 rxBurst = pullRadioVector(burstTime, RSSI, TOA, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000738
739 if (rxBurst) {
740
741 LOG(DEBUG) << "burst parameters: "
742 << " time: " << burstTime
743 << " RSSI: " << RSSI
744 << " TOA: " << TOA
745 << " bits: " << *rxBurst;
746
747 char burstString[gSlotLen+10];
748 burstString[0] = burstTime.TN();
749 for (int i = 0; i < 4; i++)
750 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
751 burstString[5] = RSSI;
752 burstString[6] = (TOA >> 8) & 0x0ff;
753 burstString[7] = TOA & 0x0ff;
754 SoftVector::iterator burstItr = rxBurst->begin();
755
756 for (unsigned int i = 0; i < gSlotLen; i++) {
757 burstString[8+i] =(char) round((*burstItr++)*255.0);
758 }
759 burstString[gSlotLen+9] = '\0';
760 delete rxBurst;
761
Thomas Tsou204a9f12013-10-29 18:34:16 -0400762 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +0000763 }
dburgessb3a0ca42011-10-12 07:44:40 +0000764}
765
Thomas Tsou204a9f12013-10-29 18:34:16 -0400766void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000767{
768
769 /**
770 Features a carefully controlled latency mechanism, to
771 assure that transmit packets arrive at the radio/USRP
772 before they need to be transmitted.
773
774 Deadline clock indicates the burst that needs to be
775 pushed into the FIFO right NOW. If transmit queue does
776 not have a burst, stick in filler data.
777 */
778
779
780 RadioClock *radioClock = (mRadioInterface->getClock());
781
782 if (mOn) {
783 //radioClock->wait(); // wait until clock updates
784 LOG(DEBUG) << "radio clock " << radioClock->get();
785 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
786 // if underrun, then we're not providing bursts to radio/USRP fast
787 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400788 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000789 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000790 // only update latency at the defined frame interval
791 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000792 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
793 LOG(INFO) << "new latency: " << mTransmitLatency;
794 mLatencyUpdateTime = radioClock->get();
795 }
796 }
797 else {
798 // if underrun hasn't occurred in the last sec (216 frames) drop
799 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000800 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000801 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
802 mTransmitLatency.decTN();
803 LOG(INFO) << "reduced latency: " << mTransmitLatency;
804 mLatencyUpdateTime = radioClock->get();
805 }
806 }
807 }
dburgessb3a0ca42011-10-12 07:44:40 +0000808 }
dburgessb3a0ca42011-10-12 07:44:40 +0000809 // time to push burst to transmit FIFO
810 pushRadioVector(mTransmitDeadlineClock);
811 mTransmitDeadlineClock.incTN();
812 }
dburgessb3a0ca42011-10-12 07:44:40 +0000813 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400814
815 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000816}
817
818
819
820void Transceiver::writeClockInterface()
821{
822 char command[50];
823 // FIXME -- This should be adaptive.
824 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
825
826 LOG(INFO) << "ClockInterface: sending " << command;
827
Thomas Tsoud647ec52013-10-29 15:17:34 -0400828 mClockSocket->write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000829
830 mLastClockUpdateTime = mTransmitDeadlineClock;
831
Thomas Tsou92c16df2013-09-28 18:04:19 -0400832}
dburgessb3a0ca42011-10-12 07:44:40 +0000833
Thomas Tsou204a9f12013-10-29 18:34:16 -0400834void *RxUpperLoopAdapter(TransceiverChannel *chan)
835{
836 Transceiver *trx = chan->trx;
837 size_t num = chan->num;
838
839 delete chan;
840
Thomas Tsou7553aa92013-11-08 12:50:03 -0500841 trx->setPriority(0.42);
842
Thomas Tsou204a9f12013-10-29 18:34:16 -0400843 while (1) {
844 trx->driveReceiveFIFO(num);
845 pthread_testcancel();
846 }
847 return NULL;
848}
849
850void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +0000851{
Thomas Tsou7553aa92013-11-08 12:50:03 -0500852 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +0000853
dburgessb3a0ca42011-10-12 07:44:40 +0000854 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400855 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -0400856 pthread_testcancel();
857 }
858 return NULL;
859}
860
Thomas Tsou204a9f12013-10-29 18:34:16 -0400861void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -0400862{
Thomas Tsou7553aa92013-11-08 12:50:03 -0500863 transceiver->setPriority(0.44);
864
Thomas Tsou92c16df2013-09-28 18:04:19 -0400865 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400866 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +0000867 pthread_testcancel();
868 }
869 return NULL;
870}
871
Thomas Tsou204a9f12013-10-29 18:34:16 -0400872void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000873{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400874 Transceiver *trx = chan->trx;
875 size_t num = chan->num;
876
877 delete chan;
878
dburgessb3a0ca42011-10-12 07:44:40 +0000879 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400880 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +0000881 pthread_testcancel();
882 }
883 return NULL;
884}
885
Thomas Tsou204a9f12013-10-29 18:34:16 -0400886void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000887{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400888 Transceiver *trx = chan->trx;
889 size_t num = chan->num;
890
891 delete chan;
892
Thomas Tsoua4cf48c2013-11-09 21:44:26 -0500893 trx->setPriority(0.40);
894
dburgessb3a0ca42011-10-12 07:44:40 +0000895 while (1) {
896 bool stale = false;
897 // Flush the UDP packets until a successful transfer.
Thomas Tsou204a9f12013-10-29 18:34:16 -0400898 while (!trx->driveTxPriorityQueue(num)) {
899 stale = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000900 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400901 if (!num && stale) {
dburgessb3a0ca42011-10-12 07:44:40 +0000902 // If a packet was stale, remind the GSM stack of the clock.
Thomas Tsou204a9f12013-10-29 18:34:16 -0400903 trx->writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000904 }
905 pthread_testcancel();
906 }
907 return NULL;
908}