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