blob: 31eea60337eb8f37e6cd7adaf42d50158afa8e39 [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()
Tom Tsoua4d1a412014-11-25 15:46:56 -080046 : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
Thomas Tsouf0782732013-10-29 15:55:47 -040047{
48 for (int i = 0; i < 8; i++) {
49 chanType[i] = Transceiver::NONE;
50 fillerModulus[i] = 26;
51 chanResponse[i] = NULL;
52 DFEForward[i] = NULL;
53 DFEFeedback[i] = NULL;
54
55 for (int n = 0; n < 102; n++)
56 fillerTable[n][i] = NULL;
57 }
58}
59
60TransceiverState::~TransceiverState()
61{
62 for (int i = 0; i < 8; i++) {
63 delete chanResponse[i];
64 delete DFEForward[i];
65 delete DFEFeedback[i];
66
67 for (int n = 0; n < 102; n++)
68 delete fillerTable[n][i];
69 }
70}
71
Thomas Tsou15d743e2014-01-25 02:34:03 -050072void TransceiverState::init(size_t slot, signalVector *burst, bool fill)
Thomas Tsouf0782732013-10-29 15:55:47 -040073{
Thomas Tsou15d743e2014-01-25 02:34:03 -050074 signalVector *filler;
75
76 for (int i = 0; i < 102; i++) {
77 if (fill)
78 filler = new signalVector(*burst);
79 else
80 filler = new signalVector(burst->size());
81
82 fillerTable[i][slot] = filler;
83 }
Thomas Tsouf0782732013-10-29 15:55:47 -040084}
85
dburgessb3a0ca42011-10-12 07:44:40 +000086Transceiver::Transceiver(int wBasePort,
Tom Tsoueb54bdd2014-11-25 16:06:32 -080087 const char *wTRXAddress,
Thomas Tsou204a9f12013-10-29 18:34:16 -040088 size_t wSPS, size_t wChans,
dburgessb3a0ca42011-10-12 07:44:40 +000089 GSM::Time wTransmitLatency,
90 RadioInterface *wRadioInterface)
Tom Tsoueb54bdd2014-11-25 16:06:32 -080091 : mBasePort(wBasePort), mAddr(wTRXAddress),
92 mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
93 mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
94 mSPSTx(wSPS), mSPSRx(1), mChans(wChans), mOn(false),
95 mTxFreq(0.0), mRxFreq(0.0), mMaxExpectedDelay(0)
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{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800103 stop();
104
dburgessb3a0ca42011-10-12 07:44:40 +0000105 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400106
Thomas Tsou204a9f12013-10-29 18:34:16 -0400107 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800108 mControlServiceLoopThreads[i]->cancel();
109 mControlServiceLoopThreads[i]->join();
110 delete mControlServiceLoopThreads[i];
111
Thomas Tsou204a9f12013-10-29 18:34:16 -0400112 mTxPriorityQueues[i].clear();
113 delete mCtrlSockets[i];
114 delete mDataSockets[i];
115 }
dburgessb3a0ca42011-10-12 07:44:40 +0000116}
Thomas Tsou83e06892013-08-20 16:10:01 -0400117
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800118/*
119 * Initialize transceiver
120 *
121 * Start or restart the control loop. Any further control is handled through the
122 * socket API. Randomize the central radio clock set the downlink burst
123 * counters. Note that the clock will not update until the radio starts, but we
124 * are still expected to report clock indications through control channel
125 * activity.
126 */
Thomas Tsou15d743e2014-01-25 02:34:03 -0500127bool Transceiver::init(bool filler)
Thomas Tsou83e06892013-08-20 16:10:01 -0400128{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500129 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400130 signalVector *burst;
131
Thomas Tsou204a9f12013-10-29 18:34:16 -0400132 if (!mChans) {
133 LOG(ALERT) << "No channels assigned";
134 return false;
135 }
136
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400137 if (!sigProcLibSetup(mSPSTx)) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400138 LOG(ALERT) << "Failed to initialize signal processing library";
139 return false;
140 }
141
Thomas Tsou204a9f12013-10-29 18:34:16 -0400142 mDataSockets.resize(mChans);
143 mCtrlSockets.resize(mChans);
144
145 mControlServiceLoopThreads.resize(mChans);
146 mTxPriorityQueueServiceLoopThreads.resize(mChans);
147 mRxServiceLoopThreads.resize(mChans);
148
149 mTxPriorityQueues.resize(mChans);
150 mReceiveFIFO.resize(mChans);
151 mStates.resize(mChans);
152
Thomas Tsouccb73e12014-04-15 17:41:28 -0400153 /* Filler table retransmissions - support only on channel 0 */
154 if (filler)
155 mStates[0].mRetrans = true;
156
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800157 /* Setup sockets */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400158 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500159 c_srcport = mBasePort + 2 * i + 1;
160 c_dstport = mBasePort + 2 * i + 101;
161 d_srcport = mBasePort + 2 * i + 2;
162 d_dstport = mBasePort + 2 * i + 102;
163
164 mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
165 mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400166 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400167
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800168 /* Randomize the central clock */
169 GSM::Time startTime(random() % gHyperframe, 0);
170 mRadioInterface->getClock()->set(startTime);
171 mTransmitDeadlineClock = startTime;
172 mLastClockUpdateTime = startTime;
173 mLatencyUpdateTime = startTime;
174
175 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400176 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800177 TransceiverChannel *chan = new TransceiverChannel(this, i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400178 mControlServiceLoopThreads[i] = new Thread(32768);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800179 mControlServiceLoopThreads[i]->start((void * (*)(void*))
180 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400181
182 for (size_t n = 0; n < 8; n++) {
183 burst = modulateBurst(gDummyBurst, 8 + (n % 4 == 0), mSPSTx);
184 scaleVector(*burst, txFullScale);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500185 mStates[i].init(n, burst, filler && !i);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400186 delete burst;
187 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400188 }
189
190 return true;
191}
dburgessb3a0ca42011-10-12 07:44:40 +0000192
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800193/*
194 * Start the transceiver
195 *
196 * Submit command(s) to the radio device to commence streaming samples and
197 * launch threads to handle sample I/O. Re-synchronize the transmit burst
198 * counters to the central radio clock here as well.
199 */
200bool Transceiver::start()
201{
202 ScopedLock lock(mLock);
203
204 if (mOn) {
205 LOG(ERR) << "Transceiver already running";
206 return false;
207 }
208
209 LOG(NOTICE) << "Starting the transceiver";
210
211 GSM::Time time = mRadioInterface->getClock()->get();
212 mTransmitDeadlineClock = time;
213 mLastClockUpdateTime = time;
214 mLatencyUpdateTime = time;
215
216 if (!mRadioInterface->start()) {
217 LOG(ALERT) << "Device failed to start";
218 return false;
219 }
220
221 /* Device is running - launch I/O threads */
222 mRxLowerLoopThread = new Thread(32768);
223 mTxLowerLoopThread = new Thread(32768);
224 mTxLowerLoopThread->start((void * (*)(void*))
225 TxLowerLoopAdapter,(void*) this);
226 mRxLowerLoopThread->start((void * (*)(void*))
227 RxLowerLoopAdapter,(void*) this);
228
229 /* Launch uplink and downlink burst processing threads */
230 for (size_t i = 0; i < mChans; i++) {
231 TransceiverChannel *chan = new TransceiverChannel(this, i);
232 mRxServiceLoopThreads[i] = new Thread(32768);
233 mRxServiceLoopThreads[i]->start((void * (*)(void*))
234 RxUpperLoopAdapter, (void*) chan);
235
236 chan = new TransceiverChannel(this, i);
237 mTxPriorityQueueServiceLoopThreads[i] = new Thread(32768);
238 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
239 TxUpperLoopAdapter, (void*) chan);
240 }
241
242 writeClockInterface();
243 mOn = true;
244 return true;
245}
246
247/*
248 * Stop the transceiver
249 *
250 * Perform stopping by disabling receive streaming and issuing cancellation
251 * requests to running threads. Most threads will timeout and terminate once
252 * device is disabled, but the transmit loop may block waiting on the central
253 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
254 * makes it to the thread cancellation point.
255 */
256void Transceiver::stop()
257{
258 ScopedLock lock(mLock);
259
260 if (!mOn)
261 return;
262
263 LOG(NOTICE) << "Stopping the transceiver";
264 mTxLowerLoopThread->cancel();
265 mRxLowerLoopThread->cancel();
266
267 for (size_t i = 0; i < mChans; i++) {
268 mRxServiceLoopThreads[i]->cancel();
269 mTxPriorityQueueServiceLoopThreads[i]->cancel();
270 }
271
272 LOG(INFO) << "Stopping the device";
273 mRadioInterface->stop();
274
275 for (size_t i = 0; i < mChans; i++) {
276 mRxServiceLoopThreads[i]->join();
277 mTxPriorityQueueServiceLoopThreads[i]->join();
278 delete mRxServiceLoopThreads[i];
279 delete mTxPriorityQueueServiceLoopThreads[i];
280
281 mTxPriorityQueues[i].clear();
282 }
283
284 mTxLowerLoopThread->join();
285 mRxLowerLoopThread->join();
286 delete mTxLowerLoopThread;
287 delete mRxLowerLoopThread;
288
289 mOn = false;
290 LOG(NOTICE) << "Transceiver stopped";
291}
292
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500293void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400294 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000295{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500296 signalVector *burst;
297 radioVector *radio_burst;
298
Thomas Tsou204a9f12013-10-29 18:34:16 -0400299 if (chan >= mTxPriorityQueues.size()) {
300 LOG(ALERT) << "Invalid channel " << chan;
301 return;
302 }
303
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500304 if (wTime.TN() > 7) {
305 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
306 return;
307 }
308
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500309 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
310 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000311
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500312 radio_burst = new radioVector(wTime, burst);
313
314 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000315}
316
Thomas Tsou15d743e2014-01-25 02:34:03 -0500317void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
318{
319 int TN, modFN;
320 TransceiverState *state = &mStates[chan];
321
322 TN = burst->getTime().TN();
323 modFN = burst->getTime().FN() % state->fillerModulus[TN];
324
325 delete state->fillerTable[modFN][TN];
326 state->fillerTable[modFN][TN] = burst->getVector();
327 burst->setVector(NULL);
328}
329
dburgessb3a0ca42011-10-12 07:44:40 +0000330void Transceiver::pushRadioVector(GSM::Time &nowTime)
331{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400332 int TN, modFN;
333 radioVector *burst;
334 TransceiverState *state;
335 std::vector<signalVector *> bursts(mChans);
336 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500337 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000338
Thomas Tsou204a9f12013-10-29 18:34:16 -0400339 for (size_t i = 0; i < mChans; i ++) {
340 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000341
Thomas Tsou204a9f12013-10-29 18:34:16 -0400342 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
343 LOG(NOTICE) << "dumping STALE burst in TRX->USRP interface";
Thomas Tsou15d743e2014-01-25 02:34:03 -0500344 if (state->mRetrans)
345 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500346 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400347 }
348
349 TN = nowTime.TN();
350 modFN = nowTime.FN() % state->fillerModulus[TN];
351
352 bursts[i] = state->fillerTable[modFN][TN];
353 zeros[i] = state->chanType[TN] == NONE;
354
355 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500356 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500357
358 if (state->mRetrans) {
359 updateFillerTable(i, burst);
360 } else {
361 burst->setVector(NULL);
362 filler[i] = false;
363 }
364
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500365 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400366 }
dburgessb3a0ca42011-10-12 07:44:40 +0000367 }
368
Thomas Tsou204a9f12013-10-29 18:34:16 -0400369 mRadioInterface->driveTransmitRadio(bursts, zeros);
370
Thomas Tsou15d743e2014-01-25 02:34:03 -0500371 for (size_t i = 0; i < mChans; i++) {
372 if (!filler[i])
373 delete bursts[i];
374 }
dburgessb3a0ca42011-10-12 07:44:40 +0000375}
376
Thomas Tsou204a9f12013-10-29 18:34:16 -0400377void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000378{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400379 TransceiverState *state = &mStates[chan];
380
381 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000382 case NONE:
383 case I:
384 case II:
385 case III:
386 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400387 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000388 break;
389 case IV:
390 case VI:
391 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400392 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000393 break;
394 //case V:
395 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400396 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000397 break;
ttsoufc40a842013-06-09 22:38:18 +0000398 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400399 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000400 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000401 default:
402 break;
403 }
404}
405
406
Thomas Tsou204a9f12013-10-29 18:34:16 -0400407Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
408 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000409{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400410 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000411 unsigned burstTN = currTime.TN();
412 unsigned burstFN = currTime.FN();
413
Thomas Tsou204a9f12013-10-29 18:34:16 -0400414 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000415 case NONE:
416 return OFF;
417 break;
418 case FILL:
419 return IDLE;
420 break;
421 case I:
422 return TSC;
423 /*if (burstFN % 26 == 25)
424 return IDLE;
425 else
426 return TSC;*/
427 break;
428 case II:
ttsou20642972013-03-27 22:00:25 +0000429 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000430 break;
431 case III:
432 return TSC;
433 break;
434 case IV:
435 case VI:
436 return RACH;
437 break;
438 case V: {
439 int mod51 = burstFN % 51;
440 if ((mod51 <= 36) && (mod51 >= 14))
441 return RACH;
442 else if ((mod51 == 4) || (mod51 == 5))
443 return RACH;
444 else if ((mod51 == 45) || (mod51 == 46))
445 return RACH;
446 else
447 return TSC;
448 break;
449 }
450 case VII:
451 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
452 return IDLE;
453 else
454 return TSC;
455 break;
ttsoufc40a842013-06-09 22:38:18 +0000456 case XIII: {
457 int mod52 = burstFN % 52;
458 if ((mod52 == 12) || (mod52 == 38))
459 return RACH;
460 else if ((mod52 == 25) || (mod52 == 51))
461 return IDLE;
462 else
463 return TSC;
464 break;
465 }
dburgessb3a0ca42011-10-12 07:44:40 +0000466 case LOOPBACK:
467 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
468 return IDLE;
469 else
470 return TSC;
471 break;
472 default:
473 return OFF;
474 break;
475 }
dburgessb3a0ca42011-10-12 07:44:40 +0000476}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400477
Thomas Tsou30421a72013-11-13 23:14:48 -0500478/*
479 * Detect RACH synchronization sequence within a burst. No equalization
480 * is used or available on the RACH channel.
481 */
482bool Transceiver::detectRACH(TransceiverState *state,
483 signalVector &burst,
484 complex &amp, float &toa)
485{
486 float threshold = 6.0;
487
488 return detectRACHBurst(burst, threshold, mSPSRx, &amp, &toa);
489}
490
491/*
492 * Detect normal burst training sequence midamble. Update equalization
493 * state information and channel estimate if necessary. Equalization
494 * is currently disabled.
495 */
Thomas Tsoua0179e32013-11-14 15:52:04 -0500496bool Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
Thomas Tsou30421a72013-11-13 23:14:48 -0500497 complex &amp, float &toa, GSM::Time &time)
498{
499 int tn = time.TN();
500 float chanOffset, threshold = 5.0;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500501 bool noise, needDFE = false, estimateChan = false;
Thomas Tsou30421a72013-11-13 23:14:48 -0500502 double elapsed = time - state->chanEstimateTime[tn];
503 signalVector *chanResp;
504
505 /* Check equalization update state */
Thomas Tsoufb827d02013-11-16 16:14:12 -0500506 if (needDFE && ((elapsed > 50) || (!state->chanResponse[tn]))) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500507 delete state->DFEForward[tn];
508 delete state->DFEFeedback[tn];
509 state->DFEForward[tn] = NULL;
510 state->DFEFeedback[tn] = NULL;
511
512 estimateChan = true;
513 }
514
515 /* Detect normal burst midambles */
516 if (!analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, &amp,
517 &toa, mMaxExpectedDelay, estimateChan,
518 &chanResp, &chanOffset)) {
519 return false;
520 }
521
Thomas Tsoua0179e32013-11-14 15:52:04 -0500522 noise = state->mNoiseLev;
523 state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
Thomas Tsou30421a72013-11-13 23:14:48 -0500524
525 /* Set equalizer if unabled */
526 if (needDFE && estimateChan) {
527 state->chanResponse[tn] = chanResp;
528 state->chanRespOffset[tn] = chanOffset;
529 state->chanRespAmplitude[tn] = amp;
530
531 scaleVector(*chanResp, complex(1.0, 0.0) / amp);
532
533 designDFE(*chanResp, state->SNRestimate[tn],
534 7, &state->DFEForward[tn], &state->DFEFeedback[tn]);
535
536 state->chanEstimateTime[tn] = time;
537 }
538
539 return true;;
540}
541
542/*
543 * Demodulate GMSK burst using equalization if requested. Otherwise
544 * demodulate by direct rotation and soft slicing.
545 */
546SoftVector *Transceiver::demodulate(TransceiverState *state,
547 signalVector &burst, complex amp,
548 float toa, size_t tn, bool equalize)
549{
550 if (equalize) {
551 scaleVector(burst, complex(1.0, 0.0) / amp);
552 return equalizeBurst(burst,
553 toa - state->chanRespOffset[tn],
554 mSPSRx,
555 *state->DFEForward[tn],
556 *state->DFEFeedback[tn]);
557 }
558
559 return demodulateBurst(burst, mSPSRx, amp, toa);
560}
561
562/*
563 * Pull bursts from the FIFO and handle according to the slot
564 * and burst correlation type. Equalzation is currently disabled.
565 */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400566SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
567 int &timingOffset, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000568{
Thomas Tsou30421a72013-11-13 23:14:48 -0500569 bool success, equalize = false;
570 complex amp;
571 float toa, pow, max = -1.0, avg = 0.0;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500572 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500573 signalVector *burst;
Thomas Tsouef25dba2013-11-14 15:31:24 -0500574 SoftVector *bits = NULL;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500575 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000576
Thomas Tsou30421a72013-11-13 23:14:48 -0500577 /* Blocking FIFO read */
578 radioVector *radio_burst = mReceiveFIFO[chan]->read();
579 if (!radio_burst)
580 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000581
Thomas Tsou30421a72013-11-13 23:14:48 -0500582 /* Set time and determine correlation type */
583 GSM::Time time = radio_burst->getTime();
584 CorrType type = expectedCorrType(time, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000585
Thomas Tsou30421a72013-11-13 23:14:48 -0500586 if ((type == OFF) || (type == IDLE)) {
587 delete radio_burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000588 return NULL;
589 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000590
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500591 /* Select the diversity channel with highest energy */
592 for (size_t i = 0; i < radio_burst->chans(); i++) {
593 energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
594 if (pow > max) {
595 max = pow;
596 max_i = i;
597 }
598 avg += pow;
599 }
600
601 if (max_i < 0) {
602 LOG(ALERT) << "Received empty burst";
603 delete radio_burst;
604 return NULL;
605 }
606
Thomas Tsou30421a72013-11-13 23:14:48 -0500607 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500608 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500609 avg = sqrt(avg / radio_burst->chans());
Thomas Tsoua0179e32013-11-14 15:52:04 -0500610 state->mNoiseLev = state->mNoises.avg();
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400611
Thomas Tsou30421a72013-11-13 23:14:48 -0500612 /* Detect normal or RACH bursts */
613 if (type == TSC)
Thomas Tsoua0179e32013-11-14 15:52:04 -0500614 success = detectTSC(state, *burst, amp, toa, time);
Thomas Tsou30421a72013-11-13 23:14:48 -0500615 else
Thomas Tsoua0179e32013-11-14 15:52:04 -0500616 success = detectRACH(state, *burst, amp, toa);
Thomas Tsouf0782732013-10-29 15:55:47 -0400617
Tom Tsou577cd022015-05-18 13:57:54 -0700618 /* Update noise average if no bust detected or alert on error */
619 if (success <= 0) {
620 if (!success) {
621 state->mNoises.insert(avg);
622 } else if (success == -SIGERR_CLIP) {
623 LOG(ALERT) << "Clipping detected on RACH input";
624 } else if (success < 0) {
625 LOG(ALERT) << "Unhandled RACH error";
626 }
627
Thomas Tsou30421a72013-11-13 23:14:48 -0500628 delete radio_burst;
629 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000630 }
dburgessb3a0ca42011-10-12 07:44:40 +0000631
Thomas Tsou30421a72013-11-13 23:14:48 -0500632 /* Demodulate and set output info */
633 if (equalize && (type != TSC))
634 equalize = false;
dburgessb3a0ca42011-10-12 07:44:40 +0000635
Thomas Tsoua0179e32013-11-14 15:52:04 -0500636 if (avg - state->mNoiseLev > 0.0)
637 bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500638
Thomas Tsou30421a72013-11-13 23:14:48 -0500639 wTime = time;
640 RSSI = (int) floor(20.0 * log10(rxFullScale / avg));
641 timingOffset = (int) round(toa * 256.0 / mSPSRx);
dburgessb3a0ca42011-10-12 07:44:40 +0000642
Thomas Tsou30421a72013-11-13 23:14:48 -0500643 delete radio_burst;
644
645 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +0000646}
647
dburgessb3a0ca42011-10-12 07:44:40 +0000648void Transceiver::reset()
649{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400650 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
651 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000652}
653
654
Thomas Tsou204a9f12013-10-29 18:34:16 -0400655void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000656{
dburgessb3a0ca42011-10-12 07:44:40 +0000657 int MAX_PACKET_LENGTH = 100;
658
659 // check control socket
660 char buffer[MAX_PACKET_LENGTH];
661 int msgLen = -1;
662 buffer[0] = '\0';
Thomas Tsoud647ec52013-10-29 15:17:34 -0400663
Thomas Tsou204a9f12013-10-29 18:34:16 -0400664 msgLen = mCtrlSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000665
666 if (msgLen < 1) {
667 return;
668 }
669
670 char cmdcheck[4];
671 char command[MAX_PACKET_LENGTH];
672 char response[MAX_PACKET_LENGTH];
673
674 sscanf(buffer,"%3s %s",cmdcheck,command);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400675
676 if (!chan)
677 writeClockInterface();
dburgessb3a0ca42011-10-12 07:44:40 +0000678
679 if (strcmp(cmdcheck,"CMD")!=0) {
680 LOG(WARNING) << "bogus message on control interface";
681 return;
682 }
683 LOG(INFO) << "command is " << buffer;
684
685 if (strcmp(command,"POWEROFF")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800686 stop();
687 sprintf(response,"RSP POWEROFF 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000688 }
689 else if (strcmp(command,"POWERON")==0) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800690 if (!start())
dburgessb3a0ca42011-10-12 07:44:40 +0000691 sprintf(response,"RSP POWERON 1");
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800692 else
dburgessb3a0ca42011-10-12 07:44:40 +0000693 sprintf(response,"RSP POWERON 0");
dburgessb3a0ca42011-10-12 07:44:40 +0000694 }
695 else if (strcmp(command,"SETMAXDLY")==0) {
696 //set expected maximum time-of-arrival
697 int maxDelay;
698 sscanf(buffer,"%3s %s %d",cmdcheck,command,&maxDelay);
699 mMaxExpectedDelay = maxDelay; // 1 GSM symbol is approx. 1 km
700 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
701 }
702 else if (strcmp(command,"SETRXGAIN")==0) {
703 //set expected maximum time-of-arrival
704 int newGain;
705 sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400706 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000707 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
708 }
709 else if (strcmp(command,"NOISELEV")==0) {
710 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500711 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000712 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500713 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000714 }
715 else {
716 sprintf(response,"RSP NOISELEV 1 0");
717 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500718 }
719 else if (!strcmp(command, "SETPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800720 int power;
721 sscanf(buffer, "%3s %s %d", cmdcheck, command, &power);
722 power = mRadioInterface->setPowerAttenuation(power, chan);
723 mStates[chan].mPower = power;
724 sprintf(response, "RSP SETPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000725 }
Thomas Tsoucb269a32013-11-15 14:15:47 -0500726 else if (!strcmp(command,"ADJPOWER")) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800727 int power, step;
728 sscanf(buffer, "%3s %s %d", cmdcheck, command, &step);
729 power = mStates[chan].mPower + step;
730 power = mRadioInterface->setPowerAttenuation(power, chan);
731 mStates[chan].mPower = power;
732 sprintf(response, "RSP ADJPOWER 0 %d", power);
dburgessb3a0ca42011-10-12 07:44:40 +0000733 }
dburgessb3a0ca42011-10-12 07:44:40 +0000734 else if (strcmp(command,"RXTUNE")==0) {
735 // tune receiver
736 int freqKhz;
737 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500738 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400739 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000740 LOG(ALERT) << "RX failed to tune";
741 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
742 }
743 else
744 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
745 }
746 else if (strcmp(command,"TXTUNE")==0) {
747 // tune txmtr
748 int freqKhz;
749 sscanf(buffer,"%3s %s %d",cmdcheck,command,&freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500750 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400751 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000752 LOG(ALERT) << "TX failed to tune";
753 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
754 }
755 else
756 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
757 }
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500758 else if (!strcmp(command,"SETTSC")) {
dburgessb3a0ca42011-10-12 07:44:40 +0000759 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500760 unsigned TSC;
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500761 sscanf(buffer, "%3s %s %d", cmdcheck, command, &TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000762 if (mOn)
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500763 sprintf(response, "RSP SETTSC 1 %d", TSC);
764 else if (chan && (TSC != mTSC))
765 sprintf(response, "RSP SETTSC 1 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000766 else {
767 mTSC = TSC;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400768 generateMidamble(mSPSRx, TSC);
Thomas Tsou83e06892013-08-20 16:10:01 -0400769 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000770 }
771 }
772 else if (strcmp(command,"SETSLOT")==0) {
773 // set TSC
774 int corrCode;
775 int timeslot;
776 sscanf(buffer,"%3s %s %d %d",cmdcheck,command,&timeslot,&corrCode);
777 if ((timeslot < 0) || (timeslot > 7)) {
778 LOG(WARNING) << "bogus message on control interface";
779 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
780 return;
781 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400782 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
783 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000784 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
785
786 }
787 else {
788 LOG(WARNING) << "bogus command " << command << " on control interface.";
789 }
790
Thomas Tsou204a9f12013-10-29 18:34:16 -0400791 mCtrlSockets[chan]->write(response, strlen(response) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000792}
793
Thomas Tsou204a9f12013-10-29 18:34:16 -0400794bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000795{
dburgessb3a0ca42011-10-12 07:44:40 +0000796 char buffer[gSlotLen+50];
797
798 // check data socket
Thomas Tsou204a9f12013-10-29 18:34:16 -0400799 size_t msgLen = mDataSockets[chan]->read(buffer);
dburgessb3a0ca42011-10-12 07:44:40 +0000800
801 if (msgLen!=gSlotLen+1+4+1) {
802 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
803 return false;
804 }
805
806 int timeSlot = (int) buffer[0];
807 uint64_t frameNum = 0;
808 for (int i = 0; i < 4; i++)
809 frameNum = (frameNum << 8) | (0x0ff & buffer[i+1]);
dburgessb3a0ca42011-10-12 07:44:40 +0000810
dburgessb3a0ca42011-10-12 07:44:40 +0000811 // periodically update GSM core clock
812 LOG(DEBUG) << "mTransmitDeadlineClock " << mTransmitDeadlineClock
813 << " mLastClockUpdateTime " << mLastClockUpdateTime;
dburgessb3a0ca42011-10-12 07:44:40 +0000814
Thomas Tsou204a9f12013-10-29 18:34:16 -0400815 if (!chan) {
816 if (mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0))
817 writeClockInterface();
818 }
dburgessb3a0ca42011-10-12 07:44:40 +0000819
820 LOG(DEBUG) << "rcvd. burst at: " << GSM::Time(frameNum,timeSlot);
821
822 int RSSI = (int) buffer[5];
823 static BitVector newBurst(gSlotLen);
824 BitVector::iterator itr = newBurst.begin();
825 char *bufferItr = buffer+6;
826 while (itr < newBurst.end())
827 *itr++ = *bufferItr++;
828
829 GSM::Time currTime = GSM::Time(frameNum,timeSlot);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400830
831 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000832
833 return true;
834
835
836}
dburgessb3a0ca42011-10-12 07:44:40 +0000837
Thomas Tsou204a9f12013-10-29 18:34:16 -0400838void Transceiver::driveReceiveRadio()
839{
840 if (!mRadioInterface->driveReceiveRadio())
841 usleep(100000);
842}
843
844void Transceiver::driveReceiveFIFO(size_t chan)
845{
dburgessb3a0ca42011-10-12 07:44:40 +0000846 SoftVector *rxBurst = NULL;
847 int RSSI;
848 int TOA; // in 1/256 of a symbol
849 GSM::Time burstTime;
850
Thomas Tsou204a9f12013-10-29 18:34:16 -0400851 rxBurst = pullRadioVector(burstTime, RSSI, TOA, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000852
853 if (rxBurst) {
854
855 LOG(DEBUG) << "burst parameters: "
856 << " time: " << burstTime
857 << " RSSI: " << RSSI
858 << " TOA: " << TOA
859 << " bits: " << *rxBurst;
860
861 char burstString[gSlotLen+10];
862 burstString[0] = burstTime.TN();
863 for (int i = 0; i < 4; i++)
864 burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
865 burstString[5] = RSSI;
866 burstString[6] = (TOA >> 8) & 0x0ff;
867 burstString[7] = TOA & 0x0ff;
868 SoftVector::iterator burstItr = rxBurst->begin();
869
870 for (unsigned int i = 0; i < gSlotLen; i++) {
871 burstString[8+i] =(char) round((*burstItr++)*255.0);
872 }
873 burstString[gSlotLen+9] = '\0';
874 delete rxBurst;
875
Thomas Tsou204a9f12013-10-29 18:34:16 -0400876 mDataSockets[chan]->write(burstString,gSlotLen+10);
dburgessb3a0ca42011-10-12 07:44:40 +0000877 }
dburgessb3a0ca42011-10-12 07:44:40 +0000878}
879
Thomas Tsou204a9f12013-10-29 18:34:16 -0400880void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +0000881{
882
883 /**
884 Features a carefully controlled latency mechanism, to
885 assure that transmit packets arrive at the radio/USRP
886 before they need to be transmitted.
887
888 Deadline clock indicates the burst that needs to be
889 pushed into the FIFO right NOW. If transmit queue does
890 not have a burst, stick in filler data.
891 */
892
893
894 RadioClock *radioClock = (mRadioInterface->getClock());
895
896 if (mOn) {
897 //radioClock->wait(); // wait until clock updates
898 LOG(DEBUG) << "radio clock " << radioClock->get();
899 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
900 // if underrun, then we're not providing bursts to radio/USRP fast
901 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -0400902 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000903 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +0000904 // only update latency at the defined frame interval
905 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000906 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
907 LOG(INFO) << "new latency: " << mTransmitLatency;
908 mLatencyUpdateTime = radioClock->get();
909 }
910 }
911 else {
912 // if underrun hasn't occurred in the last sec (216 frames) drop
913 // transmit latency by a timeslot
ttsou2173abf2012-08-08 00:51:31 +0000914 if (mTransmitLatency > GSM::Time(USB_LATENCY_MIN)) {
kurtis.heimerle380af32011-11-26 03:18:55 +0000915 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
916 mTransmitLatency.decTN();
917 LOG(INFO) << "reduced latency: " << mTransmitLatency;
918 mLatencyUpdateTime = radioClock->get();
919 }
920 }
921 }
dburgessb3a0ca42011-10-12 07:44:40 +0000922 }
dburgessb3a0ca42011-10-12 07:44:40 +0000923 // time to push burst to transmit FIFO
924 pushRadioVector(mTransmitDeadlineClock);
925 mTransmitDeadlineClock.incTN();
926 }
dburgessb3a0ca42011-10-12 07:44:40 +0000927 }
Thomas Tsou92c16df2013-09-28 18:04:19 -0400928
929 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +0000930}
931
932
933
934void Transceiver::writeClockInterface()
935{
936 char command[50];
937 // FIXME -- This should be adaptive.
938 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
939
940 LOG(INFO) << "ClockInterface: sending " << command;
941
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800942 mClockSocket.write(command, strlen(command) + 1);
dburgessb3a0ca42011-10-12 07:44:40 +0000943
944 mLastClockUpdateTime = mTransmitDeadlineClock;
945
Thomas Tsou92c16df2013-09-28 18:04:19 -0400946}
dburgessb3a0ca42011-10-12 07:44:40 +0000947
Thomas Tsou204a9f12013-10-29 18:34:16 -0400948void *RxUpperLoopAdapter(TransceiverChannel *chan)
949{
950 Transceiver *trx = chan->trx;
951 size_t num = chan->num;
952
953 delete chan;
954
Thomas Tsou7553aa92013-11-08 12:50:03 -0500955 trx->setPriority(0.42);
956
Thomas Tsou204a9f12013-10-29 18:34:16 -0400957 while (1) {
958 trx->driveReceiveFIFO(num);
959 pthread_testcancel();
960 }
961 return NULL;
962}
963
964void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +0000965{
Thomas Tsou7553aa92013-11-08 12:50:03 -0500966 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +0000967
dburgessb3a0ca42011-10-12 07:44:40 +0000968 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400969 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -0400970 pthread_testcancel();
971 }
972 return NULL;
973}
974
Thomas Tsou204a9f12013-10-29 18:34:16 -0400975void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -0400976{
Thomas Tsou7553aa92013-11-08 12:50:03 -0500977 transceiver->setPriority(0.44);
978
Thomas Tsou92c16df2013-09-28 18:04:19 -0400979 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400980 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +0000981 pthread_testcancel();
982 }
983 return NULL;
984}
985
Thomas Tsou204a9f12013-10-29 18:34:16 -0400986void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000987{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400988 Transceiver *trx = chan->trx;
989 size_t num = chan->num;
990
991 delete chan;
992
dburgessb3a0ca42011-10-12 07:44:40 +0000993 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400994 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +0000995 pthread_testcancel();
996 }
997 return NULL;
998}
999
Thomas Tsou204a9f12013-10-29 18:34:16 -04001000void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001001{
Thomas Tsou204a9f12013-10-29 18:34:16 -04001002 Transceiver *trx = chan->trx;
1003 size_t num = chan->num;
1004
1005 delete chan;
1006
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001007 trx->setPriority(0.40);
1008
dburgessb3a0ca42011-10-12 07:44:40 +00001009 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001010 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001011 pthread_testcancel();
1012 }
1013 return NULL;
1014}