blob: 2be7ab05bfdf4ec68aaf04970567d30496fc5096 [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,
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800146 size_t tx_sps, size_t rx_sps, size_t chans,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400147 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 Tsou5cd70dc2016-03-06 01:28:40 -0800154 mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), 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();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300159
160 for (int i = 0; i < 8; i++) {
161 for (int j = 0; j < 8; j++)
162 mHandover[i][j] = false;
163 }
dburgessb3a0ca42011-10-12 07:44:40 +0000164}
165
166Transceiver::~Transceiver()
167{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800168 stop();
169
dburgessb3a0ca42011-10-12 07:44:40 +0000170 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400171
Thomas Tsou204a9f12013-10-29 18:34:16 -0400172 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800173 mControlServiceLoopThreads[i]->cancel();
174 mControlServiceLoopThreads[i]->join();
175 delete mControlServiceLoopThreads[i];
176
Thomas Tsou204a9f12013-10-29 18:34:16 -0400177 mTxPriorityQueues[i].clear();
178 delete mCtrlSockets[i];
179 delete mDataSockets[i];
180 }
dburgessb3a0ca42011-10-12 07:44:40 +0000181}
Thomas Tsou83e06892013-08-20 16:10:01 -0400182
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800183/*
184 * Initialize transceiver
185 *
186 * Start or restart the control loop. Any further control is handled through the
187 * socket API. Randomize the central radio clock set the downlink burst
188 * counters. Note that the clock will not update until the radio starts, but we
189 * are still expected to report clock indications through control channel
190 * activity.
191 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700192bool Transceiver::init(int filler, size_t rtsc)
Thomas Tsou83e06892013-08-20 16:10:01 -0400193{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500194 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400195
Thomas Tsou204a9f12013-10-29 18:34:16 -0400196 if (!mChans) {
197 LOG(ALERT) << "No channels assigned";
198 return false;
199 }
200
Tom Tsou2079a3c2016-03-06 00:58:56 -0800201 if (!sigProcLibSetup()) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400202 LOG(ALERT) << "Failed to initialize signal processing library";
203 return false;
204 }
205
Thomas Tsou204a9f12013-10-29 18:34:16 -0400206 mDataSockets.resize(mChans);
207 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400208 mControlServiceLoopThreads.resize(mChans);
209 mTxPriorityQueueServiceLoopThreads.resize(mChans);
210 mRxServiceLoopThreads.resize(mChans);
211
212 mTxPriorityQueues.resize(mChans);
213 mReceiveFIFO.resize(mChans);
214 mStates.resize(mChans);
215
Thomas Tsouccb73e12014-04-15 17:41:28 -0400216 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700217 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400218 mStates[0].mRetrans = true;
219
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800220 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400221 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500222 c_srcport = mBasePort + 2 * i + 1;
223 c_dstport = mBasePort + 2 * i + 101;
224 d_srcport = mBasePort + 2 * i + 2;
225 d_dstport = mBasePort + 2 * i + 102;
226
227 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
228 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400229 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400230
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800231 /* Randomize the central clock */
232 GSM::Time startTime(random() % gHyperframe, 0);
233 mRadioInterface->getClock()->set(startTime);
234 mTransmitDeadlineClock = startTime;
235 mLastClockUpdateTime = startTime;
236 mLatencyUpdateTime = startTime;
237
238 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400239 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800240 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400241 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800242 mControlServiceLoopThreads[i]->start((void * (*)(void*))
243 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400244
Tom Tsou64ad7122015-05-19 18:26:31 -0700245 if (i && filler == FILLER_DUMMY)
246 filler = FILLER_ZERO;
247
248 mStates[i].init(filler, mSPSTx, txFullScale, rtsc);
Thomas Tsou83e06892013-08-20 16:10:01 -0400249 }
250
251 return true;
252}
dburgessb3a0ca42011-10-12 07:44:40 +0000253
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800254/*
255 * Start the transceiver
256 *
257 * Submit command(s) to the radio device to commence streaming samples and
258 * launch threads to handle sample I/O. Re-synchronize the transmit burst
259 * counters to the central radio clock here as well.
260 */
261bool Transceiver::start()
262{
263 ScopedLock lock(mLock);
264
265 if (mOn) {
266 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300267 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800268 }
269
270 LOG(NOTICE) << "Starting the transceiver";
271
272 GSM::Time time = mRadioInterface->getClock()->get();
273 mTransmitDeadlineClock = time;
274 mLastClockUpdateTime = time;
275 mLatencyUpdateTime = time;
276
277 if (!mRadioInterface->start()) {
278 LOG(ALERT) << "Device failed to start";
279 return false;
280 }
281
282 /* Device is running - launch I/O threads */
283 mRxLowerLoopThread = new Thread(32768);
284 mTxLowerLoopThread = new Thread(32768);
285 mTxLowerLoopThread->start((void * (*)(void*))
286 TxLowerLoopAdapter,(void*) this);
287 mRxLowerLoopThread->start((void * (*)(void*))
288 RxLowerLoopAdapter,(void*) this);
289
290 /* Launch uplink and downlink burst processing threads */
291 for (size_t i = 0; i < mChans; i++) {
292 TransceiverChannel *chan = new TransceiverChannel(this, i);
293 mRxServiceLoopThreads[i] = new Thread(32768);
294 mRxServiceLoopThreads[i]->start((void * (*)(void*))
295 RxUpperLoopAdapter, (void*) chan);
296
297 chan = new TransceiverChannel(this, i);
298 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
299 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
300 TxUpperLoopAdapter, (void*) chan);
301 }
302
303 writeClockInterface();
304 mOn = true;
305 return true;
306}
307
308/*
309 * Stop the transceiver
310 *
311 * Perform stopping by disabling receive streaming and issuing cancellation
312 * requests to running threads. Most threads will timeout and terminate once
313 * device is disabled, but the transmit loop may block waiting on the central
314 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
315 * makes it to the thread cancellation point.
316 */
317void Transceiver::stop()
318{
319 ScopedLock lock(mLock);
320
321 if (!mOn)
322 return;
323
324 LOG(NOTICE) << "Stopping the transceiver";
325 mTxLowerLoopThread->cancel();
326 mRxLowerLoopThread->cancel();
327
328 for (size_t i = 0; i < mChans; i++) {
329 mRxServiceLoopThreads[i]->cancel();
330 mTxPriorityQueueServiceLoopThreads[i]->cancel();
331 }
332
333 LOG(INFO) << "Stopping the device";
334 mRadioInterface->stop();
335
336 for (size_t i = 0; i < mChans; i++) {
337 mRxServiceLoopThreads[i]->join();
338 mTxPriorityQueueServiceLoopThreads[i]->join();
339 delete mRxServiceLoopThreads[i];
340 delete mTxPriorityQueueServiceLoopThreads[i];
341
342 mTxPriorityQueues[i].clear();
343 }
344
345 mTxLowerLoopThread->join();
346 mRxLowerLoopThread->join();
347 delete mTxLowerLoopThread;
348 delete mRxLowerLoopThread;
349
350 mOn = false;
351 LOG(NOTICE) << "Transceiver stopped";
352}
353
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500354void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400355 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000356{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500357 signalVector *burst;
358 radioVector *radio_burst;
359
Thomas Tsou204a9f12013-10-29 18:34:16 -0400360 if (chan >= mTxPriorityQueues.size()) {
361 LOG(ALERT) << "Invalid channel " << chan;
362 return;
363 }
364
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500365 if (wTime.TN() > 7) {
366 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
367 return;
368 }
369
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500370 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
371 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000372
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500373 radio_burst = new radioVector(wTime, burst);
374
375 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000376}
377
Thomas Tsou15d743e2014-01-25 02:34:03 -0500378void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
379{
380 int TN, modFN;
381 TransceiverState *state = &mStates[chan];
382
383 TN = burst->getTime().TN();
384 modFN = burst->getTime().FN() % state->fillerModulus[TN];
385
386 delete state->fillerTable[modFN][TN];
387 state->fillerTable[modFN][TN] = burst->getVector();
388 burst->setVector(NULL);
389}
390
dburgessb3a0ca42011-10-12 07:44:40 +0000391void Transceiver::pushRadioVector(GSM::Time &nowTime)
392{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400393 int TN, modFN;
394 radioVector *burst;
395 TransceiverState *state;
396 std::vector<signalVector *> bursts(mChans);
397 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500398 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000399
Thomas Tsou204a9f12013-10-29 18:34:16 -0400400 for (size_t i = 0; i < mChans; i ++) {
401 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000402
Thomas Tsou204a9f12013-10-29 18:34:16 -0400403 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
404 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500405 if (state->mRetrans)
406 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500407 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400408 }
409
410 TN = nowTime.TN();
411 modFN = nowTime.FN() % state->fillerModulus[TN];
412
413 bursts[i] = state->fillerTable[modFN][TN];
414 zeros[i] = state->chanType[TN] == NONE;
415
416 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500417 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500418
419 if (state->mRetrans) {
420 updateFillerTable(i, burst);
421 } else {
422 burst->setVector(NULL);
423 filler[i] = false;
424 }
425
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500426 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400427 }
dburgessb3a0ca42011-10-12 07:44:40 +0000428 }
429
Thomas Tsou204a9f12013-10-29 18:34:16 -0400430 mRadioInterface->driveTransmitRadio(bursts, zeros);
431
Thomas Tsou15d743e2014-01-25 02:34:03 -0500432 for (size_t i = 0; i < mChans; i++) {
433 if (!filler[i])
434 delete bursts[i];
435 }
dburgessb3a0ca42011-10-12 07:44:40 +0000436}
437
Thomas Tsou204a9f12013-10-29 18:34:16 -0400438void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000439{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400440 TransceiverState *state = &mStates[chan];
441
442 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000443 case NONE:
444 case I:
445 case II:
446 case III:
447 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400448 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000449 break;
450 case IV:
451 case VI:
452 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400453 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000454 break;
455 //case V:
456 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400457 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000458 break;
ttsoufc40a842013-06-09 22:38:18 +0000459 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400460 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000461 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000462 default:
463 break;
464 }
465}
466
467
Thomas Tsou204a9f12013-10-29 18:34:16 -0400468Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
469 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000470{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300471 static int tchh_subslot[26] = { 0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,1 };
472 static int sdcch4_subslot[102] = { 3,3,3,3,0,0,2,2,2,2,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,2,2,2,2,
473 3,3,3,3,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,2,2,2,2 };
474 static int sdcch8_subslot[102] = { 5,5,5,5,6,6,6,6,7,7,7,7,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,0,0,0,0,
475 1,1,1,1,2,2,2,2,3,3,3,3,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,4,4,4,4 };
Thomas Tsou204a9f12013-10-29 18:34:16 -0400476 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000477 unsigned burstTN = currTime.TN();
478 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300479 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000480
Thomas Tsou204a9f12013-10-29 18:34:16 -0400481 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000482 case NONE:
483 return OFF;
484 break;
485 case FILL:
486 return IDLE;
487 break;
488 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300489 // TODO: Are we expecting RACH on an IDLE frame?
490/* if (burstFN % 26 == 25)
491 return IDLE;*/
492 if (mHandover[burstTN][0])
493 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000494 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000495 break;
496 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300497 subch = tchh_subslot[burstFN % 26];
498 if (subch == 1)
499 return IDLE;
500 if (mHandover[burstTN][0])
501 return RACH;
ttsou20642972013-03-27 22:00:25 +0000502 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000503 break;
504 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300505 subch = tchh_subslot[burstFN % 26];
506 if (mHandover[burstTN][subch])
507 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000508 return TSC;
509 break;
510 case IV:
511 case VI:
512 return RACH;
513 break;
514 case V: {
515 int mod51 = burstFN % 51;
516 if ((mod51 <= 36) && (mod51 >= 14))
517 return RACH;
518 else if ((mod51 == 4) || (mod51 == 5))
519 return RACH;
520 else if ((mod51 == 45) || (mod51 == 46))
521 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300522 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
523 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000524 else
525 return TSC;
526 break;
527 }
528 case VII:
529 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
530 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300531 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
532 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000533 else
534 return TSC;
535 break;
ttsoufc40a842013-06-09 22:38:18 +0000536 case XIII: {
537 int mod52 = burstFN % 52;
538 if ((mod52 == 12) || (mod52 == 38))
539 return RACH;
540 else if ((mod52 == 25) || (mod52 == 51))
541 return IDLE;
542 else
543 return TSC;
544 break;
545 }
dburgessb3a0ca42011-10-12 07:44:40 +0000546 case LOOPBACK:
547 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
548 return IDLE;
549 else
550 return TSC;
551 break;
552 default:
553 return OFF;
554 break;
555 }
dburgessb3a0ca42011-10-12 07:44:40 +0000556}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400557
Tom Tsou46569402016-03-06 01:59:38 -0800558int Transceiver::detectBurst(TransceiverState *state, signalVector &burst,
559 complex &amp, float &toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500560{
Tom Tsou46569402016-03-06 01:59:38 -0800561 float threshold = 5.0, rc = 0;
Thomas Tsou30421a72013-11-13 23:14:48 -0500562
Tom Tsou46569402016-03-06 01:59:38 -0800563 switch (type) {
564 case TSC:
565 rc = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx,
566 amp, toa, mMaxExpectedDelay);
567 break;
568 case RACH:
569 threshold = 6.0;
570 rc = detectRACHBurst(burst, threshold, mSPSRx, amp, toa);
571 break;
572 default:
573 LOG(ERR) << "Invalid correlation type";
574 }
575
576
577 return rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500578}
579
Thomas Tsou30421a72013-11-13 23:14:48 -0500580
581/*
Tom Tsou46569402016-03-06 01:59:38 -0800582 * Demodulate GMSK by direct rotation and soft slicing.
Thomas Tsou30421a72013-11-13 23:14:48 -0500583 */
584SoftVector *Transceiver::demodulate(TransceiverState *state,
585 signalVector &burst, complex amp,
Tom Tsou46569402016-03-06 01:59:38 -0800586 float toa)
Thomas Tsou30421a72013-11-13 23:14:48 -0500587{
Thomas Tsou30421a72013-11-13 23:14:48 -0500588 return demodulateBurst(burst, mSPSRx, amp, toa);
589}
590
Alexander Chemerise692ce92015-06-12 00:15:31 -0400591void writeToFile(radioVector *radio_burst, size_t chan)
592{
593 GSM::Time time = radio_burst->getTime();
594 std::ostringstream fname;
595 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
596 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
597 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
598 outfile.close();
599}
600
Thomas Tsou30421a72013-11-13 23:14:48 -0500601/*
602 * Pull bursts from the FIFO and handle according to the slot
603 * and burst correlation type. Equalzation is currently disabled.
604 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400605SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400606 double &timingOffset, double &noise,
607 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000608{
Alexander Chemeris954b1182015-06-04 15:39:41 -0400609 int success;
Thomas Tsou30421a72013-11-13 23:14:48 -0500610 complex amp;
611 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500612 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500613 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500614 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500615 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400616 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000617
Thomas Tsou30421a72013-11-13 23:14:48 -0500618 /* Blocking FIFO read */
619 radioVector *radio_burst = mReceiveFIFO[chan]->read();
620 if (!radio_burst)
621 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000622
Thomas Tsou30421a72013-11-13 23:14:48 -0500623 /* Set time and determine correlation type */
624 GSM::Time time = radio_burst->getTime();
625 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000626
Alexander Chemerise692ce92015-06-12 00:15:31 -0400627 /* Debug: dump bursts to disk */
628 /* bits 0-7 - chan 0 timeslots
629 * bits 8-15 - chan 1 timeslots */
630 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
631 writeToFile(radio_burst, chan);
632
Alexander Chemeris2b542102015-06-08 22:46:38 -0400633 /* No processing if the timeslot is off.
634 * Not even power level or noise calculation. */
635 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500636 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000637 return NULL;
638 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000639
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500640 /* Select the diversity channel with highest energy */
641 for (size_t i = 0; i < radio_burst->chans(); i++) {
642 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
643 if (pow > max) {
644 max = pow;
645 max_i = i;
646 }
647 avg += pow;
648 }
649
650 if (max_i < 0) {
651 LOG(ALERT) << "Received empty burst";
652 delete radio_burst;
653 return NULL;
654 }
655
Thomas Tsou30421a72013-11-13 23:14:48 -0500656 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500657 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500658 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400659
660 wTime = time;
661 RSSI = 20.0 * log10(rxFullScale / avg);
662
663 /* RSSI estimation are valid */
664 isRssiValid = true;
665
666 if (type == IDLE) {
667 /* Update noise levels */
668 state->mNoises.insert(avg);
669 state->mNoiseLev = state->mNoises.avg();
670 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
671
672 delete radio_burst;
673 return NULL;
674 } else {
675 /* Do not update noise levels */
676 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
677 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400678
Thomas Tsou30421a72013-11-13 23:14:48 -0500679 /* Detect normal or RACH bursts */
Tom Tsou46569402016-03-06 01:59:38 -0800680 success = detectBurst(state, *burst, amp, toa, type);
Thomas Tsouf0782732013-10-29 15:55:47 -0400681
Alexander Chemeris2b542102015-06-08 22:46:38 -0400682 /* Alert an error and exit */
Tom Tsou577cd022015-05-18 13:57:54 -0700683 if (success <= 0) {
Alexander Chemeris2b542102015-06-08 22:46:38 -0400684 if (success == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400685 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Alexander Chemeris2b542102015-06-08 22:46:38 -0400686 } else if (success != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400687 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700688 }
689
Thomas Tsou30421a72013-11-13 23:14:48 -0500690 delete radio_burst;
691 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000692 }
dburgessb3a0ca42011-10-12 07:44:40 +0000693
Alexander Chemeris2b542102015-06-08 22:46:38 -0400694 timingOffset = toa / mSPSRx;
695
Tom Tsou46569402016-03-06 01:59:38 -0800696 bits = demodulate(state, *burst, amp, toa);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500697
Thomas Tsou30421a72013-11-13 23:14:48 -0500698 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500699 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000700}
701
dburgessb3a0ca42011-10-12 07:44:40 +0000702void Transceiver::reset()
703{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400704 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
705 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000706}
707
708
Thomas Tsou204a9f12013-10-29 18:34:16 -0400709void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000710{
dburgessb3a0ca42011-10-12 07:44:40 +0000711 int MAX_PACKET_LENGTH = 100;
712
713 // check control socket
714 char buffer[MAX_PACKET_LENGTH];
715 int msgLen = -1;
716 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400717
Thomas Tsou204a9f12013-10-29 18:34:16 -0400718 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000719
720 if (msgLen < 1) {
721 return;
722 }
723
724 char cmdcheck[4];
725 char command[MAX_PACKET_LENGTH];
726 char response[MAX_PACKET_LENGTH];
727
728 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400729
730 if (!chan)
731 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000732
733 if (strcmp(cmdcheck,"CMD")!=0) {
734 LOG(WARNING) << "bogus message on control interface";
735 return;
736 }
737 LOG(INFO) << "command is " << buffer;
738
739 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800740 stop();
741 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000742 }
743 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800744 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000745 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800746 else
dburgessb3a0ca42011-10-12 07:44:40 +0000747 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300748 for (int i = 0; i < 8; i++) {
749 for (int j = 0; j < 8; j++)
750 mHandover[i][j] = false;
751 }
752 }
753 else if (strcmp(command,"HANDOVER")==0){
754 int ts=0,ss=0;
755 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
756 mHandover[ts][ss] = true;
757 LOG(WARNING) << "HANDOVER RACH at timeslot " << ts << " subslot " << ss;
758 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
759 }
760 else if (strcmp(command,"NOHANDOVER")==0){
761 int ts=0,ss=0;
762 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
763 mHandover[ts][ss] = false;
764 LOG(WARNING) << "NOHANDOVER at timeslot " << ts << " subslot " << ss;
765 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000766 }
767 else if (strcmp(command,"SETMAXDLY")==0) {
768 //set expected maximum time-of-arrival
769 int maxDelay;
770 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
771 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
772 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
773 }
774 else if (strcmp(command,"SETRXGAIN")==0) {
775 //set expected maximum time-of-arrival
776 int newGain;
777 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400778 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000779 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
780 }
781 else if (strcmp(command,"NOISELEV")==0) {
782 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500783 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000784 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500785 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000786 }
787 else {
788 sprintf(response,"RSP NOISELEV 1 0");
789 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500790 }
791 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800792 int power;
793 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
794 power = mRadioInterface->setPowerAttenuation(power, chan);
795 mStates[chan].mPower = power;
796 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000797 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500798 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800799 int power, step;
800 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
801 power = mStates[chan].mPower + step;
802 power = mRadioInterface->setPowerAttenuation(power, chan);
803 mStates[chan].mPower = power;
804 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000805 }
dburgessb3a0ca42011-10-12 07:44:40 +0000806 else if (strcmp(command,"RXTUNE")==0) {
807 // tune receiver
808 int freqKhz;
809 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500810 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400811 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000812 LOG(ALERT) << "RX failed to tune";
813 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
814 }
815 else
816 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
817 }
818 else if (strcmp(command,"TXTUNE")==0) {
819 // tune txmtr
820 int freqKhz;
821 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500822 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400823 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000824 LOG(ALERT) << "TX failed to tune";
825 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
826 }
827 else
828 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
829 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500830 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000831 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500832 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500833 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700834 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500835 sprintf(response, "RSP SETTSC 1 %d", TSC);
836 else if (chan && (TSC != mTSC))
837 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000838 else {
839 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400840 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000841 }
842 }
843 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700844 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000845 int corrCode;
846 int timeslot;
847 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
848 if ((timeslot < 0) || (timeslot > 7)) {
849 LOG(WARNING) << "bogus message on control interface";
850 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
851 return;
852 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400853 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
854 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000855 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
856
857 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400858 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
859 // debug command! may change or disapear without notice
860 // set a mask which bursts to dump to disk
861 int mask;
862 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
863 mWriteBurstToDiskMask = mask;
864 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
865 }
dburgessb3a0ca42011-10-12 07:44:40 +0000866 else {
867 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200868 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000869 }
870
Thomas Tsou204a9f12013-10-29 18:34:16 -0400871 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000872}
873
Thomas Tsou204a9f12013-10-29 18:34:16 -0400874bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000875{
dburgessb3a0ca42011-10-12 07:44:40 +0000876 char buffer[gSlotLen+50];
877
878 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400879 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000880
881 if (msgLen!=gSlotLen+1+4+1) {
882 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
883 return false;
884 }
885
886 int timeSlot = (int) buffer[0];
887 uint64_t frameNum = 0;
888 for (int i = 0; i < 4; i++)
889 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000890
dburgessb3a0ca42011-10-12 07:44:40 +0000891 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
892
893 int RSSI = (int) buffer[5];
894 static BitVector newBurst(gSlotLen);
895 BitVector::iterator itr = newBurst.begin();
896 char *bufferItr = buffer+6;
897 while (itr < newBurst.end())
898 *itr++ = *bufferItr++;
899
900 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400901
902 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000903
904 return true;
905
906
907}
dburgessb3a0ca42011-10-12 07:44:40 +0000908
Thomas Tsou204a9f12013-10-29 18:34:16 -0400909void Transceiver::driveReceiveRadio()
910{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400911 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400912 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400913 } else {
914 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
915 writeClockInterface();
916 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400917}
918
919void Transceiver::driveReceiveFIFO(size_t chan)
920{
dburgessb3a0ca42011-10-12 07:44:40 +0000921 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400922 double RSSI; // in dBFS
923 double dBm; // in dBm
924 double TOA; // in symbols
925 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400926 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000927 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400928 bool isRssiValid; // are RSSI, noise and burstTime valid
dburgessb3a0ca42011-10-12 07:44:40 +0000929
Alexander Chemeris2b542102015-06-08 22:46:38 -0400930 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000931
932 if (rxBurst) {
Alexander Chemerise8905a02015-06-03 23:47:56 -0400933 dBm = RSSI+rssiOffset;
934 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000935
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400936 LOG(DEBUG) << std::fixed << std::right
937 << " time: " << burstTime
938 << " RSSI: " << std::setw(5) << std::setprecision(1) << RSSI << "dBFS/" << std::setw(6) << -dBm << "dBm"
939 << " noise: " << std::setw(5) << std::setprecision(1) << noise << "dBFS/" << std::setw(6) << -(noise+rssiOffset) << "dBm"
940 << " TOA: " << std::setw(5) << std::setprecision(2) << TOA
941 << " bits: " << *rxBurst;
942
dburgessb3a0ca42011-10-12 07:44:40 +0000943 char burstString[gSlotLen+10];
944 burstString[0] = burstTime.TN();
945 for (int i = 0; i < 4; i++)
946 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400947 burstString[5] = (int)dBm;
948 burstString[6] = (TOAint >> 8) & 0x0ff;
949 burstString[7] = TOAint & 0x0ff;
dburgessb3a0ca42011-10-12 07:44:40 +0000950 SoftVector::iterator burstItr = rxBurst->begin();
951
952 for (unsigned int i = 0; i < gSlotLen; i++) {
953 burstString[8+i] =(char) round((*burstItr++)*255.0);
954 }
955 burstString[gSlotLen+9] = '\0';
956 delete rxBurst;
957
Thomas Tsou204a9f12013-10-29 18:34:16 -0400958 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +0000959 }
dburgessb3a0ca42011-10-12 07:44:40 +0000960}
961
Thomas Tsou204a9f12013-10-29 18:34:16 -0400962void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000963{
964
965 /**
966 Features a carefully controlled latency mechanism, to
967 assure that transmit packets arrive at the radio/USRP
968 before they need to be transmitted.
969
970 Deadline clock indicates the burst that needs to be
971 pushed into the FIFO right NOW. If transmit queue does
972 not have a burst, stick in filler data.
973 */
974
975
976 RadioClock *radioClock = (mRadioInterface->getClock());
977
978 if (mOn) {
979 //radioClock->wait(); // wait until clock updates
980 LOG(DEBUG) << "radio clock " << radioClock->get();
981 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
982 // if underrun, then we're not providing bursts to radio/USRP fast
983 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400984 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000985 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000986 // only update latency at the defined frame interval
987 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000988 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
989 LOG(INFO) << "new latency: " << mTransmitLatency;
990 mLatencyUpdateTime = radioClock->get();
991 }
992 }
993 else {
994 // if underrun hasn't occurred in the last sec (216 frames) drop
995 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000996 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000997 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
998 mTransmitLatency.decTN();
999 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1000 mLatencyUpdateTime = radioClock->get();
1001 }
1002 }
1003 }
dburgessb3a0ca42011-10-12 07:44:40 +00001004 }
dburgessb3a0ca42011-10-12 07:44:40 +00001005 // time to push burst to transmit FIFO
1006 pushRadioVector(mTransmitDeadlineClock);
1007 mTransmitDeadlineClock.incTN();
1008 }
dburgessb3a0ca42011-10-12 07:44:40 +00001009 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001010
1011 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001012}
1013
1014
1015
1016void Transceiver::writeClockInterface()
1017{
1018 char command[50];
1019 // FIXME -- This should be adaptive.
1020 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1021
1022 LOG(INFO) << "ClockInterface: sending " << command;
1023
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001024 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001025
1026 mLastClockUpdateTime = mTransmitDeadlineClock;
1027
Thomas Tsou92c16df2013-09-28 18:04:19 -04001028}
dburgessb3a0ca42011-10-12 07:44:40 +00001029
Thomas Tsou204a9f12013-10-29 18:34:16 -04001030void *RxUpperLoopAdapter(TransceiverChannel *chan)
1031{
1032 Transceiver *trx = chan->trx;
1033 size_t num = chan->num;
1034
1035 delete chan;
1036
Thomas Tsou7553aa92013-11-08 12:50:03 -05001037 trx->setPriority(0.42);
1038
Thomas Tsou204a9f12013-10-29 18:34:16 -04001039 while (1) {
1040 trx->driveReceiveFIFO(num);
1041 pthread_testcancel();
1042 }
1043 return NULL;
1044}
1045
1046void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001047{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001048 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001049
dburgessb3a0ca42011-10-12 07:44:40 +00001050 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001051 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001052 pthread_testcancel();
1053 }
1054 return NULL;
1055}
1056
Thomas Tsou204a9f12013-10-29 18:34:16 -04001057void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001058{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001059 transceiver->setPriority(0.44);
1060
Thomas Tsou92c16df2013-09-28 18:04:19 -04001061 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001062 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001063 pthread_testcancel();
1064 }
1065 return NULL;
1066}
1067
Thomas Tsou204a9f12013-10-29 18:34:16 -04001068void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001069{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001070 Transceiver *trx = chan->trx;
1071 size_t num = chan->num;
1072
1073 delete chan;
1074
dburgessb3a0ca42011-10-12 07:44:40 +00001075 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001076 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001077 pthread_testcancel();
1078 }
1079 return NULL;
1080}
1081
Thomas Tsou204a9f12013-10-29 18:34:16 -04001082void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001083{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001084 Transceiver *trx = chan->trx;
1085 size_t num = chan->num;
1086
1087 delete chan;
1088
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001089 trx->setPriority(0.40);
1090
dburgessb3a0ca42011-10-12 07:44:40 +00001091 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001092 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001093 pthread_testcancel();
1094 }
1095 return NULL;
1096}