blob: caf24524628b38925a65fd6590c540894f81d44c [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 Tsoue1ce9252013-11-13 22:40:44 -0500116 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400117 signalVector *burst;
118
Thomas Tsou204a9f12013-10-29 18:34:16 -0400119 if (!mChans) {
120 LOG(ALERT) << "No channels assigned";
121 return false;
122 }
123
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400124 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400125 LOG(ALERT) << "Failed to initialize signal processing library";
126 return false;
127 }
128
Thomas Tsou204a9f12013-10-29 18:34:16 -0400129 mDataSockets.resize(mChans);
130 mCtrlSockets.resize(mChans);
131
132 mControlServiceLoopThreads.resize(mChans);
133 mTxPriorityQueueServiceLoopThreads.resize(mChans);
134 mRxServiceLoopThreads.resize(mChans);
135
136 mTxPriorityQueues.resize(mChans);
137 mReceiveFIFO.resize(mChans);
138 mStates.resize(mChans);
139
Thomas Tsoud647ec52013-10-29 15:17:34 -0400140 mClockSocket = new UDPSocket(mBasePort, mAddr.c_str(), mBasePort + 100);
Thomas Tsoud647ec52013-10-29 15:17:34 -0400141
Thomas Tsou204a9f12013-10-29 18:34:16 -0400142 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500143 c_srcport = mBasePort + 2 * i + 1;
144 c_dstport = mBasePort + 2 * i + 101;
145 d_srcport = mBasePort + 2 * i + 2;
146 d_dstport = mBasePort + 2 * i + 102;
147
148 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
149 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400150 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400151
Thomas Tsou204a9f12013-10-29 18:34:16 -0400152 for (size_t i = 0; i < mChans; i++) {
153 mControlServiceLoopThreads[i] = new Thread(32768);
154 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
155 mRxServiceLoopThreads[i] = new Thread(32768);
156
157 for (size_t n = 0; n < 8; n++) {
158 burst = modulateBurst(gDummyBurst, 8 + (n % 4 == 0), mSPSTx);
159 scaleVector(*burst, txFullScale);
160 mStates[i].init(n, burst);
161 delete burst;
162 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400163 }
164
165 return true;
166}
dburgessb3a0ca42011-10-12 07:44:40 +0000167
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500168void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400169 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000170{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500171 signalVector *burst;
172 radioVector *radio_burst;
173
Thomas Tsou204a9f12013-10-29 18:34:16 -0400174 if (chan >= mTxPriorityQueues.size()) {
175 LOG(ALERT) << "Invalid channel " << chan;
176 return;
177 }
178
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500179 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
180 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000181
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500182 radio_burst = new radioVector(wTime, burst);
183
184 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000185}
186
dburgessb3a0ca42011-10-12 07:44:40 +0000187void Transceiver::pushRadioVector(GSM::Time &nowTime)
188{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400189 int TN, modFN;
190 radioVector *burst;
191 TransceiverState *state;
192 std::vector<signalVector *> bursts(mChans);
193 std::vector<bool> zeros(mChans);
dburgessb3a0ca42011-10-12 07:44:40 +0000194
Thomas Tsou204a9f12013-10-29 18:34:16 -0400195 for (size_t i = 0; i < mChans; i ++) {
196 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000197
Thomas Tsou204a9f12013-10-29 18:34:16 -0400198 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
199 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
200
201 TN = burst->getTime().TN();
202 modFN = burst->getTime().FN() % state->fillerModulus[TN];
203
204 delete state->fillerTable[modFN][TN];
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500205 state->fillerTable[modFN][TN] = burst->getVector();
206 burst->setVector(NULL);
207 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400208 }
209
210 TN = nowTime.TN();
211 modFN = nowTime.FN() % state->fillerModulus[TN];
212
213 bursts[i] = state->fillerTable[modFN][TN];
214 zeros[i] = state->chanType[TN] == NONE;
215
216 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
217 delete state->fillerTable[modFN][TN];
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500218 state->fillerTable[modFN][TN] = burst->getVector();
219 bursts[i] = burst->getVector();
220 burst->setVector(NULL);
221 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400222 }
dburgessb3a0ca42011-10-12 07:44:40 +0000223 }
224
Thomas Tsou204a9f12013-10-29 18:34:16 -0400225 mRadioInterface->driveTransmitRadio(bursts, zeros);
226
227 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000228}
229
Thomas Tsou204a9f12013-10-29 18:34:16 -0400230void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000231{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400232 TransceiverState *state = &mStates[chan];
233
234 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000235 case NONE:
236 case I:
237 case II:
238 case III:
239 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400240 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000241 break;
242 case IV:
243 case VI:
244 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400245 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000246 break;
247 //case V:
248 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400249 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000250 break;
ttsoufc40a842013-06-09 22:38:18 +0000251 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400252 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000253 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000254 default:
255 break;
256 }
257}
258
259
Thomas Tsou204a9f12013-10-29 18:34:16 -0400260Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
261 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000262{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400263 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000264 unsigned burstTN = currTime.TN();
265 unsigned burstFN = currTime.FN();
266
Thomas Tsou204a9f12013-10-29 18:34:16 -0400267 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000268 case NONE:
269 return OFF;
270 break;
271 case FILL:
272 return IDLE;
273 break;
274 case I:
275 return TSC;
276 /*if (burstFN % 26 == 25)
277 return IDLE;
278 else
279 return TSC;*/
280 break;
281 case II:
ttsou20642972013-03-27 22:00:25 +0000282 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000283 break;
284 case III:
285 return TSC;
286 break;
287 case IV:
288 case VI:
289 return RACH;
290 break;
291 case V: {
292 int mod51 = burstFN % 51;
293 if ((mod51 <= 36) && (mod51 >= 14))
294 return RACH;
295 else if ((mod51 == 4) || (mod51 == 5))
296 return RACH;
297 else if ((mod51 == 45) || (mod51 == 46))
298 return RACH;
299 else
300 return TSC;
301 break;
302 }
303 case VII:
304 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
305 return IDLE;
306 else
307 return TSC;
308 break;
ttsoufc40a842013-06-09 22:38:18 +0000309 case XIII: {
310 int mod52 = burstFN % 52;
311 if ((mod52 == 12) || (mod52 == 38))
312 return RACH;
313 else if ((mod52 == 25) || (mod52 == 51))
314 return IDLE;
315 else
316 return TSC;
317 break;
318 }
dburgessb3a0ca42011-10-12 07:44:40 +0000319 case LOOPBACK:
320 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
321 return IDLE;
322 else
323 return TSC;
324 break;
325 default:
326 return OFF;
327 break;
328 }
dburgessb3a0ca42011-10-12 07:44:40 +0000329}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400330
Thomas Tsou204a9f12013-10-29 18:34:16 -0400331SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
332 int &timingOffset, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000333{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400334 bool needDFE = false;
335 bool success = false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400336 complex amp = 0.0;
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400337 float TOA = 0.0, avg = 0.0;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400338 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000339
Thomas Tsou204a9f12013-10-29 18:34:16 -0400340 radioVector *rxBurst = (radioVector *) mReceiveFIFO[chan]->read();
dburgessb3a0ca42011-10-12 07:44:40 +0000341
342 if (!rxBurst) return NULL;
343
kurtis.heimerl06286132011-11-26 03:18:43 +0000344 int timeslot = rxBurst->getTime().TN();
dburgessb3a0ca42011-10-12 07:44:40 +0000345
Thomas Tsou204a9f12013-10-29 18:34:16 -0400346 CorrType corrType = expectedCorrType(rxBurst->getTime(), chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000347
348 if ((corrType==OFF) || (corrType==IDLE)) {
349 delete rxBurst;
350 return NULL;
351 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000352
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500353 signalVector *vectorBurst = rxBurst->getVector();
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400354
355 energyDetect(*vectorBurst, 20 * mSPSRx, 0.0, &avg);
356
357 // Update noise level
358 mNoiseLev = mNoises.avg();
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400359 avg = sqrt(avg);
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400360
dburgessb3a0ca42011-10-12 07:44:40 +0000361 // run the proper correlator
dburgessb3a0ca42011-10-12 07:44:40 +0000362 if (corrType==TSC) {
kurtis.heimerl06286132011-11-26 03:18:43 +0000363 LOG(DEBUG) << "looking for TSC at time: " << rxBurst->getTime();
Thomas Tsou204a9f12013-10-29 18:34:16 -0400364 signalVector *channelResp;
365 double framesElapsed = rxBurst->getTime() - state->chanEstimateTime[timeslot];
366 bool estimateChannel = false;
367 if ((framesElapsed > 50) || (state->chanResponse[timeslot]==NULL)) {
368 if (state->chanResponse[timeslot])
369 delete state->chanResponse[timeslot];
370 if (state->DFEForward[timeslot])
371 delete state->DFEForward[timeslot];
372 if (state->DFEFeedback[timeslot])
373 delete state->DFEFeedback[timeslot];
Thomas Tsouf0782732013-10-29 15:55:47 -0400374
Thomas Tsou204a9f12013-10-29 18:34:16 -0400375 state->chanResponse[timeslot] = NULL;
376 state->DFEForward[timeslot] = NULL;
377 state->DFEFeedback[timeslot] = NULL;
378 estimateChannel = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000379 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400380 if (!needDFE) estimateChannel = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000381 float chanOffset;
382 success = analyzeTrafficBurst(*vectorBurst,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400383 mTSC,
384 5.0,
385 mSPSRx,
386 &amp,
387 &TOA,
388 mMaxExpectedDelay,
389 estimateChannel,
390 &channelResp,
391 &chanOffset);
dburgessb3a0ca42011-10-12 07:44:40 +0000392 if (success) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400393 state->SNRestimate[timeslot] = amp.norm2() / (mNoiseLev * mNoiseLev + 1.0);
394
dburgessb3a0ca42011-10-12 07:44:40 +0000395 if (estimateChannel) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400396 state->chanResponse[timeslot] = channelResp;
397 state->chanRespOffset[timeslot] = chanOffset;
398 state->chanRespAmplitude[timeslot] = amp;
399 scaleVector(*channelResp, complex(1.0, 0.0) / amp);
400 designDFE(*channelResp, state->SNRestimate[timeslot],
401 7, &state->DFEForward[timeslot],
402 &state->DFEFeedback[timeslot]);
Thomas Tsouf0782732013-10-29 15:55:47 -0400403
Thomas Tsou204a9f12013-10-29 18:34:16 -0400404 state->chanEstimateTime[timeslot] = rxBurst->getTime();
dburgessb3a0ca42011-10-12 07:44:40 +0000405 }
406 }
407 else {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400408 state->chanResponse[timeslot] = NULL;
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400409 mNoises.insert(avg);
dburgessb3a0ca42011-10-12 07:44:40 +0000410 }
411 }
412 else {
413 // RACH burst
Thomas Tsou204a9f12013-10-29 18:34:16 -0400414 if ((success = detectRACHBurst(*vectorBurst, 6.0, mSPSRx, &amp, &TOA)))
415 state->chanResponse[timeslot] = NULL;
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400416 else
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400417 mNoises.insert(avg);
dburgessb3a0ca42011-10-12 07:44:40 +0000418 }
dburgessb3a0ca42011-10-12 07:44:40 +0000419
420 // demodulate burst
421 SoftVector *burst = NULL;
422 if ((rxBurst) && (success)) {
423 if ((corrType==RACH) || (!needDFE)) {
Thomas Tsouf0782732013-10-29 15:55:47 -0400424 burst = demodulateBurst(*vectorBurst, mSPSRx, amp, TOA);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400425 } else {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400426 scaleVector(*vectorBurst, complex(1.0, 0.0) / amp);
dburgessb3a0ca42011-10-12 07:44:40 +0000427 burst = equalizeBurst(*vectorBurst,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400428 TOA - state->chanRespOffset[timeslot],
429 mSPSRx,
430 *state->DFEForward[timeslot],
431 *state->DFEFeedback[timeslot]);
dburgessb3a0ca42011-10-12 07:44:40 +0000432 }
kurtis.heimerl06286132011-11-26 03:18:43 +0000433 wTime = rxBurst->getTime();
Thomas Tsoua1a3ab42013-10-18 10:50:52 -0400434 RSSI = (int) floor(20.0*log10(rxFullScale/avg));
dburgessb3a0ca42011-10-12 07:44:40 +0000435 LOG(DEBUG) << "RSSI: " << RSSI;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400436 timingOffset = (int) round(TOA * 256.0 / mSPSRx);
dburgessb3a0ca42011-10-12 07:44:40 +0000437 }
438
dburgessb3a0ca42011-10-12 07:44:40 +0000439 delete rxBurst;
440
441 return burst;
442}
443
444void Transceiver::start()
445{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400446 TransceiverChannel *chan;
447
448 for (size_t i = 0; i < mControlServiceLoopThreads.size(); i++) {
449 chan = new TransceiverChannel(this, i);
450 mControlServiceLoopThreads[i]->start((void * (*)(void*))
451 ControlServiceLoopAdapter, (void*) chan);
452 }
dburgessb3a0ca42011-10-12 07:44:40 +0000453}
454
455void Transceiver::reset()
456{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400457 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
458 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000459}
460
461
Thomas Tsou204a9f12013-10-29 18:34:16 -0400462void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000463{
dburgessb3a0ca42011-10-12 07:44:40 +0000464 int MAX_PACKET_LENGTH = 100;
465
466 // check control socket
467 char buffer[MAX_PACKET_LENGTH];
468 int msgLen = -1;
469 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400470
Thomas Tsou204a9f12013-10-29 18:34:16 -0400471 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000472
473 if (msgLen < 1) {
474 return;
475 }
476
477 char cmdcheck[4];
478 char command[MAX_PACKET_LENGTH];
479 char response[MAX_PACKET_LENGTH];
480
481 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400482
483 if (!chan)
484 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000485
486 if (strcmp(cmdcheck,"CMD")!=0) {
487 LOG(WARNING) << "bogus message on control interface";
488 return;
489 }
490 LOG(INFO) << "command is " << buffer;
491
492 if (strcmp(command,"POWEROFF")==0) {
493 // turn off transmitter/demod
494 sprintf(response,"RSP POWEROFF 0");
495 }
496 else if (strcmp(command,"POWERON")==0) {
497 // turn on transmitter/demod
498 if (!mTxFreq || !mRxFreq)
499 sprintf(response,"RSP POWERON 1");
500 else {
501 sprintf(response,"RSP POWERON 0");
Thomas Tsou204a9f12013-10-29 18:34:16 -0400502 if (!chan && !mOn) {
dburgessb3a0ca42011-10-12 07:44:40 +0000503 // Prepare for thread start
504 mPower = -20;
505 mRadioInterface->start();
dburgessb3a0ca42011-10-12 07:44:40 +0000506
507 // Start radio interface threads.
Thomas Tsou204a9f12013-10-29 18:34:16 -0400508 mTxLowerLoopThread->start((void * (*)(void*))
509 TxLowerLoopAdapter,(void*) this);
510 mRxLowerLoopThread->start((void * (*)(void*))
511 RxLowerLoopAdapter,(void*) this);
dburgessb3a0ca42011-10-12 07:44:40 +0000512
Thomas Tsou204a9f12013-10-29 18:34:16 -0400513 for (size_t i = 0; i < mChans; i++) {
514 TransceiverChannel *chan = new TransceiverChannel(this, i);
515 mRxServiceLoopThreads[i]->start((void * (*)(void*))
516 RxUpperLoopAdapter, (void*) chan);
517
518 chan = new TransceiverChannel(this, i);
519 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
520 TxUpperLoopAdapter, (void*) chan);
521 }
522
523 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000524 mOn = true;
525 }
526 }
527 }
528 else if (strcmp(command,"SETMAXDLY")==0) {
529 //set expected maximum time-of-arrival
530 int maxDelay;
531 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
532 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
533 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
534 }
535 else if (strcmp(command,"SETRXGAIN")==0) {
536 //set expected maximum time-of-arrival
537 int newGain;
538 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400539 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000540 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
541 }
542 else if (strcmp(command,"NOISELEV")==0) {
543 if (mOn) {
544 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400545 (int) round(20.0*log10(rxFullScale/mNoiseLev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000546 }
547 else {
548 sprintf(response,"RSP NOISELEV 1 0");
549 }
550 }
551 else if (strcmp(command,"SETPOWER")==0) {
552 // set output power in dB
553 int dbPwr;
554 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbPwr);
555 if (!mOn)
556 sprintf(response,"RSP SETPOWER 1 %d",dbPwr);
557 else {
558 mPower = dbPwr;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400559 mRadioInterface->setPowerAttenuation(dbPwr, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000560 sprintf(response,"RSP SETPOWER 0 %d",dbPwr);
561 }
562 }
563 else if (strcmp(command,"ADJPOWER")==0) {
564 // adjust power in dB steps
565 int dbStep;
566 sscanf(buffer,"%3s %s %d",cmdcheck,command,&dbStep);
567 if (!mOn)
568 sprintf(response,"RSP ADJPOWER 1 %d",mPower);
569 else {
570 mPower += dbStep;
571 sprintf(response,"RSP ADJPOWER 0 %d",mPower);
572 }
573 }
574#define FREQOFFSET 0//11.2e3
575 else if (strcmp(command,"RXTUNE")==0) {
576 // tune receiver
577 int freqKhz;
578 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
579 mRxFreq = freqKhz*1.0e3+FREQOFFSET;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400580 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000581 LOG(ALERT) << "RX failed to tune";
582 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
583 }
584 else
585 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
586 }
587 else if (strcmp(command,"TXTUNE")==0) {
588 // tune txmtr
589 int freqKhz;
590 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
591 //freqKhz = 890e3;
592 mTxFreq = freqKhz*1.0e3+FREQOFFSET;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400593 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000594 LOG(ALERT) << "TX failed to tune";
595 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
596 }
597 else
598 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
599 }
600 else if (strcmp(command,"SETTSC")==0) {
601 // set TSC
602 int TSC;
603 sscanf(buffer,"%3s %s %d",cmdcheck,command,&TSC);
604 if (mOn)
605 sprintf(response,"RSP SETTSC 1 %d",TSC);
606 else {
607 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400608 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400609 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000610 }
611 }
612 else if (strcmp(command,"SETSLOT")==0) {
613 // set TSC
614 int corrCode;
615 int timeslot;
616 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
617 if ((timeslot < 0) || (timeslot > 7)) {
618 LOG(WARNING) << "bogus message on control interface";
619 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
620 return;
621 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400622 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
623 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000624 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
625
626 }
627 else {
628 LOG(WARNING) << "bogus command " << command << " on control interface.";
629 }
630
Thomas Tsou204a9f12013-10-29 18:34:16 -0400631 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000632}
633
Thomas Tsou204a9f12013-10-29 18:34:16 -0400634bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000635{
dburgessb3a0ca42011-10-12 07:44:40 +0000636 char buffer[gSlotLen+50];
637
638 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400639 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000640
641 if (msgLen!=gSlotLen+1+4+1) {
642 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
643 return false;
644 }
645
646 int timeSlot = (int) buffer[0];
647 uint64_t frameNum = 0;
648 for (int i = 0; i < 4; i++)
649 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
650
651 /*
652 if (GSM::Time(frameNum,timeSlot) > mTransmitDeadlineClock + GSM::Time(51,0)) {
653 // stale burst
654 //LOG(DEBUG) << "FAST! "<< GSM::Time(frameNum,timeSlot);
655 //writeClockInterface();
656 }*/
657
658/*
659 DAB -- Just let these go through the demod.
660 if (GSM::Time(frameNum,timeSlot) < mTransmitDeadlineClock) {
661 // stale burst from GSM core
662 LOG(NOTICE) << "STALE packet on GSM->TRX interface at time "<< GSM::Time(frameNum,timeSlot);
663 return false;
664 }
665*/
666
667 // periodically update GSM core clock
668 LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
669 << " mLastClockUpdateTime " << mLastClockUpdateTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000670
Thomas Tsou204a9f12013-10-29 18:34:16 -0400671 if (!chan) {
672 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
673 writeClockInterface();
674 }
dburgessb3a0ca42011-10-12 07:44:40 +0000675
676 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
677
678 int RSSI = (int) buffer[5];
679 static BitVector newBurst(gSlotLen);
680 BitVector::iterator itr = newBurst.begin();
681 char *bufferItr = buffer+6;
682 while (itr < newBurst.end())
683 *itr++ = *bufferItr++;
684
685 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400686
687 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000688
689 return true;
690
691
692}
dburgessb3a0ca42011-10-12 07:44:40 +0000693
Thomas Tsou204a9f12013-10-29 18:34:16 -0400694void Transceiver::driveReceiveRadio()
695{
696 if (!mRadioInterface->driveReceiveRadio())
697 usleep(100000);
698}
699
700void Transceiver::driveReceiveFIFO(size_t chan)
701{
dburgessb3a0ca42011-10-12 07:44:40 +0000702 SoftVector *rxBurst = NULL;
703 int RSSI;
704 int TOA; // in 1/256 of a symbol
705 GSM::Time burstTime;
706
Thomas Tsou204a9f12013-10-29 18:34:16 -0400707 rxBurst = pullRadioVector(burstTime, RSSI, TOA, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000708
709 if (rxBurst) {
710
711 LOG(DEBUG) << "burst parameters: "
712 << " time: " << burstTime
713 << " RSSI: " << RSSI
714 << " TOA: " << TOA
715 << " bits: " << *rxBurst;
716
717 char burstString[gSlotLen+10];
718 burstString[0] = burstTime.TN();
719 for (int i = 0; i < 4; i++)
720 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
721 burstString[5] = RSSI;
722 burstString[6] = (TOA >> 8) & 0x0ff;
723 burstString[7] = TOA & 0x0ff;
724 SoftVector::iterator burstItr = rxBurst->begin();
725
726 for (unsigned int i = 0; i < gSlotLen; i++) {
727 burstString[8+i] =(char) round((*burstItr++)*255.0);
728 }
729 burstString[gSlotLen+9] = '\0';
730 delete rxBurst;
731
Thomas Tsou204a9f12013-10-29 18:34:16 -0400732 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +0000733 }
dburgessb3a0ca42011-10-12 07:44:40 +0000734}
735
Thomas Tsou204a9f12013-10-29 18:34:16 -0400736void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000737{
738
739 /**
740 Features a carefully controlled latency mechanism, to
741 assure that transmit packets arrive at the radio/USRP
742 before they need to be transmitted.
743
744 Deadline clock indicates the burst that needs to be
745 pushed into the FIFO right NOW. If transmit queue does
746 not have a burst, stick in filler data.
747 */
748
749
750 RadioClock *radioClock = (mRadioInterface->getClock());
751
752 if (mOn) {
753 //radioClock->wait(); // wait until clock updates
754 LOG(DEBUG) << "radio clock " << radioClock->get();
755 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
756 // if underrun, then we're not providing bursts to radio/USRP fast
757 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400758 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000759 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000760 // only update latency at the defined frame interval
761 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000762 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
763 LOG(INFO) << "new latency: " << mTransmitLatency;
764 mLatencyUpdateTime = radioClock->get();
765 }
766 }
767 else {
768 // if underrun hasn't occurred in the last sec (216 frames) drop
769 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000770 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000771 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
772 mTransmitLatency.decTN();
773 LOG(INFO) << "reduced latency: " << mTransmitLatency;
774 mLatencyUpdateTime = radioClock->get();
775 }
776 }
777 }
dburgessb3a0ca42011-10-12 07:44:40 +0000778 }
dburgessb3a0ca42011-10-12 07:44:40 +0000779 // time to push burst to transmit FIFO
780 pushRadioVector(mTransmitDeadlineClock);
781 mTransmitDeadlineClock.incTN();
782 }
dburgessb3a0ca42011-10-12 07:44:40 +0000783 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400784
785 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000786}
787
788
789
790void Transceiver::writeClockInterface()
791{
792 char command[50];
793 // FIXME -- This should be adaptive.
794 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
795
796 LOG(INFO) << "ClockInterface: sending " << command;
797
Thomas Tsoud647ec52013-10-29 15:17:34 -0400798 mClockSocket->write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000799
800 mLastClockUpdateTime = mTransmitDeadlineClock;
801
Thomas Tsou92c16df2013-09-28 18:04:19 -0400802}
dburgessb3a0ca42011-10-12 07:44:40 +0000803
Thomas Tsou204a9f12013-10-29 18:34:16 -0400804void *RxUpperLoopAdapter(TransceiverChannel *chan)
805{
806 Transceiver *trx = chan->trx;
807 size_t num = chan->num;
808
809 delete chan;
810
Thomas Tsou7553aa92013-11-08 12:50:03 -0500811 trx->setPriority(0.42);
812
Thomas Tsou204a9f12013-10-29 18:34:16 -0400813 while (1) {
814 trx->driveReceiveFIFO(num);
815 pthread_testcancel();
816 }
817 return NULL;
818}
819
820void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +0000821{
Thomas Tsou7553aa92013-11-08 12:50:03 -0500822 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +0000823
dburgessb3a0ca42011-10-12 07:44:40 +0000824 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400825 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -0400826 pthread_testcancel();
827 }
828 return NULL;
829}
830
Thomas Tsou204a9f12013-10-29 18:34:16 -0400831void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -0400832{
Thomas Tsou7553aa92013-11-08 12:50:03 -0500833 transceiver->setPriority(0.44);
834
Thomas Tsou92c16df2013-09-28 18:04:19 -0400835 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400836 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +0000837 pthread_testcancel();
838 }
839 return NULL;
840}
841
Thomas Tsou204a9f12013-10-29 18:34:16 -0400842void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000843{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400844 Transceiver *trx = chan->trx;
845 size_t num = chan->num;
846
847 delete chan;
848
dburgessb3a0ca42011-10-12 07:44:40 +0000849 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400850 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +0000851 pthread_testcancel();
852 }
853 return NULL;
854}
855
Thomas Tsou204a9f12013-10-29 18:34:16 -0400856void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000857{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400858 Transceiver *trx = chan->trx;
859 size_t num = chan->num;
860
861 delete chan;
862
Thomas Tsoua4cf48c2013-11-09 21:44:26 -0500863 trx->setPriority(0.40);
864
dburgessb3a0ca42011-10-12 07:44:40 +0000865 while (1) {
866 bool stale = false;
867 // Flush the UDP packets until a successful transfer.
Thomas Tsou204a9f12013-10-29 18:34:16 -0400868 while (!trx->driveTxPriorityQueue(num)) {
869 stale = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000870 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400871 if (!num && stale) {
dburgessb3a0ca42011-10-12 07:44:40 +0000872 // If a packet was stale, remind the GSM stack of the clock.
Thomas Tsou204a9f12013-10-29 18:34:16 -0400873 trx->writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000874 }
875 pthread_testcancel();
876 }
877 return NULL;
878}