blob: a1ebb30cd56f9806c275348b2ebd61c1c15ff422 [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
Thomas Tsoufa3a7872013-10-17 21:23:34 -040038/* Number of running values use in noise average */
39#define NOISE_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000040
Thomas Tsouf0782732013-10-29 15:55:47 -040041TransceiverState::TransceiverState()
Tom Tsoua4d1a412014-11-25 15:46:56 -080042 : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
Thomas Tsouf0782732013-10-29 15:55:47 -040043{
44 for (int i = 0; i < 8; i++) {
45 chanType[i] = Transceiver::NONE;
46 fillerModulus[i] = 26;
47 chanResponse[i] = NULL;
48 DFEForward[i] = NULL;
49 DFEFeedback[i] = NULL;
50
51 for (int n = 0; n < 102; n++)
52 fillerTable[n][i] = NULL;
53 }
54}
55
56TransceiverState::~TransceiverState()
57{
58 for (int i = 0; i < 8; i++) {
59 delete chanResponse[i];
60 delete DFEForward[i];
61 delete DFEFeedback[i];
62
63 for (int n = 0; n < 102; n++)
64 delete fillerTable[n][i];
65 }
66}
67
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010068bool TransceiverState::init(FillerType filler, size_t sps, float scale, size_t rtsc, unsigned rach_delay)
Tom Tsou64ad7122015-05-19 18:26:31 -070069{
Tom Tsou64ad7122015-05-19 18:26:31 -070070 signalVector *burst;
71
72 if ((sps != 1) && (sps != 4))
73 return false;
74
75 for (size_t n = 0; n < 8; n++) {
Tom Tsou64ad7122015-05-19 18:26:31 -070076 for (size_t i = 0; i < 102; i++) {
77 switch (filler) {
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010078 case FILLER_DUMMY:
Tom Tsou8ee2f382016-03-06 20:57:34 -080079 burst = generateDummyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070080 break;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010081 case FILLER_NORM_RAND:
Tom Tsou8ee2f382016-03-06 20:57:34 -080082 burst = genRandNormalBurst(rtsc, sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070083 break;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010084 case FILLER_EDGE_RAND:
Tom Tsouaf717b22016-03-06 22:19:15 -080085 burst = generateEdgeBurst(rtsc);
86 break;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010087 case FILLER_ACCESS_RAND:
Alexander Chemeris37c52c72016-03-25 18:28:34 +030088 burst = genRandAccessBurst(rach_delay, sps, n);
Alexander Chemeris5efe0502016-03-23 17:06:32 +030089 break;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010090 case FILLER_ZERO:
Tom Tsou64ad7122015-05-19 18:26:31 -070091 default:
Tom Tsou8ee2f382016-03-06 20:57:34 -080092 burst = generateEmptyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070093 }
94
95 scaleVector(*burst, scale);
96 fillerTable[i][n] = burst;
97 }
98
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010099 if ((filler == FILLER_NORM_RAND) ||
100 (filler == FILLER_EDGE_RAND)) {
Alexander Chemerisf9e78be2017-03-17 15:00:34 -0700101 chanType[n] = TSC;
Tom Tsouaf717b22016-03-06 22:19:15 -0800102 }
Thomas Tsou15d743e2014-01-25 02:34:03 -0500103 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700104
105 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400106}
107
dburgessb3a0ca42011-10-12 07:44:40 +0000108Transceiver::Transceiver(int wBasePort,
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200109 const char *TRXAddress,
110 const char *GSMcoreAddress,
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800111 size_t tx_sps, size_t rx_sps, size_t chans,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400112 GSM::Time wTransmitLatency,
113 RadioInterface *wRadioInterface,
114 double wRssiOffset)
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200115 : mBasePort(wBasePort), mLocalAddr(TRXAddress), mRemoteAddr(GSMcoreAddress),
116 mClockSocket(TRXAddress, wBasePort, GSMcoreAddress, wBasePort + 100),
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800117 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Alexander Chemerise8905a02015-06-03 23:47:56 -0400118 rssiOffset(wRssiOffset),
Pau Espin Pedrol934da482017-07-04 16:25:20 +0200119 mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mEdge(false), mOn(false), mForceClockInterface(false),
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300120 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
121 mWriteBurstToDiskMask(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000122{
dburgessb3a0ca42011-10-12 07:44:40 +0000123 txFullScale = mRadioInterface->fullScaleInputValue();
124 rxFullScale = mRadioInterface->fullScaleOutputValue();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300125
126 for (int i = 0; i < 8; i++) {
127 for (int j = 0; j < 8; j++)
128 mHandover[i][j] = false;
129 }
dburgessb3a0ca42011-10-12 07:44:40 +0000130}
131
132Transceiver::~Transceiver()
133{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800134 stop();
135
dburgessb3a0ca42011-10-12 07:44:40 +0000136 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400137
Thomas Tsou204a9f12013-10-29 18:34:16 -0400138 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800139 mControlServiceLoopThreads[i]->cancel();
140 mControlServiceLoopThreads[i]->join();
141 delete mControlServiceLoopThreads[i];
142
Thomas Tsou204a9f12013-10-29 18:34:16 -0400143 mTxPriorityQueues[i].clear();
144 delete mCtrlSockets[i];
145 delete mDataSockets[i];
146 }
dburgessb3a0ca42011-10-12 07:44:40 +0000147}
Thomas Tsou83e06892013-08-20 16:10:01 -0400148
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800149/*
150 * Initialize transceiver
151 *
152 * Start or restart the control loop. Any further control is handled through the
153 * socket API. Randomize the central radio clock set the downlink burst
154 * counters. Note that the clock will not update until the radio starts, but we
155 * are still expected to report clock indications through control channel
156 * activity.
157 */
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +0100158bool Transceiver::init(FillerType filler, size_t rtsc, unsigned rach_delay, bool edge)
Thomas Tsou83e06892013-08-20 16:10:01 -0400159{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500160 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400161
Thomas Tsou204a9f12013-10-29 18:34:16 -0400162 if (!mChans) {
163 LOG(ALERT) << "No channels assigned";
164 return false;
165 }
166
Tom Tsou2079a3c2016-03-06 00:58:56 -0800167 if (!sigProcLibSetup()) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400168 LOG(ALERT) << "Failed to initialize signal processing library";
169 return false;
170 }
171
Tom Tsou64464e62016-07-01 03:46:46 -0700172 mEdge = edge;
173
Thomas Tsou204a9f12013-10-29 18:34:16 -0400174 mDataSockets.resize(mChans);
175 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400176 mControlServiceLoopThreads.resize(mChans);
177 mTxPriorityQueueServiceLoopThreads.resize(mChans);
178 mRxServiceLoopThreads.resize(mChans);
179
180 mTxPriorityQueues.resize(mChans);
181 mReceiveFIFO.resize(mChans);
182 mStates.resize(mChans);
183
Thomas Tsouccb73e12014-04-15 17:41:28 -0400184 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700185 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400186 mStates[0].mRetrans = true;
187
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800188 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400189 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500190 c_srcport = mBasePort + 2 * i + 1;
191 c_dstport = mBasePort + 2 * i + 101;
192 d_srcport = mBasePort + 2 * i + 2;
193 d_dstport = mBasePort + 2 * i + 102;
194
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200195 mCtrlSockets[i] = new UDPSocket(mLocalAddr.c_str(), c_srcport, mRemoteAddr.c_str(), c_dstport);
196 mDataSockets[i] = new UDPSocket(mLocalAddr.c_str(), d_srcport, mRemoteAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400197 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400198
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800199 /* Randomize the central clock */
200 GSM::Time startTime(random() % gHyperframe, 0);
201 mRadioInterface->getClock()->set(startTime);
202 mTransmitDeadlineClock = startTime;
203 mLastClockUpdateTime = startTime;
204 mLatencyUpdateTime = startTime;
205
206 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400207 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800208 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400209 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800210 mControlServiceLoopThreads[i]->start((void * (*)(void*))
211 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400212
Tom Tsou64ad7122015-05-19 18:26:31 -0700213 if (i && filler == FILLER_DUMMY)
214 filler = FILLER_ZERO;
215
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300216 mStates[i].init(filler, mSPSTx, txFullScale, rtsc, rach_delay);
Thomas Tsou83e06892013-08-20 16:10:01 -0400217 }
218
219 return true;
220}
dburgessb3a0ca42011-10-12 07:44:40 +0000221
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800222/*
223 * Start the transceiver
224 *
225 * Submit command(s) to the radio device to commence streaming samples and
226 * launch threads to handle sample I/O. Re-synchronize the transmit burst
227 * counters to the central radio clock here as well.
228 */
229bool Transceiver::start()
230{
231 ScopedLock lock(mLock);
232
233 if (mOn) {
234 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300235 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800236 }
237
238 LOG(NOTICE) << "Starting the transceiver";
239
240 GSM::Time time = mRadioInterface->getClock()->get();
241 mTransmitDeadlineClock = time;
242 mLastClockUpdateTime = time;
243 mLatencyUpdateTime = time;
244
245 if (!mRadioInterface->start()) {
246 LOG(ALERT) << "Device failed to start";
247 return false;
248 }
249
250 /* Device is running - launch I/O threads */
251 mRxLowerLoopThread = new Thread(32768);
252 mTxLowerLoopThread = new Thread(32768);
253 mTxLowerLoopThread->start((void * (*)(void*))
254 TxLowerLoopAdapter,(void*) this);
255 mRxLowerLoopThread->start((void * (*)(void*))
256 RxLowerLoopAdapter,(void*) this);
257
258 /* Launch uplink and downlink burst processing threads */
259 for (size_t i = 0; i < mChans; i++) {
260 TransceiverChannel *chan = new TransceiverChannel(this, i);
261 mRxServiceLoopThreads[i] = new Thread(32768);
262 mRxServiceLoopThreads[i]->start((void * (*)(void*))
263 RxUpperLoopAdapter, (void*) chan);
264
265 chan = new TransceiverChannel(this, i);
266 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
267 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
268 TxUpperLoopAdapter, (void*) chan);
269 }
270
Pau Espin Pedrol934da482017-07-04 16:25:20 +0200271 mForceClockInterface = true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800272 mOn = true;
273 return true;
274}
275
276/*
277 * Stop the transceiver
278 *
279 * Perform stopping by disabling receive streaming and issuing cancellation
280 * requests to running threads. Most threads will timeout and terminate once
281 * device is disabled, but the transmit loop may block waiting on the central
282 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
283 * makes it to the thread cancellation point.
284 */
285void Transceiver::stop()
286{
287 ScopedLock lock(mLock);
288
289 if (!mOn)
290 return;
291
292 LOG(NOTICE) << "Stopping the transceiver";
293 mTxLowerLoopThread->cancel();
294 mRxLowerLoopThread->cancel();
Tom Tsoud67bd602017-06-15 15:35:02 -0700295 mTxLowerLoopThread->join();
296 mRxLowerLoopThread->join();
297 delete mTxLowerLoopThread;
298 delete mRxLowerLoopThread;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800299
300 for (size_t i = 0; i < mChans; i++) {
301 mRxServiceLoopThreads[i]->cancel();
302 mTxPriorityQueueServiceLoopThreads[i]->cancel();
303 }
304
305 LOG(INFO) << "Stopping the device";
306 mRadioInterface->stop();
307
308 for (size_t i = 0; i < mChans; i++) {
309 mRxServiceLoopThreads[i]->join();
310 mTxPriorityQueueServiceLoopThreads[i]->join();
311 delete mRxServiceLoopThreads[i];
312 delete mTxPriorityQueueServiceLoopThreads[i];
313
314 mTxPriorityQueues[i].clear();
315 }
316
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800317 mOn = false;
318 LOG(NOTICE) << "Transceiver stopped";
319}
320
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500321void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400322 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000323{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500324 signalVector *burst;
325 radioVector *radio_burst;
326
Thomas Tsou204a9f12013-10-29 18:34:16 -0400327 if (chan >= mTxPriorityQueues.size()) {
328 LOG(ALERT) << "Invalid channel " << chan;
329 return;
330 }
331
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500332 if (wTime.TN() > 7) {
333 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
334 return;
335 }
336
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800337 /* Use the number of bits as the EDGE burst indicator */
338 if (bits.size() == EDGE_BURST_NBITS)
339 burst = modulateEdgeBurst(bits, mSPSTx);
340 else
341 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
342
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500343 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000344
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500345 radio_burst = new radioVector(wTime, burst);
346
347 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000348}
349
Thomas Tsou15d743e2014-01-25 02:34:03 -0500350void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
351{
352 int TN, modFN;
353 TransceiverState *state = &mStates[chan];
354
355 TN = burst->getTime().TN();
356 modFN = burst->getTime().FN() % state->fillerModulus[TN];
357
358 delete state->fillerTable[modFN][TN];
359 state->fillerTable[modFN][TN] = burst->getVector();
360 burst->setVector(NULL);
361}
362
dburgessb3a0ca42011-10-12 07:44:40 +0000363void Transceiver::pushRadioVector(GSM::Time &nowTime)
364{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400365 int TN, modFN;
366 radioVector *burst;
367 TransceiverState *state;
368 std::vector<signalVector *> bursts(mChans);
369 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500370 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000371
Thomas Tsou204a9f12013-10-29 18:34:16 -0400372 for (size_t i = 0; i < mChans; i ++) {
373 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000374
Thomas Tsou204a9f12013-10-29 18:34:16 -0400375 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
Pau Espin Pedrolf37b0ad2018-04-25 18:01:27 +0200376 LOG(NOTICE) << "chan " << i << " dumping STALE burst in TRX->USRP interface ("
377 << burst->getTime() <<" vs " << nowTime << "), retrans=" << state->mRetrans;
Thomas Tsou15d743e2014-01-25 02:34:03 -0500378 if (state->mRetrans)
379 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500380 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400381 }
382
383 TN = nowTime.TN();
384 modFN = nowTime.FN() % state->fillerModulus[TN];
385
386 bursts[i] = state->fillerTable[modFN][TN];
387 zeros[i] = state->chanType[TN] == NONE;
388
389 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500390 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500391
392 if (state->mRetrans) {
393 updateFillerTable(i, burst);
394 } else {
395 burst->setVector(NULL);
396 filler[i] = false;
397 }
398
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500399 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400400 }
dburgessb3a0ca42011-10-12 07:44:40 +0000401 }
402
Thomas Tsou204a9f12013-10-29 18:34:16 -0400403 mRadioInterface->driveTransmitRadio(bursts, zeros);
404
Thomas Tsou15d743e2014-01-25 02:34:03 -0500405 for (size_t i = 0; i < mChans; i++) {
406 if (!filler[i])
407 delete bursts[i];
408 }
dburgessb3a0ca42011-10-12 07:44:40 +0000409}
410
Thomas Tsou204a9f12013-10-29 18:34:16 -0400411void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000412{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400413 TransceiverState *state = &mStates[chan];
414
415 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000416 case NONE:
417 case I:
418 case II:
419 case III:
420 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400421 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000422 break;
423 case IV:
424 case VI:
425 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400426 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000427 break;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200428 //case V:
dburgessb3a0ca42011-10-12 07:44:40 +0000429 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400430 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000431 break;
ttsoufc40a842013-06-09 22:38:18 +0000432 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400433 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000434 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000435 default:
436 break;
437 }
438}
439
440
Alexander Chemerisf9e78be2017-03-17 15:00:34 -0700441CorrType Transceiver::expectedCorrType(GSM::Time currTime,
442 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000443{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300444 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 };
445 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,
446 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 };
447 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,
448 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 -0400449 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000450 unsigned burstTN = currTime.TN();
451 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300452 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000453
Thomas Tsou204a9f12013-10-29 18:34:16 -0400454 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000455 case NONE:
456 return OFF;
457 break;
458 case FILL:
459 return IDLE;
460 break;
461 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300462 // TODO: Are we expecting RACH on an IDLE frame?
463/* if (burstFN % 26 == 25)
464 return IDLE;*/
465 if (mHandover[burstTN][0])
466 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000467 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000468 break;
469 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300470 subch = tchh_subslot[burstFN % 26];
471 if (subch == 1)
472 return IDLE;
473 if (mHandover[burstTN][0])
474 return RACH;
ttsou20642972013-03-27 22:00:25 +0000475 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000476 break;
477 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300478 subch = tchh_subslot[burstFN % 26];
479 if (mHandover[burstTN][subch])
480 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000481 return TSC;
482 break;
483 case IV:
484 case VI:
485 return RACH;
486 break;
487 case V: {
488 int mod51 = burstFN % 51;
489 if ((mod51 <= 36) && (mod51 >= 14))
490 return RACH;
491 else if ((mod51 == 4) || (mod51 == 5))
492 return RACH;
493 else if ((mod51 == 45) || (mod51 == 46))
494 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300495 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
496 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000497 else
498 return TSC;
499 break;
500 }
501 case VII:
502 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
503 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300504 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
505 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000506 else
507 return TSC;
508 break;
ttsoufc40a842013-06-09 22:38:18 +0000509 case XIII: {
510 int mod52 = burstFN % 52;
511 if ((mod52 == 12) || (mod52 == 38))
512 return RACH;
513 else if ((mod52 == 25) || (mod52 == 51))
514 return IDLE;
515 else
516 return TSC;
517 break;
518 }
dburgessb3a0ca42011-10-12 07:44:40 +0000519 case LOOPBACK:
520 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
521 return IDLE;
522 else
523 return TSC;
524 break;
525 default:
526 return OFF;
527 break;
528 }
dburgessb3a0ca42011-10-12 07:44:40 +0000529}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400530
Alexander Chemerise692ce92015-06-12 00:15:31 -0400531void writeToFile(radioVector *radio_burst, size_t chan)
532{
533 GSM::Time time = radio_burst->getTime();
534 std::ostringstream fname;
535 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
536 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
537 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
538 outfile.close();
539}
540
Thomas Tsou30421a72013-11-13 23:14:48 -0500541/*
542 * Pull bursts from the FIFO and handle according to the slot
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200543 * and burst correlation type. Equalzation is currently disabled.
Thomas Tsou30421a72013-11-13 23:14:48 -0500544 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400545SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400546 double &timingOffset, double &noise,
547 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000548{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800549 int rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500550 complex amp;
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +0300551 float toa, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500552 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500553 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500554 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500555 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400556 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000557
Thomas Tsou30421a72013-11-13 23:14:48 -0500558 /* Blocking FIFO read */
559 radioVector *radio_burst = mReceiveFIFO[chan]->read();
560 if (!radio_burst)
561 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000562
Thomas Tsou30421a72013-11-13 23:14:48 -0500563 /* Set time and determine correlation type */
564 GSM::Time time = radio_burst->getTime();
565 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000566
Tom Tsou64464e62016-07-01 03:46:46 -0700567 /* Enable 8-PSK burst detection if EDGE is enabled */
568 if (mEdge && (type == TSC))
569 type = EDGE;
570
Alexander Chemerise692ce92015-06-12 00:15:31 -0400571 /* Debug: dump bursts to disk */
572 /* bits 0-7 - chan 0 timeslots
573 * bits 8-15 - chan 1 timeslots */
574 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
575 writeToFile(radio_burst, chan);
576
Alexander Chemeris2b542102015-06-08 22:46:38 -0400577 /* No processing if the timeslot is off.
578 * Not even power level or noise calculation. */
579 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500580 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000581 return NULL;
582 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000583
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500584 /* Select the diversity channel with highest energy */
585 for (size_t i = 0; i < radio_burst->chans(); i++) {
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +0300586 float pow = energyDetect(*radio_burst->getVector(i), 20 * mSPSRx);
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500587 if (pow > max) {
588 max = pow;
589 max_i = i;
590 }
591 avg += pow;
592 }
593
594 if (max_i < 0) {
595 LOG(ALERT) << "Received empty burst";
596 delete radio_burst;
597 return NULL;
598 }
599
Thomas Tsou30421a72013-11-13 23:14:48 -0500600 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500601 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500602 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400603
604 wTime = time;
605 RSSI = 20.0 * log10(rxFullScale / avg);
606
607 /* RSSI estimation are valid */
608 isRssiValid = true;
609
610 if (type == IDLE) {
611 /* Update noise levels */
612 state->mNoises.insert(avg);
613 state->mNoiseLev = state->mNoises.avg();
614 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
615
616 delete radio_burst;
617 return NULL;
618 } else {
619 /* Do not update noise levels */
620 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
621 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400622
Thomas Tsou30421a72013-11-13 23:14:48 -0500623 /* Detect normal or RACH bursts */
Alexander Chemeris4e6c9382017-03-17 15:24:18 -0700624 rc = detectAnyBurst(*burst, mTSC, BURST_THRESH, mSPSRx, type, amp, toa,
625 (type==RACH)?mMaxExpectedDelayAB:mMaxExpectedDelayNB);
Thomas Tsouf0782732013-10-29 15:55:47 -0400626
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800627 if (rc > 0) {
628 type = (CorrType) rc;
629 } else if (rc <= 0) {
630 if (rc == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400631 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800632 } else if (rc != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400633 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700634 }
635
Thomas Tsou30421a72013-11-13 23:14:48 -0500636 delete radio_burst;
637 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000638 }
dburgessb3a0ca42011-10-12 07:44:40 +0000639
Tom Tsou4609f322016-07-19 11:28:51 -0700640 timingOffset = toa;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400641
Alexander Chemeris6e1dffd2017-03-17 16:13:51 -0700642 bits = demodAnyBurst(*burst, mSPSRx, amp, toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500643
Thomas Tsou30421a72013-11-13 23:14:48 -0500644 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500645 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000646}
647
dburgessb3a0ca42011-10-12 07:44:40 +0000648void Transceiver::reset()
649{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400650 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
651 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000652}
653
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200654
Vadim Yanitskiybd0efb02018-03-09 02:45:07 +0700655#define MAX_PACKET_LENGTH 100
656
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700657/**
658 * Matches a buffer with a command.
659 * @param buf a buffer to look command in
660 * @param cmd a command to look in buffer
661 * @param params pointer to arguments, or NULL
662 * @return true if command matches, otherwise false
663 */
664static bool match_cmd(char *buf,
665 const char *cmd, char **params)
666{
667 size_t cmd_len = strlen(cmd);
668
669 /* Check a command itself */
670 if (strncmp(buf, cmd, cmd_len))
671 return false;
672
673 /* A command has arguments */
674 if (params != NULL) {
675 /* Make sure there is a space */
676 if (buf[cmd_len] != ' ')
677 return false;
678
679 /* Update external pointer */
680 *params = buf + cmd_len + 1;
681 }
682
683 return true;
684}
685
Thomas Tsou204a9f12013-10-29 18:34:16 -0400686void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000687{
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700688 char buffer[MAX_PACKET_LENGTH + 1];
689 char response[MAX_PACKET_LENGTH + 1];
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700690 char *command, *params;
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700691 int msgLen;
Thomas Tsoud647ec52013-10-29 15:17:34 -0400692
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700693 /* Attempt to read from control socket */
694 msgLen = mCtrlSockets[chan]->read(buffer, MAX_PACKET_LENGTH);
695 if (msgLen < 1)
dburgessb3a0ca42011-10-12 07:44:40 +0000696 return;
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700697
698 /* Zero-terminate received string */
699 buffer[msgLen] = '\0';
dburgessb3a0ca42011-10-12 07:44:40 +0000700
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700701 /* Verify a command signature */
702 if (strncmp(buffer, "CMD ", 4)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000703 LOG(WARNING) << "bogus message on control interface";
704 return;
705 }
dburgessb3a0ca42011-10-12 07:44:40 +0000706
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700707 /* Set command pointer */
708 command = buffer + 4;
709 LOG(INFO) << "command is " << command;
710
711 if (match_cmd(command, "POWEROFF", NULL)) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800712 stop();
713 sprintf(response,"RSP POWEROFF 0");
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700714 } else if (match_cmd(command, "POWERON", NULL)) {
Tom Tsou365bc382016-10-19 15:26:04 -0700715 if (!start()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000716 sprintf(response,"RSP POWERON 1");
Tom Tsou365bc382016-10-19 15:26:04 -0700717 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000718 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300719 for (int i = 0; i < 8; i++) {
720 for (int j = 0; j < 8; j++)
721 mHandover[i][j] = false;
722 }
Tom Tsou365bc382016-10-19 15:26:04 -0700723 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700724 } else if (match_cmd(command, "HANDOVER", &params)) {
Vadim Yanitskiyc0c6d702018-03-09 05:08:23 +0700725 unsigned ts = 0, ss = 0;
726 sscanf(params, "%u %u", &ts, &ss);
727 if (ts > 7 || ss > 7) {
728 sprintf(response, "RSP NOHANDOVER 1 %u %u", ts, ss);
729 } else {
730 mHandover[ts][ss] = true;
731 sprintf(response, "RSP HANDOVER 0 %u %u", ts, ss);
732 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700733 } else if (match_cmd(command, "NOHANDOVER", &params)) {
Vadim Yanitskiyc0c6d702018-03-09 05:08:23 +0700734 unsigned ts = 0, ss = 0;
735 sscanf(params, "%u %u", &ts, &ss);
736 if (ts > 7 || ss > 7) {
737 sprintf(response, "RSP NOHANDOVER 1 %u %u", ts, ss);
738 } else {
739 mHandover[ts][ss] = false;
740 sprintf(response, "RSP NOHANDOVER 0 %u %u", ts, ss);
741 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700742 } else if (match_cmd(command, "SETMAXDLY", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000743 //set expected maximum time-of-arrival
744 int maxDelay;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700745 sscanf(params, "%d", &maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300746 mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
dburgessb3a0ca42011-10-12 07:44:40 +0000747 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700748 } else if (match_cmd(command, "SETMAXDLYNB", &params)) {
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300749 //set expected maximum time-of-arrival
750 int maxDelay;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700751 sscanf(params, "%d", &maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300752 mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
753 sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700754 } else if (match_cmd(command, "SETRXGAIN", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000755 //set expected maximum time-of-arrival
756 int newGain;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700757 sscanf(params, "%d", &newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400758 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000759 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700760 } else if (match_cmd(command, "NOISELEV", NULL)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000761 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500762 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000763 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500764 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000765 }
766 else {
767 sprintf(response,"RSP NOISELEV 1 0");
768 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700769 } else if (match_cmd(command, "SETPOWER", &params)) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800770 int power;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700771 sscanf(params, "%d", &power);
Tom Tsoua4d1a412014-11-25 15:46:56 -0800772 power = mRadioInterface->setPowerAttenuation(power, chan);
773 mStates[chan].mPower = power;
774 sprintf(response, "RSP SETPOWER 0 %d", power);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700775 } else if (match_cmd(command, "ADJPOWER", &params)) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800776 int power, step;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700777 sscanf(params, "%d", &step);
Tom Tsoua4d1a412014-11-25 15:46:56 -0800778 power = mStates[chan].mPower + step;
779 power = mRadioInterface->setPowerAttenuation(power, chan);
780 mStates[chan].mPower = power;
781 sprintf(response, "RSP ADJPOWER 0 %d", power);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700782 } else if (match_cmd(command, "RXTUNE", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000783 // tune receiver
784 int freqKhz;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700785 sscanf(params, "%d", &freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500786 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400787 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000788 LOG(ALERT) << "RX failed to tune";
789 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
790 }
791 else
792 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700793 } else if (match_cmd(command, "TXTUNE", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000794 // tune txmtr
795 int freqKhz;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700796 sscanf(params, "%d", &freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500797 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400798 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000799 LOG(ALERT) << "TX failed to tune";
800 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
801 }
802 else
803 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700804 } else if (match_cmd(command, "SETTSC", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000805 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500806 unsigned TSC;
Vadim Yanitskiy8c6c5d22018-03-09 05:01:21 +0700807 sscanf(params, "%u", &TSC);
Tom Tsou60317342017-03-30 19:36:41 -0700808 if (TSC > 7) {
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500809 sprintf(response, "RSP SETTSC 1 %d", TSC);
Tom Tsou60317342017-03-30 19:36:41 -0700810 } else {
Tom Tsouc37594f2016-07-08 14:39:42 -0700811 LOG(NOTICE) << "Changing TSC from " << mTSC << " to " << TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000812 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400813 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000814 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700815 } else if (match_cmd(command, "SETSLOT", &params)) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700816 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000817 int corrCode;
818 int timeslot;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700819 sscanf(params, "%d %d", &timeslot, &corrCode);
dburgessb3a0ca42011-10-12 07:44:40 +0000820 if ((timeslot < 0) || (timeslot > 7)) {
821 LOG(WARNING) << "bogus message on control interface";
822 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
823 return;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200824 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400825 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
826 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000827 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700828 } else if (match_cmd(command, "_SETBURSTTODISKMASK", &params)) {
Alexander Chemerise692ce92015-06-12 00:15:31 -0400829 // debug command! may change or disapear without notice
830 // set a mask which bursts to dump to disk
831 int mask;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700832 sscanf(params, "%d", &mask);
Alexander Chemerise692ce92015-06-12 00:15:31 -0400833 mWriteBurstToDiskMask = mask;
834 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700835 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000836 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200837 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000838 }
839
Thomas Tsou204a9f12013-10-29 18:34:16 -0400840 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000841}
842
Thomas Tsou204a9f12013-10-29 18:34:16 -0400843bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000844{
Tom Tsoue8871082016-07-01 02:46:04 -0700845 int burstLen;
846 char buffer[EDGE_BURST_NBITS + 50];
dburgessb3a0ca42011-10-12 07:44:40 +0000847
848 // check data socket
Tom Tsou2c650a62016-04-28 21:55:17 -0700849 size_t msgLen = mDataSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000850
Tom Tsoue8871082016-07-01 02:46:04 -0700851 if (msgLen == gSlotLen + 1 + 4 + 1) {
852 burstLen = gSlotLen;
853 } else if (msgLen == EDGE_BURST_NBITS + 1 + 4 + 1) {
854 if (mSPSTx != 4)
855 return false;
856
857 burstLen = EDGE_BURST_NBITS;
858 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000859 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
860 return false;
861 }
862
863 int timeSlot = (int) buffer[0];
864 uint64_t frameNum = 0;
865 for (int i = 0; i < 4; i++)
866 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000867
dburgessb3a0ca42011-10-12 07:44:40 +0000868 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200869
dburgessb3a0ca42011-10-12 07:44:40 +0000870 int RSSI = (int) buffer[5];
Tom Tsou7c741ec2016-07-19 11:20:59 -0700871 BitVector newBurst(burstLen);
dburgessb3a0ca42011-10-12 07:44:40 +0000872 BitVector::iterator itr = newBurst.begin();
873 char *bufferItr = buffer+6;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200874 while (itr < newBurst.end())
dburgessb3a0ca42011-10-12 07:44:40 +0000875 *itr++ = *bufferItr++;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200876
dburgessb3a0ca42011-10-12 07:44:40 +0000877 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400878
879 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000880
881 return true;
882
883
884}
dburgessb3a0ca42011-10-12 07:44:40 +0000885
Thomas Tsou204a9f12013-10-29 18:34:16 -0400886void Transceiver::driveReceiveRadio()
887{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400888 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400889 usleep(100000);
Pau Espin Pedrol934da482017-07-04 16:25:20 +0200890 } else if (mForceClockInterface || mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0)) {
891 mForceClockInterface = false;
892 writeClockInterface();
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400893 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400894}
895
Alexander Chemeris58e95912016-03-25 18:20:28 +0300896void Transceiver::logRxBurst(size_t chan, SoftVector *burst, GSM::Time time, double dbm,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800897 double rssi, double noise, double toa)
898{
899 LOG(DEBUG) << std::fixed << std::right
Alexander Chemeris58e95912016-03-25 18:20:28 +0300900 << " chan: " << chan
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800901 << " time: " << time
902 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
903 << "dBFS/" << std::setw(6) << -dbm << "dBm"
904 << " noise: " << std::setw(5) << std::setprecision(1) << noise
905 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
906 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
907 << " bits: " << *burst;
908}
909
Thomas Tsou204a9f12013-10-29 18:34:16 -0400910void Transceiver::driveReceiveFIFO(size_t chan)
911{
dburgessb3a0ca42011-10-12 07:44:40 +0000912 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400913 double RSSI; // in dBFS
914 double dBm; // in dBm
915 double TOA; // in symbols
916 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400917 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000918 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400919 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800920 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000921
Alexander Chemeris2b542102015-06-08 22:46:38 -0400922 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800923 if (!rxBurst)
924 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000925
Alexander Chemerisb61c6102017-03-17 18:22:19 -0700926 // Convert -1..+1 soft bits to 0..1 soft bits
927 vectorSlicer(rxBurst);
928
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800929 /*
930 * EDGE demodulator returns 444 (148 * 3) bits
931 */
932 if (rxBurst->size() == gSlotLen * 3)
933 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000934
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800935 dBm = RSSI + rssiOffset;
Alexander Chemeris58e95912016-03-25 18:20:28 +0300936 logRxBurst(chan, rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400937
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800938 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000939
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800940 char burstString[nbits + 10];
941 burstString[0] = burstTime.TN();
942 for (int i = 0; i < 4; i++)
943 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
944 burstString[5] = (int)dBm;
945 burstString[6] = (TOAint >> 8) & 0x0ff;
946 burstString[7] = TOAint & 0x0ff;
947 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000948
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800949 for (unsigned i = 0; i < nbits; i++)
950 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
951
952 burstString[nbits + 9] = '\0';
953 delete rxBurst;
954
955 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000956}
957
Thomas Tsou204a9f12013-10-29 18:34:16 -0400958void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000959{
960
961 /**
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200962 Features a carefully controlled latency mechanism, to
dburgessb3a0ca42011-10-12 07:44:40 +0000963 assure that transmit packets arrive at the radio/USRP
964 before they need to be transmitted.
965
966 Deadline clock indicates the burst that needs to be
967 pushed into the FIFO right NOW. If transmit queue does
968 not have a burst, stick in filler data.
969 */
970
971
972 RadioClock *radioClock = (mRadioInterface->getClock());
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200973
dburgessb3a0ca42011-10-12 07:44:40 +0000974 if (mOn) {
975 //radioClock->wait(); // wait until clock updates
976 LOG(DEBUG) << "radio clock " << radioClock->get();
977 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
978 // if underrun, then we're not providing bursts to radio/USRP fast
979 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400980 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000981 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000982 // only update latency at the defined frame interval
983 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000984 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
985 LOG(INFO) << "new latency: " << mTransmitLatency;
986 mLatencyUpdateTime = radioClock->get();
987 }
988 }
989 else {
990 // if underrun hasn't occurred in the last sec (216 frames) drop
991 // transmit latency by a timeslot
Pau Espin Pedrole564f0f2018-04-24 18:43:51 +0200992 if (mTransmitLatency > mRadioInterface->minLatency()) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000993 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
994 mTransmitLatency.decTN();
995 LOG(INFO) << "reduced latency: " << mTransmitLatency;
996 mLatencyUpdateTime = radioClock->get();
997 }
998 }
999 }
dburgessb3a0ca42011-10-12 07:44:40 +00001000 }
dburgessb3a0ca42011-10-12 07:44:40 +00001001 // time to push burst to transmit FIFO
1002 pushRadioVector(mTransmitDeadlineClock);
1003 mTransmitDeadlineClock.incTN();
1004 }
dburgessb3a0ca42011-10-12 07:44:40 +00001005 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001006
1007 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001008}
1009
1010
1011
1012void Transceiver::writeClockInterface()
1013{
1014 char command[50];
1015 // FIXME -- This should be adaptive.
1016 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1017
1018 LOG(INFO) << "ClockInterface: sending " << command;
1019
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001020 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001021
1022 mLastClockUpdateTime = mTransmitDeadlineClock;
1023
Thomas Tsou92c16df2013-09-28 18:04:19 -04001024}
dburgessb3a0ca42011-10-12 07:44:40 +00001025
Thomas Tsou204a9f12013-10-29 18:34:16 -04001026void *RxUpperLoopAdapter(TransceiverChannel *chan)
1027{
1028 Transceiver *trx = chan->trx;
1029 size_t num = chan->num;
1030
1031 delete chan;
1032
Thomas Tsou7553aa92013-11-08 12:50:03 -05001033 trx->setPriority(0.42);
1034
Thomas Tsou204a9f12013-10-29 18:34:16 -04001035 while (1) {
1036 trx->driveReceiveFIFO(num);
1037 pthread_testcancel();
1038 }
1039 return NULL;
1040}
1041
1042void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001043{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001044 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001045
dburgessb3a0ca42011-10-12 07:44:40 +00001046 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001047 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001048 pthread_testcancel();
1049 }
1050 return NULL;
1051}
1052
Thomas Tsou204a9f12013-10-29 18:34:16 -04001053void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001054{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001055 transceiver->setPriority(0.44);
1056
Thomas Tsou92c16df2013-09-28 18:04:19 -04001057 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001058 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001059 pthread_testcancel();
1060 }
1061 return NULL;
1062}
1063
Thomas Tsou204a9f12013-10-29 18:34:16 -04001064void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001065{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001066 Transceiver *trx = chan->trx;
1067 size_t num = chan->num;
1068
1069 delete chan;
1070
dburgessb3a0ca42011-10-12 07:44:40 +00001071 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001072 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001073 pthread_testcancel();
1074 }
1075 return NULL;
1076}
1077
Thomas Tsou204a9f12013-10-29 18:34:16 -04001078void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001079{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001080 Transceiver *trx = chan->trx;
1081 size_t num = chan->num;
1082
1083 delete chan;
1084
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001085 trx->setPriority(0.40);
1086
dburgessb3a0ca42011-10-12 07:44:40 +00001087 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001088 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001089 pthread_testcancel();
1090 }
1091 return NULL;
1092}