From e2085e8c29eb1b4e09cbcf18fb7e187bea5b3854 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 31 Dec 2018 01:43:24 +0100 Subject: [PATCH] XTRX input: refactoring to prepare MI operation --- devices/xtrx/devicextrx.cpp | 37 + devices/xtrx/devicextrx.h | 12 + devices/xtrx/devicextrxparam.cpp | 31 +- devices/xtrx/devicextrxparam.h | 31 +- devices/xtrx/devicextrxshared.cpp | 22 +- devices/xtrx/devicextrxshared.h | 34 +- plugins/samplesource/xtrxinput/xtrxinput.cpp | 660 ++++++++++-------- plugins/samplesource/xtrxinput/xtrxinput.h | 17 +- .../xtrxinput/xtrxinputthread.cpp | 225 ++++-- .../samplesource/xtrxinput/xtrxinputthread.h | 47 +- 10 files changed, 647 insertions(+), 469 deletions(-) diff --git a/devices/xtrx/devicextrx.cpp b/devices/xtrx/devicextrx.cpp index 02e969681..78eaaed17 100644 --- a/devices/xtrx/devicextrx.cpp +++ b/devices/xtrx/devicextrx.cpp @@ -14,6 +14,9 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#include + +#include "xtrx_api.h" #include "devicextrx.h" const uint32_t DeviceXTRX::m_lnaTbl[m_nbGains] = { @@ -32,6 +35,40 @@ const uint32_t DeviceXTRX::m_pgaTbl[m_nbGains] = { 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; +DeviceXTRX::DeviceXTRX() : + m_dev(0) +{} + +DeviceXTRX::~DeviceXTRX() +{ + close(); +} + +bool DeviceXTRX::open(const char* deviceStr) +{ + int res; + qDebug("DeviceXTRX::open: serial: %s", (const char *) deviceStr); + + res = xtrx_open(deviceStr, XTRX_O_RESET | 4, &m_dev); + + if (res) + { + qCritical() << "DeviceXTRX::open: cannot open device " << deviceStr; + return false; + } + + return true; +} + +void DeviceXTRX::close() +{ + if (m_dev) + { + xtrx_close(m_dev); + m_dev = 0; + } +} + void DeviceXTRX::getAutoGains(uint32_t autoGain, uint32_t& lnaGain, uint32_t& tiaGain, uint32_t& pgaGain) { uint32_t value = autoGain + 12 > 73 ? 73 : autoGain + 12; diff --git a/devices/xtrx/devicextrx.h b/devices/xtrx/devicextrx.h index 362a08e5d..e42b1dc52 100644 --- a/devices/xtrx/devicextrx.h +++ b/devices/xtrx/devicextrx.h @@ -21,13 +21,25 @@ #include "export.h" +struct strx_dev; + class DEVICES_API DeviceXTRX { public: + DeviceXTRX(); + ~DeviceXTRX(); + + bool open(const char* deviceStr); + void close(); + struct xtrx_dev *getDevice() { return m_dev; } static void getAutoGains(uint32_t autoGain, uint32_t& lnaGain, uint32_t& tiaGain, uint32_t& pgaGain); + static const uint32_t m_nbGains = 74; + static const unsigned int blockSize = (1<<14); private: + struct xtrx_dev *m_dev; //!< device handle + static const uint32_t m_lnaTbl[m_nbGains]; static const uint32_t m_pgaTbl[m_nbGains]; }; diff --git a/devices/xtrx/devicextrxparam.cpp b/devices/xtrx/devicextrxparam.cpp index 249656412..9570404eb 100644 --- a/devices/xtrx/devicextrxparam.cpp +++ b/devices/xtrx/devicextrxparam.cpp @@ -1,5 +1,6 @@ /////////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. // +// Copyright (C) 2018 Edouard Griffiths, F4EXB // // // // This program is free software; you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // @@ -17,28 +18,10 @@ #include #include "devicextrxparam.h" -bool DeviceXTRXParams::open(const char* deviceStr) -{ - int res; - qDebug("DeviceXTRXParams::open: serial: %s", (const char *) deviceStr); +DeviceXTRXParams::DeviceXTRXParams() : + m_nbRxChannels(2), + m_nbTxChannels(2) +{} - res = xtrx_open(deviceStr, XTRX_O_RESET | 4, &m_dev); - - if (res) - { - qCritical() << "DeviceXTRXParams::open: cannot open device " << deviceStr; - return false; - } - - - return true; -} - -void DeviceXTRXParams::close() -{ - if (m_dev) - { - xtrx_close(m_dev); - m_dev = 0; - } -} +DeviceXTRXParams::~DeviceXTRXParams() +{} diff --git a/devices/xtrx/devicextrxparam.h b/devices/xtrx/devicextrxparam.h index c7e2b4233..9aed515d9 100644 --- a/devices/xtrx/devicextrxparam.h +++ b/devices/xtrx/devicextrxparam.h @@ -1,5 +1,6 @@ /////////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. // +// Copyright (C) 2018 Edouard Griffiths, F4EXB // // // // This program is free software; you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // @@ -22,37 +23,11 @@ struct DeviceXTRXParams { - struct xtrx_dev *m_dev; //!< device handle uint32_t m_nbRxChannels; //!< number of Rx channels uint32_t m_nbTxChannels; //!< number of Tx channels - unsigned m_log2OvSRRx; - double m_sampleRate; //!< ADC/DAC sample rate - double m_rxFrequency; //!< Rx frequency - double m_txFrequency; //!< Tx frequency - - DeviceXTRXParams() : - m_dev(0), - m_nbRxChannels(2), - m_nbTxChannels(2), - m_log2OvSRRx(0), - m_sampleRate(5e6), - m_rxFrequency(30e6), - m_txFrequency(30e6) - { - } - - /** - * Opens and initialize the device and obtain information (# channels, ranges, ...) - */ - bool open(const char* deviceStr); - void close(); - - struct xtrx_dev *getDevice() { return m_dev; } - - ~DeviceXTRXParams() - { - } + DeviceXTRXParams(); + ~DeviceXTRXParams(); }; #endif /* DEVICES_XTRX_DEVICEXTRXPARAM_H_ */ diff --git a/devices/xtrx/devicextrxshared.cpp b/devices/xtrx/devicextrxshared.cpp index 204db381c..fc3c93ae2 100644 --- a/devices/xtrx/devicextrxshared.cpp +++ b/devices/xtrx/devicextrxshared.cpp @@ -17,6 +17,7 @@ #include #include "devicextrxshared.h" +#include "devicextrx.h" MESSAGE_CLASS_DEFINITION(DeviceXTRXShared::MsgReportBuddyChange, Message) MESSAGE_CLASS_DEFINITION(DeviceXTRXShared::MsgReportClockSourceChange, Message) @@ -25,11 +26,20 @@ MESSAGE_CLASS_DEFINITION(DeviceXTRXShared::MsgReportDeviceInfo, Message) const float DeviceXTRXShared::m_sampleFifoLengthInSeconds = 0.25; const int DeviceXTRXShared::m_sampleFifoMinSize = 48000; // 192kS/s knee +DeviceXTRXShared::DeviceXTRXShared() : + m_dev(0), + m_channel(-1), + m_source(0), + m_sink(0), + m_inputRate(0), + m_outputRate(0), + m_masterRate(0) +{} +DeviceXTRXShared::~DeviceXTRXShared() +{} -double DeviceXTRXShared::set_samplerate(double rate, - double master, - bool output) +double DeviceXTRXShared::set_samplerate(double rate, double master, bool output) { if (output) { @@ -52,7 +62,7 @@ double DeviceXTRXShared::set_samplerate(double rate, double actualrx; double actualtx; - int res = xtrx_set_samplerate(m_deviceParams->getDevice(), + int res = xtrx_set_samplerate(m_dev->getDevice(), m_masterRate, m_inputRate, m_outputRate, @@ -90,7 +100,7 @@ double DeviceXTRXShared::get_board_temperature() { uint64_t val = 0; - int res = xtrx_val_get(m_deviceParams->getDevice(), XTRX_TRX, XTRX_CH_AB, XTRX_BOARD_TEMP, &val); + int res = xtrx_val_get(m_dev->getDevice(), XTRX_TRX, XTRX_CH_AB, XTRX_BOARD_TEMP, &val); if (res) { return 0; @@ -103,7 +113,7 @@ bool DeviceXTRXShared::get_gps_status() { uint64_t val = 0; - int res = xtrx_val_get(m_deviceParams->getDevice(), XTRX_TRX, XTRX_CH_AB, XTRX_WAIT_1PPS, &val); + int res = xtrx_val_get(m_dev->getDevice(), XTRX_TRX, XTRX_CH_AB, XTRX_WAIT_1PPS, &val); if (res) { return false; diff --git a/devices/xtrx/devicextrxshared.h b/devices/xtrx/devicextrxshared.h index 0be1b8d71..671b7c0d1 100644 --- a/devices/xtrx/devicextrxshared.h +++ b/devices/xtrx/devicextrxshared.h @@ -21,6 +21,10 @@ #include "devicextrxparam.h" #include "util/message.h" +class DeviceXTRX; +class XTRXInput; +class XTRXOutput; + /** * Structure shared by a buddy with other buddies */ @@ -129,14 +133,10 @@ public: virtual bool isRunning() = 0; }; - DeviceXTRXParams *m_deviceParams; //!< unique hardware device parameters - xtrx_channel_t m_channel; //!< logical device channel number (-1 if none) - ThreadInterface *m_thread; //!< holds the thread address if started else 0 - int m_ncoFrequency; - double m_centerFrequency; - uint32_t m_log2Soft; - bool m_threadWasRunning; //!< flag to know if thread needs to be resumed after suspend - + DeviceXTRX *m_dev; + int m_channel; //!< allocated channel (-1 if none) + XTRXInput *m_source; + XTRXOutput *m_sink; double m_inputRate; double m_outputRate; double m_masterRate; @@ -144,24 +144,10 @@ public: static const float m_sampleFifoLengthInSeconds; static const int m_sampleFifoMinSize; - DeviceXTRXShared() : - m_deviceParams(0), - m_channel(XTRX_CH_AB), - m_thread(0), - m_ncoFrequency(0), - m_centerFrequency(0), - m_log2Soft(0), - m_threadWasRunning(false), - m_inputRate(0), - m_outputRate(0), - m_masterRate(0) - {} - - ~DeviceXTRXShared() - {} + DeviceXTRXShared(); + ~DeviceXTRXShared(); double set_samplerate(double rate, double master, bool output); - double get_board_temperature(); bool get_gps_status(); }; diff --git a/plugins/samplesource/xtrxinput/xtrxinput.cpp b/plugins/samplesource/xtrxinput/xtrxinput.cpp index 91354c79c..40abe42b8 100644 --- a/plugins/samplesource/xtrxinput/xtrxinput.cpp +++ b/plugins/samplesource/xtrxinput/xtrxinput.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2017 Edouard Griffiths, F4EXB // +// Copyright (C) 2017, 2018 Edouard Griffiths, F4EXB // // Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. // // // // This program is free software; you can redistribute it and/or modify // @@ -43,15 +43,9 @@ XTRXInput::XTRXInput(DeviceSourceAPI *deviceAPI) : m_settings(), m_XTRXInputThread(0), m_deviceDescription("XTRXInput"), - m_running(false), - m_channelAcquired(false) + m_running(false) { - - suspendRxBuddies(); - suspendTxBuddies(); openDevice(); - resumeTxBuddies(); - resumeRxBuddies(); m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID())); m_deviceAPI->addSink(m_fileSink); @@ -59,14 +53,13 @@ XTRXInput::XTRXInput(DeviceSourceAPI *deviceAPI) : XTRXInput::~XTRXInput() { - if (m_running) stop(); + if (m_running) { + stop(); + } + m_deviceAPI->removeSink(m_fileSink); delete m_fileSink; - suspendRxBuddies(); - suspendTxBuddies(); closeDevice(); - resumeTxBuddies(); - resumeRxBuddies(); } void XTRXInput::destroy() @@ -86,271 +79,264 @@ bool XTRXInput::openDevice() qDebug("XTRXInput::openDevice: allocated SampleFifo"); } - xtrx_channel_t requestedChannel = m_deviceAPI->getItemIndex() ? XTRX_CH_B : XTRX_CH_A; - - // look for Rx buddies and get reference to common parameters - // if there is a channel left take the first available + // look for Rx buddies and get reference to the device object if (m_deviceAPI->getSourceBuddies().size() > 0) // look source sibling first { qDebug("XTRXInput::openDevice: look in Rx buddies"); DeviceSourceAPI *sourceBuddy = m_deviceAPI->getSourceBuddies()[0]; - m_deviceShared = *((DeviceXTRXShared *) sourceBuddy->getBuddySharedPtr()); // copy shared data - DeviceXTRXParams *deviceParams = m_deviceShared.m_deviceParams; // get device parameters + DeviceXTRXShared *deviceXTRXShared = (DeviceXTRXShared*) sourceBuddy->getBuddySharedPtr(); - if (deviceParams == 0) + if (deviceXTRXShared == 0) { - qCritical("XTRXInput::openDevice: cannot get device parameters from Rx buddy"); - return false; // the device params should have been created by the buddy - } - else - { - qDebug("XTRXInput::openDevice: getting device parameters from Rx buddy"); + qCritical("XTRXInput::openDevice: the source buddy shared pointer is null"); + return false; } - if (m_deviceAPI->getSourceBuddies().size() == deviceParams->m_nbRxChannels) + DeviceXTRX *device = deviceXTRXShared->m_dev; + + if (device == 0) { - qCritical("XTRXInput::openDevice: no more Rx channels available in device"); - return false; // no more Rx channels available in device - } - else - { - qDebug("XTRXInput::openDevice: at least one more Rx channel is available in device"); + qCritical("XTRXInput::openDevice: cannot get device pointer from Rx buddy"); + return false; } - // check if the requested channel is busy and abort if so (should not happen if device management is working correctly) - - char *busyChannels = new char[deviceParams->m_nbRxChannels]; - memset(busyChannels, 0, deviceParams->m_nbRxChannels); - - for (unsigned int i = 0; i < m_deviceAPI->getSourceBuddies().size(); i++) - { - DeviceSourceAPI *buddy = m_deviceAPI->getSourceBuddies()[i]; - DeviceXTRXShared *buddyShared = (DeviceXTRXShared *) buddy->getBuddySharedPtr(); - - if (buddyShared->m_channel == requestedChannel) - { - qCritical("XTRXInput::openDevice: cannot open busy channel %u", requestedChannel); - return false; - } - } - - m_deviceShared.m_channel = requestedChannel; // acknowledge the requested channel - delete[] busyChannels; + m_deviceShared.m_dev = device; } - // look for Tx buddies and get reference to common parameters - // take the first Rx channel + // look for Tx buddies and get reference to the device object else if (m_deviceAPI->getSinkBuddies().size() > 0) // then sink { qDebug("XTRXInput::openDevice: look in Tx buddies"); DeviceSinkAPI *sinkBuddy = m_deviceAPI->getSinkBuddies()[0]; - m_deviceShared = *((DeviceXTRXShared *) sinkBuddy->getBuddySharedPtr()); // copy parameters + DeviceXTRXShared *deviceXTRXShared = (DeviceXTRXShared*) sinkBuddy->getBuddySharedPtr(); - if (m_deviceShared.m_deviceParams == 0) + if (deviceXTRXShared == 0) { - qCritical("XTRXInput::openDevice: cannot get device parameters from Tx buddy"); - return false; // the device params should have been created by the buddy - } - else - { - qDebug("XTRXInput::openDevice: getting device parameters from Tx buddy"); + qCritical("XTRXInput::openDevice: the sink buddy shared pointer is null"); + return false; } - m_deviceShared.m_channel = requestedChannel; // acknowledge the requested channel + DeviceXTRX *device = deviceXTRXShared->m_dev; + + if (device == 0) + { + qCritical("XTRXInput::openDevice: cannot get device pointer from Tx buddy"); + return false; + } + + m_deviceShared.m_dev = device; } - // There are no buddies then create the first XTRX common parameters - // open the device this will also populate common fields - // take the first Rx channel + // There are no buddies then create the first BladeRF2 device else { qDebug("XTRXInput::openDevice: open device here"); - m_deviceShared.m_deviceParams = new DeviceXTRXParams(); + m_deviceShared.m_dev = new DeviceXTRX(); char serial[256]; strcpy(serial, qPrintable(m_deviceAPI->getSampleSourceSerial())); - if (!m_deviceShared.m_deviceParams->open(serial)) { - delete m_deviceShared.m_deviceParams; - m_deviceShared.m_deviceParams = 0; - + if (!m_deviceShared.m_dev->open(serial)) + { + qCritical("XTRXInput::openDevice: cannot open BladeRF2 device"); return false; } - - m_deviceShared.m_channel = requestedChannel; // acknowledge the requested channel } + m_deviceShared.m_channel = m_deviceAPI->getItemIndex(); // publicly allocate channel + m_deviceShared.m_source = this; m_deviceAPI->setBuddySharedPtr(&m_deviceShared); // propagate common parameters to API - return true; } -void XTRXInput::suspendRxBuddies() -{ - const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); - std::vector::const_iterator itSource = sourceBuddies.begin(); - - qDebug("XTRXInput::suspendRxBuddies (%lu)", sourceBuddies.size()); - - for (; itSource != sourceBuddies.end(); ++itSource) - { - DeviceXTRXShared *buddySharedPtr = (DeviceXTRXShared *) (*itSource)->getBuddySharedPtr(); - - if (buddySharedPtr->m_thread && buddySharedPtr->m_thread->isRunning()) - { - buddySharedPtr->m_thread->stopWork(); - buddySharedPtr->m_threadWasRunning = true; - } - else - { - buddySharedPtr->m_threadWasRunning = false; - } - } -} - -void XTRXInput::suspendTxBuddies() -{ - const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); - std::vector::const_iterator itSink = sinkBuddies.begin(); - - qDebug("XTRXInput::suspendTxBuddies (%lu)", sinkBuddies.size()); - - for (; itSink != sinkBuddies.end(); ++itSink) - { - DeviceXTRXShared *buddySharedPtr = (DeviceXTRXShared *) (*itSink)->getBuddySharedPtr(); - - if (buddySharedPtr->m_thread) { - buddySharedPtr->m_thread->stopWork(); - buddySharedPtr->m_threadWasRunning = true; - } - else - { - buddySharedPtr->m_threadWasRunning = false; - } - } -} - -void XTRXInput::resumeRxBuddies() -{ - const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); - std::vector::const_iterator itSource = sourceBuddies.begin(); - - qDebug("XTRXInput::resumeRxBuddies (%lu)", sourceBuddies.size()); - - for (; itSource != sourceBuddies.end(); ++itSource) - { - DeviceXTRXShared *buddySharedPtr = (DeviceXTRXShared *) (*itSource)->getBuddySharedPtr(); - - if (buddySharedPtr->m_threadWasRunning) { - buddySharedPtr->m_thread->startWork(); - } - } -} - -void XTRXInput::resumeTxBuddies() -{ - const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); - std::vector::const_iterator itSink = sinkBuddies.begin(); - - qDebug("XTRXInput::resumeTxBuddies (%lu)", sinkBuddies.size()); - - for (; itSink != sinkBuddies.end(); ++itSink) - { - DeviceXTRXShared *buddySharedPtr = (DeviceXTRXShared *) (*itSink)->getBuddySharedPtr(); - - if (buddySharedPtr->m_threadWasRunning) { - buddySharedPtr->m_thread->startWork(); - } - } -} - void XTRXInput::closeDevice() { - if (m_deviceShared.m_deviceParams->getDevice() == 0) { // was never open + if (m_deviceShared.m_dev == 0) { // was never open return; } - if (m_running) { stop(); } + if (m_running) { + stop(); + } - m_deviceShared.m_channel = XTRX_CH_AB; + if (m_XTRXInputThread) { // stills own the thread => transfer to a buddy + moveThreadToBuddy(); + } + + m_deviceShared.m_channel = -1; // publicly release channel + m_deviceShared.m_source = 0; // No buddies so effectively close the device if ((m_deviceAPI->getSinkBuddies().size() == 0) && (m_deviceAPI->getSourceBuddies().size() == 0)) { - m_deviceShared.m_deviceParams->close(); - delete m_deviceShared.m_deviceParams; - m_deviceShared.m_deviceParams = 0; + m_deviceShared.m_dev->close(); + delete m_deviceShared.m_dev; + m_deviceShared.m_dev = 0; } } -bool XTRXInput::acquireChannel() -{ - //suspendRxBuddies(); - //suspendTxBuddies(); - - qDebug("XTRXInput::acquireChannel: stream set up on Rx channel %d", m_deviceShared.m_channel); - - //resumeTxBuddies(); - //resumeRxBuddies(); - - m_channelAcquired = true; - return true; -} - -void XTRXInput::releaseChannel() -{ - //suspendRxBuddies(); - //suspendTxBuddies(); - - qDebug("XTRXInput::releaseChannel: Rx channel %d disabled", m_deviceShared.m_channel); - - //resumeTxBuddies(); - //resumeRxBuddies(); - - // The channel will be effectively released to be reused in another device set only at close time - - m_channelAcquired = false; -} - void XTRXInput::init() { applySettings(m_settings, true, false); } +XTRXInputThread *XTRXInput::findThread() +{ + if (m_XTRXInputThread == 0) // this does not own the thread + { + XTRXInputThread *xtrxInputThread = 0; + + // find a buddy that has allocated the thread + const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); + std::vector::const_iterator it = sourceBuddies.begin(); + + for (; it != sourceBuddies.end(); ++it) + { + XTRXInput *buddySource = ((DeviceXTRXShared*) (*it)->getBuddySharedPtr())->m_source; + + if (buddySource) + { + xtrxInputThread = buddySource->getThread(); + + if (xtrxInputThread) { + break; + } + } + } + + return xtrxInputThread; + } + else + { + return m_XTRXInputThread; // own thread + } +} + +void XTRXInput::moveThreadToBuddy() +{ + const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); + std::vector::const_iterator it = sourceBuddies.begin(); + + for (; it != sourceBuddies.end(); ++it) + { + XTRXInput *buddySource = ((DeviceXTRXShared*) (*it)->getBuddySharedPtr())->m_source; + + if (buddySource) + { + buddySource->setThread(m_XTRXInputThread); + m_XTRXInputThread = 0; // zero for others + } + } +} + bool XTRXInput::start() { - if (!m_deviceShared.m_deviceParams->getDevice()) { + // There is a single thread per physical device (Rx side). This thread is unique and referenced by a unique + // buddy in the group of source buddies associated with this physical device. + // + // This start method is responsible for managing the thread when the streaming of a Rx channel is started + // + // It checks the following conditions + // - the thread is allocated or not (by itself or one of its buddies). If it is it grabs the thread pointer. + // - the requested channel is another channel (one is already streaming). + // + // The XTRX support library lets you work in two possible modes: + // - Single Input (SI) with only one channel streaming. This can be channel 0 or 1 (channels can be swapped - unlike with BladeRF2). + // - Multiple Input (MI) with two channels streaming using interleaved samples. It MUST be in this configuration if both channels are + // streaming. + // + // It manages the transition form SI where only one channel is running to the Multiple Input (MI) if the both channels are requested. + // To perform the transition it stops the thread, deletes it and creates a new one. + // It marks the thread as needing start. + // + // If there is no thread allocated it means we are in SI mode and it creates a new one with the requested channel. + // It marks the thread as needing start. + // + // Eventually it registers the FIFO in the thread. If the thread has to be started it enables the channels up to the number of channels + // allocated in the thread and starts the thread. + + if (!m_deviceShared.m_dev || !m_deviceShared.m_dev->getDevice()) + { + qDebug("XTRXInput::start: no device object"); return false; } - if (m_running) { - stop(); + int requestedChannel = m_deviceAPI->getItemIndex(); + XTRXInputThread *xtrxInputThread = findThread(); + bool needsStart = false; + + if (xtrxInputThread) // if thread is already allocated + { + qDebug("XTRXInput::start: thread is already allocated"); + + unsigned int nbOriginalChannels = xtrxInputThread->getNbChannels(); + + // if one channel is already allocated it must be the other one so we'll end up with both channels + // thus we expand by deleting and re-creating the thread + if (nbOriginalChannels != 0) + { + qDebug("XTRXInput::start: expand channels. Re-allocate thread and take ownership"); + + SampleSinkFifo **fifos = new SampleSinkFifo*[2]; + unsigned int *log2Decims = new unsigned int[2]; + + for (int i = 0; i < 2; i++) // save original FIFO references and data + { + fifos[i] = xtrxInputThread->getFifo(i); + log2Decims[i] = xtrxInputThread->getLog2Decimation(i); + } + + xtrxInputThread->stopWork(); + delete xtrxInputThread; + xtrxInputThread = new XTRXInputThread(m_deviceShared.m_dev->getDevice(), 2); // MI mode (2 channels) + m_XTRXInputThread = xtrxInputThread; // take ownership + + for (int i = 0; i < 2; i++) // restore original FIFO references + { + xtrxInputThread->setFifo(i, fifos[i]); + xtrxInputThread->setLog2Decimation(i, log2Decims[i]); + } + + // remove old thread address from buddies (reset in all buddies). The address being held only in the owning source. + const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); + std::vector::const_iterator it = sourceBuddies.begin(); + + for (; it != sourceBuddies.end(); ++it) { + ((DeviceXTRXShared*) (*it)->getBuddySharedPtr())->m_source->setThread(0); + } + + // was used as temporary storage: + delete[] fifos; + delete[] log2Decims; + + needsStart = true; + } + else + { + qDebug("XTRXInput::start: keep buddy thread"); + } + } + else // first allocation + { + qDebug("XTRXInput::start: allocate thread and take ownership"); + xtrxInputThread = new XTRXInputThread(m_deviceShared.m_dev->getDevice(), 1, requestedChannel); + m_XTRXInputThread = xtrxInputThread; // take ownership + needsStart = true; } - if (!acquireChannel()) { - return false; + xtrxInputThread->setFifo(requestedChannel, &m_sampleFifo); + xtrxInputThread->setLog2Decimation(requestedChannel, m_settings.m_log2SoftDecim); + + if (needsStart) + { + qDebug("XTRXInput::start: (re)sart thread"); + xtrxInputThread->startWork(); } applySettings(m_settings, true); - // start / stop streaming is done in the thread. - - if ((m_XTRXInputThread = new XTRXInputThread(&m_deviceShared, &m_sampleFifo)) == 0) - { - qFatal("XTRXInput::start: cannot create thread"); - stop(); - return false; - } - else - { - qDebug("XTRXInput::start: thread created"); - } - - m_XTRXInputThread->setLog2Decimation(m_settings.m_log2SoftDecim); - m_XTRXInputThread->startWork(); - - m_deviceShared.m_thread = m_XTRXInputThread; + qDebug("XTRXInput::start: started"); m_running = true; return true; @@ -358,20 +344,140 @@ bool XTRXInput::start() void XTRXInput::stop() { - qDebug("XTRXInput::stop"); - disconnect(m_XTRXInputThread, SIGNAL(finished()), this, SLOT(threadFinished())); + // This stop method is responsible for managing the thread when the streaming of a Rx channel is stopped + // + // If the thread is currently managing only one channel (SI mode). The thread can be just stopped and deleted. + // Then the channel is closed. + // + // If the thread is currently managing both channels (MI mode) then we are removing one channel. Thus we must + // transition from MI to SI. This transition is handled by stopping the thread, deleting it and creating a new one + // managing a single channel. - if (m_XTRXInputThread != 0) - { - m_XTRXInputThread->stopWork(); - delete m_XTRXInputThread; - m_XTRXInputThread = 0; + if (!m_running) { + return; } - m_deviceShared.m_thread = 0; - m_running = false; + int requestedChannel = m_deviceAPI->getItemIndex(); // channel to remove + XTRXInputThread *xtrxInputThread = findThread(); - releaseChannel(); + if (xtrxInputThread == 0) { // no thread allocated + return; + } + + int nbOriginalChannels = xtrxInputThread->getNbChannels(); + + if (nbOriginalChannels == 1) // SI mode => just stop and delete the thread + { + qDebug("XTRXInput::stop: SI mode. Just stop and delete the thread"); + xtrxInputThread->stopWork(); + delete xtrxInputThread; + m_XTRXInputThread = 0; + + // remove old thread address from buddies (reset in all buddies) + const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); + std::vector::const_iterator it = sourceBuddies.begin(); + + for (; it != sourceBuddies.end(); ++it) { + ((DeviceXTRXShared*) (*it)->getBuddySharedPtr())->m_source->setThread(0); + } + } + else if (nbOriginalChannels == 2) // Reduce from MI to SI by deleting and re-creating the thread + { + qDebug("XTRXInput::stop: MI mode. Reduce by deleting and re-creating the thread"); + xtrxInputThread->stopWork(); + SampleSinkFifo **fifos = new SampleSinkFifo*[2]; + unsigned int *log2Decims = new unsigned int[2]; + + for (int i = 0; i < 2; i++) // save original FIFO references + { + fifos[i] = xtrxInputThread->getFifo(i); + log2Decims[i] = xtrxInputThread->getLog2Decimation(i); + } + + delete xtrxInputThread; + m_XTRXInputThread = 0; + + xtrxInputThread = new XTRXInputThread(m_deviceShared.m_dev->getDevice(), 1, requestedChannel ^ 1); // leave opposite channel + m_XTRXInputThread = xtrxInputThread; // take ownership + + for (int i = 0; i < nbOriginalChannels-1; i++) // restore original FIFO references + { + xtrxInputThread->setFifo(i, fifos[i]); + xtrxInputThread->setLog2Decimation(i, log2Decims[i]); + } + + // remove old thread address from buddies (reset in all buddies). The address being held only in the owning source. + const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); + std::vector::const_iterator it = sourceBuddies.begin(); + + for (; it != sourceBuddies.end(); ++it) { + ((DeviceXTRXShared*) (*it)->getBuddySharedPtr())->m_source->setThread(0); + } + + xtrxInputThread->startWork(); + + // was used as temporary storage: + delete[] fifos; + delete[] log2Decims; + } + + m_running = false; +} + +void XTRXInput::suspendTxThread() +{ + // TODO: activate when output is managed +// XTRXOutputThread *xtrxOutputThread = 0; +// +// // find a buddy that has allocated the thread +// const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); +// std::vector::const_iterator itSink = sinkBuddies.begin() +// +// for (; itSink != sinkBuddies.end(); ++itSink) +// { +// XTRXOutput *buddySink = ((DeviceXTRXShared*) (*itSink)->getBuddySharedPtr())->m_sink; +// +// if (buddySink) +// { +// xtrxOutputThread = buddySink->getThread(); +// +// if (xtrxOutputThread) { +// break; +// } +// } +// } +// +// if (xtrxOutputThread) { +// xtrxOutputThread->stopWork(); +// } +} + +void XTRXInput::resumeTxThread() +{ + // TODO: activate when output is managed +// XTRXOutputThread *xtrxOutputThread = 0; +// +// // find a buddy that has allocated the thread +// const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); +// std::vector::const_iterator itSink = sinkBuddies.begin() +// +// for (; itSink != sinkBuddies.end(); ++itSink) +// { +// XTRXOutput *buddySink = ((DeviceXTRXShared*) (*itSink)->getBuddySharedPtr())->m_sink; +// +// if (buddySink) +// { +// xtrxOutputThread = buddySink->getThread(); +// +// if (xtrxOutputThread) { +// break; +// } +// } +// } +// +// if (xtrxOutputThread) { +// xtrxOutputThread->startWork(); +// } } QByteArray XTRXInput::serialize() const @@ -464,11 +570,6 @@ void XTRXInput::getLPRange(float& minF, float& maxF, float& stepF) const minF, maxF, stepF); } -uint32_t XTRXInput::getHWLog2Decim() const -{ - return m_deviceShared.m_deviceParams->m_log2OvSRRx; -} - bool XTRXInput::handleMessage(const Message& message) { if (MsgConfigureXTRX::match(message)) @@ -541,7 +642,7 @@ bool XTRXInput::handleMessage(const Message& message) { uint64_t fifolevel = 0; - xtrx_val_get(m_deviceShared.m_deviceParams->getDevice(), + xtrx_val_get(m_deviceShared.m_dev->getDevice(), XTRX_RX, XTRX_CH_AB, XTRX_PERF_LLFIFO, &fifolevel); MsgReportStreamInfo *report = MsgReportStreamInfo::create( @@ -562,11 +663,11 @@ bool XTRXInput::handleMessage(const Message& message) double board_temp = 0.0; bool gps_locked = false; - if (!m_deviceShared.m_deviceParams->getDevice() || ((board_temp = m_deviceShared.get_board_temperature() / 256.0) == 0.0)) { + if (!m_deviceShared.m_dev->getDevice() || ((board_temp = m_deviceShared.get_board_temperature() / 256.0) == 0.0)) { qDebug("XTRXInput::handleMessage: MsgGetDeviceInfo: cannot get board temperature"); } - if (!m_deviceShared.m_deviceParams->getDevice()) { + if (!m_deviceShared.m_dev->getDevice()) { qDebug("XTRXInput::handleMessage: MsgGetDeviceInfo: cannot get GPS lock status"); } else { gps_locked = m_deviceShared.get_gps_status(); @@ -667,7 +768,7 @@ void XTRXInput::apply_gain_auto(uint32_t gain) void XTRXInput::apply_gain_lna(double gain) { - if (xtrx_set_gain(m_deviceShared.m_deviceParams->getDevice(), + if (xtrx_set_gain(m_deviceShared.m_dev->getDevice(), XTRX_CH_AB /*m_deviceShared.m_channel*/, XTRX_RX_LNA_GAIN, gain, @@ -683,7 +784,7 @@ void XTRXInput::apply_gain_lna(double gain) void XTRXInput::apply_gain_tia(double gain) { - if (xtrx_set_gain(m_deviceShared.m_deviceParams->getDevice(), + if (xtrx_set_gain(m_deviceShared.m_dev->getDevice(), XTRX_CH_AB /*m_deviceShared.m_channel*/, XTRX_RX_TIA_GAIN, gain, @@ -699,7 +800,7 @@ void XTRXInput::apply_gain_tia(double gain) void XTRXInput::apply_gain_pga(double gain) { - if (xtrx_set_gain(m_deviceShared.m_deviceParams->getDevice(), + if (xtrx_set_gain(m_deviceShared.m_dev->getDevice(), XTRX_CH_AB /*m_deviceShared.m_channel*/, XTRX_RX_PGA_GAIN, gain, @@ -715,11 +816,14 @@ void XTRXInput::apply_gain_pga(double gain) bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, bool forceNCOFrequency) { + int requestedChannel = m_deviceAPI->getItemIndex(); + XTRXInputThread *inputThread = findThread(); + bool forwardChangeOwnDSP = false; bool forwardChangeRxDSP = false; bool forwardChangeAllDSP = false; bool forwardClockSource = false; - bool ownThreadWasRunning = false; + bool rxThreadWasRunning = false; bool doLPCalibration = false; bool doChangeSampleRate = false; bool doChangeFreq = false; @@ -731,22 +835,17 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo // apply settings - if ((m_settings.m_dcBlock != settings.m_dcBlock) || force) - { + if ((m_settings.m_dcBlock != settings.m_dcBlock) || force) { m_deviceAPI->configureCorrections(settings.m_dcBlock, settings.m_iqCorrection); } - if ((m_settings.m_iqCorrection != settings.m_iqCorrection) || force) - { + if ((m_settings.m_iqCorrection != settings.m_iqCorrection) || force) { m_deviceAPI->configureCorrections(settings.m_dcBlock, settings.m_iqCorrection); } if ((m_settings.m_pwrmode != settings.m_pwrmode)) { - if (xtrx_val_set(m_deviceShared.m_deviceParams->getDevice(), - XTRX_TRX, XTRX_CH_AB, XTRX_LMS7_PWR_MODE, settings.m_pwrmode) < 0) - { - qCritical("XTRXInput::applySettings: could not set power mode %d", - settings.m_pwrmode); + if (xtrx_val_set(m_deviceShared.m_dev->getDevice(), XTRX_TRX, XTRX_CH_AB, XTRX_LMS7_PWR_MODE, settings.m_pwrmode) < 0) { + qCritical("XTRXInput::applySettings: could not set power mode %d", settings.m_pwrmode); } } @@ -754,7 +853,7 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo (settings.m_extClock && (m_settings.m_extClockFreq != settings.m_extClockFreq)) || force) { - xtrx_set_ref_clk(m_deviceShared.m_deviceParams->getDevice(), + xtrx_set_ref_clk(m_deviceShared.m_dev->getDevice(), (settings.m_extClock) ? settings.m_extClockFreq : 0, (settings.m_extClock) ? XTRX_CLKSRC_EXT : XTRX_CLKSRC_INT); { @@ -772,13 +871,12 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo { forwardChangeAllDSP = true; //m_settings.m_devSampleRate != settings.m_devSampleRate; - if (m_deviceShared.m_deviceParams->getDevice() != 0 && m_channelAcquired) - { + if (m_deviceShared.m_dev->getDevice() != 0) { doChangeSampleRate = true; } } - if (m_deviceShared.m_deviceParams->getDevice() != 0 && m_channelAcquired) + if (m_deviceShared.m_dev->getDevice() != 0) { if ((m_settings.m_gainMode != settings.m_gainMode) || force) { @@ -799,16 +897,13 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo } else if (m_settings.m_gainMode == XTRXInputSettings::GAIN_MANUAL) { - if (m_settings.m_lnaGain != settings.m_lnaGain) - { + if (m_settings.m_lnaGain != settings.m_lnaGain) { doGainLna = true; } - if (m_settings.m_tiaGain != settings.m_tiaGain) - { + if (m_settings.m_tiaGain != settings.m_tiaGain) { doGainTia = true; } - if (m_settings.m_pgaGain != settings.m_pgaGain) - { + if (m_settings.m_pgaGain != settings.m_pgaGain) { doGainPga = true; } } @@ -816,8 +911,7 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo if ((m_settings.m_lpfBW != settings.m_lpfBW) || force) { - if (m_deviceShared.m_deviceParams->getDevice() != 0 && m_channelAcquired) - { + if (m_deviceShared.m_dev->getDevice() != 0) { doLPCalibration = true; } } @@ -852,36 +946,27 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo if ((m_settings.m_log2SoftDecim != settings.m_log2SoftDecim) || force) { forwardChangeOwnDSP = true; - m_deviceShared.m_log2Soft = settings.m_log2SoftDecim; // for buddies - if (m_XTRXInputThread != 0) + if (inputThread != 0) { - m_XTRXInputThread->setLog2Decimation(settings.m_log2SoftDecim); + inputThread->setLog2Decimation(requestedChannel, settings.m_log2SoftDecim); qDebug() << "XTRXInput::applySettings: set soft decimation to " << (1<getDevice() != 0 && m_channelAcquired) + if (m_deviceShared.m_dev->getDevice() != 0) { - if (xtrx_set_antenna(m_deviceShared.m_deviceParams->getDevice(), - settings.m_antennaPath) < 0) - { - qCritical("XTRXInput::applySettings: could not set antenna path to %d", - (int) settings.m_antennaPath); - } - else - { - qDebug("XTRXInput::applySettings: set antenna path to %d on channel %d", - (int) settings.m_antennaPath, - m_deviceShared.m_channel); + if (xtrx_set_antenna(m_deviceShared.m_dev->getDevice(), settings.m_antennaPath) < 0) { + qCritical("XTRXInput::applySettings: could not set antenna path to %d", (int) settings.m_antennaPath); + } else { + qDebug("XTRXInput::applySettings: set antenna path to %d", (int) settings.m_antennaPath); } } } - if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force) - { + if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force) { doChangeFreq = true; } @@ -896,14 +981,15 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo if (doChangeSampleRate) { - if (m_XTRXInputThread && m_XTRXInputThread->isRunning()) + XTRXInputThread *rxThread = findThread(); + + if (rxThread && rxThread->isRunning()) { - m_XTRXInputThread->stopWork(); - ownThreadWasRunning = true; + rxThread->stopWork(); + rxThreadWasRunning = true; } - suspendRxBuddies(); - suspendTxBuddies(); + suspendTxThread(); double master = (settings.m_log2HardDecim == 0) ? 0 : (settings.m_devSampleRate * 4 * (1 << settings.m_log2HardDecim)); @@ -917,8 +1003,6 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo } else { - m_deviceShared.m_deviceParams->m_log2OvSRRx = settings.m_log2HardDecim; - m_deviceShared.m_deviceParams->m_sampleRate = settings.m_devSampleRate; doChangeFreq = true; forceNCOFrequency = true; @@ -927,19 +1011,17 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo 1<startWork(); + if (rxThreadWasRunning) { + rxThread->startWork(); } } if (doLPCalibration) { - if (xtrx_tune_rx_bandwidth(m_deviceShared.m_deviceParams->getDevice(), - m_deviceShared.m_channel, + if (xtrx_tune_rx_bandwidth(m_deviceShared.m_dev->getDevice(), + m_deviceShared.m_channel == 0 ? XTRX_CH_A : XTRX_CH_B, m_settings.m_lpfBW, NULL) < 0) { @@ -972,9 +1054,9 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo { forwardChangeRxDSP = true; - if (m_deviceShared.m_deviceParams->getDevice() != 0 && m_channelAcquired) + if (m_deviceShared.m_dev->getDevice() != 0) { - if (xtrx_tune(m_deviceShared.m_deviceParams->getDevice(), + if (xtrx_tune(m_deviceShared.m_dev->getDevice(), XTRX_TUNE_RX_FDD, settings.m_centerFrequency, NULL) < 0) @@ -984,7 +1066,6 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo else { //doCalibration = true; - m_deviceShared.m_centerFrequency = settings.m_centerFrequency; // for buddies qDebug("XTRXInput::applySettings: frequency set to %lu", settings.m_centerFrequency); } } @@ -992,9 +1073,9 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo if (forceNCOFrequency) { - if (m_deviceShared.m_deviceParams->getDevice() != 0 && m_channelAcquired) + if (m_deviceShared.m_dev->getDevice() != 0) { - if (xtrx_tune(m_deviceShared.m_deviceParams->getDevice(), + if (xtrx_tune(m_deviceShared.m_dev->getDevice(), XTRX_TUNE_BB_RX, /* m_deviceShared.m_channel, */ (settings.m_ncoEnable) ? settings.m_ncoFrequency : 0, @@ -1007,7 +1088,6 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo else { forwardChangeOwnDSP = true; - m_deviceShared.m_ncoFrequency = settings.m_ncoEnable ? settings.m_ncoFrequency : 0; // for buddies qDebug("XTRXInput::applySettings: %sd and set NCO to %d Hz", settings.m_ncoEnable ? "enable" : "disable", settings.m_ncoFrequency); diff --git a/plugins/samplesource/xtrxinput/xtrxinput.h b/plugins/samplesource/xtrxinput/xtrxinput.h index 3c771fffa..64d951695 100644 --- a/plugins/samplesource/xtrxinput/xtrxinput.h +++ b/plugins/samplesource/xtrxinput/xtrxinput.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2017 Edouard Griffiths, F4EXB // +// Copyright (C) 2017, 2018 Edouard Griffiths, F4EXB // // Copyright (C) 2017 Sergey Kostanbaev, Fairwaves Inc. // // // // This program is free software; you can redistribute it and/or modify // @@ -176,6 +176,8 @@ public: virtual void init(); virtual bool start(); virtual void stop(); + XTRXInputThread *getThread() { return m_XTRXInputThread; } + void setThread(XTRXInputThread *thread) { m_XTRXInputThread = thread; } virtual QByteArray serialize() const; virtual bool deserialize(const QByteArray& data); @@ -192,7 +194,6 @@ public: void getLORange(float& minF, float& maxF, float& stepF) const; void getSRRange(float& minF, float& maxF, float& stepF) const; void getLPRange(float& minF, float& maxF, float& stepF) const; - uint32_t getHWLog2Decim() const; void apply_gain_auto(uint32_t gain); void apply_gain_lna(double gain); @@ -207,18 +208,16 @@ private: QString m_deviceDescription; bool m_running; DeviceXTRXShared m_deviceShared; - bool m_channelAcquired; FileRecord *m_fileSink; //!< File sink to record device I/Q output bool openDevice(); void closeDevice(); - bool acquireChannel(); - void releaseChannel(); - void suspendRxBuddies(); - void resumeRxBuddies(); - void suspendTxBuddies(); - void resumeTxBuddies(); + XTRXInputThread *findThread(); + void moveThreadToBuddy(); + + void suspendTxThread(); + void resumeTxThread(); bool applySettings(const XTRXInputSettings& settings, bool force = false, bool forceNCOFrequency = false); }; diff --git a/plugins/samplesource/xtrxinput/xtrxinputthread.cpp b/plugins/samplesource/xtrxinput/xtrxinputthread.cpp index 96865c48d..28b265423 100644 --- a/plugins/samplesource/xtrxinput/xtrxinputthread.cpp +++ b/plugins/samplesource/xtrxinput/xtrxinputthread.cpp @@ -16,25 +16,42 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include +#include +#include "xtrx_api.h" + +#include "xtrx/devicextrx.h" #include "xtrxinputsettings.h" #include "xtrxinputthread.h" -XTRXInputThread::XTRXInputThread(DeviceXTRXShared* shared, - SampleSinkFifo* sampleFifo, - QObject* parent) : +XTRXInputThread::XTRXInputThread(struct xtrx_dev *dev, unsigned int nbChannels, unsigned int uniqueChannelIndex, QObject* parent) : QThread(parent), m_running(false), - m_convertBuffer(XTRX_BLOCKSIZE), - m_sampleFifo(sampleFifo), - m_log2Decim(0), - m_shared(shared) + m_dev(dev), + m_nbChannels(nbChannels), + m_uniqueChannelIndex(uniqueChannelIndex) { + qDebug("XTRXInputThread::XTRXInputThread"); + m_channels = new Channel[2]; + + for (unsigned int i = 0; i < 2; i++) { + m_channels[i].m_convertBuffer.resize(DeviceXTRX::blockSize, Sample{0,0}); + } + + m_buf = new qint16[2*DeviceXTRX::blockSize*2]; // room for two channels } XTRXInputThread::~XTRXInputThread() { - stopWork(); + qDebug("XTRXInputThread::~XTRXInputThread"); + + if (m_running) { + stopWork(); + } + + delete[] m_buf; + delete[] m_channels; } void XTRXInputThread::startWork() @@ -63,10 +80,6 @@ void XTRXInputThread::stopWork() wait(); } -void XTRXInputThread::setLog2Decimation(unsigned int log2_decim) -{ - m_log2Decim = log2_decim; -} void XTRXInputThread::run() { @@ -75,106 +88,172 @@ void XTRXInputThread::run() m_running = true; m_startWaiter.wakeAll(); - xtrx_run_params params; - xtrx_run_params_init(¶ms); + unsigned int nbFifos = getNbFifos(); - params.dir = XTRX_RX; - params.rx.chs = XTRX_CH_AB; - params.rx.wfmt = XTRX_WF_16; - params.rx.hfmt = XTRX_IQ_INT16; - params.rx.flags |= XTRX_RSP_SISO_MODE; - params.rx_stream_start = 2*8192; - - // TODO: replace this - if (m_shared->m_channel == XTRX_CH_B) { - params.rx.flags |= XTRX_RSP_SWAP_AB; - } - - res = xtrx_run_ex(m_shared->m_deviceParams->getDevice(), ¶ms); - - if (res != 0) + if ((m_nbChannels > 0) && (nbFifos > 0)) { - qCritical("XTRXInputThread::run: could not start stream err:%d", res); - m_running = false; - } - else - { - usleep(50000); - qDebug("XTRXInputThread::run: stream started"); - } + xtrx_run_params params; + xtrx_run_params_init(¶ms); - void* buffers[1] = { m_buf }; - xtrx_recv_ex_info_t nfo; - nfo.samples = XTRX_BLOCKSIZE; - nfo.buffer_count = 1; - nfo.buffers = (void* const*)buffers; - nfo.flags = RCVEX_DONT_INSER_ZEROS | RCVEX_DROP_OLD_ON_OVERFLOW; + params.dir = XTRX_RX; + params.rx.chs = XTRX_CH_AB; + params.rx.wfmt = XTRX_WF_16; + params.rx.hfmt = XTRX_IQ_INT16; + params.rx_stream_start = 2*8192; - - while (m_running) - { - //if ((res = LMS_RecvStream(m_stream, (void *) m_buf, XTRX_BLOCKSIZE, &metadata, 1000)) < 0) - res = xtrx_recv_sync_ex(m_shared->m_deviceParams->getDevice(), &nfo); - - if (res < 0) + if (m_nbChannels == 1) { - qCritical("XTRXInputThread::run read error: %d", res); - break; + params.rx.flags |= XTRX_RSP_SISO_MODE; + + if (m_uniqueChannelIndex == 1) { + params.rx.flags |= XTRX_RSP_SWAP_AB; + } } - callback(m_buf, 2 * nfo.out_samples); - } + res = xtrx_run_ex(m_dev, ¶ms); - res = xtrx_stop(m_shared->m_deviceParams->getDevice(), XTRX_RX); + if (res != 0) + { + qCritical("XTRXInputThread::run: could not start stream err:%d", res); + m_running = false; + } + else + { + std::this_thread::sleep_for(std::chrono::microseconds(50000)); + qDebug("XTRXInputThread::run: stream started"); + } - if (res != 0) - { - qCritical("XTRXInputThread::run: could not stop stream"); + void* buffers[1] = { m_buf }; + xtrx_recv_ex_info_t nfo; + nfo.samples = DeviceXTRX::blockSize; + nfo.buffer_count = 1; + nfo.buffers = (void* const*)buffers; + nfo.flags = RCVEX_DONT_INSER_ZEROS | RCVEX_DROP_OLD_ON_OVERFLOW; + + while (m_running) + { + res = xtrx_recv_sync_ex(m_dev, &nfo); + + if (res < 0) + { + qCritical("XTRXInputThread::run read error: %d", res); + break; + } + + if (m_nbChannels > 1) { + callbackMI(m_buf, 2 * nfo.out_samples); + } else { + callbackSI(m_buf, 2 * nfo.out_samples); + } + } + + res = xtrx_stop(m_dev, XTRX_RX); + + if (res != 0) + { + qCritical("XTRXInputThread::run: could not stop stream"); + } + else + { + std::this_thread::sleep_for(std::chrono::microseconds(50000)); + qDebug("XTRXInputThread::run: stream stopped"); + } } else { - usleep(50000); - qDebug("XTRXInputThread::run: stream stopped"); + qWarning("XTRXInputThread::run: no channels or FIFO allocated. Aborting"); } m_running = false; } -// Decimate according to specified log2 (ex: log2=4 => decim=16) -void XTRXInputThread::callback(const qint16* buf, qint32 len) +unsigned int XTRXInputThread::getNbFifos() { - SampleVector::iterator it = m_convertBuffer.begin(); + unsigned int fifoCount = 0; - if (m_log2Decim == 0) + for (unsigned int i = 0; i < m_nbChannels; i++) { - m_decimators.decimate1(&it, buf, len); + if (m_channels[i].m_sampleFifo) { + fifoCount++; + } + } + + return fifoCount; +} + +void XTRXInputThread::setLog2Decimation(unsigned int channel, unsigned int log2_decim) +{ + if (channel < m_nbChannels) { + m_channels[channel].m_log2Decim = log2_decim; + } +} + +unsigned int XTRXInputThread::getLog2Decimation(unsigned int channel) const +{ + if (channel < m_nbChannels) { + return m_channels[channel].m_log2Decim; + } else { + return 0; + } +} + +void XTRXInputThread::setFifo(unsigned int channel, SampleSinkFifo *sampleFifo) +{ + if (channel < m_nbChannels) { + m_channels[channel].m_sampleFifo = sampleFifo; + } +} + +SampleSinkFifo *XTRXInputThread::getFifo(unsigned int channel) +{ + if (channel < m_nbChannels) { + return m_channels[channel].m_sampleFifo; + } else { + return 0; + } +} + +void XTRXInputThread::callbackSI(const qint16* buf, qint32 len) +{ + SampleVector::iterator it = m_channels[m_uniqueChannelIndex].m_convertBuffer.begin(); + + if (m_channels[m_uniqueChannelIndex].m_log2Decim == 0) + { + m_channels[m_uniqueChannelIndex].m_decimators.decimate1(&it, buf, len); } else { - switch (m_log2Decim) + switch (m_channels[m_uniqueChannelIndex].m_log2Decim) { case 1: - m_decimators.decimate2_cen(&it, buf, len); + m_channels[m_uniqueChannelIndex].m_decimators.decimate2_cen(&it, buf, len); break; case 2: - m_decimators.decimate4_cen(&it, buf, len); + m_channels[m_uniqueChannelIndex].m_decimators.decimate4_cen(&it, buf, len); break; case 3: - m_decimators.decimate8_cen(&it, buf, len); + m_channels[m_uniqueChannelIndex].m_decimators.decimate8_cen(&it, buf, len); break; case 4: - m_decimators.decimate16_cen(&it, buf, len); + m_channels[m_uniqueChannelIndex].m_decimators.decimate16_cen(&it, buf, len); break; case 5: - m_decimators.decimate32_cen(&it, buf, len); + m_channels[m_uniqueChannelIndex].m_decimators.decimate32_cen(&it, buf, len); break; case 6: - m_decimators.decimate64_cen(&it, buf, len); + m_channels[m_uniqueChannelIndex].m_decimators.decimate64_cen(&it, buf, len); break; default: break; } } - m_sampleFifo->write(m_convertBuffer.begin(), it); + m_channels[m_uniqueChannelIndex].m_sampleFifo->write(m_channels[m_uniqueChannelIndex].m_convertBuffer.begin(), it); +} + +void XTRXInputThread::callbackMI(const qint16* buf, qint32 len) +{ + (void) buf; + (void) len; + // TODO } diff --git a/plugins/samplesource/xtrxinput/xtrxinputthread.h b/plugins/samplesource/xtrxinput/xtrxinputthread.h index a119e5b92..bf1c4866f 100644 --- a/plugins/samplesource/xtrxinput/xtrxinputthread.h +++ b/plugins/samplesource/xtrxinput/xtrxinputthread.h @@ -28,39 +28,56 @@ #include "dsp/decimators.h" #include "xtrx/devicextrxshared.h" -#define XTRX_BLOCKSIZE (1<<15) //complex samples per buffer (was 1<<13) +struct xtrx_dev; -class XTRXInputThread : public QThread, public DeviceXTRXShared::ThreadInterface +class XTRXInputThread : public QThread { Q_OBJECT public: - XTRXInputThread(DeviceXTRXShared* shared, SampleSinkFifo* sampleFifo, QObject* parent = 0); + XTRXInputThread(struct xtrx_dev *dev, unsigned int nbChannels, unsigned int uniqueChannelIndex = 0, QObject* parent = 0); ~XTRXInputThread(); virtual void startWork(); virtual void stopWork(); - virtual void setDeviceSampleRate(int sampleRate __attribute__((unused))) {} virtual bool isRunning() { return m_running; } - void setLog2Decimation(unsigned int log2_decim); + unsigned int getNbChannels() const { return m_nbChannels; } + void setLog2Decimation(unsigned int channel, unsigned int log2_decim); + unsigned int getLog2Decimation(unsigned int channel) const; + void setFifo(unsigned int channel, SampleSinkFifo *sampleFifo); + SampleSinkFifo *getFifo(unsigned int channel); private: + struct Channel + { + SampleVector m_convertBuffer; + SampleSinkFifo* m_sampleFifo; + unsigned int m_log2Decim; + Decimators m_decimators; + + Channel() : + m_sampleFifo(0), + m_log2Decim(0) + {} + + ~Channel() + {} + }; + QMutex m_startWaitMutex; QWaitCondition m_startWaiter; bool m_running; + struct xtrx_dev *m_dev; - qint16 m_buf[2*XTRX_BLOCKSIZE]; //must hold I+Q values of each sample hence 2xcomplex size - SampleVector m_convertBuffer; - SampleSinkFifo* m_sampleFifo; - - unsigned int m_log2Decim; // soft decimation - - Decimators m_decimators; - - DeviceXTRXShared* m_shared; + Channel *m_channels; //!< Array of channels dynamically allocated for the given number of Rx channels + qint16 *m_buf; + unsigned int m_nbChannels; + unsigned int m_uniqueChannelIndex; void run(); - void callback(const qint16* buf, qint32 len); + unsigned int getNbFifos(); + void callbackSI(const qint16* buf, qint32 len); + void callbackMI(const qint16* buf, qint32 len); };