blob: ff5de49899382f7e2f46fc30fd0ae2ede741ce83 [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;
217 default:
218 break;
219 }
220}
221
222
223Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime)
224{
225
226 unsigned burstTN = currTime.TN();
227 unsigned burstFN = currTime.FN();
228
229 switch (mChanType[burstTN]) {
230 case NONE:
231 return OFF;
232 break;
233 case FILL:
234 return IDLE;
235 break;
236 case I:
237 return TSC;
238 /*if (burstFN % 26 == 25)
239 return IDLE;
240 else
241 return TSC;*/
242 break;
243 case II:
244 if (burstFN % 2 == 1)
245 return IDLE;
246 else
247 return TSC;
248 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;
274 case LOOPBACK:
275 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
276 return IDLE;
277 else
278 return TSC;
279 break;
280 default:
281 return OFF;
282 break;
283 }
284
285}
286
287SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
288 int &RSSI,
289 int &timingOffset)
290{
291 bool needDFE = (mMaxExpectedDelay > 1);
292
293 radioVector *rxBurst = (radioVector *) mReceiveFIFO->get();
294
295 if (!rxBurst) return NULL;
296
kurtis.heimerl06286132011-11-26 03:18:43 +0000297 LOG(DEBUG) << "receiveFIFO: read radio vector at time: " << rxBurst->getTime() << ", new size: " << mReceiveFIFO->size();
dburgessb3a0ca42011-10-12 07:44:40 +0000298
kurtis.heimerl06286132011-11-26 03:18:43 +0000299 int timeslot = rxBurst->getTime().TN();
dburgessb3a0ca42011-10-12 07:44:40 +0000300
kurtis.heimerl06286132011-11-26 03:18:43 +0000301 CorrType corrType = expectedCorrType(rxBurst->getTime());
dburgessb3a0ca42011-10-12 07:44:40 +0000302
303 if ((corrType==OFF) || (corrType==IDLE)) {
304 delete rxBurst;
305 return NULL;
306 }
307
308 // check to see if received burst has sufficient
309 signalVector *vectorBurst = rxBurst;
310 complex amplitude = 0.0;
311 float TOA = 0.0;
312 float avgPwr = 0.0;
313 if (!energyDetect(*vectorBurst,20*mSamplesPerSymbol,mEnergyThreshold,&avgPwr)) {
kurtis.heimerl06286132011-11-26 03:18:43 +0000314 LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->getTime();
315 double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000316 if (framesElapsed > 50) { // if we haven't had any false detections for a while, lower threshold
317 mEnergyThreshold -= 10.0/10.0;
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000318 if (mEnergyThreshold < 0.0)
319 mEnergyThreshold = 0.0;
320
kurtis.heimerl06286132011-11-26 03:18:43 +0000321 prevFalseDetectionTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000322 }
323 delete rxBurst;
324 return NULL;
325 }
kurtis.heimerl06286132011-11-26 03:18:43 +0000326 LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000327
328 // run the proper correlator
329 bool success = false;
330 if (corrType==TSC) {
kurtis.heimerl06286132011-11-26 03:18:43 +0000331 LOG(DEBUG) << "looking for TSC at time: " << rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000332 signalVector *channelResp;
kurtis.heimerl06286132011-11-26 03:18:43 +0000333 double framesElapsed = rxBurst->getTime()-channelEstimateTime[timeslot];
dburgessb3a0ca42011-10-12 07:44:40 +0000334 bool estimateChannel = false;
335 if ((framesElapsed > 50) || (channelResponse[timeslot]==NULL)) {
336 if (channelResponse[timeslot]) delete channelResponse[timeslot];
337 if (DFEForward[timeslot]) delete DFEForward[timeslot];
338 if (DFEFeedback[timeslot]) delete DFEFeedback[timeslot];
339 channelResponse[timeslot] = NULL;
340 DFEForward[timeslot] = NULL;
341 DFEFeedback[timeslot] = NULL;
342 estimateChannel = true;
343 }
344 if (!needDFE) estimateChannel = false;
345 float chanOffset;
346 success = analyzeTrafficBurst(*vectorBurst,
347 mTSC,
348 3.0,
349 mSamplesPerSymbol,
350 &amplitude,
351 &TOA,
352 mMaxExpectedDelay,
353 estimateChannel,
354 &channelResp,
355 &chanOffset);
356 if (success) {
357 LOG(DEBUG) << "FOUND TSC!!!!!! " << amplitude << " " << TOA;
358 mEnergyThreshold -= 1.0F/10.0F;
359 if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
360 SNRestimate[timeslot] = amplitude.norm2()/(mEnergyThreshold*mEnergyThreshold+1.0); // this is not highly accurate
361 if (estimateChannel) {
362 LOG(DEBUG) << "estimating channel...";
363 channelResponse[timeslot] = channelResp;
364 chanRespOffset[timeslot] = chanOffset;
365 chanRespAmplitude[timeslot] = amplitude;
366 scaleVector(*channelResp, complex(1.0,0.0)/amplitude);
367 designDFE(*channelResp, SNRestimate[timeslot], 7, &DFEForward[timeslot], &DFEFeedback[timeslot]);
kurtis.heimerl06286132011-11-26 03:18:43 +0000368 channelEstimateTime[timeslot] = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000369 LOG(DEBUG) << "SNR: " << SNRestimate[timeslot] << ", DFE forward: " << *DFEForward[timeslot] << ", DFE backward: " << *DFEFeedback[timeslot];
370 }
371 }
372 else {
kurtis.heimerl06286132011-11-26 03:18:43 +0000373 double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
374 LOG(DEBUG) << "wTime: " << rxBurst->getTime() << ", pTime: " << prevFalseDetectionTime << ", fElapsed: " << framesElapsed;
dburgessb3a0ca42011-10-12 07:44:40 +0000375 mEnergyThreshold += 10.0F/10.0F*exp(-framesElapsed);
kurtis.heimerl06286132011-11-26 03:18:43 +0000376 prevFalseDetectionTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000377 channelResponse[timeslot] = NULL;
378 }
379 }
380 else {
381 // RACH burst
382 success = detectRACHBurst(*vectorBurst,
383 5.0, // detection threshold
384 mSamplesPerSymbol,
385 &amplitude,
386 &TOA);
387 if (success) {
388 LOG(DEBUG) << "FOUND RACH!!!!!! " << amplitude << " " << TOA;
389 mEnergyThreshold -= (1.0F/10.0F);
390 if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
391 channelResponse[timeslot] = NULL;
392 }
393 else {
kurtis.heimerl06286132011-11-26 03:18:43 +0000394 double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000395 mEnergyThreshold += (1.0F/10.0F)*exp(-framesElapsed);
kurtis.heimerl06286132011-11-26 03:18:43 +0000396 prevFalseDetectionTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000397 }
398 }
399 LOG(DEBUG) << "energy Threshold = " << mEnergyThreshold;
400
401 // demodulate burst
402 SoftVector *burst = NULL;
403 if ((rxBurst) && (success)) {
404 if ((corrType==RACH) || (!needDFE)) {
405 burst = demodulateBurst(*vectorBurst,
406 *gsmPulse,
407 mSamplesPerSymbol,
408 amplitude,TOA);
409 }
410 else { // TSC
411 scaleVector(*vectorBurst,complex(1.0,0.0)/amplitude);
412 burst = equalizeBurst(*vectorBurst,
413 TOA-chanRespOffset[timeslot],
414 mSamplesPerSymbol,
415 *DFEForward[timeslot],
416 *DFEFeedback[timeslot]);
417 }
kurtis.heimerl06286132011-11-26 03:18:43 +0000418 wTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000419 RSSI = (int) floor(20.0*log10(rxFullScale/amplitude.abs()));
420 LOG(DEBUG) << "RSSI: " << RSSI;
421 timingOffset = (int) round(TOA*256.0/mSamplesPerSymbol);
422 }
423
424 //if (burst) LOG(DEBUG) << "burst: " << *burst << '\n';
425
426 delete rxBurst;
427
428 return burst;
429}
430
431void Transceiver::start()
432{
433 mControlServiceLoopThread->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) this);
434}
435
436void Transceiver::reset()
437{
438 mTransmitPriorityQueue.clear();
439 //mTransmitFIFO->clear();
440 //mReceiveFIFO->clear();
441}
442
443
444void Transceiver::driveControl()
445{
446
447 int MAX_PACKET_LENGTH = 100;
448
449 // check control socket
450 char buffer[MAX_PACKET_LENGTH];
451 int msgLen = -1;
452 buffer[0] = '\0';
453
454 msgLen = mControlSocket.read(buffer);
455
456 if (msgLen < 1) {
457 return;
458 }
459
460 char cmdcheck[4];
461 char command[MAX_PACKET_LENGTH];
462 char response[MAX_PACKET_LENGTH];
463
464 sscanf(buffer,"%3s %s",cmdcheck,command);
465
466 writeClockInterface();
467
468 if (strcmp(cmdcheck,"CMD")!=0) {
469 LOG(WARNING) << "bogus message on control interface";
470 return;
471 }
472 LOG(INFO) << "command is " << buffer;
473
474 if (strcmp(command,"POWEROFF")==0) {
475 // turn off transmitter/demod
476 sprintf(response,"RSP POWEROFF 0");
477 }
478 else if (strcmp(command,"POWERON")==0) {
479 // turn on transmitter/demod
480 if (!mTxFreq || !mRxFreq)
481 sprintf(response,"RSP POWERON 1");
482 else {
483 sprintf(response,"RSP POWERON 0");
484 if (!mOn) {
485 // Prepare for thread start
486 mPower = -20;
487 mRadioInterface->start();
488 generateRACHSequence(*gsmPulse,mSamplesPerSymbol);
489
490 // Start radio interface threads.
491 mFIFOServiceLoopThread->start((void * (*)(void*))FIFOServiceLoopAdapter,(void*) this);
492 mTransmitPriorityQueueServiceLoopThread->start((void * (*)(void*))TransmitPriorityQueueServiceLoopAdapter,(void*) this);
493 writeClockInterface();
494
495 mOn = true;
496 }
497 }
498 }
499 else if (strcmp(command,"SETMAXDLY")==0) {
500 //set expected maximum time-of-arrival
501 int maxDelay;
502 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
503 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
504 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
505 }
506 else if (strcmp(command,"SETRXGAIN")==0) {
507 //set expected maximum time-of-arrival
508 int newGain;
509 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
510 newGain = mRadioInterface->setRxGain(newGain);
ttsoue8dde022012-12-06 15:43:55 +0000511 mEnergyThreshold = INIT_ENERGY_THRSHD;
dburgessb3a0ca42011-10-12 07:44:40 +0000512 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
513 }
514 else if (strcmp(command,"NOISELEV")==0) {
515 if (mOn) {
516 sprintf(response,"RSP NOISELEV 0 %d",
517 (int) round(20.0*log10(rxFullScale/mEnergyThreshold)));
518 }
519 else {
520 sprintf(response,"RSP NOISELEV 1 0");
521 }
522 }
523 else if (strcmp(command,"SETPOWER")==0) {
524 // set output power in dB
525 int dbPwr;
526 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr);
527 if (!mOn)
528 sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
529 else {
530 mPower = dbPwr;
kurtis.heimerl58d6a012011-11-26 03:17:38 +0000531 mRadioInterface->setPowerAttenuation(dbPwr);
dburgessb3a0ca42011-10-12 07:44:40 +0000532 sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
533 }
534 }
535 else if (strcmp(command,"ADJPOWER")==0) {
536 // adjust power in dB steps
537 int dbStep;
538 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep);
539 if (!mOn)
540 sprintf(response,"RSP ADJPOWER 1 %d",mPower);
541 else {
542 mPower += dbStep;
543 sprintf(response,"RSP ADJPOWER 0 %d",mPower);
544 }
545 }
546#define FREQOFFSET 0//11.2e3
547 else if (strcmp(command,"RXTUNE")==0) {
548 // tune receiver
549 int freqKhz;
550 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
551 mRxFreq = freqKhz*1.0e3+FREQOFFSET;
552 if (!mRadioInterface->tuneRx(mRxFreq)) {
553 LOG(ALERT) << "RX failed to tune";
554 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
555 }
556 else
557 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
558 }
559 else if (strcmp(command,"TXTUNE")==0) {
560 // tune txmtr
561 int freqKhz;
562 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
563 //freqKhz = 890e3;
564 mTxFreq = freqKhz*1.0e3+FREQOFFSET;
565 if (!mRadioInterface->tuneTx(mTxFreq)) {
566 LOG(ALERT) << "TX failed to tune";
567 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
568 }
569 else
570 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
571 }
572 else if (strcmp(command,"SETTSC")==0) {
573 // set TSC
574 int TSC;
575 sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC);
576 if (mOn)
577 sprintf(response,"RSP SETTSC 1 %d",TSC);
578 else {
579 mTSC = TSC;
580 generateMidamble(*gsmPulse,mSamplesPerSymbol,TSC);
581 sprintf(response,"RSP SETTSC 0 %d",TSC);
582 }
583 }
584 else if (strcmp(command,"SETSLOT")==0) {
585 // set TSC
586 int corrCode;
587 int timeslot;
588 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
589 if ((timeslot < 0) || (timeslot > 7)) {
590 LOG(WARNING) << "bogus message on control interface";
591 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
592 return;
593 }
594 mChanType[timeslot] = (ChannelCombination) corrCode;
595 setModulus(timeslot);
596 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
597
598 }
599 else {
600 LOG(WARNING) << "bogus command " << command << " on control interface.";
601 }
602
603 mControlSocket.write(response,strlen(response)+1);
604
605}
606
607bool Transceiver::driveTransmitPriorityQueue()
608{
609
610 char buffer[gSlotLen+50];
611
612 // check data socket
613 size_t msgLen = mDataSocket.read(buffer);
614
615 if (msgLen!=gSlotLen+1+4+1) {
616 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
617 return false;
618 }
619
620 int timeSlot = (int) buffer[0];
621 uint64_t frameNum = 0;
622 for (int i = 0; i < 4; i++)
623 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
624
625 /*
626 if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) {
627 // stale burst
628 //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot);
629 //writeClockInterface();
630 }*/
631
632/*
633 DAB -- Just let these go through the demod.
634 if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) {
635 // stale burst from GSM core
636 LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot);
637 return false;
638 }
639*/
640
641 // periodically update GSM core clock
642 LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
643 << " mLastClockUpdateTime " << mLastClockUpdateTime;
644 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
645 writeClockInterface();
646
647
648 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
649
650 int RSSI = (int) buffer[5];
651 static BitVector newBurst(gSlotLen);
652 BitVector::iterator itr = newBurst.begin();
653 char *bufferItr = buffer+6;
654 while (itr < newBurst.end())
655 *itr++ = *bufferItr++;
656
657 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
658
659 addRadioVector(newBurst,RSSI,currTime);
660
661 LOG(DEBUG) "added burst - time: " << currTime << ", RSSI: " << RSSI; // << ", data: " << newBurst;
662
663 return true;
664
665
666}
667
668void Transceiver::driveReceiveFIFO()
669{
670
671 SoftVector *rxBurst = NULL;
672 int RSSI;
673 int TOA; // in 1/256 of a symbol
674 GSM::Time burstTime;
675
676 mRadioInterface->driveReceiveRadio();
677
678 rxBurst = pullRadioVector(burstTime,RSSI,TOA);
679
680 if (rxBurst) {
681
682 LOG(DEBUG) << "burst parameters: "
683 << " time: " << burstTime
684 << " RSSI: " << RSSI
685 << " TOA: " << TOA
686 << " bits: " << *rxBurst;
687
688 char burstString[gSlotLen+10];
689 burstString[0] = burstTime.TN();
690 for (int i = 0; i < 4; i++)
691 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
692 burstString[5] = RSSI;
693 burstString[6] = (TOA >> 8) & 0x0ff;
694 burstString[7] = TOA & 0x0ff;
695 SoftVector::iterator burstItr = rxBurst->begin();
696
697 for (unsigned int i = 0; i < gSlotLen; i++) {
698 burstString[8+i] =(char) round((*burstItr++)*255.0);
699 }
700 burstString[gSlotLen+9] = '\0';
701 delete rxBurst;
702
703 mDataSocket.write(burstString,gSlotLen+10);
704 }
705
706}
707
708void Transceiver::driveTransmitFIFO()
709{
710
711 /**
712 Features a carefully controlled latency mechanism, to
713 assure that transmit packets arrive at the radio/USRP
714 before they need to be transmitted.
715
716 Deadline clock indicates the burst that needs to be
717 pushed into the FIFO right NOW. If transmit queue does
718 not have a burst, stick in filler data.
719 */
720
721
722 RadioClock *radioClock = (mRadioInterface->getClock());
723
724 if (mOn) {
725 //radioClock->wait(); // wait until clock updates
726 LOG(DEBUG) << "radio clock " << radioClock->get();
727 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
728 // if underrun, then we're not providing bursts to radio/USRP fast
729 // enough. Need to increase latency by one GSM frame.
kurtis.heimerle380af32011-11-26 03:18:55 +0000730 if (mRadioInterface->getBus() == RadioDevice::USB) {
731 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000732 // only update latency at the defined frame interval
733 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000734 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
735 LOG(INFO) << "new latency: " << mTransmitLatency;
736 mLatencyUpdateTime = radioClock->get();
737 }
738 }
739 else {
740 // if underrun hasn't occurred in the last sec (216 frames) drop
741 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000742 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000743 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
744 mTransmitLatency.decTN();
745 LOG(INFO) << "reduced latency: " << mTransmitLatency;
746 mLatencyUpdateTime = radioClock->get();
747 }
748 }
749 }
dburgessb3a0ca42011-10-12 07:44:40 +0000750 }
dburgessb3a0ca42011-10-12 07:44:40 +0000751 // time to push burst to transmit FIFO
752 pushRadioVector(mTransmitDeadlineClock);
753 mTransmitDeadlineClock.incTN();
754 }
755
756 }
757 // FIXME -- This should not be a hard spin.
758 // But any delay here causes us to throw omni_thread_fatal.
759 //else radioClock->wait();
760}
761
762
763
764void Transceiver::writeClockInterface()
765{
766 char command[50];
767 // FIXME -- This should be adaptive.
768 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
769
770 LOG(INFO) << "ClockInterface: sending " << command;
771
772 mClockSocket.write(command,strlen(command)+1);
773
774 mLastClockUpdateTime = mTransmitDeadlineClock;
775
776}
777
778
779
780
781void *FIFOServiceLoopAdapter(Transceiver *transceiver)
782{
kurtis.heimerl6b495a52011-11-26 03:17:21 +0000783 transceiver->setPriority();
784
dburgessb3a0ca42011-10-12 07:44:40 +0000785 while (1) {
786 transceiver->driveReceiveFIFO();
787 transceiver->driveTransmitFIFO();
788 pthread_testcancel();
789 }
790 return NULL;
791}
792
793void *ControlServiceLoopAdapter(Transceiver *transceiver)
794{
795 while (1) {
796 transceiver->driveControl();
797 pthread_testcancel();
798 }
799 return NULL;
800}
801
802void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *transceiver)
803{
804 while (1) {
805 bool stale = false;
806 // Flush the UDP packets until a successful transfer.
807 while (!transceiver->driveTransmitPriorityQueue()) {
808 stale = true;
809 }
810 if (stale) {
811 // If a packet was stale, remind the GSM stack of the clock.
812 transceiver->writeClockInterface();
813 }
814 pthread_testcancel();
815 }
816 return NULL;
817}