blob: 1f59f78f3ea4007c0c5a966d1ae0c733a16b827d [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 -070074bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc)
75{
Tom Tsou64ad7122015-05-19 18:26:31 -070076 signalVector *burst;
77
78 if ((sps != 1) && (sps != 4))
79 return false;
80
81 for (size_t n = 0; n < 8; n++) {
Tom Tsou64ad7122015-05-19 18:26:31 -070082 for (size_t i = 0; i < 102; i++) {
83 switch (filler) {
84 case Transceiver::FILLER_DUMMY:
Tom Tsou8ee2f382016-03-06 20:57:34 -080085 burst = generateDummyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070086 break;
Tom Tsouaf717b22016-03-06 22:19:15 -080087 case Transceiver::FILLER_NORM_RAND:
Tom Tsou8ee2f382016-03-06 20:57:34 -080088 burst = genRandNormalBurst(rtsc, sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070089 break;
Tom Tsouaf717b22016-03-06 22:19:15 -080090 case Transceiver::FILLER_EDGE_RAND:
91 burst = generateEdgeBurst(rtsc);
92 break;
Tom Tsou64ad7122015-05-19 18:26:31 -070093 case Transceiver::FILLER_ZERO:
94 default:
Tom Tsou8ee2f382016-03-06 20:57:34 -080095 burst = generateEmptyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070096 }
97
98 scaleVector(*burst, scale);
99 fillerTable[i][n] = burst;
100 }
101
Tom Tsouaf717b22016-03-06 22:19:15 -0800102 if ((filler == Transceiver::FILLER_NORM_RAND) ||
103 (filler == Transceiver::FILLER_EDGE_RAND)) {
104 chanType[n] = Transceiver::TSC;
105 }
Thomas Tsou15d743e2014-01-25 02:34:03 -0500106 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700107
108 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400109}
110
dburgessb3a0ca42011-10-12 07:44:40 +0000111Transceiver::Transceiver(int wBasePort,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400112 const char *wTRXAddress,
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800113 size_t tx_sps, size_t rx_sps, size_t chans,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400114 GSM::Time wTransmitLatency,
115 RadioInterface *wRadioInterface,
116 double wRssiOffset)
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800117 : mBasePort(wBasePort), mAddr(wTRXAddress),
118 mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
119 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Alexander Chemerise8905a02015-06-03 23:47:56 -0400120 rssiOffset(wRssiOffset),
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800121 mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mOn(false),
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300122 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
123 mWriteBurstToDiskMask(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000124{
dburgessb3a0ca42011-10-12 07:44:40 +0000125 txFullScale = mRadioInterface->fullScaleInputValue();
126 rxFullScale = mRadioInterface->fullScaleOutputValue();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300127
128 for (int i = 0; i < 8; i++) {
129 for (int j = 0; j < 8; j++)
130 mHandover[i][j] = false;
131 }
dburgessb3a0ca42011-10-12 07:44:40 +0000132}
133
134Transceiver::~Transceiver()
135{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800136 stop();
137
dburgessb3a0ca42011-10-12 07:44:40 +0000138 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400139
Thomas Tsou204a9f12013-10-29 18:34:16 -0400140 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800141 mControlServiceLoopThreads[i]->cancel();
142 mControlServiceLoopThreads[i]->join();
143 delete mControlServiceLoopThreads[i];
144
Thomas Tsou204a9f12013-10-29 18:34:16 -0400145 mTxPriorityQueues[i].clear();
146 delete mCtrlSockets[i];
147 delete mDataSockets[i];
148 }
dburgessb3a0ca42011-10-12 07:44:40 +0000149}
Thomas Tsou83e06892013-08-20 16:10:01 -0400150
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800151/*
152 * Initialize transceiver
153 *
154 * Start or restart the control loop. Any further control is handled through the
155 * socket API. Randomize the central radio clock set the downlink burst
156 * counters. Note that the clock will not update until the radio starts, but we
157 * are still expected to report clock indications through control channel
158 * activity.
159 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700160bool Transceiver::init(int filler, size_t rtsc)
Thomas Tsou83e06892013-08-20 16:10:01 -0400161{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500162 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400163
Thomas Tsou204a9f12013-10-29 18:34:16 -0400164 if (!mChans) {
165 LOG(ALERT) << "No channels assigned";
166 return false;
167 }
168
Tom Tsou2079a3c2016-03-06 00:58:56 -0800169 if (!sigProcLibSetup()) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400170 LOG(ALERT) << "Failed to initialize signal processing library";
171 return false;
172 }
173
Thomas Tsou204a9f12013-10-29 18:34:16 -0400174 mDataSockets.resize(mChans);
175 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400176 mControlServiceLoopThreads.resize(mChans);
177 mTxPriorityQueueServiceLoopThreads.resize(mChans);
178 mRxServiceLoopThreads.resize(mChans);
179
180 mTxPriorityQueues.resize(mChans);
181 mReceiveFIFO.resize(mChans);
182 mStates.resize(mChans);
183
Thomas Tsouccb73e12014-04-15 17:41:28 -0400184 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700185 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400186 mStates[0].mRetrans = true;
187
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800188 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400189 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500190 c_srcport = mBasePort + 2 * i + 1;
191 c_dstport = mBasePort + 2 * i + 101;
192 d_srcport = mBasePort + 2 * i + 2;
193 d_dstport = mBasePort + 2 * i + 102;
194
195 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
196 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400197 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400198
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800199 /* Randomize the central clock */
200 GSM::Time startTime(random() % gHyperframe, 0);
201 mRadioInterface->getClock()->set(startTime);
202 mTransmitDeadlineClock = startTime;
203 mLastClockUpdateTime = startTime;
204 mLatencyUpdateTime = startTime;
205
206 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400207 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800208 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400209 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800210 mControlServiceLoopThreads[i]->start((void * (*)(void*))
211 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400212
Tom Tsou64ad7122015-05-19 18:26:31 -0700213 if (i && filler == FILLER_DUMMY)
214 filler = FILLER_ZERO;
215
216 mStates[i].init(filler, mSPSTx, txFullScale, rtsc);
Thomas Tsou83e06892013-08-20 16:10:01 -0400217 }
218
219 return true;
220}
dburgessb3a0ca42011-10-12 07:44:40 +0000221
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800222/*
223 * Start the transceiver
224 *
225 * Submit command(s) to the radio device to commence streaming samples and
226 * launch threads to handle sample I/O. Re-synchronize the transmit burst
227 * counters to the central radio clock here as well.
228 */
229bool Transceiver::start()
230{
231 ScopedLock lock(mLock);
232
233 if (mOn) {
234 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300235 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800236 }
237
238 LOG(NOTICE) << "Starting the transceiver";
239
240 GSM::Time time = mRadioInterface->getClock()->get();
241 mTransmitDeadlineClock = time;
242 mLastClockUpdateTime = time;
243 mLatencyUpdateTime = time;
244
245 if (!mRadioInterface->start()) {
246 LOG(ALERT) << "Device failed to start";
247 return false;
248 }
249
250 /* Device is running - launch I/O threads */
251 mRxLowerLoopThread = new Thread(32768);
252 mTxLowerLoopThread = new Thread(32768);
253 mTxLowerLoopThread->start((void * (*)(void*))
254 TxLowerLoopAdapter,(void*) this);
255 mRxLowerLoopThread->start((void * (*)(void*))
256 RxLowerLoopAdapter,(void*) this);
257
258 /* Launch uplink and downlink burst processing threads */
259 for (size_t i = 0; i < mChans; i++) {
260 TransceiverChannel *chan = new TransceiverChannel(this, i);
261 mRxServiceLoopThreads[i] = new Thread(32768);
262 mRxServiceLoopThreads[i]->start((void * (*)(void*))
263 RxUpperLoopAdapter, (void*) chan);
264
265 chan = new TransceiverChannel(this, i);
266 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
267 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
268 TxUpperLoopAdapter, (void*) chan);
269 }
270
271 writeClockInterface();
272 mOn = true;
273 return true;
274}
275
276/*
277 * Stop the transceiver
278 *
279 * Perform stopping by disabling receive streaming and issuing cancellation
280 * requests to running threads. Most threads will timeout and terminate once
281 * device is disabled, but the transmit loop may block waiting on the central
282 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
283 * makes it to the thread cancellation point.
284 */
285void Transceiver::stop()
286{
287 ScopedLock lock(mLock);
288
289 if (!mOn)
290 return;
291
292 LOG(NOTICE) << "Stopping the transceiver";
293 mTxLowerLoopThread->cancel();
294 mRxLowerLoopThread->cancel();
295
296 for (size_t i = 0; i < mChans; i++) {
297 mRxServiceLoopThreads[i]->cancel();
298 mTxPriorityQueueServiceLoopThreads[i]->cancel();
299 }
300
301 LOG(INFO) << "Stopping the device";
302 mRadioInterface->stop();
303
304 for (size_t i = 0; i < mChans; i++) {
305 mRxServiceLoopThreads[i]->join();
306 mTxPriorityQueueServiceLoopThreads[i]->join();
307 delete mRxServiceLoopThreads[i];
308 delete mTxPriorityQueueServiceLoopThreads[i];
309
310 mTxPriorityQueues[i].clear();
311 }
312
313 mTxLowerLoopThread->join();
314 mRxLowerLoopThread->join();
315 delete mTxLowerLoopThread;
316 delete mRxLowerLoopThread;
317
318 mOn = false;
319 LOG(NOTICE) << "Transceiver stopped";
320}
321
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500322void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400323 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000324{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500325 signalVector *burst;
326 radioVector *radio_burst;
327
Thomas Tsou204a9f12013-10-29 18:34:16 -0400328 if (chan >= mTxPriorityQueues.size()) {
329 LOG(ALERT) << "Invalid channel " << chan;
330 return;
331 }
332
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500333 if (wTime.TN() > 7) {
334 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
335 return;
336 }
337
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800338 /* Use the number of bits as the EDGE burst indicator */
339 if (bits.size() == EDGE_BURST_NBITS)
340 burst = modulateEdgeBurst(bits, mSPSTx);
341 else
342 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
343
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500344 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000345
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500346 radio_burst = new radioVector(wTime, burst);
347
348 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000349}
350
Thomas Tsou15d743e2014-01-25 02:34:03 -0500351void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
352{
353 int TN, modFN;
354 TransceiverState *state = &mStates[chan];
355
356 TN = burst->getTime().TN();
357 modFN = burst->getTime().FN() % state->fillerModulus[TN];
358
359 delete state->fillerTable[modFN][TN];
360 state->fillerTable[modFN][TN] = burst->getVector();
361 burst->setVector(NULL);
362}
363
dburgessb3a0ca42011-10-12 07:44:40 +0000364void Transceiver::pushRadioVector(GSM::Time &nowTime)
365{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400366 int TN, modFN;
367 radioVector *burst;
368 TransceiverState *state;
369 std::vector<signalVector *> bursts(mChans);
370 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500371 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000372
Thomas Tsou204a9f12013-10-29 18:34:16 -0400373 for (size_t i = 0; i < mChans; i ++) {
374 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000375
Thomas Tsou204a9f12013-10-29 18:34:16 -0400376 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
377 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500378 if (state->mRetrans)
379 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500380 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400381 }
382
383 TN = nowTime.TN();
384 modFN = nowTime.FN() % state->fillerModulus[TN];
385
386 bursts[i] = state->fillerTable[modFN][TN];
387 zeros[i] = state->chanType[TN] == NONE;
388
389 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500390 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500391
392 if (state->mRetrans) {
393 updateFillerTable(i, burst);
394 } else {
395 burst->setVector(NULL);
396 filler[i] = false;
397 }
398
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500399 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400400 }
dburgessb3a0ca42011-10-12 07:44:40 +0000401 }
402
Thomas Tsou204a9f12013-10-29 18:34:16 -0400403 mRadioInterface->driveTransmitRadio(bursts, zeros);
404
Thomas Tsou15d743e2014-01-25 02:34:03 -0500405 for (size_t i = 0; i < mChans; i++) {
406 if (!filler[i])
407 delete bursts[i];
408 }
dburgessb3a0ca42011-10-12 07:44:40 +0000409}
410
Thomas Tsou204a9f12013-10-29 18:34:16 -0400411void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000412{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400413 TransceiverState *state = &mStates[chan];
414
415 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000416 case NONE:
417 case I:
418 case II:
419 case III:
420 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400421 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000422 break;
423 case IV:
424 case VI:
425 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400426 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000427 break;
428 //case V:
429 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400430 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000431 break;
ttsoufc40a842013-06-09 22:38:18 +0000432 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400433 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000434 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000435 default:
436 break;
437 }
438}
439
440
Thomas Tsou204a9f12013-10-29 18:34:16 -0400441Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
442 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000443{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300444 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 };
445 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,
446 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 };
447 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,
448 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 -0400449 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000450 unsigned burstTN = currTime.TN();
451 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300452 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000453
Thomas Tsou204a9f12013-10-29 18:34:16 -0400454 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000455 case NONE:
456 return OFF;
457 break;
458 case FILL:
459 return IDLE;
460 break;
461 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300462 // TODO: Are we expecting RACH on an IDLE frame?
463/* if (burstFN % 26 == 25)
464 return IDLE;*/
465 if (mHandover[burstTN][0])
466 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000467 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000468 break;
469 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300470 subch = tchh_subslot[burstFN % 26];
471 if (subch == 1)
472 return IDLE;
473 if (mHandover[burstTN][0])
474 return RACH;
ttsou20642972013-03-27 22:00:25 +0000475 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000476 break;
477 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300478 subch = tchh_subslot[burstFN % 26];
479 if (mHandover[burstTN][subch])
480 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000481 return TSC;
482 break;
483 case IV:
484 case VI:
485 return RACH;
486 break;
487 case V: {
488 int mod51 = burstFN % 51;
489 if ((mod51 <= 36) && (mod51 >= 14))
490 return RACH;
491 else if ((mod51 == 4) || (mod51 == 5))
492 return RACH;
493 else if ((mod51 == 45) || (mod51 == 46))
494 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300495 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
496 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000497 else
498 return TSC;
499 break;
500 }
501 case VII:
502 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
503 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300504 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
505 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000506 else
507 return TSC;
508 break;
ttsoufc40a842013-06-09 22:38:18 +0000509 case XIII: {
510 int mod52 = burstFN % 52;
511 if ((mod52 == 12) || (mod52 == 38))
512 return RACH;
513 else if ((mod52 == 25) || (mod52 == 51))
514 return IDLE;
515 else
516 return TSC;
517 break;
518 }
dburgessb3a0ca42011-10-12 07:44:40 +0000519 case LOOPBACK:
520 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
521 return IDLE;
522 else
523 return TSC;
524 break;
525 default:
526 return OFF;
527 break;
528 }
dburgessb3a0ca42011-10-12 07:44:40 +0000529}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400530
Tom Tsou46569402016-03-06 01:59:38 -0800531int Transceiver::detectBurst(TransceiverState *state, signalVector &burst,
532 complex &amp, float &toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500533{
Tom Tsou46569402016-03-06 01:59:38 -0800534 float threshold = 5.0, rc = 0;
Thomas Tsou30421a72013-11-13 23:14:48 -0500535
Tom Tsou46569402016-03-06 01:59:38 -0800536 switch (type) {
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800537 case EDGE:
538 rc = detectEdgeBurst(burst, mTSC, threshold, mSPSRx,
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300539 amp, toa, mMaxExpectedDelayNB);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800540 if (rc > 0)
541 break;
542 else
543 type = TSC;
Tom Tsou46569402016-03-06 01:59:38 -0800544 case TSC:
545 rc = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx,
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300546 amp, toa, mMaxExpectedDelayNB);
Tom Tsou46569402016-03-06 01:59:38 -0800547 break;
548 case RACH:
549 threshold = 6.0;
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300550 rc = detectRACHBurst(burst, threshold, mSPSRx, amp, toa,
551 mMaxExpectedDelayAB);
Tom Tsou46569402016-03-06 01:59:38 -0800552 break;
553 default:
554 LOG(ERR) << "Invalid correlation type";
555 }
556
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800557 if (rc > 0)
558 return type;
Tom Tsou46569402016-03-06 01:59:38 -0800559
560 return rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500561}
562
Thomas Tsou30421a72013-11-13 23:14:48 -0500563
564/*
Tom Tsou46569402016-03-06 01:59:38 -0800565 * Demodulate GMSK by direct rotation and soft slicing.
Thomas Tsou30421a72013-11-13 23:14:48 -0500566 */
567SoftVector *Transceiver::demodulate(TransceiverState *state,
568 signalVector &burst, complex amp,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800569 float toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500570{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800571 if (type == EDGE)
572 return demodEdgeBurst(burst, mSPSRx, amp, toa);
573
Thomas Tsou30421a72013-11-13 23:14:48 -0500574 return demodulateBurst(burst, mSPSRx, amp, toa);
575}
576
Alexander Chemerise692ce92015-06-12 00:15:31 -0400577void writeToFile(radioVector *radio_burst, size_t chan)
578{
579 GSM::Time time = radio_burst->getTime();
580 std::ostringstream fname;
581 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
582 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
583 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
584 outfile.close();
585}
586
Thomas Tsou30421a72013-11-13 23:14:48 -0500587/*
588 * Pull bursts from the FIFO and handle according to the slot
589 * and burst correlation type. Equalzation is currently disabled.
590 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400591SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400592 double &timingOffset, double &noise,
593 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000594{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800595 int rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500596 complex amp;
597 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500598 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500599 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500600 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500601 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400602 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000603
Thomas Tsou30421a72013-11-13 23:14:48 -0500604 /* Blocking FIFO read */
605 radioVector *radio_burst = mReceiveFIFO[chan]->read();
606 if (!radio_burst)
607 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000608
Thomas Tsou30421a72013-11-13 23:14:48 -0500609 /* Set time and determine correlation type */
610 GSM::Time time = radio_burst->getTime();
611 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000612
Alexander Chemerise692ce92015-06-12 00:15:31 -0400613 /* Debug: dump bursts to disk */
614 /* bits 0-7 - chan 0 timeslots
615 * bits 8-15 - chan 1 timeslots */
616 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
617 writeToFile(radio_burst, chan);
618
Alexander Chemeris2b542102015-06-08 22:46:38 -0400619 /* No processing if the timeslot is off.
620 * Not even power level or noise calculation. */
621 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500622 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000623 return NULL;
624 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000625
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500626 /* Select the diversity channel with highest energy */
627 for (size_t i = 0; i < radio_burst->chans(); i++) {
628 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
629 if (pow > max) {
630 max = pow;
631 max_i = i;
632 }
633 avg += pow;
634 }
635
636 if (max_i < 0) {
637 LOG(ALERT) << "Received empty burst";
638 delete radio_burst;
639 return NULL;
640 }
641
Thomas Tsou30421a72013-11-13 23:14:48 -0500642 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500643 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500644 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400645
646 wTime = time;
647 RSSI = 20.0 * log10(rxFullScale / avg);
648
649 /* RSSI estimation are valid */
650 isRssiValid = true;
651
652 if (type == IDLE) {
653 /* Update noise levels */
654 state->mNoises.insert(avg);
655 state->mNoiseLev = state->mNoises.avg();
656 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
657
658 delete radio_burst;
659 return NULL;
660 } else {
661 /* Do not update noise levels */
662 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
663 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400664
Thomas Tsou30421a72013-11-13 23:14:48 -0500665 /* Detect normal or RACH bursts */
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800666 rc = detectBurst(state, *burst, amp, toa, type);
Thomas Tsouf0782732013-10-29 15:55:47 -0400667
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800668 if (rc > 0) {
669 type = (CorrType) rc;
670 } else if (rc <= 0) {
671 if (rc == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400672 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800673 } else if (rc != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400674 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700675 }
676
Thomas Tsou30421a72013-11-13 23:14:48 -0500677 delete radio_burst;
678 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000679 }
dburgessb3a0ca42011-10-12 07:44:40 +0000680
Alexander Chemeris2b542102015-06-08 22:46:38 -0400681 timingOffset = toa / mSPSRx;
682
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800683 bits = demodulate(state, *burst, amp, toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500684
Thomas Tsou30421a72013-11-13 23:14:48 -0500685 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500686 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000687}
688
dburgessb3a0ca42011-10-12 07:44:40 +0000689void Transceiver::reset()
690{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400691 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
692 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000693}
694
695
Thomas Tsou204a9f12013-10-29 18:34:16 -0400696void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000697{
dburgessb3a0ca42011-10-12 07:44:40 +0000698 int MAX_PACKET_LENGTH = 100;
699
700 // check control socket
701 char buffer[MAX_PACKET_LENGTH];
702 int msgLen = -1;
703 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400704
Thomas Tsou204a9f12013-10-29 18:34:16 -0400705 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000706
707 if (msgLen < 1) {
708 return;
709 }
710
711 char cmdcheck[4];
712 char command[MAX_PACKET_LENGTH];
713 char response[MAX_PACKET_LENGTH];
714
715 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400716
717 if (!chan)
718 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000719
720 if (strcmp(cmdcheck,"CMD")!=0) {
721 LOG(WARNING) << "bogus message on control interface";
722 return;
723 }
724 LOG(INFO) << "command is " << buffer;
725
726 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800727 stop();
728 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000729 }
730 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800731 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000732 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800733 else
dburgessb3a0ca42011-10-12 07:44:40 +0000734 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300735 for (int i = 0; i < 8; i++) {
736 for (int j = 0; j < 8; j++)
737 mHandover[i][j] = false;
738 }
739 }
740 else if (strcmp(command,"HANDOVER")==0){
741 int ts=0,ss=0;
742 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
743 mHandover[ts][ss] = true;
744 LOG(WARNING) << "HANDOVER RACH at timeslot " << ts << " subslot " << ss;
745 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
746 }
747 else if (strcmp(command,"NOHANDOVER")==0){
748 int ts=0,ss=0;
749 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
750 mHandover[ts][ss] = false;
751 LOG(WARNING) << "NOHANDOVER at timeslot " << ts << " subslot " << ss;
752 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000753 }
754 else if (strcmp(command,"SETMAXDLY")==0) {
755 //set expected maximum time-of-arrival
756 int maxDelay;
757 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300758 mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
dburgessb3a0ca42011-10-12 07:44:40 +0000759 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
760 }
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300761 else if (strcmp(command,"SETMAXDLYNB")==0) {
762 //set expected maximum time-of-arrival
763 int maxDelay;
764 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
765 mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
766 sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
767 }
dburgessb3a0ca42011-10-12 07:44:40 +0000768 else if (strcmp(command,"SETRXGAIN")==0) {
769 //set expected maximum time-of-arrival
770 int newGain;
771 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400772 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000773 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
774 }
775 else if (strcmp(command,"NOISELEV")==0) {
776 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500777 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000778 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500779 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000780 }
781 else {
782 sprintf(response,"RSP NOISELEV 1 0");
783 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500784 }
785 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800786 int power;
787 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
788 power = mRadioInterface->setPowerAttenuation(power, chan);
789 mStates[chan].mPower = power;
790 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000791 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500792 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800793 int power, step;
794 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
795 power = mStates[chan].mPower + step;
796 power = mRadioInterface->setPowerAttenuation(power, chan);
797 mStates[chan].mPower = power;
798 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000799 }
dburgessb3a0ca42011-10-12 07:44:40 +0000800 else if (strcmp(command,"RXTUNE")==0) {
801 // tune receiver
802 int freqKhz;
803 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500804 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400805 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000806 LOG(ALERT) << "RX failed to tune";
807 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
808 }
809 else
810 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
811 }
812 else if (strcmp(command,"TXTUNE")==0) {
813 // tune txmtr
814 int freqKhz;
815 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500816 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400817 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000818 LOG(ALERT) << "TX failed to tune";
819 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
820 }
821 else
822 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
823 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500824 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000825 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500826 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500827 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700828 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500829 sprintf(response, "RSP SETTSC 1 %d", TSC);
830 else if (chan && (TSC != mTSC))
831 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000832 else {
833 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400834 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000835 }
836 }
837 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700838 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000839 int corrCode;
840 int timeslot;
841 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
842 if ((timeslot < 0) || (timeslot > 7)) {
843 LOG(WARNING) << "bogus message on control interface";
844 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
845 return;
846 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400847 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
848 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000849 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
850
851 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400852 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
853 // debug command! may change or disapear without notice
854 // set a mask which bursts to dump to disk
855 int mask;
856 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
857 mWriteBurstToDiskMask = mask;
858 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
859 }
dburgessb3a0ca42011-10-12 07:44:40 +0000860 else {
861 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200862 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000863 }
864
Thomas Tsou204a9f12013-10-29 18:34:16 -0400865 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000866}
867
Thomas Tsou204a9f12013-10-29 18:34:16 -0400868bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000869{
dburgessb3a0ca42011-10-12 07:44:40 +0000870 char buffer[gSlotLen+50];
871
872 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400873 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000874
875 if (msgLen!=gSlotLen+1+4+1) {
876 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
877 return false;
878 }
879
880 int timeSlot = (int) buffer[0];
881 uint64_t frameNum = 0;
882 for (int i = 0; i < 4; i++)
883 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000884
dburgessb3a0ca42011-10-12 07:44:40 +0000885 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
886
887 int RSSI = (int) buffer[5];
888 static BitVector newBurst(gSlotLen);
889 BitVector::iterator itr = newBurst.begin();
890 char *bufferItr = buffer+6;
891 while (itr < newBurst.end())
892 *itr++ = *bufferItr++;
893
894 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400895
896 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000897
898 return true;
899
900
901}
dburgessb3a0ca42011-10-12 07:44:40 +0000902
Thomas Tsou204a9f12013-10-29 18:34:16 -0400903void Transceiver::driveReceiveRadio()
904{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400905 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400906 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400907 } else {
908 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
909 writeClockInterface();
910 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400911}
912
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800913void Transceiver::logRxBurst(SoftVector *burst, GSM::Time time, double dbm,
914 double rssi, double noise, double toa)
915{
916 LOG(DEBUG) << std::fixed << std::right
917 << " time: " << time
918 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
919 << "dBFS/" << std::setw(6) << -dbm << "dBm"
920 << " noise: " << std::setw(5) << std::setprecision(1) << noise
921 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
922 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
923 << " bits: " << *burst;
924}
925
Thomas Tsou204a9f12013-10-29 18:34:16 -0400926void Transceiver::driveReceiveFIFO(size_t chan)
927{
dburgessb3a0ca42011-10-12 07:44:40 +0000928 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400929 double RSSI; // in dBFS
930 double dBm; // in dBm
931 double TOA; // in symbols
932 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400933 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000934 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400935 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800936 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000937
Alexander Chemeris2b542102015-06-08 22:46:38 -0400938 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800939 if (!rxBurst)
940 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000941
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800942 /*
943 * EDGE demodulator returns 444 (148 * 3) bits
944 */
945 if (rxBurst->size() == gSlotLen * 3)
946 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000947
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800948 dBm = RSSI + rssiOffset;
949 logRxBurst(rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400950
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800951 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000952
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800953 char burstString[nbits + 10];
954 burstString[0] = burstTime.TN();
955 for (int i = 0; i < 4; i++)
956 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
957 burstString[5] = (int)dBm;
958 burstString[6] = (TOAint >> 8) & 0x0ff;
959 burstString[7] = TOAint & 0x0ff;
960 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000961
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800962 for (unsigned i = 0; i < nbits; i++)
963 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
964
965 burstString[nbits + 9] = '\0';
966 delete rxBurst;
967
968 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000969}
970
Thomas Tsou204a9f12013-10-29 18:34:16 -0400971void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000972{
973
974 /**
975 Features a carefully controlled latency mechanism, to
976 assure that transmit packets arrive at the radio/USRP
977 before they need to be transmitted.
978
979 Deadline clock indicates the burst that needs to be
980 pushed into the FIFO right NOW. If transmit queue does
981 not have a burst, stick in filler data.
982 */
983
984
985 RadioClock *radioClock = (mRadioInterface->getClock());
986
987 if (mOn) {
988 //radioClock->wait(); // wait until clock updates
989 LOG(DEBUG) << "radio clock " << radioClock->get();
990 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
991 // if underrun, then we're not providing bursts to radio/USRP fast
992 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400993 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000994 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000995 // only update latency at the defined frame interval
996 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000997 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
998 LOG(INFO) << "new latency: " << mTransmitLatency;
999 mLatencyUpdateTime = radioClock->get();
1000 }
1001 }
1002 else {
1003 // if underrun hasn't occurred in the last sec (216 frames) drop
1004 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +00001005 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001006 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1007 mTransmitLatency.decTN();
1008 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1009 mLatencyUpdateTime = radioClock->get();
1010 }
1011 }
1012 }
dburgessb3a0ca42011-10-12 07:44:40 +00001013 }
dburgessb3a0ca42011-10-12 07:44:40 +00001014 // time to push burst to transmit FIFO
1015 pushRadioVector(mTransmitDeadlineClock);
1016 mTransmitDeadlineClock.incTN();
1017 }
dburgessb3a0ca42011-10-12 07:44:40 +00001018 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001019
1020 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001021}
1022
1023
1024
1025void Transceiver::writeClockInterface()
1026{
1027 char command[50];
1028 // FIXME -- This should be adaptive.
1029 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1030
1031 LOG(INFO) << "ClockInterface: sending " << command;
1032
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001033 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001034
1035 mLastClockUpdateTime = mTransmitDeadlineClock;
1036
Thomas Tsou92c16df2013-09-28 18:04:19 -04001037}
dburgessb3a0ca42011-10-12 07:44:40 +00001038
Thomas Tsou204a9f12013-10-29 18:34:16 -04001039void *RxUpperLoopAdapter(TransceiverChannel *chan)
1040{
1041 Transceiver *trx = chan->trx;
1042 size_t num = chan->num;
1043
1044 delete chan;
1045
Thomas Tsou7553aa92013-11-08 12:50:03 -05001046 trx->setPriority(0.42);
1047
Thomas Tsou204a9f12013-10-29 18:34:16 -04001048 while (1) {
1049 trx->driveReceiveFIFO(num);
1050 pthread_testcancel();
1051 }
1052 return NULL;
1053}
1054
1055void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001056{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001057 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001058
dburgessb3a0ca42011-10-12 07:44:40 +00001059 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001060 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001061 pthread_testcancel();
1062 }
1063 return NULL;
1064}
1065
Thomas Tsou204a9f12013-10-29 18:34:16 -04001066void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001067{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001068 transceiver->setPriority(0.44);
1069
Thomas Tsou92c16df2013-09-28 18:04:19 -04001070 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001071 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001072 pthread_testcancel();
1073 }
1074 return NULL;
1075}
1076
Thomas Tsou204a9f12013-10-29 18:34:16 -04001077void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001078{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001079 Transceiver *trx = chan->trx;
1080 size_t num = chan->num;
1081
1082 delete chan;
1083
dburgessb3a0ca42011-10-12 07:44:40 +00001084 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001085 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001086 pthread_testcancel();
1087 }
1088 return NULL;
1089}
1090
Thomas Tsou204a9f12013-10-29 18:34:16 -04001091void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001092{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001093 Transceiver *trx = chan->trx;
1094 size_t num = chan->num;
1095
1096 delete chan;
1097
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001098 trx->setPriority(0.40);
1099
dburgessb3a0ca42011-10-12 07:44:40 +00001100 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001101 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001102 pthread_testcancel();
1103 }
1104 return NULL;
1105}