Beginning of scheduler code

pull/521/head
AlexandreRouma 2021-11-14 18:30:58 +01:00
rodzic d20b41401f
commit 0ab4d16f9d
11 zmienionych plików z 419 dodań i 37 usunięć

Wyświetl plik

@ -45,6 +45,7 @@ option(OPT_BUILD_FREQUENCY_MANAGER "Build the Frequency Manager module" ON)
option(OPT_BUILD_RECORDER "Audio and baseband recorder" ON)
option(OPT_BUILD_RIGCTL_SERVER "Rigctl backend for controlling SDR++ with software like gpredict" ON)
option(OPT_BUILD_SCANNER "Frequency scanner" OFF)
option(OPT_BUILD_SCHEDULER "Build the scheduler" OFF)
# Other options
option(USE_INTERNAL_LIBCORRECT "Use an external version of libcorrect" ON)
@ -171,6 +172,10 @@ if (OPT_BUILD_SCANNER)
add_subdirectory("misc_modules/scanner")
endif (OPT_BUILD_SCANNER)
if (OPT_BUILD_SCHEDULER)
add_subdirectory("misc_modules/scheduler")
endif (OPT_BUILD_SCHEDULER)
add_executable(sdrpp "src/main.cpp" "win32/resources.rc")
target_link_libraries(sdrpp PRIVATE sdrpp_core)
@ -208,7 +213,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
add_custom_target(do_always ALL cp \"$<TARGET_FILE_DIR:sdrpp_core>/libsdrpp_core.dylib\" \"$<TARGET_FILE_DIR:sdrpp>\")
endif ()
# cmake .. "-DCMAKE_TOOLCHAIN_FILE=C:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake" -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_M17_DECODER=ON
# cmake .. "-DCMAKE_TOOLCHAIN_FILE=C:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake" -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_SCANNER=ON -DOPT_BUILD_SCHEDULER=ON
# Install directives
install(TARGETS sdrpp DESTINATION bin)

Wyświetl plik

@ -0,0 +1,35 @@
#pragma once
#include <string>
namespace utils {
std::string formatFreq(double freq) {
char str[128];
if (freq >= 1000000.0) {
sprintf(str, "%.06lf", freq / 1000000.0);
int len = strlen(str) - 1;
while ((str[len] == '0' || str[len] == '.') && len > 0) {
len--;
if (str[len] == '.') { len--; break; }
}
return std::string(str).substr(0, len + 1) + "MHz";
}
else if (freq >= 1000.0) {
sprintf(str, "%.06lf", freq / 1000.0);
int len = strlen(str) - 1;
while ((str[len] == '0' || str[len] == '.') && len > 0) {
len--;
if (str[len] == '.') { len--; break; }
}
return std::string(str).substr(0, len + 1) + "KHz";
}
else {
sprintf(str, "%.06lf", freq);
int len = strlen(str) - 1;
while ((str[len] == '0' || str[len] == '.') && len > 0) {
len--;
if (str[len] == '.') { len--; break; }
}
return std::string(str).substr(0, len + 1) + "Hz";
}
}
}

Wyświetl plik

@ -11,6 +11,7 @@
#include <vector>
#include <gui/tuner.h>
#include <gui/file_dialogs.h>
#include <utils/freq_formatting.h>
SDRPP_MOD_INFO {
/* Name: */ "frequency_manager",
@ -102,36 +103,6 @@ public:
}
private:
static std::string freqToStr(double freq) {
char str[128];
if (freq >= 1000000.0) {
sprintf(str, "%.06lf", freq / 1000000.0);
int len = strlen(str) - 1;
while ((str[len] == '0' || str[len] == '.') && len > 0) {
len--;
if (str[len] == '.') { len--; break; }
}
return std::string(str).substr(0, len + 1) + "MHz";
}
else if (freq >= 1000.0) {
sprintf(str, "%.06lf", freq / 1000.0);
int len = strlen(str) - 1;
while ((str[len] == '0' || str[len] == '.') && len > 0) {
len--;
if (str[len] == '.') { len--; break; }
}
return std::string(str).substr(0, len + 1) + "KHz";
}
else {
sprintf(str, "%.06lf", freq);
int len = strlen(str) - 1;
while ((str[len] == '0' || str[len] == '.') && len > 0) {
len--;
if (str[len] == '.') { len--; break; }
}
return std::string(str).substr(0, len + 1) + "Hz";
}
}
static void applyBookmark(FrequencyBookmark bm, std::string vfoName) {
if (vfoName == "") {
@ -525,7 +496,7 @@ private:
}
ImGui::TableSetColumnIndex(1);
ImGui::Text("%s %s", freqToStr(bm.frequency).c_str(), demodModeList[bm.mode]);
ImGui::Text("%s %s", utils::formatFreq(bm.frequency).c_str(), demodModeList[bm.mode]);
ImVec2 max = ImGui::GetCursorPos();
}
ImGui::EndTable();
@ -756,8 +727,8 @@ private:
ImGui::Text(hoveredBookmarkName.c_str());
ImGui::Separator();
ImGui::Text("List: %s", hoveredBookmark.listName.c_str());
ImGui::Text("Frequency: %s", freqToStr(hoveredBookmark.bookmark.frequency).c_str());
ImGui::Text("Bandwidth: %s", freqToStr(hoveredBookmark.bookmark.bandwidth).c_str());
ImGui::Text("Frequency: %s", utils::formatFreq(hoveredBookmark.bookmark.frequency).c_str());
ImGui::Text("Bandwidth: %s", utils::formatFreq(hoveredBookmark.bookmark.bandwidth).c_str());
ImGui::Text("Mode: %s", demodModeList[hoveredBookmark.bookmark.mode]);
ImGui::EndTooltip();
}

Wyświetl plik

@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.13)
project(scheduler)
file(GLOB SRC "src/*.cpp")
add_library(scheduler SHARED ${SRC})
target_link_libraries(scheduler PRIVATE sdrpp_core)
set_target_properties(scheduler PROPERTIES PREFIX "")
target_include_directories(scheduler PRIVATE "src/")
if (MSVC)
target_compile_options(scheduler PRIVATE /O2 /Ob2 /std:c++17 /EHsc)
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
target_compile_options(scheduler PRIVATE -O3 -std=c++17 -Wno-unused-command-line-argument -undefined dynamic_lookup)
else ()
target_compile_options(scheduler PRIVATE -O3 -std=c++17)
endif ()
# Install directives
install(TARGETS scheduler DESTINATION lib/sdrpp/plugins)

Wyświetl plik

@ -0,0 +1,46 @@
#pragma once
#include <sched_action.h>
namespace sched_action {
class StartRecorderClass : public ActionClass {
public:
StartRecorderClass() {}
~StartRecorderClass() {}
void trigger() {
}
void showEditMenu() {
}
void loadFromConfig(json config) {
if (config.contains("recorder")) { recorderName = config["recorder"]; }
}
json saveToConfig() {
json config;
config["recorder"] = recorderName;
return config;
}
std::string getName() {
return "Start \"" + recorderName + "\"";
}
bool isValid() {
return valid;
}
private:
std::string recorderName;
bool valid = false;
};
Action StartRecorder() {
return Action(new StartRecorderClass);
}
}

Wyświetl plik

@ -0,0 +1,53 @@
#pragma once
#include <sched_action.h>
#include <utils/freq_formatting.h>
namespace sched_action {
class TuneVFOClass : public ActionClass {
public:
TuneVFOClass() {}
~TuneVFOClass() {}
void trigger() {
}
void prepareEditMenu() {}
void validateEditMenu() {}
void showEditMenu() {
}
void loadFromConfig(json config) {
if (config.contains("vfo")) { vfoName = config["vfo"]; }
if (config.contains("frequency")) { frequency = config["frequency"]; }
}
json saveToConfig() {
json config;
config["vfo"] = vfoName;
config["frequency"] = frequency;
return config;
}
std::string getName() {
return "Tune \"" + vfoName + "\" to " + utils::formatFreq(frequency);
}
bool isValid() {
return valid;
}
private:
std::string vfoName;
double frequency;
bool valid = false;
};
Action TuneVFO() {
return Action(new TuneVFOClass);
}
}

Wyświetl plik

@ -0,0 +1,148 @@
#include <imgui.h>
#include <module.h>
#include <gui/gui.h>
#include <sched_task.h>
#include <map>
SDRPP_MOD_INFO {
/* Name: */ "scheduler",
/* Description: */ "SDR++ Scheduler",
/* Author: */ "Ryzerth",
/* Version: */ 0, 1, 0,
/* Max instances */ -1
};
class DemoModule : public ModuleManager::Instance {
public:
DemoModule(std::string name) {
this->name = name;
gui::menu.registerEntry(name, menuHandler, this, NULL);
Task t;
t.selected = false;
json recStartConfig;
recStartConfig["recorder"] = "Recorder";
json tuneVFOConfig;
tuneVFOConfig["vfo"] = "Radio";
tuneVFOConfig["frequency"] = 103500000.0;
auto recStart = sched_action::StartRecorder();
auto tuneVFO = sched_action::TuneVFO();
recStart->loadFromConfig(recStartConfig);
tuneVFO->loadFromConfig(tuneVFOConfig);
t.addAction(tuneVFO);
t.addAction(recStart);
tasks["Test"] = t;
tasks["Another test"] = t;
}
~DemoModule() {
gui::menu.removeEntry(name);
}
void postInit() {}
void enable() {
enabled = true;
}
void disable() {
enabled = false;
}
bool isEnabled() {
return enabled;
}
private:
static void menuHandler(void* ctx) {
DemoModule* _this = (DemoModule*)ctx;
// If editing, show menu
if (!_this->editedTask.empty()) {
gui::mainWindow.lockWaterfallControls = true;
std::string id = "Edit##scheduler_edit_task_" + _this->name;
ImGui::OpenPopup(id.c_str());
if (ImGui::BeginPopup(id.c_str(), ImGuiWindowFlags_NoResize)) {
bool valid = false;
bool open = _this->tasks[_this->editedTask].showEditMenu(_this->editedName, valid);
// Stop editing of closed
if (!open) {
// Rename if name changed and valid
if (valid && strcmp(_this->editedName, _this->editedTask.c_str())) {
Task task = _this->tasks[_this->editedTask];
_this->tasks.erase(_this->editedTask);
_this->tasks[_this->editedName] = task;
}
// Stop showing edit window
_this->editedTask.clear();
}
ImGui::EndPopup();
}
}
if (ImGui::BeginTable(("freq_manager_bkm_table"+_this->name).c_str(), 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, ImVec2(0, 200))) {
ImGui::TableSetupColumn("Name");
ImGui::TableSetupColumn("Countdown");
ImGui::TableSetupScrollFreeze(2, 1);
ImGui::TableHeadersRow();
for (auto& [name, bm] : _this->tasks) {
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImVec2 min = ImGui::GetCursorPos();
if (ImGui::Selectable((name + "##_freq_mgr_bkm_name_" + _this->name).c_str(), &bm.selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SelectOnClick)) {
// if shift or control isn't pressed, deselect all others
if (!ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT) && !ImGui::IsKeyDown(GLFW_KEY_RIGHT_SHIFT) &&
!ImGui::IsKeyDown(GLFW_KEY_LEFT_CONTROL) && !ImGui::IsKeyDown(GLFW_KEY_RIGHT_CONTROL)) {
for (auto& [_name, _bm] : _this->tasks) {
if (name == _name) { continue; }
_bm.selected = false;
}
}
}
if (ImGui::TableGetHoveredColumn() >= 0 && ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && _this->editedTask.empty()) {
_this->editedTask = name;
strcpy(_this->editedName, name.c_str());
}
ImGui::TableSetColumnIndex(1);
ImGui::Text("todo");
}
ImGui::EndTable();
}
}
std::string name;
bool enabled = true;
std::string editedTask = "";
char editedName[1024];
std::map<std::string, Task> tasks;
};
MOD_EXPORT void _INIT_() {
// Nothing here
}
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
return new DemoModule(name);
}
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
delete (DemoModule*)instance;
}
MOD_EXPORT void _END_() {
// Nothing here
}

Wyświetl plik

@ -0,0 +1,28 @@
#pragma once
#include <json.hpp>
#include <memory>
#include <spdlog/spdlog.h>
using namespace nlohmann;
namespace sched_action {
class ActionClass {
public:
virtual ~ActionClass() {
spdlog::warn("Base destructor");
};
virtual void trigger() = 0;
virtual void prepareEditMenu() = 0;
virtual void validateEditMenu() = 0;
virtual void showEditMenu() = 0;
virtual void loadFromConfig(json config) = 0;
virtual json saveToConfig() = 0;
virtual std::string getName() = 0;
virtual bool isValid() = 0;
};
typedef std::shared_ptr<ActionClass> Action;
}
#include <actions/start_recorder.h>
#include <actions/tune_vfo.h>

Wyświetl plik

@ -0,0 +1,75 @@
#pragma once
#include <vector>
#include <imgui.h>
#include <gui/style.h>
#include <sched_action.h>
class Task {
public:
void trigger() {
for (auto& act : actions) {
act->trigger();
}
}
void addAction(sched_action::Action act) {
actions.push_back(act);
}
bool removeAction(sched_action::Action act) {
auto it = std::find(actions.begin(), actions.end(), act);
if (it == actions.end()) { return false; }
actions.erase(it);
return true;
}
bool showEditMenu(char* name, bool& valid) {
ImGui::LeftLabel("Name");
ImGui::InputText("##scheduler_task_edit_name", name, 1023);
if (ImGui::BeginTable("scheduler_task_triggers", 1, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, ImVec2(0, 100))) {
ImGui::TableSetupColumn("Triggers");
ImGui::TableSetupScrollFreeze(1, 1);
ImGui::TableHeadersRow();
// Fill rows here
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text("Every day at 00:00:00");
ImGui::EndTable();
}
if (ImGui::BeginTable("scheduler_task_actions", 1, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, ImVec2(0, 100))) {
ImGui::TableSetupColumn("Actions");
ImGui::TableSetupScrollFreeze(1, 1);
ImGui::TableHeadersRow();
for (auto& act : actions) {
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text(act->getName().c_str());
}
ImGui::EndTable();
}
if (ImGui::Button("Apply")) {
valid = true;
return false;
}
ImGui::SameLine();
if (ImGui::Button("Cancel")) {
valid = false;
return false;
}
return true;
}
bool selected;
private:
std::vector<sched_action::Action> actions;
};

Wyświetl plik

@ -14,8 +14,8 @@
#define CONCAT(a, b) ((std::string(a) + b).c_str())
SDRPP_MOD_INFO {
/* Name: */ "spyserver_source",
/* Description: */ "Airspy HF+ source module for SDR++",
/* Name: */ "rfspace_source",
/* Description: */ "RFspace source module for SDR++",
/* Author: */ "Ryzerth",
/* Version: */ 0, 1, 0,
/* Max instances */ 1

Wyświetl plik

@ -15,7 +15,7 @@
SDRPP_MOD_INFO {
/* Name: */ "spyserver_source",
/* Description: */ "Airspy HF+ source module for SDR++",
/* Description: */ "SpyServer source module for SDR++",
/* Author: */ "Ryzerth",
/* Version: */ 0, 1, 0,
/* Max instances */ 1