blob: aafeaba554eae9bf7c2d53dbd177a233e2fbdf54 [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 Tsou5cd70dc2016-03-06 01:28:40 -0800133 mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), 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 */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300172bool Transceiver::init(int filler, size_t rtsc, unsigned rach_delay)
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
Thomas Tsou204a9f12013-10-29 18:34:16 -0400186 mDataSockets.resize(mChans);
187 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400188 mControlServiceLoopThreads.resize(mChans);
189 mTxPriorityQueueServiceLoopThreads.resize(mChans);
190 mRxServiceLoopThreads.resize(mChans);
191
192 mTxPriorityQueues.resize(mChans);
193 mReceiveFIFO.resize(mChans);
194 mStates.resize(mChans);
195
Thomas Tsouccb73e12014-04-15 17:41:28 -0400196 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700197 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400198 mStates[0].mRetrans = true;
199
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800200 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400201 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500202 c_srcport = mBasePort + 2 * i + 1;
203 c_dstport = mBasePort + 2 * i + 101;
204 d_srcport = mBasePort + 2 * i + 2;
205 d_dstport = mBasePort + 2 * i + 102;
206
207 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
208 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400209 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400210
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800211 /* Randomize the central clock */
212 GSM::Time startTime(random() % gHyperframe, 0);
213 mRadioInterface->getClock()->set(startTime);
214 mTransmitDeadlineClock = startTime;
215 mLastClockUpdateTime = startTime;
216 mLatencyUpdateTime = startTime;
217
218 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400219 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800220 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400221 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800222 mControlServiceLoopThreads[i]->start((void * (*)(void*))
223 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400224
Tom Tsou64ad7122015-05-19 18:26:31 -0700225 if (i && filler == FILLER_DUMMY)
226 filler = FILLER_ZERO;
227
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300228 mStates[i].init(filler, mSPSTx, txFullScale, rtsc, rach_delay);
Thomas Tsou83e06892013-08-20 16:10:01 -0400229 }
230
231 return true;
232}
dburgessb3a0ca42011-10-12 07:44:40 +0000233
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800234/*
235 * Start the transceiver
236 *
237 * Submit command(s) to the radio device to commence streaming samples and
238 * launch threads to handle sample I/O. Re-synchronize the transmit burst
239 * counters to the central radio clock here as well.
240 */
241bool Transceiver::start()
242{
243 ScopedLock lock(mLock);
244
245 if (mOn) {
246 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300247 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800248 }
249
250 LOG(NOTICE) << "Starting the transceiver";
251
252 GSM::Time time = mRadioInterface->getClock()->get();
253 mTransmitDeadlineClock = time;
254 mLastClockUpdateTime = time;
255 mLatencyUpdateTime = time;
256
257 if (!mRadioInterface->start()) {
258 LOG(ALERT) << "Device failed to start";
259 return false;
260 }
261
262 /* Device is running - launch I/O threads */
263 mRxLowerLoopThread = new Thread(32768);
264 mTxLowerLoopThread = new Thread(32768);
265 mTxLowerLoopThread->start((void * (*)(void*))
266 TxLowerLoopAdapter,(void*) this);
267 mRxLowerLoopThread->start((void * (*)(void*))
268 RxLowerLoopAdapter,(void*) this);
269
270 /* Launch uplink and downlink burst processing threads */
271 for (size_t i = 0; i < mChans; i++) {
272 TransceiverChannel *chan = new TransceiverChannel(this, i);
273 mRxServiceLoopThreads[i] = new Thread(32768);
274 mRxServiceLoopThreads[i]->start((void * (*)(void*))
275 RxUpperLoopAdapter, (void*) chan);
276
277 chan = new TransceiverChannel(this, i);
278 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
279 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
280 TxUpperLoopAdapter, (void*) chan);
281 }
282
283 writeClockInterface();
284 mOn = true;
285 return true;
286}
287
288/*
289 * Stop the transceiver
290 *
291 * Perform stopping by disabling receive streaming and issuing cancellation
292 * requests to running threads. Most threads will timeout and terminate once
293 * device is disabled, but the transmit loop may block waiting on the central
294 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
295 * makes it to the thread cancellation point.
296 */
297void Transceiver::stop()
298{
299 ScopedLock lock(mLock);
300
301 if (!mOn)
302 return;
303
304 LOG(NOTICE) << "Stopping the transceiver";
305 mTxLowerLoopThread->cancel();
306 mRxLowerLoopThread->cancel();
307
308 for (size_t i = 0; i < mChans; i++) {
309 mRxServiceLoopThreads[i]->cancel();
310 mTxPriorityQueueServiceLoopThreads[i]->cancel();
311 }
312
313 LOG(INFO) << "Stopping the device";
314 mRadioInterface->stop();
315
316 for (size_t i = 0; i < mChans; i++) {
317 mRxServiceLoopThreads[i]->join();
318 mTxPriorityQueueServiceLoopThreads[i]->join();
319 delete mRxServiceLoopThreads[i];
320 delete mTxPriorityQueueServiceLoopThreads[i];
321
322 mTxPriorityQueues[i].clear();
323 }
324
325 mTxLowerLoopThread->join();
326 mRxLowerLoopThread->join();
327 delete mTxLowerLoopThread;
328 delete mRxLowerLoopThread;
329
330 mOn = false;
331 LOG(NOTICE) << "Transceiver stopped";
332}
333
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500334void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400335 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000336{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500337 signalVector *burst;
338 radioVector *radio_burst;
339
Thomas Tsou204a9f12013-10-29 18:34:16 -0400340 if (chan >= mTxPriorityQueues.size()) {
341 LOG(ALERT) << "Invalid channel " << chan;
342 return;
343 }
344
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500345 if (wTime.TN() > 7) {
346 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
347 return;
348 }
349
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800350 /* Use the number of bits as the EDGE burst indicator */
351 if (bits.size() == EDGE_BURST_NBITS)
352 burst = modulateEdgeBurst(bits, mSPSTx);
353 else
354 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
355
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500356 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000357
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500358 radio_burst = new radioVector(wTime, burst);
359
360 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000361}
362
Thomas Tsou15d743e2014-01-25 02:34:03 -0500363void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
364{
365 int TN, modFN;
366 TransceiverState *state = &mStates[chan];
367
368 TN = burst->getTime().TN();
369 modFN = burst->getTime().FN() % state->fillerModulus[TN];
370
371 delete state->fillerTable[modFN][TN];
372 state->fillerTable[modFN][TN] = burst->getVector();
373 burst->setVector(NULL);
374}
375
dburgessb3a0ca42011-10-12 07:44:40 +0000376void Transceiver::pushRadioVector(GSM::Time &nowTime)
377{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400378 int TN, modFN;
379 radioVector *burst;
380 TransceiverState *state;
381 std::vector<signalVector *> bursts(mChans);
382 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500383 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000384
Thomas Tsou204a9f12013-10-29 18:34:16 -0400385 for (size_t i = 0; i < mChans; i ++) {
386 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000387
Thomas Tsou204a9f12013-10-29 18:34:16 -0400388 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
389 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500390 if (state->mRetrans)
391 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500392 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400393 }
394
395 TN = nowTime.TN();
396 modFN = nowTime.FN() % state->fillerModulus[TN];
397
398 bursts[i] = state->fillerTable[modFN][TN];
399 zeros[i] = state->chanType[TN] == NONE;
400
401 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500402 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500403
404 if (state->mRetrans) {
405 updateFillerTable(i, burst);
406 } else {
407 burst->setVector(NULL);
408 filler[i] = false;
409 }
410
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500411 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400412 }
dburgessb3a0ca42011-10-12 07:44:40 +0000413 }
414
Thomas Tsou204a9f12013-10-29 18:34:16 -0400415 mRadioInterface->driveTransmitRadio(bursts, zeros);
416
Thomas Tsou15d743e2014-01-25 02:34:03 -0500417 for (size_t i = 0; i < mChans; i++) {
418 if (!filler[i])
419 delete bursts[i];
420 }
dburgessb3a0ca42011-10-12 07:44:40 +0000421}
422
Thomas Tsou204a9f12013-10-29 18:34:16 -0400423void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000424{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400425 TransceiverState *state = &mStates[chan];
426
427 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000428 case NONE:
429 case I:
430 case II:
431 case III:
432 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400433 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000434 break;
435 case IV:
436 case VI:
437 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400438 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000439 break;
440 //case V:
441 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400442 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000443 break;
ttsoufc40a842013-06-09 22:38:18 +0000444 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400445 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000446 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000447 default:
448 break;
449 }
450}
451
452
Thomas Tsou204a9f12013-10-29 18:34:16 -0400453Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
454 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000455{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300456 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 };
457 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,
458 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 };
459 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,
460 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 -0400461 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000462 unsigned burstTN = currTime.TN();
463 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300464 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000465
Thomas Tsou204a9f12013-10-29 18:34:16 -0400466 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000467 case NONE:
468 return OFF;
469 break;
470 case FILL:
471 return IDLE;
472 break;
473 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300474 // TODO: Are we expecting RACH on an IDLE frame?
475/* if (burstFN % 26 == 25)
476 return IDLE;*/
477 if (mHandover[burstTN][0])
478 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000479 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000480 break;
481 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300482 subch = tchh_subslot[burstFN % 26];
483 if (subch == 1)
484 return IDLE;
485 if (mHandover[burstTN][0])
486 return RACH;
ttsou20642972013-03-27 22:00:25 +0000487 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000488 break;
489 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300490 subch = tchh_subslot[burstFN % 26];
491 if (mHandover[burstTN][subch])
492 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000493 return TSC;
494 break;
495 case IV:
496 case VI:
497 return RACH;
498 break;
499 case V: {
500 int mod51 = burstFN % 51;
501 if ((mod51 <= 36) && (mod51 >= 14))
502 return RACH;
503 else if ((mod51 == 4) || (mod51 == 5))
504 return RACH;
505 else if ((mod51 == 45) || (mod51 == 46))
506 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300507 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
508 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000509 else
510 return TSC;
511 break;
512 }
513 case VII:
514 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
515 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300516 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
517 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000518 else
519 return TSC;
520 break;
ttsoufc40a842013-06-09 22:38:18 +0000521 case XIII: {
522 int mod52 = burstFN % 52;
523 if ((mod52 == 12) || (mod52 == 38))
524 return RACH;
525 else if ((mod52 == 25) || (mod52 == 51))
526 return IDLE;
527 else
528 return TSC;
529 break;
530 }
dburgessb3a0ca42011-10-12 07:44:40 +0000531 case LOOPBACK:
532 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
533 return IDLE;
534 else
535 return TSC;
536 break;
537 default:
538 return OFF;
539 break;
540 }
dburgessb3a0ca42011-10-12 07:44:40 +0000541}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400542
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300543int Transceiver::detectBurst(signalVector &burst,
544 complex &amp, float &toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500545{
Tom Tsoua84e1622016-06-29 14:50:25 -0700546 int rc = 0;
Thomas Tsou30421a72013-11-13 23:14:48 -0500547
Tom Tsou46569402016-03-06 01:59:38 -0800548 switch (type) {
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800549 case EDGE:
Tom Tsoua84e1622016-06-29 14:50:25 -0700550 rc = detectEdgeBurst(burst, mTSC, BURST_THRESH, mSPSRx,
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300551 amp, toa, mMaxExpectedDelayNB);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800552 if (rc > 0)
553 break;
554 else
555 type = TSC;
Tom Tsou46569402016-03-06 01:59:38 -0800556 case TSC:
Tom Tsoua84e1622016-06-29 14:50:25 -0700557 rc = analyzeTrafficBurst(burst, mTSC, BURST_THRESH, mSPSRx,
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300558 amp, toa, mMaxExpectedDelayNB);
Tom Tsou46569402016-03-06 01:59:38 -0800559 break;
560 case RACH:
Tom Tsoua84e1622016-06-29 14:50:25 -0700561 rc = detectRACHBurst(burst, BURST_THRESH, mSPSRx, amp, toa,
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300562 mMaxExpectedDelayAB);
Tom Tsou46569402016-03-06 01:59:38 -0800563 break;
564 default:
565 LOG(ERR) << "Invalid correlation type";
566 }
567
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800568 if (rc > 0)
569 return type;
Tom Tsou46569402016-03-06 01:59:38 -0800570
571 return rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500572}
573
Thomas Tsou30421a72013-11-13 23:14:48 -0500574
575/*
Tom Tsou46569402016-03-06 01:59:38 -0800576 * Demodulate GMSK by direct rotation and soft slicing.
Thomas Tsou30421a72013-11-13 23:14:48 -0500577 */
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300578SoftVector *Transceiver::demodulate(signalVector &burst, complex amp,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800579 float toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500580{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800581 if (type == EDGE)
582 return demodEdgeBurst(burst, mSPSRx, amp, toa);
583
Thomas Tsou30421a72013-11-13 23:14:48 -0500584 return demodulateBurst(burst, mSPSRx, amp, toa);
585}
586
Alexander Chemerise692ce92015-06-12 00:15:31 -0400587void writeToFile(radioVector *radio_burst, size_t chan)
588{
589 GSM::Time time = radio_burst->getTime();
590 std::ostringstream fname;
591 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
592 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
593 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
594 outfile.close();
595}
596
Thomas Tsou30421a72013-11-13 23:14:48 -0500597/*
598 * Pull bursts from the FIFO and handle according to the slot
599 * and burst correlation type. Equalzation is currently disabled.
600 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400601SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400602 double &timingOffset, double &noise,
603 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000604{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800605 int rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500606 complex amp;
607 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500608 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500609 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500610 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500611 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400612 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000613
Thomas Tsou30421a72013-11-13 23:14:48 -0500614 /* Blocking FIFO read */
615 radioVector *radio_burst = mReceiveFIFO[chan]->read();
616 if (!radio_burst)
617 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000618
Thomas Tsou30421a72013-11-13 23:14:48 -0500619 /* Set time and determine correlation type */
620 GSM::Time time = radio_burst->getTime();
621 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000622
Alexander Chemerise692ce92015-06-12 00:15:31 -0400623 /* Debug: dump bursts to disk */
624 /* bits 0-7 - chan 0 timeslots
625 * bits 8-15 - chan 1 timeslots */
626 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
627 writeToFile(radio_burst, chan);
628
Alexander Chemeris2b542102015-06-08 22:46:38 -0400629 /* No processing if the timeslot is off.
630 * Not even power level or noise calculation. */
631 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500632 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000633 return NULL;
634 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000635
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500636 /* Select the diversity channel with highest energy */
637 for (size_t i = 0; i < radio_burst->chans(); i++) {
638 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
639 if (pow > max) {
640 max = pow;
641 max_i = i;
642 }
643 avg += pow;
644 }
645
646 if (max_i < 0) {
647 LOG(ALERT) << "Received empty burst";
648 delete radio_burst;
649 return NULL;
650 }
651
Thomas Tsou30421a72013-11-13 23:14:48 -0500652 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500653 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500654 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400655
656 wTime = time;
657 RSSI = 20.0 * log10(rxFullScale / avg);
658
659 /* RSSI estimation are valid */
660 isRssiValid = true;
661
662 if (type == IDLE) {
663 /* Update noise levels */
664 state->mNoises.insert(avg);
665 state->mNoiseLev = state->mNoises.avg();
666 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
667
668 delete radio_burst;
669 return NULL;
670 } else {
671 /* Do not update noise levels */
672 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
673 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400674
Thomas Tsou30421a72013-11-13 23:14:48 -0500675 /* Detect normal or RACH bursts */
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300676 rc = detectBurst(*burst, amp, toa, type);
Thomas Tsouf0782732013-10-29 15:55:47 -0400677
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800678 if (rc > 0) {
679 type = (CorrType) rc;
680 } else if (rc <= 0) {
681 if (rc == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400682 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800683 } else if (rc != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400684 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700685 }
686
Thomas Tsou30421a72013-11-13 23:14:48 -0500687 delete radio_burst;
688 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000689 }
dburgessb3a0ca42011-10-12 07:44:40 +0000690
Alexander Chemeris2b542102015-06-08 22:46:38 -0400691 timingOffset = toa / mSPSRx;
692
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300693 bits = demodulate(*burst, amp, toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500694
Thomas Tsou30421a72013-11-13 23:14:48 -0500695 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500696 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000697}
698
dburgessb3a0ca42011-10-12 07:44:40 +0000699void Transceiver::reset()
700{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400701 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
702 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000703}
704
705
Thomas Tsou204a9f12013-10-29 18:34:16 -0400706void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000707{
dburgessb3a0ca42011-10-12 07:44:40 +0000708 int MAX_PACKET_LENGTH = 100;
709
710 // check control socket
711 char buffer[MAX_PACKET_LENGTH];
712 int msgLen = -1;
713 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400714
Tom Tsou2c650a62016-04-28 21:55:17 -0700715 msgLen = mCtrlSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000716
717 if (msgLen < 1) {
718 return;
719 }
720
721 char cmdcheck[4];
722 char command[MAX_PACKET_LENGTH];
723 char response[MAX_PACKET_LENGTH];
724
725 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400726
727 if (!chan)
728 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000729
730 if (strcmp(cmdcheck,"CMD")!=0) {
731 LOG(WARNING) << "bogus message on control interface";
732 return;
733 }
734 LOG(INFO) << "command is " << buffer;
735
736 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800737 stop();
738 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000739 }
740 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800741 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000742 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800743 else
dburgessb3a0ca42011-10-12 07:44:40 +0000744 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300745 for (int i = 0; i < 8; i++) {
746 for (int j = 0; j < 8; j++)
747 mHandover[i][j] = false;
748 }
749 }
750 else if (strcmp(command,"HANDOVER")==0){
751 int ts=0,ss=0;
752 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
753 mHandover[ts][ss] = true;
754 LOG(WARNING) << "HANDOVER RACH at timeslot " << ts << " subslot " << ss;
755 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
756 }
757 else if (strcmp(command,"NOHANDOVER")==0){
758 int ts=0,ss=0;
759 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
760 mHandover[ts][ss] = false;
761 LOG(WARNING) << "NOHANDOVER at timeslot " << ts << " subslot " << ss;
762 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000763 }
764 else if (strcmp(command,"SETMAXDLY")==0) {
765 //set expected maximum time-of-arrival
766 int maxDelay;
767 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300768 mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
dburgessb3a0ca42011-10-12 07:44:40 +0000769 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
770 }
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300771 else if (strcmp(command,"SETMAXDLYNB")==0) {
772 //set expected maximum time-of-arrival
773 int maxDelay;
774 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
775 mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
776 sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
777 }
dburgessb3a0ca42011-10-12 07:44:40 +0000778 else if (strcmp(command,"SETRXGAIN")==0) {
779 //set expected maximum time-of-arrival
780 int newGain;
781 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400782 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000783 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
784 }
785 else if (strcmp(command,"NOISELEV")==0) {
786 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500787 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000788 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500789 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000790 }
791 else {
792 sprintf(response,"RSP NOISELEV 1 0");
793 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500794 }
795 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800796 int power;
797 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
798 power = mRadioInterface->setPowerAttenuation(power, chan);
799 mStates[chan].mPower = power;
800 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000801 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500802 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800803 int power, step;
804 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
805 power = mStates[chan].mPower + step;
806 power = mRadioInterface->setPowerAttenuation(power, chan);
807 mStates[chan].mPower = power;
808 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000809 }
dburgessb3a0ca42011-10-12 07:44:40 +0000810 else if (strcmp(command,"RXTUNE")==0) {
811 // tune receiver
812 int freqKhz;
813 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500814 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400815 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000816 LOG(ALERT) << "RX failed to tune";
817 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
818 }
819 else
820 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
821 }
822 else if (strcmp(command,"TXTUNE")==0) {
823 // tune txmtr
824 int freqKhz;
825 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500826 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400827 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000828 LOG(ALERT) << "TX failed to tune";
829 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
830 }
831 else
832 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
833 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500834 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000835 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500836 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500837 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Tom Tsouc8c4eac2016-06-28 17:00:54 -0700838 if ((TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500839 sprintf(response, "RSP SETTSC 1 %d", TSC);
840 else if (chan && (TSC != mTSC))
841 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000842 else {
843 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400844 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000845 }
846 }
847 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700848 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000849 int corrCode;
850 int timeslot;
851 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
852 if ((timeslot < 0) || (timeslot > 7)) {
853 LOG(WARNING) << "bogus message on control interface";
854 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
855 return;
856 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400857 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
858 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000859 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
860
861 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400862 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
863 // debug command! may change or disapear without notice
864 // set a mask which bursts to dump to disk
865 int mask;
866 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
867 mWriteBurstToDiskMask = mask;
868 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
869 }
dburgessb3a0ca42011-10-12 07:44:40 +0000870 else {
871 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200872 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000873 }
874
Thomas Tsou204a9f12013-10-29 18:34:16 -0400875 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000876}
877
Thomas Tsou204a9f12013-10-29 18:34:16 -0400878bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000879{
Tom Tsoue8871082016-07-01 02:46:04 -0700880 int burstLen;
881 char buffer[EDGE_BURST_NBITS + 50];
dburgessb3a0ca42011-10-12 07:44:40 +0000882
883 // check data socket
Tom Tsou2c650a62016-04-28 21:55:17 -0700884 size_t msgLen = mDataSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000885
Tom Tsoue8871082016-07-01 02:46:04 -0700886 if (msgLen == gSlotLen + 1 + 4 + 1) {
887 burstLen = gSlotLen;
888 } else if (msgLen == EDGE_BURST_NBITS + 1 + 4 + 1) {
889 if (mSPSTx != 4)
890 return false;
891
892 burstLen = EDGE_BURST_NBITS;
893 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000894 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
895 return false;
896 }
897
898 int timeSlot = (int) buffer[0];
899 uint64_t frameNum = 0;
900 for (int i = 0; i < 4; i++)
901 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000902
dburgessb3a0ca42011-10-12 07:44:40 +0000903 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
904
905 int RSSI = (int) buffer[5];
Tom Tsoue8871082016-07-01 02:46:04 -0700906 static BitVector newBurst(burstLen);
dburgessb3a0ca42011-10-12 07:44:40 +0000907 BitVector::iterator itr = newBurst.begin();
908 char *bufferItr = buffer+6;
909 while (itr < newBurst.end())
910 *itr++ = *bufferItr++;
911
912 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400913
914 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000915
916 return true;
917
918
919}
dburgessb3a0ca42011-10-12 07:44:40 +0000920
Thomas Tsou204a9f12013-10-29 18:34:16 -0400921void Transceiver::driveReceiveRadio()
922{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400923 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400924 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400925 } else {
926 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
927 writeClockInterface();
928 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400929}
930
Alexander Chemeris58e95912016-03-25 18:20:28 +0300931void Transceiver::logRxBurst(size_t chan, SoftVector *burst, GSM::Time time, double dbm,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800932 double rssi, double noise, double toa)
933{
934 LOG(DEBUG) << std::fixed << std::right
Alexander Chemeris58e95912016-03-25 18:20:28 +0300935 << " chan: " << chan
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800936 << " time: " << time
937 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
938 << "dBFS/" << std::setw(6) << -dbm << "dBm"
939 << " noise: " << std::setw(5) << std::setprecision(1) << noise
940 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
941 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
942 << " bits: " << *burst;
943}
944
Thomas Tsou204a9f12013-10-29 18:34:16 -0400945void Transceiver::driveReceiveFIFO(size_t chan)
946{
dburgessb3a0ca42011-10-12 07:44:40 +0000947 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400948 double RSSI; // in dBFS
949 double dBm; // in dBm
950 double TOA; // in symbols
951 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400952 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000953 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400954 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800955 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000956
Alexander Chemeris2b542102015-06-08 22:46:38 -0400957 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800958 if (!rxBurst)
959 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000960
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800961 /*
962 * EDGE demodulator returns 444 (148 * 3) bits
963 */
964 if (rxBurst->size() == gSlotLen * 3)
965 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000966
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800967 dBm = RSSI + rssiOffset;
Alexander Chemeris58e95912016-03-25 18:20:28 +0300968 logRxBurst(chan, rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400969
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800970 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000971
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800972 char burstString[nbits + 10];
973 burstString[0] = burstTime.TN();
974 for (int i = 0; i < 4; i++)
975 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
976 burstString[5] = (int)dBm;
977 burstString[6] = (TOAint >> 8) & 0x0ff;
978 burstString[7] = TOAint & 0x0ff;
979 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000980
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800981 for (unsigned i = 0; i < nbits; i++)
982 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
983
984 burstString[nbits + 9] = '\0';
985 delete rxBurst;
986
987 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000988}
989
Thomas Tsou204a9f12013-10-29 18:34:16 -0400990void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000991{
992
993 /**
994 Features a carefully controlled latency mechanism, to
995 assure that transmit packets arrive at the radio/USRP
996 before they need to be transmitted.
997
998 Deadline clock indicates the burst that needs to be
999 pushed into the FIFO right NOW. If transmit queue does
1000 not have a burst, stick in filler data.
1001 */
1002
1003
1004 RadioClock *radioClock = (mRadioInterface->getClock());
1005
1006 if (mOn) {
1007 //radioClock->wait(); // wait until clock updates
1008 LOG(DEBUG) << "radio clock " << radioClock->get();
1009 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
1010 // if underrun, then we're not providing bursts to radio/USRP fast
1011 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -04001012 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001013 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +00001014 // only update latency at the defined frame interval
1015 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001016 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
1017 LOG(INFO) << "new latency: " << mTransmitLatency;
1018 mLatencyUpdateTime = radioClock->get();
1019 }
1020 }
1021 else {
1022 // if underrun hasn't occurred in the last sec (216 frames) drop
1023 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +00001024 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001025 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1026 mTransmitLatency.decTN();
1027 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1028 mLatencyUpdateTime = radioClock->get();
1029 }
1030 }
1031 }
dburgessb3a0ca42011-10-12 07:44:40 +00001032 }
dburgessb3a0ca42011-10-12 07:44:40 +00001033 // time to push burst to transmit FIFO
1034 pushRadioVector(mTransmitDeadlineClock);
1035 mTransmitDeadlineClock.incTN();
1036 }
dburgessb3a0ca42011-10-12 07:44:40 +00001037 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001038
1039 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001040}
1041
1042
1043
1044void Transceiver::writeClockInterface()
1045{
1046 char command[50];
1047 // FIXME -- This should be adaptive.
1048 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1049
1050 LOG(INFO) << "ClockInterface: sending " << command;
1051
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001052 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001053
1054 mLastClockUpdateTime = mTransmitDeadlineClock;
1055
Thomas Tsou92c16df2013-09-28 18:04:19 -04001056}
dburgessb3a0ca42011-10-12 07:44:40 +00001057
Thomas Tsou204a9f12013-10-29 18:34:16 -04001058void *RxUpperLoopAdapter(TransceiverChannel *chan)
1059{
1060 Transceiver *trx = chan->trx;
1061 size_t num = chan->num;
1062
1063 delete chan;
1064
Thomas Tsou7553aa92013-11-08 12:50:03 -05001065 trx->setPriority(0.42);
1066
Thomas Tsou204a9f12013-10-29 18:34:16 -04001067 while (1) {
1068 trx->driveReceiveFIFO(num);
1069 pthread_testcancel();
1070 }
1071 return NULL;
1072}
1073
1074void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001075{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001076 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001077
dburgessb3a0ca42011-10-12 07:44:40 +00001078 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001079 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001080 pthread_testcancel();
1081 }
1082 return NULL;
1083}
1084
Thomas Tsou204a9f12013-10-29 18:34:16 -04001085void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001086{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001087 transceiver->setPriority(0.44);
1088
Thomas Tsou92c16df2013-09-28 18:04:19 -04001089 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001090 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001091 pthread_testcancel();
1092 }
1093 return NULL;
1094}
1095
Thomas Tsou204a9f12013-10-29 18:34:16 -04001096void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001097{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001098 Transceiver *trx = chan->trx;
1099 size_t num = chan->num;
1100
1101 delete chan;
1102
dburgessb3a0ca42011-10-12 07:44:40 +00001103 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001104 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001105 pthread_testcancel();
1106 }
1107 return NULL;
1108}
1109
Thomas Tsou204a9f12013-10-29 18:34:16 -04001110void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001111{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001112 Transceiver *trx = chan->trx;
1113 size_t num = chan->num;
1114
1115 delete chan;
1116
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001117 trx->setPriority(0.40);
1118
dburgessb3a0ca42011-10-12 07:44:40 +00001119 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001120 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001121 pthread_testcancel();
1122 }
1123 return NULL;
1124}