blob: 0156580c3666df6371b0029617d5dbcb91ca8260 [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 Chemerise8905a02015-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 Chemerise8905a02015-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 Chemerise8905a02015-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 */
Alexander Chemeris954b1182015-06-04 15:39:41 -0400537int Transceiver::detectRACH(TransceiverState *state,
538 signalVector &burst,
539 complex &amp, float &toa)
Thomas Tsou30421a72013-11-13 23:14:48 -0500540{
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 */
Alexander Chemeris954b1182015-06-04 15:39:41 -0400551int Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
552 complex &amp, float &toa, GSM::Time &time)
Thomas Tsou30421a72013-11-13 23:14:48 -0500553{
Alexander Chemeris954b1182015-06-04 15:39:41 -0400554 int success;
Thomas Tsou30421a72013-11-13 23:14:48 -0500555 int tn = time.TN();
556 float chanOffset, threshold = 5.0;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500557 bool noise, needDFE = false, estimateChan = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500558 double elapsed = time - state->chanEstimateTime[tn];
559 signalVector *chanResp;
560
561 /* Check equalization update state */
Thomas Tsoufb827d02013-11-16 16:14:12 -0500562 if (needDFE && ((elapsed > 50) || (!state->chanResponse[tn]))) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500563 delete state->DFEForward[tn];
564 delete state->DFEFeedback[tn];
565 state->DFEForward[tn] = NULL;
566 state->DFEFeedback[tn] = NULL;
567
568 estimateChan = true;
569 }
570
571 /* Detect normal burst midambles */
Alexander Chemeris954b1182015-06-04 15:39:41 -0400572 success = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, &amp,
573 &toa, mMaxExpectedDelay, estimateChan,
574 &chanResp, &chanOffset);
575 if (success <= 0) {
576 return success;
Thomas Tsou30421a72013-11-13 23:14:48 -0500577 }
578
Thomas Tsoua0179e32013-11-14 15:52:04 -0500579 noise = state->mNoiseLev;
580 state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
Thomas Tsou30421a72013-11-13 23:14:48 -0500581
582 /* Set equalizer if unabled */
583 if (needDFE && estimateChan) {
584 state->chanResponse[tn] = chanResp;
585 state->chanRespOffset[tn] = chanOffset;
586 state->chanRespAmplitude[tn] = amp;
587
588 scaleVector(*chanResp, complex(1.0, 0.0) / amp);
589
590 designDFE(*chanResp, state->SNRestimate[tn],
591 7, &state->DFEForward[tn], &state->DFEFeedback[tn]);
592
593 state->chanEstimateTime[tn] = time;
594 }
595
Alexander Chemeris954b1182015-06-04 15:39:41 -0400596 return 1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500597}
598
599/*
600 * Demodulate GMSK burst using equalization if requested. Otherwise
601 * demodulate by direct rotation and soft slicing.
602 */
603SoftVector *Transceiver::demodulate(TransceiverState *state,
604 signalVector &burst, complex amp,
605 float toa, size_t tn, bool equalize)
606{
607 if (equalize) {
608 scaleVector(burst, complex(1.0, 0.0) / amp);
609 return equalizeBurst(burst,
610 toa - state->chanRespOffset[tn],
611 mSPSRx,
612 *state->DFEForward[tn],
613 *state->DFEFeedback[tn]);
614 }
615
616 return demodulateBurst(burst, mSPSRx, amp, toa);
617}
618
619/*
620 * Pull bursts from the FIFO and handle according to the slot
621 * and burst correlation type. Equalzation is currently disabled.
622 */
Alexander Chemerise8905a02015-06-03 23:47:56 -0400623SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400624 double &timingOffset, double &noise,
625 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000626{
Alexander Chemeris954b1182015-06-04 15:39:41 -0400627 int success;
628 bool equalize = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500629 complex amp;
630 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500631 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500632 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500633 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500634 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000635
Thomas Tsou30421a72013-11-13 23:14:48 -0500636 /* Blocking FIFO read */
637 radioVector *radio_burst = mReceiveFIFO[chan]->read();
638 if (!radio_burst)
639 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000640
Thomas Tsou30421a72013-11-13 23:14:48 -0500641 /* Set time and determine correlation type */
642 GSM::Time time = radio_burst->getTime();
643 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000644
Thomas Tsou30421a72013-11-13 23:14:48 -0500645 if ((type == OFF) || (type == IDLE)) {
646 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000647 return NULL;
648 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000649
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500650 /* Select the diversity channel with highest energy */
651 for (size_t i = 0; i < radio_burst->chans(); i++) {
652 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
653 if (pow > max) {
654 max = pow;
655 max_i = i;
656 }
657 avg += pow;
658 }
659
660 if (max_i < 0) {
661 LOG(ALERT) << "Received empty burst";
662 delete radio_burst;
663 return NULL;
664 }
665
Thomas Tsou30421a72013-11-13 23:14:48 -0500666 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500667 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500668 avg = sqrt(avg / radio_burst->chans());
Thomas Tsoua0179e32013-11-14 15:52:04 -0500669 state->mNoiseLev = state->mNoises.avg();
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400670
Thomas Tsou30421a72013-11-13 23:14:48 -0500671 /* Detect normal or RACH bursts */
672 if (type == TSC)
Thomas Tsoua0179e32013-11-14 15:52:04 -0500673 success = detectTSC(state, *burst, amp, toa, time);
Thomas Tsou30421a72013-11-13 23:14:48 -0500674 else
Thomas Tsoua0179e32013-11-14 15:52:04 -0500675 success = detectRACH(state, *burst, amp, toa);
Thomas Tsouf0782732013-10-29 15:55:47 -0400676
Tom Tsou577cd022015-05-18 13:57:54 -0700677 /* Update noise average if no bust detected or alert on error */
678 if (success <= 0) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400679 if (success == SIGERR_NONE) {
Tom Tsou577cd022015-05-18 13:57:54 -0700680 state->mNoises.insert(avg);
681 } else if (success == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400682 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
683 } else {
684 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700685 }
686
Thomas Tsou30421a72013-11-13 23:14:48 -0500687 delete radio_burst;
688 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000689 }
dburgessb3a0ca42011-10-12 07:44:40 +0000690
Thomas Tsou30421a72013-11-13 23:14:48 -0500691 /* Demodulate and set output info */
692 if (equalize && (type != TSC))
693 equalize = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000694
Alexander Chemeris2268c852015-06-07 01:10:11 -0400695 bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500696
Thomas Tsou30421a72013-11-13 23:14:48 -0500697 wTime = time;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400698 RSSI = 20.0 * log10(rxFullScale / avg);
699 timingOffset = toa / mSPSRx;
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400700 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
dburgessb3a0ca42011-10-12 07:44:40 +0000701
Thomas Tsou30421a72013-11-13 23:14:48 -0500702 delete radio_burst;
703
704 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000705}
706
dburgessb3a0ca42011-10-12 07:44:40 +0000707void Transceiver::reset()
708{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400709 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
710 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000711}
712
713
Thomas Tsou204a9f12013-10-29 18:34:16 -0400714void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000715{
dburgessb3a0ca42011-10-12 07:44:40 +0000716 int MAX_PACKET_LENGTH = 100;
717
718 // check control socket
719 char buffer[MAX_PACKET_LENGTH];
720 int msgLen = -1;
721 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400722
Thomas Tsou204a9f12013-10-29 18:34:16 -0400723 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000724
725 if (msgLen < 1) {
726 return;
727 }
728
729 char cmdcheck[4];
730 char command[MAX_PACKET_LENGTH];
731 char response[MAX_PACKET_LENGTH];
732
733 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400734
735 if (!chan)
736 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000737
738 if (strcmp(cmdcheck,"CMD")!=0) {
739 LOG(WARNING) << "bogus message on control interface";
740 return;
741 }
742 LOG(INFO) << "command is " << buffer;
743
744 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800745 stop();
746 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000747 }
748 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800749 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000750 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800751 else
dburgessb3a0ca42011-10-12 07:44:40 +0000752 sprintf(response,"RSP POWERON 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000753 }
754 else if (strcmp(command,"SETMAXDLY")==0) {
755 //set expected maximum time-of-arrival
756 int maxDelay;
757 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
758 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
759 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
760 }
761 else if (strcmp(command,"SETRXGAIN")==0) {
762 //set expected maximum time-of-arrival
763 int newGain;
764 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400765 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000766 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
767 }
768 else if (strcmp(command,"NOISELEV")==0) {
769 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500770 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000771 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500772 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000773 }
774 else {
775 sprintf(response,"RSP NOISELEV 1 0");
776 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500777 }
778 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800779 int power;
780 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
781 power = mRadioInterface->setPowerAttenuation(power, chan);
782 mStates[chan].mPower = power;
783 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000784 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500785 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800786 int power, step;
787 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
788 power = mStates[chan].mPower + step;
789 power = mRadioInterface->setPowerAttenuation(power, chan);
790 mStates[chan].mPower = power;
791 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000792 }
dburgessb3a0ca42011-10-12 07:44:40 +0000793 else if (strcmp(command,"RXTUNE")==0) {
794 // tune receiver
795 int freqKhz;
796 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500797 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400798 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000799 LOG(ALERT) << "RX failed to tune";
800 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
801 }
802 else
803 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
804 }
805 else if (strcmp(command,"TXTUNE")==0) {
806 // tune txmtr
807 int freqKhz;
808 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500809 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400810 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000811 LOG(ALERT) << "TX failed to tune";
812 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
813 }
814 else
815 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
816 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500817 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000818 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500819 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500820 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700821 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500822 sprintf(response, "RSP SETTSC 1 %d", TSC);
823 else if (chan && (TSC != mTSC))
824 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000825 else {
826 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400827 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400828 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000829 }
830 }
831 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700832 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000833 int corrCode;
834 int timeslot;
835 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
836 if ((timeslot < 0) || (timeslot > 7)) {
837 LOG(WARNING) << "bogus message on control interface";
838 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
839 return;
840 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400841 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
842 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000843 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
844
845 }
846 else {
847 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200848 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000849 }
850
Thomas Tsou204a9f12013-10-29 18:34:16 -0400851 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000852}
853
Thomas Tsou204a9f12013-10-29 18:34:16 -0400854bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000855{
dburgessb3a0ca42011-10-12 07:44:40 +0000856 char buffer[gSlotLen+50];
857
858 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400859 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000860
861 if (msgLen!=gSlotLen+1+4+1) {
862 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
863 return false;
864 }
865
866 int timeSlot = (int) buffer[0];
867 uint64_t frameNum = 0;
868 for (int i = 0; i < 4; i++)
869 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000870
dburgessb3a0ca42011-10-12 07:44:40 +0000871 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
872
873 int RSSI = (int) buffer[5];
874 static BitVector newBurst(gSlotLen);
875 BitVector::iterator itr = newBurst.begin();
876 char *bufferItr = buffer+6;
877 while (itr < newBurst.end())
878 *itr++ = *bufferItr++;
879
880 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400881
882 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000883
884 return true;
885
886
887}
dburgessb3a0ca42011-10-12 07:44:40 +0000888
Thomas Tsou204a9f12013-10-29 18:34:16 -0400889void Transceiver::driveReceiveRadio()
890{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400891 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400892 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400893 } else {
894 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
895 writeClockInterface();
896 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400897}
898
899void Transceiver::driveReceiveFIFO(size_t chan)
900{
dburgessb3a0ca42011-10-12 07:44:40 +0000901 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400902 double RSSI; // in dBFS
903 double dBm; // in dBm
904 double TOA; // in symbols
905 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400906 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000907 GSM::Time burstTime;
908
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400909 rxBurst = pullRadioVector(burstTime, RSSI, TOA, noise, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000910
911 if (rxBurst) {
Alexander Chemerise8905a02015-06-03 23:47:56 -0400912 dBm = RSSI+rssiOffset;
913 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000914
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400915 LOG(DEBUG) << std::fixed << std::right
916 << " time: " << burstTime
917 << " RSSI: " << std::setw(5) << std::setprecision(1) << RSSI << "dBFS/" << std::setw(6) << -dBm << "dBm"
918 << " noise: " << std::setw(5) << std::setprecision(1) << noise << "dBFS/" << std::setw(6) << -(noise+rssiOffset) << "dBm"
919 << " TOA: " << std::setw(5) << std::setprecision(2) << TOA
920 << " bits: " << *rxBurst;
921
dburgessb3a0ca42011-10-12 07:44:40 +0000922 char burstString[gSlotLen+10];
923 burstString[0] = burstTime.TN();
924 for (int i = 0; i < 4; i++)
925 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400926 burstString[5] = (int)dBm;
927 burstString[6] = (TOAint >> 8) & 0x0ff;
928 burstString[7] = TOAint & 0x0ff;
dburgessb3a0ca42011-10-12 07:44:40 +0000929 SoftVector::iterator burstItr = rxBurst->begin();
930
931 for (unsigned int i = 0; i < gSlotLen; i++) {
932 burstString[8+i] =(char) round((*burstItr++)*255.0);
933 }
934 burstString[gSlotLen+9] = '\0';
935 delete rxBurst;
936
Thomas Tsou204a9f12013-10-29 18:34:16 -0400937 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +0000938 }
dburgessb3a0ca42011-10-12 07:44:40 +0000939}
940
Thomas Tsou204a9f12013-10-29 18:34:16 -0400941void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000942{
943
944 /**
945 Features a carefully controlled latency mechanism, to
946 assure that transmit packets arrive at the radio/USRP
947 before they need to be transmitted.
948
949 Deadline clock indicates the burst that needs to be
950 pushed into the FIFO right NOW. If transmit queue does
951 not have a burst, stick in filler data.
952 */
953
954
955 RadioClock *radioClock = (mRadioInterface->getClock());
956
957 if (mOn) {
958 //radioClock->wait(); // wait until clock updates
959 LOG(DEBUG) << "radio clock " << radioClock->get();
960 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
961 // if underrun, then we're not providing bursts to radio/USRP fast
962 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400963 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000964 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000965 // only update latency at the defined frame interval
966 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000967 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
968 LOG(INFO) << "new latency: " << mTransmitLatency;
969 mLatencyUpdateTime = radioClock->get();
970 }
971 }
972 else {
973 // if underrun hasn't occurred in the last sec (216 frames) drop
974 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000975 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000976 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
977 mTransmitLatency.decTN();
978 LOG(INFO) << "reduced latency: " << mTransmitLatency;
979 mLatencyUpdateTime = radioClock->get();
980 }
981 }
982 }
dburgessb3a0ca42011-10-12 07:44:40 +0000983 }
dburgessb3a0ca42011-10-12 07:44:40 +0000984 // time to push burst to transmit FIFO
985 pushRadioVector(mTransmitDeadlineClock);
986 mTransmitDeadlineClock.incTN();
987 }
dburgessb3a0ca42011-10-12 07:44:40 +0000988 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400989
990 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000991}
992
993
994
995void Transceiver::writeClockInterface()
996{
997 char command[50];
998 // FIXME -- This should be adaptive.
999 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1000
1001 LOG(INFO) << "ClockInterface: sending " << command;
1002
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001003 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001004
1005 mLastClockUpdateTime = mTransmitDeadlineClock;
1006
Thomas Tsou92c16df2013-09-28 18:04:19 -04001007}
dburgessb3a0ca42011-10-12 07:44:40 +00001008
Thomas Tsou204a9f12013-10-29 18:34:16 -04001009void *RxUpperLoopAdapter(TransceiverChannel *chan)
1010{
1011 Transceiver *trx = chan->trx;
1012 size_t num = chan->num;
1013
1014 delete chan;
1015
Thomas Tsou7553aa92013-11-08 12:50:03 -05001016 trx->setPriority(0.42);
1017
Thomas Tsou204a9f12013-10-29 18:34:16 -04001018 while (1) {
1019 trx->driveReceiveFIFO(num);
1020 pthread_testcancel();
1021 }
1022 return NULL;
1023}
1024
1025void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001026{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001027 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001028
dburgessb3a0ca42011-10-12 07:44:40 +00001029 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001030 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001031 pthread_testcancel();
1032 }
1033 return NULL;
1034}
1035
Thomas Tsou204a9f12013-10-29 18:34:16 -04001036void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001037{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001038 transceiver->setPriority(0.44);
1039
Thomas Tsou92c16df2013-09-28 18:04:19 -04001040 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001041 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001042 pthread_testcancel();
1043 }
1044 return NULL;
1045}
1046
Thomas Tsou204a9f12013-10-29 18:34:16 -04001047void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001048{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001049 Transceiver *trx = chan->trx;
1050 size_t num = chan->num;
1051
1052 delete chan;
1053
dburgessb3a0ca42011-10-12 07:44:40 +00001054 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001055 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001056 pthread_testcancel();
1057 }
1058 return NULL;
1059}
1060
Thomas Tsou204a9f12013-10-29 18:34:16 -04001061void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001062{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001063 Transceiver *trx = chan->trx;
1064 size_t num = chan->num;
1065
1066 delete chan;
1067
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001068 trx->setPriority(0.40);
1069
dburgessb3a0ca42011-10-12 07:44:40 +00001070 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001071 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001072 pthread_testcancel();
1073 }
1074 return NULL;
1075}