blob: 2ec0c57f35ec2946bd2a4ea59b218dd99f375862 [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;
Thomas Tsouf0782732013-10-29 15:55:47 -040053
54 for (int n = 0; n < 102; n++)
55 fillerTable[n][i] = NULL;
56 }
57}
58
59TransceiverState::~TransceiverState()
60{
61 for (int i = 0; i < 8; i++) {
Thomas Tsouf0782732013-10-29 15:55:47 -040062 for (int n = 0; n < 102; n++)
63 delete fillerTable[n][i];
64 }
65}
66
Tom Tsou64ad7122015-05-19 18:26:31 -070067static BitVector *genRandNormalBurst(size_t tsc)
Thomas Tsouf0782732013-10-29 15:55:47 -040068{
Tom Tsou64ad7122015-05-19 18:26:31 -070069 if (tsc > 7)
70 return NULL;
Thomas Tsou15d743e2014-01-25 02:34:03 -050071
Tom Tsou64ad7122015-05-19 18:26:31 -070072 BitVector *bits = new BitVector(148);
Thomas Tsou15d743e2014-01-25 02:34:03 -050073
Tom Tsou64ad7122015-05-19 18:26:31 -070074 size_t i = 0;
75
76 /* Tail bits */
77 for (; i < 4; i++)
78 (*bits)[i] = 0;
79
80 /* Random bits */
81 for (; i < 61; i++)
82 (*bits)[i] = rand() % 2;
83
84 /* Training sequence */
Alexander Chemeris29660482015-05-24 19:13:38 -040085 for (int j = 0; i < 87; i++, j++)
86 (*bits)[i] = GSM::gTrainingSequence[tsc][j];
Tom Tsou64ad7122015-05-19 18:26:31 -070087
88 /* Random bits */
89 for (; i < 144; i++)
90 (*bits)[i] = rand() % 2;
91
92 /* Tail bits */
93 for (; i < 148; i++)
94 (*bits)[i] = 0;
95
96 return bits;
97}
98
99bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc)
100{
101 BitVector *bits;
102 signalVector *burst;
103
104 if ((sps != 1) && (sps != 4))
105 return false;
106
107 for (size_t n = 0; n < 8; n++) {
108 size_t guard = 8 + !(n % 4);
109 size_t len = sps == 4 ? 625 : 148 + guard;
110
111 for (size_t i = 0; i < 102; i++) {
112 switch (filler) {
113 case Transceiver::FILLER_DUMMY:
114 burst = modulateBurst(gDummyBurst, guard, sps);
115 break;
116 case Transceiver::FILLER_RAND:
117 bits = genRandNormalBurst(rtsc);
118 burst = modulateBurst(*bits, guard, sps);
119 delete bits;
120 break;
121 case Transceiver::FILLER_ZERO:
122 default:
123 burst = new signalVector(len);
124 }
125
126 scaleVector(*burst, scale);
127 fillerTable[i][n] = burst;
128 }
129
130 if (filler == Transceiver::FILLER_RAND)
131 chanType[n] = Transceiver::TSC;
Thomas Tsou15d743e2014-01-25 02:34:03 -0500132 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700133
134 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400135}
136
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800137void Transceiver::reset()
138{
139 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
140 mTxPriorityQueues[i].clear();
141}
142
dburgessb3a0ca42011-10-12 07:44:40 +0000143Transceiver::Transceiver(int wBasePort,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400144 const char *wTRXAddress,
145 size_t wSPS, size_t wChans,
146 GSM::Time wTransmitLatency,
147 RadioInterface *wRadioInterface,
Alexander Chemeris9155d8d2015-11-13 11:00:21 -0800148 double wRssiOffset,
149 bool wExternalDemod)
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),
Alexander Chemeris9155d8d2015-11-13 11:00:21 -0800154 mExternalDemod(wExternalDemod),
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800155 mSPSTx(wSPS), mSPSRx(1), mChans(wChans), mOn(false),
Alexander Chemerise692ce92015-06-12 00:15:31 -0400156 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0), mWriteBurstToDiskMask(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000157{
dburgessb3a0ca42011-10-12 07:44:40 +0000158 txFullScale = mRadioInterface->fullScaleInputValue();
159 rxFullScale = mRadioInterface->fullScaleOutputValue();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300160
161 for (int i = 0; i < 8; i++) {
162 for (int j = 0; j < 8; j++)
163 mHandover[i][j] = false;
164 }
dburgessb3a0ca42011-10-12 07:44:40 +0000165}
166
167Transceiver::~Transceiver()
168{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800169 stop();
170
dburgessb3a0ca42011-10-12 07:44:40 +0000171 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400172
Thomas Tsou204a9f12013-10-29 18:34:16 -0400173 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800174 mControlServiceLoopThreads[i]->cancel();
175 mControlServiceLoopThreads[i]->join();
176 delete mControlServiceLoopThreads[i];
177
Thomas Tsou204a9f12013-10-29 18:34:16 -0400178 mTxPriorityQueues[i].clear();
179 delete mCtrlSockets[i];
180 delete mDataSockets[i];
181 }
dburgessb3a0ca42011-10-12 07:44:40 +0000182}
Thomas Tsou83e06892013-08-20 16:10:01 -0400183
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800184/*
185 * Initialize transceiver
186 *
187 * Start or restart the control loop. Any further control is handled through the
188 * socket API. Randomize the central radio clock set the downlink burst
189 * counters. Note that the clock will not update until the radio starts, but we
190 * are still expected to report clock indications through control channel
191 * activity.
192 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700193bool Transceiver::init(int filler, size_t rtsc)
Thomas Tsou83e06892013-08-20 16:10:01 -0400194{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500195 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400196
Thomas Tsou204a9f12013-10-29 18:34:16 -0400197 if (!mChans) {
198 LOG(ALERT) << "No channels assigned";
199 return false;
200 }
201
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400202 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400203 LOG(ALERT) << "Failed to initialize signal processing library";
204 return false;
205 }
206
Thomas Tsou204a9f12013-10-29 18:34:16 -0400207 mDataSockets.resize(mChans);
208 mCtrlSockets.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++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500223 c_srcport = mBasePort + 2 * i + 1;
224 c_dstport = mBasePort + 2 * i + 101;
225 d_srcport = mBasePort + 2 * i + 2;
Alexander Chemerisf8f000c2016-03-26 14:43:37 +0300226 d_dstport = mBasePort + 2 * i + (mExternalDemod?202:102);
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500227
228 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
229 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400230 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400231
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800232 /* Randomize the central clock */
233 GSM::Time startTime(random() % gHyperframe, 0);
234 mRadioInterface->getClock()->set(startTime);
235 mTransmitDeadlineClock = startTime;
236 mLastClockUpdateTime = startTime;
237 mLatencyUpdateTime = startTime;
238
239 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400240 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800241 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400242 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800243 mControlServiceLoopThreads[i]->start((void * (*)(void*))
244 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400245
Tom Tsou64ad7122015-05-19 18:26:31 -0700246 if (i && filler == FILLER_DUMMY)
247 filler = FILLER_ZERO;
248
249 mStates[i].init(filler, mSPSTx, txFullScale, rtsc);
Thomas Tsou83e06892013-08-20 16:10:01 -0400250 }
251
252 return true;
253}
dburgessb3a0ca42011-10-12 07:44:40 +0000254
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800255/*
256 * Start the transceiver
257 *
258 * Submit command(s) to the radio device to commence streaming samples and
259 * launch threads to handle sample I/O. Re-synchronize the transmit burst
260 * counters to the central radio clock here as well.
261 */
262bool Transceiver::start()
263{
264 ScopedLock lock(mLock);
265
266 if (mOn) {
267 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300268 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800269 }
270
271 LOG(NOTICE) << "Starting the transceiver";
272
273 GSM::Time time = mRadioInterface->getClock()->get();
274 mTransmitDeadlineClock = time;
275 mLastClockUpdateTime = time;
276 mLatencyUpdateTime = time;
277
278 if (!mRadioInterface->start()) {
279 LOG(ALERT) << "Device failed to start";
280 return false;
281 }
282
283 /* Device is running - launch I/O threads */
284 mRxLowerLoopThread = new Thread(32768);
285 mTxLowerLoopThread = new Thread(32768);
286 mTxLowerLoopThread->start((void * (*)(void*))
287 TxLowerLoopAdapter,(void*) this);
288 mRxLowerLoopThread->start((void * (*)(void*))
289 RxLowerLoopAdapter,(void*) this);
290
291 /* Launch uplink and downlink burst processing threads */
292 for (size_t i = 0; i < mChans; i++) {
293 TransceiverChannel *chan = new TransceiverChannel(this, i);
294 mRxServiceLoopThreads[i] = new Thread(32768);
295 mRxServiceLoopThreads[i]->start((void * (*)(void*))
296 RxUpperLoopAdapter, (void*) chan);
297
298 chan = new TransceiverChannel(this, i);
299 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
300 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
301 TxUpperLoopAdapter, (void*) chan);
302 }
303
304 writeClockInterface();
305 mOn = true;
306 return true;
307}
308
309/*
310 * Stop the transceiver
311 *
312 * Perform stopping by disabling receive streaming and issuing cancellation
313 * requests to running threads. Most threads will timeout and terminate once
314 * device is disabled, but the transmit loop may block waiting on the central
315 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
316 * makes it to the thread cancellation point.
317 */
318void Transceiver::stop()
319{
320 ScopedLock lock(mLock);
321
322 if (!mOn)
323 return;
324
325 LOG(NOTICE) << "Stopping the transceiver";
326 mTxLowerLoopThread->cancel();
327 mRxLowerLoopThread->cancel();
328
329 for (size_t i = 0; i < mChans; i++) {
330 mRxServiceLoopThreads[i]->cancel();
331 mTxPriorityQueueServiceLoopThreads[i]->cancel();
332 }
333
334 LOG(INFO) << "Stopping the device";
335 mRadioInterface->stop();
336
337 for (size_t i = 0; i < mChans; i++) {
338 mRxServiceLoopThreads[i]->join();
339 mTxPriorityQueueServiceLoopThreads[i]->join();
340 delete mRxServiceLoopThreads[i];
341 delete mTxPriorityQueueServiceLoopThreads[i];
342
343 mTxPriorityQueues[i].clear();
344 }
345
346 mTxLowerLoopThread->join();
347 mRxLowerLoopThread->join();
348 delete mTxLowerLoopThread;
349 delete mRxLowerLoopThread;
350
351 mOn = false;
352 LOG(NOTICE) << "Transceiver stopped";
353}
354
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500355void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400356 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000357{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500358 signalVector *burst;
359 radioVector *radio_burst;
360
Thomas Tsou204a9f12013-10-29 18:34:16 -0400361 if (chan >= mTxPriorityQueues.size()) {
362 LOG(ALERT) << "Invalid channel " << chan;
363 return;
364 }
365
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500366 if (wTime.TN() > 7) {
367 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
368 return;
369 }
370
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500371 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
372 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000373
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500374 radio_burst = new radioVector(wTime, burst);
375
376 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000377}
378
Thomas Tsou15d743e2014-01-25 02:34:03 -0500379void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
380{
381 int TN, modFN;
382 TransceiverState *state = &mStates[chan];
383
384 TN = burst->getTime().TN();
385 modFN = burst->getTime().FN() % state->fillerModulus[TN];
386
387 delete state->fillerTable[modFN][TN];
388 state->fillerTable[modFN][TN] = burst->getVector();
389 burst->setVector(NULL);
390}
391
dburgessb3a0ca42011-10-12 07:44:40 +0000392void Transceiver::pushRadioVector(GSM::Time &nowTime)
393{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400394 int TN, modFN;
395 radioVector *burst;
396 TransceiverState *state;
397 std::vector<signalVector *> bursts(mChans);
398 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500399 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000400
Thomas Tsou204a9f12013-10-29 18:34:16 -0400401 for (size_t i = 0; i < mChans; i ++) {
402 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000403
Thomas Tsou204a9f12013-10-29 18:34:16 -0400404 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
405 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500406 if (state->mRetrans)
407 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500408 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400409 }
410
411 TN = nowTime.TN();
412 modFN = nowTime.FN() % state->fillerModulus[TN];
413
414 bursts[i] = state->fillerTable[modFN][TN];
415 zeros[i] = state->chanType[TN] == NONE;
416
417 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500418 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500419
420 if (state->mRetrans) {
421 updateFillerTable(i, burst);
422 } else {
423 burst->setVector(NULL);
424 filler[i] = false;
425 }
426
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500427 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400428 }
dburgessb3a0ca42011-10-12 07:44:40 +0000429 }
430
Thomas Tsou204a9f12013-10-29 18:34:16 -0400431 mRadioInterface->driveTransmitRadio(bursts, zeros);
432
Thomas Tsou15d743e2014-01-25 02:34:03 -0500433 for (size_t i = 0; i < mChans; i++) {
434 if (!filler[i])
435 delete bursts[i];
436 }
dburgessb3a0ca42011-10-12 07:44:40 +0000437}
438
Thomas Tsou204a9f12013-10-29 18:34:16 -0400439void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000440{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400441 TransceiverState *state = &mStates[chan];
442
443 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000444 case NONE:
445 case I:
446 case II:
447 case III:
448 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400449 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000450 break;
451 case IV:
452 case VI:
453 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400454 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000455 break;
456 //case V:
457 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400458 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000459 break;
ttsoufc40a842013-06-09 22:38:18 +0000460 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400461 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000462 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000463 default:
464 break;
465 }
466}
467
468
Thomas Tsou204a9f12013-10-29 18:34:16 -0400469Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
470 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000471{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300472 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 };
473 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,
474 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 };
475 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,
476 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 -0400477 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000478 unsigned burstTN = currTime.TN();
479 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300480 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000481
Thomas Tsou204a9f12013-10-29 18:34:16 -0400482 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000483 case NONE:
484 return OFF;
485 break;
486 case FILL:
487 return IDLE;
488 break;
489 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300490 // TODO: Are we expecting RACH on an IDLE frame?
491/* if (burstFN % 26 == 25)
492 return IDLE;*/
493 if (mHandover[burstTN][0])
494 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000495 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000496 break;
497 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300498 subch = tchh_subslot[burstFN % 26];
499 if (subch == 1)
500 return IDLE;
501 if (mHandover[burstTN][0])
502 return RACH;
ttsou20642972013-03-27 22:00:25 +0000503 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000504 break;
505 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300506 subch = tchh_subslot[burstFN % 26];
507 if (mHandover[burstTN][subch])
508 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000509 return TSC;
510 break;
511 case IV:
512 case VI:
513 return RACH;
514 break;
515 case V: {
516 int mod51 = burstFN % 51;
517 if ((mod51 <= 36) && (mod51 >= 14))
518 return RACH;
519 else if ((mod51 == 4) || (mod51 == 5))
520 return RACH;
521 else if ((mod51 == 45) || (mod51 == 46))
522 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300523 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
524 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000525 else
526 return TSC;
527 break;
528 }
529 case VII:
530 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
531 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300532 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
533 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000534 else
535 return TSC;
536 break;
ttsoufc40a842013-06-09 22:38:18 +0000537 case XIII: {
538 int mod52 = burstFN % 52;
539 if ((mod52 == 12) || (mod52 == 38))
540 return RACH;
541 else if ((mod52 == 25) || (mod52 == 51))
542 return IDLE;
543 else
544 return TSC;
545 break;
546 }
dburgessb3a0ca42011-10-12 07:44:40 +0000547 case LOOPBACK:
548 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
549 return IDLE;
550 else
551 return TSC;
552 break;
553 default:
554 return OFF;
555 break;
556 }
dburgessb3a0ca42011-10-12 07:44:40 +0000557}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400558
Thomas Tsou30421a72013-11-13 23:14:48 -0500559/*
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800560 * Detect RACH synchronization sequence within a burst.
Thomas Tsou30421a72013-11-13 23:14:48 -0500561 */
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800562int Transceiver::detectRACH(signalVector &burst,
Alexander Chemeris954b1182015-06-04 15:39:41 -0400563 complex &amp, float &toa)
Thomas Tsou30421a72013-11-13 23:14:48 -0500564{
565 float threshold = 6.0;
566
Alexander Chemeris130a8002015-06-09 20:52:11 -0400567 return detectRACHBurst(burst, threshold, mSPSRx, amp, toa);
Thomas Tsou30421a72013-11-13 23:14:48 -0500568}
569
570/*
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800571 * Detect normal burst training sequence midamble.
Thomas Tsou30421a72013-11-13 23:14:48 -0500572 */
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800573int Transceiver::detectTSC(signalVector &burst,
574 complex &amp, float &toa)
Thomas Tsou30421a72013-11-13 23:14:48 -0500575{
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800576 float threshold = 5.0;
Thomas Tsou30421a72013-11-13 23:14:48 -0500577
578 /* Detect normal burst midambles */
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800579 return analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, amp,
580 toa, mMaxExpectedDelay);
Thomas Tsou30421a72013-11-13 23:14:48 -0500581}
582
Alexander Chemerise692ce92015-06-12 00:15:31 -0400583void writeToFile(radioVector *radio_burst, size_t chan)
584{
585 GSM::Time time = radio_burst->getTime();
586 std::ostringstream fname;
587 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
588 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
589 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
590 outfile.close();
591}
592
Thomas Tsou30421a72013-11-13 23:14:48 -0500593/*
594 * Pull bursts from the FIFO and handle according to the slot
595 * and burst correlation type. Equalzation is currently disabled.
596 */
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800597SoftVector *Transceiver::demodSignalVector(signalVector *burst,
598 CorrType type,
599 double &timingOffset)
dburgessb3a0ca42011-10-12 07:44:40 +0000600{
Alexander Chemeris954b1182015-06-04 15:39:41 -0400601 int success;
Thomas Tsou30421a72013-11-13 23:14:48 -0500602 complex amp;
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800603 float toa;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500604 SoftVector *bits = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000605
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800606 /* Detect normal or RACH bursts */
607 if (type == TSC)
608 success = detectTSC(*burst, amp, toa);
609 else
610 success = detectRACH(*burst, amp, toa);
dburgessb3a0ca42011-10-12 07:44:40 +0000611
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800612 /* Alert an error and exit */
613 if (success <= 0) {
614 if (success == -SIGERR_CLIP) {
615 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
616 } else if (success != SIGERR_NONE) {
617 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
618 }
dburgessb3a0ca42011-10-12 07:44:40 +0000619
dburgessb3a0ca42011-10-12 07:44:40 +0000620 return NULL;
621 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000622
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800623 timingOffset = toa / mSPSRx;
624
625 bits = demodulateBurst(*burst, mSPSRx, amp, toa);
626
627 return bits;
628}
629
630signalVector *Transceiver::chooseDiversityPath(radioVector *radio_burst, double &avg)
631{
632 signalVector *burst;
633 int max_i = -1;
634 float pow, max = -1.0;
635
636 avg = 0.0;
637
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500638 /* Select the diversity channel with highest energy */
639 for (size_t i = 0; i < radio_burst->chans(); i++) {
640 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
641 if (pow > max) {
642 max = pow;
643 max_i = i;
644 }
645 avg += pow;
646 }
647
648 if (max_i < 0) {
649 LOG(ALERT) << "Received empty burst";
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500650 return NULL;
651 }
652
Thomas Tsou30421a72013-11-13 23:14:48 -0500653 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500654 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500655 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400656
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800657 return burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000658}
659
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800660void TransceiverState::updateNoiseEstimates(double avg)
dburgessb3a0ca42011-10-12 07:44:40 +0000661{
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800662 /* Update noise levels */
663 mNoises.insert(avg);
664 mNoiseLev = mNoises.avg();
dburgessb3a0ca42011-10-12 07:44:40 +0000665}
666
Thomas Tsou204a9f12013-10-29 18:34:16 -0400667void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000668{
dburgessb3a0ca42011-10-12 07:44:40 +0000669 int MAX_PACKET_LENGTH = 100;
670
671 // check control socket
672 char buffer[MAX_PACKET_LENGTH];
673 int msgLen = -1;
674 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400675
Thomas Tsou204a9f12013-10-29 18:34:16 -0400676 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000677
678 if (msgLen < 1) {
679 return;
680 }
681
682 char cmdcheck[4];
683 char command[MAX_PACKET_LENGTH];
684 char response[MAX_PACKET_LENGTH];
685
686 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400687
688 if (!chan)
689 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000690
691 if (strcmp(cmdcheck,"CMD")!=0) {
692 LOG(WARNING) << "bogus message on control interface";
693 return;
694 }
695 LOG(INFO) << "command is " << buffer;
696
697 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800698 stop();
699 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000700 }
701 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800702 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000703 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800704 else
dburgessb3a0ca42011-10-12 07:44:40 +0000705 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300706 for (int i = 0; i < 8; i++) {
707 for (int j = 0; j < 8; j++)
708 mHandover[i][j] = false;
709 }
710 }
711 else if (strcmp(command,"HANDOVER")==0){
712 int ts=0,ss=0;
713 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
714 mHandover[ts][ss] = true;
715 LOG(WARNING) << "HANDOVER RACH at timeslot " << ts << " subslot " << ss;
716 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
717 }
718 else if (strcmp(command,"NOHANDOVER")==0){
719 int ts=0,ss=0;
720 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
721 mHandover[ts][ss] = false;
722 LOG(WARNING) << "NOHANDOVER at timeslot " << ts << " subslot " << ss;
723 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000724 }
725 else if (strcmp(command,"SETMAXDLY")==0) {
726 //set expected maximum time-of-arrival
727 int maxDelay;
728 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
729 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
730 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
731 }
732 else if (strcmp(command,"SETRXGAIN")==0) {
733 //set expected maximum time-of-arrival
734 int newGain;
735 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400736 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000737 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
738 }
739 else if (strcmp(command,"NOISELEV")==0) {
740 if (mOn) {
741 sprintf(response,"RSP NOISELEV 0 %d",
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800742 (int) round(dB2(rxFullScale / mStates[chan].mNoiseLev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000743 }
744 else {
745 sprintf(response,"RSP NOISELEV 1 0");
746 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500747 }
748 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800749 int power;
750 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
751 power = mRadioInterface->setPowerAttenuation(power, chan);
752 mStates[chan].mPower = power;
753 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000754 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500755 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800756 int power, step;
757 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
758 power = mStates[chan].mPower + step;
759 power = mRadioInterface->setPowerAttenuation(power, chan);
760 mStates[chan].mPower = power;
761 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000762 }
dburgessb3a0ca42011-10-12 07:44:40 +0000763 else if (strcmp(command,"RXTUNE")==0) {
764 // tune receiver
765 int freqKhz;
766 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500767 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400768 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000769 LOG(ALERT) << "RX failed to tune";
770 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
771 }
772 else
773 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
774 }
775 else if (strcmp(command,"TXTUNE")==0) {
776 // tune txmtr
777 int freqKhz;
778 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500779 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400780 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000781 LOG(ALERT) << "TX failed to tune";
782 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
783 }
784 else
785 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
786 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500787 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000788 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500789 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500790 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700791 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500792 sprintf(response, "RSP SETTSC 1 %d", TSC);
793 else if (chan && (TSC != mTSC))
794 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000795 else {
796 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400797 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400798 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000799 }
800 }
801 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700802 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000803 int corrCode;
804 int timeslot;
805 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
806 if ((timeslot < 0) || (timeslot > 7)) {
807 LOG(WARNING) << "bogus message on control interface";
808 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
809 return;
810 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400811 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
812 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000813 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
814
815 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400816 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
817 // debug command! may change or disapear without notice
818 // set a mask which bursts to dump to disk
819 int mask;
820 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
821 mWriteBurstToDiskMask = mask;
822 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
823 }
dburgessb3a0ca42011-10-12 07:44:40 +0000824 else {
825 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200826 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000827 }
828
Thomas Tsou204a9f12013-10-29 18:34:16 -0400829 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000830}
831
Thomas Tsou204a9f12013-10-29 18:34:16 -0400832bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000833{
dburgessb3a0ca42011-10-12 07:44:40 +0000834 char buffer[gSlotLen+50];
835
836 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400837 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000838
839 if (msgLen!=gSlotLen+1+4+1) {
840 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
841 return false;
842 }
843
844 int timeSlot = (int) buffer[0];
845 uint64_t frameNum = 0;
846 for (int i = 0; i < 4; i++)
847 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000848
dburgessb3a0ca42011-10-12 07:44:40 +0000849 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
850
851 int RSSI = (int) buffer[5];
852 static BitVector newBurst(gSlotLen);
853 BitVector::iterator itr = newBurst.begin();
854 char *bufferItr = buffer+6;
855 while (itr < newBurst.end())
856 *itr++ = *bufferItr++;
857
858 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400859
860 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000861
862 return true;
863
864
865}
dburgessb3a0ca42011-10-12 07:44:40 +0000866
Thomas Tsou204a9f12013-10-29 18:34:16 -0400867void Transceiver::driveReceiveRadio()
868{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400869 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400870 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400871 } else {
872 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
873 writeClockInterface();
874 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400875}
876
877void Transceiver::driveReceiveFIFO(size_t chan)
878{
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800879 radioVector *radio_burst = NULL;
880 signalVector *burst = NULL;
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800881 double burst_power; // sqr(amp)
Alexander Chemerise8905a02015-06-03 23:47:56 -0400882 double RSSI; // in dBFS
883 double dBm; // in dBm
884 double TOA; // in symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400885 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000886 GSM::Time burstTime;
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800887 CorrType burstType;
Alexander Chemeris9155d8d2015-11-13 11:00:21 -0800888 char burstString[3000];
889 int pktLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000890
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800891 /* Blocking FIFO read */
892 radio_burst = mReceiveFIFO[chan]->read();
893 if (!radio_burst)
894 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000895
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800896 /* Set time and determine correlation type */
897 burstTime = radio_burst->getTime();
898 burstType = expectedCorrType(burstTime, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000899
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800900 /* Debug: dump bursts to disk */
901 /* bits 0-7 - chan 0 timeslots
902 * bits 8-15 - chan 1 timeslots */
903 if (mWriteBurstToDiskMask & ((1<<burstTime.TN()) << (8*chan)))
904 writeToFile(radio_burst, chan);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400905
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800906 /* No processing if the timeslot is off. */
907 if (burstType == OFF) {
908 delete radio_burst;
909 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000910 }
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800911
912 /* Choose a diversity channel to use */
Alexander Chemerisf1c13792016-03-26 10:57:41 +0300913 /* Returned value is a pointer to the radio_burst internal structure */
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800914 burst = chooseDiversityPath(radio_burst, burst_power);
Alexander Chemerisf1c13792016-03-26 10:57:41 +0300915 if (!burst) {
916 delete radio_burst;
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800917 return;
Alexander Chemerisf1c13792016-03-26 10:57:41 +0300918 }
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800919
920 /* We use idle timeslots to calculate noise levels for informational purposes.
921 * Otherwise we ignore them. */
922 if (burstType == IDLE) {
923 mStates[chan].updateNoiseEstimates(burst_power);
924 return;
925 }
926
927 /* Update/calculate burst info */
928 noise = dB2(rxFullScale / mStates[chan].mNoiseLev);
929 RSSI = dB2(rxFullScale / burst_power);
930 dBm = RSSI+rssiOffset;
931
Alexander Chemeris9155d8d2015-11-13 11:00:21 -0800932 if (!mExternalDemod) {
933 /* Pre-process and demodulate radio vector */
934 SoftVector *rxBurst = demodSignalVector(burst, burstType, TOA);
935 if (!rxBurst)
936 return;
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800937
Alexander Chemeris9155d8d2015-11-13 11:00:21 -0800938 LOG(DEBUG) << std::fixed << std::right
939 << " time: " << burstTime
940 << " RSSI: " << std::setw(5) << std::setprecision(1) << RSSI << "dBFS/" << std::setw(6) << -dBm << "dBm"
941 << " noise: " << std::setw(5) << std::setprecision(1) << noise << "dBFS/" << std::setw(6) << -(noise+rssiOffset) << "dBm"
942 << " TOA: " << std::setw(5) << std::setprecision(2) << TOA
943 << " bits: " << *rxBurst;
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800944
Alexander Chemerisf1c13792016-03-26 10:57:41 +0300945 pktLen = formatDemodPacket(burstTime, dBm, TOA, rxBurst, burstString);
Alexander Chemeris9155d8d2015-11-13 11:00:21 -0800946 delete rxBurst;
947 } else {
948 /* Send radio vector as is */
Alexander Chemerisf1c13792016-03-26 10:57:41 +0300949 pktLen = formatRawPacket(burstTime, dBm, TOA, burstType, mTSC, burst, burstString);
Alexander Chemeris9155d8d2015-11-13 11:00:21 -0800950 }
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800951
Alexander Chemeris9155d8d2015-11-13 11:00:21 -0800952 mDataSockets[chan]->write(burstString, pktLen);
Alexander Chemeris8b8e7ec2015-11-13 10:08:36 -0800953
Alexander Chemerisf1c13792016-03-26 10:57:41 +0300954 delete radio_burst;
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800955}
956
Alexander Chemeris9155d8d2015-11-13 11:00:21 -0800957int Transceiver::formatCommonPacketHeader(GSM::Time burstTime, double dBm, double TOA,
Alexander Chemerisbb7b0572015-11-13 11:10:04 -0800958 char *burstString)
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800959{
960 int TOAint; // in 1/256 symbols
961 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
962
963 burstString[0] = burstTime.TN();
964 for (int i = 0; i < 4; i++)
Alexander Chemerisbb7b0572015-11-13 11:10:04 -0800965 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800966 burstString[5] = (int)dBm;
967 burstString[6] = (TOAint >> 8) & 0x0ff;
968 burstString[7] = TOAint & 0x0ff;
Alexander Chemeris9155d8d2015-11-13 11:00:21 -0800969
970 return 8;
971}
972
973int Transceiver::formatDemodPacket(GSM::Time burstTime, double dBm, double TOA,
Alexander Chemerisbb7b0572015-11-13 11:10:04 -0800974 SoftVector *rxBurst, char *burstString)
Alexander Chemeris9155d8d2015-11-13 11:00:21 -0800975{
976 int headerSize = formatCommonPacketHeader(burstTime, dBm, TOA, burstString);
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800977 SoftVector::iterator burstItr = rxBurst->begin();
978
979 for (unsigned int i = 0; i < gSlotLen; i++) {
Alexander Chemerisbb7b0572015-11-13 11:10:04 -0800980 burstString[headerSize+i] =(char) round((*burstItr++)*255.0);
Alexander Chemeris5d1eaaf2015-11-13 09:38:56 -0800981 }
Alexander Chemeris9155d8d2015-11-13 11:00:21 -0800982 burstString[gSlotLen+headerSize+1] = '\0';
983
984 return gSlotLen+headerSize+2;
985}
986
987int Transceiver::formatRawPacket(GSM::Time burstTime, double dBm, double TOA,
Alexander Chemerisbb7b0572015-11-13 11:10:04 -0800988 CorrType burstType, unsigned tsc,
989 signalVector *rxBurst, char *burstString)
Alexander Chemeris9155d8d2015-11-13 11:00:21 -0800990{
991 int headerSize = formatCommonPacketHeader(burstTime, dBm, TOA, burstString);
992 burstString[headerSize++] = burstType;
993 burstString[headerSize++] = tsc;
994 burstString[headerSize++] = 0; // alignment
995 burstString[headerSize++] = 0; // alignment
996
997 signalVector::iterator burstItr = rxBurst->begin();
998 float *signalItr = (float*)(&burstString[headerSize]);
999
1000 for (unsigned int i = 0; i < gSlotLen; i++, burstItr++) {
Alexander Chemerisbb7b0572015-11-13 11:10:04 -08001001 signalItr[2*i] = (*burstItr).real();
1002 signalItr[2*i+1] = (*burstItr).imag();
Alexander Chemeris9155d8d2015-11-13 11:00:21 -08001003 }
1004
1005 return headerSize + 2*gSlotLen*sizeof(float);
dburgessb3a0ca42011-10-12 07:44:40 +00001006}
1007
Thomas Tsou204a9f12013-10-29 18:34:16 -04001008void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +00001009{
1010
1011 /**
1012 Features a carefully controlled latency mechanism, to
1013 assure that transmit packets arrive at the radio/USRP
1014 before they need to be transmitted.
1015
1016 Deadline clock indicates the burst that needs to be
1017 pushed into the FIFO right NOW. If transmit queue does
1018 not have a burst, stick in filler data.
1019 */
1020
1021
1022 RadioClock *radioClock = (mRadioInterface->getClock());
1023
1024 if (mOn) {
1025 //radioClock->wait(); // wait until clock updates
1026 LOG(DEBUG) << "radio clock " << radioClock->get();
1027 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
1028 // if underrun, then we're not providing bursts to radio/USRP fast
1029 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -04001030 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001031 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +00001032 // only update latency at the defined frame interval
1033 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001034 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
1035 LOG(INFO) << "new latency: " << mTransmitLatency;
1036 mLatencyUpdateTime = radioClock->get();
1037 }
1038 }
1039 else {
1040 // if underrun hasn't occurred in the last sec (216 frames) drop
1041 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +00001042 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001043 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1044 mTransmitLatency.decTN();
1045 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1046 mLatencyUpdateTime = radioClock->get();
1047 }
1048 }
1049 }
dburgessb3a0ca42011-10-12 07:44:40 +00001050 }
dburgessb3a0ca42011-10-12 07:44:40 +00001051 // time to push burst to transmit FIFO
1052 pushRadioVector(mTransmitDeadlineClock);
1053 mTransmitDeadlineClock.incTN();
1054 }
dburgessb3a0ca42011-10-12 07:44:40 +00001055 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001056
1057 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001058}
1059
1060
1061
1062void Transceiver::writeClockInterface()
1063{
1064 char command[50];
1065 // FIXME -- This should be adaptive.
1066 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1067
1068 LOG(INFO) << "ClockInterface: sending " << command;
1069
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001070 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001071
1072 mLastClockUpdateTime = mTransmitDeadlineClock;
1073
Thomas Tsou92c16df2013-09-28 18:04:19 -04001074}
dburgessb3a0ca42011-10-12 07:44:40 +00001075
Thomas Tsou204a9f12013-10-29 18:34:16 -04001076void *RxUpperLoopAdapter(TransceiverChannel *chan)
1077{
1078 Transceiver *trx = chan->trx;
1079 size_t num = chan->num;
1080
1081 delete chan;
1082
Thomas Tsou7553aa92013-11-08 12:50:03 -05001083 trx->setPriority(0.42);
1084
Thomas Tsou204a9f12013-10-29 18:34:16 -04001085 while (1) {
1086 trx->driveReceiveFIFO(num);
1087 pthread_testcancel();
1088 }
1089 return NULL;
1090}
1091
1092void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001093{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001094 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001095
dburgessb3a0ca42011-10-12 07:44:40 +00001096 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001097 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001098 pthread_testcancel();
1099 }
1100 return NULL;
1101}
1102
Thomas Tsou204a9f12013-10-29 18:34:16 -04001103void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001104{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001105 transceiver->setPriority(0.44);
1106
Thomas Tsou92c16df2013-09-28 18:04:19 -04001107 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001108 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001109 pthread_testcancel();
1110 }
1111 return NULL;
1112}
1113
Thomas Tsou204a9f12013-10-29 18:34:16 -04001114void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001115{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001116 Transceiver *trx = chan->trx;
1117 size_t num = chan->num;
1118
1119 delete chan;
1120
dburgessb3a0ca42011-10-12 07:44:40 +00001121 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001122 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001123 pthread_testcancel();
1124 }
1125 return NULL;
1126}
1127
Thomas Tsou204a9f12013-10-29 18:34:16 -04001128void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001129{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001130 Transceiver *trx = chan->trx;
1131 size_t num = chan->num;
1132
1133 delete chan;
1134
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001135 trx->setPriority(0.40);
1136
dburgessb3a0ca42011-10-12 07:44:40 +00001137 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001138 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001139 pthread_testcancel();
1140 }
1141 return NULL;
1142}