changes to the build system

This commit is contained in:
Ryzerth 2020-12-22 14:50:26 +01:00
parent e90b6656c3
commit bd545feb2c
57 changed files with 1456 additions and 275 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ build/
.DS_Store
sdrpp_v0.2.5_beta_x64
sdrpp_v0.2.5_beta_x64_new_wf
root_dev/

View File

@ -1,19 +1,44 @@
cmake_minimum_required(VERSION 3.13)
project(sdrpp)
option(OPT_BUILD_RTL_TCP_SOURCE "Build RTL-TCP Source Module (no dependencies required)" ON)
option(OPT_BUILD_SPYSERVER_SOURCE "Build SpyServer Source Module (no dependencies required)" ON)
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_AUDIO_SINK "Build Audio Sink Module (Depedencies: portaudio)" ON)
# Core of SDR++
add_subdirectory("core")
# Cross platform modules
# Base modules
add_subdirectory("radio")
add_subdirectory("recorder")
add_subdirectory("soapy_source")
add_subdirectory("airspyhf_source")
#add_subdirectory("file_source")
# Source modules
if (OPT_BUILD_RTL_TCP_SOURCE)
add_subdirectory("rtl_tcp_source")
add_subdirectory("audio_sink")
#add_subdirectory("rx888_source")
endif (OPT_BUILD_RTL_TCP_SOURCE)
if (OPT_BUILD_SPYSERVER_SOURCE)
add_subdirectory("spyserver_source")
endif (OPT_BUILD_SPYSERVER_SOURCE)
if (OPT_BUILD_SOAPY_SOURCE)
add_subdirectory("soapy_source")
endif (OPT_BUILD_SOAPY_SOURCE)
if (OPT_BUILD_AIRSPYHF_SOURCE)
add_subdirectory("airspyhf_source")
endif (OPT_BUILD_AIRSPYHF_SOURCE)
if (OPT_BUILD_PLUTOSDR_SOURCE)
add_subdirectory("plutosdr_source")
endif (OPT_BUILD_PLUTOSDR_SOURCE)
if (OPT_BUILD_AUDIO_SINK)
add_subdirectory("audio_sink")
endif (OPT_BUILD_AUDIO_SINK)
if (MSVC)
set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")

View File

@ -5,6 +5,7 @@
#include <signal_path/signal_path.h>
#include <core.h>
#include <gui/style.h>
#include <config.h>
#include <libairspyhf/airspyhf.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str())
@ -17,6 +18,8 @@ SDRPP_MOD_INFO {
/* Max instances */ 1
};
//ConfigManager config;
const char* AGG_MODES_STR = "Off\0Low\0High\0";
class AirspyHFSourceModule : public ModuleManager::Instance {
@ -36,7 +39,10 @@ public:
handler.stream = &stream;
refresh();
selectFirst();
// config.aquire();
// std::string serString = config.conf["device"];
// config.release();
sigpath::sourceManager.registerSource("Airspy HF+", &handler);
}
@ -92,9 +98,10 @@ public:
std::string str = buf;
if (serial == str) {
selectBySerial(devList[i]);
break;
return;
}
}
selectFirst();
}
void selectBySerial(uint64_t serial) {
@ -287,7 +294,12 @@ private:
};
MOD_EXPORT void _INIT_() {
// Do your one time init here
// 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) {
@ -299,5 +311,6 @@ MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) {
}
MOD_EXPORT void _END_() {
// Do your one shutdown here
// config.disableAutoSave();
// config.save();
}

View File

@ -6,20 +6,6 @@
using nlohmann::json;
#define DEV_BUILD
#define SDRPP_RESOURCE_DIR "/usr/local/"
#ifndef ROOT_DIR
#ifdef DEV_BUILD
#define ROOT_DIR "../root_dev"
#elif _WIN32
#define ROOT_DIR "."
#else
#define ROOT_DIR "/etc/sdrpp"
#endif
#endif
class ConfigManager {
public:
ConfigManager();
@ -32,20 +18,11 @@ public:
void aquire();
void release(bool changed = false);
// static void setResourceDir(std::string path);
// static std::string getResourceDir();
// static void setConfigDir(std::string path);
// static std::string getConfigDir();
json conf;
private:
static void autoSaveWorker(ConfigManager* _this);
//static std::string resDir;
//static std::string configDir;
std::string path = "";
bool changed = false;
bool autoSaveEnabled = false;

View File

@ -14,6 +14,7 @@
#include <stb_image.h>
#include <config.h>
#include <core.h>
#include <options.h>
#include <duktape/duktape.h>
#include <duktape/duk_console.h>
@ -63,16 +64,19 @@ duk_ret_t test_func(duk_context *ctx) {
}
// main
int sdrpp_main() {
int sdrpp_main(int argc, char *argv[]) {
#ifdef _WIN32
//FreeConsole();
// ConfigManager::setResourceDir("./res");
// ConfigManager::setConfigDir(".");
#endif
spdlog::info("SDR++ v" VERSION_STR);
// Load default options and parse command line
options::loadDefaults();
if (!options::parse(argc, argv)) { return -1; }
// ======== DEFAULT CONFIG ========
json defConfig;
defConfig["bandColors"]["amateur"] = "#FF0000FF";
@ -114,8 +118,8 @@ int sdrpp_main() {
defConfig["windowSize"]["w"] = 1280;
// Load config
spdlog::info("Loading config");
core::configManager.setPath(ROOT_DIR "/config.json");
spdlog::info("Loading config {0}");
core::configManager.setPath(options::opts.root + "/config.json");
core::configManager.load(defConfig);
core::configManager.enableAutoSave();
@ -153,7 +157,7 @@ int sdrpp_main() {
// Load app icon
GLFWimage icons[10];
icons[0].pixels = stbi_load(((std::string)(ROOT_DIR "/res/icons/sdrpp.png")).c_str(), &icons[0].width, &icons[0].height, 0, 4);
icons[0].pixels = stbi_load(((std::string)(options::opts.root + "/res/icons/sdrpp.png")).c_str(), &icons[0].width, &icons[0].height, 0, 4);
icons[1].pixels = (unsigned char*)malloc(16 * 16 * 4); icons[1].width = icons[1].height = 16;
icons[2].pixels = (unsigned char*)malloc(24 * 24 * 4); icons[2].width = icons[2].height = 24;
icons[3].pixels = (unsigned char*)malloc(32 * 32 * 4); icons[3].width = icons[3].height = 32;
@ -204,11 +208,11 @@ int sdrpp_main() {
LoadingScreen::show("Loading band plans");
spdlog::info("Loading band plans");
bandplan::loadFromDir(ROOT_DIR "/bandplans");
bandplan::loadFromDir(options::opts.root + "/bandplans");
LoadingScreen::show("Loading band plan colors");
spdlog::info("Loading band plans color table");
bandplan::loadColorTable(ROOT_DIR "/band_colors.json");
bandplan::loadColorTable(options::opts.root + "/band_colors.json");
windowInit();

View File

@ -12,4 +12,4 @@ namespace core {
void setInputSampleRate(double samplerate);
};
int sdrpp_main();
int sdrpp_main(int argc, char *argv[]);

View File

@ -2,6 +2,7 @@
#include <stdint.h>
#include <GL/glew.h>
#include <config.h>
#include <options.h>
#define STB_IMAGE_IMPLEMENTATION
#include <imgui/stb_image.h>
@ -31,13 +32,13 @@ namespace icons {
}
void load() {
LOGO = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/sdrpp.png");
PLAY = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/play.png");
STOP = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/stop.png");
MENU = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/menu.png");
MUTED = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/muted.png");
UNMUTED = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/unmuted.png");
NORMAL_TUNING = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/normal_tuning.png");
CENTER_TUNING = (ImTextureID)(uintptr_t)loadTexture(ROOT_DIR "/res/icons/center_tuning.png");
LOGO = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/sdrpp.png");
PLAY = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/play.png");
STOP = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/stop.png");
MENU = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/menu.png");
MUTED = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/muted.png");
UNMUTED = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/unmuted.png");
NORMAL_TUNING = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/normal_tuning.png");
CENTER_TUNING = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/center_tuning.png");
}
}

View File

@ -30,6 +30,7 @@
#include <filesystem>
#include <signal_path/source.h>
#include <gui/dialogs/loading_screen.h>
#include <options.h>
// const int FFTSizes[] = {
// 65536,
@ -143,8 +144,8 @@ void windowInit() {
spdlog::info("Loading modules");
// Load modules from /module directory
if (std::filesystem::is_directory(ROOT_DIR "/modules")) {
for (const auto & file : std::filesystem::directory_iterator(ROOT_DIR "/modules")) {
if (std::filesystem::is_directory(options::opts.root + "/modules")) {
for (const auto & file : std::filesystem::directory_iterator(options::opts.root + "/modules")) {
std::string path = file.path().generic_string();
if (file.path().extension().generic_string() != SDRPP_MOD_EXTENTSION) {
continue;
@ -595,7 +596,6 @@ void drawWindow() {
gui::waterfall.setWaterfallMin(fftMin);
gui::waterfall.setWaterfallMax(fftMax);
ImGui::End();
if (showCredits) {

View File

@ -2,6 +2,7 @@
#include <imgui.h>
#include <imgui_internal.h>
#include <config.h>
#include <options.h>
namespace style {
ImFont* baseFont;
@ -16,9 +17,9 @@ namespace style {
ImGui::GetStyle().PopupRounding = 0.0f;
ImGui::GetStyle().ScrollbarRounding = 0.0f;
baseFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(ROOT_DIR "/res/fonts/Roboto-Medium.ttf")).c_str(), 16.0f);
bigFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(ROOT_DIR "/res/fonts/Roboto-Medium.ttf")).c_str(), 42.0f);
hugeFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(ROOT_DIR "/res/fonts/Roboto-Medium.ttf")).c_str(), 128.0f);
baseFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(options::opts.root + "/res/fonts/Roboto-Medium.ttf")).c_str(), 16.0f);
bigFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(options::opts.root + "/res/fonts/Roboto-Medium.ttf")).c_str(), 42.0f);
hugeFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(options::opts.root + "/res/fonts/Roboto-Medium.ttf")).c_str(), 128.0f);
ImGui::StyleColorsDark();
//ImGui::StyleColorsLight();
@ -36,9 +37,9 @@ namespace style {
ImGui::GetStyle().PopupRounding = 0.0f;
ImGui::GetStyle().ScrollbarRounding = 0.0f;
baseFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(ROOT_DIR "/res/fonts/Roboto-Medium.ttf")).c_str(), 16.0f);
bigFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(ROOT_DIR "/res/fonts/Roboto-Medium.ttf")).c_str(), 42.0f);
hugeFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(ROOT_DIR "/res/fonts/Roboto-Medium.ttf")).c_str(), 128.0f);
baseFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(options::opts.root + "/res/fonts/Roboto-Medium.ttf")).c_str(), 16.0f);
bigFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(options::opts.root + "/res/fonts/Roboto-Medium.ttf")).c_str(), 42.0f);
hugeFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(options::opts.root + "/res/fonts/Roboto-Medium.ttf")).c_str(), 128.0f);
ImGui::StyleColorsDark();

View File

@ -1,7 +1,29 @@
#include <options.h>
#include <spdlog/spdlog.h>
namespace options {
void parse(char** argv, int argc) {
CMDLineOptions opts;
void loadDefaults() {
#ifdef _WIN32
opts.root = ".";
#else
opts.root = "~/.sdrpp/";
#endif
}
bool parse(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
char* arg = argv[i];
if (!strcmp(arg, "-r") || !strcmp(arg, "--root")) {
if (i == argc - 1) { return false; }
opts.root = argv[++i];
}
else {
spdlog::error("Invalid command line option: {0}", arg);
return false;
}
}
return true;
}
}

View File

@ -1,13 +1,14 @@
#pragma once
#include <string>
#include <new_module.h>
namespace options {
struct CMDLineOptions {
std::string root;
bool help;
};
CMDLineOptions opts;
SDRPP_EXPORT CMDLineOptions opts;
void parse(char** argv, int argc);
void loadDefaults();
bool parse(int argc, char *argv[]);
}

4
create_root.bat Normal file
View File

@ -0,0 +1,4 @@
echo OFF
mkdir root_dev
Xcopy root root_dev /E /H /C /I

3
create_root.sh Normal file
View File

@ -0,0 +1,3 @@
#!/bin/sh
cp -r root root_dev

View File

@ -7,6 +7,7 @@
#include <gui/style.h>
#include <iio.h>
#include <ad9361.h>
#include <options.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str())
@ -262,7 +263,7 @@ MOD_EXPORT void _INIT_() {
defConf["sampleRate"] = 4000000.0f;
defConf["gainMode"] = 0;
defConf["gain"] = 0.0f;
config.setPath(ROOT_DIR "/plutosdr_source_config.json");
config.setPath(options::opts.root + "/plutosdr_source_config.json");
config.load(defConf);
config.enableAutoSave();
}

View File

@ -1,6 +0,0 @@
echo OFF
copy /b/v/y build\Release\* root\
copy /b/v/y build\radio\Release\radio.dll root\modules\radio.dll
copy /b/v/y build\recorder\Release\recorder.dll root\modules\recorder.dll
copy /b/v/y build\rtl_tcp_source\Release\rtl_tcp_source.dll root\modules\rtl_tcp_source.dll
copy /b/v/y build\soapy\Release\soapy.dll root\modules\soapy.dll

View File

@ -1,3 +0,0 @@
#!/bin/sh
cp build/*/*.so root/modules

View File

@ -14,6 +14,7 @@
#include <dsb_demod.h>
#include <raw_demod.h>
#include <cw_demod.h>
#include <options.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str())
@ -197,7 +198,7 @@ private:
MOD_EXPORT void _INIT_() {
json def = json({});
config.setPath(ROOT_DIR "/radio_config.json");
config.setPath(options::opts.root + "/radio_config.json");
config.load(def);
config.enableAutoSave();
}

View File

@ -12,6 +12,7 @@
#include <config.h>
#include <gui/style.h>
#include <regex>
#include <options.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str())
@ -44,7 +45,7 @@ void sampleRateChanged(void* ctx, double sampleRate, int blockSize) {
}
std::string expandString(std::string input) {
input = std::regex_replace(input, std::regex("%ROOT%"), ROOT_DIR);
input = std::regex_replace(input, std::regex("%ROOT%"), options::opts.root);
return std::regex_replace(input, std::regex("//"), "/");
}
@ -306,7 +307,7 @@ struct RecorderContext_t {
MOD_EXPORT void _INIT_() {
json def = json({});
config.setPath(ROOT_DIR "/recorder_config.json");
config.setPath(options::opts.root + "/recorder_config.json");
config.load(def);
config.enableAutoSave();
}

View File

@ -1,43 +0,0 @@
{
"audio": {
"Radio": {
"device": "CABLE Input (VB-Audio Virtual Cable)",
"sampleRate": 48000.0,
"volume": 0.42578125
},
"Radio 1": {
"device": "CABLE-A Input (VB-Audio Cable A)",
"sampleRate": 48000.0,
"volume": 1.0
},
"Radio 2": {
"device": "CABLE Input (VB-Audio Virtual Cable)",
"sampleRate": 48000.0,
"volume": 1.0
}
},
"bandPlan": "General",
"bandPlanEnabled": true,
"fftHeight": 300,
"frequency": 98391106,
"max": 0.0,
"maximized": false,
"menuOrder": [
"Source",
"Radio",
"Recorder",
"Audio",
"Scripting",
"Band Plan",
"Display"
],
"menuWidth": 300,
"min": -72.05882263183594,
"showWaterfall": true,
"source": "",
"sourceSettings": {},
"windowSize": {
"h": 720,
"w": 1280
}
}

View File

@ -1,6 +0,0 @@
{
"Radio": "./modules/radio.dll",
"Recorder": "./modules/recorder.dll",
"Soapy": "./modules/soapy.dll",
"RTLTCPSource": "./modules/rtl_tcp_source.dll"
}

View File

@ -1,5 +0,0 @@
{
"Radio 1": {
"demodulator":1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
root/res/icons/muted.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
root/res/icons/unmuted.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -1,4 +0,0 @@
{
"device": "",
"devices": {}
}

View File

@ -1,11 +1,18 @@
{
"bandColors": {
"amateur": "#FF0000FF",
"aviation": "#00FF00FF",
"broadcast": "#0000FFFF",
"marine": "#00FFFFFF",
"military": "#FFFF00FF"
},
"bandPlan": "General",
"bandPlanEnabled": true,
"centerTuning": false,
"fftHeight": 300,
"frequency": 7350000,
"max": -25.0,
"maximized": true,
"frequency": 105000000,
"max": 0.0,
"maximized": false,
"menuOrder": [
"Source",
"Radio",
@ -17,7 +24,7 @@
"Display"
],
"menuWidth": 300,
"min": -63.235294342041016,
"min": -70.0,
"moduleInstances": {
"AirspyHF+ Source": "airspyhf_source",
"Audio Sink": "audio_sink",
@ -25,7 +32,8 @@
"RTL-TCP Source": "rtl_tcp_source",
"Radio": "radio",
"Recorder": "recorder",
"SoapySDR Source": "soapy_source"
"SoapySDR Source": "soapy_source",
"SpyServer Source": "spyserver_source"
},
"modules": [
"./radio/Release/radio.dll",
@ -34,26 +42,17 @@
"./airspyhf_source/Release/airspyhf_source.dll",
"./rtl_tcp_source/Release/rtl_tcp_source.dll",
"./audio_sink/Release/audio_sink.dll",
"./plutosdr_source/Release/plutosdr_source.dll"
"./plutosdr_source/Release/plutosdr_source.dll",
"./spyserver_source/Release/spyserver_source.dll"
],
"offset": 0.0,
"showWaterfall": true,
"source": "Airspy HF+",
"source": "SoapySDR",
"streams": {
"Radio": {
"muted": false,
"sink": "Audio",
"volume": 0.13265305757522583
},
"Radio 1": {
"muted": false,
"sink": "Audio",
"volume": 0.6377550959587097
},
"Radio 2": {
"muted": false,
"sink": "Audio",
"volume": 0.4292035400867462
"volume": 0.5867347121238708
}
},
"windowSize": {

View File

@ -1,6 +1,6 @@
{
"IP": "192.168.2.1",
"gain": 0.0,
"gainMode": 2,
"gainMode": 0,
"sampleRate": 4000000.0
}

View File

@ -1,44 +1,5 @@
{
"Radio": {
"AM": {
"bandwidth": 12500.0,
"snapInterval": 1000.0,
"squelchLevel": -100.0
},
"CW": {
"bandwidth": 200.0,
"snapInterval": 10.0,
"squelchLevel": -100.0
},
"DSB": {
"bandwidth": 6000.0,
"snapInterval": 100.0
},
"FM": {
"bandwidth": 12500.0,
"snapInterval": 10000.0,
"squelchLevel": -47.474998474121094
},
"LSB": {
"bandwidth": 3000.0,
"snapInterval": 100.0
},
"RAW": {
"snapInterval": 10000.0
},
"USB": {
"bandwidth": 3000.0,
"snapInterval": 100.0
},
"WFM": {
"bandwidth": 200000.0,
"deempMode": 0,
"snapInterval": 100000.0,
"squelchLevel": -100.0
},
"selectedDemodId": 2
},
"Radio 1": {
"AM": {
"bandwidth": 12500.0,
"snapInterval": 1000.0
@ -70,43 +31,7 @@
"bandwidth": 200000.0,
"deempMode": 0,
"snapInterval": 100000.0,
"squelchLevel": -100.0
},
"selectedDemodId": 1
},
"Radio 2": {
"AM": {
"bandwidth": 12500.0,
"snapInterval": 1000.0
},
"CW": {
"bandwidth": 200.0,
"snapInterval": 10.0
},
"DSB": {
"bandwidth": 6000.0,
"snapInterval": 100.0
},
"FM": {
"bandwidth": 12500.0,
"snapInterval": 10000.0
},
"LSB": {
"bandwidth": 3000.0,
"snapInterval": 100.0
},
"RAW": {
"snapInterval": 10000.0
},
"USB": {
"bandwidth": 3000.0,
"snapInterval": 100.0
},
"WFM": {
"bandwidth": 200000.0,
"deempMode": 1,
"snapInterval": 100000.0,
"squelchLevel": -70.2020034790039
"squelchLevel": -60.60599899291992
},
"selectedDemodId": 1
}

View File

@ -1,49 +1,12 @@
{
"device": "AirSpy HF+ [c852435de0224af7]",
"device": "Generic RTL2832U OEM :: 00000001",
"devices": {
"": {
"Generic RTL2832U OEM :: 00000001": {
"agc": true,
"gains": {
"PGA": 0.0
"TUNER": 0.0
},
"sampleRate": 4000000.0
},
"AirSpy HF+ [c852435de0224af7]": {
"agc": false,
"gains": {
"LNA": 6.0,
"RF": -48.0
},
"sampleRate": 768000.0
},
"CABLE Output (VB-Audio Virtual Cable)": {
"sampleRate": 96000.0
},
"Default Device": {
"agc": false,
"sampleRate": 192000.0
},
"Generic RTL2832U OEM :: 00000001": {
"agc": false,
"gains": {
"TUNER": 37.3390007019043
},
"sampleRate": 250000.0
},
"HackRF One #0 901868dc282c8f8b": {
"gains": {
"AMP": 0.0,
"LNA": 24.503000259399414,
"VGA": 16.332000732421875
},
"sampleRate": 8000000.0
},
"Microphone (Realtek High Definition Audio)": {
"agc": false,
"sampleRate": 44100.0
},
"PulseAudio": {
"sampleRate": 96000.0
"sampleRate": 2560000.0
}
}
}

View File

@ -0,0 +1,7 @@
{
"broadcast": "#0000FFFF",
"amateur": "#FF0000FF",
"aviation": "#00FF00FF",
"marine": "#00FFFFFF",
"military": "#FFFF00FF"
}

View File

@ -0,0 +1,267 @@
{
"name": "General",
"country_name": "Worldwide",
"country_code": "--",
"author_name": "Ryzerth",
"author_url": "https://github.com/AlexandreRouma",
"bands": [
{
"name": "Long Wave",
"type": "broadcast",
"start": 148500,
"end": 283500
},
{
"name": "Medium Wave",
"type": "broadcast",
"start": 526500,
"end": 1606500
},
{
"name": "Shortwave Broadcast",
"type": "broadcast",
"start": 2300000,
"end": 2468000
},
{
"name": "Shortwave Broadcast",
"type": "broadcast",
"start": 3200000,
"end": 3400000
},
{
"name": "Shortwave Broadcast",
"type": "broadcast",
"start": 3950000,
"end": 4000000
},
{
"name": "Shortwave Broadcast",
"type": "broadcast",
"start": 4750000,
"end": 4995000
},
{
"name": "Shortwave Broadcast",
"type": "broadcast",
"start": 5005000,
"end": 5060000
},
{
"name": "Shortwave Broadcast",
"type": "broadcast",
"start": 5900000,
"end": 6200000
},
{
"name": "Shortwave Broadcast",
"type": "broadcast",
"start": 7200000,
"end": 7450000
},
{
"name": "Shortwave Broadcast",
"type": "broadcast",
"start": 9400000,
"end": 9900000
},
{
"name": "Shortwave Broadcast",
"type": "broadcast",
"start": 11600000,
"end": 12100000
},
{
"name": "Shortwave Broadcast",
"type": "broadcast",
"start": 13570000,
"end": 13870000
},
{
"name": "Shortwave Broadcast",
"type": "broadcast",
"start": 15100000,
"end": 15800000
},
{
"name": "Shortwave Broadcast",
"type": "broadcast",
"start": 17480000,
"end": 17900000
},
{
"name": "Shortwave Broadcast",
"type": "broadcast",
"start": 18900000,
"end": 19020000
},
{
"name": "Shortwave Broadcast",
"type": "broadcast",
"start": 21450000,
"end": 21850000
},
{
"name": "Shortwave Broadcast",
"type": "broadcast",
"start": 25670000,
"end": 26100000
},
{
"name": "FM Broadcast",
"type": "broadcast",
"start": 87500000,
"end": 108000000
},
{
"name": "Air Band VOR/ILS",
"type": "aviation",
"start": 108000000,
"end": 118000000
},
{
"name": "Air Band Voice",
"type": "aviation",
"start": 118000000,
"end": 137000000
},
{
"name": "160m Ham Band",
"type": "amateur",
"start": 1800000,
"end": 2000000
},
{
"name": "80m Ham Band",
"type": "amateur",
"start": 3500000,
"end": 3950000
},
{
"name": "60m Ham Band",
"type": "amateur",
"start": 5351500,
"end": 5366500
},
{
"name": "40m Ham Band",
"type": "amateur",
"start": 7000000,
"end": 7200000
},
{
"name": "30m Ham Band",
"type": "amateur",
"start": 10100000,
"end": 10150000
},
{
"name": "20m Ham Band",
"type": "amateur",
"start": 14000000,
"end": 14350000
},
{
"name": "17m Ham Band",
"type": "amateur",
"start": 18068000,
"end": 18168000
},
{
"name": "15m Ham Band",
"type": "amateur",
"start": 21000000,
"end": 21450000
},
{
"name": "12m Ham Band",
"type": "amateur",
"start": 24890000,
"end": 24990000
},
{
"name": "CB",
"type": "amateur",
"start": 26960000,
"end": 27410000
},
{
"name": "10m Ham Band",
"type": "amateur",
"start": 28000000,
"end": 29750000
},
{
"name": "6m Ham Band",
"type": "amateur",
"start": 50000000,
"end": 54000000
},
{
"name": "2m Ham Band",
"type": "amateur",
"start": 144000000,
"end": 148000000
},
{
"name": "Marine",
"type": "marine",
"start": 156000000,
"end": 162025000
},
{
"name": "1.25m Ham Band",
"type": "amateur",
"start": 222000000,
"end": 225000000
},
{
"name": "Military Air",
"type": "military",
"start": 225000000,
"end": 380000000
},
{
"name": "Military Sat",
"type": "military",
"start": 240000000,
"end": 270000000
},
{
"name": "70cm Ham Band",
"type": "amateur",
"start": 420000000,
"end": 450000000
},
{
"name": "PMR446",
"type": "amateur",
"start": 446000000,
"end": 446200000
},
{
"name": "33cm Ham Band",
"type": "amateur",
"start": 902000000,
"end": 928000000
},
{
"name": "23cm Ham Band",
"type": "amateur",
"start": 1240000000,
"end": 1300000000
},
{
"name": "13cm Ham Band",
"type": "amateur",
"start": 2300000000,
"end": 2310000000
},
{
"name": "13cm Ham Band",
"type": "amateur",
"start": 2390000000,
"end": 2450000000
}
]
}

View File

@ -0,0 +1,141 @@
{
"name": "Germany",
"country_name": "Germany",
"country_code": "DE",
"author_name": "Tobias Mädel",
"author_url": "https://tbspace.de",
"bands": [
{
"name": "LW",
"type": "amateur",
"start": 135700,
"end": 137800
},
{
"name": "630m",
"type": "amateur",
"start": 472000,
"end": 479000
},
{
"name": "160m",
"type": "amateur",
"start": 1810000,
"end": 2000000
},
{
"name": "80m",
"type": "amateur",
"start": 3500000,
"end": 3800000
},
{
"name": "60m",
"type": "amateur",
"start": 5351500,
"end": 5366500
},
{
"name": "40m",
"type": "amateur",
"start": 7000000,
"end": 7200000
},
{
"name": "30m",
"type": "amateur",
"start": 10100000,
"end": 10150000
},
{
"name": "20m",
"type": "amateur",
"start": 14000000,
"end": 14350000
},
{
"name": "17m",
"type": "amateur",
"start": 18068000,
"end": 18168000
},
{
"name": "15m",
"type": "amateur",
"start": 21000000,
"end": 21450000
},
{
"name": "12m",
"type": "amateur",
"start": 24890000,
"end": 24990000
},
{
"name": "CB",
"type": "other",
"start": 26565000,
"end": 27405000
},
{
"name": "10m",
"type": "amateur",
"start": 28000000,
"end": 29700000
},
{
"name": "6m",
"type": "amateur",
"start": 50030000,
"end": 51000000
},
{
"name": "4m",
"type": "amateur",
"start": 70150000,
"end": 70200000
},
{
"name": "FM",
"type": "broadcast",
"start": 87500000,
"end": 108000000
},
{
"name": "2m",
"type": "amateur",
"start": 144000000,
"end": 146000000
},
{
"name": "Freenet",
"type": "other",
"start": 149025000,
"end": 149115625
},
{
"name": "70cm",
"type": "amateur",
"start": 430000000,
"end": 440000000
},
{
"name": "PMR446",
"type": "other",
"start": 446006250,
"end": 446196875
},
{
"name": "23cm",
"type": "amateur",
"start": 1240000000,
"end": 1300000000
},
{
"name": "13cm",
"type": "amateur",
"start": 2320000000,
"end": 2450000000
}
]
}

View File

@ -0,0 +1,135 @@
{
"name": "Russia",
"country_name": "Russia",
"country_code": "RU",
"author_name": "Raov",
"author_url": "https://twitter.com/raov_birbtog",
"bands": [
{
"name": "160m CW",
"type": "amateur",
"start": 1810000,
"end": 1838000
},
{
"name": "160m NB",
"type": "amateur",
"start": 1838000,
"end": 1840000
},
{
"name": "160m + Digi",
"type": "amateur",
"start": 1840000,
"end": 1843000
},
{
"name": "160m",
"type": "amateur",
"start": 1843000,
"end": 2000000
},
{
"name": "80m CW",
"type": "amateur",
"start": 3500000,
"end": 3510000
},
{
"name": "80m CW Contest",
"type": "amateur",
"start": 3510000,
"end": 3560000
},
{
"name": "80m CW",
"type": "amateur",
"start": 3560000,
"end": 3570000
},
{
"name": "80m NB, Digi 200Hz",
"type": "amateur",
"start": 3570000,
"end": 3580000
},
{
"name": "80m NB, Digi 500Hz",
"type": "amateur",
"start": 3580000,
"end": 3600000
},
{
"name": "80m SSB Contest",
"type": "amateur",
"start": 3600000,
"end": 3650000
},
{
"name": "80m",
"type": "amateur",
"start": 3650000,
"end": 3700000
},
{
"name": "80m SSB Contest",
"type": "amateur",
"start": 3700000,
"end": 3800000
},
{
"name": "60m CW 200Hz",
"type": "amateur",
"start": 5351500,
"end": 5354000
},
{
"name": "60m USB",
"type": "amateur",
"start": 5354000,
"end": 5366000
},
{
"name": "60m CW 20Hz",
"type": "amateur",
"start": 5356000,
"end": 5366500
},
{
"name": "40m CW",
"type": "amateur",
"start": 7000000,
"end": 7040000
},
{
"name": "40m NB, Digi 500Hz",
"type": "amateur",
"start": 7040000,
"end": 7050000
},
{
"name": "40m",
"type": "amateur",
"start": 7050000,
"end": 7060000
},
{
"name": "40m SSB Contest",
"type": "amateur",
"start": 7060000,
"end": 7100000
},
{
"name": "40m",
"type": "amateur",
"start": 7100000,
"end": 7130000
},
{
"name": "40m SSB Contest",
"type": "amateur",
"start": 7130000,
"end": 7200000
}
]
}

View File

@ -0,0 +1,46 @@
{
"bandColors": {
"amateur": "#FF0000FF",
"aviation": "#00FF00FF",
"broadcast": "#0000FFFF",
"marine": "#00FFFFFF",
"military": "#FFFF00FF"
},
"bandPlan": "General",
"bandPlanEnabled": true,
"centerTuning": false,
"fftHeight": 300,
"frequency": 100004000,
"max": 0.0,
"maximized": false,
"menuOrder": [
"Source",
"Radio",
"Recorder",
"Sinks",
"Audio",
"Scripting",
"Band Plan",
"Display"
],
"menuWidth": 300,
"min": -70.0,
"moduleInstances": {
"AirspyHF+ Source": "airspyhf_source",
"Audio Sink": "audio_sink",
"PlutoSDR Source": "plutosdr_source",
"RTL-TCP Source": "rtl_tcp_source",
"Radio": "radio",
"Recorder": "recorder",
"SoapySDR Source": "soapy_source"
},
"modules": [],
"offset": 0.0,
"showWaterfall": true,
"source": "",
"streams": {},
"windowSize": {
"h": 720,
"w": 1280
}
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -8,6 +8,7 @@
#include <SoapySDR/Logger.hpp>
#include <core.h>
#include <gui/style.h>
#include <options.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str())
@ -386,7 +387,7 @@ private:
};
MOD_EXPORT void _INIT_() {
config.setPath(ROOT_DIR "/soapy_source_config.json");
config.setPath(options::opts.root + "/soapy_source_config.json");
json defConf;
defConf["device"] = "";
defConf["devices"] = json({});

View File

@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.13)
project(spyserver_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(spyserver_source SHARED ${SRC})
target_link_libraries(spyserver_source PRIVATE sdrpp_core)
set_target_properties(spyserver_source PROPERTIES PREFIX "")
if(WIN32)
target_link_libraries(spyserver_source PRIVATE wsock32 ws2_32)
endif()

View File

@ -0,0 +1,178 @@
#include <spyserver_client.h>
#include <imgui.h>
#include <spdlog/spdlog.h>
#include <new_module.h>
#include <gui/gui.h>
#include <signal_path/signal_path.h>
#include <core.h>
#include <gui/style.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str())
SDRPP_MOD_INFO {
/* Name: */ "spyserver_source",
/* Description: */ "SpyServer source module for SDR++",
/* Author: */ "Ryzerth",
/* Version: */ 0, 1, 0,
/* Max instances */ 1
};
class SpyServerSourceModule : public ModuleManager::Instance {
public:
SpyServerSourceModule(std::string name) {
this->name = name;
sampleRate = 2560000.0;
handler.ctx = this;
handler.selectHandler = menuSelected;
handler.deselectHandler = menuDeselected;
handler.menuHandler = menuHandler;
handler.startHandler = start;
handler.stopHandler = stop;
handler.tuneHandler = tune;
handler.stream = &client.iqStream;
sigpath::sourceManager.registerSource("SpyServer", &handler);
}
~SpyServerSourceModule() {
}
void enable() {
enabled = true;
}
void disable() {
enabled = false;
}
bool isEnabled() {
return enabled;
}
private:
static void menuSelected(void* ctx) {
SpyServerSourceModule* _this = (SpyServerSourceModule*)ctx;
core::setInputSampleRate(_this->sampleRate);
spdlog::info("SpyServerSourceModule '{0}': Menu Select!", _this->name);
}
static void menuDeselected(void* ctx) {
SpyServerSourceModule* _this = (SpyServerSourceModule*)ctx;
spdlog::info("SpyServerSourceModule '{0}': Menu Deselect!", _this->name);
}
static void start(void* ctx) {
SpyServerSourceModule* _this = (SpyServerSourceModule*)ctx;
if (_this->running) {
return;
}
if (!_this->client.connectToSpyserver(_this->ip, _this->port)) {
spdlog::error("Could not connect to {0}:{1}", _this->ip, _this->port);
return;
}
_this->client.tune(_this->freq);
_this->client.setSampleRate(_this->sampleRate);
//_this->client.setGainIndex(_this->gain);
//_this->client.setGainMode(!_this->tunerAGC);
//_this->client.setDirectSampling(_this->directSamplingMode);
//_this->client.setAGCMode(_this->rtlAGC);
_this->running = true;
spdlog::info("SpyServerSourceModule '{0}': Start!", _this->name);
}
static void stop(void* ctx) {
SpyServerSourceModule* _this = (SpyServerSourceModule*)ctx;
if (!_this->running) {
return;
}
_this->running = false;
_this->client.disconnect();
spdlog::info("SpyServerSourceModule '{0}': Stop!", _this->name);
}
static void tune(double freq, void* ctx) {
SpyServerSourceModule* _this = (SpyServerSourceModule*)ctx;
if (_this->running) {
_this->client.tune(freq);
}
_this->freq = freq;
spdlog::info("SpyServerSourceModule '{0}': Tune: {1}!", _this->name, freq);
}
static void menuHandler(void* ctx) {
SpyServerSourceModule* _this = (SpyServerSourceModule*)ctx;
float menuWidth = ImGui::GetContentRegionAvailWidth();
float portWidth = ImGui::CalcTextSize("00000").x + 20;
ImGui::SetNextItemWidth(menuWidth - portWidth);
ImGui::InputText(CONCAT("##_ip_select_", _this->name), _this->ip, 1024);
ImGui::SameLine();
ImGui::SetNextItemWidth(portWidth);
ImGui::InputInt(CONCAT("##_port_select_", _this->name), &_this->port, 0);
ImGui::SetNextItemWidth(ImGui::CalcTextSize("OOOOOOOOOO").x);
if (ImGui::Combo("Direct sampling", &_this->directSamplingMode, "Disabled\0I branch\0Q branch\0")) {
if (_this->running) {
//_this->client.setDirectSampling(_this->directSamplingMode);
}
}
if (ImGui::Checkbox("RTL AGC", &_this->rtlAGC)) {
if (_this->running) {
//_this->client.setAGCMode(_this->rtlAGC);
}
}
if (ImGui::Checkbox("Tuner AGC", &_this->tunerAGC)) {
if (_this->running) {
//_this->client.setGainMode(!_this->tunerAGC);
if (!_this->tunerAGC) {
//_this->client.setGainIndex(_this->gain);
}
}
}
if (_this->tunerAGC) { style::beginDisabled(); }
ImGui::SetNextItemWidth(menuWidth);
if (ImGui::SliderInt(CONCAT("##_gain_select_", _this->name), &_this->gain, 0, 29, "")) {
if (_this->running) {
//_this->client.setGainIndex(_this->gain);
}
}
if (_this->tunerAGC) { style::endDisabled(); }
}
std::string name;
bool enabled = true;
dsp::stream<dsp::complex_t> stream;
double sampleRate;
SourceManager::SourceHandler handler;
std::thread workerThread;
SpyServerClient client;
bool running = false;
double freq;
char ip[1024] = "localhost";
int port = 5555;
int gain = 0;
bool rtlAGC = false;
bool tunerAGC = false;
int directSamplingMode = 0;
};
MOD_EXPORT void _INIT_() {
// Do your one time init here
}
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
return new SpyServerSourceModule(name);
}
MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) {
delete (SpyServerSourceModule*)instance;
}
MOD_EXPORT void _END_() {
// Do your one shutdown here
}

View File

@ -0,0 +1,254 @@
#include <spyserver_client.h>
#include <spdlog/spdlog.h>
SpyServerClient::SpyServerClient() {
}
bool SpyServerClient::connectToSpyserver(char* host, int port) {
if (connected) {
return true;
}
#ifdef _WIN32
struct addrinfo *result = NULL;
struct addrinfo *ptr = NULL;
struct addrinfo hints;
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
char buf[128];
sprintf(buf, "%hu", port);
int iResult = getaddrinfo(host, buf, &hints, &result);
if (iResult != 0) {
// TODO: log error
printf("A");
WSACleanup();
return false;
}
ptr = result;
sock = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (sock == INVALID_SOCKET) {
// TODO: log error
printf("B");
freeaddrinfo(result);
WSACleanup();
return false;
}
iResult = connect(sock, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("C");
closesocket(sock);
freeaddrinfo(result);
WSACleanup();
return false;
}
freeaddrinfo(result);
#else
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
// TODO: Log error
return false;
}
struct hostent *server = gethostbyname(host);
struct sockaddr_in serv_addr;
bzero(&serv_addr, sizeof(struct sockaddr_in));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(port);
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) {
// TODO: log error
return false;
}
#endif
// Switch to non-blocking mode
#ifdef _WIN32
unsigned long mode = 1;
ioctlsocket(sock, FIONBIO, &mode);
#else
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK)
#endif
connected = true;
waiting = true;
workerThread = std::thread(&SpyServerClient::worker, this);
printf("Connected");
return true;
}
bool SpyServerClient::disconnect() {
if (!connected) {
return false;
}
waiting = false;
if (workerThread.joinable()) {
workerThread.join();
}
#ifdef _WIN32
closesocket(sock);
WSACleanup();
#else
close(sockfd);
#endif
connected = false;
return true;
}
void SpyServerClient::setSampleRate(uint32_t setSampleRate) {
}
void SpyServerClient::tune(uint32_t freq) {
}
int SpyServerClient::receive(char* buf, int count) {
#ifdef _WIN32
return checkError(recv(sock, (char*)buf, count, 0), count);
#else
return checkError(read(sockfd, buf, count));
#endif
}
int SpyServerClient::checkError(int len, int expected) {
#ifdef _WIN32
if (len != SOCKET_ERROR) { return len; }
int code = WSAGetLastError();
if (code == WSAEWOULDBLOCK) { return 0; }
spdlog::error("{0}", code);
return -1;
#else
if (len <= expected) {
return len;
}
if (len == EAGAIN || len == EWOULDBLOCK) { return 0; }
return -1;
#endif
}
int SpyServerClient::receiveSync(char* buf, int count) {
int len = receive(buf, count);
while (len == 0 && waiting) {
len = receive(buf, count);
}
if (!waiting) {
return 0;
}
return len;
}
void SpyServerClient::worker() {
// Allocate dummy buffer
char* dummyBuf = (char*)malloc(1000000);
// Send hello
hello();
// SETTING_STREAMING_MODE = 0,
// SETTING_STREAMING_ENABLED = 1,
// SETTING_GAIN = 2,
// SETTING_IQ_FORMAT = 100, // 0x64
// SETTING_IQ_FREQUENCY = 101, // 0x65
// SETTING_IQ_DECIMATION = 102, // 0x66
// SETTING_IQ_DIGITAL_GAIN = 103, // 0x67
// Set settings
setSetting(SETTING_STREAMING_MODE, STREAM_MODE_IQ_ONLY);
setSetting(SETTING_GAIN, 5);
setSetting(SETTING_IQ_FORMAT, STREAM_FORMAT_FLOAT);
setSetting(SETTING_IQ_FREQUENCY, 2000000);
setSetting(SETTING_IQ_DECIMATION, 1);
setSetting(SETTING_IQ_DIGITAL_GAIN, 1);
// Enable stream
setSetting(SETTING_STREAMING_ENABLED, 1);
// Main message receive loop
while (true) {
MessageHeader msgHeader;
int len = receiveSync((char*)&msgHeader, sizeof(MessageHeader));
if (len < 0) {
spdlog::error("Socket error");
return;
}
if (len == 0) { return; }
int type = (msgHeader.MessageType & 0xFFFF);
if (type == MSG_TYPE_DEVICE_INFO) {
DeviceInfo devInfo;
len = receiveSync((char*)&devInfo, sizeof(DeviceInfo));
if (len < 0) {
spdlog::error("A Socket error");
return;
}
if (len == 0) { return; }
spdlog::warn("Dev type: {0}", devInfo.DeviceType);
}
// else if (type == MSG_TYPE_FLOAT_IQ) {
// //if (iqStream.aquire() < 0) { return; }
// len = receiveSync(dummyBuf, msgHeader.BodySize);
// //iqStream.write(msgHeader.BodySize);
// if (len < 0) {
// spdlog::error("T Socket error");
// return;
// }
// if (len == 0) { return; }
// }
else if (msgHeader.BodySize > 0) {
len = receiveSync(dummyBuf, msgHeader.BodySize);
if (len < 0) {
spdlog::error("B Socket error {0}", msgHeader.ProtocolID);
return;
}
if (len == 0) { return; }
}
}
free(dummyBuf);
}
void SpyServerClient::sendCommand(uint32_t cmd, void* body, size_t bodySize) {
int size = sizeof(CommandHeader) + bodySize;
char* buf = new char[size];
CommandHeader* cmdHdr = (CommandHeader*)buf;
memcpy(&buf[sizeof(CommandHeader)], body, bodySize);
cmdHdr->CommandType = cmd;
cmdHdr->BodySize = bodySize;
#ifdef _WIN32
send(sock, buf, size, 0);
#else
write(sockfd, buf, size);
#endif
delete[] buf;
}
void SpyServerClient::setSetting(uint32_t setting, uint32_t value) {
char buf[sizeof(SettingTarget) + sizeof(uint32_t)];
SettingTarget* tgt = (SettingTarget*)buf;
uint32_t* val = (uint32_t*)&buf[sizeof(SettingTarget)];
tgt->SettingType = setting;
*val = value;
sendCommand(CMD_SET_SETTING, buf, sizeof(SettingTarget) + sizeof(uint32_t));
}
void SpyServerClient::hello() {
char buf[1024];
ClientHandshake* handshake = (ClientHandshake*)buf;
handshake->ProtocolVersion = SPYSERVER_PROTOCOL_VERSION;
strcpy(&buf[sizeof(ClientHandshake)], "sdr++");
sendCommand(CMD_HELLO, buf, sizeof(ClientHandshake) + 5);
}

View File

@ -0,0 +1,69 @@
#pragma once
#include <spyserver_protocol.h>
#include <dsp/stream.h>
#include <dsp/types.h>
#include <thread>
#include <string>
#ifdef _WIN32
#include <WinSock2.h>
#include <WS2tcpip.h>
#else
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#endif
#ifdef _WIN32
#define __attribute__(x)
#pragma pack(push, 1)
#endif
struct command_t{
unsigned char cmd;
unsigned int param;
}__attribute__((packed));
#ifdef _WIN32
#pragma pack(pop)
#endif
class SpyServerClient {
public:
SpyServerClient();
bool connectToSpyserver(char* host, int port);
bool disconnect();
void start();
void stop();
void setSampleRate(uint32_t setSampleRate);
void tune(uint32_t freq);
dsp::stream<dsp::complex_t> iqStream;
private:
int receive(char* buf, int count);
int receiveSync(char* buf, int count);
int checkError(int err, int expected);
void worker();
void sendCommand(uint32_t cmd, void* body, size_t bodySize);
void setSetting(uint32_t setting, uint32_t value);
void hello();
#ifdef _WIN32
SOCKET sock;
#else
int sockfd;
#endif
bool connected = false;
bool waiting = false;
std::thread workerThread;
};

View File

@ -0,0 +1,188 @@
/*
SPY Server protocol structures and constants
Copyright (C) 2017 Youssef Touil youssef@live.com
*/
#pragma once
#include <stdint.h>
#include <limits.h>
#define SPYSERVER_PROTOCOL_VERSION (((2) << 24) | ((0) << 16) | (1700))
#define SPYSERVER_MAX_COMMAND_BODY_SIZE (256)
#define SPYSERVER_MAX_MESSAGE_BODY_SIZE (1 << 20)
#define SPYSERVER_MAX_DISPLAY_PIXELS (1 << 15)
#define SPYSERVER_MIN_DISPLAY_PIXELS (100)
#define SPYSERVER_MAX_FFT_DB_RANGE (150)
#define SPYSERVER_MIN_FFT_DB_RANGE (10)
#define SPYSERVER_MAX_FFT_DB_OFFSET (100)
enum DeviceType
{
DEVICE_INVALID = 0,
DEVICE_AIRSPY_ONE = 1,
DEVICE_AIRSPY_HF = 2,
DEVICE_RTLSDR = 3,
};
enum CommandType
{
CMD_HELLO = 0,
CMD_GET_SETTING = 1,
CMD_SET_SETTING = 2,
CMD_PING = 3,
};
enum SettingType
{
SETTING_STREAMING_MODE = 0,
SETTING_STREAMING_ENABLED = 1,
SETTING_GAIN = 2,
SETTING_IQ_FORMAT = 100, // 0x64
SETTING_IQ_FREQUENCY = 101, // 0x65
SETTING_IQ_DECIMATION = 102, // 0x66
SETTING_IQ_DIGITAL_GAIN = 103, // 0x67
SETTING_FFT_FORMAT = 200, // 0xc8
SETTING_FFT_FREQUENCY = 201, // 0xc9
SETTING_FFT_DECIMATION = 202, // 0xca
SETTING_FFT_DB_OFFSET = 203, // 0xcb
SETTING_FFT_DB_RANGE = 204, // 0xcc
SETTING_FFT_DISPLAY_PIXELS = 205, // 0xcd
};
enum StreamType
{
STREAM_TYPE_STATUS = 0,
STREAM_TYPE_IQ = 1,
STREAM_TYPE_AF = 2,
STREAM_TYPE_FFT = 4,
};
enum StreamingMode
{
STREAM_MODE_IQ_ONLY = STREAM_TYPE_IQ, // 0x01
STREAM_MODE_AF_ONLY = STREAM_TYPE_AF, // 0x02
STREAM_MODE_FFT_ONLY = STREAM_TYPE_FFT, // 0x04
STREAM_MODE_FFT_IQ = STREAM_TYPE_FFT | STREAM_TYPE_IQ, // 0x05
STREAM_MODE_FFT_AF = STREAM_TYPE_FFT | STREAM_TYPE_AF, // 0x06
};
enum StreamFormat
{
STREAM_FORMAT_INVALID = 0,
STREAM_FORMAT_UINT8 = 1,
STREAM_FORMAT_INT16 = 2,
STREAM_FORMAT_INT24 = 3,
STREAM_FORMAT_FLOAT = 4,
STREAM_FORMAT_DINT4 = 5,
};
enum MessageType
{
MSG_TYPE_DEVICE_INFO = 0,
MSG_TYPE_CLIENT_SYNC = 1,
MSG_TYPE_PONG = 2,
MSG_TYPE_READ_SETTING = 3,
MSG_TYPE_UINT8_IQ = 100, // 0x64
MSG_TYPE_INT16_IQ = 101, // 0x65
MSG_TYPE_INT24_IQ = 102, // 0x66
MSG_TYPE_FLOAT_IQ = 103, // 0x67
MSG_TYPE_UINT8_AF = 200, // 0xc8
MSG_TYPE_INT16_AF = 201, // 0xc9
MSG_TYPE_INT24_AF = 202, // 0xca
MSG_TYPE_FLOAT_AF = 203, // 0xcb
MSG_TYPE_DINT4_FFT = 300, //0x12C
MSG_TYPE_UINT8_FFT = 301, //0x12D
};
#ifdef _WIN32
#define __attribute__(x)
#pragma pack(push, 1)
#endif
struct ClientHandshake
{
uint32_t ProtocolVersion;
// SDR# doesn't seem to send this
//uint32_t ClientNameLength;
}__attribute__((packed));
struct CommandHeader
{
uint32_t CommandType;
uint32_t BodySize;
}__attribute__((packed));
struct SettingTarget
{
// Again, not used
//uint32_t StreamType;
uint32_t SettingType;
}__attribute__((packed));
struct MessageHeader
{
uint32_t ProtocolID;
uint32_t MessageType;
uint32_t StreamType;
uint32_t SequenceNumber;
uint32_t BodySize;
}__attribute__((packed));
struct DeviceInfo
{
uint32_t DeviceType;
uint32_t DeviceSerial;
uint32_t MaximumSampleRate;
uint32_t MaximumBandwidth;
uint32_t DecimationStageCount;
uint32_t GainStageCount;
uint32_t MaximumGainIndex;
uint32_t MinimumFrequency;
uint32_t MaximumFrequency;
uint32_t Resolution;
uint32_t MinimumIQDecimation;
uint32_t ForcedIQFormat;
}__attribute__((packed));
struct ClientSync
{
uint32_t CanControl;
uint32_t Gain;
uint32_t DeviceCenterFrequency;
uint32_t IQCenterFrequency;
uint32_t FFTCenterFrequency;
uint32_t MinimumIQCenterFrequency;
uint32_t MaximumIQCenterFrequency;
uint32_t MinimumFFTCenterFrequency;
uint32_t MaximumFFTCenterFrequency;
}__attribute__((packed));
struct ComplexInt16
{
int16_t real;
int16_t imag;
}__attribute__((packed));
struct ComplexUInt8
{
uint8_t real;
uint8_t imag;
}__attribute__((packed));
#ifdef _WIN32
#pragma pack(pop)
#endif
enum ParserPhase {
AcquiringHeader,
ReadingData
};

View File

@ -1,6 +1,6 @@
#include <core.h>
#include <stdio.h>
int main() {
return sdrpp_main();
int main(int argc, char *argv[]) {
return sdrpp_main(argc, argv);
}