blob: cb191d5f64efac38eee1594bab7c3873eb2a8eeb [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
2* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
3*
4* This software is distributed under the terms of the GNU Public License.
5* See the COPYING file in the main directory for details.
6*
7* This use of this software may be subject to additional restrictions.
8* See the LEGAL file in the main directory for details.
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22*/
23
dburgessb3a0ca42011-10-12 07:44:40 +000024#include <stdio.h>
Alexander Chemerise8905a02015-06-03 23:47:56 -040025#include <iomanip> // std::setprecision
Alexander Chemerise692ce92015-06-12 00:15:31 -040026#include <fstream>
dburgessb3a0ca42011-10-12 07:44:40 +000027#include "Transceiver.h"
28#include <Logger.h>
29
ttsou2173abf2012-08-08 00:51:31 +000030#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
dburgessb3a0ca42011-10-12 07:44:40 +000033
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040034using namespace GSM;
35
kurtis.heimerlec842de2012-11-23 08:37:32 +000036#define USB_LATENCY_INTRVL 10,0
ttsou2173abf2012-08-08 00:51:31 +000037
38#if USE_UHD
kurtis.heimerlec842de2012-11-23 08:37:32 +000039# define USB_LATENCY_MIN 6,7
ttsou2173abf2012-08-08 00:51:31 +000040#else
kurtis.heimerlec842de2012-11-23 08:37:32 +000041# define USB_LATENCY_MIN 1,1
ttsou2173abf2012-08-08 00:51:31 +000042#endif
dburgessb3a0ca42011-10-12 07:44:40 +000043
Thomas Tsoufa3a7872013-10-17 21:23:34 -040044/* Number of running values use in noise average */
45#define NOISE_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000046
Thomas Tsouf0782732013-10-29 15:55:47 -040047TransceiverState::TransceiverState()
Tom Tsoua4d1a412014-11-25 15:46:56 -080048 : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
Thomas Tsouf0782732013-10-29 15:55:47 -040049{
50 for (int i = 0; i < 8; i++) {
51 chanType[i] = Transceiver::NONE;
52 fillerModulus[i] = 26;
53 chanResponse[i] = NULL;
54 DFEForward[i] = NULL;
55 DFEFeedback[i] = NULL;
56
57 for (int n = 0; n < 102; n++)
58 fillerTable[n][i] = NULL;
59 }
60}
61
62TransceiverState::~TransceiverState()
63{
64 for (int i = 0; i < 8; i++) {
65 delete chanResponse[i];
66 delete DFEForward[i];
67 delete DFEFeedback[i];
68
69 for (int n = 0; n < 102; n++)
70 delete fillerTable[n][i];
71 }
72}
73
Alexander Chemeris37c52c72016-03-25 18:28:34 +030074bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc, unsigned rach_delay)
Tom Tsou64ad7122015-05-19 18:26:31 -070075{
Tom Tsou64ad7122015-05-19 18:26:31 -070076 signalVector *burst;
77
78 if ((sps != 1) && (sps != 4))
79 return false;
80
81 for (size_t n = 0; n < 8; n++) {
Tom Tsou64ad7122015-05-19 18:26:31 -070082 for (size_t i = 0; i < 102; i++) {
83 switch (filler) {
84 case Transceiver::FILLER_DUMMY:
Tom Tsou8ee2f382016-03-06 20:57:34 -080085 burst = generateDummyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070086 break;
Tom Tsouaf717b22016-03-06 22:19:15 -080087 case Transceiver::FILLER_NORM_RAND:
Tom Tsou8ee2f382016-03-06 20:57:34 -080088 burst = genRandNormalBurst(rtsc, sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070089 break;
Tom Tsouaf717b22016-03-06 22:19:15 -080090 case Transceiver::FILLER_EDGE_RAND:
91 burst = generateEdgeBurst(rtsc);
92 break;
Alexander Chemeris5efe0502016-03-23 17:06:32 +030093 case Transceiver::FILLER_ACCESS_RAND:
Alexander Chemeris37c52c72016-03-25 18:28:34 +030094 burst = genRandAccessBurst(rach_delay, sps, n);
Alexander Chemeris5efe0502016-03-23 17:06:32 +030095 break;
Tom Tsou64ad7122015-05-19 18:26:31 -070096 case Transceiver::FILLER_ZERO:
97 default:
Tom Tsou8ee2f382016-03-06 20:57:34 -080098 burst = generateEmptyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070099 }
100
101 scaleVector(*burst, scale);
102 fillerTable[i][n] = burst;
103 }
104
Tom Tsouaf717b22016-03-06 22:19:15 -0800105 if ((filler == Transceiver::FILLER_NORM_RAND) ||
106 (filler == Transceiver::FILLER_EDGE_RAND)) {
107 chanType[n] = Transceiver::TSC;
108 }
Thomas Tsou15d743e2014-01-25 02:34:03 -0500109 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700110
111 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400112}
113
dburgessb3a0ca42011-10-12 07:44:40 +0000114Transceiver::Transceiver(int wBasePort,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400115 const char *wTRXAddress,
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800116 size_t tx_sps, size_t rx_sps, size_t chans,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400117 GSM::Time wTransmitLatency,
118 RadioInterface *wRadioInterface,
119 double wRssiOffset)
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800120 : mBasePort(wBasePort), mAddr(wTRXAddress),
121 mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
122 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Alexander Chemerise8905a02015-06-03 23:47:56 -0400123 rssiOffset(wRssiOffset),
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800124 mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mOn(false),
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300125 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
126 mWriteBurstToDiskMask(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000127{
dburgessb3a0ca42011-10-12 07:44:40 +0000128 txFullScale = mRadioInterface->fullScaleInputValue();
129 rxFullScale = mRadioInterface->fullScaleOutputValue();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300130
131 for (int i = 0; i < 8; i++) {
132 for (int j = 0; j < 8; j++)
133 mHandover[i][j] = false;
134 }
dburgessb3a0ca42011-10-12 07:44:40 +0000135}
136
137Transceiver::~Transceiver()
138{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800139 stop();
140
dburgessb3a0ca42011-10-12 07:44:40 +0000141 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400142
Thomas Tsou204a9f12013-10-29 18:34:16 -0400143 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800144 mControlServiceLoopThreads[i]->cancel();
145 mControlServiceLoopThreads[i]->join();
146 delete mControlServiceLoopThreads[i];
147
Thomas Tsou204a9f12013-10-29 18:34:16 -0400148 mTxPriorityQueues[i].clear();
149 delete mCtrlSockets[i];
150 delete mDataSockets[i];
151 }
dburgessb3a0ca42011-10-12 07:44:40 +0000152}
Thomas Tsou83e06892013-08-20 16:10:01 -0400153
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800154/*
155 * Initialize transceiver
156 *
157 * Start or restart the control loop. Any further control is handled through the
158 * socket API. Randomize the central radio clock set the downlink burst
159 * counters. Note that the clock will not update until the radio starts, but we
160 * are still expected to report clock indications through control channel
161 * activity.
162 */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300163bool Transceiver::init(int filler, size_t rtsc, unsigned rach_delay)
Thomas Tsou83e06892013-08-20 16:10:01 -0400164{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500165 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400166
Thomas Tsou204a9f12013-10-29 18:34:16 -0400167 if (!mChans) {
168 LOG(ALERT) << "No channels assigned";
169 return false;
170 }
171
Tom Tsou2079a3c2016-03-06 00:58:56 -0800172 if (!sigProcLibSetup()) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400173 LOG(ALERT) << "Failed to initialize signal processing library";
174 return false;
175 }
176
Thomas Tsou204a9f12013-10-29 18:34:16 -0400177 mDataSockets.resize(mChans);
178 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400179 mControlServiceLoopThreads.resize(mChans);
180 mTxPriorityQueueServiceLoopThreads.resize(mChans);
181 mRxServiceLoopThreads.resize(mChans);
182
183 mTxPriorityQueues.resize(mChans);
184 mReceiveFIFO.resize(mChans);
185 mStates.resize(mChans);
186
Thomas Tsouccb73e12014-04-15 17:41:28 -0400187 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700188 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400189 mStates[0].mRetrans = true;
190
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800191 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400192 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500193 c_srcport = mBasePort + 2 * i + 1;
194 c_dstport = mBasePort + 2 * i + 101;
195 d_srcport = mBasePort + 2 * i + 2;
196 d_dstport = mBasePort + 2 * i + 102;
197
198 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
199 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400200 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400201
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800202 /* Randomize the central clock */
203 GSM::Time startTime(random() % gHyperframe, 0);
204 mRadioInterface->getClock()->set(startTime);
205 mTransmitDeadlineClock = startTime;
206 mLastClockUpdateTime = startTime;
207 mLatencyUpdateTime = startTime;
208
209 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400210 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800211 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400212 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800213 mControlServiceLoopThreads[i]->start((void * (*)(void*))
214 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400215
Tom Tsou64ad7122015-05-19 18:26:31 -0700216 if (i && filler == FILLER_DUMMY)
217 filler = FILLER_ZERO;
218
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300219 mStates[i].init(filler, mSPSTx, txFullScale, rtsc, rach_delay);
Thomas Tsou83e06892013-08-20 16:10:01 -0400220 }
221
222 return true;
223}
dburgessb3a0ca42011-10-12 07:44:40 +0000224
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800225/*
226 * Start the transceiver
227 *
228 * Submit command(s) to the radio device to commence streaming samples and
229 * launch threads to handle sample I/O. Re-synchronize the transmit burst
230 * counters to the central radio clock here as well.
231 */
232bool Transceiver::start()
233{
234 ScopedLock lock(mLock);
235
236 if (mOn) {
237 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300238 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800239 }
240
241 LOG(NOTICE) << "Starting the transceiver";
242
243 GSM::Time time = mRadioInterface->getClock()->get();
244 mTransmitDeadlineClock = time;
245 mLastClockUpdateTime = time;
246 mLatencyUpdateTime = time;
247
248 if (!mRadioInterface->start()) {
249 LOG(ALERT) << "Device failed to start";
250 return false;
251 }
252
253 /* Device is running - launch I/O threads */
254 mRxLowerLoopThread = new Thread(32768);
255 mTxLowerLoopThread = new Thread(32768);
256 mTxLowerLoopThread->start((void * (*)(void*))
257 TxLowerLoopAdapter,(void*) this);
258 mRxLowerLoopThread->start((void * (*)(void*))
259 RxLowerLoopAdapter,(void*) this);
260
261 /* Launch uplink and downlink burst processing threads */
262 for (size_t i = 0; i < mChans; i++) {
263 TransceiverChannel *chan = new TransceiverChannel(this, i);
264 mRxServiceLoopThreads[i] = new Thread(32768);
265 mRxServiceLoopThreads[i]->start((void * (*)(void*))
266 RxUpperLoopAdapter, (void*) chan);
267
268 chan = new TransceiverChannel(this, i);
269 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
270 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
271 TxUpperLoopAdapter, (void*) chan);
272 }
273
274 writeClockInterface();
275 mOn = true;
276 return true;
277}
278
279/*
280 * Stop the transceiver
281 *
282 * Perform stopping by disabling receive streaming and issuing cancellation
283 * requests to running threads. Most threads will timeout and terminate once
284 * device is disabled, but the transmit loop may block waiting on the central
285 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
286 * makes it to the thread cancellation point.
287 */
288void Transceiver::stop()
289{
290 ScopedLock lock(mLock);
291
292 if (!mOn)
293 return;
294
295 LOG(NOTICE) << "Stopping the transceiver";
296 mTxLowerLoopThread->cancel();
297 mRxLowerLoopThread->cancel();
298
299 for (size_t i = 0; i < mChans; i++) {
300 mRxServiceLoopThreads[i]->cancel();
301 mTxPriorityQueueServiceLoopThreads[i]->cancel();
302 }
303
304 LOG(INFO) << "Stopping the device";
305 mRadioInterface->stop();
306
307 for (size_t i = 0; i < mChans; i++) {
308 mRxServiceLoopThreads[i]->join();
309 mTxPriorityQueueServiceLoopThreads[i]->join();
310 delete mRxServiceLoopThreads[i];
311 delete mTxPriorityQueueServiceLoopThreads[i];
312
313 mTxPriorityQueues[i].clear();
314 }
315
316 mTxLowerLoopThread->join();
317 mRxLowerLoopThread->join();
318 delete mTxLowerLoopThread;
319 delete mRxLowerLoopThread;
320
321 mOn = false;
322 LOG(NOTICE) << "Transceiver stopped";
323}
324
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500325void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400326 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000327{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500328 signalVector *burst;
329 radioVector *radio_burst;
330
Thomas Tsou204a9f12013-10-29 18:34:16 -0400331 if (chan >= mTxPriorityQueues.size()) {
332 LOG(ALERT) << "Invalid channel " << chan;
333 return;
334 }
335
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500336 if (wTime.TN() > 7) {
337 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
338 return;
339 }
340
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800341 /* Use the number of bits as the EDGE burst indicator */
342 if (bits.size() == EDGE_BURST_NBITS)
343 burst = modulateEdgeBurst(bits, mSPSTx);
344 else
345 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
346
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500347 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000348
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500349 radio_burst = new radioVector(wTime, burst);
350
351 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000352}
353
Thomas Tsou15d743e2014-01-25 02:34:03 -0500354void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
355{
356 int TN, modFN;
357 TransceiverState *state = &mStates[chan];
358
359 TN = burst->getTime().TN();
360 modFN = burst->getTime().FN() % state->fillerModulus[TN];
361
362 delete state->fillerTable[modFN][TN];
363 state->fillerTable[modFN][TN] = burst->getVector();
364 burst->setVector(NULL);
365}
366
dburgessb3a0ca42011-10-12 07:44:40 +0000367void Transceiver::pushRadioVector(GSM::Time &nowTime)
368{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400369 int TN, modFN;
370 radioVector *burst;
371 TransceiverState *state;
372 std::vector<signalVector *> bursts(mChans);
373 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500374 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000375
Thomas Tsou204a9f12013-10-29 18:34:16 -0400376 for (size_t i = 0; i < mChans; i ++) {
377 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000378
Thomas Tsou204a9f12013-10-29 18:34:16 -0400379 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
380 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500381 if (state->mRetrans)
382 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500383 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400384 }
385
386 TN = nowTime.TN();
387 modFN = nowTime.FN() % state->fillerModulus[TN];
388
389 bursts[i] = state->fillerTable[modFN][TN];
390 zeros[i] = state->chanType[TN] == NONE;
391
392 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500393 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500394
395 if (state->mRetrans) {
396 updateFillerTable(i, burst);
397 } else {
398 burst->setVector(NULL);
399 filler[i] = false;
400 }
401
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500402 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400403 }
dburgessb3a0ca42011-10-12 07:44:40 +0000404 }
405
Thomas Tsou204a9f12013-10-29 18:34:16 -0400406 mRadioInterface->driveTransmitRadio(bursts, zeros);
407
Thomas Tsou15d743e2014-01-25 02:34:03 -0500408 for (size_t i = 0; i < mChans; i++) {
409 if (!filler[i])
410 delete bursts[i];
411 }
dburgessb3a0ca42011-10-12 07:44:40 +0000412}
413
Thomas Tsou204a9f12013-10-29 18:34:16 -0400414void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000415{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400416 TransceiverState *state = &mStates[chan];
417
418 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000419 case NONE:
420 case I:
421 case II:
422 case III:
423 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400424 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000425 break;
426 case IV:
427 case VI:
428 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400429 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000430 break;
431 //case V:
432 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400433 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000434 break;
ttsoufc40a842013-06-09 22:38:18 +0000435 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400436 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000437 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000438 default:
439 break;
440 }
441}
442
443
Thomas Tsou204a9f12013-10-29 18:34:16 -0400444Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
445 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000446{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300447 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 };
448 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,
449 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 };
450 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,
451 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 -0400452 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000453 unsigned burstTN = currTime.TN();
454 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300455 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000456
Thomas Tsou204a9f12013-10-29 18:34:16 -0400457 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000458 case NONE:
459 return OFF;
460 break;
461 case FILL:
462 return IDLE;
463 break;
464 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300465 // TODO: Are we expecting RACH on an IDLE frame?
466/* if (burstFN % 26 == 25)
467 return IDLE;*/
468 if (mHandover[burstTN][0])
469 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000470 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000471 break;
472 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300473 subch = tchh_subslot[burstFN % 26];
474 if (subch == 1)
475 return IDLE;
476 if (mHandover[burstTN][0])
477 return RACH;
ttsou20642972013-03-27 22:00:25 +0000478 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000479 break;
480 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300481 subch = tchh_subslot[burstFN % 26];
482 if (mHandover[burstTN][subch])
483 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000484 return TSC;
485 break;
486 case IV:
487 case VI:
488 return RACH;
489 break;
490 case V: {
491 int mod51 = burstFN % 51;
492 if ((mod51 <= 36) && (mod51 >= 14))
493 return RACH;
494 else if ((mod51 == 4) || (mod51 == 5))
495 return RACH;
496 else if ((mod51 == 45) || (mod51 == 46))
497 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300498 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
499 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000500 else
501 return TSC;
502 break;
503 }
504 case VII:
505 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
506 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300507 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
508 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000509 else
510 return TSC;
511 break;
ttsoufc40a842013-06-09 22:38:18 +0000512 case XIII: {
513 int mod52 = burstFN % 52;
514 if ((mod52 == 12) || (mod52 == 38))
515 return RACH;
516 else if ((mod52 == 25) || (mod52 == 51))
517 return IDLE;
518 else
519 return TSC;
520 break;
521 }
dburgessb3a0ca42011-10-12 07:44:40 +0000522 case LOOPBACK:
523 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
524 return IDLE;
525 else
526 return TSC;
527 break;
528 default:
529 return OFF;
530 break;
531 }
dburgessb3a0ca42011-10-12 07:44:40 +0000532}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400533
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300534int Transceiver::detectBurst(signalVector &burst,
535 complex &amp, float &toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500536{
Tom Tsou46569402016-03-06 01:59:38 -0800537 float threshold = 5.0, rc = 0;
Thomas Tsou30421a72013-11-13 23:14:48 -0500538
Tom Tsou46569402016-03-06 01:59:38 -0800539 switch (type) {
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800540 case EDGE:
541 rc = detectEdgeBurst(burst, mTSC, threshold, mSPSRx,
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300542 amp, toa, mMaxExpectedDelayNB);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800543 if (rc > 0)
544 break;
545 else
546 type = TSC;
Tom Tsou46569402016-03-06 01:59:38 -0800547 case TSC:
548 rc = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx,
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300549 amp, toa, mMaxExpectedDelayNB);
Tom Tsou46569402016-03-06 01:59:38 -0800550 break;
551 case RACH:
552 threshold = 6.0;
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300553 rc = detectRACHBurst(burst, threshold, mSPSRx, amp, toa,
554 mMaxExpectedDelayAB);
Tom Tsou46569402016-03-06 01:59:38 -0800555 break;
556 default:
557 LOG(ERR) << "Invalid correlation type";
558 }
559
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800560 if (rc > 0)
561 return type;
Tom Tsou46569402016-03-06 01:59:38 -0800562
563 return rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500564}
565
Thomas Tsou30421a72013-11-13 23:14:48 -0500566
567/*
Tom Tsou46569402016-03-06 01:59:38 -0800568 * Demodulate GMSK by direct rotation and soft slicing.
Thomas Tsou30421a72013-11-13 23:14:48 -0500569 */
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300570SoftVector *Transceiver::demodulate(signalVector &burst, complex amp,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800571 float toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500572{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800573 if (type == EDGE)
574 return demodEdgeBurst(burst, mSPSRx, amp, toa);
575
Thomas Tsou30421a72013-11-13 23:14:48 -0500576 return demodulateBurst(burst, mSPSRx, amp, toa);
577}
578
Alexander Chemerise692ce92015-06-12 00:15:31 -0400579void writeToFile(radioVector *radio_burst, size_t chan)
580{
581 GSM::Time time = radio_burst->getTime();
582 std::ostringstream fname;
583 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
584 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
585 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
586 outfile.close();
587}
588
Thomas Tsou30421a72013-11-13 23:14:48 -0500589/*
590 * Pull bursts from the FIFO and handle according to the slot
591 * and burst correlation type. Equalzation is currently disabled.
592 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400593SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400594 double &timingOffset, double &noise,
595 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000596{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800597 int rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500598 complex amp;
599 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500600 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500601 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500602 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500603 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400604 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000605
Thomas Tsou30421a72013-11-13 23:14:48 -0500606 /* Blocking FIFO read */
607 radioVector *radio_burst = mReceiveFIFO[chan]->read();
608 if (!radio_burst)
609 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000610
Thomas Tsou30421a72013-11-13 23:14:48 -0500611 /* Set time and determine correlation type */
612 GSM::Time time = radio_burst->getTime();
613 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000614
Alexander Chemerise692ce92015-06-12 00:15:31 -0400615 /* Debug: dump bursts to disk */
616 /* bits 0-7 - chan 0 timeslots
617 * bits 8-15 - chan 1 timeslots */
618 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
619 writeToFile(radio_burst, chan);
620
Alexander Chemeris2b542102015-06-08 22:46:38 -0400621 /* No processing if the timeslot is off.
622 * Not even power level or noise calculation. */
623 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500624 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000625 return NULL;
626 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000627
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500628 /* Select the diversity channel with highest energy */
629 for (size_t i = 0; i < radio_burst->chans(); i++) {
630 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
631 if (pow > max) {
632 max = pow;
633 max_i = i;
634 }
635 avg += pow;
636 }
637
638 if (max_i < 0) {
639 LOG(ALERT) << "Received empty burst";
640 delete radio_burst;
641 return NULL;
642 }
643
Thomas Tsou30421a72013-11-13 23:14:48 -0500644 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500645 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500646 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400647
648 wTime = time;
649 RSSI = 20.0 * log10(rxFullScale / avg);
650
651 /* RSSI estimation are valid */
652 isRssiValid = true;
653
654 if (type == IDLE) {
655 /* Update noise levels */
656 state->mNoises.insert(avg);
657 state->mNoiseLev = state->mNoises.avg();
658 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
659
660 delete radio_burst;
661 return NULL;
662 } else {
663 /* Do not update noise levels */
664 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
665 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400666
Thomas Tsou30421a72013-11-13 23:14:48 -0500667 /* Detect normal or RACH bursts */
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300668 rc = detectBurst(*burst, amp, toa, type);
Thomas Tsouf0782732013-10-29 15:55:47 -0400669
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800670 if (rc > 0) {
671 type = (CorrType) rc;
672 } else if (rc <= 0) {
673 if (rc == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400674 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800675 } else if (rc != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400676 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700677 }
678
Thomas Tsou30421a72013-11-13 23:14:48 -0500679 delete radio_burst;
680 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000681 }
dburgessb3a0ca42011-10-12 07:44:40 +0000682
Alexander Chemeris2b542102015-06-08 22:46:38 -0400683 timingOffset = toa / mSPSRx;
684
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300685 bits = demodulate(*burst, amp, toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500686
Thomas Tsou30421a72013-11-13 23:14:48 -0500687 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500688 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000689}
690
dburgessb3a0ca42011-10-12 07:44:40 +0000691void Transceiver::reset()
692{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400693 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
694 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000695}
696
697
Thomas Tsou204a9f12013-10-29 18:34:16 -0400698void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000699{
dburgessb3a0ca42011-10-12 07:44:40 +0000700 int MAX_PACKET_LENGTH = 100;
701
702 // check control socket
703 char buffer[MAX_PACKET_LENGTH];
704 int msgLen = -1;
705 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400706
Tom Tsou2c650a62016-04-28 21:55:17 -0700707 msgLen = mCtrlSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000708
709 if (msgLen < 1) {
710 return;
711 }
712
713 char cmdcheck[4];
714 char command[MAX_PACKET_LENGTH];
715 char response[MAX_PACKET_LENGTH];
716
717 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400718
719 if (!chan)
720 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000721
722 if (strcmp(cmdcheck,"CMD")!=0) {
723 LOG(WARNING) << "bogus message on control interface";
724 return;
725 }
726 LOG(INFO) << "command is " << buffer;
727
728 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800729 stop();
730 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000731 }
732 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800733 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000734 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800735 else
dburgessb3a0ca42011-10-12 07:44:40 +0000736 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300737 for (int i = 0; i < 8; i++) {
738 for (int j = 0; j < 8; j++)
739 mHandover[i][j] = false;
740 }
741 }
742 else if (strcmp(command,"HANDOVER")==0){
743 int ts=0,ss=0;
744 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
745 mHandover[ts][ss] = true;
746 LOG(WARNING) << "HANDOVER RACH at timeslot " << ts << " subslot " << ss;
747 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
748 }
749 else if (strcmp(command,"NOHANDOVER")==0){
750 int ts=0,ss=0;
751 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
752 mHandover[ts][ss] = false;
753 LOG(WARNING) << "NOHANDOVER at timeslot " << ts << " subslot " << ss;
754 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000755 }
756 else if (strcmp(command,"SETMAXDLY")==0) {
757 //set expected maximum time-of-arrival
758 int maxDelay;
759 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300760 mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
dburgessb3a0ca42011-10-12 07:44:40 +0000761 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
762 }
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300763 else if (strcmp(command,"SETMAXDLYNB")==0) {
764 //set expected maximum time-of-arrival
765 int maxDelay;
766 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
767 mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
768 sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
769 }
dburgessb3a0ca42011-10-12 07:44:40 +0000770 else if (strcmp(command,"SETRXGAIN")==0) {
771 //set expected maximum time-of-arrival
772 int newGain;
773 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400774 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000775 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
776 }
777 else if (strcmp(command,"NOISELEV")==0) {
778 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500779 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000780 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500781 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000782 }
783 else {
784 sprintf(response,"RSP NOISELEV 1 0");
785 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500786 }
787 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800788 int power;
789 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
790 power = mRadioInterface->setPowerAttenuation(power, chan);
791 mStates[chan].mPower = power;
792 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000793 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500794 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800795 int power, step;
796 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
797 power = mStates[chan].mPower + step;
798 power = mRadioInterface->setPowerAttenuation(power, chan);
799 mStates[chan].mPower = power;
800 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000801 }
dburgessb3a0ca42011-10-12 07:44:40 +0000802 else if (strcmp(command,"RXTUNE")==0) {
803 // tune receiver
804 int freqKhz;
805 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500806 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400807 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000808 LOG(ALERT) << "RX failed to tune";
809 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
810 }
811 else
812 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
813 }
814 else if (strcmp(command,"TXTUNE")==0) {
815 // tune txmtr
816 int freqKhz;
817 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500818 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400819 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000820 LOG(ALERT) << "TX failed to tune";
821 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
822 }
823 else
824 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
825 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500826 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000827 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500828 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500829 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700830 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500831 sprintf(response, "RSP SETTSC 1 %d", TSC);
832 else if (chan && (TSC != mTSC))
833 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000834 else {
835 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400836 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000837 }
838 }
839 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700840 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000841 int corrCode;
842 int timeslot;
843 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
844 if ((timeslot < 0) || (timeslot > 7)) {
845 LOG(WARNING) << "bogus message on control interface";
846 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
847 return;
848 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400849 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
850 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000851 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
852
853 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400854 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
855 // debug command! may change or disapear without notice
856 // set a mask which bursts to dump to disk
857 int mask;
858 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
859 mWriteBurstToDiskMask = mask;
860 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
861 }
dburgessb3a0ca42011-10-12 07:44:40 +0000862 else {
863 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200864 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000865 }
866
Thomas Tsou204a9f12013-10-29 18:34:16 -0400867 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000868}
869
Thomas Tsou204a9f12013-10-29 18:34:16 -0400870bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000871{
dburgessb3a0ca42011-10-12 07:44:40 +0000872 char buffer[gSlotLen+50];
873
874 // check data socket
Tom Tsou2c650a62016-04-28 21:55:17 -0700875 size_t msgLen = mDataSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000876
877 if (msgLen!=gSlotLen+1+4+1) {
878 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
879 return false;
880 }
881
882 int timeSlot = (int) buffer[0];
883 uint64_t frameNum = 0;
884 for (int i = 0; i < 4; i++)
885 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000886
dburgessb3a0ca42011-10-12 07:44:40 +0000887 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
888
889 int RSSI = (int) buffer[5];
890 static BitVector newBurst(gSlotLen);
891 BitVector::iterator itr = newBurst.begin();
892 char *bufferItr = buffer+6;
893 while (itr < newBurst.end())
894 *itr++ = *bufferItr++;
895
896 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400897
898 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000899
900 return true;
901
902
903}
dburgessb3a0ca42011-10-12 07:44:40 +0000904
Thomas Tsou204a9f12013-10-29 18:34:16 -0400905void Transceiver::driveReceiveRadio()
906{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400907 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400908 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400909 } else {
910 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
911 writeClockInterface();
912 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400913}
914
Alexander Chemeris58e95912016-03-25 18:20:28 +0300915void Transceiver::logRxBurst(size_t chan, SoftVector *burst, GSM::Time time, double dbm,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800916 double rssi, double noise, double toa)
917{
918 LOG(DEBUG) << std::fixed << std::right
Alexander Chemeris58e95912016-03-25 18:20:28 +0300919 << " chan: " << chan
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800920 << " time: " << time
921 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
922 << "dBFS/" << std::setw(6) << -dbm << "dBm"
923 << " noise: " << std::setw(5) << std::setprecision(1) << noise
924 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
925 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
926 << " bits: " << *burst;
927}
928
Thomas Tsou204a9f12013-10-29 18:34:16 -0400929void Transceiver::driveReceiveFIFO(size_t chan)
930{
dburgessb3a0ca42011-10-12 07:44:40 +0000931 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400932 double RSSI; // in dBFS
933 double dBm; // in dBm
934 double TOA; // in symbols
935 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400936 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000937 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400938 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800939 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000940
Alexander Chemeris2b542102015-06-08 22:46:38 -0400941 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800942 if (!rxBurst)
943 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000944
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800945 /*
946 * EDGE demodulator returns 444 (148 * 3) bits
947 */
948 if (rxBurst->size() == gSlotLen * 3)
949 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000950
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800951 dBm = RSSI + rssiOffset;
Alexander Chemeris58e95912016-03-25 18:20:28 +0300952 logRxBurst(chan, rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400953
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800954 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000955
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800956 char burstString[nbits + 10];
957 burstString[0] = burstTime.TN();
958 for (int i = 0; i < 4; i++)
959 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
960 burstString[5] = (int)dBm;
961 burstString[6] = (TOAint >> 8) & 0x0ff;
962 burstString[7] = TOAint & 0x0ff;
963 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000964
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800965 for (unsigned i = 0; i < nbits; i++)
966 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
967
968 burstString[nbits + 9] = '\0';
969 delete rxBurst;
970
971 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000972}
973
Thomas Tsou204a9f12013-10-29 18:34:16 -0400974void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000975{
976
977 /**
978 Features a carefully controlled latency mechanism, to
979 assure that transmit packets arrive at the radio/USRP
980 before they need to be transmitted.
981
982 Deadline clock indicates the burst that needs to be
983 pushed into the FIFO right NOW. If transmit queue does
984 not have a burst, stick in filler data.
985 */
986
987
988 RadioClock *radioClock = (mRadioInterface->getClock());
989
990 if (mOn) {
991 //radioClock->wait(); // wait until clock updates
992 LOG(DEBUG) << "radio clock " << radioClock->get();
993 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
994 // if underrun, then we're not providing bursts to radio/USRP fast
995 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400996 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000997 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000998 // only update latency at the defined frame interval
999 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001000 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
1001 LOG(INFO) << "new latency: " << mTransmitLatency;
1002 mLatencyUpdateTime = radioClock->get();
1003 }
1004 }
1005 else {
1006 // if underrun hasn't occurred in the last sec (216 frames) drop
1007 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +00001008 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001009 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1010 mTransmitLatency.decTN();
1011 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1012 mLatencyUpdateTime = radioClock->get();
1013 }
1014 }
1015 }
dburgessb3a0ca42011-10-12 07:44:40 +00001016 }
dburgessb3a0ca42011-10-12 07:44:40 +00001017 // time to push burst to transmit FIFO
1018 pushRadioVector(mTransmitDeadlineClock);
1019 mTransmitDeadlineClock.incTN();
1020 }
dburgessb3a0ca42011-10-12 07:44:40 +00001021 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001022
1023 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001024}
1025
1026
1027
1028void Transceiver::writeClockInterface()
1029{
1030 char command[50];
1031 // FIXME -- This should be adaptive.
1032 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1033
1034 LOG(INFO) << "ClockInterface: sending " << command;
1035
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001036 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001037
1038 mLastClockUpdateTime = mTransmitDeadlineClock;
1039
Thomas Tsou92c16df2013-09-28 18:04:19 -04001040}
dburgessb3a0ca42011-10-12 07:44:40 +00001041
Thomas Tsou204a9f12013-10-29 18:34:16 -04001042void *RxUpperLoopAdapter(TransceiverChannel *chan)
1043{
1044 Transceiver *trx = chan->trx;
1045 size_t num = chan->num;
1046
1047 delete chan;
1048
Thomas Tsou7553aa92013-11-08 12:50:03 -05001049 trx->setPriority(0.42);
1050
Thomas Tsou204a9f12013-10-29 18:34:16 -04001051 while (1) {
1052 trx->driveReceiveFIFO(num);
1053 pthread_testcancel();
1054 }
1055 return NULL;
1056}
1057
1058void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001059{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001060 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001061
dburgessb3a0ca42011-10-12 07:44:40 +00001062 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001063 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001064 pthread_testcancel();
1065 }
1066 return NULL;
1067}
1068
Thomas Tsou204a9f12013-10-29 18:34:16 -04001069void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001070{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001071 transceiver->setPriority(0.44);
1072
Thomas Tsou92c16df2013-09-28 18:04:19 -04001073 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001074 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001075 pthread_testcancel();
1076 }
1077 return NULL;
1078}
1079
Thomas Tsou204a9f12013-10-29 18:34:16 -04001080void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001081{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001082 Transceiver *trx = chan->trx;
1083 size_t num = chan->num;
1084
1085 delete chan;
1086
dburgessb3a0ca42011-10-12 07:44:40 +00001087 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001088 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001089 pthread_testcancel();
1090 }
1091 return NULL;
1092}
1093
Thomas Tsou204a9f12013-10-29 18:34:16 -04001094void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001095{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001096 Transceiver *trx = chan->trx;
1097 size_t num = chan->num;
1098
1099 delete chan;
1100
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001101 trx->setPriority(0.40);
1102
dburgessb3a0ca42011-10-12 07:44:40 +00001103 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001104 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001105 pthread_testcancel();
1106 }
1107 return NULL;
1108}