blob: 9a62365b372b7019923896698c7a818e9f1175ec [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
Thomas Tsoufa3a7872013-10-17 21:23:34 -040049/* Number of running values use in noise average */
50#define NOISE_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000051
dburgessb3a0ca42011-10-12 07:44:40 +000052Transceiver::Transceiver(int wBasePort,
53 const char *TRXAddress,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -040054 int wSPS,
dburgessb3a0ca42011-10-12 07:44:40 +000055 GSM::Time wTransmitLatency,
56 RadioInterface *wRadioInterface)
57 :mDataSocket(wBasePort+2,TRXAddress,wBasePort+102),
58 mControlSocket(wBasePort+1,TRXAddress,wBasePort+101),
Thomas Tsouc1f7c422013-10-11 13:49:55 -040059 mClockSocket(wBasePort,TRXAddress,wBasePort+100),
Thomas Tsoufa3a7872013-10-17 21:23:34 -040060 mSPSTx(wSPS), mSPSRx(1), mNoises(NOISE_CNT)
dburgessb3a0ca42011-10-12 07:44:40 +000061{
dburgessb3a0ca42011-10-12 07:44:40 +000062 GSM::Time startTime(random() % gHyperframe,0);
63
Thomas Tsou92c16df2013-09-28 18:04:19 -040064 mRxServiceLoopThread = new Thread(32768);
65 mTxServiceLoopThread = new Thread(32768);
dburgessb3a0ca42011-10-12 07:44:40 +000066 mControlServiceLoopThread = new Thread(32768); ///< thread to process control messages from GSM core
67 mTransmitPriorityQueueServiceLoopThread = new Thread(32768);///< thread to process transmit bursts from GSM core
68
dburgessb3a0ca42011-10-12 07:44:40 +000069 mRadioInterface = wRadioInterface;
70 mTransmitLatency = wTransmitLatency;
71 mTransmitDeadlineClock = startTime;
72 mLastClockUpdateTime = startTime;
73 mLatencyUpdateTime = startTime;
74 mRadioInterface->getClock()->set(startTime);
75 mMaxExpectedDelay = 0;
76
dburgessb3a0ca42011-10-12 07:44:40 +000077 txFullScale = mRadioInterface->fullScaleInputValue();
78 rxFullScale = mRadioInterface->fullScaleOutputValue();
79
dburgessb3a0ca42011-10-12 07:44:40 +000080 mOn = false;
81 mTxFreq = 0.0;
82 mRxFreq = 0.0;
83 mPower = -10;
Thomas Tsoufa3a7872013-10-17 21:23:34 -040084 mNoiseLev = 0.0;
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{
Thomas Tsouc1f7c422013-10-11 13:49:55 -040095 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -040096 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),
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
143#ifdef TRANSMIT_LOGGING
144void Transceiver::unModulateVector(signalVector wVector)
145{
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400146 SoftVector *burst = demodulateBurst(wVector, mSPSTx, 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}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400303
dburgessb3a0ca42011-10-12 07:44:40 +0000304SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
305 int &RSSI,
306 int &timingOffset)
307{
Thomas Tsoud5a80c32013-09-19 11:24:14 -0400308 bool needDFE = false;
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400309 bool success = false;
310 complex amplitude = 0.0;
311 float TOA = 0.0, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +0000312
313 radioVector *rxBurst = (radioVector *) mReceiveFIFO->get();
314
315 if (!rxBurst) return NULL;
316
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 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000325
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400326 signalVector *vectorBurst = rxBurst;
327
328 energyDetect(*vectorBurst, 20 * mSPSRx, 0.0, &avg);
329
330 // Update noise level
331 mNoiseLev = mNoises.avg();
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400332 avg = sqrt(avg);
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400333
dburgessb3a0ca42011-10-12 07:44:40 +0000334 // run the proper correlator
dburgessb3a0ca42011-10-12 07:44:40 +0000335 if (corrType==TSC) {
kurtis.heimerl06286132011-11-26 03:18:43 +0000336 LOG(DEBUG) << "looking for TSC at time: " << rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000337 signalVector *channelResp;
kurtis.heimerl06286132011-11-26 03:18:43 +0000338 double framesElapsed = rxBurst->getTime()-channelEstimateTime[timeslot];
dburgessb3a0ca42011-10-12 07:44:40 +0000339 bool estimateChannel = false;
340 if ((framesElapsed > 50) || (channelResponse[timeslot]==NULL)) {
341 if (channelResponse[timeslot]) delete channelResponse[timeslot];
342 if (DFEForward[timeslot]) delete DFEForward[timeslot];
343 if (DFEFeedback[timeslot]) delete DFEFeedback[timeslot];
344 channelResponse[timeslot] = NULL;
345 DFEForward[timeslot] = NULL;
346 DFEFeedback[timeslot] = NULL;
347 estimateChannel = true;
348 }
349 if (!needDFE) estimateChannel = false;
350 float chanOffset;
351 success = analyzeTrafficBurst(*vectorBurst,
352 mTSC,
Thomas Tsou865bca42013-08-21 20:58:00 -0400353 5.0,
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400354 mSPSRx,
dburgessb3a0ca42011-10-12 07:44:40 +0000355 &amplitude,
356 &TOA,
357 mMaxExpectedDelay,
358 estimateChannel,
359 &channelResp,
360 &chanOffset);
361 if (success) {
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400362 SNRestimate[timeslot] = amplitude.norm2()/(mNoiseLev*mNoiseLev+1.0); // this is not highly accurate
dburgessb3a0ca42011-10-12 07:44:40 +0000363 if (estimateChannel) {
364 LOG(DEBUG) << "estimating channel...";
365 channelResponse[timeslot] = channelResp;
366 chanRespOffset[timeslot] = chanOffset;
367 chanRespAmplitude[timeslot] = amplitude;
368 scaleVector(*channelResp, complex(1.0,0.0)/amplitude);
369 designDFE(*channelResp, SNRestimate[timeslot], 7, &DFEForward[timeslot], &DFEFeedback[timeslot]);
kurtis.heimerl06286132011-11-26 03:18:43 +0000370 channelEstimateTime[timeslot] = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000371 LOG(DEBUG) << "SNR: " << SNRestimate[timeslot] << ", DFE forward: " << *DFEForward[timeslot] << ", DFE backward: " << *DFEFeedback[timeslot];
372 }
373 }
374 else {
dburgessb3a0ca42011-10-12 07:44:40 +0000375 channelResponse[timeslot] = NULL;
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400376 mNoises.insert(avg);
dburgessb3a0ca42011-10-12 07:44:40 +0000377 }
378 }
379 else {
380 // RACH burst
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400381 if (success = detectRACHBurst(*vectorBurst, 6.0, mSPSRx, &amplitude, &TOA))
382 channelResponse[timeslot] = NULL;
383 else
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400384 mNoises.insert(avg);
dburgessb3a0ca42011-10-12 07:44:40 +0000385 }
dburgessb3a0ca42011-10-12 07:44:40 +0000386
387 // demodulate burst
388 SoftVector *burst = NULL;
389 if ((rxBurst) && (success)) {
390 if ((corrType==RACH) || (!needDFE)) {
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400391 burst = demodulateBurst(*vectorBurst, mSPSRx, amplitude, TOA);
392 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000393 scaleVector(*vectorBurst,complex(1.0,0.0)/amplitude);
394 burst = equalizeBurst(*vectorBurst,
395 TOA-chanRespOffset[timeslot],
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400396 mSPSRx,
dburgessb3a0ca42011-10-12 07:44:40 +0000397 *DFEForward[timeslot],
398 *DFEFeedback[timeslot]);
399 }
kurtis.heimerl06286132011-11-26 03:18:43 +0000400 wTime = rxBurst->getTime();
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400401 RSSI = (int) floor(20.0*log10(rxFullScale/avg));
dburgessb3a0ca42011-10-12 07:44:40 +0000402 LOG(DEBUG) << "RSSI: " << RSSI;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400403 timingOffset = (int) round(TOA * 256.0 / mSPSRx);
dburgessb3a0ca42011-10-12 07:44:40 +0000404 }
405
406 //if (burst) LOG(DEBUG) << "burst: " << *burst << '\n';
407
408 delete rxBurst;
409
410 return burst;
411}
412
413void Transceiver::start()
414{
415 mControlServiceLoopThread->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) this);
416}
417
418void Transceiver::reset()
419{
420 mTransmitPriorityQueue.clear();
421 //mTransmitFIFO->clear();
422 //mReceiveFIFO->clear();
423}
424
425
426void Transceiver::driveControl()
427{
428
429 int MAX_PACKET_LENGTH = 100;
430
431 // check control socket
432 char buffer[MAX_PACKET_LENGTH];
433 int msgLen = -1;
434 buffer[0] = '\0';
435
436 msgLen = mControlSocket.read(buffer);
437
438 if (msgLen < 1) {
439 return;
440 }
441
442 char cmdcheck[4];
443 char command[MAX_PACKET_LENGTH];
444 char response[MAX_PACKET_LENGTH];
445
446 sscanf(buffer,"%3s %s",cmdcheck,command);
447
448 writeClockInterface();
449
450 if (strcmp(cmdcheck,"CMD")!=0) {
451 LOG(WARNING) << "bogus message on control interface";
452 return;
453 }
454 LOG(INFO) << "command is " << buffer;
455
456 if (strcmp(command,"POWEROFF")==0) {
457 // turn off transmitter/demod
458 sprintf(response,"RSP POWEROFF 0");
459 }
460 else if (strcmp(command,"POWERON")==0) {
461 // turn on transmitter/demod
462 if (!mTxFreq || !mRxFreq)
463 sprintf(response,"RSP POWERON 1");
464 else {
465 sprintf(response,"RSP POWERON 0");
466 if (!mOn) {
467 // Prepare for thread start
468 mPower = -20;
469 mRadioInterface->start();
dburgessb3a0ca42011-10-12 07:44:40 +0000470
471 // Start radio interface threads.
Thomas Tsou92c16df2013-09-28 18:04:19 -0400472 mTxServiceLoopThread->start((void * (*)(void*))TxServiceLoopAdapter,(void*) this);
473 mRxServiceLoopThread->start((void * (*)(void*))RxServiceLoopAdapter,(void*) this);
dburgessb3a0ca42011-10-12 07:44:40 +0000474 mTransmitPriorityQueueServiceLoopThread->start((void * (*)(void*))TransmitPriorityQueueServiceLoopAdapter,(void*) this);
475 writeClockInterface();
476
477 mOn = true;
478 }
479 }
480 }
481 else if (strcmp(command,"SETMAXDLY")==0) {
482 //set expected maximum time-of-arrival
483 int maxDelay;
484 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
485 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
486 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
487 }
488 else if (strcmp(command,"SETRXGAIN")==0) {
489 //set expected maximum time-of-arrival
490 int newGain;
491 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
492 newGain = mRadioInterface->setRxGain(newGain);
493 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
494 }
495 else if (strcmp(command,"NOISELEV")==0) {
496 if (mOn) {
497 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400498 (int) round(20.0*log10(rxFullScale/mNoiseLev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000499 }
500 else {
501 sprintf(response,"RSP NOISELEV 1 0");
502 }
503 }
504 else if (strcmp(command,"SETPOWER")==0) {
505 // set output power in dB
506 int dbPwr;
507 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr);
508 if (!mOn)
509 sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
510 else {
511 mPower = dbPwr;
kurtis.heimerl58d6a012011-11-26 03:17:38 +0000512 mRadioInterface->setPowerAttenuation(dbPwr);
dburgessb3a0ca42011-10-12 07:44:40 +0000513 sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
514 }
515 }
516 else if (strcmp(command,"ADJPOWER")==0) {
517 // adjust power in dB steps
518 int dbStep;
519 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep);
520 if (!mOn)
521 sprintf(response,"RSP ADJPOWER 1 %d",mPower);
522 else {
523 mPower += dbStep;
524 sprintf(response,"RSP ADJPOWER 0 %d",mPower);
525 }
526 }
527#define FREQOFFSET 0//11.2e3
528 else if (strcmp(command,"RXTUNE")==0) {
529 // tune receiver
530 int freqKhz;
531 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
532 mRxFreq = freqKhz*1.0e3+FREQOFFSET;
533 if (!mRadioInterface->tuneRx(mRxFreq)) {
534 LOG(ALERT) << "RX failed to tune";
535 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
536 }
537 else
538 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
539 }
540 else if (strcmp(command,"TXTUNE")==0) {
541 // tune txmtr
542 int freqKhz;
543 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
544 //freqKhz = 890e3;
545 mTxFreq = freqKhz*1.0e3+FREQOFFSET;
546 if (!mRadioInterface->tuneTx(mTxFreq)) {
547 LOG(ALERT) << "TX failed to tune";
548 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
549 }
550 else
551 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
552 }
553 else if (strcmp(command,"SETTSC")==0) {
554 // set TSC
555 int TSC;
556 sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC);
557 if (mOn)
558 sprintf(response,"RSP SETTSC 1 %d",TSC);
559 else {
560 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400561 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400562 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000563 }
564 }
565 else if (strcmp(command,"SETSLOT")==0) {
566 // set TSC
567 int corrCode;
568 int timeslot;
569 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
570 if ((timeslot < 0) || (timeslot > 7)) {
571 LOG(WARNING) << "bogus message on control interface";
572 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
573 return;
574 }
575 mChanType[timeslot] = (ChannelCombination) corrCode;
576 setModulus(timeslot);
577 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
578
579 }
580 else {
581 LOG(WARNING) << "bogus command " << command << " on control interface.";
582 }
583
584 mControlSocket.write(response,strlen(response)+1);
585
586}
587
588bool Transceiver::driveTransmitPriorityQueue()
589{
590
591 char buffer[gSlotLen+50];
592
593 // check data socket
594 size_t msgLen = mDataSocket.read(buffer);
595
596 if (msgLen!=gSlotLen+1+4+1) {
597 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
598 return false;
599 }
600
601 int timeSlot = (int) buffer[0];
602 uint64_t frameNum = 0;
603 for (int i = 0; i < 4; i++)
604 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
605
606 /*
607 if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) {
608 // stale burst
609 //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot);
610 //writeClockInterface();
611 }*/
612
613/*
614 DAB -- Just let these go through the demod.
615 if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) {
616 // stale burst from GSM core
617 LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot);
618 return false;
619 }
620*/
621
622 // periodically update GSM core clock
623 LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
624 << " mLastClockUpdateTime " << mLastClockUpdateTime;
625 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
626 writeClockInterface();
627
628
629 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
630
631 int RSSI = (int) buffer[5];
632 static BitVector newBurst(gSlotLen);
633 BitVector::iterator itr = newBurst.begin();
634 char *bufferItr = buffer+6;
635 while (itr < newBurst.end())
636 *itr++ = *bufferItr++;
637
638 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
639
640 addRadioVector(newBurst,RSSI,currTime);
641
642 LOG(DEBUG) "added burst - time: " << currTime << ", RSSI: " << RSSI; // << ", data: " << newBurst;
643
644 return true;
645
646
647}
648
649void Transceiver::driveReceiveFIFO()
650{
651
652 SoftVector *rxBurst = NULL;
653 int RSSI;
654 int TOA; // in 1/256 of a symbol
655 GSM::Time burstTime;
656
657 mRadioInterface->driveReceiveRadio();
658
659 rxBurst = pullRadioVector(burstTime,RSSI,TOA);
660
661 if (rxBurst) {
662
663 LOG(DEBUG) << "burst parameters: "
664 << " time: " << burstTime
665 << " RSSI: " << RSSI
666 << " TOA: " << TOA
667 << " bits: " << *rxBurst;
668
669 char burstString[gSlotLen+10];
670 burstString[0] = burstTime.TN();
671 for (int i = 0; i < 4; i++)
672 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
673 burstString[5] = RSSI;
674 burstString[6] = (TOA >> 8) & 0x0ff;
675 burstString[7] = TOA & 0x0ff;
676 SoftVector::iterator burstItr = rxBurst->begin();
677
678 for (unsigned int i = 0; i < gSlotLen; i++) {
679 burstString[8+i] =(char) round((*burstItr++)*255.0);
680 }
681 burstString[gSlotLen+9] = '\0';
682 delete rxBurst;
683
684 mDataSocket.write(burstString,gSlotLen+10);
685 }
686
687}
688
689void Transceiver::driveTransmitFIFO()
690{
691
692 /**
693 Features a carefully controlled latency mechanism, to
694 assure that transmit packets arrive at the radio/USRP
695 before they need to be transmitted.
696
697 Deadline clock indicates the burst that needs to be
698 pushed into the FIFO right NOW. If transmit queue does
699 not have a burst, stick in filler data.
700 */
701
702
703 RadioClock *radioClock = (mRadioInterface->getClock());
704
705 if (mOn) {
706 //radioClock->wait(); // wait until clock updates
707 LOG(DEBUG) << "radio clock " << radioClock->get();
708 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
709 // if underrun, then we're not providing bursts to radio/USRP fast
710 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400711 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000712 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000713 // only update latency at the defined frame interval
714 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000715 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
716 LOG(INFO) << "new latency: " << mTransmitLatency;
717 mLatencyUpdateTime = radioClock->get();
718 }
719 }
720 else {
721 // if underrun hasn't occurred in the last sec (216 frames) drop
722 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000723 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000724 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
725 mTransmitLatency.decTN();
726 LOG(INFO) << "reduced latency: " << mTransmitLatency;
727 mLatencyUpdateTime = radioClock->get();
728 }
729 }
730 }
dburgessb3a0ca42011-10-12 07:44:40 +0000731 }
dburgessb3a0ca42011-10-12 07:44:40 +0000732 // time to push burst to transmit FIFO
733 pushRadioVector(mTransmitDeadlineClock);
734 mTransmitDeadlineClock.incTN();
735 }
dburgessb3a0ca42011-10-12 07:44:40 +0000736 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400737
738 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000739}
740
741
742
743void Transceiver::writeClockInterface()
744{
745 char command[50];
746 // FIXME -- This should be adaptive.
747 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
748
749 LOG(INFO) << "ClockInterface: sending " << command;
750
751 mClockSocket.write(command,strlen(command)+1);
752
753 mLastClockUpdateTime = mTransmitDeadlineClock;
754
Thomas Tsou92c16df2013-09-28 18:04:19 -0400755}
dburgessb3a0ca42011-10-12 07:44:40 +0000756
Thomas Tsou92c16df2013-09-28 18:04:19 -0400757void *RxServiceLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +0000758{
kurtis.heimerl6b495a52011-11-26 03:17:21 +0000759 transceiver->setPriority();
760
dburgessb3a0ca42011-10-12 07:44:40 +0000761 while (1) {
762 transceiver->driveReceiveFIFO();
Thomas Tsou92c16df2013-09-28 18:04:19 -0400763 pthread_testcancel();
764 }
765 return NULL;
766}
767
768void *TxServiceLoopAdapter(Transceiver *transceiver)
769{
770 while (1) {
dburgessb3a0ca42011-10-12 07:44:40 +0000771 transceiver->driveTransmitFIFO();
772 pthread_testcancel();
773 }
774 return NULL;
775}
776
777void *ControlServiceLoopAdapter(Transceiver *transceiver)
778{
779 while (1) {
780 transceiver->driveControl();
781 pthread_testcancel();
782 }
783 return NULL;
784}
785
786void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *transceiver)
787{
788 while (1) {
789 bool stale = false;
790 // Flush the UDP packets until a successful transfer.
791 while (!transceiver->driveTransmitPriorityQueue()) {
792 stale = true;
793 }
794 if (stale) {
795 // If a packet was stale, remind the GSM stack of the clock.
796 transceiver->writeClockInterface();
797 }
798 pthread_testcancel();
799 }
800 return NULL;
801}