diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 7416afbc..af670e9e 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -74,7 +74,6 @@ else() target_link_libraries(sdrpp_core PUBLIC dl) endif (MSVC) -target_link_libraries(sdrpp_core PUBLIC SoapySDR) target_link_libraries(sdrpp_core PUBLIC volk) set(CORE_FILES ${RUNTIME_OUTPUT_DIRECTORY} PARENT_SCOPE) diff --git a/core/src/core.cpp b/core/src/core.cpp index fe20dcb5..37815b36 100644 --- a/core/src/core.cpp +++ b/core/src/core.cpp @@ -26,6 +26,12 @@ namespace core { ConfigManager configManager; + + void setInputSampleRate(double samplerate) { + // NOTE: Zoom controls won't work + gui::waterfall.setBandwidth(samplerate); + sigpath::signalPath.setSampleRate(samplerate); + } }; bool maximized = false; diff --git a/core/src/core.h b/core/src/core.h index 14983520..c3e065f0 100644 --- a/core/src/core.h +++ b/core/src/core.h @@ -4,6 +4,8 @@ namespace core { SDRPP_EXPORT ConfigManager configManager; + + void setInputSampleRate(double samplerate); }; int sdrpp_main(); \ No newline at end of file diff --git a/core/src/module.cpp b/core/src/module.cpp index 3251ad2a..8417473a 100644 --- a/core/src/module.cpp +++ b/core/src/module.cpp @@ -28,7 +28,7 @@ namespace mod { mod._INIT_ = (void(*)())GetProcAddress(mod.inst, "_INIT_"); mod._CREATE_INSTANCE_ = (void*(*)(std::string))GetProcAddress(mod.inst, "_CREATE_INSTANCE_"); mod._DELETE_INSTANCE_ = (void(*)(void*))GetProcAddress(mod.inst, "_DELETE_INSTANCE_"); - mod._STOP_ = (void(*)(void*))GetProcAddress(mod.inst, "_STOP_"); + mod._STOP_ = (void(*)())GetProcAddress(mod.inst, "_STOP_"); #else mod.inst = dlopen(path.c_str(), RTLD_LAZY); if (mod.inst == NULL) { diff --git a/root_dev/config.json b/root_dev/config.json index 2f180be9..57340ef6 100644 --- a/root_dev/config.json +++ b/root_dev/config.json @@ -1,21 +1,5 @@ { - "audio": { - "Radio": { - "device": "Speakers (Realtek High Definiti", - "sampleRate": 48000.0, - "volume": 0.602150559425354 - }, - "Radio 1": { - "device": "Speakers (Realtek High Definiti", - "sampleRate": 48000.0, - "volume": 0.4185185134410858 - }, - "Radio 2": { - "device": "Speakers (Realtek High Definiti", - "sampleRate": 48000.0, - "volume": 0.0 - } - }, + "audio": {}, "bandPlan": "General", "bandPlanEnabled": true, "fftHeight": 300, @@ -25,28 +9,10 @@ "menuWidth": 300, "min": -51.47058868408203, "showWaterfall": true, - "source": "Generic RTL2832U OEM :: 00000001", - "sourceSettings": { - "Generic RTL2832U OEM :: 00000001": { - "gains": { - "TUNER": 11.625 - }, - "sampleRate": 2560000 - }, - "HackRF One #0 901868dc282c8f8b": { - "gains": { - "AMP": 0.0, - "LNA": 24.503000259399414, - "VGA": 16.229999542236328 - }, - "sampleRate": 8000000 - }, - "PulseAudio": { - "sampleRate": 96000 - } - }, + "source": "", + "sourceSettings": {}, "windowSize": { - "h": 1053, - "w": 959 + "h": 720, + "w": 1280 } } \ No newline at end of file diff --git a/root_dev/module_list.json b/root_dev/module_list.json index fff6c734..b83e4c69 100644 --- a/root_dev/module_list.json +++ b/root_dev/module_list.json @@ -1,6 +1,6 @@ { - "Radio": "./radio/radio.so", - "Recorder": "./recorder/recorder.so", - "Soapy": "./soapy/soapy.so", - "FileSource": "./file_source/file_source.so" + "Radio": "./radio/Release/radio.dll", + "Recorder": "./recorder/Release/recorder.dll", + "Soapy": "./soapy/Release/soapy.dll", + "FileSource": "./file_source/Release/file_source.dll" } \ No newline at end of file diff --git a/soapy/CMakeLists.txt b/soapy/CMakeLists.txt index 7e4fcbfa..a5c0e444 100644 --- a/soapy/CMakeLists.txt +++ b/soapy/CMakeLists.txt @@ -3,6 +3,12 @@ project(soapy) if (MSVC) set(CMAKE_CXX_FLAGS "-O2 /std:c++17") + + # Lib path + target_link_directories(sdrpp_core PUBLIC "C:/Program Files/PothosSDR/lib/") + + # Misc headers + target_include_directories(sdrpp_core PUBLIC "C:/Program Files/PothosSDR/include/") else() set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") endif (MSVC) @@ -11,4 +17,6 @@ file(GLOB SRC "src/*.cpp") add_library(soapy SHARED ${SRC}) target_link_libraries(soapy PRIVATE sdrpp_core) -set_target_properties(soapy PROPERTIES PREFIX "") \ No newline at end of file +set_target_properties(soapy PROPERTIES PREFIX "") + +target_link_libraries(soapy PUBLIC SoapySDR) \ No newline at end of file diff --git a/soapy/src/main.cpp b/soapy/src/main.cpp index 6a19bab9..ae6be718 100644 --- a/soapy/src/main.cpp +++ b/soapy/src/main.cpp @@ -3,6 +3,10 @@ #include #include #include +#include +#include +#include +#include #define CONCAT(a, b) ((std::string(a) + b).c_str()) @@ -20,6 +24,13 @@ public: //TODO: Make module tune on source select change (in sdrpp_core) + devList = SoapySDR::Device::enumerate(); + txtDevList = ""; + for (auto& dev : devList) { + txtDevList += dev["label"]; + txtDevList += '\0'; + } + stream.init(100); handler.ctx = this; @@ -32,6 +43,9 @@ public: handler.stream = &stream; sigpath::sourceManager.registerSource("SoapySDR", &handler); spdlog::info("SoapyModule '{0}': Instance created!", name); + + // Select default device + selectDevice(devList[0]["label"]); } ~SoapyModule() { @@ -39,9 +53,69 @@ public: } private: + void selectSampleRate(double samplerate) { + if (sampleRates.size() == 0) { + devId = -1; + return; + } + bool found = false; + int i = 0; + for (auto& sr : sampleRates) { + if (sr == samplerate) { + srId = i; + sampleRate = sr; + found = true; + break; + } + i++; + } + if (!found) { + // Select default sample rate + selectSampleRate(sampleRates[0]); + } + } + + void selectDevice(std::string name) { + if (devList.size() == 0) { + devId = -1; + return; + } + bool found = false; + int i = 0; + for (auto& args : devList) { + if (args["label"] == name) { + devArgs = args; + devId = i; + found = true; + break; + } + i++; + } + if (!found) { + // If device was not found, select default device instead + selectDevice(devList[0]["label"]); + return; + } + + SoapySDR::Device* dev = SoapySDR::Device::make(devArgs); + sampleRates = dev->listSampleRates(SOAPY_SDR_RX, 0); + txtSrList = ""; + for (double sr : sampleRates) { + txtSrList += std::to_string((int)sr); + txtSrList += '\0'; + } + SoapySDR::Device::unmake(dev); + selectSampleRate(sampleRates[0]); + + } + static void menuSelected(void* ctx) { SoapyModule* _this = (SoapyModule*)ctx; spdlog::info("SoapyModule '{0}': Menu Select!", _this->name); + if (_this->devList.size() == 0) { + return; + } + core::setInputSampleRate(_this->sampleRate); } static void menuDeselected(void* ctx) { @@ -51,28 +125,84 @@ private: static void start(void* ctx) { SoapyModule* _this = (SoapyModule*)ctx; + _this->dev = SoapySDR::Device::make(_this->devArgs); + _this->dev->setSampleRate(SOAPY_SDR_RX, 0, _this->sampleRate); + _this->devStream = _this->dev->setupStream(SOAPY_SDR_RX, "CF32"); + _this->dev->activateStream(_this->devStream); + _this->running = true; + _this->workerThread = std::thread(_worker, _this); spdlog::info("SoapyModule '{0}': Start!", _this->name); } static void stop(void* ctx) { SoapyModule* _this = (SoapyModule*)ctx; + _this->running = false; spdlog::info("SoapyModule '{0}': Stop!", _this->name); } static void tune(double freq, void* ctx) { SoapyModule* _this = (SoapyModule*)ctx; + _this->freq = freq; + if (_this->running) { + _this->dev->setFrequency(SOAPY_SDR_RX, 0, freq); + } spdlog::info("SoapyModule '{0}': Tune: {1}!", _this->name, freq); } static void menuHandler(void* ctx) { SoapyModule* _this = (SoapyModule*)ctx; - ImGui::Text("Hi from %s!", _this->name.c_str()); + + // If no device is available, do not attempt to display menu + if (_this->devId < 0) { + return; + } + + float menuWidth = ImGui::GetContentRegionAvailWidth(); + ImGui::SetNextItemWidth(menuWidth); + if (ImGui::Combo(CONCAT("##_dev_select_", _this->name), &_this->devId, _this->txtDevList.c_str())) { + _this->selectDevice(_this->devList[_this->devId]["label"]); + } + ImGui::SetNextItemWidth(menuWidth); + if (ImGui::Combo(CONCAT("##_sr_select_", _this->name), &_this->srId, _this->txtSrList.c_str())) { + _this->selectSampleRate(_this->sampleRates[_this->srId]); + core::setInputSampleRate(_this->sampleRate); + } + } + + static void _worker(SoapyModule* _this) { + spdlog::info("SOAPY: WORKER STARTED {0}", _this->sampleRate); + int blockSize = _this->sampleRate / 200.0f; + dsp::complex_t* buf = new dsp::complex_t[blockSize]; + int flags = 0; + long long timeMs = 0; + + while (_this->running) { + int res = _this->dev->readStream(_this->devStream, (void**)&buf, blockSize, flags, timeMs); + if (res < 1) { + continue; + } + _this->stream.write(buf, res); + } + delete[] buf; } std::string name; dsp::stream stream; + SoapySDR::Stream* devStream; SourceManager::SourceHandler handler; + SoapySDR::KwargsList devList; + SoapySDR::Kwargs devArgs; + SoapySDR::Device* dev; + std::string txtDevList; + std::string txtSrList; + std::thread workerThread; + int devId = -1; + double freq; + double sampleRate; + bool running = false; + std::vector sampleRates; + int srId = -1; }; MOD_EXPORT void _INIT_() {