blob: 7aec64c6af8a0a5ce596d578aebb509993b10b48 [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
ttsou2173abf2012-08-08 00:51:31 +000028#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
dburgessb3a0ca42011-10-12 07:44:40 +000031
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040032using namespace GSM;
33
kurtis.heimerlec842de2012-11-23 08:37:32 +000034#define USB_LATENCY_INTRVL 10,0
ttsou2173abf2012-08-08 00:51:31 +000035
36#if USE_UHD
kurtis.heimerlec842de2012-11-23 08:37:32 +000037# define USB_LATENCY_MIN 6,7
ttsou2173abf2012-08-08 00:51:31 +000038#else
kurtis.heimerlec842de2012-11-23 08:37:32 +000039# define USB_LATENCY_MIN 1,1
ttsou2173abf2012-08-08 00:51:31 +000040#endif
dburgessb3a0ca42011-10-12 07:44:40 +000041
Thomas Tsoufa3a7872013-10-17 21:23:34 -040042/* Number of running values use in noise average */
43#define NOISE_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000044
Thomas Tsouf0782732013-10-29 15:55:47 -040045TransceiverState::TransceiverState()
Thomas Tsoua0179e32013-11-14 15:52:04 -050046 : mNoiseLev(0.0), mNoises(NOISE_CNT)
Thomas Tsouf0782732013-10-29 15:55:47 -040047{
48 for (int i = 0; i < 8; i++) {
49 chanType[i] = Transceiver::NONE;
50 fillerModulus[i] = 26;
51 chanResponse[i] = NULL;
52 DFEForward[i] = NULL;
53 DFEFeedback[i] = NULL;
54
55 for (int n = 0; n < 102; n++)
56 fillerTable[n][i] = NULL;
57 }
58}
59
60TransceiverState::~TransceiverState()
61{
62 for (int i = 0; i < 8; i++) {
63 delete chanResponse[i];
64 delete DFEForward[i];
65 delete DFEFeedback[i];
66
67 for (int n = 0; n < 102; n++)
68 delete fillerTable[n][i];
69 }
70}
71
72void TransceiverState::init(size_t slot, signalVector *burst)
73{
74 for (int i = 0; i < 102; i++)
75 fillerTable[i][slot] = new signalVector(*burst);
76}
77
dburgessb3a0ca42011-10-12 07:44:40 +000078Transceiver::Transceiver(int wBasePort,
79 const char *TRXAddress,
Thomas Tsou204a9f12013-10-29 18:34:16 -040080 size_t wSPS, size_t wChans,
dburgessb3a0ca42011-10-12 07:44:40 +000081 GSM::Time wTransmitLatency,
82 RadioInterface *wRadioInterface)
Thomas Tsoud647ec52013-10-29 15:17:34 -040083 : mBasePort(wBasePort), mAddr(TRXAddress),
Thomas Tsoua0179e32013-11-14 15:52:04 -050084 mTransmitLatency(wTransmitLatency), mClockSocket(NULL),
85 mRadioInterface(wRadioInterface), mSPSTx(wSPS), mSPSRx(1), mChans(wChans),
Thomas Tsou204a9f12013-10-29 18:34:16 -040086 mOn(false), mTxFreq(0.0), mRxFreq(0.0), mPower(-10), mMaxExpectedDelay(0)
dburgessb3a0ca42011-10-12 07:44:40 +000087{
dburgessb3a0ca42011-10-12 07:44:40 +000088 GSM::Time startTime(random() % gHyperframe,0);
89
Thomas Tsou204a9f12013-10-29 18:34:16 -040090 mRxLowerLoopThread = new Thread(32768);
91 mTxLowerLoopThread = new Thread(32768);
dburgessb3a0ca42011-10-12 07:44:40 +000092
dburgessb3a0ca42011-10-12 07:44:40 +000093 mTransmitDeadlineClock = startTime;
94 mLastClockUpdateTime = startTime;
95 mLatencyUpdateTime = startTime;
96 mRadioInterface->getClock()->set(startTime);
dburgessb3a0ca42011-10-12 07:44:40 +000097
dburgessb3a0ca42011-10-12 07:44:40 +000098 txFullScale = mRadioInterface->fullScaleInputValue();
99 rxFullScale = mRadioInterface->fullScaleOutputValue();
dburgessb3a0ca42011-10-12 07:44:40 +0000100}
101
102Transceiver::~Transceiver()
103{
dburgessb3a0ca42011-10-12 07:44:40 +0000104 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400105
106 delete mClockSocket;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400107
108 for (size_t i = 0; i < mChans; i++) {
109 mTxPriorityQueues[i].clear();
110 delete mCtrlSockets[i];
111 delete mDataSockets[i];
112 }
dburgessb3a0ca42011-10-12 07:44:40 +0000113}
Thomas Tsou83e06892013-08-20 16:10:01 -0400114
115bool Transceiver::init()
116{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500117 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400118 signalVector *burst;
119
Thomas Tsou204a9f12013-10-29 18:34:16 -0400120 if (!mChans) {
121 LOG(ALERT) << "No channels assigned";
122 return false;
123 }
124
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400125 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400126 LOG(ALERT) << "Failed to initialize signal processing library";
127 return false;
128 }
129
Thomas Tsou204a9f12013-10-29 18:34:16 -0400130 mDataSockets.resize(mChans);
131 mCtrlSockets.resize(mChans);
132
133 mControlServiceLoopThreads.resize(mChans);
134 mTxPriorityQueueServiceLoopThreads.resize(mChans);
135 mRxServiceLoopThreads.resize(mChans);
136
137 mTxPriorityQueues.resize(mChans);
138 mReceiveFIFO.resize(mChans);
139 mStates.resize(mChans);
140
Thomas Tsoud647ec52013-10-29 15:17:34 -0400141 mClockSocket = new UDPSocket(mBasePort, mAddr.c_str(), mBasePort + 100);
Thomas Tsoud647ec52013-10-29 15:17:34 -0400142
Thomas Tsou204a9f12013-10-29 18:34:16 -0400143 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500144 c_srcport = mBasePort + 2 * i + 1;
145 c_dstport = mBasePort + 2 * i + 101;
146 d_srcport = mBasePort + 2 * i + 2;
147 d_dstport = mBasePort + 2 * i + 102;
148
149 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
150 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400151 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400152
Thomas Tsou204a9f12013-10-29 18:34:16 -0400153 for (size_t i = 0; i < mChans; i++) {
154 mControlServiceLoopThreads[i] = new Thread(32768);
155 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
156 mRxServiceLoopThreads[i] = new Thread(32768);
157
158 for (size_t n = 0; n < 8; n++) {
159 burst = modulateBurst(gDummyBurst, 8 + (n % 4 == 0), mSPSTx);
160 scaleVector(*burst, txFullScale);
161 mStates[i].init(n, burst);
162 delete burst;
163 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400164 }
165
166 return true;
167}
dburgessb3a0ca42011-10-12 07:44:40 +0000168
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500169void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400170 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000171{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500172 signalVector *burst;
173 radioVector *radio_burst;
174
Thomas Tsou204a9f12013-10-29 18:34:16 -0400175 if (chan >= mTxPriorityQueues.size()) {
176 LOG(ALERT) << "Invalid channel " << chan;
177 return;
178 }
179
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500180 if (wTime.TN() > 7) {
181 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
182 return;
183 }
184
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500185 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
186 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000187
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500188 radio_burst = new radioVector(wTime, burst);
189
190 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000191}
192
dburgessb3a0ca42011-10-12 07:44:40 +0000193void Transceiver::pushRadioVector(GSM::Time &nowTime)
194{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400195 int TN, modFN;
196 radioVector *burst;
197 TransceiverState *state;
198 std::vector<signalVector *> bursts(mChans);
199 std::vector<bool> zeros(mChans);
dburgessb3a0ca42011-10-12 07:44:40 +0000200
Thomas Tsou204a9f12013-10-29 18:34:16 -0400201 for (size_t i = 0; i < mChans; i ++) {
202 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000203
Thomas Tsou204a9f12013-10-29 18:34:16 -0400204 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
205 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
206
207 TN = burst->getTime().TN();
208 modFN = burst->getTime().FN() % state->fillerModulus[TN];
209
210 delete state->fillerTable[modFN][TN];
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500211 state->fillerTable[modFN][TN] = burst->getVector();
212 burst->setVector(NULL);
213 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400214 }
215
216 TN = nowTime.TN();
217 modFN = nowTime.FN() % state->fillerModulus[TN];
218
219 bursts[i] = state->fillerTable[modFN][TN];
220 zeros[i] = state->chanType[TN] == NONE;
221
222 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
223 delete state->fillerTable[modFN][TN];
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500224 state->fillerTable[modFN][TN] = burst->getVector();
225 bursts[i] = burst->getVector();
226 burst->setVector(NULL);
227 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400228 }
dburgessb3a0ca42011-10-12 07:44:40 +0000229 }
230
Thomas Tsou204a9f12013-10-29 18:34:16 -0400231 mRadioInterface->driveTransmitRadio(bursts, zeros);
232
233 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000234}
235
Thomas Tsou204a9f12013-10-29 18:34:16 -0400236void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000237{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400238 TransceiverState *state = &mStates[chan];
239
240 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000241 case NONE:
242 case I:
243 case II:
244 case III:
245 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400246 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000247 break;
248 case IV:
249 case VI:
250 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400251 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000252 break;
253 //case V:
254 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400255 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000256 break;
ttsoufc40a842013-06-09 22:38:18 +0000257 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400258 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000259 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000260 default:
261 break;
262 }
263}
264
265
Thomas Tsou204a9f12013-10-29 18:34:16 -0400266Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
267 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000268{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400269 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000270 unsigned burstTN = currTime.TN();
271 unsigned burstFN = currTime.FN();
272
Thomas Tsou204a9f12013-10-29 18:34:16 -0400273 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000274 case NONE:
275 return OFF;
276 break;
277 case FILL:
278 return IDLE;
279 break;
280 case I:
281 return TSC;
282 /*if (burstFN % 26 == 25)
283 return IDLE;
284 else
285 return TSC;*/
286 break;
287 case II:
ttsou20642972013-03-27 22:00:25 +0000288 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000289 break;
290 case III:
291 return TSC;
292 break;
293 case IV:
294 case VI:
295 return RACH;
296 break;
297 case V: {
298 int mod51 = burstFN % 51;
299 if ((mod51 <= 36) && (mod51 >= 14))
300 return RACH;
301 else if ((mod51 == 4) || (mod51 == 5))
302 return RACH;
303 else if ((mod51 == 45) || (mod51 == 46))
304 return RACH;
305 else
306 return TSC;
307 break;
308 }
309 case VII:
310 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
311 return IDLE;
312 else
313 return TSC;
314 break;
ttsoufc40a842013-06-09 22:38:18 +0000315 case XIII: {
316 int mod52 = burstFN % 52;
317 if ((mod52 == 12) || (mod52 == 38))
318 return RACH;
319 else if ((mod52 == 25) || (mod52 == 51))
320 return IDLE;
321 else
322 return TSC;
323 break;
324 }
dburgessb3a0ca42011-10-12 07:44:40 +0000325 case LOOPBACK:
326 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
327 return IDLE;
328 else
329 return TSC;
330 break;
331 default:
332 return OFF;
333 break;
334 }
dburgessb3a0ca42011-10-12 07:44:40 +0000335}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400336
Thomas Tsou30421a72013-11-13 23:14:48 -0500337/*
338 * Detect RACH synchronization sequence within a burst. No equalization
339 * is used or available on the RACH channel.
340 */
341bool Transceiver::detectRACH(TransceiverState *state,
342 signalVector &burst,
343 complex &amp, float &toa)
344{
345 float threshold = 6.0;
346
347 return detectRACHBurst(burst, threshold, mSPSRx, &amp, &toa);
348}
349
350/*
351 * Detect normal burst training sequence midamble. Update equalization
352 * state information and channel estimate if necessary. Equalization
353 * is currently disabled.
354 */
Thomas Tsoua0179e32013-11-14 15:52:04 -0500355bool Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
Thomas Tsou30421a72013-11-13 23:14:48 -0500356 complex &amp, float &toa, GSM::Time &time)
357{
358 int tn = time.TN();
359 float chanOffset, threshold = 5.0;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500360 bool noise, needDFE = false, estimateChan = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500361 double elapsed = time - state->chanEstimateTime[tn];
362 signalVector *chanResp;
363
364 /* Check equalization update state */
365 if ((elapsed > 50) || (!state->chanResponse[tn])) {
366 delete state->DFEForward[tn];
367 delete state->DFEFeedback[tn];
368 state->DFEForward[tn] = NULL;
369 state->DFEFeedback[tn] = NULL;
370
371 estimateChan = true;
372 }
373
374 /* Detect normal burst midambles */
375 if (!analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, &amp,
376 &toa, mMaxExpectedDelay, estimateChan,
377 &chanResp, &chanOffset)) {
378 return false;
379 }
380
Thomas Tsoua0179e32013-11-14 15:52:04 -0500381 noise = state->mNoiseLev;
382 state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
Thomas Tsou30421a72013-11-13 23:14:48 -0500383
384 /* Set equalizer if unabled */
385 if (needDFE && estimateChan) {
386 state->chanResponse[tn] = chanResp;
387 state->chanRespOffset[tn] = chanOffset;
388 state->chanRespAmplitude[tn] = amp;
389
390 scaleVector(*chanResp, complex(1.0, 0.0) / amp);
391
392 designDFE(*chanResp, state->SNRestimate[tn],
393 7, &state->DFEForward[tn], &state->DFEFeedback[tn]);
394
395 state->chanEstimateTime[tn] = time;
396 }
397
398 return true;;
399}
400
401/*
402 * Demodulate GMSK burst using equalization if requested. Otherwise
403 * demodulate by direct rotation and soft slicing.
404 */
405SoftVector *Transceiver::demodulate(TransceiverState *state,
406 signalVector &burst, complex amp,
407 float toa, size_t tn, bool equalize)
408{
409 if (equalize) {
410 scaleVector(burst, complex(1.0, 0.0) / amp);
411 return equalizeBurst(burst,
412 toa - state->chanRespOffset[tn],
413 mSPSRx,
414 *state->DFEForward[tn],
415 *state->DFEFeedback[tn]);
416 }
417
418 return demodulateBurst(burst, mSPSRx, amp, toa);
419}
420
421/*
422 * Pull bursts from the FIFO and handle according to the slot
423 * and burst correlation type. Equalzation is currently disabled.
424 */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400425SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
426 int &timingOffset, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000427{
Thomas Tsou30421a72013-11-13 23:14:48 -0500428 bool success, equalize = false;
429 complex amp;
430 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500431 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500432 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500433 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500434 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000435
Thomas Tsou30421a72013-11-13 23:14:48 -0500436 /* Blocking FIFO read */
437 radioVector *radio_burst = mReceiveFIFO[chan]->read();
438 if (!radio_burst)
439 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000440
Thomas Tsou30421a72013-11-13 23:14:48 -0500441 /* Set time and determine correlation type */
442 GSM::Time time = radio_burst->getTime();
443 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000444
Thomas Tsou30421a72013-11-13 23:14:48 -0500445 if ((type == OFF) || (type == IDLE)) {
446 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000447 return NULL;
448 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000449
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500450 /* Select the diversity channel with highest energy */
451 for (size_t i = 0; i < radio_burst->chans(); i++) {
452 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
453 if (pow > max) {
454 max = pow;
455 max_i = i;
456 }
457 avg += pow;
458 }
459
460 if (max_i < 0) {
461 LOG(ALERT) << "Received empty burst";
462 delete radio_burst;
463 return NULL;
464 }
465
Thomas Tsou30421a72013-11-13 23:14:48 -0500466 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500467 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500468 avg = sqrt(avg / radio_burst->chans());
Thomas Tsoua0179e32013-11-14 15:52:04 -0500469 state->mNoiseLev = state->mNoises.avg();
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400470
Thomas Tsou30421a72013-11-13 23:14:48 -0500471 /* Detect normal or RACH bursts */
472 if (type == TSC)
Thomas Tsoua0179e32013-11-14 15:52:04 -0500473 success = detectTSC(state, *burst, amp, toa, time);
Thomas Tsou30421a72013-11-13 23:14:48 -0500474 else
Thomas Tsoua0179e32013-11-14 15:52:04 -0500475 success = detectRACH(state, *burst, amp, toa);
Thomas Tsouf0782732013-10-29 15:55:47 -0400476
Thomas Tsou30421a72013-11-13 23:14:48 -0500477 if (!success) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500478 state->mNoises.insert(avg);
Thomas Tsou30421a72013-11-13 23:14:48 -0500479 delete radio_burst;
480 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000481 }
dburgessb3a0ca42011-10-12 07:44:40 +0000482
Thomas Tsou30421a72013-11-13 23:14:48 -0500483 /* Demodulate and set output info */
484 if (equalize && (type != TSC))
485 equalize = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000486
Thomas Tsoua0179e32013-11-14 15:52:04 -0500487 if (avg - state->mNoiseLev > 0.0)
488 bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500489
Thomas Tsou30421a72013-11-13 23:14:48 -0500490 wTime = time;
491 RSSI = (int) floor(20.0 * log10(rxFullScale / avg));
492 timingOffset = (int) round(toa * 256.0 / mSPSRx);
dburgessb3a0ca42011-10-12 07:44:40 +0000493
Thomas Tsou30421a72013-11-13 23:14:48 -0500494 delete radio_burst;
495
496 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000497}
498
499void Transceiver::start()
500{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400501 TransceiverChannel *chan;
502
503 for (size_t i = 0; i < mControlServiceLoopThreads.size(); i++) {
504 chan = new TransceiverChannel(this, i);
505 mControlServiceLoopThreads[i]->start((void * (*)(void*))
506 ControlServiceLoopAdapter, (void*) chan);
507 }
dburgessb3a0ca42011-10-12 07:44:40 +0000508}
509
510void Transceiver::reset()
511{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400512 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
513 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000514}
515
516
Thomas Tsou204a9f12013-10-29 18:34:16 -0400517void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000518{
dburgessb3a0ca42011-10-12 07:44:40 +0000519 int MAX_PACKET_LENGTH = 100;
520
521 // check control socket
522 char buffer[MAX_PACKET_LENGTH];
523 int msgLen = -1;
524 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400525
Thomas Tsou204a9f12013-10-29 18:34:16 -0400526 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000527
528 if (msgLen < 1) {
529 return;
530 }
531
532 char cmdcheck[4];
533 char command[MAX_PACKET_LENGTH];
534 char response[MAX_PACKET_LENGTH];
535
536 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400537
538 if (!chan)
539 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000540
541 if (strcmp(cmdcheck,"CMD")!=0) {
542 LOG(WARNING) << "bogus message on control interface";
543 return;
544 }
545 LOG(INFO) << "command is " << buffer;
546
547 if (strcmp(command,"POWEROFF")==0) {
548 // turn off transmitter/demod
549 sprintf(response,"RSP POWEROFF 0");
550 }
551 else if (strcmp(command,"POWERON")==0) {
552 // turn on transmitter/demod
553 if (!mTxFreq || !mRxFreq)
554 sprintf(response,"RSP POWERON 1");
555 else {
556 sprintf(response,"RSP POWERON 0");
Thomas Tsou204a9f12013-10-29 18:34:16 -0400557 if (!chan && !mOn) {
dburgessb3a0ca42011-10-12 07:44:40 +0000558 // Prepare for thread start
559 mPower = -20;
560 mRadioInterface->start();
dburgessb3a0ca42011-10-12 07:44:40 +0000561
562 // Start radio interface threads.
Thomas Tsou204a9f12013-10-29 18:34:16 -0400563 mTxLowerLoopThread->start((void * (*)(void*))
564 TxLowerLoopAdapter,(void*) this);
565 mRxLowerLoopThread->start((void * (*)(void*))
566 RxLowerLoopAdapter,(void*) this);
dburgessb3a0ca42011-10-12 07:44:40 +0000567
Thomas Tsou204a9f12013-10-29 18:34:16 -0400568 for (size_t i = 0; i < mChans; i++) {
569 TransceiverChannel *chan = new TransceiverChannel(this, i);
570 mRxServiceLoopThreads[i]->start((void * (*)(void*))
571 RxUpperLoopAdapter, (void*) chan);
572
573 chan = new TransceiverChannel(this, i);
574 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
575 TxUpperLoopAdapter, (void*) chan);
576 }
577
578 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000579 mOn = true;
580 }
581 }
582 }
583 else if (strcmp(command,"SETMAXDLY")==0) {
584 //set expected maximum time-of-arrival
585 int maxDelay;
586 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
587 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
588 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
589 }
590 else if (strcmp(command,"SETRXGAIN")==0) {
591 //set expected maximum time-of-arrival
592 int newGain;
593 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400594 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000595 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
596 }
597 else if (strcmp(command,"NOISELEV")==0) {
598 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500599 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000600 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500601 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000602 }
603 else {
604 sprintf(response,"RSP NOISELEV 1 0");
605 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500606 }
607 else if (!strcmp(command, "SETPOWER")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000608 // set output power in dB
609 int dbPwr;
Thomas Tsoucb269a32013-11-15 14:15:47 -0500610 sscanf(buffer, "%3s %s %d", cmdcheck, command, &dbPwr);
611 if (!mOn)
612 sprintf(response, "RSP SETPOWER 1 %d", dbPwr);
dburgessb3a0ca42011-10-12 07:44:40 +0000613 else {
614 mPower = dbPwr;
Thomas Tsoucb269a32013-11-15 14:15:47 -0500615 mRadioInterface->setPowerAttenuation(mPower, chan);
616 sprintf(response, "RSP SETPOWER 0 %d", dbPwr);
dburgessb3a0ca42011-10-12 07:44:40 +0000617 }
618 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500619 else if (!strcmp(command,"ADJPOWER")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000620 // adjust power in dB steps
621 int dbStep;
Thomas Tsoucb269a32013-11-15 14:15:47 -0500622 sscanf(buffer, "%3s %s %d", cmdcheck, command, &dbStep);
623 if (!mOn)
624 sprintf(response, "RSP ADJPOWER 1 %d", mPower);
dburgessb3a0ca42011-10-12 07:44:40 +0000625 else {
626 mPower += dbStep;
Thomas Tsoucb269a32013-11-15 14:15:47 -0500627 mRadioInterface->setPowerAttenuation(mPower, chan);
628 sprintf(response, "RSP ADJPOWER 0 %d", mPower);
dburgessb3a0ca42011-10-12 07:44:40 +0000629 }
630 }
dburgessb3a0ca42011-10-12 07:44:40 +0000631 else if (strcmp(command,"RXTUNE")==0) {
632 // tune receiver
633 int freqKhz;
634 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500635 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400636 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000637 LOG(ALERT) << "RX failed to tune";
638 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
639 }
640 else
641 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
642 }
643 else if (strcmp(command,"TXTUNE")==0) {
644 // tune txmtr
645 int freqKhz;
646 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500647 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400648 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000649 LOG(ALERT) << "TX failed to tune";
650 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
651 }
652 else
653 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
654 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500655 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000656 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500657 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500658 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000659 if (mOn)
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500660 sprintf(response, "RSP SETTSC 1 %d", TSC);
661 else if (chan && (TSC != mTSC))
662 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000663 else {
664 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400665 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400666 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000667 }
668 }
669 else if (strcmp(command,"SETSLOT")==0) {
670 // set TSC
671 int corrCode;
672 int timeslot;
673 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
674 if ((timeslot < 0) || (timeslot > 7)) {
675 LOG(WARNING) << "bogus message on control interface";
676 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
677 return;
678 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400679 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
680 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000681 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
682
683 }
684 else {
685 LOG(WARNING) << "bogus command " << command << " on control interface.";
686 }
687
Thomas Tsou204a9f12013-10-29 18:34:16 -0400688 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000689}
690
Thomas Tsou204a9f12013-10-29 18:34:16 -0400691bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000692{
dburgessb3a0ca42011-10-12 07:44:40 +0000693 char buffer[gSlotLen+50];
694
695 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400696 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000697
698 if (msgLen!=gSlotLen+1+4+1) {
699 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
700 return false;
701 }
702
703 int timeSlot = (int) buffer[0];
704 uint64_t frameNum = 0;
705 for (int i = 0; i < 4; i++)
706 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000707
dburgessb3a0ca42011-10-12 07:44:40 +0000708 // periodically update GSM core clock
709 LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
710 << " mLastClockUpdateTime " << mLastClockUpdateTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000711
Thomas Tsou204a9f12013-10-29 18:34:16 -0400712 if (!chan) {
713 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
714 writeClockInterface();
715 }
dburgessb3a0ca42011-10-12 07:44:40 +0000716
717 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
718
719 int RSSI = (int) buffer[5];
720 static BitVector newBurst(gSlotLen);
721 BitVector::iterator itr = newBurst.begin();
722 char *bufferItr = buffer+6;
723 while (itr < newBurst.end())
724 *itr++ = *bufferItr++;
725
726 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400727
728 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000729
730 return true;
731
732
733}
dburgessb3a0ca42011-10-12 07:44:40 +0000734
Thomas Tsou204a9f12013-10-29 18:34:16 -0400735void Transceiver::driveReceiveRadio()
736{
737 if (!mRadioInterface->driveReceiveRadio())
738 usleep(100000);
739}
740
741void Transceiver::driveReceiveFIFO(size_t chan)
742{
dburgessb3a0ca42011-10-12 07:44:40 +0000743 SoftVector *rxBurst = NULL;
744 int RSSI;
745 int TOA; // in 1/256 of a symbol
746 GSM::Time burstTime;
747
Thomas Tsou204a9f12013-10-29 18:34:16 -0400748 rxBurst = pullRadioVector(burstTime, RSSI, TOA, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000749
750 if (rxBurst) {
751
752 LOG(DEBUG) << "burst parameters: "
753 << " time: " << burstTime
754 << " RSSI: " << RSSI
755 << " TOA: " << TOA
756 << " bits: " << *rxBurst;
757
758 char burstString[gSlotLen+10];
759 burstString[0] = burstTime.TN();
760 for (int i = 0; i < 4; i++)
761 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
762 burstString[5] = RSSI;
763 burstString[6] = (TOA >> 8) & 0x0ff;
764 burstString[7] = TOA & 0x0ff;
765 SoftVector::iterator burstItr = rxBurst->begin();
766
767 for (unsigned int i = 0; i < gSlotLen; i++) {
768 burstString[8+i] =(char) round((*burstItr++)*255.0);
769 }
770 burstString[gSlotLen+9] = '\0';
771 delete rxBurst;
772
Thomas Tsou204a9f12013-10-29 18:34:16 -0400773 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +0000774 }
dburgessb3a0ca42011-10-12 07:44:40 +0000775}
776
Thomas Tsou204a9f12013-10-29 18:34:16 -0400777void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000778{
779
780 /**
781 Features a carefully controlled latency mechanism, to
782 assure that transmit packets arrive at the radio/USRP
783 before they need to be transmitted.
784
785 Deadline clock indicates the burst that needs to be
786 pushed into the FIFO right NOW. If transmit queue does
787 not have a burst, stick in filler data.
788 */
789
790
791 RadioClock *radioClock = (mRadioInterface->getClock());
792
793 if (mOn) {
794 //radioClock->wait(); // wait until clock updates
795 LOG(DEBUG) << "radio clock " << radioClock->get();
796 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
797 // if underrun, then we're not providing bursts to radio/USRP fast
798 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400799 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000800 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000801 // only update latency at the defined frame interval
802 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000803 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
804 LOG(INFO) << "new latency: " << mTransmitLatency;
805 mLatencyUpdateTime = radioClock->get();
806 }
807 }
808 else {
809 // if underrun hasn't occurred in the last sec (216 frames) drop
810 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000811 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000812 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
813 mTransmitLatency.decTN();
814 LOG(INFO) << "reduced latency: " << mTransmitLatency;
815 mLatencyUpdateTime = radioClock->get();
816 }
817 }
818 }
dburgessb3a0ca42011-10-12 07:44:40 +0000819 }
dburgessb3a0ca42011-10-12 07:44:40 +0000820 // time to push burst to transmit FIFO
821 pushRadioVector(mTransmitDeadlineClock);
822 mTransmitDeadlineClock.incTN();
823 }
dburgessb3a0ca42011-10-12 07:44:40 +0000824 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400825
826 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000827}
828
829
830
831void Transceiver::writeClockInterface()
832{
833 char command[50];
834 // FIXME -- This should be adaptive.
835 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
836
837 LOG(INFO) << "ClockInterface: sending " << command;
838
Thomas Tsoud647ec52013-10-29 15:17:34 -0400839 mClockSocket->write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000840
841 mLastClockUpdateTime = mTransmitDeadlineClock;
842
Thomas Tsou92c16df2013-09-28 18:04:19 -0400843}
dburgessb3a0ca42011-10-12 07:44:40 +0000844
Thomas Tsou204a9f12013-10-29 18:34:16 -0400845void *RxUpperLoopAdapter(TransceiverChannel *chan)
846{
847 Transceiver *trx = chan->trx;
848 size_t num = chan->num;
849
850 delete chan;
851
Thomas Tsou7553aa92013-11-08 12:50:03 -0500852 trx->setPriority(0.42);
853
Thomas Tsou204a9f12013-10-29 18:34:16 -0400854 while (1) {
855 trx->driveReceiveFIFO(num);
856 pthread_testcancel();
857 }
858 return NULL;
859}
860
861void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +0000862{
Thomas Tsou7553aa92013-11-08 12:50:03 -0500863 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +0000864
dburgessb3a0ca42011-10-12 07:44:40 +0000865 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400866 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -0400867 pthread_testcancel();
868 }
869 return NULL;
870}
871
Thomas Tsou204a9f12013-10-29 18:34:16 -0400872void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -0400873{
Thomas Tsou7553aa92013-11-08 12:50:03 -0500874 transceiver->setPriority(0.44);
875
Thomas Tsou92c16df2013-09-28 18:04:19 -0400876 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400877 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +0000878 pthread_testcancel();
879 }
880 return NULL;
881}
882
Thomas Tsou204a9f12013-10-29 18:34:16 -0400883void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000884{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400885 Transceiver *trx = chan->trx;
886 size_t num = chan->num;
887
888 delete chan;
889
dburgessb3a0ca42011-10-12 07:44:40 +0000890 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400891 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +0000892 pthread_testcancel();
893 }
894 return NULL;
895}
896
Thomas Tsou204a9f12013-10-29 18:34:16 -0400897void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000898{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400899 Transceiver *trx = chan->trx;
900 size_t num = chan->num;
901
902 delete chan;
903
Thomas Tsoua4cf48c2013-11-09 21:44:26 -0500904 trx->setPriority(0.40);
905
dburgessb3a0ca42011-10-12 07:44:40 +0000906 while (1) {
907 bool stale = false;
908 // Flush the UDP packets until a successful transfer.
Thomas Tsou204a9f12013-10-29 18:34:16 -0400909 while (!trx->driveTxPriorityQueue(num)) {
910 stale = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000911 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400912 if (!num && stale) {
dburgessb3a0ca42011-10-12 07:44:40 +0000913 // If a packet was stale, remind the GSM stack of the clock.
Thomas Tsou204a9f12013-10-29 18:34:16 -0400914 trx->writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000915 }
916 pthread_testcancel();
917 }
918 return NULL;
919}