blob: 9fc335a02fcc71446856294aaa5905c4a2f8c6a6 [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
dburgessb3a0ca42011-10-12 07:44:40 +000026#include "Transceiver.h"
27#include <Logger.h>
28
ttsou2173abf2012-08-08 00:51:31 +000029#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
dburgessb3a0ca42011-10-12 07:44:40 +000032
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040033using namespace GSM;
34
kurtis.heimerlec842de2012-11-23 08:37:32 +000035#define USB_LATENCY_INTRVL 10,0
ttsou2173abf2012-08-08 00:51:31 +000036
37#if USE_UHD
kurtis.heimerlec842de2012-11-23 08:37:32 +000038# define USB_LATENCY_MIN 6,7
ttsou2173abf2012-08-08 00:51:31 +000039#else
kurtis.heimerlec842de2012-11-23 08:37:32 +000040# define USB_LATENCY_MIN 1,1
ttsou2173abf2012-08-08 00:51:31 +000041#endif
dburgessb3a0ca42011-10-12 07:44:40 +000042
Thomas Tsoufa3a7872013-10-17 21:23:34 -040043/* Number of running values use in noise average */
44#define NOISE_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000045
Thomas Tsouf0782732013-10-29 15:55:47 -040046TransceiverState::TransceiverState()
Tom Tsoua4d1a412014-11-25 15:46:56 -080047 : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
Thomas Tsouf0782732013-10-29 15:55:47 -040048{
49 for (int i = 0; i < 8; i++) {
50 chanType[i] = Transceiver::NONE;
51 fillerModulus[i] = 26;
52 chanResponse[i] = NULL;
53 DFEForward[i] = NULL;
54 DFEFeedback[i] = NULL;
55
56 for (int n = 0; n < 102; n++)
57 fillerTable[n][i] = NULL;
58 }
59}
60
61TransceiverState::~TransceiverState()
62{
63 for (int i = 0; i < 8; i++) {
64 delete chanResponse[i];
65 delete DFEForward[i];
66 delete DFEFeedback[i];
67
68 for (int n = 0; n < 102; n++)
69 delete fillerTable[n][i];
70 }
71}
72
Tom Tsou64ad7122015-05-19 18:26:31 -070073static BitVector *genRandNormalBurst(size_t tsc)
Thomas Tsouf0782732013-10-29 15:55:47 -040074{
Tom Tsou64ad7122015-05-19 18:26:31 -070075 if (tsc > 7)
76 return NULL;
Thomas Tsou15d743e2014-01-25 02:34:03 -050077
Tom Tsou64ad7122015-05-19 18:26:31 -070078 BitVector *bits = new BitVector(148);
Thomas Tsou15d743e2014-01-25 02:34:03 -050079
Tom Tsou64ad7122015-05-19 18:26:31 -070080 size_t i = 0;
81
82 /* Tail bits */
83 for (; i < 4; i++)
84 (*bits)[i] = 0;
85
86 /* Random bits */
87 for (; i < 61; i++)
88 (*bits)[i] = rand() % 2;
89
90 /* Training sequence */
Alexander Chemeris29660482015-05-24 19:13:38 -040091 for (int j = 0; i < 87; i++, j++)
92 (*bits)[i] = GSM::gTrainingSequence[tsc][j];
Tom Tsou64ad7122015-05-19 18:26:31 -070093
94 /* Random bits */
95 for (; i < 144; i++)
96 (*bits)[i] = rand() % 2;
97
98 /* Tail bits */
99 for (; i < 148; i++)
100 (*bits)[i] = 0;
101
102 return bits;
103}
104
105bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc)
106{
107 BitVector *bits;
108 signalVector *burst;
109
110 if ((sps != 1) && (sps != 4))
111 return false;
112
113 for (size_t n = 0; n < 8; n++) {
114 size_t guard = 8 + !(n % 4);
115 size_t len = sps == 4 ? 625 : 148 + guard;
116
117 for (size_t i = 0; i < 102; i++) {
118 switch (filler) {
119 case Transceiver::FILLER_DUMMY:
120 burst = modulateBurst(gDummyBurst, guard, sps);
121 break;
122 case Transceiver::FILLER_RAND:
123 bits = genRandNormalBurst(rtsc);
124 burst = modulateBurst(*bits, guard, sps);
125 delete bits;
126 break;
127 case Transceiver::FILLER_ZERO:
128 default:
129 burst = new signalVector(len);
130 }
131
132 scaleVector(*burst, scale);
133 fillerTable[i][n] = burst;
134 }
135
136 if (filler == Transceiver::FILLER_RAND)
137 chanType[n] = Transceiver::TSC;
Thomas Tsou15d743e2014-01-25 02:34:03 -0500138 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700139
140 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400141}
142
dburgessb3a0ca42011-10-12 07:44:40 +0000143Transceiver::Transceiver(int wBasePort,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400144 const char *wTRXAddress,
145 size_t wSPS, size_t wChans,
146 GSM::Time wTransmitLatency,
147 RadioInterface *wRadioInterface,
148 double wRssiOffset)
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800149 : mBasePort(wBasePort), mAddr(wTRXAddress),
150 mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
151 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Alexander Chemerise8905a02015-06-03 23:47:56 -0400152 rssiOffset(wRssiOffset),
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800153 mSPSTx(wSPS), mSPSRx(1), mChans(wChans), mOn(false),
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700154 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000155{
dburgessb3a0ca42011-10-12 07:44:40 +0000156 txFullScale = mRadioInterface->fullScaleInputValue();
157 rxFullScale = mRadioInterface->fullScaleOutputValue();
dburgessb3a0ca42011-10-12 07:44:40 +0000158}
159
160Transceiver::~Transceiver()
161{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800162 stop();
163
dburgessb3a0ca42011-10-12 07:44:40 +0000164 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400165
Thomas Tsou204a9f12013-10-29 18:34:16 -0400166 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800167 mControlServiceLoopThreads[i]->cancel();
168 mControlServiceLoopThreads[i]->join();
169 delete mControlServiceLoopThreads[i];
170
Thomas Tsou204a9f12013-10-29 18:34:16 -0400171 mTxPriorityQueues[i].clear();
172 delete mCtrlSockets[i];
173 delete mDataSockets[i];
174 }
dburgessb3a0ca42011-10-12 07:44:40 +0000175}
Thomas Tsou83e06892013-08-20 16:10:01 -0400176
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800177/*
178 * Initialize transceiver
179 *
180 * Start or restart the control loop. Any further control is handled through the
181 * socket API. Randomize the central radio clock set the downlink burst
182 * counters. Note that the clock will not update until the radio starts, but we
183 * are still expected to report clock indications through control channel
184 * activity.
185 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700186bool Transceiver::init(int filler, size_t rtsc)
Thomas Tsou83e06892013-08-20 16:10:01 -0400187{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500188 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400189
Thomas Tsou204a9f12013-10-29 18:34:16 -0400190 if (!mChans) {
191 LOG(ALERT) << "No channels assigned";
192 return false;
193 }
194
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400195 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400196 LOG(ALERT) << "Failed to initialize signal processing library";
197 return false;
198 }
199
Thomas Tsou204a9f12013-10-29 18:34:16 -0400200 mDataSockets.resize(mChans);
201 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400202 mControlServiceLoopThreads.resize(mChans);
203 mTxPriorityQueueServiceLoopThreads.resize(mChans);
204 mRxServiceLoopThreads.resize(mChans);
205
206 mTxPriorityQueues.resize(mChans);
207 mReceiveFIFO.resize(mChans);
208 mStates.resize(mChans);
209
Thomas Tsouccb73e12014-04-15 17:41:28 -0400210 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700211 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400212 mStates[0].mRetrans = true;
213
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800214 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400215 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500216 c_srcport = mBasePort + 2 * i + 1;
217 c_dstport = mBasePort + 2 * i + 101;
218 d_srcport = mBasePort + 2 * i + 2;
219 d_dstport = mBasePort + 2 * i + 102;
220
221 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
222 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400223 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400224
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800225 /* Randomize the central clock */
226 GSM::Time startTime(random() % gHyperframe, 0);
227 mRadioInterface->getClock()->set(startTime);
228 mTransmitDeadlineClock = startTime;
229 mLastClockUpdateTime = startTime;
230 mLatencyUpdateTime = startTime;
231
232 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400233 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800234 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400235 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800236 mControlServiceLoopThreads[i]->start((void * (*)(void*))
237 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400238
Tom Tsou64ad7122015-05-19 18:26:31 -0700239 if (i && filler == FILLER_DUMMY)
240 filler = FILLER_ZERO;
241
242 mStates[i].init(filler, mSPSTx, txFullScale, rtsc);
Thomas Tsou83e06892013-08-20 16:10:01 -0400243 }
244
245 return true;
246}
dburgessb3a0ca42011-10-12 07:44:40 +0000247
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800248/*
249 * Start the transceiver
250 *
251 * Submit command(s) to the radio device to commence streaming samples and
252 * launch threads to handle sample I/O. Re-synchronize the transmit burst
253 * counters to the central radio clock here as well.
254 */
255bool Transceiver::start()
256{
257 ScopedLock lock(mLock);
258
259 if (mOn) {
260 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300261 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800262 }
263
264 LOG(NOTICE) << "Starting the transceiver";
265
266 GSM::Time time = mRadioInterface->getClock()->get();
267 mTransmitDeadlineClock = time;
268 mLastClockUpdateTime = time;
269 mLatencyUpdateTime = time;
270
271 if (!mRadioInterface->start()) {
272 LOG(ALERT) << "Device failed to start";
273 return false;
274 }
275
276 /* Device is running - launch I/O threads */
277 mRxLowerLoopThread = new Thread(32768);
278 mTxLowerLoopThread = new Thread(32768);
279 mTxLowerLoopThread->start((void * (*)(void*))
280 TxLowerLoopAdapter,(void*) this);
281 mRxLowerLoopThread->start((void * (*)(void*))
282 RxLowerLoopAdapter,(void*) this);
283
284 /* Launch uplink and downlink burst processing threads */
285 for (size_t i = 0; i < mChans; i++) {
286 TransceiverChannel *chan = new TransceiverChannel(this, i);
287 mRxServiceLoopThreads[i] = new Thread(32768);
288 mRxServiceLoopThreads[i]->start((void * (*)(void*))
289 RxUpperLoopAdapter, (void*) chan);
290
291 chan = new TransceiverChannel(this, i);
292 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
293 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
294 TxUpperLoopAdapter, (void*) chan);
295 }
296
297 writeClockInterface();
298 mOn = true;
299 return true;
300}
301
302/*
303 * Stop the transceiver
304 *
305 * Perform stopping by disabling receive streaming and issuing cancellation
306 * requests to running threads. Most threads will timeout and terminate once
307 * device is disabled, but the transmit loop may block waiting on the central
308 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
309 * makes it to the thread cancellation point.
310 */
311void Transceiver::stop()
312{
313 ScopedLock lock(mLock);
314
315 if (!mOn)
316 return;
317
318 LOG(NOTICE) << "Stopping the transceiver";
319 mTxLowerLoopThread->cancel();
320 mRxLowerLoopThread->cancel();
321
322 for (size_t i = 0; i < mChans; i++) {
323 mRxServiceLoopThreads[i]->cancel();
324 mTxPriorityQueueServiceLoopThreads[i]->cancel();
325 }
326
327 LOG(INFO) << "Stopping the device";
328 mRadioInterface->stop();
329
330 for (size_t i = 0; i < mChans; i++) {
331 mRxServiceLoopThreads[i]->join();
332 mTxPriorityQueueServiceLoopThreads[i]->join();
333 delete mRxServiceLoopThreads[i];
334 delete mTxPriorityQueueServiceLoopThreads[i];
335
336 mTxPriorityQueues[i].clear();
337 }
338
339 mTxLowerLoopThread->join();
340 mRxLowerLoopThread->join();
341 delete mTxLowerLoopThread;
342 delete mRxLowerLoopThread;
343
344 mOn = false;
345 LOG(NOTICE) << "Transceiver stopped";
346}
347
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500348void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400349 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000350{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500351 signalVector *burst;
352 radioVector *radio_burst;
353
Thomas Tsou204a9f12013-10-29 18:34:16 -0400354 if (chan >= mTxPriorityQueues.size()) {
355 LOG(ALERT) << "Invalid channel " << chan;
356 return;
357 }
358
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500359 if (wTime.TN() > 7) {
360 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
361 return;
362 }
363
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500364 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
365 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000366
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500367 radio_burst = new radioVector(wTime, burst);
368
369 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000370}
371
Thomas Tsou15d743e2014-01-25 02:34:03 -0500372void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
373{
374 int TN, modFN;
375 TransceiverState *state = &mStates[chan];
376
377 TN = burst->getTime().TN();
378 modFN = burst->getTime().FN() % state->fillerModulus[TN];
379
380 delete state->fillerTable[modFN][TN];
381 state->fillerTable[modFN][TN] = burst->getVector();
382 burst->setVector(NULL);
383}
384
dburgessb3a0ca42011-10-12 07:44:40 +0000385void Transceiver::pushRadioVector(GSM::Time &nowTime)
386{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400387 int TN, modFN;
388 radioVector *burst;
389 TransceiverState *state;
390 std::vector<signalVector *> bursts(mChans);
391 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500392 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000393
Thomas Tsou204a9f12013-10-29 18:34:16 -0400394 for (size_t i = 0; i < mChans; i ++) {
395 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000396
Thomas Tsou204a9f12013-10-29 18:34:16 -0400397 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
398 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500399 if (state->mRetrans)
400 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500401 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400402 }
403
404 TN = nowTime.TN();
405 modFN = nowTime.FN() % state->fillerModulus[TN];
406
407 bursts[i] = state->fillerTable[modFN][TN];
408 zeros[i] = state->chanType[TN] == NONE;
409
410 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500411 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500412
413 if (state->mRetrans) {
414 updateFillerTable(i, burst);
415 } else {
416 burst->setVector(NULL);
417 filler[i] = false;
418 }
419
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500420 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400421 }
dburgessb3a0ca42011-10-12 07:44:40 +0000422 }
423
Thomas Tsou204a9f12013-10-29 18:34:16 -0400424 mRadioInterface->driveTransmitRadio(bursts, zeros);
425
Thomas Tsou15d743e2014-01-25 02:34:03 -0500426 for (size_t i = 0; i < mChans; i++) {
427 if (!filler[i])
428 delete bursts[i];
429 }
dburgessb3a0ca42011-10-12 07:44:40 +0000430}
431
Thomas Tsou204a9f12013-10-29 18:34:16 -0400432void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000433{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400434 TransceiverState *state = &mStates[chan];
435
436 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000437 case NONE:
438 case I:
439 case II:
440 case III:
441 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400442 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000443 break;
444 case IV:
445 case VI:
446 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400447 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000448 break;
449 //case V:
450 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400451 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000452 break;
ttsoufc40a842013-06-09 22:38:18 +0000453 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400454 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000455 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000456 default:
457 break;
458 }
459}
460
461
Thomas Tsou204a9f12013-10-29 18:34:16 -0400462Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
463 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000464{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400465 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000466 unsigned burstTN = currTime.TN();
467 unsigned burstFN = currTime.FN();
468
Thomas Tsou204a9f12013-10-29 18:34:16 -0400469 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000470 case NONE:
471 return OFF;
472 break;
473 case FILL:
474 return IDLE;
475 break;
476 case I:
477 return TSC;
478 /*if (burstFN % 26 == 25)
479 return IDLE;
480 else
481 return TSC;*/
482 break;
483 case II:
ttsou20642972013-03-27 22:00:25 +0000484 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000485 break;
486 case III:
487 return TSC;
488 break;
489 case IV:
490 case VI:
491 return RACH;
492 break;
493 case V: {
494 int mod51 = burstFN % 51;
495 if ((mod51 <= 36) && (mod51 >= 14))
496 return RACH;
497 else if ((mod51 == 4) || (mod51 == 5))
498 return RACH;
499 else if ((mod51 == 45) || (mod51 == 46))
500 return RACH;
501 else
502 return TSC;
503 break;
504 }
505 case VII:
506 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
507 return IDLE;
508 else
509 return TSC;
510 break;
ttsoufc40a842013-06-09 22:38:18 +0000511 case XIII: {
512 int mod52 = burstFN % 52;
513 if ((mod52 == 12) || (mod52 == 38))
514 return RACH;
515 else if ((mod52 == 25) || (mod52 == 51))
516 return IDLE;
517 else
518 return TSC;
519 break;
520 }
dburgessb3a0ca42011-10-12 07:44:40 +0000521 case LOOPBACK:
522 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
523 return IDLE;
524 else
525 return TSC;
526 break;
527 default:
528 return OFF;
529 break;
530 }
dburgessb3a0ca42011-10-12 07:44:40 +0000531}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400532
Thomas Tsou30421a72013-11-13 23:14:48 -0500533/*
534 * Detect RACH synchronization sequence within a burst. No equalization
535 * is used or available on the RACH channel.
536 */
Alexander Chemeris954b1182015-06-04 15:39:41 -0400537int Transceiver::detectRACH(TransceiverState *state,
538 signalVector &burst,
539 complex &amp, float &toa)
Thomas Tsou30421a72013-11-13 23:14:48 -0500540{
541 float threshold = 6.0;
542
543 return detectRACHBurst(burst, threshold, mSPSRx, &amp, &toa);
544}
545
546/*
547 * Detect normal burst training sequence midamble. Update equalization
548 * state information and channel estimate if necessary. Equalization
549 * is currently disabled.
550 */
Alexander Chemeris954b1182015-06-04 15:39:41 -0400551int Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
552 complex &amp, float &toa, GSM::Time &time)
Thomas Tsou30421a72013-11-13 23:14:48 -0500553{
Alexander Chemeris954b1182015-06-04 15:39:41 -0400554 int success;
Thomas Tsou30421a72013-11-13 23:14:48 -0500555 int tn = time.TN();
556 float chanOffset, threshold = 5.0;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500557 bool noise, needDFE = false, estimateChan = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500558 double elapsed = time - state->chanEstimateTime[tn];
559 signalVector *chanResp;
560
561 /* Check equalization update state */
Thomas Tsoufb827d02013-11-16 16:14:12 -0500562 if (needDFE && ((elapsed > 50) || (!state->chanResponse[tn]))) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500563 delete state->DFEForward[tn];
564 delete state->DFEFeedback[tn];
565 state->DFEForward[tn] = NULL;
566 state->DFEFeedback[tn] = NULL;
567
568 estimateChan = true;
569 }
570
571 /* Detect normal burst midambles */
Alexander Chemeris954b1182015-06-04 15:39:41 -0400572 success = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, &amp,
573 &toa, mMaxExpectedDelay, estimateChan,
574 &chanResp, &chanOffset);
575 if (success <= 0) {
576 return success;
Thomas Tsou30421a72013-11-13 23:14:48 -0500577 }
578
Thomas Tsoua0179e32013-11-14 15:52:04 -0500579 noise = state->mNoiseLev;
580 state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
Thomas Tsou30421a72013-11-13 23:14:48 -0500581
582 /* Set equalizer if unabled */
583 if (needDFE && estimateChan) {
584 state->chanResponse[tn] = chanResp;
585 state->chanRespOffset[tn] = chanOffset;
586 state->chanRespAmplitude[tn] = amp;
587
588 scaleVector(*chanResp, complex(1.0, 0.0) / amp);
589
590 designDFE(*chanResp, state->SNRestimate[tn],
591 7, &state->DFEForward[tn], &state->DFEFeedback[tn]);
592
593 state->chanEstimateTime[tn] = time;
594 }
595
Alexander Chemeris954b1182015-06-04 15:39:41 -0400596 return 1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500597}
598
599/*
600 * Demodulate GMSK burst using equalization if requested. Otherwise
601 * demodulate by direct rotation and soft slicing.
602 */
603SoftVector *Transceiver::demodulate(TransceiverState *state,
604 signalVector &burst, complex amp,
605 float toa, size_t tn, bool equalize)
606{
607 if (equalize) {
608 scaleVector(burst, complex(1.0, 0.0) / amp);
609 return equalizeBurst(burst,
610 toa - state->chanRespOffset[tn],
611 mSPSRx,
612 *state->DFEForward[tn],
613 *state->DFEFeedback[tn]);
614 }
615
616 return demodulateBurst(burst, mSPSRx, amp, toa);
617}
618
619/*
620 * Pull bursts from the FIFO and handle according to the slot
621 * and burst correlation type. Equalzation is currently disabled.
622 */
Alexander Chemerise8905a02015-06-03 23:47:56 -0400623SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400624 double &timingOffset, double &noise,
625 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000626{
Alexander Chemeris954b1182015-06-04 15:39:41 -0400627 int success;
628 bool equalize = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500629 complex amp;
630 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500631 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500632 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500633 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500634 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000635
Thomas Tsou30421a72013-11-13 23:14:48 -0500636 /* Blocking FIFO read */
637 radioVector *radio_burst = mReceiveFIFO[chan]->read();
638 if (!radio_burst)
639 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000640
Thomas Tsou30421a72013-11-13 23:14:48 -0500641 /* Set time and determine correlation type */
642 GSM::Time time = radio_burst->getTime();
643 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000644
Thomas Tsou30421a72013-11-13 23:14:48 -0500645 if ((type == OFF) || (type == IDLE)) {
646 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000647 return NULL;
648 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000649
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500650 /* Select the diversity channel with highest energy */
651 for (size_t i = 0; i < radio_burst->chans(); i++) {
652 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
653 if (pow > max) {
654 max = pow;
655 max_i = i;
656 }
657 avg += pow;
658 }
659
660 if (max_i < 0) {
661 LOG(ALERT) << "Received empty burst";
662 delete radio_burst;
663 return NULL;
664 }
665
Thomas Tsou30421a72013-11-13 23:14:48 -0500666 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500667 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500668 avg = sqrt(avg / radio_burst->chans());
Thomas Tsoua0179e32013-11-14 15:52:04 -0500669 state->mNoiseLev = state->mNoises.avg();
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400670
Thomas Tsou30421a72013-11-13 23:14:48 -0500671 /* Detect normal or RACH bursts */
672 if (type == TSC)
Thomas Tsoua0179e32013-11-14 15:52:04 -0500673 success = detectTSC(state, *burst, amp, toa, time);
Thomas Tsou30421a72013-11-13 23:14:48 -0500674 else
Thomas Tsoua0179e32013-11-14 15:52:04 -0500675 success = detectRACH(state, *burst, amp, toa);
Thomas Tsouf0782732013-10-29 15:55:47 -0400676
Tom Tsou577cd022015-05-18 13:57:54 -0700677 /* Update noise average if no bust detected or alert on error */
678 if (success <= 0) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400679 if (success == SIGERR_NONE) {
Tom Tsou577cd022015-05-18 13:57:54 -0700680 state->mNoises.insert(avg);
681 } else if (success == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400682 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
683 } else {
684 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
Thomas Tsou30421a72013-11-13 23:14:48 -0500691 /* Demodulate and set output info */
692 if (equalize && (type != TSC))
693 equalize = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000694
Thomas Tsoua0179e32013-11-14 15:52:04 -0500695 if (avg - state->mNoiseLev > 0.0)
696 bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500697
Thomas Tsou30421a72013-11-13 23:14:48 -0500698 wTime = time;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400699 RSSI = 20.0 * log10(rxFullScale / avg);
700 timingOffset = toa / mSPSRx;
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400701 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
dburgessb3a0ca42011-10-12 07:44:40 +0000702
Thomas Tsou30421a72013-11-13 23:14:48 -0500703 delete radio_burst;
704
705 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000706}
707
dburgessb3a0ca42011-10-12 07:44:40 +0000708void Transceiver::reset()
709{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400710 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
711 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000712}
713
714
Thomas Tsou204a9f12013-10-29 18:34:16 -0400715void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000716{
dburgessb3a0ca42011-10-12 07:44:40 +0000717 int MAX_PACKET_LENGTH = 100;
718
719 // check control socket
720 char buffer[MAX_PACKET_LENGTH];
721 int msgLen = -1;
722 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400723
Thomas Tsou204a9f12013-10-29 18:34:16 -0400724 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000725
726 if (msgLen < 1) {
727 return;
728 }
729
730 char cmdcheck[4];
731 char command[MAX_PACKET_LENGTH];
732 char response[MAX_PACKET_LENGTH];
733
734 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400735
736 if (!chan)
737 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000738
739 if (strcmp(cmdcheck,"CMD")!=0) {
740 LOG(WARNING) << "bogus message on control interface";
741 return;
742 }
743 LOG(INFO) << "command is " << buffer;
744
745 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800746 stop();
747 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000748 }
749 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800750 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000751 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800752 else
dburgessb3a0ca42011-10-12 07:44:40 +0000753 sprintf(response,"RSP POWERON 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000754 }
755 else if (strcmp(command,"SETMAXDLY")==0) {
756 //set expected maximum time-of-arrival
757 int maxDelay;
758 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
759 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
760 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
761 }
762 else if (strcmp(command,"SETRXGAIN")==0) {
763 //set expected maximum time-of-arrival
764 int newGain;
765 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400766 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000767 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
768 }
769 else if (strcmp(command,"NOISELEV")==0) {
770 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500771 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000772 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500773 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000774 }
775 else {
776 sprintf(response,"RSP NOISELEV 1 0");
777 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500778 }
779 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800780 int power;
781 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
782 power = mRadioInterface->setPowerAttenuation(power, chan);
783 mStates[chan].mPower = power;
784 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000785 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500786 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800787 int power, step;
788 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
789 power = mStates[chan].mPower + step;
790 power = mRadioInterface->setPowerAttenuation(power, chan);
791 mStates[chan].mPower = power;
792 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000793 }
dburgessb3a0ca42011-10-12 07:44:40 +0000794 else if (strcmp(command,"RXTUNE")==0) {
795 // tune receiver
796 int freqKhz;
797 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500798 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400799 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000800 LOG(ALERT) << "RX failed to tune";
801 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
802 }
803 else
804 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
805 }
806 else if (strcmp(command,"TXTUNE")==0) {
807 // tune txmtr
808 int freqKhz;
809 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500810 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400811 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000812 LOG(ALERT) << "TX failed to tune";
813 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
814 }
815 else
816 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
817 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500818 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000819 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500820 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500821 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700822 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500823 sprintf(response, "RSP SETTSC 1 %d", TSC);
824 else if (chan && (TSC != mTSC))
825 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000826 else {
827 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400828 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400829 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000830 }
831 }
832 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700833 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000834 int corrCode;
835 int timeslot;
836 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
837 if ((timeslot < 0) || (timeslot > 7)) {
838 LOG(WARNING) << "bogus message on control interface";
839 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
840 return;
841 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400842 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
843 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000844 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
845
846 }
847 else {
848 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200849 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000850 }
851
Thomas Tsou204a9f12013-10-29 18:34:16 -0400852 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000853}
854
Thomas Tsou204a9f12013-10-29 18:34:16 -0400855bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000856{
dburgessb3a0ca42011-10-12 07:44:40 +0000857 char buffer[gSlotLen+50];
858
859 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400860 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000861
862 if (msgLen!=gSlotLen+1+4+1) {
863 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
864 return false;
865 }
866
867 int timeSlot = (int) buffer[0];
868 uint64_t frameNum = 0;
869 for (int i = 0; i < 4; i++)
870 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000871
dburgessb3a0ca42011-10-12 07:44:40 +0000872 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
873
874 int RSSI = (int) buffer[5];
875 static BitVector newBurst(gSlotLen);
876 BitVector::iterator itr = newBurst.begin();
877 char *bufferItr = buffer+6;
878 while (itr < newBurst.end())
879 *itr++ = *bufferItr++;
880
881 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400882
883 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000884
885 return true;
886
887
888}
dburgessb3a0ca42011-10-12 07:44:40 +0000889
Thomas Tsou204a9f12013-10-29 18:34:16 -0400890void Transceiver::driveReceiveRadio()
891{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400892 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400893 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400894 } else {
895 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
896 writeClockInterface();
897 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400898}
899
900void Transceiver::driveReceiveFIFO(size_t chan)
901{
dburgessb3a0ca42011-10-12 07:44:40 +0000902 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400903 double RSSI; // in dBFS
904 double dBm; // in dBm
905 double TOA; // in symbols
906 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400907 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000908 GSM::Time burstTime;
909
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400910 rxBurst = pullRadioVector(burstTime, RSSI, TOA, noise, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000911
912 if (rxBurst) {
Alexander Chemerise8905a02015-06-03 23:47:56 -0400913 dBm = RSSI+rssiOffset;
914 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000915
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400916 LOG(DEBUG) << std::fixed << std::right
917 << " time: " << burstTime
918 << " RSSI: " << std::setw(5) << std::setprecision(1) << RSSI << "dBFS/" << std::setw(6) << -dBm << "dBm"
919 << " noise: " << std::setw(5) << std::setprecision(1) << noise << "dBFS/" << std::setw(6) << -(noise+rssiOffset) << "dBm"
920 << " TOA: " << std::setw(5) << std::setprecision(2) << TOA
921 << " bits: " << *rxBurst;
922
dburgessb3a0ca42011-10-12 07:44:40 +0000923 char burstString[gSlotLen+10];
924 burstString[0] = burstTime.TN();
925 for (int i = 0; i < 4; i++)
926 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400927 burstString[5] = (int)dBm;
928 burstString[6] = (TOAint >> 8) & 0x0ff;
929 burstString[7] = TOAint & 0x0ff;
dburgessb3a0ca42011-10-12 07:44:40 +0000930 SoftVector::iterator burstItr = rxBurst->begin();
931
932 for (unsigned int i = 0; i < gSlotLen; i++) {
933 burstString[8+i] =(char) round((*burstItr++)*255.0);
934 }
935 burstString[gSlotLen+9] = '\0';
936 delete rxBurst;
937
Thomas Tsou204a9f12013-10-29 18:34:16 -0400938 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +0000939 }
dburgessb3a0ca42011-10-12 07:44:40 +0000940}
941
Thomas Tsou204a9f12013-10-29 18:34:16 -0400942void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000943{
944
945 /**
946 Features a carefully controlled latency mechanism, to
947 assure that transmit packets arrive at the radio/USRP
948 before they need to be transmitted.
949
950 Deadline clock indicates the burst that needs to be
951 pushed into the FIFO right NOW. If transmit queue does
952 not have a burst, stick in filler data.
953 */
954
955
956 RadioClock *radioClock = (mRadioInterface->getClock());
957
958 if (mOn) {
959 //radioClock->wait(); // wait until clock updates
960 LOG(DEBUG) << "radio clock " << radioClock->get();
961 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
962 // if underrun, then we're not providing bursts to radio/USRP fast
963 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400964 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000965 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000966 // only update latency at the defined frame interval
967 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000968 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
969 LOG(INFO) << "new latency: " << mTransmitLatency;
970 mLatencyUpdateTime = radioClock->get();
971 }
972 }
973 else {
974 // if underrun hasn't occurred in the last sec (216 frames) drop
975 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000976 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000977 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
978 mTransmitLatency.decTN();
979 LOG(INFO) << "reduced latency: " << mTransmitLatency;
980 mLatencyUpdateTime = radioClock->get();
981 }
982 }
983 }
dburgessb3a0ca42011-10-12 07:44:40 +0000984 }
dburgessb3a0ca42011-10-12 07:44:40 +0000985 // time to push burst to transmit FIFO
986 pushRadioVector(mTransmitDeadlineClock);
987 mTransmitDeadlineClock.incTN();
988 }
dburgessb3a0ca42011-10-12 07:44:40 +0000989 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400990
991 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000992}
993
994
995
996void Transceiver::writeClockInterface()
997{
998 char command[50];
999 // FIXME -- This should be adaptive.
1000 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1001
1002 LOG(INFO) << "ClockInterface: sending " << command;
1003
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001004 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001005
1006 mLastClockUpdateTime = mTransmitDeadlineClock;
1007
Thomas Tsou92c16df2013-09-28 18:04:19 -04001008}
dburgessb3a0ca42011-10-12 07:44:40 +00001009
Thomas Tsou204a9f12013-10-29 18:34:16 -04001010void *RxUpperLoopAdapter(TransceiverChannel *chan)
1011{
1012 Transceiver *trx = chan->trx;
1013 size_t num = chan->num;
1014
1015 delete chan;
1016
Thomas Tsou7553aa92013-11-08 12:50:03 -05001017 trx->setPriority(0.42);
1018
Thomas Tsou204a9f12013-10-29 18:34:16 -04001019 while (1) {
1020 trx->driveReceiveFIFO(num);
1021 pthread_testcancel();
1022 }
1023 return NULL;
1024}
1025
1026void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001027{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001028 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001029
dburgessb3a0ca42011-10-12 07:44:40 +00001030 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001031 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001032 pthread_testcancel();
1033 }
1034 return NULL;
1035}
1036
Thomas Tsou204a9f12013-10-29 18:34:16 -04001037void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001038{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001039 transceiver->setPriority(0.44);
1040
Thomas Tsou92c16df2013-09-28 18:04:19 -04001041 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001042 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001043 pthread_testcancel();
1044 }
1045 return NULL;
1046}
1047
Thomas Tsou204a9f12013-10-29 18:34:16 -04001048void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001049{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001050 Transceiver *trx = chan->trx;
1051 size_t num = chan->num;
1052
1053 delete chan;
1054
dburgessb3a0ca42011-10-12 07:44:40 +00001055 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001056 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001057 pthread_testcancel();
1058 }
1059 return NULL;
1060}
1061
Thomas Tsou204a9f12013-10-29 18:34:16 -04001062void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001063{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001064 Transceiver *trx = chan->trx;
1065 size_t num = chan->num;
1066
1067 delete chan;
1068
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001069 trx->setPriority(0.40);
1070
dburgessb3a0ca42011-10-12 07:44:40 +00001071 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001072 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001073 pthread_testcancel();
1074 }
1075 return NULL;
1076}