blob: df41eacbd3749aad0c73f5223ec22237524b2c0e [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();
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
Thomas Tsou30421a72013-11-13 23:14:48 -0500558/*
559 * Detect RACH synchronization sequence within a burst. No equalization
560 * is used or available on the RACH channel.
561 */
Alexander Chemeris954b1182015-06-04 15:39:41 -0400562int Transceiver::detectRACH(TransceiverState *state,
563 signalVector &burst,
564 complex &amp, float &toa)
Thomas Tsou30421a72013-11-13 23:14:48 -0500565{
566 float threshold = 6.0;
567
Alexander Chemeris130a8002015-06-09 20:52:11 -0400568 return detectRACHBurst(burst, threshold, mSPSRx, amp, toa);
Thomas Tsou30421a72013-11-13 23:14:48 -0500569}
570
571/*
572 * Detect normal burst training sequence midamble. Update equalization
573 * state information and channel estimate if necessary. Equalization
574 * is currently disabled.
575 */
Alexander Chemeris954b1182015-06-04 15:39:41 -0400576int Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
577 complex &amp, float &toa, GSM::Time &time)
Thomas Tsou30421a72013-11-13 23:14:48 -0500578{
Alexander Chemeris954b1182015-06-04 15:39:41 -0400579 int success;
Thomas Tsou30421a72013-11-13 23:14:48 -0500580 int tn = time.TN();
581 float chanOffset, threshold = 5.0;
Alexander Chemeris81c68732015-06-10 22:18:31 -0400582 bool needDFE = false, estimateChan = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500583 double elapsed = time - state->chanEstimateTime[tn];
584 signalVector *chanResp;
585
586 /* Check equalization update state */
Thomas Tsoufb827d02013-11-16 16:14:12 -0500587 if (needDFE && ((elapsed > 50) || (!state->chanResponse[tn]))) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500588 delete state->DFEForward[tn];
589 delete state->DFEFeedback[tn];
590 state->DFEForward[tn] = NULL;
591 state->DFEFeedback[tn] = NULL;
592
593 estimateChan = true;
594 }
595
596 /* Detect normal burst midambles */
Alexander Chemeris130a8002015-06-09 20:52:11 -0400597 success = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, amp,
598 toa, mMaxExpectedDelay, estimateChan,
Alexander Chemeris954b1182015-06-04 15:39:41 -0400599 &chanResp, &chanOffset);
600 if (success <= 0) {
601 return success;
Thomas Tsou30421a72013-11-13 23:14:48 -0500602 }
603
Thomas Tsou30421a72013-11-13 23:14:48 -0500604 /* Set equalizer if unabled */
605 if (needDFE && estimateChan) {
Alexander Chemeris81c68732015-06-10 22:18:31 -0400606 float noise = state->mNoiseLev;
607 state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
608
Thomas Tsou30421a72013-11-13 23:14:48 -0500609 state->chanResponse[tn] = chanResp;
610 state->chanRespOffset[tn] = chanOffset;
611 state->chanRespAmplitude[tn] = amp;
612
613 scaleVector(*chanResp, complex(1.0, 0.0) / amp);
614
615 designDFE(*chanResp, state->SNRestimate[tn],
616 7, &state->DFEForward[tn], &state->DFEFeedback[tn]);
617
618 state->chanEstimateTime[tn] = time;
619 }
620
Alexander Chemeris954b1182015-06-04 15:39:41 -0400621 return 1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500622}
623
624/*
625 * Demodulate GMSK burst using equalization if requested. Otherwise
626 * demodulate by direct rotation and soft slicing.
627 */
628SoftVector *Transceiver::demodulate(TransceiverState *state,
629 signalVector &burst, complex amp,
630 float toa, size_t tn, bool equalize)
631{
632 if (equalize) {
633 scaleVector(burst, complex(1.0, 0.0) / amp);
634 return equalizeBurst(burst,
635 toa - state->chanRespOffset[tn],
636 mSPSRx,
637 *state->DFEForward[tn],
638 *state->DFEFeedback[tn]);
639 }
640
641 return demodulateBurst(burst, mSPSRx, amp, toa);
642}
643
Alexander Chemerise692ce92015-06-12 00:15:31 -0400644void writeToFile(radioVector *radio_burst, size_t chan)
645{
646 GSM::Time time = radio_burst->getTime();
647 std::ostringstream fname;
648 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
649 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
650 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
651 outfile.close();
652}
653
Thomas Tsou30421a72013-11-13 23:14:48 -0500654/*
655 * Pull bursts from the FIFO and handle according to the slot
656 * and burst correlation type. Equalzation is currently disabled.
657 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400658SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400659 double &timingOffset, double &noise,
660 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000661{
Alexander Chemeris954b1182015-06-04 15:39:41 -0400662 int success;
663 bool equalize = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500664 complex amp;
665 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500666 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500667 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500668 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500669 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400670 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000671
Thomas Tsou30421a72013-11-13 23:14:48 -0500672 /* Blocking FIFO read */
673 radioVector *radio_burst = mReceiveFIFO[chan]->read();
674 if (!radio_burst)
675 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000676
Thomas Tsou30421a72013-11-13 23:14:48 -0500677 /* Set time and determine correlation type */
678 GSM::Time time = radio_burst->getTime();
679 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000680
Alexander Chemerise692ce92015-06-12 00:15:31 -0400681 /* Debug: dump bursts to disk */
682 /* bits 0-7 - chan 0 timeslots
683 * bits 8-15 - chan 1 timeslots */
684 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
685 writeToFile(radio_burst, chan);
686
Alexander Chemeris2b542102015-06-08 22:46:38 -0400687 /* No processing if the timeslot is off.
688 * Not even power level or noise calculation. */
689 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500690 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000691 return NULL;
692 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000693
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500694 /* Select the diversity channel with highest energy */
695 for (size_t i = 0; i < radio_burst->chans(); i++) {
696 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
697 if (pow > max) {
698 max = pow;
699 max_i = i;
700 }
701 avg += pow;
702 }
703
704 if (max_i < 0) {
705 LOG(ALERT) << "Received empty burst";
706 delete radio_burst;
707 return NULL;
708 }
709
Thomas Tsou30421a72013-11-13 23:14:48 -0500710 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500711 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500712 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400713
714 wTime = time;
715 RSSI = 20.0 * log10(rxFullScale / avg);
716
717 /* RSSI estimation are valid */
718 isRssiValid = true;
719
720 if (type == IDLE) {
721 /* Update noise levels */
722 state->mNoises.insert(avg);
723 state->mNoiseLev = state->mNoises.avg();
724 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
725
726 delete radio_burst;
727 return NULL;
728 } else {
729 /* Do not update noise levels */
730 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
731 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400732
Thomas Tsou30421a72013-11-13 23:14:48 -0500733 /* Detect normal or RACH bursts */
734 if (type == TSC)
Thomas Tsoua0179e32013-11-14 15:52:04 -0500735 success = detectTSC(state, *burst, amp, toa, time);
Thomas Tsou30421a72013-11-13 23:14:48 -0500736 else
Thomas Tsoua0179e32013-11-14 15:52:04 -0500737 success = detectRACH(state, *burst, amp, toa);
Thomas Tsouf0782732013-10-29 15:55:47 -0400738
Alexander Chemeris2b542102015-06-08 22:46:38 -0400739 /* Alert an error and exit */
Tom Tsou577cd022015-05-18 13:57:54 -0700740 if (success <= 0) {
Alexander Chemeris2b542102015-06-08 22:46:38 -0400741 if (success == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400742 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Alexander Chemeris2b542102015-06-08 22:46:38 -0400743 } else if (success != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400744 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700745 }
746
Thomas Tsou30421a72013-11-13 23:14:48 -0500747 delete radio_burst;
748 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000749 }
dburgessb3a0ca42011-10-12 07:44:40 +0000750
Alexander Chemeris2b542102015-06-08 22:46:38 -0400751 timingOffset = toa / mSPSRx;
752
Thomas Tsou30421a72013-11-13 23:14:48 -0500753 /* Demodulate and set output info */
754 if (equalize && (type != TSC))
755 equalize = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000756
Alexander Chemeris2268c852015-06-07 01:10:11 -0400757 bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500758
Thomas Tsou30421a72013-11-13 23:14:48 -0500759 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500760 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000761}
762
dburgessb3a0ca42011-10-12 07:44:40 +0000763void Transceiver::reset()
764{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400765 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
766 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000767}
768
769
Thomas Tsou204a9f12013-10-29 18:34:16 -0400770void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000771{
dburgessb3a0ca42011-10-12 07:44:40 +0000772 int MAX_PACKET_LENGTH = 100;
773
774 // check control socket
775 char buffer[MAX_PACKET_LENGTH];
776 int msgLen = -1;
777 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400778
Thomas Tsou204a9f12013-10-29 18:34:16 -0400779 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000780
781 if (msgLen < 1) {
782 return;
783 }
784
785 char cmdcheck[4];
786 char command[MAX_PACKET_LENGTH];
787 char response[MAX_PACKET_LENGTH];
788
789 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400790
791 if (!chan)
792 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000793
794 if (strcmp(cmdcheck,"CMD")!=0) {
795 LOG(WARNING) << "bogus message on control interface";
796 return;
797 }
798 LOG(INFO) << "command is " << buffer;
799
800 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800801 stop();
802 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000803 }
804 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800805 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000806 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800807 else
dburgessb3a0ca42011-10-12 07:44:40 +0000808 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300809 for (int i = 0; i < 8; i++) {
810 for (int j = 0; j < 8; j++)
811 mHandover[i][j] = false;
812 }
813 }
814 else if (strcmp(command,"HANDOVER")==0){
815 int ts=0,ss=0;
816 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
817 mHandover[ts][ss] = true;
818 LOG(WARNING) << "HANDOVER RACH at timeslot " << ts << " subslot " << ss;
819 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
820 }
821 else if (strcmp(command,"NOHANDOVER")==0){
822 int ts=0,ss=0;
823 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
824 mHandover[ts][ss] = false;
825 LOG(WARNING) << "NOHANDOVER at timeslot " << ts << " subslot " << ss;
826 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000827 }
828 else if (strcmp(command,"SETMAXDLY")==0) {
829 //set expected maximum time-of-arrival
830 int maxDelay;
831 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
832 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
833 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
834 }
835 else if (strcmp(command,"SETRXGAIN")==0) {
836 //set expected maximum time-of-arrival
837 int newGain;
838 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400839 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000840 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
841 }
842 else if (strcmp(command,"NOISELEV")==0) {
843 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500844 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000845 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500846 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000847 }
848 else {
849 sprintf(response,"RSP NOISELEV 1 0");
850 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500851 }
852 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800853 int power;
854 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
855 power = mRadioInterface->setPowerAttenuation(power, chan);
856 mStates[chan].mPower = power;
857 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000858 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500859 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800860 int power, step;
861 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
862 power = mStates[chan].mPower + step;
863 power = mRadioInterface->setPowerAttenuation(power, chan);
864 mStates[chan].mPower = power;
865 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000866 }
dburgessb3a0ca42011-10-12 07:44:40 +0000867 else if (strcmp(command,"RXTUNE")==0) {
868 // tune receiver
869 int freqKhz;
870 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500871 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400872 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000873 LOG(ALERT) << "RX failed to tune";
874 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
875 }
876 else
877 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
878 }
879 else if (strcmp(command,"TXTUNE")==0) {
880 // tune txmtr
881 int freqKhz;
882 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500883 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400884 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000885 LOG(ALERT) << "TX failed to tune";
886 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
887 }
888 else
889 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
890 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500891 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000892 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500893 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500894 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700895 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500896 sprintf(response, "RSP SETTSC 1 %d", TSC);
897 else if (chan && (TSC != mTSC))
898 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000899 else {
900 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400901 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000902 }
903 }
904 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700905 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000906 int corrCode;
907 int timeslot;
908 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
909 if ((timeslot < 0) || (timeslot > 7)) {
910 LOG(WARNING) << "bogus message on control interface";
911 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
912 return;
913 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400914 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
915 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000916 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
917
918 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400919 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
920 // debug command! may change or disapear without notice
921 // set a mask which bursts to dump to disk
922 int mask;
923 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
924 mWriteBurstToDiskMask = mask;
925 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
926 }
dburgessb3a0ca42011-10-12 07:44:40 +0000927 else {
928 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200929 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000930 }
931
Thomas Tsou204a9f12013-10-29 18:34:16 -0400932 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000933}
934
Thomas Tsou204a9f12013-10-29 18:34:16 -0400935bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000936{
dburgessb3a0ca42011-10-12 07:44:40 +0000937 char buffer[gSlotLen+50];
938
939 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400940 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000941
942 if (msgLen!=gSlotLen+1+4+1) {
943 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
944 return false;
945 }
946
947 int timeSlot = (int) buffer[0];
948 uint64_t frameNum = 0;
949 for (int i = 0; i < 4; i++)
950 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000951
dburgessb3a0ca42011-10-12 07:44:40 +0000952 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
953
954 int RSSI = (int) buffer[5];
955 static BitVector newBurst(gSlotLen);
956 BitVector::iterator itr = newBurst.begin();
957 char *bufferItr = buffer+6;
958 while (itr < newBurst.end())
959 *itr++ = *bufferItr++;
960
961 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400962
963 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000964
965 return true;
966
967
968}
dburgessb3a0ca42011-10-12 07:44:40 +0000969
Thomas Tsou204a9f12013-10-29 18:34:16 -0400970void Transceiver::driveReceiveRadio()
971{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400972 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400973 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400974 } else {
975 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
976 writeClockInterface();
977 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400978}
979
980void Transceiver::driveReceiveFIFO(size_t chan)
981{
dburgessb3a0ca42011-10-12 07:44:40 +0000982 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400983 double RSSI; // in dBFS
984 double dBm; // in dBm
985 double TOA; // in symbols
986 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400987 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000988 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400989 bool isRssiValid; // are RSSI, noise and burstTime valid
dburgessb3a0ca42011-10-12 07:44:40 +0000990
Alexander Chemeris2b542102015-06-08 22:46:38 -0400991 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000992
993 if (rxBurst) {
Alexander Chemerise8905a02015-06-03 23:47:56 -0400994 dBm = RSSI+rssiOffset;
995 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000996
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400997 LOG(DEBUG) << std::fixed << std::right
998 << " time: " << burstTime
999 << " RSSI: " << std::setw(5) << std::setprecision(1) << RSSI << "dBFS/" << std::setw(6) << -dBm << "dBm"
1000 << " noise: " << std::setw(5) << std::setprecision(1) << noise << "dBFS/" << std::setw(6) << -(noise+rssiOffset) << "dBm"
1001 << " TOA: " << std::setw(5) << std::setprecision(2) << TOA
1002 << " bits: " << *rxBurst;
1003
dburgessb3a0ca42011-10-12 07:44:40 +00001004 char burstString[gSlotLen+10];
1005 burstString[0] = burstTime.TN();
1006 for (int i = 0; i < 4; i++)
1007 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
Alexander Chemerise8905a02015-06-03 23:47:56 -04001008 burstString[5] = (int)dBm;
1009 burstString[6] = (TOAint >> 8) & 0x0ff;
1010 burstString[7] = TOAint & 0x0ff;
dburgessb3a0ca42011-10-12 07:44:40 +00001011 SoftVector::iterator burstItr = rxBurst->begin();
1012
1013 for (unsigned int i = 0; i < gSlotLen; i++) {
1014 burstString[8+i] =(char) round((*burstItr++)*255.0);
1015 }
1016 burstString[gSlotLen+9] = '\0';
1017 delete rxBurst;
1018
Thomas Tsou204a9f12013-10-29 18:34:16 -04001019 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +00001020 }
dburgessb3a0ca42011-10-12 07:44:40 +00001021}
1022
Thomas Tsou204a9f12013-10-29 18:34:16 -04001023void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +00001024{
1025
1026 /**
1027 Features a carefully controlled latency mechanism, to
1028 assure that transmit packets arrive at the radio/USRP
1029 before they need to be transmitted.
1030
1031 Deadline clock indicates the burst that needs to be
1032 pushed into the FIFO right NOW. If transmit queue does
1033 not have a burst, stick in filler data.
1034 */
1035
1036
1037 RadioClock *radioClock = (mRadioInterface->getClock());
1038
1039 if (mOn) {
1040 //radioClock->wait(); // wait until clock updates
1041 LOG(DEBUG) << "radio clock " << radioClock->get();
1042 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
1043 // if underrun, then we're not providing bursts to radio/USRP fast
1044 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -04001045 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001046 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +00001047 // only update latency at the defined frame interval
1048 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001049 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
1050 LOG(INFO) << "new latency: " << mTransmitLatency;
1051 mLatencyUpdateTime = radioClock->get();
1052 }
1053 }
1054 else {
1055 // if underrun hasn't occurred in the last sec (216 frames) drop
1056 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +00001057 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001058 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1059 mTransmitLatency.decTN();
1060 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1061 mLatencyUpdateTime = radioClock->get();
1062 }
1063 }
1064 }
dburgessb3a0ca42011-10-12 07:44:40 +00001065 }
dburgessb3a0ca42011-10-12 07:44:40 +00001066 // time to push burst to transmit FIFO
1067 pushRadioVector(mTransmitDeadlineClock);
1068 mTransmitDeadlineClock.incTN();
1069 }
dburgessb3a0ca42011-10-12 07:44:40 +00001070 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001071
1072 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001073}
1074
1075
1076
1077void Transceiver::writeClockInterface()
1078{
1079 char command[50];
1080 // FIXME -- This should be adaptive.
1081 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1082
1083 LOG(INFO) << "ClockInterface: sending " << command;
1084
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001085 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001086
1087 mLastClockUpdateTime = mTransmitDeadlineClock;
1088
Thomas Tsou92c16df2013-09-28 18:04:19 -04001089}
dburgessb3a0ca42011-10-12 07:44:40 +00001090
Thomas Tsou204a9f12013-10-29 18:34:16 -04001091void *RxUpperLoopAdapter(TransceiverChannel *chan)
1092{
1093 Transceiver *trx = chan->trx;
1094 size_t num = chan->num;
1095
1096 delete chan;
1097
Thomas Tsou7553aa92013-11-08 12:50:03 -05001098 trx->setPriority(0.42);
1099
Thomas Tsou204a9f12013-10-29 18:34:16 -04001100 while (1) {
1101 trx->driveReceiveFIFO(num);
1102 pthread_testcancel();
1103 }
1104 return NULL;
1105}
1106
1107void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001108{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001109 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001110
dburgessb3a0ca42011-10-12 07:44:40 +00001111 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001112 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001113 pthread_testcancel();
1114 }
1115 return NULL;
1116}
1117
Thomas Tsou204a9f12013-10-29 18:34:16 -04001118void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001119{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001120 transceiver->setPriority(0.44);
1121
Thomas Tsou92c16df2013-09-28 18:04:19 -04001122 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001123 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001124 pthread_testcancel();
1125 }
1126 return NULL;
1127}
1128
Thomas Tsou204a9f12013-10-29 18:34:16 -04001129void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001130{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001131 Transceiver *trx = chan->trx;
1132 size_t num = chan->num;
1133
1134 delete chan;
1135
dburgessb3a0ca42011-10-12 07:44:40 +00001136 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001137 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001138 pthread_testcancel();
1139 }
1140 return NULL;
1141}
1142
Thomas Tsou204a9f12013-10-29 18:34:16 -04001143void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001144{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001145 Transceiver *trx = chan->trx;
1146 size_t num = chan->num;
1147
1148 delete chan;
1149
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001150 trx->setPriority(0.40);
1151
dburgessb3a0ca42011-10-12 07:44:40 +00001152 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001153 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001154 pthread_testcancel();
1155 }
1156 return NULL;
1157}