blob: f09f036e5a6bde8984c0e96390b3e67a0afd6016 [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,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -040053 int wSPS,
dburgessb3a0ca42011-10-12 07:44:40 +000054 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{
dburgessb3a0ca42011-10-12 07:44:40 +000060 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
Thomas Tsoud24cc2c2013-08-20 15:41:45 -040066 mSPS = wSPS;
dburgessb3a0ca42011-10-12 07:44:40 +000067 mRadioInterface = wRadioInterface;
68 mTransmitLatency = wTransmitLatency;
69 mTransmitDeadlineClock = startTime;
70 mLastClockUpdateTime = startTime;
71 mLatencyUpdateTime = startTime;
72 mRadioInterface->getClock()->set(startTime);
73 mMaxExpectedDelay = 0;
74
dburgessb3a0ca42011-10-12 07:44:40 +000075 txFullScale = mRadioInterface->fullScaleInputValue();
76 rxFullScale = mRadioInterface->fullScaleOutputValue();
77
dburgessb3a0ca42011-10-12 07:44:40 +000078 mOn = false;
79 mTxFreq = 0.0;
80 mRxFreq = 0.0;
81 mPower = -10;
ttsoue8dde022012-12-06 15:43:55 +000082 mEnergyThreshold = INIT_ENERGY_THRSHD;
dburgessb3a0ca42011-10-12 07:44:40 +000083 prevFalseDetectionTime = startTime;
Thomas Tsou83e06892013-08-20 16:10:01 -040084
dburgessb3a0ca42011-10-12 07:44:40 +000085}
86
87Transceiver::~Transceiver()
88{
dburgessb3a0ca42011-10-12 07:44:40 +000089 sigProcLibDestroy();
90 mTransmitPriorityQueue.clear();
91}
Thomas Tsou83e06892013-08-20 16:10:01 -040092
93bool Transceiver::init()
94{
95 if (!sigProcLibSetup(mSPS)) {
96 LOG(ALERT) << "Failed to initialize signal processing library";
97 return false;
98 }
99
100 // initialize filler tables with dummy bursts
101 for (int i = 0; i < 8; i++) {
102 signalVector* modBurst = modulateBurst(gDummyBurst,
103 8 + (i % 4 == 0),
104 mSPS);
105 if (!modBurst) {
106 sigProcLibDestroy();
107 LOG(ALERT) << "Failed to initialize filler table";
108 return false;
109 }
110
111 scaleVector(*modBurst,txFullScale);
112 fillerModulus[i]=26;
113 for (int j = 0; j < 102; j++) {
114 fillerTable[j][i] = new signalVector(*modBurst);
115 }
116
117 delete modBurst;
118 mChanType[i] = NONE;
119 channelResponse[i] = NULL;
120 DFEForward[i] = NULL;
121 DFEFeedback[i] = NULL;
122 channelEstimateTime[i] = mTransmitDeadlineClock;
123 }
124
125 return true;
126}
dburgessb3a0ca42011-10-12 07:44:40 +0000127
128void Transceiver::addRadioVector(BitVector &burst,
129 int RSSI,
130 GSM::Time &wTime)
131{
132 // modulate and stick into queue
Thomas Tsou83e06892013-08-20 16:10:01 -0400133 signalVector* modBurst = modulateBurst(burst,
dburgessb3a0ca42011-10-12 07:44:40 +0000134 8 + (wTime.TN() % 4 == 0),
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400135 mSPS);
dburgessb3a0ca42011-10-12 07:44:40 +0000136 scaleVector(*modBurst,txFullScale * pow(10,-RSSI/10));
137 radioVector *newVec = new radioVector(*modBurst,wTime);
138 mTransmitPriorityQueue.write(newVec);
139
140 delete modBurst;
141}
142
143#ifdef TRANSMIT_LOGGING
144void Transceiver::unModulateVector(signalVector wVector)
145{
Thomas Tsou83e06892013-08-20 16:10:01 -0400146 SoftVector *burst = demodulateBurst(wVector, mSPS, 1.0, 0.0);
dburgessb3a0ca42011-10-12 07:44:40 +0000147 LOG(DEBUG) << "LOGGED BURST: " << *burst;
148
149/*
150 unsigned char burstStr[gSlotLen+1];
151 SoftVector::iterator burstItr = burst->begin();
152 for (int i = 0; i < gSlotLen; i++) {
153 // FIXME: Demod bits are inverted!
154 burstStr[i] = (unsigned char) ((*burstItr++)*255.0);
155 }
156 burstStr[gSlotLen]='\0';
157 LOG(DEBUG) << "LOGGED BURST: " << burstStr;
158*/
159 delete burst;
160}
161#endif
162
163void Transceiver::pushRadioVector(GSM::Time &nowTime)
164{
165
166 // dump stale bursts, if any
167 while (radioVector* staleBurst = mTransmitPriorityQueue.getStaleBurst(nowTime)) {
168 // Even if the burst is stale, put it in the fillter table.
169 // (It might be an idle pattern.)
170 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
kurtis.heimerl06286132011-11-26 03:18:43 +0000171 const GSM::Time& nextTime = staleBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000172 int TN = nextTime.TN();
173 int modFN = nextTime.FN() % fillerModulus[TN];
174 delete fillerTable[modFN][TN];
175 fillerTable[modFN][TN] = staleBurst;
176 }
177
178 int TN = nowTime.TN();
179 int modFN = nowTime.FN() % fillerModulus[nowTime.TN()];
180
181 // if queue contains data at the desired timestamp, stick it into FIFO
182 if (radioVector *next = (radioVector*) mTransmitPriorityQueue.getCurrentBurst(nowTime)) {
183 LOG(DEBUG) << "transmitFIFO: wrote burst " << next << " at time: " << nowTime;
184 delete fillerTable[modFN][TN];
185 fillerTable[modFN][TN] = new signalVector(*(next));
186 mRadioInterface->driveTransmitRadio(*(next),(mChanType[TN]==NONE)); //fillerTable[modFN][TN]));
187 delete next;
188#ifdef TRANSMIT_LOGGING
189 if (nowTime.TN()==TRANSMIT_LOGGING) {
190 unModulateVector(*(fillerTable[modFN][TN]));
191 }
192#endif
193 return;
194 }
195
196 // otherwise, pull filler data, and push to radio FIFO
197 mRadioInterface->driveTransmitRadio(*(fillerTable[modFN][TN]),(mChanType[TN]==NONE));
198#ifdef TRANSMIT_LOGGING
199 if (nowTime.TN()==TRANSMIT_LOGGING)
200 unModulateVector(*fillerTable[modFN][TN]);
201#endif
202
203}
204
205void Transceiver::setModulus(int timeslot)
206{
207 switch (mChanType[timeslot]) {
208 case NONE:
209 case I:
210 case II:
211 case III:
212 case FILL:
213 fillerModulus[timeslot] = 26;
214 break;
215 case IV:
216 case VI:
217 case V:
218 fillerModulus[timeslot] = 51;
219 break;
220 //case V:
221 case VII:
222 fillerModulus[timeslot] = 102;
223 break;
ttsoufc40a842013-06-09 22:38:18 +0000224 case XIII:
225 fillerModulus[timeslot] = 52;
226 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000227 default:
228 break;
229 }
230}
231
232
233Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime)
234{
235
236 unsigned burstTN = currTime.TN();
237 unsigned burstFN = currTime.FN();
238
239 switch (mChanType[burstTN]) {
240 case NONE:
241 return OFF;
242 break;
243 case FILL:
244 return IDLE;
245 break;
246 case I:
247 return TSC;
248 /*if (burstFN % 26 == 25)
249 return IDLE;
250 else
251 return TSC;*/
252 break;
253 case II:
ttsou20642972013-03-27 22:00:25 +0000254 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000255 break;
256 case III:
257 return TSC;
258 break;
259 case IV:
260 case VI:
261 return RACH;
262 break;
263 case V: {
264 int mod51 = burstFN % 51;
265 if ((mod51 <= 36) && (mod51 >= 14))
266 return RACH;
267 else if ((mod51 == 4) || (mod51 == 5))
268 return RACH;
269 else if ((mod51 == 45) || (mod51 == 46))
270 return RACH;
271 else
272 return TSC;
273 break;
274 }
275 case VII:
276 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
277 return IDLE;
278 else
279 return TSC;
280 break;
ttsoufc40a842013-06-09 22:38:18 +0000281 case XIII: {
282 int mod52 = burstFN % 52;
283 if ((mod52 == 12) || (mod52 == 38))
284 return RACH;
285 else if ((mod52 == 25) || (mod52 == 51))
286 return IDLE;
287 else
288 return TSC;
289 break;
290 }
dburgessb3a0ca42011-10-12 07:44:40 +0000291 case LOOPBACK:
292 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
293 return IDLE;
294 else
295 return TSC;
296 break;
297 default:
298 return OFF;
299 break;
300 }
301
302}
303
304SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
305 int &RSSI,
306 int &timingOffset)
307{
308 bool needDFE = (mMaxExpectedDelay > 1);
309
310 radioVector *rxBurst = (radioVector *) mReceiveFIFO->get();
311
312 if (!rxBurst) return NULL;
313
kurtis.heimerl06286132011-11-26 03:18:43 +0000314 LOG(DEBUG) << "receiveFIFO: read radio vector at time: " << rxBurst->getTime() << ", new size: " << mReceiveFIFO->size();
dburgessb3a0ca42011-10-12 07:44:40 +0000315
kurtis.heimerl06286132011-11-26 03:18:43 +0000316 int timeslot = rxBurst->getTime().TN();
dburgessb3a0ca42011-10-12 07:44:40 +0000317
kurtis.heimerl06286132011-11-26 03:18:43 +0000318 CorrType corrType = expectedCorrType(rxBurst->getTime());
dburgessb3a0ca42011-10-12 07:44:40 +0000319
320 if ((corrType==OFF) || (corrType==IDLE)) {
321 delete rxBurst;
322 return NULL;
323 }
324
325 // check to see if received burst has sufficient
326 signalVector *vectorBurst = rxBurst;
327 complex amplitude = 0.0;
328 float TOA = 0.0;
329 float avgPwr = 0.0;
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400330 if (!energyDetect(*vectorBurst, 20 * mSPS, mEnergyThreshold, &avgPwr)) {
kurtis.heimerl06286132011-11-26 03:18:43 +0000331 LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->getTime();
332 double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000333 if (framesElapsed > 50) { // if we haven't had any false detections for a while, lower threshold
334 mEnergyThreshold -= 10.0/10.0;
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000335 if (mEnergyThreshold < 0.0)
336 mEnergyThreshold = 0.0;
337
kurtis.heimerl06286132011-11-26 03:18:43 +0000338 prevFalseDetectionTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000339 }
340 delete rxBurst;
341 return NULL;
342 }
kurtis.heimerl06286132011-11-26 03:18:43 +0000343 LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000344
345 // run the proper correlator
346 bool success = false;
347 if (corrType==TSC) {
kurtis.heimerl06286132011-11-26 03:18:43 +0000348 LOG(DEBUG) << "looking for TSC at time: " << rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000349 signalVector *channelResp;
kurtis.heimerl06286132011-11-26 03:18:43 +0000350 double framesElapsed = rxBurst->getTime()-channelEstimateTime[timeslot];
dburgessb3a0ca42011-10-12 07:44:40 +0000351 bool estimateChannel = false;
352 if ((framesElapsed > 50) || (channelResponse[timeslot]==NULL)) {
353 if (channelResponse[timeslot]) delete channelResponse[timeslot];
354 if (DFEForward[timeslot]) delete DFEForward[timeslot];
355 if (DFEFeedback[timeslot]) delete DFEFeedback[timeslot];
356 channelResponse[timeslot] = NULL;
357 DFEForward[timeslot] = NULL;
358 DFEFeedback[timeslot] = NULL;
359 estimateChannel = true;
360 }
361 if (!needDFE) estimateChannel = false;
362 float chanOffset;
363 success = analyzeTrafficBurst(*vectorBurst,
364 mTSC,
365 3.0,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400366 mSPS,
dburgessb3a0ca42011-10-12 07:44:40 +0000367 &amplitude,
368 &TOA,
369 mMaxExpectedDelay,
370 estimateChannel,
371 &channelResp,
372 &chanOffset);
373 if (success) {
374 LOG(DEBUG) << "FOUND TSC!!!!!! " << amplitude << " " << TOA;
375 mEnergyThreshold -= 1.0F/10.0F;
376 if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
377 SNRestimate[timeslot] = amplitude.norm2()/(mEnergyThreshold*mEnergyThreshold+1.0); // this is not highly accurate
378 if (estimateChannel) {
379 LOG(DEBUG) << "estimating channel...";
380 channelResponse[timeslot] = channelResp;
381 chanRespOffset[timeslot] = chanOffset;
382 chanRespAmplitude[timeslot] = amplitude;
383 scaleVector(*channelResp, complex(1.0,0.0)/amplitude);
384 designDFE(*channelResp, SNRestimate[timeslot], 7, &DFEForward[timeslot], &DFEFeedback[timeslot]);
kurtis.heimerl06286132011-11-26 03:18:43 +0000385 channelEstimateTime[timeslot] = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000386 LOG(DEBUG) << "SNR: " << SNRestimate[timeslot] << ", DFE forward: " << *DFEForward[timeslot] << ", DFE backward: " << *DFEFeedback[timeslot];
387 }
388 }
389 else {
kurtis.heimerl06286132011-11-26 03:18:43 +0000390 double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
391 LOG(DEBUG) << "wTime: " << rxBurst->getTime() << ", pTime: " << prevFalseDetectionTime << ", fElapsed: " << framesElapsed;
dburgessb3a0ca42011-10-12 07:44:40 +0000392 mEnergyThreshold += 10.0F/10.0F*exp(-framesElapsed);
kurtis.heimerl06286132011-11-26 03:18:43 +0000393 prevFalseDetectionTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000394 channelResponse[timeslot] = NULL;
395 }
396 }
397 else {
398 // RACH burst
399 success = detectRACHBurst(*vectorBurst,
400 5.0, // detection threshold
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400401 mSPS,
dburgessb3a0ca42011-10-12 07:44:40 +0000402 &amplitude,
403 &TOA);
404 if (success) {
405 LOG(DEBUG) << "FOUND RACH!!!!!! " << amplitude << " " << TOA;
406 mEnergyThreshold -= (1.0F/10.0F);
407 if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
408 channelResponse[timeslot] = NULL;
409 }
410 else {
kurtis.heimerl06286132011-11-26 03:18:43 +0000411 double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000412 mEnergyThreshold += (1.0F/10.0F)*exp(-framesElapsed);
kurtis.heimerl06286132011-11-26 03:18:43 +0000413 prevFalseDetectionTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000414 }
415 }
416 LOG(DEBUG) << "energy Threshold = " << mEnergyThreshold;
417
418 // demodulate burst
419 SoftVector *burst = NULL;
420 if ((rxBurst) && (success)) {
421 if ((corrType==RACH) || (!needDFE)) {
422 burst = demodulateBurst(*vectorBurst,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400423 mSPS,
dburgessb3a0ca42011-10-12 07:44:40 +0000424 amplitude,TOA);
425 }
426 else { // TSC
427 scaleVector(*vectorBurst,complex(1.0,0.0)/amplitude);
428 burst = equalizeBurst(*vectorBurst,
429 TOA-chanRespOffset[timeslot],
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400430 mSPS,
dburgessb3a0ca42011-10-12 07:44:40 +0000431 *DFEForward[timeslot],
432 *DFEFeedback[timeslot]);
433 }
kurtis.heimerl06286132011-11-26 03:18:43 +0000434 wTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000435 RSSI = (int) floor(20.0*log10(rxFullScale/amplitude.abs()));
436 LOG(DEBUG) << "RSSI: " << RSSI;
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400437 timingOffset = (int) round(TOA * 256.0 / mSPS);
dburgessb3a0ca42011-10-12 07:44:40 +0000438 }
439
440 //if (burst) LOG(DEBUG) << "burst: " << *burst << '\n';
441
442 delete rxBurst;
443
444 return burst;
445}
446
447void Transceiver::start()
448{
449 mControlServiceLoopThread->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) this);
450}
451
452void Transceiver::reset()
453{
454 mTransmitPriorityQueue.clear();
455 //mTransmitFIFO->clear();
456 //mReceiveFIFO->clear();
457}
458
459
460void Transceiver::driveControl()
461{
462
463 int MAX_PACKET_LENGTH = 100;
464
465 // check control socket
466 char buffer[MAX_PACKET_LENGTH];
467 int msgLen = -1;
468 buffer[0] = '\0';
469
470 msgLen = mControlSocket.read(buffer);
471
472 if (msgLen < 1) {
473 return;
474 }
475
476 char cmdcheck[4];
477 char command[MAX_PACKET_LENGTH];
478 char response[MAX_PACKET_LENGTH];
479
480 sscanf(buffer,"%3s %s",cmdcheck,command);
481
482 writeClockInterface();
483
484 if (strcmp(cmdcheck,"CMD")!=0) {
485 LOG(WARNING) << "bogus message on control interface";
486 return;
487 }
488 LOG(INFO) << "command is " << buffer;
489
490 if (strcmp(command,"POWEROFF")==0) {
491 // turn off transmitter/demod
492 sprintf(response,"RSP POWEROFF 0");
493 }
494 else if (strcmp(command,"POWERON")==0) {
495 // turn on transmitter/demod
496 if (!mTxFreq || !mRxFreq)
497 sprintf(response,"RSP POWERON 1");
498 else {
499 sprintf(response,"RSP POWERON 0");
500 if (!mOn) {
501 // Prepare for thread start
502 mPower = -20;
503 mRadioInterface->start();
dburgessb3a0ca42011-10-12 07:44:40 +0000504
505 // Start radio interface threads.
506 mFIFOServiceLoopThread->start((void * (*)(void*))FIFOServiceLoopAdapter,(void*) this);
507 mTransmitPriorityQueueServiceLoopThread->start((void * (*)(void*))TransmitPriorityQueueServiceLoopAdapter,(void*) this);
508 writeClockInterface();
509
510 mOn = true;
511 }
512 }
513 }
514 else if (strcmp(command,"SETMAXDLY")==0) {
515 //set expected maximum time-of-arrival
516 int maxDelay;
517 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
518 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
519 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
520 }
521 else if (strcmp(command,"SETRXGAIN")==0) {
522 //set expected maximum time-of-arrival
523 int newGain;
524 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
525 newGain = mRadioInterface->setRxGain(newGain);
ttsoue8dde022012-12-06 15:43:55 +0000526 mEnergyThreshold = INIT_ENERGY_THRSHD;
dburgessb3a0ca42011-10-12 07:44:40 +0000527 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
528 }
529 else if (strcmp(command,"NOISELEV")==0) {
530 if (mOn) {
531 sprintf(response,"RSP NOISELEV 0 %d",
532 (int) round(20.0*log10(rxFullScale/mEnergyThreshold)));
533 }
534 else {
535 sprintf(response,"RSP NOISELEV 1 0");
536 }
537 }
538 else if (strcmp(command,"SETPOWER")==0) {
539 // set output power in dB
540 int dbPwr;
541 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr);
542 if (!mOn)
543 sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
544 else {
545 mPower = dbPwr;
kurtis.heimerl58d6a012011-11-26 03:17:38 +0000546 mRadioInterface->setPowerAttenuation(dbPwr);
dburgessb3a0ca42011-10-12 07:44:40 +0000547 sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
548 }
549 }
550 else if (strcmp(command,"ADJPOWER")==0) {
551 // adjust power in dB steps
552 int dbStep;
553 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep);
554 if (!mOn)
555 sprintf(response,"RSP ADJPOWER 1 %d",mPower);
556 else {
557 mPower += dbStep;
558 sprintf(response,"RSP ADJPOWER 0 %d",mPower);
559 }
560 }
561#define FREQOFFSET 0//11.2e3
562 else if (strcmp(command,"RXTUNE")==0) {
563 // tune receiver
564 int freqKhz;
565 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
566 mRxFreq = freqKhz*1.0e3+FREQOFFSET;
567 if (!mRadioInterface->tuneRx(mRxFreq)) {
568 LOG(ALERT) << "RX failed to tune";
569 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
570 }
571 else
572 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
573 }
574 else if (strcmp(command,"TXTUNE")==0) {
575 // tune txmtr
576 int freqKhz;
577 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
578 //freqKhz = 890e3;
579 mTxFreq = freqKhz*1.0e3+FREQOFFSET;
580 if (!mRadioInterface->tuneTx(mTxFreq)) {
581 LOG(ALERT) << "TX failed to tune";
582 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
583 }
584 else
585 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
586 }
587 else if (strcmp(command,"SETTSC")==0) {
588 // set TSC
589 int TSC;
590 sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC);
591 if (mOn)
592 sprintf(response,"RSP SETTSC 1 %d",TSC);
593 else {
594 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400595 generateMidamble(mSPS, TSC);
596 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000597 }
598 }
599 else if (strcmp(command,"SETSLOT")==0) {
600 // set TSC
601 int corrCode;
602 int timeslot;
603 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
604 if ((timeslot < 0) || (timeslot > 7)) {
605 LOG(WARNING) << "bogus message on control interface";
606 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
607 return;
608 }
609 mChanType[timeslot] = (ChannelCombination) corrCode;
610 setModulus(timeslot);
611 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
612
613 }
614 else {
615 LOG(WARNING) << "bogus command " << command << " on control interface.";
616 }
617
618 mControlSocket.write(response,strlen(response)+1);
619
620}
621
622bool Transceiver::driveTransmitPriorityQueue()
623{
624
625 char buffer[gSlotLen+50];
626
627 // check data socket
628 size_t msgLen = mDataSocket.read(buffer);
629
630 if (msgLen!=gSlotLen+1+4+1) {
631 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
632 return false;
633 }
634
635 int timeSlot = (int) buffer[0];
636 uint64_t frameNum = 0;
637 for (int i = 0; i < 4; i++)
638 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
639
640 /*
641 if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) {
642 // stale burst
643 //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot);
644 //writeClockInterface();
645 }*/
646
647/*
648 DAB -- Just let these go through the demod.
649 if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) {
650 // stale burst from GSM core
651 LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot);
652 return false;
653 }
654*/
655
656 // periodically update GSM core clock
657 LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
658 << " mLastClockUpdateTime " << mLastClockUpdateTime;
659 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
660 writeClockInterface();
661
662
663 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
664
665 int RSSI = (int) buffer[5];
666 static BitVector newBurst(gSlotLen);
667 BitVector::iterator itr = newBurst.begin();
668 char *bufferItr = buffer+6;
669 while (itr < newBurst.end())
670 *itr++ = *bufferItr++;
671
672 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
673
674 addRadioVector(newBurst,RSSI,currTime);
675
676 LOG(DEBUG) "added burst - time: " << currTime << ", RSSI: " << RSSI; // << ", data: " << newBurst;
677
678 return true;
679
680
681}
682
683void Transceiver::driveReceiveFIFO()
684{
685
686 SoftVector *rxBurst = NULL;
687 int RSSI;
688 int TOA; // in 1/256 of a symbol
689 GSM::Time burstTime;
690
691 mRadioInterface->driveReceiveRadio();
692
693 rxBurst = pullRadioVector(burstTime,RSSI,TOA);
694
695 if (rxBurst) {
696
697 LOG(DEBUG) << "burst parameters: "
698 << " time: " << burstTime
699 << " RSSI: " << RSSI
700 << " TOA: " << TOA
701 << " bits: " << *rxBurst;
702
703 char burstString[gSlotLen+10];
704 burstString[0] = burstTime.TN();
705 for (int i = 0; i < 4; i++)
706 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
707 burstString[5] = RSSI;
708 burstString[6] = (TOA >> 8) & 0x0ff;
709 burstString[7] = TOA & 0x0ff;
710 SoftVector::iterator burstItr = rxBurst->begin();
711
712 for (unsigned int i = 0; i < gSlotLen; i++) {
713 burstString[8+i] =(char) round((*burstItr++)*255.0);
714 }
715 burstString[gSlotLen+9] = '\0';
716 delete rxBurst;
717
718 mDataSocket.write(burstString,gSlotLen+10);
719 }
720
721}
722
723void Transceiver::driveTransmitFIFO()
724{
725
726 /**
727 Features a carefully controlled latency mechanism, to
728 assure that transmit packets arrive at the radio/USRP
729 before they need to be transmitted.
730
731 Deadline clock indicates the burst that needs to be
732 pushed into the FIFO right NOW. If transmit queue does
733 not have a burst, stick in filler data.
734 */
735
736
737 RadioClock *radioClock = (mRadioInterface->getClock());
738
739 if (mOn) {
740 //radioClock->wait(); // wait until clock updates
741 LOG(DEBUG) << "radio clock " << radioClock->get();
742 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
743 // if underrun, then we're not providing bursts to radio/USRP fast
744 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400745 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000746 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000747 // only update latency at the defined frame interval
748 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000749 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
750 LOG(INFO) << "new latency: " << mTransmitLatency;
751 mLatencyUpdateTime = radioClock->get();
752 }
753 }
754 else {
755 // if underrun hasn't occurred in the last sec (216 frames) drop
756 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000757 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000758 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
759 mTransmitLatency.decTN();
760 LOG(INFO) << "reduced latency: " << mTransmitLatency;
761 mLatencyUpdateTime = radioClock->get();
762 }
763 }
764 }
dburgessb3a0ca42011-10-12 07:44:40 +0000765 }
dburgessb3a0ca42011-10-12 07:44:40 +0000766 // time to push burst to transmit FIFO
767 pushRadioVector(mTransmitDeadlineClock);
768 mTransmitDeadlineClock.incTN();
769 }
770
771 }
772 // FIXME -- This should not be a hard spin.
773 // But any delay here causes us to throw omni_thread_fatal.
774 //else radioClock->wait();
775}
776
777
778
779void Transceiver::writeClockInterface()
780{
781 char command[50];
782 // FIXME -- This should be adaptive.
783 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
784
785 LOG(INFO) << "ClockInterface: sending " << command;
786
787 mClockSocket.write(command,strlen(command)+1);
788
789 mLastClockUpdateTime = mTransmitDeadlineClock;
790
791}
792
793
794
795
796void *FIFOServiceLoopAdapter(Transceiver *transceiver)
797{
kurtis.heimerl6b495a52011-11-26 03:17:21 +0000798 transceiver->setPriority();
799
dburgessb3a0ca42011-10-12 07:44:40 +0000800 while (1) {
801 transceiver->driveReceiveFIFO();
802 transceiver->driveTransmitFIFO();
803 pthread_testcancel();
804 }
805 return NULL;
806}
807
808void *ControlServiceLoopAdapter(Transceiver *transceiver)
809{
810 while (1) {
811 transceiver->driveControl();
812 pthread_testcancel();
813 }
814 return NULL;
815}
816
817void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *transceiver)
818{
819 while (1) {
820 bool stale = false;
821 // Flush the UDP packets until a successful transfer.
822 while (!transceiver->driveTransmitPriorityQueue()) {
823 stale = true;
824 }
825 if (stale) {
826 // If a packet was stale, remind the GSM stack of the clock.
827 transceiver->writeClockInterface();
828 }
829 pthread_testcancel();
830 }
831 return NULL;
832}