mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-27 11:00:31 -04:00 
			
		
		
		
	XTRX input: refactoring to prepare MI operation
This commit is contained in:
		
							parent
							
								
									2eb78ebad8
								
							
						
					
					
						commit
						e2085e8c29
					
				| @ -14,6 +14,9 @@ | ||||
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #include <QDebug> | ||||
| 
 | ||||
| #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; | ||||
|  | ||||
| @ -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]; | ||||
| }; | ||||
|  | ||||
| @ -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 <QDebug> | ||||
| #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() | ||||
| {} | ||||
|  | ||||
| @ -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_ */ | ||||
|  | ||||
| @ -17,6 +17,7 @@ | ||||
| #include <QDebug> | ||||
| 
 | ||||
| #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; | ||||
|  | ||||
| @ -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(); | ||||
| }; | ||||
|  | ||||
| @ -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"); | ||||
|         } | ||||
| 
 | ||||
|         if (m_deviceAPI->getSourceBuddies().size() == deviceParams->m_nbRxChannels) | ||||
|         { | ||||
|             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"); | ||||
|         } | ||||
| 
 | ||||
|         // 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); | ||||
|             qCritical("XTRXInput::openDevice: the source buddy shared pointer is null"); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         DeviceXTRX *device = deviceXTRXShared->m_dev; | ||||
| 
 | ||||
|         if (device == 0) | ||||
|         { | ||||
|             qCritical("XTRXInput::openDevice: cannot get device pointer from Rx buddy"); | ||||
|             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; | ||||
|         } | ||||
|     // 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
 | ||||
| 
 | ||||
|         m_deviceShared.m_dev = device; | ||||
|     } | ||||
|     // 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<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies(); | ||||
|     std::vector<DeviceSourceAPI*>::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<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies(); | ||||
|     std::vector<DeviceSinkAPI*>::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<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies(); | ||||
|     std::vector<DeviceSourceAPI*>::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<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies(); | ||||
|     std::vector<DeviceSinkAPI*>::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<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies(); | ||||
|         std::vector<DeviceSourceAPI*>::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<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies(); | ||||
|     std::vector<DeviceSourceAPI*>::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); | ||||
|             } | ||||
| 
 | ||||
|     if (!acquireChannel()) { | ||||
|         return false; | ||||
|             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<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies(); | ||||
|             std::vector<DeviceSourceAPI*>::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; | ||||
|     } | ||||
| 
 | ||||
|     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<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies(); | ||||
|         std::vector<DeviceSourceAPI*>::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<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies(); | ||||
|         std::vector<DeviceSourceAPI*>::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<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
 | ||||
| //    std::vector<DeviceSinkAPI*>::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<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
 | ||||
| //    std::vector<DeviceSinkAPI*>::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<<settings.m_log2SoftDecim); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if ((m_settings.m_antennaPath != settings.m_antennaPath) || force) | ||||
|     { | ||||
|         if (m_deviceShared.m_deviceParams->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<<settings.m_log2HardDecim); | ||||
|         } | ||||
| 
 | ||||
|         // TODO hangs!!!
 | ||||
|         resumeTxBuddies(); | ||||
|         resumeRxBuddies(); | ||||
|         resumeTxThread(); | ||||
| 
 | ||||
|         if (ownThreadWasRunning) { | ||||
|             m_XTRXInputThread->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); | ||||
|  | ||||
| @ -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); | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -16,25 +16,42 @@ | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #include <errno.h> | ||||
| #include <chrono> | ||||
| #include <thread> | ||||
| 
 | ||||
| #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() | ||||
| { | ||||
|     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,6 +88,10 @@ void XTRXInputThread::run() | ||||
|     m_running = true; | ||||
|     m_startWaiter.wakeAll(); | ||||
| 
 | ||||
|     unsigned int nbFifos = getNbFifos(); | ||||
| 
 | ||||
|     if ((m_nbChannels > 0) && (nbFifos > 0)) | ||||
|     { | ||||
|         xtrx_run_params params; | ||||
|         xtrx_run_params_init(¶ms); | ||||
| 
 | ||||
| @ -82,15 +99,18 @@ void XTRXInputThread::run() | ||||
|         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) { | ||||
|         if (m_nbChannels == 1) | ||||
|         { | ||||
|             params.rx.flags |= XTRX_RSP_SISO_MODE; | ||||
| 
 | ||||
|             if (m_uniqueChannelIndex == 1) { | ||||
|                 params.rx.flags |= XTRX_RSP_SWAP_AB; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     res = xtrx_run_ex(m_shared->m_deviceParams->getDevice(), ¶ms); | ||||
|         res = xtrx_run_ex(m_dev, ¶ms); | ||||
| 
 | ||||
|         if (res != 0) | ||||
|         { | ||||
| @ -99,22 +119,20 @@ void XTRXInputThread::run() | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|         usleep(50000); | ||||
|             std::this_thread::sleep_for(std::chrono::microseconds(50000)); | ||||
|             qDebug("XTRXInputThread::run: stream started"); | ||||
|         } | ||||
| 
 | ||||
|         void* buffers[1] = { m_buf }; | ||||
|         xtrx_recv_ex_info_t nfo; | ||||
|     nfo.samples = XTRX_BLOCKSIZE; | ||||
|         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) | ||||
|         { | ||||
|         //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); | ||||
|             res = xtrx_recv_sync_ex(m_dev, &nfo); | ||||
| 
 | ||||
|             if (res < 0) | ||||
|             { | ||||
| @ -122,10 +140,14 @@ void XTRXInputThread::run() | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|         callback(m_buf, 2 * nfo.out_samples); | ||||
|             if (m_nbChannels > 1) { | ||||
|                 callbackMI(m_buf, 2 * nfo.out_samples); | ||||
|             } else { | ||||
|                 callbackSI(m_buf, 2 * nfo.out_samples); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     res = xtrx_stop(m_shared->m_deviceParams->getDevice(), XTRX_RX); | ||||
|         res = xtrx_stop(m_dev, XTRX_RX); | ||||
| 
 | ||||
|         if (res != 0) | ||||
|         { | ||||
| @ -133,48 +155,105 @@ void XTRXInputThread::run() | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|         usleep(50000); | ||||
|             std::this_thread::sleep_for(std::chrono::microseconds(50000)); | ||||
|             qDebug("XTRXInputThread::run: stream stopped"); | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         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
 | ||||
| } | ||||
|  | ||||
| @ -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<qint32, qint16, SDR_RX_SAMP_SZ, 12> 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<qint32, qint16, SDR_RX_SAMP_SZ, 12> 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); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user