blob: a9e7035db5fc41a8dc6c2bae7f64713c9acd65d2 [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
Tom Tsou64ad7122015-05-19 18:26:31 -070074bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc)
75{
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;
87 case Transceiver::FILLER_RAND:
Tom Tsou8ee2f382016-03-06 20:57:34 -080088 burst = genRandNormalBurst(rtsc, sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070089 break;
90 case Transceiver::FILLER_ZERO:
91 default:
Tom Tsou8ee2f382016-03-06 20:57:34 -080092 burst = generateEmptyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070093 }
94
95 scaleVector(*burst, scale);
96 fillerTable[i][n] = burst;
97 }
98
99 if (filler == Transceiver::FILLER_RAND)
100 chanType[n] = Transceiver::TSC;
Thomas Tsou15d743e2014-01-25 02:34:03 -0500101 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700102
103 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400104}
105
dburgessb3a0ca42011-10-12 07:44:40 +0000106Transceiver::Transceiver(int wBasePort,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400107 const char *wTRXAddress,
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800108 size_t tx_sps, size_t rx_sps, size_t chans,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400109 GSM::Time wTransmitLatency,
110 RadioInterface *wRadioInterface,
111 double wRssiOffset)
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800112 : mBasePort(wBasePort), mAddr(wTRXAddress),
113 mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
114 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Alexander Chemerise8905a02015-06-03 23:47:56 -0400115 rssiOffset(wRssiOffset),
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800116 mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mOn(false),
Alexander Chemerise692ce92015-06-12 00:15:31 -0400117 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0), mWriteBurstToDiskMask(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000118{
dburgessb3a0ca42011-10-12 07:44:40 +0000119 txFullScale = mRadioInterface->fullScaleInputValue();
120 rxFullScale = mRadioInterface->fullScaleOutputValue();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300121
122 for (int i = 0; i < 8; i++) {
123 for (int j = 0; j < 8; j++)
124 mHandover[i][j] = false;
125 }
dburgessb3a0ca42011-10-12 07:44:40 +0000126}
127
128Transceiver::~Transceiver()
129{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800130 stop();
131
dburgessb3a0ca42011-10-12 07:44:40 +0000132 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400133
Thomas Tsou204a9f12013-10-29 18:34:16 -0400134 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800135 mControlServiceLoopThreads[i]->cancel();
136 mControlServiceLoopThreads[i]->join();
137 delete mControlServiceLoopThreads[i];
138
Thomas Tsou204a9f12013-10-29 18:34:16 -0400139 mTxPriorityQueues[i].clear();
140 delete mCtrlSockets[i];
141 delete mDataSockets[i];
142 }
dburgessb3a0ca42011-10-12 07:44:40 +0000143}
Thomas Tsou83e06892013-08-20 16:10:01 -0400144
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800145/*
146 * Initialize transceiver
147 *
148 * Start or restart the control loop. Any further control is handled through the
149 * socket API. Randomize the central radio clock set the downlink burst
150 * counters. Note that the clock will not update until the radio starts, but we
151 * are still expected to report clock indications through control channel
152 * activity.
153 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700154bool Transceiver::init(int filler, size_t rtsc)
Thomas Tsou83e06892013-08-20 16:10:01 -0400155{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500156 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400157
Thomas Tsou204a9f12013-10-29 18:34:16 -0400158 if (!mChans) {
159 LOG(ALERT) << "No channels assigned";
160 return false;
161 }
162
Tom Tsou2079a3c2016-03-06 00:58:56 -0800163 if (!sigProcLibSetup()) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400164 LOG(ALERT) << "Failed to initialize signal processing library";
165 return false;
166 }
167
Thomas Tsou204a9f12013-10-29 18:34:16 -0400168 mDataSockets.resize(mChans);
169 mCtrlSockets.resize(mChans);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400170 mControlServiceLoopThreads.resize(mChans);
171 mTxPriorityQueueServiceLoopThreads.resize(mChans);
172 mRxServiceLoopThreads.resize(mChans);
173
174 mTxPriorityQueues.resize(mChans);
175 mReceiveFIFO.resize(mChans);
176 mStates.resize(mChans);
177
Thomas Tsouccb73e12014-04-15 17:41:28 -0400178 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700179 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400180 mStates[0].mRetrans = true;
181
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800182 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400183 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500184 c_srcport = mBasePort + 2 * i + 1;
185 c_dstport = mBasePort + 2 * i + 101;
186 d_srcport = mBasePort + 2 * i + 2;
187 d_dstport = mBasePort + 2 * i + 102;
188
189 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
190 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400191 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400192
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800193 /* Randomize the central clock */
194 GSM::Time startTime(random() % gHyperframe, 0);
195 mRadioInterface->getClock()->set(startTime);
196 mTransmitDeadlineClock = startTime;
197 mLastClockUpdateTime = startTime;
198 mLatencyUpdateTime = startTime;
199
200 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400201 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800202 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400203 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800204 mControlServiceLoopThreads[i]->start((void * (*)(void*))
205 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400206
Tom Tsou64ad7122015-05-19 18:26:31 -0700207 if (i && filler == FILLER_DUMMY)
208 filler = FILLER_ZERO;
209
210 mStates[i].init(filler, mSPSTx, txFullScale, rtsc);
Thomas Tsou83e06892013-08-20 16:10:01 -0400211 }
212
213 return true;
214}
dburgessb3a0ca42011-10-12 07:44:40 +0000215
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800216/*
217 * Start the transceiver
218 *
219 * Submit command(s) to the radio device to commence streaming samples and
220 * launch threads to handle sample I/O. Re-synchronize the transmit burst
221 * counters to the central radio clock here as well.
222 */
223bool Transceiver::start()
224{
225 ScopedLock lock(mLock);
226
227 if (mOn) {
228 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300229 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800230 }
231
232 LOG(NOTICE) << "Starting the transceiver";
233
234 GSM::Time time = mRadioInterface->getClock()->get();
235 mTransmitDeadlineClock = time;
236 mLastClockUpdateTime = time;
237 mLatencyUpdateTime = time;
238
239 if (!mRadioInterface->start()) {
240 LOG(ALERT) << "Device failed to start";
241 return false;
242 }
243
244 /* Device is running - launch I/O threads */
245 mRxLowerLoopThread = new Thread(32768);
246 mTxLowerLoopThread = new Thread(32768);
247 mTxLowerLoopThread->start((void * (*)(void*))
248 TxLowerLoopAdapter,(void*) this);
249 mRxLowerLoopThread->start((void * (*)(void*))
250 RxLowerLoopAdapter,(void*) this);
251
252 /* Launch uplink and downlink burst processing threads */
253 for (size_t i = 0; i < mChans; i++) {
254 TransceiverChannel *chan = new TransceiverChannel(this, i);
255 mRxServiceLoopThreads[i] = new Thread(32768);
256 mRxServiceLoopThreads[i]->start((void * (*)(void*))
257 RxUpperLoopAdapter, (void*) chan);
258
259 chan = new TransceiverChannel(this, i);
260 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
261 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
262 TxUpperLoopAdapter, (void*) chan);
263 }
264
265 writeClockInterface();
266 mOn = true;
267 return true;
268}
269
270/*
271 * Stop the transceiver
272 *
273 * Perform stopping by disabling receive streaming and issuing cancellation
274 * requests to running threads. Most threads will timeout and terminate once
275 * device is disabled, but the transmit loop may block waiting on the central
276 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
277 * makes it to the thread cancellation point.
278 */
279void Transceiver::stop()
280{
281 ScopedLock lock(mLock);
282
283 if (!mOn)
284 return;
285
286 LOG(NOTICE) << "Stopping the transceiver";
287 mTxLowerLoopThread->cancel();
288 mRxLowerLoopThread->cancel();
289
290 for (size_t i = 0; i < mChans; i++) {
291 mRxServiceLoopThreads[i]->cancel();
292 mTxPriorityQueueServiceLoopThreads[i]->cancel();
293 }
294
295 LOG(INFO) << "Stopping the device";
296 mRadioInterface->stop();
297
298 for (size_t i = 0; i < mChans; i++) {
299 mRxServiceLoopThreads[i]->join();
300 mTxPriorityQueueServiceLoopThreads[i]->join();
301 delete mRxServiceLoopThreads[i];
302 delete mTxPriorityQueueServiceLoopThreads[i];
303
304 mTxPriorityQueues[i].clear();
305 }
306
307 mTxLowerLoopThread->join();
308 mRxLowerLoopThread->join();
309 delete mTxLowerLoopThread;
310 delete mRxLowerLoopThread;
311
312 mOn = false;
313 LOG(NOTICE) << "Transceiver stopped";
314}
315
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500316void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400317 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000318{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500319 signalVector *burst;
320 radioVector *radio_burst;
321
Thomas Tsou204a9f12013-10-29 18:34:16 -0400322 if (chan >= mTxPriorityQueues.size()) {
323 LOG(ALERT) << "Invalid channel " << chan;
324 return;
325 }
326
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500327 if (wTime.TN() > 7) {
328 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
329 return;
330 }
331
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800332 /* Use the number of bits as the EDGE burst indicator */
333 if (bits.size() == EDGE_BURST_NBITS)
334 burst = modulateEdgeBurst(bits, mSPSTx);
335 else
336 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
337
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500338 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000339
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500340 radio_burst = new radioVector(wTime, burst);
341
342 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000343}
344
Thomas Tsou15d743e2014-01-25 02:34:03 -0500345void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
346{
347 int TN, modFN;
348 TransceiverState *state = &mStates[chan];
349
350 TN = burst->getTime().TN();
351 modFN = burst->getTime().FN() % state->fillerModulus[TN];
352
353 delete state->fillerTable[modFN][TN];
354 state->fillerTable[modFN][TN] = burst->getVector();
355 burst->setVector(NULL);
356}
357
dburgessb3a0ca42011-10-12 07:44:40 +0000358void Transceiver::pushRadioVector(GSM::Time &nowTime)
359{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400360 int TN, modFN;
361 radioVector *burst;
362 TransceiverState *state;
363 std::vector<signalVector *> bursts(mChans);
364 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500365 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000366
Thomas Tsou204a9f12013-10-29 18:34:16 -0400367 for (size_t i = 0; i < mChans; i ++) {
368 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000369
Thomas Tsou204a9f12013-10-29 18:34:16 -0400370 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
371 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500372 if (state->mRetrans)
373 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500374 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400375 }
376
377 TN = nowTime.TN();
378 modFN = nowTime.FN() % state->fillerModulus[TN];
379
380 bursts[i] = state->fillerTable[modFN][TN];
381 zeros[i] = state->chanType[TN] == NONE;
382
383 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500384 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500385
386 if (state->mRetrans) {
387 updateFillerTable(i, burst);
388 } else {
389 burst->setVector(NULL);
390 filler[i] = false;
391 }
392
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500393 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400394 }
dburgessb3a0ca42011-10-12 07:44:40 +0000395 }
396
Thomas Tsou204a9f12013-10-29 18:34:16 -0400397 mRadioInterface->driveTransmitRadio(bursts, zeros);
398
Thomas Tsou15d743e2014-01-25 02:34:03 -0500399 for (size_t i = 0; i < mChans; i++) {
400 if (!filler[i])
401 delete bursts[i];
402 }
dburgessb3a0ca42011-10-12 07:44:40 +0000403}
404
Thomas Tsou204a9f12013-10-29 18:34:16 -0400405void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000406{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400407 TransceiverState *state = &mStates[chan];
408
409 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000410 case NONE:
411 case I:
412 case II:
413 case III:
414 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400415 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000416 break;
417 case IV:
418 case VI:
419 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400420 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000421 break;
422 //case V:
423 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400424 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000425 break;
ttsoufc40a842013-06-09 22:38:18 +0000426 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400427 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000428 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000429 default:
430 break;
431 }
432}
433
434
Thomas Tsou204a9f12013-10-29 18:34:16 -0400435Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
436 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000437{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300438 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 };
439 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,
440 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 };
441 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,
442 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 -0400443 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000444 unsigned burstTN = currTime.TN();
445 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300446 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000447
Thomas Tsou204a9f12013-10-29 18:34:16 -0400448 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000449 case NONE:
450 return OFF;
451 break;
452 case FILL:
453 return IDLE;
454 break;
455 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300456 // TODO: Are we expecting RACH on an IDLE frame?
457/* if (burstFN % 26 == 25)
458 return IDLE;*/
459 if (mHandover[burstTN][0])
460 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000461 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000462 break;
463 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300464 subch = tchh_subslot[burstFN % 26];
465 if (subch == 1)
466 return IDLE;
467 if (mHandover[burstTN][0])
468 return RACH;
ttsou20642972013-03-27 22:00:25 +0000469 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000470 break;
471 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300472 subch = tchh_subslot[burstFN % 26];
473 if (mHandover[burstTN][subch])
474 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000475 return TSC;
476 break;
477 case IV:
478 case VI:
479 return RACH;
480 break;
481 case V: {
482 int mod51 = burstFN % 51;
483 if ((mod51 <= 36) && (mod51 >= 14))
484 return RACH;
485 else if ((mod51 == 4) || (mod51 == 5))
486 return RACH;
487 else if ((mod51 == 45) || (mod51 == 46))
488 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300489 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
490 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000491 else
492 return TSC;
493 break;
494 }
495 case VII:
496 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
497 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300498 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
499 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000500 else
501 return TSC;
502 break;
ttsoufc40a842013-06-09 22:38:18 +0000503 case XIII: {
504 int mod52 = burstFN % 52;
505 if ((mod52 == 12) || (mod52 == 38))
506 return RACH;
507 else if ((mod52 == 25) || (mod52 == 51))
508 return IDLE;
509 else
510 return TSC;
511 break;
512 }
dburgessb3a0ca42011-10-12 07:44:40 +0000513 case LOOPBACK:
514 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
515 return IDLE;
516 else
517 return TSC;
518 break;
519 default:
520 return OFF;
521 break;
522 }
dburgessb3a0ca42011-10-12 07:44:40 +0000523}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400524
Tom Tsou46569402016-03-06 01:59:38 -0800525int Transceiver::detectBurst(TransceiverState *state, signalVector &burst,
526 complex &amp, float &toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500527{
Tom Tsou46569402016-03-06 01:59:38 -0800528 float threshold = 5.0, rc = 0;
Thomas Tsou30421a72013-11-13 23:14:48 -0500529
Tom Tsou46569402016-03-06 01:59:38 -0800530 switch (type) {
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800531 case EDGE:
532 rc = detectEdgeBurst(burst, mTSC, threshold, mSPSRx,
533 amp, toa, mMaxExpectedDelay);
534 if (rc > 0)
535 break;
536 else
537 type = TSC;
Tom Tsou46569402016-03-06 01:59:38 -0800538 case TSC:
539 rc = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx,
540 amp, toa, mMaxExpectedDelay);
541 break;
542 case RACH:
543 threshold = 6.0;
544 rc = detectRACHBurst(burst, threshold, mSPSRx, amp, toa);
545 break;
546 default:
547 LOG(ERR) << "Invalid correlation type";
548 }
549
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800550 if (rc > 0)
551 return type;
Tom Tsou46569402016-03-06 01:59:38 -0800552
553 return rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500554}
555
Thomas Tsou30421a72013-11-13 23:14:48 -0500556
557/*
Tom Tsou46569402016-03-06 01:59:38 -0800558 * Demodulate GMSK by direct rotation and soft slicing.
Thomas Tsou30421a72013-11-13 23:14:48 -0500559 */
560SoftVector *Transceiver::demodulate(TransceiverState *state,
561 signalVector &burst, complex amp,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800562 float toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500563{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800564 if (type == EDGE)
565 return demodEdgeBurst(burst, mSPSRx, amp, toa);
566
Thomas Tsou30421a72013-11-13 23:14:48 -0500567 return demodulateBurst(burst, mSPSRx, amp, toa);
568}
569
Alexander Chemerise692ce92015-06-12 00:15:31 -0400570void writeToFile(radioVector *radio_burst, size_t chan)
571{
572 GSM::Time time = radio_burst->getTime();
573 std::ostringstream fname;
574 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
575 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
576 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
577 outfile.close();
578}
579
Thomas Tsou30421a72013-11-13 23:14:48 -0500580/*
581 * Pull bursts from the FIFO and handle according to the slot
582 * and burst correlation type. Equalzation is currently disabled.
583 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400584SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400585 double &timingOffset, double &noise,
586 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000587{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800588 int rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500589 complex amp;
590 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500591 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500592 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500593 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500594 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400595 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000596
Thomas Tsou30421a72013-11-13 23:14:48 -0500597 /* Blocking FIFO read */
598 radioVector *radio_burst = mReceiveFIFO[chan]->read();
599 if (!radio_burst)
600 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000601
Thomas Tsou30421a72013-11-13 23:14:48 -0500602 /* Set time and determine correlation type */
603 GSM::Time time = radio_burst->getTime();
604 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000605
Alexander Chemerise692ce92015-06-12 00:15:31 -0400606 /* Debug: dump bursts to disk */
607 /* bits 0-7 - chan 0 timeslots
608 * bits 8-15 - chan 1 timeslots */
609 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
610 writeToFile(radio_burst, chan);
611
Alexander Chemeris2b542102015-06-08 22:46:38 -0400612 /* No processing if the timeslot is off.
613 * Not even power level or noise calculation. */
614 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500615 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000616 return NULL;
617 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000618
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500619 /* Select the diversity channel with highest energy */
620 for (size_t i = 0; i < radio_burst->chans(); i++) {
621 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
622 if (pow > max) {
623 max = pow;
624 max_i = i;
625 }
626 avg += pow;
627 }
628
629 if (max_i < 0) {
630 LOG(ALERT) << "Received empty burst";
631 delete radio_burst;
632 return NULL;
633 }
634
Thomas Tsou30421a72013-11-13 23:14:48 -0500635 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500636 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500637 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400638
639 wTime = time;
640 RSSI = 20.0 * log10(rxFullScale / avg);
641
642 /* RSSI estimation are valid */
643 isRssiValid = true;
644
645 if (type == IDLE) {
646 /* Update noise levels */
647 state->mNoises.insert(avg);
648 state->mNoiseLev = state->mNoises.avg();
649 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
650
651 delete radio_burst;
652 return NULL;
653 } else {
654 /* Do not update noise levels */
655 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
656 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400657
Thomas Tsou30421a72013-11-13 23:14:48 -0500658 /* Detect normal or RACH bursts */
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800659 rc = detectBurst(state, *burst, amp, toa, type);
Thomas Tsouf0782732013-10-29 15:55:47 -0400660
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800661 if (rc > 0) {
662 type = (CorrType) rc;
663 } else if (rc <= 0) {
664 if (rc == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400665 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800666 } else if (rc != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400667 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700668 }
669
Thomas Tsou30421a72013-11-13 23:14:48 -0500670 delete radio_burst;
671 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000672 }
dburgessb3a0ca42011-10-12 07:44:40 +0000673
Alexander Chemeris2b542102015-06-08 22:46:38 -0400674 timingOffset = toa / mSPSRx;
675
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800676 bits = demodulate(state, *burst, amp, toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500677
Thomas Tsou30421a72013-11-13 23:14:48 -0500678 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500679 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000680}
681
dburgessb3a0ca42011-10-12 07:44:40 +0000682void Transceiver::reset()
683{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400684 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
685 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000686}
687
688
Thomas Tsou204a9f12013-10-29 18:34:16 -0400689void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000690{
dburgessb3a0ca42011-10-12 07:44:40 +0000691 int MAX_PACKET_LENGTH = 100;
692
693 // check control socket
694 char buffer[MAX_PACKET_LENGTH];
695 int msgLen = -1;
696 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400697
Thomas Tsou204a9f12013-10-29 18:34:16 -0400698 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000699
700 if (msgLen < 1) {
701 return;
702 }
703
704 char cmdcheck[4];
705 char command[MAX_PACKET_LENGTH];
706 char response[MAX_PACKET_LENGTH];
707
708 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400709
710 if (!chan)
711 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000712
713 if (strcmp(cmdcheck,"CMD")!=0) {
714 LOG(WARNING) << "bogus message on control interface";
715 return;
716 }
717 LOG(INFO) << "command is " << buffer;
718
719 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800720 stop();
721 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000722 }
723 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800724 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000725 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800726 else
dburgessb3a0ca42011-10-12 07:44:40 +0000727 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300728 for (int i = 0; i < 8; i++) {
729 for (int j = 0; j < 8; j++)
730 mHandover[i][j] = false;
731 }
732 }
733 else if (strcmp(command,"HANDOVER")==0){
734 int ts=0,ss=0;
735 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
736 mHandover[ts][ss] = true;
737 LOG(WARNING) << "HANDOVER RACH at timeslot " << ts << " subslot " << ss;
738 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
739 }
740 else if (strcmp(command,"NOHANDOVER")==0){
741 int ts=0,ss=0;
742 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
743 mHandover[ts][ss] = false;
744 LOG(WARNING) << "NOHANDOVER at timeslot " << ts << " subslot " << ss;
745 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000746 }
747 else if (strcmp(command,"SETMAXDLY")==0) {
748 //set expected maximum time-of-arrival
749 int maxDelay;
750 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
751 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
752 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
753 }
754 else if (strcmp(command,"SETRXGAIN")==0) {
755 //set expected maximum time-of-arrival
756 int newGain;
757 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400758 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000759 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
760 }
761 else if (strcmp(command,"NOISELEV")==0) {
762 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500763 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000764 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500765 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000766 }
767 else {
768 sprintf(response,"RSP NOISELEV 1 0");
769 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500770 }
771 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800772 int power;
773 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
774 power = mRadioInterface->setPowerAttenuation(power, chan);
775 mStates[chan].mPower = power;
776 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000777 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500778 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800779 int power, step;
780 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
781 power = mStates[chan].mPower + step;
782 power = mRadioInterface->setPowerAttenuation(power, chan);
783 mStates[chan].mPower = power;
784 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000785 }
dburgessb3a0ca42011-10-12 07:44:40 +0000786 else if (strcmp(command,"RXTUNE")==0) {
787 // tune receiver
788 int freqKhz;
789 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500790 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400791 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000792 LOG(ALERT) << "RX failed to tune";
793 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
794 }
795 else
796 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
797 }
798 else if (strcmp(command,"TXTUNE")==0) {
799 // tune txmtr
800 int freqKhz;
801 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500802 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400803 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000804 LOG(ALERT) << "TX failed to tune";
805 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
806 }
807 else
808 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
809 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500810 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000811 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500812 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500813 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700814 if (mOn || (TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500815 sprintf(response, "RSP SETTSC 1 %d", TSC);
816 else if (chan && (TSC != mTSC))
817 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000818 else {
819 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400820 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000821 }
822 }
823 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700824 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000825 int corrCode;
826 int timeslot;
827 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
828 if ((timeslot < 0) || (timeslot > 7)) {
829 LOG(WARNING) << "bogus message on control interface";
830 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
831 return;
832 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400833 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
834 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000835 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
836
837 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400838 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
839 // debug command! may change or disapear without notice
840 // set a mask which bursts to dump to disk
841 int mask;
842 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
843 mWriteBurstToDiskMask = mask;
844 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
845 }
dburgessb3a0ca42011-10-12 07:44:40 +0000846 else {
847 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200848 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000849 }
850
Thomas Tsou204a9f12013-10-29 18:34:16 -0400851 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000852}
853
Thomas Tsou204a9f12013-10-29 18:34:16 -0400854bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000855{
dburgessb3a0ca42011-10-12 07:44:40 +0000856 char buffer[gSlotLen+50];
857
858 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400859 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000860
861 if (msgLen!=gSlotLen+1+4+1) {
862 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
863 return false;
864 }
865
866 int timeSlot = (int) buffer[0];
867 uint64_t frameNum = 0;
868 for (int i = 0; i < 4; i++)
869 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000870
dburgessb3a0ca42011-10-12 07:44:40 +0000871 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
872
873 int RSSI = (int) buffer[5];
874 static BitVector newBurst(gSlotLen);
875 BitVector::iterator itr = newBurst.begin();
876 char *bufferItr = buffer+6;
877 while (itr < newBurst.end())
878 *itr++ = *bufferItr++;
879
880 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400881
882 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000883
884 return true;
885
886
887}
dburgessb3a0ca42011-10-12 07:44:40 +0000888
Thomas Tsou204a9f12013-10-29 18:34:16 -0400889void Transceiver::driveReceiveRadio()
890{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400891 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400892 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400893 } else {
894 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
895 writeClockInterface();
896 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400897}
898
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800899void Transceiver::logRxBurst(SoftVector *burst, GSM::Time time, double dbm,
900 double rssi, double noise, double toa)
901{
902 LOG(DEBUG) << std::fixed << std::right
903 << " time: " << time
904 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
905 << "dBFS/" << std::setw(6) << -dbm << "dBm"
906 << " noise: " << std::setw(5) << std::setprecision(1) << noise
907 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
908 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
909 << " bits: " << *burst;
910}
911
Thomas Tsou204a9f12013-10-29 18:34:16 -0400912void Transceiver::driveReceiveFIFO(size_t chan)
913{
dburgessb3a0ca42011-10-12 07:44:40 +0000914 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400915 double RSSI; // in dBFS
916 double dBm; // in dBm
917 double TOA; // in symbols
918 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400919 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000920 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400921 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800922 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000923
Alexander Chemeris2b542102015-06-08 22:46:38 -0400924 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800925 if (!rxBurst)
926 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000927
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800928 /*
929 * EDGE demodulator returns 444 (148 * 3) bits
930 */
931 if (rxBurst->size() == gSlotLen * 3)
932 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000933
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800934 dBm = RSSI + rssiOffset;
935 logRxBurst(rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400936
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800937 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000938
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800939 char burstString[nbits + 10];
940 burstString[0] = burstTime.TN();
941 for (int i = 0; i < 4; i++)
942 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
943 burstString[5] = (int)dBm;
944 burstString[6] = (TOAint >> 8) & 0x0ff;
945 burstString[7] = TOAint & 0x0ff;
946 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000947
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800948 for (unsigned i = 0; i < nbits; i++)
949 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
950
951 burstString[nbits + 9] = '\0';
952 delete rxBurst;
953
954 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000955}
956
Thomas Tsou204a9f12013-10-29 18:34:16 -0400957void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000958{
959
960 /**
961 Features a carefully controlled latency mechanism, to
962 assure that transmit packets arrive at the radio/USRP
963 before they need to be transmitted.
964
965 Deadline clock indicates the burst that needs to be
966 pushed into the FIFO right NOW. If transmit queue does
967 not have a burst, stick in filler data.
968 */
969
970
971 RadioClock *radioClock = (mRadioInterface->getClock());
972
973 if (mOn) {
974 //radioClock->wait(); // wait until clock updates
975 LOG(DEBUG) << "radio clock " << radioClock->get();
976 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
977 // if underrun, then we're not providing bursts to radio/USRP fast
978 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400979 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000980 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000981 // only update latency at the defined frame interval
982 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000983 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
984 LOG(INFO) << "new latency: " << mTransmitLatency;
985 mLatencyUpdateTime = radioClock->get();
986 }
987 }
988 else {
989 // if underrun hasn't occurred in the last sec (216 frames) drop
990 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000991 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000992 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
993 mTransmitLatency.decTN();
994 LOG(INFO) << "reduced latency: " << mTransmitLatency;
995 mLatencyUpdateTime = radioClock->get();
996 }
997 }
998 }
dburgessb3a0ca42011-10-12 07:44:40 +0000999 }
dburgessb3a0ca42011-10-12 07:44:40 +00001000 // time to push burst to transmit FIFO
1001 pushRadioVector(mTransmitDeadlineClock);
1002 mTransmitDeadlineClock.incTN();
1003 }
dburgessb3a0ca42011-10-12 07:44:40 +00001004 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001005
1006 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001007}
1008
1009
1010
1011void Transceiver::writeClockInterface()
1012{
1013 char command[50];
1014 // FIXME -- This should be adaptive.
1015 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1016
1017 LOG(INFO) << "ClockInterface: sending " << command;
1018
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001019 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001020
1021 mLastClockUpdateTime = mTransmitDeadlineClock;
1022
Thomas Tsou92c16df2013-09-28 18:04:19 -04001023}
dburgessb3a0ca42011-10-12 07:44:40 +00001024
Thomas Tsou204a9f12013-10-29 18:34:16 -04001025void *RxUpperLoopAdapter(TransceiverChannel *chan)
1026{
1027 Transceiver *trx = chan->trx;
1028 size_t num = chan->num;
1029
1030 delete chan;
1031
Thomas Tsou7553aa92013-11-08 12:50:03 -05001032 trx->setPriority(0.42);
1033
Thomas Tsou204a9f12013-10-29 18:34:16 -04001034 while (1) {
1035 trx->driveReceiveFIFO(num);
1036 pthread_testcancel();
1037 }
1038 return NULL;
1039}
1040
1041void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001042{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001043 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001044
dburgessb3a0ca42011-10-12 07:44:40 +00001045 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001046 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001047 pthread_testcancel();
1048 }
1049 return NULL;
1050}
1051
Thomas Tsou204a9f12013-10-29 18:34:16 -04001052void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001053{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001054 transceiver->setPriority(0.44);
1055
Thomas Tsou92c16df2013-09-28 18:04:19 -04001056 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001057 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001058 pthread_testcancel();
1059 }
1060 return NULL;
1061}
1062
Thomas Tsou204a9f12013-10-29 18:34:16 -04001063void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001064{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001065 Transceiver *trx = chan->trx;
1066 size_t num = chan->num;
1067
1068 delete chan;
1069
dburgessb3a0ca42011-10-12 07:44:40 +00001070 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001071 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001072 pthread_testcancel();
1073 }
1074 return NULL;
1075}
1076
Thomas Tsou204a9f12013-10-29 18:34:16 -04001077void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001078{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001079 Transceiver *trx = chan->trx;
1080 size_t num = chan->num;
1081
1082 delete chan;
1083
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001084 trx->setPriority(0.40);
1085
dburgessb3a0ca42011-10-12 07:44:40 +00001086 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001087 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001088 pthread_testcancel();
1089 }
1090 return NULL;
1091}