blob: af6b0dd26ab7ddd905c87f46b1c1a8226b9fa853 [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
2* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
3*
Pau Espin Pedrol21d03d32019-07-22 12:05:52 +02004* SPDX-License-Identifier: GPL-3.0+
5*
dburgessb3a0ca42011-10-12 07:44:40 +00006* This software is distributed under the terms of the GNU Public License.
7* See the COPYING file in the main directory for details.
8*
9* This use of this software may be subject to additional restrictions.
10* See the LEGAL file in the main directory for details.
11
12 This program is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
24*/
25
dburgessb3a0ca42011-10-12 07:44:40 +000026#include <stdio.h>
Alexander Chemerise8905a02015-06-03 23:47:56 -040027#include <iomanip> // std::setprecision
Alexander Chemerise692ce92015-06-12 00:15:31 -040028#include <fstream>
dburgessb3a0ca42011-10-12 07:44:40 +000029#include "Transceiver.h"
30#include <Logger.h>
31
Pau Espin Pedroldb936b92018-09-03 16:50:49 +020032extern "C" {
33#include "osmo_signal.h"
Pau Espin Pedrol778b30a2019-06-28 13:27:24 +020034#include "proto_trxd.h"
35
Pau Espin Pedrol15fa64b2019-07-01 20:41:55 +020036#include <osmocom/core/utils.h>
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +020037#include <osmocom/core/socket.h>
Vadim Yanitskiyb3123252019-07-15 23:53:08 +070038#include <osmocom/core/bits.h>
Pau Espin Pedroldb936b92018-09-03 16:50:49 +020039}
40
ttsou2173abf2012-08-08 00:51:31 +000041#ifdef HAVE_CONFIG_H
42#include "config.h"
43#endif
dburgessb3a0ca42011-10-12 07:44:40 +000044
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040045using namespace GSM;
46
kurtis.heimerlec842de2012-11-23 08:37:32 +000047#define USB_LATENCY_INTRVL 10,0
ttsou2173abf2012-08-08 00:51:31 +000048
Thomas Tsoufa3a7872013-10-17 21:23:34 -040049/* Number of running values use in noise average */
50#define NOISE_CNT 20
ttsoue8dde022012-12-06 15:43:55 +000051
Thomas Tsouf0782732013-10-29 15:55:47 -040052TransceiverState::TransceiverState()
Tom Tsoua4d1a412014-11-25 15:46:56 -080053 : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), mPower(0.0)
Thomas Tsouf0782732013-10-29 15:55:47 -040054{
55 for (int i = 0; i < 8; i++) {
56 chanType[i] = Transceiver::NONE;
57 fillerModulus[i] = 26;
58 chanResponse[i] = NULL;
59 DFEForward[i] = NULL;
60 DFEFeedback[i] = NULL;
61
62 for (int n = 0; n < 102; n++)
63 fillerTable[n][i] = NULL;
64 }
65}
66
67TransceiverState::~TransceiverState()
68{
69 for (int i = 0; i < 8; i++) {
70 delete chanResponse[i];
71 delete DFEForward[i];
72 delete DFEFeedback[i];
73
74 for (int n = 0; n < 102; n++)
75 delete fillerTable[n][i];
76 }
77}
78
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010079bool TransceiverState::init(FillerType filler, size_t sps, float scale, size_t rtsc, unsigned rach_delay)
Tom Tsou64ad7122015-05-19 18:26:31 -070080{
Tom Tsou64ad7122015-05-19 18:26:31 -070081 signalVector *burst;
82
83 if ((sps != 1) && (sps != 4))
84 return false;
85
86 for (size_t n = 0; n < 8; n++) {
Tom Tsou64ad7122015-05-19 18:26:31 -070087 for (size_t i = 0; i < 102; i++) {
88 switch (filler) {
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010089 case FILLER_DUMMY:
Tom Tsou8ee2f382016-03-06 20:57:34 -080090 burst = generateDummyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070091 break;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010092 case FILLER_NORM_RAND:
Tom Tsou8ee2f382016-03-06 20:57:34 -080093 burst = genRandNormalBurst(rtsc, sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -070094 break;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010095 case FILLER_EDGE_RAND:
Tom Tsouaf717b22016-03-06 22:19:15 -080096 burst = generateEdgeBurst(rtsc);
97 break;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +010098 case FILLER_ACCESS_RAND:
Alexander Chemeris37c52c72016-03-25 18:28:34 +030099 burst = genRandAccessBurst(rach_delay, sps, n);
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300100 break;
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +0100101 case FILLER_ZERO:
Tom Tsou64ad7122015-05-19 18:26:31 -0700102 default:
Tom Tsou8ee2f382016-03-06 20:57:34 -0800103 burst = generateEmptyBurst(sps, n);
Tom Tsou64ad7122015-05-19 18:26:31 -0700104 }
105
106 scaleVector(*burst, scale);
107 fillerTable[i][n] = burst;
108 }
109
Pau Espin Pedrolefac20b2018-02-21 14:59:19 +0100110 if ((filler == FILLER_NORM_RAND) ||
111 (filler == FILLER_EDGE_RAND)) {
Alexander Chemerisf9e78be2017-03-17 15:00:34 -0700112 chanType[n] = TSC;
Tom Tsouaf717b22016-03-06 22:19:15 -0800113 }
Thomas Tsou15d743e2014-01-25 02:34:03 -0500114 }
Tom Tsou64ad7122015-05-19 18:26:31 -0700115
116 return false;
Thomas Tsouf0782732013-10-29 15:55:47 -0400117}
118
dburgessb3a0ca42011-10-12 07:44:40 +0000119Transceiver::Transceiver(int wBasePort,
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200120 const char *TRXAddress,
121 const char *GSMcoreAddress,
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800122 size_t tx_sps, size_t rx_sps, size_t chans,
Alexander Chemerise8905a02015-06-03 23:47:56 -0400123 GSM::Time wTransmitLatency,
124 RadioInterface *wRadioInterface,
Eric Wildac0487e2019-06-17 13:02:44 +0200125 double wRssiOffset, int wStackSize)
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200126 : mBasePort(wBasePort), mLocalAddr(TRXAddress), mRemoteAddr(GSMcoreAddress),
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200127 mClockSocket(-1), mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
Eric Wildac0487e2019-06-17 13:02:44 +0200128 rssiOffset(wRssiOffset), stackSize(wStackSize),
Pau Espin Pedrol758381b2019-07-16 21:55:03 +0200129 mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mExtRACH(false), mEdge(false),
130 mOn(false), mForceClockInterface(false),
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300131 mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
Pau Espin Pedrol15fa64b2019-07-01 20:41:55 +0200132 mWriteBurstToDiskMask(0), mVersionTRXD(0)
dburgessb3a0ca42011-10-12 07:44:40 +0000133{
dburgessb3a0ca42011-10-12 07:44:40 +0000134 txFullScale = mRadioInterface->fullScaleInputValue();
135 rxFullScale = mRadioInterface->fullScaleOutputValue();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300136
137 for (int i = 0; i < 8; i++) {
138 for (int j = 0; j < 8; j++)
139 mHandover[i][j] = false;
140 }
dburgessb3a0ca42011-10-12 07:44:40 +0000141}
142
143Transceiver::~Transceiver()
144{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800145 stop();
146
dburgessb3a0ca42011-10-12 07:44:40 +0000147 sigProcLibDestroy();
Thomas Tsoud647ec52013-10-29 15:17:34 -0400148
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200149 if (mClockSocket >= 0)
150 close(mClockSocket);
151
Thomas Tsou204a9f12013-10-29 18:34:16 -0400152 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800153 mControlServiceLoopThreads[i]->cancel();
154 mControlServiceLoopThreads[i]->join();
155 delete mControlServiceLoopThreads[i];
156
Thomas Tsou204a9f12013-10-29 18:34:16 -0400157 mTxPriorityQueues[i].clear();
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200158 if (mCtrlSockets[i] >= 0)
159 close(mCtrlSockets[i]);
160 if (mDataSockets[i] >= 0)
161 close(mDataSockets[i]);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400162 }
dburgessb3a0ca42011-10-12 07:44:40 +0000163}
Thomas Tsou83e06892013-08-20 16:10:01 -0400164
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800165/*
166 * Initialize transceiver
167 *
168 * Start or restart the control loop. Any further control is handled through the
169 * socket API. Randomize the central radio clock set the downlink burst
170 * counters. Note that the clock will not update until the radio starts, but we
171 * are still expected to report clock indications through control channel
172 * activity.
173 */
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200174bool Transceiver::init(FillerType filler, size_t rtsc, unsigned rach_delay,
175 bool edge, bool ext_rach)
Thomas Tsou83e06892013-08-20 16:10:01 -0400176{
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500177 int d_srcport, d_dstport, c_srcport, c_dstport;
Thomas Tsouf0782732013-10-29 15:55:47 -0400178
Thomas Tsou204a9f12013-10-29 18:34:16 -0400179 if (!mChans) {
180 LOG(ALERT) << "No channels assigned";
181 return false;
182 }
183
Tom Tsou2079a3c2016-03-06 00:58:56 -0800184 if (!sigProcLibSetup()) {
Thomas Tsou83e06892013-08-20 16:10:01 -0400185 LOG(ALERT) << "Failed to initialize signal processing library";
186 return false;
187 }
188
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200189 mExtRACH = ext_rach;
Tom Tsou64464e62016-07-01 03:46:46 -0700190 mEdge = edge;
191
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200192 mDataSockets.resize(mChans, -1);
193 mCtrlSockets.resize(mChans, -1);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400194 mControlServiceLoopThreads.resize(mChans);
195 mTxPriorityQueueServiceLoopThreads.resize(mChans);
196 mRxServiceLoopThreads.resize(mChans);
197
198 mTxPriorityQueues.resize(mChans);
199 mReceiveFIFO.resize(mChans);
200 mStates.resize(mChans);
201
Thomas Tsouccb73e12014-04-15 17:41:28 -0400202 /* Filler table retransmissions - support only on channel 0 */
Tom Tsou64ad7122015-05-19 18:26:31 -0700203 if (filler == FILLER_DUMMY)
Thomas Tsouccb73e12014-04-15 17:41:28 -0400204 mStates[0].mRetrans = true;
205
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800206 /* Setup sockets */
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200207 mClockSocket = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
208 mLocalAddr.c_str(), mBasePort,
209 mRemoteAddr.c_str(), mBasePort + 100,
210 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
211
Thomas Tsou204a9f12013-10-29 18:34:16 -0400212 for (size_t i = 0; i < mChans; i++) {
Thomas Tsoue1ce9252013-11-13 22:40:44 -0500213 c_srcport = mBasePort + 2 * i + 1;
214 c_dstport = mBasePort + 2 * i + 101;
215 d_srcport = mBasePort + 2 * i + 2;
216 d_dstport = mBasePort + 2 * i + 102;
217
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200218 mCtrlSockets[i] = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
219 mLocalAddr.c_str(), c_srcport,
220 mRemoteAddr.c_str(), c_dstport,
221 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
222 if (mCtrlSockets[i] < 0)
223 return false;
224
225 mDataSockets[i] = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
226 mLocalAddr.c_str(), d_srcport,
227 mRemoteAddr.c_str(), d_dstport,
228 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
229 if (mCtrlSockets[i] < 0)
230 return false;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400231 }
Thomas Tsou83e06892013-08-20 16:10:01 -0400232
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800233 /* Randomize the central clock */
234 GSM::Time startTime(random() % gHyperframe, 0);
235 mRadioInterface->getClock()->set(startTime);
236 mTransmitDeadlineClock = startTime;
237 mLastClockUpdateTime = startTime;
238 mLatencyUpdateTime = startTime;
239
240 /* Start control threads */
Thomas Tsou204a9f12013-10-29 18:34:16 -0400241 for (size_t i = 0; i < mChans; i++) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800242 TransceiverChannel *chan = new TransceiverChannel(this, i);
Eric Wildac0487e2019-06-17 13:02:44 +0200243 mControlServiceLoopThreads[i] = new Thread(stackSize);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800244 mControlServiceLoopThreads[i]->start((void * (*)(void*))
245 ControlServiceLoopAdapter, (void*) chan);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400246
Tom Tsou64ad7122015-05-19 18:26:31 -0700247 if (i && filler == FILLER_DUMMY)
248 filler = FILLER_ZERO;
249
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300250 mStates[i].init(filler, mSPSTx, txFullScale, rtsc, rach_delay);
Thomas Tsou83e06892013-08-20 16:10:01 -0400251 }
252
253 return true;
254}
dburgessb3a0ca42011-10-12 07:44:40 +0000255
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800256/*
257 * Start the transceiver
258 *
259 * Submit command(s) to the radio device to commence streaming samples and
260 * launch threads to handle sample I/O. Re-synchronize the transmit burst
261 * counters to the central radio clock here as well.
262 */
263bool Transceiver::start()
264{
265 ScopedLock lock(mLock);
266
267 if (mOn) {
268 LOG(ERR) << "Transceiver already running";
Ivan Kluchnikov194a9b12015-04-23 17:08:27 +0300269 return true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800270 }
271
272 LOG(NOTICE) << "Starting the transceiver";
273
274 GSM::Time time = mRadioInterface->getClock()->get();
275 mTransmitDeadlineClock = time;
276 mLastClockUpdateTime = time;
277 mLatencyUpdateTime = time;
278
279 if (!mRadioInterface->start()) {
280 LOG(ALERT) << "Device failed to start";
281 return false;
282 }
283
284 /* Device is running - launch I/O threads */
Eric Wildac0487e2019-06-17 13:02:44 +0200285 mRxLowerLoopThread = new Thread(stackSize);
286 mTxLowerLoopThread = new Thread(stackSize);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800287 mTxLowerLoopThread->start((void * (*)(void*))
288 TxLowerLoopAdapter,(void*) this);
289 mRxLowerLoopThread->start((void * (*)(void*))
290 RxLowerLoopAdapter,(void*) this);
291
292 /* Launch uplink and downlink burst processing threads */
293 for (size_t i = 0; i < mChans; i++) {
294 TransceiverChannel *chan = new TransceiverChannel(this, i);
Eric Wildac0487e2019-06-17 13:02:44 +0200295 mRxServiceLoopThreads[i] = new Thread(stackSize);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800296 mRxServiceLoopThreads[i]->start((void * (*)(void*))
297 RxUpperLoopAdapter, (void*) chan);
298
299 chan = new TransceiverChannel(this, i);
Eric Wildac0487e2019-06-17 13:02:44 +0200300 mTxPriorityQueueServiceLoopThreads[i] = new Thread(stackSize);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800301 mTxPriorityQueueServiceLoopThreads[i]->start((void * (*)(void*))
302 TxUpperLoopAdapter, (void*) chan);
303 }
304
Pau Espin Pedrol934da482017-07-04 16:25:20 +0200305 mForceClockInterface = true;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800306 mOn = true;
307 return true;
308}
309
310/*
311 * Stop the transceiver
312 *
313 * Perform stopping by disabling receive streaming and issuing cancellation
314 * requests to running threads. Most threads will timeout and terminate once
315 * device is disabled, but the transmit loop may block waiting on the central
316 * UMTS clock. Explicitly signal the clock to make sure that the transmit loop
317 * makes it to the thread cancellation point.
318 */
319void Transceiver::stop()
320{
321 ScopedLock lock(mLock);
322
323 if (!mOn)
324 return;
325
326 LOG(NOTICE) << "Stopping the transceiver";
327 mTxLowerLoopThread->cancel();
328 mRxLowerLoopThread->cancel();
Tom Tsoud67bd602017-06-15 15:35:02 -0700329 mTxLowerLoopThread->join();
330 mRxLowerLoopThread->join();
331 delete mTxLowerLoopThread;
332 delete mRxLowerLoopThread;
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800333
334 for (size_t i = 0; i < mChans; i++) {
335 mRxServiceLoopThreads[i]->cancel();
336 mTxPriorityQueueServiceLoopThreads[i]->cancel();
337 }
338
339 LOG(INFO) << "Stopping the device";
340 mRadioInterface->stop();
341
342 for (size_t i = 0; i < mChans; i++) {
343 mRxServiceLoopThreads[i]->join();
344 mTxPriorityQueueServiceLoopThreads[i]->join();
345 delete mRxServiceLoopThreads[i];
346 delete mTxPriorityQueueServiceLoopThreads[i];
347
348 mTxPriorityQueues[i].clear();
349 }
350
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800351 mOn = false;
352 LOG(NOTICE) << "Transceiver stopped";
353}
354
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500355void Transceiver::addRadioVector(size_t chan, BitVector &bits,
Thomas Tsou204a9f12013-10-29 18:34:16 -0400356 int RSSI, GSM::Time &wTime)
dburgessb3a0ca42011-10-12 07:44:40 +0000357{
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500358 signalVector *burst;
359 radioVector *radio_burst;
360
Thomas Tsou204a9f12013-10-29 18:34:16 -0400361 if (chan >= mTxPriorityQueues.size()) {
362 LOG(ALERT) << "Invalid channel " << chan;
363 return;
364 }
365
Thomas Tsou2d0c00b2013-11-14 15:28:23 -0500366 if (wTime.TN() > 7) {
367 LOG(ALERT) << "Received burst with invalid slot " << wTime.TN();
368 return;
369 }
370
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800371 /* Use the number of bits as the EDGE burst indicator */
372 if (bits.size() == EDGE_BURST_NBITS)
373 burst = modulateEdgeBurst(bits, mSPSTx);
374 else
375 burst = modulateBurst(bits, 8 + (wTime.TN() % 4 == 0), mSPSTx);
376
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500377 scaleVector(*burst, txFullScale * pow(10, -RSSI / 10));
dburgessb3a0ca42011-10-12 07:44:40 +0000378
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500379 radio_burst = new radioVector(wTime, burst);
380
381 mTxPriorityQueues[chan].write(radio_burst);
dburgessb3a0ca42011-10-12 07:44:40 +0000382}
383
Thomas Tsou15d743e2014-01-25 02:34:03 -0500384void Transceiver::updateFillerTable(size_t chan, radioVector *burst)
385{
386 int TN, modFN;
387 TransceiverState *state = &mStates[chan];
388
389 TN = burst->getTime().TN();
390 modFN = burst->getTime().FN() % state->fillerModulus[TN];
391
392 delete state->fillerTable[modFN][TN];
393 state->fillerTable[modFN][TN] = burst->getVector();
394 burst->setVector(NULL);
395}
396
dburgessb3a0ca42011-10-12 07:44:40 +0000397void Transceiver::pushRadioVector(GSM::Time &nowTime)
398{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400399 int TN, modFN;
400 radioVector *burst;
401 TransceiverState *state;
402 std::vector<signalVector *> bursts(mChans);
403 std::vector<bool> zeros(mChans);
Thomas Tsou15d743e2014-01-25 02:34:03 -0500404 std::vector<bool> filler(mChans, true);
dburgessb3a0ca42011-10-12 07:44:40 +0000405
Thomas Tsou204a9f12013-10-29 18:34:16 -0400406 for (size_t i = 0; i < mChans; i ++) {
407 state = &mStates[i];
dburgessb3a0ca42011-10-12 07:44:40 +0000408
Thomas Tsou204a9f12013-10-29 18:34:16 -0400409 while ((burst = mTxPriorityQueues[i].getStaleBurst(nowTime))) {
Pau Espin Pedrolfc73c072019-05-03 19:40:00 +0200410 LOGCHAN(i, DMAIN, NOTICE) << "dumping STALE burst in TRX->SDR interface ("
Pau Espin Pedrolf37b0ad2018-04-25 18:01:27 +0200411 << burst->getTime() <<" vs " << nowTime << "), retrans=" << state->mRetrans;
Thomas Tsou15d743e2014-01-25 02:34:03 -0500412 if (state->mRetrans)
413 updateFillerTable(i, burst);
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500414 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400415 }
416
417 TN = nowTime.TN();
418 modFN = nowTime.FN() % state->fillerModulus[TN];
419
420 bursts[i] = state->fillerTable[modFN][TN];
421 zeros[i] = state->chanType[TN] == NONE;
422
423 if ((burst = mTxPriorityQueues[i].getCurrentBurst(nowTime))) {
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500424 bursts[i] = burst->getVector();
Thomas Tsou15d743e2014-01-25 02:34:03 -0500425
426 if (state->mRetrans) {
427 updateFillerTable(i, burst);
428 } else {
429 burst->setVector(NULL);
430 filler[i] = false;
431 }
432
Thomas Tsoua2fe91a2013-11-13 22:48:11 -0500433 delete burst;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400434 }
dburgessb3a0ca42011-10-12 07:44:40 +0000435 }
436
Thomas Tsou204a9f12013-10-29 18:34:16 -0400437 mRadioInterface->driveTransmitRadio(bursts, zeros);
438
Thomas Tsou15d743e2014-01-25 02:34:03 -0500439 for (size_t i = 0; i < mChans; i++) {
440 if (!filler[i])
441 delete bursts[i];
442 }
dburgessb3a0ca42011-10-12 07:44:40 +0000443}
444
Thomas Tsou204a9f12013-10-29 18:34:16 -0400445void Transceiver::setModulus(size_t timeslot, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000446{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400447 TransceiverState *state = &mStates[chan];
448
449 switch (state->chanType[timeslot]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000450 case NONE:
451 case I:
452 case II:
453 case III:
454 case FILL:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400455 state->fillerModulus[timeslot] = 26;
dburgessb3a0ca42011-10-12 07:44:40 +0000456 break;
457 case IV:
458 case VI:
459 case V:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400460 state->fillerModulus[timeslot] = 51;
dburgessb3a0ca42011-10-12 07:44:40 +0000461 break;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200462 //case V:
dburgessb3a0ca42011-10-12 07:44:40 +0000463 case VII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400464 state->fillerModulus[timeslot] = 102;
dburgessb3a0ca42011-10-12 07:44:40 +0000465 break;
ttsoufc40a842013-06-09 22:38:18 +0000466 case XIII:
Thomas Tsou204a9f12013-10-29 18:34:16 -0400467 state->fillerModulus[timeslot] = 52;
ttsoufc40a842013-06-09 22:38:18 +0000468 break;
dburgessb3a0ca42011-10-12 07:44:40 +0000469 default:
470 break;
471 }
472}
473
474
Alexander Chemerisf9e78be2017-03-17 15:00:34 -0700475CorrType Transceiver::expectedCorrType(GSM::Time currTime,
476 size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000477{
Alexander Chemeris5a068062015-06-20 01:38:47 +0300478 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 };
479 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,
480 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 };
481 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,
482 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 -0400483 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000484 unsigned burstTN = currTime.TN();
485 unsigned burstFN = currTime.FN();
Alexander Chemeris5a068062015-06-20 01:38:47 +0300486 int subch;
dburgessb3a0ca42011-10-12 07:44:40 +0000487
Thomas Tsou204a9f12013-10-29 18:34:16 -0400488 switch (state->chanType[burstTN]) {
dburgessb3a0ca42011-10-12 07:44:40 +0000489 case NONE:
490 return OFF;
491 break;
492 case FILL:
493 return IDLE;
494 break;
495 case I:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300496 // TODO: Are we expecting RACH on an IDLE frame?
497/* if (burstFN % 26 == 25)
498 return IDLE;*/
499 if (mHandover[burstTN][0])
500 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000501 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000502 break;
503 case II:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300504 subch = tchh_subslot[burstFN % 26];
505 if (subch == 1)
506 return IDLE;
507 if (mHandover[burstTN][0])
508 return RACH;
ttsou20642972013-03-27 22:00:25 +0000509 return TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000510 break;
511 case III:
Alexander Chemeris5a068062015-06-20 01:38:47 +0300512 subch = tchh_subslot[burstFN % 26];
513 if (mHandover[burstTN][subch])
514 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000515 return TSC;
516 break;
517 case IV:
518 case VI:
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200519 return mExtRACH ? EXT_RACH : RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000520 break;
521 case V: {
522 int mod51 = burstFN % 51;
523 if ((mod51 <= 36) && (mod51 >= 14))
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200524 return mExtRACH ? EXT_RACH : RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000525 else if ((mod51 == 4) || (mod51 == 5))
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200526 return mExtRACH ? EXT_RACH : RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000527 else if ((mod51 == 45) || (mod51 == 46))
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200528 return mExtRACH ? EXT_RACH : RACH;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300529 else if (mHandover[burstTN][sdcch4_subslot[burstFN % 102]])
530 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000531 else
532 return TSC;
533 break;
534 }
535 case VII:
536 if ((burstFN % 51 <= 14) && (burstFN % 51 >= 12))
537 return IDLE;
Alexander Chemeris5a068062015-06-20 01:38:47 +0300538 else if (mHandover[burstTN][sdcch8_subslot[burstFN % 102]])
539 return RACH;
dburgessb3a0ca42011-10-12 07:44:40 +0000540 else
541 return TSC;
542 break;
ttsoufc40a842013-06-09 22:38:18 +0000543 case XIII: {
544 int mod52 = burstFN % 52;
545 if ((mod52 == 12) || (mod52 == 38))
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200546 return mExtRACH ? EXT_RACH : RACH;
ttsoufc40a842013-06-09 22:38:18 +0000547 else if ((mod52 == 25) || (mod52 == 51))
548 return IDLE;
549 else
550 return TSC;
551 break;
552 }
dburgessb3a0ca42011-10-12 07:44:40 +0000553 case LOOPBACK:
554 if ((burstFN % 51 <= 50) && (burstFN % 51 >=48))
555 return IDLE;
556 else
557 return TSC;
558 break;
559 default:
560 return OFF;
561 break;
562 }
dburgessb3a0ca42011-10-12 07:44:40 +0000563}
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400564
Alexander Chemerise692ce92015-06-12 00:15:31 -0400565void writeToFile(radioVector *radio_burst, size_t chan)
566{
567 GSM::Time time = radio_burst->getTime();
568 std::ostringstream fname;
569 fname << chan << "_" << time.FN() << "_" << time.TN() << ".fc";
570 std::ofstream outfile (fname.str().c_str(), std::ofstream::binary);
571 outfile.write((char*)radio_burst->getVector()->begin(), radio_burst->getVector()->size() * 2 * sizeof(float));
572 outfile.close();
573}
574
Thomas Tsou30421a72013-11-13 23:14:48 -0500575/*
576 * Pull bursts from the FIFO and handle according to the slot
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200577 * and burst correlation type. Equalzation is currently disabled.
Thomas Tsou30421a72013-11-13 23:14:48 -0500578 */
Pau Espin Pedrolddd18a52019-06-28 17:01:16 +0200579bool Transceiver::pullRadioVector(size_t chan, struct trx_ul_burst_ind *bi)
dburgessb3a0ca42011-10-12 07:44:40 +0000580{
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800581 int rc;
Pau Espin Pedrol7ee2d102019-07-04 13:02:12 +0200582 struct estim_burst_params ebp;
583 float max = -1.0, avg = 0.0;
Pau Espin Pedrol9bb24a12019-07-03 15:43:03 +0200584 unsigned max_toa;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500585 int max_i = -1;
Thomas Tsou30421a72013-11-13 23:14:48 -0500586 signalVector *burst;
Pau Espin Pedrol07ddce52019-07-01 16:36:10 +0200587 GSM::Time burstTime;
Pau Espin Pedrol7dc07b92019-07-01 17:55:01 +0200588 SoftVector *rxBurst;
Thomas Tsoua0179e32013-11-14 15:52:04 -0500589 TransceiverState *state = &mStates[chan];
dburgessb3a0ca42011-10-12 07:44:40 +0000590
Thomas Tsou30421a72013-11-13 23:14:48 -0500591 /* Blocking FIFO read */
592 radioVector *radio_burst = mReceiveFIFO[chan]->read();
593 if (!radio_burst)
Pau Espin Pedrolddd18a52019-06-28 17:01:16 +0200594 return false;
dburgessb3a0ca42011-10-12 07:44:40 +0000595
Thomas Tsou30421a72013-11-13 23:14:48 -0500596 /* Set time and determine correlation type */
Pau Espin Pedrol07ddce52019-07-01 16:36:10 +0200597 burstTime = radio_burst->getTime();
Pau Espin Pedrol07ddce52019-07-01 16:36:10 +0200598 CorrType type = expectedCorrType(burstTime, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000599
Tom Tsou64464e62016-07-01 03:46:46 -0700600 /* Enable 8-PSK burst detection if EDGE is enabled */
601 if (mEdge && (type == TSC))
602 type = EDGE;
603
Alexander Chemerise692ce92015-06-12 00:15:31 -0400604 /* Debug: dump bursts to disk */
605 /* bits 0-7 - chan 0 timeslots
606 * bits 8-15 - chan 1 timeslots */
Pau Espin Pedrol07ddce52019-07-01 16:36:10 +0200607 if (mWriteBurstToDiskMask & ((1<<bi->tn) << (8*chan)))
Alexander Chemerise692ce92015-06-12 00:15:31 -0400608 writeToFile(radio_burst, chan);
609
Alexander Chemeris2b542102015-06-08 22:46:38 -0400610 /* No processing if the timeslot is off.
611 * Not even power level or noise calculation. */
612 if (type == OFF) {
Thomas Tsou30421a72013-11-13 23:14:48 -0500613 delete radio_burst;
Pau Espin Pedrolddd18a52019-06-28 17:01:16 +0200614 return false;
dburgessb3a0ca42011-10-12 07:44:40 +0000615 }
kurtis.heimerl3ed6fb72011-11-26 03:17:52 +0000616
Pau Espin Pedrol95c83182019-07-03 16:01:12 +0200617 /* Initialize struct bi */
618 bi->nbits = 0;
619 bi->fn = burstTime.FN();
620 bi->tn = burstTime.TN();
621 bi->rssi = 0.0;
622 bi->toa = 0.0;
623 bi->noise = 0.0;
624 bi->idle = false;
Pau Espin Pedrolcf6113b2019-07-01 20:42:53 +0200625 bi->modulation = MODULATION_GMSK;
626 bi->tss = 0; /* TODO: we only support tss 0 right now */
627 bi->tsc = 0;
628 bi->ci = 0.0;
Pau Espin Pedrol95c83182019-07-03 16:01:12 +0200629
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500630 /* Select the diversity channel with highest energy */
631 for (size_t i = 0; i < radio_burst->chans(); i++) {
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +0300632 float pow = energyDetect(*radio_burst->getVector(i), 20 * mSPSRx);
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500633 if (pow > max) {
634 max = pow;
635 max_i = i;
636 }
637 avg += pow;
638 }
639
640 if (max_i < 0) {
641 LOG(ALERT) << "Received empty burst";
Pau Espin Pedrol95c83182019-07-03 16:01:12 +0200642 goto ret_idle;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500643 }
644
Thomas Tsou30421a72013-11-13 23:14:48 -0500645 /* Average noise on diversity paths and update global levels */
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500646 burst = radio_burst->getVector(max_i);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500647 avg = sqrt(avg / radio_burst->chans());
Alexander Chemeris2b542102015-06-08 22:46:38 -0400648
Alexander Chemeris2b542102015-06-08 22:46:38 -0400649 if (type == IDLE) {
650 /* Update noise levels */
651 state->mNoises.insert(avg);
652 state->mNoiseLev = state->mNoises.avg();
Pau Espin Pedrolbe9cd662019-07-03 15:00:56 +0200653 }
Alexander Chemeris2b542102015-06-08 22:46:38 -0400654
Pau Espin Pedrolbe9cd662019-07-03 15:00:56 +0200655 bi->rssi = 20.0 * log10(rxFullScale / avg) + rssiOffset;
656 bi->noise = 20.0 * log10(rxFullScale / state->mNoiseLev) + rssiOffset;
657
Pau Espin Pedrol95c83182019-07-03 16:01:12 +0200658 if (type == IDLE)
659 goto ret_idle;
Thomas Tsoufa3a7872013-10-17 21:23:34 -0400660
Pau Espin Pedrol9bb24a12019-07-03 15:43:03 +0200661 max_toa = (type == RACH || type == EXT_RACH) ?
662 mMaxExpectedDelayAB : mMaxExpectedDelayNB;
Vadim Yanitskiya8b35652018-10-22 02:52:18 +0200663
Thomas Tsou30421a72013-11-13 23:14:48 -0500664 /* Detect normal or RACH bursts */
Pau Espin Pedrol7ee2d102019-07-04 13:02:12 +0200665 rc = detectAnyBurst(*burst, mTSC, BURST_THRESH, mSPSRx, type, max_toa, &ebp);
Pau Espin Pedrold6dbb1b2019-07-03 15:23:56 +0200666 if (rc <= 0) {
667 if (rc == -SIGERR_CLIP)
Alexander Chemeris954b1182015-06-04 15:39:41 -0400668 LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
Pau Espin Pedrold6dbb1b2019-07-03 15:23:56 +0200669 else if (rc != SIGERR_NONE)
Alexander Chemeris954b1182015-06-04 15:39:41 -0400670 LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
Pau Espin Pedrol95c83182019-07-03 16:01:12 +0200671 goto ret_idle;
dburgessb3a0ca42011-10-12 07:44:40 +0000672 }
dburgessb3a0ca42011-10-12 07:44:40 +0000673
Pau Espin Pedrold6dbb1b2019-07-03 15:23:56 +0200674 type = (CorrType) rc;
Pau Espin Pedrol7ee2d102019-07-04 13:02:12 +0200675 bi->toa = ebp.toa;
Pau Espin Pedrolcf6113b2019-07-01 20:42:53 +0200676 bi->tsc = ebp.tsc;
677 bi->ci = ebp.ci;
Pau Espin Pedrol7ee2d102019-07-04 13:02:12 +0200678 rxBurst = demodAnyBurst(*burst, mSPSRx, ebp.amp, ebp.toa, type);
Thomas Tsouef25dba2013-11-14 15:31:24 -0500679
Pau Espin Pedrol0e67cf22019-07-02 14:59:47 +0200680 /* EDGE demodulator returns 444 (gSlotLen * 3) bits */
Pau Espin Pedrolcf6113b2019-07-01 20:42:53 +0200681 if (rxBurst->size() == EDGE_BURST_NBITS) {
682 bi->modulation = MODULATION_8PSK;
Pau Espin Pedrol0e67cf22019-07-02 14:59:47 +0200683 bi->nbits = EDGE_BURST_NBITS;
Pau Espin Pedrolcf6113b2019-07-01 20:42:53 +0200684 } else { /* size() here is actually gSlotLen + 8, due to guard periods */
685 bi->modulation = MODULATION_GMSK;
Pau Espin Pedrol0e67cf22019-07-02 14:59:47 +0200686 bi->nbits = gSlotLen;
Pau Espin Pedrolcf6113b2019-07-01 20:42:53 +0200687 }
Pau Espin Pedrol0e67cf22019-07-02 14:59:47 +0200688
Pau Espin Pedrol25ae1902019-07-01 16:40:44 +0200689 // Convert -1..+1 soft bits to 0..1 soft bits
Pau Espin Pedrol7dc07b92019-07-01 17:55:01 +0200690 vectorSlicer(bi->rx_burst, rxBurst->begin(), bi->nbits);
Pau Espin Pedrol25ae1902019-07-01 16:40:44 +0200691
Pau Espin Pedrol7dc07b92019-07-01 17:55:01 +0200692 delete rxBurst;
Thomas Tsou30421a72013-11-13 23:14:48 -0500693 delete radio_burst;
Pau Espin Pedrolddd18a52019-06-28 17:01:16 +0200694 return true;
Pau Espin Pedrol95c83182019-07-03 16:01:12 +0200695
696ret_idle:
697 bi->idle = true;
698 delete radio_burst;
699 return false;
dburgessb3a0ca42011-10-12 07:44:40 +0000700}
701
dburgessb3a0ca42011-10-12 07:44:40 +0000702void Transceiver::reset()
703{
Thomas Tsou204a9f12013-10-29 18:34:16 -0400704 for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
705 mTxPriorityQueues[i].clear();
dburgessb3a0ca42011-10-12 07:44:40 +0000706}
707
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200708
Vadim Yanitskiybd0efb02018-03-09 02:45:07 +0700709#define MAX_PACKET_LENGTH 100
710
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700711/**
712 * Matches a buffer with a command.
713 * @param buf a buffer to look command in
714 * @param cmd a command to look in buffer
715 * @param params pointer to arguments, or NULL
716 * @return true if command matches, otherwise false
717 */
718static bool match_cmd(char *buf,
719 const char *cmd, char **params)
720{
721 size_t cmd_len = strlen(cmd);
722
723 /* Check a command itself */
724 if (strncmp(buf, cmd, cmd_len))
725 return false;
726
727 /* A command has arguments */
728 if (params != NULL) {
729 /* Make sure there is a space */
730 if (buf[cmd_len] != ' ')
731 return false;
732
733 /* Update external pointer */
734 *params = buf + cmd_len + 1;
735 }
736
737 return true;
738}
739
Thomas Tsou204a9f12013-10-29 18:34:16 -0400740void Transceiver::driveControl(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000741{
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700742 char buffer[MAX_PACKET_LENGTH + 1];
743 char response[MAX_PACKET_LENGTH + 1];
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700744 char *command, *params;
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700745 int msgLen;
Thomas Tsoud647ec52013-10-29 15:17:34 -0400746
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700747 /* Attempt to read from control socket */
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200748 msgLen = read(mCtrlSockets[chan], buffer, MAX_PACKET_LENGTH);
749 if (msgLen <= 0) {
750 LOGCHAN(chan, DTRXCTRL, WARNING) << "mCtrlSockets read(" << mCtrlSockets[chan] << ") failed: " << msgLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000751 return;
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200752 }
Vadim Yanitskiy4d9b59c2018-03-09 02:54:45 +0700753
754 /* Zero-terminate received string */
755 buffer[msgLen] = '\0';
dburgessb3a0ca42011-10-12 07:44:40 +0000756
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700757 /* Verify a command signature */
758 if (strncmp(buffer, "CMD ", 4)) {
Pau Espin Pedrol441d82a2018-12-04 16:37:24 +0100759 LOGC(DTRXCTRL, WARNING) << "bogus message on control interface";
dburgessb3a0ca42011-10-12 07:44:40 +0000760 return;
761 }
dburgessb3a0ca42011-10-12 07:44:40 +0000762
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700763 /* Set command pointer */
764 command = buffer + 4;
Pau Espin Pedrolfc73c072019-05-03 19:40:00 +0200765 LOGCHAN(chan, DTRXCTRL, INFO) << "command is '" << command << "'";
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700766
767 if (match_cmd(command, "POWEROFF", NULL)) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800768 stop();
769 sprintf(response,"RSP POWEROFF 0");
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700770 } else if (match_cmd(command, "POWERON", NULL)) {
Tom Tsou365bc382016-10-19 15:26:04 -0700771 if (!start()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000772 sprintf(response,"RSP POWERON 1");
Tom Tsou365bc382016-10-19 15:26:04 -0700773 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000774 sprintf(response,"RSP POWERON 0");
Alexander Chemeris5a068062015-06-20 01:38:47 +0300775 for (int i = 0; i < 8; i++) {
776 for (int j = 0; j < 8; j++)
777 mHandover[i][j] = false;
778 }
Tom Tsou365bc382016-10-19 15:26:04 -0700779 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700780 } else if (match_cmd(command, "HANDOVER", &params)) {
Vadim Yanitskiyc0c6d702018-03-09 05:08:23 +0700781 unsigned ts = 0, ss = 0;
782 sscanf(params, "%u %u", &ts, &ss);
783 if (ts > 7 || ss > 7) {
784 sprintf(response, "RSP NOHANDOVER 1 %u %u", ts, ss);
785 } else {
786 mHandover[ts][ss] = true;
787 sprintf(response, "RSP HANDOVER 0 %u %u", ts, ss);
788 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700789 } else if (match_cmd(command, "NOHANDOVER", &params)) {
Vadim Yanitskiyc0c6d702018-03-09 05:08:23 +0700790 unsigned ts = 0, ss = 0;
791 sscanf(params, "%u %u", &ts, &ss);
792 if (ts > 7 || ss > 7) {
793 sprintf(response, "RSP NOHANDOVER 1 %u %u", ts, ss);
794 } else {
795 mHandover[ts][ss] = false;
796 sprintf(response, "RSP NOHANDOVER 0 %u %u", ts, ss);
797 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700798 } else if (match_cmd(command, "SETMAXDLY", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000799 //set expected maximum time-of-arrival
800 int maxDelay;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700801 sscanf(params, "%d", &maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300802 mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km
dburgessb3a0ca42011-10-12 07:44:40 +0000803 sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700804 } else if (match_cmd(command, "SETMAXDLYNB", &params)) {
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300805 //set expected maximum time-of-arrival
806 int maxDelay;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700807 sscanf(params, "%d", &maxDelay);
Alexander Chemeris78d1fc92016-03-19 21:16:22 +0300808 mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km
809 sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700810 } else if (match_cmd(command, "SETRXGAIN", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000811 //set expected maximum time-of-arrival
812 int newGain;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700813 sscanf(params, "%d", &newGain);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400814 newGain = mRadioInterface->setRxGain(newGain, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000815 sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700816 } else if (match_cmd(command, "NOISELEV", NULL)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000817 if (mOn) {
Thomas Tsoua0179e32013-11-14 15:52:04 -0500818 float lev = mStates[chan].mNoiseLev;
dburgessb3a0ca42011-10-12 07:44:40 +0000819 sprintf(response,"RSP NOISELEV 0 %d",
Thomas Tsoua0179e32013-11-14 15:52:04 -0500820 (int) round(20.0 * log10(rxFullScale / lev)));
dburgessb3a0ca42011-10-12 07:44:40 +0000821 }
822 else {
823 sprintf(response,"RSP NOISELEV 1 0");
824 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700825 } else if (match_cmd(command, "SETPOWER", &params)) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800826 int power;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700827 sscanf(params, "%d", &power);
Tom Tsoua4d1a412014-11-25 15:46:56 -0800828 power = mRadioInterface->setPowerAttenuation(power, chan);
829 mStates[chan].mPower = power;
830 sprintf(response, "RSP SETPOWER 0 %d", power);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700831 } else if (match_cmd(command, "ADJPOWER", &params)) {
Tom Tsoua4d1a412014-11-25 15:46:56 -0800832 int power, step;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700833 sscanf(params, "%d", &step);
Tom Tsoua4d1a412014-11-25 15:46:56 -0800834 power = mStates[chan].mPower + step;
835 power = mRadioInterface->setPowerAttenuation(power, chan);
836 mStates[chan].mPower = power;
837 sprintf(response, "RSP ADJPOWER 0 %d", power);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700838 } else if (match_cmd(command, "RXTUNE", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000839 // tune receiver
840 int freqKhz;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700841 sscanf(params, "%d", &freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500842 mRxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400843 if (!mRadioInterface->tuneRx(mRxFreq, chan)) {
Pau Espin Pedrol441d82a2018-12-04 16:37:24 +0100844 LOGC(DTRXCTRL, ALERT) << "RX failed to tune";
dburgessb3a0ca42011-10-12 07:44:40 +0000845 sprintf(response,"RSP RXTUNE 1 %d",freqKhz);
846 }
847 else
848 sprintf(response,"RSP RXTUNE 0 %d",freqKhz);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700849 } else if (match_cmd(command, "TXTUNE", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000850 // tune txmtr
851 int freqKhz;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700852 sscanf(params, "%d", &freqKhz);
Thomas Tsou477b77c2013-11-15 16:13:59 -0500853 mTxFreq = freqKhz * 1e3;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400854 if (!mRadioInterface->tuneTx(mTxFreq, chan)) {
Pau Espin Pedrol441d82a2018-12-04 16:37:24 +0100855 LOGC(DTRXCTRL, ALERT) << "TX failed to tune";
dburgessb3a0ca42011-10-12 07:44:40 +0000856 sprintf(response,"RSP TXTUNE 1 %d",freqKhz);
857 }
858 else
859 sprintf(response,"RSP TXTUNE 0 %d",freqKhz);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700860 } else if (match_cmd(command, "SETTSC", &params)) {
dburgessb3a0ca42011-10-12 07:44:40 +0000861 // set TSC
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500862 unsigned TSC;
Vadim Yanitskiy8c6c5d22018-03-09 05:01:21 +0700863 sscanf(params, "%u", &TSC);
Tom Tsou60317342017-03-30 19:36:41 -0700864 if (TSC > 7) {
Thomas Tsoud3fccea2013-11-15 14:22:53 -0500865 sprintf(response, "RSP SETTSC 1 %d", TSC);
Tom Tsou60317342017-03-30 19:36:41 -0700866 } else {
Pau Espin Pedrol441d82a2018-12-04 16:37:24 +0100867 LOGC(DTRXCTRL, NOTICE) << "Changing TSC from " << mTSC << " to " << TSC;
dburgessb3a0ca42011-10-12 07:44:40 +0000868 mTSC = TSC;
Thomas Tsou83e06892013-08-20 16:10:01 -0400869 sprintf(response,"RSP SETTSC 0 %d", TSC);
dburgessb3a0ca42011-10-12 07:44:40 +0000870 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700871 } else if (match_cmd(command, "SETSLOT", &params)) {
Alexander Chemeris1fe52822015-05-20 12:02:29 -0700872 // set slot type
dburgessb3a0ca42011-10-12 07:44:40 +0000873 int corrCode;
874 int timeslot;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700875 sscanf(params, "%d %d", &timeslot, &corrCode);
dburgessb3a0ca42011-10-12 07:44:40 +0000876 if ((timeslot < 0) || (timeslot > 7)) {
Pau Espin Pedrol441d82a2018-12-04 16:37:24 +0100877 LOGC(DTRXCTRL, WARNING) << "bogus message on control interface";
dburgessb3a0ca42011-10-12 07:44:40 +0000878 sprintf(response,"RSP SETSLOT 1 %d %d",timeslot,corrCode);
879 return;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200880 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400881 mStates[chan].chanType[timeslot] = (ChannelCombination) corrCode;
882 setModulus(timeslot, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000883 sprintf(response,"RSP SETSLOT 0 %d %d",timeslot,corrCode);
Pau Espin Pedrol13c81092019-07-03 16:17:06 +0200884 } else if (match_cmd(command, "SETFORMAT", &params)) {
885 // set TRXD protocol version
886 unsigned version_recv;
887 sscanf(params, "%u", &version_recv);
888 LOGC(DTRXCTRL, INFO) << "BTS requests TRXD version switch: " << version_recv;
889 if (version_recv > TRX_DATA_FORMAT_VER) {
890 LOGC(DTRXCTRL, INFO) << "rejecting TRXD version " << version_recv
891 << "in favor of " << TRX_DATA_FORMAT_VER;
892 sprintf(response, "RSP SETFORMAT %u %u", TRX_DATA_FORMAT_VER, version_recv);
893 } else {
894 LOGC(DTRXCTRL, NOTICE) << "switching to TRXD version " << version_recv;
895 mVersionTRXD = version_recv;
896 sprintf(response, "RSP SETFORMAT %u %u", version_recv, version_recv);
897 }
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700898 } else if (match_cmd(command, "_SETBURSTTODISKMASK", &params)) {
Alexander Chemerise692ce92015-06-12 00:15:31 -0400899 // debug command! may change or disapear without notice
900 // set a mask which bursts to dump to disk
901 int mask;
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700902 sscanf(params, "%d", &mask);
Alexander Chemerise692ce92015-06-12 00:15:31 -0400903 mWriteBurstToDiskMask = mask;
904 sprintf(response,"RSP _SETBURSTTODISKMASK 0 %d",mask);
Vadim Yanitskiya62fcf72018-03-09 03:24:08 +0700905 } else {
Pau Espin Pedrol441d82a2018-12-04 16:37:24 +0100906 LOGC(DTRXCTRL, WARNING) << "bogus command " << command << " on control interface.";
Alexander Chemeris4438a9f2013-04-08 00:14:08 +0200907 sprintf(response,"RSP ERR 1");
dburgessb3a0ca42011-10-12 07:44:40 +0000908 }
909
Pau Espin Pedrolfc73c072019-05-03 19:40:00 +0200910 LOGCHAN(chan, DTRXCTRL, INFO) << "response is '" << response << "'";
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200911 msgLen = write(mCtrlSockets[chan], response, strlen(response) + 1);
912 if (msgLen <= 0)
913 LOGCHAN(chan, DTRXCTRL, WARNING) << "mCtrlSockets write(" << mCtrlSockets[chan] << ") failed: " << msgLen;
dburgessb3a0ca42011-10-12 07:44:40 +0000914}
915
Thomas Tsou204a9f12013-10-29 18:34:16 -0400916bool Transceiver::driveTxPriorityQueue(size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000917{
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200918 int msgLen;
Tom Tsoue8871082016-07-01 02:46:04 -0700919 int burstLen;
920 char buffer[EDGE_BURST_NBITS + 50];
Vadim Yanitskiyb3123252019-07-15 23:53:08 +0700921 struct trxd_hdr_common *chdr;
922 uint32_t fn;
dburgessb3a0ca42011-10-12 07:44:40 +0000923
924 // check data socket
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +0200925 msgLen = read(mDataSockets[chan], buffer, sizeof(buffer));
926 if (msgLen <= 0) {
927 LOGCHAN(chan, DTRXCTRL, WARNING) << "mDataSockets read(" << mCtrlSockets[chan] << ") failed: " << msgLen;
928 return false;
929 }
dburgessb3a0ca42011-10-12 07:44:40 +0000930
Tom Tsoue8871082016-07-01 02:46:04 -0700931 if (msgLen == gSlotLen + 1 + 4 + 1) {
932 burstLen = gSlotLen;
933 } else if (msgLen == EDGE_BURST_NBITS + 1 + 4 + 1) {
934 if (mSPSTx != 4)
935 return false;
936
937 burstLen = EDGE_BURST_NBITS;
938 } else {
dburgessb3a0ca42011-10-12 07:44:40 +0000939 LOG(ERR) << "badly formatted packet on GSM->TRX interface";
940 return false;
941 }
942
Vadim Yanitskiyb3123252019-07-15 23:53:08 +0700943 /* Common header part: HDR version, TDMA TN & FN */
944 chdr = (struct trxd_hdr_common *) buffer;
dburgessb3a0ca42011-10-12 07:44:40 +0000945
Vadim Yanitskiyb3123252019-07-15 23:53:08 +0700946 /* Convert TDMA FN to the host endianness */
947 fn = osmo_load32be(&chdr->fn);
948
Vadim Yanitskiydd571c62019-07-15 23:56:56 +0700949 /* Make sure we support the received header format */
950 switch (chdr->version) {
951 case 0:
952 /* Version 1 has the same format */
953 case 1:
954 break;
955
956 default:
957 LOG(ERR) << "Rx TRXD message with unknown header version " << chdr->version;
958 return false;
959 }
960
Vadim Yanitskiy56c5f292019-07-16 00:02:56 +0700961 LOG(DEBUG) << "Rx TRXD message (hdr_ver=" << chdr->version << "): "
962 << "fn=" << fn << ", tn=" << chdr->tn << ", "
963 << "burst_len=" << burstLen;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200964
dburgessb3a0ca42011-10-12 07:44:40 +0000965 int RSSI = (int) buffer[5];
Tom Tsou7c741ec2016-07-19 11:20:59 -0700966 BitVector newBurst(burstLen);
dburgessb3a0ca42011-10-12 07:44:40 +0000967 BitVector::iterator itr = newBurst.begin();
968 char *bufferItr = buffer+6;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200969 while (itr < newBurst.end())
dburgessb3a0ca42011-10-12 07:44:40 +0000970 *itr++ = *bufferItr++;
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +0200971
Vadim Yanitskiyb3123252019-07-15 23:53:08 +0700972 GSM::Time currTime = GSM::Time(fn, chdr->tn);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400973
974 addRadioVector(chan, newBurst, RSSI, currTime);
dburgessb3a0ca42011-10-12 07:44:40 +0000975
976 return true;
977
978
979}
dburgessb3a0ca42011-10-12 07:44:40 +0000980
Thomas Tsou204a9f12013-10-29 18:34:16 -0400981void Transceiver::driveReceiveRadio()
982{
Pau Espin Pedroldb936b92018-09-03 16:50:49 +0200983 int rc = mRadioInterface->driveReceiveRadio();
984 if (rc == 0) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400985 usleep(100000);
Pau Espin Pedroldb936b92018-09-03 16:50:49 +0200986 } else if (rc < 0) {
987 LOG(FATAL) << "radio Interface receive failed, requesting stop.";
Pau Espin Pedrolb426e4a2019-06-04 12:39:28 +0200988 osmo_signal_dispatch(SS_MAIN, S_MAIN_STOP_REQUIRED, NULL);
Pau Espin Pedrol934da482017-07-04 16:25:20 +0200989 } else if (mForceClockInterface || mTransmitDeadlineClock > mLastClockUpdateTime + GSM::Time(216,0)) {
990 mForceClockInterface = false;
991 writeClockInterface();
Alexander Chemeris6a2bf0d2015-05-24 19:28:09 -0400992 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400993}
994
Pau Espin Pedrol607a4142019-07-01 13:56:17 +0200995void Transceiver::logRxBurst(size_t chan, const struct trx_ul_burst_ind *bi)
Tom Tsoub0aefcb2016-03-06 03:44:34 -0800996{
Pau Espin Pedrol7dc07b92019-07-01 17:55:01 +0200997 std::ostringstream os;
998 for (size_t i=0; i < bi->nbits; i++) {
999 if (bi->rx_burst[i] > 0.5) os << "1";
1000 else if (bi->rx_burst[i] > 0.25) os << "|";
1001 else if (bi->rx_burst[i] > 0.0) os << "'";
1002 else os << "-";
1003 }
1004
Tom Tsoub0aefcb2016-03-06 03:44:34 -08001005 LOG(DEBUG) << std::fixed << std::right
Alexander Chemeris58e95912016-03-25 18:20:28 +03001006 << " chan: " << chan
Pau Espin Pedrol07ddce52019-07-01 16:36:10 +02001007 << " time: " << bi->tn << ":" << bi->fn
Pau Espin Pedrol607a4142019-07-01 13:56:17 +02001008 << " RSSI: " << std::setw(5) << std::setprecision(1) << (bi->rssi - rssiOffset)
1009 << "dBFS/" << std::setw(6) << -bi->rssi << "dBm"
1010 << " noise: " << std::setw(5) << std::setprecision(1) << (bi->noise - rssiOffset)
1011 << "dBFS/" << std::setw(6) << -bi->noise << "dBm"
Pau Espin Pedrolddd18a52019-06-28 17:01:16 +02001012 << " TOA: " << std::setw(5) << std::setprecision(2) << bi->toa
Pau Espin Pedrolcf6113b2019-07-01 20:42:53 +02001013 << " C/I: " << std::setw(5) << std::setprecision(2) << bi->ci << "dB"
Pau Espin Pedrol7dc07b92019-07-01 17:55:01 +02001014 << " bits: " << os;
Tom Tsoub0aefcb2016-03-06 03:44:34 -08001015}
1016
Thomas Tsou204a9f12013-10-29 18:34:16 -04001017void Transceiver::driveReceiveFIFO(size_t chan)
1018{
Pau Espin Pedrolddd18a52019-06-28 17:01:16 +02001019 struct trx_ul_burst_ind bi;
1020
Pau Espin Pedrol15fa64b2019-07-01 20:41:55 +02001021 if (!pullRadioVector(chan, &bi))
Pau Espin Pedrolddd18a52019-06-28 17:01:16 +02001022 return;
Pau Espin Pedrol15fa64b2019-07-01 20:41:55 +02001023 if (!bi.idle)
1024 logRxBurst(chan, &bi);
dburgessb3a0ca42011-10-12 07:44:40 +00001025
Pau Espin Pedrol15fa64b2019-07-01 20:41:55 +02001026 switch (mVersionTRXD) {
1027 case 0:
1028 trxd_send_burst_ind_v0(chan, mDataSockets[chan], &bi);
1029 break;
Pau Espin Pedrolcf6113b2019-07-01 20:42:53 +02001030 case 1:
1031 trxd_send_burst_ind_v1(chan, mDataSockets[chan], &bi);
1032 break;
Pau Espin Pedrol15fa64b2019-07-01 20:41:55 +02001033 default:
1034 OSMO_ASSERT(false);
1035 }
dburgessb3a0ca42011-10-12 07:44:40 +00001036}
1037
Thomas Tsou204a9f12013-10-29 18:34:16 -04001038void Transceiver::driveTxFIFO()
dburgessb3a0ca42011-10-12 07:44:40 +00001039{
1040
1041 /**
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +02001042 Features a carefully controlled latency mechanism, to
dburgessb3a0ca42011-10-12 07:44:40 +00001043 assure that transmit packets arrive at the radio/USRP
1044 before they need to be transmitted.
1045
1046 Deadline clock indicates the burst that needs to be
1047 pushed into the FIFO right NOW. If transmit queue does
1048 not have a burst, stick in filler data.
1049 */
1050
1051
1052 RadioClock *radioClock = (mRadioInterface->getClock());
Pau Espin Pedrol7c405a02017-07-04 16:24:06 +02001053
dburgessb3a0ca42011-10-12 07:44:40 +00001054 if (mOn) {
1055 //radioClock->wait(); // wait until clock updates
1056 LOG(DEBUG) << "radio clock " << radioClock->get();
1057 while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) {
1058 // if underrun, then we're not providing bursts to radio/USRP fast
1059 // enough. Need to increase latency by one GSM frame.
Thomas Tsou02d88d12013-04-05 15:36:30 -04001060 if (mRadioInterface->getWindowType() == RadioDevice::TX_WINDOW_USRP1) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001061 if (mRadioInterface->isUnderrun()) {
ttsou2173abf2012-08-08 00:51:31 +00001062 // only update latency at the defined frame interval
1063 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL)) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001064 mTransmitLatency = mTransmitLatency + GSM::Time(1,0);
Pau Espin Pedrol74bcc562018-10-02 17:30:28 +02001065 LOG(INFO) << "new latency: " << mTransmitLatency << " (underrun "
1066 << radioClock->get() << " vs " << mLatencyUpdateTime + GSM::Time(USB_LATENCY_INTRVL) << ")";
kurtis.heimerle380af32011-11-26 03:18:55 +00001067 mLatencyUpdateTime = radioClock->get();
1068 }
1069 }
1070 else {
1071 // if underrun hasn't occurred in the last sec (216 frames) drop
1072 // transmit latency by a timeslot
Pau Espin Pedrole564f0f2018-04-24 18:43:51 +02001073 if (mTransmitLatency > mRadioInterface->minLatency()) {
kurtis.heimerle380af32011-11-26 03:18:55 +00001074 if (radioClock->get() > mLatencyUpdateTime + GSM::Time(216,0)) {
1075 mTransmitLatency.decTN();
1076 LOG(INFO) << "reduced latency: " << mTransmitLatency;
1077 mLatencyUpdateTime = radioClock->get();
1078 }
1079 }
1080 }
dburgessb3a0ca42011-10-12 07:44:40 +00001081 }
dburgessb3a0ca42011-10-12 07:44:40 +00001082 // time to push burst to transmit FIFO
1083 pushRadioVector(mTransmitDeadlineClock);
1084 mTransmitDeadlineClock.incTN();
1085 }
dburgessb3a0ca42011-10-12 07:44:40 +00001086 }
Thomas Tsou92c16df2013-09-28 18:04:19 -04001087
1088 radioClock->wait();
dburgessb3a0ca42011-10-12 07:44:40 +00001089}
1090
1091
1092
1093void Transceiver::writeClockInterface()
1094{
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +02001095 int msgLen;
dburgessb3a0ca42011-10-12 07:44:40 +00001096 char command[50];
1097 // FIXME -- This should be adaptive.
1098 sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
1099
1100 LOG(INFO) << "ClockInterface: sending " << command;
1101
Pau Espin Pedrolb9d25152019-07-01 19:03:49 +02001102 msgLen = write(mClockSocket, command, strlen(command) + 1);
1103 if (msgLen <= 0)
1104 LOG(WARNING) << "mClockSocket write(" << mClockSocket << ") failed: " << msgLen;
dburgessb3a0ca42011-10-12 07:44:40 +00001105
1106 mLastClockUpdateTime = mTransmitDeadlineClock;
1107
Thomas Tsou92c16df2013-09-28 18:04:19 -04001108}
dburgessb3a0ca42011-10-12 07:44:40 +00001109
Thomas Tsou204a9f12013-10-29 18:34:16 -04001110void *RxUpperLoopAdapter(TransceiverChannel *chan)
1111{
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001112 char thread_name[16];
Thomas Tsou204a9f12013-10-29 18:34:16 -04001113 Transceiver *trx = chan->trx;
1114 size_t num = chan->num;
1115
1116 delete chan;
1117
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001118 snprintf(thread_name, 16, "RxUpper%zu", num);
1119 set_selfthread_name(thread_name);
1120
Thomas Tsou7553aa92013-11-08 12:50:03 -05001121 trx->setPriority(0.42);
1122
Thomas Tsou204a9f12013-10-29 18:34:16 -04001123 while (1) {
1124 trx->driveReceiveFIFO(num);
1125 pthread_testcancel();
1126 }
1127 return NULL;
1128}
1129
1130void *RxLowerLoopAdapter(Transceiver *transceiver)
dburgessb3a0ca42011-10-12 07:44:40 +00001131{
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001132 set_selfthread_name("RxLower");
1133
Thomas Tsou7553aa92013-11-08 12:50:03 -05001134 transceiver->setPriority(0.45);
kurtis.heimerl6b495a52011-11-26 03:17:21 +00001135
dburgessb3a0ca42011-10-12 07:44:40 +00001136 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001137 transceiver->driveReceiveRadio();
Thomas Tsou92c16df2013-09-28 18:04:19 -04001138 pthread_testcancel();
1139 }
1140 return NULL;
1141}
1142
Thomas Tsou204a9f12013-10-29 18:34:16 -04001143void *TxLowerLoopAdapter(Transceiver *transceiver)
Thomas Tsou92c16df2013-09-28 18:04:19 -04001144{
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001145 set_selfthread_name("TxLower");
1146
Thomas Tsou7553aa92013-11-08 12:50:03 -05001147 transceiver->setPriority(0.44);
1148
Thomas Tsou92c16df2013-09-28 18:04:19 -04001149 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001150 transceiver->driveTxFIFO();
dburgessb3a0ca42011-10-12 07:44:40 +00001151 pthread_testcancel();
1152 }
1153 return NULL;
1154}
1155
Thomas Tsou204a9f12013-10-29 18:34:16 -04001156void *ControlServiceLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001157{
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001158 char thread_name[16];
Thomas Tsou204a9f12013-10-29 18:34:16 -04001159 Transceiver *trx = chan->trx;
1160 size_t num = chan->num;
1161
1162 delete chan;
1163
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001164 snprintf(thread_name, 16, "CtrlService%zu", num);
1165 set_selfthread_name(thread_name);
1166
dburgessb3a0ca42011-10-12 07:44:40 +00001167 while (1) {
Thomas Tsou204a9f12013-10-29 18:34:16 -04001168 trx->driveControl(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001169 pthread_testcancel();
1170 }
1171 return NULL;
1172}
1173
Thomas Tsou204a9f12013-10-29 18:34:16 -04001174void *TxUpperLoopAdapter(TransceiverChannel *chan)
dburgessb3a0ca42011-10-12 07:44:40 +00001175{
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001176 char thread_name[16];
Thomas Tsou204a9f12013-10-29 18:34:16 -04001177 Transceiver *trx = chan->trx;
1178 size_t num = chan->num;
1179
1180 delete chan;
1181
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +02001182 snprintf(thread_name, 16, "TxUpper%zu", num);
1183 set_selfthread_name(thread_name);
1184
Thomas Tsoua4cf48c2013-11-09 21:44:26 -05001185 trx->setPriority(0.40);
1186
dburgessb3a0ca42011-10-12 07:44:40 +00001187 while (1) {
Tom Tsoueb54bdd2014-11-25 16:06:32 -08001188 trx->driveTxPriorityQueue(num);
dburgessb3a0ca42011-10-12 07:44:40 +00001189 pthread_testcancel();
1190 }
1191 return NULL;
1192}