blob: 6e446f3791212446cef1d65168acfc7a9d4057e6 [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 Tsou204a9f12013-10-29 18:34:16 -040079 size_t wSPS, size_t wChans,
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),
Thomas Tsou204a9f12013-10-29 18:34:16 -040083 mTransmitLatency(wTransmitLatency), mClockSocket(NULL), mRadioInterface(wRadioInterface),
84 mNoiseLev(0.0), mNoises(NOISE_CNT), mSPSTx(wSPS), mSPSRx(1), mChans(wChans),
85 mOn(false), mTxFreq(0.0), mRxFreq(0.0), mPower(-10), mMaxExpectedDelay(0)
dburgessb3a0ca42011-10-12 07:44:40 +000086{
dburgessb3a0ca42011-10-12 07:44:40 +000087 GSM::Time startTime(random() % gHyperframe,0);
88
Thomas Tsou204a9f12013-10-29 18:34:16 -040089 mRxLowerLoopThread = new Thread(32768);
90 mTxLowerLoopThread = new Thread(32768);
dburgessb3a0ca42011-10-12 07:44:40 +000091
dburgessb3a0ca42011-10-12 07:44:40 +000092 mTransmitDeadlineClock = startTime;
93 mLastClockUpdateTime = startTime;
94 mLatencyUpdateTime = startTime;
95 mRadioInterface->getClock()->set(startTime);
dburgessb3a0ca42011-10-12 07:44:40 +000096
dburgessb3a0ca42011-10-12 07:44:40 +000097 txFullScale = mRadioInterface->fullScaleInputValue();
98 rxFullScale = mRadioInterface->fullScaleOutputValue();
dburgessb3a0ca42011-10-12 07:44:40 +000099}
100
101Transceiver::~Transceiver()
102{
dburgessb3a0ca42011-10-12 07:44:40 +0000103 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400104
105 delete mClockSocket;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400106
107 for (size_t i = 0; i < mChans; i++) {
108 mTxPriorityQueues[i].clear();
109 delete mCtrlSockets[i];
110 delete mDataSockets[i];
111 }
dburgessb3a0ca42011-10-12 07:44:40 +0000112}
Thomas Tsou83e06892013-08-20 16:10:01 -0400113
114bool Transceiver::init()
115{
Thomas Tsouf0782732013-10-29 15:55:47 -0400116 signalVector *burst;
117
Thomas Tsou204a9f12013-10-29 18:34:16 -0400118 if (!mChans) {
119 LOG(ALERT) << "No channels assigned";
120 return false;
121 }
122
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400123 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400124 LOG(ALERT) << "Failed to initialize signal processing library";
125 return false;
126 }
127
Thomas Tsou204a9f12013-10-29 18:34:16 -0400128 mDataSockets.resize(mChans);
129 mCtrlSockets.resize(mChans);
130
131 mControlServiceLoopThreads.resize(mChans);
132 mTxPriorityQueueServiceLoopThreads.resize(mChans);
133 mRxServiceLoopThreads.resize(mChans);
134
135 mTxPriorityQueues.resize(mChans);
136 mReceiveFIFO.resize(mChans);
137 mStates.resize(mChans);
138
Thomas Tsoud647ec52013-10-29 15:17:34 -0400139 mClockSocket = new UDPSocket(mBasePort, mAddr.c_str(), mBasePort + 100);
Thomas Tsoud647ec52013-10-29 15:17:34 -0400140
Thomas Tsou204a9f12013-10-29 18:34:16 -0400141 for (size_t i = 0; i < mChans; i++) {
142 mDataSockets[i] = new UDPSocket(mBasePort + 2 * i + 2, mAddr.c_str(),
143 mBasePort + 2 * i + 102);
144 mCtrlSockets[i] = new UDPSocket(mBasePort + 2 * i + 1, mAddr.c_str(),
145 mBasePort + 2 * i + 101);
146 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400147
Thomas Tsou204a9f12013-10-29 18:34:16 -0400148 for (size_t i = 0; i < mChans; i++) {
149 mControlServiceLoopThreads[i] = new Thread(32768);
150 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
151 mRxServiceLoopThreads[i] = new Thread(32768);
152
153 for (size_t n = 0; n < 8; n++) {
154 burst = modulateBurst(gDummyBurst, 8 + (n % 4 == 0), mSPSTx);
155 scaleVector(*burst, txFullScale);
156 mStates[i].init(n, burst);
157 delete burst;
158 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400159 }
160
161 return true;
162}
dburgessb3a0ca42011-10-12 07:44:40 +0000163
Thomas Tsou204a9f12013-10-29 18:34:16 -0400164void Transceiver::addRadioVector(size_t chan, BitVector &burst,
165 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000166{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400167 if (chan >= mTxPriorityQueues.size()) {
168 LOG(ALERT) << "Invalid channel " << chan;
169 return;
170 }
171
dburgessb3a0ca42011-10-12 07:44:40 +0000172 // modulate and stick into queue
Thomas Tsou83e06892013-08-20 16:10:01 -0400173 signalVector* modBurst = modulateBurst(burst,
dburgessb3a0ca42011-10-12 07:44:40 +0000174 8 + (wTime.TN() % 4 == 0),
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400175 mSPSTx);
dburgessb3a0ca42011-10-12 07:44:40 +0000176 scaleVector(*modBurst,txFullScale * pow(10,-RSSI/10));
177 radioVector *newVec = new radioVector(*modBurst,wTime);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400178 mTxPriorityQueues[chan].write(newVec);
dburgessb3a0ca42011-10-12 07:44:40 +0000179
180 delete modBurst;
181}
182
dburgessb3a0ca42011-10-12 07:44:40 +0000183void Transceiver::pushRadioVector(GSM::Time &nowTime)
184{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400185 int TN, modFN;
186 radioVector *burst;
187 TransceiverState *state;
188 std::vector<signalVector *> bursts(mChans);
189 std::vector<bool> zeros(mChans);
dburgessb3a0ca42011-10-12 07:44:40 +0000190
Thomas Tsou204a9f12013-10-29 18:34:16 -0400191 for (size_t i = 0; i < mChans; i ++) {
192 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000193
Thomas Tsou204a9f12013-10-29 18:34:16 -0400194 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
195 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
196
197 TN = burst->getTime().TN();
198 modFN = burst->getTime().FN() % state->fillerModulus[TN];
199
200 delete state->fillerTable[modFN][TN];
201 state->fillerTable[modFN][TN] = burst;
202 }
203
204 TN = nowTime.TN();
205 modFN = nowTime.FN() % state->fillerModulus[TN];
206
207 bursts[i] = state->fillerTable[modFN][TN];
208 zeros[i] = state->chanType[TN] == NONE;
209
210 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
211 delete state->fillerTable[modFN][TN];
212 state->fillerTable[modFN][TN] = burst;
213 bursts[i] = burst;
214 }
dburgessb3a0ca42011-10-12 07:44:40 +0000215 }
216
Thomas Tsou204a9f12013-10-29 18:34:16 -0400217 mRadioInterface->driveTransmitRadio(bursts, zeros);
218
219 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000220}
221
Thomas Tsou204a9f12013-10-29 18:34:16 -0400222void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000223{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400224 TransceiverState *state = &mStates[chan];
225
226 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000227 case NONE:
228 case I:
229 case II:
230 case III:
231 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400232 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000233 break;
234 case IV:
235 case VI:
236 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400237 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000238 break;
239 //case V:
240 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400241 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000242 break;
ttsoufc40a842013-06-09 22:38:18 +0000243 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400244 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000245 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000246 default:
247 break;
248 }
249}
250
251
Thomas Tsou204a9f12013-10-29 18:34:16 -0400252Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
253 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000254{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400255 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000256 unsigned burstTN = currTime.TN();
257 unsigned burstFN = currTime.FN();
258
Thomas Tsou204a9f12013-10-29 18:34:16 -0400259 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000260 case NONE:
261 return OFF;
262 break;
263 case FILL:
264 return IDLE;
265 break;
266 case I:
267 return TSC;
268 /*if (burstFN % 26 == 25)
269 return IDLE;
270 else
271 return TSC;*/
272 break;
273 case II:
ttsou20642972013-03-27 22:00:25 +0000274 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000275 break;
276 case III:
277 return TSC;
278 break;
279 case IV:
280 case VI:
281 return RACH;
282 break;
283 case V: {
284 int mod51 = burstFN % 51;
285 if ((mod51 <= 36) && (mod51 >= 14))
286 return RACH;
287 else if ((mod51 == 4) || (mod51 == 5))
288 return RACH;
289 else if ((mod51 == 45) || (mod51 == 46))
290 return RACH;
291 else
292 return TSC;
293 break;
294 }
295 case VII:
296 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
297 return IDLE;
298 else
299 return TSC;
300 break;
ttsoufc40a842013-06-09 22:38:18 +0000301 case XIII: {
302 int mod52 = burstFN % 52;
303 if ((mod52 == 12) || (mod52 == 38))
304 return RACH;
305 else if ((mod52 == 25) || (mod52 == 51))
306 return IDLE;
307 else
308 return TSC;
309 break;
310 }
dburgessb3a0ca42011-10-12 07:44:40 +0000311 case LOOPBACK:
312 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
313 return IDLE;
314 else
315 return TSC;
316 break;
317 default:
318 return OFF;
319 break;
320 }
dburgessb3a0ca42011-10-12 07:44:40 +0000321}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400322
Thomas Tsou204a9f12013-10-29 18:34:16 -0400323SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
324 int &timingOffset, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000325{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400326 bool needDFE = false;
327 bool success = false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400328 complex amp = 0.0;
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400329 float TOA = 0.0, avg = 0.0;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400330 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000331
Thomas Tsou204a9f12013-10-29 18:34:16 -0400332 radioVector *rxBurst = (radioVector *) mReceiveFIFO[chan]->read();
dburgessb3a0ca42011-10-12 07:44:40 +0000333
334 if (!rxBurst) return NULL;
335
kurtis.heimerl06286132011-11-26 03:18:43 +0000336 int timeslot = rxBurst->getTime().TN();
dburgessb3a0ca42011-10-12 07:44:40 +0000337
Thomas Tsou204a9f12013-10-29 18:34:16 -0400338 CorrType corrType = expectedCorrType(rxBurst->getTime(), chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000339
340 if ((corrType==OFF) || (corrType==IDLE)) {
341 delete rxBurst;
342 return NULL;
343 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000344
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400345 signalVector *vectorBurst = rxBurst;
346
347 energyDetect(*vectorBurst, 20 * mSPSRx, 0.0, &avg);
348
349 // Update noise level
350 mNoiseLev = mNoises.avg();
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400351 avg = sqrt(avg);
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400352
dburgessb3a0ca42011-10-12 07:44:40 +0000353 // run the proper correlator
dburgessb3a0ca42011-10-12 07:44:40 +0000354 if (corrType==TSC) {
kurtis.heimerl06286132011-11-26 03:18:43 +0000355 LOG(DEBUG) << "looking for TSC at time: " << rxBurst->getTime();
Thomas Tsou204a9f12013-10-29 18:34:16 -0400356 signalVector *channelResp;
357 double framesElapsed = rxBurst->getTime() - state->chanEstimateTime[timeslot];
358 bool estimateChannel = false;
359 if ((framesElapsed > 50) || (state->chanResponse[timeslot]==NULL)) {
360 if (state->chanResponse[timeslot])
361 delete state->chanResponse[timeslot];
362 if (state->DFEForward[timeslot])
363 delete state->DFEForward[timeslot];
364 if (state->DFEFeedback[timeslot])
365 delete state->DFEFeedback[timeslot];
Thomas Tsouf0782732013-10-29 15:55:47 -0400366
Thomas Tsou204a9f12013-10-29 18:34:16 -0400367 state->chanResponse[timeslot] = NULL;
368 state->DFEForward[timeslot] = NULL;
369 state->DFEFeedback[timeslot] = NULL;
370 estimateChannel = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000371 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400372 if (!needDFE) estimateChannel = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000373 float chanOffset;
374 success = analyzeTrafficBurst(*vectorBurst,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400375 mTSC,
376 5.0,
377 mSPSRx,
378 &amp,
379 &TOA,
380 mMaxExpectedDelay,
381 estimateChannel,
382 &channelResp,
383 &chanOffset);
dburgessb3a0ca42011-10-12 07:44:40 +0000384 if (success) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400385 state->SNRestimate[timeslot] = amp.norm2() / (mNoiseLev * mNoiseLev + 1.0);
386
dburgessb3a0ca42011-10-12 07:44:40 +0000387 if (estimateChannel) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400388 state->chanResponse[timeslot] = channelResp;
389 state->chanRespOffset[timeslot] = chanOffset;
390 state->chanRespAmplitude[timeslot] = amp;
391 scaleVector(*channelResp, complex(1.0, 0.0) / amp);
392 designDFE(*channelResp, state->SNRestimate[timeslot],
393 7, &state->DFEForward[timeslot],
394 &state->DFEFeedback[timeslot]);
Thomas Tsouf0782732013-10-29 15:55:47 -0400395
Thomas Tsou204a9f12013-10-29 18:34:16 -0400396 state->chanEstimateTime[timeslot] = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000397 }
398 }
399 else {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400400 state->chanResponse[timeslot] = NULL;
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400401 mNoises.insert(avg);
dburgessb3a0ca42011-10-12 07:44:40 +0000402 }
403 }
404 else {
405 // RACH burst
Thomas Tsou204a9f12013-10-29 18:34:16 -0400406 if ((success = detectRACHBurst(*vectorBurst, 6.0, mSPSRx, &amp, &TOA)))
407 state->chanResponse[timeslot] = NULL;
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400408 else
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400409 mNoises.insert(avg);
dburgessb3a0ca42011-10-12 07:44:40 +0000410 }
dburgessb3a0ca42011-10-12 07:44:40 +0000411
412 // demodulate burst
413 SoftVector *burst = NULL;
414 if ((rxBurst) && (success)) {
415 if ((corrType==RACH) || (!needDFE)) {
Thomas Tsouf0782732013-10-29 15:55:47 -0400416 burst = demodulateBurst(*vectorBurst, mSPSRx, amp, TOA);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400417 } else {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400418 scaleVector(*vectorBurst, complex(1.0, 0.0) / amp);
dburgessb3a0ca42011-10-12 07:44:40 +0000419 burst = equalizeBurst(*vectorBurst,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400420 TOA - state->chanRespOffset[timeslot],
421 mSPSRx,
422 *state->DFEForward[timeslot],
423 *state->DFEFeedback[timeslot]);
dburgessb3a0ca42011-10-12 07:44:40 +0000424 }
kurtis.heimerl06286132011-11-26 03:18:43 +0000425 wTime = rxBurst->getTime();
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400426 RSSI = (int) floor(20.0*log10(rxFullScale/avg));
dburgessb3a0ca42011-10-12 07:44:40 +0000427 LOG(DEBUG) << "RSSI: " << RSSI;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400428 timingOffset = (int) round(TOA * 256.0 / mSPSRx);
dburgessb3a0ca42011-10-12 07:44:40 +0000429 }
430
dburgessb3a0ca42011-10-12 07:44:40 +0000431 delete rxBurst;
432
433 return burst;
434}
435
436void Transceiver::start()
437{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400438 TransceiverChannel *chan;
439
440 for (size_t i = 0; i < mControlServiceLoopThreads.size(); i++) {
441 chan = new TransceiverChannel(this, i);
442 mControlServiceLoopThreads[i]->start((void * (*)(void*))
443 ControlServiceLoopAdapter, (void*) chan);
444 }
dburgessb3a0ca42011-10-12 07:44:40 +0000445}
446
447void Transceiver::reset()
448{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400449 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
450 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000451}
452
453
Thomas Tsou204a9f12013-10-29 18:34:16 -0400454void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000455{
dburgessb3a0ca42011-10-12 07:44:40 +0000456 int MAX_PACKET_LENGTH = 100;
457
458 // check control socket
459 char buffer[MAX_PACKET_LENGTH];
460 int msgLen = -1;
461 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400462
Thomas Tsou204a9f12013-10-29 18:34:16 -0400463 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000464
465 if (msgLen < 1) {
466 return;
467 }
468
469 char cmdcheck[4];
470 char command[MAX_PACKET_LENGTH];
471 char response[MAX_PACKET_LENGTH];
472
473 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400474
475 if (!chan)
476 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000477
478 if (strcmp(cmdcheck,"CMD")!=0) {
479 LOG(WARNING) << "bogus message on control interface";
480 return;
481 }
482 LOG(INFO) << "command is " << buffer;
483
484 if (strcmp(command,"POWEROFF")==0) {
485 // turn off transmitter/demod
486 sprintf(response,"RSP POWEROFF 0");
487 }
488 else if (strcmp(command,"POWERON")==0) {
489 // turn on transmitter/demod
490 if (!mTxFreq || !mRxFreq)
491 sprintf(response,"RSP POWERON 1");
492 else {
493 sprintf(response,"RSP POWERON 0");
Thomas Tsou204a9f12013-10-29 18:34:16 -0400494 if (!chan && !mOn) {
dburgessb3a0ca42011-10-12 07:44:40 +0000495 // Prepare for thread start
496 mPower = -20;
497 mRadioInterface->start();
dburgessb3a0ca42011-10-12 07:44:40 +0000498
499 // Start radio interface threads.
Thomas Tsou204a9f12013-10-29 18:34:16 -0400500 mTxLowerLoopThread->start((void * (*)(void*))
501 TxLowerLoopAdapter,(void*) this);
502 mRxLowerLoopThread->start((void * (*)(void*))
503 RxLowerLoopAdapter,(void*) this);
dburgessb3a0ca42011-10-12 07:44:40 +0000504
Thomas Tsou204a9f12013-10-29 18:34:16 -0400505 for (size_t i = 0; i < mChans; i++) {
506 TransceiverChannel *chan = new TransceiverChannel(this, i);
507 mRxServiceLoopThreads[i]->start((void * (*)(void*))
508 RxUpperLoopAdapter, (void*) chan);
509
510 chan = new TransceiverChannel(this, i);
511 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
512 TxUpperLoopAdapter, (void*) chan);
513 }
514
515 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000516 mOn = true;
517 }
518 }
519 }
520 else if (strcmp(command,"SETMAXDLY")==0) {
521 //set expected maximum time-of-arrival
522 int maxDelay;
523 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
524 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
525 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
526 }
527 else if (strcmp(command,"SETRXGAIN")==0) {
528 //set expected maximum time-of-arrival
529 int newGain;
530 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400531 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000532 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
533 }
534 else if (strcmp(command,"NOISELEV")==0) {
535 if (mOn) {
536 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400537 (int) round(20.0*log10(rxFullScale/mNoiseLev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000538 }
539 else {
540 sprintf(response,"RSP NOISELEV 1 0");
541 }
542 }
543 else if (strcmp(command,"SETPOWER")==0) {
544 // set output power in dB
545 int dbPwr;
546 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr);
547 if (!mOn)
548 sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
549 else {
550 mPower = dbPwr;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400551 mRadioInterface->setPowerAttenuation(dbPwr, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000552 sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
553 }
554 }
555 else if (strcmp(command,"ADJPOWER")==0) {
556 // adjust power in dB steps
557 int dbStep;
558 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep);
559 if (!mOn)
560 sprintf(response,"RSP ADJPOWER 1 %d",mPower);
561 else {
562 mPower += dbStep;
563 sprintf(response,"RSP ADJPOWER 0 %d",mPower);
564 }
565 }
566#define FREQOFFSET 0//11.2e3
567 else if (strcmp(command,"RXTUNE")==0) {
568 // tune receiver
569 int freqKhz;
570 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
571 mRxFreq = freqKhz*1.0e3+FREQOFFSET;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400572 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000573 LOG(ALERT) << "RX failed to tune";
574 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
575 }
576 else
577 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
578 }
579 else if (strcmp(command,"TXTUNE")==0) {
580 // tune txmtr
581 int freqKhz;
582 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
583 //freqKhz = 890e3;
584 mTxFreq = freqKhz*1.0e3+FREQOFFSET;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400585 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000586 LOG(ALERT) << "TX failed to tune";
587 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
588 }
589 else
590 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
591 }
592 else if (strcmp(command,"SETTSC")==0) {
593 // set TSC
594 int TSC;
595 sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC);
596 if (mOn)
597 sprintf(response,"RSP SETTSC 1 %d",TSC);
598 else {
599 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400600 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400601 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000602 }
603 }
604 else if (strcmp(command,"SETSLOT")==0) {
605 // set TSC
606 int corrCode;
607 int timeslot;
608 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
609 if ((timeslot < 0) || (timeslot > 7)) {
610 LOG(WARNING) << "bogus message on control interface";
611 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
612 return;
613 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400614 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
615 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000616 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
617
618 }
619 else {
620 LOG(WARNING) << "bogus command " << command << " on control interface.";
621 }
622
Thomas Tsou204a9f12013-10-29 18:34:16 -0400623 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000624}
625
Thomas Tsou204a9f12013-10-29 18:34:16 -0400626bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000627{
dburgessb3a0ca42011-10-12 07:44:40 +0000628 char buffer[gSlotLen+50];
629
630 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400631 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000632
633 if (msgLen!=gSlotLen+1+4+1) {
634 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
635 return false;
636 }
637
638 int timeSlot = (int) buffer[0];
639 uint64_t frameNum = 0;
640 for (int i = 0; i < 4; i++)
641 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
642
643 /*
644 if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) {
645 // stale burst
646 //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot);
647 //writeClockInterface();
648 }*/
649
650/*
651 DAB -- Just let these go through the demod.
652 if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) {
653 // stale burst from GSM core
654 LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot);
655 return false;
656 }
657*/
658
659 // periodically update GSM core clock
660 LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
661 << " mLastClockUpdateTime " << mLastClockUpdateTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000662
Thomas Tsou204a9f12013-10-29 18:34:16 -0400663 if (!chan) {
664 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
665 writeClockInterface();
666 }
dburgessb3a0ca42011-10-12 07:44:40 +0000667
668 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
669
670 int RSSI = (int) buffer[5];
671 static BitVector newBurst(gSlotLen);
672 BitVector::iterator itr = newBurst.begin();
673 char *bufferItr = buffer+6;
674 while (itr < newBurst.end())
675 *itr++ = *bufferItr++;
676
677 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400678
679 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000680
681 return true;
682
683
684}
dburgessb3a0ca42011-10-12 07:44:40 +0000685
Thomas Tsou204a9f12013-10-29 18:34:16 -0400686void Transceiver::driveReceiveRadio()
687{
688 if (!mRadioInterface->driveReceiveRadio())
689 usleep(100000);
690}
691
692void Transceiver::driveReceiveFIFO(size_t chan)
693{
dburgessb3a0ca42011-10-12 07:44:40 +0000694 SoftVector *rxBurst = NULL;
695 int RSSI;
696 int TOA; // in 1/256 of a symbol
697 GSM::Time burstTime;
698
Thomas Tsou204a9f12013-10-29 18:34:16 -0400699 rxBurst = pullRadioVector(burstTime, RSSI, TOA, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000700
701 if (rxBurst) {
702
703 LOG(DEBUG) << "burst parameters: "
704 << " time: " << burstTime
705 << " RSSI: " << RSSI
706 << " TOA: " << TOA
707 << " bits: " << *rxBurst;
708
709 char burstString[gSlotLen+10];
710 burstString[0] = burstTime.TN();
711 for (int i = 0; i < 4; i++)
712 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
713 burstString[5] = RSSI;
714 burstString[6] = (TOA >> 8) & 0x0ff;
715 burstString[7] = TOA & 0x0ff;
716 SoftVector::iterator burstItr = rxBurst->begin();
717
718 for (unsigned int i = 0; i < gSlotLen; i++) {
719 burstString[8+i] =(char) round((*burstItr++)*255.0);
720 }
721 burstString[gSlotLen+9] = '\0';
722 delete rxBurst;
723
Thomas Tsou204a9f12013-10-29 18:34:16 -0400724 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +0000725 }
dburgessb3a0ca42011-10-12 07:44:40 +0000726}
727
Thomas Tsou204a9f12013-10-29 18:34:16 -0400728void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000729{
730
731 /**
732 Features a carefully controlled latency mechanism, to
733 assure that transmit packets arrive at the radio/USRP
734 before they need to be transmitted.
735
736 Deadline clock indicates the burst that needs to be
737 pushed into the FIFO right NOW. If transmit queue does
738 not have a burst, stick in filler data.
739 */
740
741
742 RadioClock *radioClock = (mRadioInterface->getClock());
743
744 if (mOn) {
745 //radioClock->wait(); // wait until clock updates
746 LOG(DEBUG) << "radio clock " << radioClock->get();
747 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
748 // if underrun, then we're not providing bursts to radio/USRP fast
749 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400750 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000751 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000752 // only update latency at the defined frame interval
753 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000754 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
755 LOG(INFO) << "new latency: " << mTransmitLatency;
756 mLatencyUpdateTime = radioClock->get();
757 }
758 }
759 else {
760 // if underrun hasn't occurred in the last sec (216 frames) drop
761 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000762 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000763 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
764 mTransmitLatency.decTN();
765 LOG(INFO) << "reduced latency: " << mTransmitLatency;
766 mLatencyUpdateTime = radioClock->get();
767 }
768 }
769 }
dburgessb3a0ca42011-10-12 07:44:40 +0000770 }
dburgessb3a0ca42011-10-12 07:44:40 +0000771 // time to push burst to transmit FIFO
772 pushRadioVector(mTransmitDeadlineClock);
773 mTransmitDeadlineClock.incTN();
774 }
dburgessb3a0ca42011-10-12 07:44:40 +0000775 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400776
777 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000778}
779
780
781
782void Transceiver::writeClockInterface()
783{
784 char command[50];
785 // FIXME -- This should be adaptive.
786 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
787
788 LOG(INFO) << "ClockInterface: sending " << command;
789
Thomas Tsoud647ec52013-10-29 15:17:34 -0400790 mClockSocket->write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000791
792 mLastClockUpdateTime = mTransmitDeadlineClock;
793
Thomas Tsou92c16df2013-09-28 18:04:19 -0400794}
dburgessb3a0ca42011-10-12 07:44:40 +0000795
Thomas Tsou204a9f12013-10-29 18:34:16 -0400796void *RxUpperLoopAdapter(TransceiverChannel *chan)
797{
798 Transceiver *trx = chan->trx;
799 size_t num = chan->num;
800
801 delete chan;
802
Thomas Tsou7553aa92013-11-08 12:50:03 -0500803 trx->setPriority(0.42);
804
Thomas Tsou204a9f12013-10-29 18:34:16 -0400805 while (1) {
806 trx->driveReceiveFIFO(num);
807 pthread_testcancel();
808 }
809 return NULL;
810}
811
812void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +0000813{
Thomas Tsou7553aa92013-11-08 12:50:03 -0500814 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +0000815
dburgessb3a0ca42011-10-12 07:44:40 +0000816 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400817 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -0400818 pthread_testcancel();
819 }
820 return NULL;
821}
822
Thomas Tsou204a9f12013-10-29 18:34:16 -0400823void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -0400824{
Thomas Tsou7553aa92013-11-08 12:50:03 -0500825 transceiver->setPriority(0.44);
826
Thomas Tsou92c16df2013-09-28 18:04:19 -0400827 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400828 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +0000829 pthread_testcancel();
830 }
831 return NULL;
832}
833
Thomas Tsou204a9f12013-10-29 18:34:16 -0400834void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000835{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400836 Transceiver *trx = chan->trx;
837 size_t num = chan->num;
838
839 delete chan;
840
dburgessb3a0ca42011-10-12 07:44:40 +0000841 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400842 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +0000843 pthread_testcancel();
844 }
845 return NULL;
846}
847
Thomas Tsou204a9f12013-10-29 18:34:16 -0400848void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000849{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400850 Transceiver *trx = chan->trx;
851 size_t num = chan->num;
852
853 delete chan;
854
dburgessb3a0ca42011-10-12 07:44:40 +0000855 while (1) {
856 bool stale = false;
857 // Flush the UDP packets until a successful transfer.
Thomas Tsou204a9f12013-10-29 18:34:16 -0400858 while (!trx->driveTxPriorityQueue(num)) {
859 stale = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000860 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400861 if (!num && stale) {
dburgessb3a0ca42011-10-12 07:44:40 +0000862 // If a packet was stale, remind the GSM stack of the clock.
Thomas Tsou204a9f12013-10-29 18:34:16 -0400863 trx->writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000864 }
865 pthread_testcancel();
866 }
867 return NULL;
868}