diff --git a/GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp b/GUI/fftviewer_wxgui/fftviewer_frFFTviewer.cpp index ca927fa3..1dedea89 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,9 +464,16 @@ void fftviewer_frFFTviewer::StreamingLoop( const lime::complex32f_t* src[2] = { txPattern[0].data(), txPattern[1].data() };*/ + std::optional callbackId{ std::nullopt }; try { 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) { @@ -646,6 +654,10 @@ void fftviewer_frFFTviewer::StreamingLoop( }*/ kiss_fft_free(m_fftCalcPlan); + if (callbackId) + { + pthis->device->RemoveHotplugDisconnectCallback(callbackId.value()); + } pthis->stopProcessing.store(true); pthis->device->StreamStop(chipIndex); pthis->device->StreamDestroy(chipIndex); diff --git a/GUI/limeGUIFrame.cpp b/GUI/limeGUIFrame.cpp index 38d34a86..2935eee0 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" @@ -34,6 +32,9 @@ #include "limesuiteng/SDRDescriptor.h" #include "DeviceTreeNode.h" #include "limesuiteng/Logger.h" +#include "DeviceConnectionPanel.h" + +#include 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) @@ -399,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/GUI/limeGUIFrame.h b/GUI/limeGUIFrame.h index 9e357a9c..00a53a96 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); diff --git a/embedded/lms7002m/privates.c b/embedded/lms7002m/privates.c index 8460c24a..8796b85c 100644 --- a/embedded/lms7002m/privates.c +++ b/embedded/lms7002m/privates.c @@ -69,7 +69,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); } diff --git a/src/boards/LMS7002M_SDRDevice.cpp b/src/boards/LMS7002M_SDRDevice.cpp index fccc1df8..628ee61a 100644 --- a/src/boards/LMS7002M_SDRDevice.cpp +++ b/src/boards/LMS7002M_SDRDevice.cpp @@ -1194,4 +1194,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 eef780ed..0ee0efd3 100644 --- a/src/boards/LMS7002M_SDRDevice.h +++ b/src/boards/LMS7002M_SDRDevice.h @@ -128,6 +128,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 RFSOCDescriptor GetDefaultLMS7002MDescriptor(); static OpStatus UpdateFPGAInterfaceFrequency(LMS7002M& soc, FPGA& fpga, uint8_t chipIndex); diff --git a/src/boards/LimeSDR/LimeSDR.cpp b/src/boards/LimeSDR/LimeSDR.cpp index 3757a794..23b0ba15 100644 --- a/src/boards/LimeSDR/LimeSDR.cpp +++ b/src/boards/LimeSDR/LimeSDR.cpp @@ -22,11 +22,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; @@ -144,6 +145,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) { @@ -539,3 +552,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 78384186..7f2d3212 100644 --- a/src/boards/LimeSDR/LimeSDR.h +++ b/src/boards/LimeSDR/LimeSDR.h @@ -49,6 +49,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(); @@ -70,6 +73,9 @@ class LimeSDR : public LMS7002M_SDRDevice std::shared_ptr mlms7002mPort; std::shared_ptr mfpgaPort; 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 4199fc4d..e25aa076 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 uint8_t SPI_LMS7002M = 0; static const uint8_t SPI_FPGA = 1; @@ -198,6 +199,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() @@ -597,3 +610,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 04207045..77c71f79 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; @@ -49,6 +48,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); @@ -59,6 +61,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/MMX8/MM_X8.cpp b/src/boards/MMX8/MM_X8.cpp index 7df1cd5f..9eaf1da7 100644 --- a/src/boards/MMX8/MM_X8.cpp +++ b/src/boards/MMX8/MM_X8.cpp @@ -836,4 +836,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 b7fac292..f3edb0dc 100644 --- a/src/boards/MMX8/MM_X8.h +++ b/src/boards/MMX8/MM_X8.h @@ -150,6 +150,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/cli/limeTRX.cpp b/src/cli/limeTRX.cpp index 980b71df..d8e743c3 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/FT601/FT601.cpp b/src/comms/USB/FT601/FT601.cpp index 8f68df78..f70a4dcb 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 + // Hotplug events are not supported by the library +#endif +} + } // namespace lime diff --git a/src/comms/USB/FT601/FT601.h b/src/comms/USB/FT601/FT601.h index 50ab8657..662988f8 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 10b08f81..8dbcdafc 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,15 @@ 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: 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 +} + +} // namespace lime diff --git a/src/comms/USB/FX3/FX3.h b/src/comms/USB/FX3/FX3.h index bc4197b7..ed633559 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 b7dbf15f..885f70fa 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,15 @@ 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; + + void operator()() { return function(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 bf44510a..4bb2898e 100644 --- a/src/comms/USB/USBGeneric.cpp +++ b/src/comms/USB/USBGeneric.cpp @@ -110,6 +110,20 @@ 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 (auto iter = usb->hotplugDisconnectCallbacks.rbegin(); iter != usb->hotplugDisconnectCallbacks.rend(); ++iter) + { + (*iter)(); + } + + usb->Disconnect(); + return 1; +} + USBGeneric::AsyncContext::AsyncContext() : transfer(libusb_alloc_transfer(0)) , bytesXfered(0) @@ -258,7 +272,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; @@ -340,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) { @@ -409,4 +440,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 90a1f988..0f067fda 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/examples/basicRX.cpp b/src/examples/basicRX.cpp index f55f6dec..e9718822 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 213776bd..a96a1ecd 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 71efe7f7..b6517e8c 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/include/limesuiteng/SDRDevice.h b/src/include/limesuiteng/SDRDevice.h index d109b708..5a17f9d3 100644 --- a/src/include/limesuiteng/SDRDevice.h +++ b/src/include/limesuiteng/SDRDevice.h @@ -577,6 +577,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 diff --git a/src/protocols/TRXLooper.cpp b/src/protocols/TRXLooper.cpp index 1014136e..8ef003cf 100644 --- a/src/protocols/TRXLooper.cpp +++ b/src/protocols/TRXLooper.cpp @@ -1038,7 +1038,14 @@ void TRXLooper::TxTeardown() uint32_t fpgaTxPktIngressCount; uint32_t fpgaTxPktDropCounter; - fpga->ReadTxPacketCounters(chipId, &fpgaTxPktIngressCount, &fpgaTxPktDropCounter); + try + { + fpga->ReadTxPacketCounters(chipId, &fpgaTxPktIngressCount, &fpgaTxPktDropCounter); + } catch (const std::exception& e) + { + lime::error(e.what()); + } + if (mCallback_logMessage) { char msg[512];