blob: 7a1160dbb983ee75419760a9bacab94d1806303a [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
dburgessb3a0ca42011-10-12 07:44:40 +000024#include <stdio.h>
25#include "Transceiver.h"
26#include <Logger.h>
27
ttsou2173abf2012-08-08 00:51:31 +000028#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
dburgessb3a0ca42011-10-12 07:44:40 +000031
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040032using namespace GSM;
33
kurtis.heimerlec842de2012-11-23 08:37:32 +000034#define USB_LATENCY_INTRVL 10,0
ttsou2173abf2012-08-08 00:51:31 +000035
36#if USE_UHD
kurtis.heimerlec842de2012-11-23 08:37:32 +000037# define USB_LATENCY_MIN 6,7
ttsou2173abf2012-08-08 00:51:31 +000038#else
kurtis.heimerlec842de2012-11-23 08:37:32 +000039# define USB_LATENCY_MIN 1,1
ttsou2173abf2012-08-08 00:51:31 +000040#endif
dburgessb3a0ca42011-10-12 07:44:40 +000041
Thomas Tsoufa3a7872013-10-17 21:23:34 -040042/* Number of running values use in noise average */
43#define NOISE_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000044
dburgessb3a0ca42011-10-12 07:44:40 +000045Transceiver::Transceiver(int wBasePort,
46 const char *TRXAddress,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -040047 int wSPS,
dburgessb3a0ca42011-10-12 07:44:40 +000048 GSM::Time wTransmitLatency,
49 RadioInterface *wRadioInterface)
Thomas Tsoud647ec52013-10-29 15:17:34 -040050 : mBasePort(wBasePort), mAddr(TRXAddress),
51 mDataSocket(NULL), mCtrlSocket(NULL), mClockSocket(NULL),
52 mSPSTx(wSPS), mSPSRx(1), mNoises(NOISE_CNT)
dburgessb3a0ca42011-10-12 07:44:40 +000053{
dburgessb3a0ca42011-10-12 07:44:40 +000054 GSM::Time startTime(random() % gHyperframe,0);
55
Thomas Tsou92c16df2013-09-28 18:04:19 -040056 mRxServiceLoopThread = new Thread(32768);
57 mTxServiceLoopThread = new Thread(32768);
dburgessb3a0ca42011-10-12 07:44:40 +000058 mControlServiceLoopThread = new Thread(32768); ///< thread to process control messages from GSM core
59 mTransmitPriorityQueueServiceLoopThread = new Thread(32768);///< thread to process transmit bursts from GSM core
60
dburgessb3a0ca42011-10-12 07:44:40 +000061 mRadioInterface = wRadioInterface;
62 mTransmitLatency = wTransmitLatency;
63 mTransmitDeadlineClock = startTime;
64 mLastClockUpdateTime = startTime;
65 mLatencyUpdateTime = startTime;
66 mRadioInterface->getClock()->set(startTime);
67 mMaxExpectedDelay = 0;
68
dburgessb3a0ca42011-10-12 07:44:40 +000069 txFullScale = mRadioInterface->fullScaleInputValue();
70 rxFullScale = mRadioInterface->fullScaleOutputValue();
71
dburgessb3a0ca42011-10-12 07:44:40 +000072 mOn = false;
73 mTxFreq = 0.0;
74 mRxFreq = 0.0;
75 mPower = -10;
Thomas Tsoufa3a7872013-10-17 21:23:34 -040076 mNoiseLev = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +000077}
78
79Transceiver::~Transceiver()
80{
dburgessb3a0ca42011-10-12 07:44:40 +000081 sigProcLibDestroy();
82 mTransmitPriorityQueue.clear();
Thomas Tsoud647ec52013-10-29 15:17:34 -040083
84 delete mClockSocket;
85 delete mCtrlSocket;
86 delete mDataSocket;
dburgessb3a0ca42011-10-12 07:44:40 +000087}
Thomas Tsou83e06892013-08-20 16:10:01 -040088
89bool Transceiver::init()
90{
Thomas Tsouc1f7c422013-10-11 13:49:55 -040091 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -040092 LOG(ALERT) << "Failed to initialize signal processing library";
93 return false;
94 }
95
Thomas Tsoud647ec52013-10-29 15:17:34 -040096 mClockSocket = new UDPSocket(mBasePort, mAddr.c_str(), mBasePort + 100);
97 mCtrlSocket = new UDPSocket(mBasePort + 1, mAddr.c_str(), mBasePort + 101);
98 mDataSocket = new UDPSocket(mBasePort + 2, mAddr.c_str(), mBasePort + 102);
99
Thomas Tsou83e06892013-08-20 16:10:01 -0400100 // initialize filler tables with dummy bursts
101 for (int i = 0; i < 8; i++) {
102 signalVector* modBurst = modulateBurst(gDummyBurst,
103 8 + (i % 4 == 0),
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400104 mSPSTx);
Thomas Tsou83e06892013-08-20 16:10:01 -0400105 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 Tsouc1f7c422013-10-11 13:49:55 -0400135 mSPSTx);
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
dburgessb3a0ca42011-10-12 07:44:40 +0000143void Transceiver::pushRadioVector(GSM::Time &nowTime)
144{
145
146 // dump stale bursts, if any
147 while (radioVector* staleBurst = mTransmitPriorityQueue.getStaleBurst(nowTime)) {
148 // Even if the burst is stale, put it in the fillter table.
149 // (It might be an idle pattern.)
150 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
kurtis.heimerl06286132011-11-26 03:18:43 +0000151 const GSM::Time& nextTime = staleBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000152 int TN = nextTime.TN();
153 int modFN = nextTime.FN() % fillerModulus[TN];
154 delete fillerTable[modFN][TN];
155 fillerTable[modFN][TN] = staleBurst;
156 }
157
158 int TN = nowTime.TN();
159 int modFN = nowTime.FN() % fillerModulus[nowTime.TN()];
160
161 // if queue contains data at the desired timestamp, stick it into FIFO
162 if (radioVector *next = (radioVector*) mTransmitPriorityQueue.getCurrentBurst(nowTime)) {
163 LOG(DEBUG) << "transmitFIFO: wrote burst " << next << " at time: " << nowTime;
164 delete fillerTable[modFN][TN];
165 fillerTable[modFN][TN] = new signalVector(*(next));
166 mRadioInterface->driveTransmitRadio(*(next),(mChanType[TN]==NONE)); //fillerTable[modFN][TN]));
167 delete next;
dburgessb3a0ca42011-10-12 07:44:40 +0000168 return;
169 }
170
171 // otherwise, pull filler data, and push to radio FIFO
172 mRadioInterface->driveTransmitRadio(*(fillerTable[modFN][TN]),(mChanType[TN]==NONE));
dburgessb3a0ca42011-10-12 07:44:40 +0000173}
174
175void Transceiver::setModulus(int timeslot)
176{
177 switch (mChanType[timeslot]) {
178 case NONE:
179 case I:
180 case II:
181 case III:
182 case FILL:
183 fillerModulus[timeslot] = 26;
184 break;
185 case IV:
186 case VI:
187 case V:
188 fillerModulus[timeslot] = 51;
189 break;
190 //case V:
191 case VII:
192 fillerModulus[timeslot] = 102;
193 break;
ttsoufc40a842013-06-09 22:38:18 +0000194 case XIII:
195 fillerModulus[timeslot] = 52;
196 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000197 default:
198 break;
199 }
200}
201
202
203Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime)
204{
205
206 unsigned burstTN = currTime.TN();
207 unsigned burstFN = currTime.FN();
208
209 switch (mChanType[burstTN]) {
210 case NONE:
211 return OFF;
212 break;
213 case FILL:
214 return IDLE;
215 break;
216 case I:
217 return TSC;
218 /*if (burstFN % 26 == 25)
219 return IDLE;
220 else
221 return TSC;*/
222 break;
223 case II:
ttsou20642972013-03-27 22:00:25 +0000224 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000225 break;
226 case III:
227 return TSC;
228 break;
229 case IV:
230 case VI:
231 return RACH;
232 break;
233 case V: {
234 int mod51 = burstFN % 51;
235 if ((mod51 <= 36) && (mod51 >= 14))
236 return RACH;
237 else if ((mod51 == 4) || (mod51 == 5))
238 return RACH;
239 else if ((mod51 == 45) || (mod51 == 46))
240 return RACH;
241 else
242 return TSC;
243 break;
244 }
245 case VII:
246 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
247 return IDLE;
248 else
249 return TSC;
250 break;
ttsoufc40a842013-06-09 22:38:18 +0000251 case XIII: {
252 int mod52 = burstFN % 52;
253 if ((mod52 == 12) || (mod52 == 38))
254 return RACH;
255 else if ((mod52 == 25) || (mod52 == 51))
256 return IDLE;
257 else
258 return TSC;
259 break;
260 }
dburgessb3a0ca42011-10-12 07:44:40 +0000261 case LOOPBACK:
262 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
263 return IDLE;
264 else
265 return TSC;
266 break;
267 default:
268 return OFF;
269 break;
270 }
271
272}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400273
dburgessb3a0ca42011-10-12 07:44:40 +0000274SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
275 int &RSSI,
276 int &timingOffset)
277{
Thomas Tsoud5a80c32013-09-19 11:24:14 -0400278 bool needDFE = false;
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400279 bool success = false;
280 complex amplitude = 0.0;
281 float TOA = 0.0, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +0000282
283 radioVector *rxBurst = (radioVector *) mReceiveFIFO->get();
284
285 if (!rxBurst) return NULL;
286
kurtis.heimerl06286132011-11-26 03:18:43 +0000287 int timeslot = rxBurst->getTime().TN();
dburgessb3a0ca42011-10-12 07:44:40 +0000288
kurtis.heimerl06286132011-11-26 03:18:43 +0000289 CorrType corrType = expectedCorrType(rxBurst->getTime());
dburgessb3a0ca42011-10-12 07:44:40 +0000290
291 if ((corrType==OFF) || (corrType==IDLE)) {
292 delete rxBurst;
293 return NULL;
294 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000295
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400296 signalVector *vectorBurst = rxBurst;
297
298 energyDetect(*vectorBurst, 20 * mSPSRx, 0.0, &avg);
299
300 // Update noise level
301 mNoiseLev = mNoises.avg();
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400302 avg = sqrt(avg);
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400303
dburgessb3a0ca42011-10-12 07:44:40 +0000304 // run the proper correlator
dburgessb3a0ca42011-10-12 07:44:40 +0000305 if (corrType==TSC) {
kurtis.heimerl06286132011-11-26 03:18:43 +0000306 LOG(DEBUG) << "looking for TSC at time: " << rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000307 signalVector *channelResp;
kurtis.heimerl06286132011-11-26 03:18:43 +0000308 double framesElapsed = rxBurst->getTime()-channelEstimateTime[timeslot];
dburgessb3a0ca42011-10-12 07:44:40 +0000309 bool estimateChannel = false;
310 if ((framesElapsed > 50) || (channelResponse[timeslot]==NULL)) {
311 if (channelResponse[timeslot]) delete channelResponse[timeslot];
312 if (DFEForward[timeslot]) delete DFEForward[timeslot];
313 if (DFEFeedback[timeslot]) delete DFEFeedback[timeslot];
314 channelResponse[timeslot] = NULL;
315 DFEForward[timeslot] = NULL;
316 DFEFeedback[timeslot] = NULL;
317 estimateChannel = true;
318 }
319 if (!needDFE) estimateChannel = false;
320 float chanOffset;
321 success = analyzeTrafficBurst(*vectorBurst,
322 mTSC,
Thomas Tsou865bca42013-08-21 20:58:00 -0400323 5.0,
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400324 mSPSRx,
dburgessb3a0ca42011-10-12 07:44:40 +0000325 &amplitude,
326 &TOA,
327 mMaxExpectedDelay,
328 estimateChannel,
329 &channelResp,
330 &chanOffset);
331 if (success) {
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400332 SNRestimate[timeslot] = amplitude.norm2()/(mNoiseLev*mNoiseLev+1.0); // this is not highly accurate
dburgessb3a0ca42011-10-12 07:44:40 +0000333 if (estimateChannel) {
334 LOG(DEBUG) << "estimating channel...";
335 channelResponse[timeslot] = channelResp;
336 chanRespOffset[timeslot] = chanOffset;
337 chanRespAmplitude[timeslot] = amplitude;
338 scaleVector(*channelResp, complex(1.0,0.0)/amplitude);
339 designDFE(*channelResp, SNRestimate[timeslot], 7, &DFEForward[timeslot], &DFEFeedback[timeslot]);
kurtis.heimerl06286132011-11-26 03:18:43 +0000340 channelEstimateTime[timeslot] = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000341 LOG(DEBUG) << "SNR: " << SNRestimate[timeslot] << ", DFE forward: " << *DFEForward[timeslot] << ", DFE backward: " << *DFEFeedback[timeslot];
342 }
343 }
344 else {
dburgessb3a0ca42011-10-12 07:44:40 +0000345 channelResponse[timeslot] = NULL;
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400346 mNoises.insert(avg);
dburgessb3a0ca42011-10-12 07:44:40 +0000347 }
348 }
349 else {
350 // RACH burst
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400351 if (success = detectRACHBurst(*vectorBurst, 6.0, mSPSRx, &amplitude, &TOA))
352 channelResponse[timeslot] = NULL;
353 else
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400354 mNoises.insert(avg);
dburgessb3a0ca42011-10-12 07:44:40 +0000355 }
dburgessb3a0ca42011-10-12 07:44:40 +0000356
357 // demodulate burst
358 SoftVector *burst = NULL;
359 if ((rxBurst) && (success)) {
360 if ((corrType==RACH) || (!needDFE)) {
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400361 burst = demodulateBurst(*vectorBurst, mSPSRx, amplitude, TOA);
362 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000363 scaleVector(*vectorBurst,complex(1.0,0.0)/amplitude);
364 burst = equalizeBurst(*vectorBurst,
365 TOA-chanRespOffset[timeslot],
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400366 mSPSRx,
dburgessb3a0ca42011-10-12 07:44:40 +0000367 *DFEForward[timeslot],
368 *DFEFeedback[timeslot]);
369 }
kurtis.heimerl06286132011-11-26 03:18:43 +0000370 wTime = rxBurst->getTime();
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400371 RSSI = (int) floor(20.0*log10(rxFullScale/avg));
dburgessb3a0ca42011-10-12 07:44:40 +0000372 LOG(DEBUG) << "RSSI: " << RSSI;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400373 timingOffset = (int) round(TOA * 256.0 / mSPSRx);
dburgessb3a0ca42011-10-12 07:44:40 +0000374 }
375
376 //if (burst) LOG(DEBUG) << "burst: " << *burst << '\n';
377
378 delete rxBurst;
379
380 return burst;
381}
382
383void Transceiver::start()
384{
385 mControlServiceLoopThread->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) this);
386}
387
388void Transceiver::reset()
389{
390 mTransmitPriorityQueue.clear();
391 //mTransmitFIFO->clear();
392 //mReceiveFIFO->clear();
393}
394
395
396void Transceiver::driveControl()
397{
398
399 int MAX_PACKET_LENGTH = 100;
400
401 // check control socket
402 char buffer[MAX_PACKET_LENGTH];
403 int msgLen = -1;
404 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400405
406 msgLen = mCtrlSocket->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000407
408 if (msgLen < 1) {
409 return;
410 }
411
412 char cmdcheck[4];
413 char command[MAX_PACKET_LENGTH];
414 char response[MAX_PACKET_LENGTH];
415
416 sscanf(buffer,"%3s %s",cmdcheck,command);
417
418 writeClockInterface();
419
420 if (strcmp(cmdcheck,"CMD")!=0) {
421 LOG(WARNING) << "bogus message on control interface";
422 return;
423 }
424 LOG(INFO) << "command is " << buffer;
425
426 if (strcmp(command,"POWEROFF")==0) {
427 // turn off transmitter/demod
428 sprintf(response,"RSP POWEROFF 0");
429 }
430 else if (strcmp(command,"POWERON")==0) {
431 // turn on transmitter/demod
432 if (!mTxFreq || !mRxFreq)
433 sprintf(response,"RSP POWERON 1");
434 else {
435 sprintf(response,"RSP POWERON 0");
436 if (!mOn) {
437 // Prepare for thread start
438 mPower = -20;
439 mRadioInterface->start();
dburgessb3a0ca42011-10-12 07:44:40 +0000440
441 // Start radio interface threads.
Thomas Tsou92c16df2013-09-28 18:04:19 -0400442 mTxServiceLoopThread->start((void * (*)(void*))TxServiceLoopAdapter,(void*) this);
443 mRxServiceLoopThread->start((void * (*)(void*))RxServiceLoopAdapter,(void*) this);
dburgessb3a0ca42011-10-12 07:44:40 +0000444 mTransmitPriorityQueueServiceLoopThread->start((void * (*)(void*))TransmitPriorityQueueServiceLoopAdapter,(void*) this);
445 writeClockInterface();
446
447 mOn = true;
448 }
449 }
450 }
451 else if (strcmp(command,"SETMAXDLY")==0) {
452 //set expected maximum time-of-arrival
453 int maxDelay;
454 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
455 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
456 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
457 }
458 else if (strcmp(command,"SETRXGAIN")==0) {
459 //set expected maximum time-of-arrival
460 int newGain;
461 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
462 newGain = mRadioInterface->setRxGain(newGain);
463 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
464 }
465 else if (strcmp(command,"NOISELEV")==0) {
466 if (mOn) {
467 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400468 (int) round(20.0*log10(rxFullScale/mNoiseLev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000469 }
470 else {
471 sprintf(response,"RSP NOISELEV 1 0");
472 }
473 }
474 else if (strcmp(command,"SETPOWER")==0) {
475 // set output power in dB
476 int dbPwr;
477 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr);
478 if (!mOn)
479 sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
480 else {
481 mPower = dbPwr;
kurtis.heimerl58d6a012011-11-26 03:17:38 +0000482 mRadioInterface->setPowerAttenuation(dbPwr);
dburgessb3a0ca42011-10-12 07:44:40 +0000483 sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
484 }
485 }
486 else if (strcmp(command,"ADJPOWER")==0) {
487 // adjust power in dB steps
488 int dbStep;
489 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep);
490 if (!mOn)
491 sprintf(response,"RSP ADJPOWER 1 %d",mPower);
492 else {
493 mPower += dbStep;
494 sprintf(response,"RSP ADJPOWER 0 %d",mPower);
495 }
496 }
497#define FREQOFFSET 0//11.2e3
498 else if (strcmp(command,"RXTUNE")==0) {
499 // tune receiver
500 int freqKhz;
501 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
502 mRxFreq = freqKhz*1.0e3+FREQOFFSET;
503 if (!mRadioInterface->tuneRx(mRxFreq)) {
504 LOG(ALERT) << "RX failed to tune";
505 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
506 }
507 else
508 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
509 }
510 else if (strcmp(command,"TXTUNE")==0) {
511 // tune txmtr
512 int freqKhz;
513 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
514 //freqKhz = 890e3;
515 mTxFreq = freqKhz*1.0e3+FREQOFFSET;
516 if (!mRadioInterface->tuneTx(mTxFreq)) {
517 LOG(ALERT) << "TX failed to tune";
518 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
519 }
520 else
521 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
522 }
523 else if (strcmp(command,"SETTSC")==0) {
524 // set TSC
525 int TSC;
526 sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC);
527 if (mOn)
528 sprintf(response,"RSP SETTSC 1 %d",TSC);
529 else {
530 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400531 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400532 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000533 }
534 }
535 else if (strcmp(command,"SETSLOT")==0) {
536 // set TSC
537 int corrCode;
538 int timeslot;
539 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
540 if ((timeslot < 0) || (timeslot > 7)) {
541 LOG(WARNING) << "bogus message on control interface";
542 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
543 return;
544 }
545 mChanType[timeslot] = (ChannelCombination) corrCode;
546 setModulus(timeslot);
547 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
548
549 }
550 else {
551 LOG(WARNING) << "bogus command " << command << " on control interface.";
552 }
553
Thomas Tsoud647ec52013-10-29 15:17:34 -0400554 mCtrlSocket->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000555}
556
557bool Transceiver::driveTransmitPriorityQueue()
558{
559
560 char buffer[gSlotLen+50];
561
562 // check data socket
Thomas Tsoud647ec52013-10-29 15:17:34 -0400563 size_t msgLen = mDataSocket->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000564
565 if (msgLen!=gSlotLen+1+4+1) {
566 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
567 return false;
568 }
569
570 int timeSlot = (int) buffer[0];
571 uint64_t frameNum = 0;
572 for (int i = 0; i < 4; i++)
573 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
574
575 /*
576 if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) {
577 // stale burst
578 //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot);
579 //writeClockInterface();
580 }*/
581
582/*
583 DAB -- Just let these go through the demod.
584 if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) {
585 // stale burst from GSM core
586 LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot);
587 return false;
588 }
589*/
590
591 // periodically update GSM core clock
592 LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
593 << " mLastClockUpdateTime " << mLastClockUpdateTime;
594 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
595 writeClockInterface();
596
597
598 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
599
600 int RSSI = (int) buffer[5];
601 static BitVector newBurst(gSlotLen);
602 BitVector::iterator itr = newBurst.begin();
603 char *bufferItr = buffer+6;
604 while (itr < newBurst.end())
605 *itr++ = *bufferItr++;
606
607 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
608
609 addRadioVector(newBurst,RSSI,currTime);
610
611 LOG(DEBUG) "added burst - time: " << currTime << ", RSSI: " << RSSI; // << ", data: " << newBurst;
612
613 return true;
614
615
616}
617
618void Transceiver::driveReceiveFIFO()
619{
620
621 SoftVector *rxBurst = NULL;
622 int RSSI;
623 int TOA; // in 1/256 of a symbol
624 GSM::Time burstTime;
625
626 mRadioInterface->driveReceiveRadio();
627
628 rxBurst = pullRadioVector(burstTime,RSSI,TOA);
629
630 if (rxBurst) {
631
632 LOG(DEBUG) << "burst parameters: "
633 << " time: " << burstTime
634 << " RSSI: " << RSSI
635 << " TOA: " << TOA
636 << " bits: " << *rxBurst;
637
638 char burstString[gSlotLen+10];
639 burstString[0] = burstTime.TN();
640 for (int i = 0; i < 4; i++)
641 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
642 burstString[5] = RSSI;
643 burstString[6] = (TOA >> 8) & 0x0ff;
644 burstString[7] = TOA & 0x0ff;
645 SoftVector::iterator burstItr = rxBurst->begin();
646
647 for (unsigned int i = 0; i < gSlotLen; i++) {
648 burstString[8+i] =(char) round((*burstItr++)*255.0);
649 }
650 burstString[gSlotLen+9] = '\0';
651 delete rxBurst;
652
Thomas Tsoud647ec52013-10-29 15:17:34 -0400653 mDataSocket->write(burstString, gSlotLen + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000654 }
dburgessb3a0ca42011-10-12 07:44:40 +0000655}
656
657void Transceiver::driveTransmitFIFO()
658{
659
660 /**
661 Features a carefully controlled latency mechanism, to
662 assure that transmit packets arrive at the radio/USRP
663 before they need to be transmitted.
664
665 Deadline clock indicates the burst that needs to be
666 pushed into the FIFO right NOW. If transmit queue does
667 not have a burst, stick in filler data.
668 */
669
670
671 RadioClock *radioClock = (mRadioInterface->getClock());
672
673 if (mOn) {
674 //radioClock->wait(); // wait until clock updates
675 LOG(DEBUG) << "radio clock " << radioClock->get();
676 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
677 // if underrun, then we're not providing bursts to radio/USRP fast
678 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400679 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000680 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000681 // only update latency at the defined frame interval
682 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000683 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
684 LOG(INFO) << "new latency: " << mTransmitLatency;
685 mLatencyUpdateTime = radioClock->get();
686 }
687 }
688 else {
689 // if underrun hasn't occurred in the last sec (216 frames) drop
690 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000691 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000692 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
693 mTransmitLatency.decTN();
694 LOG(INFO) << "reduced latency: " << mTransmitLatency;
695 mLatencyUpdateTime = radioClock->get();
696 }
697 }
698 }
dburgessb3a0ca42011-10-12 07:44:40 +0000699 }
dburgessb3a0ca42011-10-12 07:44:40 +0000700 // time to push burst to transmit FIFO
701 pushRadioVector(mTransmitDeadlineClock);
702 mTransmitDeadlineClock.incTN();
703 }
dburgessb3a0ca42011-10-12 07:44:40 +0000704 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400705
706 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000707}
708
709
710
711void Transceiver::writeClockInterface()
712{
713 char command[50];
714 // FIXME -- This should be adaptive.
715 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
716
717 LOG(INFO) << "ClockInterface: sending " << command;
718
Thomas Tsoud647ec52013-10-29 15:17:34 -0400719 mClockSocket->write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000720
721 mLastClockUpdateTime = mTransmitDeadlineClock;
722
Thomas Tsou92c16df2013-09-28 18:04:19 -0400723}
dburgessb3a0ca42011-10-12 07:44:40 +0000724
Thomas Tsou92c16df2013-09-28 18:04:19 -0400725void *RxServiceLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +0000726{
kurtis.heimerl6b495a52011-11-26 03:17:21 +0000727 transceiver->setPriority();
728
dburgessb3a0ca42011-10-12 07:44:40 +0000729 while (1) {
730 transceiver->driveReceiveFIFO();
Thomas Tsou92c16df2013-09-28 18:04:19 -0400731 pthread_testcancel();
732 }
733 return NULL;
734}
735
736void *TxServiceLoopAdapter(Transceiver *transceiver)
737{
738 while (1) {
dburgessb3a0ca42011-10-12 07:44:40 +0000739 transceiver->driveTransmitFIFO();
740 pthread_testcancel();
741 }
742 return NULL;
743}
744
745void *ControlServiceLoopAdapter(Transceiver *transceiver)
746{
747 while (1) {
748 transceiver->driveControl();
749 pthread_testcancel();
750 }
751 return NULL;
752}
753
754void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *transceiver)
755{
756 while (1) {
757 bool stale = false;
758 // Flush the UDP packets until a successful transfer.
759 while (!transceiver->driveTransmitPriorityQueue()) {
760 stale = true;
761 }
762 if (stale) {
763 // If a packet was stale, remind the GSM stack of the clock.
764 transceiver->writeClockInterface();
765 }
766 pthread_testcancel();
767 }
768 return NULL;
769}