blob: b88ec87768140f764fcba38de8ab032efed5bf2f [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
2* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
3*
4* This software is distributed under the terms of the GNU Public License.
5* See the COPYING file in the main directory for details.
6*
7* This use of this software may be subject to additional restrictions.
8* See the LEGAL file in the main directory for details.
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22*/
23
dburgessb3a0ca42011-10-12 07:44:40 +000024#include <stdio.h>
Alexander Chemerisfdbf9142015-06-03 23:47:56 -040025#include <iomanip> // std::setprecision
Alexander Chemerisf2bdd1a2015-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 Chemerisfdbf9142015-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),
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800151 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Alexander Chemerisfdbf9142015-06-03 23:47:56 -0400152 rssiOffset(wRssiOffset),
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800153 mSPSTx(wSPS), mSPSRx(1), mChans(wChans), mOn(false),
Alexander Chemerisf2bdd1a2015-06-12 00:15:31 -0400154 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0), mWriteBurstToDiskMask(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000155{
dburgessb3a0ca42011-10-12 07:44:40 +0000156 txFullScale = mRadioInterface->fullScaleInputValue();
157 rxFullScale = mRadioInterface->fullScaleOutputValue();
Alexander Chemeris3ac1cbf2015-06-20 01:38:47 +0300158
159 for (int i = 0; i < 8; i++) {
160 for (int j = 0; j < 8; j++)
161 mHandover[i][j] = false;
162 }
dburgessb3a0ca42011-10-12 07:44:40 +0000163}
164
165Transceiver::~Transceiver()
166{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800167 stop();
168
dburgessb3a0ca42011-10-12 07:44:40 +0000169 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400170
Thomas Tsou204a9f12013-10-29 18:34:16 -0400171 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800172 mControlServiceLoopThreads[i]->cancel();
173 mControlServiceLoopThreads[i]->join();
174 delete mControlServiceLoopThreads[i];
175
Thomas Tsou204a9f12013-10-29 18:34:16 -0400176 mTxPriorityQueues[i].clear();
177 delete mCtrlSockets[i];
178 delete mDataSockets[i];
Alexander Chemeriseac726b2015-06-30 22:37:12 -0400179 delete mClockSockets[i];
Thomas Tsou204a9f12013-10-29 18:34:16 -0400180 }
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{
Alexander Chemeriseac726b2015-06-30 22:37:12 -0400194 int t_srcport, t_dstport, 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
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400201 if (!sigProcLibSetup(mSPSTx)) {
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);
Alexander Chemeriseac726b2015-06-30 22:37:12 -0400208 mClockSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400209 mControlServiceLoopThreads.resize(mChans);
210 mTxPriorityQueueServiceLoopThreads.resize(mChans);
211 mRxServiceLoopThreads.resize(mChans);
212
213 mTxPriorityQueues.resize(mChans);
214 mReceiveFIFO.resize(mChans);
215 mStates.resize(mChans);
216
Thomas Tsouccb73e12014-04-15 17:41:28 -0400217 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700218 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400219 mStates[0].mRetrans = true;
220
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800221 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400222 for (size_t i = 0; i < mChans; i++) {
Alexander Chemeriseac726b2015-06-30 22:37:12 -0400223 t_srcport = mBasePort + 3 * i;
224 t_dstport = mBasePort + 3 * i + 100;
225 c_srcport = mBasePort + 3 * i + 1;
226 c_dstport = mBasePort + 3 * i + 101;
227 d_srcport = mBasePort + 3 * i + 2;
228 d_dstport = mBasePort + 3 * i + 102;
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500229
230 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
231 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Alexander Chemeriseac726b2015-06-30 22:37:12 -0400232 mClockSockets[i] = new UDPSocket(t_srcport, mAddr.c_str(), t_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400233 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400234
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800235 /* Randomize the central clock */
236 GSM::Time startTime(random() % gHyperframe, 0);
237 mRadioInterface->getClock()->set(startTime);
238 mTransmitDeadlineClock = startTime;
239 mLastClockUpdateTime = startTime;
240 mLatencyUpdateTime = startTime;
241
242 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400243 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800244 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400245 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800246 mControlServiceLoopThreads[i]->start((void * (*)(void*))
247 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400248
Tom Tsou64ad7122015-05-19 18:26:31 -0700249 if (i && filler == FILLER_DUMMY)
250 filler = FILLER_ZERO;
251
252 mStates[i].init(filler, mSPSTx, txFullScale, rtsc);
Thomas Tsou83e06892013-08-20 16:10:01 -0400253 }
254
255 return true;
256}
dburgessb3a0ca42011-10-12 07:44:40 +0000257
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800258/*
259 * Start the transceiver
260 *
261 * Submit command(s) to the radio device to commence streaming samples and
262 * launch threads to handle sample I/O. Re-synchronize the transmit burst
263 * counters to the central radio clock here as well.
264 */
265bool Transceiver::start()
266{
267 ScopedLock lock(mLock);
268
269 if (mOn) {
270 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300271 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800272 }
273
274 LOG(NOTICE) << "Starting the transceiver";
275
276 GSM::Time time = mRadioInterface->getClock()->get();
277 mTransmitDeadlineClock = time;
278 mLastClockUpdateTime = time;
279 mLatencyUpdateTime = time;
280
281 if (!mRadioInterface->start()) {
282 LOG(ALERT) << "Device failed to start";
283 return false;
284 }
285
286 /* Device is running - launch I/O threads */
287 mRxLowerLoopThread = new Thread(32768);
288 mTxLowerLoopThread = new Thread(32768);
289 mTxLowerLoopThread->start((void * (*)(void*))
290 TxLowerLoopAdapter,(void*) this);
291 mRxLowerLoopThread->start((void * (*)(void*))
292 RxLowerLoopAdapter,(void*) this);
293
294 /* Launch uplink and downlink burst processing threads */
295 for (size_t i = 0; i < mChans; i++) {
296 TransceiverChannel *chan = new TransceiverChannel(this, i);
297 mRxServiceLoopThreads[i] = new Thread(32768);
298 mRxServiceLoopThreads[i]->start((void * (*)(void*))
299 RxUpperLoopAdapter, (void*) chan);
300
301 chan = new TransceiverChannel(this, i);
302 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
303 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
304 TxUpperLoopAdapter, (void*) chan);
305 }
306
307 writeClockInterface();
308 mOn = true;
309 return true;
310}
311
312/*
313 * Stop the transceiver
314 *
315 * Perform stopping by disabling receive streaming and issuing cancellation
316 * requests to running threads. Most threads will timeout and terminate once
317 * device is disabled, but the transmit loop may block waiting on the central
318 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
319 * makes it to the thread cancellation point.
320 */
321void Transceiver::stop()
322{
323 ScopedLock lock(mLock);
324
325 if (!mOn)
326 return;
327
328 LOG(NOTICE) << "Stopping the transceiver";
329 mTxLowerLoopThread->cancel();
330 mRxLowerLoopThread->cancel();
331
332 for (size_t i = 0; i < mChans; i++) {
333 mRxServiceLoopThreads[i]->cancel();
334 mTxPriorityQueueServiceLoopThreads[i]->cancel();
335 }
336
337 LOG(INFO) << "Stopping the device";
338 mRadioInterface->stop();
339
340 for (size_t i = 0; i < mChans; i++) {
341 mRxServiceLoopThreads[i]->join();
342 mTxPriorityQueueServiceLoopThreads[i]->join();
343 delete mRxServiceLoopThreads[i];
344 delete mTxPriorityQueueServiceLoopThreads[i];
345
346 mTxPriorityQueues[i].clear();
347 }
348
349 mTxLowerLoopThread->join();
350 mRxLowerLoopThread->join();
351 delete mTxLowerLoopThread;
352 delete mRxLowerLoopThread;
353
354 mOn = false;
355 LOG(NOTICE) << "Transceiver stopped";
356}
357
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500358void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400359 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000360{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500361 signalVector *burst;
362 radioVector *radio_burst;
363
Thomas Tsou204a9f12013-10-29 18:34:16 -0400364 if (chan >= mTxPriorityQueues.size()) {
365 LOG(ALERT) << "Invalid channel " << chan;
366 return;
367 }
368
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500369 if (wTime.TN() > 7) {
370 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
371 return;
372 }
373
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500374 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
375 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000376
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500377 radio_burst = new radioVector(wTime, burst);
378
379 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000380}
381
Thomas Tsou15d743e2014-01-25 02:34:03 -0500382void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
383{
384 int TN, modFN;
385 TransceiverState *state = &mStates[chan];
386
387 TN = burst->getTime().TN();
388 modFN = burst->getTime().FN() % state->fillerModulus[TN];
389
390 delete state->fillerTable[modFN][TN];
391 state->fillerTable[modFN][TN] = burst->getVector();
392 burst->setVector(NULL);
393}
394
dburgessb3a0ca42011-10-12 07:44:40 +0000395void Transceiver::pushRadioVector(GSM::Time &nowTime)
396{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400397 int TN, modFN;
398 radioVector *burst;
399 TransceiverState *state;
400 std::vector<signalVector *> bursts(mChans);
401 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500402 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000403
Thomas Tsou204a9f12013-10-29 18:34:16 -0400404 for (size_t i = 0; i < mChans; i ++) {
405 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000406
Thomas Tsou204a9f12013-10-29 18:34:16 -0400407 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
408 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500409 if (state->mRetrans)
410 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500411 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400412 }
413
414 TN = nowTime.TN();
415 modFN = nowTime.FN() % state->fillerModulus[TN];
416
417 bursts[i] = state->fillerTable[modFN][TN];
418 zeros[i] = state->chanType[TN] == NONE;
419
420 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500421 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500422
423 if (state->mRetrans) {
424 updateFillerTable(i, burst);
425 } else {
426 burst->setVector(NULL);
427 filler[i] = false;
428 }
429
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500430 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400431 }
dburgessb3a0ca42011-10-12 07:44:40 +0000432 }
433
Thomas Tsou204a9f12013-10-29 18:34:16 -0400434 mRadioInterface->driveTransmitRadio(bursts, zeros);
435
Thomas Tsou15d743e2014-01-25 02:34:03 -0500436 for (size_t i = 0; i < mChans; i++) {
437 if (!filler[i])
438 delete bursts[i];
439 }
dburgessb3a0ca42011-10-12 07:44:40 +0000440}
441
Thomas Tsou204a9f12013-10-29 18:34:16 -0400442void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000443{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400444 TransceiverState *state = &mStates[chan];
445
446 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000447 case NONE:
448 case I:
449 case II:
450 case III:
451 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400452 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000453 break;
454 case IV:
455 case VI:
456 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400457 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000458 break;
459 //case V:
460 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400461 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000462 break;
ttsoufc40a842013-06-09 22:38:18 +0000463 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400464 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000465 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000466 default:
467 break;
468 }
469}
470
471
Thomas Tsou204a9f12013-10-29 18:34:16 -0400472Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
473 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000474{
Alexander Chemeris3ac1cbf2015-06-20 01:38:47 +0300475 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 };
476 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,
477 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 };
478 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,
479 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 -0400480 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000481 unsigned burstTN = currTime.TN();
482 unsigned burstFN = currTime.FN();
Alexander Chemeris3ac1cbf2015-06-20 01:38:47 +0300483 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000484
Thomas Tsou204a9f12013-10-29 18:34:16 -0400485 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000486 case NONE:
487 return OFF;
488 break;
489 case FILL:
490 return IDLE;
491 break;
492 case I:
Alexander Chemeris3ac1cbf2015-06-20 01:38:47 +0300493 // TODO: Are we expecting RACH on an IDLE frame?
494/* if (burstFN % 26 == 25)
495 return IDLE;*/
496 if (mHandover[burstTN][0])
497 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000498 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000499 break;
500 case II:
Alexander Chemeris3ac1cbf2015-06-20 01:38:47 +0300501 subch = tchh_subslot[burstFN % 26];
502 if (subch == 1)
503 return IDLE;
504 if (mHandover[burstTN][0])
505 return RACH;
ttsou20642972013-03-27 22:00:25 +0000506 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000507 break;
508 case III:
Alexander Chemeris3ac1cbf2015-06-20 01:38:47 +0300509 subch = tchh_subslot[burstFN % 26];
510 if (mHandover[burstTN][subch])
511 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000512 return TSC;
513 break;
514 case IV:
515 case VI:
516 return RACH;
517 break;
518 case V: {
519 int mod51 = burstFN % 51;
520 if ((mod51 <= 36) && (mod51 >= 14))
521 return RACH;
522 else if ((mod51 == 4) || (mod51 == 5))
523 return RACH;
524 else if ((mod51 == 45) || (mod51 == 46))
525 return RACH;
Alexander Chemeris3ac1cbf2015-06-20 01:38:47 +0300526 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
527 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000528 else
529 return TSC;
530 break;
531 }
532 case VII:
533 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
534 return IDLE;
Alexander Chemeris3ac1cbf2015-06-20 01:38:47 +0300535 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
536 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000537 else
538 return TSC;
539 break;
ttsoufc40a842013-06-09 22:38:18 +0000540 case XIII: {
541 int mod52 = burstFN % 52;
542 if ((mod52 == 12) || (mod52 == 38))
543 return RACH;
544 else if ((mod52 == 25) || (mod52 == 51))
545 return IDLE;
546 else
547 return TSC;
548 break;
549 }
dburgessb3a0ca42011-10-12 07:44:40 +0000550 case LOOPBACK:
551 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
552 return IDLE;
553 else
554 return TSC;
555 break;
556 default:
557 return OFF;
558 break;
559 }
dburgessb3a0ca42011-10-12 07:44:40 +0000560}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400561
Thomas Tsou30421a72013-11-13 23:14:48 -0500562/*
563 * Detect RACH synchronization sequence within a burst. No equalization
564 * is used or available on the RACH channel.
565 */
Alexander Chemerisded68da2015-06-04 15:39:41 -0400566int Transceiver::detectRACH(TransceiverState *state,
567 signalVector &burst,
568 complex &amp, float &toa)
Thomas Tsou30421a72013-11-13 23:14:48 -0500569{
570 float threshold = 6.0;
571
Alexander Chemeris03095162015-06-09 20:52:11 -0400572 return detectRACHBurst(burst, threshold, mSPSRx, amp, toa);
Thomas Tsou30421a72013-11-13 23:14:48 -0500573}
574
575/*
576 * Detect normal burst training sequence midamble. Update equalization
577 * state information and channel estimate if necessary. Equalization
578 * is currently disabled.
579 */
Alexander Chemerisded68da2015-06-04 15:39:41 -0400580int Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
581 complex &amp, float &toa, GSM::Time &time)
Thomas Tsou30421a72013-11-13 23:14:48 -0500582{
Alexander Chemerisded68da2015-06-04 15:39:41 -0400583 int success;
Thomas Tsou30421a72013-11-13 23:14:48 -0500584 int tn = time.TN();
585 float chanOffset, threshold = 5.0;
Alexander Chemeris34e5a382015-06-10 22:18:31 -0400586 bool needDFE = false, estimateChan = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500587 double elapsed = time - state->chanEstimateTime[tn];
588 signalVector *chanResp;
589
590 /* Check equalization update state */
Thomas Tsoufb827d02013-11-16 16:14:12 -0500591 if (needDFE && ((elapsed > 50) || (!state->chanResponse[tn]))) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500592 delete state->DFEForward[tn];
593 delete state->DFEFeedback[tn];
594 state->DFEForward[tn] = NULL;
595 state->DFEFeedback[tn] = NULL;
596
597 estimateChan = true;
598 }
599
600 /* Detect normal burst midambles */
Alexander Chemeris03095162015-06-09 20:52:11 -0400601 success = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, amp,
602 toa, mMaxExpectedDelay, estimateChan,
Alexander Chemerisded68da2015-06-04 15:39:41 -0400603 &chanResp, &chanOffset);
604 if (success <= 0) {
605 return success;
Thomas Tsou30421a72013-11-13 23:14:48 -0500606 }
607
Thomas Tsou30421a72013-11-13 23:14:48 -0500608 /* Set equalizer if unabled */
609 if (needDFE && estimateChan) {
Alexander Chemeris34e5a382015-06-10 22:18:31 -0400610 float noise = state->mNoiseLev;
611 state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
612
Thomas Tsou30421a72013-11-13 23:14:48 -0500613 state->chanResponse[tn] = chanResp;
614 state->chanRespOffset[tn] = chanOffset;
615 state->chanRespAmplitude[tn] = amp;
616
617 scaleVector(*chanResp, complex(1.0, 0.0) / amp);
618
619 designDFE(*chanResp, state->SNRestimate[tn],
620 7, &state->DFEForward[tn], &state->DFEFeedback[tn]);
621
622 state->chanEstimateTime[tn] = time;
623 }
624
Alexander Chemerisded68da2015-06-04 15:39:41 -0400625 return 1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500626}
627
628/*
629 * Demodulate GMSK burst using equalization if requested. Otherwise
630 * demodulate by direct rotation and soft slicing.
631 */
632SoftVector *Transceiver::demodulate(TransceiverState *state,
633 signalVector &burst, complex amp,
634 float toa, size_t tn, bool equalize)
635{
636 if (equalize) {
637 scaleVector(burst, complex(1.0, 0.0) / amp);
638 return equalizeBurst(burst,
639 toa - state->chanRespOffset[tn],
640 mSPSRx,
641 *state->DFEForward[tn],
642 *state->DFEFeedback[tn]);
643 }
644
645 return demodulateBurst(burst, mSPSRx, amp, toa);
646}
647
Alexander Chemerisf2bdd1a2015-06-12 00:15:31 -0400648void writeToFile(radioVector *radio_burst, size_t chan)
649{
650 GSM::Time time = radio_burst->getTime();
651 std::ostringstream fname;
652 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
653 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
654 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
655 outfile.close();
656}
657
Thomas Tsou30421a72013-11-13 23:14:48 -0500658/*
659 * Pull bursts from the FIFO and handle according to the slot
660 * and burst correlation type. Equalzation is currently disabled.
661 */
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400662SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemeris37bbfa22015-06-04 00:14:51 -0400663 double &timingOffset, double &noise,
664 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000665{
Alexander Chemerisded68da2015-06-04 15:39:41 -0400666 int success;
667 bool equalize = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500668 complex amp;
669 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500670 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500671 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500672 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500673 TransceiverState *state = &mStates[chan];
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400674 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000675
Thomas Tsou30421a72013-11-13 23:14:48 -0500676 /* Blocking FIFO read */
677 radioVector *radio_burst = mReceiveFIFO[chan]->read();
678 if (!radio_burst)
679 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000680
Thomas Tsou30421a72013-11-13 23:14:48 -0500681 /* Set time and determine correlation type */
682 GSM::Time time = radio_burst->getTime();
683 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000684
Alexander Chemerisf2bdd1a2015-06-12 00:15:31 -0400685 /* Debug: dump bursts to disk */
686 /* bits 0-7 - chan 0 timeslots
687 * bits 8-15 - chan 1 timeslots */
688 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
689 writeToFile(radio_burst, chan);
690
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400691 /* No processing if the timeslot is off.
692 * Not even power level or noise calculation. */
693 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500694 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000695 return NULL;
696 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000697
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500698 /* Select the diversity channel with highest energy */
699 for (size_t i = 0; i < radio_burst->chans(); i++) {
700 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
701 if (pow > max) {
702 max = pow;
703 max_i = i;
704 }
705 avg += pow;
706 }
707
708 if (max_i < 0) {
709 LOG(ALERT) << "Received empty burst";
710 delete radio_burst;
711 return NULL;
712 }
713
Thomas Tsou30421a72013-11-13 23:14:48 -0500714 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500715 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500716 avg = sqrt(avg / radio_burst->chans());
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400717
718 wTime = time;
719 RSSI = 20.0 * log10(rxFullScale / avg);
720
721 /* RSSI estimation are valid */
722 isRssiValid = true;
723
724 if (type == IDLE) {
725 /* Update noise levels */
726 state->mNoises.insert(avg);
727 state->mNoiseLev = state->mNoises.avg();
728 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
729
730 delete radio_burst;
731 return NULL;
732 } else {
733 /* Do not update noise levels */
734 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
735 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400736
Thomas Tsou30421a72013-11-13 23:14:48 -0500737 /* Detect normal or RACH bursts */
738 if (type == TSC)
Thomas Tsoua0179e32013-11-14 15:52:04 -0500739 success = detectTSC(state, *burst, amp, toa, time);
Thomas Tsou30421a72013-11-13 23:14:48 -0500740 else
Thomas Tsoua0179e32013-11-14 15:52:04 -0500741 success = detectRACH(state, *burst, amp, toa);
Thomas Tsouf0782732013-10-29 15:55:47 -0400742
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400743 /* Alert an error and exit */
Tom Tsou577cd022015-05-18 13:57:54 -0700744 if (success <= 0) {
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400745 if (success == -SIGERR_CLIP) {
Alexander Chemerisded68da2015-06-04 15:39:41 -0400746 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400747 } else if (success != SIGERR_NONE) {
Alexander Chemerisded68da2015-06-04 15:39:41 -0400748 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700749 }
750
Thomas Tsou30421a72013-11-13 23:14:48 -0500751 delete radio_burst;
752 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000753 }
dburgessb3a0ca42011-10-12 07:44:40 +0000754
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400755 timingOffset = toa / mSPSRx;
756
Thomas Tsou30421a72013-11-13 23:14:48 -0500757 /* Demodulate and set output info */
758 if (equalize && (type != TSC))
759 equalize = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000760
Alexander Chemeris37b445d2015-06-07 01:10:11 -0400761 bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500762
Thomas Tsou30421a72013-11-13 23:14:48 -0500763 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500764 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000765}
766
dburgessb3a0ca42011-10-12 07:44:40 +0000767void Transceiver::reset()
768{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400769 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
770 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000771}
772
773
Thomas Tsou204a9f12013-10-29 18:34:16 -0400774void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000775{
dburgessb3a0ca42011-10-12 07:44:40 +0000776 int MAX_PACKET_LENGTH = 100;
777
778 // check control socket
779 char buffer[MAX_PACKET_LENGTH];
780 int msgLen = -1;
781 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400782
Thomas Tsou204a9f12013-10-29 18:34:16 -0400783 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000784
785 if (msgLen < 1) {
786 return;
787 }
788
789 char cmdcheck[4];
790 char command[MAX_PACKET_LENGTH];
791 char response[MAX_PACKET_LENGTH];
792
793 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400794
795 if (!chan)
796 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000797
798 if (strcmp(cmdcheck,"CMD")!=0) {
799 LOG(WARNING) << "bogus message on control interface";
800 return;
801 }
802 LOG(INFO) << "command is " << buffer;
803
804 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800805 stop();
806 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000807 }
808 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800809 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000810 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800811 else
dburgessb3a0ca42011-10-12 07:44:40 +0000812 sprintf(response,"RSP POWERON 0");
Alexander Chemeris3ac1cbf2015-06-20 01:38:47 +0300813 for (int i = 0; i < 8; i++) {
814 for (int j = 0; j < 8; j++)
815 mHandover[i][j] = false;
816 }
817 }
818 else if (strcmp(command,"HANDOVER")==0){
819 int ts=0,ss=0;
820 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
821 mHandover[ts][ss] = true;
822 LOG(WARNING) << "HANDOVER RACH at timeslot " << ts << " subslot " << ss;
823 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
824 }
825 else if (strcmp(command,"NOHANDOVER")==0){
826 int ts=0,ss=0;
827 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
828 mHandover[ts][ss] = false;
829 LOG(WARNING) << "NOHANDOVER at timeslot " << ts << " subslot " << ss;
830 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000831 }
832 else if (strcmp(command,"SETMAXDLY")==0) {
833 //set expected maximum time-of-arrival
834 int maxDelay;
835 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
836 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
837 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
838 }
839 else if (strcmp(command,"SETRXGAIN")==0) {
840 //set expected maximum time-of-arrival
841 int newGain;
842 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400843 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000844 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
845 }
846 else if (strcmp(command,"NOISELEV")==0) {
847 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500848 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000849 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500850 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000851 }
852 else {
853 sprintf(response,"RSP NOISELEV 1 0");
854 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500855 }
856 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800857 int power;
858 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
859 power = mRadioInterface->setPowerAttenuation(power, chan);
860 mStates[chan].mPower = power;
861 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000862 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500863 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800864 int power, step;
865 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
866 power = mStates[chan].mPower + step;
867 power = mRadioInterface->setPowerAttenuation(power, chan);
868 mStates[chan].mPower = power;
869 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000870 }
dburgessb3a0ca42011-10-12 07:44:40 +0000871 else if (strcmp(command,"RXTUNE")==0) {
872 // tune receiver
873 int freqKhz;
874 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500875 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400876 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000877 LOG(ALERT) << "RX failed to tune";
878 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
879 }
880 else
881 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
882 }
883 else if (strcmp(command,"TXTUNE")==0) {
884 // tune txmtr
885 int freqKhz;
886 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500887 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400888 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000889 LOG(ALERT) << "TX failed to tune";
890 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
891 }
892 else
893 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
894 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500895 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000896 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500897 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500898 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700899 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500900 sprintf(response, "RSP SETTSC 1 %d", TSC);
901 else if (chan && (TSC != mTSC))
902 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000903 else {
904 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400905 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400906 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000907 }
908 }
909 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700910 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000911 int corrCode;
912 int timeslot;
913 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
914 if ((timeslot < 0) || (timeslot > 7)) {
915 LOG(WARNING) << "bogus message on control interface";
916 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
917 return;
918 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400919 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
920 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000921 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
922
923 }
Alexander Chemerisf2bdd1a2015-06-12 00:15:31 -0400924 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
925 // debug command! may change or disapear without notice
926 // set a mask which bursts to dump to disk
927 int mask;
928 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
929 mWriteBurstToDiskMask = mask;
930 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
931 }
dburgessb3a0ca42011-10-12 07:44:40 +0000932 else {
933 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200934 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000935 }
936
Thomas Tsou204a9f12013-10-29 18:34:16 -0400937 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000938}
939
Thomas Tsou204a9f12013-10-29 18:34:16 -0400940bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000941{
dburgessb3a0ca42011-10-12 07:44:40 +0000942 char buffer[gSlotLen+50];
943
944 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400945 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000946
947 if (msgLen!=gSlotLen+1+4+1) {
948 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
949 return false;
950 }
951
952 int timeSlot = (int) buffer[0];
953 uint64_t frameNum = 0;
954 for (int i = 0; i < 4; i++)
955 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000956
dburgessb3a0ca42011-10-12 07:44:40 +0000957 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
958
959 int RSSI = (int) buffer[5];
960 static BitVector newBurst(gSlotLen);
961 BitVector::iterator itr = newBurst.begin();
962 char *bufferItr = buffer+6;
963 while (itr < newBurst.end())
964 *itr++ = *bufferItr++;
965
966 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400967
968 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000969
970 return true;
971
972
973}
dburgessb3a0ca42011-10-12 07:44:40 +0000974
Thomas Tsou204a9f12013-10-29 18:34:16 -0400975void Transceiver::driveReceiveRadio()
976{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400977 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400978 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400979 } else {
980 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
981 writeClockInterface();
982 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400983}
984
985void Transceiver::driveReceiveFIFO(size_t chan)
986{
dburgessb3a0ca42011-10-12 07:44:40 +0000987 SoftVector *rxBurst = NULL;
Alexander Chemerisfdbf9142015-06-03 23:47:56 -0400988 double RSSI; // in dBFS
989 double dBm; // in dBm
990 double TOA; // in symbols
991 int TOAint; // in 1/256 symbols
Alexander Chemeris37bbfa22015-06-04 00:14:51 -0400992 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000993 GSM::Time burstTime;
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400994 bool isRssiValid; // are RSSI, noise and burstTime valid
dburgessb3a0ca42011-10-12 07:44:40 +0000995
Alexander Chemerisf0d8a582015-06-08 22:46:38 -0400996 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000997
998 if (rxBurst) {
Alexander Chemerisfdbf9142015-06-03 23:47:56 -0400999 dBm = RSSI+rssiOffset;
1000 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +00001001
Alexander Chemeris37bbfa22015-06-04 00:14:51 -04001002 LOG(DEBUG) << std::fixed << std::right
1003 << " time: " << burstTime
1004 << " RSSI: " << std::setw(5) << std::setprecision(1) << RSSI << "dBFS/" << std::setw(6) << -dBm << "dBm"
1005 << " noise: " << std::setw(5) << std::setprecision(1) << noise << "dBFS/" << std::setw(6) << -(noise+rssiOffset) << "dBm"
1006 << " TOA: " << std::setw(5) << std::setprecision(2) << TOA
1007 << " bits: " << *rxBurst;
1008
dburgessb3a0ca42011-10-12 07:44:40 +00001009 char burstString[gSlotLen+10];
1010 burstString[0] = burstTime.TN();
1011 for (int i = 0; i < 4; i++)
1012 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
Alexander Chemerisfdbf9142015-06-03 23:47:56 -04001013 burstString[5] = (int)dBm;
1014 burstString[6] = (TOAint >> 8) & 0x0ff;
1015 burstString[7] = TOAint & 0x0ff;
dburgessb3a0ca42011-10-12 07:44:40 +00001016 SoftVector::iterator burstItr = rxBurst->begin();
1017
1018 for (unsigned int i = 0; i < gSlotLen; i++) {
1019 burstString[8+i] =(char) round((*burstItr++)*255.0);
1020 }
1021 burstString[gSlotLen+9] = '\0';
1022 delete rxBurst;
1023
Thomas Tsou204a9f12013-10-29 18:34:16 -04001024 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +00001025 }
dburgessb3a0ca42011-10-12 07:44:40 +00001026}
1027
Thomas Tsou204a9f12013-10-29 18:34:16 -04001028void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +00001029{
1030
1031 /**
1032 Features a carefully controlled latency mechanism, to
1033 assure that transmit packets arrive at the radio/USRP
1034 before they need to be transmitted.
1035
1036 Deadline clock indicates the burst that needs to be
1037 pushed into the FIFO right NOW. If transmit queue does
1038 not have a burst, stick in filler data.
1039 */
1040
1041
1042 RadioClock *radioClock = (mRadioInterface->getClock());
1043
1044 if (mOn) {
1045 //radioClock->wait(); // wait until clock updates
1046 LOG(DEBUG) << "radio clock " << radioClock->get();
1047 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
1048 // if underrun, then we're not providing bursts to radio/USRP fast
1049 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -04001050 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001051 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +00001052 // only update latency at the defined frame interval
1053 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001054 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
1055 LOG(INFO) << "new latency: " << mTransmitLatency;
1056 mLatencyUpdateTime = radioClock->get();
1057 }
1058 }
1059 else {
1060 // if underrun hasn't occurred in the last sec (216 frames) drop
1061 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +00001062 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001063 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1064 mTransmitLatency.decTN();
1065 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1066 mLatencyUpdateTime = radioClock->get();
1067 }
1068 }
1069 }
dburgessb3a0ca42011-10-12 07:44:40 +00001070 }
dburgessb3a0ca42011-10-12 07:44:40 +00001071 // time to push burst to transmit FIFO
1072 pushRadioVector(mTransmitDeadlineClock);
1073 mTransmitDeadlineClock.incTN();
1074 }
dburgessb3a0ca42011-10-12 07:44:40 +00001075 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001076
1077 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001078}
1079
1080
1081
1082void Transceiver::writeClockInterface()
1083{
1084 char command[50];
1085 // FIXME -- This should be adaptive.
1086 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1087
1088 LOG(INFO) << "ClockInterface: sending " << command;
1089
Alexander Chemeriseac726b2015-06-30 22:37:12 -04001090 for (size_t i=0; i<mClockSockets.size(); i++)
1091 mClockSockets[i]->write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001092
1093 mLastClockUpdateTime = mTransmitDeadlineClock;
1094
Thomas Tsou92c16df2013-09-28 18:04:19 -04001095}
dburgessb3a0ca42011-10-12 07:44:40 +00001096
Thomas Tsou204a9f12013-10-29 18:34:16 -04001097void *RxUpperLoopAdapter(TransceiverChannel *chan)
1098{
1099 Transceiver *trx = chan->trx;
1100 size_t num = chan->num;
1101
1102 delete chan;
1103
Thomas Tsou7553aa92013-11-08 12:50:03 -05001104 trx->setPriority(0.42);
1105
Thomas Tsou204a9f12013-10-29 18:34:16 -04001106 while (1) {
1107 trx->driveReceiveFIFO(num);
1108 pthread_testcancel();
1109 }
1110 return NULL;
1111}
1112
1113void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001114{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001115 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001116
dburgessb3a0ca42011-10-12 07:44:40 +00001117 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001118 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001119 pthread_testcancel();
1120 }
1121 return NULL;
1122}
1123
Thomas Tsou204a9f12013-10-29 18:34:16 -04001124void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001125{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001126 transceiver->setPriority(0.44);
1127
Thomas Tsou92c16df2013-09-28 18:04:19 -04001128 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001129 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001130 pthread_testcancel();
1131 }
1132 return NULL;
1133}
1134
Thomas Tsou204a9f12013-10-29 18:34:16 -04001135void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001136{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001137 Transceiver *trx = chan->trx;
1138 size_t num = chan->num;
1139
1140 delete chan;
1141
dburgessb3a0ca42011-10-12 07:44:40 +00001142 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001143 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001144 pthread_testcancel();
1145 }
1146 return NULL;
1147}
1148
Thomas Tsou204a9f12013-10-29 18:34:16 -04001149void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001150{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001151 Transceiver *trx = chan->trx;
1152 size_t num = chan->num;
1153
1154 delete chan;
1155
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001156 trx->setPriority(0.40);
1157
dburgessb3a0ca42011-10-12 07:44:40 +00001158 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001159 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001160 pthread_testcancel();
1161 }
1162 return NULL;
1163}