blob: 61da416cd27b3581e65a3ac49c1cb58bcb84c754 [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)) {
Alexander Chemerisf9e78be2017-03-17 15:00:34 -0700107 chanType[n] = TSC;
Tom Tsouaf717b22016-03-06 22:19:15 -0800108 }
Thomas Tsou15d743e2014-01-25 02:34:03 -0500109 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700110
111 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400112}
113
dburgessb3a0ca42011-10-12 07:44:40 +0000114Transceiver::Transceiver(int wBasePort,
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 Tsou64464e62016-07-01 03:46:46 -0700124 mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mEdge(false), 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 */
Tom Tsou64464e62016-07-01 03:46:46 -0700163bool Transceiver::init(int filler, size_t rtsc, unsigned rach_delay, bool edge)
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
Tom Tsou64464e62016-07-01 03:46:46 -0700177 mEdge = edge;
178
Thomas Tsou204a9f12013-10-29 18:34:16 -0400179 mDataSockets.resize(mChans);
180 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400181 mControlServiceLoopThreads.resize(mChans);
182 mTxPriorityQueueServiceLoopThreads.resize(mChans);
183 mRxServiceLoopThreads.resize(mChans);
184
185 mTxPriorityQueues.resize(mChans);
186 mReceiveFIFO.resize(mChans);
187 mStates.resize(mChans);
188
Thomas Tsouccb73e12014-04-15 17:41:28 -0400189 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700190 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400191 mStates[0].mRetrans = true;
192
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800193 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400194 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500195 c_srcport = mBasePort + 2 * i + 1;
196 c_dstport = mBasePort + 2 * i + 101;
197 d_srcport = mBasePort + 2 * i + 2;
198 d_dstport = mBasePort + 2 * i + 102;
199
200 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
201 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400202 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400203
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800204 /* Randomize the central clock */
205 GSM::Time startTime(random() % gHyperframe, 0);
206 mRadioInterface->getClock()->set(startTime);
207 mTransmitDeadlineClock = startTime;
208 mLastClockUpdateTime = startTime;
209 mLatencyUpdateTime = startTime;
210
211 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400212 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800213 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400214 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800215 mControlServiceLoopThreads[i]->start((void * (*)(void*))
216 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400217
Tom Tsou64ad7122015-05-19 18:26:31 -0700218 if (i && filler == FILLER_DUMMY)
219 filler = FILLER_ZERO;
220
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300221 mStates[i].init(filler, mSPSTx, txFullScale, rtsc, rach_delay);
Thomas Tsou83e06892013-08-20 16:10:01 -0400222 }
223
224 return true;
225}
dburgessb3a0ca42011-10-12 07:44:40 +0000226
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800227/*
228 * Start the transceiver
229 *
230 * Submit command(s) to the radio device to commence streaming samples and
231 * launch threads to handle sample I/O. Re-synchronize the transmit burst
232 * counters to the central radio clock here as well.
233 */
234bool Transceiver::start()
235{
236 ScopedLock lock(mLock);
237
238 if (mOn) {
239 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300240 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800241 }
242
243 LOG(NOTICE) << "Starting the transceiver";
244
245 GSM::Time time = mRadioInterface->getClock()->get();
246 mTransmitDeadlineClock = time;
247 mLastClockUpdateTime = time;
248 mLatencyUpdateTime = time;
249
250 if (!mRadioInterface->start()) {
251 LOG(ALERT) << "Device failed to start";
252 return false;
253 }
254
255 /* Device is running - launch I/O threads */
256 mRxLowerLoopThread = new Thread(32768);
257 mTxLowerLoopThread = new Thread(32768);
258 mTxLowerLoopThread->start((void * (*)(void*))
259 TxLowerLoopAdapter,(void*) this);
260 mRxLowerLoopThread->start((void * (*)(void*))
261 RxLowerLoopAdapter,(void*) this);
262
263 /* Launch uplink and downlink burst processing threads */
264 for (size_t i = 0; i < mChans; i++) {
265 TransceiverChannel *chan = new TransceiverChannel(this, i);
266 mRxServiceLoopThreads[i] = new Thread(32768);
267 mRxServiceLoopThreads[i]->start((void * (*)(void*))
268 RxUpperLoopAdapter, (void*) chan);
269
270 chan = new TransceiverChannel(this, i);
271 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
272 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
273 TxUpperLoopAdapter, (void*) chan);
274 }
275
276 writeClockInterface();
277 mOn = true;
278 return true;
279}
280
281/*
282 * Stop the transceiver
283 *
284 * Perform stopping by disabling receive streaming and issuing cancellation
285 * requests to running threads. Most threads will timeout and terminate once
286 * device is disabled, but the transmit loop may block waiting on the central
287 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
288 * makes it to the thread cancellation point.
289 */
290void Transceiver::stop()
291{
292 ScopedLock lock(mLock);
293
294 if (!mOn)
295 return;
296
297 LOG(NOTICE) << "Stopping the transceiver";
298 mTxLowerLoopThread->cancel();
299 mRxLowerLoopThread->cancel();
Tom Tsoud67bd602017-06-15 15:35:02 -0700300 mTxLowerLoopThread->join();
301 mRxLowerLoopThread->join();
302 delete mTxLowerLoopThread;
303 delete mRxLowerLoopThread;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800304
305 for (size_t i = 0; i < mChans; i++) {
306 mRxServiceLoopThreads[i]->cancel();
307 mTxPriorityQueueServiceLoopThreads[i]->cancel();
308 }
309
310 LOG(INFO) << "Stopping the device";
311 mRadioInterface->stop();
312
313 for (size_t i = 0; i < mChans; i++) {
314 mRxServiceLoopThreads[i]->join();
315 mTxPriorityQueueServiceLoopThreads[i]->join();
316 delete mRxServiceLoopThreads[i];
317 delete mTxPriorityQueueServiceLoopThreads[i];
318
319 mTxPriorityQueues[i].clear();
320 }
321
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800322 mOn = false;
323 LOG(NOTICE) << "Transceiver stopped";
324}
325
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500326void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400327 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000328{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500329 signalVector *burst;
330 radioVector *radio_burst;
331
Thomas Tsou204a9f12013-10-29 18:34:16 -0400332 if (chan >= mTxPriorityQueues.size()) {
333 LOG(ALERT) << "Invalid channel " << chan;
334 return;
335 }
336
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500337 if (wTime.TN() > 7) {
338 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
339 return;
340 }
341
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800342 /* Use the number of bits as the EDGE burst indicator */
343 if (bits.size() == EDGE_BURST_NBITS)
344 burst = modulateEdgeBurst(bits, mSPSTx);
345 else
346 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
347
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500348 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000349
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500350 radio_burst = new radioVector(wTime, burst);
351
352 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000353}
354
Thomas Tsou15d743e2014-01-25 02:34:03 -0500355void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
356{
357 int TN, modFN;
358 TransceiverState *state = &mStates[chan];
359
360 TN = burst->getTime().TN();
361 modFN = burst->getTime().FN() % state->fillerModulus[TN];
362
363 delete state->fillerTable[modFN][TN];
364 state->fillerTable[modFN][TN] = burst->getVector();
365 burst->setVector(NULL);
366}
367
dburgessb3a0ca42011-10-12 07:44:40 +0000368void Transceiver::pushRadioVector(GSM::Time &nowTime)
369{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400370 int TN, modFN;
371 radioVector *burst;
372 TransceiverState *state;
373 std::vector<signalVector *> bursts(mChans);
374 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500375 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000376
Thomas Tsou204a9f12013-10-29 18:34:16 -0400377 for (size_t i = 0; i < mChans; i ++) {
378 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000379
Thomas Tsou204a9f12013-10-29 18:34:16 -0400380 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
381 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500382 if (state->mRetrans)
383 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500384 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400385 }
386
387 TN = nowTime.TN();
388 modFN = nowTime.FN() % state->fillerModulus[TN];
389
390 bursts[i] = state->fillerTable[modFN][TN];
391 zeros[i] = state->chanType[TN] == NONE;
392
393 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500394 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500395
396 if (state->mRetrans) {
397 updateFillerTable(i, burst);
398 } else {
399 burst->setVector(NULL);
400 filler[i] = false;
401 }
402
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500403 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400404 }
dburgessb3a0ca42011-10-12 07:44:40 +0000405 }
406
Thomas Tsou204a9f12013-10-29 18:34:16 -0400407 mRadioInterface->driveTransmitRadio(bursts, zeros);
408
Thomas Tsou15d743e2014-01-25 02:34:03 -0500409 for (size_t i = 0; i < mChans; i++) {
410 if (!filler[i])
411 delete bursts[i];
412 }
dburgessb3a0ca42011-10-12 07:44:40 +0000413}
414
Thomas Tsou204a9f12013-10-29 18:34:16 -0400415void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000416{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400417 TransceiverState *state = &mStates[chan];
418
419 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000420 case NONE:
421 case I:
422 case II:
423 case III:
424 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400425 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000426 break;
427 case IV:
428 case VI:
429 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400430 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000431 break;
432 //case V:
433 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400434 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000435 break;
ttsoufc40a842013-06-09 22:38:18 +0000436 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400437 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000438 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000439 default:
440 break;
441 }
442}
443
444
Alexander Chemerisf9e78be2017-03-17 15:00:34 -0700445CorrType Transceiver::expectedCorrType(GSM::Time currTime,
446 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000447{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300448 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 };
449 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,
450 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 };
451 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,
452 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 -0400453 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000454 unsigned burstTN = currTime.TN();
455 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300456 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000457
Thomas Tsou204a9f12013-10-29 18:34:16 -0400458 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000459 case NONE:
460 return OFF;
461 break;
462 case FILL:
463 return IDLE;
464 break;
465 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300466 // TODO: Are we expecting RACH on an IDLE frame?
467/* if (burstFN % 26 == 25)
468 return IDLE;*/
469 if (mHandover[burstTN][0])
470 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000471 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000472 break;
473 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300474 subch = tchh_subslot[burstFN % 26];
475 if (subch == 1)
476 return IDLE;
477 if (mHandover[burstTN][0])
478 return RACH;
ttsou20642972013-03-27 22:00:25 +0000479 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000480 break;
481 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300482 subch = tchh_subslot[burstFN % 26];
483 if (mHandover[burstTN][subch])
484 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000485 return TSC;
486 break;
487 case IV:
488 case VI:
489 return RACH;
490 break;
491 case V: {
492 int mod51 = burstFN % 51;
493 if ((mod51 <= 36) && (mod51 >= 14))
494 return RACH;
495 else if ((mod51 == 4) || (mod51 == 5))
496 return RACH;
497 else if ((mod51 == 45) || (mod51 == 46))
498 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300499 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
500 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000501 else
502 return TSC;
503 break;
504 }
505 case VII:
506 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
507 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300508 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
509 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000510 else
511 return TSC;
512 break;
ttsoufc40a842013-06-09 22:38:18 +0000513 case XIII: {
514 int mod52 = burstFN % 52;
515 if ((mod52 == 12) || (mod52 == 38))
516 return RACH;
517 else if ((mod52 == 25) || (mod52 == 51))
518 return IDLE;
519 else
520 return TSC;
521 break;
522 }
dburgessb3a0ca42011-10-12 07:44:40 +0000523 case LOOPBACK:
524 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
525 return IDLE;
526 else
527 return TSC;
528 break;
529 default:
530 return OFF;
531 break;
532 }
dburgessb3a0ca42011-10-12 07:44:40 +0000533}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400534
Alexander Chemerise692ce92015-06-12 00:15:31 -0400535void writeToFile(radioVector *radio_burst, size_t chan)
536{
537 GSM::Time time = radio_burst->getTime();
538 std::ostringstream fname;
539 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
540 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
541 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
542 outfile.close();
543}
544
Thomas Tsou30421a72013-11-13 23:14:48 -0500545/*
546 * Pull bursts from the FIFO and handle according to the slot
547 * and burst correlation type. Equalzation is currently disabled.
548 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400549SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400550 double &timingOffset, double &noise,
551 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000552{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800553 int rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500554 complex amp;
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +0300555 float toa, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500556 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500557 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500558 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500559 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400560 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000561
Thomas Tsou30421a72013-11-13 23:14:48 -0500562 /* Blocking FIFO read */
563 radioVector *radio_burst = mReceiveFIFO[chan]->read();
564 if (!radio_burst)
565 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000566
Thomas Tsou30421a72013-11-13 23:14:48 -0500567 /* Set time and determine correlation type */
568 GSM::Time time = radio_burst->getTime();
569 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000570
Tom Tsou64464e62016-07-01 03:46:46 -0700571 /* Enable 8-PSK burst detection if EDGE is enabled */
572 if (mEdge && (type == TSC))
573 type = EDGE;
574
Alexander Chemerise692ce92015-06-12 00:15:31 -0400575 /* Debug: dump bursts to disk */
576 /* bits 0-7 - chan 0 timeslots
577 * bits 8-15 - chan 1 timeslots */
578 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
579 writeToFile(radio_burst, chan);
580
Alexander Chemeris2b542102015-06-08 22:46:38 -0400581 /* No processing if the timeslot is off.
582 * Not even power level or noise calculation. */
583 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500584 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000585 return NULL;
586 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000587
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500588 /* Select the diversity channel with highest energy */
589 for (size_t i = 0; i < radio_burst->chans(); i++) {
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +0300590 float pow = energyDetect(*radio_burst->getVector(i), 20 * mSPSRx);
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500591 if (pow > max) {
592 max = pow;
593 max_i = i;
594 }
595 avg += pow;
596 }
597
598 if (max_i < 0) {
599 LOG(ALERT) << "Received empty burst";
600 delete radio_burst;
601 return NULL;
602 }
603
Thomas Tsou30421a72013-11-13 23:14:48 -0500604 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500605 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500606 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400607
608 wTime = time;
609 RSSI = 20.0 * log10(rxFullScale / avg);
610
611 /* RSSI estimation are valid */
612 isRssiValid = true;
613
614 if (type == IDLE) {
615 /* Update noise levels */
616 state->mNoises.insert(avg);
617 state->mNoiseLev = state->mNoises.avg();
618 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
619
620 delete radio_burst;
621 return NULL;
622 } else {
623 /* Do not update noise levels */
624 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
625 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400626
Thomas Tsou30421a72013-11-13 23:14:48 -0500627 /* Detect normal or RACH bursts */
Alexander Chemeris4e6c9382017-03-17 15:24:18 -0700628 rc = detectAnyBurst(*burst, mTSC, BURST_THRESH, mSPSRx, type, amp, toa,
629 (type==RACH)?mMaxExpectedDelayAB:mMaxExpectedDelayNB);
Thomas Tsouf0782732013-10-29 15:55:47 -0400630
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800631 if (rc > 0) {
632 type = (CorrType) rc;
633 } else if (rc <= 0) {
634 if (rc == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400635 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800636 } else if (rc != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400637 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700638 }
639
Thomas Tsou30421a72013-11-13 23:14:48 -0500640 delete radio_burst;
641 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000642 }
dburgessb3a0ca42011-10-12 07:44:40 +0000643
Tom Tsou4609f322016-07-19 11:28:51 -0700644 timingOffset = toa;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400645
Alexander Chemeris6e1dffd2017-03-17 16:13:51 -0700646 bits = demodAnyBurst(*burst, mSPSRx, amp, toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500647
Thomas Tsou30421a72013-11-13 23:14:48 -0500648 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500649 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000650}
651
dburgessb3a0ca42011-10-12 07:44:40 +0000652void Transceiver::reset()
653{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400654 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
655 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000656}
657
658
Thomas Tsou204a9f12013-10-29 18:34:16 -0400659void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000660{
dburgessb3a0ca42011-10-12 07:44:40 +0000661 int MAX_PACKET_LENGTH = 100;
662
663 // check control socket
664 char buffer[MAX_PACKET_LENGTH];
665 int msgLen = -1;
666 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400667
Tom Tsou2c650a62016-04-28 21:55:17 -0700668 msgLen = mCtrlSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000669
670 if (msgLen < 1) {
671 return;
672 }
673
674 char cmdcheck[4];
675 char command[MAX_PACKET_LENGTH];
676 char response[MAX_PACKET_LENGTH];
677
678 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400679
680 if (!chan)
681 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000682
683 if (strcmp(cmdcheck,"CMD")!=0) {
684 LOG(WARNING) << "bogus message on control interface";
685 return;
686 }
687 LOG(INFO) << "command is " << buffer;
688
689 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800690 stop();
691 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000692 }
693 else if (strcmp(command,"POWERON")==0) {
Tom Tsou365bc382016-10-19 15:26:04 -0700694 if (!start()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000695 sprintf(response,"RSP POWERON 1");
Tom Tsou365bc382016-10-19 15:26:04 -0700696 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000697 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300698 for (int i = 0; i < 8; i++) {
699 for (int j = 0; j < 8; j++)
700 mHandover[i][j] = false;
701 }
Tom Tsou365bc382016-10-19 15:26:04 -0700702 }
Alexander Chemeris5a068062015-06-20 01:38:47 +0300703 }
704 else if (strcmp(command,"HANDOVER")==0){
705 int ts=0,ss=0;
706 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
707 mHandover[ts][ss] = true;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300708 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
709 }
710 else if (strcmp(command,"NOHANDOVER")==0){
711 int ts=0,ss=0;
712 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
713 mHandover[ts][ss] = false;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300714 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000715 }
716 else if (strcmp(command,"SETMAXDLY")==0) {
717 //set expected maximum time-of-arrival
718 int maxDelay;
719 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300720 mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
dburgessb3a0ca42011-10-12 07:44:40 +0000721 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
722 }
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300723 else if (strcmp(command,"SETMAXDLYNB")==0) {
724 //set expected maximum time-of-arrival
725 int maxDelay;
726 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
727 mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
728 sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
729 }
dburgessb3a0ca42011-10-12 07:44:40 +0000730 else if (strcmp(command,"SETRXGAIN")==0) {
731 //set expected maximum time-of-arrival
732 int newGain;
733 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400734 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000735 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
736 }
737 else if (strcmp(command,"NOISELEV")==0) {
738 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500739 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000740 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500741 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000742 }
743 else {
744 sprintf(response,"RSP NOISELEV 1 0");
745 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500746 }
747 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800748 int power;
749 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
750 power = mRadioInterface->setPowerAttenuation(power, chan);
751 mStates[chan].mPower = power;
752 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000753 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500754 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800755 int power, step;
756 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
757 power = mStates[chan].mPower + step;
758 power = mRadioInterface->setPowerAttenuation(power, chan);
759 mStates[chan].mPower = power;
760 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000761 }
dburgessb3a0ca42011-10-12 07:44:40 +0000762 else if (strcmp(command,"RXTUNE")==0) {
763 // tune receiver
764 int freqKhz;
765 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500766 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400767 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000768 LOG(ALERT) << "RX failed to tune";
769 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
770 }
771 else
772 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
773 }
774 else if (strcmp(command,"TXTUNE")==0) {
775 // tune txmtr
776 int freqKhz;
777 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500778 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400779 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000780 LOG(ALERT) << "TX failed to tune";
781 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
782 }
783 else
784 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
785 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500786 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000787 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500788 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500789 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Tom Tsou60317342017-03-30 19:36:41 -0700790 if (TSC > 7) {
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500791 sprintf(response, "RSP SETTSC 1 %d", TSC);
Tom Tsou60317342017-03-30 19:36:41 -0700792 } else {
Tom Tsouc37594f2016-07-08 14:39:42 -0700793 LOG(NOTICE) << "Changing TSC from " << mTSC << " to " << TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000794 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400795 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000796 }
797 }
798 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700799 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000800 int corrCode;
801 int timeslot;
802 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
803 if ((timeslot < 0) || (timeslot > 7)) {
804 LOG(WARNING) << "bogus message on control interface";
805 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
806 return;
807 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400808 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
809 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000810 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
811
812 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400813 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
814 // debug command! may change or disapear without notice
815 // set a mask which bursts to dump to disk
816 int mask;
817 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
818 mWriteBurstToDiskMask = mask;
819 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
820 }
dburgessb3a0ca42011-10-12 07:44:40 +0000821 else {
822 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200823 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000824 }
825
Thomas Tsou204a9f12013-10-29 18:34:16 -0400826 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000827}
828
Thomas Tsou204a9f12013-10-29 18:34:16 -0400829bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000830{
Tom Tsoue8871082016-07-01 02:46:04 -0700831 int burstLen;
832 char buffer[EDGE_BURST_NBITS + 50];
dburgessb3a0ca42011-10-12 07:44:40 +0000833
834 // check data socket
Tom Tsou2c650a62016-04-28 21:55:17 -0700835 size_t msgLen = mDataSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000836
Tom Tsoue8871082016-07-01 02:46:04 -0700837 if (msgLen == gSlotLen + 1 + 4 + 1) {
838 burstLen = gSlotLen;
839 } else if (msgLen == EDGE_BURST_NBITS + 1 + 4 + 1) {
840 if (mSPSTx != 4)
841 return false;
842
843 burstLen = EDGE_BURST_NBITS;
844 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000845 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
846 return false;
847 }
848
849 int timeSlot = (int) buffer[0];
850 uint64_t frameNum = 0;
851 for (int i = 0; i < 4; i++)
852 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000853
dburgessb3a0ca42011-10-12 07:44:40 +0000854 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
855
856 int RSSI = (int) buffer[5];
Tom Tsou7c741ec2016-07-19 11:20:59 -0700857 BitVector newBurst(burstLen);
dburgessb3a0ca42011-10-12 07:44:40 +0000858 BitVector::iterator itr = newBurst.begin();
859 char *bufferItr = buffer+6;
860 while (itr < newBurst.end())
861 *itr++ = *bufferItr++;
862
863 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400864
865 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000866
867 return true;
868
869
870}
dburgessb3a0ca42011-10-12 07:44:40 +0000871
Thomas Tsou204a9f12013-10-29 18:34:16 -0400872void Transceiver::driveReceiveRadio()
873{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400874 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400875 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400876 } else {
877 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
878 writeClockInterface();
879 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400880}
881
Alexander Chemeris58e95912016-03-25 18:20:28 +0300882void Transceiver::logRxBurst(size_t chan, SoftVector *burst, GSM::Time time, double dbm,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800883 double rssi, double noise, double toa)
884{
885 LOG(DEBUG) << std::fixed << std::right
Alexander Chemeris58e95912016-03-25 18:20:28 +0300886 << " chan: " << chan
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800887 << " time: " << time
888 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
889 << "dBFS/" << std::setw(6) << -dbm << "dBm"
890 << " noise: " << std::setw(5) << std::setprecision(1) << noise
891 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
892 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
893 << " bits: " << *burst;
894}
895
Thomas Tsou204a9f12013-10-29 18:34:16 -0400896void Transceiver::driveReceiveFIFO(size_t chan)
897{
dburgessb3a0ca42011-10-12 07:44:40 +0000898 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400899 double RSSI; // in dBFS
900 double dBm; // in dBm
901 double TOA; // in symbols
902 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400903 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000904 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400905 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800906 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000907
Alexander Chemeris2b542102015-06-08 22:46:38 -0400908 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800909 if (!rxBurst)
910 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000911
Alexander Chemerisb61c6102017-03-17 18:22:19 -0700912 // Convert -1..+1 soft bits to 0..1 soft bits
913 vectorSlicer(rxBurst);
914
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800915 /*
916 * EDGE demodulator returns 444 (148 * 3) bits
917 */
918 if (rxBurst->size() == gSlotLen * 3)
919 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000920
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800921 dBm = RSSI + rssiOffset;
Alexander Chemeris58e95912016-03-25 18:20:28 +0300922 logRxBurst(chan, rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400923
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800924 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000925
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800926 char burstString[nbits + 10];
927 burstString[0] = burstTime.TN();
928 for (int i = 0; i < 4; i++)
929 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
930 burstString[5] = (int)dBm;
931 burstString[6] = (TOAint >> 8) & 0x0ff;
932 burstString[7] = TOAint & 0x0ff;
933 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000934
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800935 for (unsigned i = 0; i < nbits; i++)
936 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
937
938 burstString[nbits + 9] = '\0';
939 delete rxBurst;
940
941 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000942}
943
Thomas Tsou204a9f12013-10-29 18:34:16 -0400944void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000945{
946
947 /**
948 Features a carefully controlled latency mechanism, to
949 assure that transmit packets arrive at the radio/USRP
950 before they need to be transmitted.
951
952 Deadline clock indicates the burst that needs to be
953 pushed into the FIFO right NOW. If transmit queue does
954 not have a burst, stick in filler data.
955 */
956
957
958 RadioClock *radioClock = (mRadioInterface->getClock());
959
960 if (mOn) {
961 //radioClock->wait(); // wait until clock updates
962 LOG(DEBUG) << "radio clock " << radioClock->get();
963 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
964 // if underrun, then we're not providing bursts to radio/USRP fast
965 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400966 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000967 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000968 // only update latency at the defined frame interval
969 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000970 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
971 LOG(INFO) << "new latency: " << mTransmitLatency;
972 mLatencyUpdateTime = radioClock->get();
973 }
974 }
975 else {
976 // if underrun hasn't occurred in the last sec (216 frames) drop
977 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000978 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000979 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
980 mTransmitLatency.decTN();
981 LOG(INFO) << "reduced latency: " << mTransmitLatency;
982 mLatencyUpdateTime = radioClock->get();
983 }
984 }
985 }
dburgessb3a0ca42011-10-12 07:44:40 +0000986 }
dburgessb3a0ca42011-10-12 07:44:40 +0000987 // time to push burst to transmit FIFO
988 pushRadioVector(mTransmitDeadlineClock);
989 mTransmitDeadlineClock.incTN();
990 }
dburgessb3a0ca42011-10-12 07:44:40 +0000991 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400992
993 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000994}
995
996
997
998void Transceiver::writeClockInterface()
999{
1000 char command[50];
1001 // FIXME -- This should be adaptive.
1002 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1003
1004 LOG(INFO) << "ClockInterface: sending " << command;
1005
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001006 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001007
1008 mLastClockUpdateTime = mTransmitDeadlineClock;
1009
Thomas Tsou92c16df2013-09-28 18:04:19 -04001010}
dburgessb3a0ca42011-10-12 07:44:40 +00001011
Thomas Tsou204a9f12013-10-29 18:34:16 -04001012void *RxUpperLoopAdapter(TransceiverChannel *chan)
1013{
1014 Transceiver *trx = chan->trx;
1015 size_t num = chan->num;
1016
1017 delete chan;
1018
Thomas Tsou7553aa92013-11-08 12:50:03 -05001019 trx->setPriority(0.42);
1020
Thomas Tsou204a9f12013-10-29 18:34:16 -04001021 while (1) {
1022 trx->driveReceiveFIFO(num);
1023 pthread_testcancel();
1024 }
1025 return NULL;
1026}
1027
1028void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001029{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001030 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001031
dburgessb3a0ca42011-10-12 07:44:40 +00001032 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001033 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001034 pthread_testcancel();
1035 }
1036 return NULL;
1037}
1038
Thomas Tsou204a9f12013-10-29 18:34:16 -04001039void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001040{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001041 transceiver->setPriority(0.44);
1042
Thomas Tsou92c16df2013-09-28 18:04:19 -04001043 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001044 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001045 pthread_testcancel();
1046 }
1047 return NULL;
1048}
1049
Thomas Tsou204a9f12013-10-29 18:34:16 -04001050void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001051{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001052 Transceiver *trx = chan->trx;
1053 size_t num = chan->num;
1054
1055 delete chan;
1056
dburgessb3a0ca42011-10-12 07:44:40 +00001057 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001058 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001059 pthread_testcancel();
1060 }
1061 return NULL;
1062}
1063
Thomas Tsou204a9f12013-10-29 18:34:16 -04001064void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001065{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001066 Transceiver *trx = chan->trx;
1067 size_t num = chan->num;
1068
1069 delete chan;
1070
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001071 trx->setPriority(0.40);
1072
dburgessb3a0ca42011-10-12 07:44:40 +00001073 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001074 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001075 pthread_testcancel();
1076 }
1077 return NULL;
1078}