blob: d32967ebfb0a220a13aa427f7be64f1533669881 [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();
300
301 for (size_t i = 0; i < mChans; i++) {
302 mRxServiceLoopThreads[i]->cancel();
303 mTxPriorityQueueServiceLoopThreads[i]->cancel();
304 }
305
306 LOG(INFO) << "Stopping the device";
307 mRadioInterface->stop();
308
309 for (size_t i = 0; i < mChans; i++) {
310 mRxServiceLoopThreads[i]->join();
311 mTxPriorityQueueServiceLoopThreads[i]->join();
312 delete mRxServiceLoopThreads[i];
313 delete mTxPriorityQueueServiceLoopThreads[i];
314
315 mTxPriorityQueues[i].clear();
316 }
317
318 mTxLowerLoopThread->join();
319 mRxLowerLoopThread->join();
320 delete mTxLowerLoopThread;
321 delete mRxLowerLoopThread;
322
323 mOn = false;
324 LOG(NOTICE) << "Transceiver stopped";
325}
326
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500327void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400328 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000329{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500330 signalVector *burst;
331 radioVector *radio_burst;
332
Thomas Tsou204a9f12013-10-29 18:34:16 -0400333 if (chan >= mTxPriorityQueues.size()) {
334 LOG(ALERT) << "Invalid channel " << chan;
335 return;
336 }
337
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500338 if (wTime.TN() > 7) {
339 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
340 return;
341 }
342
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800343 /* Use the number of bits as the EDGE burst indicator */
344 if (bits.size() == EDGE_BURST_NBITS)
345 burst = modulateEdgeBurst(bits, mSPSTx);
346 else
347 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
348
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500349 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000350
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500351 radio_burst = new radioVector(wTime, burst);
352
353 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000354}
355
Thomas Tsou15d743e2014-01-25 02:34:03 -0500356void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
357{
358 int TN, modFN;
359 TransceiverState *state = &mStates[chan];
360
361 TN = burst->getTime().TN();
362 modFN = burst->getTime().FN() % state->fillerModulus[TN];
363
364 delete state->fillerTable[modFN][TN];
365 state->fillerTable[modFN][TN] = burst->getVector();
366 burst->setVector(NULL);
367}
368
dburgessb3a0ca42011-10-12 07:44:40 +0000369void Transceiver::pushRadioVector(GSM::Time &nowTime)
370{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400371 int TN, modFN;
372 radioVector *burst;
373 TransceiverState *state;
374 std::vector<signalVector *> bursts(mChans);
375 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500376 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000377
Thomas Tsou204a9f12013-10-29 18:34:16 -0400378 for (size_t i = 0; i < mChans; i ++) {
379 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000380
Thomas Tsou204a9f12013-10-29 18:34:16 -0400381 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
382 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500383 if (state->mRetrans)
384 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500385 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400386 }
387
388 TN = nowTime.TN();
389 modFN = nowTime.FN() % state->fillerModulus[TN];
390
391 bursts[i] = state->fillerTable[modFN][TN];
392 zeros[i] = state->chanType[TN] == NONE;
393
394 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500395 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500396
397 if (state->mRetrans) {
398 updateFillerTable(i, burst);
399 } else {
400 burst->setVector(NULL);
401 filler[i] = false;
402 }
403
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500404 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400405 }
dburgessb3a0ca42011-10-12 07:44:40 +0000406 }
407
Thomas Tsou204a9f12013-10-29 18:34:16 -0400408 mRadioInterface->driveTransmitRadio(bursts, zeros);
409
Thomas Tsou15d743e2014-01-25 02:34:03 -0500410 for (size_t i = 0; i < mChans; i++) {
411 if (!filler[i])
412 delete bursts[i];
413 }
dburgessb3a0ca42011-10-12 07:44:40 +0000414}
415
Thomas Tsou204a9f12013-10-29 18:34:16 -0400416void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000417{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400418 TransceiverState *state = &mStates[chan];
419
420 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000421 case NONE:
422 case I:
423 case II:
424 case III:
425 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400426 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000427 break;
428 case IV:
429 case VI:
430 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400431 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000432 break;
433 //case V:
434 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400435 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000436 break;
ttsoufc40a842013-06-09 22:38:18 +0000437 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400438 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000439 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000440 default:
441 break;
442 }
443}
444
445
Alexander Chemerisf9e78be2017-03-17 15:00:34 -0700446CorrType Transceiver::expectedCorrType(GSM::Time currTime,
447 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000448{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300449 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 };
450 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,
451 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 };
452 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,
453 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 -0400454 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000455 unsigned burstTN = currTime.TN();
456 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300457 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000458
Thomas Tsou204a9f12013-10-29 18:34:16 -0400459 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000460 case NONE:
461 return OFF;
462 break;
463 case FILL:
464 return IDLE;
465 break;
466 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300467 // TODO: Are we expecting RACH on an IDLE frame?
468/* if (burstFN % 26 == 25)
469 return IDLE;*/
470 if (mHandover[burstTN][0])
471 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000472 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000473 break;
474 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300475 subch = tchh_subslot[burstFN % 26];
476 if (subch == 1)
477 return IDLE;
478 if (mHandover[burstTN][0])
479 return RACH;
ttsou20642972013-03-27 22:00:25 +0000480 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000481 break;
482 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300483 subch = tchh_subslot[burstFN % 26];
484 if (mHandover[burstTN][subch])
485 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000486 return TSC;
487 break;
488 case IV:
489 case VI:
490 return RACH;
491 break;
492 case V: {
493 int mod51 = burstFN % 51;
494 if ((mod51 <= 36) && (mod51 >= 14))
495 return RACH;
496 else if ((mod51 == 4) || (mod51 == 5))
497 return RACH;
498 else if ((mod51 == 45) || (mod51 == 46))
499 return RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300500 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
501 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000502 else
503 return TSC;
504 break;
505 }
506 case VII:
507 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
508 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300509 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
510 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000511 else
512 return TSC;
513 break;
ttsoufc40a842013-06-09 22:38:18 +0000514 case XIII: {
515 int mod52 = burstFN % 52;
516 if ((mod52 == 12) || (mod52 == 38))
517 return RACH;
518 else if ((mod52 == 25) || (mod52 == 51))
519 return IDLE;
520 else
521 return TSC;
522 break;
523 }
dburgessb3a0ca42011-10-12 07:44:40 +0000524 case LOOPBACK:
525 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
526 return IDLE;
527 else
528 return TSC;
529 break;
530 default:
531 return OFF;
532 break;
533 }
dburgessb3a0ca42011-10-12 07:44:40 +0000534}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400535
Thomas Tsou30421a72013-11-13 23:14:48 -0500536/*
Tom Tsou46569402016-03-06 01:59:38 -0800537 * Demodulate GMSK by direct rotation and soft slicing.
Thomas Tsou30421a72013-11-13 23:14:48 -0500538 */
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300539SoftVector *Transceiver::demodulate(signalVector &burst, complex amp,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800540 float toa, CorrType type)
Thomas Tsou30421a72013-11-13 23:14:48 -0500541{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800542 if (type == EDGE)
543 return demodEdgeBurst(burst, mSPSRx, amp, toa);
544
Alexander Chemeris1c0b8b32017-03-17 16:12:47 -0700545 return demodGmskBurst(burst, mSPSRx, amp, toa);
Thomas Tsou30421a72013-11-13 23:14:48 -0500546}
547
Alexander Chemerise692ce92015-06-12 00:15:31 -0400548void writeToFile(radioVector *radio_burst, size_t chan)
549{
550 GSM::Time time = radio_burst->getTime();
551 std::ostringstream fname;
552 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
553 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
554 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
555 outfile.close();
556}
557
Thomas Tsou30421a72013-11-13 23:14:48 -0500558/*
559 * Pull bursts from the FIFO and handle according to the slot
560 * and burst correlation type. Equalzation is currently disabled.
561 */
Alexander Chemeris2b542102015-06-08 22:46:38 -0400562SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400563 double &timingOffset, double &noise,
564 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000565{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800566 int rc;
Thomas Tsou30421a72013-11-13 23:14:48 -0500567 complex amp;
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +0300568 float toa, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500569 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500570 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500571 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500572 TransceiverState *state = &mStates[chan];
Alexander Chemeris2b542102015-06-08 22:46:38 -0400573 isRssiValid = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000574
Thomas Tsou30421a72013-11-13 23:14:48 -0500575 /* Blocking FIFO read */
576 radioVector *radio_burst = mReceiveFIFO[chan]->read();
577 if (!radio_burst)
578 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000579
Thomas Tsou30421a72013-11-13 23:14:48 -0500580 /* Set time and determine correlation type */
581 GSM::Time time = radio_burst->getTime();
582 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000583
Tom Tsou64464e62016-07-01 03:46:46 -0700584 /* Enable 8-PSK burst detection if EDGE is enabled */
585 if (mEdge && (type == TSC))
586 type = EDGE;
587
Alexander Chemerise692ce92015-06-12 00:15:31 -0400588 /* Debug: dump bursts to disk */
589 /* bits 0-7 - chan 0 timeslots
590 * bits 8-15 - chan 1 timeslots */
591 if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
592 writeToFile(radio_burst, chan);
593
Alexander Chemeris2b542102015-06-08 22:46:38 -0400594 /* No processing if the timeslot is off.
595 * Not even power level or noise calculation. */
596 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500597 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000598 return NULL;
599 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000600
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500601 /* Select the diversity channel with highest energy */
602 for (size_t i = 0; i < radio_burst->chans(); i++) {
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +0300603 float pow = energyDetect(*radio_burst->getVector(i), 20 * mSPSRx);
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500604 if (pow > max) {
605 max = pow;
606 max_i = i;
607 }
608 avg += pow;
609 }
610
611 if (max_i < 0) {
612 LOG(ALERT) << "Received empty burst";
613 delete radio_burst;
614 return NULL;
615 }
616
Thomas Tsou30421a72013-11-13 23:14:48 -0500617 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500618 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500619 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400620
621 wTime = time;
622 RSSI = 20.0 * log10(rxFullScale / avg);
623
624 /* RSSI estimation are valid */
625 isRssiValid = true;
626
627 if (type == IDLE) {
628 /* Update noise levels */
629 state->mNoises.insert(avg);
630 state->mNoiseLev = state->mNoises.avg();
631 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
632
633 delete radio_burst;
634 return NULL;
635 } else {
636 /* Do not update noise levels */
637 noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
638 }
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400639
Thomas Tsou30421a72013-11-13 23:14:48 -0500640 /* Detect normal or RACH bursts */
Alexander Chemeris4e6c9382017-03-17 15:24:18 -0700641 rc = detectAnyBurst(*burst, mTSC, BURST_THRESH, mSPSRx, type, amp, toa,
642 (type==RACH)?mMaxExpectedDelayAB:mMaxExpectedDelayNB);
Thomas Tsouf0782732013-10-29 15:55:47 -0400643
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800644 if (rc > 0) {
645 type = (CorrType) rc;
646 } else if (rc <= 0) {
647 if (rc == -SIGERR_CLIP) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400648 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800649 } else if (rc != SIGERR_NONE) {
Alexander Chemeris954b1182015-06-04 15:39:41 -0400650 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Tom Tsou577cd022015-05-18 13:57:54 -0700651 }
652
Thomas Tsou30421a72013-11-13 23:14:48 -0500653 delete radio_burst;
654 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000655 }
dburgessb3a0ca42011-10-12 07:44:40 +0000656
Tom Tsou4609f322016-07-19 11:28:51 -0700657 timingOffset = toa;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400658
Alexander Chemeris9664c3a2016-04-20 08:42:58 +0300659 bits = demodulate(*burst, amp, toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500660
Thomas Tsou30421a72013-11-13 23:14:48 -0500661 delete radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500662 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000663}
664
dburgessb3a0ca42011-10-12 07:44:40 +0000665void Transceiver::reset()
666{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400667 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
668 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000669}
670
671
Thomas Tsou204a9f12013-10-29 18:34:16 -0400672void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000673{
dburgessb3a0ca42011-10-12 07:44:40 +0000674 int MAX_PACKET_LENGTH = 100;
675
676 // check control socket
677 char buffer[MAX_PACKET_LENGTH];
678 int msgLen = -1;
679 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400680
Tom Tsou2c650a62016-04-28 21:55:17 -0700681 msgLen = mCtrlSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000682
683 if (msgLen < 1) {
684 return;
685 }
686
687 char cmdcheck[4];
688 char command[MAX_PACKET_LENGTH];
689 char response[MAX_PACKET_LENGTH];
690
691 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400692
693 if (!chan)
694 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000695
696 if (strcmp(cmdcheck,"CMD")!=0) {
697 LOG(WARNING) << "bogus message on control interface";
698 return;
699 }
700 LOG(INFO) << "command is " << buffer;
701
702 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800703 stop();
704 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000705 }
706 else if (strcmp(command,"POWERON")==0) {
Tom Tsou365bc382016-10-19 15:26:04 -0700707 if (!start()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000708 sprintf(response,"RSP POWERON 1");
Tom Tsou365bc382016-10-19 15:26:04 -0700709 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000710 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300711 for (int i = 0; i < 8; i++) {
712 for (int j = 0; j < 8; j++)
713 mHandover[i][j] = false;
714 }
Tom Tsou365bc382016-10-19 15:26:04 -0700715 }
Alexander Chemeris5a068062015-06-20 01:38:47 +0300716 }
717 else if (strcmp(command,"HANDOVER")==0){
718 int ts=0,ss=0;
719 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
720 mHandover[ts][ss] = true;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300721 sprintf(response,"RSP HANDOVER 0 %d %d",ts,ss);
722 }
723 else if (strcmp(command,"NOHANDOVER")==0){
724 int ts=0,ss=0;
725 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&ts,&ss);
726 mHandover[ts][ss] = false;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300727 sprintf(response,"RSP NOHANDOVER 0 %d %d",ts,ss);
dburgessb3a0ca42011-10-12 07:44:40 +0000728 }
729 else if (strcmp(command,"SETMAXDLY")==0) {
730 //set expected maximum time-of-arrival
731 int maxDelay;
732 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300733 mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
dburgessb3a0ca42011-10-12 07:44:40 +0000734 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
735 }
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300736 else if (strcmp(command,"SETMAXDLYNB")==0) {
737 //set expected maximum time-of-arrival
738 int maxDelay;
739 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
740 mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
741 sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
742 }
dburgessb3a0ca42011-10-12 07:44:40 +0000743 else if (strcmp(command,"SETRXGAIN")==0) {
744 //set expected maximum time-of-arrival
745 int newGain;
746 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400747 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000748 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
749 }
750 else if (strcmp(command,"NOISELEV")==0) {
751 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500752 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000753 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500754 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000755 }
756 else {
757 sprintf(response,"RSP NOISELEV 1 0");
758 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500759 }
760 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800761 int power;
762 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
763 power = mRadioInterface->setPowerAttenuation(power, chan);
764 mStates[chan].mPower = power;
765 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000766 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500767 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800768 int power, step;
769 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
770 power = mStates[chan].mPower + step;
771 power = mRadioInterface->setPowerAttenuation(power, chan);
772 mStates[chan].mPower = power;
773 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000774 }
dburgessb3a0ca42011-10-12 07:44:40 +0000775 else if (strcmp(command,"RXTUNE")==0) {
776 // tune receiver
777 int freqKhz;
778 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500779 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400780 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000781 LOG(ALERT) << "RX failed to tune";
782 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
783 }
784 else
785 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
786 }
787 else if (strcmp(command,"TXTUNE")==0) {
788 // tune txmtr
789 int freqKhz;
790 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500791 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400792 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000793 LOG(ALERT) << "TX failed to tune";
794 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
795 }
796 else
797 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
798 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500799 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000800 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500801 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500802 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
Tom Tsouc8c4eac2016-06-28 17:00:54 -0700803 if ((TSC < 0) || (TSC > 7))
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500804 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000805 else {
Tom Tsouc37594f2016-07-08 14:39:42 -0700806 LOG(NOTICE) << "Changing TSC from " << mTSC << " to " << TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000807 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400808 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000809 }
810 }
811 else if (strcmp(command,"SETSLOT")==0) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700812 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000813 int corrCode;
814 int timeslot;
815 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
816 if ((timeslot < 0) || (timeslot > 7)) {
817 LOG(WARNING) << "bogus message on control interface";
818 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
819 return;
820 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400821 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
822 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000823 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
824
825 }
Alexander Chemerise692ce92015-06-12 00:15:31 -0400826 else if (strcmp(command,"_SETBURSTTODISKMASK")==0) {
827 // debug command! may change or disapear without notice
828 // set a mask which bursts to dump to disk
829 int mask;
830 sscanf(buffer,"%3s %s %d",cmdcheck,command,&mask);
831 mWriteBurstToDiskMask = mask;
832 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
833 }
dburgessb3a0ca42011-10-12 07:44:40 +0000834 else {
835 LOG(WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200836 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000837 }
838
Thomas Tsou204a9f12013-10-29 18:34:16 -0400839 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000840}
841
Thomas Tsou204a9f12013-10-29 18:34:16 -0400842bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000843{
Tom Tsoue8871082016-07-01 02:46:04 -0700844 int burstLen;
845 char buffer[EDGE_BURST_NBITS + 50];
dburgessb3a0ca42011-10-12 07:44:40 +0000846
847 // check data socket
Tom Tsou2c650a62016-04-28 21:55:17 -0700848 size_t msgLen = mDataSockets[chan]->read(buffer, sizeof(buffer));
dburgessb3a0ca42011-10-12 07:44:40 +0000849
Tom Tsoue8871082016-07-01 02:46:04 -0700850 if (msgLen == gSlotLen + 1 + 4 + 1) {
851 burstLen = gSlotLen;
852 } else if (msgLen == EDGE_BURST_NBITS + 1 + 4 + 1) {
853 if (mSPSTx != 4)
854 return false;
855
856 burstLen = EDGE_BURST_NBITS;
857 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000858 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
859 return false;
860 }
861
862 int timeSlot = (int) buffer[0];
863 uint64_t frameNum = 0;
864 for (int i = 0; i < 4; i++)
865 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000866
dburgessb3a0ca42011-10-12 07:44:40 +0000867 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
868
869 int RSSI = (int) buffer[5];
Tom Tsou7c741ec2016-07-19 11:20:59 -0700870 BitVector newBurst(burstLen);
dburgessb3a0ca42011-10-12 07:44:40 +0000871 BitVector::iterator itr = newBurst.begin();
872 char *bufferItr = buffer+6;
873 while (itr < newBurst.end())
874 *itr++ = *bufferItr++;
875
876 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400877
878 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000879
880 return true;
881
882
883}
dburgessb3a0ca42011-10-12 07:44:40 +0000884
Thomas Tsou204a9f12013-10-29 18:34:16 -0400885void Transceiver::driveReceiveRadio()
886{
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400887 if (!mRadioInterface->driveReceiveRadio()) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400888 usleep(100000);
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400889 } else {
890 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
891 writeClockInterface();
892 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400893}
894
Alexander Chemeris58e95912016-03-25 18:20:28 +0300895void Transceiver::logRxBurst(size_t chan, SoftVector *burst, GSM::Time time, double dbm,
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800896 double rssi, double noise, double toa)
897{
898 LOG(DEBUG) << std::fixed << std::right
Alexander Chemeris58e95912016-03-25 18:20:28 +0300899 << " chan: " << chan
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800900 << " time: " << time
901 << " RSSI: " << std::setw(5) << std::setprecision(1) << rssi
902 << "dBFS/" << std::setw(6) << -dbm << "dBm"
903 << " noise: " << std::setw(5) << std::setprecision(1) << noise
904 << "dBFS/" << std::setw(6) << -(noise + rssiOffset) << "dBm"
905 << " TOA: " << std::setw(5) << std::setprecision(2) << toa
906 << " bits: " << *burst;
907}
908
Thomas Tsou204a9f12013-10-29 18:34:16 -0400909void Transceiver::driveReceiveFIFO(size_t chan)
910{
dburgessb3a0ca42011-10-12 07:44:40 +0000911 SoftVector *rxBurst = NULL;
Alexander Chemerise8905a02015-06-03 23:47:56 -0400912 double RSSI; // in dBFS
913 double dBm; // in dBm
914 double TOA; // in symbols
915 int TOAint; // in 1/256 symbols
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400916 double noise; // noise level in dBFS
dburgessb3a0ca42011-10-12 07:44:40 +0000917 GSM::Time burstTime;
Alexander Chemeris2b542102015-06-08 22:46:38 -0400918 bool isRssiValid; // are RSSI, noise and burstTime valid
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800919 unsigned nbits = gSlotLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000920
Alexander Chemeris2b542102015-06-08 22:46:38 -0400921 rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800922 if (!rxBurst)
923 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000924
Alexander Chemerisb61c6102017-03-17 18:22:19 -0700925 // Convert -1..+1 soft bits to 0..1 soft bits
926 vectorSlicer(rxBurst);
927
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800928 /*
929 * EDGE demodulator returns 444 (148 * 3) bits
930 */
931 if (rxBurst->size() == gSlotLen * 3)
932 nbits = gSlotLen * 3;
dburgessb3a0ca42011-10-12 07:44:40 +0000933
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800934 dBm = RSSI + rssiOffset;
Alexander Chemeris58e95912016-03-25 18:20:28 +0300935 logRxBurst(chan, rxBurst, burstTime, dBm, RSSI, noise, TOA);
Alexander Chemerisdbe26ab2015-06-04 00:14:51 -0400936
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800937 TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
dburgessb3a0ca42011-10-12 07:44:40 +0000938
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800939 char burstString[nbits + 10];
940 burstString[0] = burstTime.TN();
941 for (int i = 0; i < 4; i++)
942 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
943 burstString[5] = (int)dBm;
944 burstString[6] = (TOAint >> 8) & 0x0ff;
945 burstString[7] = TOAint & 0x0ff;
946 SoftVector::iterator burstItr = rxBurst->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000947
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800948 for (unsigned i = 0; i < nbits; i++)
949 burstString[8 + i] = (char) round((*burstItr++) * 255.0);
950
951 burstString[nbits + 9] = '\0';
952 delete rxBurst;
953
954 mDataSockets[chan]->write(burstString, nbits + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000955}
956
Thomas Tsou204a9f12013-10-29 18:34:16 -0400957void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000958{
959
960 /**
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}