mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2024-11-14 06:22:52 +01:00
New custom network lib + half finished rigctl server
This commit is contained in:
parent
def6036b30
commit
f6e0e2f39d
13
recorder/src/recorder_interface.h
Normal file
13
recorder/src/recorder_interface.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum {
|
||||||
|
RECORDER_IFACE_CMD_GET_MODE,
|
||||||
|
RECORDER_IFACE_CMD_SET_MODE,
|
||||||
|
RECORDER_IFACE_CMD_START,
|
||||||
|
RECORDER_IFACE_CMD_STOP
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
RECORDER_MODE_BASEBAND,
|
||||||
|
RECORDER_MODE_AUDIO
|
||||||
|
};
|
22
rigctl_server/CMakeLists.txt
Normal file
22
rigctl_server/CMakeLists.txt
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
project(rigctl_server)
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
|
||||||
|
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
|
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -Wno-unused-command-line-argument -undefined dynamic_lookup")
|
||||||
|
else ()
|
||||||
|
set(CMAKE_CXX_FLAGS "-O3 -std=c++17")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
file(GLOB SRC "src/*.cpp")
|
||||||
|
|
||||||
|
include_directories("src/")
|
||||||
|
include_directories("../recorder/src")
|
||||||
|
|
||||||
|
add_library(rigctl_server SHARED ${SRC})
|
||||||
|
target_link_libraries(rigctl_server PRIVATE sdrpp_core)
|
||||||
|
set_target_properties(rigctl_server PROPERTIES PREFIX "")
|
||||||
|
|
||||||
|
# Install directives
|
||||||
|
install(TARGETS rigctl_server DESTINATION lib/sdrpp/plugins)
|
226
rigctl_server/src/main.cpp
Normal file
226
rigctl_server/src/main.cpp
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
#include <utils/networking.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <module.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <gui/style.h>
|
||||||
|
#include <signal_path/signal_path.h>
|
||||||
|
#include <core.h>
|
||||||
|
#include <recorder_interface.h>
|
||||||
|
|
||||||
|
|
||||||
|
SDRPP_MOD_INFO {
|
||||||
|
/* Name: */ "rigctl_server",
|
||||||
|
/* Description: */ "My fancy new module",
|
||||||
|
/* Author: */ "Ryzerth",
|
||||||
|
/* Version: */ 0, 1, 0,
|
||||||
|
/* Max instances */ -1
|
||||||
|
};
|
||||||
|
|
||||||
|
class SigctlServerModule : public ModuleManager::Instance {
|
||||||
|
public:
|
||||||
|
SigctlServerModule(std::string name) {
|
||||||
|
this->name = name;
|
||||||
|
|
||||||
|
strcpy(hostname, "localhost");
|
||||||
|
|
||||||
|
gui::menu.registerEntry(name, menuHandler, this, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
~SigctlServerModule() {
|
||||||
|
gui::menu.removeEntry(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable() {
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void disable() {
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void menuHandler(void* ctx) {
|
||||||
|
SigctlServerModule* _this = (SigctlServerModule*)ctx;
|
||||||
|
float menuWidth = ImGui::GetContentRegionAvailWidth();
|
||||||
|
|
||||||
|
bool listening = (_this->listener && _this->listener->isListening());
|
||||||
|
|
||||||
|
if (listening) { style::beginDisabled(); }
|
||||||
|
ImGui::InputText("##testestssss", _this->hostname, 1023);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
|
ImGui::InputInt("##anothertest", &_this->port, 0, 0);
|
||||||
|
if (listening) { style::endDisabled(); }
|
||||||
|
|
||||||
|
int test = 0;
|
||||||
|
|
||||||
|
ImGui::Text("Controlled VFO");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
|
ImGui::Combo("##anotesssss", &test, "Radio\0");
|
||||||
|
|
||||||
|
ImGui::Text("Controlled Recorder");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
|
ImGui::Combo("##anotesssss2", &test, "Recorder\0");
|
||||||
|
|
||||||
|
if (listening && ImGui::Button("Stop##lasttestamirite", ImVec2(menuWidth, 0))) {
|
||||||
|
if (_this->client) { _this->client->close(); }
|
||||||
|
_this->listener->close();
|
||||||
|
}
|
||||||
|
else if (!listening && ImGui::Button("Start##lasttestamirite", ImVec2(menuWidth, 0))) {
|
||||||
|
try {
|
||||||
|
_this->listener = net::listen(net::PROTO_TCP, _this->hostname, _this->port);
|
||||||
|
_this->listener->acceptAsync(clientHandler, _this);
|
||||||
|
}
|
||||||
|
catch (std::exception e) {
|
||||||
|
spdlog::error("Could not start rigctl server: {0}", e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Text("Status:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (_this->client && _this->client->isOpen()) {
|
||||||
|
ImGui::TextColored(ImVec4(0.0, 1.0, 0.0, 1.0), "Connected");
|
||||||
|
}
|
||||||
|
else if (listening) {
|
||||||
|
ImGui::TextColored(ImVec4(1.0, 1.0, 0.0, 1.0), "Listening");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ImGui::Text("Idle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clientHandler(net::Conn _client, void* ctx) {
|
||||||
|
SigctlServerModule* _this = (SigctlServerModule*)ctx;
|
||||||
|
spdlog::info("New client!");
|
||||||
|
|
||||||
|
_this->client = std::move(_client);
|
||||||
|
_this->client->readAsync(1024, _this->dataBuf, dataHandler, _this);
|
||||||
|
_this->client->waitForEnd();
|
||||||
|
_this->client->close();
|
||||||
|
|
||||||
|
spdlog::info("Client disconnected!");
|
||||||
|
|
||||||
|
_this->listener->acceptAsync(clientHandler, _this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dataHandler(int count, uint8_t* data, void* ctx) {
|
||||||
|
SigctlServerModule* _this = (SigctlServerModule*)ctx;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (data[i] == '\n') {
|
||||||
|
_this->commandHandler(_this->command);
|
||||||
|
_this->command.clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_this->command += (char)data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
_this->client->readAsync(1024, _this->dataBuf, dataHandler, _this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void commandHandler(std::string cmd) {
|
||||||
|
std::string corr = "";
|
||||||
|
std::vector<std::string> parts;
|
||||||
|
bool lastWasSpace = false;
|
||||||
|
std::string resp = "";
|
||||||
|
|
||||||
|
// Split command into parts and remove excess spaces
|
||||||
|
for (char c : cmd) {
|
||||||
|
if (lastWasSpace && c == ' ') { continue; }
|
||||||
|
else if (c == ' ') {
|
||||||
|
parts.push_back(corr);
|
||||||
|
corr.clear();
|
||||||
|
lastWasSpace = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lastWasSpace = false;
|
||||||
|
corr += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!corr.empty()) {
|
||||||
|
parts.push_back(corr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: THIS STUFF ISN'T THREADSAFE AND WILL LIKELY BREAK.
|
||||||
|
|
||||||
|
// Execute commands
|
||||||
|
if (parts.size() == 0) { return; }
|
||||||
|
else if (parts[0] == "F") {
|
||||||
|
// if number of arguments isn't correct, return error
|
||||||
|
if (parts.size() != 2) {
|
||||||
|
resp = "RPRT 1\n";
|
||||||
|
client->write(resp.size(), (uint8_t*)resp.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse frequency and assign it to the VFO
|
||||||
|
long long freq = std::stoll(parts[1]);
|
||||||
|
resp = "RPRT 0\n";
|
||||||
|
client->write(resp.size(), (uint8_t*)resp.c_str());
|
||||||
|
tuner::tune(tuner::TUNER_MODE_NORMAL, gui::waterfall.selectedVFO, freq);
|
||||||
|
}
|
||||||
|
else if (parts[0] == "f") {
|
||||||
|
double freq = gui::waterfall.getCenterFrequency();
|
||||||
|
|
||||||
|
// Get frequency of VFO if it exists
|
||||||
|
if (sigpath::vfoManager.vfoExists(gui::waterfall.selectedVFO)) {
|
||||||
|
freq += sigpath::vfoManager.getOffset(gui::waterfall.selectedVFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[128];
|
||||||
|
sprintf(buf, "%" PRIu64, (uint64_t)freq);
|
||||||
|
client->write(strlen(buf), (uint8_t*)buf);
|
||||||
|
}
|
||||||
|
else if (parts[0] == "AOS") {
|
||||||
|
// TODO: Start Recorder
|
||||||
|
core::modComManager.callInterface("Recorder", RECORDER_IFACE_CMD_START, NULL, NULL);
|
||||||
|
}
|
||||||
|
else if (parts[0] == "LOS") {
|
||||||
|
// TODO: Stop Recorder
|
||||||
|
core::modComManager.callInterface("Recorder", RECORDER_IFACE_CMD_STOP, NULL, NULL);
|
||||||
|
}
|
||||||
|
else if (parts[0] == "q") {
|
||||||
|
// Will close automatically
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
spdlog::error("Rigctl client sent invalid command: '{0}'", cmd);
|
||||||
|
resp = "RPRT 1\n";
|
||||||
|
client->write(resp.size(), (uint8_t*)resp.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
bool enabled = true;
|
||||||
|
|
||||||
|
char hostname[1024];
|
||||||
|
int port = 4532;
|
||||||
|
uint8_t dataBuf[1024];
|
||||||
|
net::Listener listener;
|
||||||
|
net::Conn client;
|
||||||
|
|
||||||
|
std::string command = "";
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
MOD_EXPORT void _INIT_() {
|
||||||
|
// Nothing here
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
||||||
|
return new SigctlServerModule(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
|
||||||
|
delete (SigctlServerModule*)instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD_EXPORT void _END_() {
|
||||||
|
// Nothing here
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user