Fixed support in the module manager

This commit is contained in:
Ryzerth 2021-07-26 03:11:51 +02:00
parent b327bfbe5d
commit 85de72a859
37 changed files with 369 additions and 138 deletions

View File

@ -50,15 +50,18 @@ public:
std::string devSerial = config.conf["device"]; std::string devSerial = config.conf["device"];
config.release(); config.release();
selectByString(devSerial); selectByString(devSerial);
core::setInputSampleRate(sampleRate);
sigpath::sourceManager.registerSource("Airspy", &handler); sigpath::sourceManager.registerSource("Airspy", &handler);
} }
~AirspySourceModule() { ~AirspySourceModule() {
stop(this);
sigpath::sourceManager.unregisterSource("Airspy");
airspy_exit(); airspy_exit();
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -46,15 +46,17 @@ public:
std::string devSerial = config.conf["device"]; std::string devSerial = config.conf["device"];
config.release(); config.release();
selectByString(devSerial); selectByString(devSerial);
core::setInputSampleRate(sampleRate);
sigpath::sourceManager.registerSource("Airspy HF+", &handler); sigpath::sourceManager.registerSource("Airspy HF+", &handler);
} }
~AirspyHFSourceModule() { ~AirspyHFSourceModule() {
stop(this);
sigpath::sourceManager.unregisterSource("Airspy HF+");
} }
void postInit() {}
enum AGCMode { enum AGCMode {
AGC_MODE_OFF, AGC_MODE_OFF,
AGC_MODE_LOW, AGC_MODE_LOW,

View File

@ -251,6 +251,8 @@ public:
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -50,15 +50,17 @@ public:
std::string serial = config.conf["device"]; std::string serial = config.conf["device"];
config.release(); config.release();
selectBySerial(serial); selectBySerial(serial);
core::setInputSampleRate(sampleRate);
sigpath::sourceManager.registerSource("BladeRF", &handler); sigpath::sourceManager.registerSource("BladeRF", &handler);
} }
~BladeRFSourceModule() { ~BladeRFSourceModule() {
stop(this);
sigpath::sourceManager.unregisterSource("BladeRF");
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -77,6 +77,7 @@ namespace dsp {
// NOTE: For some reason, the base class destrcutor doesn't get called.... this is a temporary fix I guess // NOTE: For some reason, the base class destrcutor doesn't get called.... this is a temporary fix I guess
// I also don't check for _block_init for the exact sample reason, something's weird // I also don't check for _block_init for the exact sample reason, something's weird
~Reshaper() { ~Reshaper() {
if (!generic_block<Reshaper<T>>::_block_init) { return; }
generic_block<Reshaper<T>>::stop(); generic_block<Reshaper<T>>::stop();
} }

View File

@ -47,6 +47,7 @@ namespace dsp {
void updateWindow(dsp::filter_window::generic_complex_window* window) { void updateWindow(dsp::filter_window::generic_complex_window* window) {
assert(generic_block<FMStereoDemuxPilotFilter>::_block_init); assert(generic_block<FMStereoDemuxPilotFilter>::_block_init);
std::lock_guard<std::mutex> lck(generic_block<FMStereoDemuxPilotFilter>::ctrlMtx); std::lock_guard<std::mutex> lck(generic_block<FMStereoDemuxPilotFilter>::ctrlMtx);
std::lock_guard<std::mutex> lck2(bufMtx);
_window = window; _window = window;
volk_free(taps); volk_free(taps);
tapCount = window->getTapCount(); tapCount = window->getTapCount();
@ -59,7 +60,7 @@ namespace dsp {
int count = _in->read(); int count = _in->read();
if (count < 0) { return -1; } if (count < 0) { return -1; }
generic_block<FMStereoDemuxPilotFilter>::ctrlMtx.lock(); bufMtx.lock();
memcpy(bufStart, _in->readBuf, count * sizeof(complex_t)); memcpy(bufStart, _in->readBuf, count * sizeof(complex_t));
_in->flush(); _in->flush();
@ -70,12 +71,14 @@ namespace dsp {
memcpy(dataOut.writeBuf, &buffer[tapCount - ((tapCount-1)/2)], count * sizeof(complex_t)); memcpy(dataOut.writeBuf, &buffer[tapCount - ((tapCount-1)/2)], count * sizeof(complex_t));
if (!dataOut.swap(count)) { return -1; } if (!pilotOut.swap(count) || !dataOut.swap(count)) {
if (!pilotOut.swap(count)) { return -1; } bufMtx.unlock();
return -1;
}
memmove(buffer, &buffer[count], tapCount * sizeof(complex_t)); memmove(buffer, &buffer[count], tapCount * sizeof(complex_t));
generic_block<FMStereoDemuxPilotFilter>::ctrlMtx.unlock(); bufMtx.unlock();
return count; return count;
} }
@ -89,6 +92,8 @@ namespace dsp {
dsp::filter_window::generic_complex_window* _window; dsp::filter_window::generic_complex_window* _window;
std::mutex bufMtx;
complex_t* bufStart; complex_t* bufStart;
complex_t* buffer; complex_t* buffer;
int tapCount; int tapCount;

View File

@ -212,7 +212,7 @@ void MainWindow::init() {
initComplete = true; initComplete = true;
onInitComplete.emit(true); core::moduleManager.doPostInitAll();
} }
void MainWindow::fftHandler(dsp::complex_t* samples, int count, void* ctx) { void MainWindow::fftHandler(dsp::complex_t* samples, int count, void* ctx) {

View File

@ -35,7 +35,6 @@ public:
bool playButtonLocked = false; bool playButtonLocked = false;
Event<bool> onPlayStateChange; Event<bool> onPlayStateChange;
Event<bool> onInitComplete;
private: private:
void generateFFTWindow(int win, int size); void generateFFTWindow(int win, int size);

View File

@ -16,11 +16,6 @@ namespace module_manager_menu {
modTypes.clear(); modTypes.clear();
modTypesTxt = ""; modTypesTxt = "";
for (auto& [name, mod] : core::moduleManager.modules) { for (auto& [name, mod] : core::moduleManager.modules) {
// TEMPORARY EXCLUSION FOR SOURCES AND SINKS
if (name.find("source") != std::string::npos) { continue; }
if (name.find("sink") != std::string::npos) { continue; }
if (name.find("recorder") != std::string::npos) { continue; }
if (name.find("discord") != std::string::npos) { continue; }
modTypes.push_back(name); modTypes.push_back(name);
modTypesTxt += name; modTypesTxt += name;
modTypesTxt += '\0'; modTypesTxt += '\0';
@ -38,13 +33,6 @@ namespace module_manager_menu {
float height = ImGui::CalcTextSize("-").y; float height = ImGui::CalcTextSize("-").y;
for (auto& [name, inst] : core::moduleManager.instances) { for (auto& [name, inst] : core::moduleManager.instances) {
// TEMPORARY EXCLUSION FOR SOURCES AND SINKS
std::string type = inst.module.info->name;
if (type.find("source") != std::string::npos) { continue; }
if (type.find("sink") != std::string::npos) { continue; }
if (type.find("recorder") != std::string::npos) { continue; }
if (type.find("discord") != std::string::npos) { continue; }
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0); ImGui::TableSetColumnIndex(0);
@ -83,6 +71,7 @@ namespace module_manager_menu {
if (strlen(modName) == 0) { style::beginDisabled(); } if (strlen(modName) == 0) { style::beginDisabled(); }
if (ImGui::Button("+##module_mgr_add_btn", ImVec2(16,0))) { if (ImGui::Button("+##module_mgr_add_btn", ImVec2(16,0))) {
core::moduleManager.createInstance(modName, modTypes[modTypeId]); core::moduleManager.createInstance(modName, modTypes[modTypeId]);
core::moduleManager.postInit(modName);
} }
if (strlen(modName) == 0) { style::endDisabled(); } if (strlen(modName) == 0) { style::endDisabled(); }
ImGui::EndTable(); ImGui::EndTable();

View File

@ -12,6 +12,14 @@ namespace sourecmenu {
double customOffset = 0.0; double customOffset = 0.0;
double effectiveOffset = 0.0; double effectiveOffset = 0.0;
EventHandler<std::string> sourceRegisteredHandler;
EventHandler<std::string> sourceUnregisterHandler;
EventHandler<std::string> sourceUnregisteredHandler;
std::vector<std::string> sourceNames;
std::string sourceNamesTxt;
std::string selectedSource;
enum { enum {
OFFSET_MODE_NONE, OFFSET_MODE_NONE,
OFFSET_MODE_CUSTOM, OFFSET_MODE_CUSTOM,
@ -42,41 +50,94 @@ namespace sourecmenu {
sigpath::sourceManager.setTuningOffset(effectiveOffset); sigpath::sourceManager.setTuningOffset(effectiveOffset);
} }
void refreshSources() {
sourceNames = sigpath::sourceManager.getSourceNames();
sourceNamesTxt.clear();
for (auto name : sourceNames) {
sourceNamesTxt += name;
sourceNamesTxt += '\0';
}
}
void selectSource(std::string name) {
if (sourceNames.empty()) {
selectedSource.clear();
return;
}
auto it = std::find(sourceNames.begin(), sourceNames.end(), name);
if (it == sourceNames.end()) {
selectSource(sourceNames[0]);
}
sourceId = std::distance(sourceNames.begin(), it);
selectedSource = sourceNames[sourceId];
sigpath::sourceManager.selectSource(sourceNames[sourceId]);
}
void onSourceRegistered(std::string name, void* ctx) {
refreshSources();
if (selectedSource.empty()) {
sourceId = 0;
selectSource(sourceNames[0]);
return;
}
sourceId = std::distance(sourceNames.begin(), std::find(sourceNames.begin(), sourceNames.end(), selectedSource));
}
void onSourceUnregister(std::string name, void* ctx) {
if (name != selectedSource) { return; }
// TODO: Stop everything
}
void onSourceUnregistered(std::string name, void* ctx) {
refreshSources();
if (sourceNames.empty()) {
selectedSource = "";
return;
}
if (name == selectedSource) {
sourceId = std::clamp<int>(sourceId, 0, sourceNames.size() - 1);
selectSource(sourceNames[sourceId]);
return;
}
sourceId = std::distance(sourceNames.begin(), std::find(sourceNames.begin(), sourceNames.end(), selectedSource));
}
void init() { void init() {
core::configManager.acquire(); core::configManager.acquire();
std::string name = core::configManager.conf["source"]; std::string selected = core::configManager.conf["source"];
auto it = std::find(sigpath::sourceManager.sourceNames.begin(), sigpath::sourceManager.sourceNames.end(), name);
if (it != sigpath::sourceManager.sourceNames.end()) {
sigpath::sourceManager.selectSource(name);
sourceId = std::distance(sigpath::sourceManager.sourceNames.begin(), it);
}
else if (sigpath::sourceManager.sourceNames.size() > 0) {
sigpath::sourceManager.selectSource(sigpath::sourceManager.sourceNames[0]);
}
else {
spdlog::warn("No source available...");
}
customOffset = core::configManager.conf["offset"]; customOffset = core::configManager.conf["offset"];
offsetMode = core::configManager.conf["offsetMode"]; offsetMode = core::configManager.conf["offsetMode"];
updateOffset(); updateOffset();
refreshSources();
selectSource(selected);
sourceRegisteredHandler.handler = onSourceRegistered;
sourceUnregisterHandler.handler = onSourceUnregister;
sourceUnregisteredHandler.handler = onSourceUnregistered;
sigpath::sourceManager.onSourceRegistered.bindHandler(&sourceRegisteredHandler);
sigpath::sourceManager.onSourceUnregister.bindHandler(&sourceUnregisterHandler);
sigpath::sourceManager.onSourceUnregistered.bindHandler(&sourceUnregisteredHandler);
core::configManager.release(); core::configManager.release();
} }
void draw(void* ctx) { void draw(void* ctx) {
std::string items = "";
for (std::string name : sigpath::sourceManager.sourceNames) {
items += name;
items += '\0';
}
float itemWidth = ImGui::GetContentRegionAvailWidth(); float itemWidth = ImGui::GetContentRegionAvailWidth();
if (gui::mainWindow.sdrIsRunning()) { style::beginDisabled(); } if (gui::mainWindow.sdrIsRunning()) { style::beginDisabled(); }
ImGui::SetNextItemWidth(itemWidth); ImGui::SetNextItemWidth(itemWidth);
if (ImGui::Combo("##source", &sourceId, items.c_str())) { if (ImGui::Combo("##source", &sourceId, sourceNamesTxt.c_str())) {
sigpath::sourceManager.selectSource(sigpath::sourceManager.sourceNames[sourceId]); selectSource(sourceNames[sourceId]);
core::configManager.acquire(); core::configManager.acquire();
core::configManager.conf["source"] = sigpath::sourceManager.sourceNames[sourceId]; core::configManager.conf["source"] = sourceNames[sourceId];
core::configManager.release(true); core::configManager.release(true);
} }
@ -110,6 +171,5 @@ namespace sourecmenu {
ImGui::InputDouble("##freq_offset", &effectiveOffset, 1.0, 100.0); ImGui::InputDouble("##freq_offset", &effectiveOffset, 1.0, 100.0);
style::endDisabled(); style::endDisabled();
} }
} }
} }

View File

@ -140,6 +140,14 @@ bool ModuleManager::instanceEnabled(std::string name) {
return instances[name].instance->isEnabled(); return instances[name].instance->isEnabled();
} }
void ModuleManager::postInit(std::string name) {
if (instances.find(name) == instances.end()) {
spdlog::error("Cannot post-init '{0}', instance doesn't exist", name);
return;
}
instances[name].instance->postInit();
}
std::string ModuleManager::getInstanceModuleName(std::string name) { std::string ModuleManager::getInstanceModuleName(std::string name) {
if (instances.find(name) == instances.end()) { if (instances.find(name) == instances.end()) {
spdlog::error("Cannot get module name of'{0}', instance doesn't exist", name); spdlog::error("Cannot get module name of'{0}', instance doesn't exist", name);
@ -159,4 +167,11 @@ int ModuleManager::countModuleInstances(std::string module) {
if (instance.module == mod) { count++; } if (instance.module == mod) { count++; }
} }
return count; return count;
}
void ModuleManager::doPostInitAll() {
for (auto& [name, inst] : instances) {
spdlog::info("Running post-init for {0}", name);
inst.instance->postInit();
}
} }

View File

@ -42,6 +42,7 @@ public:
class Instance { class Instance {
public: public:
virtual void postInit() = 0;
virtual void enable() = 0; virtual void enable() = 0;
virtual void disable() = 0; virtual void disable() = 0;
virtual bool isEnabled() = 0; virtual bool isEnabled() = 0;
@ -84,10 +85,13 @@ public:
void enableInstance(std::string name); void enableInstance(std::string name);
void disableInstance(std::string name); void disableInstance(std::string name);
bool instanceEnabled(std::string name); bool instanceEnabled(std::string name);
void postInit(std::string name);
std::string getInstanceModuleName(std::string name); std::string getInstanceModuleName(std::string name);
int countModuleInstances(std::string module); int countModuleInstances(std::string module);
void doPostInitAll();
Event<std::string> onInstanceCreated; Event<std::string> onInstanceCreated;
Event<std::string> onInstanceDelete; Event<std::string> onInstanceDelete;
Event<std::string> onInstanceDeleted; Event<std::string> onInstanceDeleted;

View File

@ -115,7 +115,7 @@ void SinkManager::registerStream(std::string name, SinkManager::Stream* stream)
core::configManager.release(); core::configManager.release();
if (available) { loadStreamConfig(name); } if (available) { loadStreamConfig(name); }
streamRegisteredEvnt.emit(name); onStreamRegistered.emit(name);
} }
void SinkManager::unregisterStream(std::string name) { void SinkManager::unregisterStream(std::string name) {
@ -123,12 +123,13 @@ void SinkManager::unregisterStream(std::string name) {
spdlog::error("Cannot unregister stream '{0}', this stream doesn't exist", name); spdlog::error("Cannot unregister stream '{0}', this stream doesn't exist", name);
return; return;
} }
streamUnregisteredEvnt.emit(name); onStreamUnregister.emit(name);
SinkManager::Stream* stream = streams[name]; SinkManager::Stream* stream = streams[name];
stream->stop(); stream->stop();
delete stream->sink; delete stream->sink;
streams.erase(name); streams.erase(name);
streamNames.erase(std::remove(streamNames.begin(), streamNames.end(), name), streamNames.end()); streamNames.erase(std::remove(streamNames.begin(), streamNames.end(), name), streamNames.end());
onStreamUnregistered.emit(name);
} }
void SinkManager::startStream(std::string name) { void SinkManager::startStream(std::string name) {

View File

@ -110,8 +110,9 @@ public:
std::vector<std::string> getStreamNames(); std::vector<std::string> getStreamNames();
Event<std::string> streamRegisteredEvnt; Event<std::string> onStreamRegistered;
Event<std::string> streamUnregisteredEvnt; Event<std::string> onStreamUnregister;
Event<std::string> onStreamUnregistered;
private: private:
void loadStreamConfig(std::string name); void loadStreamConfig(std::string name);

View File

@ -12,7 +12,27 @@ void SourceManager::registerSource(std::string name, SourceHandler* handler) {
return; return;
} }
sources[name] = handler; sources[name] = handler;
sourceNames.push_back(name); onSourceRegistered.emit(name);
}
void SourceManager::unregisterSource(std::string name) {
if (sources.find(name) == sources.end()) {
spdlog::error("Tried to unregister non existant source: {0}", name);
return;
}
onSourceUnregister.emit(name);
if (name == selectedName) {
sigpath::signalPath.setInput(&nullSource);
selectedHandler = NULL;
}
sources.erase(name);
onSourceUnregistered.emit(name);
}
std::vector<std::string> SourceManager::getSourceNames() {
std::vector<std::string> names;
for (auto const& [name, src] : sources) { names.push_back(name); }
return names;
} }
void SourceManager::selectSource(std::string name) { void SourceManager::selectSource(std::string name) {
@ -20,7 +40,7 @@ void SourceManager::selectSource(std::string name) {
spdlog::error("Tried to select non existant source: {0}", name); spdlog::error("Tried to select non existant source: {0}", name);
return; return;
} }
if (selectedName != "") { if (selectedHandler != NULL) {
sources[selectedName]->deselectHandler(sources[selectedName]->ctx); sources[selectedName]->deselectHandler(sources[selectedName]->ctx);
} }
selectedHandler = sources[name]; selectedHandler = sources[name];

View File

@ -4,6 +4,7 @@
#include <map> #include <map>
#include <dsp/stream.h> #include <dsp/stream.h>
#include <dsp/types.h> #include <dsp/types.h>
#include <utils/event.h>
class SourceManager { class SourceManager {
public: public:
@ -21,6 +22,7 @@ public:
}; };
void registerSource(std::string name, SourceHandler* handler); void registerSource(std::string name, SourceHandler* handler);
void unregisterSource(std::string name);
void selectSource(std::string name); void selectSource(std::string name);
void showSelectedMenu(); void showSelectedMenu();
void start(); void start();
@ -28,7 +30,11 @@ public:
void tune(double freq); void tune(double freq);
void setTuningOffset(double offset); void setTuningOffset(double offset);
std::vector<std::string> sourceNames; std::vector<std::string> getSourceNames();
Event<std::string> onSourceRegistered;
Event<std::string> onSourceUnregister;
Event<std::string> onSourceUnregistered;
private: private:
std::map<std::string, SourceHandler*> sources; std::map<std::string, SourceHandler*> sources;
@ -36,5 +42,6 @@ private:
SourceHandler* selectedHandler = NULL; SourceHandler* selectedHandler = NULL;
double tuneOffset; double tuneOffset;
double currentFreq; double currentFreq;
dsp::stream<dsp::complex_t> nullSource;
}; };

View File

@ -21,6 +21,8 @@ public:
gui::menu.removeEntry(name); gui::menu.removeEntry(name);
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -34,8 +34,12 @@ public:
// Change to timer stop later on // Change to timer stop later on
workerRunning = false; workerRunning = false;
if (workerThread.joinable()) { workerThread.join(); } if (workerThread.joinable()) { workerThread.join(); }
Discord_ClearPresence();
Discord_Shutdown();
} }
void postInit() {}
void enable() { void enable() {
// Change to timer start later on // Change to timer start later on
workerRunning = true; workerRunning = true;

View File

@ -5,7 +5,7 @@
#include <signal_path/signal_path.h> #include <signal_path/signal_path.h>
#include <module.h> #include <module.h>
#include <options.h> #include <options.h>
#include <gui/gui.h>
#include <dsp/pll.h> #include <dsp/pll.h>
#include <dsp/stream.h> #include <dsp/stream.h>
#include <dsp/demodulator.h> #include <dsp/demodulator.h>
@ -87,6 +87,8 @@ public:
} }
void postInit() {}
void enable() { void enable() {
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 4000000, INPUT_SAMPLE_RATE, 4000000, 4000000, true); vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 4000000, INPUT_SAMPLE_RATE, 4000000, 4000000, true);
@ -155,7 +157,7 @@ private:
if (ImGui::Button("Clear logs##GPSClear")) { _this->gpsLogs.clear(); } if (ImGui::Button("Clear logs##GPSClear")) { _this->gpsLogs.clear(); }
ImGui::BeginChild(ImGuiID("GPSChild")); ImGui::BeginChild(ImGuiID("GPSChild"));
ImGui::TextUnformatted(_this->gpsLogs.c_str()); ImGui::TextUnformatted(_this->gpsLogs.c_str());
ImGui::SetScrollHere(1.0f); ImGui::SetScrollHereY(1.0f);
ImGui::EndChild(); ImGui::EndChild();
ImGui::EndTabItem(); ImGui::EndTabItem();

View File

@ -41,15 +41,15 @@ public:
handler.tuneHandler = tune; handler.tuneHandler = tune;
handler.stream = &stream; handler.stream = &stream;
sigpath::sourceManager.registerSource("File", &handler); sigpath::sourceManager.registerSource("File", &handler);
spdlog::info("FileSourceModule '{0}': Instance created!", name);
} }
~FileSourceModule() { ~FileSourceModule() {
stop(this);
spdlog::info("FileSourceModule '{0}': Instance deleted!", name); sigpath::sourceManager.unregisterSource("File");
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -87,6 +87,8 @@ public:
gui::waterfall.onInputProcess.unbindHandler(&inputHandler); gui::waterfall.onInputProcess.unbindHandler(&inputHandler);
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -104,9 +104,12 @@ public:
} }
~HackRFSourceModule() { ~HackRFSourceModule() {
stop(this);
hackrf_exit(); hackrf_exit();
sigpath::sourceManager.unregisterSource("HackRF");
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;

View File

@ -44,15 +44,17 @@ public:
// Select device from config // Select device from config
selectFirst(); selectFirst();
core::setInputSampleRate(sampleRate);
sigpath::sourceManager.registerSource("LimeSDR", &handler); sigpath::sourceManager.registerSource("LimeSDR", &handler);
} }
~LimeSDRSourceModule() { ~LimeSDRSourceModule() {
// Exit limesuite if needed stop(this);
sigpath::sourceManager.unregisterSource("LimeSDR");
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -94,6 +94,8 @@ public:
gui::menu.removeEntry(name); gui::menu.removeEntry(name);
} }
void postInit() {}
void enable() { void enable() {
double bw = gui::waterfall.getBandwidth(); double bw = gui::waterfall.getBandwidth();
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, std::clamp<double>(0, -bw/2.0, bw/2.0), 150000, INPUT_SAMPLE_RATE, 150000, 150000, true); vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, std::clamp<double>(0, -bw/2.0, bw/2.0), 150000, INPUT_SAMPLE_RATE, 150000, 150000, true);

View File

@ -398,6 +398,8 @@ public:
Pa_Terminate(); Pa_Terminate();
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -50,14 +50,15 @@ public:
handler.tuneHandler = tune; handler.tuneHandler = tune;
handler.stream = &stream; handler.stream = &stream;
sigpath::sourceManager.registerSource("PlutoSDR", &handler); sigpath::sourceManager.registerSource("PlutoSDR", &handler);
spdlog::info("PlutoSDRSourceModule '{0}': Instance created!", name);
} }
~PlutoSDRSourceModule() { ~PlutoSDRSourceModule() {
spdlog::info("PlutoSDRSourceModule '{0}': Instance deleted!", name); stop(this);
sigpath::sourceManager.unregisterSource("PlutoSDR");
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -296,6 +296,8 @@ public:
Pa_Terminate(); Pa_Terminate();
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -79,6 +79,8 @@ public:
sigpath::sinkManager.unregisterStream(name); sigpath::sinkManager.unregisterStream(name);
} }
void postInit() {}
void enable() { void enable() {
double bw = gui::waterfall.getBandwidth(); double bw = gui::waterfall.getBandwidth();
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, std::clamp<double>(0, -bw/2.0, bw/2.0), 200000, 200000, 50000, 200000, false); vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, std::clamp<double>(0, -bw/2.0, bw/2.0), 200000, 200000, 50000, 200000, false);

View File

@ -84,40 +84,51 @@ public:
wavSampleBuf = new int16_t[2 * STREAM_BUFFER_SIZE]; wavSampleBuf = new int16_t[2 * STREAM_BUFFER_SIZE];
refreshStreams();
gui::menu.registerEntry(name, menuHandler, this); gui::menu.registerEntry(name, menuHandler, this);
core::modComManager.registerInterface("recorder", name, moduleInterfaceHandler, this); core::modComManager.registerInterface("recorder", name, moduleInterfaceHandler, this);
streamRegisteredHandler.handler = onStreamRegistered;
streamRegisteredHandler.ctx = this;
streamUnregisterHandler.handler = onStreamUnregister;
streamUnregisterHandler.ctx = this;
streamUnregisteredHandler.handler = onStreamUnregistered;
streamUnregisteredHandler.ctx = this;
sigpath::sinkManager.onStreamRegistered.bindHandler(&streamRegisteredHandler);
sigpath::sinkManager.onStreamUnregister.bindHandler(&streamUnregisterHandler);
sigpath::sinkManager.onStreamUnregistered.bindHandler(&streamUnregisteredHandler);
} }
~RecorderModule() { ~RecorderModule() {
std::lock_guard lck(recMtx);
gui::menu.removeEntry(name);
core::modComManager.unregisterInterface(name); core::modComManager.unregisterInterface(name);
// Stop recording // Stop recording
if (recording) { if (recording) { stopRecording(); }
if (recMode == RECORDER_MODE_AUDIO) {
audioSplit.unbindStream(&audioHandlerStream); if (audioInput != NULL) { sigpath::sinkManager.unbindStream(selectedStreamName, audioInput); }
audioHandler.stop();
audioWriter->close(); sigpath::sinkManager.onStreamRegistered.unbindHandler(&streamRegisteredHandler);
delete audioWriter; sigpath::sinkManager.onStreamUnregister.unbindHandler(&streamUnregisterHandler);
} sigpath::sinkManager.onStreamUnregistered.unbindHandler(&streamUnregisteredHandler);
else {
sigpath::signalPath.unbindIQStream(&basebandStream);
basebandHandler.stop();
basebandWriter->close();
delete basebandWriter;
}
}
vol.stop(); vol.stop();
audioSplit.stop(); audioSplit.stop();
meter.stop(); meter.stop();
gui::menu.removeEntry(name);
delete[] wavSampleBuf; delete[] wavSampleBuf;
} }
void postInit() {
refreshStreams();
if (selectedStreamName == "") {
selectStream(streamNames[0]);
}
else {
selectStream(selectedStreamName);
}
}
void enable() { void enable() {
enabled = true; enabled = true;
} }
@ -134,35 +145,39 @@ private:
void refreshStreams() { void refreshStreams() {
std::vector<std::string> names = sigpath::sinkManager.getStreamNames(); std::vector<std::string> names = sigpath::sinkManager.getStreamNames();
// If there are no stream, cancel
if (names.size() == 0) { return; }
// List streams
streamNames.clear(); streamNames.clear();
streamNamesTxt = ""; streamNamesTxt = "";
// If there are no stream, cancel
if (names.size() == 0) {return; }
// List streams
for (auto const& name : names) { for (auto const& name : names) {
streamNames.push_back(name); streamNames.push_back(name);
streamNamesTxt += name; streamNamesTxt += name;
streamNamesTxt += '\0'; streamNamesTxt += '\0';
} }
if (selectedStreamName == "") {
selectStream(streamNames[0]);
}
else {
selectStream(selectedStreamName);
}
} }
void selectStream(std::string name) { void selectStream(std::string name) {
if (streamNames.empty()) {
selectedStreamName = "";
return;
}
auto it = std::find(streamNames.begin(), streamNames.end(), name); auto it = std::find(streamNames.begin(), streamNames.end(), name);
if (it == streamNames.end()) { return; } if (it == streamNames.end()) {
selectStream(streamNames[0]);
return;
}
streamId = std::distance(streamNames.begin(), it); streamId = std::distance(streamNames.begin(), it);
vol.stop(); vol.stop();
if (audioInput != NULL) { sigpath::sinkManager.unbindStream(selectedStreamName, audioInput); } if (audioInput != NULL) { sigpath::sinkManager.unbindStream(selectedStreamName, audioInput); }
audioInput = sigpath::sinkManager.bindStream(name); audioInput = sigpath::sinkManager.bindStream(name);
if (audioInput == NULL) { return; } if (audioInput == NULL) {
selectedStreamName = "";
return;
}
selectedStreamName = name; selectedStreamName = name;
vol.setInput(audioInput); vol.setInput(audioInput);
vol.start(); vol.start();
@ -237,8 +252,6 @@ private:
ImGui::PushItemWidth(menuColumnWidth); ImGui::PushItemWidth(menuColumnWidth);
if (streamNames.size() == 0) { if (streamNames.size() == 0) {
refreshStreams();
ImGui::PopItemWidth();
return; return;
} }
@ -339,6 +352,9 @@ private:
} }
} }
else if (recMode == RECORDER_MODE_AUDIO) { else if (recMode == RECORDER_MODE_AUDIO) {
if (selectedStreamName.empty()) {
spdlog::error("Cannot record with no selected stream");
}
samplesWritten = 0; samplesWritten = 0;
std::string expandedPath = expandString(folderSelect.path + genFileName("/audio_", true, selectedStreamName)); std::string expandedPath = expandString(folderSelect.path + genFileName("/audio_", true, selectedStreamName));
sampleRate = sigpath::sinkManager.getStreamSampleRate(selectedStreamName); sampleRate = sigpath::sinkManager.getStreamSampleRate(selectedStreamName);
@ -372,6 +388,69 @@ private:
} }
} }
static void onStreamRegistered(std::string name, void* ctx){
RecorderModule* _this = (RecorderModule*)ctx;
_this->refreshStreams();
if (_this->streamNames.empty()) {
_this->selectedStreamName = "";
return;
}
if (_this->selectedStreamName.empty()) {
_this->streamId = 0;
_this->selectedStreamName = _this->streamNames[0];
return;
}
// Reselect stream in UI to make sure the ID is correct
int id = 0;
for (auto& str : _this->streamNames) {
if (str == _this->selectedStreamName) {
_this->streamId = id;
break;
}
id++;
}
}
static void onStreamUnregister(std::string name, void* ctx){
RecorderModule* _this = (RecorderModule*)ctx;
if (name != _this->selectedStreamName) { return; }
if (_this->recording) { _this->stopRecording(); }
if (_this->audioInput != NULL) {
sigpath::sinkManager.unbindStream(_this->selectedStreamName, _this->audioInput);
_this->audioInput = NULL;
}
}
static void onStreamUnregistered(std::string name, void* ctx){
RecorderModule* _this = (RecorderModule*)ctx;
_this->refreshStreams();
if (_this->streamNames.empty()) {
_this->selectedStreamName = "";
return;
}
// If current stream was deleted, reselect steam completely
if (name == _this->selectedStreamName) {
_this->streamId = std::clamp<int>(_this->streamId, 0, _this->streamNames.size() - 1);
_this->selectStream(_this->streamNames[_this->streamId]);
return;
}
// Reselect stream in UI to make sure the ID is correct
int id = 0;
for (auto& str : _this->streamNames) {
if (str == _this->selectedStreamName) {
_this->streamId = id;
break;
}
id++;
}
}
std::string name; std::string name;
bool enabled = true; bool enabled = true;
@ -415,6 +494,10 @@ private:
uint64_t samplesWritten; uint64_t samplesWritten;
int16_t* wavSampleBuf; int16_t* wavSampleBuf;
EventHandler<std::string> streamRegisteredHandler;
EventHandler<std::string> streamUnregisterHandler;
EventHandler<std::string> streamUnregisteredHandler;
}; };
struct RecorderContext_t { struct RecorderContext_t {

View File

@ -53,16 +53,41 @@ public:
selectedRecorder = config.conf[name]["recorder"]; selectedRecorder = config.conf[name]["recorder"];
config.release(true); config.release(true);
initHandler.handler = _initHandler;
initHandler.ctx = this;
gui::mainWindow.onInitComplete.bindHandler(&initHandler);
gui::menu.registerEntry(name, menuHandler, this, NULL); gui::menu.registerEntry(name, menuHandler, this, NULL);
} }
~SigctlServerModule() { ~SigctlServerModule() {
gui::menu.removeEntry(name); gui::menu.removeEntry(name);
// TODO: Use several handler instead of one for the recorders and remove event bindings sigpath::vfoManager.onVfoCreated.unbindHandler(&vfoCreatedHandler);
sigpath::vfoManager.onVfoDeleted.unbindHandler(&vfoDeletedHandler);
core::moduleManager.onInstanceCreated.unbindHandler(&modChangedHandler);
core::moduleManager.onInstanceDeleted.unbindHandler(&modChangedHandler);
if (client) { client->close(); }
if (listener) { listener->close(); }
}
void postInit() {
// Refresh modules
refreshModules();
// Select VFO and recorder from config
selectVfoByName(selectedVfo);
selectRecorderByName(selectedRecorder);
// Bind handlers
vfoCreatedHandler.handler = _vfoCreatedHandler;
vfoCreatedHandler.ctx = this;
vfoDeletedHandler.handler = _vfoDeletedHandler;
vfoDeletedHandler.ctx = this;
modChangedHandler.handler = _modChangeHandler;
modChangedHandler.ctx = this;
sigpath::vfoManager.onVfoCreated.bindHandler(&vfoCreatedHandler);
sigpath::vfoManager.onVfoDeleted.bindHandler(&vfoDeletedHandler);
core::moduleManager.onInstanceCreated.bindHandler(&modChangedHandler);
core::moduleManager.onInstanceDeleted.bindHandler(&modChangedHandler);
// If autostart is enabled, start the server
if (autoStart) { startServer(); }
} }
void enable() { void enable() {
@ -262,32 +287,6 @@ private:
} }
} }
static void _initHandler(bool dummy, void* ctx) {
SigctlServerModule* _this = (SigctlServerModule*)ctx;
// Refresh modules
_this->refreshModules();
// Select VFO and recorder from config
_this->selectVfoByName(_this->selectedVfo);
_this->selectRecorderByName(_this->selectedRecorder);
// Bind handlers
_this->vfoCreatedHandler.handler = _vfoCreatedHandler;
_this->vfoCreatedHandler.ctx = _this;
_this->vfoDeletedHandler.handler = _vfoDeletedHandler;
_this->vfoDeletedHandler.ctx = _this;
_this->modChangedHandler.handler = _modChangeHandler;
_this->modChangedHandler.ctx = _this;
sigpath::vfoManager.onVfoCreated.bindHandler(&_this->vfoCreatedHandler);
sigpath::vfoManager.onVfoDeleted.bindHandler(&_this->vfoDeletedHandler);
core::moduleManager.onInstanceCreated.bindHandler(&_this->modChangedHandler);
core::moduleManager.onInstanceDeleted.bindHandler(&_this->modChangedHandler);
// If autostart is enabled, start the server
if (_this->autoStart) { _this->startServer(); }
}
static void _vfoCreatedHandler(VFOManager::VFO* vfo, void* ctx) { static void _vfoCreatedHandler(VFOManager::VFO* vfo, void* ctx) {
SigctlServerModule* _this = (SigctlServerModule*)ctx; SigctlServerModule* _this = (SigctlServerModule*)ctx;
_this->refreshModules(); _this->refreshModules();
@ -465,7 +464,6 @@ private:
std::string command = ""; std::string command = "";
EventHandler<bool> initHandler;
EventHandler<std::string> modChangedHandler; EventHandler<std::string> modChangedHandler;
EventHandler<VFOManager::VFO*> vfoCreatedHandler; EventHandler<VFOManager::VFO*> vfoCreatedHandler;
EventHandler<std::string> vfoDeletedHandler; EventHandler<std::string> vfoDeletedHandler;

View File

@ -88,15 +88,16 @@ public:
config.release(true); config.release(true);
selectByName(selectedDevName); selectByName(selectedDevName);
core::setInputSampleRate(sampleRate);
sigpath::sourceManager.registerSource("RTL-SDR", &handler); sigpath::sourceManager.registerSource("RTL-SDR", &handler);
} }
~RTLSDRSourceModule() { ~RTLSDRSourceModule() {
stop(this);
sigpath::sourceManager.unregisterSource("RTL-SDR");
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -87,9 +87,12 @@ public:
} }
~RTLTCPSourceModule() { ~RTLTCPSourceModule() {
stop(this);
sigpath::sourceManager.unregisterSource("RTL-TCP");
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -44,15 +44,16 @@ public:
selectFirst(); selectFirst();
core::setInputSampleRate(sampleRate);
sigpath::sourceManager.registerSource("SDDC", &handler); sigpath::sourceManager.registerSource("SDDC", &handler);
} }
~AirspyHFSourceModule() { ~AirspyHFSourceModule() {
stop(this);
sigpath::sourceManager.unregisterSource("SDDC");
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -155,9 +155,13 @@ public:
} }
~SDRPlaySourceModule() { ~SDRPlaySourceModule() {
stop(this);
sdrplay_api_Close(); sdrplay_api_Close();
sigpath::sourceManager.unregisterSource("SDRplay");
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -50,14 +50,15 @@ public:
handler.tuneHandler = tune; handler.tuneHandler = tune;
handler.stream = &stream; handler.stream = &stream;
sigpath::sourceManager.registerSource("SoapySDR", &handler); sigpath::sourceManager.registerSource("SoapySDR", &handler);
spdlog::info("SoapyModule '{0}': Instance created!", name);
} }
~SoapyModule() { ~SoapyModule() {
spdlog::info("SoapyModule '{0}': Instance deleted!", name); stop(this);
sigpath::sourceManager.unregisterSource("SoapySDR");
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -71,9 +71,12 @@ public:
} }
~AirspyHFSourceModule() { ~AirspyHFSourceModule() {
stop(this);
sigpath::sourceManager.unregisterSource("SpyServer");
} }
void postInit() {}
void enable() { void enable() {
enabled = true; enabled = true;
} }

View File

@ -67,6 +67,8 @@ public:
decoder->stop(); decoder->stop();
} }
void postInit() {}
void enable() { void enable() {
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 1000000, 1000000, 1000000, 1000000, true); vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 1000000, 1000000, 1000000, 1000000, true);
for (auto const& [name, dec] : decoders) { dec->setVFO(vfo); } for (auto const& [name, dec] : decoders) { dec->setVFO(vfo); }