blob: d3dce4950cf88ea372c45b2df8003d83e49dece2 [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
Tom Tsoua84e1622016-06-29 14:50:25 -070047/*
48 * Burst detection threshold
49 *
50 * Decision threshold value for burst gating on peak-to-average value of
51 * correlated synchronization sequences. Lower values pass more bursts up
52 * to upper layers but will increase the false detection rate.
53 */
54#define BURST_THRESH 4.0
55
Thomas Tsouf0782732013-10-29 15:55:47 -040056TransceiverState::TransceiverState()
Tom Tsoua4d1a412014-11-25 15:46:56 -080057 : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
Thomas Tsouf0782732013-10-29 15:55:47 -040058{
59 for (int i = 0; i < 8; i++) {
60 chanType[i] = Transceiver::NONE;
61 fillerModulus[i] = 26;
62 chanResponse[i] = NULL;
63 DFEForward[i] = NULL;
64 DFEFeedback[i] = NULL;
65
66 for (int n = 0; n < 102; n++)
67 fillerTable[n][i] = NULL;
68 }
69}
70
71TransceiverState::~TransceiverState()
72{
73 for (int i = 0; i < 8; i++) {
74 delete chanResponse[i];
75 delete DFEForward[i];
76 delete DFEFeedback[i];
77
78 for (int n = 0; n < 102; n++)
79 delete fillerTable[n][i];
80 }
81}
82
Alexander Chemeris37c52c72016-03-25 18:28:34 +030083bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc, unsigned rach_delay)
Tom Tsou64ad7122015-05-19 18:26:31 -070084{
Tom Tsou64ad7122015-05-19 18:26:31 -070085 signalVector *burst;
86
87 if ((sps != 1) && (sps != 4))
88 return false;
89
90 for (size_t n = 0; n < 8; n++) {
Tom Tsou64ad7122015-05-19 18:26:31 -070091 for (size_t i = 0; i < 102; i++) {
92 switch (filler) {
93 case Transceiver::FILLER_DUMMY:
Tom Tsou8ee2f382016-03-06 20:57:34 -080094 burst = generateDummyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070095 break;
Tom Tsouaf717b22016-03-06 22:19:15 -080096 case Transceiver::FILLER_NORM_RAND:
Tom Tsou8ee2f382016-03-06 20:57:34 -080097 burst = genRandNormalBurst(rtsc, sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070098 break;
Tom Tsouaf717b22016-03-06 22:19:15 -080099 case Transceiver::FILLER_EDGE_RAND:
100 burst = generateEdgeBurst(rtsc);
101 break;
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300102 case Transceiver::FILLER_ACCESS_RAND:
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300103 burst = genRandAccessBurst(rach_delay, sps, n);
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300104 break;
Tom Tsou64ad7122015-05-19 18:26:31 -0700105 case Transceiver::FILLER_ZERO:
106 default:
Tom Tsou8ee2f382016-03-06 20:57:34 -0800107 burst = generateEmptyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -0700108 }
109
110 scaleVector(*burst, scale);
111 fillerTable[i][n] = burst;
112 }
113
Tom Tsouaf717b22016-03-06 22:19:15 -0800114 if ((filler == Transceiver::FILLER_NORM_RAND) ||
115 (filler == Transceiver::FILLER_EDGE_RAND)) {
116 chanType[n] = Transceiver::TSC;
117 }
Thomas Tsou15d743e2014-01-25 02:34:03 -0500118 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700119
120 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400121}
122
dburgessb3a0ca42011-10-12 07:44:40 +0000123Transceiver::Transceiver(int wBasePort,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400124 const char *wTRXAddress,
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800125 size_t tx_sps, size_t rx_sps, size_t chans,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400126 GSM::Time wTransmitLatency,
127 RadioInterface *wRadioInterface,
128 double wRssiOffset)
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800129 : mBasePort(wBasePort), mAddr(wTRXAddress),
130 mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
131 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Alexander Chemerise8905a02015-06-03 23:47:56 -0400132 rssiOffset(wRssiOffset),
Tom Tsou64464e62016-07-01 03:46:46 -0700133 mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mEdge(false), mOn(false),
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300134 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
135 mWriteBurstToDiskMask(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000136{
dburgessb3a0ca42011-10-12 07:44:40 +0000137 txFullScale = mRadioInterface->fullScaleInputValue();
138 rxFullScale = mRadioInterface->fullScaleOutputValue();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300139
140 for (int i = 0; i < 8; i++) {
141 for (int j = 0; j < 8; j++)
142 mHandover[i][j] = false;
143 }
dburgessb3a0ca42011-10-12 07:44:40 +0000144}
145
146Transceiver::~Transceiver()
147{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800148 stop();
149
dburgessb3a0ca42011-10-12 07:44:40 +0000150 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400151
Thomas Tsou204a9f12013-10-29 18:34:16 -0400152 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800153 mControlServiceLoopThreads[i]->cancel();
154 mControlServiceLoopThreads[i]->join();
155 delete mControlServiceLoopThreads[i];
156
Thomas Tsou204a9f12013-10-29 18:34:16 -0400157 mTxPriorityQueues[i].clear();
158 delete mCtrlSockets[i];
159 delete mDataSockets[i];
160 }
dburgessb3a0ca42011-10-12 07:44:40 +0000161}
Thomas Tsou83e06892013-08-20 16:10:01 -0400162
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800163/*
164 * Initialize transceiver
165 *
166 * Start or restart the control loop. Any further control is handled through the
167 * socket API. Randomize the central radio clock set the downlink burst
168 * counters. Note that the clock will not update until the radio starts, but we
169 * are still expected to report clock indications through control channel
170 * activity.
171 */
Tom Tsou64464e62016-07-01 03:46:46 -0700172bool Transceiver::init(int filler, size_t rtsc, unsigned rach_delay, bool edge)
Thomas Tsou83e06892013-08-20 16:10:01 -0400173{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500174 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400175
Thomas Tsou204a9f12013-10-29 18:34:16 -0400176 if (!mChans) {
177 LOG(ALERT) << "No channels assigned";
178 return false;
179 }
180
Tom Tsou2079a3c2016-03-06 00:58:56 -0800181 if (!sigProcLibSetup()) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400182 LOG(ALERT) << "Failed to initialize signal processing library";
183 return false;
184 }
185
Tom Tsou64464e62016-07-01 03:46:46 -0700186 mEdge = edge;
187
Thomas Tsou204a9f12013-10-29 18:34:16 -0400188 mDataSockets.resize(mChans);
189 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400190 mControlServiceLoopThreads.resize(mChans);
191 mTxPriorityQueueServiceLoopThreads.resize(mChans);
192 mRxServiceLoopThreads.resize(mChans);
193
194 mTxPriorityQueues.resize(mChans);
195 mReceiveFIFO.resize(mChans);
196 mStates.resize(mChans);
197
Thomas Tsouccb73e12014-04-15 17:41:28 -0400198 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700199 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400200 mStates[0].mRetrans = true;
201
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800202 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400203 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500204 c_srcport = mBasePort + 2 * i + 1;
205 c_dstport = mBasePort + 2 * i + 101;
206 d_srcport = mBasePort + 2 * i + 2;
207 d_dstport = mBasePort + 2 * i + 102;
208
209 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
210 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400211 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400212
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800213 /* Randomize the central clock */
214 GSM::Time startTime(random() % gHyperframe, 0);
215 mRadioInterface->getClock()->set(startTime);
216 mTransmitDeadlineClock = startTime;
217 mLastClockUpdateTime = startTime;
218 mLatencyUpdateTime = startTime;
219
220 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400221 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800222 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400223 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800224 mControlServiceLoopThreads[i]->start((void * (*)(void*))
225 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400226
Tom Tsou64ad7122015-05-19 18:26:31 -0700227 if (i && filler == FILLER_DUMMY)
228 filler = FILLER_ZERO;
229
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300230 mStates[i].init(filler, mSPSTx, txFullScale, rtsc, rach_delay);
Thomas Tsou83e06892013-08-20 16:10:01 -0400231 }
232
233 return true;
234}
dburgessb3a0ca42011-10-12 07:44:40 +0000235
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800236/*
237 * Start the transceiver
238 *
239 * Submit command(s) to the radio device to commence streaming samples and
240 * launch threads to handle sample I/O. Re-synchronize the transmit burst
241 * counters to the central radio clock here as well.
242 */
243bool Transceiver::start()
244{
245 ScopedLock lock(mLock);
246
247 if (mOn) {
248 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300249 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800250 }
251
252 LOG(NOTICE) << "Starting the transceiver";
253
254 GSM::Time time = mRadioInterface->getClock()->get();
255 mTransmitDeadlineClock = time;
256 mLastClockUpdateTime = time;
257 mLatencyUpdateTime = time;
258
259 if (!mRadioInterface->start()) {
260 LOG(ALERT) << "Device failed to start";
261 return false;
262 }
263
264 /* Device is running - launch I/O threads */
265 mRxLowerLoopThread = new Thread(32768);
266 mTxLowerLoopThread = new Thread(32768);
267 mTxLowerLoopThread->start((void * (*)(void*))
268 TxLowerLoopAdapter,(void*) this);
269 mRxLowerLoopThread->start((void * (*)(void*))
270 RxLowerLoopAdapter,(void*) this);
271
272 /* Launch uplink and downlink burst processing threads */
273 for (size_t i = 0; i < mChans; i++) {
274 TransceiverChannel *chan = new TransceiverChannel(this, i);
275 mRxServiceLoopThreads[i] = new Thread(32768);
276 mRxServiceLoopThreads[i]->start((void * (*)(void*))
277 RxUpperLoopAdapter, (void*) chan);
278
279 chan = new TransceiverChannel(this, i);
280 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
281 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
282 TxUpperLoopAdapter, (void*) chan);
283 }
284
285 writeClockInterface();
286 mOn = true;
287 return true;
288}
289
290/*
291 * Stop the transceiver
292 *
293 * Perform stopping by disabling receive streaming and issuing cancellation
294 * requests to running threads. Most threads will timeout and terminate once
295 * device is disabled, but the transmit loop may block waiting on the central
296 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
297 * makes it to the thread cancellation point.
298 */
299void Transceiver::stop()
300{
301 ScopedLock lock(mLock);
302
303 if (!mOn)
304 return;
305
306 LOG(NOTICE) << "Stopping the transceiver";
307 mTxLowerLoopThread->cancel();
308 mRxLowerLoopThread->cancel();
309
310 for (size_t i = 0; i < mChans; i++) {
311 mRxServiceLoopThreads[i]->cancel();
312 mTxPriorityQueueServiceLoopThreads[i]->cancel();
313 }
314
315 LOG(INFO) << "Stopping the device";
316 mRadioInterface->stop();
317
318 for (size_t i = 0; i < mChans; i++) {
319 mRxServiceLoopThreads[i]->join();
320 mTxPriorityQueueServiceLoopThreads[i]->join();
321 delete mRxServiceLoopThreads[i];
322 delete mTxPriorityQueueServiceLoopThreads[i];
323
324 mTxPriorityQueues[i].clear();
325 }
326
327 mTxLowerLoopThread->join();
328 mRxLowerLoopThread->join();
329 delete mTxLowerLoopThread;
330 delete mRxLowerLoopThread;
331
332 mOn = false;
333 LOG(NOTICE) << "Transceiver stopped";
334}
335
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500336void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400337 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000338{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500339 signalVector *burst;
340 radioVector *radio_burst;
341
Thomas Tsou204a9f12013-10-29 18:34:16 -0400342 if (chan >= mTxPriorityQueues.size()) {
343 LOG(ALERT) << "Invalid channel " << chan;
344 return;
345 }
346
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500347 if (wTime.TN() > 7) {
348 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
349 return;
350 }
351
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800352 /* Use the number of bits as the EDGE burst indicator */
353 if (bits.size() == EDGE_BURST_NBITS)
354 burst = modulateEdgeBurst(bits, mSPSTx);
355 else
356 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
357
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500358 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000359
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500360 radio_burst = new radioVector(wTime, burst);
361
362 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000363}
364
Thomas Tsou15d743e2014-01-25 02:34:03 -0500365void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
366{
367 int TN, modFN;
368 TransceiverState *state = &mStates[chan];
369
370 TN = burst->getTime().TN();
371 modFN = burst->getTime().FN() % state->fillerModulus[TN];
372
373 delete state->fillerTable[modFN][TN];
374 state->fillerTable[modFN][TN] = burst->getVector();
375 burst->setVector(NULL);
376}
377
dburgessb3a0ca42011-10-12 07:44:40 +0000378void Transceiver::pushRadioVector(GSM::Time &nowTime)
379{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400380 int TN, modFN;
381 radioVector *burst;
382 TransceiverState *state;
383 std::vector<signalVector *> bursts(mChans);
384 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500385 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000386
Thomas Tsou204a9f12013-10-29 18:34:16 -0400387 for (size_t i = 0; i < mChans; i ++) {
388 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000389
Thomas Tsou204a9f12013-10-29 18:34:16 -0400390 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
391 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500392 if (state->mRetrans)
393 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500394 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400395 }
396
397 TN = nowTime.TN();
398 modFN = nowTime.FN() % state->fillerModulus[TN];
399
400 bursts[i] = state->fillerTable[modFN][TN];
401 zeros[i] = state->chanType[TN] == NONE;
402
403 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500404 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500405
406 if (state->mRetrans) {
407 updateFillerTable(i, burst);
408 } else {
409 burst->setVector(NULL);
410 filler[i] = false;
411 }
412
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500413 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400414 }
dburgessb3a0ca42011-10-12 07:44:40 +0000415 }
416
Thomas Tsou204a9f12013-10-29 18:34:16 -0400417 mRadioInterface->driveTransmitRadio(bursts, zeros);
418
Thomas Tsou15d743e2014-01-25 02:34:03 -0500419 for (size_t i = 0; i < mChans; i++) {
420 if (!filler[i])
421 delete bursts[i];
422 }
dburgessb3a0ca42011-10-12 07:44:40 +0000423}
424
Thomas Tsou204a9f12013-10-29 18:34:16 -0400425void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000426{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400427 TransceiverState *state = &mStates[chan];
428
429 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000430 case NONE:
431 case I:
432 case II:
433 case III:
434 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400435 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000436 break;
437 case IV:
438 case VI:
439 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400440 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000441 break;
442 //case V:
443 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400444 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000445 break;
ttsoufc40a842013-06-09 22:38:18 +0000446 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400447 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000448 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000449 default:
450 break;
451 }
452}
453
454
Thomas Tsou204a9f12013-10-29 18:34:16 -0400455Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
456 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000457{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300458 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 };
459 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,
460 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 };
461 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,
462 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 -0400463 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000464 unsigned burstTN = currTime.TN();
465 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300466 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000467
Thomas Tsou204a9f12013-10-29 18:34:16 -0400468 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000469 case NONE:
470 return OFF;
471 break;
472 case FILL:
473 return IDLE;
474 break;
475 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300476 // TODO: Are we expecting RACH on an IDLE frame?
477/* if (burstFN % 26 == 25)
478 return IDLE;*/
479 if (mHandover[burstTN][0])
480 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000481 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000482 break;
483 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300484 subch = tchh_subslot[burstFN % 26];
485 if (subch == 1)
486 return IDLE;
487 if (mHandover[burstTN][0])
488 return RACH;
ttsou20642972013-03-27 22:00:25 +0000489 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000490 break;
491 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300492 subch = tchh_subslot[burstFN % 26];
493 if (mHandover[burstTN][subch])
494 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000495 return TSC;
496 break;
497 case IV:
498 case VI:
499 return RACH;
500 break;
501 case V: {
502 int mod51 = burstFN % 51;
503 if ((mod51 <= 36) && (mod51 >= 14))
504 return RACH;
505 else if ((mod51 == 4) || (mod51 == 5))
506 return RACH;
507 else if ((mod51 == 45) || (mod51 == 46))
508 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300509 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
510 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000511 else
512 return TSC;
513 break;
514 }
515 case VII:
516 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
517 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300518 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
519 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000520 else
521 return TSC;
522 break;
ttsoufc40a842013-06-09 22:38:18 +0000523 case XIII: {
524 int mod52 = burstFN % 52;
525 if ((mod52 == 12) || (mod52 == 38))
526 return RACH;
527 else if ((mod52 == 25) || (mod52 == 51))
528 return IDLE;
529 else
530 return TSC;
531 break;
532 }
dburgessb3a0ca42011-10-12 07:44:40 +0000533 case LOOPBACK:
534 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
535 return IDLE;
536 else
537 return TSC;
538 break;
539 default:
540 return OFF;
541 break;
542 }
dburgessb3a0ca42011-10-12 07:44:40 +0000543}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400544
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300545int Transceiver::detectBurst(signalVector &burst,
546 complex &amp, float &toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500547{
Tom Tsoua84e1622016-06-29 14:50:25 -0700548 int rc = 0;
Thomas Tsou30421a72013-11-13 23:14:48 -0500549
Tom Tsou46569402016-03-06 01:59:38 -0800550 switch (type) {
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800551 case EDGE:
Tom Tsoua84e1622016-06-29 14:50:25 -0700552 rc = detectEdgeBurst(burst, mTSC, BURST_THRESH, mSPSRx,
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300553 amp, toa, mMaxExpectedDelayNB);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800554 if (rc > 0)
555 break;
556 else
557 type = TSC;
Tom Tsou46569402016-03-06 01:59:38 -0800558 case TSC:
Tom Tsoua84e1622016-06-29 14:50:25 -0700559 rc = analyzeTrafficBurst(burst, mTSC, BURST_THRESH, mSPSRx,
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300560 amp, toa, mMaxExpectedDelayNB);
Tom Tsou46569402016-03-06 01:59:38 -0800561 break;
562 case RACH:
Tom Tsoua84e1622016-06-29 14:50:25 -0700563 rc = detectRACHBurst(burst, BURST_THRESH, mSPSRx, amp, toa,
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300564 mMaxExpectedDelayAB);
Tom Tsou46569402016-03-06 01:59:38 -0800565 break;
566 default:
567 LOG(ERR) << "Invalid correlation type";
568 }
569
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800570 if (rc > 0)
571 return type;
Tom Tsou46569402016-03-06 01:59:38 -0800572
573 return rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500574}
575
Thomas Tsou30421a72013-11-13 23:14:48 -0500576
577/*
Tom Tsou46569402016-03-06 01:59:38 -0800578 * Demodulate GMSK by direct rotation and soft slicing.
Thomas Tsou30421a72013-11-13 23:14:48 -0500579 */
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300580SoftVector *Transceiver::demodulate(signalVector &burst, complex amp,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800581 float toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500582{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800583 if (type == EDGE)
584 return demodEdgeBurst(burst, mSPSRx, amp, toa);
585
Thomas Tsou30421a72013-11-13 23:14:48 -0500586 return demodulateBurst(burst, mSPSRx, amp, toa);
587}
588
Alexander Chemerise692ce92015-06-12 00:15:31 -0400589void writeToFile(radioVector *radio_burst, size_t chan)
590{
591 GSM::Time time = radio_burst->getTime();
592 std::ostringstream fname;
593 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
594 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
595 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
596 outfile.close();
597}
598
Thomas Tsou30421a72013-11-13 23:14:48 -0500599/*
600 * Pull bursts from the FIFO and handle according to the slot
601 * and burst correlation type. Equalzation is currently disabled.
602 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400603SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400604 double &timingOffset, double &noise,
605 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000606{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800607 int rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500608 complex amp;
609 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500610 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500611 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500612 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500613 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400614 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000615
Thomas Tsou30421a72013-11-13 23:14:48 -0500616 /* Blocking FIFO read */
617 radioVector *radio_burst = mReceiveFIFO[chan]->read();
618 if (!radio_burst)
619 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000620
Thomas Tsou30421a72013-11-13 23:14:48 -0500621 /* Set time and determine correlation type */
622 GSM::Time time = radio_burst->getTime();
623 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000624
Tom Tsou64464e62016-07-01 03:46:46 -0700625 /* Enable 8-PSK burst detection if EDGE is enabled */
626 if (mEdge && (type == TSC))
627 type = EDGE;
628
Alexander Chemerise692ce92015-06-12 00:15:31 -0400629 /* Debug: dump bursts to disk */
630 /* bits 0-7 - chan 0 timeslots
631 * bits 8-15 - chan 1 timeslots */
632 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
633 writeToFile(radio_burst, chan);
634
Alexander Chemeris2b542102015-06-08 22:46:38 -0400635 /* No processing if the timeslot is off.
636 * Not even power level or noise calculation. */
637 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500638 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000639 return NULL;
640 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000641
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500642 /* Select the diversity channel with highest energy */
643 for (size_t i = 0; i < radio_burst->chans(); i++) {
644 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
645 if (pow > max) {
646 max = pow;
647 max_i = i;
648 }
649 avg += pow;
650 }
651
652 if (max_i < 0) {
653 LOG(ALERT) << "Received empty burst";
654 delete radio_burst;
655 return NULL;
656 }
657
Thomas Tsou30421a72013-11-13 23:14:48 -0500658 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500659 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500660 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400661
662 wTime = time;
663 RSSI = 20.0 * log10(rxFullScale / avg);
664
665 /* RSSI estimation are valid */
666 isRssiValid = true;
667
668 if (type == IDLE) {
669 /* Update noise levels */
670 state->mNoises.insert(avg);
671 state->mNoiseLev = state->mNoises.avg();
672 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
673
674 delete radio_burst;
675 return NULL;
676 } else {
677 /* Do not update noise levels */
678 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
679 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400680
Thomas Tsou30421a72013-11-13 23:14:48 -0500681 /* Detect normal or RACH bursts */
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300682 rc = detectBurst(*burst, amp, toa, type);
Thomas Tsouf0782732013-10-29 15:55:47 -0400683
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800684 if (rc > 0) {
685 type = (CorrType) rc;
686 } else if (rc <= 0) {
687 if (rc == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400688 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800689 } else if (rc != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400690 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700691 }
692
Thomas Tsou30421a72013-11-13 23:14:48 -0500693 delete radio_burst;
694 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000695 }
dburgessb3a0ca42011-10-12 07:44:40 +0000696
Alexander Chemeris2b542102015-06-08 22:46:38 -0400697 timingOffset = toa / mSPSRx;
698
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300699 bits = demodulate(*burst, amp, toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500700
Thomas Tsou30421a72013-11-13 23:14:48 -0500701 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500702 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000703}
704
dburgessb3a0ca42011-10-12 07:44:40 +0000705void Transceiver::reset()
706{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400707 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
708 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000709}
710
711
Thomas Tsou204a9f12013-10-29 18:34:16 -0400712void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000713{
dburgessb3a0ca42011-10-12 07:44:40 +0000714 int MAX_PACKET_LENGTH = 100;
715
716 // check control socket
717 char buffer[MAX_PACKET_LENGTH];
718 int msgLen = -1;
719 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400720
Tom Tsou2c650a62016-04-28 21:55:17 -0700721 msgLen = mCtrlSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000722
723 if (msgLen < 1) {
724 return;
725 }
726
727 char cmdcheck[4];
728 char command[MAX_PACKET_LENGTH];
729 char response[MAX_PACKET_LENGTH];
730
731 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400732
733 if (!chan)
734 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000735
736 if (strcmp(cmdcheck,"CMD")!=0) {
737 LOG(WARNING) << "bogus message on control interface";
738 return;
739 }
740 LOG(INFO) << "command is " << buffer;
741
742 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800743 stop();
744 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000745 }
746 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800747 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000748 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800749 else
dburgessb3a0ca42011-10-12 07:44:40 +0000750 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300751 for (int i = 0; i < 8; i++) {
752 for (int j = 0; j < 8; j++)
753 mHandover[i][j] = false;
754 }
755 }
756 else if (strcmp(command,"HANDOVER")==0){
757 int ts=0,ss=0;
758 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
759 mHandover[ts][ss] = true;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300760 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
761 }
762 else if (strcmp(command,"NOHANDOVER")==0){
763 int ts=0,ss=0;
764 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
765 mHandover[ts][ss] = false;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300766 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000767 }
768 else if (strcmp(command,"SETMAXDLY")==0) {
769 //set expected maximum time-of-arrival
770 int maxDelay;
771 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300772 mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
dburgessb3a0ca42011-10-12 07:44:40 +0000773 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
774 }
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300775 else if (strcmp(command,"SETMAXDLYNB")==0) {
776 //set expected maximum time-of-arrival
777 int maxDelay;
778 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
779 mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
780 sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
781 }
dburgessb3a0ca42011-10-12 07:44:40 +0000782 else if (strcmp(command,"SETRXGAIN")==0) {
783 //set expected maximum time-of-arrival
784 int newGain;
785 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400786 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000787 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
788 }
789 else if (strcmp(command,"NOISELEV")==0) {
790 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500791 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000792 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500793 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000794 }
795 else {
796 sprintf(response,"RSP NOISELEV 1 0");
797 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500798 }
799 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800800 int power;
801 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
802 power = mRadioInterface->setPowerAttenuation(power, chan);
803 mStates[chan].mPower = power;
804 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000805 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500806 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800807 int power, step;
808 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
809 power = mStates[chan].mPower + step;
810 power = mRadioInterface->setPowerAttenuation(power, chan);
811 mStates[chan].mPower = power;
812 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000813 }
dburgessb3a0ca42011-10-12 07:44:40 +0000814 else if (strcmp(command,"RXTUNE")==0) {
815 // tune receiver
816 int freqKhz;
817 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500818 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400819 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000820 LOG(ALERT) << "RX failed to tune";
821 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
822 }
823 else
824 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
825 }
826 else if (strcmp(command,"TXTUNE")==0) {
827 // tune txmtr
828 int freqKhz;
829 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500830 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400831 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000832 LOG(ALERT) << "TX failed to tune";
833 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
834 }
835 else
836 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
837 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500838 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000839 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500840 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500841 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Tom Tsouc8c4eac2016-06-28 17:00:54 -0700842 if ((TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500843 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000844 else {
Tom Tsouc37594f2016-07-08 14:39:42 -0700845 LOG(NOTICE) << "Changing TSC from " << mTSC << " to " << TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000846 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400847 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000848 }
849 }
850 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700851 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000852 int corrCode;
853 int timeslot;
854 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
855 if ((timeslot < 0) || (timeslot > 7)) {
856 LOG(WARNING) << "bogus message on control interface";
857 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
858 return;
859 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400860 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
861 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000862 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
863
864 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400865 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
866 // debug command! may change or disapear without notice
867 // set a mask which bursts to dump to disk
868 int mask;
869 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
870 mWriteBurstToDiskMask = mask;
871 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
872 }
dburgessb3a0ca42011-10-12 07:44:40 +0000873 else {
874 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200875 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000876 }
877
Thomas Tsou204a9f12013-10-29 18:34:16 -0400878 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000879}
880
Thomas Tsou204a9f12013-10-29 18:34:16 -0400881bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000882{
Tom Tsoue8871082016-07-01 02:46:04 -0700883 int burstLen;
884 char buffer[EDGE_BURST_NBITS + 50];
dburgessb3a0ca42011-10-12 07:44:40 +0000885
886 // check data socket
Tom Tsou2c650a62016-04-28 21:55:17 -0700887 size_t msgLen = mDataSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000888
Tom Tsoue8871082016-07-01 02:46:04 -0700889 if (msgLen == gSlotLen + 1 + 4 + 1) {
890 burstLen = gSlotLen;
891 } else if (msgLen == EDGE_BURST_NBITS + 1 + 4 + 1) {
892 if (mSPSTx != 4)
893 return false;
894
895 burstLen = EDGE_BURST_NBITS;
896 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000897 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
898 return false;
899 }
900
901 int timeSlot = (int) buffer[0];
902 uint64_t frameNum = 0;
903 for (int i = 0; i < 4; i++)
904 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000905
dburgessb3a0ca42011-10-12 07:44:40 +0000906 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
907
908 int RSSI = (int) buffer[5];
Tom Tsoue8871082016-07-01 02:46:04 -0700909 static BitVector newBurst(burstLen);
dburgessb3a0ca42011-10-12 07:44:40 +0000910 BitVector::iterator itr = newBurst.begin();
911 char *bufferItr = buffer+6;
912 while (itr < newBurst.end())
913 *itr++ = *bufferItr++;
914
915 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400916
917 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000918
919 return true;
920
921
922}
dburgessb3a0ca42011-10-12 07:44:40 +0000923
Thomas Tsou204a9f12013-10-29 18:34:16 -0400924void Transceiver::driveReceiveRadio()
925{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400926 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400927 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400928 } else {
929 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
930 writeClockInterface();
931 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400932}
933
Alexander Chemeris58e95912016-03-25 18:20:28 +0300934void Transceiver::logRxBurst(size_t chan, SoftVector *burst, GSM::Time time, double dbm,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800935 double rssi, double noise, double toa)
936{
937 LOG(DEBUG) << std::fixed << std::right
Alexander Chemeris58e95912016-03-25 18:20:28 +0300938 << " chan: " << chan
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800939 << " time: " << time
940 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
941 << "dBFS/" << std::setw(6) << -dbm << "dBm"
942 << " noise: " << std::setw(5) << std::setprecision(1) << noise
943 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
944 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
945 << " bits: " << *burst;
946}
947
Thomas Tsou204a9f12013-10-29 18:34:16 -0400948void Transceiver::driveReceiveFIFO(size_t chan)
949{
dburgessb3a0ca42011-10-12 07:44:40 +0000950 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400951 double RSSI; // in dBFS
952 double dBm; // in dBm
953 double TOA; // in symbols
954 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400955 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000956 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400957 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800958 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000959
Alexander Chemeris2b542102015-06-08 22:46:38 -0400960 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800961 if (!rxBurst)
962 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000963
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800964 /*
965 * EDGE demodulator returns 444 (148 * 3) bits
966 */
967 if (rxBurst->size() == gSlotLen * 3)
968 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000969
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800970 dBm = RSSI + rssiOffset;
Alexander Chemeris58e95912016-03-25 18:20:28 +0300971 logRxBurst(chan, rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400972
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800973 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000974
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800975 char burstString[nbits + 10];
976 burstString[0] = burstTime.TN();
977 for (int i = 0; i < 4; i++)
978 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
979 burstString[5] = (int)dBm;
980 burstString[6] = (TOAint >> 8) & 0x0ff;
981 burstString[7] = TOAint & 0x0ff;
982 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000983
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800984 for (unsigned i = 0; i < nbits; i++)
985 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
986
987 burstString[nbits + 9] = '\0';
988 delete rxBurst;
989
990 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000991}
992
Thomas Tsou204a9f12013-10-29 18:34:16 -0400993void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000994{
995
996 /**
997 Features a carefully controlled latency mechanism, to
998 assure that transmit packets arrive at the radio/USRP
999 before they need to be transmitted.
1000
1001 Deadline clock indicates the burst that needs to be
1002 pushed into the FIFO right NOW. If transmit queue does
1003 not have a burst, stick in filler data.
1004 */
1005
1006
1007 RadioClock *radioClock = (mRadioInterface->getClock());
1008
1009 if (mOn) {
1010 //radioClock->wait(); // wait until clock updates
1011 LOG(DEBUG) << "radio clock " << radioClock->get();
1012 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
1013 // if underrun, then we're not providing bursts to radio/USRP fast
1014 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -04001015 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001016 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +00001017 // only update latency at the defined frame interval
1018 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001019 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
1020 LOG(INFO) << "new latency: " << mTransmitLatency;
1021 mLatencyUpdateTime = radioClock->get();
1022 }
1023 }
1024 else {
1025 // if underrun hasn't occurred in the last sec (216 frames) drop
1026 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +00001027 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001028 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1029 mTransmitLatency.decTN();
1030 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1031 mLatencyUpdateTime = radioClock->get();
1032 }
1033 }
1034 }
dburgessb3a0ca42011-10-12 07:44:40 +00001035 }
dburgessb3a0ca42011-10-12 07:44:40 +00001036 // time to push burst to transmit FIFO
1037 pushRadioVector(mTransmitDeadlineClock);
1038 mTransmitDeadlineClock.incTN();
1039 }
dburgessb3a0ca42011-10-12 07:44:40 +00001040 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001041
1042 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001043}
1044
1045
1046
1047void Transceiver::writeClockInterface()
1048{
1049 char command[50];
1050 // FIXME -- This should be adaptive.
1051 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1052
1053 LOG(INFO) << "ClockInterface: sending " << command;
1054
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001055 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001056
1057 mLastClockUpdateTime = mTransmitDeadlineClock;
1058
Thomas Tsou92c16df2013-09-28 18:04:19 -04001059}
dburgessb3a0ca42011-10-12 07:44:40 +00001060
Thomas Tsou204a9f12013-10-29 18:34:16 -04001061void *RxUpperLoopAdapter(TransceiverChannel *chan)
1062{
1063 Transceiver *trx = chan->trx;
1064 size_t num = chan->num;
1065
1066 delete chan;
1067
Thomas Tsou7553aa92013-11-08 12:50:03 -05001068 trx->setPriority(0.42);
1069
Thomas Tsou204a9f12013-10-29 18:34:16 -04001070 while (1) {
1071 trx->driveReceiveFIFO(num);
1072 pthread_testcancel();
1073 }
1074 return NULL;
1075}
1076
1077void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001078{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001079 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001080
dburgessb3a0ca42011-10-12 07:44:40 +00001081 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001082 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001083 pthread_testcancel();
1084 }
1085 return NULL;
1086}
1087
Thomas Tsou204a9f12013-10-29 18:34:16 -04001088void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001089{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001090 transceiver->setPriority(0.44);
1091
Thomas Tsou92c16df2013-09-28 18:04:19 -04001092 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001093 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001094 pthread_testcancel();
1095 }
1096 return NULL;
1097}
1098
Thomas Tsou204a9f12013-10-29 18:34:16 -04001099void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001100{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001101 Transceiver *trx = chan->trx;
1102 size_t num = chan->num;
1103
1104 delete chan;
1105
dburgessb3a0ca42011-10-12 07:44:40 +00001106 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001107 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001108 pthread_testcancel();
1109 }
1110 return NULL;
1111}
1112
Thomas Tsou204a9f12013-10-29 18:34:16 -04001113void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001114{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001115 Transceiver *trx = chan->trx;
1116 size_t num = chan->num;
1117
1118 delete chan;
1119
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001120 trx->setPriority(0.40);
1121
dburgessb3a0ca42011-10-12 07:44:40 +00001122 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001123 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001124 pthread_testcancel();
1125 }
1126 return NULL;
1127}