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