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