blob: 17e0476a3b1ff32f43eaf7f85ba095a1f4587ba8 [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>
Alexander Chemerise8905a02015-06-03 23:47:56 -040025#include <iomanip> // std::setprecision
Alexander Chemerise692ce92015-06-12 00:15:31 -040026#include <fstream>
dburgessb3a0ca42011-10-12 07:44:40 +000027#include "Transceiver.h"
28#include <Logger.h>
29
Pau Espin Pedroldb936b92018-09-03 16:50:49 +020030extern "C" {
31#include "osmo_signal.h"
Pau Espin Pedrol778b30a2019-06-28 13:27:24 +020032#include "proto_trxd.h"
33
Pau Espin Pedrol15fa64b2019-07-01 20:41:55 +020034#include <osmocom/core/utils.h>
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +020035#include <osmocom/core/socket.h>
Vadim Yanitskiyb3123252019-07-15 23:53:08 +070036#include <osmocom/core/bits.h>
Pau Espin Pedroldb936b92018-09-03 16:50:49 +020037}
38
ttsou2173abf2012-08-08 00:51:31 +000039#ifdef HAVE_CONFIG_H
40#include "config.h"
41#endif
dburgessb3a0ca42011-10-12 07:44:40 +000042
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040043using namespace GSM;
44
kurtis.heimerlec842de2012-11-23 08:37:32 +000045#define USB_LATENCY_INTRVL 10,0
ttsou2173abf2012-08-08 00:51:31 +000046
Thomas Tsoufa3a7872013-10-17 21:23:34 -040047/* Number of running values use in noise average */
48#define NOISE_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000049
Thomas Tsouf0782732013-10-29 15:55:47 -040050TransceiverState::TransceiverState()
Tom Tsoua4d1a412014-11-25 15:46:56 -080051 : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
Thomas Tsouf0782732013-10-29 15:55:47 -040052{
53 for (int i = 0; i < 8; i++) {
54 chanType[i] = Transceiver::NONE;
55 fillerModulus[i] = 26;
56 chanResponse[i] = NULL;
57 DFEForward[i] = NULL;
58 DFEFeedback[i] = NULL;
59
60 for (int n = 0; n < 102; n++)
61 fillerTable[n][i] = NULL;
62 }
63}
64
65TransceiverState::~TransceiverState()
66{
67 for (int i = 0; i < 8; i++) {
68 delete chanResponse[i];
69 delete DFEForward[i];
70 delete DFEFeedback[i];
71
72 for (int n = 0; n < 102; n++)
73 delete fillerTable[n][i];
74 }
75}
76
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010077bool TransceiverState::init(FillerType filler, size_t sps, float scale, size_t rtsc, unsigned rach_delay)
Tom Tsou64ad7122015-05-19 18:26:31 -070078{
Tom Tsou64ad7122015-05-19 18:26:31 -070079 signalVector *burst;
80
81 if ((sps != 1) && (sps != 4))
82 return false;
83
84 for (size_t n = 0; n < 8; n++) {
Tom Tsou64ad7122015-05-19 18:26:31 -070085 for (size_t i = 0; i < 102; i++) {
86 switch (filler) {
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010087 case FILLER_DUMMY:
Tom Tsou8ee2f382016-03-06 20:57:34 -080088 burst = generateDummyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070089 break;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010090 case FILLER_NORM_RAND:
Tom Tsou8ee2f382016-03-06 20:57:34 -080091 burst = genRandNormalBurst(rtsc, sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070092 break;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010093 case FILLER_EDGE_RAND:
Tom Tsouaf717b22016-03-06 22:19:15 -080094 burst = generateEdgeBurst(rtsc);
95 break;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010096 case FILLER_ACCESS_RAND:
Alexander Chemeris37c52c72016-03-25 18:28:34 +030097 burst = genRandAccessBurst(rach_delay, sps, n);
Alexander Chemeris5efe0502016-03-23 17:06:32 +030098 break;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010099 case FILLER_ZERO:
Tom Tsou64ad7122015-05-19 18:26:31 -0700100 default:
Tom Tsou8ee2f382016-03-06 20:57:34 -0800101 burst = generateEmptyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -0700102 }
103
104 scaleVector(*burst, scale);
105 fillerTable[i][n] = burst;
106 }
107
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +0100108 if ((filler == FILLER_NORM_RAND) ||
109 (filler == FILLER_EDGE_RAND)) {
Alexander Chemerisf9e78be2017-03-17 15:00:34 -0700110 chanType[n] = TSC;
Tom Tsouaf717b22016-03-06 22:19:15 -0800111 }
Thomas Tsou15d743e2014-01-25 02:34:03 -0500112 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700113
114 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400115}
116
dburgessb3a0ca42011-10-12 07:44:40 +0000117Transceiver::Transceiver(int wBasePort,
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200118 const char *TRXAddress,
119 const char *GSMcoreAddress,
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800120 size_t tx_sps, size_t rx_sps, size_t chans,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400121 GSM::Time wTransmitLatency,
122 RadioInterface *wRadioInterface,
Eric Wildac0487e2019-06-17 13:02:44 +0200123 double wRssiOffset, int wStackSize)
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200124 : mBasePort(wBasePort), mLocalAddr(TRXAddress), mRemoteAddr(GSMcoreAddress),
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200125 mClockSocket(-1), mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Eric Wildac0487e2019-06-17 13:02:44 +0200126 rssiOffset(wRssiOffset), stackSize(wStackSize),
Pau Espin Pedrol758381b2019-07-16 21:55:03 +0200127 mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mExtRACH(false), mEdge(false),
128 mOn(false), mForceClockInterface(false),
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300129 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
Pau Espin Pedrol15fa64b2019-07-01 20:41:55 +0200130 mWriteBurstToDiskMask(0), mVersionTRXD(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000131{
dburgessb3a0ca42011-10-12 07:44:40 +0000132 txFullScale = mRadioInterface->fullScaleInputValue();
133 rxFullScale = mRadioInterface->fullScaleOutputValue();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300134
135 for (int i = 0; i < 8; i++) {
136 for (int j = 0; j < 8; j++)
137 mHandover[i][j] = false;
138 }
dburgessb3a0ca42011-10-12 07:44:40 +0000139}
140
141Transceiver::~Transceiver()
142{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800143 stop();
144
dburgessb3a0ca42011-10-12 07:44:40 +0000145 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400146
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200147 if (mClockSocket >= 0)
148 close(mClockSocket);
149
Thomas Tsou204a9f12013-10-29 18:34:16 -0400150 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800151 mControlServiceLoopThreads[i]->cancel();
152 mControlServiceLoopThreads[i]->join();
153 delete mControlServiceLoopThreads[i];
154
Thomas Tsou204a9f12013-10-29 18:34:16 -0400155 mTxPriorityQueues[i].clear();
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200156 if (mCtrlSockets[i] >= 0)
157 close(mCtrlSockets[i]);
158 if (mDataSockets[i] >= 0)
159 close(mDataSockets[i]);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400160 }
dburgessb3a0ca42011-10-12 07:44:40 +0000161}
Thomas Tsou83e06892013-08-20 16:10:01 -0400162
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800163/*
164 * Initialize transceiver
165 *
166 * Start or restart the control loop. Any further control is handled through the
167 * socket API. Randomize the central radio clock set the downlink burst
168 * counters. Note that the clock will not update until the radio starts, but we
169 * are still expected to report clock indications through control channel
170 * activity.
171 */
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200172bool Transceiver::init(FillerType filler, size_t rtsc, unsigned rach_delay,
173 bool edge, bool ext_rach)
Thomas Tsou83e06892013-08-20 16:10:01 -0400174{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500175 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400176
Thomas Tsou204a9f12013-10-29 18:34:16 -0400177 if (!mChans) {
178 LOG(ALERT) << "No channels assigned";
179 return false;
180 }
181
Tom Tsou2079a3c2016-03-06 00:58:56 -0800182 if (!sigProcLibSetup()) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400183 LOG(ALERT) << "Failed to initialize signal processing library";
184 return false;
185 }
186
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200187 mExtRACH = ext_rach;
Tom Tsou64464e62016-07-01 03:46:46 -0700188 mEdge = edge;
189
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200190 mDataSockets.resize(mChans, -1);
191 mCtrlSockets.resize(mChans, -1);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400192 mControlServiceLoopThreads.resize(mChans);
193 mTxPriorityQueueServiceLoopThreads.resize(mChans);
194 mRxServiceLoopThreads.resize(mChans);
195
196 mTxPriorityQueues.resize(mChans);
197 mReceiveFIFO.resize(mChans);
198 mStates.resize(mChans);
199
Thomas Tsouccb73e12014-04-15 17:41:28 -0400200 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700201 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400202 mStates[0].mRetrans = true;
203
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800204 /* Setup sockets */
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200205 mClockSocket = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
206 mLocalAddr.c_str(), mBasePort,
207 mRemoteAddr.c_str(), mBasePort + 100,
208 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
209
Thomas Tsou204a9f12013-10-29 18:34:16 -0400210 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500211 c_srcport = mBasePort + 2 * i + 1;
212 c_dstport = mBasePort + 2 * i + 101;
213 d_srcport = mBasePort + 2 * i + 2;
214 d_dstport = mBasePort + 2 * i + 102;
215
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200216 mCtrlSockets[i] = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
217 mLocalAddr.c_str(), c_srcport,
218 mRemoteAddr.c_str(), c_dstport,
219 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
220 if (mCtrlSockets[i] < 0)
221 return false;
222
223 mDataSockets[i] = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
224 mLocalAddr.c_str(), d_srcport,
225 mRemoteAddr.c_str(), d_dstport,
226 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
227 if (mCtrlSockets[i] < 0)
228 return false;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400229 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400230
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800231 /* Randomize the central clock */
232 GSM::Time startTime(random() % gHyperframe, 0);
233 mRadioInterface->getClock()->set(startTime);
234 mTransmitDeadlineClock = startTime;
235 mLastClockUpdateTime = startTime;
236 mLatencyUpdateTime = startTime;
237
238 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400239 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800240 TransceiverChannel *chan = new TransceiverChannel(this, i);
Eric Wildac0487e2019-06-17 13:02:44 +0200241 mControlServiceLoopThreads[i] = new Thread(stackSize);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800242 mControlServiceLoopThreads[i]->start((void * (*)(void*))
243 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400244
Tom Tsou64ad7122015-05-19 18:26:31 -0700245 if (i && filler == FILLER_DUMMY)
246 filler = FILLER_ZERO;
247
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300248 mStates[i].init(filler, mSPSTx, txFullScale, rtsc, rach_delay);
Thomas Tsou83e06892013-08-20 16:10:01 -0400249 }
250
251 return true;
252}
dburgessb3a0ca42011-10-12 07:44:40 +0000253
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800254/*
255 * Start the transceiver
256 *
257 * Submit command(s) to the radio device to commence streaming samples and
258 * launch threads to handle sample I/O. Re-synchronize the transmit burst
259 * counters to the central radio clock here as well.
260 */
261bool Transceiver::start()
262{
263 ScopedLock lock(mLock);
264
265 if (mOn) {
266 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300267 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800268 }
269
270 LOG(NOTICE) << "Starting the transceiver";
271
272 GSM::Time time = mRadioInterface->getClock()->get();
273 mTransmitDeadlineClock = time;
274 mLastClockUpdateTime = time;
275 mLatencyUpdateTime = time;
276
277 if (!mRadioInterface->start()) {
278 LOG(ALERT) << "Device failed to start";
279 return false;
280 }
281
282 /* Device is running - launch I/O threads */
Eric Wildac0487e2019-06-17 13:02:44 +0200283 mRxLowerLoopThread = new Thread(stackSize);
284 mTxLowerLoopThread = new Thread(stackSize);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800285 mTxLowerLoopThread->start((void * (*)(void*))
286 TxLowerLoopAdapter,(void*) this);
287 mRxLowerLoopThread->start((void * (*)(void*))
288 RxLowerLoopAdapter,(void*) this);
289
290 /* Launch uplink and downlink burst processing threads */
291 for (size_t i = 0; i < mChans; i++) {
292 TransceiverChannel *chan = new TransceiverChannel(this, i);
Eric Wildac0487e2019-06-17 13:02:44 +0200293 mRxServiceLoopThreads[i] = new Thread(stackSize);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800294 mRxServiceLoopThreads[i]->start((void * (*)(void*))
295 RxUpperLoopAdapter, (void*) chan);
296
297 chan = new TransceiverChannel(this, i);
Eric Wildac0487e2019-06-17 13:02:44 +0200298 mTxPriorityQueueServiceLoopThreads[i] = new Thread(stackSize);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800299 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
300 TxUpperLoopAdapter, (void*) chan);
301 }
302
Pau Espin Pedrol934da482017-07-04 16:25:20 +0200303 mForceClockInterface = true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800304 mOn = true;
305 return true;
306}
307
308/*
309 * Stop the transceiver
310 *
311 * Perform stopping by disabling receive streaming and issuing cancellation
312 * requests to running threads. Most threads will timeout and terminate once
313 * device is disabled, but the transmit loop may block waiting on the central
314 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
315 * makes it to the thread cancellation point.
316 */
317void Transceiver::stop()
318{
319 ScopedLock lock(mLock);
320
321 if (!mOn)
322 return;
323
324 LOG(NOTICE) << "Stopping the transceiver";
325 mTxLowerLoopThread->cancel();
326 mRxLowerLoopThread->cancel();
Tom Tsoud67bd602017-06-15 15:35:02 -0700327 mTxLowerLoopThread->join();
328 mRxLowerLoopThread->join();
329 delete mTxLowerLoopThread;
330 delete mRxLowerLoopThread;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800331
332 for (size_t i = 0; i < mChans; i++) {
333 mRxServiceLoopThreads[i]->cancel();
334 mTxPriorityQueueServiceLoopThreads[i]->cancel();
335 }
336
337 LOG(INFO) << "Stopping the device";
338 mRadioInterface->stop();
339
340 for (size_t i = 0; i < mChans; i++) {
341 mRxServiceLoopThreads[i]->join();
342 mTxPriorityQueueServiceLoopThreads[i]->join();
343 delete mRxServiceLoopThreads[i];
344 delete mTxPriorityQueueServiceLoopThreads[i];
345
346 mTxPriorityQueues[i].clear();
347 }
348
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800349 mOn = false;
350 LOG(NOTICE) << "Transceiver stopped";
351}
352
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500353void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400354 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000355{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500356 signalVector *burst;
357 radioVector *radio_burst;
358
Thomas Tsou204a9f12013-10-29 18:34:16 -0400359 if (chan >= mTxPriorityQueues.size()) {
360 LOG(ALERT) << "Invalid channel " << chan;
361 return;
362 }
363
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500364 if (wTime.TN() > 7) {
365 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
366 return;
367 }
368
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800369 /* Use the number of bits as the EDGE burst indicator */
370 if (bits.size() == EDGE_BURST_NBITS)
371 burst = modulateEdgeBurst(bits, mSPSTx);
372 else
373 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
374
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500375 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000376
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500377 radio_burst = new radioVector(wTime, burst);
378
379 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000380}
381
Thomas Tsou15d743e2014-01-25 02:34:03 -0500382void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
383{
384 int TN, modFN;
385 TransceiverState *state = &mStates[chan];
386
387 TN = burst->getTime().TN();
388 modFN = burst->getTime().FN() % state->fillerModulus[TN];
389
390 delete state->fillerTable[modFN][TN];
391 state->fillerTable[modFN][TN] = burst->getVector();
392 burst->setVector(NULL);
393}
394
dburgessb3a0ca42011-10-12 07:44:40 +0000395void Transceiver::pushRadioVector(GSM::Time &nowTime)
396{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400397 int TN, modFN;
398 radioVector *burst;
399 TransceiverState *state;
400 std::vector<signalVector *> bursts(mChans);
401 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500402 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000403
Thomas Tsou204a9f12013-10-29 18:34:16 -0400404 for (size_t i = 0; i < mChans; i ++) {
405 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000406
Thomas Tsou204a9f12013-10-29 18:34:16 -0400407 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
Pau Espin Pedrolfc73c072019-05-03 19:40:00 +0200408 LOGCHAN(i, DMAIN, NOTICE) << "dumping STALE burst in TRX->SDR interface ("
Pau Espin Pedrolf37b0ad2018-04-25 18:01:27 +0200409 << burst->getTime() <<" vs " << nowTime << "), retrans=" << state->mRetrans;
Thomas Tsou15d743e2014-01-25 02:34:03 -0500410 if (state->mRetrans)
411 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500412 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400413 }
414
415 TN = nowTime.TN();
416 modFN = nowTime.FN() % state->fillerModulus[TN];
417
418 bursts[i] = state->fillerTable[modFN][TN];
419 zeros[i] = state->chanType[TN] == NONE;
420
421 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500422 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500423
424 if (state->mRetrans) {
425 updateFillerTable(i, burst);
426 } else {
427 burst->setVector(NULL);
428 filler[i] = false;
429 }
430
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500431 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400432 }
dburgessb3a0ca42011-10-12 07:44:40 +0000433 }
434
Thomas Tsou204a9f12013-10-29 18:34:16 -0400435 mRadioInterface->driveTransmitRadio(bursts, zeros);
436
Thomas Tsou15d743e2014-01-25 02:34:03 -0500437 for (size_t i = 0; i < mChans; i++) {
438 if (!filler[i])
439 delete bursts[i];
440 }
dburgessb3a0ca42011-10-12 07:44:40 +0000441}
442
Thomas Tsou204a9f12013-10-29 18:34:16 -0400443void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000444{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400445 TransceiverState *state = &mStates[chan];
446
447 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000448 case NONE:
449 case I:
450 case II:
451 case III:
452 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400453 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000454 break;
455 case IV:
456 case VI:
457 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400458 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000459 break;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200460 //case V:
dburgessb3a0ca42011-10-12 07:44:40 +0000461 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400462 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000463 break;
ttsoufc40a842013-06-09 22:38:18 +0000464 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400465 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000466 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000467 default:
468 break;
469 }
470}
471
472
Alexander Chemerisf9e78be2017-03-17 15:00:34 -0700473CorrType Transceiver::expectedCorrType(GSM::Time currTime,
474 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000475{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300476 static int tchh_subslot[26] = { 0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,1 };
477 static int sdcch4_subslot[102] = { 3,3,3,3,0,0,2,2,2,2,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,2,2,2,2,
478 3,3,3,3,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,2,2,2,2 };
479 static int sdcch8_subslot[102] = { 5,5,5,5,6,6,6,6,7,7,7,7,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,0,0,0,0,
480 1,1,1,1,2,2,2,2,3,3,3,3,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,4,4,4,4 };
Thomas Tsou204a9f12013-10-29 18:34:16 -0400481 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000482 unsigned burstTN = currTime.TN();
483 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300484 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000485
Thomas Tsou204a9f12013-10-29 18:34:16 -0400486 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000487 case NONE:
488 return OFF;
489 break;
490 case FILL:
491 return IDLE;
492 break;
493 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300494 // TODO: Are we expecting RACH on an IDLE frame?
495/* if (burstFN % 26 == 25)
496 return IDLE;*/
497 if (mHandover[burstTN][0])
498 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000499 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000500 break;
501 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300502 subch = tchh_subslot[burstFN % 26];
503 if (subch == 1)
504 return IDLE;
505 if (mHandover[burstTN][0])
506 return RACH;
ttsou20642972013-03-27 22:00:25 +0000507 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000508 break;
509 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300510 subch = tchh_subslot[burstFN % 26];
511 if (mHandover[burstTN][subch])
512 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000513 return TSC;
514 break;
515 case IV:
516 case VI:
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200517 return mExtRACH ? EXT_RACH : RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000518 break;
519 case V: {
520 int mod51 = burstFN % 51;
521 if ((mod51 <= 36) && (mod51 >= 14))
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200522 return mExtRACH ? EXT_RACH : RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000523 else if ((mod51 == 4) || (mod51 == 5))
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200524 return mExtRACH ? EXT_RACH : RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000525 else if ((mod51 == 45) || (mod51 == 46))
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200526 return mExtRACH ? EXT_RACH : RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300527 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
528 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000529 else
530 return TSC;
531 break;
532 }
533 case VII:
534 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
535 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300536 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
537 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000538 else
539 return TSC;
540 break;
ttsoufc40a842013-06-09 22:38:18 +0000541 case XIII: {
542 int mod52 = burstFN % 52;
543 if ((mod52 == 12) || (mod52 == 38))
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200544 return mExtRACH ? EXT_RACH : RACH;
ttsoufc40a842013-06-09 22:38:18 +0000545 else if ((mod52 == 25) || (mod52 == 51))
546 return IDLE;
547 else
548 return TSC;
549 break;
550 }
dburgessb3a0ca42011-10-12 07:44:40 +0000551 case LOOPBACK:
552 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
553 return IDLE;
554 else
555 return TSC;
556 break;
557 default:
558 return OFF;
559 break;
560 }
dburgessb3a0ca42011-10-12 07:44:40 +0000561}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400562
Alexander Chemerise692ce92015-06-12 00:15:31 -0400563void writeToFile(radioVector *radio_burst, size_t chan)
564{
565 GSM::Time time = radio_burst->getTime();
566 std::ostringstream fname;
567 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
568 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
569 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
570 outfile.close();
571}
572
Thomas Tsou30421a72013-11-13 23:14:48 -0500573/*
574 * Pull bursts from the FIFO and handle according to the slot
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200575 * and burst correlation type. Equalzation is currently disabled.
Thomas Tsou30421a72013-11-13 23:14:48 -0500576 */
Pau Espin Pedrolddd18a52019-06-28 17:01:16 +0200577bool Transceiver::pullRadioVector(size_t chan, struct trx_ul_burst_ind *bi)
dburgessb3a0ca42011-10-12 07:44:40 +0000578{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800579 int rc;
Pau Espin Pedrol7ee2d102019-07-04 13:02:12 +0200580 struct estim_burst_params ebp;
581 float max = -1.0, avg = 0.0;
Pau Espin Pedrol9bb24a12019-07-03 15:43:03 +0200582 unsigned max_toa;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500583 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500584 signalVector *burst;
Pau Espin Pedrol07ddce52019-07-01 16:36:10 +0200585 GSM::Time burstTime;
Pau Espin Pedrol7dc07b92019-07-01 17:55:01 +0200586 SoftVector *rxBurst;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500587 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000588
Thomas Tsou30421a72013-11-13 23:14:48 -0500589 /* Blocking FIFO read */
590 radioVector *radio_burst = mReceiveFIFO[chan]->read();
591 if (!radio_burst)
Pau Espin Pedrolddd18a52019-06-28 17:01:16 +0200592 return false;
dburgessb3a0ca42011-10-12 07:44:40 +0000593
Thomas Tsou30421a72013-11-13 23:14:48 -0500594 /* Set time and determine correlation type */
Pau Espin Pedrol07ddce52019-07-01 16:36:10 +0200595 burstTime = radio_burst->getTime();
Pau Espin Pedrol07ddce52019-07-01 16:36:10 +0200596 CorrType type = expectedCorrType(burstTime, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000597
Tom Tsou64464e62016-07-01 03:46:46 -0700598 /* Enable 8-PSK burst detection if EDGE is enabled */
599 if (mEdge && (type == TSC))
600 type = EDGE;
601
Alexander Chemerise692ce92015-06-12 00:15:31 -0400602 /* Debug: dump bursts to disk */
603 /* bits 0-7 - chan 0 timeslots
604 * bits 8-15 - chan 1 timeslots */
Pau Espin Pedrol07ddce52019-07-01 16:36:10 +0200605 if (mWriteBurstToDiskMask & ((1<<bi->tn) << (8*chan)))
Alexander Chemerise692ce92015-06-12 00:15:31 -0400606 writeToFile(radio_burst, chan);
607
Alexander Chemeris2b542102015-06-08 22:46:38 -0400608 /* No processing if the timeslot is off.
609 * Not even power level or noise calculation. */
610 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500611 delete radio_burst;
Pau Espin Pedrolddd18a52019-06-28 17:01:16 +0200612 return false;
dburgessb3a0ca42011-10-12 07:44:40 +0000613 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000614
Pau Espin Pedrol95c83182019-07-03 16:01:12 +0200615 /* Initialize struct bi */
616 bi->nbits = 0;
617 bi->fn = burstTime.FN();
618 bi->tn = burstTime.TN();
619 bi->rssi = 0.0;
620 bi->toa = 0.0;
621 bi->noise = 0.0;
622 bi->idle = false;
Pau Espin Pedrolcf6113b2019-07-01 20:42:53 +0200623 bi->modulation = MODULATION_GMSK;
624 bi->tss = 0; /* TODO: we only support tss 0 right now */
625 bi->tsc = 0;
626 bi->ci = 0.0;
Pau Espin Pedrol95c83182019-07-03 16:01:12 +0200627
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500628 /* Select the diversity channel with highest energy */
629 for (size_t i = 0; i < radio_burst->chans(); i++) {
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +0300630 float pow = energyDetect(*radio_burst->getVector(i), 20 * mSPSRx);
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500631 if (pow > max) {
632 max = pow;
633 max_i = i;
634 }
635 avg += pow;
636 }
637
638 if (max_i < 0) {
639 LOG(ALERT) << "Received empty burst";
Pau Espin Pedrol95c83182019-07-03 16:01:12 +0200640 goto ret_idle;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500641 }
642
Thomas Tsou30421a72013-11-13 23:14:48 -0500643 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500644 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500645 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400646
Alexander Chemeris2b542102015-06-08 22:46:38 -0400647 if (type == IDLE) {
648 /* Update noise levels */
649 state->mNoises.insert(avg);
650 state->mNoiseLev = state->mNoises.avg();
Pau Espin Pedrolbe9cd662019-07-03 15:00:56 +0200651 }
Alexander Chemeris2b542102015-06-08 22:46:38 -0400652
Pau Espin Pedrolbe9cd662019-07-03 15:00:56 +0200653 bi->rssi = 20.0 * log10(rxFullScale / avg) + rssiOffset;
654 bi->noise = 20.0 * log10(rxFullScale / state->mNoiseLev) + rssiOffset;
655
Pau Espin Pedrol95c83182019-07-03 16:01:12 +0200656 if (type == IDLE)
657 goto ret_idle;
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400658
Pau Espin Pedrol9bb24a12019-07-03 15:43:03 +0200659 max_toa = (type == RACH || type == EXT_RACH) ?
660 mMaxExpectedDelayAB : mMaxExpectedDelayNB;
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200661
Thomas Tsou30421a72013-11-13 23:14:48 -0500662 /* Detect normal or RACH bursts */
Pau Espin Pedrol7ee2d102019-07-04 13:02:12 +0200663 rc = detectAnyBurst(*burst, mTSC, BURST_THRESH, mSPSRx, type, max_toa, &ebp);
Pau Espin Pedrold6dbb1b2019-07-03 15:23:56 +0200664 if (rc <= 0) {
665 if (rc == -SIGERR_CLIP)
Alexander Chemeris954b1182015-06-04 15:39:41 -0400666 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Pau Espin Pedrold6dbb1b2019-07-03 15:23:56 +0200667 else if (rc != SIGERR_NONE)
Alexander Chemeris954b1182015-06-04 15:39:41 -0400668 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Pau Espin Pedrol95c83182019-07-03 16:01:12 +0200669 goto ret_idle;
dburgessb3a0ca42011-10-12 07:44:40 +0000670 }
dburgessb3a0ca42011-10-12 07:44:40 +0000671
Pau Espin Pedrold6dbb1b2019-07-03 15:23:56 +0200672 type = (CorrType) rc;
Pau Espin Pedrol7ee2d102019-07-04 13:02:12 +0200673 bi->toa = ebp.toa;
Pau Espin Pedrolcf6113b2019-07-01 20:42:53 +0200674 bi->tsc = ebp.tsc;
675 bi->ci = ebp.ci;
Pau Espin Pedrol7ee2d102019-07-04 13:02:12 +0200676 rxBurst = demodAnyBurst(*burst, mSPSRx, ebp.amp, ebp.toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500677
Pau Espin Pedrol0e67cf22019-07-02 14:59:47 +0200678 /* EDGE demodulator returns 444 (gSlotLen * 3) bits */
Pau Espin Pedrolcf6113b2019-07-01 20:42:53 +0200679 if (rxBurst->size() == EDGE_BURST_NBITS) {
680 bi->modulation = MODULATION_8PSK;
Pau Espin Pedrol0e67cf22019-07-02 14:59:47 +0200681 bi->nbits = EDGE_BURST_NBITS;
Pau Espin Pedrolcf6113b2019-07-01 20:42:53 +0200682 } else { /* size() here is actually gSlotLen + 8, due to guard periods */
683 bi->modulation = MODULATION_GMSK;
Pau Espin Pedrol0e67cf22019-07-02 14:59:47 +0200684 bi->nbits = gSlotLen;
Pau Espin Pedrolcf6113b2019-07-01 20:42:53 +0200685 }
Pau Espin Pedrol0e67cf22019-07-02 14:59:47 +0200686
Pau Espin Pedrol25ae1902019-07-01 16:40:44 +0200687 // Convert -1..+1 soft bits to 0..1 soft bits
Pau Espin Pedrol7dc07b92019-07-01 17:55:01 +0200688 vectorSlicer(bi->rx_burst, rxBurst->begin(), bi->nbits);
Pau Espin Pedrol25ae1902019-07-01 16:40:44 +0200689
Pau Espin Pedrol7dc07b92019-07-01 17:55:01 +0200690 delete rxBurst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500691 delete radio_burst;
Pau Espin Pedrolddd18a52019-06-28 17:01:16 +0200692 return true;
Pau Espin Pedrol95c83182019-07-03 16:01:12 +0200693
694ret_idle:
695 bi->idle = true;
696 delete radio_burst;
697 return false;
dburgessb3a0ca42011-10-12 07:44:40 +0000698}
699
dburgessb3a0ca42011-10-12 07:44:40 +0000700void Transceiver::reset()
701{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400702 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
703 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000704}
705
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200706
Vadim Yanitskiybd0efb02018-03-09 02:45:07 +0700707#define MAX_PACKET_LENGTH 100
708
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700709/**
710 * Matches a buffer with a command.
711 * @param buf a buffer to look command in
712 * @param cmd a command to look in buffer
713 * @param params pointer to arguments, or NULL
714 * @return true if command matches, otherwise false
715 */
716static bool match_cmd(char *buf,
717 const char *cmd, char **params)
718{
719 size_t cmd_len = strlen(cmd);
720
721 /* Check a command itself */
722 if (strncmp(buf, cmd, cmd_len))
723 return false;
724
725 /* A command has arguments */
726 if (params != NULL) {
727 /* Make sure there is a space */
728 if (buf[cmd_len] != ' ')
729 return false;
730
731 /* Update external pointer */
732 *params = buf + cmd_len + 1;
733 }
734
735 return true;
736}
737
Thomas Tsou204a9f12013-10-29 18:34:16 -0400738void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000739{
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700740 char buffer[MAX_PACKET_LENGTH + 1];
741 char response[MAX_PACKET_LENGTH + 1];
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700742 char *command, *params;
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700743 int msgLen;
Thomas Tsoud647ec52013-10-29 15:17:34 -0400744
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700745 /* Attempt to read from control socket */
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200746 msgLen = read(mCtrlSockets[chan], buffer, MAX_PACKET_LENGTH);
747 if (msgLen <= 0) {
748 LOGCHAN(chan, DTRXCTRL, WARNING) << "mCtrlSockets read(" << mCtrlSockets[chan] << ") failed: " << msgLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000749 return;
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200750 }
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700751
752 /* Zero-terminate received string */
753 buffer[msgLen] = '\0';
dburgessb3a0ca42011-10-12 07:44:40 +0000754
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700755 /* Verify a command signature */
756 if (strncmp(buffer, "CMD ", 4)) {
Pau Espin Pedrol441d82a2018-12-04 16:37:24 +0100757 LOGC(DTRXCTRL, WARNING) << "bogus message on control interface";
dburgessb3a0ca42011-10-12 07:44:40 +0000758 return;
759 }
dburgessb3a0ca42011-10-12 07:44:40 +0000760
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700761 /* Set command pointer */
762 command = buffer + 4;
Pau Espin Pedrolfc73c072019-05-03 19:40:00 +0200763 LOGCHAN(chan, DTRXCTRL, INFO) << "command is '" << command << "'";
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700764
765 if (match_cmd(command, "POWEROFF", NULL)) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800766 stop();
767 sprintf(response,"RSP POWEROFF 0");
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700768 } else if (match_cmd(command, "POWERON", NULL)) {
Tom Tsou365bc382016-10-19 15:26:04 -0700769 if (!start()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000770 sprintf(response,"RSP POWERON 1");
Tom Tsou365bc382016-10-19 15:26:04 -0700771 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000772 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300773 for (int i = 0; i < 8; i++) {
774 for (int j = 0; j < 8; j++)
775 mHandover[i][j] = false;
776 }
Tom Tsou365bc382016-10-19 15:26:04 -0700777 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700778 } else if (match_cmd(command, "HANDOVER", &params)) {
Vadim Yanitskiyc0c6d702018-03-09 05:08:23 +0700779 unsigned ts = 0, ss = 0;
780 sscanf(params, "%u %u", &ts, &ss);
781 if (ts > 7 || ss > 7) {
782 sprintf(response, "RSP NOHANDOVER 1 %u %u", ts, ss);
783 } else {
784 mHandover[ts][ss] = true;
785 sprintf(response, "RSP HANDOVER 0 %u %u", ts, ss);
786 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700787 } else if (match_cmd(command, "NOHANDOVER", &params)) {
Vadim Yanitskiyc0c6d702018-03-09 05:08:23 +0700788 unsigned ts = 0, ss = 0;
789 sscanf(params, "%u %u", &ts, &ss);
790 if (ts > 7 || ss > 7) {
791 sprintf(response, "RSP NOHANDOVER 1 %u %u", ts, ss);
792 } else {
793 mHandover[ts][ss] = false;
794 sprintf(response, "RSP NOHANDOVER 0 %u %u", ts, ss);
795 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700796 } else if (match_cmd(command, "SETMAXDLY", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000797 //set expected maximum time-of-arrival
798 int maxDelay;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700799 sscanf(params, "%d", &maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300800 mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
dburgessb3a0ca42011-10-12 07:44:40 +0000801 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700802 } else if (match_cmd(command, "SETMAXDLYNB", &params)) {
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300803 //set expected maximum time-of-arrival
804 int maxDelay;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700805 sscanf(params, "%d", &maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300806 mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
807 sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700808 } else if (match_cmd(command, "SETRXGAIN", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000809 //set expected maximum time-of-arrival
810 int newGain;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700811 sscanf(params, "%d", &newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400812 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000813 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700814 } else if (match_cmd(command, "NOISELEV", NULL)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000815 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500816 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000817 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500818 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000819 }
820 else {
821 sprintf(response,"RSP NOISELEV 1 0");
822 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700823 } else if (match_cmd(command, "SETPOWER", &params)) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800824 int power;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700825 sscanf(params, "%d", &power);
Tom Tsoua4d1a412014-11-25 15:46:56 -0800826 power = mRadioInterface->setPowerAttenuation(power, chan);
827 mStates[chan].mPower = power;
828 sprintf(response, "RSP SETPOWER 0 %d", power);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700829 } else if (match_cmd(command, "ADJPOWER", &params)) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800830 int power, step;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700831 sscanf(params, "%d", &step);
Tom Tsoua4d1a412014-11-25 15:46:56 -0800832 power = mStates[chan].mPower + step;
833 power = mRadioInterface->setPowerAttenuation(power, chan);
834 mStates[chan].mPower = power;
835 sprintf(response, "RSP ADJPOWER 0 %d", power);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700836 } else if (match_cmd(command, "RXTUNE", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000837 // tune receiver
838 int freqKhz;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700839 sscanf(params, "%d", &freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500840 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400841 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
Pau Espin Pedrol441d82a2018-12-04 16:37:24 +0100842 LOGC(DTRXCTRL, ALERT) << "RX failed to tune";
dburgessb3a0ca42011-10-12 07:44:40 +0000843 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
844 }
845 else
846 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700847 } else if (match_cmd(command, "TXTUNE", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000848 // tune txmtr
849 int freqKhz;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700850 sscanf(params, "%d", &freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500851 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400852 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
Pau Espin Pedrol441d82a2018-12-04 16:37:24 +0100853 LOGC(DTRXCTRL, ALERT) << "TX failed to tune";
dburgessb3a0ca42011-10-12 07:44:40 +0000854 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
855 }
856 else
857 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700858 } else if (match_cmd(command, "SETTSC", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000859 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500860 unsigned TSC;
Vadim Yanitskiy8c6c5d22018-03-09 05:01:21 +0700861 sscanf(params, "%u", &TSC);
Tom Tsou60317342017-03-30 19:36:41 -0700862 if (TSC > 7) {
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500863 sprintf(response, "RSP SETTSC 1 %d", TSC);
Tom Tsou60317342017-03-30 19:36:41 -0700864 } else {
Pau Espin Pedrol441d82a2018-12-04 16:37:24 +0100865 LOGC(DTRXCTRL, NOTICE) << "Changing TSC from " << mTSC << " to " << TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000866 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400867 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000868 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700869 } else if (match_cmd(command, "SETSLOT", &params)) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700870 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000871 int corrCode;
872 int timeslot;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700873 sscanf(params, "%d %d", &timeslot, &corrCode);
dburgessb3a0ca42011-10-12 07:44:40 +0000874 if ((timeslot < 0) || (timeslot > 7)) {
Pau Espin Pedrol441d82a2018-12-04 16:37:24 +0100875 LOGC(DTRXCTRL, WARNING) << "bogus message on control interface";
dburgessb3a0ca42011-10-12 07:44:40 +0000876 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
877 return;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200878 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400879 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
880 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000881 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
Pau Espin Pedrol13c81092019-07-03 16:17:06 +0200882 } else if (match_cmd(command, "SETFORMAT", &params)) {
883 // set TRXD protocol version
884 unsigned version_recv;
885 sscanf(params, "%u", &version_recv);
886 LOGC(DTRXCTRL, INFO) << "BTS requests TRXD version switch: " << version_recv;
887 if (version_recv > TRX_DATA_FORMAT_VER) {
888 LOGC(DTRXCTRL, INFO) << "rejecting TRXD version " << version_recv
889 << "in favor of " << TRX_DATA_FORMAT_VER;
890 sprintf(response, "RSP SETFORMAT %u %u", TRX_DATA_FORMAT_VER, version_recv);
891 } else {
892 LOGC(DTRXCTRL, NOTICE) << "switching to TRXD version " << version_recv;
893 mVersionTRXD = version_recv;
894 sprintf(response, "RSP SETFORMAT %u %u", version_recv, version_recv);
895 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700896 } else if (match_cmd(command, "_SETBURSTTODISKMASK", &params)) {
Alexander Chemerise692ce92015-06-12 00:15:31 -0400897 // debug command! may change or disapear without notice
898 // set a mask which bursts to dump to disk
899 int mask;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700900 sscanf(params, "%d", &mask);
Alexander Chemerise692ce92015-06-12 00:15:31 -0400901 mWriteBurstToDiskMask = mask;
902 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700903 } else {
Pau Espin Pedrol441d82a2018-12-04 16:37:24 +0100904 LOGC(DTRXCTRL, WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200905 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000906 }
907
Pau Espin Pedrolfc73c072019-05-03 19:40:00 +0200908 LOGCHAN(chan, DTRXCTRL, INFO) << "response is '" << response << "'";
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200909 msgLen = write(mCtrlSockets[chan], response, strlen(response) + 1);
910 if (msgLen <= 0)
911 LOGCHAN(chan, DTRXCTRL, WARNING) << "mCtrlSockets write(" << mCtrlSockets[chan] << ") failed: " << msgLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000912}
913
Thomas Tsou204a9f12013-10-29 18:34:16 -0400914bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000915{
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200916 int msgLen;
Tom Tsoue8871082016-07-01 02:46:04 -0700917 int burstLen;
918 char buffer[EDGE_BURST_NBITS + 50];
Vadim Yanitskiyb3123252019-07-15 23:53:08 +0700919 struct trxd_hdr_common *chdr;
920 uint32_t fn;
dburgessb3a0ca42011-10-12 07:44:40 +0000921
922 // check data socket
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200923 msgLen = read(mDataSockets[chan], buffer, sizeof(buffer));
924 if (msgLen <= 0) {
925 LOGCHAN(chan, DTRXCTRL, WARNING) << "mDataSockets read(" << mCtrlSockets[chan] << ") failed: " << msgLen;
926 return false;
927 }
dburgessb3a0ca42011-10-12 07:44:40 +0000928
Tom Tsoue8871082016-07-01 02:46:04 -0700929 if (msgLen == gSlotLen + 1 + 4 + 1) {
930 burstLen = gSlotLen;
931 } else if (msgLen == EDGE_BURST_NBITS + 1 + 4 + 1) {
932 if (mSPSTx != 4)
933 return false;
934
935 burstLen = EDGE_BURST_NBITS;
936 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000937 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
938 return false;
939 }
940
Vadim Yanitskiyb3123252019-07-15 23:53:08 +0700941 /* Common header part: HDR version, TDMA TN & FN */
942 chdr = (struct trxd_hdr_common *) buffer;
dburgessb3a0ca42011-10-12 07:44:40 +0000943
Vadim Yanitskiyb3123252019-07-15 23:53:08 +0700944 /* Convert TDMA FN to the host endianness */
945 fn = osmo_load32be(&chdr->fn);
946
Vadim Yanitskiydd571c62019-07-15 23:56:56 +0700947 /* Make sure we support the received header format */
948 switch (chdr->version) {
949 case 0:
950 /* Version 1 has the same format */
951 case 1:
952 break;
953
954 default:
955 LOG(ERR) << "Rx TRXD message with unknown header version " << chdr->version;
956 return false;
957 }
958
Vadim Yanitskiy56c5f292019-07-16 00:02:56 +0700959 LOG(DEBUG) << "Rx TRXD message (hdr_ver=" << chdr->version << "): "
960 << "fn=" << fn << ", tn=" << chdr->tn << ", "
961 << "burst_len=" << burstLen;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200962
dburgessb3a0ca42011-10-12 07:44:40 +0000963 int RSSI = (int) buffer[5];
Tom Tsou7c741ec2016-07-19 11:20:59 -0700964 BitVector newBurst(burstLen);
dburgessb3a0ca42011-10-12 07:44:40 +0000965 BitVector::iterator itr = newBurst.begin();
966 char *bufferItr = buffer+6;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200967 while (itr < newBurst.end())
dburgessb3a0ca42011-10-12 07:44:40 +0000968 *itr++ = *bufferItr++;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200969
Vadim Yanitskiyb3123252019-07-15 23:53:08 +0700970 GSM::Time currTime = GSM::Time(fn, chdr->tn);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400971
972 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000973
974 return true;
975
976
977}
dburgessb3a0ca42011-10-12 07:44:40 +0000978
Thomas Tsou204a9f12013-10-29 18:34:16 -0400979void Transceiver::driveReceiveRadio()
980{
Pau Espin Pedroldb936b92018-09-03 16:50:49 +0200981 int rc = mRadioInterface->driveReceiveRadio();
982 if (rc == 0) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400983 usleep(100000);
Pau Espin Pedroldb936b92018-09-03 16:50:49 +0200984 } else if (rc < 0) {
985 LOG(FATAL) << "radio Interface receive failed, requesting stop.";
Pau Espin Pedrolb426e4a2019-06-04 12:39:28 +0200986 osmo_signal_dispatch(SS_MAIN, S_MAIN_STOP_REQUIRED, NULL);
Pau Espin Pedrol934da482017-07-04 16:25:20 +0200987 } else if (mForceClockInterface || mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0)) {
988 mForceClockInterface = false;
989 writeClockInterface();
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400990 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400991}
992
Pau Espin Pedrol607a4142019-07-01 13:56:17 +0200993void Transceiver::logRxBurst(size_t chan, const struct trx_ul_burst_ind *bi)
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800994{
Pau Espin Pedrol7dc07b92019-07-01 17:55:01 +0200995 std::ostringstream os;
996 for (size_t i=0; i < bi->nbits; i++) {
997 if (bi->rx_burst[i] > 0.5) os << "1";
998 else if (bi->rx_burst[i] > 0.25) os << "|";
999 else if (bi->rx_burst[i] > 0.0) os << "'";
1000 else os << "-";
1001 }
1002
Tom Tsoub0aefcb2016-03-06 03:44:34 -08001003 LOG(DEBUG) << std::fixed << std::right
Alexander Chemeris58e95912016-03-25 18:20:28 +03001004 << " chan: " << chan
Pau Espin Pedrol07ddce52019-07-01 16:36:10 +02001005 << " time: " << bi->tn << ":" << bi->fn
Pau Espin Pedrol607a4142019-07-01 13:56:17 +02001006 << " RSSI: " << std::setw(5) << std::setprecision(1) << (bi->rssi - rssiOffset)
1007 << "dBFS/" << std::setw(6) << -bi->rssi << "dBm"
1008 << " noise: " << std::setw(5) << std::setprecision(1) << (bi->noise - rssiOffset)
1009 << "dBFS/" << std::setw(6) << -bi->noise << "dBm"
Pau Espin Pedrolddd18a52019-06-28 17:01:16 +02001010 << " TOA: " << std::setw(5) << std::setprecision(2) << bi->toa
Pau Espin Pedrolcf6113b2019-07-01 20:42:53 +02001011 << " C/I: " << std::setw(5) << std::setprecision(2) << bi->ci << "dB"
Pau Espin Pedrol7dc07b92019-07-01 17:55:01 +02001012 << " bits: " << os;
Tom Tsoub0aefcb2016-03-06 03:44:34 -08001013}
1014
Thomas Tsou204a9f12013-10-29 18:34:16 -04001015void Transceiver::driveReceiveFIFO(size_t chan)
1016{
Pau Espin Pedrolddd18a52019-06-28 17:01:16 +02001017 struct trx_ul_burst_ind bi;
1018
Pau Espin Pedrol15fa64b2019-07-01 20:41:55 +02001019 if (!pullRadioVector(chan, &bi))
Pau Espin Pedrolddd18a52019-06-28 17:01:16 +02001020 return;
Pau Espin Pedrol15fa64b2019-07-01 20:41:55 +02001021 if (!bi.idle)
1022 logRxBurst(chan, &bi);
dburgessb3a0ca42011-10-12 07:44:40 +00001023
Pau Espin Pedrol15fa64b2019-07-01 20:41:55 +02001024 switch (mVersionTRXD) {
1025 case 0:
1026 trxd_send_burst_ind_v0(chan, mDataSockets[chan], &bi);
1027 break;
Pau Espin Pedrolcf6113b2019-07-01 20:42:53 +02001028 case 1:
1029 trxd_send_burst_ind_v1(chan, mDataSockets[chan], &bi);
1030 break;
Pau Espin Pedrol15fa64b2019-07-01 20:41:55 +02001031 default:
1032 OSMO_ASSERT(false);
1033 }
dburgessb3a0ca42011-10-12 07:44:40 +00001034}
1035
Thomas Tsou204a9f12013-10-29 18:34:16 -04001036void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +00001037{
1038
1039 /**
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +02001040 Features a carefully controlled latency mechanism, to
dburgessb3a0ca42011-10-12 07:44:40 +00001041 assure that transmit packets arrive at the radio/USRP
1042 before they need to be transmitted.
1043
1044 Deadline clock indicates the burst that needs to be
1045 pushed into the FIFO right NOW. If transmit queue does
1046 not have a burst, stick in filler data.
1047 */
1048
1049
1050 RadioClock *radioClock = (mRadioInterface->getClock());
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +02001051
dburgessb3a0ca42011-10-12 07:44:40 +00001052 if (mOn) {
1053 //radioClock->wait(); // wait until clock updates
1054 LOG(DEBUG) << "radio clock " << radioClock->get();
1055 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
1056 // if underrun, then we're not providing bursts to radio/USRP fast
1057 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -04001058 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001059 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +00001060 // only update latency at the defined frame interval
1061 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001062 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
Pau Espin Pedrol74bcc562018-10-02 17:30:28 +02001063 LOG(INFO) << "new latency: " << mTransmitLatency << " (underrun "
1064 << radioClock->get() << " vs " << mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL) << ")";
kurtis.heimerle380af32011-11-26 03:18:55 +00001065 mLatencyUpdateTime = radioClock->get();
1066 }
1067 }
1068 else {
1069 // if underrun hasn't occurred in the last sec (216 frames) drop
1070 // transmit latency by a timeslot
Pau Espin Pedrole564f0f2018-04-24 18:43:51 +02001071 if (mTransmitLatency > mRadioInterface->minLatency()) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001072 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1073 mTransmitLatency.decTN();
1074 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1075 mLatencyUpdateTime = radioClock->get();
1076 }
1077 }
1078 }
dburgessb3a0ca42011-10-12 07:44:40 +00001079 }
dburgessb3a0ca42011-10-12 07:44:40 +00001080 // time to push burst to transmit FIFO
1081 pushRadioVector(mTransmitDeadlineClock);
1082 mTransmitDeadlineClock.incTN();
1083 }
dburgessb3a0ca42011-10-12 07:44:40 +00001084 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001085
1086 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001087}
1088
1089
1090
1091void Transceiver::writeClockInterface()
1092{
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +02001093 int msgLen;
dburgessb3a0ca42011-10-12 07:44:40 +00001094 char command[50];
1095 // FIXME -- This should be adaptive.
1096 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1097
1098 LOG(INFO) << "ClockInterface: sending " << command;
1099
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +02001100 msgLen = write(mClockSocket, command, strlen(command) + 1);
1101 if (msgLen <= 0)
1102 LOG(WARNING) << "mClockSocket write(" << mClockSocket << ") failed: " << msgLen;
dburgessb3a0ca42011-10-12 07:44:40 +00001103
1104 mLastClockUpdateTime = mTransmitDeadlineClock;
1105
Thomas Tsou92c16df2013-09-28 18:04:19 -04001106}
dburgessb3a0ca42011-10-12 07:44:40 +00001107
Thomas Tsou204a9f12013-10-29 18:34:16 -04001108void *RxUpperLoopAdapter(TransceiverChannel *chan)
1109{
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001110 char thread_name[16];
Thomas Tsou204a9f12013-10-29 18:34:16 -04001111 Transceiver *trx = chan->trx;
1112 size_t num = chan->num;
1113
1114 delete chan;
1115
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001116 snprintf(thread_name, 16, "RxUpper%zu", num);
1117 set_selfthread_name(thread_name);
1118
Thomas Tsou7553aa92013-11-08 12:50:03 -05001119 trx->setPriority(0.42);
1120
Thomas Tsou204a9f12013-10-29 18:34:16 -04001121 while (1) {
1122 trx->driveReceiveFIFO(num);
1123 pthread_testcancel();
1124 }
1125 return NULL;
1126}
1127
1128void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001129{
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001130 set_selfthread_name("RxLower");
1131
Thomas Tsou7553aa92013-11-08 12:50:03 -05001132 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001133
dburgessb3a0ca42011-10-12 07:44:40 +00001134 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001135 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001136 pthread_testcancel();
1137 }
1138 return NULL;
1139}
1140
Thomas Tsou204a9f12013-10-29 18:34:16 -04001141void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001142{
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001143 set_selfthread_name("TxLower");
1144
Thomas Tsou7553aa92013-11-08 12:50:03 -05001145 transceiver->setPriority(0.44);
1146
Thomas Tsou92c16df2013-09-28 18:04:19 -04001147 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001148 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001149 pthread_testcancel();
1150 }
1151 return NULL;
1152}
1153
Thomas Tsou204a9f12013-10-29 18:34:16 -04001154void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001155{
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001156 char thread_name[16];
Thomas Tsou204a9f12013-10-29 18:34:16 -04001157 Transceiver *trx = chan->trx;
1158 size_t num = chan->num;
1159
1160 delete chan;
1161
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001162 snprintf(thread_name, 16, "CtrlService%zu", num);
1163 set_selfthread_name(thread_name);
1164
dburgessb3a0ca42011-10-12 07:44:40 +00001165 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001166 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001167 pthread_testcancel();
1168 }
1169 return NULL;
1170}
1171
Thomas Tsou204a9f12013-10-29 18:34:16 -04001172void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001173{
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001174 char thread_name[16];
Thomas Tsou204a9f12013-10-29 18:34:16 -04001175 Transceiver *trx = chan->trx;
1176 size_t num = chan->num;
1177
1178 delete chan;
1179
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001180 snprintf(thread_name, 16, "TxUpper%zu", num);
1181 set_selfthread_name(thread_name);
1182
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001183 trx->setPriority(0.40);
1184
dburgessb3a0ca42011-10-12 07:44:40 +00001185 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001186 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001187 pthread_testcancel();
1188 }
1189 return NULL;
1190}