blob: 4288f1d8609143cac64dc9cd2b7d7fc0eba82cac [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()
Tom Tsoua4d1a412014-11-25 15:46:56 -080046 : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
Thomas Tsouf0782732013-10-29 15:55:47 -040047{
48 for (int i = 0; i < 8; i++) {
49 chanType[i] = Transceiver::NONE;
50 fillerModulus[i] = 26;
51 chanResponse[i] = NULL;
52 DFEForward[i] = NULL;
53 DFEFeedback[i] = NULL;
54
55 for (int n = 0; n < 102; n++)
56 fillerTable[n][i] = NULL;
57 }
58}
59
60TransceiverState::~TransceiverState()
61{
62 for (int i = 0; i < 8; i++) {
63 delete chanResponse[i];
64 delete DFEForward[i];
65 delete DFEFeedback[i];
66
67 for (int n = 0; n < 102; n++)
68 delete fillerTable[n][i];
69 }
70}
71
Tom Tsou64ad7122015-05-19 18:26:31 -070072static BitVector *genRandNormalBurst(size_t tsc)
Thomas Tsouf0782732013-10-29 15:55:47 -040073{
Tom Tsou64ad7122015-05-19 18:26:31 -070074 if (tsc > 7)
75 return NULL;
Thomas Tsou15d743e2014-01-25 02:34:03 -050076
Tom Tsou64ad7122015-05-19 18:26:31 -070077 BitVector *bits = new BitVector(148);
Thomas Tsou15d743e2014-01-25 02:34:03 -050078
Tom Tsou64ad7122015-05-19 18:26:31 -070079 size_t i = 0;
80
81 /* Tail bits */
82 for (; i < 4; i++)
83 (*bits)[i] = 0;
84
85 /* Random bits */
86 for (; i < 61; i++)
87 (*bits)[i] = rand() % 2;
88
89 /* Training sequence */
Alexander Chemeris29660482015-05-24 19:13:38 -040090 for (int j = 0; i < 87; i++, j++)
91 (*bits)[i] = GSM::gTrainingSequence[tsc][j];
Tom Tsou64ad7122015-05-19 18:26:31 -070092
93 /* Random bits */
94 for (; i < 144; i++)
95 (*bits)[i] = rand() % 2;
96
97 /* Tail bits */
98 for (; i < 148; i++)
99 (*bits)[i] = 0;
100
101 return bits;
102}
103
104bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc)
105{
106 BitVector *bits;
107 signalVector *burst;
108
109 if ((sps != 1) && (sps != 4))
110 return false;
111
112 for (size_t n = 0; n < 8; n++) {
113 size_t guard = 8 + !(n % 4);
114 size_t len = sps == 4 ? 625 : 148 + guard;
115
116 for (size_t i = 0; i < 102; i++) {
117 switch (filler) {
118 case Transceiver::FILLER_DUMMY:
119 burst = modulateBurst(gDummyBurst, guard, sps);
120 break;
121 case Transceiver::FILLER_RAND:
122 bits = genRandNormalBurst(rtsc);
123 burst = modulateBurst(*bits, guard, sps);
124 delete bits;
125 break;
126 case Transceiver::FILLER_ZERO:
127 default:
128 burst = new signalVector(len);
129 }
130
131 scaleVector(*burst, scale);
132 fillerTable[i][n] = burst;
133 }
134
135 if (filler == Transceiver::FILLER_RAND)
136 chanType[n] = Transceiver::TSC;
Thomas Tsou15d743e2014-01-25 02:34:03 -0500137 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700138
139 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400140}
141
dburgessb3a0ca42011-10-12 07:44:40 +0000142Transceiver::Transceiver(int wBasePort,
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800143 const char *wTRXAddress,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400144 size_t wSPS, size_t wChans,
dburgessb3a0ca42011-10-12 07:44:40 +0000145 GSM::Time wTransmitLatency,
146 RadioInterface *wRadioInterface)
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800147 : mBasePort(wBasePort), mAddr(wTRXAddress),
148 mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
149 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
150 mSPSTx(wSPS), mSPSRx(1), mChans(wChans), mOn(false),
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700151 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000152{
dburgessb3a0ca42011-10-12 07:44:40 +0000153 txFullScale = mRadioInterface->fullScaleInputValue();
154 rxFullScale = mRadioInterface->fullScaleOutputValue();
dburgessb3a0ca42011-10-12 07:44:40 +0000155}
156
157Transceiver::~Transceiver()
158{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800159 stop();
160
dburgessb3a0ca42011-10-12 07:44:40 +0000161 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400162
Thomas Tsou204a9f12013-10-29 18:34:16 -0400163 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800164 mControlServiceLoopThreads[i]->cancel();
165 mControlServiceLoopThreads[i]->join();
166 delete mControlServiceLoopThreads[i];
167
Thomas Tsou204a9f12013-10-29 18:34:16 -0400168 mTxPriorityQueues[i].clear();
169 delete mCtrlSockets[i];
170 delete mDataSockets[i];
171 }
dburgessb3a0ca42011-10-12 07:44:40 +0000172}
Thomas Tsou83e06892013-08-20 16:10:01 -0400173
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800174/*
175 * Initialize transceiver
176 *
177 * Start or restart the control loop. Any further control is handled through the
178 * socket API. Randomize the central radio clock set the downlink burst
179 * counters. Note that the clock will not update until the radio starts, but we
180 * are still expected to report clock indications through control channel
181 * activity.
182 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700183bool Transceiver::init(int filler, size_t rtsc)
Thomas Tsou83e06892013-08-20 16:10:01 -0400184{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500185 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400186
Thomas Tsou204a9f12013-10-29 18:34:16 -0400187 if (!mChans) {
188 LOG(ALERT) << "No channels assigned";
189 return false;
190 }
191
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400192 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400193 LOG(ALERT) << "Failed to initialize signal processing library";
194 return false;
195 }
196
Thomas Tsou204a9f12013-10-29 18:34:16 -0400197 mDataSockets.resize(mChans);
198 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400199 mControlServiceLoopThreads.resize(mChans);
200 mTxPriorityQueueServiceLoopThreads.resize(mChans);
201 mRxServiceLoopThreads.resize(mChans);
202
203 mTxPriorityQueues.resize(mChans);
204 mReceiveFIFO.resize(mChans);
205 mStates.resize(mChans);
206
Thomas Tsouccb73e12014-04-15 17:41:28 -0400207 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700208 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400209 mStates[0].mRetrans = true;
210
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800211 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400212 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500213 c_srcport = mBasePort + 2 * i + 1;
214 c_dstport = mBasePort + 2 * i + 101;
215 d_srcport = mBasePort + 2 * i + 2;
216 d_dstport = mBasePort + 2 * i + 102;
217
218 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
219 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400220 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400221
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800222 /* Randomize the central clock */
223 GSM::Time startTime(random() % gHyperframe, 0);
224 mRadioInterface->getClock()->set(startTime);
225 mTransmitDeadlineClock = startTime;
226 mLastClockUpdateTime = startTime;
227 mLatencyUpdateTime = startTime;
228
229 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400230 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800231 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400232 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800233 mControlServiceLoopThreads[i]->start((void * (*)(void*))
234 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400235
Tom Tsou64ad7122015-05-19 18:26:31 -0700236 if (i && filler == FILLER_DUMMY)
237 filler = FILLER_ZERO;
238
239 mStates[i].init(filler, mSPSTx, txFullScale, rtsc);
Thomas Tsou83e06892013-08-20 16:10:01 -0400240 }
241
242 return true;
243}
dburgessb3a0ca42011-10-12 07:44:40 +0000244
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800245/*
246 * Start the transceiver
247 *
248 * Submit command(s) to the radio device to commence streaming samples and
249 * launch threads to handle sample I/O. Re-synchronize the transmit burst
250 * counters to the central radio clock here as well.
251 */
252bool Transceiver::start()
253{
254 ScopedLock lock(mLock);
255
256 if (mOn) {
257 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300258 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800259 }
260
261 LOG(NOTICE) << "Starting the transceiver";
262
263 GSM::Time time = mRadioInterface->getClock()->get();
264 mTransmitDeadlineClock = time;
265 mLastClockUpdateTime = time;
266 mLatencyUpdateTime = time;
267
268 if (!mRadioInterface->start()) {
269 LOG(ALERT) << "Device failed to start";
270 return false;
271 }
272
273 /* Device is running - launch I/O threads */
274 mRxLowerLoopThread = new Thread(32768);
275 mTxLowerLoopThread = new Thread(32768);
276 mTxLowerLoopThread->start((void * (*)(void*))
277 TxLowerLoopAdapter,(void*) this);
278 mRxLowerLoopThread->start((void * (*)(void*))
279 RxLowerLoopAdapter,(void*) this);
280
281 /* Launch uplink and downlink burst processing threads */
282 for (size_t i = 0; i < mChans; i++) {
283 TransceiverChannel *chan = new TransceiverChannel(this, i);
284 mRxServiceLoopThreads[i] = new Thread(32768);
285 mRxServiceLoopThreads[i]->start((void * (*)(void*))
286 RxUpperLoopAdapter, (void*) chan);
287
288 chan = new TransceiverChannel(this, i);
289 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
290 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
291 TxUpperLoopAdapter, (void*) chan);
292 }
293
294 writeClockInterface();
295 mOn = true;
296 return true;
297}
298
299/*
300 * Stop the transceiver
301 *
302 * Perform stopping by disabling receive streaming and issuing cancellation
303 * requests to running threads. Most threads will timeout and terminate once
304 * device is disabled, but the transmit loop may block waiting on the central
305 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
306 * makes it to the thread cancellation point.
307 */
308void Transceiver::stop()
309{
310 ScopedLock lock(mLock);
311
312 if (!mOn)
313 return;
314
315 LOG(NOTICE) << "Stopping the transceiver";
316 mTxLowerLoopThread->cancel();
317 mRxLowerLoopThread->cancel();
318
319 for (size_t i = 0; i < mChans; i++) {
320 mRxServiceLoopThreads[i]->cancel();
321 mTxPriorityQueueServiceLoopThreads[i]->cancel();
322 }
323
324 LOG(INFO) << "Stopping the device";
325 mRadioInterface->stop();
326
327 for (size_t i = 0; i < mChans; i++) {
328 mRxServiceLoopThreads[i]->join();
329 mTxPriorityQueueServiceLoopThreads[i]->join();
330 delete mRxServiceLoopThreads[i];
331 delete mTxPriorityQueueServiceLoopThreads[i];
332
333 mTxPriorityQueues[i].clear();
334 }
335
336 mTxLowerLoopThread->join();
337 mRxLowerLoopThread->join();
338 delete mTxLowerLoopThread;
339 delete mRxLowerLoopThread;
340
341 mOn = false;
342 LOG(NOTICE) << "Transceiver stopped";
343}
344
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500345void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400346 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000347{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500348 signalVector *burst;
349 radioVector *radio_burst;
350
Thomas Tsou204a9f12013-10-29 18:34:16 -0400351 if (chan >= mTxPriorityQueues.size()) {
352 LOG(ALERT) << "Invalid channel " << chan;
353 return;
354 }
355
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500356 if (wTime.TN() > 7) {
357 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
358 return;
359 }
360
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500361 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
362 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000363
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500364 radio_burst = new radioVector(wTime, burst);
365
366 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000367}
368
Thomas Tsou15d743e2014-01-25 02:34:03 -0500369void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
370{
371 int TN, modFN;
372 TransceiverState *state = &mStates[chan];
373
374 TN = burst->getTime().TN();
375 modFN = burst->getTime().FN() % state->fillerModulus[TN];
376
377 delete state->fillerTable[modFN][TN];
378 state->fillerTable[modFN][TN] = burst->getVector();
379 burst->setVector(NULL);
380}
381
dburgessb3a0ca42011-10-12 07:44:40 +0000382void Transceiver::pushRadioVector(GSM::Time &nowTime)
383{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400384 int TN, modFN;
385 radioVector *burst;
386 TransceiverState *state;
387 std::vector<signalVector *> bursts(mChans);
388 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500389 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000390
Thomas Tsou204a9f12013-10-29 18:34:16 -0400391 for (size_t i = 0; i < mChans; i ++) {
392 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000393
Thomas Tsou204a9f12013-10-29 18:34:16 -0400394 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
395 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500396 if (state->mRetrans)
397 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500398 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400399 }
400
401 TN = nowTime.TN();
402 modFN = nowTime.FN() % state->fillerModulus[TN];
403
404 bursts[i] = state->fillerTable[modFN][TN];
405 zeros[i] = state->chanType[TN] == NONE;
406
407 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500408 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500409
410 if (state->mRetrans) {
411 updateFillerTable(i, burst);
412 } else {
413 burst->setVector(NULL);
414 filler[i] = false;
415 }
416
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500417 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400418 }
dburgessb3a0ca42011-10-12 07:44:40 +0000419 }
420
Thomas Tsou204a9f12013-10-29 18:34:16 -0400421 mRadioInterface->driveTransmitRadio(bursts, zeros);
422
Thomas Tsou15d743e2014-01-25 02:34:03 -0500423 for (size_t i = 0; i < mChans; i++) {
424 if (!filler[i])
425 delete bursts[i];
426 }
dburgessb3a0ca42011-10-12 07:44:40 +0000427}
428
Thomas Tsou204a9f12013-10-29 18:34:16 -0400429void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000430{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400431 TransceiverState *state = &mStates[chan];
432
433 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000434 case NONE:
435 case I:
436 case II:
437 case III:
438 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400439 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000440 break;
441 case IV:
442 case VI:
443 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400444 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000445 break;
446 //case V:
447 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400448 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000449 break;
ttsoufc40a842013-06-09 22:38:18 +0000450 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400451 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000452 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000453 default:
454 break;
455 }
456}
457
458
Thomas Tsou204a9f12013-10-29 18:34:16 -0400459Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
460 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000461{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400462 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000463 unsigned burstTN = currTime.TN();
464 unsigned burstFN = currTime.FN();
465
Thomas Tsou204a9f12013-10-29 18:34:16 -0400466 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000467 case NONE:
468 return OFF;
469 break;
470 case FILL:
471 return IDLE;
472 break;
473 case I:
474 return TSC;
475 /*if (burstFN % 26 == 25)
476 return IDLE;
477 else
478 return TSC;*/
479 break;
480 case II:
ttsou20642972013-03-27 22:00:25 +0000481 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000482 break;
483 case III:
484 return TSC;
485 break;
486 case IV:
487 case VI:
488 return RACH;
489 break;
490 case V: {
491 int mod51 = burstFN % 51;
492 if ((mod51 <= 36) && (mod51 >= 14))
493 return RACH;
494 else if ((mod51 == 4) || (mod51 == 5))
495 return RACH;
496 else if ((mod51 == 45) || (mod51 == 46))
497 return RACH;
498 else
499 return TSC;
500 break;
501 }
502 case VII:
503 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
504 return IDLE;
505 else
506 return TSC;
507 break;
ttsoufc40a842013-06-09 22:38:18 +0000508 case XIII: {
509 int mod52 = burstFN % 52;
510 if ((mod52 == 12) || (mod52 == 38))
511 return RACH;
512 else if ((mod52 == 25) || (mod52 == 51))
513 return IDLE;
514 else
515 return TSC;
516 break;
517 }
dburgessb3a0ca42011-10-12 07:44:40 +0000518 case LOOPBACK:
519 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
520 return IDLE;
521 else
522 return TSC;
523 break;
524 default:
525 return OFF;
526 break;
527 }
dburgessb3a0ca42011-10-12 07:44:40 +0000528}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400529
Thomas Tsou30421a72013-11-13 23:14:48 -0500530/*
531 * Detect RACH synchronization sequence within a burst. No equalization
532 * is used or available on the RACH channel.
533 */
534bool Transceiver::detectRACH(TransceiverState *state,
535 signalVector &burst,
536 complex &amp, float &toa)
537{
538 float threshold = 6.0;
539
540 return detectRACHBurst(burst, threshold, mSPSRx, &amp, &toa);
541}
542
543/*
544 * Detect normal burst training sequence midamble. Update equalization
545 * state information and channel estimate if necessary. Equalization
546 * is currently disabled.
547 */
Thomas Tsoua0179e32013-11-14 15:52:04 -0500548bool Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
Thomas Tsou30421a72013-11-13 23:14:48 -0500549 complex &amp, float &toa, GSM::Time &time)
550{
551 int tn = time.TN();
552 float chanOffset, threshold = 5.0;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500553 bool noise, needDFE = false, estimateChan = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500554 double elapsed = time - state->chanEstimateTime[tn];
555 signalVector *chanResp;
556
557 /* Check equalization update state */
Thomas Tsoufb827d02013-11-16 16:14:12 -0500558 if (needDFE && ((elapsed > 50) || (!state->chanResponse[tn]))) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500559 delete state->DFEForward[tn];
560 delete state->DFEFeedback[tn];
561 state->DFEForward[tn] = NULL;
562 state->DFEFeedback[tn] = NULL;
563
564 estimateChan = true;
565 }
566
567 /* Detect normal burst midambles */
568 if (!analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, &amp,
569 &toa, mMaxExpectedDelay, estimateChan,
570 &chanResp, &chanOffset)) {
571 return false;
572 }
573
Thomas Tsoua0179e32013-11-14 15:52:04 -0500574 noise = state->mNoiseLev;
575 state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
Thomas Tsou30421a72013-11-13 23:14:48 -0500576
577 /* Set equalizer if unabled */
578 if (needDFE && estimateChan) {
579 state->chanResponse[tn] = chanResp;
580 state->chanRespOffset[tn] = chanOffset;
581 state->chanRespAmplitude[tn] = amp;
582
583 scaleVector(*chanResp, complex(1.0, 0.0) / amp);
584
585 designDFE(*chanResp, state->SNRestimate[tn],
586 7, &state->DFEForward[tn], &state->DFEFeedback[tn]);
587
588 state->chanEstimateTime[tn] = time;
589 }
590
591 return true;;
592}
593
594/*
595 * Demodulate GMSK burst using equalization if requested. Otherwise
596 * demodulate by direct rotation and soft slicing.
597 */
598SoftVector *Transceiver::demodulate(TransceiverState *state,
599 signalVector &burst, complex amp,
600 float toa, size_t tn, bool equalize)
601{
602 if (equalize) {
603 scaleVector(burst, complex(1.0, 0.0) / amp);
604 return equalizeBurst(burst,
605 toa - state->chanRespOffset[tn],
606 mSPSRx,
607 *state->DFEForward[tn],
608 *state->DFEFeedback[tn]);
609 }
610
611 return demodulateBurst(burst, mSPSRx, amp, toa);
612}
613
614/*
615 * Pull bursts from the FIFO and handle according to the slot
616 * and burst correlation type. Equalzation is currently disabled.
617 */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400618SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
619 int &timingOffset, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000620{
Thomas Tsou30421a72013-11-13 23:14:48 -0500621 bool success, equalize = false;
622 complex amp;
623 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500624 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500625 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500626 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500627 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000628
Thomas Tsou30421a72013-11-13 23:14:48 -0500629 /* Blocking FIFO read */
630 radioVector *radio_burst = mReceiveFIFO[chan]->read();
631 if (!radio_burst)
632 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000633
Thomas Tsou30421a72013-11-13 23:14:48 -0500634 /* Set time and determine correlation type */
635 GSM::Time time = radio_burst->getTime();
636 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000637
Thomas Tsou30421a72013-11-13 23:14:48 -0500638 if ((type == OFF) || (type == IDLE)) {
639 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000640 return NULL;
641 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000642
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500643 /* Select the diversity channel with highest energy */
644 for (size_t i = 0; i < radio_burst->chans(); i++) {
645 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
646 if (pow > max) {
647 max = pow;
648 max_i = i;
649 }
650 avg += pow;
651 }
652
653 if (max_i < 0) {
654 LOG(ALERT) << "Received empty burst";
655 delete radio_burst;
656 return NULL;
657 }
658
Thomas Tsou30421a72013-11-13 23:14:48 -0500659 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500660 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500661 avg = sqrt(avg / radio_burst->chans());
Thomas Tsoua0179e32013-11-14 15:52:04 -0500662 state->mNoiseLev = state->mNoises.avg();
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400663
Thomas Tsou30421a72013-11-13 23:14:48 -0500664 /* Detect normal or RACH bursts */
665 if (type == TSC)
Thomas Tsoua0179e32013-11-14 15:52:04 -0500666 success = detectTSC(state, *burst, amp, toa, time);
Thomas Tsou30421a72013-11-13 23:14:48 -0500667 else
Thomas Tsoua0179e32013-11-14 15:52:04 -0500668 success = detectRACH(state, *burst, amp, toa);
Thomas Tsouf0782732013-10-29 15:55:47 -0400669
Tom Tsou577cd022015-05-18 13:57:54 -0700670 /* Update noise average if no bust detected or alert on error */
671 if (success <= 0) {
672 if (!success) {
673 state->mNoises.insert(avg);
674 } else if (success == -SIGERR_CLIP) {
675 LOG(ALERT) << "Clipping detected on RACH input";
676 } else if (success < 0) {
677 LOG(ALERT) << "Unhandled RACH error";
678 }
679
Thomas Tsou30421a72013-11-13 23:14:48 -0500680 delete radio_burst;
681 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000682 }
dburgessb3a0ca42011-10-12 07:44:40 +0000683
Thomas Tsou30421a72013-11-13 23:14:48 -0500684 /* Demodulate and set output info */
685 if (equalize && (type != TSC))
686 equalize = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000687
Thomas Tsoua0179e32013-11-14 15:52:04 -0500688 if (avg - state->mNoiseLev > 0.0)
689 bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500690
Thomas Tsou30421a72013-11-13 23:14:48 -0500691 wTime = time;
692 RSSI = (int) floor(20.0 * log10(rxFullScale / avg));
693 timingOffset = (int) round(toa * 256.0 / mSPSRx);
dburgessb3a0ca42011-10-12 07:44:40 +0000694
Thomas Tsou30421a72013-11-13 23:14:48 -0500695 delete radio_burst;
696
697 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000698}
699
dburgessb3a0ca42011-10-12 07:44:40 +0000700void Transceiver::reset()
701{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400702 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
703 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000704}
705
706
Thomas Tsou204a9f12013-10-29 18:34:16 -0400707void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000708{
dburgessb3a0ca42011-10-12 07:44:40 +0000709 int MAX_PACKET_LENGTH = 100;
710
711 // check control socket
712 char buffer[MAX_PACKET_LENGTH];
713 int msgLen = -1;
714 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400715
Thomas Tsou204a9f12013-10-29 18:34:16 -0400716 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000717
718 if (msgLen < 1) {
719 return;
720 }
721
722 char cmdcheck[4];
723 char command[MAX_PACKET_LENGTH];
724 char response[MAX_PACKET_LENGTH];
725
726 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400727
728 if (!chan)
729 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000730
731 if (strcmp(cmdcheck,"CMD")!=0) {
732 LOG(WARNING) << "bogus message on control interface";
733 return;
734 }
735 LOG(INFO) << "command is " << buffer;
736
737 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800738 stop();
739 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000740 }
741 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800742 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000743 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800744 else
dburgessb3a0ca42011-10-12 07:44:40 +0000745 sprintf(response,"RSP POWERON 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000746 }
747 else if (strcmp(command,"SETMAXDLY")==0) {
748 //set expected maximum time-of-arrival
749 int maxDelay;
750 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
751 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
752 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
753 }
754 else if (strcmp(command,"SETRXGAIN")==0) {
755 //set expected maximum time-of-arrival
756 int newGain;
757 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400758 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000759 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
760 }
761 else if (strcmp(command,"NOISELEV")==0) {
762 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500763 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000764 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500765 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000766 }
767 else {
768 sprintf(response,"RSP NOISELEV 1 0");
769 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500770 }
771 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800772 int power;
773 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
774 power = mRadioInterface->setPowerAttenuation(power, chan);
775 mStates[chan].mPower = power;
776 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000777 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500778 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800779 int power, step;
780 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
781 power = mStates[chan].mPower + step;
782 power = mRadioInterface->setPowerAttenuation(power, chan);
783 mStates[chan].mPower = power;
784 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000785 }
dburgessb3a0ca42011-10-12 07:44:40 +0000786 else if (strcmp(command,"RXTUNE")==0) {
787 // tune receiver
788 int freqKhz;
789 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500790 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400791 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000792 LOG(ALERT) << "RX failed to tune";
793 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
794 }
795 else
796 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
797 }
798 else if (strcmp(command,"TXTUNE")==0) {
799 // tune txmtr
800 int freqKhz;
801 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500802 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400803 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000804 LOG(ALERT) << "TX failed to tune";
805 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
806 }
807 else
808 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
809 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500810 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000811 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500812 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500813 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700814 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500815 sprintf(response, "RSP SETTSC 1 %d", TSC);
816 else if (chan && (TSC != mTSC))
817 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000818 else {
819 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400820 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400821 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000822 }
823 }
824 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700825 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000826 int corrCode;
827 int timeslot;
828 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
829 if ((timeslot < 0) || (timeslot > 7)) {
830 LOG(WARNING) << "bogus message on control interface";
831 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
832 return;
833 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400834 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
835 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000836 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
837
838 }
839 else {
840 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200841 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000842 }
843
Thomas Tsou204a9f12013-10-29 18:34:16 -0400844 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000845}
846
Thomas Tsou204a9f12013-10-29 18:34:16 -0400847bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000848{
dburgessb3a0ca42011-10-12 07:44:40 +0000849 char buffer[gSlotLen+50];
850
851 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400852 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000853
854 if (msgLen!=gSlotLen+1+4+1) {
855 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
856 return false;
857 }
858
859 int timeSlot = (int) buffer[0];
860 uint64_t frameNum = 0;
861 for (int i = 0; i < 4; i++)
862 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000863
dburgessb3a0ca42011-10-12 07:44:40 +0000864 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
865
866 int RSSI = (int) buffer[5];
867 static BitVector newBurst(gSlotLen);
868 BitVector::iterator itr = newBurst.begin();
869 char *bufferItr = buffer+6;
870 while (itr < newBurst.end())
871 *itr++ = *bufferItr++;
872
873 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400874
875 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000876
877 return true;
878
879
880}
dburgessb3a0ca42011-10-12 07:44:40 +0000881
Thomas Tsou204a9f12013-10-29 18:34:16 -0400882void Transceiver::driveReceiveRadio()
883{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400884 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400885 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400886 } else {
887 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
888 writeClockInterface();
889 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400890}
891
892void Transceiver::driveReceiveFIFO(size_t chan)
893{
dburgessb3a0ca42011-10-12 07:44:40 +0000894 SoftVector *rxBurst = NULL;
895 int RSSI;
896 int TOA; // in 1/256 of a symbol
897 GSM::Time burstTime;
898
Thomas Tsou204a9f12013-10-29 18:34:16 -0400899 rxBurst = pullRadioVector(burstTime, RSSI, TOA, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000900
901 if (rxBurst) {
902
903 LOG(DEBUG) << "burst parameters: "
904 << " time: " << burstTime
905 << " RSSI: " << RSSI
906 << " TOA: " << TOA
907 << " bits: " << *rxBurst;
908
909 char burstString[gSlotLen+10];
910 burstString[0] = burstTime.TN();
911 for (int i = 0; i < 4; i++)
912 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
913 burstString[5] = RSSI;
914 burstString[6] = (TOA >> 8) & 0x0ff;
915 burstString[7] = TOA & 0x0ff;
916 SoftVector::iterator burstItr = rxBurst->begin();
917
918 for (unsigned int i = 0; i < gSlotLen; i++) {
919 burstString[8+i] =(char) round((*burstItr++)*255.0);
920 }
921 burstString[gSlotLen+9] = '\0';
922 delete rxBurst;
923
Thomas Tsou204a9f12013-10-29 18:34:16 -0400924 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +0000925 }
dburgessb3a0ca42011-10-12 07:44:40 +0000926}
927
Thomas Tsou204a9f12013-10-29 18:34:16 -0400928void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000929{
930
931 /**
932 Features a carefully controlled latency mechanism, to
933 assure that transmit packets arrive at the radio/USRP
934 before they need to be transmitted.
935
936 Deadline clock indicates the burst that needs to be
937 pushed into the FIFO right NOW. If transmit queue does
938 not have a burst, stick in filler data.
939 */
940
941
942 RadioClock *radioClock = (mRadioInterface->getClock());
943
944 if (mOn) {
945 //radioClock->wait(); // wait until clock updates
946 LOG(DEBUG) << "radio clock " << radioClock->get();
947 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
948 // if underrun, then we're not providing bursts to radio/USRP fast
949 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400950 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000951 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000952 // only update latency at the defined frame interval
953 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000954 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
955 LOG(INFO) << "new latency: " << mTransmitLatency;
956 mLatencyUpdateTime = radioClock->get();
957 }
958 }
959 else {
960 // if underrun hasn't occurred in the last sec (216 frames) drop
961 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000962 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000963 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
964 mTransmitLatency.decTN();
965 LOG(INFO) << "reduced latency: " << mTransmitLatency;
966 mLatencyUpdateTime = radioClock->get();
967 }
968 }
969 }
dburgessb3a0ca42011-10-12 07:44:40 +0000970 }
dburgessb3a0ca42011-10-12 07:44:40 +0000971 // time to push burst to transmit FIFO
972 pushRadioVector(mTransmitDeadlineClock);
973 mTransmitDeadlineClock.incTN();
974 }
dburgessb3a0ca42011-10-12 07:44:40 +0000975 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400976
977 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000978}
979
980
981
982void Transceiver::writeClockInterface()
983{
984 char command[50];
985 // FIXME -- This should be adaptive.
986 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
987
988 LOG(INFO) << "ClockInterface: sending " << command;
989
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800990 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000991
992 mLastClockUpdateTime = mTransmitDeadlineClock;
993
Thomas Tsou92c16df2013-09-28 18:04:19 -0400994}
dburgessb3a0ca42011-10-12 07:44:40 +0000995
Thomas Tsou204a9f12013-10-29 18:34:16 -0400996void *RxUpperLoopAdapter(TransceiverChannel *chan)
997{
998 Transceiver *trx = chan->trx;
999 size_t num = chan->num;
1000
1001 delete chan;
1002
Thomas Tsou7553aa92013-11-08 12:50:03 -05001003 trx->setPriority(0.42);
1004
Thomas Tsou204a9f12013-10-29 18:34:16 -04001005 while (1) {
1006 trx->driveReceiveFIFO(num);
1007 pthread_testcancel();
1008 }
1009 return NULL;
1010}
1011
1012void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001013{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001014 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001015
dburgessb3a0ca42011-10-12 07:44:40 +00001016 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001017 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001018 pthread_testcancel();
1019 }
1020 return NULL;
1021}
1022
Thomas Tsou204a9f12013-10-29 18:34:16 -04001023void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001024{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001025 transceiver->setPriority(0.44);
1026
Thomas Tsou92c16df2013-09-28 18:04:19 -04001027 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001028 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001029 pthread_testcancel();
1030 }
1031 return NULL;
1032}
1033
Thomas Tsou204a9f12013-10-29 18:34:16 -04001034void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001035{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001036 Transceiver *trx = chan->trx;
1037 size_t num = chan->num;
1038
1039 delete chan;
1040
dburgessb3a0ca42011-10-12 07:44:40 +00001041 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001042 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001043 pthread_testcancel();
1044 }
1045 return NULL;
1046}
1047
Thomas Tsou204a9f12013-10-29 18:34:16 -04001048void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001049{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001050 Transceiver *trx = chan->trx;
1051 size_t num = chan->num;
1052
1053 delete chan;
1054
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001055 trx->setPriority(0.40);
1056
dburgessb3a0ca42011-10-12 07:44:40 +00001057 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001058 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001059 pthread_testcancel();
1060 }
1061 return NULL;
1062}