blob: 2557fecd175793469d8b1151f54e084c70a18d42 [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),
Thomas Tsouc1f7c422013-10-11 13:49:55 -040058 mClockSocket(wBasePort,TRXAddress,wBasePort+100),
59 mSPSTx(wSPS), mSPSRx(1)
dburgessb3a0ca42011-10-12 07:44:40 +000060{
dburgessb3a0ca42011-10-12 07:44:40 +000061 GSM::Time startTime(random() % gHyperframe,0);
62
Thomas Tsou92c16df2013-09-28 18:04:19 -040063 mRxServiceLoopThread = new Thread(32768);
64 mTxServiceLoopThread = new Thread(32768);
dburgessb3a0ca42011-10-12 07:44:40 +000065 mControlServiceLoopThread = new Thread(32768); ///< thread to process control messages from GSM core
66 mTransmitPriorityQueueServiceLoopThread = new Thread(32768);///< thread to process transmit bursts from GSM core
67
dburgessb3a0ca42011-10-12 07:44:40 +000068 mRadioInterface = wRadioInterface;
69 mTransmitLatency = wTransmitLatency;
70 mTransmitDeadlineClock = startTime;
71 mLastClockUpdateTime = startTime;
72 mLatencyUpdateTime = startTime;
73 mRadioInterface->getClock()->set(startTime);
74 mMaxExpectedDelay = 0;
75
dburgessb3a0ca42011-10-12 07:44:40 +000076 txFullScale = mRadioInterface->fullScaleInputValue();
77 rxFullScale = mRadioInterface->fullScaleOutputValue();
78
dburgessb3a0ca42011-10-12 07:44:40 +000079 mOn = false;
80 mTxFreq = 0.0;
81 mRxFreq = 0.0;
82 mPower = -10;
ttsoue8dde022012-12-06 15:43:55 +000083 mEnergyThreshold = INIT_ENERGY_THRSHD;
dburgessb3a0ca42011-10-12 07:44:40 +000084 prevFalseDetectionTime = startTime;
Thomas Tsou83e06892013-08-20 16:10:01 -040085
dburgessb3a0ca42011-10-12 07:44:40 +000086}
87
88Transceiver::~Transceiver()
89{
dburgessb3a0ca42011-10-12 07:44:40 +000090 sigProcLibDestroy();
91 mTransmitPriorityQueue.clear();
92}
Thomas Tsou83e06892013-08-20 16:10:01 -040093
94bool Transceiver::init()
95{
Thomas Tsouc1f7c422013-10-11 13:49:55 -040096 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -040097 LOG(ALERT) << "Failed to initialize signal processing library";
98 return false;
99 }
100
101 // initialize filler tables with dummy bursts
102 for (int i = 0; i < 8; i++) {
103 signalVector* modBurst = modulateBurst(gDummyBurst,
104 8 + (i % 4 == 0),
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400105 mSPSTx);
Thomas Tsou83e06892013-08-20 16:10:01 -0400106 if (!modBurst) {
107 sigProcLibDestroy();
108 LOG(ALERT) << "Failed to initialize filler table";
109 return false;
110 }
111
112 scaleVector(*modBurst,txFullScale);
113 fillerModulus[i]=26;
114 for (int j = 0; j < 102; j++) {
115 fillerTable[j][i] = new signalVector(*modBurst);
116 }
117
118 delete modBurst;
119 mChanType[i] = NONE;
120 channelResponse[i] = NULL;
121 DFEForward[i] = NULL;
122 DFEFeedback[i] = NULL;
123 channelEstimateTime[i] = mTransmitDeadlineClock;
124 }
125
126 return true;
127}
dburgessb3a0ca42011-10-12 07:44:40 +0000128
129void Transceiver::addRadioVector(BitVector &burst,
130 int RSSI,
131 GSM::Time &wTime)
132{
133 // modulate and stick into queue
Thomas Tsou83e06892013-08-20 16:10:01 -0400134 signalVector* modBurst = modulateBurst(burst,
dburgessb3a0ca42011-10-12 07:44:40 +0000135 8 + (wTime.TN() % 4 == 0),
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400136 mSPSTx);
dburgessb3a0ca42011-10-12 07:44:40 +0000137 scaleVector(*modBurst,txFullScale * pow(10,-RSSI/10));
138 radioVector *newVec = new radioVector(*modBurst,wTime);
139 mTransmitPriorityQueue.write(newVec);
140
141 delete modBurst;
142}
143
144#ifdef TRANSMIT_LOGGING
145void Transceiver::unModulateVector(signalVector wVector)
146{
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400147 SoftVector *burst = demodulateBurst(wVector, mSPSTx, 1.0, 0.0);
dburgessb3a0ca42011-10-12 07:44:40 +0000148 LOG(DEBUG) << "LOGGED BURST: " << *burst;
149
150/*
151 unsigned char burstStr[gSlotLen+1];
152 SoftVector::iterator burstItr = burst->begin();
153 for (int i = 0; i < gSlotLen; i++) {
154 // FIXME: Demod bits are inverted!
155 burstStr[i] = (unsigned char) ((*burstItr++)*255.0);
156 }
157 burstStr[gSlotLen]='\0';
158 LOG(DEBUG) << "LOGGED BURST: " << burstStr;
159*/
160 delete burst;
161}
162#endif
163
164void Transceiver::pushRadioVector(GSM::Time &nowTime)
165{
166
167 // dump stale bursts, if any
168 while (radioVector* staleBurst = mTransmitPriorityQueue.getStaleBurst(nowTime)) {
169 // Even if the burst is stale, put it in the fillter table.
170 // (It might be an idle pattern.)
171 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
kurtis.heimerl06286132011-11-26 03:18:43 +0000172 const GSM::Time& nextTime = staleBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000173 int TN = nextTime.TN();
174 int modFN = nextTime.FN() % fillerModulus[TN];
175 delete fillerTable[modFN][TN];
176 fillerTable[modFN][TN] = staleBurst;
177 }
178
179 int TN = nowTime.TN();
180 int modFN = nowTime.FN() % fillerModulus[nowTime.TN()];
181
182 // if queue contains data at the desired timestamp, stick it into FIFO
183 if (radioVector *next = (radioVector*) mTransmitPriorityQueue.getCurrentBurst(nowTime)) {
184 LOG(DEBUG) << "transmitFIFO: wrote burst " << next << " at time: " << nowTime;
185 delete fillerTable[modFN][TN];
186 fillerTable[modFN][TN] = new signalVector(*(next));
187 mRadioInterface->driveTransmitRadio(*(next),(mChanType[TN]==NONE)); //fillerTable[modFN][TN]));
188 delete next;
189#ifdef TRANSMIT_LOGGING
190 if (nowTime.TN()==TRANSMIT_LOGGING) {
191 unModulateVector(*(fillerTable[modFN][TN]));
192 }
193#endif
194 return;
195 }
196
197 // otherwise, pull filler data, and push to radio FIFO
198 mRadioInterface->driveTransmitRadio(*(fillerTable[modFN][TN]),(mChanType[TN]==NONE));
199#ifdef TRANSMIT_LOGGING
200 if (nowTime.TN()==TRANSMIT_LOGGING)
201 unModulateVector(*fillerTable[modFN][TN]);
202#endif
203
204}
205
206void Transceiver::setModulus(int timeslot)
207{
208 switch (mChanType[timeslot]) {
209 case NONE:
210 case I:
211 case II:
212 case III:
213 case FILL:
214 fillerModulus[timeslot] = 26;
215 break;
216 case IV:
217 case VI:
218 case V:
219 fillerModulus[timeslot] = 51;
220 break;
221 //case V:
222 case VII:
223 fillerModulus[timeslot] = 102;
224 break;
ttsoufc40a842013-06-09 22:38:18 +0000225 case XIII:
226 fillerModulus[timeslot] = 52;
227 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000228 default:
229 break;
230 }
231}
232
233
234Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime)
235{
236
237 unsigned burstTN = currTime.TN();
238 unsigned burstFN = currTime.FN();
239
240 switch (mChanType[burstTN]) {
241 case NONE:
242 return OFF;
243 break;
244 case FILL:
245 return IDLE;
246 break;
247 case I:
248 return TSC;
249 /*if (burstFN % 26 == 25)
250 return IDLE;
251 else
252 return TSC;*/
253 break;
254 case II:
ttsou20642972013-03-27 22:00:25 +0000255 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000256 break;
257 case III:
258 return TSC;
259 break;
260 case IV:
261 case VI:
262 return RACH;
263 break;
264 case V: {
265 int mod51 = burstFN % 51;
266 if ((mod51 <= 36) && (mod51 >= 14))
267 return RACH;
268 else if ((mod51 == 4) || (mod51 == 5))
269 return RACH;
270 else if ((mod51 == 45) || (mod51 == 46))
271 return RACH;
272 else
273 return TSC;
274 break;
275 }
276 case VII:
277 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
278 return IDLE;
279 else
280 return TSC;
281 break;
ttsoufc40a842013-06-09 22:38:18 +0000282 case XIII: {
283 int mod52 = burstFN % 52;
284 if ((mod52 == 12) || (mod52 == 38))
285 return RACH;
286 else if ((mod52 == 25) || (mod52 == 51))
287 return IDLE;
288 else
289 return TSC;
290 break;
291 }
dburgessb3a0ca42011-10-12 07:44:40 +0000292 case LOOPBACK:
293 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
294 return IDLE;
295 else
296 return TSC;
297 break;
298 default:
299 return OFF;
300 break;
301 }
302
303}
304
305SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
306 int &RSSI,
307 int &timingOffset)
308{
Thomas Tsoud5a80c32013-09-19 11:24:14 -0400309 bool needDFE = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000310
311 radioVector *rxBurst = (radioVector *) mReceiveFIFO->get();
312
313 if (!rxBurst) return NULL;
314
kurtis.heimerl06286132011-11-26 03:18:43 +0000315 LOG(DEBUG) << "receiveFIFO: read radio vector at time: " << rxBurst->getTime() << ", new size: " << mReceiveFIFO->size();
dburgessb3a0ca42011-10-12 07:44:40 +0000316
kurtis.heimerl06286132011-11-26 03:18:43 +0000317 int timeslot = rxBurst->getTime().TN();
dburgessb3a0ca42011-10-12 07:44:40 +0000318
kurtis.heimerl06286132011-11-26 03:18:43 +0000319 CorrType corrType = expectedCorrType(rxBurst->getTime());
dburgessb3a0ca42011-10-12 07:44:40 +0000320
321 if ((corrType==OFF) || (corrType==IDLE)) {
322 delete rxBurst;
323 return NULL;
324 }
325
326 // check to see if received burst has sufficient
327 signalVector *vectorBurst = rxBurst;
328 complex amplitude = 0.0;
329 float TOA = 0.0;
330 float avgPwr = 0.0;
Thomas Tsou8181b012013-08-20 21:17:19 -0400331#ifdef ENERGY_DETECT
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400332 if (!energyDetect(*vectorBurst, 20 * mSPSRx, mEnergyThreshold, &avgPwr)) {
kurtis.heimerl06286132011-11-26 03:18:43 +0000333 LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->getTime();
334 double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000335 if (framesElapsed > 50) { // if we haven't had any false detections for a while, lower threshold
336 mEnergyThreshold -= 10.0/10.0;
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000337 if (mEnergyThreshold < 0.0)
338 mEnergyThreshold = 0.0;
339
kurtis.heimerl06286132011-11-26 03:18:43 +0000340 prevFalseDetectionTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000341 }
342 delete rxBurst;
343 return NULL;
344 }
kurtis.heimerl06286132011-11-26 03:18:43 +0000345 LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->getTime();
Thomas Tsou8181b012013-08-20 21:17:19 -0400346#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000347 // run the proper correlator
348 bool success = false;
349 if (corrType==TSC) {
kurtis.heimerl06286132011-11-26 03:18:43 +0000350 LOG(DEBUG) << "looking for TSC at time: " << rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000351 signalVector *channelResp;
kurtis.heimerl06286132011-11-26 03:18:43 +0000352 double framesElapsed = rxBurst->getTime()-channelEstimateTime[timeslot];
dburgessb3a0ca42011-10-12 07:44:40 +0000353 bool estimateChannel = false;
354 if ((framesElapsed > 50) || (channelResponse[timeslot]==NULL)) {
355 if (channelResponse[timeslot]) delete channelResponse[timeslot];
356 if (DFEForward[timeslot]) delete DFEForward[timeslot];
357 if (DFEFeedback[timeslot]) delete DFEFeedback[timeslot];
358 channelResponse[timeslot] = NULL;
359 DFEForward[timeslot] = NULL;
360 DFEFeedback[timeslot] = NULL;
361 estimateChannel = true;
362 }
363 if (!needDFE) estimateChannel = false;
364 float chanOffset;
365 success = analyzeTrafficBurst(*vectorBurst,
366 mTSC,
Thomas Tsou865bca42013-08-21 20:58:00 -0400367 5.0,
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400368 mSPSRx,
dburgessb3a0ca42011-10-12 07:44:40 +0000369 &amplitude,
370 &TOA,
371 mMaxExpectedDelay,
372 estimateChannel,
373 &channelResp,
374 &chanOffset);
375 if (success) {
376 LOG(DEBUG) << "FOUND TSC!!!!!! " << amplitude << " " << TOA;
377 mEnergyThreshold -= 1.0F/10.0F;
378 if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
379 SNRestimate[timeslot] = amplitude.norm2()/(mEnergyThreshold*mEnergyThreshold+1.0); // this is not highly accurate
380 if (estimateChannel) {
381 LOG(DEBUG) << "estimating channel...";
382 channelResponse[timeslot] = channelResp;
383 chanRespOffset[timeslot] = chanOffset;
384 chanRespAmplitude[timeslot] = amplitude;
385 scaleVector(*channelResp, complex(1.0,0.0)/amplitude);
386 designDFE(*channelResp, SNRestimate[timeslot], 7, &DFEForward[timeslot], &DFEFeedback[timeslot]);
kurtis.heimerl06286132011-11-26 03:18:43 +0000387 channelEstimateTime[timeslot] = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000388 LOG(DEBUG) << "SNR: " << SNRestimate[timeslot] << ", DFE forward: " << *DFEForward[timeslot] << ", DFE backward: " << *DFEFeedback[timeslot];
389 }
390 }
391 else {
kurtis.heimerl06286132011-11-26 03:18:43 +0000392 double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
393 LOG(DEBUG) << "wTime: " << rxBurst->getTime() << ", pTime: " << prevFalseDetectionTime << ", fElapsed: " << framesElapsed;
dburgessb3a0ca42011-10-12 07:44:40 +0000394 mEnergyThreshold += 10.0F/10.0F*exp(-framesElapsed);
kurtis.heimerl06286132011-11-26 03:18:43 +0000395 prevFalseDetectionTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000396 channelResponse[timeslot] = NULL;
397 }
398 }
399 else {
400 // RACH burst
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400401 success = detectRACHBurst(*vectorBurst, 6.0, mSPSRx, &amplitude, &TOA);
dburgessb3a0ca42011-10-12 07:44:40 +0000402 if (success) {
403 LOG(DEBUG) << "FOUND RACH!!!!!! " << amplitude << " " << TOA;
404 mEnergyThreshold -= (1.0F/10.0F);
405 if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
406 channelResponse[timeslot] = NULL;
407 }
408 else {
kurtis.heimerl06286132011-11-26 03:18:43 +0000409 double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000410 mEnergyThreshold += (1.0F/10.0F)*exp(-framesElapsed);
kurtis.heimerl06286132011-11-26 03:18:43 +0000411 prevFalseDetectionTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000412 }
413 }
414 LOG(DEBUG) << "energy Threshold = " << mEnergyThreshold;
415
416 // demodulate burst
417 SoftVector *burst = NULL;
418 if ((rxBurst) && (success)) {
419 if ((corrType==RACH) || (!needDFE)) {
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400420 burst = demodulateBurst(*vectorBurst, mSPSRx, amplitude, TOA);
421 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000422 scaleVector(*vectorBurst,complex(1.0,0.0)/amplitude);
423 burst = equalizeBurst(*vectorBurst,
424 TOA-chanRespOffset[timeslot],
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400425 mSPSRx,
dburgessb3a0ca42011-10-12 07:44:40 +0000426 *DFEForward[timeslot],
427 *DFEFeedback[timeslot]);
428 }
kurtis.heimerl06286132011-11-26 03:18:43 +0000429 wTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000430 RSSI = (int) floor(20.0*log10(rxFullScale/amplitude.abs()));
431 LOG(DEBUG) << "RSSI: " << RSSI;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400432 timingOffset = (int) round(TOA * 256.0 / mSPSRx);
dburgessb3a0ca42011-10-12 07:44:40 +0000433 }
434
435 //if (burst) LOG(DEBUG) << "burst: " << *burst << '\n';
436
437 delete rxBurst;
438
439 return burst;
440}
441
442void Transceiver::start()
443{
444 mControlServiceLoopThread->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) this);
445}
446
447void Transceiver::reset()
448{
449 mTransmitPriorityQueue.clear();
450 //mTransmitFIFO->clear();
451 //mReceiveFIFO->clear();
452}
453
454
455void Transceiver::driveControl()
456{
457
458 int MAX_PACKET_LENGTH = 100;
459
460 // check control socket
461 char buffer[MAX_PACKET_LENGTH];
462 int msgLen = -1;
463 buffer[0] = '\0';
464
465 msgLen = mControlSocket.read(buffer);
466
467 if (msgLen < 1) {
468 return;
469 }
470
471 char cmdcheck[4];
472 char command[MAX_PACKET_LENGTH];
473 char response[MAX_PACKET_LENGTH];
474
475 sscanf(buffer,"%3s %s",cmdcheck,command);
476
477 writeClockInterface();
478
479 if (strcmp(cmdcheck,"CMD")!=0) {
480 LOG(WARNING) << "bogus message on control interface";
481 return;
482 }
483 LOG(INFO) << "command is " << buffer;
484
485 if (strcmp(command,"POWEROFF")==0) {
486 // turn off transmitter/demod
487 sprintf(response,"RSP POWEROFF 0");
488 }
489 else if (strcmp(command,"POWERON")==0) {
490 // turn on transmitter/demod
491 if (!mTxFreq || !mRxFreq)
492 sprintf(response,"RSP POWERON 1");
493 else {
494 sprintf(response,"RSP POWERON 0");
495 if (!mOn) {
496 // Prepare for thread start
497 mPower = -20;
498 mRadioInterface->start();
dburgessb3a0ca42011-10-12 07:44:40 +0000499
500 // Start radio interface threads.
Thomas Tsou92c16df2013-09-28 18:04:19 -0400501 mTxServiceLoopThread->start((void * (*)(void*))TxServiceLoopAdapter,(void*) this);
502 mRxServiceLoopThread->start((void * (*)(void*))RxServiceLoopAdapter,(void*) this);
dburgessb3a0ca42011-10-12 07:44:40 +0000503 mTransmitPriorityQueueServiceLoopThread->start((void * (*)(void*))TransmitPriorityQueueServiceLoopAdapter,(void*) this);
504 writeClockInterface();
505
506 mOn = true;
507 }
508 }
509 }
510 else if (strcmp(command,"SETMAXDLY")==0) {
511 //set expected maximum time-of-arrival
512 int maxDelay;
513 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
514 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
515 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
516 }
517 else if (strcmp(command,"SETRXGAIN")==0) {
518 //set expected maximum time-of-arrival
519 int newGain;
520 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
521 newGain = mRadioInterface->setRxGain(newGain);
ttsoue8dde022012-12-06 15:43:55 +0000522 mEnergyThreshold = INIT_ENERGY_THRSHD;
dburgessb3a0ca42011-10-12 07:44:40 +0000523 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
524 }
525 else if (strcmp(command,"NOISELEV")==0) {
526 if (mOn) {
527 sprintf(response,"RSP NOISELEV 0 %d",
528 (int) round(20.0*log10(rxFullScale/mEnergyThreshold)));
529 }
530 else {
531 sprintf(response,"RSP NOISELEV 1 0");
532 }
533 }
534 else if (strcmp(command,"SETPOWER")==0) {
535 // set output power in dB
536 int dbPwr;
537 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr);
538 if (!mOn)
539 sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
540 else {
541 mPower = dbPwr;
kurtis.heimerl58d6a012011-11-26 03:17:38 +0000542 mRadioInterface->setPowerAttenuation(dbPwr);
dburgessb3a0ca42011-10-12 07:44:40 +0000543 sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
544 }
545 }
546 else if (strcmp(command,"ADJPOWER")==0) {
547 // adjust power in dB steps
548 int dbStep;
549 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep);
550 if (!mOn)
551 sprintf(response,"RSP ADJPOWER 1 %d",mPower);
552 else {
553 mPower += dbStep;
554 sprintf(response,"RSP ADJPOWER 0 %d",mPower);
555 }
556 }
557#define FREQOFFSET 0//11.2e3
558 else if (strcmp(command,"RXTUNE")==0) {
559 // tune receiver
560 int freqKhz;
561 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
562 mRxFreq = freqKhz*1.0e3+FREQOFFSET;
563 if (!mRadioInterface->tuneRx(mRxFreq)) {
564 LOG(ALERT) << "RX failed to tune";
565 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
566 }
567 else
568 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
569 }
570 else if (strcmp(command,"TXTUNE")==0) {
571 // tune txmtr
572 int freqKhz;
573 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
574 //freqKhz = 890e3;
575 mTxFreq = freqKhz*1.0e3+FREQOFFSET;
576 if (!mRadioInterface->tuneTx(mTxFreq)) {
577 LOG(ALERT) << "TX failed to tune";
578 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
579 }
580 else
581 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
582 }
583 else if (strcmp(command,"SETTSC")==0) {
584 // set TSC
585 int TSC;
586 sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC);
587 if (mOn)
588 sprintf(response,"RSP SETTSC 1 %d",TSC);
589 else {
590 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400591 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400592 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000593 }
594 }
595 else if (strcmp(command,"SETSLOT")==0) {
596 // set TSC
597 int corrCode;
598 int timeslot;
599 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
600 if ((timeslot < 0) || (timeslot > 7)) {
601 LOG(WARNING) << "bogus message on control interface";
602 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
603 return;
604 }
605 mChanType[timeslot] = (ChannelCombination) corrCode;
606 setModulus(timeslot);
607 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
608
609 }
610 else {
611 LOG(WARNING) << "bogus command " << command << " on control interface.";
612 }
613
614 mControlSocket.write(response,strlen(response)+1);
615
616}
617
618bool Transceiver::driveTransmitPriorityQueue()
619{
620
621 char buffer[gSlotLen+50];
622
623 // check data socket
624 size_t msgLen = mDataSocket.read(buffer);
625
626 if (msgLen!=gSlotLen+1+4+1) {
627 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
628 return false;
629 }
630
631 int timeSlot = (int) buffer[0];
632 uint64_t frameNum = 0;
633 for (int i = 0; i < 4; i++)
634 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
635
636 /*
637 if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) {
638 // stale burst
639 //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot);
640 //writeClockInterface();
641 }*/
642
643/*
644 DAB -- Just let these go through the demod.
645 if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) {
646 // stale burst from GSM core
647 LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot);
648 return false;
649 }
650*/
651
652 // periodically update GSM core clock
653 LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
654 << " mLastClockUpdateTime " << mLastClockUpdateTime;
655 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
656 writeClockInterface();
657
658
659 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
660
661 int RSSI = (int) buffer[5];
662 static BitVector newBurst(gSlotLen);
663 BitVector::iterator itr = newBurst.begin();
664 char *bufferItr = buffer+6;
665 while (itr < newBurst.end())
666 *itr++ = *bufferItr++;
667
668 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
669
670 addRadioVector(newBurst,RSSI,currTime);
671
672 LOG(DEBUG) "added burst - time: " << currTime << ", RSSI: " << RSSI; // << ", data: " << newBurst;
673
674 return true;
675
676
677}
678
679void Transceiver::driveReceiveFIFO()
680{
681
682 SoftVector *rxBurst = NULL;
683 int RSSI;
684 int TOA; // in 1/256 of a symbol
685 GSM::Time burstTime;
686
687 mRadioInterface->driveReceiveRadio();
688
689 rxBurst = pullRadioVector(burstTime,RSSI,TOA);
690
691 if (rxBurst) {
692
693 LOG(DEBUG) << "burst parameters: "
694 << " time: " << burstTime
695 << " RSSI: " << RSSI
696 << " TOA: " << TOA
697 << " bits: " << *rxBurst;
698
699 char burstString[gSlotLen+10];
700 burstString[0] = burstTime.TN();
701 for (int i = 0; i < 4; i++)
702 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
703 burstString[5] = RSSI;
704 burstString[6] = (TOA >> 8) & 0x0ff;
705 burstString[7] = TOA & 0x0ff;
706 SoftVector::iterator burstItr = rxBurst->begin();
707
708 for (unsigned int i = 0; i < gSlotLen; i++) {
709 burstString[8+i] =(char) round((*burstItr++)*255.0);
710 }
711 burstString[gSlotLen+9] = '\0';
712 delete rxBurst;
713
714 mDataSocket.write(burstString,gSlotLen+10);
715 }
716
717}
718
719void Transceiver::driveTransmitFIFO()
720{
721
722 /**
723 Features a carefully controlled latency mechanism, to
724 assure that transmit packets arrive at the radio/USRP
725 before they need to be transmitted.
726
727 Deadline clock indicates the burst that needs to be
728 pushed into the FIFO right NOW. If transmit queue does
729 not have a burst, stick in filler data.
730 */
731
732
733 RadioClock *radioClock = (mRadioInterface->getClock());
734
735 if (mOn) {
736 //radioClock->wait(); // wait until clock updates
737 LOG(DEBUG) << "radio clock " << radioClock->get();
738 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
739 // if underrun, then we're not providing bursts to radio/USRP fast
740 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400741 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000742 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000743 // only update latency at the defined frame interval
744 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000745 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
746 LOG(INFO) << "new latency: " << mTransmitLatency;
747 mLatencyUpdateTime = radioClock->get();
748 }
749 }
750 else {
751 // if underrun hasn't occurred in the last sec (216 frames) drop
752 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000753 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000754 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
755 mTransmitLatency.decTN();
756 LOG(INFO) << "reduced latency: " << mTransmitLatency;
757 mLatencyUpdateTime = radioClock->get();
758 }
759 }
760 }
dburgessb3a0ca42011-10-12 07:44:40 +0000761 }
dburgessb3a0ca42011-10-12 07:44:40 +0000762 // time to push burst to transmit FIFO
763 pushRadioVector(mTransmitDeadlineClock);
764 mTransmitDeadlineClock.incTN();
765 }
dburgessb3a0ca42011-10-12 07:44:40 +0000766 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400767
768 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000769}
770
771
772
773void Transceiver::writeClockInterface()
774{
775 char command[50];
776 // FIXME -- This should be adaptive.
777 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
778
779 LOG(INFO) << "ClockInterface: sending " << command;
780
781 mClockSocket.write(command,strlen(command)+1);
782
783 mLastClockUpdateTime = mTransmitDeadlineClock;
784
Thomas Tsou92c16df2013-09-28 18:04:19 -0400785}
dburgessb3a0ca42011-10-12 07:44:40 +0000786
Thomas Tsou92c16df2013-09-28 18:04:19 -0400787void *RxServiceLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +0000788{
kurtis.heimerl6b495a52011-11-26 03:17:21 +0000789 transceiver->setPriority();
790
dburgessb3a0ca42011-10-12 07:44:40 +0000791 while (1) {
792 transceiver->driveReceiveFIFO();
Thomas Tsou92c16df2013-09-28 18:04:19 -0400793 pthread_testcancel();
794 }
795 return NULL;
796}
797
798void *TxServiceLoopAdapter(Transceiver *transceiver)
799{
800 while (1) {
dburgessb3a0ca42011-10-12 07:44:40 +0000801 transceiver->driveTransmitFIFO();
802 pthread_testcancel();
803 }
804 return NULL;
805}
806
807void *ControlServiceLoopAdapter(Transceiver *transceiver)
808{
809 while (1) {
810 transceiver->driveControl();
811 pthread_testcancel();
812 }
813 return NULL;
814}
815
816void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *transceiver)
817{
818 while (1) {
819 bool stale = false;
820 // Flush the UDP packets until a successful transfer.
821 while (!transceiver->driveTransmitPriorityQueue()) {
822 stale = true;
823 }
824 if (stale) {
825 // If a packet was stale, remind the GSM stack of the clock.
826 transceiver->writeClockInterface();
827 }
828 pthread_testcancel();
829 }
830 return NULL;
831}