1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-26 01:39:05 -05:00

Tx support: common device routines library and handle BladeRF Tx/Rx coordination on Rx side

This commit is contained in:
f4exb 2016-12-30 16:13:28 +01:00
parent 5a83dc09a5
commit 2047463dcf
16 changed files with 556 additions and 93 deletions

View File

@ -549,6 +549,7 @@ if (BUILD_DEBIAN)
add_subdirectory(libmirisdr)
endif (BUILD_DEBIAN)
add_subdirectory(devices)
add_subdirectory(plugins)
if(LIBUSB_FOUND AND UNIX)

13
devices/CMakeLists.txt Normal file
View File

@ -0,0 +1,13 @@
project(devices)
find_package(LibUSB)
find_package(LibBLADERF)
if(LIBUSB_FOUND AND LIBBLADERF_FOUND)
add_subdirectory(bladerf)
endif(LIBUSB_FOUND AND LIBBLADERF_FOUND)
if (BUILD_DEBIAN)
add_subdirectory(bladerf)
endif (BUILD_DEBIAN)

View File

@ -0,0 +1,45 @@
project(bladerfdevice)
set(bladerfdevice_SOURCES
devicebladerf.cpp
)
set(bladerfdevice_HEADERS
devicebladerf.h
)
if (BUILD_DEBIAN)
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${LIBBLADERFLIBSRC}/include
${LIBBLADERFLIBSRC}/src
)
else (BUILD_DEBIAN)
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${LIBBLADERF_INCLUDE_DIR}
)
endif (BUILD_DEBIAN)
#add_definitions(${QT_DEFINITIONS})
#add_definitions(-DQT_SHARED)
add_library(bladerfdevice SHARED
${bladerfdevice_SOURCES}
)
if (BUILD_DEBIAN)
target_link_libraries(bladerfdevice
bladerf
sdrbase
)
else (BUILD_DEBIAN)
target_link_libraries(bladerfdevice
${LIBBLADERF_LIBRARIES}
sdrbase
)
endif (BUILD_DEBIAN)
install(TARGETS bladerfdevice DESTINATION lib)

View File

@ -0,0 +1,88 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016-2017 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 //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <cstdio>
#include <cstring>
#include "devicebladerf.h"
bool DeviceBladeRF::open_bladerf(struct bladerf **dev, const char *serial)
{
int res;
int fpga_loaded;
if ((*dev = open_bladerf_from_serial(0)) == 0)
{
fprintf(stderr, "DeviceBladeRF::open_bladerf: could not open BladeRF");
return false;
}
fpga_loaded = bladerf_is_fpga_configured(*dev);
if (fpga_loaded < 0)
{
fprintf(stderr, "DeviceBladeRF::open_bladerf: failed to check FPGA state: %s",
bladerf_strerror(fpga_loaded));
return false;
}
else if (fpga_loaded == 0)
{
fprintf(stderr, "BladerfOutput::start: the device's FPGA is not loaded.");
return false;
}
return true;
}
struct bladerf *DeviceBladeRF::open_bladerf_from_serial(const char *serial)
{
int status;
struct bladerf *dev;
struct bladerf_devinfo info;
/* Initialize all fields to "don't care" wildcard values.
*
* Immediately passing this to bladerf_open_with_devinfo() would cause
* libbladeRF to open any device on any available backend. */
bladerf_init_devinfo(&info);
/* Specify the desired device's serial number, while leaving all other
* fields in the info structure wildcard values */
if (serial != 0)
{
strncpy(info.serial, serial, BLADERF_SERIAL_LENGTH - 1);
info.serial[BLADERF_SERIAL_LENGTH - 1] = '\0';
}
status = bladerf_open_with_devinfo(&dev, &info);
if (status == BLADERF_ERR_NODEV)
{
fprintf(stderr, "DeviceBladeRF::open_bladerf_from_serial: No devices available with serial=%s\n", serial);
return 0;
}
else if (status != 0)
{
fprintf(stderr, "DeviceBladeRF::open_bladerf_from_serial: Failed to open device with serial=%s (%s)\n",
serial, bladerf_strerror(status));
return 0;
}
else
{
return dev;
}
}

View File

@ -0,0 +1,33 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016-2017 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 //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef DEVICES_BLADERF_DEVICESDBLADERF_H_
#define DEVICES_BLADERF_DEVICESDBLADERF_H_
#include <libbladeRF.h>
class DeviceBladeRF
{
public:
static bool open_bladerf(struct bladerf **dev, const char *serial);
private:
static struct bladerf *open_bladerf_from_serial(const char *serial);
};
#endif /* DEVICES_BLADERF_DEVICESDBLADERF_H_ */

View File

@ -0,0 +1,38 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016-2017 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 //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef DEVICES_BLADERF_DEVICEBLADERFPARAM_H_
#define DEVICES_BLADERF_DEVICEBLADERFPARAM_H_
#include <libbladeRF.h>
/**
* This structure is owned by each of the parties sharing the same physical device
* It allows exchange of information on the common resources
*/
struct DeviceBladeRFParams
{
struct bladerf *m_dev; //!< device handle if the party has ownership else 0
bool m_xb200Attached; //!< true if XB200 is attached and owned by the party
DeviceBladeRFParams() :
m_dev(0),
m_xb200Attached(false)
{
}
};
#endif /* DEVICES_BLADERF_DEVICEBLADERFPARAM_H_ */

View File

@ -0,0 +1,87 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016-2017 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 //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "devicebladerfvalues.h"
unsigned int DeviceBladeRFSampleRates::m_rates[] = {1536, 1600, 2000, 2304, 2400, 3072, 3200, 4608, 4800, 6144, 7680, 9216, 9600, 10752, 12288, 18432, 19200, 24576, 30720, 36864, 39936};
unsigned int DeviceBladeRFSampleRates::m_nb_rates = 21;
unsigned int DeviceBladeRFSampleRates::getRate(unsigned int rate_index)
{
if (rate_index < m_nb_rates)
{
return m_rates[rate_index];
}
else
{
return m_rates[0];
}
}
unsigned int DeviceBladeRFSampleRates::getRateIndex(unsigned int rate)
{
for (unsigned int i=0; i < m_nb_rates; i++)
{
if (rate/1000 == m_rates[i])
{
return i;
}
}
return 0;
}
unsigned int DeviceBladeRFSampleRates::getNbRates()
{
return DeviceBladeRFSampleRates::m_nb_rates;
}
unsigned int DeviceBladeRFBandwidths::m_halfbw[] = {750, 875, 1250, 1375, 1500, 1920, 2500, 2750, 3000, 3500, 4375, 5000, 6000, 7000, 10000, 14000};
unsigned int DeviceBladeRFBandwidths::m_nb_halfbw = 16;
unsigned int DeviceBladeRFBandwidths::getBandwidth(unsigned int bandwidth_index)
{
if (bandwidth_index < m_nb_halfbw)
{
return m_halfbw[bandwidth_index] * 2;
}
else
{
return m_halfbw[0] * 2;
}
}
unsigned int DeviceBladeRFBandwidths::getBandwidthIndex(unsigned int bandwidth)
{
for (unsigned int i=0; i < m_nb_halfbw; i++)
{
if (bandwidth/2000 == m_halfbw[i])
{
return i;
}
}
return 0;
}
unsigned int DeviceBladeRFBandwidths::getNbBandwidths()
{
return DeviceBladeRFBandwidths::m_nb_halfbw;
}

View File

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016-2017 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 //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef DEVICES_BLADERF_DEVICEBLADERFVALUES_H_
#define DEVICES_BLADERF_DEVICEBLADERFVALUES_H_
class DeviceBladeRFSampleRates {
public:
static unsigned int getRate(unsigned int rate_index);
static unsigned int getRateIndex(unsigned int rate);
static unsigned int getNbRates();
private:
static unsigned int m_rates[21];
static unsigned int m_nb_rates;
};
class DeviceBladeRFBandwidths {
public:
static unsigned int getBandwidth(unsigned int bandwidth_index);
static unsigned int getBandwidthIndex(unsigned int bandwidth);
static unsigned int getNbBandwidths();
private:
static unsigned int m_halfbw[16];
static unsigned int m_nb_halfbw;
};
#endif /* DEVICES_BLADERF_DEVICEBLADERFVALUES_H_ */

View File

@ -3,13 +3,13 @@ project(samplesink)
find_package(LibUSB)
find_package(LibBLADERF)
if(LIBUSB_FOUND AND LIBBLADERF_FOUND)
add_subdirectory(bladerfoutput)
endif(LIBUSB_FOUND AND LIBBLADERF_FOUND)
#if(LIBUSB_FOUND AND LIBBLADERF_FOUND)
# add_subdirectory(bladerfoutput)
#endif(LIBUSB_FOUND AND LIBBLADERF_FOUND)
if (BUILD_DEBIAN)
add_subdirectory(bladerfoutput)
endif (BUILD_DEBIAN)
#if (BUILD_DEBIAN)
# add_subdirectory(bladerfoutput)
#endif (BUILD_DEBIAN)
add_subdirectory(filesink)

View File

@ -24,6 +24,7 @@ if (BUILD_DEBIAN)
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/devices
${LIBBLADERFLIBSRC}/include
${LIBBLADERFLIBSRC}/src
)
@ -31,6 +32,7 @@ else (BUILD_DEBIAN)
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/devices
${LIBBLADERF_INCLUDE_DIR}
)
endif (BUILD_DEBIAN)
@ -54,12 +56,14 @@ target_link_libraries(inputbladerf
${QT_LIBRARIES}
bladerf
sdrbase
bladerfdevice
)
else (BUILD_DEBIAN)
target_link_libraries(inputbladerf
${QT_LIBRARIES}
${LIBBLADERF_LIBRARIES}
sdrbase
bladerfdevice
)
endif (BUILD_DEBIAN)

View File

@ -23,10 +23,11 @@
#include "util/simpleserializer.h"
#include "dsp/dspcommands.h"
#include "dsp/dspengine.h"
#include <device/devicesourceapi.h>
#include "device/devicesourceapi.h"
#include "device/devicesinkapi.h"
#include "../bladerfinput/bladerfinputgui.h"
#include "../bladerfinput/bladerfinputthread.h"
#include "bladerfinputgui.h"
#include "bladerfinputthread.h"
MESSAGE_CLASS_DEFINITION(BladerfInput::MsgConfigureBladerf, Message)
MESSAGE_CLASS_DEFINITION(BladerfInput::MsgReportBladerf, Message)
@ -38,11 +39,13 @@ BladerfInput::BladerfInput(DeviceSourceAPI *deviceAPI) :
m_bladerfThread(0),
m_deviceDescription("BladeRF")
{
m_deviceAPI->setBuddySharedPtr(&m_sharedParams);
}
BladerfInput::~BladerfInput()
{
stop();
m_deviceAPI->setBuddySharedPtr(0);
}
bool BladerfInput::init(const Message& cmd)
@ -68,26 +71,67 @@ bool BladerfInput::start(int device)
return false;
}
if ((m_dev = open_bladerf_from_serial(0)) == 0) // TODO: fix; Open first available device as there is no proper handling for multiple devices
if (m_deviceAPI->getSinkBuddies().size() > 0)
{
qCritical("could not open BladeRF");
DeviceSinkAPI *buddy = m_deviceAPI->getSinkBuddies()[0];
DeviceBladeRFParams *buddySharedParams = (DeviceBladeRFParams *) buddy->getBuddySharedPtr();
if (buddySharedParams == 0)
{
qCritical("BladerfInput::start: could not get shared parameters from buddy");
return false;
}
fpga_loaded = bladerf_is_fpga_configured(m_dev);
if (buddy->getDeviceSinkEngine()->state() == DSPDeviceSinkEngine::StRunning) // Tx side is running so it must have device ownership
{
if ((m_dev = buddySharedParams->m_dev) == 0) // get device handle from Tx but do not take ownership
{
qCritical("BladerfInput::start: could not get BladeRF handle from buddy");
return false;
}
}
else // Tx is not running so Rx opens device and takes ownership
{
if (!DeviceBladeRF::open_bladerf(&m_dev, 0)) // TODO: fix; Open first available device as there is no proper handling for multiple devices
{
qCritical("BladerfInput::start: could not open BladeRF");
return false;
}
if (fpga_loaded < 0)
m_sharedParams.m_dev = m_dev;
}
}
else // No Tx part open so Rx opens device and takes ownership
{
qCritical("Failed to check FPGA state: %s",
bladerf_strerror(fpga_loaded));
if (!DeviceBladeRF::open_bladerf(&m_dev, 0)) // TODO: fix; Open first available device as there is no proper handling for multiple devices
{
qCritical("BladerfInput::start: could not open BladeRF");
return false;
}
else if (fpga_loaded == 0)
{
qCritical("The device's FPGA is not loaded.");
return false;
m_sharedParams.m_dev = m_dev;
}
// if ((m_dev = open_bladerf_from_serial(0)) == 0) // TODO: fix; Open first available device as there is no proper handling for multiple devices
// {
// qCritical("could not open BladeRF");
// return false;
// }
//
// fpga_loaded = bladerf_is_fpga_configured(m_dev);
//
// if (fpga_loaded < 0)
// {
// qCritical("Failed to check FPGA state: %s",
// bladerf_strerror(fpga_loaded));
// return false;
// }
// else if (fpga_loaded == 0)
// {
// qCritical("The device's FPGA is not loaded.");
// return false;
// }
// TODO: adjust USB transfer data according to sample rate
if ((res = bladerf_sync_config(m_dev, BLADERF_MODULE_RX, BLADERF_FORMAT_SC16_Q11, 64, 8192, 32, 10000)) < 0)
{
@ -131,11 +175,43 @@ void BladerfInput::stop()
m_bladerfThread = 0;
}
if(m_dev != 0)
if (m_deviceAPI->getSinkBuddies().size() > 0)
{
DeviceSinkAPI *buddy = m_deviceAPI->getSinkBuddies()[0];
DeviceBladeRFParams *buddySharedParams = (DeviceBladeRFParams *) buddy->getBuddySharedPtr();
if (buddy->getDeviceSinkEngine()->state() == DSPDeviceSinkEngine::StRunning) // Tx side running
{
if ((m_sharedParams.m_dev != 0) && (buddySharedParams->m_dev == 0)) // Rx has the ownership but not the Tx
{
buddySharedParams->m_dev = m_dev; // transfer ownership
}
}
else // Tx is not running so Rx must have the ownership
{
if(m_dev != 0) // close BladeRF
{
bladerf_close(m_dev);
m_dev = 0;
}
}
}
else // No Tx part open
{
if(m_dev != 0) // close BladeRF
{
bladerf_close(m_dev);
m_dev = 0;
}
}
m_sharedParams.m_dev = 0;
// if(m_dev != 0)
// {
// bladerf_close(m_dev);
// m_dev = 0;
// }
}
const QString& BladerfInput::getDeviceDescription() const
@ -249,6 +325,29 @@ bool BladerfInput::applySettings(const BladeRFInputSettings& settings, bool forc
m_settings.m_xb200 = settings.m_xb200;
if (m_dev != 0)
{
bool changeSettings;
if (m_deviceAPI->getSinkBuddies().size() > 0)
{
DeviceSinkAPI *buddy = m_deviceAPI->getSinkBuddies()[0];
DeviceBladeRFParams *buddySharedParams = (DeviceBladeRFParams *) buddy->getBuddySharedPtr();
if (buddy->getDeviceSinkEngine()->state() == DSPDeviceSinkEngine::StRunning) // Tx side running
{
changeSettings = false;
}
else
{
changeSettings = true;
}
}
else // No Tx open
{
changeSettings = true;
}
if (changeSettings)
{
if (m_settings.m_xb200)
{
@ -272,6 +371,9 @@ bool BladerfInput::applySettings(const BladeRFInputSettings& settings, bool forc
qDebug() << "BladerfInput: Detach XB200";
}
}
m_sharedParams.m_xb200Attached = m_settings.m_xb200;
}
}
}
@ -447,41 +549,41 @@ bladerf_lna_gain BladerfInput::getLnaGain(int lnaGain)
}
}
struct bladerf *BladerfInput::open_bladerf_from_serial(const char *serial)
{
int status;
struct bladerf *dev;
struct bladerf_devinfo info;
/* Initialize all fields to "don't care" wildcard values.
*
* Immediately passing this to bladerf_open_with_devinfo() would cause
* libbladeRF to open any device on any available backend. */
bladerf_init_devinfo(&info);
/* Specify the desired device's serial number, while leaving all other
* fields in the info structure wildcard values */
if (serial != NULL)
{
strncpy(info.serial, serial, BLADERF_SERIAL_LENGTH - 1);
info.serial[BLADERF_SERIAL_LENGTH - 1] = '\0';
}
status = bladerf_open_with_devinfo(&dev, &info);
if (status == BLADERF_ERR_NODEV)
{
fprintf(stderr, "No devices available with serial=%s\n", serial);
return NULL;
}
else if (status != 0)
{
fprintf(stderr, "Failed to open device with serial=%s (%s)\n",
serial, bladerf_strerror(status));
return NULL;
}
else
{
return dev;
}
}
//struct bladerf *BladerfInput::open_bladerf_from_serial(const char *serial)
//{
// int status;
// struct bladerf *dev;
// struct bladerf_devinfo info;
//
// /* Initialize all fields to "don't care" wildcard values.
// *
// * Immediately passing this to bladerf_open_with_devinfo() would cause
// * libbladeRF to open any device on any available backend. */
// bladerf_init_devinfo(&info);
//
// /* Specify the desired device's serial number, while leaving all other
// * fields in the info structure wildcard values */
// if (serial != NULL)
// {
// strncpy(info.serial, serial, BLADERF_SERIAL_LENGTH - 1);
// info.serial[BLADERF_SERIAL_LENGTH - 1] = '\0';
// }
//
// status = bladerf_open_with_devinfo(&dev, &info);
//
// if (status == BLADERF_ERR_NODEV)
// {
// fprintf(stderr, "No devices available with serial=%s\n", serial);
// return NULL;
// }
// else if (status != 0)
// {
// fprintf(stderr, "Failed to open device with serial=%s (%s)\n",
// serial, bladerf_strerror(status));
// return NULL;
// }
// else
// {
// return dev;
// }
//}

View File

@ -18,6 +18,8 @@
#define INCLUDE_BLADERFINPUT_H
#include <dsp/devicesamplesource.h>
#include "bladerf/devicebladerf.h"
#include "bladerf/devicebladerfparam.h"
#include <libbladeRF.h>
#include <QString>
@ -82,7 +84,7 @@ public:
private:
bool applySettings(const BladeRFInputSettings& settings, bool force);
bladerf_lna_gain getLnaGain(int lnaGain);
struct bladerf *open_bladerf_from_serial(const char *serial);
// struct bladerf *open_bladerf_from_serial(const char *serial);
DeviceSourceAPI *m_deviceAPI;
QMutex m_mutex;
@ -90,6 +92,7 @@ private:
struct bladerf* m_dev;
BladerfInputThread* m_bladerfThread;
QString m_deviceDescription;
DeviceBladeRFParams m_sharedParams;
};
#endif // INCLUDE_BLADERFINPUT_H

View File

@ -35,7 +35,8 @@ DeviceSinkAPI::DeviceSinkAPI(MainWindow *mainWindow,
m_spectrum(glSpectrum),
m_channelWindow(channelWindow),
m_sampleSinkSequence(0),
m_sampleSinkPluginGUI(0)
m_sampleSinkPluginGUI(0),
m_buddySharedPtr(0)
{
}

View File

@ -96,6 +96,8 @@ public:
void removeSourceBuddy(DeviceSourceAPI* buddy);
void removeSinkBuddy(DeviceSinkAPI* buddy);
void clearBuddiesLists();
void *getBuddySharedPtr() const { return m_buddySharedPtr; }
void setBuddySharedPtr(void *ptr) { m_buddySharedPtr = ptr; }
protected:
struct ChannelInstanceRegistration
@ -143,6 +145,7 @@ protected:
std::vector<DeviceSourceAPI*> m_sourceBuddies; //!< Device source APIs referencing the same physical device
std::vector<DeviceSinkAPI*> m_sinkBuddies; //!< Device sink APIs referencing the same physical device
void *m_buddySharedPtr;
friend class MainWindow;
};

View File

@ -35,7 +35,8 @@ DeviceSourceAPI::DeviceSourceAPI(MainWindow *mainWindow,
m_spectrum(glSpectrum),
m_channelWindow(channelWindow),
m_sampleSourceSequence(0),
m_sampleSourcePluginGUI(0)
m_sampleSourcePluginGUI(0),
m_buddySharedPtr(0)
{
}

View File

@ -96,6 +96,8 @@ public:
void removeSourceBuddy(DeviceSourceAPI* buddy);
void removeSinkBuddy(DeviceSinkAPI* buddy);
void clearBuddiesLists();
void *getBuddySharedPtr() const { return m_buddySharedPtr; }
void setBuddySharedPtr(void *ptr) { m_buddySharedPtr = ptr; }
protected:
struct ChannelInstanceRegistration
@ -143,6 +145,7 @@ protected:
std::vector<DeviceSourceAPI*> m_sourceBuddies; //!< Device source APIs referencing the same physical device
std::vector<DeviceSinkAPI*> m_sinkBuddies; //!< Device sink APIs referencing the same physical device
void *m_buddySharedPtr;
friend class MainWindow;
};