blob: f156ad40561640fb66d2c0aef018c88e9b28ab1e [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
Tom Tsou4609f322016-07-19 11:28:51 -0700697 timingOffset = toa;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400698
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 Tsou365bc382016-10-19 15:26:04 -0700747 if (!start()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000748 sprintf(response,"RSP POWERON 1");
Tom Tsou365bc382016-10-19 15:26:04 -0700749 } 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 }
Tom Tsou365bc382016-10-19 15:26:04 -0700755 }
Alexander Chemeris5a068062015-06-20 01:38:47 +0300756 }
757 else if (strcmp(command,"HANDOVER")==0){
758 int ts=0,ss=0;
759 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
760 mHandover[ts][ss] = true;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300761 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
762 }
763 else if (strcmp(command,"NOHANDOVER")==0){
764 int ts=0,ss=0;
765 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
766 mHandover[ts][ss] = false;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300767 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000768 }
769 else if (strcmp(command,"SETMAXDLY")==0) {
770 //set expected maximum time-of-arrival
771 int maxDelay;
772 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300773 mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
dburgessb3a0ca42011-10-12 07:44:40 +0000774 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
775 }
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300776 else if (strcmp(command,"SETMAXDLYNB")==0) {
777 //set expected maximum time-of-arrival
778 int maxDelay;
779 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
780 mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
781 sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
782 }
dburgessb3a0ca42011-10-12 07:44:40 +0000783 else if (strcmp(command,"SETRXGAIN")==0) {
784 //set expected maximum time-of-arrival
785 int newGain;
786 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400787 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000788 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
789 }
790 else if (strcmp(command,"NOISELEV")==0) {
791 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500792 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000793 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500794 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000795 }
796 else {
797 sprintf(response,"RSP NOISELEV 1 0");
798 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500799 }
800 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800801 int power;
802 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
803 power = mRadioInterface->setPowerAttenuation(power, chan);
804 mStates[chan].mPower = power;
805 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000806 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500807 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800808 int power, step;
809 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
810 power = mStates[chan].mPower + step;
811 power = mRadioInterface->setPowerAttenuation(power, chan);
812 mStates[chan].mPower = power;
813 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000814 }
dburgessb3a0ca42011-10-12 07:44:40 +0000815 else if (strcmp(command,"RXTUNE")==0) {
816 // tune receiver
817 int freqKhz;
818 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500819 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400820 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000821 LOG(ALERT) << "RX failed to tune";
822 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
823 }
824 else
825 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
826 }
827 else if (strcmp(command,"TXTUNE")==0) {
828 // tune txmtr
829 int freqKhz;
830 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500831 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400832 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000833 LOG(ALERT) << "TX failed to tune";
834 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
835 }
836 else
837 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
838 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500839 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000840 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500841 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500842 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Tom Tsouc8c4eac2016-06-28 17:00:54 -0700843 if ((TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500844 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000845 else {
Tom Tsouc37594f2016-07-08 14:39:42 -0700846 LOG(NOTICE) << "Changing TSC from " << mTSC << " to " << TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000847 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400848 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000849 }
850 }
851 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700852 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000853 int corrCode;
854 int timeslot;
855 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
856 if ((timeslot < 0) || (timeslot > 7)) {
857 LOG(WARNING) << "bogus message on control interface";
858 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
859 return;
860 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400861 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
862 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000863 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
864
865 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400866 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
867 // debug command! may change or disapear without notice
868 // set a mask which bursts to dump to disk
869 int mask;
870 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
871 mWriteBurstToDiskMask = mask;
872 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
873 }
dburgessb3a0ca42011-10-12 07:44:40 +0000874 else {
875 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200876 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000877 }
878
Thomas Tsou204a9f12013-10-29 18:34:16 -0400879 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000880}
881
Thomas Tsou204a9f12013-10-29 18:34:16 -0400882bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000883{
Tom Tsoue8871082016-07-01 02:46:04 -0700884 int burstLen;
885 char buffer[EDGE_BURST_NBITS + 50];
dburgessb3a0ca42011-10-12 07:44:40 +0000886
887 // check data socket
Tom Tsou2c650a62016-04-28 21:55:17 -0700888 size_t msgLen = mDataSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000889
Tom Tsoue8871082016-07-01 02:46:04 -0700890 if (msgLen == gSlotLen + 1 + 4 + 1) {
891 burstLen = gSlotLen;
892 } else if (msgLen == EDGE_BURST_NBITS + 1 + 4 + 1) {
893 if (mSPSTx != 4)
894 return false;
895
896 burstLen = EDGE_BURST_NBITS;
897 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000898 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
899 return false;
900 }
901
902 int timeSlot = (int) buffer[0];
903 uint64_t frameNum = 0;
904 for (int i = 0; i < 4; i++)
905 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000906
dburgessb3a0ca42011-10-12 07:44:40 +0000907 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
908
909 int RSSI = (int) buffer[5];
Tom Tsou7c741ec2016-07-19 11:20:59 -0700910 BitVector newBurst(burstLen);
dburgessb3a0ca42011-10-12 07:44:40 +0000911 BitVector::iterator itr = newBurst.begin();
912 char *bufferItr = buffer+6;
913 while (itr < newBurst.end())
914 *itr++ = *bufferItr++;
915
916 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400917
918 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000919
920 return true;
921
922
923}
dburgessb3a0ca42011-10-12 07:44:40 +0000924
Thomas Tsou204a9f12013-10-29 18:34:16 -0400925void Transceiver::driveReceiveRadio()
926{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400927 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400928 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400929 } else {
930 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
931 writeClockInterface();
932 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400933}
934
Alexander Chemeris58e95912016-03-25 18:20:28 +0300935void Transceiver::logRxBurst(size_t chan, SoftVector *burst, GSM::Time time, double dbm,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800936 double rssi, double noise, double toa)
937{
938 LOG(DEBUG) << std::fixed << std::right
Alexander Chemeris58e95912016-03-25 18:20:28 +0300939 << " chan: " << chan
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800940 << " time: " << time
941 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
942 << "dBFS/" << std::setw(6) << -dbm << "dBm"
943 << " noise: " << std::setw(5) << std::setprecision(1) << noise
944 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
945 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
946 << " bits: " << *burst;
947}
948
Thomas Tsou204a9f12013-10-29 18:34:16 -0400949void Transceiver::driveReceiveFIFO(size_t chan)
950{
dburgessb3a0ca42011-10-12 07:44:40 +0000951 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400952 double RSSI; // in dBFS
953 double dBm; // in dBm
954 double TOA; // in symbols
955 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400956 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000957 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400958 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800959 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000960
Alexander Chemeris2b542102015-06-08 22:46:38 -0400961 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800962 if (!rxBurst)
963 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000964
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800965 /*
966 * EDGE demodulator returns 444 (148 * 3) bits
967 */
968 if (rxBurst->size() == gSlotLen * 3)
969 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000970
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800971 dBm = RSSI + rssiOffset;
Alexander Chemeris58e95912016-03-25 18:20:28 +0300972 logRxBurst(chan, rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400973
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800974 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000975
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800976 char burstString[nbits + 10];
977 burstString[0] = burstTime.TN();
978 for (int i = 0; i < 4; i++)
979 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
980 burstString[5] = (int)dBm;
981 burstString[6] = (TOAint >> 8) & 0x0ff;
982 burstString[7] = TOAint & 0x0ff;
983 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000984
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800985 for (unsigned i = 0; i < nbits; i++)
986 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
987
988 burstString[nbits + 9] = '\0';
989 delete rxBurst;
990
991 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000992}
993
Thomas Tsou204a9f12013-10-29 18:34:16 -0400994void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000995{
996
997 /**
998 Features a carefully controlled latency mechanism, to
999 assure that transmit packets arrive at the radio/USRP
1000 before they need to be transmitted.
1001
1002 Deadline clock indicates the burst that needs to be
1003 pushed into the FIFO right NOW. If transmit queue does
1004 not have a burst, stick in filler data.
1005 */
1006
1007
1008 RadioClock *radioClock = (mRadioInterface->getClock());
1009
1010 if (mOn) {
1011 //radioClock->wait(); // wait until clock updates
1012 LOG(DEBUG) << "radio clock " << radioClock->get();
1013 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
1014 // if underrun, then we're not providing bursts to radio/USRP fast
1015 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -04001016 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001017 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +00001018 // only update latency at the defined frame interval
1019 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001020 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
1021 LOG(INFO) << "new latency: " << mTransmitLatency;
1022 mLatencyUpdateTime = radioClock->get();
1023 }
1024 }
1025 else {
1026 // if underrun hasn't occurred in the last sec (216 frames) drop
1027 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +00001028 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001029 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1030 mTransmitLatency.decTN();
1031 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1032 mLatencyUpdateTime = radioClock->get();
1033 }
1034 }
1035 }
dburgessb3a0ca42011-10-12 07:44:40 +00001036 }
dburgessb3a0ca42011-10-12 07:44:40 +00001037 // time to push burst to transmit FIFO
1038 pushRadioVector(mTransmitDeadlineClock);
1039 mTransmitDeadlineClock.incTN();
1040 }
dburgessb3a0ca42011-10-12 07:44:40 +00001041 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001042
1043 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001044}
1045
1046
1047
1048void Transceiver::writeClockInterface()
1049{
1050 char command[50];
1051 // FIXME -- This should be adaptive.
1052 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1053
1054 LOG(INFO) << "ClockInterface: sending " << command;
1055
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001056 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001057
1058 mLastClockUpdateTime = mTransmitDeadlineClock;
1059
Thomas Tsou92c16df2013-09-28 18:04:19 -04001060}
dburgessb3a0ca42011-10-12 07:44:40 +00001061
Thomas Tsou204a9f12013-10-29 18:34:16 -04001062void *RxUpperLoopAdapter(TransceiverChannel *chan)
1063{
1064 Transceiver *trx = chan->trx;
1065 size_t num = chan->num;
1066
1067 delete chan;
1068
Thomas Tsou7553aa92013-11-08 12:50:03 -05001069 trx->setPriority(0.42);
1070
Thomas Tsou204a9f12013-10-29 18:34:16 -04001071 while (1) {
1072 trx->driveReceiveFIFO(num);
1073 pthread_testcancel();
1074 }
1075 return NULL;
1076}
1077
1078void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001079{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001080 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001081
dburgessb3a0ca42011-10-12 07:44:40 +00001082 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001083 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001084 pthread_testcancel();
1085 }
1086 return NULL;
1087}
1088
Thomas Tsou204a9f12013-10-29 18:34:16 -04001089void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001090{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001091 transceiver->setPriority(0.44);
1092
Thomas Tsou92c16df2013-09-28 18:04:19 -04001093 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001094 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001095 pthread_testcancel();
1096 }
1097 return NULL;
1098}
1099
Thomas Tsou204a9f12013-10-29 18:34:16 -04001100void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001101{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001102 Transceiver *trx = chan->trx;
1103 size_t num = chan->num;
1104
1105 delete chan;
1106
dburgessb3a0ca42011-10-12 07:44:40 +00001107 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001108 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001109 pthread_testcancel();
1110 }
1111 return NULL;
1112}
1113
Thomas Tsou204a9f12013-10-29 18:34:16 -04001114void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001115{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001116 Transceiver *trx = chan->trx;
1117 size_t num = chan->num;
1118
1119 delete chan;
1120
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001121 trx->setPriority(0.40);
1122
dburgessb3a0ca42011-10-12 07:44:40 +00001123 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001124 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001125 pthread_testcancel();
1126 }
1127 return NULL;
1128}