blob: bdc8affee8a8bae638fd3e2070f99497af43e711 [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
24
25/*
26 Compilation switches
27 TRANSMIT_LOGGING write every burst on the given slot to a log
28*/
29
30
31#include <stdio.h>
32#include "Transceiver.h"
33#include <Logger.h>
34
ttsou2173abf2012-08-08 00:51:31 +000035#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
dburgessb3a0ca42011-10-12 07:44:40 +000038
kurtis.heimerlec842de2012-11-23 08:37:32 +000039#define USB_LATENCY_INTRVL 10,0
ttsou2173abf2012-08-08 00:51:31 +000040
41#if USE_UHD
kurtis.heimerlec842de2012-11-23 08:37:32 +000042# define USB_LATENCY_MIN 6,7
ttsou2173abf2012-08-08 00:51:31 +000043#else
kurtis.heimerlec842de2012-11-23 08:37:32 +000044# define USB_LATENCY_MIN 1,1
ttsou2173abf2012-08-08 00:51:31 +000045#endif
dburgessb3a0ca42011-10-12 07:44:40 +000046
ttsoue8dde022012-12-06 15:43:55 +000047#define INIT_ENERGY_THRSHD 5.0f
48
dburgessb3a0ca42011-10-12 07:44:40 +000049Transceiver::Transceiver(int wBasePort,
50 const char *TRXAddress,
51 int wSamplesPerSymbol,
52 GSM::Time wTransmitLatency,
53 RadioInterface *wRadioInterface)
54 :mDataSocket(wBasePort+2,TRXAddress,wBasePort+102),
55 mControlSocket(wBasePort+1,TRXAddress,wBasePort+101),
56 mClockSocket(wBasePort,TRXAddress,wBasePort+100)
57{
58 //GSM::Time startTime(0,0);
59 //GSM::Time startTime(gHyperframe/2 - 4*216*60,0);
60 GSM::Time startTime(random() % gHyperframe,0);
61
62 mFIFOServiceLoopThread = new Thread(32768); ///< thread to push bursts into transmit FIFO
63 mControlServiceLoopThread = new Thread(32768); ///< thread to process control messages from GSM core
64 mTransmitPriorityQueueServiceLoopThread = new Thread(32768);///< thread to process transmit bursts from GSM core
65
66
67 mSamplesPerSymbol = wSamplesPerSymbol;
68 mRadioInterface = wRadioInterface;
69 mTransmitLatency = wTransmitLatency;
70 mTransmitDeadlineClock = startTime;
71 mLastClockUpdateTime = startTime;
72 mLatencyUpdateTime = startTime;
73 mRadioInterface->getClock()->set(startTime);
74 mMaxExpectedDelay = 0;
75
76 // generate pulse and setup up signal processing library
77 gsmPulse = generateGSMPulse(2,mSamplesPerSymbol);
78 LOG(DEBUG) << "gsmPulse: " << *gsmPulse;
79 sigProcLibSetup(mSamplesPerSymbol);
80
81 txFullScale = mRadioInterface->fullScaleInputValue();
82 rxFullScale = mRadioInterface->fullScaleOutputValue();
83
84 // initialize filler tables with dummy bursts, initialize other per-timeslot variables
85 for (int i = 0; i < 8; i++) {
86 signalVector* modBurst = modulateBurst(gDummyBurst,*gsmPulse,
87 8 + (i % 4 == 0),
88 mSamplesPerSymbol);
89 scaleVector(*modBurst,txFullScale);
90 fillerModulus[i]=26;
91 for (int j = 0; j < 102; j++) {
92 fillerTable[j][i] = new signalVector(*modBurst);
93 }
94 delete modBurst;
95 mChanType[i] = NONE;
96 channelResponse[i] = NULL;
97 DFEForward[i] = NULL;
98 DFEFeedback[i] = NULL;
99 channelEstimateTime[i] = startTime;
100 }
101
102 mOn = false;
103 mTxFreq = 0.0;
104 mRxFreq = 0.0;
105 mPower = -10;
ttsoue8dde022012-12-06 15:43:55 +0000106 mEnergyThreshold = INIT_ENERGY_THRSHD;
dburgessb3a0ca42011-10-12 07:44:40 +0000107 prevFalseDetectionTime = startTime;
108}
109
110Transceiver::~Transceiver()
111{
112 delete gsmPulse;
113 sigProcLibDestroy();
114 mTransmitPriorityQueue.clear();
115}
116
117
118void Transceiver::addRadioVector(BitVector &burst,
119 int RSSI,
120 GSM::Time &wTime)
121{
122 // modulate and stick into queue
123 signalVector* modBurst = modulateBurst(burst,*gsmPulse,
124 8 + (wTime.TN() % 4 == 0),
125 mSamplesPerSymbol);
126 scaleVector(*modBurst,txFullScale * pow(10,-RSSI/10));
127 radioVector *newVec = new radioVector(*modBurst,wTime);
128 mTransmitPriorityQueue.write(newVec);
129
130 delete modBurst;
131}
132
133#ifdef TRANSMIT_LOGGING
134void Transceiver::unModulateVector(signalVector wVector)
135{
136 SoftVector *burst = demodulateBurst(wVector,
137 *gsmPulse,
138 mSamplesPerSymbol,
139 1.0,0.0);
140 LOG(DEBUG) << "LOGGED BURST: " << *burst;
141
142/*
143 unsigned char burstStr[gSlotLen+1];
144 SoftVector::iterator burstItr = burst->begin();
145 for (int i = 0; i < gSlotLen; i++) {
146 // FIXME: Demod bits are inverted!
147 burstStr[i] = (unsigned char) ((*burstItr++)*255.0);
148 }
149 burstStr[gSlotLen]='\0';
150 LOG(DEBUG) << "LOGGED BURST: " << burstStr;
151*/
152 delete burst;
153}
154#endif
155
156void Transceiver::pushRadioVector(GSM::Time &nowTime)
157{
158
159 // dump stale bursts, if any
160 while (radioVector* staleBurst = mTransmitPriorityQueue.getStaleBurst(nowTime)) {
161 // Even if the burst is stale, put it in the fillter table.
162 // (It might be an idle pattern.)
163 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
kurtis.heimerl06286132011-11-26 03:18:43 +0000164 const GSM::Time& nextTime = staleBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000165 int TN = nextTime.TN();
166 int modFN = nextTime.FN() % fillerModulus[TN];
167 delete fillerTable[modFN][TN];
168 fillerTable[modFN][TN] = staleBurst;
169 }
170
171 int TN = nowTime.TN();
172 int modFN = nowTime.FN() % fillerModulus[nowTime.TN()];
173
174 // if queue contains data at the desired timestamp, stick it into FIFO
175 if (radioVector *next = (radioVector*) mTransmitPriorityQueue.getCurrentBurst(nowTime)) {
176 LOG(DEBUG) << "transmitFIFO: wrote burst " << next << " at time: " << nowTime;
177 delete fillerTable[modFN][TN];
178 fillerTable[modFN][TN] = new signalVector(*(next));
179 mRadioInterface->driveTransmitRadio(*(next),(mChanType[TN]==NONE)); //fillerTable[modFN][TN]));
180 delete next;
181#ifdef TRANSMIT_LOGGING
182 if (nowTime.TN()==TRANSMIT_LOGGING) {
183 unModulateVector(*(fillerTable[modFN][TN]));
184 }
185#endif
186 return;
187 }
188
189 // otherwise, pull filler data, and push to radio FIFO
190 mRadioInterface->driveTransmitRadio(*(fillerTable[modFN][TN]),(mChanType[TN]==NONE));
191#ifdef TRANSMIT_LOGGING
192 if (nowTime.TN()==TRANSMIT_LOGGING)
193 unModulateVector(*fillerTable[modFN][TN]);
194#endif
195
196}
197
198void Transceiver::setModulus(int timeslot)
199{
200 switch (mChanType[timeslot]) {
201 case NONE:
202 case I:
203 case II:
204 case III:
205 case FILL:
206 fillerModulus[timeslot] = 26;
207 break;
208 case IV:
209 case VI:
210 case V:
211 fillerModulus[timeslot] = 51;
212 break;
213 //case V:
214 case VII:
215 fillerModulus[timeslot] = 102;
216 break;
ttsoufc40a842013-06-09 22:38:18 +0000217 case XIII:
218 fillerModulus[timeslot] = 52;
219 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000220 default:
221 break;
222 }
223}
224
225
226Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime)
227{
228
229 unsigned burstTN = currTime.TN();
230 unsigned burstFN = currTime.FN();
231
232 switch (mChanType[burstTN]) {
233 case NONE:
234 return OFF;
235 break;
236 case FILL:
237 return IDLE;
238 break;
239 case I:
240 return TSC;
241 /*if (burstFN % 26 == 25)
242 return IDLE;
243 else
244 return TSC;*/
245 break;
246 case II:
ttsou20642972013-03-27 22:00:25 +0000247 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000248 break;
249 case III:
250 return TSC;
251 break;
252 case IV:
253 case VI:
254 return RACH;
255 break;
256 case V: {
257 int mod51 = burstFN % 51;
258 if ((mod51 <= 36) && (mod51 >= 14))
259 return RACH;
260 else if ((mod51 == 4) || (mod51 == 5))
261 return RACH;
262 else if ((mod51 == 45) || (mod51 == 46))
263 return RACH;
264 else
265 return TSC;
266 break;
267 }
268 case VII:
269 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
270 return IDLE;
271 else
272 return TSC;
273 break;
ttsoufc40a842013-06-09 22:38:18 +0000274 case XIII: {
275 int mod52 = burstFN % 52;
276 if ((mod52 == 12) || (mod52 == 38))
277 return RACH;
278 else if ((mod52 == 25) || (mod52 == 51))
279 return IDLE;
280 else
281 return TSC;
282 break;
283 }
dburgessb3a0ca42011-10-12 07:44:40 +0000284 case LOOPBACK:
285 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
286 return IDLE;
287 else
288 return TSC;
289 break;
290 default:
291 return OFF;
292 break;
293 }
294
295}
296
297SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
298 int &RSSI,
299 int &timingOffset)
300{
301 bool needDFE = (mMaxExpectedDelay > 1);
302
303 radioVector *rxBurst = (radioVector *) mReceiveFIFO->get();
304
305 if (!rxBurst) return NULL;
306
kurtis.heimerl06286132011-11-26 03:18:43 +0000307 LOG(DEBUG) << "receiveFIFO: read radio vector at time: " << rxBurst->getTime() << ", new size: " << mReceiveFIFO->size();
dburgessb3a0ca42011-10-12 07:44:40 +0000308
kurtis.heimerl06286132011-11-26 03:18:43 +0000309 int timeslot = rxBurst->getTime().TN();
dburgessb3a0ca42011-10-12 07:44:40 +0000310
kurtis.heimerl06286132011-11-26 03:18:43 +0000311 CorrType corrType = expectedCorrType(rxBurst->getTime());
dburgessb3a0ca42011-10-12 07:44:40 +0000312
313 if ((corrType==OFF) || (corrType==IDLE)) {
314 delete rxBurst;
315 return NULL;
316 }
317
318 // check to see if received burst has sufficient
319 signalVector *vectorBurst = rxBurst;
320 complex amplitude = 0.0;
321 float TOA = 0.0;
322 float avgPwr = 0.0;
323 if (!energyDetect(*vectorBurst,20*mSamplesPerSymbol,mEnergyThreshold,&avgPwr)) {
kurtis.heimerl06286132011-11-26 03:18:43 +0000324 LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->getTime();
325 double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000326 if (framesElapsed > 50) { // if we haven't had any false detections for a while, lower threshold
327 mEnergyThreshold -= 10.0/10.0;
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000328 if (mEnergyThreshold < 0.0)
329 mEnergyThreshold = 0.0;
330
kurtis.heimerl06286132011-11-26 03:18:43 +0000331 prevFalseDetectionTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000332 }
333 delete rxBurst;
334 return NULL;
335 }
kurtis.heimerl06286132011-11-26 03:18:43 +0000336 LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000337
338 // run the proper correlator
339 bool success = false;
340 if (corrType==TSC) {
kurtis.heimerl06286132011-11-26 03:18:43 +0000341 LOG(DEBUG) << "looking for TSC at time: " << rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000342 signalVector *channelResp;
kurtis.heimerl06286132011-11-26 03:18:43 +0000343 double framesElapsed = rxBurst->getTime()-channelEstimateTime[timeslot];
dburgessb3a0ca42011-10-12 07:44:40 +0000344 bool estimateChannel = false;
345 if ((framesElapsed > 50) || (channelResponse[timeslot]==NULL)) {
346 if (channelResponse[timeslot]) delete channelResponse[timeslot];
347 if (DFEForward[timeslot]) delete DFEForward[timeslot];
348 if (DFEFeedback[timeslot]) delete DFEFeedback[timeslot];
349 channelResponse[timeslot] = NULL;
350 DFEForward[timeslot] = NULL;
351 DFEFeedback[timeslot] = NULL;
352 estimateChannel = true;
353 }
354 if (!needDFE) estimateChannel = false;
355 float chanOffset;
356 success = analyzeTrafficBurst(*vectorBurst,
357 mTSC,
358 3.0,
359 mSamplesPerSymbol,
360 &amplitude,
361 &TOA,
362 mMaxExpectedDelay,
363 estimateChannel,
364 &channelResp,
365 &chanOffset);
366 if (success) {
367 LOG(DEBUG) << "FOUND TSC!!!!!! " << amplitude << " " << TOA;
368 mEnergyThreshold -= 1.0F/10.0F;
369 if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
370 SNRestimate[timeslot] = amplitude.norm2()/(mEnergyThreshold*mEnergyThreshold+1.0); // this is not highly accurate
371 if (estimateChannel) {
372 LOG(DEBUG) << "estimating channel...";
373 channelResponse[timeslot] = channelResp;
374 chanRespOffset[timeslot] = chanOffset;
375 chanRespAmplitude[timeslot] = amplitude;
376 scaleVector(*channelResp, complex(1.0,0.0)/amplitude);
377 designDFE(*channelResp, SNRestimate[timeslot], 7, &DFEForward[timeslot], &DFEFeedback[timeslot]);
kurtis.heimerl06286132011-11-26 03:18:43 +0000378 channelEstimateTime[timeslot] = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000379 LOG(DEBUG) << "SNR: " << SNRestimate[timeslot] << ", DFE forward: " << *DFEForward[timeslot] << ", DFE backward: " << *DFEFeedback[timeslot];
380 }
381 }
382 else {
kurtis.heimerl06286132011-11-26 03:18:43 +0000383 double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
384 LOG(DEBUG) << "wTime: " << rxBurst->getTime() << ", pTime: " << prevFalseDetectionTime << ", fElapsed: " << framesElapsed;
dburgessb3a0ca42011-10-12 07:44:40 +0000385 mEnergyThreshold += 10.0F/10.0F*exp(-framesElapsed);
kurtis.heimerl06286132011-11-26 03:18:43 +0000386 prevFalseDetectionTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000387 channelResponse[timeslot] = NULL;
388 }
389 }
390 else {
391 // RACH burst
392 success = detectRACHBurst(*vectorBurst,
393 5.0, // detection threshold
394 mSamplesPerSymbol,
395 &amplitude,
396 &TOA);
397 if (success) {
398 LOG(DEBUG) << "FOUND RACH!!!!!! " << amplitude << " " << TOA;
399 mEnergyThreshold -= (1.0F/10.0F);
400 if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
401 channelResponse[timeslot] = NULL;
402 }
403 else {
kurtis.heimerl06286132011-11-26 03:18:43 +0000404 double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000405 mEnergyThreshold += (1.0F/10.0F)*exp(-framesElapsed);
kurtis.heimerl06286132011-11-26 03:18:43 +0000406 prevFalseDetectionTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000407 }
408 }
409 LOG(DEBUG) << "energy Threshold = " << mEnergyThreshold;
410
411 // demodulate burst
412 SoftVector *burst = NULL;
413 if ((rxBurst) && (success)) {
414 if ((corrType==RACH) || (!needDFE)) {
415 burst = demodulateBurst(*vectorBurst,
416 *gsmPulse,
417 mSamplesPerSymbol,
418 amplitude,TOA);
419 }
420 else { // TSC
421 scaleVector(*vectorBurst,complex(1.0,0.0)/amplitude);
422 burst = equalizeBurst(*vectorBurst,
423 TOA-chanRespOffset[timeslot],
424 mSamplesPerSymbol,
425 *DFEForward[timeslot],
426 *DFEFeedback[timeslot]);
427 }
kurtis.heimerl06286132011-11-26 03:18:43 +0000428 wTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000429 RSSI = (int) floor(20.0*log10(rxFullScale/amplitude.abs()));
430 LOG(DEBUG) << "RSSI: " << RSSI;
431 timingOffset = (int) round(TOA*256.0/mSamplesPerSymbol);
432 }
433
434 //if (burst) LOG(DEBUG) << "burst: " << *burst << '\n';
435
436 delete rxBurst;
437
438 return burst;
439}
440
441void Transceiver::start()
442{
443 mControlServiceLoopThread->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) this);
444}
445
446void Transceiver::reset()
447{
448 mTransmitPriorityQueue.clear();
449 //mTransmitFIFO->clear();
450 //mReceiveFIFO->clear();
451}
452
453
454void Transceiver::driveControl()
455{
456
457 int MAX_PACKET_LENGTH = 100;
458
459 // check control socket
460 char buffer[MAX_PACKET_LENGTH];
461 int msgLen = -1;
462 buffer[0] = '\0';
463
464 msgLen = mControlSocket.read(buffer);
465
466 if (msgLen < 1) {
467 return;
468 }
469
470 char cmdcheck[4];
471 char command[MAX_PACKET_LENGTH];
472 char response[MAX_PACKET_LENGTH];
473
474 sscanf(buffer,"%3s %s",cmdcheck,command);
475
476 writeClockInterface();
477
478 if (strcmp(cmdcheck,"CMD")!=0) {
479 LOG(WARNING) << "bogus message on control interface";
480 return;
481 }
482 LOG(INFO) << "command is " << buffer;
483
484 if (strcmp(command,"POWEROFF")==0) {
485 // turn off transmitter/demod
486 sprintf(response,"RSP POWEROFF 0");
487 }
488 else if (strcmp(command,"POWERON")==0) {
489 // turn on transmitter/demod
490 if (!mTxFreq || !mRxFreq)
491 sprintf(response,"RSP POWERON 1");
492 else {
493 sprintf(response,"RSP POWERON 0");
494 if (!mOn) {
495 // Prepare for thread start
496 mPower = -20;
497 mRadioInterface->start();
498 generateRACHSequence(*gsmPulse,mSamplesPerSymbol);
499
500 // Start radio interface threads.
501 mFIFOServiceLoopThread->start((void * (*)(void*))FIFOServiceLoopAdapter,(void*) this);
502 mTransmitPriorityQueueServiceLoopThread->start((void * (*)(void*))TransmitPriorityQueueServiceLoopAdapter,(void*) this);
503 writeClockInterface();
504
505 mOn = true;
506 }
507 }
508 }
509 else if (strcmp(command,"SETMAXDLY")==0) {
510 //set expected maximum time-of-arrival
511 int maxDelay;
512 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
513 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
514 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
515 }
516 else if (strcmp(command,"SETRXGAIN")==0) {
517 //set expected maximum time-of-arrival
518 int newGain;
519 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
520 newGain = mRadioInterface->setRxGain(newGain);
ttsoue8dde022012-12-06 15:43:55 +0000521 mEnergyThreshold = INIT_ENERGY_THRSHD;
dburgessb3a0ca42011-10-12 07:44:40 +0000522 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
523 }
524 else if (strcmp(command,"NOISELEV")==0) {
525 if (mOn) {
526 sprintf(response,"RSP NOISELEV 0 %d",
527 (int) round(20.0*log10(rxFullScale/mEnergyThreshold)));
528 }
529 else {
530 sprintf(response,"RSP NOISELEV 1 0");
531 }
532 }
533 else if (strcmp(command,"SETPOWER")==0) {
534 // set output power in dB
535 int dbPwr;
536 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr);
537 if (!mOn)
538 sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
539 else {
540 mPower = dbPwr;
kurtis.heimerl58d6a012011-11-26 03:17:38 +0000541 mRadioInterface->setPowerAttenuation(dbPwr);
dburgessb3a0ca42011-10-12 07:44:40 +0000542 sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
543 }
544 }
545 else if (strcmp(command,"ADJPOWER")==0) {
546 // adjust power in dB steps
547 int dbStep;
548 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep);
549 if (!mOn)
550 sprintf(response,"RSP ADJPOWER 1 %d",mPower);
551 else {
552 mPower += dbStep;
553 sprintf(response,"RSP ADJPOWER 0 %d",mPower);
554 }
555 }
556#define FREQOFFSET 0//11.2e3
557 else if (strcmp(command,"RXTUNE")==0) {
558 // tune receiver
559 int freqKhz;
560 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
561 mRxFreq = freqKhz*1.0e3+FREQOFFSET;
562 if (!mRadioInterface->tuneRx(mRxFreq)) {
563 LOG(ALERT) << "RX failed to tune";
564 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
565 }
566 else
567 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
568 }
569 else if (strcmp(command,"TXTUNE")==0) {
570 // tune txmtr
571 int freqKhz;
572 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
573 //freqKhz = 890e3;
574 mTxFreq = freqKhz*1.0e3+FREQOFFSET;
575 if (!mRadioInterface->tuneTx(mTxFreq)) {
576 LOG(ALERT) << "TX failed to tune";
577 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
578 }
579 else
580 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
581 }
582 else if (strcmp(command,"SETTSC")==0) {
583 // set TSC
584 int TSC;
585 sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC);
586 if (mOn)
587 sprintf(response,"RSP SETTSC 1 %d",TSC);
588 else {
589 mTSC = TSC;
590 generateMidamble(*gsmPulse,mSamplesPerSymbol,TSC);
591 sprintf(response,"RSP SETTSC 0 %d",TSC);
592 }
593 }
594 else if (strcmp(command,"SETSLOT")==0) {
595 // set TSC
596 int corrCode;
597 int timeslot;
598 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
599 if ((timeslot < 0) || (timeslot > 7)) {
600 LOG(WARNING) << "bogus message on control interface";
601 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
602 return;
603 }
604 mChanType[timeslot] = (ChannelCombination) corrCode;
605 setModulus(timeslot);
606 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
607
608 }
609 else {
610 LOG(WARNING) << "bogus command " << command << " on control interface.";
611 }
612
613 mControlSocket.write(response,strlen(response)+1);
614
615}
616
617bool Transceiver::driveTransmitPriorityQueue()
618{
619
620 char buffer[gSlotLen+50];
621
622 // check data socket
623 size_t msgLen = mDataSocket.read(buffer);
624
625 if (msgLen!=gSlotLen+1+4+1) {
626 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
627 return false;
628 }
629
630 int timeSlot = (int) buffer[0];
631 uint64_t frameNum = 0;
632 for (int i = 0; i < 4; i++)
633 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
634
635 /*
636 if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) {
637 // stale burst
638 //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot);
639 //writeClockInterface();
640 }*/
641
642/*
643 DAB -- Just let these go through the demod.
644 if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) {
645 // stale burst from GSM core
646 LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot);
647 return false;
648 }
649*/
650
651 // periodically update GSM core clock
652 LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
653 << " mLastClockUpdateTime " << mLastClockUpdateTime;
654 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
655 writeClockInterface();
656
657
658 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
659
660 int RSSI = (int) buffer[5];
661 static BitVector newBurst(gSlotLen);
662 BitVector::iterator itr = newBurst.begin();
663 char *bufferItr = buffer+6;
664 while (itr < newBurst.end())
665 *itr++ = *bufferItr++;
666
667 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
668
669 addRadioVector(newBurst,RSSI,currTime);
670
671 LOG(DEBUG) "added burst - time: " << currTime << ", RSSI: " << RSSI; // << ", data: " << newBurst;
672
673 return true;
674
675
676}
677
678void Transceiver::driveReceiveFIFO()
679{
680
681 SoftVector *rxBurst = NULL;
682 int RSSI;
683 int TOA; // in 1/256 of a symbol
684 GSM::Time burstTime;
685
686 mRadioInterface->driveReceiveRadio();
687
688 rxBurst = pullRadioVector(burstTime,RSSI,TOA);
689
690 if (rxBurst) {
691
692 LOG(DEBUG) << "burst parameters: "
693 << " time: " << burstTime
694 << " RSSI: " << RSSI
695 << " TOA: " << TOA
696 << " bits: " << *rxBurst;
697
698 char burstString[gSlotLen+10];
699 burstString[0] = burstTime.TN();
700 for (int i = 0; i < 4; i++)
701 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
702 burstString[5] = RSSI;
703 burstString[6] = (TOA >> 8) & 0x0ff;
704 burstString[7] = TOA & 0x0ff;
705 SoftVector::iterator burstItr = rxBurst->begin();
706
707 for (unsigned int i = 0; i < gSlotLen; i++) {
708 burstString[8+i] =(char) round((*burstItr++)*255.0);
709 }
710 burstString[gSlotLen+9] = '\0';
711 delete rxBurst;
712
713 mDataSocket.write(burstString,gSlotLen+10);
714 }
715
716}
717
718void Transceiver::driveTransmitFIFO()
719{
720
721 /**
722 Features a carefully controlled latency mechanism, to
723 assure that transmit packets arrive at the radio/USRP
724 before they need to be transmitted.
725
726 Deadline clock indicates the burst that needs to be
727 pushed into the FIFO right NOW. If transmit queue does
728 not have a burst, stick in filler data.
729 */
730
731
732 RadioClock *radioClock = (mRadioInterface->getClock());
733
734 if (mOn) {
735 //radioClock->wait(); // wait until clock updates
736 LOG(DEBUG) << "radio clock " << radioClock->get();
737 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
738 // if underrun, then we're not providing bursts to radio/USRP fast
739 // enough. Need to increase latency by one GSM frame.
kurtis.heimerle380af32011-11-26 03:18:55 +0000740 if (mRadioInterface->getBus() == RadioDevice::USB) {
741 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000742 // only update latency at the defined frame interval
743 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000744 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
745 LOG(INFO) << "new latency: " << mTransmitLatency;
746 mLatencyUpdateTime = radioClock->get();
747 }
748 }
749 else {
750 // if underrun hasn't occurred in the last sec (216 frames) drop
751 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000752 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000753 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
754 mTransmitLatency.decTN();
755 LOG(INFO) << "reduced latency: " << mTransmitLatency;
756 mLatencyUpdateTime = radioClock->get();
757 }
758 }
759 }
dburgessb3a0ca42011-10-12 07:44:40 +0000760 }
dburgessb3a0ca42011-10-12 07:44:40 +0000761 // time to push burst to transmit FIFO
762 pushRadioVector(mTransmitDeadlineClock);
763 mTransmitDeadlineClock.incTN();
764 }
765
766 }
767 // FIXME -- This should not be a hard spin.
768 // But any delay here causes us to throw omni_thread_fatal.
769 //else radioClock->wait();
770}
771
772
773
774void Transceiver::writeClockInterface()
775{
776 char command[50];
777 // FIXME -- This should be adaptive.
778 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
779
780 LOG(INFO) << "ClockInterface: sending " << command;
781
782 mClockSocket.write(command,strlen(command)+1);
783
784 mLastClockUpdateTime = mTransmitDeadlineClock;
785
786}
787
788
789
790
791void *FIFOServiceLoopAdapter(Transceiver *transceiver)
792{
kurtis.heimerl6b495a52011-11-26 03:17:21 +0000793 transceiver->setPriority();
794
dburgessb3a0ca42011-10-12 07:44:40 +0000795 while (1) {
796 transceiver->driveReceiveFIFO();
797 transceiver->driveTransmitFIFO();
798 pthread_testcancel();
799 }
800 return NULL;
801}
802
803void *ControlServiceLoopAdapter(Transceiver *transceiver)
804{
805 while (1) {
806 transceiver->driveControl();
807 pthread_testcancel();
808 }
809 return NULL;
810}
811
812void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *transceiver)
813{
814 while (1) {
815 bool stale = false;
816 // Flush the UDP packets until a successful transfer.
817 while (!transceiver->driveTransmitPriorityQueue()) {
818 stale = true;
819 }
820 if (stale) {
821 // If a packet was stale, remind the GSM stack of the clock.
822 transceiver->writeClockInterface();
823 }
824 pthread_testcancel();
825 }
826 return NULL;
827}