blob: a7c629e28990c5cafd94b0afad1f05a3bfc819db [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();
Thomas Tsou83e06892013-08-20 16:10:01 -0400504 generateRACHSequence(mSPS);
dburgessb3a0ca42011-10-12 07:44:40 +0000505
506 // Start radio interface threads.
507 mFIFOServiceLoopThread->start((void * (*)(void*))FIFOServiceLoopAdapter,(void*) this);
508 mTransmitPriorityQueueServiceLoopThread->start((void * (*)(void*))TransmitPriorityQueueServiceLoopAdapter,(void*) this);
509 writeClockInterface();
510
511 mOn = true;
512 }
513 }
514 }
515 else if (strcmp(command,"SETMAXDLY")==0) {
516 //set expected maximum time-of-arrival
517 int maxDelay;
518 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
519 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
520 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
521 }
522 else if (strcmp(command,"SETRXGAIN")==0) {
523 //set expected maximum time-of-arrival
524 int newGain;
525 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
526 newGain = mRadioInterface->setRxGain(newGain);
ttsoue8dde022012-12-06 15:43:55 +0000527 mEnergyThreshold = INIT_ENERGY_THRSHD;
dburgessb3a0ca42011-10-12 07:44:40 +0000528 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
529 }
530 else if (strcmp(command,"NOISELEV")==0) {
531 if (mOn) {
532 sprintf(response,"RSP NOISELEV 0 %d",
533 (int) round(20.0*log10(rxFullScale/mEnergyThreshold)));
534 }
535 else {
536 sprintf(response,"RSP NOISELEV 1 0");
537 }
538 }
539 else if (strcmp(command,"SETPOWER")==0) {
540 // set output power in dB
541 int dbPwr;
542 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr);
543 if (!mOn)
544 sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
545 else {
546 mPower = dbPwr;
kurtis.heimerl58d6a012011-11-26 03:17:38 +0000547 mRadioInterface->setPowerAttenuation(dbPwr);
dburgessb3a0ca42011-10-12 07:44:40 +0000548 sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
549 }
550 }
551 else if (strcmp(command,"ADJPOWER")==0) {
552 // adjust power in dB steps
553 int dbStep;
554 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep);
555 if (!mOn)
556 sprintf(response,"RSP ADJPOWER 1 %d",mPower);
557 else {
558 mPower += dbStep;
559 sprintf(response,"RSP ADJPOWER 0 %d",mPower);
560 }
561 }
562#define FREQOFFSET 0//11.2e3
563 else if (strcmp(command,"RXTUNE")==0) {
564 // tune receiver
565 int freqKhz;
566 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
567 mRxFreq = freqKhz*1.0e3+FREQOFFSET;
568 if (!mRadioInterface->tuneRx(mRxFreq)) {
569 LOG(ALERT) << "RX failed to tune";
570 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
571 }
572 else
573 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
574 }
575 else if (strcmp(command,"TXTUNE")==0) {
576 // tune txmtr
577 int freqKhz;
578 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
579 //freqKhz = 890e3;
580 mTxFreq = freqKhz*1.0e3+FREQOFFSET;
581 if (!mRadioInterface->tuneTx(mTxFreq)) {
582 LOG(ALERT) << "TX failed to tune";
583 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
584 }
585 else
586 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
587 }
588 else if (strcmp(command,"SETTSC")==0) {
589 // set TSC
590 int TSC;
591 sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC);
592 if (mOn)
593 sprintf(response,"RSP SETTSC 1 %d",TSC);
594 else {
595 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400596 generateMidamble(mSPS, TSC);
597 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000598 }
599 }
600 else if (strcmp(command,"SETSLOT")==0) {
601 // set TSC
602 int corrCode;
603 int timeslot;
604 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
605 if ((timeslot < 0) || (timeslot > 7)) {
606 LOG(WARNING) << "bogus message on control interface";
607 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
608 return;
609 }
610 mChanType[timeslot] = (ChannelCombination) corrCode;
611 setModulus(timeslot);
612 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
613
614 }
615 else {
616 LOG(WARNING) << "bogus command " << command << " on control interface.";
617 }
618
619 mControlSocket.write(response,strlen(response)+1);
620
621}
622
623bool Transceiver::driveTransmitPriorityQueue()
624{
625
626 char buffer[gSlotLen+50];
627
628 // check data socket
629 size_t msgLen = mDataSocket.read(buffer);
630
631 if (msgLen!=gSlotLen+1+4+1) {
632 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
633 return false;
634 }
635
636 int timeSlot = (int) buffer[0];
637 uint64_t frameNum = 0;
638 for (int i = 0; i < 4; i++)
639 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
640
641 /*
642 if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) {
643 // stale burst
644 //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot);
645 //writeClockInterface();
646 }*/
647
648/*
649 DAB -- Just let these go through the demod.
650 if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) {
651 // stale burst from GSM core
652 LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot);
653 return false;
654 }
655*/
656
657 // periodically update GSM core clock
658 LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
659 << " mLastClockUpdateTime " << mLastClockUpdateTime;
660 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
661 writeClockInterface();
662
663
664 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
665
666 int RSSI = (int) buffer[5];
667 static BitVector newBurst(gSlotLen);
668 BitVector::iterator itr = newBurst.begin();
669 char *bufferItr = buffer+6;
670 while (itr < newBurst.end())
671 *itr++ = *bufferItr++;
672
673 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
674
675 addRadioVector(newBurst,RSSI,currTime);
676
677 LOG(DEBUG) "added burst - time: " << currTime << ", RSSI: " << RSSI; // << ", data: " << newBurst;
678
679 return true;
680
681
682}
683
684void Transceiver::driveReceiveFIFO()
685{
686
687 SoftVector *rxBurst = NULL;
688 int RSSI;
689 int TOA; // in 1/256 of a symbol
690 GSM::Time burstTime;
691
692 mRadioInterface->driveReceiveRadio();
693
694 rxBurst = pullRadioVector(burstTime,RSSI,TOA);
695
696 if (rxBurst) {
697
698 LOG(DEBUG) << "burst parameters: "
699 << " time: " << burstTime
700 << " RSSI: " << RSSI
701 << " TOA: " << TOA
702 << " bits: " << *rxBurst;
703
704 char burstString[gSlotLen+10];
705 burstString[0] = burstTime.TN();
706 for (int i = 0; i < 4; i++)
707 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
708 burstString[5] = RSSI;
709 burstString[6] = (TOA >> 8) & 0x0ff;
710 burstString[7] = TOA & 0x0ff;
711 SoftVector::iterator burstItr = rxBurst->begin();
712
713 for (unsigned int i = 0; i < gSlotLen; i++) {
714 burstString[8+i] =(char) round((*burstItr++)*255.0);
715 }
716 burstString[gSlotLen+9] = '\0';
717 delete rxBurst;
718
719 mDataSocket.write(burstString,gSlotLen+10);
720 }
721
722}
723
724void Transceiver::driveTransmitFIFO()
725{
726
727 /**
728 Features a carefully controlled latency mechanism, to
729 assure that transmit packets arrive at the radio/USRP
730 before they need to be transmitted.
731
732 Deadline clock indicates the burst that needs to be
733 pushed into the FIFO right NOW. If transmit queue does
734 not have a burst, stick in filler data.
735 */
736
737
738 RadioClock *radioClock = (mRadioInterface->getClock());
739
740 if (mOn) {
741 //radioClock->wait(); // wait until clock updates
742 LOG(DEBUG) << "radio clock " << radioClock->get();
743 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
744 // if underrun, then we're not providing bursts to radio/USRP fast
745 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400746 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000747 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000748 // only update latency at the defined frame interval
749 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000750 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
751 LOG(INFO) << "new latency: " << mTransmitLatency;
752 mLatencyUpdateTime = radioClock->get();
753 }
754 }
755 else {
756 // if underrun hasn't occurred in the last sec (216 frames) drop
757 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000758 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000759 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
760 mTransmitLatency.decTN();
761 LOG(INFO) << "reduced latency: " << mTransmitLatency;
762 mLatencyUpdateTime = radioClock->get();
763 }
764 }
765 }
dburgessb3a0ca42011-10-12 07:44:40 +0000766 }
dburgessb3a0ca42011-10-12 07:44:40 +0000767 // time to push burst to transmit FIFO
768 pushRadioVector(mTransmitDeadlineClock);
769 mTransmitDeadlineClock.incTN();
770 }
771
772 }
773 // FIXME -- This should not be a hard spin.
774 // But any delay here causes us to throw omni_thread_fatal.
775 //else radioClock->wait();
776}
777
778
779
780void Transceiver::writeClockInterface()
781{
782 char command[50];
783 // FIXME -- This should be adaptive.
784 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
785
786 LOG(INFO) << "ClockInterface: sending " << command;
787
788 mClockSocket.write(command,strlen(command)+1);
789
790 mLastClockUpdateTime = mTransmitDeadlineClock;
791
792}
793
794
795
796
797void *FIFOServiceLoopAdapter(Transceiver *transceiver)
798{
kurtis.heimerl6b495a52011-11-26 03:17:21 +0000799 transceiver->setPriority();
800
dburgessb3a0ca42011-10-12 07:44:40 +0000801 while (1) {
802 transceiver->driveReceiveFIFO();
803 transceiver->driveTransmitFIFO();
804 pthread_testcancel();
805 }
806 return NULL;
807}
808
809void *ControlServiceLoopAdapter(Transceiver *transceiver)
810{
811 while (1) {
812 transceiver->driveControl();
813 pthread_testcancel();
814 }
815 return NULL;
816}
817
818void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *transceiver)
819{
820 while (1) {
821 bool stale = false;
822 // Flush the UDP packets until a successful transfer.
823 while (!transceiver->driveTransmitPriorityQueue()) {
824 stale = true;
825 }
826 if (stale) {
827 // If a packet was stale, remind the GSM stack of the clock.
828 transceiver->writeClockInterface();
829 }
830 pthread_testcancel();
831 }
832 return NULL;
833}