blob: 255e1209c2afa319e83d8be5d44b8d6bfc5b8369 [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
2* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
3*
4* This software is distributed under the terms of the GNU Public License.
5* See the COPYING file in the main directory for details.
6*
7* This use of this software may be subject to additional restrictions.
8* See the LEGAL file in the main directory for details.
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22*/
23
dburgessb3a0ca42011-10-12 07:44:40 +000024#include <stdio.h>
Alexander Chemerise8905a02015-06-03 23:47:56 -040025#include <iomanip> // std::setprecision
Alexander Chemerise692ce92015-06-12 00:15:31 -040026#include <fstream>
dburgessb3a0ca42011-10-12 07:44:40 +000027#include "Transceiver.h"
28#include <Logger.h>
29
ttsou2173abf2012-08-08 00:51:31 +000030#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
dburgessb3a0ca42011-10-12 07:44:40 +000033
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040034using namespace GSM;
35
kurtis.heimerlec842de2012-11-23 08:37:32 +000036#define USB_LATENCY_INTRVL 10,0
ttsou2173abf2012-08-08 00:51:31 +000037
38#if USE_UHD
kurtis.heimerlec842de2012-11-23 08:37:32 +000039# define USB_LATENCY_MIN 6,7
ttsou2173abf2012-08-08 00:51:31 +000040#else
kurtis.heimerlec842de2012-11-23 08:37:32 +000041# define USB_LATENCY_MIN 1,1
ttsou2173abf2012-08-08 00:51:31 +000042#endif
dburgessb3a0ca42011-10-12 07:44:40 +000043
Thomas Tsoufa3a7872013-10-17 21:23:34 -040044/* Number of running values use in noise average */
45#define NOISE_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000046
Thomas Tsouf0782732013-10-29 15:55:47 -040047TransceiverState::TransceiverState()
Tom Tsoua4d1a412014-11-25 15:46:56 -080048 : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
Thomas Tsouf0782732013-10-29 15:55:47 -040049{
50 for (int i = 0; i < 8; i++) {
51 chanType[i] = Transceiver::NONE;
52 fillerModulus[i] = 26;
53 chanResponse[i] = NULL;
54 DFEForward[i] = NULL;
55 DFEFeedback[i] = NULL;
56
57 for (int n = 0; n < 102; n++)
58 fillerTable[n][i] = NULL;
59 }
60}
61
62TransceiverState::~TransceiverState()
63{
64 for (int i = 0; i < 8; i++) {
65 delete chanResponse[i];
66 delete DFEForward[i];
67 delete DFEFeedback[i];
68
69 for (int n = 0; n < 102; n++)
70 delete fillerTable[n][i];
71 }
72}
73
Tom Tsou64ad7122015-05-19 18:26:31 -070074static BitVector *genRandNormalBurst(size_t tsc)
Thomas Tsouf0782732013-10-29 15:55:47 -040075{
Tom Tsou64ad7122015-05-19 18:26:31 -070076 if (tsc > 7)
77 return NULL;
Thomas Tsou15d743e2014-01-25 02:34:03 -050078
Tom Tsou64ad7122015-05-19 18:26:31 -070079 BitVector *bits = new BitVector(148);
Thomas Tsou15d743e2014-01-25 02:34:03 -050080
Tom Tsou64ad7122015-05-19 18:26:31 -070081 size_t i = 0;
82
83 /* Tail bits */
84 for (; i < 4; i++)
85 (*bits)[i] = 0;
86
87 /* Random bits */
88 for (; i < 61; i++)
89 (*bits)[i] = rand() % 2;
90
91 /* Training sequence */
Alexander Chemeris29660482015-05-24 19:13:38 -040092 for (int j = 0; i < 87; i++, j++)
93 (*bits)[i] = GSM::gTrainingSequence[tsc][j];
Tom Tsou64ad7122015-05-19 18:26:31 -070094
95 /* Random bits */
96 for (; i < 144; i++)
97 (*bits)[i] = rand() % 2;
98
99 /* Tail bits */
100 for (; i < 148; i++)
101 (*bits)[i] = 0;
102
103 return bits;
104}
105
106bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc)
107{
108 BitVector *bits;
109 signalVector *burst;
110
111 if ((sps != 1) && (sps != 4))
112 return false;
113
114 for (size_t n = 0; n < 8; n++) {
115 size_t guard = 8 + !(n % 4);
116 size_t len = sps == 4 ? 625 : 148 + guard;
117
118 for (size_t i = 0; i < 102; i++) {
119 switch (filler) {
120 case Transceiver::FILLER_DUMMY:
121 burst = modulateBurst(gDummyBurst, guard, sps);
122 break;
123 case Transceiver::FILLER_RAND:
124 bits = genRandNormalBurst(rtsc);
125 burst = modulateBurst(*bits, guard, sps);
126 delete bits;
127 break;
128 case Transceiver::FILLER_ZERO:
129 default:
130 burst = new signalVector(len);
131 }
132
133 scaleVector(*burst, scale);
134 fillerTable[i][n] = burst;
135 }
136
137 if (filler == Transceiver::FILLER_RAND)
138 chanType[n] = Transceiver::TSC;
Thomas Tsou15d743e2014-01-25 02:34:03 -0500139 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700140
141 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400142}
143
dburgessb3a0ca42011-10-12 07:44:40 +0000144Transceiver::Transceiver(int wBasePort,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400145 const char *wTRXAddress,
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800146 size_t tx_sps, size_t rx_sps, size_t chans,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400147 GSM::Time wTransmitLatency,
148 RadioInterface *wRadioInterface,
149 double wRssiOffset)
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800150 : mBasePort(wBasePort), mAddr(wTRXAddress),
151 mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
152 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Alexander Chemerise8905a02015-06-03 23:47:56 -0400153 rssiOffset(wRssiOffset),
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800154 mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mOn(false),
Alexander Chemerise692ce92015-06-12 00:15:31 -0400155 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0), mWriteBurstToDiskMask(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000156{
dburgessb3a0ca42011-10-12 07:44:40 +0000157 txFullScale = mRadioInterface->fullScaleInputValue();
158 rxFullScale = mRadioInterface->fullScaleOutputValue();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300159
160 for (int i = 0; i < 8; i++) {
161 for (int j = 0; j < 8; j++)
162 mHandover[i][j] = false;
163 }
dburgessb3a0ca42011-10-12 07:44:40 +0000164}
165
166Transceiver::~Transceiver()
167{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800168 stop();
169
dburgessb3a0ca42011-10-12 07:44:40 +0000170 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400171
Thomas Tsou204a9f12013-10-29 18:34:16 -0400172 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800173 mControlServiceLoopThreads[i]->cancel();
174 mControlServiceLoopThreads[i]->join();
175 delete mControlServiceLoopThreads[i];
176
Thomas Tsou204a9f12013-10-29 18:34:16 -0400177 mTxPriorityQueues[i].clear();
178 delete mCtrlSockets[i];
179 delete mDataSockets[i];
180 }
dburgessb3a0ca42011-10-12 07:44:40 +0000181}
Thomas Tsou83e06892013-08-20 16:10:01 -0400182
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800183/*
184 * Initialize transceiver
185 *
186 * Start or restart the control loop. Any further control is handled through the
187 * socket API. Randomize the central radio clock set the downlink burst
188 * counters. Note that the clock will not update until the radio starts, but we
189 * are still expected to report clock indications through control channel
190 * activity.
191 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700192bool Transceiver::init(int filler, size_t rtsc)
Thomas Tsou83e06892013-08-20 16:10:01 -0400193{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500194 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400195
Thomas Tsou204a9f12013-10-29 18:34:16 -0400196 if (!mChans) {
197 LOG(ALERT) << "No channels assigned";
198 return false;
199 }
200
Tom Tsou2079a3c2016-03-06 00:58:56 -0800201 if (!sigProcLibSetup()) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400202 LOG(ALERT) << "Failed to initialize signal processing library";
203 return false;
204 }
205
Thomas Tsou204a9f12013-10-29 18:34:16 -0400206 mDataSockets.resize(mChans);
207 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400208 mControlServiceLoopThreads.resize(mChans);
209 mTxPriorityQueueServiceLoopThreads.resize(mChans);
210 mRxServiceLoopThreads.resize(mChans);
211
212 mTxPriorityQueues.resize(mChans);
213 mReceiveFIFO.resize(mChans);
214 mStates.resize(mChans);
215
Thomas Tsouccb73e12014-04-15 17:41:28 -0400216 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700217 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400218 mStates[0].mRetrans = true;
219
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800220 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400221 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500222 c_srcport = mBasePort + 2 * i + 1;
223 c_dstport = mBasePort + 2 * i + 101;
224 d_srcport = mBasePort + 2 * i + 2;
225 d_dstport = mBasePort + 2 * i + 102;
226
227 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
228 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400229 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400230
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800231 /* Randomize the central clock */
232 GSM::Time startTime(random() % gHyperframe, 0);
233 mRadioInterface->getClock()->set(startTime);
234 mTransmitDeadlineClock = startTime;
235 mLastClockUpdateTime = startTime;
236 mLatencyUpdateTime = startTime;
237
238 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400239 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800240 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400241 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800242 mControlServiceLoopThreads[i]->start((void * (*)(void*))
243 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400244
Tom Tsou64ad7122015-05-19 18:26:31 -0700245 if (i && filler == FILLER_DUMMY)
246 filler = FILLER_ZERO;
247
248 mStates[i].init(filler, mSPSTx, txFullScale, rtsc);
Thomas Tsou83e06892013-08-20 16:10:01 -0400249 }
250
251 return true;
252}
dburgessb3a0ca42011-10-12 07:44:40 +0000253
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800254/*
255 * Start the transceiver
256 *
257 * Submit command(s) to the radio device to commence streaming samples and
258 * launch threads to handle sample I/O. Re-synchronize the transmit burst
259 * counters to the central radio clock here as well.
260 */
261bool Transceiver::start()
262{
263 ScopedLock lock(mLock);
264
265 if (mOn) {
266 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300267 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800268 }
269
270 LOG(NOTICE) << "Starting the transceiver";
271
272 GSM::Time time = mRadioInterface->getClock()->get();
273 mTransmitDeadlineClock = time;
274 mLastClockUpdateTime = time;
275 mLatencyUpdateTime = time;
276
277 if (!mRadioInterface->start()) {
278 LOG(ALERT) << "Device failed to start";
279 return false;
280 }
281
282 /* Device is running - launch I/O threads */
283 mRxLowerLoopThread = new Thread(32768);
284 mTxLowerLoopThread = new Thread(32768);
285 mTxLowerLoopThread->start((void * (*)(void*))
286 TxLowerLoopAdapter,(void*) this);
287 mRxLowerLoopThread->start((void * (*)(void*))
288 RxLowerLoopAdapter,(void*) this);
289
290 /* Launch uplink and downlink burst processing threads */
291 for (size_t i = 0; i < mChans; i++) {
292 TransceiverChannel *chan = new TransceiverChannel(this, i);
293 mRxServiceLoopThreads[i] = new Thread(32768);
294 mRxServiceLoopThreads[i]->start((void * (*)(void*))
295 RxUpperLoopAdapter, (void*) chan);
296
297 chan = new TransceiverChannel(this, i);
298 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
299 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
300 TxUpperLoopAdapter, (void*) chan);
301 }
302
303 writeClockInterface();
304 mOn = true;
305 return true;
306}
307
308/*
309 * Stop the transceiver
310 *
311 * Perform stopping by disabling receive streaming and issuing cancellation
312 * requests to running threads. Most threads will timeout and terminate once
313 * device is disabled, but the transmit loop may block waiting on the central
314 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
315 * makes it to the thread cancellation point.
316 */
317void Transceiver::stop()
318{
319 ScopedLock lock(mLock);
320
321 if (!mOn)
322 return;
323
324 LOG(NOTICE) << "Stopping the transceiver";
325 mTxLowerLoopThread->cancel();
326 mRxLowerLoopThread->cancel();
327
328 for (size_t i = 0; i < mChans; i++) {
329 mRxServiceLoopThreads[i]->cancel();
330 mTxPriorityQueueServiceLoopThreads[i]->cancel();
331 }
332
333 LOG(INFO) << "Stopping the device";
334 mRadioInterface->stop();
335
336 for (size_t i = 0; i < mChans; i++) {
337 mRxServiceLoopThreads[i]->join();
338 mTxPriorityQueueServiceLoopThreads[i]->join();
339 delete mRxServiceLoopThreads[i];
340 delete mTxPriorityQueueServiceLoopThreads[i];
341
342 mTxPriorityQueues[i].clear();
343 }
344
345 mTxLowerLoopThread->join();
346 mRxLowerLoopThread->join();
347 delete mTxLowerLoopThread;
348 delete mRxLowerLoopThread;
349
350 mOn = false;
351 LOG(NOTICE) << "Transceiver stopped";
352}
353
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500354void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400355 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000356{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500357 signalVector *burst;
358 radioVector *radio_burst;
359
Thomas Tsou204a9f12013-10-29 18:34:16 -0400360 if (chan >= mTxPriorityQueues.size()) {
361 LOG(ALERT) << "Invalid channel " << chan;
362 return;
363 }
364
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500365 if (wTime.TN() > 7) {
366 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
367 return;
368 }
369
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800370 /* Use the number of bits as the EDGE burst indicator */
371 if (bits.size() == EDGE_BURST_NBITS)
372 burst = modulateEdgeBurst(bits, mSPSTx);
373 else
374 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
375
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500376 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000377
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500378 radio_burst = new radioVector(wTime, burst);
379
380 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000381}
382
Thomas Tsou15d743e2014-01-25 02:34:03 -0500383void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
384{
385 int TN, modFN;
386 TransceiverState *state = &mStates[chan];
387
388 TN = burst->getTime().TN();
389 modFN = burst->getTime().FN() % state->fillerModulus[TN];
390
391 delete state->fillerTable[modFN][TN];
392 state->fillerTable[modFN][TN] = burst->getVector();
393 burst->setVector(NULL);
394}
395
dburgessb3a0ca42011-10-12 07:44:40 +0000396void Transceiver::pushRadioVector(GSM::Time &nowTime)
397{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400398 int TN, modFN;
399 radioVector *burst;
400 TransceiverState *state;
401 std::vector<signalVector *> bursts(mChans);
402 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500403 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000404
Thomas Tsou204a9f12013-10-29 18:34:16 -0400405 for (size_t i = 0; i < mChans; i ++) {
406 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000407
Thomas Tsou204a9f12013-10-29 18:34:16 -0400408 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
409 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500410 if (state->mRetrans)
411 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500412 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400413 }
414
415 TN = nowTime.TN();
416 modFN = nowTime.FN() % state->fillerModulus[TN];
417
418 bursts[i] = state->fillerTable[modFN][TN];
419 zeros[i] = state->chanType[TN] == NONE;
420
421 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500422 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500423
424 if (state->mRetrans) {
425 updateFillerTable(i, burst);
426 } else {
427 burst->setVector(NULL);
428 filler[i] = false;
429 }
430
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500431 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400432 }
dburgessb3a0ca42011-10-12 07:44:40 +0000433 }
434
Thomas Tsou204a9f12013-10-29 18:34:16 -0400435 mRadioInterface->driveTransmitRadio(bursts, zeros);
436
Thomas Tsou15d743e2014-01-25 02:34:03 -0500437 for (size_t i = 0; i < mChans; i++) {
438 if (!filler[i])
439 delete bursts[i];
440 }
dburgessb3a0ca42011-10-12 07:44:40 +0000441}
442
Thomas Tsou204a9f12013-10-29 18:34:16 -0400443void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000444{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400445 TransceiverState *state = &mStates[chan];
446
447 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000448 case NONE:
449 case I:
450 case II:
451 case III:
452 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400453 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000454 break;
455 case IV:
456 case VI:
457 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400458 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000459 break;
460 //case V:
461 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400462 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000463 break;
ttsoufc40a842013-06-09 22:38:18 +0000464 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400465 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000466 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000467 default:
468 break;
469 }
470}
471
472
Thomas Tsou204a9f12013-10-29 18:34:16 -0400473Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
474 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000475{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300476 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 };
477 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,
478 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 };
479 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,
480 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 -0400481 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000482 unsigned burstTN = currTime.TN();
483 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300484 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000485
Thomas Tsou204a9f12013-10-29 18:34:16 -0400486 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000487 case NONE:
488 return OFF;
489 break;
490 case FILL:
491 return IDLE;
492 break;
493 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300494 // TODO: Are we expecting RACH on an IDLE frame?
495/* if (burstFN % 26 == 25)
496 return IDLE;*/
497 if (mHandover[burstTN][0])
498 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000499 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000500 break;
501 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300502 subch = tchh_subslot[burstFN % 26];
503 if (subch == 1)
504 return IDLE;
505 if (mHandover[burstTN][0])
506 return RACH;
ttsou20642972013-03-27 22:00:25 +0000507 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000508 break;
509 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300510 subch = tchh_subslot[burstFN % 26];
511 if (mHandover[burstTN][subch])
512 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000513 return TSC;
514 break;
515 case IV:
516 case VI:
517 return RACH;
518 break;
519 case V: {
520 int mod51 = burstFN % 51;
521 if ((mod51 <= 36) && (mod51 >= 14))
522 return RACH;
523 else if ((mod51 == 4) || (mod51 == 5))
524 return RACH;
525 else if ((mod51 == 45) || (mod51 == 46))
526 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300527 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
528 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000529 else
530 return TSC;
531 break;
532 }
533 case VII:
534 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
535 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300536 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
537 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000538 else
539 return TSC;
540 break;
ttsoufc40a842013-06-09 22:38:18 +0000541 case XIII: {
542 int mod52 = burstFN % 52;
543 if ((mod52 == 12) || (mod52 == 38))
544 return RACH;
545 else if ((mod52 == 25) || (mod52 == 51))
546 return IDLE;
547 else
548 return TSC;
549 break;
550 }
dburgessb3a0ca42011-10-12 07:44:40 +0000551 case LOOPBACK:
552 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
553 return IDLE;
554 else
555 return TSC;
556 break;
557 default:
558 return OFF;
559 break;
560 }
dburgessb3a0ca42011-10-12 07:44:40 +0000561}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400562
Tom Tsou46569402016-03-06 01:59:38 -0800563int Transceiver::detectBurst(TransceiverState *state, signalVector &burst,
564 complex &amp, float &toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500565{
Tom Tsou46569402016-03-06 01:59:38 -0800566 float threshold = 5.0, rc = 0;
Thomas Tsou30421a72013-11-13 23:14:48 -0500567
Tom Tsou46569402016-03-06 01:59:38 -0800568 switch (type) {
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800569 case EDGE:
570 rc = detectEdgeBurst(burst, mTSC, threshold, mSPSRx,
571 amp, toa, mMaxExpectedDelay);
572 if (rc > 0)
573 break;
574 else
575 type = TSC;
Tom Tsou46569402016-03-06 01:59:38 -0800576 case TSC:
577 rc = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx,
578 amp, toa, mMaxExpectedDelay);
579 break;
580 case RACH:
581 threshold = 6.0;
582 rc = detectRACHBurst(burst, threshold, mSPSRx, amp, toa);
583 break;
584 default:
585 LOG(ERR) << "Invalid correlation type";
586 }
587
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800588 if (rc > 0)
589 return type;
Tom Tsou46569402016-03-06 01:59:38 -0800590
591 return rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500592}
593
Thomas Tsou30421a72013-11-13 23:14:48 -0500594
595/*
Tom Tsou46569402016-03-06 01:59:38 -0800596 * Demodulate GMSK by direct rotation and soft slicing.
Thomas Tsou30421a72013-11-13 23:14:48 -0500597 */
598SoftVector *Transceiver::demodulate(TransceiverState *state,
599 signalVector &burst, complex amp,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800600 float toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500601{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800602 if (type == EDGE)
603 return demodEdgeBurst(burst, mSPSRx, amp, toa);
604
Thomas Tsou30421a72013-11-13 23:14:48 -0500605 return demodulateBurst(burst, mSPSRx, amp, toa);
606}
607
Alexander Chemerise692ce92015-06-12 00:15:31 -0400608void writeToFile(radioVector *radio_burst, size_t chan)
609{
610 GSM::Time time = radio_burst->getTime();
611 std::ostringstream fname;
612 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
613 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
614 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
615 outfile.close();
616}
617
Thomas Tsou30421a72013-11-13 23:14:48 -0500618/*
619 * Pull bursts from the FIFO and handle according to the slot
620 * and burst correlation type. Equalzation is currently disabled.
621 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400622SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400623 double &timingOffset, double &noise,
624 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000625{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800626 int rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500627 complex amp;
628 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500629 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500630 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500631 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500632 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400633 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000634
Thomas Tsou30421a72013-11-13 23:14:48 -0500635 /* Blocking FIFO read */
636 radioVector *radio_burst = mReceiveFIFO[chan]->read();
637 if (!radio_burst)
638 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000639
Thomas Tsou30421a72013-11-13 23:14:48 -0500640 /* Set time and determine correlation type */
641 GSM::Time time = radio_burst->getTime();
642 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000643
Alexander Chemerise692ce92015-06-12 00:15:31 -0400644 /* Debug: dump bursts to disk */
645 /* bits 0-7 - chan 0 timeslots
646 * bits 8-15 - chan 1 timeslots */
647 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
648 writeToFile(radio_burst, chan);
649
Alexander Chemeris2b542102015-06-08 22:46:38 -0400650 /* No processing if the timeslot is off.
651 * Not even power level or noise calculation. */
652 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500653 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000654 return NULL;
655 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000656
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500657 /* Select the diversity channel with highest energy */
658 for (size_t i = 0; i < radio_burst->chans(); i++) {
659 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
660 if (pow > max) {
661 max = pow;
662 max_i = i;
663 }
664 avg += pow;
665 }
666
667 if (max_i < 0) {
668 LOG(ALERT) << "Received empty burst";
669 delete radio_burst;
670 return NULL;
671 }
672
Thomas Tsou30421a72013-11-13 23:14:48 -0500673 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500674 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500675 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400676
677 wTime = time;
678 RSSI = 20.0 * log10(rxFullScale / avg);
679
680 /* RSSI estimation are valid */
681 isRssiValid = true;
682
683 if (type == IDLE) {
684 /* Update noise levels */
685 state->mNoises.insert(avg);
686 state->mNoiseLev = state->mNoises.avg();
687 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
688
689 delete radio_burst;
690 return NULL;
691 } else {
692 /* Do not update noise levels */
693 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
694 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400695
Thomas Tsou30421a72013-11-13 23:14:48 -0500696 /* Detect normal or RACH bursts */
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800697 rc = detectBurst(state, *burst, amp, toa, type);
Thomas Tsouf0782732013-10-29 15:55:47 -0400698
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800699 if (rc > 0) {
700 type = (CorrType) rc;
701 } else if (rc <= 0) {
702 if (rc == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400703 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800704 } else if (rc != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400705 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700706 }
707
Thomas Tsou30421a72013-11-13 23:14:48 -0500708 delete radio_burst;
709 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000710 }
dburgessb3a0ca42011-10-12 07:44:40 +0000711
Alexander Chemeris2b542102015-06-08 22:46:38 -0400712 timingOffset = toa / mSPSRx;
713
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800714 bits = demodulate(state, *burst, amp, toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500715
Thomas Tsou30421a72013-11-13 23:14:48 -0500716 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500717 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000718}
719
dburgessb3a0ca42011-10-12 07:44:40 +0000720void Transceiver::reset()
721{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400722 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
723 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000724}
725
726
Thomas Tsou204a9f12013-10-29 18:34:16 -0400727void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000728{
dburgessb3a0ca42011-10-12 07:44:40 +0000729 int MAX_PACKET_LENGTH = 100;
730
731 // check control socket
732 char buffer[MAX_PACKET_LENGTH];
733 int msgLen = -1;
734 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400735
Thomas Tsou204a9f12013-10-29 18:34:16 -0400736 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000737
738 if (msgLen < 1) {
739 return;
740 }
741
742 char cmdcheck[4];
743 char command[MAX_PACKET_LENGTH];
744 char response[MAX_PACKET_LENGTH];
745
746 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400747
748 if (!chan)
749 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000750
751 if (strcmp(cmdcheck,"CMD")!=0) {
752 LOG(WARNING) << "bogus message on control interface";
753 return;
754 }
755 LOG(INFO) << "command is " << buffer;
756
757 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800758 stop();
759 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000760 }
761 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800762 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000763 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800764 else
dburgessb3a0ca42011-10-12 07:44:40 +0000765 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300766 for (int i = 0; i < 8; i++) {
767 for (int j = 0; j < 8; j++)
768 mHandover[i][j] = false;
769 }
770 }
771 else if (strcmp(command,"HANDOVER")==0){
772 int ts=0,ss=0;
773 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
774 mHandover[ts][ss] = true;
775 LOG(WARNING) << "HANDOVER RACH at timeslot " << ts << " subslot " << ss;
776 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
777 }
778 else if (strcmp(command,"NOHANDOVER")==0){
779 int ts=0,ss=0;
780 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
781 mHandover[ts][ss] = false;
782 LOG(WARNING) << "NOHANDOVER at timeslot " << ts << " subslot " << ss;
783 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000784 }
785 else if (strcmp(command,"SETMAXDLY")==0) {
786 //set expected maximum time-of-arrival
787 int maxDelay;
788 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
789 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
790 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
791 }
792 else if (strcmp(command,"SETRXGAIN")==0) {
793 //set expected maximum time-of-arrival
794 int newGain;
795 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400796 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000797 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
798 }
799 else if (strcmp(command,"NOISELEV")==0) {
800 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500801 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000802 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500803 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000804 }
805 else {
806 sprintf(response,"RSP NOISELEV 1 0");
807 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500808 }
809 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800810 int power;
811 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
812 power = mRadioInterface->setPowerAttenuation(power, chan);
813 mStates[chan].mPower = power;
814 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000815 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500816 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800817 int power, step;
818 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
819 power = mStates[chan].mPower + step;
820 power = mRadioInterface->setPowerAttenuation(power, chan);
821 mStates[chan].mPower = power;
822 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000823 }
dburgessb3a0ca42011-10-12 07:44:40 +0000824 else if (strcmp(command,"RXTUNE")==0) {
825 // tune receiver
826 int freqKhz;
827 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500828 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400829 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000830 LOG(ALERT) << "RX failed to tune";
831 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
832 }
833 else
834 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
835 }
836 else if (strcmp(command,"TXTUNE")==0) {
837 // tune txmtr
838 int freqKhz;
839 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500840 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400841 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000842 LOG(ALERT) << "TX failed to tune";
843 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
844 }
845 else
846 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
847 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500848 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000849 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500850 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500851 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700852 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500853 sprintf(response, "RSP SETTSC 1 %d", TSC);
854 else if (chan && (TSC != mTSC))
855 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000856 else {
857 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400858 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000859 }
860 }
861 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700862 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000863 int corrCode;
864 int timeslot;
865 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
866 if ((timeslot < 0) || (timeslot > 7)) {
867 LOG(WARNING) << "bogus message on control interface";
868 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
869 return;
870 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400871 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
872 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000873 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
874
875 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400876 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
877 // debug command! may change or disapear without notice
878 // set a mask which bursts to dump to disk
879 int mask;
880 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
881 mWriteBurstToDiskMask = mask;
882 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
883 }
dburgessb3a0ca42011-10-12 07:44:40 +0000884 else {
885 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200886 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000887 }
888
Thomas Tsou204a9f12013-10-29 18:34:16 -0400889 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000890}
891
Thomas Tsou204a9f12013-10-29 18:34:16 -0400892bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000893{
dburgessb3a0ca42011-10-12 07:44:40 +0000894 char buffer[gSlotLen+50];
895
896 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400897 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000898
899 if (msgLen!=gSlotLen+1+4+1) {
900 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
901 return false;
902 }
903
904 int timeSlot = (int) buffer[0];
905 uint64_t frameNum = 0;
906 for (int i = 0; i < 4; i++)
907 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000908
dburgessb3a0ca42011-10-12 07:44:40 +0000909 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
910
911 int RSSI = (int) buffer[5];
912 static BitVector newBurst(gSlotLen);
913 BitVector::iterator itr = newBurst.begin();
914 char *bufferItr = buffer+6;
915 while (itr < newBurst.end())
916 *itr++ = *bufferItr++;
917
918 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400919
920 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000921
922 return true;
923
924
925}
dburgessb3a0ca42011-10-12 07:44:40 +0000926
Thomas Tsou204a9f12013-10-29 18:34:16 -0400927void Transceiver::driveReceiveRadio()
928{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400929 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400930 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400931 } else {
932 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
933 writeClockInterface();
934 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400935}
936
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800937void Transceiver::logRxBurst(SoftVector *burst, GSM::Time time, double dbm,
938 double rssi, double noise, double toa)
939{
940 LOG(DEBUG) << std::fixed << std::right
941 << " time: " << time
942 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
943 << "dBFS/" << std::setw(6) << -dbm << "dBm"
944 << " noise: " << std::setw(5) << std::setprecision(1) << noise
945 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
946 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
947 << " bits: " << *burst;
948}
949
Thomas Tsou204a9f12013-10-29 18:34:16 -0400950void Transceiver::driveReceiveFIFO(size_t chan)
951{
dburgessb3a0ca42011-10-12 07:44:40 +0000952 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400953 double RSSI; // in dBFS
954 double dBm; // in dBm
955 double TOA; // in symbols
956 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400957 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000958 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400959 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800960 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000961
Alexander Chemeris2b542102015-06-08 22:46:38 -0400962 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800963 if (!rxBurst)
964 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000965
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800966 /*
967 * EDGE demodulator returns 444 (148 * 3) bits
968 */
969 if (rxBurst->size() == gSlotLen * 3)
970 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000971
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800972 dBm = RSSI + rssiOffset;
973 logRxBurst(rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400974
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800975 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000976
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800977 char burstString[nbits + 10];
978 burstString[0] = burstTime.TN();
979 for (int i = 0; i < 4; i++)
980 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
981 burstString[5] = (int)dBm;
982 burstString[6] = (TOAint >> 8) & 0x0ff;
983 burstString[7] = TOAint & 0x0ff;
984 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000985
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800986 for (unsigned i = 0; i < nbits; i++)
987 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
988
989 burstString[nbits + 9] = '\0';
990 delete rxBurst;
991
992 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000993}
994
Thomas Tsou204a9f12013-10-29 18:34:16 -0400995void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000996{
997
998 /**
999 Features a carefully controlled latency mechanism, to
1000 assure that transmit packets arrive at the radio/USRP
1001 before they need to be transmitted.
1002
1003 Deadline clock indicates the burst that needs to be
1004 pushed into the FIFO right NOW. If transmit queue does
1005 not have a burst, stick in filler data.
1006 */
1007
1008
1009 RadioClock *radioClock = (mRadioInterface->getClock());
1010
1011 if (mOn) {
1012 //radioClock->wait(); // wait until clock updates
1013 LOG(DEBUG) << "radio clock " << radioClock->get();
1014 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
1015 // if underrun, then we're not providing bursts to radio/USRP fast
1016 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -04001017 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001018 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +00001019 // only update latency at the defined frame interval
1020 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001021 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
1022 LOG(INFO) << "new latency: " << mTransmitLatency;
1023 mLatencyUpdateTime = radioClock->get();
1024 }
1025 }
1026 else {
1027 // if underrun hasn't occurred in the last sec (216 frames) drop
1028 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +00001029 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001030 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1031 mTransmitLatency.decTN();
1032 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1033 mLatencyUpdateTime = radioClock->get();
1034 }
1035 }
1036 }
dburgessb3a0ca42011-10-12 07:44:40 +00001037 }
dburgessb3a0ca42011-10-12 07:44:40 +00001038 // time to push burst to transmit FIFO
1039 pushRadioVector(mTransmitDeadlineClock);
1040 mTransmitDeadlineClock.incTN();
1041 }
dburgessb3a0ca42011-10-12 07:44:40 +00001042 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001043
1044 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001045}
1046
1047
1048
1049void Transceiver::writeClockInterface()
1050{
1051 char command[50];
1052 // FIXME -- This should be adaptive.
1053 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1054
1055 LOG(INFO) << "ClockInterface: sending " << command;
1056
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001057 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001058
1059 mLastClockUpdateTime = mTransmitDeadlineClock;
1060
Thomas Tsou92c16df2013-09-28 18:04:19 -04001061}
dburgessb3a0ca42011-10-12 07:44:40 +00001062
Thomas Tsou204a9f12013-10-29 18:34:16 -04001063void *RxUpperLoopAdapter(TransceiverChannel *chan)
1064{
1065 Transceiver *trx = chan->trx;
1066 size_t num = chan->num;
1067
1068 delete chan;
1069
Thomas Tsou7553aa92013-11-08 12:50:03 -05001070 trx->setPriority(0.42);
1071
Thomas Tsou204a9f12013-10-29 18:34:16 -04001072 while (1) {
1073 trx->driveReceiveFIFO(num);
1074 pthread_testcancel();
1075 }
1076 return NULL;
1077}
1078
1079void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001080{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001081 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001082
dburgessb3a0ca42011-10-12 07:44:40 +00001083 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001084 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001085 pthread_testcancel();
1086 }
1087 return NULL;
1088}
1089
Thomas Tsou204a9f12013-10-29 18:34:16 -04001090void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001091{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001092 transceiver->setPriority(0.44);
1093
Thomas Tsou92c16df2013-09-28 18:04:19 -04001094 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001095 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001096 pthread_testcancel();
1097 }
1098 return NULL;
1099}
1100
Thomas Tsou204a9f12013-10-29 18:34:16 -04001101void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001102{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001103 Transceiver *trx = chan->trx;
1104 size_t num = chan->num;
1105
1106 delete chan;
1107
dburgessb3a0ca42011-10-12 07:44:40 +00001108 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001109 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001110 pthread_testcancel();
1111 }
1112 return NULL;
1113}
1114
Thomas Tsou204a9f12013-10-29 18:34:16 -04001115void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001116{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001117 Transceiver *trx = chan->trx;
1118 size_t num = chan->num;
1119
1120 delete chan;
1121
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001122 trx->setPriority(0.40);
1123
dburgessb3a0ca42011-10-12 07:44:40 +00001124 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001125 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001126 pthread_testcancel();
1127 }
1128 return NULL;
1129}