blob: 875245d63f76b26d07316016c20e0a521d1cf5e2 [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
Tom Tsou28670fb2015-08-21 19:32:58 -07002 * Radio device interface
3 *
4 * Copyright (C) 2008-2014 Free Software Foundation, Inc.
5 * Copyright (C) 2015 Ettus Research LLC
6 *
Pau Espin Pedrol21d03d32019-07-22 12:05:52 +02007 * SPDX-License-Identifier: AGPL-3.0+
8 *
Tom Tsou28670fb2015-08-21 19:32:58 -07009 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Affero General Public License for more details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * See the COPYING file in the main directory for details.
22 */
dburgessb3a0ca42011-10-12 07:44:40 +000023
dburgessb3a0ca42011-10-12 07:44:40 +000024#include "radioInterface.h"
Thomas Tsouc1f7c422013-10-11 13:49:55 -040025#include "Resampler.h"
dburgessb3a0ca42011-10-12 07:44:40 +000026#include <Logger.h>
Pau Espin Pedrole503c982019-09-13 18:56:08 +020027#include <Threads.h>
dburgessb3a0ca42011-10-12 07:44:40 +000028
Thomas Tsou9471d762013-08-20 21:24:24 -040029extern "C" {
Pau Espin Pedrol553a2502020-07-29 18:05:25 +020030#include <osmocom/core/utils.h>
31#include <osmocom/vty/cpu_sched_vty.h>
32
Thomas Tsou9471d762013-08-20 21:24:24 -040033#include "convert.h"
34}
35
Thomas Tsou3952d802013-10-15 15:12:24 -040036#define CHUNK 625
37#define NUMCHUNKS 4
kurtis.heimerl9b557832011-11-26 03:18:34 +000038
Pau Espin Pedrola801ae52019-09-13 15:59:29 +020039RadioInterface::RadioInterface(RadioDevice *wDevice, size_t tx_sps,
Tom Tsoud6ae8642017-03-30 17:22:58 -070040 size_t rx_sps, size_t chans,
Thomas Tsoue90a42b2013-11-13 23:38:09 -050041 int wReceiveOffset, GSM::Time wStartTime)
Pau Espin Pedrola801ae52019-09-13 15:59:29 +020042 : mDevice(wDevice), mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans),
Harald Welte2896cec2019-07-21 11:55:22 +020043 underrun(false), overrun(false), writeTimestamp(0), readTimestamp(0),
44 receiveOffset(wReceiveOffset), mOn(false)
dburgessb3a0ca42011-10-12 07:44:40 +000045{
dburgessb3a0ca42011-10-12 07:44:40 +000046 mClock.set(wStartTime);
dburgessb3a0ca42011-10-12 07:44:40 +000047}
48
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040049RadioInterface::~RadioInterface(void)
50{
51 close();
52}
kurtis.heimerl54354042011-11-26 03:18:49 +000053
Thomas Tsoufe269fe2013-10-14 23:56:51 -040054bool RadioInterface::init(int type)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040055{
Tom Tsoud6ae8642017-03-30 17:22:58 -070056 if ((type != RadioDevice::NORMAL) || !mChans) {
Thomas Tsoue90a42b2013-11-13 23:38:09 -050057 LOG(ALERT) << "Invalid configuration";
Thomas Tsou204a9f12013-10-29 18:34:16 -040058 return false;
59 }
60
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040061 close();
62
Thomas Tsou204a9f12013-10-29 18:34:16 -040063 sendBuffer.resize(mChans);
64 recvBuffer.resize(mChans);
65 convertSendBuffer.resize(mChans);
66 convertRecvBuffer.resize(mChans);
67 mReceiveFIFO.resize(mChans);
Thomas Tsoucb269a32013-11-15 14:15:47 -050068 powerScaling.resize(mChans);
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040069
Thomas Tsou204a9f12013-10-29 18:34:16 -040070 for (size_t i = 0; i < mChans; i++) {
Tom Tsou28670fb2015-08-21 19:32:58 -070071 sendBuffer[i] = new RadioBuffer(NUMCHUNKS, CHUNK * mSPSTx, 0, true);
72 recvBuffer[i] = new RadioBuffer(NUMCHUNKS, CHUNK * mSPSRx, 0, false);
Thomas Tsou204a9f12013-10-29 18:34:16 -040073
Tom Tsou28670fb2015-08-21 19:32:58 -070074 convertSendBuffer[i] = new short[CHUNK * mSPSTx * 2];
75 convertRecvBuffer[i] = new short[CHUNK * mSPSRx * 2];
Alexander Chemeris19174f52016-06-18 11:16:54 +030076
77 powerScaling[i] = 1.0;
Thomas Tsou204a9f12013-10-29 18:34:16 -040078 }
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040079
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040080 return true;
81}
82
83void RadioInterface::close()
84{
Pau Espin Pedrol39e0bba2018-12-03 12:19:51 +010085 for (std::vector<RadioBuffer*>::iterator it = sendBuffer.begin(); it != sendBuffer.end(); ++it)
86 delete *it;
87 for (std::vector<RadioBuffer*>::iterator it = recvBuffer.begin(); it != recvBuffer.end(); ++it)
88 delete *it;
89 for (std::vector<short*>::iterator it = convertSendBuffer.begin(); it != convertSendBuffer.end(); ++it)
90 delete[] *it;
91 for (std::vector<short*>::iterator it = convertRecvBuffer.begin(); it != convertRecvBuffer.end(); ++it)
92 delete[] *it;
Thomas Tsou204a9f12013-10-29 18:34:16 -040093 sendBuffer.resize(0);
94 recvBuffer.resize(0);
95 convertSendBuffer.resize(0);
96 convertRecvBuffer.resize(0);
dburgessb3a0ca42011-10-12 07:44:40 +000097}
98
99double RadioInterface::fullScaleInputValue(void) {
Pau Espin Pedrola801ae52019-09-13 15:59:29 +0200100 return mDevice->fullScaleInputValue();
dburgessb3a0ca42011-10-12 07:44:40 +0000101}
102
103double RadioInterface::fullScaleOutputValue(void) {
Pau Espin Pedrola801ae52019-09-13 15:59:29 +0200104 return mDevice->fullScaleOutputValue();
dburgessb3a0ca42011-10-12 07:44:40 +0000105}
106
Tom Tsoua4d1a412014-11-25 15:46:56 -0800107int RadioInterface::setPowerAttenuation(int atten, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000108{
Pau Espin Pedrol992c9bd2020-06-08 13:44:24 +0200109 double rfAtten, digAtten;
kurtis.heimerlee5347a2011-11-26 03:18:05 +0000110
Thomas Tsou204a9f12013-10-29 18:34:16 -0400111 if (chan >= mChans) {
112 LOG(ALERT) << "Invalid channel requested";
Tom Tsoua4d1a412014-11-25 15:46:56 -0800113 return -1;
Thomas Tsou204a9f12013-10-29 18:34:16 -0400114 }
115
Tom Tsoua4d1a412014-11-25 15:46:56 -0800116 if (atten < 0.0)
117 atten = 0.0;
118
Pau Espin Pedrol992c9bd2020-06-08 13:44:24 +0200119 rfAtten = mDevice->setPowerAttenuation((double) atten, chan);
120 digAtten = (double) atten - rfAtten;
kurtis.heimerlee5347a2011-11-26 03:18:05 +0000121
122 if (digAtten < 1.0)
Thomas Tsoucb269a32013-11-15 14:15:47 -0500123 powerScaling[chan] = 1.0;
kurtis.heimerlee5347a2011-11-26 03:18:05 +0000124 else
Thomas Tsoucb269a32013-11-15 14:15:47 -0500125 powerScaling[chan] = 1.0 / sqrt(pow(10, digAtten / 10.0));
Tom Tsoua4d1a412014-11-25 15:46:56 -0800126
127 return atten;
dburgessb3a0ca42011-10-12 07:44:40 +0000128}
129
Pau Espin Pedrol0e09e7c2020-05-29 16:39:07 +0200130int RadioInterface::getNominalTxPower(size_t chan)
131{
132 if (chan >= mChans) {
133 LOG(ALERT) << "Invalid channel requested";
134 return -1;
135 }
136
137 return mDevice->getNominalTxPower(chan);
138}
139
kurtis.heimerl9b557832011-11-26 03:18:34 +0000140int RadioInterface::radioifyVector(signalVector &wVector,
Tom Tsou28670fb2015-08-21 19:32:58 -0700141 size_t chan, bool zero)
dburgessb3a0ca42011-10-12 07:44:40 +0000142{
Tom Tsou28670fb2015-08-21 19:32:58 -0700143 if (zero)
144 sendBuffer[chan]->zero(wVector.size());
145 else
146 sendBuffer[chan]->write((float *) wVector.begin(), wVector.size());
kurtis.heimerl9b557832011-11-26 03:18:34 +0000147
148 return wVector.size();
dburgessb3a0ca42011-10-12 07:44:40 +0000149}
150
Tom Tsou28670fb2015-08-21 19:32:58 -0700151int RadioInterface::unRadioifyVector(signalVector *newVector, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000152{
Tom Tsou28670fb2015-08-21 19:32:58 -0700153 if (newVector->size() > recvBuffer[chan]->getAvailSamples()) {
Thomas Tsou9471d762013-08-20 21:24:24 -0400154 LOG(ALERT) << "Insufficient number of samples in receive buffer";
155 return -1;
156 }
157
Tom Tsou28670fb2015-08-21 19:32:58 -0700158 recvBuffer[chan]->read((float *) newVector->begin(), newVector->size());
dburgessb3a0ca42011-10-12 07:44:40 +0000159
Tom Tsou28670fb2015-08-21 19:32:58 -0700160 return newVector->size();
dburgessb3a0ca42011-10-12 07:44:40 +0000161}
162
Thomas Tsou204a9f12013-10-29 18:34:16 -0400163bool RadioInterface::tuneTx(double freq, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000164{
Pau Espin Pedrola801ae52019-09-13 15:59:29 +0200165 return mDevice->setTxFreq(freq, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000166}
167
Thomas Tsou204a9f12013-10-29 18:34:16 -0400168bool RadioInterface::tuneRx(double freq, size_t chan)
dburgessb3a0ca42011-10-12 07:44:40 +0000169{
Pau Espin Pedrola801ae52019-09-13 15:59:29 +0200170 return mDevice->setRxFreq(freq, chan);
dburgessb3a0ca42011-10-12 07:44:40 +0000171}
172
Pau Espin Pedrol0fc20d12018-04-24 17:48:52 +0200173/** synchronization thread loop */
174void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface)
175{
Pau Espin Pedrol5b60c982018-09-20 18:04:46 +0200176 set_selfthread_name("AlignRadio");
Pau Espin Pedrol553a2502020-07-29 18:05:25 +0200177 OSMO_ASSERT(osmo_cpu_sched_vty_apply_localthread() == 0);
Pau Espin Pedrol0fc20d12018-04-24 17:48:52 +0200178 while (1) {
179 sleep(60);
180 radioInterface->alignRadio();
181 pthread_testcancel();
182 }
183 return NULL;
184}
185
186void RadioInterface::alignRadio() {
Pau Espin Pedrola801ae52019-09-13 15:59:29 +0200187 mDevice->updateAlignment(writeTimestamp+ (TIMESTAMP) 10000);
Pau Espin Pedrol0fc20d12018-04-24 17:48:52 +0200188}
189
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800190bool RadioInterface::start()
dburgessb3a0ca42011-10-12 07:44:40 +0000191{
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800192 if (mOn)
193 return true;
194
195 LOG(INFO) << "Starting radio device";
Pau Espin Pedrola801ae52019-09-13 15:59:29 +0200196 if (mDevice->requiresRadioAlign())
Pau Espin Pedrol0fc20d12018-04-24 17:48:52 +0200197 mAlignRadioServiceLoopThread.start(
198 (void * (*)(void*))AlignRadioServiceLoopAdapter,
199 (void*)this);
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800200
Pau Espin Pedrola801ae52019-09-13 15:59:29 +0200201 if (!mDevice->start())
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800202 return false;
203
Tom Tsou28670fb2015-08-21 19:32:58 -0700204 for (size_t i = 0; i < mChans; i++) {
205 sendBuffer[i]->reset();
206 recvBuffer[i]->reset();
207 }
Tom Tsoud7610cf2015-05-07 17:39:49 -0700208
Pau Espin Pedrola801ae52019-09-13 15:59:29 +0200209 writeTimestamp = mDevice->initialWriteTimestamp();
210 readTimestamp = mDevice->initialReadTimestamp();
Thomas Tsou18d3b832014-02-13 14:55:23 -0500211
Pau Espin Pedrola801ae52019-09-13 15:59:29 +0200212 mDevice->updateAlignment(writeTimestamp-10000);
213 mDevice->updateAlignment(writeTimestamp-10000);
dburgessb3a0ca42011-10-12 07:44:40 +0000214
dburgessb3a0ca42011-10-12 07:44:40 +0000215 mOn = true;
Thomas Tsou18d3b832014-02-13 14:55:23 -0500216 LOG(INFO) << "Radio started";
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800217 return true;
218}
219
220/*
221 * Stop the radio device
222 *
223 * This is a pass-through call to the device interface. Because the underlying
224 * stop command issuance generally doesn't return confirmation on device status,
225 * this call will only return false if the device is already stopped.
226 */
227bool RadioInterface::stop()
228{
Pau Espin Pedrola801ae52019-09-13 15:59:29 +0200229 if (!mOn || !mDevice->stop())
Tom Tsoueb54bdd2014-11-25 16:06:32 -0800230 return false;
231
232 mOn = false;
233 return true;
dburgessb3a0ca42011-10-12 07:44:40 +0000234}
235
Thomas Tsou204a9f12013-10-29 18:34:16 -0400236void RadioInterface::driveTransmitRadio(std::vector<signalVector *> &bursts,
237 std::vector<bool> &zeros)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400238{
239 if (!mOn)
240 return;
dburgessb3a0ca42011-10-12 07:44:40 +0000241
Tom Tsou28670fb2015-08-21 19:32:58 -0700242 for (size_t i = 0; i < mChans; i++)
243 radioifyVector(*bursts[i], i, zeros[i]);
dburgessb3a0ca42011-10-12 07:44:40 +0000244
Tom Tsou28670fb2015-08-21 19:32:58 -0700245 while (pushBuffer());
dburgessb3a0ca42011-10-12 07:44:40 +0000246}
247
Pau Espin Pedrol8e498bf2018-09-03 16:45:15 +0200248int RadioInterface::driveReceiveRadio()
Thomas Tsou204a9f12013-10-29 18:34:16 -0400249{
250 radioVector *burst = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000251
Thomas Tsou204a9f12013-10-29 18:34:16 -0400252 if (!mOn)
Pau Espin Pedrol8e498bf2018-09-03 16:45:15 +0200253 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +0000254
Pau Espin Pedrol8e498bf2018-09-03 16:45:15 +0200255 if (pullBuffer() < 0)
256 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +0000257
258 GSM::Time rcvClock = mClock.get();
259 rcvClock.decTN(receiveOffset);
260 unsigned tN = rcvClock.TN();
Tom Tsou28670fb2015-08-21 19:32:58 -0700261 int recvSz = recvBuffer[0]->getAvailSamples();
dburgessb3a0ca42011-10-12 07:44:40 +0000262 const int symbolsPerSlot = gSlotLen + 8;
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800263 int burstSize;
264
265 if (mSPSRx == 4)
266 burstSize = 625;
267 else
268 burstSize = symbolsPerSlot + (tN % 4 == 0);
dburgessb3a0ca42011-10-12 07:44:40 +0000269
Pau Espin Pedrol46444632018-09-03 16:42:04 +0200270 /*
Thomas Tsoud0f3ca32013-11-09 22:05:23 -0500271 * Pre-allocate head room for the largest correlation size
272 * so we can later avoid a re-allocation and copy
273 * */
Vadim Yanitskiya79bc702018-10-17 11:01:58 +0200274 size_t head = GSM::gRACHSynchSequenceTS0.size();
Thomas Tsoud0f3ca32013-11-09 22:05:23 -0500275
276 /*
277 * Form receive bursts and pass up to transceiver. Use repeating
278 * pattern of 157-156-156-156 symbols per timeslot
279 */
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500280 while (recvSz > burstSize) {
Thomas Tsou204a9f12013-10-29 18:34:16 -0400281 for (size_t i = 0; i < mChans; i++) {
Tom Tsoud6ae8642017-03-30 17:22:58 -0700282 burst = new radioVector(rcvClock, burstSize, head);
283 unRadioifyVector(burst->getVector(), i);
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500284
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500285 if (mReceiveFIFO[i].size() < 32)
Thomas Tsou204a9f12013-10-29 18:34:16 -0400286 mReceiveFIFO[i].write(burst);
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500287 else
Thomas Tsou204a9f12013-10-29 18:34:16 -0400288 delete burst;
dburgessb3a0ca42011-10-12 07:44:40 +0000289 }
Thomas Tsou204a9f12013-10-29 18:34:16 -0400290
291 mClock.incTN();
dburgessb3a0ca42011-10-12 07:44:40 +0000292 rcvClock.incTN();
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500293 recvSz -= burstSize;
dburgessb3a0ca42011-10-12 07:44:40 +0000294
295 tN = rcvClock.TN();
Thomas Tsoue0fa2bf2013-11-09 02:46:29 -0500296
Tom Tsou5cd70dc2016-03-06 01:28:40 -0800297 if (mSPSRx != 4)
298 burstSize = (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx;
dburgessb3a0ca42011-10-12 07:44:40 +0000299 }
300
Pau Espin Pedrol8e498bf2018-09-03 16:45:15 +0200301 return 1;
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000302}
303
304bool RadioInterface::isUnderrun()
305{
Pau Espin Pedrole503c982019-09-13 18:56:08 +0200306 bool retVal;
307 /* atomically get previous value of "underrun" and set the var to false */
308 retVal = osmo_trx_sync_fetch_and_and(&underrun, false);
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000309 return retVal;
310}
311
Thomas Tsou204a9f12013-10-29 18:34:16 -0400312VectorFIFO* RadioInterface::receiveFIFO(size_t chan)
313{
314 if (chan >= mReceiveFIFO.size())
315 return NULL;
316
317 return &mReceiveFIFO[chan];
318}
319
320double RadioInterface::setRxGain(double dB, size_t chan)
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000321{
Pau Espin Pedrola801ae52019-09-13 15:59:29 +0200322 return mDevice->setRxGain(dB, chan);
kurtis.heimerle724d6d2011-11-26 03:18:46 +0000323}
324
Pau Espin Pedrole91544d2020-10-13 17:03:37 +0200325double RadioInterface::rssiOffset(size_t chan)
326{
327 return mDevice->rssiOffset(chan);
328}
329
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400330/* Receive a timestamped chunk from the device */
Pau Espin Pedrol8e498bf2018-09-03 16:45:15 +0200331int RadioInterface::pullBuffer()
Thomas Tsoucb69f082013-04-08 14:18:26 -0400332{
333 bool local_underrun;
Pau Espin Pedrol97009692018-09-03 17:01:59 +0200334 int numRecv;
335 size_t segmentLen = recvBuffer[0]->getSegmentLen();
Thomas Tsoucb69f082013-04-08 14:18:26 -0400336
Tom Tsou28670fb2015-08-21 19:32:58 -0700337 if (recvBuffer[0]->getFreeSegments() <= 0)
Pau Espin Pedrol8e498bf2018-09-03 16:45:15 +0200338 return -1;
Thomas Tsou3952d802013-10-15 15:12:24 -0400339
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400340 /* Outer buffer access size is fixed */
Pau Espin Pedrola801ae52019-09-13 15:59:29 +0200341 numRecv = mDevice->readSamples(convertRecvBuffer,
Tom Tsou28670fb2015-08-21 19:32:58 -0700342 segmentLen,
343 &overrun,
344 readTimestamp,
345 &local_underrun);
346
Pau Espin Pedrol97009692018-09-03 17:01:59 +0200347 if ((size_t) numRecv != segmentLen) {
Tom Tsou28670fb2015-08-21 19:32:58 -0700348 LOG(ALERT) << "Receive error " << numRecv;
Pau Espin Pedrol8e498bf2018-09-03 16:45:15 +0200349 return -1;
Thomas Tsou9471d762013-08-20 21:24:24 -0400350 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400351
Thomas Tsou204a9f12013-10-29 18:34:16 -0400352 for (size_t i = 0; i < mChans; i++) {
Tom Tsou28670fb2015-08-21 19:32:58 -0700353 convert_short_float(recvBuffer[i]->getWriteSegment(),
354 convertRecvBuffer[i],
355 segmentLen * 2);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400356 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400357
Pau Espin Pedrole503c982019-09-13 18:56:08 +0200358 osmo_trx_sync_or_and_fetch(&underrun, local_underrun);
Tom Tsou28670fb2015-08-21 19:32:58 -0700359 readTimestamp += numRecv;
Pau Espin Pedrol8e498bf2018-09-03 16:45:15 +0200360 return 0;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400361}
362
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400363/* Send timestamped chunk to the device with arbitrary size */
Tom Tsou28670fb2015-08-21 19:32:58 -0700364bool RadioInterface::pushBuffer()
Thomas Tsoucb69f082013-04-08 14:18:26 -0400365{
Pau Espin Pedrol2c673e02019-07-29 20:14:47 +0200366 bool local_underrun;
Tom Tsou28670fb2015-08-21 19:32:58 -0700367 size_t numSent, segmentLen = sendBuffer[0]->getSegmentLen();
Thomas Tsou9471d762013-08-20 21:24:24 -0400368
Tom Tsou28670fb2015-08-21 19:32:58 -0700369 if (sendBuffer[0]->getAvailSegments() < 1)
370 return false;
Thomas Tsou3952d802013-10-15 15:12:24 -0400371
Thomas Tsou204a9f12013-10-29 18:34:16 -0400372 for (size_t i = 0; i < mChans; i++) {
373 convert_float_short(convertSendBuffer[i],
Tom Tsoub577ef02016-07-12 16:07:48 -0700374 (float *) sendBuffer[i]->getReadSegment(),
Tom Tsou28670fb2015-08-21 19:32:58 -0700375 powerScaling[i],
376 segmentLen * 2);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400377 }
Thomas Tsoucb69f082013-04-08 14:18:26 -0400378
Tom Tsou28670fb2015-08-21 19:32:58 -0700379 /* Send the all samples in the send buffer */
Pau Espin Pedrola801ae52019-09-13 15:59:29 +0200380 numSent = mDevice->writeSamples(convertSendBuffer,
Tom Tsou28670fb2015-08-21 19:32:58 -0700381 segmentLen,
Pau Espin Pedrol2c673e02019-07-29 20:14:47 +0200382 &local_underrun,
Tom Tsou28670fb2015-08-21 19:32:58 -0700383 writeTimestamp);
Pau Espin Pedrole503c982019-09-13 18:56:08 +0200384 osmo_trx_sync_or_and_fetch(&underrun, local_underrun);
Tom Tsou28670fb2015-08-21 19:32:58 -0700385 writeTimestamp += numSent;
386
387 return true;
Thomas Tsoucb69f082013-04-08 14:18:26 -0400388}