blob: 64be85ac45ba2809fd58c3f02f5c4ee1ced79da4 [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>
25#include "Transceiver.h"
26#include <Logger.h>
27
Thomas Tsouc7f36c22014-04-16 22:24:00 -040028extern "C" {
29#include "sch.h"
30}
31
ttsou2173abf2012-08-08 00:51:31 +000032#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
dburgessb3a0ca42011-10-12 07:44:40 +000035
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040036using namespace GSM;
37
kurtis.heimerlec842de2012-11-23 08:37:32 +000038#define USB_LATENCY_INTRVL 10,0
ttsou2173abf2012-08-08 00:51:31 +000039
40#if USE_UHD
kurtis.heimerlec842de2012-11-23 08:37:32 +000041# define USB_LATENCY_MIN 6,7
ttsou2173abf2012-08-08 00:51:31 +000042#else
kurtis.heimerlec842de2012-11-23 08:37:32 +000043# define USB_LATENCY_MIN 1,1
ttsou2173abf2012-08-08 00:51:31 +000044#endif
dburgessb3a0ca42011-10-12 07:44:40 +000045
Tom Tsou774a0632014-10-31 13:18:43 -070046/* Clock indication interval in frames */
47#define CLK_IND_INTERVAL 100
48
Thomas Tsoufa3a7872013-10-17 21:23:34 -040049/* Number of running values use in noise average */
50#define NOISE_CNT 20
Thomas Tsou14bb9c92014-04-16 23:10:12 -040051#define FREQ_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000052
Thomas Tsouf0782732013-10-29 15:55:47 -040053TransceiverState::TransceiverState()
Thomas Tsou14bb9c92014-04-16 23:10:12 -040054 : mRetrans(false), mNoiseLev(0.0),
55 mNoises(NOISE_CNT), mFreqOffsets(FREQ_CNT), mode(Transceiver::TRX_MODE_OFF)
Thomas Tsouf0782732013-10-29 15:55:47 -040056{
57 for (int i = 0; i < 8; i++) {
58 chanType[i] = Transceiver::NONE;
59 fillerModulus[i] = 26;
60 chanResponse[i] = NULL;
61 DFEForward[i] = NULL;
62 DFEFeedback[i] = NULL;
Thomas Tsou14bb9c92014-04-16 23:10:12 -040063 prevFrame[i] = NULL;
Thomas Tsouf0782732013-10-29 15:55:47 -040064
65 for (int n = 0; n < 102; n++)
66 fillerTable[n][i] = NULL;
67 }
68}
69
70TransceiverState::~TransceiverState()
71{
72 for (int i = 0; i < 8; i++) {
73 delete chanResponse[i];
74 delete DFEForward[i];
75 delete DFEFeedback[i];
76
77 for (int n = 0; n < 102; n++)
78 delete fillerTable[n][i];
79 }
80}
81
Thomas Tsou15d743e2014-01-25 02:34:03 -050082void TransceiverState::init(size_t slot, signalVector *burst, bool fill)
Thomas Tsouf0782732013-10-29 15:55:47 -040083{
Thomas Tsou15d743e2014-01-25 02:34:03 -050084 signalVector *filler;
85
86 for (int i = 0; i < 102; i++) {
87 if (fill)
88 filler = new signalVector(*burst);
89 else
90 filler = new signalVector(burst->size());
91
92 fillerTable[i][slot] = filler;
93 }
Thomas Tsouf0782732013-10-29 15:55:47 -040094}
95
dburgessb3a0ca42011-10-12 07:44:40 +000096Transceiver::Transceiver(int wBasePort,
97 const char *TRXAddress,
Thomas Tsou204a9f12013-10-29 18:34:16 -040098 size_t wSPS, size_t wChans,
dburgessb3a0ca42011-10-12 07:44:40 +000099 GSM::Time wTransmitLatency,
100 RadioInterface *wRadioInterface)
Thomas Tsoud647ec52013-10-29 15:17:34 -0400101 : mBasePort(wBasePort), mAddr(TRXAddress),
Thomas Tsoua0179e32013-11-14 15:52:04 -0500102 mTransmitLatency(wTransmitLatency), mClockSocket(NULL),
103 mRadioInterface(wRadioInterface), mSPSTx(wSPS), mSPSRx(1), mChans(wChans),
Thomas Tsoue2875982014-10-06 10:38:43 -0700104 mOn(false), mTxFreq(0.0), mRxFreq(0.0), mPower(-10), mMaxExpectedDelay(0),
105 mBSIC(-1)
dburgessb3a0ca42011-10-12 07:44:40 +0000106{
dburgessb3a0ca42011-10-12 07:44:40 +0000107 GSM::Time startTime(random() % gHyperframe,0);
108
Thomas Tsou13033762014-10-06 19:05:52 -0700109 mLowerLoopThread = new Thread(32768);
dburgessb3a0ca42011-10-12 07:44:40 +0000110
dburgessb3a0ca42011-10-12 07:44:40 +0000111 mTransmitDeadlineClock = startTime;
112 mLastClockUpdateTime = startTime;
113 mLatencyUpdateTime = startTime;
114 mRadioInterface->getClock()->set(startTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000115
dburgessb3a0ca42011-10-12 07:44:40 +0000116 txFullScale = mRadioInterface->fullScaleInputValue();
117 rxFullScale = mRadioInterface->fullScaleOutputValue();
Thomas Tsou25021df2014-10-06 11:43:48 -0700118
119 for (int i = 0; i < 8; i++)
120 mRxSlotMask[i] = 0;
dburgessb3a0ca42011-10-12 07:44:40 +0000121}
122
123Transceiver::~Transceiver()
124{
dburgessb3a0ca42011-10-12 07:44:40 +0000125 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400126
127 delete mClockSocket;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400128
129 for (size_t i = 0; i < mChans; i++) {
130 mTxPriorityQueues[i].clear();
131 delete mCtrlSockets[i];
132 delete mDataSockets[i];
133 }
dburgessb3a0ca42011-10-12 07:44:40 +0000134}
Thomas Tsou83e06892013-08-20 16:10:01 -0400135
Thomas Tsou15d743e2014-01-25 02:34:03 -0500136bool Transceiver::init(bool filler)
Thomas Tsou83e06892013-08-20 16:10:01 -0400137{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500138 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400139 signalVector *burst;
140
Thomas Tsou204a9f12013-10-29 18:34:16 -0400141 if (!mChans) {
142 LOG(ALERT) << "No channels assigned";
143 return false;
144 }
145
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400146 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400147 LOG(ALERT) << "Failed to initialize signal processing library";
148 return false;
149 }
150
Thomas Tsou204a9f12013-10-29 18:34:16 -0400151 mDataSockets.resize(mChans);
152 mCtrlSockets.resize(mChans);
153
154 mControlServiceLoopThreads.resize(mChans);
155 mTxPriorityQueueServiceLoopThreads.resize(mChans);
156 mRxServiceLoopThreads.resize(mChans);
157
158 mTxPriorityQueues.resize(mChans);
159 mReceiveFIFO.resize(mChans);
160 mStates.resize(mChans);
161
Thomas Tsouccb73e12014-04-15 17:41:28 -0400162 /* Filler table retransmissions - support only on channel 0 */
163 if (filler)
164 mStates[0].mRetrans = true;
165
Thomas Tsoud647ec52013-10-29 15:17:34 -0400166 mClockSocket = new UDPSocket(mBasePort, mAddr.c_str(), mBasePort + 100);
Thomas Tsoud647ec52013-10-29 15:17:34 -0400167
Thomas Tsou204a9f12013-10-29 18:34:16 -0400168 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500169 c_srcport = mBasePort + 2 * i + 1;
170 c_dstport = mBasePort + 2 * i + 101;
171 d_srcport = mBasePort + 2 * i + 2;
172 d_dstport = mBasePort + 2 * i + 102;
173
174 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
175 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400176 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400177
Thomas Tsou204a9f12013-10-29 18:34:16 -0400178 for (size_t i = 0; i < mChans; i++) {
179 mControlServiceLoopThreads[i] = new Thread(32768);
180 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
181 mRxServiceLoopThreads[i] = new Thread(32768);
182
183 for (size_t n = 0; n < 8; n++) {
184 burst = modulateBurst(gDummyBurst, 8 + (n % 4 == 0), mSPSTx);
185 scaleVector(*burst, txFullScale);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500186 mStates[i].init(n, burst, filler && !i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400187 delete burst;
188 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400189 }
190
191 return true;
192}
dburgessb3a0ca42011-10-12 07:44:40 +0000193
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500194void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400195 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000196{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500197 signalVector *burst;
198 radioVector *radio_burst;
199
Thomas Tsou204a9f12013-10-29 18:34:16 -0400200 if (chan >= mTxPriorityQueues.size()) {
201 LOG(ALERT) << "Invalid channel " << chan;
202 return;
203 }
204
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500205 if (wTime.TN() > 7) {
206 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
207 return;
208 }
209
Thomas Tsouf31e4bb2014-04-16 20:02:06 -0400210 if (mStates[0].mode != TRX_MODE_BTS)
211 return;
212
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500213 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
214 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000215
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500216 radio_burst = new radioVector(wTime, burst);
217
218 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000219}
220
Thomas Tsou15d743e2014-01-25 02:34:03 -0500221void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
222{
223 int TN, modFN;
224 TransceiverState *state = &mStates[chan];
225
226 TN = burst->getTime().TN();
227 modFN = burst->getTime().FN() % state->fillerModulus[TN];
228
229 delete state->fillerTable[modFN][TN];
230 state->fillerTable[modFN][TN] = burst->getVector();
231 burst->setVector(NULL);
232}
233
dburgessb3a0ca42011-10-12 07:44:40 +0000234void Transceiver::pushRadioVector(GSM::Time &nowTime)
235{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400236 int TN, modFN;
237 radioVector *burst;
238 TransceiverState *state;
239 std::vector<signalVector *> bursts(mChans);
Thomas Tsou13033762014-10-06 19:05:52 -0700240 std::vector<bool> zeros(mChans, false);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500241 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000242
Thomas Tsou204a9f12013-10-29 18:34:16 -0400243 for (size_t i = 0; i < mChans; i ++) {
244 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000245
Thomas Tsou204a9f12013-10-29 18:34:16 -0400246 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
247 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500248 if (state->mRetrans)
249 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500250 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400251 }
252
253 TN = nowTime.TN();
254 modFN = nowTime.FN() % state->fillerModulus[TN];
255
256 bursts[i] = state->fillerTable[modFN][TN];
Thomas Tsou13033762014-10-06 19:05:52 -0700257 if (state->mode == TRX_MODE_BTS)
258 zeros[i] = state->chanType[TN] == NONE;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400259
260 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500261 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500262
263 if (state->mRetrans) {
264 updateFillerTable(i, burst);
265 } else {
266 burst->setVector(NULL);
267 filler[i] = false;
268 }
269
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500270 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400271 }
dburgessb3a0ca42011-10-12 07:44:40 +0000272 }
273
Thomas Tsou204a9f12013-10-29 18:34:16 -0400274 mRadioInterface->driveTransmitRadio(bursts, zeros);
275
Thomas Tsou15d743e2014-01-25 02:34:03 -0500276 for (size_t i = 0; i < mChans; i++) {
277 if (!filler[i])
278 delete bursts[i];
279 }
dburgessb3a0ca42011-10-12 07:44:40 +0000280}
281
Thomas Tsou204a9f12013-10-29 18:34:16 -0400282void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000283{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400284 TransceiverState *state = &mStates[chan];
285
286 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000287 case NONE:
288 case I:
289 case II:
290 case III:
291 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400292 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000293 break;
294 case IV:
295 case VI:
296 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400297 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000298 break;
299 //case V:
300 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400301 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000302 break;
ttsoufc40a842013-06-09 22:38:18 +0000303 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400304 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000305 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000306 default:
307 break;
308 }
309}
310
311
Thomas Tsou204a9f12013-10-29 18:34:16 -0400312Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
313 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000314{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400315 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000316 unsigned burstTN = currTime.TN();
317 unsigned burstFN = currTime.FN();
318
Thomas Tsou25021df2014-10-06 11:43:48 -0700319 if (state->mode == TRX_MODE_MS_TRACK) {
320 /* 102 modulus case currently unhandled */
321 if (state->fillerModulus[burstTN] > 52)
322 return OFF;
323
324 int modFN = burstFN % state->fillerModulus[burstTN];
Thomas Tsou94ce8352014-10-08 11:49:08 -0700325 unsigned long long reg = (unsigned long long) 1 << modFN;
326 if (reg & mRxSlotMask[burstTN])
Thomas Tsou25021df2014-10-06 11:43:48 -0700327 return TSC;
328 else
329 return OFF;
330 }
331
Thomas Tsou204a9f12013-10-29 18:34:16 -0400332 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000333 case NONE:
334 return OFF;
335 break;
336 case FILL:
337 return IDLE;
338 break;
339 case I:
340 return TSC;
341 /*if (burstFN % 26 == 25)
342 return IDLE;
343 else
344 return TSC;*/
345 break;
346 case II:
ttsou20642972013-03-27 22:00:25 +0000347 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000348 break;
349 case III:
350 return TSC;
351 break;
352 case IV:
353 case VI:
354 return RACH;
355 break;
356 case V: {
357 int mod51 = burstFN % 51;
358 if ((mod51 <= 36) && (mod51 >= 14))
359 return RACH;
360 else if ((mod51 == 4) || (mod51 == 5))
361 return RACH;
362 else if ((mod51 == 45) || (mod51 == 46))
363 return RACH;
364 else
365 return TSC;
366 break;
367 }
368 case VII:
369 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
370 return IDLE;
371 else
372 return TSC;
373 break;
ttsoufc40a842013-06-09 22:38:18 +0000374 case XIII: {
375 int mod52 = burstFN % 52;
376 if ((mod52 == 12) || (mod52 == 38))
377 return RACH;
378 else if ((mod52 == 25) || (mod52 == 51))
379 return IDLE;
380 else
381 return TSC;
382 break;
383 }
dburgessb3a0ca42011-10-12 07:44:40 +0000384 case LOOPBACK:
385 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
386 return IDLE;
387 else
388 return TSC;
389 break;
390 default:
391 return OFF;
392 break;
393 }
dburgessb3a0ca42011-10-12 07:44:40 +0000394}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400395
Thomas Tsou30421a72013-11-13 23:14:48 -0500396/*
397 * Detect RACH synchronization sequence within a burst. No equalization
398 * is used or available on the RACH channel.
399 */
400bool Transceiver::detectRACH(TransceiverState *state,
401 signalVector &burst,
402 complex &amp, float &toa)
403{
404 float threshold = 6.0;
405
406 return detectRACHBurst(burst, threshold, mSPSRx, &amp, &toa);
407}
408
Thomas Tsou11890192014-04-16 19:36:30 -0400409/* Detect SCH synchronization sequence within a burst */
410bool Transceiver::detectSCH(TransceiverState *state,
411 signalVector &burst,
412 complex &amp, float &toa)
413{
Thomas Tsou98b1af82014-04-16 23:34:21 -0400414 int shift, full;;
Thomas Tsou11890192014-04-16 19:36:30 -0400415 float mag, threshold = 7.0;
416
Thomas Tsou98b1af82014-04-16 23:34:21 -0400417 full = (state->mode == TRX_MODE_MS_TRACK) ?
418 SCH_DETECT_NARROW : SCH_DETECT_FULL;
419
420 if (!detectSCHBurst(burst, threshold, mSPSRx, &amp, &toa, full))
Thomas Tsou11890192014-04-16 19:36:30 -0400421 return false;
422
423 std::cout << "SCH : Timing offset " << toa << " symbols" << std::endl;
424
425 mag = fabsf(toa);
426 if (mag < 1.0f)
427 return true;
428
429 shift = (int) (mag / 2.0f);
430 if (!shift)
431 shift++;
432
433 mRadioInterface->applyOffset(toa > 0 ? shift : -shift);
434 return false;
435}
436
Thomas Tsouc7f36c22014-04-16 22:24:00 -0400437#define SCH_BIT_SCALE 64
438
439/* Decode SCH burst */
440bool Transceiver::decodeSCH(SoftVector *burst, GSM::Time *time)
441{
442 int fn;
443 struct sch_info sch;
444 ubit_t info[GSM_SCH_INFO_LEN];
445 sbit_t data[GSM_SCH_CODED_LEN];
446
447 if (burst->size() < 156) {
448 std::cout << "Invalid SCH burst length" << std::endl;
449 return false;
450 }
451
452 float_to_sbit(&(*burst)[3], &data[0], SCH_BIT_SCALE, 39);
453 float_to_sbit(&(*burst)[106], &data[39], SCH_BIT_SCALE, 39);
454
455 if (!gsm_sch_decode(info, data)) {
456 gsm_sch_parse(info, &sch);
457
Thomas Tsoue2875982014-10-06 10:38:43 -0700458 mBSIC = sch.bsic;
459
Thomas Tsouc7f36c22014-04-16 22:24:00 -0400460 std::cout << "SCH : Decoded values" << std::endl;
461 std::cout << " BSIC: " << sch.bsic << std::endl;
462 std::cout << " T1 : " << sch.t1 << std::endl;
463 std::cout << " T2 : " << sch.t2 << std::endl;
464 std::cout << " T3p : " << sch.t3p << std::endl;
465 std::cout << " FN : " << gsm_sch_to_fn(&sch) << std::endl;
466
467 fn = gsm_sch_to_fn(&sch);
468 if (fn < 0) {
469 std::cout << "SCH : Failed to convert FN " << std::endl;
470 return false;
471 }
472
473 time->FN(fn);
474 time->TN(0);
475 } else {
476 return false;
477 }
478
479 return true;
480}
481
Thomas Tsou14bb9c92014-04-16 23:10:12 -0400482#define FCCH_OFFSET_LIMIT 2e3
483#define FCCH_ADJUST_LIMIT 20.0
484
485/* Apply FCCH frequency correction */
486bool Transceiver::correctFCCH(TransceiverState *state, signalVector *burst)
487{
488 double offset, avg;
489
490 if (!burst)
491 return false;
492
493 offset = gsm_fcch_offset((float *) burst->begin(), burst->size());
494 if (offset > FCCH_OFFSET_LIMIT)
495 return false;
496
497 state->mFreqOffsets.insert(offset);
498 avg = state->mFreqOffsets.avg();
499
500 if (state->mFreqOffsets.full())
501 std::cout << "FCCH: Frequency offset " << avg << " Hz" << std::endl;
502
503 if (state->mFreqOffsets.full() && (fabs(avg) > FCCH_ADJUST_LIMIT)) {
504 mRadioInterface->tuneRxOffset(-avg);
505 state->mFreqOffsets.reset();
506 }
507
508 return true;
509}
Thomas Tsouc7f36c22014-04-16 22:24:00 -0400510
Thomas Tsou30421a72013-11-13 23:14:48 -0500511/*
512 * Detect normal burst training sequence midamble. Update equalization
513 * state information and channel estimate if necessary. Equalization
514 * is currently disabled.
515 */
Thomas Tsoua0179e32013-11-14 15:52:04 -0500516bool Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
Thomas Tsou30421a72013-11-13 23:14:48 -0500517 complex &amp, float &toa, GSM::Time &time)
518{
519 int tn = time.TN();
520 float chanOffset, threshold = 5.0;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500521 bool noise, needDFE = false, estimateChan = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500522 double elapsed = time - state->chanEstimateTime[tn];
523 signalVector *chanResp;
524
525 /* Check equalization update state */
Thomas Tsoufb827d02013-11-16 16:14:12 -0500526 if (needDFE && ((elapsed > 50) || (!state->chanResponse[tn]))) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500527 delete state->DFEForward[tn];
528 delete state->DFEFeedback[tn];
529 state->DFEForward[tn] = NULL;
530 state->DFEFeedback[tn] = NULL;
531
532 estimateChan = true;
533 }
534
535 /* Detect normal burst midambles */
536 if (!analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, &amp,
537 &toa, mMaxExpectedDelay, estimateChan,
538 &chanResp, &chanOffset)) {
539 return false;
540 }
541
Thomas Tsoua0179e32013-11-14 15:52:04 -0500542 noise = state->mNoiseLev;
543 state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
Thomas Tsou30421a72013-11-13 23:14:48 -0500544
545 /* Set equalizer if unabled */
546 if (needDFE && estimateChan) {
547 state->chanResponse[tn] = chanResp;
548 state->chanRespOffset[tn] = chanOffset;
549 state->chanRespAmplitude[tn] = amp;
550
551 scaleVector(*chanResp, complex(1.0, 0.0) / amp);
552
553 designDFE(*chanResp, state->SNRestimate[tn],
554 7, &state->DFEForward[tn], &state->DFEFeedback[tn]);
555
556 state->chanEstimateTime[tn] = time;
557 }
558
559 return true;;
560}
561
562/*
563 * Demodulate GMSK burst using equalization if requested. Otherwise
564 * demodulate by direct rotation and soft slicing.
565 */
566SoftVector *Transceiver::demodulate(TransceiverState *state,
567 signalVector &burst, complex amp,
568 float toa, size_t tn, bool equalize)
569{
570 if (equalize) {
571 scaleVector(burst, complex(1.0, 0.0) / amp);
572 return equalizeBurst(burst,
573 toa - state->chanRespOffset[tn],
574 mSPSRx,
575 *state->DFEForward[tn],
576 *state->DFEFeedback[tn]);
577 }
578
579 return demodulateBurst(burst, mSPSRx, amp, toa);
580}
581
582/*
583 * Pull bursts from the FIFO and handle according to the slot
584 * and burst correlation type. Equalzation is currently disabled.
585 */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400586SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
587 int &timingOffset, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000588{
Thomas Tsou30421a72013-11-13 23:14:48 -0500589 bool success, equalize = false;
590 complex amp;
591 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500592 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500593 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500594 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500595 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000596
Thomas Tsouc7f36c22014-04-16 22:24:00 -0400597 GSM::Time sch_time, burst_time, diff_time;
598
Thomas Tsou30421a72013-11-13 23:14:48 -0500599 /* Blocking FIFO read */
600 radioVector *radio_burst = mReceiveFIFO[chan]->read();
601 if (!radio_burst)
602 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000603
Thomas Tsou30421a72013-11-13 23:14:48 -0500604 /* Set time and determine correlation type */
Thomas Tsouc7f36c22014-04-16 22:24:00 -0400605 burst_time = radio_burst->getTime();
606 CorrType type = expectedCorrType(burst_time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000607
Thomas Tsouf31e4bb2014-04-16 20:02:06 -0400608 switch (state->mode) {
609 case TRX_MODE_MS_ACQUIRE:
610 type = SCH;
611 break;
Thomas Tsouc7f36c22014-04-16 22:24:00 -0400612 case TRX_MODE_MS_TRACK:
Thomas Tsou94ce8352014-10-08 11:49:08 -0700613 if (gsm_sch_check_fn(burst_time.FN()))
614 type = SCH;
615 else if (type == OFF)
616 goto release;
Thomas Tsouc7f36c22014-04-16 22:24:00 -0400617 break;
Thomas Tsouf31e4bb2014-04-16 20:02:06 -0400618 case TRX_MODE_BTS:
619 if ((type == TSC) || (type == RACH))
620 break;
621 case TRX_MODE_OFF:
622 default:
623 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +0000624 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000625
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500626 /* Select the diversity channel with highest energy */
627 for (size_t i = 0; i < radio_burst->chans(); i++) {
628 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
629 if (pow > max) {
630 max = pow;
631 max_i = i;
632 }
633 avg += pow;
634 }
635
636 if (max_i < 0) {
637 LOG(ALERT) << "Received empty burst";
Thomas Tsouf31e4bb2014-04-16 20:02:06 -0400638 goto release;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500639 }
640
Thomas Tsou30421a72013-11-13 23:14:48 -0500641 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500642 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500643 avg = sqrt(avg / radio_burst->chans());
Thomas Tsoua0179e32013-11-14 15:52:04 -0500644 state->mNoiseLev = state->mNoises.avg();
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400645
Thomas Tsou30421a72013-11-13 23:14:48 -0500646 /* Detect normal or RACH bursts */
647 if (type == TSC)
Thomas Tsouc7f36c22014-04-16 22:24:00 -0400648 success = detectTSC(state, *burst, amp, toa, burst_time);
Thomas Tsouf31e4bb2014-04-16 20:02:06 -0400649 else if (type == RACH)
Thomas Tsoua0179e32013-11-14 15:52:04 -0500650 success = detectRACH(state, *burst, amp, toa);
Thomas Tsouf31e4bb2014-04-16 20:02:06 -0400651 else if (type == SCH)
652 success = detectSCH(state, *burst, amp, toa);
653 else
654 success = false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400655
Thomas Tsou30421a72013-11-13 23:14:48 -0500656 if (!success) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500657 state->mNoises.insert(avg);
Thomas Tsouf31e4bb2014-04-16 20:02:06 -0400658 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +0000659 }
dburgessb3a0ca42011-10-12 07:44:40 +0000660
Thomas Tsou30421a72013-11-13 23:14:48 -0500661 /* Demodulate and set output info */
662 if (equalize && (type != TSC))
663 equalize = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000664
Thomas Tsouc7f36c22014-04-16 22:24:00 -0400665 /* Ignore noise threshold on MS mode for now */
666 if ((type == SCH) || (avg - state->mNoiseLev > 0.0))
667 bits = demodulate(state, *burst, amp, toa,
668 burst_time.TN(), equalize);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500669
Thomas Tsouc7f36c22014-04-16 22:24:00 -0400670 /* MS: Decode SCH and adjust GSM clock */
671 if ((state->mode == TRX_MODE_MS_ACQUIRE) ||
672 (state->mode == TRX_MODE_MS_TRACK)) {
Thomas Tsou14bb9c92014-04-16 23:10:12 -0400673 correctFCCH(state, state->prevFrame[burst_time.TN()]->getVector());
Thomas Tsouc7f36c22014-04-16 22:24:00 -0400674
675 if (decodeSCH(bits, &sch_time)) {
676 if (state->mode == TRX_MODE_MS_ACQUIRE) {
677 diff_time = GSM::Time(sch_time.FN() - burst_time.FN(),
678 -burst_time.TN());
679 mRadioInterface->adjustClock(diff_time);
Thomas Tsou13033762014-10-06 19:05:52 -0700680 mTransmitDeadlineClock = RadioClock::adjust(
681 mTransmitDeadlineClock,
682 diff_time);
Thomas Tsouc7f36c22014-04-16 22:24:00 -0400683 state->mode = TRX_MODE_MS_TRACK;
684
685 std::cout << "SCH : Locking GSM clock " << std::endl;
686 } else {
687 std::cout << "SCH : Read SCH at FN " << burst_time.FN()
688 << " FN51 " << burst_time.FN() % 51 << std::endl;
689 }
690 }
691 goto release;
692 }
693
694 wTime = burst_time;
Thomas Tsou30421a72013-11-13 23:14:48 -0500695 RSSI = (int) floor(20.0 * log10(rxFullScale / avg));
696 timingOffset = (int) round(toa * 256.0 / mSPSRx);
dburgessb3a0ca42011-10-12 07:44:40 +0000697
Thomas Tsou14bb9c92014-04-16 23:10:12 -0400698 delete state->prevFrame[burst_time.TN()];
699 state->prevFrame[burst_time.TN()] = radio_burst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500700
701 return bits;
Thomas Tsouf31e4bb2014-04-16 20:02:06 -0400702
703release:
Thomas Tsou14bb9c92014-04-16 23:10:12 -0400704 delete state->prevFrame[burst_time.TN()];
705 state->prevFrame[burst_time.TN()] = radio_burst;
Thomas Tsouf31e4bb2014-04-16 20:02:06 -0400706 delete bits;
707 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000708}
709
710void Transceiver::start()
711{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400712 TransceiverChannel *chan;
713
714 for (size_t i = 0; i < mControlServiceLoopThreads.size(); i++) {
715 chan = new TransceiverChannel(this, i);
716 mControlServiceLoopThreads[i]->start((void * (*)(void*))
717 ControlServiceLoopAdapter, (void*) chan);
718 }
dburgessb3a0ca42011-10-12 07:44:40 +0000719}
720
721void Transceiver::reset()
722{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400723 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
724 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000725}
726
727
Thomas Tsou204a9f12013-10-29 18:34:16 -0400728void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000729{
dburgessb3a0ca42011-10-12 07:44:40 +0000730 int MAX_PACKET_LENGTH = 100;
731
732 // check control socket
733 char buffer[MAX_PACKET_LENGTH];
734 int msgLen = -1;
735 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400736
Thomas Tsou204a9f12013-10-29 18:34:16 -0400737 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000738
739 if (msgLen < 1) {
740 return;
741 }
742
743 char cmdcheck[4];
744 char command[MAX_PACKET_LENGTH];
745 char response[MAX_PACKET_LENGTH];
746
747 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400748
749 if (!chan)
750 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000751
752 if (strcmp(cmdcheck,"CMD")!=0) {
753 LOG(WARNING) << "bogus message on control interface";
754 return;
755 }
756 LOG(INFO) << "command is " << buffer;
757
758 if (strcmp(command,"POWEROFF")==0) {
759 // turn off transmitter/demod
760 sprintf(response,"RSP POWEROFF 0");
761 }
762 else if (strcmp(command,"POWERON")==0) {
763 // turn on transmitter/demod
764 if (!mTxFreq || !mRxFreq)
765 sprintf(response,"RSP POWERON 1");
766 else {
767 sprintf(response,"RSP POWERON 0");
Thomas Tsou204a9f12013-10-29 18:34:16 -0400768 if (!chan && !mOn) {
dburgessb3a0ca42011-10-12 07:44:40 +0000769 // Prepare for thread start
770 mPower = -20;
771 mRadioInterface->start();
dburgessb3a0ca42011-10-12 07:44:40 +0000772
773 // Start radio interface threads.
Thomas Tsou13033762014-10-06 19:05:52 -0700774 mLowerLoopThread->start((void * (*)(void*))
775 LowerLoopAdapter,(void*) this);
dburgessb3a0ca42011-10-12 07:44:40 +0000776
Thomas Tsou204a9f12013-10-29 18:34:16 -0400777 for (size_t i = 0; i < mChans; i++) {
778 TransceiverChannel *chan = new TransceiverChannel(this, i);
779 mRxServiceLoopThreads[i]->start((void * (*)(void*))
780 RxUpperLoopAdapter, (void*) chan);
781
782 chan = new TransceiverChannel(this, i);
783 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
784 TxUpperLoopAdapter, (void*) chan);
785 }
786
787 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000788 mOn = true;
789 }
790 }
791 }
792 else if (strcmp(command,"SETMAXDLY")==0) {
793 //set expected maximum time-of-arrival
794 int maxDelay;
795 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
796 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
797 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
798 }
799 else if (strcmp(command,"SETRXGAIN")==0) {
800 //set expected maximum time-of-arrival
801 int newGain;
802 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400803 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000804 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
805 }
806 else if (strcmp(command,"NOISELEV")==0) {
807 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500808 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000809 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500810 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000811 }
812 else {
813 sprintf(response,"RSP NOISELEV 1 0");
814 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500815 }
816 else if (!strcmp(command, "SETPOWER")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000817 // set output power in dB
818 int dbPwr;
Thomas Tsoucb269a32013-11-15 14:15:47 -0500819 sscanf(buffer, "%3s %s %d", cmdcheck, command, &dbPwr);
820 if (!mOn)
821 sprintf(response, "RSP SETPOWER 1 %d", dbPwr);
dburgessb3a0ca42011-10-12 07:44:40 +0000822 else {
823 mPower = dbPwr;
Thomas Tsoucb269a32013-11-15 14:15:47 -0500824 mRadioInterface->setPowerAttenuation(mPower, chan);
825 sprintf(response, "RSP SETPOWER 0 %d", dbPwr);
dburgessb3a0ca42011-10-12 07:44:40 +0000826 }
827 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500828 else if (!strcmp(command,"ADJPOWER")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000829 // adjust power in dB steps
830 int dbStep;
Thomas Tsoucb269a32013-11-15 14:15:47 -0500831 sscanf(buffer, "%3s %s %d", cmdcheck, command, &dbStep);
832 if (!mOn)
833 sprintf(response, "RSP ADJPOWER 1 %d", mPower);
dburgessb3a0ca42011-10-12 07:44:40 +0000834 else {
835 mPower += dbStep;
Thomas Tsoucb269a32013-11-15 14:15:47 -0500836 mRadioInterface->setPowerAttenuation(mPower, chan);
837 sprintf(response, "RSP ADJPOWER 0 %d", mPower);
dburgessb3a0ca42011-10-12 07:44:40 +0000838 }
839 }
dburgessb3a0ca42011-10-12 07:44:40 +0000840 else if (strcmp(command,"RXTUNE")==0) {
841 // tune receiver
842 int freqKhz;
843 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500844 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400845 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000846 LOG(ALERT) << "RX failed to tune";
847 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
848 }
849 else
850 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
851 }
852 else if (strcmp(command,"TXTUNE")==0) {
853 // tune txmtr
854 int freqKhz;
855 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500856 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400857 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000858 LOG(ALERT) << "TX failed to tune";
859 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
860 }
861 else
862 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
863 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500864 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000865 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500866 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500867 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000868 if (mOn)
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500869 sprintf(response, "RSP SETTSC 1 %d", TSC);
870 else if (chan && (TSC != mTSC))
871 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000872 else {
873 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400874 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400875 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000876 }
877 }
Thomas Tsoue2875982014-10-06 10:38:43 -0700878 else if (!strcmp(command,"GETBSIC")) {
879 if (mBSIC < 0)
880 sprintf(response, "RSP GETBSIC 1");
881 else
882 sprintf(response, "RSP GETBSIC 0 %d", mBSIC);
883 }
dburgessb3a0ca42011-10-12 07:44:40 +0000884 else if (strcmp(command,"SETSLOT")==0) {
885 // set TSC
886 int corrCode;
887 int timeslot;
888 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
889 if ((timeslot < 0) || (timeslot > 7)) {
890 LOG(WARNING) << "bogus message on control interface";
891 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
892 return;
893 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400894 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
895 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000896 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
Thomas Tsouf31e4bb2014-04-16 20:02:06 -0400897 }
Thomas Tsou25021df2014-10-06 11:43:48 -0700898 else if (!strcmp(command,"SETRXMASK")) {
899 int slot;
900 unsigned long long mask;
Thomas Tsou94ce8352014-10-08 11:49:08 -0700901 sscanf(buffer,"%3s %s %d 0x%llx", cmdcheck, command, &slot, &mask);
Thomas Tsou25021df2014-10-06 11:43:48 -0700902 if ((slot < 0) || (slot > 7)) {
903 sprintf(response, "RSP SETRXMASK 1");
904 } else {
905 mRxSlotMask[slot] = mask;
Thomas Tsou94ce8352014-10-08 11:49:08 -0700906 sprintf(response, "RSP SETRXMASK 0 %d 0x%llx", slot, mask);
Thomas Tsou25021df2014-10-06 11:43:48 -0700907 }
908 }
Thomas Tsouf31e4bb2014-04-16 20:02:06 -0400909 else if (!strcmp(command, "SYNC")) {
910 mStates[0].mode = TRX_MODE_MS_ACQUIRE;
911 sprintf(response,"RSP SYNC 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000912 }
913 else {
914 LOG(WARNING) << "bogus command " << command << " on control interface.";
915 }
916
Thomas Tsou204a9f12013-10-29 18:34:16 -0400917 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000918}
919
Thomas Tsou204a9f12013-10-29 18:34:16 -0400920bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000921{
dburgessb3a0ca42011-10-12 07:44:40 +0000922 char buffer[gSlotLen+50];
923
924 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400925 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000926
927 if (msgLen!=gSlotLen+1+4+1) {
928 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
929 return false;
930 }
931
932 int timeSlot = (int) buffer[0];
933 uint64_t frameNum = 0;
934 for (int i = 0; i < 4; i++)
935 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000936
dburgessb3a0ca42011-10-12 07:44:40 +0000937 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
938
939 int RSSI = (int) buffer[5];
940 static BitVector newBurst(gSlotLen);
941 BitVector::iterator itr = newBurst.begin();
942 char *bufferItr = buffer+6;
943 while (itr < newBurst.end())
944 *itr++ = *bufferItr++;
945
946 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400947
948 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000949
950 return true;
951
952
953}
dburgessb3a0ca42011-10-12 07:44:40 +0000954
Thomas Tsou204a9f12013-10-29 18:34:16 -0400955void Transceiver::driveReceiveRadio()
956{
957 if (!mRadioInterface->driveReceiveRadio())
958 usleep(100000);
959}
960
961void Transceiver::driveReceiveFIFO(size_t chan)
962{
dburgessb3a0ca42011-10-12 07:44:40 +0000963 SoftVector *rxBurst = NULL;
964 int RSSI;
965 int TOA; // in 1/256 of a symbol
966 GSM::Time burstTime;
967
Thomas Tsou204a9f12013-10-29 18:34:16 -0400968 rxBurst = pullRadioVector(burstTime, RSSI, TOA, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000969
970 if (rxBurst) {
971
972 LOG(DEBUG) << "burst parameters: "
973 << " time: " << burstTime
974 << " RSSI: " << RSSI
975 << " TOA: " << TOA
976 << " bits: " << *rxBurst;
977
978 char burstString[gSlotLen+10];
979 burstString[0] = burstTime.TN();
980 for (int i = 0; i < 4; i++)
981 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
982 burstString[5] = RSSI;
983 burstString[6] = (TOA >> 8) & 0x0ff;
984 burstString[7] = TOA & 0x0ff;
985 SoftVector::iterator burstItr = rxBurst->begin();
986
987 for (unsigned int i = 0; i < gSlotLen; i++) {
988 burstString[8+i] =(char) round((*burstItr++)*255.0);
989 }
990 burstString[gSlotLen+9] = '\0';
991 delete rxBurst;
992
Thomas Tsou204a9f12013-10-29 18:34:16 -0400993 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +0000994 }
dburgessb3a0ca42011-10-12 07:44:40 +0000995}
996
Thomas Tsou204a9f12013-10-29 18:34:16 -0400997void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000998{
999
1000 /**
1001 Features a carefully controlled latency mechanism, to
1002 assure that transmit packets arrive at the radio/USRP
1003 before they need to be transmitted.
1004
1005 Deadline clock indicates the burst that needs to be
1006 pushed into the FIFO right NOW. If transmit queue does
1007 not have a burst, stick in filler data.
1008 */
1009
1010
1011 RadioClock *radioClock = (mRadioInterface->getClock());
1012
1013 if (mOn) {
1014 //radioClock->wait(); // wait until clock updates
1015 LOG(DEBUG) << "radio clock " << radioClock->get();
1016 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
1017 // if underrun, then we're not providing bursts to radio/USRP fast
1018 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -04001019 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001020 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +00001021 // only update latency at the defined frame interval
1022 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001023 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
1024 LOG(INFO) << "new latency: " << mTransmitLatency;
1025 mLatencyUpdateTime = radioClock->get();
1026 }
1027 }
1028 else {
1029 // if underrun hasn't occurred in the last sec (216 frames) drop
1030 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +00001031 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001032 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1033 mTransmitLatency.decTN();
1034 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1035 mLatencyUpdateTime = radioClock->get();
1036 }
1037 }
1038 }
dburgessb3a0ca42011-10-12 07:44:40 +00001039 }
dburgessb3a0ca42011-10-12 07:44:40 +00001040 // time to push burst to transmit FIFO
Thomas Tsou13033762014-10-06 19:05:52 -07001041 pushRadioVector(mTransmitDeadlineClock);
Thomas Tsouf31e4bb2014-04-16 20:02:06 -04001042
dburgessb3a0ca42011-10-12 07:44:40 +00001043 mTransmitDeadlineClock.incTN();
Tom Tsou774a0632014-10-31 13:18:43 -07001044
1045 if (!mTransmitDeadlineClock.TN() &&
1046 !(mTransmitDeadlineClock.FN() % CLK_IND_INTERVAL)) {
1047 writeClockInterface();
1048 }
dburgessb3a0ca42011-10-12 07:44:40 +00001049 }
dburgessb3a0ca42011-10-12 07:44:40 +00001050 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001051
1052 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001053}
1054
1055
1056
1057void Transceiver::writeClockInterface()
1058{
1059 char command[50];
1060 // FIXME -- This should be adaptive.
1061 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1062
1063 LOG(INFO) << "ClockInterface: sending " << command;
1064
Thomas Tsoud647ec52013-10-29 15:17:34 -04001065 mClockSocket->write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +00001066
1067 mLastClockUpdateTime = mTransmitDeadlineClock;
1068
Thomas Tsou92c16df2013-09-28 18:04:19 -04001069}
dburgessb3a0ca42011-10-12 07:44:40 +00001070
Thomas Tsou204a9f12013-10-29 18:34:16 -04001071void *RxUpperLoopAdapter(TransceiverChannel *chan)
1072{
1073 Transceiver *trx = chan->trx;
1074 size_t num = chan->num;
1075
1076 delete chan;
1077
Thomas Tsou7553aa92013-11-08 12:50:03 -05001078 trx->setPriority(0.42);
1079
Thomas Tsou204a9f12013-10-29 18:34:16 -04001080 while (1) {
1081 trx->driveReceiveFIFO(num);
1082 pthread_testcancel();
1083 }
1084 return NULL;
1085}
1086
Thomas Tsou13033762014-10-06 19:05:52 -07001087void *LowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001088{
Thomas Tsou7553aa92013-11-08 12:50:03 -05001089 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001090
dburgessb3a0ca42011-10-12 07:44:40 +00001091 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001092 transceiver->driveReceiveRadio();
Thomas Tsou204a9f12013-10-29 18:34:16 -04001093 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001094 pthread_testcancel();
1095 }
1096 return NULL;
1097}
1098
Thomas Tsou204a9f12013-10-29 18:34:16 -04001099void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001100{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001101 Transceiver *trx = chan->trx;
1102 size_t num = chan->num;
1103
1104 delete chan;
1105
dburgessb3a0ca42011-10-12 07:44:40 +00001106 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001107 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001108 pthread_testcancel();
1109 }
1110 return NULL;
1111}
1112
Thomas Tsou204a9f12013-10-29 18:34:16 -04001113void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001114{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001115 Transceiver *trx = chan->trx;
1116 size_t num = chan->num;
1117
1118 delete chan;
1119
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001120 trx->setPriority(0.40);
1121
dburgessb3a0ca42011-10-12 07:44:40 +00001122 while (1) {
1123 bool stale = false;
1124 // Flush the UDP packets until a successful transfer.
Thomas Tsou204a9f12013-10-29 18:34:16 -04001125 while (!trx->driveTxPriorityQueue(num)) {
1126 stale = true;
dburgessb3a0ca42011-10-12 07:44:40 +00001127 }
Thomas Tsou204a9f12013-10-29 18:34:16 -04001128 if (!num && stale) {
dburgessb3a0ca42011-10-12 07:44:40 +00001129 // If a packet was stale, remind the GSM stack of the clock.
Thomas Tsou204a9f12013-10-29 18:34:16 -04001130 trx->writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +00001131 }
1132 pthread_testcancel();
1133 }
1134 return NULL;
1135}