blob: be6f526fc791c70d4e10a1bbc64a85dbd1bd37b5 [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))) {
376 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500377 if (state->mRetrans)
378 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500379 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400380 }
381
382 TN = nowTime.TN();
383 modFN = nowTime.FN() % state->fillerModulus[TN];
384
385 bursts[i] = state->fillerTable[modFN][TN];
386 zeros[i] = state->chanType[TN] == NONE;
387
388 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500389 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500390
391 if (state->mRetrans) {
392 updateFillerTable(i, burst);
393 } else {
394 burst->setVector(NULL);
395 filler[i] = false;
396 }
397
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500398 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400399 }
dburgessb3a0ca42011-10-12 07:44:40 +0000400 }
401
Thomas Tsou204a9f12013-10-29 18:34:16 -0400402 mRadioInterface->driveTransmitRadio(bursts, zeros);
403
Thomas Tsou15d743e2014-01-25 02:34:03 -0500404 for (size_t i = 0; i < mChans; i++) {
405 if (!filler[i])
406 delete bursts[i];
407 }
dburgessb3a0ca42011-10-12 07:44:40 +0000408}
409
Thomas Tsou204a9f12013-10-29 18:34:16 -0400410void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000411{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400412 TransceiverState *state = &mStates[chan];
413
414 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000415 case NONE:
416 case I:
417 case II:
418 case III:
419 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400420 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000421 break;
422 case IV:
423 case VI:
424 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400425 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000426 break;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200427 //case V:
dburgessb3a0ca42011-10-12 07:44:40 +0000428 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400429 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000430 break;
ttsoufc40a842013-06-09 22:38:18 +0000431 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400432 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000433 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000434 default:
435 break;
436 }
437}
438
439
Alexander Chemerisf9e78be2017-03-17 15:00:34 -0700440CorrType Transceiver::expectedCorrType(GSM::Time currTime,
441 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000442{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300443 static int tchh_subslot[26] = { 0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,1 };
444 static int sdcch4_subslot[102] = { 3,3,3,3,0,0,2,2,2,2,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,2,2,2,2,
445 3,3,3,3,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,2,2,2,2 };
446 static int sdcch8_subslot[102] = { 5,5,5,5,6,6,6,6,7,7,7,7,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,0,0,0,0,
447 1,1,1,1,2,2,2,2,3,3,3,3,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,4,4,4,4 };
Thomas Tsou204a9f12013-10-29 18:34:16 -0400448 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000449 unsigned burstTN = currTime.TN();
450 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300451 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000452
Thomas Tsou204a9f12013-10-29 18:34:16 -0400453 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000454 case NONE:
455 return OFF;
456 break;
457 case FILL:
458 return IDLE;
459 break;
460 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300461 // TODO: Are we expecting RACH on an IDLE frame?
462/* if (burstFN % 26 == 25)
463 return IDLE;*/
464 if (mHandover[burstTN][0])
465 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000466 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000467 break;
468 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300469 subch = tchh_subslot[burstFN % 26];
470 if (subch == 1)
471 return IDLE;
472 if (mHandover[burstTN][0])
473 return RACH;
ttsou20642972013-03-27 22:00:25 +0000474 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000475 break;
476 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300477 subch = tchh_subslot[burstFN % 26];
478 if (mHandover[burstTN][subch])
479 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000480 return TSC;
481 break;
482 case IV:
483 case VI:
484 return RACH;
485 break;
486 case V: {
487 int mod51 = burstFN % 51;
488 if ((mod51 <= 36) && (mod51 >= 14))
489 return RACH;
490 else if ((mod51 == 4) || (mod51 == 5))
491 return RACH;
492 else if ((mod51 == 45) || (mod51 == 46))
493 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300494 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
495 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000496 else
497 return TSC;
498 break;
499 }
500 case VII:
501 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
502 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300503 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
504 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000505 else
506 return TSC;
507 break;
ttsoufc40a842013-06-09 22:38:18 +0000508 case XIII: {
509 int mod52 = burstFN % 52;
510 if ((mod52 == 12) || (mod52 == 38))
511 return RACH;
512 else if ((mod52 == 25) || (mod52 == 51))
513 return IDLE;
514 else
515 return TSC;
516 break;
517 }
dburgessb3a0ca42011-10-12 07:44:40 +0000518 case LOOPBACK:
519 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
520 return IDLE;
521 else
522 return TSC;
523 break;
524 default:
525 return OFF;
526 break;
527 }
dburgessb3a0ca42011-10-12 07:44:40 +0000528}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400529
Alexander Chemerise692ce92015-06-12 00:15:31 -0400530void writeToFile(radioVector *radio_burst, size_t chan)
531{
532 GSM::Time time = radio_burst->getTime();
533 std::ostringstream fname;
534 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
535 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
536 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
537 outfile.close();
538}
539
Thomas Tsou30421a72013-11-13 23:14:48 -0500540/*
541 * Pull bursts from the FIFO and handle according to the slot
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200542 * and burst correlation type. Equalzation is currently disabled.
Thomas Tsou30421a72013-11-13 23:14:48 -0500543 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400544SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400545 double &timingOffset, double &noise,
546 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000547{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800548 int rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500549 complex amp;
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +0300550 float toa, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500551 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500552 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500553 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500554 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400555 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000556
Thomas Tsou30421a72013-11-13 23:14:48 -0500557 /* Blocking FIFO read */
558 radioVector *radio_burst = mReceiveFIFO[chan]->read();
559 if (!radio_burst)
560 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000561
Thomas Tsou30421a72013-11-13 23:14:48 -0500562 /* Set time and determine correlation type */
563 GSM::Time time = radio_burst->getTime();
564 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000565
Tom Tsou64464e62016-07-01 03:46:46 -0700566 /* Enable 8-PSK burst detection if EDGE is enabled */
567 if (mEdge && (type == TSC))
568 type = EDGE;
569
Alexander Chemerise692ce92015-06-12 00:15:31 -0400570 /* Debug: dump bursts to disk */
571 /* bits 0-7 - chan 0 timeslots
572 * bits 8-15 - chan 1 timeslots */
573 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
574 writeToFile(radio_burst, chan);
575
Alexander Chemeris2b542102015-06-08 22:46:38 -0400576 /* No processing if the timeslot is off.
577 * Not even power level or noise calculation. */
578 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500579 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000580 return NULL;
581 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000582
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500583 /* Select the diversity channel with highest energy */
584 for (size_t i = 0; i < radio_burst->chans(); i++) {
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +0300585 float pow = energyDetect(*radio_burst->getVector(i), 20 * mSPSRx);
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500586 if (pow > max) {
587 max = pow;
588 max_i = i;
589 }
590 avg += pow;
591 }
592
593 if (max_i < 0) {
594 LOG(ALERT) << "Received empty burst";
595 delete radio_burst;
596 return NULL;
597 }
598
Thomas Tsou30421a72013-11-13 23:14:48 -0500599 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500600 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500601 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400602
603 wTime = time;
604 RSSI = 20.0 * log10(rxFullScale / avg);
605
606 /* RSSI estimation are valid */
607 isRssiValid = true;
608
609 if (type == IDLE) {
610 /* Update noise levels */
611 state->mNoises.insert(avg);
612 state->mNoiseLev = state->mNoises.avg();
613 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
614
615 delete radio_burst;
616 return NULL;
617 } else {
618 /* Do not update noise levels */
619 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
620 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400621
Thomas Tsou30421a72013-11-13 23:14:48 -0500622 /* Detect normal or RACH bursts */
Alexander Chemeris4e6c9382017-03-17 15:24:18 -0700623 rc = detectAnyBurst(*burst, mTSC, BURST_THRESH, mSPSRx, type, amp, toa,
624 (type==RACH)?mMaxExpectedDelayAB:mMaxExpectedDelayNB);
Thomas Tsouf0782732013-10-29 15:55:47 -0400625
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800626 if (rc > 0) {
627 type = (CorrType) rc;
628 } else if (rc <= 0) {
629 if (rc == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400630 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800631 } else if (rc != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400632 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700633 }
634
Thomas Tsou30421a72013-11-13 23:14:48 -0500635 delete radio_burst;
636 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000637 }
dburgessb3a0ca42011-10-12 07:44:40 +0000638
Tom Tsou4609f322016-07-19 11:28:51 -0700639 timingOffset = toa;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400640
Alexander Chemeris6e1dffd2017-03-17 16:13:51 -0700641 bits = demodAnyBurst(*burst, mSPSRx, amp, toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500642
Thomas Tsou30421a72013-11-13 23:14:48 -0500643 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500644 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000645}
646
dburgessb3a0ca42011-10-12 07:44:40 +0000647void Transceiver::reset()
648{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400649 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
650 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000651}
652
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200653
Vadim Yanitskiybd0efb02018-03-09 02:45:07 +0700654#define MAX_PACKET_LENGTH 100
655
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700656/**
657 * Matches a buffer with a command.
658 * @param buf a buffer to look command in
659 * @param cmd a command to look in buffer
660 * @param params pointer to arguments, or NULL
661 * @return true if command matches, otherwise false
662 */
663static bool match_cmd(char *buf,
664 const char *cmd, char **params)
665{
666 size_t cmd_len = strlen(cmd);
667
668 /* Check a command itself */
669 if (strncmp(buf, cmd, cmd_len))
670 return false;
671
672 /* A command has arguments */
673 if (params != NULL) {
674 /* Make sure there is a space */
675 if (buf[cmd_len] != ' ')
676 return false;
677
678 /* Update external pointer */
679 *params = buf + cmd_len + 1;
680 }
681
682 return true;
683}
684
Thomas Tsou204a9f12013-10-29 18:34:16 -0400685void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000686{
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700687 char buffer[MAX_PACKET_LENGTH + 1];
688 char response[MAX_PACKET_LENGTH + 1];
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700689 char *command, *params;
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700690 int msgLen;
Thomas Tsoud647ec52013-10-29 15:17:34 -0400691
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700692 /* Attempt to read from control socket */
693 msgLen = mCtrlSockets[chan]->read(buffer, MAX_PACKET_LENGTH);
694 if (msgLen < 1)
dburgessb3a0ca42011-10-12 07:44:40 +0000695 return;
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700696
697 /* Zero-terminate received string */
698 buffer[msgLen] = '\0';
dburgessb3a0ca42011-10-12 07:44:40 +0000699
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700700 /* Verify a command signature */
701 if (strncmp(buffer, "CMD ", 4)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000702 LOG(WARNING) << "bogus message on control interface";
703 return;
704 }
dburgessb3a0ca42011-10-12 07:44:40 +0000705
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700706 /* Set command pointer */
707 command = buffer + 4;
708 LOG(INFO) << "command is " << command;
709
710 if (match_cmd(command, "POWEROFF", NULL)) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800711 stop();
712 sprintf(response,"RSP POWEROFF 0");
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700713 } else if (match_cmd(command, "POWERON", NULL)) {
Tom Tsou365bc382016-10-19 15:26:04 -0700714 if (!start()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000715 sprintf(response,"RSP POWERON 1");
Tom Tsou365bc382016-10-19 15:26:04 -0700716 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000717 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300718 for (int i = 0; i < 8; i++) {
719 for (int j = 0; j < 8; j++)
720 mHandover[i][j] = false;
721 }
Tom Tsou365bc382016-10-19 15:26:04 -0700722 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700723 } else if (match_cmd(command, "HANDOVER", &params)) {
Vadim Yanitskiyc0c6d702018-03-09 05:08:23 +0700724 unsigned ts = 0, ss = 0;
725 sscanf(params, "%u %u", &ts, &ss);
726 if (ts > 7 || ss > 7) {
727 sprintf(response, "RSP NOHANDOVER 1 %u %u", ts, ss);
728 } else {
729 mHandover[ts][ss] = true;
730 sprintf(response, "RSP HANDOVER 0 %u %u", ts, ss);
731 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700732 } else if (match_cmd(command, "NOHANDOVER", &params)) {
Vadim Yanitskiyc0c6d702018-03-09 05:08:23 +0700733 unsigned ts = 0, ss = 0;
734 sscanf(params, "%u %u", &ts, &ss);
735 if (ts > 7 || ss > 7) {
736 sprintf(response, "RSP NOHANDOVER 1 %u %u", ts, ss);
737 } else {
738 mHandover[ts][ss] = false;
739 sprintf(response, "RSP NOHANDOVER 0 %u %u", ts, ss);
740 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700741 } else if (match_cmd(command, "SETMAXDLY", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000742 //set expected maximum time-of-arrival
743 int maxDelay;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700744 sscanf(params, "%d", &maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300745 mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
dburgessb3a0ca42011-10-12 07:44:40 +0000746 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700747 } else if (match_cmd(command, "SETMAXDLYNB", &params)) {
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300748 //set expected maximum time-of-arrival
749 int maxDelay;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700750 sscanf(params, "%d", &maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300751 mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
752 sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700753 } else if (match_cmd(command, "SETRXGAIN", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000754 //set expected maximum time-of-arrival
755 int newGain;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700756 sscanf(params, "%d", &newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400757 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000758 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700759 } else if (match_cmd(command, "NOISELEV", NULL)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000760 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500761 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000762 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500763 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000764 }
765 else {
766 sprintf(response,"RSP NOISELEV 1 0");
767 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700768 } else if (match_cmd(command, "SETPOWER", &params)) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800769 int power;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700770 sscanf(params, "%d", &power);
Tom Tsoua4d1a412014-11-25 15:46:56 -0800771 power = mRadioInterface->setPowerAttenuation(power, chan);
772 mStates[chan].mPower = power;
773 sprintf(response, "RSP SETPOWER 0 %d", power);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700774 } else if (match_cmd(command, "ADJPOWER", &params)) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800775 int power, step;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700776 sscanf(params, "%d", &step);
Tom Tsoua4d1a412014-11-25 15:46:56 -0800777 power = mStates[chan].mPower + step;
778 power = mRadioInterface->setPowerAttenuation(power, chan);
779 mStates[chan].mPower = power;
780 sprintf(response, "RSP ADJPOWER 0 %d", power);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700781 } else if (match_cmd(command, "RXTUNE", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000782 // tune receiver
783 int freqKhz;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700784 sscanf(params, "%d", &freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500785 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400786 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000787 LOG(ALERT) << "RX failed to tune";
788 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
789 }
790 else
791 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700792 } else if (match_cmd(command, "TXTUNE", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000793 // tune txmtr
794 int freqKhz;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700795 sscanf(params, "%d", &freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500796 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400797 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000798 LOG(ALERT) << "TX failed to tune";
799 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
800 }
801 else
802 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700803 } else if (match_cmd(command, "SETTSC", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000804 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500805 unsigned TSC;
Vadim Yanitskiy8c6c5d22018-03-09 05:01:21 +0700806 sscanf(params, "%u", &TSC);
Tom Tsou60317342017-03-30 19:36:41 -0700807 if (TSC > 7) {
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500808 sprintf(response, "RSP SETTSC 1 %d", TSC);
Tom Tsou60317342017-03-30 19:36:41 -0700809 } else {
Tom Tsouc37594f2016-07-08 14:39:42 -0700810 LOG(NOTICE) << "Changing TSC from " << mTSC << " to " << TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000811 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400812 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000813 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700814 } else if (match_cmd(command, "SETSLOT", &params)) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700815 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000816 int corrCode;
817 int timeslot;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700818 sscanf(params, "%d %d", &timeslot, &corrCode);
dburgessb3a0ca42011-10-12 07:44:40 +0000819 if ((timeslot < 0) || (timeslot > 7)) {
820 LOG(WARNING) << "bogus message on control interface";
821 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
822 return;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200823 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400824 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
825 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000826 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700827 } else if (match_cmd(command, "_SETBURSTTODISKMASK", &params)) {
Alexander Chemerise692ce92015-06-12 00:15:31 -0400828 // debug command! may change or disapear without notice
829 // set a mask which bursts to dump to disk
830 int mask;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700831 sscanf(params, "%d", &mask);
Alexander Chemerise692ce92015-06-12 00:15:31 -0400832 mWriteBurstToDiskMask = mask;
833 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700834 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000835 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200836 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000837 }
838
Thomas Tsou204a9f12013-10-29 18:34:16 -0400839 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000840}
841
Thomas Tsou204a9f12013-10-29 18:34:16 -0400842bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000843{
Tom Tsoue8871082016-07-01 02:46:04 -0700844 int burstLen;
845 char buffer[EDGE_BURST_NBITS + 50];
dburgessb3a0ca42011-10-12 07:44:40 +0000846
847 // check data socket
Tom Tsou2c650a62016-04-28 21:55:17 -0700848 size_t msgLen = mDataSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000849
Tom Tsoue8871082016-07-01 02:46:04 -0700850 if (msgLen == gSlotLen + 1 + 4 + 1) {
851 burstLen = gSlotLen;
852 } else if (msgLen == EDGE_BURST_NBITS + 1 + 4 + 1) {
853 if (mSPSTx != 4)
854 return false;
855
856 burstLen = EDGE_BURST_NBITS;
857 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000858 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
859 return false;
860 }
861
862 int timeSlot = (int) buffer[0];
863 uint64_t frameNum = 0;
864 for (int i = 0; i < 4; i++)
865 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000866
dburgessb3a0ca42011-10-12 07:44:40 +0000867 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200868
dburgessb3a0ca42011-10-12 07:44:40 +0000869 int RSSI = (int) buffer[5];
Tom Tsou7c741ec2016-07-19 11:20:59 -0700870 BitVector newBurst(burstLen);
dburgessb3a0ca42011-10-12 07:44:40 +0000871 BitVector::iterator itr = newBurst.begin();
872 char *bufferItr = buffer+6;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200873 while (itr < newBurst.end())
dburgessb3a0ca42011-10-12 07:44:40 +0000874 *itr++ = *bufferItr++;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200875
dburgessb3a0ca42011-10-12 07:44:40 +0000876 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400877
878 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000879
880 return true;
881
882
883}
dburgessb3a0ca42011-10-12 07:44:40 +0000884
Thomas Tsou204a9f12013-10-29 18:34:16 -0400885void Transceiver::driveReceiveRadio()
886{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400887 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400888 usleep(100000);
Pau Espin Pedrol934da482017-07-04 16:25:20 +0200889 } else if (mForceClockInterface || mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0)) {
890 mForceClockInterface = false;
891 writeClockInterface();
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400892 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400893}
894
Alexander Chemeris58e95912016-03-25 18:20:28 +0300895void Transceiver::logRxBurst(size_t chan, SoftVector *burst, GSM::Time time, double dbm,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800896 double rssi, double noise, double toa)
897{
898 LOG(DEBUG) << std::fixed << std::right
Alexander Chemeris58e95912016-03-25 18:20:28 +0300899 << " chan: " << chan
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800900 << " time: " << time
901 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
902 << "dBFS/" << std::setw(6) << -dbm << "dBm"
903 << " noise: " << std::setw(5) << std::setprecision(1) << noise
904 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
905 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
906 << " bits: " << *burst;
907}
908
Thomas Tsou204a9f12013-10-29 18:34:16 -0400909void Transceiver::driveReceiveFIFO(size_t chan)
910{
dburgessb3a0ca42011-10-12 07:44:40 +0000911 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400912 double RSSI; // in dBFS
913 double dBm; // in dBm
914 double TOA; // in symbols
915 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400916 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000917 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400918 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800919 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000920
Alexander Chemeris2b542102015-06-08 22:46:38 -0400921 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800922 if (!rxBurst)
923 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000924
Alexander Chemerisb61c6102017-03-17 18:22:19 -0700925 // Convert -1..+1 soft bits to 0..1 soft bits
926 vectorSlicer(rxBurst);
927
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800928 /*
929 * EDGE demodulator returns 444 (148 * 3) bits
930 */
931 if (rxBurst->size() == gSlotLen * 3)
932 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000933
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800934 dBm = RSSI + rssiOffset;
Alexander Chemeris58e95912016-03-25 18:20:28 +0300935 logRxBurst(chan, rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400936
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800937 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000938
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800939 char burstString[nbits + 10];
940 burstString[0] = burstTime.TN();
941 for (int i = 0; i < 4; i++)
942 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
943 burstString[5] = (int)dBm;
944 burstString[6] = (TOAint >> 8) & 0x0ff;
945 burstString[7] = TOAint & 0x0ff;
946 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000947
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800948 for (unsigned i = 0; i < nbits; i++)
949 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
950
951 burstString[nbits + 9] = '\0';
952 delete rxBurst;
953
954 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000955}
956
Thomas Tsou204a9f12013-10-29 18:34:16 -0400957void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000958{
959
960 /**
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200961 Features a carefully controlled latency mechanism, to
dburgessb3a0ca42011-10-12 07:44:40 +0000962 assure that transmit packets arrive at the radio/USRP
963 before they need to be transmitted.
964
965 Deadline clock indicates the burst that needs to be
966 pushed into the FIFO right NOW. If transmit queue does
967 not have a burst, stick in filler data.
968 */
969
970
971 RadioClock *radioClock = (mRadioInterface->getClock());
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200972
dburgessb3a0ca42011-10-12 07:44:40 +0000973 if (mOn) {
974 //radioClock->wait(); // wait until clock updates
975 LOG(DEBUG) << "radio clock " << radioClock->get();
976 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
977 // if underrun, then we're not providing bursts to radio/USRP fast
978 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400979 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000980 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000981 // only update latency at the defined frame interval
982 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000983 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
984 LOG(INFO) << "new latency: " << mTransmitLatency;
985 mLatencyUpdateTime = radioClock->get();
986 }
987 }
988 else {
989 // if underrun hasn't occurred in the last sec (216 frames) drop
990 // transmit latency by a timeslot
Pau Espin Pedrole564f0f2018-04-24 18:43:51 +0200991 if (mTransmitLatency > mRadioInterface->minLatency()) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000992 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
993 mTransmitLatency.decTN();
994 LOG(INFO) << "reduced latency: " << mTransmitLatency;
995 mLatencyUpdateTime = radioClock->get();
996 }
997 }
998 }
dburgessb3a0ca42011-10-12 07:44:40 +0000999 }
dburgessb3a0ca42011-10-12 07:44:40 +00001000 // time to push burst to transmit FIFO
1001 pushRadioVector(mTransmitDeadlineClock);
1002 mTransmitDeadlineClock.incTN();
1003 }
dburgessb3a0ca42011-10-12 07:44:40 +00001004 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001005
1006 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001007}
1008
1009
1010
1011void Transceiver::writeClockInterface()
1012{
1013 char command[50];
1014 // FIXME -- This should be adaptive.
1015 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1016
1017 LOG(INFO) << "ClockInterface: sending " << command;
1018
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001019 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001020
1021 mLastClockUpdateTime = mTransmitDeadlineClock;
1022
Thomas Tsou92c16df2013-09-28 18:04:19 -04001023}
dburgessb3a0ca42011-10-12 07:44:40 +00001024
Thomas Tsou204a9f12013-10-29 18:34:16 -04001025void *RxUpperLoopAdapter(TransceiverChannel *chan)
1026{
1027 Transceiver *trx = chan->trx;
1028 size_t num = chan->num;
1029
1030 delete chan;
1031
Thomas Tsou7553aa92013-11-08 12:50:03 -05001032 trx->setPriority(0.42);
1033
Thomas Tsou204a9f12013-10-29 18:34:16 -04001034 while (1) {
1035 trx->driveReceiveFIFO(num);
1036 pthread_testcancel();
1037 }
1038 return NULL;
1039}
1040
1041void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001042{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001043 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001044
dburgessb3a0ca42011-10-12 07:44:40 +00001045 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001046 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001047 pthread_testcancel();
1048 }
1049 return NULL;
1050}
1051
Thomas Tsou204a9f12013-10-29 18:34:16 -04001052void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001053{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001054 transceiver->setPriority(0.44);
1055
Thomas Tsou92c16df2013-09-28 18:04:19 -04001056 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001057 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001058 pthread_testcancel();
1059 }
1060 return NULL;
1061}
1062
Thomas Tsou204a9f12013-10-29 18:34:16 -04001063void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001064{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001065 Transceiver *trx = chan->trx;
1066 size_t num = chan->num;
1067
1068 delete chan;
1069
dburgessb3a0ca42011-10-12 07:44:40 +00001070 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001071 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001072 pthread_testcancel();
1073 }
1074 return NULL;
1075}
1076
Thomas Tsou204a9f12013-10-29 18:34:16 -04001077void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001078{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001079 Transceiver *trx = chan->trx;
1080 size_t num = chan->num;
1081
1082 delete chan;
1083
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001084 trx->setPriority(0.40);
1085
dburgessb3a0ca42011-10-12 07:44:40 +00001086 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001087 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001088 pthread_testcancel();
1089 }
1090 return NULL;
1091}