blob: a1d0f49ac0abbce5e54f8470cd5b32740d213f96 [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;
760 LOG(WARNING) << "HANDOVER RACH at timeslot " << ts << " subslot " << ss;
761 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;
767 LOG(WARNING) << "NOHANDOVER at timeslot " << ts << " subslot " << ss;
768 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000769 }
770 else if (strcmp(command,"SETMAXDLY")==0) {
771 //set expected maximum time-of-arrival
772 int maxDelay;
773 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300774 mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
dburgessb3a0ca42011-10-12 07:44:40 +0000775 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
776 }
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300777 else if (strcmp(command,"SETMAXDLYNB")==0) {
778 //set expected maximum time-of-arrival
779 int maxDelay;
780 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
781 mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
782 sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
783 }
dburgessb3a0ca42011-10-12 07:44:40 +0000784 else if (strcmp(command,"SETRXGAIN")==0) {
785 //set expected maximum time-of-arrival
786 int newGain;
787 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400788 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000789 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
790 }
791 else if (strcmp(command,"NOISELEV")==0) {
792 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500793 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000794 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500795 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000796 }
797 else {
798 sprintf(response,"RSP NOISELEV 1 0");
799 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500800 }
801 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800802 int power;
803 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
804 power = mRadioInterface->setPowerAttenuation(power, chan);
805 mStates[chan].mPower = power;
806 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000807 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500808 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800809 int power, step;
810 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
811 power = mStates[chan].mPower + step;
812 power = mRadioInterface->setPowerAttenuation(power, chan);
813 mStates[chan].mPower = power;
814 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000815 }
dburgessb3a0ca42011-10-12 07:44:40 +0000816 else if (strcmp(command,"RXTUNE")==0) {
817 // tune receiver
818 int freqKhz;
819 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500820 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400821 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000822 LOG(ALERT) << "RX failed to tune";
823 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
824 }
825 else
826 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
827 }
828 else if (strcmp(command,"TXTUNE")==0) {
829 // tune txmtr
830 int freqKhz;
831 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500832 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400833 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000834 LOG(ALERT) << "TX failed to tune";
835 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
836 }
837 else
838 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
839 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500840 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000841 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500842 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500843 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Tom Tsouc8c4eac2016-06-28 17:00:54 -0700844 if ((TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500845 sprintf(response, "RSP SETTSC 1 %d", TSC);
846 else if (chan && (TSC != mTSC))
847 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000848 else {
849 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400850 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000851 }
852 }
853 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700854 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000855 int corrCode;
856 int timeslot;
857 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
858 if ((timeslot < 0) || (timeslot > 7)) {
859 LOG(WARNING) << "bogus message on control interface";
860 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
861 return;
862 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400863 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
864 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000865 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
866
867 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400868 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
869 // debug command! may change or disapear without notice
870 // set a mask which bursts to dump to disk
871 int mask;
872 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
873 mWriteBurstToDiskMask = mask;
874 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
875 }
dburgessb3a0ca42011-10-12 07:44:40 +0000876 else {
877 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200878 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000879 }
880
Thomas Tsou204a9f12013-10-29 18:34:16 -0400881 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000882}
883
Thomas Tsou204a9f12013-10-29 18:34:16 -0400884bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000885{
Tom Tsoue8871082016-07-01 02:46:04 -0700886 int burstLen;
887 char buffer[EDGE_BURST_NBITS + 50];
dburgessb3a0ca42011-10-12 07:44:40 +0000888
889 // check data socket
Tom Tsou2c650a62016-04-28 21:55:17 -0700890 size_t msgLen = mDataSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000891
Tom Tsoue8871082016-07-01 02:46:04 -0700892 if (msgLen == gSlotLen + 1 + 4 + 1) {
893 burstLen = gSlotLen;
894 } else if (msgLen == EDGE_BURST_NBITS + 1 + 4 + 1) {
895 if (mSPSTx != 4)
896 return false;
897
898 burstLen = EDGE_BURST_NBITS;
899 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000900 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
901 return false;
902 }
903
904 int timeSlot = (int) buffer[0];
905 uint64_t frameNum = 0;
906 for (int i = 0; i < 4; i++)
907 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000908
dburgessb3a0ca42011-10-12 07:44:40 +0000909 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
910
911 int RSSI = (int) buffer[5];
Tom Tsoue8871082016-07-01 02:46:04 -0700912 static BitVector newBurst(burstLen);
dburgessb3a0ca42011-10-12 07:44:40 +0000913 BitVector::iterator itr = newBurst.begin();
914 char *bufferItr = buffer+6;
915 while (itr < newBurst.end())
916 *itr++ = *bufferItr++;
917
918 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400919
920 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000921
922 return true;
923
924
925}
dburgessb3a0ca42011-10-12 07:44:40 +0000926
Thomas Tsou204a9f12013-10-29 18:34:16 -0400927void Transceiver::driveReceiveRadio()
928{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400929 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400930 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400931 } else {
932 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
933 writeClockInterface();
934 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400935}
936
Alexander Chemeris58e95912016-03-25 18:20:28 +0300937void Transceiver::logRxBurst(size_t chan, SoftVector *burst, GSM::Time time, double dbm,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800938 double rssi, double noise, double toa)
939{
940 LOG(DEBUG) << std::fixed << std::right
Alexander Chemeris58e95912016-03-25 18:20:28 +0300941 << " chan: " << chan
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800942 << " time: " << time
943 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
944 << "dBFS/" << std::setw(6) << -dbm << "dBm"
945 << " noise: " << std::setw(5) << std::setprecision(1) << noise
946 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
947 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
948 << " bits: " << *burst;
949}
950
Thomas Tsou204a9f12013-10-29 18:34:16 -0400951void Transceiver::driveReceiveFIFO(size_t chan)
952{
dburgessb3a0ca42011-10-12 07:44:40 +0000953 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400954 double RSSI; // in dBFS
955 double dBm; // in dBm
956 double TOA; // in symbols
957 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400958 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000959 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400960 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800961 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000962
Alexander Chemeris2b542102015-06-08 22:46:38 -0400963 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800964 if (!rxBurst)
965 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000966
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800967 /*
968 * EDGE demodulator returns 444 (148 * 3) bits
969 */
970 if (rxBurst->size() == gSlotLen * 3)
971 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000972
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800973 dBm = RSSI + rssiOffset;
Alexander Chemeris58e95912016-03-25 18:20:28 +0300974 logRxBurst(chan, rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400975
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800976 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000977
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800978 char burstString[nbits + 10];
979 burstString[0] = burstTime.TN();
980 for (int i = 0; i < 4; i++)
981 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
982 burstString[5] = (int)dBm;
983 burstString[6] = (TOAint >> 8) & 0x0ff;
984 burstString[7] = TOAint & 0x0ff;
985 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000986
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800987 for (unsigned i = 0; i < nbits; i++)
988 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
989
990 burstString[nbits + 9] = '\0';
991 delete rxBurst;
992
993 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000994}
995
Thomas Tsou204a9f12013-10-29 18:34:16 -0400996void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000997{
998
999 /**
1000 Features a carefully controlled latency mechanism, to
1001 assure that transmit packets arrive at the radio/USRP
1002 before they need to be transmitted.
1003
1004 Deadline clock indicates the burst that needs to be
1005 pushed into the FIFO right NOW. If transmit queue does
1006 not have a burst, stick in filler data.
1007 */
1008
1009
1010 RadioClock *radioClock = (mRadioInterface->getClock());
1011
1012 if (mOn) {
1013 //radioClock->wait(); // wait until clock updates
1014 LOG(DEBUG) << "radio clock " << radioClock->get();
1015 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
1016 // if underrun, then we're not providing bursts to radio/USRP fast
1017 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -04001018 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001019 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +00001020 // only update latency at the defined frame interval
1021 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001022 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
1023 LOG(INFO) << "new latency: " << mTransmitLatency;
1024 mLatencyUpdateTime = radioClock->get();
1025 }
1026 }
1027 else {
1028 // if underrun hasn't occurred in the last sec (216 frames) drop
1029 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +00001030 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001031 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1032 mTransmitLatency.decTN();
1033 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1034 mLatencyUpdateTime = radioClock->get();
1035 }
1036 }
1037 }
dburgessb3a0ca42011-10-12 07:44:40 +00001038 }
dburgessb3a0ca42011-10-12 07:44:40 +00001039 // time to push burst to transmit FIFO
1040 pushRadioVector(mTransmitDeadlineClock);
1041 mTransmitDeadlineClock.incTN();
1042 }
dburgessb3a0ca42011-10-12 07:44:40 +00001043 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001044
1045 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001046}
1047
1048
1049
1050void Transceiver::writeClockInterface()
1051{
1052 char command[50];
1053 // FIXME -- This should be adaptive.
1054 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1055
1056 LOG(INFO) << "ClockInterface: sending " << command;
1057
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001058 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001059
1060 mLastClockUpdateTime = mTransmitDeadlineClock;
1061
Thomas Tsou92c16df2013-09-28 18:04:19 -04001062}
dburgessb3a0ca42011-10-12 07:44:40 +00001063
Thomas Tsou204a9f12013-10-29 18:34:16 -04001064void *RxUpperLoopAdapter(TransceiverChannel *chan)
1065{
1066 Transceiver *trx = chan->trx;
1067 size_t num = chan->num;
1068
1069 delete chan;
1070
Thomas Tsou7553aa92013-11-08 12:50:03 -05001071 trx->setPriority(0.42);
1072
Thomas Tsou204a9f12013-10-29 18:34:16 -04001073 while (1) {
1074 trx->driveReceiveFIFO(num);
1075 pthread_testcancel();
1076 }
1077 return NULL;
1078}
1079
1080void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001081{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001082 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001083
dburgessb3a0ca42011-10-12 07:44:40 +00001084 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001085 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001086 pthread_testcancel();
1087 }
1088 return NULL;
1089}
1090
Thomas Tsou204a9f12013-10-29 18:34:16 -04001091void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001092{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001093 transceiver->setPriority(0.44);
1094
Thomas Tsou92c16df2013-09-28 18:04:19 -04001095 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001096 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001097 pthread_testcancel();
1098 }
1099 return NULL;
1100}
1101
Thomas Tsou204a9f12013-10-29 18:34:16 -04001102void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001103{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001104 Transceiver *trx = chan->trx;
1105 size_t num = chan->num;
1106
1107 delete chan;
1108
dburgessb3a0ca42011-10-12 07:44:40 +00001109 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001110 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001111 pthread_testcancel();
1112 }
1113 return NULL;
1114}
1115
Thomas Tsou204a9f12013-10-29 18:34:16 -04001116void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001117{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001118 Transceiver *trx = chan->trx;
1119 size_t num = chan->num;
1120
1121 delete chan;
1122
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001123 trx->setPriority(0.40);
1124
dburgessb3a0ca42011-10-12 07:44:40 +00001125 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001126 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001127 pthread_testcancel();
1128 }
1129 return NULL;
1130}