blob: a1c6f1bdc94f6a41b802aed3f1d9720ed3c1f757 [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;
Tom Tsou64ad7122015-05-19 18:26:31 -070093 case Transceiver::FILLER_ZERO:
94 default:
Tom Tsou8ee2f382016-03-06 20:57:34 -080095 burst = generateEmptyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070096 }
97
98 scaleVector(*burst, scale);
99 fillerTable[i][n] = burst;
100 }
101
Tom Tsouaf717b22016-03-06 22:19:15 -0800102 if ((filler == Transceiver::FILLER_NORM_RAND) ||
103 (filler == Transceiver::FILLER_EDGE_RAND)) {
104 chanType[n] = Transceiver::TSC;
105 }
Thomas Tsou15d743e2014-01-25 02:34:03 -0500106 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700107
108 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400109}
110
dburgessb3a0ca42011-10-12 07:44:40 +0000111Transceiver::Transceiver(int wBasePort,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400112 const char *wTRXAddress,
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800113 size_t tx_sps, size_t rx_sps, size_t chans,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400114 GSM::Time wTransmitLatency,
115 RadioInterface *wRadioInterface,
116 double wRssiOffset)
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800117 : mBasePort(wBasePort), mAddr(wTRXAddress),
118 mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
119 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Alexander Chemerise8905a02015-06-03 23:47:56 -0400120 rssiOffset(wRssiOffset),
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800121 mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mOn(false),
Alexander Chemerise692ce92015-06-12 00:15:31 -0400122 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0), mWriteBurstToDiskMask(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000123{
dburgessb3a0ca42011-10-12 07:44:40 +0000124 txFullScale = mRadioInterface->fullScaleInputValue();
125 rxFullScale = mRadioInterface->fullScaleOutputValue();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300126
127 for (int i = 0; i < 8; i++) {
128 for (int j = 0; j < 8; j++)
129 mHandover[i][j] = false;
130 }
dburgessb3a0ca42011-10-12 07:44:40 +0000131}
132
133Transceiver::~Transceiver()
134{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800135 stop();
136
dburgessb3a0ca42011-10-12 07:44:40 +0000137 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400138
Thomas Tsou204a9f12013-10-29 18:34:16 -0400139 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800140 mControlServiceLoopThreads[i]->cancel();
141 mControlServiceLoopThreads[i]->join();
142 delete mControlServiceLoopThreads[i];
143
Thomas Tsou204a9f12013-10-29 18:34:16 -0400144 mTxPriorityQueues[i].clear();
145 delete mCtrlSockets[i];
146 delete mDataSockets[i];
147 }
dburgessb3a0ca42011-10-12 07:44:40 +0000148}
Thomas Tsou83e06892013-08-20 16:10:01 -0400149
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800150/*
151 * Initialize transceiver
152 *
153 * Start or restart the control loop. Any further control is handled through the
154 * socket API. Randomize the central radio clock set the downlink burst
155 * counters. Note that the clock will not update until the radio starts, but we
156 * are still expected to report clock indications through control channel
157 * activity.
158 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700159bool Transceiver::init(int filler, size_t rtsc)
Thomas Tsou83e06892013-08-20 16:10:01 -0400160{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500161 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400162
Thomas Tsou204a9f12013-10-29 18:34:16 -0400163 if (!mChans) {
164 LOG(ALERT) << "No channels assigned";
165 return false;
166 }
167
Tom Tsou2079a3c2016-03-06 00:58:56 -0800168 if (!sigProcLibSetup()) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400169 LOG(ALERT) << "Failed to initialize signal processing library";
170 return false;
171 }
172
Thomas Tsou204a9f12013-10-29 18:34:16 -0400173 mDataSockets.resize(mChans);
174 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400175 mControlServiceLoopThreads.resize(mChans);
176 mTxPriorityQueueServiceLoopThreads.resize(mChans);
177 mRxServiceLoopThreads.resize(mChans);
178
179 mTxPriorityQueues.resize(mChans);
180 mReceiveFIFO.resize(mChans);
181 mStates.resize(mChans);
182
Thomas Tsouccb73e12014-04-15 17:41:28 -0400183 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700184 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400185 mStates[0].mRetrans = true;
186
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800187 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400188 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500189 c_srcport = mBasePort + 2 * i + 1;
190 c_dstport = mBasePort + 2 * i + 101;
191 d_srcport = mBasePort + 2 * i + 2;
192 d_dstport = mBasePort + 2 * i + 102;
193
194 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
195 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400196 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400197
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800198 /* Randomize the central clock */
199 GSM::Time startTime(random() % gHyperframe, 0);
200 mRadioInterface->getClock()->set(startTime);
201 mTransmitDeadlineClock = startTime;
202 mLastClockUpdateTime = startTime;
203 mLatencyUpdateTime = startTime;
204
205 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400206 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800207 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400208 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800209 mControlServiceLoopThreads[i]->start((void * (*)(void*))
210 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400211
Tom Tsou64ad7122015-05-19 18:26:31 -0700212 if (i && filler == FILLER_DUMMY)
213 filler = FILLER_ZERO;
214
215 mStates[i].init(filler, mSPSTx, txFullScale, rtsc);
Thomas Tsou83e06892013-08-20 16:10:01 -0400216 }
217
218 return true;
219}
dburgessb3a0ca42011-10-12 07:44:40 +0000220
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800221/*
222 * Start the transceiver
223 *
224 * Submit command(s) to the radio device to commence streaming samples and
225 * launch threads to handle sample I/O. Re-synchronize the transmit burst
226 * counters to the central radio clock here as well.
227 */
228bool Transceiver::start()
229{
230 ScopedLock lock(mLock);
231
232 if (mOn) {
233 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300234 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800235 }
236
237 LOG(NOTICE) << "Starting the transceiver";
238
239 GSM::Time time = mRadioInterface->getClock()->get();
240 mTransmitDeadlineClock = time;
241 mLastClockUpdateTime = time;
242 mLatencyUpdateTime = time;
243
244 if (!mRadioInterface->start()) {
245 LOG(ALERT) << "Device failed to start";
246 return false;
247 }
248
249 /* Device is running - launch I/O threads */
250 mRxLowerLoopThread = new Thread(32768);
251 mTxLowerLoopThread = new Thread(32768);
252 mTxLowerLoopThread->start((void * (*)(void*))
253 TxLowerLoopAdapter,(void*) this);
254 mRxLowerLoopThread->start((void * (*)(void*))
255 RxLowerLoopAdapter,(void*) this);
256
257 /* Launch uplink and downlink burst processing threads */
258 for (size_t i = 0; i < mChans; i++) {
259 TransceiverChannel *chan = new TransceiverChannel(this, i);
260 mRxServiceLoopThreads[i] = new Thread(32768);
261 mRxServiceLoopThreads[i]->start((void * (*)(void*))
262 RxUpperLoopAdapter, (void*) chan);
263
264 chan = new TransceiverChannel(this, i);
265 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
266 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
267 TxUpperLoopAdapter, (void*) chan);
268 }
269
270 writeClockInterface();
271 mOn = true;
272 return true;
273}
274
275/*
276 * Stop the transceiver
277 *
278 * Perform stopping by disabling receive streaming and issuing cancellation
279 * requests to running threads. Most threads will timeout and terminate once
280 * device is disabled, but the transmit loop may block waiting on the central
281 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
282 * makes it to the thread cancellation point.
283 */
284void Transceiver::stop()
285{
286 ScopedLock lock(mLock);
287
288 if (!mOn)
289 return;
290
291 LOG(NOTICE) << "Stopping the transceiver";
292 mTxLowerLoopThread->cancel();
293 mRxLowerLoopThread->cancel();
294
295 for (size_t i = 0; i < mChans; i++) {
296 mRxServiceLoopThreads[i]->cancel();
297 mTxPriorityQueueServiceLoopThreads[i]->cancel();
298 }
299
300 LOG(INFO) << "Stopping the device";
301 mRadioInterface->stop();
302
303 for (size_t i = 0; i < mChans; i++) {
304 mRxServiceLoopThreads[i]->join();
305 mTxPriorityQueueServiceLoopThreads[i]->join();
306 delete mRxServiceLoopThreads[i];
307 delete mTxPriorityQueueServiceLoopThreads[i];
308
309 mTxPriorityQueues[i].clear();
310 }
311
312 mTxLowerLoopThread->join();
313 mRxLowerLoopThread->join();
314 delete mTxLowerLoopThread;
315 delete mRxLowerLoopThread;
316
317 mOn = false;
318 LOG(NOTICE) << "Transceiver stopped";
319}
320
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500321void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400322 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000323{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500324 signalVector *burst;
325 radioVector *radio_burst;
326
Thomas Tsou204a9f12013-10-29 18:34:16 -0400327 if (chan >= mTxPriorityQueues.size()) {
328 LOG(ALERT) << "Invalid channel " << chan;
329 return;
330 }
331
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500332 if (wTime.TN() > 7) {
333 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
334 return;
335 }
336
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800337 /* Use the number of bits as the EDGE burst indicator */
338 if (bits.size() == EDGE_BURST_NBITS)
339 burst = modulateEdgeBurst(bits, mSPSTx);
340 else
341 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
342
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500343 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000344
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500345 radio_burst = new radioVector(wTime, burst);
346
347 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000348}
349
Thomas Tsou15d743e2014-01-25 02:34:03 -0500350void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
351{
352 int TN, modFN;
353 TransceiverState *state = &mStates[chan];
354
355 TN = burst->getTime().TN();
356 modFN = burst->getTime().FN() % state->fillerModulus[TN];
357
358 delete state->fillerTable[modFN][TN];
359 state->fillerTable[modFN][TN] = burst->getVector();
360 burst->setVector(NULL);
361}
362
dburgessb3a0ca42011-10-12 07:44:40 +0000363void Transceiver::pushRadioVector(GSM::Time &nowTime)
364{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400365 int TN, modFN;
366 radioVector *burst;
367 TransceiverState *state;
368 std::vector<signalVector *> bursts(mChans);
369 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500370 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000371
Thomas Tsou204a9f12013-10-29 18:34:16 -0400372 for (size_t i = 0; i < mChans; i ++) {
373 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000374
Thomas Tsou204a9f12013-10-29 18:34:16 -0400375 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
376 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500377 if (state->mRetrans)
378 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500379 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400380 }
381
382 TN = nowTime.TN();
383 modFN = nowTime.FN() % state->fillerModulus[TN];
384
385 bursts[i] = state->fillerTable[modFN][TN];
386 zeros[i] = state->chanType[TN] == NONE;
387
388 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500389 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500390
391 if (state->mRetrans) {
392 updateFillerTable(i, burst);
393 } else {
394 burst->setVector(NULL);
395 filler[i] = false;
396 }
397
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500398 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400399 }
dburgessb3a0ca42011-10-12 07:44:40 +0000400 }
401
Thomas Tsou204a9f12013-10-29 18:34:16 -0400402 mRadioInterface->driveTransmitRadio(bursts, zeros);
403
Thomas Tsou15d743e2014-01-25 02:34:03 -0500404 for (size_t i = 0; i < mChans; i++) {
405 if (!filler[i])
406 delete bursts[i];
407 }
dburgessb3a0ca42011-10-12 07:44:40 +0000408}
409
Thomas Tsou204a9f12013-10-29 18:34:16 -0400410void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000411{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400412 TransceiverState *state = &mStates[chan];
413
414 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000415 case NONE:
416 case I:
417 case II:
418 case III:
419 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400420 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000421 break;
422 case IV:
423 case VI:
424 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400425 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000426 break;
427 //case V:
428 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400429 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000430 break;
ttsoufc40a842013-06-09 22:38:18 +0000431 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400432 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000433 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000434 default:
435 break;
436 }
437}
438
439
Thomas Tsou204a9f12013-10-29 18:34:16 -0400440Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
441 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000442{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300443 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 };
444 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,
445 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 };
446 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,
447 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 -0400448 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000449 unsigned burstTN = currTime.TN();
450 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300451 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000452
Thomas Tsou204a9f12013-10-29 18:34:16 -0400453 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000454 case NONE:
455 return OFF;
456 break;
457 case FILL:
458 return IDLE;
459 break;
460 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300461 // TODO: Are we expecting RACH on an IDLE frame?
462/* if (burstFN % 26 == 25)
463 return IDLE;*/
464 if (mHandover[burstTN][0])
465 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000466 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000467 break;
468 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300469 subch = tchh_subslot[burstFN % 26];
470 if (subch == 1)
471 return IDLE;
472 if (mHandover[burstTN][0])
473 return RACH;
ttsou20642972013-03-27 22:00:25 +0000474 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000475 break;
476 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300477 subch = tchh_subslot[burstFN % 26];
478 if (mHandover[burstTN][subch])
479 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000480 return TSC;
481 break;
482 case IV:
483 case VI:
484 return RACH;
485 break;
486 case V: {
487 int mod51 = burstFN % 51;
488 if ((mod51 <= 36) && (mod51 >= 14))
489 return RACH;
490 else if ((mod51 == 4) || (mod51 == 5))
491 return RACH;
492 else if ((mod51 == 45) || (mod51 == 46))
493 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300494 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
495 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000496 else
497 return TSC;
498 break;
499 }
500 case VII:
501 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
502 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300503 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
504 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000505 else
506 return TSC;
507 break;
ttsoufc40a842013-06-09 22:38:18 +0000508 case XIII: {
509 int mod52 = burstFN % 52;
510 if ((mod52 == 12) || (mod52 == 38))
511 return RACH;
512 else if ((mod52 == 25) || (mod52 == 51))
513 return IDLE;
514 else
515 return TSC;
516 break;
517 }
dburgessb3a0ca42011-10-12 07:44:40 +0000518 case LOOPBACK:
519 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
520 return IDLE;
521 else
522 return TSC;
523 break;
524 default:
525 return OFF;
526 break;
527 }
dburgessb3a0ca42011-10-12 07:44:40 +0000528}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400529
Tom Tsou46569402016-03-06 01:59:38 -0800530int Transceiver::detectBurst(TransceiverState *state, signalVector &burst,
531 complex &amp, float &toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500532{
Tom Tsou46569402016-03-06 01:59:38 -0800533 float threshold = 5.0, rc = 0;
Thomas Tsou30421a72013-11-13 23:14:48 -0500534
Tom Tsou46569402016-03-06 01:59:38 -0800535 switch (type) {
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800536 case EDGE:
537 rc = detectEdgeBurst(burst, mTSC, threshold, mSPSRx,
538 amp, toa, mMaxExpectedDelay);
539 if (rc > 0)
540 break;
541 else
542 type = TSC;
Tom Tsou46569402016-03-06 01:59:38 -0800543 case TSC:
544 rc = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx,
545 amp, toa, mMaxExpectedDelay);
546 break;
547 case RACH:
548 threshold = 6.0;
549 rc = detectRACHBurst(burst, threshold, mSPSRx, amp, toa);
550 break;
551 default:
552 LOG(ERR) << "Invalid correlation type";
553 }
554
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800555 if (rc > 0)
556 return type;
Tom Tsou46569402016-03-06 01:59:38 -0800557
558 return rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500559}
560
Thomas Tsou30421a72013-11-13 23:14:48 -0500561
562/*
Tom Tsou46569402016-03-06 01:59:38 -0800563 * Demodulate GMSK by direct rotation and soft slicing.
Thomas Tsou30421a72013-11-13 23:14:48 -0500564 */
565SoftVector *Transceiver::demodulate(TransceiverState *state,
566 signalVector &burst, complex amp,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800567 float toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500568{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800569 if (type == EDGE)
570 return demodEdgeBurst(burst, mSPSRx, amp, toa);
571
Thomas Tsou30421a72013-11-13 23:14:48 -0500572 return demodulateBurst(burst, mSPSRx, amp, toa);
573}
574
Alexander Chemerise692ce92015-06-12 00:15:31 -0400575void writeToFile(radioVector *radio_burst, size_t chan)
576{
577 GSM::Time time = radio_burst->getTime();
578 std::ostringstream fname;
579 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
580 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
581 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
582 outfile.close();
583}
584
Thomas Tsou30421a72013-11-13 23:14:48 -0500585/*
586 * Pull bursts from the FIFO and handle according to the slot
587 * and burst correlation type. Equalzation is currently disabled.
588 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400589SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400590 double &timingOffset, double &noise,
591 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000592{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800593 int rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500594 complex amp;
595 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500596 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500597 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500598 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500599 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400600 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000601
Thomas Tsou30421a72013-11-13 23:14:48 -0500602 /* Blocking FIFO read */
603 radioVector *radio_burst = mReceiveFIFO[chan]->read();
604 if (!radio_burst)
605 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000606
Thomas Tsou30421a72013-11-13 23:14:48 -0500607 /* Set time and determine correlation type */
608 GSM::Time time = radio_burst->getTime();
609 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000610
Alexander Chemerise692ce92015-06-12 00:15:31 -0400611 /* Debug: dump bursts to disk */
612 /* bits 0-7 - chan 0 timeslots
613 * bits 8-15 - chan 1 timeslots */
614 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
615 writeToFile(radio_burst, chan);
616
Alexander Chemeris2b542102015-06-08 22:46:38 -0400617 /* No processing if the timeslot is off.
618 * Not even power level or noise calculation. */
619 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500620 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000621 return NULL;
622 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000623
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500624 /* Select the diversity channel with highest energy */
625 for (size_t i = 0; i < radio_burst->chans(); i++) {
626 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
627 if (pow > max) {
628 max = pow;
629 max_i = i;
630 }
631 avg += pow;
632 }
633
634 if (max_i < 0) {
635 LOG(ALERT) << "Received empty burst";
636 delete radio_burst;
637 return NULL;
638 }
639
Thomas Tsou30421a72013-11-13 23:14:48 -0500640 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500641 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500642 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400643
644 wTime = time;
645 RSSI = 20.0 * log10(rxFullScale / avg);
646
647 /* RSSI estimation are valid */
648 isRssiValid = true;
649
650 if (type == IDLE) {
651 /* Update noise levels */
652 state->mNoises.insert(avg);
653 state->mNoiseLev = state->mNoises.avg();
654 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
655
656 delete radio_burst;
657 return NULL;
658 } else {
659 /* Do not update noise levels */
660 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
661 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400662
Thomas Tsou30421a72013-11-13 23:14:48 -0500663 /* Detect normal or RACH bursts */
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800664 rc = detectBurst(state, *burst, amp, toa, type);
Thomas Tsouf0782732013-10-29 15:55:47 -0400665
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800666 if (rc > 0) {
667 type = (CorrType) rc;
668 } else if (rc <= 0) {
669 if (rc == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400670 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800671 } else if (rc != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400672 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700673 }
674
Thomas Tsou30421a72013-11-13 23:14:48 -0500675 delete radio_burst;
676 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000677 }
dburgessb3a0ca42011-10-12 07:44:40 +0000678
Alexander Chemeris2b542102015-06-08 22:46:38 -0400679 timingOffset = toa / mSPSRx;
680
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800681 bits = demodulate(state, *burst, amp, toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500682
Thomas Tsou30421a72013-11-13 23:14:48 -0500683 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500684 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000685}
686
dburgessb3a0ca42011-10-12 07:44:40 +0000687void Transceiver::reset()
688{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400689 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
690 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000691}
692
693
Thomas Tsou204a9f12013-10-29 18:34:16 -0400694void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000695{
dburgessb3a0ca42011-10-12 07:44:40 +0000696 int MAX_PACKET_LENGTH = 100;
697
698 // check control socket
699 char buffer[MAX_PACKET_LENGTH];
700 int msgLen = -1;
701 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400702
Thomas Tsou204a9f12013-10-29 18:34:16 -0400703 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000704
705 if (msgLen < 1) {
706 return;
707 }
708
709 char cmdcheck[4];
710 char command[MAX_PACKET_LENGTH];
711 char response[MAX_PACKET_LENGTH];
712
713 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400714
715 if (!chan)
716 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000717
718 if (strcmp(cmdcheck,"CMD")!=0) {
719 LOG(WARNING) << "bogus message on control interface";
720 return;
721 }
722 LOG(INFO) << "command is " << buffer;
723
724 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800725 stop();
726 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000727 }
728 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800729 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000730 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800731 else
dburgessb3a0ca42011-10-12 07:44:40 +0000732 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300733 for (int i = 0; i < 8; i++) {
734 for (int j = 0; j < 8; j++)
735 mHandover[i][j] = false;
736 }
737 }
738 else if (strcmp(command,"HANDOVER")==0){
739 int ts=0,ss=0;
740 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
741 mHandover[ts][ss] = true;
742 LOG(WARNING) << "HANDOVER RACH at timeslot " << ts << " subslot " << ss;
743 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
744 }
745 else if (strcmp(command,"NOHANDOVER")==0){
746 int ts=0,ss=0;
747 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
748 mHandover[ts][ss] = false;
749 LOG(WARNING) << "NOHANDOVER at timeslot " << ts << " subslot " << ss;
750 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000751 }
752 else if (strcmp(command,"SETMAXDLY")==0) {
753 //set expected maximum time-of-arrival
754 int maxDelay;
755 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
756 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
757 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
758 }
759 else if (strcmp(command,"SETRXGAIN")==0) {
760 //set expected maximum time-of-arrival
761 int newGain;
762 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400763 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000764 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
765 }
766 else if (strcmp(command,"NOISELEV")==0) {
767 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500768 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000769 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500770 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000771 }
772 else {
773 sprintf(response,"RSP NOISELEV 1 0");
774 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500775 }
776 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800777 int power;
778 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
779 power = mRadioInterface->setPowerAttenuation(power, chan);
780 mStates[chan].mPower = power;
781 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000782 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500783 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800784 int power, step;
785 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
786 power = mStates[chan].mPower + step;
787 power = mRadioInterface->setPowerAttenuation(power, chan);
788 mStates[chan].mPower = power;
789 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000790 }
dburgessb3a0ca42011-10-12 07:44:40 +0000791 else if (strcmp(command,"RXTUNE")==0) {
792 // tune receiver
793 int freqKhz;
794 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500795 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400796 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000797 LOG(ALERT) << "RX failed to tune";
798 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
799 }
800 else
801 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
802 }
803 else if (strcmp(command,"TXTUNE")==0) {
804 // tune txmtr
805 int freqKhz;
806 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500807 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400808 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000809 LOG(ALERT) << "TX failed to tune";
810 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
811 }
812 else
813 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
814 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500815 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000816 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500817 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500818 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700819 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500820 sprintf(response, "RSP SETTSC 1 %d", TSC);
821 else if (chan && (TSC != mTSC))
822 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000823 else {
824 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400825 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000826 }
827 }
828 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700829 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000830 int corrCode;
831 int timeslot;
832 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
833 if ((timeslot < 0) || (timeslot > 7)) {
834 LOG(WARNING) << "bogus message on control interface";
835 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
836 return;
837 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400838 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
839 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000840 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
841
842 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400843 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
844 // debug command! may change or disapear without notice
845 // set a mask which bursts to dump to disk
846 int mask;
847 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
848 mWriteBurstToDiskMask = mask;
849 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
850 }
dburgessb3a0ca42011-10-12 07:44:40 +0000851 else {
852 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200853 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000854 }
855
Thomas Tsou204a9f12013-10-29 18:34:16 -0400856 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000857}
858
Thomas Tsou204a9f12013-10-29 18:34:16 -0400859bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000860{
dburgessb3a0ca42011-10-12 07:44:40 +0000861 char buffer[gSlotLen+50];
862
863 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400864 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000865
866 if (msgLen!=gSlotLen+1+4+1) {
867 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
868 return false;
869 }
870
871 int timeSlot = (int) buffer[0];
872 uint64_t frameNum = 0;
873 for (int i = 0; i < 4; i++)
874 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000875
dburgessb3a0ca42011-10-12 07:44:40 +0000876 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
877
878 int RSSI = (int) buffer[5];
879 static BitVector newBurst(gSlotLen);
880 BitVector::iterator itr = newBurst.begin();
881 char *bufferItr = buffer+6;
882 while (itr < newBurst.end())
883 *itr++ = *bufferItr++;
884
885 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400886
887 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000888
889 return true;
890
891
892}
dburgessb3a0ca42011-10-12 07:44:40 +0000893
Thomas Tsou204a9f12013-10-29 18:34:16 -0400894void Transceiver::driveReceiveRadio()
895{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400896 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400897 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400898 } else {
899 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
900 writeClockInterface();
901 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400902}
903
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800904void Transceiver::logRxBurst(SoftVector *burst, GSM::Time time, double dbm,
905 double rssi, double noise, double toa)
906{
907 LOG(DEBUG) << std::fixed << std::right
908 << " time: " << time
909 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
910 << "dBFS/" << std::setw(6) << -dbm << "dBm"
911 << " noise: " << std::setw(5) << std::setprecision(1) << noise
912 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
913 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
914 << " bits: " << *burst;
915}
916
Thomas Tsou204a9f12013-10-29 18:34:16 -0400917void Transceiver::driveReceiveFIFO(size_t chan)
918{
dburgessb3a0ca42011-10-12 07:44:40 +0000919 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400920 double RSSI; // in dBFS
921 double dBm; // in dBm
922 double TOA; // in symbols
923 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400924 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000925 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400926 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800927 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000928
Alexander Chemeris2b542102015-06-08 22:46:38 -0400929 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800930 if (!rxBurst)
931 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000932
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800933 /*
934 * EDGE demodulator returns 444 (148 * 3) bits
935 */
936 if (rxBurst->size() == gSlotLen * 3)
937 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000938
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800939 dBm = RSSI + rssiOffset;
940 logRxBurst(rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400941
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800942 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000943
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800944 char burstString[nbits + 10];
945 burstString[0] = burstTime.TN();
946 for (int i = 0; i < 4; i++)
947 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
948 burstString[5] = (int)dBm;
949 burstString[6] = (TOAint >> 8) & 0x0ff;
950 burstString[7] = TOAint & 0x0ff;
951 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000952
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800953 for (unsigned i = 0; i < nbits; i++)
954 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
955
956 burstString[nbits + 9] = '\0';
957 delete rxBurst;
958
959 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000960}
961
Thomas Tsou204a9f12013-10-29 18:34:16 -0400962void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000963{
964
965 /**
966 Features a carefully controlled latency mechanism, to
967 assure that transmit packets arrive at the radio/USRP
968 before they need to be transmitted.
969
970 Deadline clock indicates the burst that needs to be
971 pushed into the FIFO right NOW. If transmit queue does
972 not have a burst, stick in filler data.
973 */
974
975
976 RadioClock *radioClock = (mRadioInterface->getClock());
977
978 if (mOn) {
979 //radioClock->wait(); // wait until clock updates
980 LOG(DEBUG) << "radio clock " << radioClock->get();
981 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
982 // if underrun, then we're not providing bursts to radio/USRP fast
983 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400984 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000985 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000986 // only update latency at the defined frame interval
987 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000988 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
989 LOG(INFO) << "new latency: " << mTransmitLatency;
990 mLatencyUpdateTime = radioClock->get();
991 }
992 }
993 else {
994 // if underrun hasn't occurred in the last sec (216 frames) drop
995 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000996 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000997 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
998 mTransmitLatency.decTN();
999 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1000 mLatencyUpdateTime = radioClock->get();
1001 }
1002 }
1003 }
dburgessb3a0ca42011-10-12 07:44:40 +00001004 }
dburgessb3a0ca42011-10-12 07:44:40 +00001005 // time to push burst to transmit FIFO
1006 pushRadioVector(mTransmitDeadlineClock);
1007 mTransmitDeadlineClock.incTN();
1008 }
dburgessb3a0ca42011-10-12 07:44:40 +00001009 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001010
1011 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001012}
1013
1014
1015
1016void Transceiver::writeClockInterface()
1017{
1018 char command[50];
1019 // FIXME -- This should be adaptive.
1020 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1021
1022 LOG(INFO) << "ClockInterface: sending " << command;
1023
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001024 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001025
1026 mLastClockUpdateTime = mTransmitDeadlineClock;
1027
Thomas Tsou92c16df2013-09-28 18:04:19 -04001028}
dburgessb3a0ca42011-10-12 07:44:40 +00001029
Thomas Tsou204a9f12013-10-29 18:34:16 -04001030void *RxUpperLoopAdapter(TransceiverChannel *chan)
1031{
1032 Transceiver *trx = chan->trx;
1033 size_t num = chan->num;
1034
1035 delete chan;
1036
Thomas Tsou7553aa92013-11-08 12:50:03 -05001037 trx->setPriority(0.42);
1038
Thomas Tsou204a9f12013-10-29 18:34:16 -04001039 while (1) {
1040 trx->driveReceiveFIFO(num);
1041 pthread_testcancel();
1042 }
1043 return NULL;
1044}
1045
1046void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001047{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001048 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001049
dburgessb3a0ca42011-10-12 07:44:40 +00001050 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001051 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001052 pthread_testcancel();
1053 }
1054 return NULL;
1055}
1056
Thomas Tsou204a9f12013-10-29 18:34:16 -04001057void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001058{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001059 transceiver->setPriority(0.44);
1060
Thomas Tsou92c16df2013-09-28 18:04:19 -04001061 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001062 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001063 pthread_testcancel();
1064 }
1065 return NULL;
1066}
1067
Thomas Tsou204a9f12013-10-29 18:34:16 -04001068void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001069{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001070 Transceiver *trx = chan->trx;
1071 size_t num = chan->num;
1072
1073 delete chan;
1074
dburgessb3a0ca42011-10-12 07:44:40 +00001075 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001076 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001077 pthread_testcancel();
1078 }
1079 return NULL;
1080}
1081
Thomas Tsou204a9f12013-10-29 18:34:16 -04001082void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001083{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001084 Transceiver *trx = chan->trx;
1085 size_t num = chan->num;
1086
1087 delete chan;
1088
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001089 trx->setPriority(0.40);
1090
dburgessb3a0ca42011-10-12 07:44:40 +00001091 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001092 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001093 pthread_testcancel();
1094 }
1095 return NULL;
1096}