blob: f5729872c0de5ceb41d1869b6b0113d3b37e252f [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 */
Alexander Chemerisded68da2015-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
Alexander Chemeris03095162015-06-09 20:52:11 -0400543 return detectRACHBurst(burst, threshold, mSPSRx, amp, toa);
Thomas Tsou30421a72013-11-13 23:14:48 -0500544}
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 Chemerisded68da2015-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 Chemerisded68da2015-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;
Alexander Chemeris34e5a382015-06-10 22:18:31 -0400557 bool 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 Chemeris03095162015-06-09 20:52:11 -0400572 success = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, amp,
573 toa, mMaxExpectedDelay, estimateChan,
Alexander Chemerisded68da2015-06-04 15:39:41 -0400574 &chanResp, &chanOffset);
575 if (success <= 0) {
576 return success;
Thomas Tsou30421a72013-11-13 23:14:48 -0500577 }
578
Thomas Tsou30421a72013-11-13 23:14:48 -0500579 /* Set equalizer if unabled */
580 if (needDFE && estimateChan) {
Alexander Chemeris34e5a382015-06-10 22:18:31 -0400581 float noise = state->mNoiseLev;
582 state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
583
Thomas Tsou30421a72013-11-13 23:14:48 -0500584 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 Chemerisded68da2015-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 Chemerisf0d8a582015-06-08 22:46:38 -0400623SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemeris37bbfa22015-06-04 00:14:51 -0400624 double &timingOffset, double &noise,
625 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000626{
Alexander Chemerisded68da2015-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];
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400635 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000636
Thomas Tsou30421a72013-11-13 23:14:48 -0500637 /* Blocking FIFO read */
638 radioVector *radio_burst = mReceiveFIFO[chan]->read();
639 if (!radio_burst)
640 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000641
Thomas Tsou30421a72013-11-13 23:14:48 -0500642 /* Set time and determine correlation type */
643 GSM::Time time = radio_burst->getTime();
644 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000645
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400646 /* No processing if the timeslot is off.
647 * Not even power level or noise calculation. */
648 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500649 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000650 return NULL;
651 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000652
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500653 /* Select the diversity channel with highest energy */
654 for (size_t i = 0; i < radio_burst->chans(); i++) {
655 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
656 if (pow > max) {
657 max = pow;
658 max_i = i;
659 }
660 avg += pow;
661 }
662
663 if (max_i < 0) {
664 LOG(ALERT) << "Received empty burst";
665 delete radio_burst;
666 return NULL;
667 }
668
Thomas Tsou30421a72013-11-13 23:14:48 -0500669 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500670 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500671 avg = sqrt(avg / radio_burst->chans());
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400672
673 wTime = time;
674 RSSI = 20.0 * log10(rxFullScale / avg);
675
676 /* RSSI estimation are valid */
677 isRssiValid = true;
678
679 if (type == IDLE) {
680 /* Update noise levels */
681 state->mNoises.insert(avg);
682 state->mNoiseLev = state->mNoises.avg();
683 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
684
685 delete radio_burst;
686 return NULL;
687 } else {
688 /* Do not update noise levels */
689 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
690 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400691
Thomas Tsou30421a72013-11-13 23:14:48 -0500692 /* Detect normal or RACH bursts */
693 if (type == TSC)
Thomas Tsoua0179e32013-11-14 15:52:04 -0500694 success = detectTSC(state, *burst, amp, toa, time);
Thomas Tsou30421a72013-11-13 23:14:48 -0500695 else
Thomas Tsoua0179e32013-11-14 15:52:04 -0500696 success = detectRACH(state, *burst, amp, toa);
Thomas Tsouf0782732013-10-29 15:55:47 -0400697
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400698 /* Alert an error and exit */
Tom Tsou577cd022015-05-18 13:57:54 -0700699 if (success <= 0) {
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400700 if (success == -SIGERR_CLIP) {
Alexander Chemerisded68da2015-06-04 15:39:41 -0400701 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400702 } else if (success != SIGERR_NONE) {
Alexander Chemerisded68da2015-06-04 15:39:41 -0400703 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700704 }
705
Thomas Tsou30421a72013-11-13 23:14:48 -0500706 delete radio_burst;
707 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000708 }
dburgessb3a0ca42011-10-12 07:44:40 +0000709
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400710 timingOffset = toa / mSPSRx;
711
Thomas Tsou30421a72013-11-13 23:14:48 -0500712 /* Demodulate and set output info */
713 if (equalize && (type != TSC))
714 equalize = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000715
Alexander Chemeris37b445d2015-06-07 01:10:11 -0400716 bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500717
Thomas Tsou30421a72013-11-13 23:14:48 -0500718 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500719 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000720}
721
dburgessb3a0ca42011-10-12 07:44:40 +0000722void Transceiver::reset()
723{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400724 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
725 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000726}
727
728
Thomas Tsou204a9f12013-10-29 18:34:16 -0400729void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000730{
dburgessb3a0ca42011-10-12 07:44:40 +0000731 int MAX_PACKET_LENGTH = 100;
732
733 // check control socket
734 char buffer[MAX_PACKET_LENGTH];
735 int msgLen = -1;
736 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400737
Thomas Tsou204a9f12013-10-29 18:34:16 -0400738 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000739
740 if (msgLen < 1) {
741 return;
742 }
743
744 char cmdcheck[4];
745 char command[MAX_PACKET_LENGTH];
746 char response[MAX_PACKET_LENGTH];
747
748 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400749
750 if (!chan)
751 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000752
753 if (strcmp(cmdcheck,"CMD")!=0) {
754 LOG(WARNING) << "bogus message on control interface";
755 return;
756 }
757 LOG(INFO) << "command is " << buffer;
758
759 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800760 stop();
761 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000762 }
763 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800764 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000765 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800766 else
dburgessb3a0ca42011-10-12 07:44:40 +0000767 sprintf(response,"RSP POWERON 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000768 }
769 else if (strcmp(command,"SETMAXDLY")==0) {
770 //set expected maximum time-of-arrival
771 int maxDelay;
772 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
773 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
774 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
775 }
776 else if (strcmp(command,"SETRXGAIN")==0) {
777 //set expected maximum time-of-arrival
778 int newGain;
779 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400780 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000781 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
782 }
783 else if (strcmp(command,"NOISELEV")==0) {
784 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500785 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000786 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500787 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000788 }
789 else {
790 sprintf(response,"RSP NOISELEV 1 0");
791 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500792 }
793 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800794 int power;
795 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
796 power = mRadioInterface->setPowerAttenuation(power, chan);
797 mStates[chan].mPower = power;
798 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000799 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500800 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800801 int power, step;
802 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
803 power = mStates[chan].mPower + step;
804 power = mRadioInterface->setPowerAttenuation(power, chan);
805 mStates[chan].mPower = power;
806 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000807 }
dburgessb3a0ca42011-10-12 07:44:40 +0000808 else if (strcmp(command,"RXTUNE")==0) {
809 // tune receiver
810 int freqKhz;
811 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500812 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400813 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000814 LOG(ALERT) << "RX failed to tune";
815 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
816 }
817 else
818 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
819 }
820 else if (strcmp(command,"TXTUNE")==0) {
821 // tune txmtr
822 int freqKhz;
823 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500824 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400825 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000826 LOG(ALERT) << "TX failed to tune";
827 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
828 }
829 else
830 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
831 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500832 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000833 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500834 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500835 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700836 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500837 sprintf(response, "RSP SETTSC 1 %d", TSC);
838 else if (chan && (TSC != mTSC))
839 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000840 else {
841 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400842 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400843 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000844 }
845 }
846 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700847 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000848 int corrCode;
849 int timeslot;
850 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
851 if ((timeslot < 0) || (timeslot > 7)) {
852 LOG(WARNING) << "bogus message on control interface";
853 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
854 return;
855 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400856 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
857 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000858 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
859
860 }
861 else {
862 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200863 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000864 }
865
Thomas Tsou204a9f12013-10-29 18:34:16 -0400866 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000867}
868
Thomas Tsou204a9f12013-10-29 18:34:16 -0400869bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000870{
dburgessb3a0ca42011-10-12 07:44:40 +0000871 char buffer[gSlotLen+50];
872
873 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400874 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000875
876 if (msgLen!=gSlotLen+1+4+1) {
877 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
878 return false;
879 }
880
881 int timeSlot = (int) buffer[0];
882 uint64_t frameNum = 0;
883 for (int i = 0; i < 4; i++)
884 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000885
dburgessb3a0ca42011-10-12 07:44:40 +0000886 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
887
888 int RSSI = (int) buffer[5];
889 static BitVector newBurst(gSlotLen);
890 BitVector::iterator itr = newBurst.begin();
891 char *bufferItr = buffer+6;
892 while (itr < newBurst.end())
893 *itr++ = *bufferItr++;
894
895 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400896
897 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000898
899 return true;
900
901
902}
dburgessb3a0ca42011-10-12 07:44:40 +0000903
Thomas Tsou204a9f12013-10-29 18:34:16 -0400904void Transceiver::driveReceiveRadio()
905{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400906 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400907 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400908 } else {
909 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
910 writeClockInterface();
911 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400912}
913
914void Transceiver::driveReceiveFIFO(size_t chan)
915{
dburgessb3a0ca42011-10-12 07:44:40 +0000916 SoftVector *rxBurst = NULL;
Alexander Chemerisfdbf9142015-06-03 23:47:56 -0400917 double RSSI; // in dBFS
918 double dBm; // in dBm
919 double TOA; // in symbols
920 int TOAint; // in 1/256 symbols
Alexander Chemeris37bbfa22015-06-04 00:14:51 -0400921 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000922 GSM::Time burstTime;
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400923 bool isRssiValid; // are RSSI, noise and burstTime valid
dburgessb3a0ca42011-10-12 07:44:40 +0000924
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400925 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000926
927 if (rxBurst) {
Alexander Chemerisfdbf9142015-06-03 23:47:56 -0400928 dBm = RSSI+rssiOffset;
929 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000930
Alexander Chemeris37bbfa22015-06-04 00:14:51 -0400931 LOG(DEBUG) << std::fixed << std::right
932 << " time: " << burstTime
933 << " RSSI: " << std::setw(5) << std::setprecision(1) << RSSI << "dBFS/" << std::setw(6) << -dBm << "dBm"
934 << " noise: " << std::setw(5) << std::setprecision(1) << noise << "dBFS/" << std::setw(6) << -(noise+rssiOffset) << "dBm"
935 << " TOA: " << std::setw(5) << std::setprecision(2) << TOA
936 << " bits: " << *rxBurst;
937
dburgessb3a0ca42011-10-12 07:44:40 +0000938 char burstString[gSlotLen+10];
939 burstString[0] = burstTime.TN();
940 for (int i = 0; i < 4; i++)
941 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
Alexander Chemerisfdbf9142015-06-03 23:47:56 -0400942 burstString[5] = (int)dBm;
943 burstString[6] = (TOAint >> 8) & 0x0ff;
944 burstString[7] = TOAint & 0x0ff;
dburgessb3a0ca42011-10-12 07:44:40 +0000945 SoftVector::iterator burstItr = rxBurst->begin();
946
947 for (unsigned int i = 0; i < gSlotLen; i++) {
948 burstString[8+i] =(char) round((*burstItr++)*255.0);
949 }
950 burstString[gSlotLen+9] = '\0';
951 delete rxBurst;
952
Thomas Tsou204a9f12013-10-29 18:34:16 -0400953 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +0000954 }
dburgessb3a0ca42011-10-12 07:44:40 +0000955}
956
Thomas Tsou204a9f12013-10-29 18:34:16 -0400957void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000958{
959
960 /**
961 Features a carefully controlled latency mechanism, to
962 assure that transmit packets arrive at the radio/USRP
963 before they need to be transmitted.
964
965 Deadline clock indicates the burst that needs to be
966 pushed into the FIFO right NOW. If transmit queue does
967 not have a burst, stick in filler data.
968 */
969
970
971 RadioClock *radioClock = (mRadioInterface->getClock());
972
973 if (mOn) {
974 //radioClock->wait(); // wait until clock updates
975 LOG(DEBUG) << "radio clock " << radioClock->get();
976 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
977 // if underrun, then we're not providing bursts to radio/USRP fast
978 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400979 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000980 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000981 // only update latency at the defined frame interval
982 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000983 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
984 LOG(INFO) << "new latency: " << mTransmitLatency;
985 mLatencyUpdateTime = radioClock->get();
986 }
987 }
988 else {
989 // if underrun hasn't occurred in the last sec (216 frames) drop
990 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000991 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000992 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
993 mTransmitLatency.decTN();
994 LOG(INFO) << "reduced latency: " << mTransmitLatency;
995 mLatencyUpdateTime = radioClock->get();
996 }
997 }
998 }
dburgessb3a0ca42011-10-12 07:44:40 +0000999 }
dburgessb3a0ca42011-10-12 07:44:40 +00001000 // time to push burst to transmit FIFO
1001 pushRadioVector(mTransmitDeadlineClock);
1002 mTransmitDeadlineClock.incTN();
1003 }
dburgessb3a0ca42011-10-12 07:44:40 +00001004 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001005
1006 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001007}
1008
1009
1010
1011void Transceiver::writeClockInterface()
1012{
1013 char command[50];
1014 // FIXME -- This should be adaptive.
1015 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1016
1017 LOG(INFO) << "ClockInterface: sending " << command;
1018
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001019 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001020
1021 mLastClockUpdateTime = mTransmitDeadlineClock;
1022
Thomas Tsou92c16df2013-09-28 18:04:19 -04001023}
dburgessb3a0ca42011-10-12 07:44:40 +00001024
Thomas Tsou204a9f12013-10-29 18:34:16 -04001025void *RxUpperLoopAdapter(TransceiverChannel *chan)
1026{
1027 Transceiver *trx = chan->trx;
1028 size_t num = chan->num;
1029
1030 delete chan;
1031
Thomas Tsou7553aa92013-11-08 12:50:03 -05001032 trx->setPriority(0.42);
1033
Thomas Tsou204a9f12013-10-29 18:34:16 -04001034 while (1) {
1035 trx->driveReceiveFIFO(num);
1036 pthread_testcancel();
1037 }
1038 return NULL;
1039}
1040
1041void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001042{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001043 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001044
dburgessb3a0ca42011-10-12 07:44:40 +00001045 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001046 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001047 pthread_testcancel();
1048 }
1049 return NULL;
1050}
1051
Thomas Tsou204a9f12013-10-29 18:34:16 -04001052void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001053{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001054 transceiver->setPriority(0.44);
1055
Thomas Tsou92c16df2013-09-28 18:04:19 -04001056 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001057 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001058 pthread_testcancel();
1059 }
1060 return NULL;
1061}
1062
Thomas Tsou204a9f12013-10-29 18:34:16 -04001063void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001064{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001065 Transceiver *trx = chan->trx;
1066 size_t num = chan->num;
1067
1068 delete chan;
1069
dburgessb3a0ca42011-10-12 07:44:40 +00001070 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001071 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001072 pthread_testcancel();
1073 }
1074 return NULL;
1075}
1076
Thomas Tsou204a9f12013-10-29 18:34:16 -04001077void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001078{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001079 Transceiver *trx = chan->trx;
1080 size_t num = chan->num;
1081
1082 delete chan;
1083
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001084 trx->setPriority(0.40);
1085
dburgessb3a0ca42011-10-12 07:44:40 +00001086 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001087 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001088 pthread_testcancel();
1089 }
1090 return NULL;
1091}