From 17c169143c257a8f9e78a203b515898571208819 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 11 Jun 2024 10:35:28 +0300 Subject: [PATCH 01/17] First iteration of hot-plug disconnect handling --- GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp | 9 +++++- src/boards/LimeSDR/LimeSDR.cpp | 11 ++++++- src/boards/LimeSDR/LimeSDR.h | 4 ++- src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp | 11 ++++++- src/boards/LimeSDR_Mini/LimeSDR_Mini.h | 5 ++-- src/boards/LimeSDR_X3/LimeSDR_X3.cpp | 4 ++- src/boards/LimeSDR_X3/LimeSDR_X3.h | 4 ++- src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp | 4 ++- src/boards/LimeSDR_XTRX/LimeSDR_XTRX.h | 4 ++- src/boards/MMX8/MM_X8.cpp | 4 ++- src/boards/MMX8/MM_X8.h | 4 ++- src/comms/USB/FT601/FT601.cpp | 9 ++++++ src/comms/USB/FT601/FT601.h | 2 ++ src/comms/USB/FX3/FX3.cpp | 21 +++++++++++-- src/comms/USB/FX3/FX3.h | 2 ++ src/comms/USB/IUSB.h | 8 +++++ src/comms/USB/USBGeneric.cpp | 30 +++++++++++++++++++ src/comms/USB/USBGeneric.h | 22 +++++++++++--- src/include/limesuiteng/SDRDevice.h | 15 +++++++++- 19 files changed, 153 insertions(+), 20 deletions(-) diff --git a/GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp b/GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp index 826cf74bf..96861efd1 100644 --- a/GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp +++ b/GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp @@ -465,7 +465,14 @@ void fftviewer_frFFTviewer::StreamingLoop( try { - pthis->device->StreamSetup(config, chipIndex); + pthis->device->StreamSetup(config, + chipIndex, + { [](void* data) { + lime::error("Testing how many times this gets called"); + auto* const viewer = reinterpret_cast(data); + viewer->StopStreaming(); + }, + pthis }); pthis->device->StreamStart(chipIndex); } catch (std::logic_error& e) { diff --git a/src/boards/LimeSDR/LimeSDR.cpp b/src/boards/LimeSDR/LimeSDR.cpp index 149b692fe..b82f1bb13 100644 --- a/src/boards/LimeSDR/LimeSDR.cpp +++ b/src/boards/LimeSDR/LimeSDR.cpp @@ -491,7 +491,8 @@ void LimeSDR::ResetUSBFIFO() } } -OpStatus LimeSDR::StreamSetup(const StreamConfig& config, uint8_t moduleIndex) +OpStatus LimeSDR::StreamSetup( + const StreamConfig& config, uint8_t moduleIndex, const CallbackInfo& hotplugDisconnectCallback) { // Allow multiple setup calls if (mStreamers.at(moduleIndex) != nullptr) @@ -499,6 +500,14 @@ OpStatus LimeSDR::StreamSetup(const StreamConfig& config, uint8_t moduleIndex) delete mStreamers.at(moduleIndex); } + mStreamPort->AddOnHotplugDisconnectCallback( + [&hotplugDisconnectCallback](void* userData) { + hotplugDisconnectCallback.function(hotplugDisconnectCallback.userData); + auto* const sdr = reinterpret_cast(userData); + sdr->StreamStop(0); + }, + this); + constexpr uint8_t rxBulkEndpoint = 0x81; constexpr uint8_t txBulkEndpoint = 0x01; auto rxdma = std::make_shared(mStreamPort, rxBulkEndpoint, DataTransferDirection::DeviceToHost); diff --git a/src/boards/LimeSDR/LimeSDR.h b/src/boards/LimeSDR/LimeSDR.h index 14520e57f..475c6734c 100644 --- a/src/boards/LimeSDR/LimeSDR.h +++ b/src/boards/LimeSDR/LimeSDR.h @@ -36,7 +36,9 @@ class LimeSDR : public LMS7002M_SDRDevice OpStatus SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; - OpStatus StreamSetup(const StreamConfig& config, uint8_t moduleIndex) override; + OpStatus StreamSetup(const StreamConfig& config, + uint8_t moduleIndex, + const CallbackInfo& hotplugDisconnectCallback) override; void StreamStart(uint8_t moduleIndex) override; void StreamStop(uint8_t moduleIndex) override; diff --git a/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp b/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp index fe54303bd..f59867b68 100644 --- a/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp +++ b/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp @@ -526,7 +526,8 @@ SDRDescriptor LimeSDR_Mini::GetDeviceInfo(void) return deviceDescriptor; } -OpStatus LimeSDR_Mini::StreamSetup(const StreamConfig& config, uint8_t moduleIndex) +OpStatus LimeSDR_Mini::StreamSetup( + const StreamConfig& config, uint8_t moduleIndex, const CallbackInfo& hotplugDisconnectCallback) { if (moduleIndex != 0) return ReportError(OpStatus::InvalidValue, "StreamSetup: invalid module index"); @@ -540,6 +541,14 @@ OpStatus LimeSDR_Mini::StreamSetup(const StreamConfig& config, uint8_t moduleInd FT601* ftdi = dynamic_cast(mStreamPort.get()); ftdi->ResetStreamBuffers(); + mStreamPort->AddOnHotplugDisconnectCallback( + [&hotplugDisconnectCallback](void* userData) { + hotplugDisconnectCallback.function(hotplugDisconnectCallback.userData); + auto* const mini = reinterpret_cast(userData); + mini->StreamStop(0); + }, + this); + auto rxdma = std::make_shared(mStreamPort, STREAM_BULK_READ_ADDRESS, DataTransferDirection::DeviceToHost); auto txdma = std::make_shared(mStreamPort, STREAM_BULK_WRITE_ADDRESS, DataTransferDirection::HostToDevice); diff --git a/src/boards/LimeSDR_Mini/LimeSDR_Mini.h b/src/boards/LimeSDR_Mini/LimeSDR_Mini.h index 32bb480bf..b6eacb46c 100644 --- a/src/boards/LimeSDR_Mini/LimeSDR_Mini.h +++ b/src/boards/LimeSDR_Mini/LimeSDR_Mini.h @@ -9,7 +9,6 @@ namespace lime { -class USBGeneric; class IComms; class IUSB; @@ -39,7 +38,9 @@ class LimeSDR_Mini : public LMS7002M_SDRDevice OpStatus SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; - OpStatus StreamSetup(const StreamConfig& config, uint8_t moduleIndex) override; + OpStatus StreamSetup(const StreamConfig& config, + uint8_t moduleIndex, + const CallbackInfo& hotplugDisconnectCallback) override; void StreamStart(uint8_t moduleIndex) override; void StreamStop(uint8_t moduleIndex) override; diff --git a/src/boards/LimeSDR_X3/LimeSDR_X3.cpp b/src/boards/LimeSDR_X3/LimeSDR_X3.cpp index f148029e1..fbb107946 100644 --- a/src/boards/LimeSDR_X3/LimeSDR_X3.cpp +++ b/src/boards/LimeSDR_X3/LimeSDR_X3.cpp @@ -865,7 +865,9 @@ OpStatus LimeSDR_X3::SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MI } } -OpStatus LimeSDR_X3::StreamSetup(const StreamConfig& config, uint8_t moduleIndex) +OpStatus LimeSDR_X3::StreamSetup(const StreamConfig& config, + uint8_t moduleIndex, + [[maybe_unused]] const CallbackInfo& hotplugDisconnectCallback) { // Allow multiple setup calls if (mStreamers.at(moduleIndex) != nullptr) diff --git a/src/boards/LimeSDR_X3/LimeSDR_X3.h b/src/boards/LimeSDR_X3/LimeSDR_X3.h index 527318e08..3e03590c3 100644 --- a/src/boards/LimeSDR_X3/LimeSDR_X3.h +++ b/src/boards/LimeSDR_X3/LimeSDR_X3.h @@ -41,7 +41,9 @@ class LimeSDR_X3 : public LMS7002M_SDRDevice OpStatus SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; - OpStatus StreamSetup(const StreamConfig& config, uint8_t moduleIndex) override; + OpStatus StreamSetup(const StreamConfig& config, + uint8_t moduleIndex, + const CallbackInfo& hotplugDisconnectCallback) override; void StreamStop(uint8_t moduleIndex) override; OpStatus CustomParameterWrite(const std::vector& parameters) override; diff --git a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp index ee3ff9620..e583e010b 100644 --- a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp +++ b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp @@ -364,7 +364,9 @@ OpStatus LimeSDR_XTRX::SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* } } -OpStatus LimeSDR_XTRX::StreamSetup(const StreamConfig& config, uint8_t moduleIndex) +OpStatus LimeSDR_XTRX::StreamSetup(const StreamConfig& config, + uint8_t moduleIndex, + [[maybe_unused]] const CallbackInfo& hotplugDisconnectCallback) { // Allow multiple setup calls if (mStreamers.at(moduleIndex) != nullptr) diff --git a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.h b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.h index 9f07d7c4a..a750e46f1 100644 --- a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.h +++ b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.h @@ -37,7 +37,9 @@ class LimeSDR_XTRX : public LMS7002M_SDRDevice OpStatus SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; - OpStatus StreamSetup(const StreamConfig& config, uint8_t moduleIndex) override; + OpStatus StreamSetup(const StreamConfig& config, + uint8_t moduleIndex, + const CallbackInfo& hotplugDisconnectCallback = { 0, nullptr }) override; void StreamStop(uint8_t moduleIndex) override; OpStatus CustomParameterWrite(const std::vector& parameters) override; diff --git a/src/boards/MMX8/MM_X8.cpp b/src/boards/MMX8/MM_X8.cpp index 3a00182ac..2ef9c42e9 100644 --- a/src/boards/MMX8/MM_X8.cpp +++ b/src/boards/MMX8/MM_X8.cpp @@ -611,7 +611,9 @@ ChannelConfig::Direction::TestSignal LimeSDR_MMX8::GetTestSignal(uint8_t moduleI return mSubDevices[moduleIndex]->GetTestSignal(0, direction, channel); } -OpStatus LimeSDR_MMX8::StreamSetup(const StreamConfig& config, uint8_t moduleIndex) +OpStatus LimeSDR_MMX8::StreamSetup(const StreamConfig& config, + uint8_t moduleIndex, + [[maybe_unused]] const CallbackInfo& hotplugDisconnectCallback) { OpStatus ret = mSubDevices[moduleIndex]->StreamSetup(config, 0); if (ret != OpStatus::Success) diff --git a/src/boards/MMX8/MM_X8.h b/src/boards/MMX8/MM_X8.h index 032f870eb..f5de4f0dd 100644 --- a/src/boards/MMX8/MM_X8.h +++ b/src/boards/MMX8/MM_X8.h @@ -117,7 +117,9 @@ class LimeSDR_MMX8 : public SDRDevice uint64_t GetHardwareTimestamp(uint8_t moduleIndex) override; OpStatus SetHardwareTimestamp(uint8_t moduleIndex, const uint64_t now) override; - OpStatus StreamSetup(const StreamConfig& config, uint8_t moduleIndex) override; + OpStatus StreamSetup(const StreamConfig& config, + uint8_t moduleIndex, + const CallbackInfo& hotplugDisconnectCallback) override; void StreamStart(uint8_t moduleIndex) override; void StreamStart(const std::vector moduleIndexes) override; void StreamStop(uint8_t moduleIndex) override; diff --git a/src/comms/USB/FT601/FT601.cpp b/src/comms/USB/FT601/FT601.cpp index 8f68df784..facd77e16 100644 --- a/src/comms/USB/FT601/FT601.cpp +++ b/src/comms/USB/FT601/FT601.cpp @@ -373,4 +373,13 @@ int FT601::FT_SetStreamPipe(unsigned char ep, size_t size) } #endif +void FT601::AddOnHotplugDisconnectCallback(const IUSB::HotplugDisconnectCallbackType& function, void* userData) +{ +#ifdef __unix__ + libusb_impl.AddOnHotplugDisconnectCallback(function, userData); +#else + // TODO: IMPLEMENT +#endif +} + } // namespace lime diff --git a/src/comms/USB/FT601/FT601.h b/src/comms/USB/FT601/FT601.h index 50ab86577..662988f88 100644 --- a/src/comms/USB/FT601/FT601.h +++ b/src/comms/USB/FT601/FT601.h @@ -41,6 +41,8 @@ class FT601 : public IUSB */ OpStatus ResetStreamBuffers(); + void AddOnHotplugDisconnectCallback(const HotplugDisconnectCallbackType& function, void* userData) override; + protected: #ifdef __unix__ USBGeneric libusb_impl; diff --git a/src/comms/USB/FX3/FX3.cpp b/src/comms/USB/FX3/FX3.cpp index 10b08f817..ca59f4263 100644 --- a/src/comms/USB/FX3/FX3.cpp +++ b/src/comms/USB/FX3/FX3.cpp @@ -2,7 +2,6 @@ #include -using namespace lime; using namespace std::literals::string_literals; #ifdef __unix__ @@ -14,13 +13,18 @@ using namespace std::literals::string_literals; #ifdef __GNUC__ #pragma GCC diagnostic pop #endif -const int FX3::CTR_WRITE_REQUEST_VALUE = LIBUSB_REQUEST_TYPE_VENDOR; -const int FX3::CTR_READ_REQUEST_VALUE = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN; #else #include "windows.h" #include "CyAPI.h" #include +#endif + +namespace lime { +#ifdef __unix__ +const int FX3::CTR_WRITE_REQUEST_VALUE = LIBUSB_REQUEST_TYPE_VENDOR; +const int FX3::CTR_READ_REQUEST_VALUE = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN; +#else class FX3AsyncContext { public: @@ -250,3 +254,14 @@ void FX3::FreeAsyncContext(void* context) delete reinterpret_cast(context); #endif } + +void FX3::AddOnHotplugDisconnectCallback(const IUSB::HotplugDisconnectCallbackType& function, void* userData) +{ +#ifdef __unix__ + libusb_impl.AddOnHotplugDisconnectCallback(function, userData); +#else + // TODO: IMPLEMENT +#endif +} + +} // namespace lime diff --git a/src/comms/USB/FX3/FX3.h b/src/comms/USB/FX3/FX3.h index bc4197b73..ed6335593 100644 --- a/src/comms/USB/FX3/FX3.h +++ b/src/comms/USB/FX3/FX3.h @@ -38,6 +38,8 @@ class FX3 : public IUSB int32_t ControlTransfer( int requestType, int request, int value, int index, uint8_t* data, size_t length, int32_t timeout_ms) override; + void AddOnHotplugDisconnectCallback(const HotplugDisconnectCallbackType& function, void* userData) override; + static const int CTR_WRITE_REQUEST_VALUE; static const int CTR_READ_REQUEST_VALUE; diff --git a/src/comms/USB/IUSB.h b/src/comms/USB/IUSB.h index b7dbf15f4..d3068c8aa 100644 --- a/src/comms/USB/IUSB.h +++ b/src/comms/USB/IUSB.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "limesuiteng/OpStatus.h" namespace lime { @@ -116,6 +117,13 @@ class IUSB @param context Pointer to transfer context (retuned by AllocateAsyncContext). */ virtual void FreeAsyncContext(void* context) = 0; + + typedef std::function HotplugDisconnectCallbackType; + template struct CallbackInfo { + T function; + void* userData; + }; + virtual void AddOnHotplugDisconnectCallback(const HotplugDisconnectCallbackType& function, void* userData) = 0; }; } // namespace lime diff --git a/src/comms/USB/USBGeneric.cpp b/src/comms/USB/USBGeneric.cpp index bf44510a6..8333c8f93 100644 --- a/src/comms/USB/USBGeneric.cpp +++ b/src/comms/USB/USBGeneric.cpp @@ -110,6 +110,19 @@ static void process_libusbtransfer(libusb_transfer* trans) context->cv.notify_one(); } +int USBGeneric::HotplugCallback(libusb_context* ctx, libusb_device* device, libusb_hotplug_event event, void* user_data) +{ + auto* usb = reinterpret_cast(user_data); + + for (const auto& callback : usb->hotplugDisconnectCallbacks) + { + callback.function(callback.userData); + } + + usb->Disconnect(); + return 1; +} + USBGeneric::AsyncContext::AsyncContext() : transfer(libusb_alloc_transfer(0)) , bytesXfered(0) @@ -258,7 +271,19 @@ bool USBGeneric::Connect(uint16_t vid, uint16_t pid, const char* serial) } if (std::string{ serial }.empty() || std::string{ serial } == foundSerial) + { + libusb_hotplug_register_callback(gContextLibUsb, + LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, + 0, + desc.idVendor, + desc.idProduct, + LIBUSB_HOTPLUG_MATCH_ANY, + HotplugCallback, + this, + nullptr); + break; //found it + } libusb_close(dev_handle); dev_handle = nullptr; @@ -409,4 +434,9 @@ OpStatus USBGeneric::ClaimInterface(int32_t interface_number) return OpStatus::Success; } +void USBGeneric::AddOnHotplugDisconnectCallback(const IUSB::HotplugDisconnectCallbackType& function, void* userData) +{ + hotplugDisconnectCallbacks.push_back({ function, userData }); +} + } // namespace lime diff --git a/src/comms/USB/USBGeneric.h b/src/comms/USB/USBGeneric.h index 90a1f988f..0f067fdab 100644 --- a/src/comms/USB/USBGeneric.h +++ b/src/comms/USB/USBGeneric.h @@ -5,8 +5,16 @@ #include #include -struct libusb_device_handle; -struct libusb_transfer; +#ifdef __unix__ + #ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpedantic" + #endif + #include + #ifdef __GNUC__ + #pragma GCC diagnostic pop + #endif +#endif namespace lime { @@ -52,10 +60,16 @@ class USBGeneric : IUSB OpStatus AbortXfer(void* context) override; void FreeAsyncContext(void* context) override; - virtual OpStatus ClaimInterface(int32_t interface_number); + OpStatus ClaimInterface(int32_t interface_number); - protected: + void AddOnHotplugDisconnectCallback(const HotplugDisconnectCallbackType& function, void* userData) override; + + private: libusb_device_handle* dev_handle; //a device handle + + std::vector> hotplugDisconnectCallbacks{}; + + static int HotplugCallback(libusb_context* ctx, libusb_device* device, libusb_hotplug_event event, void* user_data); }; } // namespace lime diff --git a/src/include/limesuiteng/SDRDevice.h b/src/include/limesuiteng/SDRDevice.h index 34dd1e78c..b00667fcc 100644 --- a/src/include/limesuiteng/SDRDevice.h +++ b/src/include/limesuiteng/SDRDevice.h @@ -425,11 +425,24 @@ class LIME_API SDRDevice /// @return The status of the operation. virtual OpStatus SetHardwareTimestamp(uint8_t moduleIndex, const uint64_t now) = 0; + /// @brief The type of the function to call when a disconnect event happens. + typedef std::function HotplugDisconnectCallbackType; + + /// @brief The structure to hold the information for the callback + /// @tparam T The type of function to call + template struct CallbackInfo { + T function; + void* userData; + }; + /// @brief Sets up all the streams on a device. /// @param config The configuration to use for setting the streams up. /// @param moduleIndex The index of the device to set up. + /// @param hotplugDisconnectCallback The function to call if the device gets suddenly disconnected (USB only). /// @return The status code of the operation. - virtual OpStatus StreamSetup(const StreamConfig& config, uint8_t moduleIndex) = 0; + virtual OpStatus StreamSetup(const StreamConfig& config, + uint8_t moduleIndex, + const CallbackInfo& hotplugDisconnectCallback = { 0, nullptr }) = 0; /// @brief Starts all the set up streams on the device. /// @param moduleIndex The index of the device to start the streams on. From a08b4276a49a325e6654baec7ff9d36f9a3bc2f4 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 11 Jun 2024 11:43:47 +0300 Subject: [PATCH 02/17] Add hotplug callback adding and removal --- GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp | 17 ++++---- src/boards/LMS7002M_SDRDevice.cpp | 10 +++++ src/boards/LMS7002M_SDRDevice.h | 3 ++ src/boards/LimeSDR/LimeSDR.cpp | 40 ++++++++++++++++--- src/boards/LimeSDR/LimeSDR.h | 9 +++-- src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp | 40 ++++++++++++++++--- src/boards/LimeSDR_Mini/LimeSDR_Mini.h | 9 +++-- src/boards/LimeSDR_X3/LimeSDR_X3.cpp | 4 +- src/boards/LimeSDR_X3/LimeSDR_X3.h | 4 +- src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp | 4 +- src/boards/LimeSDR_XTRX/LimeSDR_XTRX.h | 4 +- src/boards/MMX8/MM_X8.cpp | 14 +++++-- src/boards/MMX8/MM_X8.h | 7 ++-- src/include/limesuiteng/SDRDevice.h | 38 +++++++++++------- 14 files changed, 147 insertions(+), 56 deletions(-) diff --git a/GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp b/GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp index 96861efd1..e9cc2589f 100644 --- a/GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp +++ b/GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp @@ -463,16 +463,16 @@ void fftviewer_frFFTviewer::StreamingLoop( const lime::complex32f_t* src[2] = { txPattern[0].data(), txPattern[1].data() };*/ + std::size_t callbackId = 0; try { - pthis->device->StreamSetup(config, - chipIndex, - { [](void* data) { - lime::error("Testing how many times this gets called"); - auto* const viewer = reinterpret_cast(data); - viewer->StopStreaming(); - }, - pthis }); + pthis->device->StreamSetup(config, chipIndex); + callbackId = pthis->device->AddHotplugDisconnectCallback( + [](void* data) { + auto* const viewer = reinterpret_cast(data); + viewer->StopStreaming(); + }, + pthis); pthis->device->StreamStart(chipIndex); } catch (std::logic_error& e) { @@ -653,6 +653,7 @@ void fftviewer_frFFTviewer::StreamingLoop( }*/ kiss_fft_free(m_fftCalcPlan); + pthis->device->RemoveHotplugDisconnectCallback(callbackId); pthis->stopProcessing.store(true); pthis->device->StreamStop(chipIndex); diff --git a/src/boards/LMS7002M_SDRDevice.cpp b/src/boards/LMS7002M_SDRDevice.cpp index e30790f4f..554d0d54b 100644 --- a/src/boards/LMS7002M_SDRDevice.cpp +++ b/src/boards/LMS7002M_SDRDevice.cpp @@ -1274,4 +1274,14 @@ OpStatus LMS7002M_SDRDevice::LMS7002TestSignalConfigure(LMS7002M* chip, const Ch return OpStatus::Success; } +std::size_t LMS7002M_SDRDevice::AddHotplugDisconnectCallback(const HotplugDisconnectCallbackType& function, void* userData) +{ + return 0; +} + +void LMS7002M_SDRDevice::RemoveHotplugDisconnectCallback(std::size_t id) +{ + return; +} + } // namespace lime diff --git a/src/boards/LMS7002M_SDRDevice.h b/src/boards/LMS7002M_SDRDevice.h index 477b0bd83..d756975c9 100644 --- a/src/boards/LMS7002M_SDRDevice.h +++ b/src/boards/LMS7002M_SDRDevice.h @@ -125,6 +125,9 @@ class LIME_API LMS7002M_SDRDevice : public SDRDevice /// @copydoc FPGA::WriteRegister() virtual OpStatus WriteFPGARegister(uint32_t address, uint32_t value); + std::size_t AddHotplugDisconnectCallback(const HotplugDisconnectCallbackType& function, void* userData) override; + void RemoveHotplugDisconnectCallback(std::size_t id) override; + protected: static OpStatus UpdateFPGAInterfaceFrequency(LMS7002M& soc, FPGA& fpga, uint8_t chipIndex); void SetGainInformationInDescriptor(RFSOCDescriptor& descriptor); diff --git a/src/boards/LimeSDR/LimeSDR.cpp b/src/boards/LimeSDR/LimeSDR.cpp index b82f1bb13..1a33d257b 100644 --- a/src/boards/LimeSDR/LimeSDR.cpp +++ b/src/boards/LimeSDR/LimeSDR.cpp @@ -24,11 +24,12 @@ #include #include -using namespace lime; using namespace lime::LMS64CProtocol; using namespace lime::LMS7002MCSR_Data; using namespace std::literals::string_literals; +namespace lime { + static const uint8_t SPI_LMS7002M = 0; static const uint8_t SPI_FPGA = 1; static const uint8_t SPI_ADF4002 = 2; @@ -491,8 +492,7 @@ void LimeSDR::ResetUSBFIFO() } } -OpStatus LimeSDR::StreamSetup( - const StreamConfig& config, uint8_t moduleIndex, const CallbackInfo& hotplugDisconnectCallback) +OpStatus LimeSDR::StreamSetup(const StreamConfig& config, uint8_t moduleIndex) { // Allow multiple setup calls if (mStreamers.at(moduleIndex) != nullptr) @@ -501,9 +501,14 @@ OpStatus LimeSDR::StreamSetup( } mStreamPort->AddOnHotplugDisconnectCallback( - [&hotplugDisconnectCallback](void* userData) { - hotplugDisconnectCallback.function(hotplugDisconnectCallback.userData); + [](void* userData) { auto* const sdr = reinterpret_cast(userData); + + for (const auto& callback : sdr->disconnectCallbacks) + { + callback(); + } + sdr->StreamStop(0); }, this); @@ -610,3 +615,28 @@ OpStatus LimeSDR::MemoryRead(std::shared_ptr storage, Region region return OpStatus::Error; return mfpgaPort->MemoryRead(region.address, data, region.size); } + +std::size_t LimeSDR::AddHotplugDisconnectCallback(const HotplugDisconnectCallbackType& function, void* userData) +{ + std::size_t id = 0; + + if (!disconnectCallbacks.empty()) + { + // As long as elements are not out of order this guarantees a unique ID in the array. + id = disconnectCallbacks.back().id + 1; + } + + disconnectCallbacks.push_back({ function, userData, id }); + + return id; +} + +void LimeSDR::RemoveHotplugDisconnectCallback(std::size_t id) +{ + disconnectCallbacks.erase(std::remove_if(disconnectCallbacks.begin(), + disconnectCallbacks.end(), + [&id](const CallbackInfo& info) { return id == info.id; }), + disconnectCallbacks.end()); +} + +} // namespace lime diff --git a/src/boards/LimeSDR/LimeSDR.h b/src/boards/LimeSDR/LimeSDR.h index 475c6734c..6447ff5bf 100644 --- a/src/boards/LimeSDR/LimeSDR.h +++ b/src/boards/LimeSDR/LimeSDR.h @@ -36,9 +36,7 @@ class LimeSDR : public LMS7002M_SDRDevice OpStatus SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; - OpStatus StreamSetup(const StreamConfig& config, - uint8_t moduleIndex, - const CallbackInfo& hotplugDisconnectCallback) override; + OpStatus StreamSetup(const StreamConfig& config, uint8_t moduleIndex) override; void StreamStart(uint8_t moduleIndex) override; void StreamStop(uint8_t moduleIndex) override; @@ -58,6 +56,9 @@ class LimeSDR : public LMS7002M_SDRDevice OpStatus MemoryWrite(std::shared_ptr storage, Region region, const void* data) override; OpStatus MemoryRead(std::shared_ptr storage, Region region, void* data) override; + std::size_t AddHotplugDisconnectCallback(const HotplugDisconnectCallbackType& function, void* userData) override; + void RemoveHotplugDisconnectCallback(std::size_t id) override; + protected: SDRDescriptor GetDeviceInfo(); void ResetUSBFIFO(); @@ -79,6 +80,8 @@ class LimeSDR : public LMS7002M_SDRDevice std::shared_ptr mlms7002mPort; std::shared_ptr mfpgaPort; bool mConfigInProgress; + + std::vector> disconnectCallbacks; }; } // namespace lime diff --git a/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp b/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp index f59867b68..ee1082bd2 100644 --- a/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp +++ b/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp @@ -23,12 +23,13 @@ #include #include -using namespace lime; using namespace lime::LMS64CProtocol; using namespace lime::EqualizerCSR; using namespace lime::LMS7002MCSR_Data; using namespace std::literals::string_literals; +namespace lime { + static const int STREAM_BULK_WRITE_ADDRESS = 0x03; static const int STREAM_BULK_READ_ADDRESS = 0x83; @@ -526,8 +527,7 @@ SDRDescriptor LimeSDR_Mini::GetDeviceInfo(void) return deviceDescriptor; } -OpStatus LimeSDR_Mini::StreamSetup( - const StreamConfig& config, uint8_t moduleIndex, const CallbackInfo& hotplugDisconnectCallback) +OpStatus LimeSDR_Mini::StreamSetup(const StreamConfig& config, uint8_t moduleIndex) { if (moduleIndex != 0) return ReportError(OpStatus::InvalidValue, "StreamSetup: invalid module index"); @@ -542,9 +542,14 @@ OpStatus LimeSDR_Mini::StreamSetup( ftdi->ResetStreamBuffers(); mStreamPort->AddOnHotplugDisconnectCallback( - [&hotplugDisconnectCallback](void* userData) { - hotplugDisconnectCallback.function(hotplugDisconnectCallback.userData); + [](void* userData) { auto* const mini = reinterpret_cast(userData); + + for (const auto& callback : mini->disconnectCallbacks) + { + callback(); + } + mini->StreamStop(0); }, this); @@ -669,3 +674,28 @@ void LimeSDR_Mini::SetSerialNumber(const std::string& number) sscanf(number.c_str(), "%16lX", &sn); mDeviceDescriptor.serialNumber = sn; } + +std::size_t LimeSDR_Mini::AddHotplugDisconnectCallback(const HotplugDisconnectCallbackType& function, void* userData) +{ + std::size_t id = 0; + + if (!disconnectCallbacks.empty()) + { + // As long as elements are not out of order this guarantees a unique ID in the array. + id = disconnectCallbacks.back().id + 1; + } + + disconnectCallbacks.push_back({ function, userData, id }); + + return id; +} + +void LimeSDR_Mini::RemoveHotplugDisconnectCallback(std::size_t id) +{ + disconnectCallbacks.erase(std::remove_if(disconnectCallbacks.begin(), + disconnectCallbacks.end(), + [&id](const CallbackInfo& info) { return id == info.id; }), + disconnectCallbacks.end()); +} + +} // namespace lime diff --git a/src/boards/LimeSDR_Mini/LimeSDR_Mini.h b/src/boards/LimeSDR_Mini/LimeSDR_Mini.h index b6eacb46c..b69dd85b8 100644 --- a/src/boards/LimeSDR_Mini/LimeSDR_Mini.h +++ b/src/boards/LimeSDR_Mini/LimeSDR_Mini.h @@ -38,9 +38,7 @@ class LimeSDR_Mini : public LMS7002M_SDRDevice OpStatus SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; - OpStatus StreamSetup(const StreamConfig& config, - uint8_t moduleIndex, - const CallbackInfo& hotplugDisconnectCallback) override; + OpStatus StreamSetup(const StreamConfig& config, uint8_t moduleIndex) override; void StreamStart(uint8_t moduleIndex) override; void StreamStop(uint8_t moduleIndex) override; @@ -55,6 +53,9 @@ class LimeSDR_Mini : public LMS7002M_SDRDevice void SetSerialNumber(const std::string& number); + std::size_t AddHotplugDisconnectCallback(const HotplugDisconnectCallbackType& function, void* userData) override; + void RemoveHotplugDisconnectCallback(std::size_t id) override; + protected: SDRDescriptor GetDeviceInfo(); static OpStatus UpdateFPGAInterface(void* userData); @@ -65,6 +66,8 @@ class LimeSDR_Mini : public LMS7002M_SDRDevice std::shared_ptr mlms7002mPort; std::shared_ptr mfpgaPort; bool mConfigInProgress{}; + + std::vector> disconnectCallbacks; }; } // namespace lime diff --git a/src/boards/LimeSDR_X3/LimeSDR_X3.cpp b/src/boards/LimeSDR_X3/LimeSDR_X3.cpp index fbb107946..f148029e1 100644 --- a/src/boards/LimeSDR_X3/LimeSDR_X3.cpp +++ b/src/boards/LimeSDR_X3/LimeSDR_X3.cpp @@ -865,9 +865,7 @@ OpStatus LimeSDR_X3::SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MI } } -OpStatus LimeSDR_X3::StreamSetup(const StreamConfig& config, - uint8_t moduleIndex, - [[maybe_unused]] const CallbackInfo& hotplugDisconnectCallback) +OpStatus LimeSDR_X3::StreamSetup(const StreamConfig& config, uint8_t moduleIndex) { // Allow multiple setup calls if (mStreamers.at(moduleIndex) != nullptr) diff --git a/src/boards/LimeSDR_X3/LimeSDR_X3.h b/src/boards/LimeSDR_X3/LimeSDR_X3.h index 3e03590c3..527318e08 100644 --- a/src/boards/LimeSDR_X3/LimeSDR_X3.h +++ b/src/boards/LimeSDR_X3/LimeSDR_X3.h @@ -41,9 +41,7 @@ class LimeSDR_X3 : public LMS7002M_SDRDevice OpStatus SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; - OpStatus StreamSetup(const StreamConfig& config, - uint8_t moduleIndex, - const CallbackInfo& hotplugDisconnectCallback) override; + OpStatus StreamSetup(const StreamConfig& config, uint8_t moduleIndex) override; void StreamStop(uint8_t moduleIndex) override; OpStatus CustomParameterWrite(const std::vector& parameters) override; diff --git a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp index e583e010b..ee3ff9620 100644 --- a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp +++ b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp @@ -364,9 +364,7 @@ OpStatus LimeSDR_XTRX::SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* } } -OpStatus LimeSDR_XTRX::StreamSetup(const StreamConfig& config, - uint8_t moduleIndex, - [[maybe_unused]] const CallbackInfo& hotplugDisconnectCallback) +OpStatus LimeSDR_XTRX::StreamSetup(const StreamConfig& config, uint8_t moduleIndex) { // Allow multiple setup calls if (mStreamers.at(moduleIndex) != nullptr) diff --git a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.h b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.h index a750e46f1..9f07d7c4a 100644 --- a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.h +++ b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.h @@ -37,9 +37,7 @@ class LimeSDR_XTRX : public LMS7002M_SDRDevice OpStatus SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; - OpStatus StreamSetup(const StreamConfig& config, - uint8_t moduleIndex, - const CallbackInfo& hotplugDisconnectCallback = { 0, nullptr }) override; + OpStatus StreamSetup(const StreamConfig& config, uint8_t moduleIndex) override; void StreamStop(uint8_t moduleIndex) override; OpStatus CustomParameterWrite(const std::vector& parameters) override; diff --git a/src/boards/MMX8/MM_X8.cpp b/src/boards/MMX8/MM_X8.cpp index 2ef9c42e9..d073571f2 100644 --- a/src/boards/MMX8/MM_X8.cpp +++ b/src/boards/MMX8/MM_X8.cpp @@ -611,9 +611,7 @@ ChannelConfig::Direction::TestSignal LimeSDR_MMX8::GetTestSignal(uint8_t moduleI return mSubDevices[moduleIndex]->GetTestSignal(0, direction, channel); } -OpStatus LimeSDR_MMX8::StreamSetup(const StreamConfig& config, - uint8_t moduleIndex, - [[maybe_unused]] const CallbackInfo& hotplugDisconnectCallback) +OpStatus LimeSDR_MMX8::StreamSetup(const StreamConfig& config, uint8_t moduleIndex) { OpStatus ret = mSubDevices[moduleIndex]->StreamSetup(config, 0); if (ret != OpStatus::Success) @@ -832,4 +830,14 @@ OpStatus LimeSDR_MMX8::UploadTxWaveform(const StreamConfig& config, uint8_t modu return mSubDevices[moduleIndex]->UploadTxWaveform(config, 0, samples, count); } +std::size_t LimeSDR_MMX8::AddHotplugDisconnectCallback(const HotplugDisconnectCallbackType& function, void* userData) +{ + return 0; +} + +void LimeSDR_MMX8::RemoveHotplugDisconnectCallback(std::size_t id) +{ + return; +} + } //namespace lime diff --git a/src/boards/MMX8/MM_X8.h b/src/boards/MMX8/MM_X8.h index f5de4f0dd..a7f990ca7 100644 --- a/src/boards/MMX8/MM_X8.h +++ b/src/boards/MMX8/MM_X8.h @@ -117,9 +117,7 @@ class LimeSDR_MMX8 : public SDRDevice uint64_t GetHardwareTimestamp(uint8_t moduleIndex) override; OpStatus SetHardwareTimestamp(uint8_t moduleIndex, const uint64_t now) override; - OpStatus StreamSetup(const StreamConfig& config, - uint8_t moduleIndex, - const CallbackInfo& hotplugDisconnectCallback) override; + OpStatus StreamSetup(const StreamConfig& config, uint8_t moduleIndex) override; void StreamStart(uint8_t moduleIndex) override; void StreamStart(const std::vector moduleIndexes) override; void StreamStop(uint8_t moduleIndex) override; @@ -151,6 +149,9 @@ class LimeSDR_MMX8 : public SDRDevice OpStatus MemoryRead(std::shared_ptr storage, Region region, void* data) override; OpStatus UploadTxWaveform(const StreamConfig& config, uint8_t moduleIndex, const void** samples, uint32_t count) override; + std::size_t AddHotplugDisconnectCallback(const HotplugDisconnectCallbackType& function, void* userData) override; + void RemoveHotplugDisconnectCallback(std::size_t id) override; + private: std::shared_ptr mMainFPGAcomms; SDRDescriptor mDeviceDescriptor; diff --git a/src/include/limesuiteng/SDRDevice.h b/src/include/limesuiteng/SDRDevice.h index b00667fcc..79fe238ef 100644 --- a/src/include/limesuiteng/SDRDevice.h +++ b/src/include/limesuiteng/SDRDevice.h @@ -425,24 +425,11 @@ class LIME_API SDRDevice /// @return The status of the operation. virtual OpStatus SetHardwareTimestamp(uint8_t moduleIndex, const uint64_t now) = 0; - /// @brief The type of the function to call when a disconnect event happens. - typedef std::function HotplugDisconnectCallbackType; - - /// @brief The structure to hold the information for the callback - /// @tparam T The type of function to call - template struct CallbackInfo { - T function; - void* userData; - }; - /// @brief Sets up all the streams on a device. /// @param config The configuration to use for setting the streams up. /// @param moduleIndex The index of the device to set up. - /// @param hotplugDisconnectCallback The function to call if the device gets suddenly disconnected (USB only). /// @return The status code of the operation. - virtual OpStatus StreamSetup(const StreamConfig& config, - uint8_t moduleIndex, - const CallbackInfo& hotplugDisconnectCallback = { 0, nullptr }) = 0; + virtual OpStatus StreamSetup(const StreamConfig& config, uint8_t moduleIndex) = 0; /// @brief Starts all the set up streams on the device. /// @param moduleIndex The index of the device to start the streams on. @@ -585,6 +572,29 @@ class LIME_API SDRDevice /// @param serialNumber Device's serial number /// @return The operation success state. virtual OpStatus WriteSerialNumber(uint64_t serialNumber); + + /// @brief The type of the function to call when a disconnect event happens. + typedef std::function HotplugDisconnectCallbackType; + + /// @brief The structure to hold the information for the callback + /// @tparam T The type of function to call + template struct CallbackInfo { + T function; + void* userData; + std::size_t id; + + void operator()() const { return function(userData); } + }; + + /// @brief Adds a callback to run when a hotplug disconnect event happens (currently USB only). + /// @param function The function to run when a disconnect happens. + /// @param userData The data to pass into the function when it runs. + /// @return The ID of the callback for removal later. + virtual std::size_t AddHotplugDisconnectCallback(const HotplugDisconnectCallbackType& function, void* userData) = 0; + + /// @brief Removes the given hotplug disconnect callback by ID. + /// @param id The ID of the callback to remove. + virtual void RemoveHotplugDisconnectCallback(std::size_t id) = 0; }; } // namespace lime From 291949da17fc4f209d310994fd3a3d8f2c95d2c5 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 11 Jun 2024 14:01:32 +0300 Subject: [PATCH 03/17] Slight GUI file clean-up --- GUI/limeGUIFrame.cpp | 3 +-- GUI/limeGUIFrame.h | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/GUI/limeGUIFrame.cpp b/GUI/limeGUIFrame.cpp index 38d34a86c..b5c950a35 100644 --- a/GUI/limeGUIFrame.cpp +++ b/GUI/limeGUIFrame.cpp @@ -34,6 +34,7 @@ #include "limesuiteng/SDRDescriptor.h" #include "DeviceTreeNode.h" #include "limesuiteng/Logger.h" +#include "DeviceConnectionPanel.h" using namespace std; using namespace lime; @@ -43,8 +44,6 @@ static constexpr int controlColumn = 1; limeGUIFrame* limeGUIFrame::obj_ptr = nullptr; -int limeGUIFrame::m_lmsSelection = 0; - void limeGUIFrame::OnGlobalLogEvent(const lime::LogLevel level, const std::string& message) { if (obj_ptr == nullptr || obj_ptr->mMiniLog == nullptr) diff --git a/GUI/limeGUIFrame.h b/GUI/limeGUIFrame.h index 9e357a9c6..00a53a963 100644 --- a/GUI/limeGUIFrame.h +++ b/GUI/limeGUIFrame.h @@ -29,10 +29,6 @@ #include #include -#include "IModuleFrame.h" -#include "ISOCPanel.h" -#include "DeviceConnectionPanel.h" -#include "dlgAbout.h" #include "limeGUI.h" class pnlMiniLog; @@ -40,10 +36,21 @@ class lms7002_mainPanel; class fftviewer_frFFTviewer; class LMS_Programming_wxgui; class pnlBoardControls; +class IModuleFrame; +class ISOCPanel; + +namespace lime { +class SDRDevice; +class DeviceConnectionPanel; +} // namespace lime class limeGUIFrame : public wxFrame { - protected: + public: + limeGUIFrame(wxWindow* parent, const AppArgs& appArgs); + ~limeGUIFrame(); + + private: void AddModule(IModuleFrame* module, const std::string& title); void RemoveModule(IModuleFrame* module); // Handlers for AppFrame events. @@ -57,13 +64,6 @@ class limeGUIFrame : public wxFrame void DeviceTreeSelectionChanged(wxTreeEvent& event); - public: - limeGUIFrame(wxWindow* parent, const AppArgs& appArgs); - - virtual ~limeGUIFrame(); - static int m_lmsSelection; - - protected: static void OnGlobalLogEvent(const lime::LogLevel level, const std::string& message); void OnLogMessage(wxCommandEvent& event); void UpdateConnections(lime::SDRDevice* port); From cb44fe6f9932fba1f950e38c7f5f4f51c4c4f011 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 11 Jun 2024 14:59:31 +0300 Subject: [PATCH 04/17] Fix small tiny piece of undefined behaviour --- embedded/lms7002m/privates.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embedded/lms7002m/privates.c b/embedded/lms7002m/privates.c index a4227998b..f19b3016c 100644 --- a/embedded/lms7002m/privates.c +++ b/embedded/lms7002m/privates.c @@ -59,7 +59,7 @@ void lms7002m_sleep(long timeInMicroseconds) void lms7002m_spi_write(lms7002m_context* self, uint16_t address, uint16_t value) { uint32_t mosi = address << 16 | value; - mosi |= 1 << 31; + mosi |= 0x80000000; self->hooks.spi16_transact(&mosi, NULL, 1, self->hooks.spi16_userData); } From 05107455264f4fe2d134025cfe43e6fec439ad84 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 11 Jun 2024 15:18:46 +0300 Subject: [PATCH 05/17] Fix all related GUI crashes --- GUI/limeGUIFrame.cpp | 15 +++++++++++--- src/boards/LimeSDR/LimeSDR.cpp | 25 ++++++++++++------------ src/boards/LimeSDR/LimeSDR.h | 1 + src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp | 25 ++++++++++++------------ src/comms/USB/USBGeneric.cpp | 5 +++-- 5 files changed, 40 insertions(+), 31 deletions(-) diff --git a/GUI/limeGUIFrame.cpp b/GUI/limeGUIFrame.cpp index b5c950a35..2935eee0a 100644 --- a/GUI/limeGUIFrame.cpp +++ b/GUI/limeGUIFrame.cpp @@ -5,9 +5,9 @@ #endif //__BORLANDC__ #include +#include #include "chips/LMS7002M/lms7002_mainPanel.h" - #include "limeGUIFrame.h" #include "dlgAbout.h" #include "lms7suiteEvents.h" @@ -19,9 +19,7 @@ #include "utility/pnlMiniLog.h" #include "FPGAcontrols_wxgui.h" #include "utility/SPI_wxgui.h" -#include #include "utility/dlgDeviceInfo.h" -#include #include "boards/pnlBoardControls.h" #include "protocols/LMSBoards.h" #include "utility/SPI_wxgui.h" @@ -36,6 +34,8 @@ #include "limesuiteng/Logger.h" #include "DeviceConnectionPanel.h" +#include + using namespace std; using namespace lime; using namespace std::literals::string_literals; @@ -398,6 +398,15 @@ void limeGUIFrame::OnDeviceHandleChange(wxCommandEvent& event) wxPostEvent(this, evt); UpdateConnections(lmsControl); + lmsControl->AddHotplugDisconnectCallback( + [&](void* data) { + auto* evt = new wxCommandEvent(); + evt->SetEventType(limeEVT_SDR_HANDLE_SELECTED); + evt->SetString(wxEmptyString); + wxQueueEvent(this, evt); + }, + this); + Fit(); } catch (std::runtime_error& e) { diff --git a/src/boards/LimeSDR/LimeSDR.cpp b/src/boards/LimeSDR/LimeSDR.cpp index 1a33d257b..89e025304 100644 --- a/src/boards/LimeSDR/LimeSDR.cpp +++ b/src/boards/LimeSDR/LimeSDR.cpp @@ -155,6 +155,18 @@ LimeSDR::LimeSDR(std::shared_ptr spiLMS, mDeviceDescriptor = descriptor; + mStreamPort->AddOnHotplugDisconnectCallback( + [](void* userData) { + auto* const sdr = reinterpret_cast(userData); + + // Call in reverse order so that the "smaller" scoped callbacks run first. + for (auto iter = sdr->disconnectCallbacks.rbegin(); iter != sdr->disconnectCallbacks.rend(); ++iter) + { + (*iter)(); + } + }, + this); + //must configure synthesizer before using LimeSDR /*if (info.device == LMS_DEV_LIMESDR && info.hardware < 4) { @@ -500,19 +512,6 @@ OpStatus LimeSDR::StreamSetup(const StreamConfig& config, uint8_t moduleIndex) delete mStreamers.at(moduleIndex); } - mStreamPort->AddOnHotplugDisconnectCallback( - [](void* userData) { - auto* const sdr = reinterpret_cast(userData); - - for (const auto& callback : sdr->disconnectCallbacks) - { - callback(); - } - - sdr->StreamStop(0); - }, - this); - constexpr uint8_t rxBulkEndpoint = 0x81; constexpr uint8_t txBulkEndpoint = 0x01; auto rxdma = std::make_shared(mStreamPort, rxBulkEndpoint, DataTransferDirection::DeviceToHost); diff --git a/src/boards/LimeSDR/LimeSDR.h b/src/boards/LimeSDR/LimeSDR.h index 6447ff5bf..5e065185f 100644 --- a/src/boards/LimeSDR/LimeSDR.h +++ b/src/boards/LimeSDR/LimeSDR.h @@ -82,6 +82,7 @@ class LimeSDR : public LMS7002M_SDRDevice bool mConfigInProgress; std::vector> disconnectCallbacks; + std::size_t mStreamStopCallbackId; }; } // namespace lime diff --git a/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp b/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp index ee1082bd2..7e6364a9f 100644 --- a/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp +++ b/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp @@ -206,6 +206,18 @@ LimeSDR_Mini::LimeSDR_Mini(std::shared_ptr spiLMS, descriptor.socTree->children.push_back(fpgaNode); mDeviceDescriptor = descriptor; + + mStreamPort->AddOnHotplugDisconnectCallback( + [](void* userData) { + auto* const mini = reinterpret_cast(userData); + + // Call in reverse order so that the "smaller" scoped callbacks run first. + for (auto iter = mini->disconnectCallbacks.rbegin(); iter != mini->disconnectCallbacks.rend(); ++iter) + { + (*iter)(); + } + }, + this); } LimeSDR_Mini::~LimeSDR_Mini() @@ -541,19 +553,6 @@ OpStatus LimeSDR_Mini::StreamSetup(const StreamConfig& config, uint8_t moduleInd FT601* ftdi = dynamic_cast(mStreamPort.get()); ftdi->ResetStreamBuffers(); - mStreamPort->AddOnHotplugDisconnectCallback( - [](void* userData) { - auto* const mini = reinterpret_cast(userData); - - for (const auto& callback : mini->disconnectCallbacks) - { - callback(); - } - - mini->StreamStop(0); - }, - this); - auto rxdma = std::make_shared(mStreamPort, STREAM_BULK_READ_ADDRESS, DataTransferDirection::DeviceToHost); auto txdma = std::make_shared(mStreamPort, STREAM_BULK_WRITE_ADDRESS, DataTransferDirection::HostToDevice); diff --git a/src/comms/USB/USBGeneric.cpp b/src/comms/USB/USBGeneric.cpp index 8333c8f93..7c74f9aa6 100644 --- a/src/comms/USB/USBGeneric.cpp +++ b/src/comms/USB/USBGeneric.cpp @@ -110,13 +110,14 @@ static void process_libusbtransfer(libusb_transfer* trans) context->cv.notify_one(); } +// Runs within the gUSBProcessingThread thread int USBGeneric::HotplugCallback(libusb_context* ctx, libusb_device* device, libusb_hotplug_event event, void* user_data) { auto* usb = reinterpret_cast(user_data); - for (const auto& callback : usb->hotplugDisconnectCallbacks) + for (auto iter = usb->hotplugDisconnectCallbacks.rbegin(); iter != usb->hotplugDisconnectCallbacks.rend(); ++iter) { - callback.function(callback.userData); + iter->function(iter->userData); } usb->Disconnect(); From 61727ad6eb431d3f33719be2a26e4c8d26a687d5 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 11 Jun 2024 15:18:57 +0300 Subject: [PATCH 06/17] Make the IUSB struct nicer as well --- src/comms/USB/IUSB.h | 2 ++ src/comms/USB/USBGeneric.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/comms/USB/IUSB.h b/src/comms/USB/IUSB.h index d3068c8aa..885f70faa 100644 --- a/src/comms/USB/IUSB.h +++ b/src/comms/USB/IUSB.h @@ -122,6 +122,8 @@ class IUSB template struct CallbackInfo { T function; void* userData; + + void operator()() { return function(userData); } }; virtual void AddOnHotplugDisconnectCallback(const HotplugDisconnectCallbackType& function, void* userData) = 0; }; diff --git a/src/comms/USB/USBGeneric.cpp b/src/comms/USB/USBGeneric.cpp index 7c74f9aa6..1fdb8e7ee 100644 --- a/src/comms/USB/USBGeneric.cpp +++ b/src/comms/USB/USBGeneric.cpp @@ -117,7 +117,7 @@ int USBGeneric::HotplugCallback(libusb_context* ctx, libusb_device* device, libu for (auto iter = usb->hotplugDisconnectCallbacks.rbegin(); iter != usb->hotplugDisconnectCallbacks.rend(); ++iter) { - iter->function(iter->userData); + (*iter)(); } usb->Disconnect(); From 13ae46e23e2f00f4f621b2be35035521c81ff304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominykas=20Petkevi=C4=8Dius?= Date: Tue, 11 Jun 2024 15:57:18 +0300 Subject: [PATCH 07/17] Add note in FT601 code that hotplugging events are not supported by the library --- src/comms/USB/FT601/FT601.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/comms/USB/FT601/FT601.cpp b/src/comms/USB/FT601/FT601.cpp index facd77e16..f70a4dcbb 100644 --- a/src/comms/USB/FT601/FT601.cpp +++ b/src/comms/USB/FT601/FT601.cpp @@ -378,7 +378,7 @@ void FT601::AddOnHotplugDisconnectCallback(const IUSB::HotplugDisconnectCallback #ifdef __unix__ libusb_impl.AddOnHotplugDisconnectCallback(function, userData); #else - // TODO: IMPLEMENT + // Hotplug events are not supported by the library #endif } From 2cf4f615916e8a5428f9a8466c8e1cb01665840a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominykas=20Petkevi=C4=8Dius?= Date: Wed, 12 Jun 2024 09:42:34 +0300 Subject: [PATCH 08/17] Add note on Cypress API library hotplugging capabilities --- src/comms/USB/FX3/FX3.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/comms/USB/FX3/FX3.cpp b/src/comms/USB/FX3/FX3.cpp index ca59f4263..8dbcdafc1 100644 --- a/src/comms/USB/FX3/FX3.cpp +++ b/src/comms/USB/FX3/FX3.cpp @@ -260,7 +260,8 @@ void FX3::AddOnHotplugDisconnectCallback(const IUSB::HotplugDisconnectCallbackTy #ifdef __unix__ libusb_impl.AddOnHotplugDisconnectCallback(function, userData); #else - // TODO: IMPLEMENT + // TODO: figure out how to pass something to CCyUSBDevice constructor's first parameter + // that would be able to collect the Windows Plug and Play events that the library would send #endif } From 450b74e99ebf8fc805ec8cc50bf5136d5e879f49 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Wed, 12 Jun 2024 09:56:08 +0300 Subject: [PATCH 09/17] Don't remove the callback event in fftviewer if it did not actually assign it --- GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp b/GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp index e9cc2589f..9068938f9 100644 --- a/GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp +++ b/GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp @@ -15,6 +15,7 @@ #include "limesuiteng/StreamConfig.h" #include "limesuiteng/complex.h" #include +#include using namespace std; using namespace lime; @@ -463,7 +464,7 @@ void fftviewer_frFFTviewer::StreamingLoop( const lime::complex32f_t* src[2] = { txPattern[0].data(), txPattern[1].data() };*/ - std::size_t callbackId = 0; + std::optional callbackId{ std::nullopt }; try { pthis->device->StreamSetup(config, chipIndex); @@ -653,7 +654,10 @@ void fftviewer_frFFTviewer::StreamingLoop( }*/ kiss_fft_free(m_fftCalcPlan); - pthis->device->RemoveHotplugDisconnectCallback(callbackId); + if (callbackId) + { + pthis->device->RemoveHotplugDisconnectCallback(callbackId.value()); + } pthis->stopProcessing.store(true); pthis->device->StreamStop(chipIndex); From fc432356f0f00abfe41f4e5d2981d024ff0580bb Mon Sep 17 00:00:00 2001 From: Dominykas Date: Wed, 12 Jun 2024 10:26:14 +0300 Subject: [PATCH 10/17] Add stopping callbacks to examples and `limeTRX` --- src/cli/limeTRX.cpp | 2 ++ src/comms/USB/USBGeneric.cpp | 5 ++++ src/examples/basicRX.cpp | 2 +- src/examples/basicTX.cpp | 2 +- src/examples/dualRXTX.cpp | 2 +- src/protocols/TRXLooper.cpp | 46 +++++++++++++++++++++--------------- 6 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/cli/limeTRX.cpp b/src/cli/limeTRX.cpp index 980b71dfa..d8e743c38 100644 --- a/src/cli/limeTRX.cpp +++ b/src/cli/limeTRX.cpp @@ -467,6 +467,8 @@ int main(int argc, char** argv) else device->StreamStart(chipIndex); + device->AddHotplugDisconnectCallback([](void* data) { *reinterpret_cast(data) = true; }, &stopProgram); + auto startTime = std::chrono::high_resolution_clock::now(); auto t1 = startTime - std::chrono::seconds(2); // rewind t1 to do update on first loop auto t2 = t1; diff --git a/src/comms/USB/USBGeneric.cpp b/src/comms/USB/USBGeneric.cpp index 1fdb8e7ee..4bb2898e7 100644 --- a/src/comms/USB/USBGeneric.cpp +++ b/src/comms/USB/USBGeneric.cpp @@ -366,6 +366,11 @@ OpStatus USBGeneric::BeginDataXfer(void* context, uint8_t* buffer, size_t length libusb_fill_bulk_transfer(tr, dev_handle, endPointAddr, buffer, length, process_libusbtransfer, xfer, 0); xfer->done.store(false); xfer->bytesXfered = 0; + if (tr->dev_handle == nullptr) + { + return OpStatus::Error; + } + int status = libusb_submit_transfer(tr); if (status != 0) { diff --git a/src/examples/basicRX.cpp b/src/examples/basicRX.cpp index f55f6decb..e97188228 100644 --- a/src/examples/basicRX.cpp +++ b/src/examples/basicRX.cpp @@ -97,7 +97,7 @@ int main(int argc, char** argv) device->StreamSetup(stream, chipIndex); device->StreamStart(chipIndex); - + device->AddHotplugDisconnectCallback([](void* data) { *reinterpret_cast(data) = true; }, &stopProgram); } catch (std::runtime_error& e) { std::cout << "Failed to configure settings: "sv << e.what() << std::endl; diff --git a/src/examples/basicTX.cpp b/src/examples/basicTX.cpp index 213776bd1..a96a1ecdb 100644 --- a/src/examples/basicTX.cpp +++ b/src/examples/basicTX.cpp @@ -90,7 +90,7 @@ int main(int argc, char** argv) device->StreamSetup(stream, chipIndex); device->StreamStart(chipIndex); - + device->AddHotplugDisconnectCallback([](void* data) { *reinterpret_cast(data) = true; }, &stopProgram); } catch (std::runtime_error& e) { std::cout << "Failed to configure settings: "sv << e.what() << std::endl; diff --git a/src/examples/dualRXTX.cpp b/src/examples/dualRXTX.cpp index 71efe7f7e..b6517e8c7 100644 --- a/src/examples/dualRXTX.cpp +++ b/src/examples/dualRXTX.cpp @@ -110,7 +110,7 @@ int main(int argc, char** argv) device->StreamSetup(stream, chipIndex); device->StreamStart(chipIndex); - + device->AddHotplugDisconnectCallback([](void* data) { *reinterpret_cast(data) = true; }, &stopProgram); } catch (std::runtime_error& e) { std::cout << "Failed to configure settings: "sv << e.what() << std::endl; diff --git a/src/protocols/TRXLooper.cpp b/src/protocols/TRXLooper.cpp index 457d5acf2..c1a574df2 100644 --- a/src/protocols/TRXLooper.cpp +++ b/src/protocols/TRXLooper.cpp @@ -257,28 +257,36 @@ void TRXLooper::Stop() { lime::error("Failed to join TRXLooper threads"s); } - fpga->StopStreaming(); - uint32_t fpgaTxPktIngressCount; - uint32_t fpgaTxPktDropCounter; - fpga->ReadTxPacketCounters(chipId, &fpgaTxPktIngressCount, &fpgaTxPktDropCounter); - if (mCallback_logMessage) + mStreamEnabled = false; + + try { - char msg[512]; - std::snprintf(msg, - sizeof(msg), - "Tx%i stop: host sent packets: %li (0x%08lX), FPGA packet ingresed: %i (0x%08X), diff: %li, Tx packet dropped: %i", - chipId, - mTx.stats.packets, - mTx.stats.packets, - fpgaTxPktIngressCount, - fpgaTxPktIngressCount, - (mTx.stats.packets & 0xFFFFFFFF) - fpgaTxPktIngressCount, - fpgaTxPktDropCounter); - mCallback_logMessage(LogLevel::Debug, msg); - } + fpga->StopStreaming(); - mStreamEnabled = false; + uint32_t fpgaTxPktIngressCount; + uint32_t fpgaTxPktDropCounter; + fpga->ReadTxPacketCounters(chipId, &fpgaTxPktIngressCount, &fpgaTxPktDropCounter); + if (mCallback_logMessage) + { + char msg[512]; + std::snprintf(msg, + sizeof(msg), + "Tx%i stop: host sent packets: %li (0x%08lX), FPGA packet ingresed: %i (0x%08X), diff: %li, Tx packet dropped: %i", + chipId, + mTx.stats.packets, + mTx.stats.packets, + fpgaTxPktIngressCount, + fpgaTxPktIngressCount, + (mTx.stats.packets & 0xFFFFFFFF) - fpgaTxPktIngressCount, + fpgaTxPktDropCounter); + mCallback_logMessage(LogLevel::Debug, msg); + } + } + catch (const std::exception& e) + { + lime::error("%s", e.what()); + } } void TRXLooper::Teardown() From 6b6598ee6a2733751e637264f2b8586f38286739 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Wed, 12 Jun 2024 10:58:20 +0300 Subject: [PATCH 11/17] clang-format --- src/protocols/TRXLooper.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/protocols/TRXLooper.cpp b/src/protocols/TRXLooper.cpp index c1a574df2..78dffa900 100644 --- a/src/protocols/TRXLooper.cpp +++ b/src/protocols/TRXLooper.cpp @@ -282,8 +282,7 @@ void TRXLooper::Stop() fpgaTxPktDropCounter); mCallback_logMessage(LogLevel::Debug, msg); } - } - catch (const std::exception& e) + } catch (const std::exception& e) { lime::error("%s", e.what()); } From 9339a01d17707cf47a52860bd50e17c1eec0fc11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominykas=20Petkevi=C4=8Dius?= Date: Thu, 20 Jun 2024 09:09:14 +0300 Subject: [PATCH 12/17] Change USB serial in `IUSB::Connect` to `std::string` --- src/comms/USB/FT601/FT601.cpp | 4 ++-- src/comms/USB/FT601/FT601.h | 2 +- src/comms/USB/FX3/FX3.cpp | 2 +- src/comms/USB/FX3/FX3.h | 2 +- src/comms/USB/IUSB.h | 2 +- src/comms/USB/USBGeneric.cpp | 4 ++-- src/comms/USB/USBGeneric.h | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/comms/USB/FT601/FT601.cpp b/src/comms/USB/FT601/FT601.cpp index f70a4dcbb..75ca9d5ac 100644 --- a/src/comms/USB/FT601/FT601.cpp +++ b/src/comms/USB/FT601/FT601.cpp @@ -71,7 +71,7 @@ FT601::~FT601() Disconnect(); } -bool FT601::Connect(uint16_t vid, uint16_t pid, const char* serial) +bool FT601::Connect(uint16_t vid, uint16_t pid, const std::string& serial) { Disconnect(); #ifdef __unix__ @@ -95,7 +95,7 @@ bool FT601::Connect(uint16_t vid, uint16_t pid, const char* serial) FT_STATUS ftStatus = FT_OK; DWORD dwNumDevices = 0; // Open a device - ftStatus = FT_Create(reinterpret_cast(const_cast(serial)), FT_OPEN_BY_SERIAL_NUMBER, &mFTHandle); + ftStatus = FT_Create(reinterpret_cast(const_cast(serial.c_str())), FT_OPEN_BY_SERIAL_NUMBER, &mFTHandle); if (FT_FAILED(ftStatus)) return false; diff --git a/src/comms/USB/FT601/FT601.h b/src/comms/USB/FT601/FT601.h index 662988f88..8b38f31d0 100644 --- a/src/comms/USB/FT601/FT601.h +++ b/src/comms/USB/FT601/FT601.h @@ -19,7 +19,7 @@ class FT601 : public IUSB FT601(); virtual ~FT601(); - bool Connect(uint16_t vid, uint16_t pid, const char* serial) override; + bool Connect(uint16_t vid, uint16_t pid, const std::string& serial) override; void Disconnect() override; bool IsConnected() override; diff --git a/src/comms/USB/FX3/FX3.cpp b/src/comms/USB/FX3/FX3.cpp index 8dbcdafc1..5ed155de5 100644 --- a/src/comms/USB/FX3/FX3.cpp +++ b/src/comms/USB/FX3/FX3.cpp @@ -102,7 +102,7 @@ FX3::~FX3() Disconnect(); } -bool FX3::Connect(uint16_t vid, uint16_t pid, const char* serial) +bool FX3::Connect(uint16_t vid, uint16_t pid, const std::string& serial) { Disconnect(); #ifdef __unix__ diff --git a/src/comms/USB/FX3/FX3.h b/src/comms/USB/FX3/FX3.h index ed6335593..843bfa8a1 100644 --- a/src/comms/USB/FX3/FX3.h +++ b/src/comms/USB/FX3/FX3.h @@ -23,7 +23,7 @@ class FX3 : public IUSB FX3(); virtual ~FX3(); - bool Connect(uint16_t vid, uint16_t pid, const char* serial) override; + bool Connect(uint16_t vid, uint16_t pid, const std::string& serial) override; void Disconnect() override; bool IsConnected() override; diff --git a/src/comms/USB/IUSB.h b/src/comms/USB/IUSB.h index 885f70faa..5c43da671 100644 --- a/src/comms/USB/IUSB.h +++ b/src/comms/USB/IUSB.h @@ -40,7 +40,7 @@ class IUSB @param serial The serial number of the device. @return The status of the operation (true on success). */ - virtual bool Connect(uint16_t vid, uint16_t pid, const char* serial = nullptr) = 0; + virtual bool Connect(uint16_t vid, uint16_t pid, const std::string& serial = "") = 0; /** @brief Returns whether this instance is connected to a device. diff --git a/src/comms/USB/USBGeneric.cpp b/src/comms/USB/USBGeneric.cpp index 4bb2898e7..4e2845f65 100644 --- a/src/comms/USB/USBGeneric.cpp +++ b/src/comms/USB/USBGeneric.cpp @@ -219,7 +219,7 @@ USBGeneric::~USBGeneric() SessionRefCountDecrement(); } -bool USBGeneric::Connect(uint16_t vid, uint16_t pid, const char* serial) +bool USBGeneric::Connect(uint16_t vid, uint16_t pid, const std::string& serial) { libusb_device** devs; // Pointer to pointer of device, used to retrieve a list of devices int usbDeviceCount = libusb_get_device_list(gContextLibUsb, &devs); @@ -271,7 +271,7 @@ bool USBGeneric::Connect(uint16_t vid, uint16_t pid, const char* serial) foundSerial = std::string(data, static_cast(stringLength)); } - if (std::string{ serial }.empty() || std::string{ serial } == foundSerial) + if (serial.empty() || serial == foundSerial) { libusb_hotplug_register_callback(gContextLibUsb, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, diff --git a/src/comms/USB/USBGeneric.h b/src/comms/USB/USBGeneric.h index 0f067fdab..ace1101dc 100644 --- a/src/comms/USB/USBGeneric.h +++ b/src/comms/USB/USBGeneric.h @@ -43,7 +43,7 @@ class USBGeneric : IUSB virtual ~USBGeneric(); static constexpr int32_t defaultTimeout = 1000; ///< The default timeout to use if none is specified. - bool Connect(uint16_t vid, uint16_t pid, const char* serial) override; + bool Connect(uint16_t vid, uint16_t pid, const std::string& serial) override; bool IsConnected() override; void Disconnect() override; From 74624f010a9941d4d706157d6702d59a2ab47488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominykas=20Petkevi=C4=8Dius?= Date: Thu, 20 Jun 2024 09:22:08 +0300 Subject: [PATCH 13/17] FX3: connect to the specified device, not the first one in the list --- src/comms/USB/FX3/FX3.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/comms/USB/FX3/FX3.cpp b/src/comms/USB/FX3/FX3.cpp index 5ed155de5..5e1d5cb96 100644 --- a/src/comms/USB/FX3/FX3.cpp +++ b/src/comms/USB/FX3/FX3.cpp @@ -111,8 +111,25 @@ bool FX3::Connect(uint16_t vid, uint16_t pid, const std::string& serial) if (fx3device->DeviceCount() == 0) return false; - if (fx3device->Open(0) == false) + for (UCHAR i = 0; i < fx3device->DeviceCount(); ++i) + { + if (fx3device->Open(i) == false) + continue; + + if (fx3device->VendorID == vid && fx3device->ProductID == pid && + (serial.empty() || + std::string{ std::wstring_convert>().to_bytes(fx3device->SerialNumber) } == serial)) + { + break; + } + + fx3device->Close(); + } + + if (!fx3device->IsOpen()) + { return false; + } for (int i = 0; i < fx3device->EndPointCount(); ++i) { From 3bf0c957660d3461e368e722e7277006818094e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominykas=20Petkevi=C4=8Dius?= Date: Thu, 20 Jun 2024 09:26:16 +0300 Subject: [PATCH 14/17] IUSB: correct the `<` operator as MSVC's STL was complaining it was written incorrectly --- src/comms/USB/IUSB.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/comms/USB/IUSB.h b/src/comms/USB/IUSB.h index 5c43da671..972e35051 100644 --- a/src/comms/USB/IUSB.h +++ b/src/comms/USB/IUSB.h @@ -23,8 +23,16 @@ class IUSB struct VendorProductId { uint16_t vendorId; uint16_t productId; - bool operator<(const VendorProductId& rhs) const { return vendorId < rhs.vendorId || productId < rhs.productId; } + bool operator<(const VendorProductId& rhs) const + { + if (vendorId == rhs.vendorId) + { + return productId < rhs.productId; + } + return vendorId < rhs.vendorId; + } }; + /** * @brief Returns list of detected devices descriptors used for connecting to device. * @param ids Set of vendor and product IDs to search for From bfaa56be2164256401e87b24f980ccd9c2f2b58e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominykas=20Petkevi=C4=8Dius?= Date: Thu, 20 Jun 2024 09:32:06 +0300 Subject: [PATCH 15/17] FX3: make header documentation a touch nicer --- src/comms/USB/FX3/FX3.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/comms/USB/FX3/FX3.h b/src/comms/USB/FX3/FX3.h index 843bfa8a1..352da3374 100644 --- a/src/comms/USB/FX3/FX3.h +++ b/src/comms/USB/FX3/FX3.h @@ -43,10 +43,11 @@ class FX3 : public IUSB static const int CTR_WRITE_REQUEST_VALUE; static const int CTR_READ_REQUEST_VALUE; - static constexpr uint8_t CONTROL_BULK_OUT_ADDRESS = - 0x0F; ///< The memory address for writing information via the bulk transfer protocol. - static constexpr uint8_t CONTROL_BULK_IN_ADDRESS = - 0x8F; ///< THe memory address for reading information via the bulk transfer protocol. + /// The memory address for writing information via the bulk transfer protocol. + static constexpr uint8_t CONTROL_BULK_OUT_ADDRESS = 0x0F; + /// The memory address for reading information via the bulk transfer protocol. + static constexpr uint8_t CONTROL_BULK_IN_ADDRESS = 0x8F; + protected: #ifdef __unix__ USBGeneric libusb_impl; From fe03b02826333ad4d8f9a8fed91f0185b2179e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominykas=20Petkevi=C4=8Dius?= Date: Thu, 20 Jun 2024 13:52:27 +0300 Subject: [PATCH 16/17] Add device disconnect callback on Windows --- src/CommonFunctions.h | 8 +- src/comms/USB/CMakeLists.txt | 4 +- src/comms/USB/FT601/FT601.cpp | 10 ++- src/comms/USB/FT601/FT601.h | 3 + src/comms/USB/FX3/FX3.cpp | 14 +++- src/comms/USB/FX3/FX3.h | 7 +- src/comms/USB/WindowsHotplug.cpp | 140 +++++++++++++++++++++++++++++++ src/comms/USB/WindowsHotplug.h | 34 ++++++++ 8 files changed, 213 insertions(+), 7 deletions(-) create mode 100644 src/comms/USB/WindowsHotplug.cpp create mode 100644 src/comms/USB/WindowsHotplug.h diff --git a/src/CommonFunctions.h b/src/CommonFunctions.h index 3210fc55e..a11c324bf 100644 --- a/src/CommonFunctions.h +++ b/src/CommonFunctions.h @@ -10,9 +10,15 @@ namespace lime { const std::string strFormat(const char* format, ...); -template std::string intToHex(T i) +template std::string intToHex(T i, bool uppercase = false) { std::stringstream stream; + + if (uppercase) + { + stream << std::uppercase; + } + stream << std::setfill('0') << std::setw(sizeof(T) * 2) << std::hex << i; return stream.str(); } diff --git a/src/comms/USB/CMakeLists.txt b/src/comms/USB/CMakeLists.txt index dfac03cb2..71f16e05f 100644 --- a/src/comms/USB/CMakeLists.txt +++ b/src/comms/USB/CMakeLists.txt @@ -19,9 +19,11 @@ set(COMMS_USB_SOURCES ######################################################################## ## Add to library ######################################################################## -target_include_directories(${MAIN_LIBRARY_NAME} PRIVATE ${THIS_SOURCE_DIR}) target_sources(${MAIN_LIBRARY_NAME} PRIVATE ${COMMS_USB_SOURCES}) if(UNIX) target_sources(${MAIN_LIBRARY_NAME} PRIVATE ${THIS_SOURCE_DIR}/USBGeneric.cpp) +else() + target_sources(${MAIN_LIBRARY_NAME} PRIVATE ${THIS_SOURCE_DIR}/WindowsHotplug.cpp) + target_link_options(${MAIN_LIBRARY_NAME} PUBLIC "cfgmgr32.lib") endif() diff --git a/src/comms/USB/FT601/FT601.cpp b/src/comms/USB/FT601/FT601.cpp index 75ca9d5ac..cb08c0267 100644 --- a/src/comms/USB/FT601/FT601.cpp +++ b/src/comms/USB/FT601/FT601.cpp @@ -110,6 +110,14 @@ bool FT601::Connect(uint16_t vid, uint16_t pid, const std::string& serial) FT_SetPipeTimeout(mFTHandle, CONTROL_BULK_READ_ADDRESS, 500); FT_SetPipeTimeout(mFTHandle, STREAM_BULK_READ_ADDRESS, 100); FT_SetPipeTimeout(mFTHandle, STREAM_BULK_WRITE_ADDRESS, 100); + + hotplug.AddDeviceToReceiveHotplugDisconnectEvents(vid, pid, serial); + hotplug.AddOnHotplugDisconnectCallback( + [](void* data) { + auto* ft601 = reinterpret_cast(data); + ft601->Disconnect(); + }, + this); return true; #endif } @@ -378,7 +386,7 @@ void FT601::AddOnHotplugDisconnectCallback(const IUSB::HotplugDisconnectCallback #ifdef __unix__ libusb_impl.AddOnHotplugDisconnectCallback(function, userData); #else - // Hotplug events are not supported by the library + hotplug.AddOnHotplugDisconnectCallback(function, userData); #endif } diff --git a/src/comms/USB/FT601/FT601.h b/src/comms/USB/FT601/FT601.h index 8b38f31d0..f1e8ac9d6 100644 --- a/src/comms/USB/FT601/FT601.h +++ b/src/comms/USB/FT601/FT601.h @@ -6,6 +6,7 @@ #include "comms/USB/USBGeneric.h" #else #include "FTD3XXLibrary/FTD3XX.h" + #include "comms/USB/WindowsHotplug.h" #endif namespace lime { @@ -52,6 +53,8 @@ class FT601 : public IUSB #else FT_HANDLE mFTHandle; int ReinitPipe(unsigned char ep); + + WindowsHotplug hotplug{}; #endif }; diff --git a/src/comms/USB/FX3/FX3.cpp b/src/comms/USB/FX3/FX3.cpp index 5e1d5cb96..b0562cff8 100644 --- a/src/comms/USB/FX3/FX3.cpp +++ b/src/comms/USB/FX3/FX3.cpp @@ -14,9 +14,10 @@ using namespace std::literals::string_literals; #pragma GCC diagnostic pop #endif #else - #include "windows.h" + #include "Windows.h" #include "CyAPI.h" #include + #include "comms/USB/WindowsHotplug.h" #endif namespace lime { @@ -138,6 +139,14 @@ bool FX3::Connect(uint16_t vid, uint16_t pid, const std::string& serial) ep->SetXferSize(len); endpoints[ep->Address] = ep; } + + hotplug.AddDeviceToReceiveHotplugDisconnectEvents(vid, pid, serial); + hotplug.AddOnHotplugDisconnectCallback( + [](void* data) { + auto* fx3 = reinterpret_cast(data); + fx3->Disconnect(); + }, + this); #endif return true; } @@ -277,8 +286,7 @@ void FX3::AddOnHotplugDisconnectCallback(const IUSB::HotplugDisconnectCallbackTy #ifdef __unix__ libusb_impl.AddOnHotplugDisconnectCallback(function, userData); #else - // TODO: figure out how to pass something to CCyUSBDevice constructor's first parameter - // that would be able to collect the Windows Plug and Play events that the library would send + hotplug.AddOnHotplugDisconnectCallback(function, userData); #endif } diff --git a/src/comms/USB/FX3/FX3.h b/src/comms/USB/FX3/FX3.h index 352da3374..812063aa2 100644 --- a/src/comms/USB/FX3/FX3.h +++ b/src/comms/USB/FX3/FX3.h @@ -7,11 +7,14 @@ #ifdef __unix__ #include "comms/USB/USBGeneric.h" -#endif // !__unix__ +#else + #include "comms/USB/WindowsHotplug.h" class CCyFX3Device; class CCyUSBEndPoint; +#endif // !__unix__ + namespace lime { /// @brief A class for communicating with devices using the Cypress USB 3.0 CYUSB3014-BZXC USB controller. @@ -57,6 +60,8 @@ class FX3 : public IUSB //end points for samples reading and writing std::map endpoints{}; + + WindowsHotplug hotplug{}; #endif }; diff --git a/src/comms/USB/WindowsHotplug.cpp b/src/comms/USB/WindowsHotplug.cpp new file mode 100644 index 000000000..26ac37959 --- /dev/null +++ b/src/comms/USB/WindowsHotplug.cpp @@ -0,0 +1,140 @@ +#include "WindowsHotplug.h" + +#include +#include + +#include "CommonFunctions.h" +#include "IUSB.h" + +#include +#include +#include +#include +#include +#include + +using namespace std::literals::string_literals; +using namespace std::literals::string_view_literals; + +namespace lime { + +namespace { + +template std::vector SplitString(strView string, strView delimiter) +{ + std::vector ret; + + auto position{ string.find(delimiter) }; + + while (position != strView::npos) + { + if (position != 0) + { + ret.push_back(string.substr(0, position)); + } + + string = string.substr(position + delimiter.size()); + position = string.find(delimiter); + } + + if (string.size() > 0) + { + ret.push_back(string); + } + return ret; +} + +std::string_view GetSpecificDeviceIDFromDeviceIDListBySerial(const std::vector& list, const std::string& serial) +{ + for (const auto& deviceID : list) + { + if (deviceID.find(serial) != std::string_view::npos) + { + return deviceID; + } + } + + throw std::runtime_error("Serial not found"s); +} + +std::string GetDeviceID(uint16_t vid, uint16_t pid, const std::string& serial) +{ + ULONG bufferSize = 0; + const std::string filter = "USB\\VID_"s + intToHex(vid, true) + "&PID_"s + intToHex(pid, true); + const ULONG flags = CM_GETIDLIST_FILTER_ENUMERATOR; + + CONFIGRET status = CM_Get_Device_ID_List_Size(&bufferSize, filter.c_str(), flags); + if (status == CR_NO_SUCH_VALUE) // no device like that exists, return + { + return ""s; + } + else if (status != CR_SUCCESS) + { + throw std::runtime_error("CM_Get_Device_ID_List_Size failed"s); + } + + const PZZSTR buffer = new CHAR[bufferSize]; + + status = CM_Get_Device_ID_List(filter.c_str(), buffer, bufferSize, flags); + if (status != CR_SUCCESS) + { + throw std::runtime_error("CM_Get_Device_ID_List failed"s); + } + + const std::string_view allDeviceIDs{ buffer, bufferSize }; + const auto& allDeviceIDsSplits = SplitString(allDeviceIDs, "\0"sv); + + const auto deviceID = std::string{ GetSpecificDeviceIDFromDeviceIDListBySerial(allDeviceIDsSplits, serial) }; + + delete[] buffer; + return deviceID; +} + +} // namespace + +WindowsHotplug ::~WindowsHotplug() +{ + CM_Unregister_Notification(deviceDisconnectCallbackHandle); +} + +void WindowsHotplug::AddOnHotplugDisconnectCallback(const IUSB::HotplugDisconnectCallbackType& function, void* userData) +{ + hotplugDisconnectCallbacks.push_back({ function, userData }); +} + +void WindowsHotplug::AddDeviceToReceiveHotplugDisconnectEvents(uint16_t vid, uint16_t pid, const std::string& serial) +{ + const auto deviceID = GetDeviceID(vid, pid, serial); + const auto wideDeviceID = std::wstring_convert>().from_bytes(deviceID); + + CM_NOTIFY_FILTER filter{}; + filter.cbSize = sizeof(filter); + filter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE; + std::wcsncpy(filter.u.DeviceInstance.InstanceId, + wideDeviceID.c_str(), + std::min(sizeof(filter.u.DeviceInstance.InstanceId), wideDeviceID.size())); + + auto returnValue = CM_Register_Notification(&filter, this, callback, &deviceDisconnectCallbackHandle); + if (returnValue != CR_SUCCESS) + { + throw std::runtime_error("CM_Register_Notification failed with error code "s + intToHex(returnValue)); + } +} + +DWORD WindowsHotplug::callback( + HCMNOTIFICATION hNotify, PVOID Context, CM_NOTIFY_ACTION Action, PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize) +{ + if (CM_NOTIFY_ACTION_DEVICEINSTANCEREMOVED == Action) + { + auto* hotplug = reinterpret_cast(Context); + + for (auto iter = hotplug->hotplugDisconnectCallbacks.rbegin(); iter != hotplug->hotplugDisconnectCallbacks.rend(); ++iter) + { + (*iter)(); + } + } + + return ERROR_SUCCESS; +} + +} // namespace lime diff --git a/src/comms/USB/WindowsHotplug.h b/src/comms/USB/WindowsHotplug.h new file mode 100644 index 000000000..a10a8f116 --- /dev/null +++ b/src/comms/USB/WindowsHotplug.h @@ -0,0 +1,34 @@ +#ifndef LIME_WINDOWS_HOTPLUG_H +#define LIME_WINDOWS_HOTPLUG_H + +#include "Windows.h" +#include "cfgmgr32.h" + +#include "comms/USB/IUSB.h" + +#include +#include +#include + +namespace lime { + +class WindowsHotplug +{ + public: + ~WindowsHotplug(); + + void AddOnHotplugDisconnectCallback(const IUSB::HotplugDisconnectCallbackType& function, void* userData); + + void AddDeviceToReceiveHotplugDisconnectEvents(uint16_t vid, uint16_t pid, const std::string& serial); + + private: + std::vector> hotplugDisconnectCallbacks{}; + HCMNOTIFICATION deviceDisconnectCallbackHandle{}; + + static DWORD callback( + HCMNOTIFICATION hNotify, PVOID Context, CM_NOTIFY_ACTION Action, PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize); +}; + +} // namespace lime + +#endif // LIME_WINDOWS_HOTPLUG_H From c00de83243873ace1e3783499036daae4fa180f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominykas=20Petkevi=C4=8Dius?= Date: Thu, 20 Jun 2024 14:09:48 +0300 Subject: [PATCH 17/17] Fix VS2017 and VS2019 compilation --- src/comms/USB/WindowsHotplug.cpp | 2 +- src/comms/USB/WindowsHotplug.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/comms/USB/WindowsHotplug.cpp b/src/comms/USB/WindowsHotplug.cpp index 26ac37959..da16a16ae 100644 --- a/src/comms/USB/WindowsHotplug.cpp +++ b/src/comms/USB/WindowsHotplug.cpp @@ -121,7 +121,7 @@ void WindowsHotplug::AddDeviceToReceiveHotplugDisconnectEvents(uint16_t vid, uin } } -DWORD WindowsHotplug::callback( +DWORD CALLBACK WindowsHotplug::callback( HCMNOTIFICATION hNotify, PVOID Context, CM_NOTIFY_ACTION Action, PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize) { if (CM_NOTIFY_ACTION_DEVICEINSTANCEREMOVED == Action) diff --git a/src/comms/USB/WindowsHotplug.h b/src/comms/USB/WindowsHotplug.h index a10a8f116..2a022f0d6 100644 --- a/src/comms/USB/WindowsHotplug.h +++ b/src/comms/USB/WindowsHotplug.h @@ -25,7 +25,7 @@ class WindowsHotplug std::vector> hotplugDisconnectCallbacks{}; HCMNOTIFICATION deviceDisconnectCallbackHandle{}; - static DWORD callback( + static DWORD CALLBACK callback( HCMNOTIFICATION hNotify, PVOID Context, CM_NOTIFY_ACTION Action, PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize); };