From 9cac95fd8269fda25df0cc74005eedf9a4e759ca Mon Sep 17 00:00:00 2001 From: Ryzerth Date: Sat, 26 Dec 2020 00:42:15 +0100 Subject: [PATCH] push before merge --- .github/workflows/cmake.yml | 2 +- CMakeLists.txt | 5 + airspyhf_source/src/main.cpp | 2 - audio_sink/src/main.cpp | 6 +- core/src/core.cpp | 1 + core/src/signal_path/sink.h | 1 + hackrf_source/CMakeLists.txt | 31 ++++ hackrf_source/src/main.cpp | 275 +++++++++++++++++++++++++++++++++++ readme.md | 2 +- 9 files changed, 319 insertions(+), 6 deletions(-) create mode 100644 hackrf_source/CMakeLists.txt create mode 100644 hackrf_source/src/main.cpp diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 6c2eed8..307f54c 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v2 - name: Install dependencies - run: sudo apt install libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libiio-dev libad9361-dev portaudio19-dev + run: sudo apt install libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libiio-dev libad9361-dev portaudio19-dev libhackrf-dev - name: Create Build Environment # Some projects don't allow in-source building, so create a separate build directory diff --git a/CMakeLists.txt b/CMakeLists.txt index fb0596e..bb95d28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ option(OPT_BUILD_SPYSERVER_SOURCE "Build SpyServer Source Module (no dependencie option(OPT_BUILD_SOAPY_SOURCE "Build SoapySDR Source Module (Depedencies: soapysdr)" ON) option(OPT_BUILD_AIRSPYHF_SOURCE "Build Airspy HF+ Source Module (Depedencies: libairspyhf)" ON) option(OPT_BUILD_PLUTOSDR_SOURCE "Build PlutoSDR Source Module (Depedencies: libiio, libad9361)" ON) +option(OPT_BUILD_HACKRF_SOURCE "Build HackRF Source Module (Depedencies: libhackrf)" ON) option(OPT_BUILD_AUDIO_SINK "Build Audio Sink Module (Depedencies: portaudio)" ON) # Core of SDR++ @@ -36,6 +37,10 @@ if (OPT_BUILD_PLUTOSDR_SOURCE) add_subdirectory("plutosdr_source") endif (OPT_BUILD_PLUTOSDR_SOURCE) +if (OPT_BUILD_HACKRF_SOURCE) +add_subdirectory("hackrf_source") +endif (OPT_BUILD_HACKRF_SOURCE) + if (OPT_BUILD_AUDIO_SINK) add_subdirectory("audio_sink") endif (OPT_BUILD_AUDIO_SINK) diff --git a/airspyhf_source/src/main.cpp b/airspyhf_source/src/main.cpp index ddd4a8b..cd207ec 100644 --- a/airspyhf_source/src/main.cpp +++ b/airspyhf_source/src/main.cpp @@ -166,8 +166,6 @@ private: return; } - spdlog::warn("{0}", _this->sampleRateList[_this->srId]); - airspyhf_set_samplerate(_this->openDev, _this->sampleRateList[_this->srId]); airspyhf_set_freq(_this->openDev, _this->freq); airspyhf_set_hf_agc(_this->openDev, (_this->agcMode != 0)); diff --git a/audio_sink/src/main.cpp b/audio_sink/src/main.cpp index 5c748b1..962af1b 100644 --- a/audio_sink/src/main.cpp +++ b/audio_sink/src/main.cpp @@ -36,7 +36,6 @@ public: stereoRB.init(_stream->sinkOut); // Initialize PortAudio - Pa_Initialize(); devCount = Pa_GetDeviceCount(); devId = Pa_GetDefaultOutputDevice(); const PaDeviceInfo *deviceInfo; @@ -239,11 +238,14 @@ public: this->name = name; provider.create = create_sink; provider.ctx = this; + + Pa_Initialize(); + sigpath::sinkManager.registerSinkProvider("Audio", provider); } ~AudioSinkModule() { - + Pa_Terminate(); } void enable() { diff --git a/core/src/core.cpp b/core/src/core.cpp index 83a1da2..1c11f79 100644 --- a/core/src/core.cpp +++ b/core/src/core.cpp @@ -125,6 +125,7 @@ int sdrpp_main(int argc, char *argv[]) { defConfig["moduleInstances"]["PlutoSDR Source"] = "plutosdr_source"; defConfig["moduleInstances"]["RTL-TCP Source"] = "rtl_tcp_source"; defConfig["moduleInstances"]["AirspyHF+ Source"] = "airspyhf_source"; + defConfig["moduleInstances"]["HackRF Source"] = "hackrf_source"; defConfig["moduleInstances"]["Audio Sink"] = "audio_sink"; defConfig["modules"] = json::array(); diff --git a/core/src/signal_path/sink.h b/core/src/signal_path/sink.h index ca30355..1edabfc 100644 --- a/core/src/signal_path/sink.h +++ b/core/src/signal_path/sink.h @@ -16,6 +16,7 @@ public: class Sink { public: + virtual ~Sink() {} virtual void start() = 0; virtual void stop() = 0; virtual void menuHandler() = 0; diff --git a/hackrf_source/CMakeLists.txt b/hackrf_source/CMakeLists.txt new file mode 100644 index 0000000..2207f7e --- /dev/null +++ b/hackrf_source/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.13) +project(hackrf_source) + +if (MSVC) + set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc") +else() + set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") +endif (MSVC) + +include_directories("src/") + +file(GLOB SRC "src/*.cpp") + +add_library(hackrf_source SHARED ${SRC}) +target_link_libraries(hackrf_source PRIVATE sdrpp_core) +set_target_properties(hackrf_source PROPERTIES PREFIX "") + +if (MSVC) + # Lib path + target_link_directories(sdrpp_core PUBLIC "C:/Program Files/PothosSDR/bin/") + + target_link_libraries(hackrf_source PUBLIC hackrf) +else (MSVC) + find_package(PkgConfig) + + pkg_check_modules(LIBHACKRF REQUIRED libhackrf) + + target_include_directories(hackrf_source PUBLIC ${LIBHACKRF_INCLUDE_DIRS}) + target_link_directories(hackrf_source PUBLIC ${LIBHACKRF_LIBRARY_DIRS}) + target_link_libraries(hackrf_source PUBLIC ${LIBHACKRF_LIBRARIES}) +endif (MSVC) \ No newline at end of file diff --git a/hackrf_source/src/main.cpp b/hackrf_source/src/main.cpp new file mode 100644 index 0000000..8bd7bba --- /dev/null +++ b/hackrf_source/src/main.cpp @@ -0,0 +1,275 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CONCAT(a, b) ((std::string(a) + b).c_str()) + +SDRPP_MOD_INFO { + /* Name: */ "hackrf_source", + /* Description: */ "HackRF source module for SDR++", + /* Author: */ "Ryzerth", + /* Version: */ 0, 1, 0, + /* Max instances */ 1 +}; + +//ConfigManager config; + +const char* AGG_MODES_STR = "Off\0Low\0High\0"; + +const char* sampleRatesTxt = "20MHz\00016MHz\00010MHz\0008MHz\0005MHz\0004MHz\0002MHz\000"; + +const int sampleRates[] = { + 20000000, + 16000000, + 10000000, + 8000000, + 5000000, + 4000000, + 2000000, +}; + +class HackRFSourceModule : public ModuleManager::Instance { +public: + HackRFSourceModule(std::string name) { + this->name = name; + + hackrf_init(); + + sampleRate = 2000000; + + handler.ctx = this; + handler.selectHandler = menuSelected; + handler.deselectHandler = menuDeselected; + handler.menuHandler = menuHandler; + handler.startHandler = start; + handler.stopHandler = stop; + handler.tuneHandler = tune; + handler.stream = &stream; + + refresh(); + + selectFirst(); + + // config.aquire(); + // std::string serString = config.conf["device"]; + // config.release(); + + sigpath::sourceManager.registerSource("HackRF", &handler); + } + + ~HackRFSourceModule() { + hackrf_exit(); + } + + + void enable() { + enabled = true; + } + + void disable() { + enabled = false; + } + + bool isEnabled() { + return enabled; + } + + void refresh() { + devList.clear(); + devListTxt = ""; + + uint64_t serials[256]; + hackrf_device_list_t* _devList = hackrf_device_list(); + + for (int i = 0; i < _devList->devicecount; i++) { + devList.push_back(_devList->serial_numbers[i]); + devListTxt += _devList->serial_numbers[i]; + devListTxt += '\0'; + } + + hackrf_device_list_free(_devList); + } + + void selectFirst() { + if (devList.size() != 0) { + selectedSerial = devList[0]; + } + } + +private: + static void menuSelected(void* ctx) { + HackRFSourceModule* _this = (HackRFSourceModule*)ctx; + core::setInputSampleRate(_this->sampleRate); + spdlog::info("HackRFSourceModule '{0}': Menu Select!", _this->name); + } + + static void menuDeselected(void* ctx) { + HackRFSourceModule* _this = (HackRFSourceModule*)ctx; + spdlog::info("HackRFSourceModule '{0}': Menu Deselect!", _this->name); + } + + #pragma optimize( "", off ) + + static void start(void* ctx) { + HackRFSourceModule* _this = (HackRFSourceModule*)ctx; + if (_this->running) { + return; + } + if (_this->selectedSerial == "") { + spdlog::error("Tried to start HackRF source with empty serial"); + return; + } + + int err = hackrf_open_by_serial(_this->selectedSerial.c_str(), &_this->openDev); + if (err != 0) { + spdlog::error("Could not open HackRF {0}", _this->selectedSerial); + return; + } + + hackrf_set_sample_rate(_this->openDev, _this->sampleRate); + hackrf_set_baseband_filter_bandwidth(_this->openDev, hackrf_compute_baseband_filter_bw(_this->sampleRate)); + hackrf_set_freq(_this->openDev, _this->freq); + + hackrf_set_amp_enable(_this->openDev, _this->amp); + hackrf_set_lna_gain(_this->openDev, _this->lna); + hackrf_set_vga_gain(_this->openDev, _this->lna); + + hackrf_start_rx(_this->openDev, callback, _this); + + _this->running = true; + spdlog::info("HackRFSourceModule '{0}': Start!", _this->name); + } + + #pragma optimize( "", on ) + + static void stop(void* ctx) { + HackRFSourceModule* _this = (HackRFSourceModule*)ctx; + if (!_this->running) { + return; + } + _this->running = false; + _this->stream.stopWriter(); + // TODO: Stream stop + hackrf_close(_this->openDev); + _this->stream.clearWriteStop(); + spdlog::info("HackRFSourceModule '{0}': Stop!", _this->name); + } + + static void tune(double freq, void* ctx) { + HackRFSourceModule* _this = (HackRFSourceModule*)ctx; + if (_this->running) { + hackrf_set_freq(_this->openDev, freq); + } + _this->freq = freq; + spdlog::info("HackRFSourceModule '{0}': Tune: {1}!", _this->name, freq); + } + + static void menuHandler(void* ctx) { + HackRFSourceModule* _this = (HackRFSourceModule*)ctx; + float menuWidth = ImGui::GetContentRegionAvailWidth(); + + if (_this->running) { style::beginDisabled(); } + + ImGui::SetNextItemWidth(menuWidth); + if (ImGui::Combo(CONCAT("##_hackrf_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) { + _this->selectedSerial = _this->devList[_this->devId]; + } + + if (ImGui::Combo(CONCAT("##_hackrf_sr_sel_", _this->name), &_this->srId, sampleRatesTxt)) { + _this->sampleRate = sampleRates[_this->srId]; + core::setInputSampleRate(_this->sampleRate); + } + + ImGui::SameLine(); + float refreshBtnWdith = menuWidth - ImGui::GetCursorPosX(); + if (ImGui::Button(CONCAT("Refresh##_hackrf_refr_", _this->name), ImVec2(refreshBtnWdith, 0))) { + _this->refresh(); + } + + if (_this->running) { style::endDisabled(); } + + ImGui::Text("Amp Enabled"); + ImGui::SameLine(); + if (ImGui::Checkbox(CONCAT("##_hackrf_amp_", _this->name), &_this->amp)) { + if (_this->running) { + hackrf_set_amp_enable(_this->openDev, _this->amp); + } + } + + ImGui::Text("LNA Gain"); + ImGui::SameLine(); + if (ImGui::SliderInt(CONCAT("##_hackrf_lna_", _this->name), &_this->lna, 0, 40)) { + _this->lna = (_this->lna / 8) * 8; + if (_this->running) { + hackrf_set_lna_gain(_this->openDev, _this->lna); + } + } + + ImGui::Text("LNA Gain"); + ImGui::SameLine(); + if (ImGui::SliderInt(CONCAT("##_hackrf_vga_", _this->name), &_this->vga, 0, 62)) { + _this->vga = (_this->vga / 2) * 2; + if (_this->running) { + hackrf_set_vga_gain(_this->openDev, _this->lna); + } + } + } + + static int callback(hackrf_transfer* transfer) { + HackRFSourceModule* _this = (HackRFSourceModule*)transfer->rx_ctx; + int count = transfer->valid_length / 2; + int8_t* buffer = (int8_t*)transfer->buffer; + for (int i = 0; i < count; i++) { + _this->stream.writeBuf[i].i = (float)buffer[i * 2] / 128.0f; + _this->stream.writeBuf[i].q = (float)buffer[(i * 2) + 1] / 128.0f; + } + if (!_this->stream.swap(count)) { return -1; } + return 0; + } + + std::string name; + hackrf_device* openDev; + bool enabled = true; + dsp::stream stream; + int sampleRate; + SourceManager::SourceHandler handler; + bool running = false; + double freq; + std::string selectedSerial = ""; + int devId = 0; + int srId = 0; + bool amp = false; + int lna = 0; + int vga = 0; + + std::vector devList; + std::string devListTxt; +}; + +MOD_EXPORT void _INIT_() { +// config.setPath(ROOT_DIR "/airspyhf_config.json"); +// json defConf; +// defConf["device"] = ""; +// defConf["devices"] = json::object(); +// config.load(defConf); +// config.enableAutoSave(); +} + +MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) { + return new HackRFSourceModule(name); +} + +MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) { + delete (HackRFSourceModule*)instance; +} + +MOD_EXPORT void _END_() { + // config.disableAutoSave(); + // config.save(); +} \ No newline at end of file diff --git a/readme.md b/readme.md index 1a7e236..d0dafed 100644 --- a/readme.md +++ b/readme.md @@ -35,7 +35,7 @@ Download the latest release from [the Releases page](https://github.com/Alexandr Then, run: ```sh -sudo apt install libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libiio-dev libad9361-dev portaudio19-dev +sudo apt install libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libiio-dev libad9361-dev portaudio19-dev libhackrf-dev sudo dpkg -i sdrpp_debian_amd64.deb ```