blob: a19d77082bacb00ade03cbe32da14f7e52ec2f5c [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
2* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
3*
4* This software is distributed under the terms of the GNU Public License.
5* See the COPYING file in the main directory for details.
6*
7* This use of this software may be subject to additional restrictions.
8* See the LEGAL file in the main directory for details.
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22*/
23
dburgessb3a0ca42011-10-12 07:44:40 +000024#include <stdio.h>
Alexander Chemerise8905a02015-06-03 23:47:56 -040025#include <iomanip> // std::setprecision
Alexander Chemerise692ce92015-06-12 00:15:31 -040026#include <fstream>
dburgessb3a0ca42011-10-12 07:44:40 +000027#include "Transceiver.h"
28#include <Logger.h>
29
ttsou2173abf2012-08-08 00:51:31 +000030#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
dburgessb3a0ca42011-10-12 07:44:40 +000033
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040034using namespace GSM;
35
kurtis.heimerlec842de2012-11-23 08:37:32 +000036#define USB_LATENCY_INTRVL 10,0
ttsou2173abf2012-08-08 00:51:31 +000037
38#if USE_UHD
kurtis.heimerlec842de2012-11-23 08:37:32 +000039# define USB_LATENCY_MIN 6,7
ttsou2173abf2012-08-08 00:51:31 +000040#else
kurtis.heimerlec842de2012-11-23 08:37:32 +000041# define USB_LATENCY_MIN 1,1
ttsou2173abf2012-08-08 00:51:31 +000042#endif
dburgessb3a0ca42011-10-12 07:44:40 +000043
Thomas Tsoufa3a7872013-10-17 21:23:34 -040044/* Number of running values use in noise average */
45#define NOISE_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000046
Thomas Tsouf0782732013-10-29 15:55:47 -040047TransceiverState::TransceiverState()
Tom Tsoua4d1a412014-11-25 15:46:56 -080048 : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
Thomas Tsouf0782732013-10-29 15:55:47 -040049{
50 for (int i = 0; i < 8; i++) {
51 chanType[i] = Transceiver::NONE;
52 fillerModulus[i] = 26;
53 chanResponse[i] = NULL;
54 DFEForward[i] = NULL;
55 DFEFeedback[i] = NULL;
56
57 for (int n = 0; n < 102; n++)
58 fillerTable[n][i] = NULL;
59 }
60}
61
62TransceiverState::~TransceiverState()
63{
64 for (int i = 0; i < 8; i++) {
65 delete chanResponse[i];
66 delete DFEForward[i];
67 delete DFEFeedback[i];
68
69 for (int n = 0; n < 102; n++)
70 delete fillerTable[n][i];
71 }
72}
73
Tom Tsou64ad7122015-05-19 18:26:31 -070074bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc)
75{
Tom Tsou64ad7122015-05-19 18:26:31 -070076 signalVector *burst;
77
78 if ((sps != 1) && (sps != 4))
79 return false;
80
81 for (size_t n = 0; n < 8; n++) {
Tom Tsou64ad7122015-05-19 18:26:31 -070082 for (size_t i = 0; i < 102; i++) {
83 switch (filler) {
84 case Transceiver::FILLER_DUMMY:
Tom Tsou8ee2f382016-03-06 20:57:34 -080085 burst = generateDummyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070086 break;
Tom Tsouaf717b22016-03-06 22:19:15 -080087 case Transceiver::FILLER_NORM_RAND:
Tom Tsou8ee2f382016-03-06 20:57:34 -080088 burst = genRandNormalBurst(rtsc, sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070089 break;
Tom Tsouaf717b22016-03-06 22:19:15 -080090 case Transceiver::FILLER_EDGE_RAND:
91 burst = generateEdgeBurst(rtsc);
92 break;
Alexander Chemeris5efe0502016-03-23 17:06:32 +030093 case Transceiver::FILLER_ACCESS_RAND:
94 burst = genRandAccessBurst(sps, n);
95 break;
Tom Tsou64ad7122015-05-19 18:26:31 -070096 case Transceiver::FILLER_ZERO:
97 default:
Tom Tsou8ee2f382016-03-06 20:57:34 -080098 burst = generateEmptyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070099 }
100
101 scaleVector(*burst, scale);
102 fillerTable[i][n] = burst;
103 }
104
Tom Tsouaf717b22016-03-06 22:19:15 -0800105 if ((filler == Transceiver::FILLER_NORM_RAND) ||
106 (filler == Transceiver::FILLER_EDGE_RAND)) {
107 chanType[n] = Transceiver::TSC;
108 }
Thomas Tsou15d743e2014-01-25 02:34:03 -0500109 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700110
111 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400112}
113
dburgessb3a0ca42011-10-12 07:44:40 +0000114Transceiver::Transceiver(int wBasePort,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400115 const char *wTRXAddress,
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800116 size_t tx_sps, size_t rx_sps, size_t chans,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400117 GSM::Time wTransmitLatency,
118 RadioInterface *wRadioInterface,
119 double wRssiOffset)
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800120 : mBasePort(wBasePort), mAddr(wTRXAddress),
121 mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
122 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Alexander Chemerise8905a02015-06-03 23:47:56 -0400123 rssiOffset(wRssiOffset),
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800124 mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mOn(false),
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300125 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
126 mWriteBurstToDiskMask(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000127{
dburgessb3a0ca42011-10-12 07:44:40 +0000128 txFullScale = mRadioInterface->fullScaleInputValue();
129 rxFullScale = mRadioInterface->fullScaleOutputValue();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300130
131 for (int i = 0; i < 8; i++) {
132 for (int j = 0; j < 8; j++)
133 mHandover[i][j] = false;
134 }
dburgessb3a0ca42011-10-12 07:44:40 +0000135}
136
137Transceiver::~Transceiver()
138{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800139 stop();
140
dburgessb3a0ca42011-10-12 07:44:40 +0000141 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400142
Thomas Tsou204a9f12013-10-29 18:34:16 -0400143 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800144 mControlServiceLoopThreads[i]->cancel();
145 mControlServiceLoopThreads[i]->join();
146 delete mControlServiceLoopThreads[i];
147
Thomas Tsou204a9f12013-10-29 18:34:16 -0400148 mTxPriorityQueues[i].clear();
149 delete mCtrlSockets[i];
150 delete mDataSockets[i];
151 }
dburgessb3a0ca42011-10-12 07:44:40 +0000152}
Thomas Tsou83e06892013-08-20 16:10:01 -0400153
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800154/*
155 * Initialize transceiver
156 *
157 * Start or restart the control loop. Any further control is handled through the
158 * socket API. Randomize the central radio clock set the downlink burst
159 * counters. Note that the clock will not update until the radio starts, but we
160 * are still expected to report clock indications through control channel
161 * activity.
162 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700163bool Transceiver::init(int filler, size_t rtsc)
Thomas Tsou83e06892013-08-20 16:10:01 -0400164{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500165 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400166
Thomas Tsou204a9f12013-10-29 18:34:16 -0400167 if (!mChans) {
168 LOG(ALERT) << "No channels assigned";
169 return false;
170 }
171
Tom Tsou2079a3c2016-03-06 00:58:56 -0800172 if (!sigProcLibSetup()) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400173 LOG(ALERT) << "Failed to initialize signal processing library";
174 return false;
175 }
176
Thomas Tsou204a9f12013-10-29 18:34:16 -0400177 mDataSockets.resize(mChans);
178 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400179 mControlServiceLoopThreads.resize(mChans);
180 mTxPriorityQueueServiceLoopThreads.resize(mChans);
181 mRxServiceLoopThreads.resize(mChans);
182
183 mTxPriorityQueues.resize(mChans);
184 mReceiveFIFO.resize(mChans);
185 mStates.resize(mChans);
186
Thomas Tsouccb73e12014-04-15 17:41:28 -0400187 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700188 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400189 mStates[0].mRetrans = true;
190
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800191 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400192 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500193 c_srcport = mBasePort + 2 * i + 1;
194 c_dstport = mBasePort + 2 * i + 101;
195 d_srcport = mBasePort + 2 * i + 2;
196 d_dstport = mBasePort + 2 * i + 102;
197
198 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
199 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400200 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400201
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800202 /* Randomize the central clock */
203 GSM::Time startTime(random() % gHyperframe, 0);
204 mRadioInterface->getClock()->set(startTime);
205 mTransmitDeadlineClock = startTime;
206 mLastClockUpdateTime = startTime;
207 mLatencyUpdateTime = startTime;
208
209 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400210 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800211 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400212 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800213 mControlServiceLoopThreads[i]->start((void * (*)(void*))
214 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400215
Tom Tsou64ad7122015-05-19 18:26:31 -0700216 if (i && filler == FILLER_DUMMY)
217 filler = FILLER_ZERO;
218
219 mStates[i].init(filler, mSPSTx, txFullScale, rtsc);
Thomas Tsou83e06892013-08-20 16:10:01 -0400220 }
221
222 return true;
223}
dburgessb3a0ca42011-10-12 07:44:40 +0000224
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800225/*
226 * Start the transceiver
227 *
228 * Submit command(s) to the radio device to commence streaming samples and
229 * launch threads to handle sample I/O. Re-synchronize the transmit burst
230 * counters to the central radio clock here as well.
231 */
232bool Transceiver::start()
233{
234 ScopedLock lock(mLock);
235
236 if (mOn) {
237 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300238 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800239 }
240
241 LOG(NOTICE) << "Starting the transceiver";
242
243 GSM::Time time = mRadioInterface->getClock()->get();
244 mTransmitDeadlineClock = time;
245 mLastClockUpdateTime = time;
246 mLatencyUpdateTime = time;
247
248 if (!mRadioInterface->start()) {
249 LOG(ALERT) << "Device failed to start";
250 return false;
251 }
252
253 /* Device is running - launch I/O threads */
254 mRxLowerLoopThread = new Thread(32768);
255 mTxLowerLoopThread = new Thread(32768);
256 mTxLowerLoopThread->start((void * (*)(void*))
257 TxLowerLoopAdapter,(void*) this);
258 mRxLowerLoopThread->start((void * (*)(void*))
259 RxLowerLoopAdapter,(void*) this);
260
261 /* Launch uplink and downlink burst processing threads */
262 for (size_t i = 0; i < mChans; i++) {
263 TransceiverChannel *chan = new TransceiverChannel(this, i);
264 mRxServiceLoopThreads[i] = new Thread(32768);
265 mRxServiceLoopThreads[i]->start((void * (*)(void*))
266 RxUpperLoopAdapter, (void*) chan);
267
268 chan = new TransceiverChannel(this, i);
269 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
270 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
271 TxUpperLoopAdapter, (void*) chan);
272 }
273
274 writeClockInterface();
275 mOn = true;
276 return true;
277}
278
279/*
280 * Stop the transceiver
281 *
282 * Perform stopping by disabling receive streaming and issuing cancellation
283 * requests to running threads. Most threads will timeout and terminate once
284 * device is disabled, but the transmit loop may block waiting on the central
285 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
286 * makes it to the thread cancellation point.
287 */
288void Transceiver::stop()
289{
290 ScopedLock lock(mLock);
291
292 if (!mOn)
293 return;
294
295 LOG(NOTICE) << "Stopping the transceiver";
296 mTxLowerLoopThread->cancel();
297 mRxLowerLoopThread->cancel();
298
299 for (size_t i = 0; i < mChans; i++) {
300 mRxServiceLoopThreads[i]->cancel();
301 mTxPriorityQueueServiceLoopThreads[i]->cancel();
302 }
303
304 LOG(INFO) << "Stopping the device";
305 mRadioInterface->stop();
306
307 for (size_t i = 0; i < mChans; i++) {
308 mRxServiceLoopThreads[i]->join();
309 mTxPriorityQueueServiceLoopThreads[i]->join();
310 delete mRxServiceLoopThreads[i];
311 delete mTxPriorityQueueServiceLoopThreads[i];
312
313 mTxPriorityQueues[i].clear();
314 }
315
316 mTxLowerLoopThread->join();
317 mRxLowerLoopThread->join();
318 delete mTxLowerLoopThread;
319 delete mRxLowerLoopThread;
320
321 mOn = false;
322 LOG(NOTICE) << "Transceiver stopped";
323}
324
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500325void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400326 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000327{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500328 signalVector *burst;
329 radioVector *radio_burst;
330
Thomas Tsou204a9f12013-10-29 18:34:16 -0400331 if (chan >= mTxPriorityQueues.size()) {
332 LOG(ALERT) << "Invalid channel " << chan;
333 return;
334 }
335
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500336 if (wTime.TN() > 7) {
337 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
338 return;
339 }
340
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800341 /* Use the number of bits as the EDGE burst indicator */
342 if (bits.size() == EDGE_BURST_NBITS)
343 burst = modulateEdgeBurst(bits, mSPSTx);
344 else
345 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
346
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500347 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000348
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500349 radio_burst = new radioVector(wTime, burst);
350
351 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000352}
353
Thomas Tsou15d743e2014-01-25 02:34:03 -0500354void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
355{
356 int TN, modFN;
357 TransceiverState *state = &mStates[chan];
358
359 TN = burst->getTime().TN();
360 modFN = burst->getTime().FN() % state->fillerModulus[TN];
361
362 delete state->fillerTable[modFN][TN];
363 state->fillerTable[modFN][TN] = burst->getVector();
364 burst->setVector(NULL);
365}
366
dburgessb3a0ca42011-10-12 07:44:40 +0000367void Transceiver::pushRadioVector(GSM::Time &nowTime)
368{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400369 int TN, modFN;
370 radioVector *burst;
371 TransceiverState *state;
372 std::vector<signalVector *> bursts(mChans);
373 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500374 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000375
Thomas Tsou204a9f12013-10-29 18:34:16 -0400376 for (size_t i = 0; i < mChans; i ++) {
377 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000378
Thomas Tsou204a9f12013-10-29 18:34:16 -0400379 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
380 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500381 if (state->mRetrans)
382 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500383 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400384 }
385
386 TN = nowTime.TN();
387 modFN = nowTime.FN() % state->fillerModulus[TN];
388
389 bursts[i] = state->fillerTable[modFN][TN];
390 zeros[i] = state->chanType[TN] == NONE;
391
392 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500393 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500394
395 if (state->mRetrans) {
396 updateFillerTable(i, burst);
397 } else {
398 burst->setVector(NULL);
399 filler[i] = false;
400 }
401
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500402 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400403 }
dburgessb3a0ca42011-10-12 07:44:40 +0000404 }
405
Thomas Tsou204a9f12013-10-29 18:34:16 -0400406 mRadioInterface->driveTransmitRadio(bursts, zeros);
407
Thomas Tsou15d743e2014-01-25 02:34:03 -0500408 for (size_t i = 0; i < mChans; i++) {
409 if (!filler[i])
410 delete bursts[i];
411 }
dburgessb3a0ca42011-10-12 07:44:40 +0000412}
413
Thomas Tsou204a9f12013-10-29 18:34:16 -0400414void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000415{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400416 TransceiverState *state = &mStates[chan];
417
418 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000419 case NONE:
420 case I:
421 case II:
422 case III:
423 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400424 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000425 break;
426 case IV:
427 case VI:
428 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400429 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000430 break;
431 //case V:
432 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400433 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000434 break;
ttsoufc40a842013-06-09 22:38:18 +0000435 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400436 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000437 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000438 default:
439 break;
440 }
441}
442
443
Thomas Tsou204a9f12013-10-29 18:34:16 -0400444Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
445 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000446{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300447 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 };
448 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,
449 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 };
450 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,
451 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 -0400452 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000453 unsigned burstTN = currTime.TN();
454 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300455 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000456
Thomas Tsou204a9f12013-10-29 18:34:16 -0400457 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000458 case NONE:
459 return OFF;
460 break;
461 case FILL:
462 return IDLE;
463 break;
464 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300465 // TODO: Are we expecting RACH on an IDLE frame?
466/* if (burstFN % 26 == 25)
467 return IDLE;*/
468 if (mHandover[burstTN][0])
469 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000470 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000471 break;
472 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300473 subch = tchh_subslot[burstFN % 26];
474 if (subch == 1)
475 return IDLE;
476 if (mHandover[burstTN][0])
477 return RACH;
ttsou20642972013-03-27 22:00:25 +0000478 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000479 break;
480 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300481 subch = tchh_subslot[burstFN % 26];
482 if (mHandover[burstTN][subch])
483 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000484 return TSC;
485 break;
486 case IV:
487 case VI:
488 return RACH;
489 break;
490 case V: {
491 int mod51 = burstFN % 51;
492 if ((mod51 <= 36) && (mod51 >= 14))
493 return RACH;
494 else if ((mod51 == 4) || (mod51 == 5))
495 return RACH;
496 else if ((mod51 == 45) || (mod51 == 46))
497 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300498 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
499 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000500 else
501 return TSC;
502 break;
503 }
504 case VII:
505 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
506 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300507 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
508 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000509 else
510 return TSC;
511 break;
ttsoufc40a842013-06-09 22:38:18 +0000512 case XIII: {
513 int mod52 = burstFN % 52;
514 if ((mod52 == 12) || (mod52 == 38))
515 return RACH;
516 else if ((mod52 == 25) || (mod52 == 51))
517 return IDLE;
518 else
519 return TSC;
520 break;
521 }
dburgessb3a0ca42011-10-12 07:44:40 +0000522 case LOOPBACK:
523 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
524 return IDLE;
525 else
526 return TSC;
527 break;
528 default:
529 return OFF;
530 break;
531 }
dburgessb3a0ca42011-10-12 07:44:40 +0000532}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400533
Tom Tsou46569402016-03-06 01:59:38 -0800534int Transceiver::detectBurst(TransceiverState *state, signalVector &burst,
535 complex &amp, float &toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500536{
Tom Tsou46569402016-03-06 01:59:38 -0800537 float threshold = 5.0, rc = 0;
Thomas Tsou30421a72013-11-13 23:14:48 -0500538
Tom Tsou46569402016-03-06 01:59:38 -0800539 switch (type) {
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800540 case EDGE:
541 rc = detectEdgeBurst(burst, mTSC, threshold, mSPSRx,
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300542 amp, toa, mMaxExpectedDelayNB);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800543 if (rc > 0)
544 break;
545 else
546 type = TSC;
Tom Tsou46569402016-03-06 01:59:38 -0800547 case TSC:
548 rc = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx,
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300549 amp, toa, mMaxExpectedDelayNB);
Tom Tsou46569402016-03-06 01:59:38 -0800550 break;
551 case RACH:
552 threshold = 6.0;
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300553 rc = detectRACHBurst(burst, threshold, mSPSRx, amp, toa,
554 mMaxExpectedDelayAB);
Tom Tsou46569402016-03-06 01:59:38 -0800555 break;
556 default:
557 LOG(ERR) << "Invalid correlation type";
558 }
559
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800560 if (rc > 0)
561 return type;
Tom Tsou46569402016-03-06 01:59:38 -0800562
563 return rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500564}
565
Thomas Tsou30421a72013-11-13 23:14:48 -0500566
567/*
Tom Tsou46569402016-03-06 01:59:38 -0800568 * Demodulate GMSK by direct rotation and soft slicing.
Thomas Tsou30421a72013-11-13 23:14:48 -0500569 */
570SoftVector *Transceiver::demodulate(TransceiverState *state,
571 signalVector &burst, complex amp,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800572 float toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500573{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800574 if (type == EDGE)
575 return demodEdgeBurst(burst, mSPSRx, amp, toa);
576
Thomas Tsou30421a72013-11-13 23:14:48 -0500577 return demodulateBurst(burst, mSPSRx, amp, toa);
578}
579
Alexander Chemerise692ce92015-06-12 00:15:31 -0400580void writeToFile(radioVector *radio_burst, size_t chan)
581{
582 GSM::Time time = radio_burst->getTime();
583 std::ostringstream fname;
584 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
585 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
586 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
587 outfile.close();
588}
589
Thomas Tsou30421a72013-11-13 23:14:48 -0500590/*
591 * Pull bursts from the FIFO and handle according to the slot
592 * and burst correlation type. Equalzation is currently disabled.
593 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400594SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400595 double &timingOffset, double &noise,
596 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000597{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800598 int rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500599 complex amp;
600 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500601 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500602 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500603 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500604 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400605 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000606
Thomas Tsou30421a72013-11-13 23:14:48 -0500607 /* Blocking FIFO read */
608 radioVector *radio_burst = mReceiveFIFO[chan]->read();
609 if (!radio_burst)
610 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000611
Thomas Tsou30421a72013-11-13 23:14:48 -0500612 /* Set time and determine correlation type */
613 GSM::Time time = radio_burst->getTime();
614 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000615
Alexander Chemerise692ce92015-06-12 00:15:31 -0400616 /* Debug: dump bursts to disk */
617 /* bits 0-7 - chan 0 timeslots
618 * bits 8-15 - chan 1 timeslots */
619 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
620 writeToFile(radio_burst, chan);
621
Alexander Chemeris2b542102015-06-08 22:46:38 -0400622 /* No processing if the timeslot is off.
623 * Not even power level or noise calculation. */
624 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500625 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000626 return NULL;
627 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000628
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500629 /* Select the diversity channel with highest energy */
630 for (size_t i = 0; i < radio_burst->chans(); i++) {
631 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
632 if (pow > max) {
633 max = pow;
634 max_i = i;
635 }
636 avg += pow;
637 }
638
639 if (max_i < 0) {
640 LOG(ALERT) << "Received empty burst";
641 delete radio_burst;
642 return NULL;
643 }
644
Thomas Tsou30421a72013-11-13 23:14:48 -0500645 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500646 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500647 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400648
649 wTime = time;
650 RSSI = 20.0 * log10(rxFullScale / avg);
651
652 /* RSSI estimation are valid */
653 isRssiValid = true;
654
655 if (type == IDLE) {
656 /* Update noise levels */
657 state->mNoises.insert(avg);
658 state->mNoiseLev = state->mNoises.avg();
659 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
660
661 delete radio_burst;
662 return NULL;
663 } else {
664 /* Do not update noise levels */
665 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
666 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400667
Thomas Tsou30421a72013-11-13 23:14:48 -0500668 /* Detect normal or RACH bursts */
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800669 rc = detectBurst(state, *burst, amp, toa, type);
Thomas Tsouf0782732013-10-29 15:55:47 -0400670
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800671 if (rc > 0) {
672 type = (CorrType) rc;
673 } else if (rc <= 0) {
674 if (rc == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400675 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800676 } else if (rc != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400677 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700678 }
679
Thomas Tsou30421a72013-11-13 23:14:48 -0500680 delete radio_burst;
681 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000682 }
dburgessb3a0ca42011-10-12 07:44:40 +0000683
Alexander Chemeris2b542102015-06-08 22:46:38 -0400684 timingOffset = toa / mSPSRx;
685
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800686 bits = demodulate(state, *burst, amp, toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500687
Thomas Tsou30421a72013-11-13 23:14:48 -0500688 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500689 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000690}
691
dburgessb3a0ca42011-10-12 07:44:40 +0000692void Transceiver::reset()
693{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400694 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
695 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000696}
697
698
Thomas Tsou204a9f12013-10-29 18:34:16 -0400699void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000700{
dburgessb3a0ca42011-10-12 07:44:40 +0000701 int MAX_PACKET_LENGTH = 100;
702
703 // check control socket
704 char buffer[MAX_PACKET_LENGTH];
705 int msgLen = -1;
706 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400707
Thomas Tsou204a9f12013-10-29 18:34:16 -0400708 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000709
710 if (msgLen < 1) {
711 return;
712 }
713
714 char cmdcheck[4];
715 char command[MAX_PACKET_LENGTH];
716 char response[MAX_PACKET_LENGTH];
717
718 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400719
720 if (!chan)
721 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000722
723 if (strcmp(cmdcheck,"CMD")!=0) {
724 LOG(WARNING) << "bogus message on control interface";
725 return;
726 }
727 LOG(INFO) << "command is " << buffer;
728
729 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800730 stop();
731 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000732 }
733 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800734 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000735 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800736 else
dburgessb3a0ca42011-10-12 07:44:40 +0000737 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300738 for (int i = 0; i < 8; i++) {
739 for (int j = 0; j < 8; j++)
740 mHandover[i][j] = false;
741 }
742 }
743 else if (strcmp(command,"HANDOVER")==0){
744 int ts=0,ss=0;
745 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
746 mHandover[ts][ss] = true;
747 LOG(WARNING) << "HANDOVER RACH at timeslot " << ts << " subslot " << ss;
748 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
749 }
750 else if (strcmp(command,"NOHANDOVER")==0){
751 int ts=0,ss=0;
752 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
753 mHandover[ts][ss] = false;
754 LOG(WARNING) << "NOHANDOVER at timeslot " << ts << " subslot " << ss;
755 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000756 }
757 else if (strcmp(command,"SETMAXDLY")==0) {
758 //set expected maximum time-of-arrival
759 int maxDelay;
760 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300761 mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
dburgessb3a0ca42011-10-12 07:44:40 +0000762 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
763 }
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300764 else if (strcmp(command,"SETMAXDLYNB")==0) {
765 //set expected maximum time-of-arrival
766 int maxDelay;
767 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
768 mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
769 sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
770 }
dburgessb3a0ca42011-10-12 07:44:40 +0000771 else if (strcmp(command,"SETRXGAIN")==0) {
772 //set expected maximum time-of-arrival
773 int newGain;
774 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400775 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000776 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
777 }
778 else if (strcmp(command,"NOISELEV")==0) {
779 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500780 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000781 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500782 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000783 }
784 else {
785 sprintf(response,"RSP NOISELEV 1 0");
786 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500787 }
788 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800789 int power;
790 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
791 power = mRadioInterface->setPowerAttenuation(power, chan);
792 mStates[chan].mPower = power;
793 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000794 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500795 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800796 int power, step;
797 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
798 power = mStates[chan].mPower + step;
799 power = mRadioInterface->setPowerAttenuation(power, chan);
800 mStates[chan].mPower = power;
801 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000802 }
dburgessb3a0ca42011-10-12 07:44:40 +0000803 else if (strcmp(command,"RXTUNE")==0) {
804 // tune receiver
805 int freqKhz;
806 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500807 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400808 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000809 LOG(ALERT) << "RX failed to tune";
810 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
811 }
812 else
813 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
814 }
815 else if (strcmp(command,"TXTUNE")==0) {
816 // tune txmtr
817 int freqKhz;
818 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500819 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400820 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000821 LOG(ALERT) << "TX failed to tune";
822 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
823 }
824 else
825 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
826 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500827 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000828 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500829 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500830 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700831 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500832 sprintf(response, "RSP SETTSC 1 %d", TSC);
833 else if (chan && (TSC != mTSC))
834 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000835 else {
836 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400837 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000838 }
839 }
840 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700841 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000842 int corrCode;
843 int timeslot;
844 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
845 if ((timeslot < 0) || (timeslot > 7)) {
846 LOG(WARNING) << "bogus message on control interface";
847 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
848 return;
849 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400850 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
851 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000852 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
853
854 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400855 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
856 // debug command! may change or disapear without notice
857 // set a mask which bursts to dump to disk
858 int mask;
859 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
860 mWriteBurstToDiskMask = mask;
861 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
862 }
dburgessb3a0ca42011-10-12 07:44:40 +0000863 else {
864 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200865 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000866 }
867
Thomas Tsou204a9f12013-10-29 18:34:16 -0400868 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000869}
870
Thomas Tsou204a9f12013-10-29 18:34:16 -0400871bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000872{
dburgessb3a0ca42011-10-12 07:44:40 +0000873 char buffer[gSlotLen+50];
874
875 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400876 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000877
878 if (msgLen!=gSlotLen+1+4+1) {
879 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
880 return false;
881 }
882
883 int timeSlot = (int) buffer[0];
884 uint64_t frameNum = 0;
885 for (int i = 0; i < 4; i++)
886 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000887
dburgessb3a0ca42011-10-12 07:44:40 +0000888 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
889
890 int RSSI = (int) buffer[5];
891 static BitVector newBurst(gSlotLen);
892 BitVector::iterator itr = newBurst.begin();
893 char *bufferItr = buffer+6;
894 while (itr < newBurst.end())
895 *itr++ = *bufferItr++;
896
897 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400898
899 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000900
901 return true;
902
903
904}
dburgessb3a0ca42011-10-12 07:44:40 +0000905
Thomas Tsou204a9f12013-10-29 18:34:16 -0400906void Transceiver::driveReceiveRadio()
907{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400908 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400909 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400910 } else {
911 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
912 writeClockInterface();
913 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400914}
915
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800916void Transceiver::logRxBurst(SoftVector *burst, GSM::Time time, double dbm,
917 double rssi, double noise, double toa)
918{
919 LOG(DEBUG) << std::fixed << std::right
920 << " time: " << time
921 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
922 << "dBFS/" << std::setw(6) << -dbm << "dBm"
923 << " noise: " << std::setw(5) << std::setprecision(1) << noise
924 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
925 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
926 << " bits: " << *burst;
927}
928
Thomas Tsou204a9f12013-10-29 18:34:16 -0400929void Transceiver::driveReceiveFIFO(size_t chan)
930{
dburgessb3a0ca42011-10-12 07:44:40 +0000931 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400932 double RSSI; // in dBFS
933 double dBm; // in dBm
934 double TOA; // in symbols
935 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400936 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000937 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400938 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800939 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000940
Alexander Chemeris2b542102015-06-08 22:46:38 -0400941 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800942 if (!rxBurst)
943 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000944
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800945 /*
946 * EDGE demodulator returns 444 (148 * 3) bits
947 */
948 if (rxBurst->size() == gSlotLen * 3)
949 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000950
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800951 dBm = RSSI + rssiOffset;
952 logRxBurst(rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400953
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800954 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000955
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800956 char burstString[nbits + 10];
957 burstString[0] = burstTime.TN();
958 for (int i = 0; i < 4; i++)
959 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
960 burstString[5] = (int)dBm;
961 burstString[6] = (TOAint >> 8) & 0x0ff;
962 burstString[7] = TOAint & 0x0ff;
963 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000964
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800965 for (unsigned i = 0; i < nbits; i++)
966 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
967
968 burstString[nbits + 9] = '\0';
969 delete rxBurst;
970
971 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000972}
973
Thomas Tsou204a9f12013-10-29 18:34:16 -0400974void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000975{
976
977 /**
978 Features a carefully controlled latency mechanism, to
979 assure that transmit packets arrive at the radio/USRP
980 before they need to be transmitted.
981
982 Deadline clock indicates the burst that needs to be
983 pushed into the FIFO right NOW. If transmit queue does
984 not have a burst, stick in filler data.
985 */
986
987
988 RadioClock *radioClock = (mRadioInterface->getClock());
989
990 if (mOn) {
991 //radioClock->wait(); // wait until clock updates
992 LOG(DEBUG) << "radio clock " << radioClock->get();
993 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
994 // if underrun, then we're not providing bursts to radio/USRP fast
995 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400996 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000997 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000998 // only update latency at the defined frame interval
999 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001000 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
1001 LOG(INFO) << "new latency: " << mTransmitLatency;
1002 mLatencyUpdateTime = radioClock->get();
1003 }
1004 }
1005 else {
1006 // if underrun hasn't occurred in the last sec (216 frames) drop
1007 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +00001008 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001009 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1010 mTransmitLatency.decTN();
1011 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1012 mLatencyUpdateTime = radioClock->get();
1013 }
1014 }
1015 }
dburgessb3a0ca42011-10-12 07:44:40 +00001016 }
dburgessb3a0ca42011-10-12 07:44:40 +00001017 // time to push burst to transmit FIFO
1018 pushRadioVector(mTransmitDeadlineClock);
1019 mTransmitDeadlineClock.incTN();
1020 }
dburgessb3a0ca42011-10-12 07:44:40 +00001021 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001022
1023 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001024}
1025
1026
1027
1028void Transceiver::writeClockInterface()
1029{
1030 char command[50];
1031 // FIXME -- This should be adaptive.
1032 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1033
1034 LOG(INFO) << "ClockInterface: sending " << command;
1035
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001036 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001037
1038 mLastClockUpdateTime = mTransmitDeadlineClock;
1039
Thomas Tsou92c16df2013-09-28 18:04:19 -04001040}
dburgessb3a0ca42011-10-12 07:44:40 +00001041
Thomas Tsou204a9f12013-10-29 18:34:16 -04001042void *RxUpperLoopAdapter(TransceiverChannel *chan)
1043{
1044 Transceiver *trx = chan->trx;
1045 size_t num = chan->num;
1046
1047 delete chan;
1048
Thomas Tsou7553aa92013-11-08 12:50:03 -05001049 trx->setPriority(0.42);
1050
Thomas Tsou204a9f12013-10-29 18:34:16 -04001051 while (1) {
1052 trx->driveReceiveFIFO(num);
1053 pthread_testcancel();
1054 }
1055 return NULL;
1056}
1057
1058void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001059{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001060 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001061
dburgessb3a0ca42011-10-12 07:44:40 +00001062 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001063 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001064 pthread_testcancel();
1065 }
1066 return NULL;
1067}
1068
Thomas Tsou204a9f12013-10-29 18:34:16 -04001069void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001070{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001071 transceiver->setPriority(0.44);
1072
Thomas Tsou92c16df2013-09-28 18:04:19 -04001073 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001074 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001075 pthread_testcancel();
1076 }
1077 return NULL;
1078}
1079
Thomas Tsou204a9f12013-10-29 18:34:16 -04001080void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001081{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001082 Transceiver *trx = chan->trx;
1083 size_t num = chan->num;
1084
1085 delete chan;
1086
dburgessb3a0ca42011-10-12 07:44:40 +00001087 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001088 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001089 pthread_testcancel();
1090 }
1091 return NULL;
1092}
1093
Thomas Tsou204a9f12013-10-29 18:34:16 -04001094void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001095{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001096 Transceiver *trx = chan->trx;
1097 size_t num = chan->num;
1098
1099 delete chan;
1100
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001101 trx->setPriority(0.40);
1102
dburgessb3a0ca42011-10-12 07:44:40 +00001103 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001104 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001105 pthread_testcancel();
1106 }
1107 return NULL;
1108}