blob: 859a1de7c7337a22a5b98a7fd7dd29f315d440d4 [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
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010074bool TransceiverState::init(FillerType filler, size_t sps, float scale, size_t rtsc, unsigned rach_delay)
Tom Tsou64ad7122015-05-19 18:26:31 -070075{
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) {
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010084 case FILLER_DUMMY:
Tom Tsou8ee2f382016-03-06 20:57:34 -080085 burst = generateDummyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070086 break;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010087 case 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;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010090 case FILLER_EDGE_RAND:
Tom Tsouaf717b22016-03-06 22:19:15 -080091 burst = generateEdgeBurst(rtsc);
92 break;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010093 case FILLER_ACCESS_RAND:
Alexander Chemeris37c52c72016-03-25 18:28:34 +030094 burst = genRandAccessBurst(rach_delay, sps, n);
Alexander Chemeris5efe0502016-03-23 17:06:32 +030095 break;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010096 case FILLER_ZERO:
Tom Tsou64ad7122015-05-19 18:26:31 -070097 default:
Tom Tsou8ee2f382016-03-06 20:57:34 -080098 burst = generateEmptyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070099 }
100
101 scaleVector(*burst, scale);
102 fillerTable[i][n] = burst;
103 }
104
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +0100105 if ((filler == FILLER_NORM_RAND) ||
106 (filler == FILLER_EDGE_RAND)) {
Alexander Chemerisf9e78be2017-03-17 15:00:34 -0700107 chanType[n] = TSC;
Tom Tsouaf717b22016-03-06 22:19:15 -0800108 }
Thomas Tsou15d743e2014-01-25 02:34:03 -0500109 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700110
111 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400112}
113
dburgessb3a0ca42011-10-12 07:44:40 +0000114Transceiver::Transceiver(int wBasePort,
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200115 const char *TRXAddress,
116 const char *GSMcoreAddress,
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800117 size_t tx_sps, size_t rx_sps, size_t chans,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400118 GSM::Time wTransmitLatency,
119 RadioInterface *wRadioInterface,
120 double wRssiOffset)
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200121 : mBasePort(wBasePort), mLocalAddr(TRXAddress), mRemoteAddr(GSMcoreAddress),
122 mClockSocket(TRXAddress, wBasePort, GSMcoreAddress, wBasePort + 100),
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800123 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Alexander Chemerise8905a02015-06-03 23:47:56 -0400124 rssiOffset(wRssiOffset),
Pau Espin Pedrol934da482017-07-04 16:25:20 +0200125 mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mEdge(false), mOn(false), mForceClockInterface(false),
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300126 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
127 mWriteBurstToDiskMask(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000128{
dburgessb3a0ca42011-10-12 07:44:40 +0000129 txFullScale = mRadioInterface->fullScaleInputValue();
130 rxFullScale = mRadioInterface->fullScaleOutputValue();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300131
132 for (int i = 0; i < 8; i++) {
133 for (int j = 0; j < 8; j++)
134 mHandover[i][j] = false;
135 }
dburgessb3a0ca42011-10-12 07:44:40 +0000136}
137
138Transceiver::~Transceiver()
139{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800140 stop();
141
dburgessb3a0ca42011-10-12 07:44:40 +0000142 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400143
Thomas Tsou204a9f12013-10-29 18:34:16 -0400144 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800145 mControlServiceLoopThreads[i]->cancel();
146 mControlServiceLoopThreads[i]->join();
147 delete mControlServiceLoopThreads[i];
148
Thomas Tsou204a9f12013-10-29 18:34:16 -0400149 mTxPriorityQueues[i].clear();
150 delete mCtrlSockets[i];
151 delete mDataSockets[i];
152 }
dburgessb3a0ca42011-10-12 07:44:40 +0000153}
Thomas Tsou83e06892013-08-20 16:10:01 -0400154
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800155/*
156 * Initialize transceiver
157 *
158 * Start or restart the control loop. Any further control is handled through the
159 * socket API. Randomize the central radio clock set the downlink burst
160 * counters. Note that the clock will not update until the radio starts, but we
161 * are still expected to report clock indications through control channel
162 * activity.
163 */
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +0100164bool Transceiver::init(FillerType filler, size_t rtsc, unsigned rach_delay, bool edge)
Thomas Tsou83e06892013-08-20 16:10:01 -0400165{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500166 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400167
Thomas Tsou204a9f12013-10-29 18:34:16 -0400168 if (!mChans) {
169 LOG(ALERT) << "No channels assigned";
170 return false;
171 }
172
Tom Tsou2079a3c2016-03-06 00:58:56 -0800173 if (!sigProcLibSetup()) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400174 LOG(ALERT) << "Failed to initialize signal processing library";
175 return false;
176 }
177
Tom Tsou64464e62016-07-01 03:46:46 -0700178 mEdge = edge;
179
Thomas Tsou204a9f12013-10-29 18:34:16 -0400180 mDataSockets.resize(mChans);
181 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400182 mControlServiceLoopThreads.resize(mChans);
183 mTxPriorityQueueServiceLoopThreads.resize(mChans);
184 mRxServiceLoopThreads.resize(mChans);
185
186 mTxPriorityQueues.resize(mChans);
187 mReceiveFIFO.resize(mChans);
188 mStates.resize(mChans);
189
Thomas Tsouccb73e12014-04-15 17:41:28 -0400190 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700191 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400192 mStates[0].mRetrans = true;
193
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800194 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400195 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500196 c_srcport = mBasePort + 2 * i + 1;
197 c_dstport = mBasePort + 2 * i + 101;
198 d_srcport = mBasePort + 2 * i + 2;
199 d_dstport = mBasePort + 2 * i + 102;
200
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200201 mCtrlSockets[i] = new UDPSocket(mLocalAddr.c_str(), c_srcport, mRemoteAddr.c_str(), c_dstport);
202 mDataSockets[i] = new UDPSocket(mLocalAddr.c_str(), d_srcport, mRemoteAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400203 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400204
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800205 /* Randomize the central clock */
206 GSM::Time startTime(random() % gHyperframe, 0);
207 mRadioInterface->getClock()->set(startTime);
208 mTransmitDeadlineClock = startTime;
209 mLastClockUpdateTime = startTime;
210 mLatencyUpdateTime = startTime;
211
212 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400213 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800214 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400215 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800216 mControlServiceLoopThreads[i]->start((void * (*)(void*))
217 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400218
Tom Tsou64ad7122015-05-19 18:26:31 -0700219 if (i && filler == FILLER_DUMMY)
220 filler = FILLER_ZERO;
221
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300222 mStates[i].init(filler, mSPSTx, txFullScale, rtsc, rach_delay);
Thomas Tsou83e06892013-08-20 16:10:01 -0400223 }
224
225 return true;
226}
dburgessb3a0ca42011-10-12 07:44:40 +0000227
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800228/*
229 * Start the transceiver
230 *
231 * Submit command(s) to the radio device to commence streaming samples and
232 * launch threads to handle sample I/O. Re-synchronize the transmit burst
233 * counters to the central radio clock here as well.
234 */
235bool Transceiver::start()
236{
237 ScopedLock lock(mLock);
238
239 if (mOn) {
240 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300241 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800242 }
243
244 LOG(NOTICE) << "Starting the transceiver";
245
246 GSM::Time time = mRadioInterface->getClock()->get();
247 mTransmitDeadlineClock = time;
248 mLastClockUpdateTime = time;
249 mLatencyUpdateTime = time;
250
251 if (!mRadioInterface->start()) {
252 LOG(ALERT) << "Device failed to start";
253 return false;
254 }
255
256 /* Device is running - launch I/O threads */
257 mRxLowerLoopThread = new Thread(32768);
258 mTxLowerLoopThread = new Thread(32768);
259 mTxLowerLoopThread->start((void * (*)(void*))
260 TxLowerLoopAdapter,(void*) this);
261 mRxLowerLoopThread->start((void * (*)(void*))
262 RxLowerLoopAdapter,(void*) this);
263
264 /* Launch uplink and downlink burst processing threads */
265 for (size_t i = 0; i < mChans; i++) {
266 TransceiverChannel *chan = new TransceiverChannel(this, i);
267 mRxServiceLoopThreads[i] = new Thread(32768);
268 mRxServiceLoopThreads[i]->start((void * (*)(void*))
269 RxUpperLoopAdapter, (void*) chan);
270
271 chan = new TransceiverChannel(this, i);
272 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
273 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
274 TxUpperLoopAdapter, (void*) chan);
275 }
276
Pau Espin Pedrol934da482017-07-04 16:25:20 +0200277 mForceClockInterface = true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800278 mOn = true;
279 return true;
280}
281
282/*
283 * Stop the transceiver
284 *
285 * Perform stopping by disabling receive streaming and issuing cancellation
286 * requests to running threads. Most threads will timeout and terminate once
287 * device is disabled, but the transmit loop may block waiting on the central
288 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
289 * makes it to the thread cancellation point.
290 */
291void Transceiver::stop()
292{
293 ScopedLock lock(mLock);
294
295 if (!mOn)
296 return;
297
298 LOG(NOTICE) << "Stopping the transceiver";
299 mTxLowerLoopThread->cancel();
300 mRxLowerLoopThread->cancel();
Tom Tsoud67bd602017-06-15 15:35:02 -0700301 mTxLowerLoopThread->join();
302 mRxLowerLoopThread->join();
303 delete mTxLowerLoopThread;
304 delete mRxLowerLoopThread;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800305
306 for (size_t i = 0; i < mChans; i++) {
307 mRxServiceLoopThreads[i]->cancel();
308 mTxPriorityQueueServiceLoopThreads[i]->cancel();
309 }
310
311 LOG(INFO) << "Stopping the device";
312 mRadioInterface->stop();
313
314 for (size_t i = 0; i < mChans; i++) {
315 mRxServiceLoopThreads[i]->join();
316 mTxPriorityQueueServiceLoopThreads[i]->join();
317 delete mRxServiceLoopThreads[i];
318 delete mTxPriorityQueueServiceLoopThreads[i];
319
320 mTxPriorityQueues[i].clear();
321 }
322
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800323 mOn = false;
324 LOG(NOTICE) << "Transceiver stopped";
325}
326
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500327void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400328 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000329{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500330 signalVector *burst;
331 radioVector *radio_burst;
332
Thomas Tsou204a9f12013-10-29 18:34:16 -0400333 if (chan >= mTxPriorityQueues.size()) {
334 LOG(ALERT) << "Invalid channel " << chan;
335 return;
336 }
337
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500338 if (wTime.TN() > 7) {
339 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
340 return;
341 }
342
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800343 /* Use the number of bits as the EDGE burst indicator */
344 if (bits.size() == EDGE_BURST_NBITS)
345 burst = modulateEdgeBurst(bits, mSPSTx);
346 else
347 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
348
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500349 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000350
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500351 radio_burst = new radioVector(wTime, burst);
352
353 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000354}
355
Thomas Tsou15d743e2014-01-25 02:34:03 -0500356void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
357{
358 int TN, modFN;
359 TransceiverState *state = &mStates[chan];
360
361 TN = burst->getTime().TN();
362 modFN = burst->getTime().FN() % state->fillerModulus[TN];
363
364 delete state->fillerTable[modFN][TN];
365 state->fillerTable[modFN][TN] = burst->getVector();
366 burst->setVector(NULL);
367}
368
dburgessb3a0ca42011-10-12 07:44:40 +0000369void Transceiver::pushRadioVector(GSM::Time &nowTime)
370{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400371 int TN, modFN;
372 radioVector *burst;
373 TransceiverState *state;
374 std::vector<signalVector *> bursts(mChans);
375 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500376 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000377
Thomas Tsou204a9f12013-10-29 18:34:16 -0400378 for (size_t i = 0; i < mChans; i ++) {
379 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000380
Thomas Tsou204a9f12013-10-29 18:34:16 -0400381 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
382 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500383 if (state->mRetrans)
384 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500385 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400386 }
387
388 TN = nowTime.TN();
389 modFN = nowTime.FN() % state->fillerModulus[TN];
390
391 bursts[i] = state->fillerTable[modFN][TN];
392 zeros[i] = state->chanType[TN] == NONE;
393
394 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500395 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500396
397 if (state->mRetrans) {
398 updateFillerTable(i, burst);
399 } else {
400 burst->setVector(NULL);
401 filler[i] = false;
402 }
403
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500404 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400405 }
dburgessb3a0ca42011-10-12 07:44:40 +0000406 }
407
Thomas Tsou204a9f12013-10-29 18:34:16 -0400408 mRadioInterface->driveTransmitRadio(bursts, zeros);
409
Thomas Tsou15d743e2014-01-25 02:34:03 -0500410 for (size_t i = 0; i < mChans; i++) {
411 if (!filler[i])
412 delete bursts[i];
413 }
dburgessb3a0ca42011-10-12 07:44:40 +0000414}
415
Thomas Tsou204a9f12013-10-29 18:34:16 -0400416void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000417{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400418 TransceiverState *state = &mStates[chan];
419
420 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000421 case NONE:
422 case I:
423 case II:
424 case III:
425 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400426 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000427 break;
428 case IV:
429 case VI:
430 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400431 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000432 break;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200433 //case V:
dburgessb3a0ca42011-10-12 07:44:40 +0000434 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400435 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000436 break;
ttsoufc40a842013-06-09 22:38:18 +0000437 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400438 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000439 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000440 default:
441 break;
442 }
443}
444
445
Alexander Chemerisf9e78be2017-03-17 15:00:34 -0700446CorrType Transceiver::expectedCorrType(GSM::Time currTime,
447 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000448{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300449 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 };
450 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,
451 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 };
452 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,
453 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 -0400454 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000455 unsigned burstTN = currTime.TN();
456 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300457 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000458
Thomas Tsou204a9f12013-10-29 18:34:16 -0400459 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000460 case NONE:
461 return OFF;
462 break;
463 case FILL:
464 return IDLE;
465 break;
466 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300467 // TODO: Are we expecting RACH on an IDLE frame?
468/* if (burstFN % 26 == 25)
469 return IDLE;*/
470 if (mHandover[burstTN][0])
471 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000472 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000473 break;
474 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300475 subch = tchh_subslot[burstFN % 26];
476 if (subch == 1)
477 return IDLE;
478 if (mHandover[burstTN][0])
479 return RACH;
ttsou20642972013-03-27 22:00:25 +0000480 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000481 break;
482 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300483 subch = tchh_subslot[burstFN % 26];
484 if (mHandover[burstTN][subch])
485 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000486 return TSC;
487 break;
488 case IV:
489 case VI:
490 return RACH;
491 break;
492 case V: {
493 int mod51 = burstFN % 51;
494 if ((mod51 <= 36) && (mod51 >= 14))
495 return RACH;
496 else if ((mod51 == 4) || (mod51 == 5))
497 return RACH;
498 else if ((mod51 == 45) || (mod51 == 46))
499 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300500 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
501 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000502 else
503 return TSC;
504 break;
505 }
506 case VII:
507 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
508 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300509 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
510 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000511 else
512 return TSC;
513 break;
ttsoufc40a842013-06-09 22:38:18 +0000514 case XIII: {
515 int mod52 = burstFN % 52;
516 if ((mod52 == 12) || (mod52 == 38))
517 return RACH;
518 else if ((mod52 == 25) || (mod52 == 51))
519 return IDLE;
520 else
521 return TSC;
522 break;
523 }
dburgessb3a0ca42011-10-12 07:44:40 +0000524 case LOOPBACK:
525 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
526 return IDLE;
527 else
528 return TSC;
529 break;
530 default:
531 return OFF;
532 break;
533 }
dburgessb3a0ca42011-10-12 07:44:40 +0000534}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400535
Alexander Chemerise692ce92015-06-12 00:15:31 -0400536void writeToFile(radioVector *radio_burst, size_t chan)
537{
538 GSM::Time time = radio_burst->getTime();
539 std::ostringstream fname;
540 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
541 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
542 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
543 outfile.close();
544}
545
Thomas Tsou30421a72013-11-13 23:14:48 -0500546/*
547 * Pull bursts from the FIFO and handle according to the slot
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200548 * and burst correlation type. Equalzation is currently disabled.
Thomas Tsou30421a72013-11-13 23:14:48 -0500549 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400550SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400551 double &timingOffset, double &noise,
552 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000553{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800554 int rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500555 complex amp;
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +0300556 float toa, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500557 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500558 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500559 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500560 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400561 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000562
Thomas Tsou30421a72013-11-13 23:14:48 -0500563 /* Blocking FIFO read */
564 radioVector *radio_burst = mReceiveFIFO[chan]->read();
565 if (!radio_burst)
566 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000567
Thomas Tsou30421a72013-11-13 23:14:48 -0500568 /* Set time and determine correlation type */
569 GSM::Time time = radio_burst->getTime();
570 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000571
Tom Tsou64464e62016-07-01 03:46:46 -0700572 /* Enable 8-PSK burst detection if EDGE is enabled */
573 if (mEdge && (type == TSC))
574 type = EDGE;
575
Alexander Chemerise692ce92015-06-12 00:15:31 -0400576 /* Debug: dump bursts to disk */
577 /* bits 0-7 - chan 0 timeslots
578 * bits 8-15 - chan 1 timeslots */
579 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
580 writeToFile(radio_burst, chan);
581
Alexander Chemeris2b542102015-06-08 22:46:38 -0400582 /* No processing if the timeslot is off.
583 * Not even power level or noise calculation. */
584 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500585 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000586 return NULL;
587 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000588
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500589 /* Select the diversity channel with highest energy */
590 for (size_t i = 0; i < radio_burst->chans(); i++) {
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +0300591 float pow = energyDetect(*radio_burst->getVector(i), 20 * mSPSRx);
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500592 if (pow > max) {
593 max = pow;
594 max_i = i;
595 }
596 avg += pow;
597 }
598
599 if (max_i < 0) {
600 LOG(ALERT) << "Received empty burst";
601 delete radio_burst;
602 return NULL;
603 }
604
Thomas Tsou30421a72013-11-13 23:14:48 -0500605 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500606 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500607 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400608
609 wTime = time;
610 RSSI = 20.0 * log10(rxFullScale / avg);
611
612 /* RSSI estimation are valid */
613 isRssiValid = true;
614
615 if (type == IDLE) {
616 /* Update noise levels */
617 state->mNoises.insert(avg);
618 state->mNoiseLev = state->mNoises.avg();
619 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
620
621 delete radio_burst;
622 return NULL;
623 } else {
624 /* Do not update noise levels */
625 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
626 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400627
Thomas Tsou30421a72013-11-13 23:14:48 -0500628 /* Detect normal or RACH bursts */
Alexander Chemeris4e6c9382017-03-17 15:24:18 -0700629 rc = detectAnyBurst(*burst, mTSC, BURST_THRESH, mSPSRx, type, amp, toa,
630 (type==RACH)?mMaxExpectedDelayAB:mMaxExpectedDelayNB);
Thomas Tsouf0782732013-10-29 15:55:47 -0400631
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800632 if (rc > 0) {
633 type = (CorrType) rc;
634 } else if (rc <= 0) {
635 if (rc == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400636 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800637 } else if (rc != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400638 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700639 }
640
Thomas Tsou30421a72013-11-13 23:14:48 -0500641 delete radio_burst;
642 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000643 }
dburgessb3a0ca42011-10-12 07:44:40 +0000644
Tom Tsou4609f322016-07-19 11:28:51 -0700645 timingOffset = toa;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400646
Alexander Chemeris6e1dffd2017-03-17 16:13:51 -0700647 bits = demodAnyBurst(*burst, mSPSRx, amp, toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500648
Thomas Tsou30421a72013-11-13 23:14:48 -0500649 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500650 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000651}
652
dburgessb3a0ca42011-10-12 07:44:40 +0000653void Transceiver::reset()
654{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400655 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
656 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000657}
658
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200659
Vadim Yanitskiybd0efb02018-03-09 02:45:07 +0700660#define MAX_PACKET_LENGTH 100
661
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700662/**
663 * Matches a buffer with a command.
664 * @param buf a buffer to look command in
665 * @param cmd a command to look in buffer
666 * @param params pointer to arguments, or NULL
667 * @return true if command matches, otherwise false
668 */
669static bool match_cmd(char *buf,
670 const char *cmd, char **params)
671{
672 size_t cmd_len = strlen(cmd);
673
674 /* Check a command itself */
675 if (strncmp(buf, cmd, cmd_len))
676 return false;
677
678 /* A command has arguments */
679 if (params != NULL) {
680 /* Make sure there is a space */
681 if (buf[cmd_len] != ' ')
682 return false;
683
684 /* Update external pointer */
685 *params = buf + cmd_len + 1;
686 }
687
688 return true;
689}
690
Thomas Tsou204a9f12013-10-29 18:34:16 -0400691void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000692{
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700693 char buffer[MAX_PACKET_LENGTH + 1];
694 char response[MAX_PACKET_LENGTH + 1];
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700695 char *command, *params;
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700696 int msgLen;
Thomas Tsoud647ec52013-10-29 15:17:34 -0400697
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700698 /* Attempt to read from control socket */
699 msgLen = mCtrlSockets[chan]->read(buffer, MAX_PACKET_LENGTH);
700 if (msgLen < 1)
dburgessb3a0ca42011-10-12 07:44:40 +0000701 return;
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700702
703 /* Zero-terminate received string */
704 buffer[msgLen] = '\0';
dburgessb3a0ca42011-10-12 07:44:40 +0000705
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700706 /* Verify a command signature */
707 if (strncmp(buffer, "CMD ", 4)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000708 LOG(WARNING) << "bogus message on control interface";
709 return;
710 }
dburgessb3a0ca42011-10-12 07:44:40 +0000711
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700712 /* Set command pointer */
713 command = buffer + 4;
714 LOG(INFO) << "command is " << command;
715
716 if (match_cmd(command, "POWEROFF", NULL)) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800717 stop();
718 sprintf(response,"RSP POWEROFF 0");
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700719 } else if (match_cmd(command, "POWERON", NULL)) {
Tom Tsou365bc382016-10-19 15:26:04 -0700720 if (!start()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000721 sprintf(response,"RSP POWERON 1");
Tom Tsou365bc382016-10-19 15:26:04 -0700722 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000723 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300724 for (int i = 0; i < 8; i++) {
725 for (int j = 0; j < 8; j++)
726 mHandover[i][j] = false;
727 }
Tom Tsou365bc382016-10-19 15:26:04 -0700728 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700729 } else if (match_cmd(command, "HANDOVER", &params)) {
Alexander Chemeris5a068062015-06-20 01:38:47 +0300730 int ts=0,ss=0;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700731 sscanf(params, "%d %d", &ts, &ss);
Alexander Chemeris5a068062015-06-20 01:38:47 +0300732 mHandover[ts][ss] = true;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300733 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700734 } else if (match_cmd(command, "NOHANDOVER", &params)) {
Alexander Chemeris5a068062015-06-20 01:38:47 +0300735 int ts=0,ss=0;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700736 sscanf(params, "%d %d", &ts, &ss);
Alexander Chemeris5a068062015-06-20 01:38:47 +0300737 mHandover[ts][ss] = false;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300738 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700739 } else if (match_cmd(command, "SETMAXDLY", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000740 //set expected maximum time-of-arrival
741 int maxDelay;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700742 sscanf(params, "%d", &maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300743 mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
dburgessb3a0ca42011-10-12 07:44:40 +0000744 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700745 } else if (match_cmd(command, "SETMAXDLYNB", &params)) {
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300746 //set expected maximum time-of-arrival
747 int maxDelay;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700748 sscanf(params, "%d", &maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300749 mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
750 sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700751 } else if (match_cmd(command, "SETRXGAIN", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000752 //set expected maximum time-of-arrival
753 int newGain;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700754 sscanf(params, "%d", &newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400755 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000756 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700757 } else if (match_cmd(command, "NOISELEV", NULL)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000758 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500759 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000760 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500761 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000762 }
763 else {
764 sprintf(response,"RSP NOISELEV 1 0");
765 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700766 } else if (match_cmd(command, "SETPOWER", &params)) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800767 int power;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700768 sscanf(params, "%d", &power);
Tom Tsoua4d1a412014-11-25 15:46:56 -0800769 power = mRadioInterface->setPowerAttenuation(power, chan);
770 mStates[chan].mPower = power;
771 sprintf(response, "RSP SETPOWER 0 %d", power);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700772 } else if (match_cmd(command, "ADJPOWER", &params)) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800773 int power, step;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700774 sscanf(params, "%d", &step);
Tom Tsoua4d1a412014-11-25 15:46:56 -0800775 power = mStates[chan].mPower + step;
776 power = mRadioInterface->setPowerAttenuation(power, chan);
777 mStates[chan].mPower = power;
778 sprintf(response, "RSP ADJPOWER 0 %d", power);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700779 } else if (match_cmd(command, "RXTUNE", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000780 // tune receiver
781 int freqKhz;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700782 sscanf(params, "%d", &freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500783 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400784 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000785 LOG(ALERT) << "RX failed to tune";
786 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
787 }
788 else
789 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700790 } else if (match_cmd(command, "TXTUNE", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000791 // tune txmtr
792 int freqKhz;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700793 sscanf(params, "%d", &freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500794 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400795 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000796 LOG(ALERT) << "TX failed to tune";
797 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
798 }
799 else
800 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700801 } else if (match_cmd(command, "SETTSC", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000802 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500803 unsigned TSC;
Vadim Yanitskiy8c6c5d22018-03-09 05:01:21 +0700804 sscanf(params, "%u", &TSC);
Tom Tsou60317342017-03-30 19:36:41 -0700805 if (TSC > 7) {
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500806 sprintf(response, "RSP SETTSC 1 %d", TSC);
Tom Tsou60317342017-03-30 19:36:41 -0700807 } else {
Tom Tsouc37594f2016-07-08 14:39:42 -0700808 LOG(NOTICE) << "Changing TSC from " << mTSC << " to " << TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000809 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400810 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000811 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700812 } else if (match_cmd(command, "SETSLOT", &params)) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700813 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000814 int corrCode;
815 int timeslot;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700816 sscanf(params, "%d %d", &timeslot, &corrCode);
dburgessb3a0ca42011-10-12 07:44:40 +0000817 if ((timeslot < 0) || (timeslot > 7)) {
818 LOG(WARNING) << "bogus message on control interface";
819 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
820 return;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200821 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400822 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
823 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000824 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700825 } else if (match_cmd(command, "_SETBURSTTODISKMASK", &params)) {
Alexander Chemerise692ce92015-06-12 00:15:31 -0400826 // debug command! may change or disapear without notice
827 // set a mask which bursts to dump to disk
828 int mask;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700829 sscanf(params, "%d", &mask);
Alexander Chemerise692ce92015-06-12 00:15:31 -0400830 mWriteBurstToDiskMask = mask;
831 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700832 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000833 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200834 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000835 }
836
Thomas Tsou204a9f12013-10-29 18:34:16 -0400837 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000838}
839
Thomas Tsou204a9f12013-10-29 18:34:16 -0400840bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000841{
Tom Tsoue8871082016-07-01 02:46:04 -0700842 int burstLen;
843 char buffer[EDGE_BURST_NBITS + 50];
dburgessb3a0ca42011-10-12 07:44:40 +0000844
845 // check data socket
Tom Tsou2c650a62016-04-28 21:55:17 -0700846 size_t msgLen = mDataSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000847
Tom Tsoue8871082016-07-01 02:46:04 -0700848 if (msgLen == gSlotLen + 1 + 4 + 1) {
849 burstLen = gSlotLen;
850 } else if (msgLen == EDGE_BURST_NBITS + 1 + 4 + 1) {
851 if (mSPSTx != 4)
852 return false;
853
854 burstLen = EDGE_BURST_NBITS;
855 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000856 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
857 return false;
858 }
859
860 int timeSlot = (int) buffer[0];
861 uint64_t frameNum = 0;
862 for (int i = 0; i < 4; i++)
863 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000864
dburgessb3a0ca42011-10-12 07:44:40 +0000865 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200866
dburgessb3a0ca42011-10-12 07:44:40 +0000867 int RSSI = (int) buffer[5];
Tom Tsou7c741ec2016-07-19 11:20:59 -0700868 BitVector newBurst(burstLen);
dburgessb3a0ca42011-10-12 07:44:40 +0000869 BitVector::iterator itr = newBurst.begin();
870 char *bufferItr = buffer+6;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200871 while (itr < newBurst.end())
dburgessb3a0ca42011-10-12 07:44:40 +0000872 *itr++ = *bufferItr++;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200873
dburgessb3a0ca42011-10-12 07:44:40 +0000874 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400875
876 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000877
878 return true;
879
880
881}
dburgessb3a0ca42011-10-12 07:44:40 +0000882
Thomas Tsou204a9f12013-10-29 18:34:16 -0400883void Transceiver::driveReceiveRadio()
884{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400885 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400886 usleep(100000);
Pau Espin Pedrol934da482017-07-04 16:25:20 +0200887 } else if (mForceClockInterface || mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0)) {
888 mForceClockInterface = false;
889 writeClockInterface();
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400890 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400891}
892
Alexander Chemeris58e95912016-03-25 18:20:28 +0300893void Transceiver::logRxBurst(size_t chan, SoftVector *burst, GSM::Time time, double dbm,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800894 double rssi, double noise, double toa)
895{
896 LOG(DEBUG) << std::fixed << std::right
Alexander Chemeris58e95912016-03-25 18:20:28 +0300897 << " chan: " << chan
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800898 << " time: " << time
899 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
900 << "dBFS/" << std::setw(6) << -dbm << "dBm"
901 << " noise: " << std::setw(5) << std::setprecision(1) << noise
902 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
903 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
904 << " bits: " << *burst;
905}
906
Thomas Tsou204a9f12013-10-29 18:34:16 -0400907void Transceiver::driveReceiveFIFO(size_t chan)
908{
dburgessb3a0ca42011-10-12 07:44:40 +0000909 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400910 double RSSI; // in dBFS
911 double dBm; // in dBm
912 double TOA; // in symbols
913 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400914 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000915 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400916 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800917 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000918
Alexander Chemeris2b542102015-06-08 22:46:38 -0400919 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800920 if (!rxBurst)
921 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000922
Alexander Chemerisb61c6102017-03-17 18:22:19 -0700923 // Convert -1..+1 soft bits to 0..1 soft bits
924 vectorSlicer(rxBurst);
925
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800926 /*
927 * EDGE demodulator returns 444 (148 * 3) bits
928 */
929 if (rxBurst->size() == gSlotLen * 3)
930 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000931
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800932 dBm = RSSI + rssiOffset;
Alexander Chemeris58e95912016-03-25 18:20:28 +0300933 logRxBurst(chan, rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400934
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800935 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000936
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800937 char burstString[nbits + 10];
938 burstString[0] = burstTime.TN();
939 for (int i = 0; i < 4; i++)
940 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
941 burstString[5] = (int)dBm;
942 burstString[6] = (TOAint >> 8) & 0x0ff;
943 burstString[7] = TOAint & 0x0ff;
944 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000945
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800946 for (unsigned i = 0; i < nbits; i++)
947 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
948
949 burstString[nbits + 9] = '\0';
950 delete rxBurst;
951
952 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000953}
954
Thomas Tsou204a9f12013-10-29 18:34:16 -0400955void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000956{
957
958 /**
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200959 Features a carefully controlled latency mechanism, to
dburgessb3a0ca42011-10-12 07:44:40 +0000960 assure that transmit packets arrive at the radio/USRP
961 before they need to be transmitted.
962
963 Deadline clock indicates the burst that needs to be
964 pushed into the FIFO right NOW. If transmit queue does
965 not have a burst, stick in filler data.
966 */
967
968
969 RadioClock *radioClock = (mRadioInterface->getClock());
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200970
dburgessb3a0ca42011-10-12 07:44:40 +0000971 if (mOn) {
972 //radioClock->wait(); // wait until clock updates
973 LOG(DEBUG) << "radio clock " << radioClock->get();
974 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
975 // if underrun, then we're not providing bursts to radio/USRP fast
976 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400977 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000978 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000979 // only update latency at the defined frame interval
980 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000981 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
982 LOG(INFO) << "new latency: " << mTransmitLatency;
983 mLatencyUpdateTime = radioClock->get();
984 }
985 }
986 else {
987 // if underrun hasn't occurred in the last sec (216 frames) drop
988 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000989 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000990 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
991 mTransmitLatency.decTN();
992 LOG(INFO) << "reduced latency: " << mTransmitLatency;
993 mLatencyUpdateTime = radioClock->get();
994 }
995 }
996 }
dburgessb3a0ca42011-10-12 07:44:40 +0000997 }
dburgessb3a0ca42011-10-12 07:44:40 +0000998 // time to push burst to transmit FIFO
999 pushRadioVector(mTransmitDeadlineClock);
1000 mTransmitDeadlineClock.incTN();
1001 }
dburgessb3a0ca42011-10-12 07:44:40 +00001002 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001003
1004 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001005}
1006
1007
1008
1009void Transceiver::writeClockInterface()
1010{
1011 char command[50];
1012 // FIXME -- This should be adaptive.
1013 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1014
1015 LOG(INFO) << "ClockInterface: sending " << command;
1016
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001017 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001018
1019 mLastClockUpdateTime = mTransmitDeadlineClock;
1020
Thomas Tsou92c16df2013-09-28 18:04:19 -04001021}
dburgessb3a0ca42011-10-12 07:44:40 +00001022
Thomas Tsou204a9f12013-10-29 18:34:16 -04001023void *RxUpperLoopAdapter(TransceiverChannel *chan)
1024{
1025 Transceiver *trx = chan->trx;
1026 size_t num = chan->num;
1027
1028 delete chan;
1029
Thomas Tsou7553aa92013-11-08 12:50:03 -05001030 trx->setPriority(0.42);
1031
Thomas Tsou204a9f12013-10-29 18:34:16 -04001032 while (1) {
1033 trx->driveReceiveFIFO(num);
1034 pthread_testcancel();
1035 }
1036 return NULL;
1037}
1038
1039void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001040{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001041 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001042
dburgessb3a0ca42011-10-12 07:44:40 +00001043 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001044 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001045 pthread_testcancel();
1046 }
1047 return NULL;
1048}
1049
Thomas Tsou204a9f12013-10-29 18:34:16 -04001050void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001051{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001052 transceiver->setPriority(0.44);
1053
Thomas Tsou92c16df2013-09-28 18:04:19 -04001054 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001055 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001056 pthread_testcancel();
1057 }
1058 return NULL;
1059}
1060
Thomas Tsou204a9f12013-10-29 18:34:16 -04001061void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001062{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001063 Transceiver *trx = chan->trx;
1064 size_t num = chan->num;
1065
1066 delete chan;
1067
dburgessb3a0ca42011-10-12 07:44:40 +00001068 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001069 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001070 pthread_testcancel();
1071 }
1072 return NULL;
1073}
1074
Thomas Tsou204a9f12013-10-29 18:34:16 -04001075void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001076{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001077 Transceiver *trx = chan->trx;
1078 size_t num = chan->num;
1079
1080 delete chan;
1081
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001082 trx->setPriority(0.40);
1083
dburgessb3a0ca42011-10-12 07:44:40 +00001084 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001085 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001086 pthread_testcancel();
1087 }
1088 return NULL;
1089}