blob: e37c08e964e8157616f3c974481eb8cd7eb5726e [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
2* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
3*
4* This software is distributed under the terms of the GNU Public License.
5* See the COPYING file in the main directory for details.
6*
7* This use of this software may be subject to additional restrictions.
8* See the LEGAL file in the main directory for details.
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22*/
23
dburgessb3a0ca42011-10-12 07:44:40 +000024#include <stdio.h>
Alexander Chemerise8905a02015-06-03 23:47:56 -040025#include <iomanip> // std::setprecision
Alexander Chemerise692ce92015-06-12 00:15:31 -040026#include <fstream>
dburgessb3a0ca42011-10-12 07:44:40 +000027#include "Transceiver.h"
28#include <Logger.h>
29
ttsou2173abf2012-08-08 00:51:31 +000030#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
dburgessb3a0ca42011-10-12 07:44:40 +000033
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040034using namespace GSM;
35
kurtis.heimerlec842de2012-11-23 08:37:32 +000036#define USB_LATENCY_INTRVL 10,0
ttsou2173abf2012-08-08 00:51:31 +000037
38#if USE_UHD
kurtis.heimerlec842de2012-11-23 08:37:32 +000039# define USB_LATENCY_MIN 6,7
ttsou2173abf2012-08-08 00:51:31 +000040#else
kurtis.heimerlec842de2012-11-23 08:37:32 +000041# define USB_LATENCY_MIN 1,1
ttsou2173abf2012-08-08 00:51:31 +000042#endif
dburgessb3a0ca42011-10-12 07:44:40 +000043
Thomas Tsoufa3a7872013-10-17 21:23:34 -040044/* Number of running values use in noise average */
45#define NOISE_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000046
Tom Tsoua84e1622016-06-29 14:50:25 -070047/*
48 * Burst detection threshold
49 *
50 * Decision threshold value for burst gating on peak-to-average value of
51 * correlated synchronization sequences. Lower values pass more bursts up
52 * to upper layers but will increase the false detection rate.
53 */
54#define BURST_THRESH 4.0
55
Thomas Tsouf0782732013-10-29 15:55:47 -040056TransceiverState::TransceiverState()
Tom Tsoua4d1a412014-11-25 15:46:56 -080057 : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
Thomas Tsouf0782732013-10-29 15:55:47 -040058{
59 for (int i = 0; i < 8; i++) {
60 chanType[i] = Transceiver::NONE;
61 fillerModulus[i] = 26;
62 chanResponse[i] = NULL;
63 DFEForward[i] = NULL;
64 DFEFeedback[i] = NULL;
65
66 for (int n = 0; n < 102; n++)
67 fillerTable[n][i] = NULL;
68 }
69}
70
71TransceiverState::~TransceiverState()
72{
73 for (int i = 0; i < 8; i++) {
74 delete chanResponse[i];
75 delete DFEForward[i];
76 delete DFEFeedback[i];
77
78 for (int n = 0; n < 102; n++)
79 delete fillerTable[n][i];
80 }
81}
82
Alexander Chemeris37c52c72016-03-25 18:28:34 +030083bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc, unsigned rach_delay)
Tom Tsou64ad7122015-05-19 18:26:31 -070084{
Tom Tsou64ad7122015-05-19 18:26:31 -070085 signalVector *burst;
86
87 if ((sps != 1) && (sps != 4))
88 return false;
89
90 for (size_t n = 0; n < 8; n++) {
Tom Tsou64ad7122015-05-19 18:26:31 -070091 for (size_t i = 0; i < 102; i++) {
92 switch (filler) {
93 case Transceiver::FILLER_DUMMY:
Tom Tsou8ee2f382016-03-06 20:57:34 -080094 burst = generateDummyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070095 break;
Tom Tsouaf717b22016-03-06 22:19:15 -080096 case Transceiver::FILLER_NORM_RAND:
Tom Tsou8ee2f382016-03-06 20:57:34 -080097 burst = genRandNormalBurst(rtsc, sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070098 break;
Tom Tsouaf717b22016-03-06 22:19:15 -080099 case Transceiver::FILLER_EDGE_RAND:
100 burst = generateEdgeBurst(rtsc);
101 break;
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300102 case Transceiver::FILLER_ACCESS_RAND:
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300103 burst = genRandAccessBurst(rach_delay, sps, n);
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300104 break;
Tom Tsou64ad7122015-05-19 18:26:31 -0700105 case Transceiver::FILLER_ZERO:
106 default:
Tom Tsou8ee2f382016-03-06 20:57:34 -0800107 burst = generateEmptyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -0700108 }
109
110 scaleVector(*burst, scale);
111 fillerTable[i][n] = burst;
112 }
113
Tom Tsouaf717b22016-03-06 22:19:15 -0800114 if ((filler == Transceiver::FILLER_NORM_RAND) ||
115 (filler == Transceiver::FILLER_EDGE_RAND)) {
Alexander Chemerisf9e78be2017-03-17 15:00:34 -0700116 chanType[n] = TSC;
Tom Tsouaf717b22016-03-06 22:19:15 -0800117 }
Thomas Tsou15d743e2014-01-25 02:34:03 -0500118 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700119
120 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400121}
122
dburgessb3a0ca42011-10-12 07:44:40 +0000123Transceiver::Transceiver(int wBasePort,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400124 const char *wTRXAddress,
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800125 size_t tx_sps, size_t rx_sps, size_t chans,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400126 GSM::Time wTransmitLatency,
127 RadioInterface *wRadioInterface,
128 double wRssiOffset)
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800129 : mBasePort(wBasePort), mAddr(wTRXAddress),
130 mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
131 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Alexander Chemerise8905a02015-06-03 23:47:56 -0400132 rssiOffset(wRssiOffset),
Tom Tsou64464e62016-07-01 03:46:46 -0700133 mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mEdge(false), mOn(false),
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300134 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
135 mWriteBurstToDiskMask(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000136{
dburgessb3a0ca42011-10-12 07:44:40 +0000137 txFullScale = mRadioInterface->fullScaleInputValue();
138 rxFullScale = mRadioInterface->fullScaleOutputValue();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300139
140 for (int i = 0; i < 8; i++) {
141 for (int j = 0; j < 8; j++)
142 mHandover[i][j] = false;
143 }
dburgessb3a0ca42011-10-12 07:44:40 +0000144}
145
146Transceiver::~Transceiver()
147{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800148 stop();
149
dburgessb3a0ca42011-10-12 07:44:40 +0000150 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400151
Thomas Tsou204a9f12013-10-29 18:34:16 -0400152 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800153 mControlServiceLoopThreads[i]->cancel();
154 mControlServiceLoopThreads[i]->join();
155 delete mControlServiceLoopThreads[i];
156
Thomas Tsou204a9f12013-10-29 18:34:16 -0400157 mTxPriorityQueues[i].clear();
158 delete mCtrlSockets[i];
159 delete mDataSockets[i];
160 }
dburgessb3a0ca42011-10-12 07:44:40 +0000161}
Thomas Tsou83e06892013-08-20 16:10:01 -0400162
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800163/*
164 * Initialize transceiver
165 *
166 * Start or restart the control loop. Any further control is handled through the
167 * socket API. Randomize the central radio clock set the downlink burst
168 * counters. Note that the clock will not update until the radio starts, but we
169 * are still expected to report clock indications through control channel
170 * activity.
171 */
Tom Tsou64464e62016-07-01 03:46:46 -0700172bool Transceiver::init(int filler, size_t rtsc, unsigned rach_delay, bool edge)
Thomas Tsou83e06892013-08-20 16:10:01 -0400173{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500174 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400175
Thomas Tsou204a9f12013-10-29 18:34:16 -0400176 if (!mChans) {
177 LOG(ALERT) << "No channels assigned";
178 return false;
179 }
180
Tom Tsou2079a3c2016-03-06 00:58:56 -0800181 if (!sigProcLibSetup()) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400182 LOG(ALERT) << "Failed to initialize signal processing library";
183 return false;
184 }
185
Tom Tsou64464e62016-07-01 03:46:46 -0700186 mEdge = edge;
187
Thomas Tsou204a9f12013-10-29 18:34:16 -0400188 mDataSockets.resize(mChans);
189 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400190 mControlServiceLoopThreads.resize(mChans);
191 mTxPriorityQueueServiceLoopThreads.resize(mChans);
192 mRxServiceLoopThreads.resize(mChans);
193
194 mTxPriorityQueues.resize(mChans);
195 mReceiveFIFO.resize(mChans);
196 mStates.resize(mChans);
197
Thomas Tsouccb73e12014-04-15 17:41:28 -0400198 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700199 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400200 mStates[0].mRetrans = true;
201
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800202 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400203 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500204 c_srcport = mBasePort + 2 * i + 1;
205 c_dstport = mBasePort + 2 * i + 101;
206 d_srcport = mBasePort + 2 * i + 2;
207 d_dstport = mBasePort + 2 * i + 102;
208
209 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
210 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400211 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400212
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800213 /* Randomize the central clock */
214 GSM::Time startTime(random() % gHyperframe, 0);
215 mRadioInterface->getClock()->set(startTime);
216 mTransmitDeadlineClock = startTime;
217 mLastClockUpdateTime = startTime;
218 mLatencyUpdateTime = startTime;
219
220 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400221 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800222 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400223 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800224 mControlServiceLoopThreads[i]->start((void * (*)(void*))
225 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400226
Tom Tsou64ad7122015-05-19 18:26:31 -0700227 if (i && filler == FILLER_DUMMY)
228 filler = FILLER_ZERO;
229
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300230 mStates[i].init(filler, mSPSTx, txFullScale, rtsc, rach_delay);
Thomas Tsou83e06892013-08-20 16:10:01 -0400231 }
232
233 return true;
234}
dburgessb3a0ca42011-10-12 07:44:40 +0000235
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800236/*
237 * Start the transceiver
238 *
239 * Submit command(s) to the radio device to commence streaming samples and
240 * launch threads to handle sample I/O. Re-synchronize the transmit burst
241 * counters to the central radio clock here as well.
242 */
243bool Transceiver::start()
244{
245 ScopedLock lock(mLock);
246
247 if (mOn) {
248 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300249 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800250 }
251
252 LOG(NOTICE) << "Starting the transceiver";
253
254 GSM::Time time = mRadioInterface->getClock()->get();
255 mTransmitDeadlineClock = time;
256 mLastClockUpdateTime = time;
257 mLatencyUpdateTime = time;
258
259 if (!mRadioInterface->start()) {
260 LOG(ALERT) << "Device failed to start";
261 return false;
262 }
263
264 /* Device is running - launch I/O threads */
265 mRxLowerLoopThread = new Thread(32768);
266 mTxLowerLoopThread = new Thread(32768);
267 mTxLowerLoopThread->start((void * (*)(void*))
268 TxLowerLoopAdapter,(void*) this);
269 mRxLowerLoopThread->start((void * (*)(void*))
270 RxLowerLoopAdapter,(void*) this);
271
272 /* Launch uplink and downlink burst processing threads */
273 for (size_t i = 0; i < mChans; i++) {
274 TransceiverChannel *chan = new TransceiverChannel(this, i);
275 mRxServiceLoopThreads[i] = new Thread(32768);
276 mRxServiceLoopThreads[i]->start((void * (*)(void*))
277 RxUpperLoopAdapter, (void*) chan);
278
279 chan = new TransceiverChannel(this, i);
280 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
281 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
282 TxUpperLoopAdapter, (void*) chan);
283 }
284
285 writeClockInterface();
286 mOn = true;
287 return true;
288}
289
290/*
291 * Stop the transceiver
292 *
293 * Perform stopping by disabling receive streaming and issuing cancellation
294 * requests to running threads. Most threads will timeout and terminate once
295 * device is disabled, but the transmit loop may block waiting on the central
296 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
297 * makes it to the thread cancellation point.
298 */
299void Transceiver::stop()
300{
301 ScopedLock lock(mLock);
302
303 if (!mOn)
304 return;
305
306 LOG(NOTICE) << "Stopping the transceiver";
307 mTxLowerLoopThread->cancel();
308 mRxLowerLoopThread->cancel();
309
310 for (size_t i = 0; i < mChans; i++) {
311 mRxServiceLoopThreads[i]->cancel();
312 mTxPriorityQueueServiceLoopThreads[i]->cancel();
313 }
314
315 LOG(INFO) << "Stopping the device";
316 mRadioInterface->stop();
317
318 for (size_t i = 0; i < mChans; i++) {
319 mRxServiceLoopThreads[i]->join();
320 mTxPriorityQueueServiceLoopThreads[i]->join();
321 delete mRxServiceLoopThreads[i];
322 delete mTxPriorityQueueServiceLoopThreads[i];
323
324 mTxPriorityQueues[i].clear();
325 }
326
327 mTxLowerLoopThread->join();
328 mRxLowerLoopThread->join();
329 delete mTxLowerLoopThread;
330 delete mRxLowerLoopThread;
331
332 mOn = false;
333 LOG(NOTICE) << "Transceiver stopped";
334}
335
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500336void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400337 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000338{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500339 signalVector *burst;
340 radioVector *radio_burst;
341
Thomas Tsou204a9f12013-10-29 18:34:16 -0400342 if (chan >= mTxPriorityQueues.size()) {
343 LOG(ALERT) << "Invalid channel " << chan;
344 return;
345 }
346
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500347 if (wTime.TN() > 7) {
348 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
349 return;
350 }
351
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800352 /* Use the number of bits as the EDGE burst indicator */
353 if (bits.size() == EDGE_BURST_NBITS)
354 burst = modulateEdgeBurst(bits, mSPSTx);
355 else
356 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
357
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500358 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000359
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500360 radio_burst = new radioVector(wTime, burst);
361
362 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000363}
364
Thomas Tsou15d743e2014-01-25 02:34:03 -0500365void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
366{
367 int TN, modFN;
368 TransceiverState *state = &mStates[chan];
369
370 TN = burst->getTime().TN();
371 modFN = burst->getTime().FN() % state->fillerModulus[TN];
372
373 delete state->fillerTable[modFN][TN];
374 state->fillerTable[modFN][TN] = burst->getVector();
375 burst->setVector(NULL);
376}
377
dburgessb3a0ca42011-10-12 07:44:40 +0000378void Transceiver::pushRadioVector(GSM::Time &nowTime)
379{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400380 int TN, modFN;
381 radioVector *burst;
382 TransceiverState *state;
383 std::vector<signalVector *> bursts(mChans);
384 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500385 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000386
Thomas Tsou204a9f12013-10-29 18:34:16 -0400387 for (size_t i = 0; i < mChans; i ++) {
388 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000389
Thomas Tsou204a9f12013-10-29 18:34:16 -0400390 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
391 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500392 if (state->mRetrans)
393 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500394 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400395 }
396
397 TN = nowTime.TN();
398 modFN = nowTime.FN() % state->fillerModulus[TN];
399
400 bursts[i] = state->fillerTable[modFN][TN];
401 zeros[i] = state->chanType[TN] == NONE;
402
403 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500404 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500405
406 if (state->mRetrans) {
407 updateFillerTable(i, burst);
408 } else {
409 burst->setVector(NULL);
410 filler[i] = false;
411 }
412
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500413 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400414 }
dburgessb3a0ca42011-10-12 07:44:40 +0000415 }
416
Thomas Tsou204a9f12013-10-29 18:34:16 -0400417 mRadioInterface->driveTransmitRadio(bursts, zeros);
418
Thomas Tsou15d743e2014-01-25 02:34:03 -0500419 for (size_t i = 0; i < mChans; i++) {
420 if (!filler[i])
421 delete bursts[i];
422 }
dburgessb3a0ca42011-10-12 07:44:40 +0000423}
424
Thomas Tsou204a9f12013-10-29 18:34:16 -0400425void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000426{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400427 TransceiverState *state = &mStates[chan];
428
429 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000430 case NONE:
431 case I:
432 case II:
433 case III:
434 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400435 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000436 break;
437 case IV:
438 case VI:
439 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400440 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000441 break;
442 //case V:
443 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400444 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000445 break;
ttsoufc40a842013-06-09 22:38:18 +0000446 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400447 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000448 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000449 default:
450 break;
451 }
452}
453
454
Alexander Chemerisf9e78be2017-03-17 15:00:34 -0700455CorrType Transceiver::expectedCorrType(GSM::Time currTime,
456 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000457{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300458 static int tchh_subslot[26] = { 0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,1 };
459 static int sdcch4_subslot[102] = { 3,3,3,3,0,0,2,2,2,2,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,2,2,2,2,
460 3,3,3,3,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,2,2,2,2 };
461 static int sdcch8_subslot[102] = { 5,5,5,5,6,6,6,6,7,7,7,7,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,0,0,0,0,
462 1,1,1,1,2,2,2,2,3,3,3,3,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,4,4,4,4 };
Thomas Tsou204a9f12013-10-29 18:34:16 -0400463 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000464 unsigned burstTN = currTime.TN();
465 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300466 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000467
Thomas Tsou204a9f12013-10-29 18:34:16 -0400468 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000469 case NONE:
470 return OFF;
471 break;
472 case FILL:
473 return IDLE;
474 break;
475 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300476 // TODO: Are we expecting RACH on an IDLE frame?
477/* if (burstFN % 26 == 25)
478 return IDLE;*/
479 if (mHandover[burstTN][0])
480 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000481 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000482 break;
483 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300484 subch = tchh_subslot[burstFN % 26];
485 if (subch == 1)
486 return IDLE;
487 if (mHandover[burstTN][0])
488 return RACH;
ttsou20642972013-03-27 22:00:25 +0000489 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000490 break;
491 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300492 subch = tchh_subslot[burstFN % 26];
493 if (mHandover[burstTN][subch])
494 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000495 return TSC;
496 break;
497 case IV:
498 case VI:
499 return RACH;
500 break;
501 case V: {
502 int mod51 = burstFN % 51;
503 if ((mod51 <= 36) && (mod51 >= 14))
504 return RACH;
505 else if ((mod51 == 4) || (mod51 == 5))
506 return RACH;
507 else if ((mod51 == 45) || (mod51 == 46))
508 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300509 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
510 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000511 else
512 return TSC;
513 break;
514 }
515 case VII:
516 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
517 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300518 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
519 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000520 else
521 return TSC;
522 break;
ttsoufc40a842013-06-09 22:38:18 +0000523 case XIII: {
524 int mod52 = burstFN % 52;
525 if ((mod52 == 12) || (mod52 == 38))
526 return RACH;
527 else if ((mod52 == 25) || (mod52 == 51))
528 return IDLE;
529 else
530 return TSC;
531 break;
532 }
dburgessb3a0ca42011-10-12 07:44:40 +0000533 case LOOPBACK:
534 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
535 return IDLE;
536 else
537 return TSC;
538 break;
539 default:
540 return OFF;
541 break;
542 }
dburgessb3a0ca42011-10-12 07:44:40 +0000543}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400544
Thomas Tsou30421a72013-11-13 23:14:48 -0500545/*
Tom Tsou46569402016-03-06 01:59:38 -0800546 * Demodulate GMSK by direct rotation and soft slicing.
Thomas Tsou30421a72013-11-13 23:14:48 -0500547 */
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300548SoftVector *Transceiver::demodulate(signalVector &burst, complex amp,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800549 float toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500550{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800551 if (type == EDGE)
552 return demodEdgeBurst(burst, mSPSRx, amp, toa);
553
Alexander Chemeris1c0b8b32017-03-17 16:12:47 -0700554 return demodGmskBurst(burst, mSPSRx, amp, toa);
Thomas Tsou30421a72013-11-13 23:14:48 -0500555}
556
Alexander Chemerise692ce92015-06-12 00:15:31 -0400557void writeToFile(radioVector *radio_burst, size_t chan)
558{
559 GSM::Time time = radio_burst->getTime();
560 std::ostringstream fname;
561 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
562 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
563 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
564 outfile.close();
565}
566
Thomas Tsou30421a72013-11-13 23:14:48 -0500567/*
568 * Pull bursts from the FIFO and handle according to the slot
569 * and burst correlation type. Equalzation is currently disabled.
570 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400571SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400572 double &timingOffset, double &noise,
573 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000574{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800575 int rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500576 complex amp;
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +0300577 float toa, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500578 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500579 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500580 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500581 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400582 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000583
Thomas Tsou30421a72013-11-13 23:14:48 -0500584 /* Blocking FIFO read */
585 radioVector *radio_burst = mReceiveFIFO[chan]->read();
586 if (!radio_burst)
587 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000588
Thomas Tsou30421a72013-11-13 23:14:48 -0500589 /* Set time and determine correlation type */
590 GSM::Time time = radio_burst->getTime();
591 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000592
Tom Tsou64464e62016-07-01 03:46:46 -0700593 /* Enable 8-PSK burst detection if EDGE is enabled */
594 if (mEdge && (type == TSC))
595 type = EDGE;
596
Alexander Chemerise692ce92015-06-12 00:15:31 -0400597 /* Debug: dump bursts to disk */
598 /* bits 0-7 - chan 0 timeslots
599 * bits 8-15 - chan 1 timeslots */
600 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
601 writeToFile(radio_burst, chan);
602
Alexander Chemeris2b542102015-06-08 22:46:38 -0400603 /* No processing if the timeslot is off.
604 * Not even power level or noise calculation. */
605 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500606 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000607 return NULL;
608 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000609
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500610 /* Select the diversity channel with highest energy */
611 for (size_t i = 0; i < radio_burst->chans(); i++) {
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +0300612 float pow = energyDetect(*radio_burst->getVector(i), 20 * mSPSRx);
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500613 if (pow > max) {
614 max = pow;
615 max_i = i;
616 }
617 avg += pow;
618 }
619
620 if (max_i < 0) {
621 LOG(ALERT) << "Received empty burst";
622 delete radio_burst;
623 return NULL;
624 }
625
Thomas Tsou30421a72013-11-13 23:14:48 -0500626 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500627 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500628 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400629
630 wTime = time;
631 RSSI = 20.0 * log10(rxFullScale / avg);
632
633 /* RSSI estimation are valid */
634 isRssiValid = true;
635
636 if (type == IDLE) {
637 /* Update noise levels */
638 state->mNoises.insert(avg);
639 state->mNoiseLev = state->mNoises.avg();
640 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
641
642 delete radio_burst;
643 return NULL;
644 } else {
645 /* Do not update noise levels */
646 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
647 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400648
Thomas Tsou30421a72013-11-13 23:14:48 -0500649 /* Detect normal or RACH bursts */
Alexander Chemeris4e6c9382017-03-17 15:24:18 -0700650 rc = detectAnyBurst(*burst, mTSC, BURST_THRESH, mSPSRx, type, amp, toa,
651 (type==RACH)?mMaxExpectedDelayAB:mMaxExpectedDelayNB);
Thomas Tsouf0782732013-10-29 15:55:47 -0400652
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800653 if (rc > 0) {
654 type = (CorrType) rc;
655 } else if (rc <= 0) {
656 if (rc == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400657 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800658 } else if (rc != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400659 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700660 }
661
Thomas Tsou30421a72013-11-13 23:14:48 -0500662 delete radio_burst;
663 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000664 }
dburgessb3a0ca42011-10-12 07:44:40 +0000665
Tom Tsou4609f322016-07-19 11:28:51 -0700666 timingOffset = toa;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400667
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300668 bits = demodulate(*burst, amp, toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500669
Thomas Tsou30421a72013-11-13 23:14:48 -0500670 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500671 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000672}
673
dburgessb3a0ca42011-10-12 07:44:40 +0000674void Transceiver::reset()
675{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400676 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
677 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000678}
679
680
Thomas Tsou204a9f12013-10-29 18:34:16 -0400681void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000682{
dburgessb3a0ca42011-10-12 07:44:40 +0000683 int MAX_PACKET_LENGTH = 100;
684
685 // check control socket
686 char buffer[MAX_PACKET_LENGTH];
687 int msgLen = -1;
688 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400689
Tom Tsou2c650a62016-04-28 21:55:17 -0700690 msgLen = mCtrlSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000691
692 if (msgLen < 1) {
693 return;
694 }
695
696 char cmdcheck[4];
697 char command[MAX_PACKET_LENGTH];
698 char response[MAX_PACKET_LENGTH];
699
700 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400701
702 if (!chan)
703 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000704
705 if (strcmp(cmdcheck,"CMD")!=0) {
706 LOG(WARNING) << "bogus message on control interface";
707 return;
708 }
709 LOG(INFO) << "command is " << buffer;
710
711 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800712 stop();
713 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000714 }
715 else if (strcmp(command,"POWERON")==0) {
Tom Tsou365bc382016-10-19 15:26:04 -0700716 if (!start()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000717 sprintf(response,"RSP POWERON 1");
Tom Tsou365bc382016-10-19 15:26:04 -0700718 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000719 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300720 for (int i = 0; i < 8; i++) {
721 for (int j = 0; j < 8; j++)
722 mHandover[i][j] = false;
723 }
Tom Tsou365bc382016-10-19 15:26:04 -0700724 }
Alexander Chemeris5a068062015-06-20 01:38:47 +0300725 }
726 else if (strcmp(command,"HANDOVER")==0){
727 int ts=0,ss=0;
728 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
729 mHandover[ts][ss] = true;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300730 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
731 }
732 else if (strcmp(command,"NOHANDOVER")==0){
733 int ts=0,ss=0;
734 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
735 mHandover[ts][ss] = false;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300736 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000737 }
738 else if (strcmp(command,"SETMAXDLY")==0) {
739 //set expected maximum time-of-arrival
740 int maxDelay;
741 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300742 mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
dburgessb3a0ca42011-10-12 07:44:40 +0000743 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
744 }
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300745 else if (strcmp(command,"SETMAXDLYNB")==0) {
746 //set expected maximum time-of-arrival
747 int maxDelay;
748 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
749 mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
750 sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
751 }
dburgessb3a0ca42011-10-12 07:44:40 +0000752 else if (strcmp(command,"SETRXGAIN")==0) {
753 //set expected maximum time-of-arrival
754 int newGain;
755 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400756 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000757 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
758 }
759 else if (strcmp(command,"NOISELEV")==0) {
760 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500761 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000762 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500763 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000764 }
765 else {
766 sprintf(response,"RSP NOISELEV 1 0");
767 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500768 }
769 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800770 int power;
771 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
772 power = mRadioInterface->setPowerAttenuation(power, chan);
773 mStates[chan].mPower = power;
774 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000775 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500776 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800777 int power, step;
778 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
779 power = mStates[chan].mPower + step;
780 power = mRadioInterface->setPowerAttenuation(power, chan);
781 mStates[chan].mPower = power;
782 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000783 }
dburgessb3a0ca42011-10-12 07:44:40 +0000784 else if (strcmp(command,"RXTUNE")==0) {
785 // tune receiver
786 int freqKhz;
787 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500788 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400789 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000790 LOG(ALERT) << "RX failed to tune";
791 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
792 }
793 else
794 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
795 }
796 else if (strcmp(command,"TXTUNE")==0) {
797 // tune txmtr
798 int freqKhz;
799 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500800 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400801 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000802 LOG(ALERT) << "TX failed to tune";
803 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
804 }
805 else
806 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
807 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500808 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000809 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500810 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500811 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Tom Tsouc8c4eac2016-06-28 17:00:54 -0700812 if ((TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500813 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000814 else {
Tom Tsouc37594f2016-07-08 14:39:42 -0700815 LOG(NOTICE) << "Changing TSC from " << mTSC << " to " << TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000816 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400817 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000818 }
819 }
820 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700821 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000822 int corrCode;
823 int timeslot;
824 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
825 if ((timeslot < 0) || (timeslot > 7)) {
826 LOG(WARNING) << "bogus message on control interface";
827 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
828 return;
829 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400830 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
831 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000832 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
833
834 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400835 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
836 // debug command! may change or disapear without notice
837 // set a mask which bursts to dump to disk
838 int mask;
839 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
840 mWriteBurstToDiskMask = mask;
841 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
842 }
dburgessb3a0ca42011-10-12 07:44:40 +0000843 else {
844 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200845 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000846 }
847
Thomas Tsou204a9f12013-10-29 18:34:16 -0400848 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000849}
850
Thomas Tsou204a9f12013-10-29 18:34:16 -0400851bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000852{
Tom Tsoue8871082016-07-01 02:46:04 -0700853 int burstLen;
854 char buffer[EDGE_BURST_NBITS + 50];
dburgessb3a0ca42011-10-12 07:44:40 +0000855
856 // check data socket
Tom Tsou2c650a62016-04-28 21:55:17 -0700857 size_t msgLen = mDataSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000858
Tom Tsoue8871082016-07-01 02:46:04 -0700859 if (msgLen == gSlotLen + 1 + 4 + 1) {
860 burstLen = gSlotLen;
861 } else if (msgLen == EDGE_BURST_NBITS + 1 + 4 + 1) {
862 if (mSPSTx != 4)
863 return false;
864
865 burstLen = EDGE_BURST_NBITS;
866 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000867 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];
Tom Tsou7c741ec2016-07-19 11:20:59 -0700879 BitVector newBurst(burstLen);
dburgessb3a0ca42011-10-12 07:44:40 +0000880 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
Alexander Chemeris58e95912016-03-25 18:20:28 +0300904void Transceiver::logRxBurst(size_t chan, SoftVector *burst, GSM::Time time, double dbm,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800905 double rssi, double noise, double toa)
906{
907 LOG(DEBUG) << std::fixed << std::right
Alexander Chemeris58e95912016-03-25 18:20:28 +0300908 << " chan: " << chan
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800909 << " time: " << time
910 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
911 << "dBFS/" << std::setw(6) << -dbm << "dBm"
912 << " noise: " << std::setw(5) << std::setprecision(1) << noise
913 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
914 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
915 << " bits: " << *burst;
916}
917
Thomas Tsou204a9f12013-10-29 18:34:16 -0400918void Transceiver::driveReceiveFIFO(size_t chan)
919{
dburgessb3a0ca42011-10-12 07:44:40 +0000920 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400921 double RSSI; // in dBFS
922 double dBm; // in dBm
923 double TOA; // in symbols
924 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400925 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000926 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400927 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800928 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000929
Alexander Chemeris2b542102015-06-08 22:46:38 -0400930 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800931 if (!rxBurst)
932 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000933
Alexander Chemerisb61c6102017-03-17 18:22:19 -0700934 // Convert -1..+1 soft bits to 0..1 soft bits
935 vectorSlicer(rxBurst);
936
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800937 /*
938 * EDGE demodulator returns 444 (148 * 3) bits
939 */
940 if (rxBurst->size() == gSlotLen * 3)
941 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000942
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800943 dBm = RSSI + rssiOffset;
Alexander Chemeris58e95912016-03-25 18:20:28 +0300944 logRxBurst(chan, rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400945
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800946 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000947
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800948 char burstString[nbits + 10];
949 burstString[0] = burstTime.TN();
950 for (int i = 0; i < 4; i++)
951 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
952 burstString[5] = (int)dBm;
953 burstString[6] = (TOAint >> 8) & 0x0ff;
954 burstString[7] = TOAint & 0x0ff;
955 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000956
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800957 for (unsigned i = 0; i < nbits; i++)
958 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
959
960 burstString[nbits + 9] = '\0';
961 delete rxBurst;
962
963 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000964}
965
Thomas Tsou204a9f12013-10-29 18:34:16 -0400966void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000967{
968
969 /**
970 Features a carefully controlled latency mechanism, to
971 assure that transmit packets arrive at the radio/USRP
972 before they need to be transmitted.
973
974 Deadline clock indicates the burst that needs to be
975 pushed into the FIFO right NOW. If transmit queue does
976 not have a burst, stick in filler data.
977 */
978
979
980 RadioClock *radioClock = (mRadioInterface->getClock());
981
982 if (mOn) {
983 //radioClock->wait(); // wait until clock updates
984 LOG(DEBUG) << "radio clock " << radioClock->get();
985 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
986 // if underrun, then we're not providing bursts to radio/USRP fast
987 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400988 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000989 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000990 // only update latency at the defined frame interval
991 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000992 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
993 LOG(INFO) << "new latency: " << mTransmitLatency;
994 mLatencyUpdateTime = radioClock->get();
995 }
996 }
997 else {
998 // if underrun hasn't occurred in the last sec (216 frames) drop
999 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +00001000 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001001 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1002 mTransmitLatency.decTN();
1003 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1004 mLatencyUpdateTime = radioClock->get();
1005 }
1006 }
1007 }
dburgessb3a0ca42011-10-12 07:44:40 +00001008 }
dburgessb3a0ca42011-10-12 07:44:40 +00001009 // time to push burst to transmit FIFO
1010 pushRadioVector(mTransmitDeadlineClock);
1011 mTransmitDeadlineClock.incTN();
1012 }
dburgessb3a0ca42011-10-12 07:44:40 +00001013 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001014
1015 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001016}
1017
1018
1019
1020void Transceiver::writeClockInterface()
1021{
1022 char command[50];
1023 // FIXME -- This should be adaptive.
1024 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1025
1026 LOG(INFO) << "ClockInterface: sending " << command;
1027
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001028 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001029
1030 mLastClockUpdateTime = mTransmitDeadlineClock;
1031
Thomas Tsou92c16df2013-09-28 18:04:19 -04001032}
dburgessb3a0ca42011-10-12 07:44:40 +00001033
Thomas Tsou204a9f12013-10-29 18:34:16 -04001034void *RxUpperLoopAdapter(TransceiverChannel *chan)
1035{
1036 Transceiver *trx = chan->trx;
1037 size_t num = chan->num;
1038
1039 delete chan;
1040
Thomas Tsou7553aa92013-11-08 12:50:03 -05001041 trx->setPriority(0.42);
1042
Thomas Tsou204a9f12013-10-29 18:34:16 -04001043 while (1) {
1044 trx->driveReceiveFIFO(num);
1045 pthread_testcancel();
1046 }
1047 return NULL;
1048}
1049
1050void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001051{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001052 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001053
dburgessb3a0ca42011-10-12 07:44:40 +00001054 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001055 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001056 pthread_testcancel();
1057 }
1058 return NULL;
1059}
1060
Thomas Tsou204a9f12013-10-29 18:34:16 -04001061void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001062{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001063 transceiver->setPriority(0.44);
1064
Thomas Tsou92c16df2013-09-28 18:04:19 -04001065 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001066 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001067 pthread_testcancel();
1068 }
1069 return NULL;
1070}
1071
Thomas Tsou204a9f12013-10-29 18:34:16 -04001072void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001073{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001074 Transceiver *trx = chan->trx;
1075 size_t num = chan->num;
1076
1077 delete chan;
1078
dburgessb3a0ca42011-10-12 07:44:40 +00001079 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001080 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001081 pthread_testcancel();
1082 }
1083 return NULL;
1084}
1085
Thomas Tsou204a9f12013-10-29 18:34:16 -04001086void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001087{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001088 Transceiver *trx = chan->trx;
1089 size_t num = chan->num;
1090
1091 delete chan;
1092
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001093 trx->setPriority(0.40);
1094
dburgessb3a0ca42011-10-12 07:44:40 +00001095 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001096 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001097 pthread_testcancel();
1098 }
1099 return NULL;
1100}