blob: ad048ee95bd44a03f924ceb943c50efeb82e6548 [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 Tsou8181b012013-08-20 21:17:19 -0400330#ifdef ENERGY_DETECT
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400331 if (!energyDetect(*vectorBurst, 20 * mSPS, mEnergyThreshold, &avgPwr)) {
kurtis.heimerl06286132011-11-26 03:18:43 +0000332 LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->getTime();
333 double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000334 if (framesElapsed > 50) { // if we haven't had any false detections for a while, lower threshold
335 mEnergyThreshold -= 10.0/10.0;
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000336 if (mEnergyThreshold < 0.0)
337 mEnergyThreshold = 0.0;
338
kurtis.heimerl06286132011-11-26 03:18:43 +0000339 prevFalseDetectionTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000340 }
341 delete rxBurst;
342 return NULL;
343 }
kurtis.heimerl06286132011-11-26 03:18:43 +0000344 LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->getTime();
Thomas Tsou8181b012013-08-20 21:17:19 -0400345#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000346 // run the proper correlator
347 bool success = false;
348 if (corrType==TSC) {
kurtis.heimerl06286132011-11-26 03:18:43 +0000349 LOG(DEBUG) << "looking for TSC at time: " << rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000350 signalVector *channelResp;
kurtis.heimerl06286132011-11-26 03:18:43 +0000351 double framesElapsed = rxBurst->getTime()-channelEstimateTime[timeslot];
dburgessb3a0ca42011-10-12 07:44:40 +0000352 bool estimateChannel = false;
353 if ((framesElapsed > 50) || (channelResponse[timeslot]==NULL)) {
354 if (channelResponse[timeslot]) delete channelResponse[timeslot];
355 if (DFEForward[timeslot]) delete DFEForward[timeslot];
356 if (DFEFeedback[timeslot]) delete DFEFeedback[timeslot];
357 channelResponse[timeslot] = NULL;
358 DFEForward[timeslot] = NULL;
359 DFEFeedback[timeslot] = NULL;
360 estimateChannel = true;
361 }
362 if (!needDFE) estimateChannel = false;
363 float chanOffset;
364 success = analyzeTrafficBurst(*vectorBurst,
365 mTSC,
366 3.0,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400367 mSPS,
dburgessb3a0ca42011-10-12 07:44:40 +0000368 &amplitude,
369 &TOA,
370 mMaxExpectedDelay,
371 estimateChannel,
372 &channelResp,
373 &chanOffset);
374 if (success) {
375 LOG(DEBUG) << "FOUND TSC!!!!!! " << amplitude << " " << TOA;
376 mEnergyThreshold -= 1.0F/10.0F;
377 if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
378 SNRestimate[timeslot] = amplitude.norm2()/(mEnergyThreshold*mEnergyThreshold+1.0); // this is not highly accurate
379 if (estimateChannel) {
380 LOG(DEBUG) << "estimating channel...";
381 channelResponse[timeslot] = channelResp;
382 chanRespOffset[timeslot] = chanOffset;
383 chanRespAmplitude[timeslot] = amplitude;
384 scaleVector(*channelResp, complex(1.0,0.0)/amplitude);
385 designDFE(*channelResp, SNRestimate[timeslot], 7, &DFEForward[timeslot], &DFEFeedback[timeslot]);
kurtis.heimerl06286132011-11-26 03:18:43 +0000386 channelEstimateTime[timeslot] = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000387 LOG(DEBUG) << "SNR: " << SNRestimate[timeslot] << ", DFE forward: " << *DFEForward[timeslot] << ", DFE backward: " << *DFEFeedback[timeslot];
388 }
389 }
390 else {
kurtis.heimerl06286132011-11-26 03:18:43 +0000391 double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
392 LOG(DEBUG) << "wTime: " << rxBurst->getTime() << ", pTime: " << prevFalseDetectionTime << ", fElapsed: " << framesElapsed;
dburgessb3a0ca42011-10-12 07:44:40 +0000393 mEnergyThreshold += 10.0F/10.0F*exp(-framesElapsed);
kurtis.heimerl06286132011-11-26 03:18:43 +0000394 prevFalseDetectionTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000395 channelResponse[timeslot] = NULL;
396 }
397 }
398 else {
399 // RACH burst
400 success = detectRACHBurst(*vectorBurst,
401 5.0, // detection threshold
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400402 mSPS,
dburgessb3a0ca42011-10-12 07:44:40 +0000403 &amplitude,
404 &TOA);
405 if (success) {
406 LOG(DEBUG) << "FOUND RACH!!!!!! " << amplitude << " " << TOA;
407 mEnergyThreshold -= (1.0F/10.0F);
408 if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
409 channelResponse[timeslot] = NULL;
410 }
411 else {
kurtis.heimerl06286132011-11-26 03:18:43 +0000412 double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000413 mEnergyThreshold += (1.0F/10.0F)*exp(-framesElapsed);
kurtis.heimerl06286132011-11-26 03:18:43 +0000414 prevFalseDetectionTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000415 }
416 }
417 LOG(DEBUG) << "energy Threshold = " << mEnergyThreshold;
418
419 // demodulate burst
420 SoftVector *burst = NULL;
421 if ((rxBurst) && (success)) {
422 if ((corrType==RACH) || (!needDFE)) {
423 burst = demodulateBurst(*vectorBurst,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400424 mSPS,
dburgessb3a0ca42011-10-12 07:44:40 +0000425 amplitude,TOA);
426 }
427 else { // TSC
428 scaleVector(*vectorBurst,complex(1.0,0.0)/amplitude);
429 burst = equalizeBurst(*vectorBurst,
430 TOA-chanRespOffset[timeslot],
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400431 mSPS,
dburgessb3a0ca42011-10-12 07:44:40 +0000432 *DFEForward[timeslot],
433 *DFEFeedback[timeslot]);
434 }
kurtis.heimerl06286132011-11-26 03:18:43 +0000435 wTime = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000436 RSSI = (int) floor(20.0*log10(rxFullScale/amplitude.abs()));
437 LOG(DEBUG) << "RSSI: " << RSSI;
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400438 timingOffset = (int) round(TOA * 256.0 / mSPS);
dburgessb3a0ca42011-10-12 07:44:40 +0000439 }
440
441 //if (burst) LOG(DEBUG) << "burst: " << *burst << '\n';
442
443 delete rxBurst;
444
445 return burst;
446}
447
448void Transceiver::start()
449{
450 mControlServiceLoopThread->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) this);
451}
452
453void Transceiver::reset()
454{
455 mTransmitPriorityQueue.clear();
456 //mTransmitFIFO->clear();
457 //mReceiveFIFO->clear();
458}
459
460
461void Transceiver::driveControl()
462{
463
464 int MAX_PACKET_LENGTH = 100;
465
466 // check control socket
467 char buffer[MAX_PACKET_LENGTH];
468 int msgLen = -1;
469 buffer[0] = '\0';
470
471 msgLen = mControlSocket.read(buffer);
472
473 if (msgLen < 1) {
474 return;
475 }
476
477 char cmdcheck[4];
478 char command[MAX_PACKET_LENGTH];
479 char response[MAX_PACKET_LENGTH];
480
481 sscanf(buffer,"%3s %s",cmdcheck,command);
482
483 writeClockInterface();
484
485 if (strcmp(cmdcheck,"CMD")!=0) {
486 LOG(WARNING) << "bogus message on control interface";
487 return;
488 }
489 LOG(INFO) << "command is " << buffer;
490
491 if (strcmp(command,"POWEROFF")==0) {
492 // turn off transmitter/demod
493 sprintf(response,"RSP POWEROFF 0");
494 }
495 else if (strcmp(command,"POWERON")==0) {
496 // turn on transmitter/demod
497 if (!mTxFreq || !mRxFreq)
498 sprintf(response,"RSP POWERON 1");
499 else {
500 sprintf(response,"RSP POWERON 0");
501 if (!mOn) {
502 // Prepare for thread start
503 mPower = -20;
504 mRadioInterface->start();
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}