blob: 71d5d0d0b943fcf6958c1fa0dee6643ebb36de87 [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>
Alexander Chemerisfdbf9142015-06-03 23:47:56 -040025#include <iomanip> // std::setprecision
dburgessb3a0ca42011-10-12 07:44:40 +000026#include "Transceiver.h"
27#include <Logger.h>
28
ttsou2173abf2012-08-08 00:51:31 +000029#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
dburgessb3a0ca42011-10-12 07:44:40 +000032
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040033using namespace GSM;
34
kurtis.heimerlec842de2012-11-23 08:37:32 +000035#define USB_LATENCY_INTRVL 10,0
ttsou2173abf2012-08-08 00:51:31 +000036
37#if USE_UHD
kurtis.heimerlec842de2012-11-23 08:37:32 +000038# define USB_LATENCY_MIN 6,7
ttsou2173abf2012-08-08 00:51:31 +000039#else
kurtis.heimerlec842de2012-11-23 08:37:32 +000040# define USB_LATENCY_MIN 1,1
ttsou2173abf2012-08-08 00:51:31 +000041#endif
dburgessb3a0ca42011-10-12 07:44:40 +000042
Thomas Tsoufa3a7872013-10-17 21:23:34 -040043/* Number of running values use in noise average */
44#define NOISE_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000045
Thomas Tsouf0782732013-10-29 15:55:47 -040046TransceiverState::TransceiverState()
Tom Tsoua4d1a412014-11-25 15:46:56 -080047 : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
Thomas Tsouf0782732013-10-29 15:55:47 -040048{
49 for (int i = 0; i < 8; i++) {
50 chanType[i] = Transceiver::NONE;
51 fillerModulus[i] = 26;
52 chanResponse[i] = NULL;
53 DFEForward[i] = NULL;
54 DFEFeedback[i] = NULL;
55
56 for (int n = 0; n < 102; n++)
57 fillerTable[n][i] = NULL;
58 }
59}
60
61TransceiverState::~TransceiverState()
62{
63 for (int i = 0; i < 8; i++) {
64 delete chanResponse[i];
65 delete DFEForward[i];
66 delete DFEFeedback[i];
67
68 for (int n = 0; n < 102; n++)
69 delete fillerTable[n][i];
70 }
71}
72
Tom Tsou64ad7122015-05-19 18:26:31 -070073static BitVector *genRandNormalBurst(size_t tsc)
Thomas Tsouf0782732013-10-29 15:55:47 -040074{
Tom Tsou64ad7122015-05-19 18:26:31 -070075 if (tsc > 7)
76 return NULL;
Thomas Tsou15d743e2014-01-25 02:34:03 -050077
Tom Tsou64ad7122015-05-19 18:26:31 -070078 BitVector *bits = new BitVector(148);
Thomas Tsou15d743e2014-01-25 02:34:03 -050079
Tom Tsou64ad7122015-05-19 18:26:31 -070080 size_t i = 0;
81
82 /* Tail bits */
83 for (; i < 4; i++)
84 (*bits)[i] = 0;
85
86 /* Random bits */
87 for (; i < 61; i++)
88 (*bits)[i] = rand() % 2;
89
90 /* Training sequence */
Alexander Chemeris29660482015-05-24 19:13:38 -040091 for (int j = 0; i < 87; i++, j++)
92 (*bits)[i] = GSM::gTrainingSequence[tsc][j];
Tom Tsou64ad7122015-05-19 18:26:31 -070093
94 /* Random bits */
95 for (; i < 144; i++)
96 (*bits)[i] = rand() % 2;
97
98 /* Tail bits */
99 for (; i < 148; i++)
100 (*bits)[i] = 0;
101
102 return bits;
103}
104
105bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc)
106{
107 BitVector *bits;
108 signalVector *burst;
109
110 if ((sps != 1) && (sps != 4))
111 return false;
112
113 for (size_t n = 0; n < 8; n++) {
114 size_t guard = 8 + !(n % 4);
115 size_t len = sps == 4 ? 625 : 148 + guard;
116
117 for (size_t i = 0; i < 102; i++) {
118 switch (filler) {
119 case Transceiver::FILLER_DUMMY:
120 burst = modulateBurst(gDummyBurst, guard, sps);
121 break;
122 case Transceiver::FILLER_RAND:
123 bits = genRandNormalBurst(rtsc);
124 burst = modulateBurst(*bits, guard, sps);
125 delete bits;
126 break;
127 case Transceiver::FILLER_ZERO:
128 default:
129 burst = new signalVector(len);
130 }
131
132 scaleVector(*burst, scale);
133 fillerTable[i][n] = burst;
134 }
135
136 if (filler == Transceiver::FILLER_RAND)
137 chanType[n] = Transceiver::TSC;
Thomas Tsou15d743e2014-01-25 02:34:03 -0500138 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700139
140 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400141}
142
dburgessb3a0ca42011-10-12 07:44:40 +0000143Transceiver::Transceiver(int wBasePort,
Alexander Chemerisfdbf9142015-06-03 23:47:56 -0400144 const char *wTRXAddress,
145 size_t wSPS, size_t wChans,
146 GSM::Time wTransmitLatency,
147 RadioInterface *wRadioInterface,
148 double wRssiOffset)
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800149 : mBasePort(wBasePort), mAddr(wTRXAddress),
150 mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
151 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Alexander Chemerisfdbf9142015-06-03 23:47:56 -0400152 rssiOffset(wRssiOffset),
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800153 mSPSTx(wSPS), mSPSRx(1), mChans(wChans), mOn(false),
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700154 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000155{
dburgessb3a0ca42011-10-12 07:44:40 +0000156 txFullScale = mRadioInterface->fullScaleInputValue();
157 rxFullScale = mRadioInterface->fullScaleOutputValue();
dburgessb3a0ca42011-10-12 07:44:40 +0000158}
159
160Transceiver::~Transceiver()
161{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800162 stop();
163
dburgessb3a0ca42011-10-12 07:44:40 +0000164 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400165
Thomas Tsou204a9f12013-10-29 18:34:16 -0400166 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800167 mControlServiceLoopThreads[i]->cancel();
168 mControlServiceLoopThreads[i]->join();
169 delete mControlServiceLoopThreads[i];
170
Thomas Tsou204a9f12013-10-29 18:34:16 -0400171 mTxPriorityQueues[i].clear();
172 delete mCtrlSockets[i];
173 delete mDataSockets[i];
174 }
dburgessb3a0ca42011-10-12 07:44:40 +0000175}
Thomas Tsou83e06892013-08-20 16:10:01 -0400176
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800177/*
178 * Initialize transceiver
179 *
180 * Start or restart the control loop. Any further control is handled through the
181 * socket API. Randomize the central radio clock set the downlink burst
182 * counters. Note that the clock will not update until the radio starts, but we
183 * are still expected to report clock indications through control channel
184 * activity.
185 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700186bool Transceiver::init(int filler, size_t rtsc)
Thomas Tsou83e06892013-08-20 16:10:01 -0400187{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500188 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400189
Thomas Tsou204a9f12013-10-29 18:34:16 -0400190 if (!mChans) {
191 LOG(ALERT) << "No channels assigned";
192 return false;
193 }
194
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400195 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400196 LOG(ALERT) << "Failed to initialize signal processing library";
197 return false;
198 }
199
Thomas Tsou204a9f12013-10-29 18:34:16 -0400200 mDataSockets.resize(mChans);
201 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400202 mControlServiceLoopThreads.resize(mChans);
203 mTxPriorityQueueServiceLoopThreads.resize(mChans);
204 mRxServiceLoopThreads.resize(mChans);
205
206 mTxPriorityQueues.resize(mChans);
207 mReceiveFIFO.resize(mChans);
208 mStates.resize(mChans);
209
Thomas Tsouccb73e12014-04-15 17:41:28 -0400210 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700211 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400212 mStates[0].mRetrans = true;
213
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800214 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400215 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500216 c_srcport = mBasePort + 2 * i + 1;
217 c_dstport = mBasePort + 2 * i + 101;
218 d_srcport = mBasePort + 2 * i + 2;
219 d_dstport = mBasePort + 2 * i + 102;
220
221 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
222 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400223 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400224
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800225 /* Randomize the central clock */
226 GSM::Time startTime(random() % gHyperframe, 0);
227 mRadioInterface->getClock()->set(startTime);
228 mTransmitDeadlineClock = startTime;
229 mLastClockUpdateTime = startTime;
230 mLatencyUpdateTime = startTime;
231
232 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400233 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800234 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400235 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800236 mControlServiceLoopThreads[i]->start((void * (*)(void*))
237 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400238
Tom Tsou64ad7122015-05-19 18:26:31 -0700239 if (i && filler == FILLER_DUMMY)
240 filler = FILLER_ZERO;
241
242 mStates[i].init(filler, mSPSTx, txFullScale, rtsc);
Thomas Tsou83e06892013-08-20 16:10:01 -0400243 }
244
245 return true;
246}
dburgessb3a0ca42011-10-12 07:44:40 +0000247
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800248/*
249 * Start the transceiver
250 *
251 * Submit command(s) to the radio device to commence streaming samples and
252 * launch threads to handle sample I/O. Re-synchronize the transmit burst
253 * counters to the central radio clock here as well.
254 */
255bool Transceiver::start()
256{
257 ScopedLock lock(mLock);
258
259 if (mOn) {
260 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300261 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800262 }
263
264 LOG(NOTICE) << "Starting the transceiver";
265
266 GSM::Time time = mRadioInterface->getClock()->get();
267 mTransmitDeadlineClock = time;
268 mLastClockUpdateTime = time;
269 mLatencyUpdateTime = time;
270
271 if (!mRadioInterface->start()) {
272 LOG(ALERT) << "Device failed to start";
273 return false;
274 }
275
276 /* Device is running - launch I/O threads */
277 mRxLowerLoopThread = new Thread(32768);
278 mTxLowerLoopThread = new Thread(32768);
279 mTxLowerLoopThread->start((void * (*)(void*))
280 TxLowerLoopAdapter,(void*) this);
281 mRxLowerLoopThread->start((void * (*)(void*))
282 RxLowerLoopAdapter,(void*) this);
283
284 /* Launch uplink and downlink burst processing threads */
285 for (size_t i = 0; i < mChans; i++) {
286 TransceiverChannel *chan = new TransceiverChannel(this, i);
287 mRxServiceLoopThreads[i] = new Thread(32768);
288 mRxServiceLoopThreads[i]->start((void * (*)(void*))
289 RxUpperLoopAdapter, (void*) chan);
290
291 chan = new TransceiverChannel(this, i);
292 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
293 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
294 TxUpperLoopAdapter, (void*) chan);
295 }
296
297 writeClockInterface();
298 mOn = true;
299 return true;
300}
301
302/*
303 * Stop the transceiver
304 *
305 * Perform stopping by disabling receive streaming and issuing cancellation
306 * requests to running threads. Most threads will timeout and terminate once
307 * device is disabled, but the transmit loop may block waiting on the central
308 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
309 * makes it to the thread cancellation point.
310 */
311void Transceiver::stop()
312{
313 ScopedLock lock(mLock);
314
315 if (!mOn)
316 return;
317
318 LOG(NOTICE) << "Stopping the transceiver";
319 mTxLowerLoopThread->cancel();
320 mRxLowerLoopThread->cancel();
321
322 for (size_t i = 0; i < mChans; i++) {
323 mRxServiceLoopThreads[i]->cancel();
324 mTxPriorityQueueServiceLoopThreads[i]->cancel();
325 }
326
327 LOG(INFO) << "Stopping the device";
328 mRadioInterface->stop();
329
330 for (size_t i = 0; i < mChans; i++) {
331 mRxServiceLoopThreads[i]->join();
332 mTxPriorityQueueServiceLoopThreads[i]->join();
333 delete mRxServiceLoopThreads[i];
334 delete mTxPriorityQueueServiceLoopThreads[i];
335
336 mTxPriorityQueues[i].clear();
337 }
338
339 mTxLowerLoopThread->join();
340 mRxLowerLoopThread->join();
341 delete mTxLowerLoopThread;
342 delete mRxLowerLoopThread;
343
344 mOn = false;
345 LOG(NOTICE) << "Transceiver stopped";
346}
347
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500348void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400349 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000350{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500351 signalVector *burst;
352 radioVector *radio_burst;
353
Thomas Tsou204a9f12013-10-29 18:34:16 -0400354 if (chan >= mTxPriorityQueues.size()) {
355 LOG(ALERT) << "Invalid channel " << chan;
356 return;
357 }
358
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500359 if (wTime.TN() > 7) {
360 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
361 return;
362 }
363
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500364 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
365 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000366
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500367 radio_burst = new radioVector(wTime, burst);
368
369 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000370}
371
Thomas Tsou15d743e2014-01-25 02:34:03 -0500372void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
373{
374 int TN, modFN;
375 TransceiverState *state = &mStates[chan];
376
377 TN = burst->getTime().TN();
378 modFN = burst->getTime().FN() % state->fillerModulus[TN];
379
380 delete state->fillerTable[modFN][TN];
381 state->fillerTable[modFN][TN] = burst->getVector();
382 burst->setVector(NULL);
383}
384
dburgessb3a0ca42011-10-12 07:44:40 +0000385void Transceiver::pushRadioVector(GSM::Time &nowTime)
386{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400387 int TN, modFN;
388 radioVector *burst;
389 TransceiverState *state;
390 std::vector<signalVector *> bursts(mChans);
391 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500392 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000393
Thomas Tsou204a9f12013-10-29 18:34:16 -0400394 for (size_t i = 0; i < mChans; i ++) {
395 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000396
Thomas Tsou204a9f12013-10-29 18:34:16 -0400397 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
398 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500399 if (state->mRetrans)
400 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500401 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400402 }
403
404 TN = nowTime.TN();
405 modFN = nowTime.FN() % state->fillerModulus[TN];
406
407 bursts[i] = state->fillerTable[modFN][TN];
408 zeros[i] = state->chanType[TN] == NONE;
409
410 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500411 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500412
413 if (state->mRetrans) {
414 updateFillerTable(i, burst);
415 } else {
416 burst->setVector(NULL);
417 filler[i] = false;
418 }
419
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500420 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400421 }
dburgessb3a0ca42011-10-12 07:44:40 +0000422 }
423
Thomas Tsou204a9f12013-10-29 18:34:16 -0400424 mRadioInterface->driveTransmitRadio(bursts, zeros);
425
Thomas Tsou15d743e2014-01-25 02:34:03 -0500426 for (size_t i = 0; i < mChans; i++) {
427 if (!filler[i])
428 delete bursts[i];
429 }
dburgessb3a0ca42011-10-12 07:44:40 +0000430}
431
Thomas Tsou204a9f12013-10-29 18:34:16 -0400432void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000433{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400434 TransceiverState *state = &mStates[chan];
435
436 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000437 case NONE:
438 case I:
439 case II:
440 case III:
441 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400442 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000443 break;
444 case IV:
445 case VI:
446 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400447 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000448 break;
449 //case V:
450 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400451 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000452 break;
ttsoufc40a842013-06-09 22:38:18 +0000453 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400454 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000455 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000456 default:
457 break;
458 }
459}
460
461
Thomas Tsou204a9f12013-10-29 18:34:16 -0400462Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
463 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000464{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400465 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000466 unsigned burstTN = currTime.TN();
467 unsigned burstFN = currTime.FN();
468
Thomas Tsou204a9f12013-10-29 18:34:16 -0400469 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000470 case NONE:
471 return OFF;
472 break;
473 case FILL:
474 return IDLE;
475 break;
476 case I:
477 return TSC;
478 /*if (burstFN % 26 == 25)
479 return IDLE;
480 else
481 return TSC;*/
482 break;
483 case II:
ttsou20642972013-03-27 22:00:25 +0000484 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000485 break;
486 case III:
487 return TSC;
488 break;
489 case IV:
490 case VI:
491 return RACH;
492 break;
493 case V: {
494 int mod51 = burstFN % 51;
495 if ((mod51 <= 36) && (mod51 >= 14))
496 return RACH;
497 else if ((mod51 == 4) || (mod51 == 5))
498 return RACH;
499 else if ((mod51 == 45) || (mod51 == 46))
500 return RACH;
501 else
502 return TSC;
503 break;
504 }
505 case VII:
506 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
507 return IDLE;
508 else
509 return TSC;
510 break;
ttsoufc40a842013-06-09 22:38:18 +0000511 case XIII: {
512 int mod52 = burstFN % 52;
513 if ((mod52 == 12) || (mod52 == 38))
514 return RACH;
515 else if ((mod52 == 25) || (mod52 == 51))
516 return IDLE;
517 else
518 return TSC;
519 break;
520 }
dburgessb3a0ca42011-10-12 07:44:40 +0000521 case LOOPBACK:
522 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
523 return IDLE;
524 else
525 return TSC;
526 break;
527 default:
528 return OFF;
529 break;
530 }
dburgessb3a0ca42011-10-12 07:44:40 +0000531}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400532
Thomas Tsou30421a72013-11-13 23:14:48 -0500533/*
534 * Detect RACH synchronization sequence within a burst. No equalization
535 * is used or available on the RACH channel.
536 */
537bool Transceiver::detectRACH(TransceiverState *state,
538 signalVector &burst,
539 complex &amp, float &toa)
540{
541 float threshold = 6.0;
542
543 return detectRACHBurst(burst, threshold, mSPSRx, &amp, &toa);
544}
545
546/*
547 * Detect normal burst training sequence midamble. Update equalization
548 * state information and channel estimate if necessary. Equalization
549 * is currently disabled.
550 */
Thomas Tsoua0179e32013-11-14 15:52:04 -0500551bool Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
Thomas Tsou30421a72013-11-13 23:14:48 -0500552 complex &amp, float &toa, GSM::Time &time)
553{
554 int tn = time.TN();
555 float chanOffset, threshold = 5.0;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500556 bool noise, needDFE = false, estimateChan = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500557 double elapsed = time - state->chanEstimateTime[tn];
558 signalVector *chanResp;
559
560 /* Check equalization update state */
Thomas Tsoufb827d02013-11-16 16:14:12 -0500561 if (needDFE && ((elapsed > 50) || (!state->chanResponse[tn]))) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500562 delete state->DFEForward[tn];
563 delete state->DFEFeedback[tn];
564 state->DFEForward[tn] = NULL;
565 state->DFEFeedback[tn] = NULL;
566
567 estimateChan = true;
568 }
569
570 /* Detect normal burst midambles */
571 if (!analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, &amp,
572 &toa, mMaxExpectedDelay, estimateChan,
573 &chanResp, &chanOffset)) {
574 return false;
575 }
576
Thomas Tsoua0179e32013-11-14 15:52:04 -0500577 noise = state->mNoiseLev;
578 state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
Thomas Tsou30421a72013-11-13 23:14:48 -0500579
580 /* Set equalizer if unabled */
581 if (needDFE && estimateChan) {
582 state->chanResponse[tn] = chanResp;
583 state->chanRespOffset[tn] = chanOffset;
584 state->chanRespAmplitude[tn] = amp;
585
586 scaleVector(*chanResp, complex(1.0, 0.0) / amp);
587
588 designDFE(*chanResp, state->SNRestimate[tn],
589 7, &state->DFEForward[tn], &state->DFEFeedback[tn]);
590
591 state->chanEstimateTime[tn] = time;
592 }
593
594 return true;;
595}
596
597/*
598 * Demodulate GMSK burst using equalization if requested. Otherwise
599 * demodulate by direct rotation and soft slicing.
600 */
601SoftVector *Transceiver::demodulate(TransceiverState *state,
602 signalVector &burst, complex amp,
603 float toa, size_t tn, bool equalize)
604{
605 if (equalize) {
606 scaleVector(burst, complex(1.0, 0.0) / amp);
607 return equalizeBurst(burst,
608 toa - state->chanRespOffset[tn],
609 mSPSRx,
610 *state->DFEForward[tn],
611 *state->DFEFeedback[tn]);
612 }
613
614 return demodulateBurst(burst, mSPSRx, amp, toa);
615}
616
617/*
618 * Pull bursts from the FIFO and handle according to the slot
619 * and burst correlation type. Equalzation is currently disabled.
620 */
Alexander Chemerisfdbf9142015-06-03 23:47:56 -0400621SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI,
622 double &timingOffset, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000623{
Thomas Tsou30421a72013-11-13 23:14:48 -0500624 bool success, equalize = false;
625 complex amp;
626 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500627 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500628 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500629 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500630 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000631
Thomas Tsou30421a72013-11-13 23:14:48 -0500632 /* Blocking FIFO read */
633 radioVector *radio_burst = mReceiveFIFO[chan]->read();
634 if (!radio_burst)
635 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000636
Thomas Tsou30421a72013-11-13 23:14:48 -0500637 /* Set time and determine correlation type */
638 GSM::Time time = radio_burst->getTime();
639 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000640
Thomas Tsou30421a72013-11-13 23:14:48 -0500641 if ((type == OFF) || (type == IDLE)) {
642 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000643 return NULL;
644 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000645
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500646 /* Select the diversity channel with highest energy */
647 for (size_t i = 0; i < radio_burst->chans(); i++) {
648 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
649 if (pow > max) {
650 max = pow;
651 max_i = i;
652 }
653 avg += pow;
654 }
655
656 if (max_i < 0) {
657 LOG(ALERT) << "Received empty burst";
658 delete radio_burst;
659 return NULL;
660 }
661
Thomas Tsou30421a72013-11-13 23:14:48 -0500662 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500663 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500664 avg = sqrt(avg / radio_burst->chans());
Thomas Tsoua0179e32013-11-14 15:52:04 -0500665 state->mNoiseLev = state->mNoises.avg();
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400666
Thomas Tsou30421a72013-11-13 23:14:48 -0500667 /* Detect normal or RACH bursts */
668 if (type == TSC)
Thomas Tsoua0179e32013-11-14 15:52:04 -0500669 success = detectTSC(state, *burst, amp, toa, time);
Thomas Tsou30421a72013-11-13 23:14:48 -0500670 else
Thomas Tsoua0179e32013-11-14 15:52:04 -0500671 success = detectRACH(state, *burst, amp, toa);
Thomas Tsouf0782732013-10-29 15:55:47 -0400672
Tom Tsou577cd022015-05-18 13:57:54 -0700673 /* Update noise average if no bust detected or alert on error */
674 if (success <= 0) {
675 if (!success) {
676 state->mNoises.insert(avg);
677 } else if (success == -SIGERR_CLIP) {
678 LOG(ALERT) << "Clipping detected on RACH input";
679 } else if (success < 0) {
680 LOG(ALERT) << "Unhandled RACH error";
681 }
682
Thomas Tsou30421a72013-11-13 23:14:48 -0500683 delete radio_burst;
684 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000685 }
dburgessb3a0ca42011-10-12 07:44:40 +0000686
Thomas Tsou30421a72013-11-13 23:14:48 -0500687 /* Demodulate and set output info */
688 if (equalize && (type != TSC))
689 equalize = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000690
Thomas Tsoua0179e32013-11-14 15:52:04 -0500691 if (avg - state->mNoiseLev > 0.0)
692 bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500693
Thomas Tsou30421a72013-11-13 23:14:48 -0500694 wTime = time;
Alexander Chemerisfdbf9142015-06-03 23:47:56 -0400695 RSSI = 20.0 * log10(rxFullScale / avg);
696 timingOffset = toa / mSPSRx;
dburgessb3a0ca42011-10-12 07:44:40 +0000697
Thomas Tsou30421a72013-11-13 23:14:48 -0500698 delete radio_burst;
699
700 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000701}
702
dburgessb3a0ca42011-10-12 07:44:40 +0000703void Transceiver::reset()
704{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400705 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
706 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000707}
708
709
Thomas Tsou204a9f12013-10-29 18:34:16 -0400710void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000711{
dburgessb3a0ca42011-10-12 07:44:40 +0000712 int MAX_PACKET_LENGTH = 100;
713
714 // check control socket
715 char buffer[MAX_PACKET_LENGTH];
716 int msgLen = -1;
717 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400718
Thomas Tsou204a9f12013-10-29 18:34:16 -0400719 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000720
721 if (msgLen < 1) {
722 return;
723 }
724
725 char cmdcheck[4];
726 char command[MAX_PACKET_LENGTH];
727 char response[MAX_PACKET_LENGTH];
728
729 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400730
731 if (!chan)
732 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000733
734 if (strcmp(cmdcheck,"CMD")!=0) {
735 LOG(WARNING) << "bogus message on control interface";
736 return;
737 }
738 LOG(INFO) << "command is " << buffer;
739
740 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800741 stop();
742 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000743 }
744 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800745 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000746 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800747 else
dburgessb3a0ca42011-10-12 07:44:40 +0000748 sprintf(response,"RSP POWERON 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000749 }
750 else if (strcmp(command,"SETMAXDLY")==0) {
751 //set expected maximum time-of-arrival
752 int maxDelay;
753 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
754 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
755 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
756 }
757 else if (strcmp(command,"SETRXGAIN")==0) {
758 //set expected maximum time-of-arrival
759 int newGain;
760 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400761 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000762 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
763 }
764 else if (strcmp(command,"NOISELEV")==0) {
765 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500766 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000767 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500768 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000769 }
770 else {
771 sprintf(response,"RSP NOISELEV 1 0");
772 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500773 }
774 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800775 int power;
776 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
777 power = mRadioInterface->setPowerAttenuation(power, chan);
778 mStates[chan].mPower = power;
779 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000780 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500781 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800782 int power, step;
783 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
784 power = mStates[chan].mPower + step;
785 power = mRadioInterface->setPowerAttenuation(power, chan);
786 mStates[chan].mPower = power;
787 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000788 }
dburgessb3a0ca42011-10-12 07:44:40 +0000789 else if (strcmp(command,"RXTUNE")==0) {
790 // tune receiver
791 int freqKhz;
792 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500793 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400794 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000795 LOG(ALERT) << "RX failed to tune";
796 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
797 }
798 else
799 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
800 }
801 else if (strcmp(command,"TXTUNE")==0) {
802 // tune txmtr
803 int freqKhz;
804 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500805 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400806 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000807 LOG(ALERT) << "TX failed to tune";
808 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
809 }
810 else
811 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
812 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500813 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000814 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500815 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500816 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700817 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500818 sprintf(response, "RSP SETTSC 1 %d", TSC);
819 else if (chan && (TSC != mTSC))
820 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000821 else {
822 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400823 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400824 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000825 }
826 }
827 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700828 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000829 int corrCode;
830 int timeslot;
831 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
832 if ((timeslot < 0) || (timeslot > 7)) {
833 LOG(WARNING) << "bogus message on control interface";
834 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
835 return;
836 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400837 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
838 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000839 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
840
841 }
842 else {
843 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200844 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000845 }
846
Thomas Tsou204a9f12013-10-29 18:34:16 -0400847 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000848}
849
Thomas Tsou204a9f12013-10-29 18:34:16 -0400850bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000851{
dburgessb3a0ca42011-10-12 07:44:40 +0000852 char buffer[gSlotLen+50];
853
854 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400855 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000856
857 if (msgLen!=gSlotLen+1+4+1) {
858 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
859 return false;
860 }
861
862 int timeSlot = (int) buffer[0];
863 uint64_t frameNum = 0;
864 for (int i = 0; i < 4; i++)
865 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000866
dburgessb3a0ca42011-10-12 07:44:40 +0000867 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
868
869 int RSSI = (int) buffer[5];
870 static BitVector newBurst(gSlotLen);
871 BitVector::iterator itr = newBurst.begin();
872 char *bufferItr = buffer+6;
873 while (itr < newBurst.end())
874 *itr++ = *bufferItr++;
875
876 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400877
878 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000879
880 return true;
881
882
883}
dburgessb3a0ca42011-10-12 07:44:40 +0000884
Thomas Tsou204a9f12013-10-29 18:34:16 -0400885void Transceiver::driveReceiveRadio()
886{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400887 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400888 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400889 } else {
890 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
891 writeClockInterface();
892 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400893}
894
895void Transceiver::driveReceiveFIFO(size_t chan)
896{
dburgessb3a0ca42011-10-12 07:44:40 +0000897 SoftVector *rxBurst = NULL;
Alexander Chemerisfdbf9142015-06-03 23:47:56 -0400898 double RSSI; // in dBFS
899 double dBm; // in dBm
900 double TOA; // in symbols
901 int TOAint; // in 1/256 symbols
dburgessb3a0ca42011-10-12 07:44:40 +0000902 GSM::Time burstTime;
903
Thomas Tsou204a9f12013-10-29 18:34:16 -0400904 rxBurst = pullRadioVector(burstTime, RSSI, TOA, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000905
906 if (rxBurst) {
Alexander Chemerisfdbf9142015-06-03 23:47:56 -0400907 dBm = RSSI+rssiOffset;
908 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000909
Alexander Chemerisfdbf9142015-06-03 23:47:56 -0400910 LOG(DEBUG) << "burst parameters: " << std::fixed
911 << " time: " << burstTime
912 << " RSSI: " << std::setprecision(1) << RSSI
913 << " dBm: " << std::setprecision(1) << dBm
914 << " TOA: " << std::setprecision(2) << TOA
915 << " bits: " << *rxBurst;
dburgessb3a0ca42011-10-12 07:44:40 +0000916
917 char burstString[gSlotLen+10];
918 burstString[0] = burstTime.TN();
919 for (int i = 0; i < 4; i++)
920 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
Alexander Chemerisfdbf9142015-06-03 23:47:56 -0400921 burstString[5] = (int)dBm;
922 burstString[6] = (TOAint >> 8) & 0x0ff;
923 burstString[7] = TOAint & 0x0ff;
dburgessb3a0ca42011-10-12 07:44:40 +0000924 SoftVector::iterator burstItr = rxBurst->begin();
925
926 for (unsigned int i = 0; i < gSlotLen; i++) {
927 burstString[8+i] =(char) round((*burstItr++)*255.0);
928 }
929 burstString[gSlotLen+9] = '\0';
930 delete rxBurst;
931
Thomas Tsou204a9f12013-10-29 18:34:16 -0400932 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +0000933 }
dburgessb3a0ca42011-10-12 07:44:40 +0000934}
935
Thomas Tsou204a9f12013-10-29 18:34:16 -0400936void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000937{
938
939 /**
940 Features a carefully controlled latency mechanism, to
941 assure that transmit packets arrive at the radio/USRP
942 before they need to be transmitted.
943
944 Deadline clock indicates the burst that needs to be
945 pushed into the FIFO right NOW. If transmit queue does
946 not have a burst, stick in filler data.
947 */
948
949
950 RadioClock *radioClock = (mRadioInterface->getClock());
951
952 if (mOn) {
953 //radioClock->wait(); // wait until clock updates
954 LOG(DEBUG) << "radio clock " << radioClock->get();
955 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
956 // if underrun, then we're not providing bursts to radio/USRP fast
957 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400958 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000959 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000960 // only update latency at the defined frame interval
961 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000962 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
963 LOG(INFO) << "new latency: " << mTransmitLatency;
964 mLatencyUpdateTime = radioClock->get();
965 }
966 }
967 else {
968 // if underrun hasn't occurred in the last sec (216 frames) drop
969 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000970 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000971 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
972 mTransmitLatency.decTN();
973 LOG(INFO) << "reduced latency: " << mTransmitLatency;
974 mLatencyUpdateTime = radioClock->get();
975 }
976 }
977 }
dburgessb3a0ca42011-10-12 07:44:40 +0000978 }
dburgessb3a0ca42011-10-12 07:44:40 +0000979 // time to push burst to transmit FIFO
980 pushRadioVector(mTransmitDeadlineClock);
981 mTransmitDeadlineClock.incTN();
982 }
dburgessb3a0ca42011-10-12 07:44:40 +0000983 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400984
985 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000986}
987
988
989
990void Transceiver::writeClockInterface()
991{
992 char command[50];
993 // FIXME -- This should be adaptive.
994 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
995
996 LOG(INFO) << "ClockInterface: sending " << command;
997
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800998 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000999
1000 mLastClockUpdateTime = mTransmitDeadlineClock;
1001
Thomas Tsou92c16df2013-09-28 18:04:19 -04001002}
dburgessb3a0ca42011-10-12 07:44:40 +00001003
Thomas Tsou204a9f12013-10-29 18:34:16 -04001004void *RxUpperLoopAdapter(TransceiverChannel *chan)
1005{
1006 Transceiver *trx = chan->trx;
1007 size_t num = chan->num;
1008
1009 delete chan;
1010
Thomas Tsou7553aa92013-11-08 12:50:03 -05001011 trx->setPriority(0.42);
1012
Thomas Tsou204a9f12013-10-29 18:34:16 -04001013 while (1) {
1014 trx->driveReceiveFIFO(num);
1015 pthread_testcancel();
1016 }
1017 return NULL;
1018}
1019
1020void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001021{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001022 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001023
dburgessb3a0ca42011-10-12 07:44:40 +00001024 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001025 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001026 pthread_testcancel();
1027 }
1028 return NULL;
1029}
1030
Thomas Tsou204a9f12013-10-29 18:34:16 -04001031void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001032{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001033 transceiver->setPriority(0.44);
1034
Thomas Tsou92c16df2013-09-28 18:04:19 -04001035 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001036 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001037 pthread_testcancel();
1038 }
1039 return NULL;
1040}
1041
Thomas Tsou204a9f12013-10-29 18:34:16 -04001042void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001043{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001044 Transceiver *trx = chan->trx;
1045 size_t num = chan->num;
1046
1047 delete chan;
1048
dburgessb3a0ca42011-10-12 07:44:40 +00001049 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001050 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001051 pthread_testcancel();
1052 }
1053 return NULL;
1054}
1055
Thomas Tsou204a9f12013-10-29 18:34:16 -04001056void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001057{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001058 Transceiver *trx = chan->trx;
1059 size_t num = chan->num;
1060
1061 delete chan;
1062
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001063 trx->setPriority(0.40);
1064
dburgessb3a0ca42011-10-12 07:44:40 +00001065 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001066 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001067 pthread_testcancel();
1068 }
1069 return NULL;
1070}