blob: 63102a14f19e201e551939ce46665750e71ed4d0 [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
Alexander Chemerise692ce92015-06-12 00:15:31 -040026#include <fstream>
dburgessb3a0ca42011-10-12 07:44:40 +000027#include "Transceiver.h"
28#include <Logger.h>
29
ttsou2173abf2012-08-08 00:51:31 +000030#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
dburgessb3a0ca42011-10-12 07:44:40 +000033
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040034using namespace GSM;
35
kurtis.heimerlec842de2012-11-23 08:37:32 +000036#define USB_LATENCY_INTRVL 10,0
ttsou2173abf2012-08-08 00:51:31 +000037
38#if USE_UHD
kurtis.heimerlec842de2012-11-23 08:37:32 +000039# define USB_LATENCY_MIN 6,7
ttsou2173abf2012-08-08 00:51:31 +000040#else
kurtis.heimerlec842de2012-11-23 08:37:32 +000041# define USB_LATENCY_MIN 1,1
ttsou2173abf2012-08-08 00:51:31 +000042#endif
dburgessb3a0ca42011-10-12 07:44:40 +000043
Thomas Tsoufa3a7872013-10-17 21:23:34 -040044/* Number of running values use in noise average */
45#define NOISE_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000046
Thomas Tsouf0782732013-10-29 15:55:47 -040047TransceiverState::TransceiverState()
Tom Tsoua4d1a412014-11-25 15:46:56 -080048 : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
Thomas Tsouf0782732013-10-29 15:55:47 -040049{
50 for (int i = 0; i < 8; i++) {
51 chanType[i] = Transceiver::NONE;
52 fillerModulus[i] = 26;
53 chanResponse[i] = NULL;
54 DFEForward[i] = NULL;
55 DFEFeedback[i] = NULL;
56
57 for (int n = 0; n < 102; n++)
58 fillerTable[n][i] = NULL;
59 }
60}
61
62TransceiverState::~TransceiverState()
63{
64 for (int i = 0; i < 8; i++) {
65 delete chanResponse[i];
66 delete DFEForward[i];
67 delete DFEFeedback[i];
68
69 for (int n = 0; n < 102; n++)
70 delete fillerTable[n][i];
71 }
72}
73
Tom Tsou64ad7122015-05-19 18:26:31 -070074static BitVector *genRandNormalBurst(size_t tsc)
Thomas Tsouf0782732013-10-29 15:55:47 -040075{
Tom Tsou64ad7122015-05-19 18:26:31 -070076 if (tsc > 7)
77 return NULL;
Thomas Tsou15d743e2014-01-25 02:34:03 -050078
Tom Tsou64ad7122015-05-19 18:26:31 -070079 BitVector *bits = new BitVector(148);
Thomas Tsou15d743e2014-01-25 02:34:03 -050080
Tom Tsou64ad7122015-05-19 18:26:31 -070081 size_t i = 0;
82
83 /* Tail bits */
84 for (; i < 4; i++)
85 (*bits)[i] = 0;
86
87 /* Random bits */
88 for (; i < 61; i++)
89 (*bits)[i] = rand() % 2;
90
91 /* Training sequence */
Alexander Chemeris29660482015-05-24 19:13:38 -040092 for (int j = 0; i < 87; i++, j++)
93 (*bits)[i] = GSM::gTrainingSequence[tsc][j];
Tom Tsou64ad7122015-05-19 18:26:31 -070094
95 /* Random bits */
96 for (; i < 144; i++)
97 (*bits)[i] = rand() % 2;
98
99 /* Tail bits */
100 for (; i < 148; i++)
101 (*bits)[i] = 0;
102
103 return bits;
104}
105
106bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc)
107{
108 BitVector *bits;
109 signalVector *burst;
110
111 if ((sps != 1) && (sps != 4))
112 return false;
113
114 for (size_t n = 0; n < 8; n++) {
115 size_t guard = 8 + !(n % 4);
116 size_t len = sps == 4 ? 625 : 148 + guard;
117
118 for (size_t i = 0; i < 102; i++) {
119 switch (filler) {
120 case Transceiver::FILLER_DUMMY:
121 burst = modulateBurst(gDummyBurst, guard, sps);
122 break;
123 case Transceiver::FILLER_RAND:
124 bits = genRandNormalBurst(rtsc);
125 burst = modulateBurst(*bits, guard, sps);
126 delete bits;
127 break;
128 case Transceiver::FILLER_ZERO:
129 default:
130 burst = new signalVector(len);
131 }
132
133 scaleVector(*burst, scale);
134 fillerTable[i][n] = burst;
135 }
136
137 if (filler == Transceiver::FILLER_RAND)
138 chanType[n] = Transceiver::TSC;
Thomas Tsou15d743e2014-01-25 02:34:03 -0500139 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700140
141 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400142}
143
dburgessb3a0ca42011-10-12 07:44:40 +0000144Transceiver::Transceiver(int wBasePort,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400145 const char *wTRXAddress,
146 size_t wSPS, size_t wChans,
147 GSM::Time wTransmitLatency,
148 RadioInterface *wRadioInterface,
149 double wRssiOffset)
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800150 : mBasePort(wBasePort), mAddr(wTRXAddress),
151 mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
152 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Alexander Chemerise8905a02015-06-03 23:47:56 -0400153 rssiOffset(wRssiOffset),
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800154 mSPSTx(wSPS), mSPSRx(1), mChans(wChans), mOn(false),
Alexander Chemerise692ce92015-06-12 00:15:31 -0400155 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0), mWriteBurstToDiskMask(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000156{
dburgessb3a0ca42011-10-12 07:44:40 +0000157 txFullScale = mRadioInterface->fullScaleInputValue();
158 rxFullScale = mRadioInterface->fullScaleOutputValue();
dburgessb3a0ca42011-10-12 07:44:40 +0000159}
160
161Transceiver::~Transceiver()
162{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800163 stop();
164
dburgessb3a0ca42011-10-12 07:44:40 +0000165 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400166
Thomas Tsou204a9f12013-10-29 18:34:16 -0400167 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800168 mControlServiceLoopThreads[i]->cancel();
169 mControlServiceLoopThreads[i]->join();
170 delete mControlServiceLoopThreads[i];
171
Thomas Tsou204a9f12013-10-29 18:34:16 -0400172 mTxPriorityQueues[i].clear();
173 delete mCtrlSockets[i];
174 delete mDataSockets[i];
175 }
dburgessb3a0ca42011-10-12 07:44:40 +0000176}
Thomas Tsou83e06892013-08-20 16:10:01 -0400177
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800178/*
179 * Initialize transceiver
180 *
181 * Start or restart the control loop. Any further control is handled through the
182 * socket API. Randomize the central radio clock set the downlink burst
183 * counters. Note that the clock will not update until the radio starts, but we
184 * are still expected to report clock indications through control channel
185 * activity.
186 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700187bool Transceiver::init(int filler, size_t rtsc)
Thomas Tsou83e06892013-08-20 16:10:01 -0400188{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500189 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400190
Thomas Tsou204a9f12013-10-29 18:34:16 -0400191 if (!mChans) {
192 LOG(ALERT) << "No channels assigned";
193 return false;
194 }
195
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400196 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400197 LOG(ALERT) << "Failed to initialize signal processing library";
198 return false;
199 }
200
Thomas Tsou204a9f12013-10-29 18:34:16 -0400201 mDataSockets.resize(mChans);
202 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400203 mControlServiceLoopThreads.resize(mChans);
204 mTxPriorityQueueServiceLoopThreads.resize(mChans);
205 mRxServiceLoopThreads.resize(mChans);
206
207 mTxPriorityQueues.resize(mChans);
208 mReceiveFIFO.resize(mChans);
209 mStates.resize(mChans);
210
Thomas Tsouccb73e12014-04-15 17:41:28 -0400211 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700212 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400213 mStates[0].mRetrans = true;
214
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800215 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400216 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500217 c_srcport = mBasePort + 2 * i + 1;
218 c_dstport = mBasePort + 2 * i + 101;
219 d_srcport = mBasePort + 2 * i + 2;
220 d_dstport = mBasePort + 2 * i + 102;
221
222 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
223 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400224 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400225
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800226 /* Randomize the central clock */
227 GSM::Time startTime(random() % gHyperframe, 0);
228 mRadioInterface->getClock()->set(startTime);
229 mTransmitDeadlineClock = startTime;
230 mLastClockUpdateTime = startTime;
231 mLatencyUpdateTime = startTime;
232
233 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400234 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800235 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400236 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800237 mControlServiceLoopThreads[i]->start((void * (*)(void*))
238 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400239
Tom Tsou64ad7122015-05-19 18:26:31 -0700240 if (i && filler == FILLER_DUMMY)
241 filler = FILLER_ZERO;
242
243 mStates[i].init(filler, mSPSTx, txFullScale, rtsc);
Thomas Tsou83e06892013-08-20 16:10:01 -0400244 }
245
246 return true;
247}
dburgessb3a0ca42011-10-12 07:44:40 +0000248
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800249/*
250 * Start the transceiver
251 *
252 * Submit command(s) to the radio device to commence streaming samples and
253 * launch threads to handle sample I/O. Re-synchronize the transmit burst
254 * counters to the central radio clock here as well.
255 */
256bool Transceiver::start()
257{
258 ScopedLock lock(mLock);
259
260 if (mOn) {
261 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300262 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800263 }
264
265 LOG(NOTICE) << "Starting the transceiver";
266
267 GSM::Time time = mRadioInterface->getClock()->get();
268 mTransmitDeadlineClock = time;
269 mLastClockUpdateTime = time;
270 mLatencyUpdateTime = time;
271
272 if (!mRadioInterface->start()) {
273 LOG(ALERT) << "Device failed to start";
274 return false;
275 }
276
277 /* Device is running - launch I/O threads */
278 mRxLowerLoopThread = new Thread(32768);
279 mTxLowerLoopThread = new Thread(32768);
280 mTxLowerLoopThread->start((void * (*)(void*))
281 TxLowerLoopAdapter,(void*) this);
282 mRxLowerLoopThread->start((void * (*)(void*))
283 RxLowerLoopAdapter,(void*) this);
284
285 /* Launch uplink and downlink burst processing threads */
286 for (size_t i = 0; i < mChans; i++) {
287 TransceiverChannel *chan = new TransceiverChannel(this, i);
288 mRxServiceLoopThreads[i] = new Thread(32768);
289 mRxServiceLoopThreads[i]->start((void * (*)(void*))
290 RxUpperLoopAdapter, (void*) chan);
291
292 chan = new TransceiverChannel(this, i);
293 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
294 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
295 TxUpperLoopAdapter, (void*) chan);
296 }
297
298 writeClockInterface();
299 mOn = true;
300 return true;
301}
302
303/*
304 * Stop the transceiver
305 *
306 * Perform stopping by disabling receive streaming and issuing cancellation
307 * requests to running threads. Most threads will timeout and terminate once
308 * device is disabled, but the transmit loop may block waiting on the central
309 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
310 * makes it to the thread cancellation point.
311 */
312void Transceiver::stop()
313{
314 ScopedLock lock(mLock);
315
316 if (!mOn)
317 return;
318
319 LOG(NOTICE) << "Stopping the transceiver";
320 mTxLowerLoopThread->cancel();
321 mRxLowerLoopThread->cancel();
322
323 for (size_t i = 0; i < mChans; i++) {
324 mRxServiceLoopThreads[i]->cancel();
325 mTxPriorityQueueServiceLoopThreads[i]->cancel();
326 }
327
328 LOG(INFO) << "Stopping the device";
329 mRadioInterface->stop();
330
331 for (size_t i = 0; i < mChans; i++) {
332 mRxServiceLoopThreads[i]->join();
333 mTxPriorityQueueServiceLoopThreads[i]->join();
334 delete mRxServiceLoopThreads[i];
335 delete mTxPriorityQueueServiceLoopThreads[i];
336
337 mTxPriorityQueues[i].clear();
338 }
339
340 mTxLowerLoopThread->join();
341 mRxLowerLoopThread->join();
342 delete mTxLowerLoopThread;
343 delete mRxLowerLoopThread;
344
345 mOn = false;
346 LOG(NOTICE) << "Transceiver stopped";
347}
348
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500349void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400350 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000351{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500352 signalVector *burst;
353 radioVector *radio_burst;
354
Thomas Tsou204a9f12013-10-29 18:34:16 -0400355 if (chan >= mTxPriorityQueues.size()) {
356 LOG(ALERT) << "Invalid channel " << chan;
357 return;
358 }
359
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500360 if (wTime.TN() > 7) {
361 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
362 return;
363 }
364
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500365 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
366 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000367
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500368 radio_burst = new radioVector(wTime, burst);
369
370 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000371}
372
Thomas Tsou15d743e2014-01-25 02:34:03 -0500373void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
374{
375 int TN, modFN;
376 TransceiverState *state = &mStates[chan];
377
378 TN = burst->getTime().TN();
379 modFN = burst->getTime().FN() % state->fillerModulus[TN];
380
381 delete state->fillerTable[modFN][TN];
382 state->fillerTable[modFN][TN] = burst->getVector();
383 burst->setVector(NULL);
384}
385
dburgessb3a0ca42011-10-12 07:44:40 +0000386void Transceiver::pushRadioVector(GSM::Time &nowTime)
387{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400388 int TN, modFN;
389 radioVector *burst;
390 TransceiverState *state;
391 std::vector<signalVector *> bursts(mChans);
392 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500393 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000394
Thomas Tsou204a9f12013-10-29 18:34:16 -0400395 for (size_t i = 0; i < mChans; i ++) {
396 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000397
Thomas Tsou204a9f12013-10-29 18:34:16 -0400398 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
399 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500400 if (state->mRetrans)
401 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500402 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400403 }
404
405 TN = nowTime.TN();
406 modFN = nowTime.FN() % state->fillerModulus[TN];
407
408 bursts[i] = state->fillerTable[modFN][TN];
409 zeros[i] = state->chanType[TN] == NONE;
410
411 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500412 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500413
414 if (state->mRetrans) {
415 updateFillerTable(i, burst);
416 } else {
417 burst->setVector(NULL);
418 filler[i] = false;
419 }
420
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500421 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400422 }
dburgessb3a0ca42011-10-12 07:44:40 +0000423 }
424
Thomas Tsou204a9f12013-10-29 18:34:16 -0400425 mRadioInterface->driveTransmitRadio(bursts, zeros);
426
Thomas Tsou15d743e2014-01-25 02:34:03 -0500427 for (size_t i = 0; i < mChans; i++) {
428 if (!filler[i])
429 delete bursts[i];
430 }
dburgessb3a0ca42011-10-12 07:44:40 +0000431}
432
Thomas Tsou204a9f12013-10-29 18:34:16 -0400433void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000434{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400435 TransceiverState *state = &mStates[chan];
436
437 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000438 case NONE:
439 case I:
440 case II:
441 case III:
442 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400443 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000444 break;
445 case IV:
446 case VI:
447 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400448 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000449 break;
450 //case V:
451 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400452 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000453 break;
ttsoufc40a842013-06-09 22:38:18 +0000454 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400455 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000456 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000457 default:
458 break;
459 }
460}
461
462
Thomas Tsou204a9f12013-10-29 18:34:16 -0400463Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
464 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000465{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400466 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000467 unsigned burstTN = currTime.TN();
468 unsigned burstFN = currTime.FN();
469
Thomas Tsou204a9f12013-10-29 18:34:16 -0400470 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000471 case NONE:
472 return OFF;
473 break;
474 case FILL:
475 return IDLE;
476 break;
477 case I:
478 return TSC;
479 /*if (burstFN % 26 == 25)
480 return IDLE;
481 else
482 return TSC;*/
483 break;
484 case II:
ttsou20642972013-03-27 22:00:25 +0000485 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000486 break;
487 case III:
488 return TSC;
489 break;
490 case IV:
491 case VI:
492 return RACH;
493 break;
494 case V: {
495 int mod51 = burstFN % 51;
496 if ((mod51 <= 36) && (mod51 >= 14))
497 return RACH;
498 else if ((mod51 == 4) || (mod51 == 5))
499 return RACH;
500 else if ((mod51 == 45) || (mod51 == 46))
501 return RACH;
502 else
503 return TSC;
504 break;
505 }
506 case VII:
507 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
508 return IDLE;
509 else
510 return TSC;
511 break;
ttsoufc40a842013-06-09 22:38:18 +0000512 case XIII: {
513 int mod52 = burstFN % 52;
514 if ((mod52 == 12) || (mod52 == 38))
515 return RACH;
516 else if ((mod52 == 25) || (mod52 == 51))
517 return IDLE;
518 else
519 return TSC;
520 break;
521 }
dburgessb3a0ca42011-10-12 07:44:40 +0000522 case LOOPBACK:
523 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
524 return IDLE;
525 else
526 return TSC;
527 break;
528 default:
529 return OFF;
530 break;
531 }
dburgessb3a0ca42011-10-12 07:44:40 +0000532}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400533
Thomas Tsou30421a72013-11-13 23:14:48 -0500534/*
535 * Detect RACH synchronization sequence within a burst. No equalization
536 * is used or available on the RACH channel.
537 */
Alexander Chemeris954b1182015-06-04 15:39:41 -0400538int Transceiver::detectRACH(TransceiverState *state,
539 signalVector &burst,
540 complex &amp, float &toa)
Thomas Tsou30421a72013-11-13 23:14:48 -0500541{
542 float threshold = 6.0;
543
Alexander Chemeris130a8002015-06-09 20:52:11 -0400544 return detectRACHBurst(burst, threshold, mSPSRx, amp, toa);
Thomas Tsou30421a72013-11-13 23:14:48 -0500545}
546
547/*
548 * Detect normal burst training sequence midamble. Update equalization
549 * state information and channel estimate if necessary. Equalization
550 * is currently disabled.
551 */
Alexander Chemeris954b1182015-06-04 15:39:41 -0400552int Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
553 complex &amp, float &toa, GSM::Time &time)
Thomas Tsou30421a72013-11-13 23:14:48 -0500554{
Alexander Chemeris954b1182015-06-04 15:39:41 -0400555 int success;
Thomas Tsou30421a72013-11-13 23:14:48 -0500556 int tn = time.TN();
557 float chanOffset, threshold = 5.0;
Alexander Chemeris81c68732015-06-10 22:18:31 -0400558 bool needDFE = false, estimateChan = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500559 double elapsed = time - state->chanEstimateTime[tn];
560 signalVector *chanResp;
561
562 /* Check equalization update state */
Thomas Tsoufb827d02013-11-16 16:14:12 -0500563 if (needDFE && ((elapsed > 50) || (!state->chanResponse[tn]))) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500564 delete state->DFEForward[tn];
565 delete state->DFEFeedback[tn];
566 state->DFEForward[tn] = NULL;
567 state->DFEFeedback[tn] = NULL;
568
569 estimateChan = true;
570 }
571
572 /* Detect normal burst midambles */
Alexander Chemeris130a8002015-06-09 20:52:11 -0400573 success = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, amp,
574 toa, mMaxExpectedDelay, estimateChan,
Alexander Chemeris954b1182015-06-04 15:39:41 -0400575 &chanResp, &chanOffset);
576 if (success <= 0) {
577 return success;
Thomas Tsou30421a72013-11-13 23:14:48 -0500578 }
579
Thomas Tsou30421a72013-11-13 23:14:48 -0500580 /* Set equalizer if unabled */
581 if (needDFE && estimateChan) {
Alexander Chemeris81c68732015-06-10 22:18:31 -0400582 float noise = state->mNoiseLev;
583 state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
584
Thomas Tsou30421a72013-11-13 23:14:48 -0500585 state->chanResponse[tn] = chanResp;
586 state->chanRespOffset[tn] = chanOffset;
587 state->chanRespAmplitude[tn] = amp;
588
589 scaleVector(*chanResp, complex(1.0, 0.0) / amp);
590
591 designDFE(*chanResp, state->SNRestimate[tn],
592 7, &state->DFEForward[tn], &state->DFEFeedback[tn]);
593
594 state->chanEstimateTime[tn] = time;
595 }
596
Alexander Chemeris954b1182015-06-04 15:39:41 -0400597 return 1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500598}
599
600/*
601 * Demodulate GMSK burst using equalization if requested. Otherwise
602 * demodulate by direct rotation and soft slicing.
603 */
604SoftVector *Transceiver::demodulate(TransceiverState *state,
605 signalVector &burst, complex amp,
606 float toa, size_t tn, bool equalize)
607{
608 if (equalize) {
609 scaleVector(burst, complex(1.0, 0.0) / amp);
610 return equalizeBurst(burst,
611 toa - state->chanRespOffset[tn],
612 mSPSRx,
613 *state->DFEForward[tn],
614 *state->DFEFeedback[tn]);
615 }
616
617 return demodulateBurst(burst, mSPSRx, amp, toa);
618}
619
Alexander Chemerise692ce92015-06-12 00:15:31 -0400620void writeToFile(radioVector *radio_burst, size_t chan)
621{
622 GSM::Time time = radio_burst->getTime();
623 std::ostringstream fname;
624 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
625 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
626 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
627 outfile.close();
628}
629
Thomas Tsou30421a72013-11-13 23:14:48 -0500630/*
631 * Pull bursts from the FIFO and handle according to the slot
632 * and burst correlation type. Equalzation is currently disabled.
633 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400634SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400635 double &timingOffset, double &noise,
636 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000637{
Alexander Chemeris954b1182015-06-04 15:39:41 -0400638 int success;
639 bool equalize = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500640 complex amp;
641 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500642 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500643 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500644 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500645 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400646 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000647
Thomas Tsou30421a72013-11-13 23:14:48 -0500648 /* Blocking FIFO read */
649 radioVector *radio_burst = mReceiveFIFO[chan]->read();
650 if (!radio_burst)
651 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000652
Thomas Tsou30421a72013-11-13 23:14:48 -0500653 /* Set time and determine correlation type */
654 GSM::Time time = radio_burst->getTime();
655 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000656
Alexander Chemerise692ce92015-06-12 00:15:31 -0400657 /* Debug: dump bursts to disk */
658 /* bits 0-7 - chan 0 timeslots
659 * bits 8-15 - chan 1 timeslots */
660 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
661 writeToFile(radio_burst, chan);
662
Alexander Chemeris2b542102015-06-08 22:46:38 -0400663 /* No processing if the timeslot is off.
664 * Not even power level or noise calculation. */
665 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500666 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000667 return NULL;
668 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000669
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500670 /* Select the diversity channel with highest energy */
671 for (size_t i = 0; i < radio_burst->chans(); i++) {
672 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
673 if (pow > max) {
674 max = pow;
675 max_i = i;
676 }
677 avg += pow;
678 }
679
680 if (max_i < 0) {
681 LOG(ALERT) << "Received empty burst";
682 delete radio_burst;
683 return NULL;
684 }
685
Thomas Tsou30421a72013-11-13 23:14:48 -0500686 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500687 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500688 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400689
690 wTime = time;
691 RSSI = 20.0 * log10(rxFullScale / avg);
692
693 /* RSSI estimation are valid */
694 isRssiValid = true;
695
696 if (type == IDLE) {
697 /* Update noise levels */
698 state->mNoises.insert(avg);
699 state->mNoiseLev = state->mNoises.avg();
700 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
701
702 delete radio_burst;
703 return NULL;
704 } else {
705 /* Do not update noise levels */
706 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
707 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400708
Thomas Tsou30421a72013-11-13 23:14:48 -0500709 /* Detect normal or RACH bursts */
710 if (type == TSC)
Thomas Tsoua0179e32013-11-14 15:52:04 -0500711 success = detectTSC(state, *burst, amp, toa, time);
Thomas Tsou30421a72013-11-13 23:14:48 -0500712 else
Thomas Tsoua0179e32013-11-14 15:52:04 -0500713 success = detectRACH(state, *burst, amp, toa);
Thomas Tsouf0782732013-10-29 15:55:47 -0400714
Alexander Chemeris2b542102015-06-08 22:46:38 -0400715 /* Alert an error and exit */
Tom Tsou577cd022015-05-18 13:57:54 -0700716 if (success <= 0) {
Alexander Chemeris2b542102015-06-08 22:46:38 -0400717 if (success == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400718 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Alexander Chemeris2b542102015-06-08 22:46:38 -0400719 } else if (success != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400720 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700721 }
722
Thomas Tsou30421a72013-11-13 23:14:48 -0500723 delete radio_burst;
724 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000725 }
dburgessb3a0ca42011-10-12 07:44:40 +0000726
Alexander Chemeris2b542102015-06-08 22:46:38 -0400727 timingOffset = toa / mSPSRx;
728
Thomas Tsou30421a72013-11-13 23:14:48 -0500729 /* Demodulate and set output info */
730 if (equalize && (type != TSC))
731 equalize = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000732
Alexander Chemeris2268c852015-06-07 01:10:11 -0400733 bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500734
Thomas Tsou30421a72013-11-13 23:14:48 -0500735 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500736 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000737}
738
dburgessb3a0ca42011-10-12 07:44:40 +0000739void Transceiver::reset()
740{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400741 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
742 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000743}
744
745
Thomas Tsou204a9f12013-10-29 18:34:16 -0400746void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000747{
dburgessb3a0ca42011-10-12 07:44:40 +0000748 int MAX_PACKET_LENGTH = 100;
749
750 // check control socket
751 char buffer[MAX_PACKET_LENGTH];
752 int msgLen = -1;
753 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400754
Thomas Tsou204a9f12013-10-29 18:34:16 -0400755 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000756
757 if (msgLen < 1) {
758 return;
759 }
760
761 char cmdcheck[4];
762 char command[MAX_PACKET_LENGTH];
763 char response[MAX_PACKET_LENGTH];
764
765 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400766
767 if (!chan)
768 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000769
770 if (strcmp(cmdcheck,"CMD")!=0) {
771 LOG(WARNING) << "bogus message on control interface";
772 return;
773 }
774 LOG(INFO) << "command is " << buffer;
775
776 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800777 stop();
778 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000779 }
780 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800781 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000782 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800783 else
dburgessb3a0ca42011-10-12 07:44:40 +0000784 sprintf(response,"RSP POWERON 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000785 }
786 else if (strcmp(command,"SETMAXDLY")==0) {
787 //set expected maximum time-of-arrival
788 int maxDelay;
789 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
790 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
791 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
792 }
793 else if (strcmp(command,"SETRXGAIN")==0) {
794 //set expected maximum time-of-arrival
795 int newGain;
796 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400797 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000798 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
799 }
800 else if (strcmp(command,"NOISELEV")==0) {
801 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500802 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000803 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500804 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000805 }
806 else {
807 sprintf(response,"RSP NOISELEV 1 0");
808 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500809 }
810 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800811 int power;
812 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
813 power = mRadioInterface->setPowerAttenuation(power, chan);
814 mStates[chan].mPower = power;
815 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000816 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500817 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800818 int power, step;
819 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
820 power = mStates[chan].mPower + step;
821 power = mRadioInterface->setPowerAttenuation(power, chan);
822 mStates[chan].mPower = power;
823 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000824 }
dburgessb3a0ca42011-10-12 07:44:40 +0000825 else if (strcmp(command,"RXTUNE")==0) {
826 // tune receiver
827 int freqKhz;
828 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500829 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400830 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000831 LOG(ALERT) << "RX failed to tune";
832 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
833 }
834 else
835 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
836 }
837 else if (strcmp(command,"TXTUNE")==0) {
838 // tune txmtr
839 int freqKhz;
840 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500841 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400842 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000843 LOG(ALERT) << "TX failed to tune";
844 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
845 }
846 else
847 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
848 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500849 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000850 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500851 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500852 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700853 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500854 sprintf(response, "RSP SETTSC 1 %d", TSC);
855 else if (chan && (TSC != mTSC))
856 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000857 else {
858 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400859 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400860 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000861 }
862 }
863 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700864 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000865 int corrCode;
866 int timeslot;
867 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
868 if ((timeslot < 0) || (timeslot > 7)) {
869 LOG(WARNING) << "bogus message on control interface";
870 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
871 return;
872 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400873 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
874 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000875 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
876
877 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400878 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
879 // debug command! may change or disapear without notice
880 // set a mask which bursts to dump to disk
881 int mask;
882 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
883 mWriteBurstToDiskMask = mask;
884 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
885 }
dburgessb3a0ca42011-10-12 07:44:40 +0000886 else {
887 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200888 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000889 }
890
Thomas Tsou204a9f12013-10-29 18:34:16 -0400891 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000892}
893
Thomas Tsou204a9f12013-10-29 18:34:16 -0400894bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000895{
dburgessb3a0ca42011-10-12 07:44:40 +0000896 char buffer[gSlotLen+50];
897
898 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400899 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000900
901 if (msgLen!=gSlotLen+1+4+1) {
902 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
903 return false;
904 }
905
906 int timeSlot = (int) buffer[0];
907 uint64_t frameNum = 0;
908 for (int i = 0; i < 4; i++)
909 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000910
dburgessb3a0ca42011-10-12 07:44:40 +0000911 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
912
913 int RSSI = (int) buffer[5];
914 static BitVector newBurst(gSlotLen);
915 BitVector::iterator itr = newBurst.begin();
916 char *bufferItr = buffer+6;
917 while (itr < newBurst.end())
918 *itr++ = *bufferItr++;
919
920 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400921
922 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000923
924 return true;
925
926
927}
dburgessb3a0ca42011-10-12 07:44:40 +0000928
Thomas Tsou204a9f12013-10-29 18:34:16 -0400929void Transceiver::driveReceiveRadio()
930{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400931 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400932 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400933 } else {
934 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
935 writeClockInterface();
936 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400937}
938
939void Transceiver::driveReceiveFIFO(size_t chan)
940{
dburgessb3a0ca42011-10-12 07:44:40 +0000941 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400942 double RSSI; // in dBFS
943 double dBm; // in dBm
944 double TOA; // in symbols
945 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400946 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000947 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400948 bool isRssiValid; // are RSSI, noise and burstTime valid
dburgessb3a0ca42011-10-12 07:44:40 +0000949
Alexander Chemeris2b542102015-06-08 22:46:38 -0400950 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000951
952 if (rxBurst) {
Alexander Chemerise8905a02015-06-03 23:47:56 -0400953 dBm = RSSI+rssiOffset;
954 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000955
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400956 LOG(DEBUG) << std::fixed << std::right
957 << " time: " << burstTime
958 << " RSSI: " << std::setw(5) << std::setprecision(1) << RSSI << "dBFS/" << std::setw(6) << -dBm << "dBm"
959 << " noise: " << std::setw(5) << std::setprecision(1) << noise << "dBFS/" << std::setw(6) << -(noise+rssiOffset) << "dBm"
960 << " TOA: " << std::setw(5) << std::setprecision(2) << TOA
961 << " bits: " << *rxBurst;
962
dburgessb3a0ca42011-10-12 07:44:40 +0000963 char burstString[gSlotLen+10];
964 burstString[0] = burstTime.TN();
965 for (int i = 0; i < 4; i++)
966 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400967 burstString[5] = (int)dBm;
968 burstString[6] = (TOAint >> 8) & 0x0ff;
969 burstString[7] = TOAint & 0x0ff;
dburgessb3a0ca42011-10-12 07:44:40 +0000970 SoftVector::iterator burstItr = rxBurst->begin();
971
972 for (unsigned int i = 0; i < gSlotLen; i++) {
973 burstString[8+i] =(char) round((*burstItr++)*255.0);
974 }
975 burstString[gSlotLen+9] = '\0';
976 delete rxBurst;
977
Thomas Tsou204a9f12013-10-29 18:34:16 -0400978 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +0000979 }
dburgessb3a0ca42011-10-12 07:44:40 +0000980}
981
Thomas Tsou204a9f12013-10-29 18:34:16 -0400982void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000983{
984
985 /**
986 Features a carefully controlled latency mechanism, to
987 assure that transmit packets arrive at the radio/USRP
988 before they need to be transmitted.
989
990 Deadline clock indicates the burst that needs to be
991 pushed into the FIFO right NOW. If transmit queue does
992 not have a burst, stick in filler data.
993 */
994
995
996 RadioClock *radioClock = (mRadioInterface->getClock());
997
998 if (mOn) {
999 //radioClock->wait(); // wait until clock updates
1000 LOG(DEBUG) << "radio clock " << radioClock->get();
1001 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
1002 // if underrun, then we're not providing bursts to radio/USRP fast
1003 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -04001004 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001005 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +00001006 // only update latency at the defined frame interval
1007 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001008 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
1009 LOG(INFO) << "new latency: " << mTransmitLatency;
1010 mLatencyUpdateTime = radioClock->get();
1011 }
1012 }
1013 else {
1014 // if underrun hasn't occurred in the last sec (216 frames) drop
1015 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +00001016 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001017 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1018 mTransmitLatency.decTN();
1019 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1020 mLatencyUpdateTime = radioClock->get();
1021 }
1022 }
1023 }
dburgessb3a0ca42011-10-12 07:44:40 +00001024 }
dburgessb3a0ca42011-10-12 07:44:40 +00001025 // time to push burst to transmit FIFO
1026 pushRadioVector(mTransmitDeadlineClock);
1027 mTransmitDeadlineClock.incTN();
1028 }
dburgessb3a0ca42011-10-12 07:44:40 +00001029 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001030
1031 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001032}
1033
1034
1035
1036void Transceiver::writeClockInterface()
1037{
1038 char command[50];
1039 // FIXME -- This should be adaptive.
1040 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1041
1042 LOG(INFO) << "ClockInterface: sending " << command;
1043
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001044 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001045
1046 mLastClockUpdateTime = mTransmitDeadlineClock;
1047
Thomas Tsou92c16df2013-09-28 18:04:19 -04001048}
dburgessb3a0ca42011-10-12 07:44:40 +00001049
Thomas Tsou204a9f12013-10-29 18:34:16 -04001050void *RxUpperLoopAdapter(TransceiverChannel *chan)
1051{
1052 Transceiver *trx = chan->trx;
1053 size_t num = chan->num;
1054
1055 delete chan;
1056
Thomas Tsou7553aa92013-11-08 12:50:03 -05001057 trx->setPriority(0.42);
1058
Thomas Tsou204a9f12013-10-29 18:34:16 -04001059 while (1) {
1060 trx->driveReceiveFIFO(num);
1061 pthread_testcancel();
1062 }
1063 return NULL;
1064}
1065
1066void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001067{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001068 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001069
dburgessb3a0ca42011-10-12 07:44:40 +00001070 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001071 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001072 pthread_testcancel();
1073 }
1074 return NULL;
1075}
1076
Thomas Tsou204a9f12013-10-29 18:34:16 -04001077void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001078{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001079 transceiver->setPriority(0.44);
1080
Thomas Tsou92c16df2013-09-28 18:04:19 -04001081 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001082 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001083 pthread_testcancel();
1084 }
1085 return NULL;
1086}
1087
Thomas Tsou204a9f12013-10-29 18:34:16 -04001088void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001089{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001090 Transceiver *trx = chan->trx;
1091 size_t num = chan->num;
1092
1093 delete chan;
1094
dburgessb3a0ca42011-10-12 07:44:40 +00001095 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001096 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001097 pthread_testcancel();
1098 }
1099 return NULL;
1100}
1101
Thomas Tsou204a9f12013-10-29 18:34:16 -04001102void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001103{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001104 Transceiver *trx = chan->trx;
1105 size_t num = chan->num;
1106
1107 delete chan;
1108
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001109 trx->setPriority(0.40);
1110
dburgessb3a0ca42011-10-12 07:44:40 +00001111 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001112 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001113 pthread_testcancel();
1114 }
1115 return NULL;
1116}