blob: fd6a00897dac9047c0006f46c0621ab29e9cedce [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
Thomas Tsouf0782732013-10-29 15:55:47 -040045TransceiverState::TransceiverState()
46{
47 for (int i = 0; i < 8; i++) {
48 chanType[i] = Transceiver::NONE;
49 fillerModulus[i] = 26;
50 chanResponse[i] = NULL;
51 DFEForward[i] = NULL;
52 DFEFeedback[i] = NULL;
53
54 for (int n = 0; n < 102; n++)
55 fillerTable[n][i] = NULL;
56 }
57}
58
59TransceiverState::~TransceiverState()
60{
61 for (int i = 0; i < 8; i++) {
62 delete chanResponse[i];
63 delete DFEForward[i];
64 delete DFEFeedback[i];
65
66 for (int n = 0; n < 102; n++)
67 delete fillerTable[n][i];
68 }
69}
70
71void TransceiverState::init(size_t slot, signalVector *burst)
72{
73 for (int i = 0; i < 102; i++)
74 fillerTable[i][slot] = new signalVector(*burst);
75}
76
dburgessb3a0ca42011-10-12 07:44:40 +000077Transceiver::Transceiver(int wBasePort,
78 const char *TRXAddress,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -040079 int wSPS,
dburgessb3a0ca42011-10-12 07:44:40 +000080 GSM::Time wTransmitLatency,
81 RadioInterface *wRadioInterface)
Thomas Tsoud647ec52013-10-29 15:17:34 -040082 : mBasePort(wBasePort), mAddr(TRXAddress),
83 mDataSocket(NULL), mCtrlSocket(NULL), mClockSocket(NULL),
84 mSPSTx(wSPS), mSPSRx(1), mNoises(NOISE_CNT)
dburgessb3a0ca42011-10-12 07:44:40 +000085{
dburgessb3a0ca42011-10-12 07:44:40 +000086 GSM::Time startTime(random() % gHyperframe,0);
87
Thomas Tsou92c16df2013-09-28 18:04:19 -040088 mRxServiceLoopThread = new Thread(32768);
89 mTxServiceLoopThread = new Thread(32768);
dburgessb3a0ca42011-10-12 07:44:40 +000090 mControlServiceLoopThread = new Thread(32768); ///< thread to process control messages from GSM core
91 mTransmitPriorityQueueServiceLoopThread = new Thread(32768);///< thread to process transmit bursts from GSM core
92
dburgessb3a0ca42011-10-12 07:44:40 +000093 mRadioInterface = wRadioInterface;
94 mTransmitLatency = wTransmitLatency;
95 mTransmitDeadlineClock = startTime;
96 mLastClockUpdateTime = startTime;
97 mLatencyUpdateTime = startTime;
98 mRadioInterface->getClock()->set(startTime);
99 mMaxExpectedDelay = 0;
100
dburgessb3a0ca42011-10-12 07:44:40 +0000101 txFullScale = mRadioInterface->fullScaleInputValue();
102 rxFullScale = mRadioInterface->fullScaleOutputValue();
103
dburgessb3a0ca42011-10-12 07:44:40 +0000104 mOn = false;
105 mTxFreq = 0.0;
106 mRxFreq = 0.0;
107 mPower = -10;
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400108 mNoiseLev = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +0000109}
110
111Transceiver::~Transceiver()
112{
dburgessb3a0ca42011-10-12 07:44:40 +0000113 sigProcLibDestroy();
114 mTransmitPriorityQueue.clear();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400115
116 delete mClockSocket;
117 delete mCtrlSocket;
118 delete mDataSocket;
dburgessb3a0ca42011-10-12 07:44:40 +0000119}
Thomas Tsou83e06892013-08-20 16:10:01 -0400120
121bool Transceiver::init()
122{
Thomas Tsouf0782732013-10-29 15:55:47 -0400123 signalVector *burst;
124
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400125 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400126 LOG(ALERT) << "Failed to initialize signal processing library";
127 return false;
128 }
129
Thomas Tsoud647ec52013-10-29 15:17:34 -0400130 mClockSocket = new UDPSocket(mBasePort, mAddr.c_str(), mBasePort + 100);
131 mCtrlSocket = new UDPSocket(mBasePort + 1, mAddr.c_str(), mBasePort + 101);
132 mDataSocket = new UDPSocket(mBasePort + 2, mAddr.c_str(), mBasePort + 102);
133
Thomas Tsouf0782732013-10-29 15:55:47 -0400134 for (size_t n = 0; n < 8; n++) {
135 burst = modulateBurst(gDummyBurst, 8 + (n % 4 == 0), mSPSTx);
136 scaleVector(*burst, txFullScale);
137 mState.init(n, burst);
138 mState.chanEstimateTime[n] = mTransmitDeadlineClock;
Thomas Tsou83e06892013-08-20 16:10:01 -0400139
Thomas Tsouf0782732013-10-29 15:55:47 -0400140 delete burst;
Thomas Tsou83e06892013-08-20 16:10:01 -0400141 }
142
143 return true;
144}
dburgessb3a0ca42011-10-12 07:44:40 +0000145
146void Transceiver::addRadioVector(BitVector &burst,
147 int RSSI,
148 GSM::Time &wTime)
149{
150 // modulate and stick into queue
Thomas Tsou83e06892013-08-20 16:10:01 -0400151 signalVector* modBurst = modulateBurst(burst,
dburgessb3a0ca42011-10-12 07:44:40 +0000152 8 + (wTime.TN() % 4 == 0),
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400153 mSPSTx);
dburgessb3a0ca42011-10-12 07:44:40 +0000154 scaleVector(*modBurst,txFullScale * pow(10,-RSSI/10));
155 radioVector *newVec = new radioVector(*modBurst,wTime);
156 mTransmitPriorityQueue.write(newVec);
157
158 delete modBurst;
159}
160
dburgessb3a0ca42011-10-12 07:44:40 +0000161void Transceiver::pushRadioVector(GSM::Time &nowTime)
162{
163
164 // dump stale bursts, if any
165 while (radioVector* staleBurst = mTransmitPriorityQueue.getStaleBurst(nowTime)) {
166 // Even if the burst is stale, put it in the fillter table.
167 // (It might be an idle pattern.)
168 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
kurtis.heimerl06286132011-11-26 03:18:43 +0000169 const GSM::Time& nextTime = staleBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000170 int TN = nextTime.TN();
Thomas Tsouf0782732013-10-29 15:55:47 -0400171 int modFN = nextTime.FN() % mState.fillerModulus[TN];
172 delete mState.fillerTable[modFN][TN];
173 mState.fillerTable[modFN][TN] = staleBurst;
dburgessb3a0ca42011-10-12 07:44:40 +0000174 }
175
176 int TN = nowTime.TN();
Thomas Tsouf0782732013-10-29 15:55:47 -0400177 int modFN = nowTime.FN() % mState.fillerModulus[nowTime.TN()];
dburgessb3a0ca42011-10-12 07:44:40 +0000178
179 // if queue contains data at the desired timestamp, stick it into FIFO
180 if (radioVector *next = (radioVector*) mTransmitPriorityQueue.getCurrentBurst(nowTime)) {
181 LOG(DEBUG) << "transmitFIFO: wrote burst " << next << " at time: " << nowTime;
Thomas Tsouf0782732013-10-29 15:55:47 -0400182 delete mState.fillerTable[modFN][TN];
183 mState.fillerTable[modFN][TN] = new signalVector(*(next));
184 mRadioInterface->driveTransmitRadio(*(next), mState.chanType[TN] == NONE);
dburgessb3a0ca42011-10-12 07:44:40 +0000185 delete next;
dburgessb3a0ca42011-10-12 07:44:40 +0000186 return;
187 }
188
189 // otherwise, pull filler data, and push to radio FIFO
Thomas Tsouf0782732013-10-29 15:55:47 -0400190 mRadioInterface->driveTransmitRadio(*(mState.fillerTable[modFN][TN]),
191 mState.chanType[TN]==NONE);
dburgessb3a0ca42011-10-12 07:44:40 +0000192}
193
194void Transceiver::setModulus(int timeslot)
195{
Thomas Tsouf0782732013-10-29 15:55:47 -0400196 switch (mState.chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000197 case NONE:
198 case I:
199 case II:
200 case III:
201 case FILL:
Thomas Tsouf0782732013-10-29 15:55:47 -0400202 mState.fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000203 break;
204 case IV:
205 case VI:
206 case V:
Thomas Tsouf0782732013-10-29 15:55:47 -0400207 mState.fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000208 break;
209 //case V:
210 case VII:
Thomas Tsouf0782732013-10-29 15:55:47 -0400211 mState.fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000212 break;
ttsoufc40a842013-06-09 22:38:18 +0000213 case XIII:
Thomas Tsouf0782732013-10-29 15:55:47 -0400214 mState.fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000215 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000216 default:
217 break;
218 }
219}
220
221
222Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime)
223{
224
225 unsigned burstTN = currTime.TN();
226 unsigned burstFN = currTime.FN();
227
Thomas Tsouf0782732013-10-29 15:55:47 -0400228 switch (mState.chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000229 case NONE:
230 return OFF;
231 break;
232 case FILL:
233 return IDLE;
234 break;
235 case I:
236 return TSC;
237 /*if (burstFN % 26 == 25)
238 return IDLE;
239 else
240 return TSC;*/
241 break;
242 case II:
ttsou20642972013-03-27 22:00:25 +0000243 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000244 break;
245 case III:
246 return TSC;
247 break;
248 case IV:
249 case VI:
250 return RACH;
251 break;
252 case V: {
253 int mod51 = burstFN % 51;
254 if ((mod51 <= 36) && (mod51 >= 14))
255 return RACH;
256 else if ((mod51 == 4) || (mod51 == 5))
257 return RACH;
258 else if ((mod51 == 45) || (mod51 == 46))
259 return RACH;
260 else
261 return TSC;
262 break;
263 }
264 case VII:
265 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
266 return IDLE;
267 else
268 return TSC;
269 break;
ttsoufc40a842013-06-09 22:38:18 +0000270 case XIII: {
271 int mod52 = burstFN % 52;
272 if ((mod52 == 12) || (mod52 == 38))
273 return RACH;
274 else if ((mod52 == 25) || (mod52 == 51))
275 return IDLE;
276 else
277 return TSC;
278 break;
279 }
dburgessb3a0ca42011-10-12 07:44:40 +0000280 case LOOPBACK:
281 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
282 return IDLE;
283 else
284 return TSC;
285 break;
286 default:
287 return OFF;
288 break;
289 }
290
291}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400292
dburgessb3a0ca42011-10-12 07:44:40 +0000293SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
294 int &RSSI,
295 int &timingOffset)
296{
Thomas Tsouf0782732013-10-29 15:55:47 -0400297 bool needDFE = false, success = false, estimateChannel = false;
298 complex amp = 0.0;
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400299 float TOA = 0.0, avg = 0.0;
Thomas Tsouf0782732013-10-29 15:55:47 -0400300 signalVector *chanResponse;
dburgessb3a0ca42011-10-12 07:44:40 +0000301
302 radioVector *rxBurst = (radioVector *) mReceiveFIFO->get();
303
304 if (!rxBurst) return NULL;
305
kurtis.heimerl06286132011-11-26 03:18:43 +0000306 int timeslot = rxBurst->getTime().TN();
dburgessb3a0ca42011-10-12 07:44:40 +0000307
kurtis.heimerl06286132011-11-26 03:18:43 +0000308 CorrType corrType = expectedCorrType(rxBurst->getTime());
dburgessb3a0ca42011-10-12 07:44:40 +0000309
310 if ((corrType==OFF) || (corrType==IDLE)) {
311 delete rxBurst;
312 return NULL;
313 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000314
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400315 signalVector *vectorBurst = rxBurst;
316
317 energyDetect(*vectorBurst, 20 * mSPSRx, 0.0, &avg);
318
319 // Update noise level
320 mNoiseLev = mNoises.avg();
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400321 avg = sqrt(avg);
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400322
dburgessb3a0ca42011-10-12 07:44:40 +0000323 // run the proper correlator
dburgessb3a0ca42011-10-12 07:44:40 +0000324 if (corrType==TSC) {
kurtis.heimerl06286132011-11-26 03:18:43 +0000325 LOG(DEBUG) << "looking for TSC at time: " << rxBurst->getTime();
Thomas Tsouf0782732013-10-29 15:55:47 -0400326 double framesElapsed = rxBurst->getTime() - mState.chanEstimateTime[timeslot];
327 if ((framesElapsed > 50) || (!mState.chanResponse[timeslot])) {
328 delete mState.chanResponse[timeslot];
329 delete mState.DFEForward[timeslot];
330 delete mState.DFEFeedback[timeslot];
331
332 mState.chanResponse[timeslot] = NULL;
333 mState.DFEForward[timeslot] = NULL;
334 mState.DFEFeedback[timeslot] = NULL;
335
336 if (needDFE)
337 estimateChannel = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000338 }
Thomas Tsouf0782732013-10-29 15:55:47 -0400339
dburgessb3a0ca42011-10-12 07:44:40 +0000340 float chanOffset;
341 success = analyzeTrafficBurst(*vectorBurst,
342 mTSC,
Thomas Tsou865bca42013-08-21 20:58:00 -0400343 5.0,
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400344 mSPSRx,
Thomas Tsouf0782732013-10-29 15:55:47 -0400345 &amp,
dburgessb3a0ca42011-10-12 07:44:40 +0000346 &TOA,
347 mMaxExpectedDelay,
348 estimateChannel,
Thomas Tsouf0782732013-10-29 15:55:47 -0400349 &chanResponse,
dburgessb3a0ca42011-10-12 07:44:40 +0000350 &chanOffset);
351 if (success) {
Thomas Tsouf0782732013-10-29 15:55:47 -0400352 mState.SNRestimate[timeslot] = amp.norm2() / (mNoiseLev * mNoiseLev+1.0);
dburgessb3a0ca42011-10-12 07:44:40 +0000353 if (estimateChannel) {
Thomas Tsouf0782732013-10-29 15:55:47 -0400354 mState.chanResponse[timeslot] = chanResponse;
355 mState.chanRespOffset[timeslot] = chanOffset;
356 mState.chanRespAmplitude[timeslot] = amp;
357 scaleVector(*chanResponse, complex(1.0,0.0) / amp);
358
359 designDFE(*chanResponse, mState.SNRestimate[timeslot], 7,
360 &mState.DFEForward[timeslot],
361 &mState.DFEFeedback[timeslot]);
362
363 mState.chanEstimateTime[timeslot] = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000364 }
365 }
366 else {
Thomas Tsouf0782732013-10-29 15:55:47 -0400367 mState.chanResponse[timeslot] = NULL;
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400368 mNoises.insert(avg);
dburgessb3a0ca42011-10-12 07:44:40 +0000369 }
370 }
371 else {
372 // RACH burst
Thomas Tsouf0782732013-10-29 15:55:47 -0400373 if (success = detectRACHBurst(*vectorBurst, 6.0, mSPSRx, &amp, &TOA))
374 mState.chanResponse[timeslot] = NULL;
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400375 else
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400376 mNoises.insert(avg);
dburgessb3a0ca42011-10-12 07:44:40 +0000377 }
dburgessb3a0ca42011-10-12 07:44:40 +0000378
379 // demodulate burst
380 SoftVector *burst = NULL;
381 if ((rxBurst) && (success)) {
382 if ((corrType==RACH) || (!needDFE)) {
Thomas Tsouf0782732013-10-29 15:55:47 -0400383 burst = demodulateBurst(*vectorBurst, mSPSRx, amp, TOA);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400384 } else {
Thomas Tsouf0782732013-10-29 15:55:47 -0400385 scaleVector(*vectorBurst,complex(1.0,0.0) / amp);
dburgessb3a0ca42011-10-12 07:44:40 +0000386 burst = equalizeBurst(*vectorBurst,
Thomas Tsouf0782732013-10-29 15:55:47 -0400387 TOA - mState.chanRespOffset[timeslot],
388 mSPSRx,
389 *mState.DFEForward[timeslot],
390 *mState.DFEFeedback[timeslot]);
dburgessb3a0ca42011-10-12 07:44:40 +0000391 }
kurtis.heimerl06286132011-11-26 03:18:43 +0000392 wTime = rxBurst->getTime();
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400393 RSSI = (int) floor(20.0*log10(rxFullScale/avg));
dburgessb3a0ca42011-10-12 07:44:40 +0000394 LOG(DEBUG) << "RSSI: " << RSSI;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400395 timingOffset = (int) round(TOA * 256.0 / mSPSRx);
dburgessb3a0ca42011-10-12 07:44:40 +0000396 }
397
398 //if (burst) LOG(DEBUG) << "burst: " << *burst << '\n';
399
400 delete rxBurst;
401
402 return burst;
403}
404
405void Transceiver::start()
406{
407 mControlServiceLoopThread->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) this);
408}
409
410void Transceiver::reset()
411{
412 mTransmitPriorityQueue.clear();
413 //mTransmitFIFO->clear();
414 //mReceiveFIFO->clear();
415}
416
417
418void Transceiver::driveControl()
419{
420
421 int MAX_PACKET_LENGTH = 100;
422
423 // check control socket
424 char buffer[MAX_PACKET_LENGTH];
425 int msgLen = -1;
426 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400427
428 msgLen = mCtrlSocket->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000429
430 if (msgLen < 1) {
431 return;
432 }
433
434 char cmdcheck[4];
435 char command[MAX_PACKET_LENGTH];
436 char response[MAX_PACKET_LENGTH];
437
438 sscanf(buffer,"%3s %s",cmdcheck,command);
439
440 writeClockInterface();
441
442 if (strcmp(cmdcheck,"CMD")!=0) {
443 LOG(WARNING) << "bogus message on control interface";
444 return;
445 }
446 LOG(INFO) << "command is " << buffer;
447
448 if (strcmp(command,"POWEROFF")==0) {
449 // turn off transmitter/demod
450 sprintf(response,"RSP POWEROFF 0");
451 }
452 else if (strcmp(command,"POWERON")==0) {
453 // turn on transmitter/demod
454 if (!mTxFreq || !mRxFreq)
455 sprintf(response,"RSP POWERON 1");
456 else {
457 sprintf(response,"RSP POWERON 0");
458 if (!mOn) {
459 // Prepare for thread start
460 mPower = -20;
461 mRadioInterface->start();
dburgessb3a0ca42011-10-12 07:44:40 +0000462
463 // Start radio interface threads.
Thomas Tsou92c16df2013-09-28 18:04:19 -0400464 mTxServiceLoopThread->start((void * (*)(void*))TxServiceLoopAdapter,(void*) this);
465 mRxServiceLoopThread->start((void * (*)(void*))RxServiceLoopAdapter,(void*) this);
dburgessb3a0ca42011-10-12 07:44:40 +0000466 mTransmitPriorityQueueServiceLoopThread->start((void * (*)(void*))TransmitPriorityQueueServiceLoopAdapter,(void*) this);
467 writeClockInterface();
468
469 mOn = true;
470 }
471 }
472 }
473 else if (strcmp(command,"SETMAXDLY")==0) {
474 //set expected maximum time-of-arrival
475 int maxDelay;
476 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
477 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
478 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
479 }
480 else if (strcmp(command,"SETRXGAIN")==0) {
481 //set expected maximum time-of-arrival
482 int newGain;
483 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
484 newGain = mRadioInterface->setRxGain(newGain);
485 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
486 }
487 else if (strcmp(command,"NOISELEV")==0) {
488 if (mOn) {
489 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400490 (int) round(20.0*log10(rxFullScale/mNoiseLev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000491 }
492 else {
493 sprintf(response,"RSP NOISELEV 1 0");
494 }
495 }
496 else if (strcmp(command,"SETPOWER")==0) {
497 // set output power in dB
498 int dbPwr;
499 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr);
500 if (!mOn)
501 sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
502 else {
503 mPower = dbPwr;
kurtis.heimerl58d6a012011-11-26 03:17:38 +0000504 mRadioInterface->setPowerAttenuation(dbPwr);
dburgessb3a0ca42011-10-12 07:44:40 +0000505 sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
506 }
507 }
508 else if (strcmp(command,"ADJPOWER")==0) {
509 // adjust power in dB steps
510 int dbStep;
511 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep);
512 if (!mOn)
513 sprintf(response,"RSP ADJPOWER 1 %d",mPower);
514 else {
515 mPower += dbStep;
516 sprintf(response,"RSP ADJPOWER 0 %d",mPower);
517 }
518 }
519#define FREQOFFSET 0//11.2e3
520 else if (strcmp(command,"RXTUNE")==0) {
521 // tune receiver
522 int freqKhz;
523 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
524 mRxFreq = freqKhz*1.0e3+FREQOFFSET;
525 if (!mRadioInterface->tuneRx(mRxFreq)) {
526 LOG(ALERT) << "RX failed to tune";
527 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
528 }
529 else
530 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
531 }
532 else if (strcmp(command,"TXTUNE")==0) {
533 // tune txmtr
534 int freqKhz;
535 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
536 //freqKhz = 890e3;
537 mTxFreq = freqKhz*1.0e3+FREQOFFSET;
538 if (!mRadioInterface->tuneTx(mTxFreq)) {
539 LOG(ALERT) << "TX failed to tune";
540 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
541 }
542 else
543 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
544 }
545 else if (strcmp(command,"SETTSC")==0) {
546 // set TSC
547 int TSC;
548 sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC);
549 if (mOn)
550 sprintf(response,"RSP SETTSC 1 %d",TSC);
551 else {
552 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400553 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400554 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000555 }
556 }
557 else if (strcmp(command,"SETSLOT")==0) {
558 // set TSC
559 int corrCode;
560 int timeslot;
561 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
562 if ((timeslot < 0) || (timeslot > 7)) {
563 LOG(WARNING) << "bogus message on control interface";
564 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
565 return;
566 }
Thomas Tsouf0782732013-10-29 15:55:47 -0400567 mState.chanType[timeslot] = corrCode;
dburgessb3a0ca42011-10-12 07:44:40 +0000568 setModulus(timeslot);
569 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
570
571 }
572 else {
573 LOG(WARNING) << "bogus command " << command << " on control interface.";
574 }
575
Thomas Tsoud647ec52013-10-29 15:17:34 -0400576 mCtrlSocket->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000577}
578
579bool Transceiver::driveTransmitPriorityQueue()
580{
581
582 char buffer[gSlotLen+50];
583
584 // check data socket
Thomas Tsoud647ec52013-10-29 15:17:34 -0400585 size_t msgLen = mDataSocket->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000586
587 if (msgLen!=gSlotLen+1+4+1) {
588 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
589 return false;
590 }
591
592 int timeSlot = (int) buffer[0];
593 uint64_t frameNum = 0;
594 for (int i = 0; i < 4; i++)
595 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
596
597 /*
598 if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) {
599 // stale burst
600 //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot);
601 //writeClockInterface();
602 }*/
603
604/*
605 DAB -- Just let these go through the demod.
606 if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) {
607 // stale burst from GSM core
608 LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot);
609 return false;
610 }
611*/
612
613 // periodically update GSM core clock
614 LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
615 << " mLastClockUpdateTime " << mLastClockUpdateTime;
616 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
617 writeClockInterface();
618
619
620 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
621
622 int RSSI = (int) buffer[5];
623 static BitVector newBurst(gSlotLen);
624 BitVector::iterator itr = newBurst.begin();
625 char *bufferItr = buffer+6;
626 while (itr < newBurst.end())
627 *itr++ = *bufferItr++;
628
629 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
630
631 addRadioVector(newBurst,RSSI,currTime);
632
633 LOG(DEBUG) "added burst - time: " << currTime << ", RSSI: " << RSSI; // << ", data: " << newBurst;
634
635 return true;
636
637
638}
639
640void Transceiver::driveReceiveFIFO()
641{
642
643 SoftVector *rxBurst = NULL;
644 int RSSI;
645 int TOA; // in 1/256 of a symbol
646 GSM::Time burstTime;
647
648 mRadioInterface->driveReceiveRadio();
649
650 rxBurst = pullRadioVector(burstTime,RSSI,TOA);
651
652 if (rxBurst) {
653
654 LOG(DEBUG) << "burst parameters: "
655 << " time: " << burstTime
656 << " RSSI: " << RSSI
657 << " TOA: " << TOA
658 << " bits: " << *rxBurst;
659
660 char burstString[gSlotLen+10];
661 burstString[0] = burstTime.TN();
662 for (int i = 0; i < 4; i++)
663 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
664 burstString[5] = RSSI;
665 burstString[6] = (TOA >> 8) & 0x0ff;
666 burstString[7] = TOA & 0x0ff;
667 SoftVector::iterator burstItr = rxBurst->begin();
668
669 for (unsigned int i = 0; i < gSlotLen; i++) {
670 burstString[8+i] =(char) round((*burstItr++)*255.0);
671 }
672 burstString[gSlotLen+9] = '\0';
673 delete rxBurst;
674
Thomas Tsoud647ec52013-10-29 15:17:34 -0400675 mDataSocket->write(burstString, gSlotLen + 10);
dburgessb3a0ca42011-10-12 07:44:40 +0000676 }
dburgessb3a0ca42011-10-12 07:44:40 +0000677}
678
679void Transceiver::driveTransmitFIFO()
680{
681
682 /**
683 Features a carefully controlled latency mechanism, to
684 assure that transmit packets arrive at the radio/USRP
685 before they need to be transmitted.
686
687 Deadline clock indicates the burst that needs to be
688 pushed into the FIFO right NOW. If transmit queue does
689 not have a burst, stick in filler data.
690 */
691
692
693 RadioClock *radioClock = (mRadioInterface->getClock());
694
695 if (mOn) {
696 //radioClock->wait(); // wait until clock updates
697 LOG(DEBUG) << "radio clock " << radioClock->get();
698 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
699 // if underrun, then we're not providing bursts to radio/USRP fast
700 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400701 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000702 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000703 // only update latency at the defined frame interval
704 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000705 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
706 LOG(INFO) << "new latency: " << mTransmitLatency;
707 mLatencyUpdateTime = radioClock->get();
708 }
709 }
710 else {
711 // if underrun hasn't occurred in the last sec (216 frames) drop
712 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000713 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000714 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
715 mTransmitLatency.decTN();
716 LOG(INFO) << "reduced latency: " << mTransmitLatency;
717 mLatencyUpdateTime = radioClock->get();
718 }
719 }
720 }
dburgessb3a0ca42011-10-12 07:44:40 +0000721 }
dburgessb3a0ca42011-10-12 07:44:40 +0000722 // time to push burst to transmit FIFO
723 pushRadioVector(mTransmitDeadlineClock);
724 mTransmitDeadlineClock.incTN();
725 }
dburgessb3a0ca42011-10-12 07:44:40 +0000726 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400727
728 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000729}
730
731
732
733void Transceiver::writeClockInterface()
734{
735 char command[50];
736 // FIXME -- This should be adaptive.
737 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
738
739 LOG(INFO) << "ClockInterface: sending " << command;
740
Thomas Tsoud647ec52013-10-29 15:17:34 -0400741 mClockSocket->write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000742
743 mLastClockUpdateTime = mTransmitDeadlineClock;
744
Thomas Tsou92c16df2013-09-28 18:04:19 -0400745}
dburgessb3a0ca42011-10-12 07:44:40 +0000746
Thomas Tsou92c16df2013-09-28 18:04:19 -0400747void *RxServiceLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +0000748{
kurtis.heimerl6b495a52011-11-26 03:17:21 +0000749 transceiver->setPriority();
750
dburgessb3a0ca42011-10-12 07:44:40 +0000751 while (1) {
752 transceiver->driveReceiveFIFO();
Thomas Tsou92c16df2013-09-28 18:04:19 -0400753 pthread_testcancel();
754 }
755 return NULL;
756}
757
758void *TxServiceLoopAdapter(Transceiver *transceiver)
759{
760 while (1) {
dburgessb3a0ca42011-10-12 07:44:40 +0000761 transceiver->driveTransmitFIFO();
762 pthread_testcancel();
763 }
764 return NULL;
765}
766
767void *ControlServiceLoopAdapter(Transceiver *transceiver)
768{
769 while (1) {
770 transceiver->driveControl();
771 pthread_testcancel();
772 }
773 return NULL;
774}
775
776void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *transceiver)
777{
778 while (1) {
779 bool stale = false;
780 // Flush the UDP packets until a successful transfer.
781 while (!transceiver->driveTransmitPriorityQueue()) {
782 stale = true;
783 }
784 if (stale) {
785 // If a packet was stale, remind the GSM stack of the clock.
786 transceiver->writeClockInterface();
787 }
788 pthread_testcancel();
789 }
790 return NULL;
791}