blob: 77577e195d17cb1623c96b7784442933fe2e7653 [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;
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000306 if (mEnergyThreshold < 0.0)
307 mEnergyThreshold = 0.0;
308
dburgessb3a0ca42011-10-12 07:44:40 +0000309 prevFalseDetectionTime = rxBurst->time();
310 }
311 delete rxBurst;
312 return NULL;
313 }
314 LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->time();
315
316 // run the proper correlator
317 bool success = false;
318 if (corrType==TSC) {
319 LOG(DEBUG) << "looking for TSC at time: " << rxBurst->time();
320 signalVector *channelResp;
321 double framesElapsed = rxBurst->time()-channelEstimateTime[timeslot];
322 bool estimateChannel = false;
323 if ((framesElapsed > 50) || (channelResponse[timeslot]==NULL)) {
324 if (channelResponse[timeslot]) delete channelResponse[timeslot];
325 if (DFEForward[timeslot]) delete DFEForward[timeslot];
326 if (DFEFeedback[timeslot]) delete DFEFeedback[timeslot];
327 channelResponse[timeslot] = NULL;
328 DFEForward[timeslot] = NULL;
329 DFEFeedback[timeslot] = NULL;
330 estimateChannel = true;
331 }
332 if (!needDFE) estimateChannel = false;
333 float chanOffset;
334 success = analyzeTrafficBurst(*vectorBurst,
335 mTSC,
336 3.0,
337 mSamplesPerSymbol,
338 &amplitude,
339 &TOA,
340 mMaxExpectedDelay,
341 estimateChannel,
342 &channelResp,
343 &chanOffset);
344 if (success) {
345 LOG(DEBUG) << "FOUND TSC!!!!!! " << amplitude << " " << TOA;
346 mEnergyThreshold -= 1.0F/10.0F;
347 if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
348 SNRestimate[timeslot] = amplitude.norm2()/(mEnergyThreshold*mEnergyThreshold+1.0); // this is not highly accurate
349 if (estimateChannel) {
350 LOG(DEBUG) << "estimating channel...";
351 channelResponse[timeslot] = channelResp;
352 chanRespOffset[timeslot] = chanOffset;
353 chanRespAmplitude[timeslot] = amplitude;
354 scaleVector(*channelResp, complex(1.0,0.0)/amplitude);
355 designDFE(*channelResp, SNRestimate[timeslot], 7, &DFEForward[timeslot], &DFEFeedback[timeslot]);
356 channelEstimateTime[timeslot] = rxBurst->time();
357 LOG(DEBUG) << "SNR: " << SNRestimate[timeslot] << ", DFE forward: " << *DFEForward[timeslot] << ", DFE backward: " << *DFEFeedback[timeslot];
358 }
359 }
360 else {
361 double framesElapsed = rxBurst->time()-prevFalseDetectionTime;
362 LOG(DEBUG) << "wTime: " << rxBurst->time() << ", pTime: " << prevFalseDetectionTime << ", fElapsed: " << framesElapsed;
363 mEnergyThreshold += 10.0F/10.0F*exp(-framesElapsed);
364 prevFalseDetectionTime = rxBurst->time();
365 channelResponse[timeslot] = NULL;
366 }
367 }
368 else {
369 // RACH burst
370 success = detectRACHBurst(*vectorBurst,
371 5.0, // detection threshold
372 mSamplesPerSymbol,
373 &amplitude,
374 &TOA);
375 if (success) {
376 LOG(DEBUG) << "FOUND RACH!!!!!! " << amplitude << " " << TOA;
377 mEnergyThreshold -= (1.0F/10.0F);
378 if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
379 channelResponse[timeslot] = NULL;
380 }
381 else {
382 double framesElapsed = rxBurst->time()-prevFalseDetectionTime;
383 mEnergyThreshold += (1.0F/10.0F)*exp(-framesElapsed);
384 prevFalseDetectionTime = rxBurst->time();
385 }
386 }
387 LOG(DEBUG) << "energy Threshold = " << mEnergyThreshold;
388
389 // demodulate burst
390 SoftVector *burst = NULL;
391 if ((rxBurst) && (success)) {
392 if ((corrType==RACH) || (!needDFE)) {
393 burst = demodulateBurst(*vectorBurst,
394 *gsmPulse,
395 mSamplesPerSymbol,
396 amplitude,TOA);
397 }
398 else { // TSC
399 scaleVector(*vectorBurst,complex(1.0,0.0)/amplitude);
400 burst = equalizeBurst(*vectorBurst,
401 TOA-chanRespOffset[timeslot],
402 mSamplesPerSymbol,
403 *DFEForward[timeslot],
404 *DFEFeedback[timeslot]);
405 }
406 wTime = rxBurst->time();
dburgessb3a0ca42011-10-12 07:44:40 +0000407 RSSI = (int) floor(20.0*log10(rxFullScale/amplitude.abs()));
408 LOG(DEBUG) << "RSSI: " << RSSI;
409 timingOffset = (int) round(TOA*256.0/mSamplesPerSymbol);
410 }
411
412 //if (burst) LOG(DEBUG) << "burst: " << *burst << '\n';
413
414 delete rxBurst;
415
416 return burst;
417}
418
419void Transceiver::start()
420{
421 mControlServiceLoopThread->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) this);
422}
423
424void Transceiver::reset()
425{
426 mTransmitPriorityQueue.clear();
427 //mTransmitFIFO->clear();
428 //mReceiveFIFO->clear();
429}
430
431
432void Transceiver::driveControl()
433{
434
435 int MAX_PACKET_LENGTH = 100;
436
437 // check control socket
438 char buffer[MAX_PACKET_LENGTH];
439 int msgLen = -1;
440 buffer[0] = '\0';
441
442 msgLen = mControlSocket.read(buffer);
443
444 if (msgLen < 1) {
445 return;
446 }
447
448 char cmdcheck[4];
449 char command[MAX_PACKET_LENGTH];
450 char response[MAX_PACKET_LENGTH];
451
452 sscanf(buffer,"%3s %s",cmdcheck,command);
453
454 writeClockInterface();
455
456 if (strcmp(cmdcheck,"CMD")!=0) {
457 LOG(WARNING) << "bogus message on control interface";
458 return;
459 }
460 LOG(INFO) << "command is " << buffer;
461
462 if (strcmp(command,"POWEROFF")==0) {
463 // turn off transmitter/demod
464 sprintf(response,"RSP POWEROFF 0");
465 }
466 else if (strcmp(command,"POWERON")==0) {
467 // turn on transmitter/demod
468 if (!mTxFreq || !mRxFreq)
469 sprintf(response,"RSP POWERON 1");
470 else {
471 sprintf(response,"RSP POWERON 0");
472 if (!mOn) {
473 // Prepare for thread start
474 mPower = -20;
475 mRadioInterface->start();
476 generateRACHSequence(*gsmPulse,mSamplesPerSymbol);
477
478 // Start radio interface threads.
479 mFIFOServiceLoopThread->start((void * (*)(void*))FIFOServiceLoopAdapter,(void*) this);
480 mTransmitPriorityQueueServiceLoopThread->start((void * (*)(void*))TransmitPriorityQueueServiceLoopAdapter,(void*) this);
481 writeClockInterface();
482
483 mOn = true;
484 }
485 }
486 }
487 else if (strcmp(command,"SETMAXDLY")==0) {
488 //set expected maximum time-of-arrival
489 int maxDelay;
490 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
491 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
492 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
493 }
494 else if (strcmp(command,"SETRXGAIN")==0) {
495 //set expected maximum time-of-arrival
496 int newGain;
497 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
498 newGain = mRadioInterface->setRxGain(newGain);
499 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
500 }
501 else if (strcmp(command,"NOISELEV")==0) {
502 if (mOn) {
503 sprintf(response,"RSP NOISELEV 0 %d",
504 (int) round(20.0*log10(rxFullScale/mEnergyThreshold)));
505 }
506 else {
507 sprintf(response,"RSP NOISELEV 1 0");
508 }
509 }
510 else if (strcmp(command,"SETPOWER")==0) {
511 // set output power in dB
512 int dbPwr;
513 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr);
514 if (!mOn)
515 sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
516 else {
517 mPower = dbPwr;
kurtis.heimerl58d6a012011-11-26 03:17:38 +0000518 mRadioInterface->setPowerAttenuation(dbPwr);
dburgessb3a0ca42011-10-12 07:44:40 +0000519 sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
520 }
521 }
522 else if (strcmp(command,"ADJPOWER")==0) {
523 // adjust power in dB steps
524 int dbStep;
525 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep);
526 if (!mOn)
527 sprintf(response,"RSP ADJPOWER 1 %d",mPower);
528 else {
529 mPower += dbStep;
530 sprintf(response,"RSP ADJPOWER 0 %d",mPower);
531 }
532 }
533#define FREQOFFSET 0//11.2e3
534 else if (strcmp(command,"RXTUNE")==0) {
535 // tune receiver
536 int freqKhz;
537 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
538 mRxFreq = freqKhz*1.0e3+FREQOFFSET;
539 if (!mRadioInterface->tuneRx(mRxFreq)) {
540 LOG(ALERT) << "RX failed to tune";
541 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
542 }
543 else
544 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
545 }
546 else if (strcmp(command,"TXTUNE")==0) {
547 // tune txmtr
548 int freqKhz;
549 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
550 //freqKhz = 890e3;
551 mTxFreq = freqKhz*1.0e3+FREQOFFSET;
552 if (!mRadioInterface->tuneTx(mTxFreq)) {
553 LOG(ALERT) << "TX failed to tune";
554 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
555 }
556 else
557 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
558 }
559 else if (strcmp(command,"SETTSC")==0) {
560 // set TSC
561 int TSC;
562 sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC);
563 if (mOn)
564 sprintf(response,"RSP SETTSC 1 %d",TSC);
565 else {
566 mTSC = TSC;
567 generateMidamble(*gsmPulse,mSamplesPerSymbol,TSC);
568 sprintf(response,"RSP SETTSC 0 %d",TSC);
569 }
570 }
571 else if (strcmp(command,"SETSLOT")==0) {
572 // set TSC
573 int corrCode;
574 int timeslot;
575 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
576 if ((timeslot < 0) || (timeslot > 7)) {
577 LOG(WARNING) << "bogus message on control interface";
578 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
579 return;
580 }
581 mChanType[timeslot] = (ChannelCombination) corrCode;
582 setModulus(timeslot);
583 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
584
585 }
586 else {
587 LOG(WARNING) << "bogus command " << command << " on control interface.";
588 }
589
590 mControlSocket.write(response,strlen(response)+1);
591
592}
593
594bool Transceiver::driveTransmitPriorityQueue()
595{
596
597 char buffer[gSlotLen+50];
598
599 // check data socket
600 size_t msgLen = mDataSocket.read(buffer);
601
602 if (msgLen!=gSlotLen+1+4+1) {
603 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
604 return false;
605 }
606
607 int timeSlot = (int) buffer[0];
608 uint64_t frameNum = 0;
609 for (int i = 0; i < 4; i++)
610 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
611
612 /*
613 if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) {
614 // stale burst
615 //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot);
616 //writeClockInterface();
617 }*/
618
619/*
620 DAB -- Just let these go through the demod.
621 if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) {
622 // stale burst from GSM core
623 LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot);
624 return false;
625 }
626*/
627
628 // periodically update GSM core clock
629 LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
630 << " mLastClockUpdateTime " << mLastClockUpdateTime;
631 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
632 writeClockInterface();
633
634
635 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
636
637 int RSSI = (int) buffer[5];
638 static BitVector newBurst(gSlotLen);
639 BitVector::iterator itr = newBurst.begin();
640 char *bufferItr = buffer+6;
641 while (itr < newBurst.end())
642 *itr++ = *bufferItr++;
643
644 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
645
646 addRadioVector(newBurst,RSSI,currTime);
647
648 LOG(DEBUG) "added burst - time: " << currTime << ", RSSI: " << RSSI; // << ", data: " << newBurst;
649
650 return true;
651
652
653}
654
655void Transceiver::driveReceiveFIFO()
656{
657
658 SoftVector *rxBurst = NULL;
659 int RSSI;
660 int TOA; // in 1/256 of a symbol
661 GSM::Time burstTime;
662
663 mRadioInterface->driveReceiveRadio();
664
665 rxBurst = pullRadioVector(burstTime,RSSI,TOA);
666
667 if (rxBurst) {
668
669 LOG(DEBUG) << "burst parameters: "
670 << " time: " << burstTime
671 << " RSSI: " << RSSI
672 << " TOA: " << TOA
673 << " bits: " << *rxBurst;
674
675 char burstString[gSlotLen+10];
676 burstString[0] = burstTime.TN();
677 for (int i = 0; i < 4; i++)
678 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
679 burstString[5] = RSSI;
680 burstString[6] = (TOA >> 8) & 0x0ff;
681 burstString[7] = TOA & 0x0ff;
682 SoftVector::iterator burstItr = rxBurst->begin();
683
684 for (unsigned int i = 0; i < gSlotLen; i++) {
685 burstString[8+i] =(char) round((*burstItr++)*255.0);
686 }
687 burstString[gSlotLen+9] = '\0';
688 delete rxBurst;
689
690 mDataSocket.write(burstString,gSlotLen+10);
691 }
692
693}
694
695void Transceiver::driveTransmitFIFO()
696{
697
698 /**
699 Features a carefully controlled latency mechanism, to
700 assure that transmit packets arrive at the radio/USRP
701 before they need to be transmitted.
702
703 Deadline clock indicates the burst that needs to be
704 pushed into the FIFO right NOW. If transmit queue does
705 not have a burst, stick in filler data.
706 */
707
708
709 RadioClock *radioClock = (mRadioInterface->getClock());
710
711 if (mOn) {
712 //radioClock->wait(); // wait until clock updates
713 LOG(DEBUG) << "radio clock " << radioClock->get();
714 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
715 // if underrun, then we're not providing bursts to radio/USRP fast
716 // enough. Need to increase latency by one GSM frame.
kurtis.heimerl41f708b2011-11-26 03:17:32 +0000717#ifndef USE_UHD
dburgessb3a0ca42011-10-12 07:44:40 +0000718 if (mRadioInterface->isUnderrun()) {
719 // only do latency update every 10 frames, so we don't over update
720 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(10,0)) {
721 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
722 LOG(INFO) << "new latency: " << mTransmitLatency;
723 mLatencyUpdateTime = radioClock->get();
724 }
725 }
726 else {
727 // if underrun hasn't occurred in the last sec (216 frames) drop
728 // transmit latency by a timeslot
729 if (mTransmitLatency > GSM::Time(1,1)) {
730 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
731 mTransmitLatency.decTN();
732 LOG(INFO) << "reduced latency: " << mTransmitLatency;
733 mLatencyUpdateTime = radioClock->get();
734 }
735 }
736 }
kurtis.heimerl41f708b2011-11-26 03:17:32 +0000737#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000738 // time to push burst to transmit FIFO
739 pushRadioVector(mTransmitDeadlineClock);
740 mTransmitDeadlineClock.incTN();
741 }
742
743 }
744 // FIXME -- This should not be a hard spin.
745 // But any delay here causes us to throw omni_thread_fatal.
746 //else radioClock->wait();
747}
748
749
750
751void Transceiver::writeClockInterface()
752{
753 char command[50];
754 // FIXME -- This should be adaptive.
755 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
756
757 LOG(INFO) << "ClockInterface: sending " << command;
758
759 mClockSocket.write(command,strlen(command)+1);
760
761 mLastClockUpdateTime = mTransmitDeadlineClock;
762
763}
764
765
766
767
768void *FIFOServiceLoopAdapter(Transceiver *transceiver)
769{
kurtis.heimerl6b495a52011-11-26 03:17:21 +0000770 transceiver->setPriority();
771
dburgessb3a0ca42011-10-12 07:44:40 +0000772 while (1) {
773 transceiver->driveReceiveFIFO();
774 transceiver->driveTransmitFIFO();
775 pthread_testcancel();
776 }
777 return NULL;
778}
779
780void *ControlServiceLoopAdapter(Transceiver *transceiver)
781{
782 while (1) {
783 transceiver->driveControl();
784 pthread_testcancel();
785 }
786 return NULL;
787}
788
789void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *transceiver)
790{
791 while (1) {
792 bool stale = false;
793 // Flush the UDP packets until a successful transfer.
794 while (!transceiver->driveTransmitPriorityQueue()) {
795 stale = true;
796 }
797 if (stale) {
798 // If a packet was stale, remind the GSM stack of the clock.
799 transceiver->writeClockInterface();
800 }
801 pthread_testcancel();
802 }
803 return NULL;
804}