blob: 4078c8f612a30b63c2fb05a31d0fdd4f6ac7b33d [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 }
606 }
607 else if (strcmp(command,"SETPOWER")==0) {
608 // set output power in dB
609 int dbPwr;
610 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr);
611 if (!mOn)
612 sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
613 else {
614 mPower = dbPwr;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400615 mRadioInterface->setPowerAttenuation(dbPwr, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000616 sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
617 }
618 }
619 else if (strcmp(command,"ADJPOWER")==0) {
620 // adjust power in dB steps
621 int dbStep;
622 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep);
623 if (!mOn)
624 sprintf(response,"RSP ADJPOWER 1 %d",mPower);
625 else {
626 mPower += dbStep;
627 sprintf(response,"RSP ADJPOWER 0 %d",mPower);
628 }
629 }
630#define FREQOFFSET 0//11.2e3
631 else if (strcmp(command,"RXTUNE")==0) {
632 // tune receiver
633 int freqKhz;
634 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
635 mRxFreq = freqKhz*1.0e3+FREQOFFSET;
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);
647 //freqKhz = 890e3;
648 mTxFreq = freqKhz*1.0e3+FREQOFFSET;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400649 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000650 LOG(ALERT) << "TX failed to tune";
651 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
652 }
653 else
654 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
655 }
656 else if (strcmp(command,"SETTSC")==0) {
657 // set TSC
658 int TSC;
659 sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC);
660 if (mOn)
661 sprintf(response,"RSP SETTSC 1 %d",TSC);
662 else {
663 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400664 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400665 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000666 }
667 }
668 else if (strcmp(command,"SETSLOT")==0) {
669 // set TSC
670 int corrCode;
671 int timeslot;
672 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
673 if ((timeslot < 0) || (timeslot > 7)) {
674 LOG(WARNING) << "bogus message on control interface";
675 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
676 return;
677 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400678 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
679 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000680 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
681
682 }
683 else {
684 LOG(WARNING) << "bogus command " << command << " on control interface.";
685 }
686
Thomas Tsou204a9f12013-10-29 18:34:16 -0400687 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000688}
689
Thomas Tsou204a9f12013-10-29 18:34:16 -0400690bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000691{
dburgessb3a0ca42011-10-12 07:44:40 +0000692 char buffer[gSlotLen+50];
693
694 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400695 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000696
697 if (msgLen!=gSlotLen+1+4+1) {
698 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
699 return false;
700 }
701
702 int timeSlot = (int) buffer[0];
703 uint64_t frameNum = 0;
704 for (int i = 0; i < 4; i++)
705 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
706
707 /*
708 if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) {
709 // stale burst
710 //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot);
711 //writeClockInterface();
712 }*/
713
714/*
715 DAB -- Just let these go through the demod.
716 if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) {
717 // stale burst from GSM core
718 LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot);
719 return false;
720 }
721*/
722
723 // periodically update GSM core clock
724 LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
725 << " mLastClockUpdateTime " << mLastClockUpdateTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000726
Thomas Tsou204a9f12013-10-29 18:34:16 -0400727 if (!chan) {
728 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
729 writeClockInterface();
730 }
dburgessb3a0ca42011-10-12 07:44:40 +0000731
732 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
733
734 int RSSI = (int) buffer[5];
735 static BitVector newBurst(gSlotLen);
736 BitVector::iterator itr = newBurst.begin();
737 char *bufferItr = buffer+6;
738 while (itr < newBurst.end())
739 *itr++ = *bufferItr++;
740
741 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400742
743 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000744
745 return true;
746
747
748}
dburgessb3a0ca42011-10-12 07:44:40 +0000749
Thomas Tsou204a9f12013-10-29 18:34:16 -0400750void Transceiver::driveReceiveRadio()
751{
752 if (!mRadioInterface->driveReceiveRadio())
753 usleep(100000);
754}
755
756void Transceiver::driveReceiveFIFO(size_t chan)
757{
dburgessb3a0ca42011-10-12 07:44:40 +0000758 SoftVector *rxBurst = NULL;
759 int RSSI;
760 int TOA; // in 1/256 of a symbol
761 GSM::Time burstTime;
762
Thomas Tsou204a9f12013-10-29 18:34:16 -0400763 rxBurst = pullRadioVector(burstTime, RSSI, TOA, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000764
765 if (rxBurst) {
766
767 LOG(DEBUG) << "burst parameters: "
768 << " time: " << burstTime
769 << " RSSI: " << RSSI
770 << " TOA: " << TOA
771 << " bits: " << *rxBurst;
772
773 char burstString[gSlotLen+10];
774 burstString[0] = burstTime.TN();
775 for (int i = 0; i < 4; i++)
776 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
777 burstString[5] = RSSI;
778 burstString[6] = (TOA >> 8) & 0x0ff;
779 burstString[7] = TOA & 0x0ff;
780 SoftVector::iterator burstItr = rxBurst->begin();
781
782 for (unsigned int i = 0; i < gSlotLen; i++) {
783 burstString[8+i] =(char) round((*burstItr++)*255.0);
784 }
785 burstString[gSlotLen+9] = '\0';
786 delete rxBurst;
787
Thomas Tsou204a9f12013-10-29 18:34:16 -0400788 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +0000789 }
dburgessb3a0ca42011-10-12 07:44:40 +0000790}
791
Thomas Tsou204a9f12013-10-29 18:34:16 -0400792void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000793{
794
795 /**
796 Features a carefully controlled latency mechanism, to
797 assure that transmit packets arrive at the radio/USRP
798 before they need to be transmitted.
799
800 Deadline clock indicates the burst that needs to be
801 pushed into the FIFO right NOW. If transmit queue does
802 not have a burst, stick in filler data.
803 */
804
805
806 RadioClock *radioClock = (mRadioInterface->getClock());
807
808 if (mOn) {
809 //radioClock->wait(); // wait until clock updates
810 LOG(DEBUG) << "radio clock " << radioClock->get();
811 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
812 // if underrun, then we're not providing bursts to radio/USRP fast
813 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400814 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000815 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000816 // only update latency at the defined frame interval
817 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000818 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
819 LOG(INFO) << "new latency: " << mTransmitLatency;
820 mLatencyUpdateTime = radioClock->get();
821 }
822 }
823 else {
824 // if underrun hasn't occurred in the last sec (216 frames) drop
825 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000826 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000827 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
828 mTransmitLatency.decTN();
829 LOG(INFO) << "reduced latency: " << mTransmitLatency;
830 mLatencyUpdateTime = radioClock->get();
831 }
832 }
833 }
dburgessb3a0ca42011-10-12 07:44:40 +0000834 }
dburgessb3a0ca42011-10-12 07:44:40 +0000835 // time to push burst to transmit FIFO
836 pushRadioVector(mTransmitDeadlineClock);
837 mTransmitDeadlineClock.incTN();
838 }
dburgessb3a0ca42011-10-12 07:44:40 +0000839 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400840
841 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000842}
843
844
845
846void Transceiver::writeClockInterface()
847{
848 char command[50];
849 // FIXME -- This should be adaptive.
850 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
851
852 LOG(INFO) << "ClockInterface: sending " << command;
853
Thomas Tsoud647ec52013-10-29 15:17:34 -0400854 mClockSocket->write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000855
856 mLastClockUpdateTime = mTransmitDeadlineClock;
857
Thomas Tsou92c16df2013-09-28 18:04:19 -0400858}
dburgessb3a0ca42011-10-12 07:44:40 +0000859
Thomas Tsou204a9f12013-10-29 18:34:16 -0400860void *RxUpperLoopAdapter(TransceiverChannel *chan)
861{
862 Transceiver *trx = chan->trx;
863 size_t num = chan->num;
864
865 delete chan;
866
Thomas Tsou7553aa92013-11-08 12:50:03 -0500867 trx->setPriority(0.42);
868
Thomas Tsou204a9f12013-10-29 18:34:16 -0400869 while (1) {
870 trx->driveReceiveFIFO(num);
871 pthread_testcancel();
872 }
873 return NULL;
874}
875
876void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +0000877{
Thomas Tsou7553aa92013-11-08 12:50:03 -0500878 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +0000879
dburgessb3a0ca42011-10-12 07:44:40 +0000880 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400881 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -0400882 pthread_testcancel();
883 }
884 return NULL;
885}
886
Thomas Tsou204a9f12013-10-29 18:34:16 -0400887void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -0400888{
Thomas Tsou7553aa92013-11-08 12:50:03 -0500889 transceiver->setPriority(0.44);
890
Thomas Tsou92c16df2013-09-28 18:04:19 -0400891 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400892 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +0000893 pthread_testcancel();
894 }
895 return NULL;
896}
897
Thomas Tsou204a9f12013-10-29 18:34:16 -0400898void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000899{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400900 Transceiver *trx = chan->trx;
901 size_t num = chan->num;
902
903 delete chan;
904
dburgessb3a0ca42011-10-12 07:44:40 +0000905 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400906 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +0000907 pthread_testcancel();
908 }
909 return NULL;
910}
911
Thomas Tsou204a9f12013-10-29 18:34:16 -0400912void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000913{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400914 Transceiver *trx = chan->trx;
915 size_t num = chan->num;
916
917 delete chan;
918
Thomas Tsoua4cf48c2013-11-09 21:44:26 -0500919 trx->setPriority(0.40);
920
dburgessb3a0ca42011-10-12 07:44:40 +0000921 while (1) {
922 bool stale = false;
923 // Flush the UDP packets until a successful transfer.
Thomas Tsou204a9f12013-10-29 18:34:16 -0400924 while (!trx->driveTxPriorityQueue(num)) {
925 stale = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000926 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400927 if (!num && stale) {
dburgessb3a0ca42011-10-12 07:44:40 +0000928 // If a packet was stale, remind the GSM stack of the clock.
Thomas Tsou204a9f12013-10-29 18:34:16 -0400929 trx->writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000930 }
931 pthread_testcancel();
932 }
933 return NULL;
934}