kopia lustrzana https://github.com/AlexandreRouma/SDRPlusPlus
pushing work for the future new source system
rodzic
5b47f900a6
commit
c488d72ce2
|
@ -15,10 +15,6 @@ namespace sourcemenu {
|
|||
bool iqCorrection = false;
|
||||
bool invertIQ = false;
|
||||
|
||||
EventHandler<std::string> sourceRegisteredHandler;
|
||||
EventHandler<std::string> sourceUnregisterHandler;
|
||||
EventHandler<std::string> sourceUnregisteredHandler;
|
||||
|
||||
std::vector<std::string> sourceNames;
|
||||
std::string sourceNamesTxt;
|
||||
std::string selectedSource;
|
||||
|
@ -99,10 +95,10 @@ namespace sourcemenu {
|
|||
}
|
||||
sourceId = std::distance(sourceNames.begin(), it);
|
||||
selectedSource = sourceNames[sourceId];
|
||||
sigpath::sourceManager.selectSource(sourceNames[sourceId]);
|
||||
sigpath::sourceManager.select(sourceNames[sourceId]);
|
||||
}
|
||||
|
||||
void onSourceRegistered(std::string name, void* ctx) {
|
||||
void onSourceRegistered(std::string name) {
|
||||
refreshSources();
|
||||
|
||||
if (selectedSource.empty()) {
|
||||
|
@ -114,13 +110,13 @@ namespace sourcemenu {
|
|||
sourceId = std::distance(sourceNames.begin(), std::find(sourceNames.begin(), sourceNames.end(), selectedSource));
|
||||
}
|
||||
|
||||
void onSourceUnregister(std::string name, void* ctx) {
|
||||
void onSourceUnregister(std::string name) {
|
||||
if (name != selectedSource) { return; }
|
||||
|
||||
// TODO: Stop everything
|
||||
}
|
||||
|
||||
void onSourceUnregistered(std::string name, void* ctx) {
|
||||
void onSourceUnregistered(std::string name) {
|
||||
refreshSources();
|
||||
|
||||
if (sourceNames.empty()) {
|
||||
|
@ -153,12 +149,9 @@ namespace sourcemenu {
|
|||
selectSource(selected);
|
||||
sigpath::iqFrontEnd.setDecimation(1 << decimationPower);
|
||||
|
||||
sourceRegisteredHandler.handler = onSourceRegistered;
|
||||
sourceUnregisterHandler.handler = onSourceUnregister;
|
||||
sourceUnregisteredHandler.handler = onSourceUnregistered;
|
||||
sigpath::sourceManager.onSourceRegistered.bindHandler(&sourceRegisteredHandler);
|
||||
sigpath::sourceManager.onSourceUnregister.bindHandler(&sourceUnregisterHandler);
|
||||
sigpath::sourceManager.onSourceUnregistered.bindHandler(&sourceUnregisteredHandler);
|
||||
sigpath::sourceManager.onSourceRegistered.bind(onSourceRegistered);
|
||||
sigpath::sourceManager.onSourceUnregister.bind(onSourceUnregister);
|
||||
sigpath::sourceManager.onSourceUnregistered.bind(onSourceUnregistered);
|
||||
|
||||
core::configManager.release();
|
||||
}
|
||||
|
@ -179,7 +172,7 @@ namespace sourcemenu {
|
|||
|
||||
if (running) { style::endDisabled(); }
|
||||
|
||||
sigpath::sourceManager.showSelectedMenu();
|
||||
sigpath::sourceManager.showMenu();
|
||||
|
||||
if (ImGui::Checkbox("IQ Correction##_sdrpp_iq_corr", &iqCorrection)) {
|
||||
sigpath::iqFrontEnd.setDCBlocking(iqCorrection);
|
||||
|
|
|
@ -146,7 +146,7 @@ namespace server {
|
|||
// Load sourceId from config
|
||||
sourceId = 0;
|
||||
if (sourceList.keyExists(sourceName)) { sourceId = sourceList.keyId(sourceName); }
|
||||
sigpath::sourceManager.selectSource(sourceList[sourceId]);
|
||||
sigpath::sourceManager.select(sourceList[sourceId]);
|
||||
|
||||
// TODO: Use command line option
|
||||
std::string host = (std::string)core::args["addr"];
|
||||
|
@ -280,8 +280,7 @@ namespace server {
|
|||
}
|
||||
}
|
||||
else if (cmd == COMMAND_START) {
|
||||
sigpath::sourceManager.start();
|
||||
running = true;
|
||||
running = sigpath::sourceManager.start();
|
||||
}
|
||||
else if (cmd == COMMAND_STOP) {
|
||||
sigpath::sourceManager.stop();
|
||||
|
@ -309,14 +308,14 @@ namespace server {
|
|||
SmGui::FillWidth();
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::Combo("##sdrpp_server_src_sel", &sourceId, sourceList.txt)) {
|
||||
sigpath::sourceManager.selectSource(sourceList[sourceId]);
|
||||
sigpath::sourceManager.select(sourceList[sourceId]);
|
||||
core::configManager.acquire();
|
||||
core::configManager.conf["source"] = sourceList.key(sourceId);
|
||||
core::configManager.release(true);
|
||||
}
|
||||
if (running) { SmGui::EndDisabled(); }
|
||||
|
||||
sigpath::sourceManager.showSelectedMenu();
|
||||
sigpath::sourceManager.showMenu();
|
||||
}
|
||||
|
||||
void renderUI(SmGui::DrawList* dl, std::string diffId, SmGui::DrawListElem diffValue) {
|
||||
|
|
|
@ -1,106 +1,186 @@
|
|||
#include <server.h>
|
||||
#include <signal_path/source.h>
|
||||
#include "source.h"
|
||||
#include <utils/flog.h>
|
||||
#include <signal_path/signal_path.h>
|
||||
#include <core.h>
|
||||
|
||||
SourceManager::SourceManager() {
|
||||
}
|
||||
void SourceManager::registerSource(const std::string& name, Source* source) {
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
|
||||
void SourceManager::registerSource(std::string name, SourceHandler* handler) {
|
||||
// Check arguments
|
||||
if (source || name.empty()) {
|
||||
flog::error("Invalid argument to register source", name);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that a source with that name doesn't already exist
|
||||
if (sources.find(name) != sources.end()) {
|
||||
flog::error("Tried to register new source with existing name: {0}", name);
|
||||
flog::error("Tried to register source with existing name: {}", name);
|
||||
return;
|
||||
}
|
||||
sources[name] = handler;
|
||||
onSourceRegistered.emit(name);
|
||||
|
||||
// Add source to map
|
||||
sources[name] = source;
|
||||
|
||||
// Add source to lists
|
||||
sourceNames.push_back(name);
|
||||
onSourceRegistered(name);
|
||||
}
|
||||
|
||||
void SourceManager::unregisterSource(std::string name) {
|
||||
void SourceManager::unregisterSource(const std::string& name) {
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
|
||||
// Check that a source with that name exists
|
||||
if (sources.find(name) == sources.end()) {
|
||||
flog::error("Tried to unregister non existent source: {0}", name);
|
||||
flog::error("Tried to unregister a non-existent source: {}", name);
|
||||
return;
|
||||
}
|
||||
onSourceUnregister.emit(name);
|
||||
if (name == selectedName) {
|
||||
if (selectedHandler != NULL) {
|
||||
sources[selectedName]->deselectHandler(sources[selectedName]->ctx);
|
||||
}
|
||||
sigpath::iqFrontEnd.setInput(&nullSource);
|
||||
selectedHandler = NULL;
|
||||
}
|
||||
|
||||
// Notify event listeners of the imminent deletion
|
||||
onSourceUnregister(name);
|
||||
|
||||
// Delete from lists
|
||||
sourceNames.erase(std::find(sourceNames.begin(), sourceNames.end(), name));
|
||||
sources.erase(name);
|
||||
onSourceUnregistered.emit(name);
|
||||
|
||||
// Notify event listeners of the deletion
|
||||
onSourceUnregistered(name);
|
||||
}
|
||||
|
||||
std::vector<std::string> SourceManager::getSourceNames() {
|
||||
std::vector<std::string> names;
|
||||
for (auto const& [name, src] : sources) { names.push_back(name); }
|
||||
return names;
|
||||
const std::vector<std::string>& SourceManager::getSourceNames() {
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
return sourceNames;
|
||||
}
|
||||
|
||||
void SourceManager::selectSource(std::string name) {
|
||||
void SourceManager::select(const std::string& name) {
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
|
||||
// make sure that source isn't currently selected
|
||||
if (selectedSourceName == name) { return; }
|
||||
|
||||
// Deselect current source
|
||||
deselect();
|
||||
|
||||
// Check that a source with that name exists
|
||||
if (sources.find(name) == sources.end()) {
|
||||
flog::error("Tried to select non existent source: {0}", name);
|
||||
flog::error("Tried to select a non-existent source: {}", name);
|
||||
return;
|
||||
}
|
||||
if (selectedHandler != NULL) {
|
||||
sources[selectedName]->deselectHandler(sources[selectedName]->ctx);
|
||||
}
|
||||
selectedHandler = sources[name];
|
||||
selectedHandler->selectHandler(selectedHandler->ctx);
|
||||
selectedName = name;
|
||||
if (core::args["server"].b()) {
|
||||
server::setInput(selectedHandler->stream);
|
||||
}
|
||||
else {
|
||||
sigpath::iqFrontEnd.setInput(selectedHandler->stream);
|
||||
}
|
||||
// Set server input here
|
||||
|
||||
// Select the source
|
||||
selectedSourceName = name;
|
||||
selectedSource = sources[name];
|
||||
|
||||
// Call the selected source
|
||||
selectedSource->select();
|
||||
|
||||
// Retune to make sure the source has the latest frequency
|
||||
tune(frequency);
|
||||
}
|
||||
|
||||
void SourceManager::showSelectedMenu() {
|
||||
if (selectedHandler == NULL) {
|
||||
return;
|
||||
}
|
||||
selectedHandler->menuHandler(selectedHandler->ctx);
|
||||
const std::string& SourceManager::getSelected() {
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
return selectedSourceName;
|
||||
}
|
||||
|
||||
void SourceManager::start() {
|
||||
if (selectedHandler == NULL) {
|
||||
return;
|
||||
}
|
||||
selectedHandler->startHandler(selectedHandler->ctx);
|
||||
bool SourceManager::start() {
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
|
||||
// Check if not already running
|
||||
if (running) { return true; }
|
||||
|
||||
// Call source if selected and save if started
|
||||
running = (!selectedSource) ? false : selectedSource->start();
|
||||
|
||||
return running;
|
||||
}
|
||||
|
||||
void SourceManager::stop() {
|
||||
if (selectedHandler == NULL) {
|
||||
return;
|
||||
}
|
||||
selectedHandler->stopHandler(selectedHandler->ctx);
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
|
||||
// Check if running
|
||||
if (!running) { return; }
|
||||
|
||||
// Call source if selected and save state
|
||||
if (selectedSource) { selectedSource->stop(); }
|
||||
running = false;
|
||||
}
|
||||
|
||||
bool SourceManager::isRunning() {
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
return running;
|
||||
}
|
||||
|
||||
void SourceManager::tune(double freq) {
|
||||
if (selectedHandler == NULL) {
|
||||
return;
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
|
||||
// Save frequency
|
||||
frequency = freq;
|
||||
|
||||
// Call source if selected
|
||||
if (selectedSource) {
|
||||
selectedSource->tune(((mode == TUNING_MODE_NORMAL) ? freq : ifFrequency) + offset);
|
||||
}
|
||||
// TODO: No need to always retune the hardware in panadpter mode
|
||||
selectedHandler->tuneHandler(((tuneMode == TuningMode::NORMAL) ? freq : ifFreq) + tuneOffset, selectedHandler->ctx);
|
||||
onRetune.emit(freq);
|
||||
currentFreq = freq;
|
||||
}
|
||||
|
||||
void SourceManager::showMenu() {
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
|
||||
// Call source if selected
|
||||
if (selectedSource) { selectedSource->showMenu(); }
|
||||
}
|
||||
|
||||
double SourceManager::getSamplerate() {
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
return samplerate;
|
||||
}
|
||||
|
||||
// =========== TODO: These functions should not happen in this class ===========
|
||||
|
||||
void SourceManager::setTuningOffset(double offset) {
|
||||
tuneOffset = offset;
|
||||
tune(currentFreq);
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
|
||||
// Update offset
|
||||
this->offset = offset;
|
||||
|
||||
// Retune to take affect
|
||||
tune(frequency);
|
||||
}
|
||||
|
||||
void SourceManager::setTuningMode(TuningMode mode) {
|
||||
tuneMode = mode;
|
||||
tune(currentFreq);
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
|
||||
// Update mode
|
||||
this->mode = mode;
|
||||
|
||||
// Retune to take affect
|
||||
tune(frequency);
|
||||
}
|
||||
|
||||
void SourceManager::setPanadpterIF(double freq) {
|
||||
ifFreq = freq;
|
||||
tune(currentFreq);
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
|
||||
// Update offset
|
||||
ifFrequency = freq;
|
||||
|
||||
// Return to take affect if in panadapter mode
|
||||
if (mode == TUNING_MODE_PANADAPTER) { tune(frequency); }
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
void SourceManager::deselect() {
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
|
||||
// Call source if selected
|
||||
if (selectedSource) { selectedSource->deselect(); }
|
||||
|
||||
// Mark as deselected
|
||||
selectedSourceName.clear();
|
||||
selectedSource = NULL;
|
||||
}
|
||||
|
||||
void SourceManager::setSamplerate(double samplerate) {
|
||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||
|
||||
// Save samplerate and emit event
|
||||
this->samplerate = samplerate;
|
||||
onSamplerateChanged(samplerate);
|
||||
}
|
|
@ -1,56 +1,153 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <dsp/stream.h>
|
||||
#include <mutex>
|
||||
#include <dsp/types.h>
|
||||
#include <dsp/stream.h>
|
||||
#include <utils/event.h>
|
||||
|
||||
enum TuningMode {
|
||||
TUNING_MODE_NORMAL,
|
||||
TUNING_MODE_PANADAPTER
|
||||
};
|
||||
|
||||
class Source;
|
||||
|
||||
class SourceManager {
|
||||
friend Source;
|
||||
public:
|
||||
SourceManager();
|
||||
/**
|
||||
* Register a source.
|
||||
* @param name Name of the source.
|
||||
* @param source Pointer to the source instance.
|
||||
*/
|
||||
void registerSource(const std::string& name, Source* source);
|
||||
|
||||
struct SourceHandler {
|
||||
dsp::stream<dsp::complex_t>* stream;
|
||||
void (*menuHandler)(void* ctx);
|
||||
void (*selectHandler)(void* ctx);
|
||||
void (*deselectHandler)(void* ctx);
|
||||
void (*startHandler)(void* ctx);
|
||||
void (*stopHandler)(void* ctx);
|
||||
void (*tuneHandler)(double freq, void* ctx);
|
||||
void* ctx;
|
||||
};
|
||||
/**
|
||||
* Unregister a source.
|
||||
* @param name Name of the source.
|
||||
*/
|
||||
void unregisterSource(const std::string& name);
|
||||
|
||||
enum TuningMode {
|
||||
NORMAL,
|
||||
PANADAPTER
|
||||
};
|
||||
/**
|
||||
* Get a list of source names.
|
||||
* @return List of source names.
|
||||
*/
|
||||
const std::vector<std::string>& getSourceNames();
|
||||
|
||||
void registerSource(std::string name, SourceHandler* handler);
|
||||
void unregisterSource(std::string name);
|
||||
void selectSource(std::string name);
|
||||
void showSelectedMenu();
|
||||
void start();
|
||||
/**
|
||||
* Select a source.
|
||||
* @param name Name of the source.
|
||||
*/
|
||||
void select(const std::string& name);
|
||||
|
||||
/**
|
||||
* Get the name of the currently selected source.
|
||||
* @return Name of the source or empty if no source is selected.
|
||||
*/
|
||||
const std::string& getSelected();
|
||||
|
||||
/**
|
||||
* Start the radio.
|
||||
* @return True if the radio started successfully, false if not.
|
||||
*/
|
||||
bool start();
|
||||
|
||||
/**
|
||||
* Stop the radio.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Check if the radio is running.
|
||||
* @return True if the radio is running, false if not.
|
||||
*/
|
||||
bool isRunning();
|
||||
|
||||
/**
|
||||
* Tune the radio.
|
||||
* @param freq Frequency in Hz.
|
||||
*/
|
||||
void tune(double freq);
|
||||
|
||||
/**
|
||||
* Tune the radio.
|
||||
* @param freq Frequency to tune the radio to.
|
||||
*/
|
||||
void showMenu();
|
||||
|
||||
/**
|
||||
* Get the current samplerate of the radio.
|
||||
* @return Samplerate in Hz.
|
||||
*/
|
||||
double getSamplerate();
|
||||
|
||||
// =========== TODO: These functions should not happen in this class ===========
|
||||
|
||||
/**
|
||||
* Set offset to add to the tuned frequency.
|
||||
* @param offset Offset in Hz.
|
||||
*/
|
||||
void setTuningOffset(double offset);
|
||||
|
||||
/**
|
||||
* Set tuning mode.
|
||||
* @param mode Tuning mode.
|
||||
*/
|
||||
void setTuningMode(TuningMode mode);
|
||||
|
||||
/**
|
||||
* Set panadapter mode IF frequency.
|
||||
* @param freq IF frequency in Hz.
|
||||
*/
|
||||
void setPanadpterIF(double freq);
|
||||
|
||||
std::vector<std::string> getSourceNames();
|
||||
// =============================================================================
|
||||
|
||||
// Emitted after a new source has been registered.
|
||||
Event<std::string> onSourceRegistered;
|
||||
|
||||
// Emitted when a source is about to be unregistered.
|
||||
Event<std::string> onSourceUnregister;
|
||||
|
||||
// Emitted after a source has been unregistered.
|
||||
Event<std::string> onSourceUnregistered;
|
||||
|
||||
// Emitted when the samplerate of the incoming IQ has changed.
|
||||
Event<double> onSamplerateChanged;
|
||||
|
||||
// Emitted when the source manager is instructed to tune the radio.
|
||||
Event<double> onRetune;
|
||||
|
||||
private:
|
||||
std::map<std::string, SourceHandler*> sources;
|
||||
std::string selectedName;
|
||||
SourceHandler* selectedHandler = NULL;
|
||||
double tuneOffset;
|
||||
double currentFreq;
|
||||
double ifFreq = 0.0;
|
||||
TuningMode tuneMode = TuningMode::NORMAL;
|
||||
dsp::stream<dsp::complex_t> nullSource;
|
||||
void deselect();
|
||||
void setSamplerate(double samplerate);
|
||||
|
||||
std::vector<std::string> sourceNames;
|
||||
std::map<std::string, Source*> sources;
|
||||
|
||||
std::string selectedSourceName = "";
|
||||
Source* selectedSource = NULL;
|
||||
|
||||
bool running = false;
|
||||
double samplerate = 1e6;
|
||||
double frequency = 100e6;
|
||||
double offset = 0;
|
||||
double ifFrequency = 8.830e6;
|
||||
TuningMode mode = TUNING_MODE_NORMAL;
|
||||
|
||||
std::recursive_mutex mtx;
|
||||
};
|
||||
|
||||
class Source {
|
||||
public:
|
||||
virtual void showMenu() {}
|
||||
virtual void select() = 0;
|
||||
virtual void deselect() {}
|
||||
virtual bool start() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual void tune(double freq) {}
|
||||
|
||||
dsp::stream<dsp::complex_t> stream;
|
||||
};
|
|
@ -1,43 +1,51 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include <utils/flog.h>
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
|
||||
template <class T>
|
||||
struct EventHandler {
|
||||
EventHandler() {}
|
||||
EventHandler(void (*handler)(T, void*), void* ctx) {
|
||||
this->handler = handler;
|
||||
this->ctx = ctx;
|
||||
}
|
||||
typedef int HandlerID;
|
||||
|
||||
void (*handler)(T, void*);
|
||||
void* ctx;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename... Args>
|
||||
class Event {
|
||||
using Handler = std::function<void(Args...)>;
|
||||
public:
|
||||
Event() {}
|
||||
~Event() {}
|
||||
|
||||
void emit(T value) {
|
||||
for (auto const& handler : handlers) {
|
||||
handler->handler(value, handler->ctx);
|
||||
}
|
||||
HandlerID bind(Handler handler) {
|
||||
std::lock_guard<std::mutex> lck(mtx);
|
||||
HandlerID id = genID();
|
||||
handlers[id] = handler;
|
||||
return id;
|
||||
}
|
||||
|
||||
void bindHandler(EventHandler<T>* handler) {
|
||||
handlers.push_back(handler);
|
||||
template<typename MHandler, class T>
|
||||
HandlerID bind(MHandler handler, T* ctx) {
|
||||
return bind([=](Args... args){
|
||||
(ctx->*handler)(args...);
|
||||
});
|
||||
}
|
||||
|
||||
void unbindHandler(EventHandler<T>* handler) {
|
||||
if (std::find(handlers.begin(), handlers.end(), handler) == handlers.end()) {
|
||||
flog::error("Tried to remove a non-existent event handler");
|
||||
return;
|
||||
void unbind(HandlerID id) {
|
||||
std::lock_guard<std::mutex> lck(mtx);
|
||||
if (handlers.find(id) == handlers.end()) {
|
||||
throw std::runtime_error("Could not unbind handler, unknown ID");
|
||||
}
|
||||
handlers.erase(id);
|
||||
}
|
||||
|
||||
void operator()(Args... args) {
|
||||
std::lock_guard<std::mutex> lck(mtx);
|
||||
for (const auto& [desc, handler] : handlers) {
|
||||
handler(args...);
|
||||
}
|
||||
handlers.erase(std::remove(handlers.begin(), handlers.end(), handler), handlers.end());
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<EventHandler<T>*> handlers;
|
||||
HandlerID genID() {
|
||||
int id;
|
||||
for (id = 1; handlers.find(id) != handlers.end(); id++);
|
||||
return id;
|
||||
}
|
||||
|
||||
std::map<HandlerID, Handler> handlers;
|
||||
std::mutex mtx;
|
||||
};
|
|
@ -45,9 +45,6 @@ public:
|
|||
}
|
||||
config.release();
|
||||
|
||||
_retuneHandler.ctx = this;
|
||||
_retuneHandler.handler = retuneHandler;
|
||||
|
||||
gui::menu.registerEntry(name, menuHandler, this, NULL);
|
||||
}
|
||||
|
||||
|
@ -87,8 +84,8 @@ public:
|
|||
|
||||
// Switch source to panadapter mode
|
||||
sigpath::sourceManager.setPanadpterIF(ifFreq);
|
||||
sigpath::sourceManager.setTuningMode(SourceManager::TuningMode::PANADAPTER);
|
||||
sigpath::sourceManager.onRetune.bindHandler(&_retuneHandler);
|
||||
sigpath::sourceManager.setTuningMode(TUNING_MODE_PANADAPTER);
|
||||
retuneHandlerId = sigpath::sourceManager.onRetune.bind(retuneHandler, this);
|
||||
|
||||
running = true;
|
||||
}
|
||||
|
@ -98,8 +95,8 @@ public:
|
|||
if (!running) { return; }
|
||||
|
||||
// Switch source back to normal mode
|
||||
sigpath::sourceManager.onRetune.unbindHandler(&_retuneHandler);
|
||||
sigpath::sourceManager.setTuningMode(SourceManager::TuningMode::NORMAL);
|
||||
sigpath::sourceManager.onRetune.unbind(retuneHandlerId);
|
||||
sigpath::sourceManager.setTuningMode(TUNING_MODE_NORMAL);
|
||||
|
||||
// Disconnect from rigctl server
|
||||
client->close();
|
||||
|
@ -159,10 +156,9 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
static void retuneHandler(double freq, void* ctx) {
|
||||
RigctlClientModule* _this = (RigctlClientModule*)ctx;
|
||||
if (!_this->client || !_this->client->isOpen()) { return; }
|
||||
if (_this->client->setFreq(freq)) {
|
||||
void retuneHandler(double freq) {
|
||||
if (!client || !client->isOpen()) { return; }
|
||||
if (client->setFreq(freq)) {
|
||||
flog::error("Could not set frequency");
|
||||
}
|
||||
}
|
||||
|
@ -178,7 +174,7 @@ private:
|
|||
|
||||
double ifFreq = 8830000.0;
|
||||
|
||||
EventHandler<double> _retuneHandler;
|
||||
HandlerID retuneHandlerId;
|
||||
};
|
||||
|
||||
MOD_EXPORT void _INIT_() {
|
||||
|
|
|
@ -25,7 +25,7 @@ SDRPP_MOD_INFO{
|
|||
|
||||
ConfigManager config;
|
||||
|
||||
class AirspySourceModule : public ModuleManager::Instance {
|
||||
class AirspySourceModule : public ModuleManager::Instance, public Source {
|
||||
public:
|
||||
AirspySourceModule(std::string name) {
|
||||
this->name = name;
|
||||
|
@ -34,15 +34,6 @@ public:
|
|||
|
||||
sampleRate = 10000000.0;
|
||||
|
||||
handler.ctx = this;
|
||||
handler.selectHandler = menuSelected;
|
||||
handler.deselectHandler = menuDeselected;
|
||||
handler.menuHandler = menuHandler;
|
||||
handler.startHandler = start;
|
||||
handler.stopHandler = stop;
|
||||
handler.tuneHandler = tune;
|
||||
handler.stream = &stream;
|
||||
|
||||
refresh();
|
||||
if (sampleRateList.size() > 0) {
|
||||
sampleRate = sampleRateList[0];
|
||||
|
@ -54,11 +45,11 @@ public:
|
|||
config.release();
|
||||
selectByString(devSerial);
|
||||
|
||||
sigpath::sourceManager.registerSource("Airspy", &handler);
|
||||
sigpath::sourceManager.registerSource("Airspy", this);
|
||||
}
|
||||
|
||||
~AirspySourceModule() {
|
||||
stop(this);
|
||||
stop();
|
||||
sigpath::sourceManager.unregisterSource("Airspy");
|
||||
airspy_exit();
|
||||
}
|
||||
|
@ -231,6 +222,315 @@ public:
|
|||
airspy_close(dev);
|
||||
}
|
||||
|
||||
void select() {
|
||||
core::setInputSampleRate(sampleRate);
|
||||
flog::info("AirspySourceModule '{0}': Select!", name);
|
||||
}
|
||||
|
||||
void deselect() {
|
||||
flog::info("AirspySourceModule '{0}': Deselect!", name);
|
||||
}
|
||||
|
||||
bool start() {
|
||||
if (running) { return true; }
|
||||
if (selectedSerial == 0) {
|
||||
flog::error("Tried to start Airspy source with null serial");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef __ANDROID__
|
||||
int err = airspy_open_sn(&openDev, selectedSerial);
|
||||
#else
|
||||
int err = airspy_open_fd(&openDev, devFd);
|
||||
#endif
|
||||
if (err != 0) {
|
||||
char buf[1024];
|
||||
sprintf(buf, "%016" PRIX64, selectedSerial);
|
||||
flog::error("Could not open Airspy {0}", buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
airspy_set_samplerate(openDev, sampleRateList[srId]);
|
||||
airspy_set_freq(openDev, freq);
|
||||
|
||||
if (gainMode == 0) {
|
||||
airspy_set_lna_agc(openDev, 0);
|
||||
airspy_set_mixer_agc(openDev, 0);
|
||||
airspy_set_sensitivity_gain(openDev, sensitiveGain);
|
||||
}
|
||||
else if (gainMode == 1) {
|
||||
airspy_set_lna_agc(openDev, 0);
|
||||
airspy_set_mixer_agc(openDev, 0);
|
||||
airspy_set_linearity_gain(openDev, linearGain);
|
||||
}
|
||||
else if (gainMode == 2) {
|
||||
if (lnaAgc) {
|
||||
airspy_set_lna_agc(openDev, 1);
|
||||
}
|
||||
else {
|
||||
airspy_set_lna_agc(openDev, 0);
|
||||
airspy_set_lna_gain(openDev, lnaGain);
|
||||
}
|
||||
if (mixerAgc) {
|
||||
airspy_set_mixer_agc(openDev, 1);
|
||||
}
|
||||
else {
|
||||
airspy_set_mixer_agc(openDev, 0);
|
||||
airspy_set_mixer_gain(openDev, mixerGain);
|
||||
}
|
||||
airspy_set_vga_gain(openDev, vgaGain);
|
||||
}
|
||||
|
||||
airspy_set_rf_bias(openDev, biasT);
|
||||
|
||||
airspy_start_rx(openDev, callback, this);
|
||||
|
||||
running = true;
|
||||
flog::info("AirspySourceModule '{0}': Start!", name);
|
||||
}
|
||||
|
||||
void stop() {
|
||||
if (!running) { return; }
|
||||
running = false;
|
||||
stream.stopWriter();
|
||||
airspy_close(openDev);
|
||||
stream.clearWriteStop();
|
||||
flog::info("AirspySourceModule '{0}': Stop!", name);
|
||||
}
|
||||
|
||||
void tune(double freq) {
|
||||
this->freq = freq;
|
||||
if (running) {
|
||||
airspy_set_freq(openDev, freq);
|
||||
}
|
||||
flog::info("AirspySourceModule '{0}': Tune: {1}!", name, freq);
|
||||
}
|
||||
|
||||
void showMenu() {
|
||||
if (running) { SmGui::BeginDisabled(); }
|
||||
|
||||
SmGui::FillWidth();
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::Combo(CONCAT("##_airspy_dev_sel_", name), &devId, devListTxt.c_str())) {
|
||||
selectBySerial(devList[devId]);
|
||||
core::setInputSampleRate(sampleRate);
|
||||
if (selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["device"] = selectedSerStr;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (SmGui::Combo(CONCAT("##_airspy_sr_sel_", name), &srId, sampleRateListTxt.c_str())) {
|
||||
sampleRate = sampleRateList[srId];
|
||||
core::setInputSampleRate(sampleRate);
|
||||
if (selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][selectedSerStr]["sampleRate"] = sampleRate;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
|
||||
SmGui::SameLine();
|
||||
SmGui::FillWidth();
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::Button(CONCAT("Refresh##_airspy_refr_", name))) {
|
||||
refresh();
|
||||
config.acquire();
|
||||
std::string devSerial = config.conf["device"];
|
||||
config.release();
|
||||
selectByString(devSerial);
|
||||
core::setInputSampleRate(sampleRate);
|
||||
}
|
||||
|
||||
if (running) { SmGui::EndDisabled(); }
|
||||
|
||||
SmGui::BeginGroup();
|
||||
SmGui::Columns(3, CONCAT("AirspyGainModeColumns##_", name), false);
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::RadioButton(CONCAT("Sensitive##_airspy_gm_", name), gainMode == 0)) {
|
||||
gainMode = 0;
|
||||
if (running) {
|
||||
airspy_set_lna_agc(openDev, 0);
|
||||
airspy_set_mixer_agc(openDev, 0);
|
||||
airspy_set_sensitivity_gain(openDev, sensitiveGain);
|
||||
}
|
||||
if (selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][selectedSerStr]["gainMode"] = 0;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
SmGui::NextColumn();
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::RadioButton(CONCAT("Linear##_airspy_gm_", name), gainMode == 1)) {
|
||||
gainMode = 1;
|
||||
if (running) {
|
||||
airspy_set_lna_agc(openDev, 0);
|
||||
airspy_set_mixer_agc(openDev, 0);
|
||||
airspy_set_linearity_gain(openDev, linearGain);
|
||||
}
|
||||
if (selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][selectedSerStr]["gainMode"] = 1;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
SmGui::NextColumn();
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::RadioButton(CONCAT("Free##_airspy_gm_", name), gainMode == 2)) {
|
||||
gainMode = 2;
|
||||
if (running) {
|
||||
if (lnaAgc) {
|
||||
airspy_set_lna_agc(openDev, 1);
|
||||
}
|
||||
else {
|
||||
airspy_set_lna_agc(openDev, 0);
|
||||
airspy_set_lna_gain(openDev, lnaGain);
|
||||
}
|
||||
if (mixerAgc) {
|
||||
airspy_set_mixer_agc(openDev, 1);
|
||||
}
|
||||
else {
|
||||
airspy_set_mixer_agc(openDev, 0);
|
||||
airspy_set_mixer_gain(openDev, mixerGain);
|
||||
}
|
||||
airspy_set_vga_gain(openDev, vgaGain);
|
||||
}
|
||||
if (selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][selectedSerStr]["gainMode"] = 2;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
SmGui::Columns(1, CONCAT("EndAirspyGainModeColumns##_", name), false);
|
||||
SmGui::EndGroup();
|
||||
|
||||
// Gain menus
|
||||
|
||||
if (gainMode == 0) {
|
||||
SmGui::LeftLabel("Gain");
|
||||
SmGui::FillWidth();
|
||||
if (SmGui::SliderInt(CONCAT("##_airspy_sens_gain_", name), &sensitiveGain, 0, 21)) {
|
||||
if (running) {
|
||||
airspy_set_sensitivity_gain(openDev, sensitiveGain);
|
||||
}
|
||||
if (selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][selectedSerStr]["sensitiveGain"] = sensitiveGain;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (gainMode == 1) {
|
||||
SmGui::LeftLabel("Gain");
|
||||
SmGui::FillWidth();
|
||||
if (SmGui::SliderInt(CONCAT("##_airspy_lin_gain_", name), &linearGain, 0, 21)) {
|
||||
if (running) {
|
||||
airspy_set_linearity_gain(openDev, linearGain);
|
||||
}
|
||||
if (selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][selectedSerStr]["linearGain"] = linearGain;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (gainMode == 2) {
|
||||
// TODO: Switch to a table for alignment
|
||||
if (lnaAgc) { SmGui::BeginDisabled(); }
|
||||
SmGui::LeftLabel("LNA Gain");
|
||||
SmGui::FillWidth();
|
||||
if (SmGui::SliderInt(CONCAT("##_airspy_lna_gain_", name), &lnaGain, 0, 15)) {
|
||||
if (running) {
|
||||
airspy_set_lna_gain(openDev, lnaGain);
|
||||
}
|
||||
if (selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][selectedSerStr]["lnaGain"] = lnaGain;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
if (lnaAgc) { SmGui::EndDisabled(); }
|
||||
|
||||
if (mixerAgc) { SmGui::BeginDisabled(); }
|
||||
SmGui::LeftLabel("Mixer Gain");
|
||||
SmGui::FillWidth();
|
||||
if (SmGui::SliderInt(CONCAT("##_airspy_mix_gain_", name), &mixerGain, 0, 15)) {
|
||||
if (running) {
|
||||
airspy_set_mixer_gain(openDev, mixerGain);
|
||||
}
|
||||
if (selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][selectedSerStr]["mixerGain"] = mixerGain;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
if (mixerAgc) { SmGui::EndDisabled(); }
|
||||
|
||||
SmGui::LeftLabel("VGA Gain");
|
||||
SmGui::FillWidth();
|
||||
if (SmGui::SliderInt(CONCAT("##_airspy_vga_gain_", name), &vgaGain, 0, 15)) {
|
||||
if (running) {
|
||||
airspy_set_vga_gain(openDev, vgaGain);
|
||||
}
|
||||
if (selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][selectedSerStr]["vgaGain"] = vgaGain;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
|
||||
// AGC Control
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::Checkbox(CONCAT("LNA AGC##_airspy_", name), &lnaAgc)) {
|
||||
if (running) {
|
||||
if (lnaAgc) {
|
||||
airspy_set_lna_agc(openDev, 1);
|
||||
}
|
||||
else {
|
||||
airspy_set_lna_agc(openDev, 0);
|
||||
airspy_set_lna_gain(openDev, lnaGain);
|
||||
}
|
||||
}
|
||||
if (selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][selectedSerStr]["lnaAgc"] = lnaAgc;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::Checkbox(CONCAT("Mixer AGC##_airspy_", name), &mixerAgc)) {
|
||||
if (running) {
|
||||
if (mixerAgc) {
|
||||
airspy_set_mixer_agc(openDev, 1);
|
||||
}
|
||||
else {
|
||||
airspy_set_mixer_agc(openDev, 0);
|
||||
airspy_set_mixer_gain(openDev, mixerGain);
|
||||
}
|
||||
}
|
||||
if (selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][selectedSerStr]["mixerAgc"] = mixerAgc;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bias T
|
||||
if (SmGui::Checkbox(CONCAT("Bias T##_airspy_", name), &biasT)) {
|
||||
if (running) {
|
||||
airspy_set_rf_bias(openDev, biasT);
|
||||
}
|
||||
if (selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][selectedSerStr]["biasT"] = biasT;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::string getBandwdithScaled(double bw) {
|
||||
char buf[1024];
|
||||
|
@ -246,322 +546,6 @@ private:
|
|||
return std::string(buf);
|
||||
}
|
||||
|
||||
static void menuSelected(void* ctx) {
|
||||
AirspySourceModule* _this = (AirspySourceModule*)ctx;
|
||||
core::setInputSampleRate(_this->sampleRate);
|
||||
flog::info("AirspySourceModule '{0}': Menu Select!", _this->name);
|
||||
}
|
||||
|
||||
static void menuDeselected(void* ctx) {
|
||||
AirspySourceModule* _this = (AirspySourceModule*)ctx;
|
||||
flog::info("AirspySourceModule '{0}': Menu Deselect!", _this->name);
|
||||
}
|
||||
|
||||
static void start(void* ctx) {
|
||||
AirspySourceModule* _this = (AirspySourceModule*)ctx;
|
||||
if (_this->running) { return; }
|
||||
if (_this->selectedSerial == 0) {
|
||||
flog::error("Tried to start Airspy source with null serial");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef __ANDROID__
|
||||
int err = airspy_open_sn(&_this->openDev, _this->selectedSerial);
|
||||
#else
|
||||
int err = airspy_open_fd(&_this->openDev, _this->devFd);
|
||||
#endif
|
||||
if (err != 0) {
|
||||
char buf[1024];
|
||||
sprintf(buf, "%016" PRIX64, _this->selectedSerial);
|
||||
flog::error("Could not open Airspy {0}", buf);
|
||||
return;
|
||||
}
|
||||
|
||||
airspy_set_samplerate(_this->openDev, _this->sampleRateList[_this->srId]);
|
||||
airspy_set_freq(_this->openDev, _this->freq);
|
||||
|
||||
if (_this->gainMode == 0) {
|
||||
airspy_set_lna_agc(_this->openDev, 0);
|
||||
airspy_set_mixer_agc(_this->openDev, 0);
|
||||
airspy_set_sensitivity_gain(_this->openDev, _this->sensitiveGain);
|
||||
}
|
||||
else if (_this->gainMode == 1) {
|
||||
airspy_set_lna_agc(_this->openDev, 0);
|
||||
airspy_set_mixer_agc(_this->openDev, 0);
|
||||
airspy_set_linearity_gain(_this->openDev, _this->linearGain);
|
||||
}
|
||||
else if (_this->gainMode == 2) {
|
||||
if (_this->lnaAgc) {
|
||||
airspy_set_lna_agc(_this->openDev, 1);
|
||||
}
|
||||
else {
|
||||
airspy_set_lna_agc(_this->openDev, 0);
|
||||
airspy_set_lna_gain(_this->openDev, _this->lnaGain);
|
||||
}
|
||||
if (_this->mixerAgc) {
|
||||
airspy_set_mixer_agc(_this->openDev, 1);
|
||||
}
|
||||
else {
|
||||
airspy_set_mixer_agc(_this->openDev, 0);
|
||||
airspy_set_mixer_gain(_this->openDev, _this->mixerGain);
|
||||
}
|
||||
airspy_set_vga_gain(_this->openDev, _this->vgaGain);
|
||||
}
|
||||
|
||||
airspy_set_rf_bias(_this->openDev, _this->biasT);
|
||||
|
||||
airspy_start_rx(_this->openDev, callback, _this);
|
||||
|
||||
_this->running = true;
|
||||
flog::info("AirspySourceModule '{0}': Start!", _this->name);
|
||||
}
|
||||
|
||||
static void stop(void* ctx) {
|
||||
AirspySourceModule* _this = (AirspySourceModule*)ctx;
|
||||
if (!_this->running) { return; }
|
||||
_this->running = false;
|
||||
_this->stream.stopWriter();
|
||||
airspy_close(_this->openDev);
|
||||
_this->stream.clearWriteStop();
|
||||
flog::info("AirspySourceModule '{0}': Stop!", _this->name);
|
||||
}
|
||||
|
||||
static void tune(double freq, void* ctx) {
|
||||
AirspySourceModule* _this = (AirspySourceModule*)ctx;
|
||||
if (_this->running) {
|
||||
airspy_set_freq(_this->openDev, freq);
|
||||
}
|
||||
_this->freq = freq;
|
||||
flog::info("AirspySourceModule '{0}': Tune: {1}!", _this->name, freq);
|
||||
}
|
||||
|
||||
static void menuHandler(void* ctx) {
|
||||
AirspySourceModule* _this = (AirspySourceModule*)ctx;
|
||||
|
||||
if (_this->running) { SmGui::BeginDisabled(); }
|
||||
|
||||
SmGui::FillWidth();
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::Combo(CONCAT("##_airspy_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) {
|
||||
_this->selectBySerial(_this->devList[_this->devId]);
|
||||
core::setInputSampleRate(_this->sampleRate);
|
||||
if (_this->selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["device"] = _this->selectedSerStr;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (SmGui::Combo(CONCAT("##_airspy_sr_sel_", _this->name), &_this->srId, _this->sampleRateListTxt.c_str())) {
|
||||
_this->sampleRate = _this->sampleRateList[_this->srId];
|
||||
core::setInputSampleRate(_this->sampleRate);
|
||||
if (_this->selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][_this->selectedSerStr]["sampleRate"] = _this->sampleRate;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
|
||||
SmGui::SameLine();
|
||||
SmGui::FillWidth();
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::Button(CONCAT("Refresh##_airspy_refr_", _this->name))) {
|
||||
_this->refresh();
|
||||
config.acquire();
|
||||
std::string devSerial = config.conf["device"];
|
||||
config.release();
|
||||
_this->selectByString(devSerial);
|
||||
core::setInputSampleRate(_this->sampleRate);
|
||||
}
|
||||
|
||||
if (_this->running) { SmGui::EndDisabled(); }
|
||||
|
||||
SmGui::BeginGroup();
|
||||
SmGui::Columns(3, CONCAT("AirspyGainModeColumns##_", _this->name), false);
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::RadioButton(CONCAT("Sensitive##_airspy_gm_", _this->name), _this->gainMode == 0)) {
|
||||
_this->gainMode = 0;
|
||||
if (_this->running) {
|
||||
airspy_set_lna_agc(_this->openDev, 0);
|
||||
airspy_set_mixer_agc(_this->openDev, 0);
|
||||
airspy_set_sensitivity_gain(_this->openDev, _this->sensitiveGain);
|
||||
}
|
||||
if (_this->selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][_this->selectedSerStr]["gainMode"] = 0;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
SmGui::NextColumn();
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::RadioButton(CONCAT("Linear##_airspy_gm_", _this->name), _this->gainMode == 1)) {
|
||||
_this->gainMode = 1;
|
||||
if (_this->running) {
|
||||
airspy_set_lna_agc(_this->openDev, 0);
|
||||
airspy_set_mixer_agc(_this->openDev, 0);
|
||||
airspy_set_linearity_gain(_this->openDev, _this->linearGain);
|
||||
}
|
||||
if (_this->selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][_this->selectedSerStr]["gainMode"] = 1;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
SmGui::NextColumn();
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::RadioButton(CONCAT("Free##_airspy_gm_", _this->name), _this->gainMode == 2)) {
|
||||
_this->gainMode = 2;
|
||||
if (_this->running) {
|
||||
if (_this->lnaAgc) {
|
||||
airspy_set_lna_agc(_this->openDev, 1);
|
||||
}
|
||||
else {
|
||||
airspy_set_lna_agc(_this->openDev, 0);
|
||||
airspy_set_lna_gain(_this->openDev, _this->lnaGain);
|
||||
}
|
||||
if (_this->mixerAgc) {
|
||||
airspy_set_mixer_agc(_this->openDev, 1);
|
||||
}
|
||||
else {
|
||||
airspy_set_mixer_agc(_this->openDev, 0);
|
||||
airspy_set_mixer_gain(_this->openDev, _this->mixerGain);
|
||||
}
|
||||
airspy_set_vga_gain(_this->openDev, _this->vgaGain);
|
||||
}
|
||||
if (_this->selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][_this->selectedSerStr]["gainMode"] = 2;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
SmGui::Columns(1, CONCAT("EndAirspyGainModeColumns##_", _this->name), false);
|
||||
SmGui::EndGroup();
|
||||
|
||||
// Gain menus
|
||||
|
||||
if (_this->gainMode == 0) {
|
||||
SmGui::LeftLabel("Gain");
|
||||
SmGui::FillWidth();
|
||||
if (SmGui::SliderInt(CONCAT("##_airspy_sens_gain_", _this->name), &_this->sensitiveGain, 0, 21)) {
|
||||
if (_this->running) {
|
||||
airspy_set_sensitivity_gain(_this->openDev, _this->sensitiveGain);
|
||||
}
|
||||
if (_this->selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][_this->selectedSerStr]["sensitiveGain"] = _this->sensitiveGain;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_this->gainMode == 1) {
|
||||
SmGui::LeftLabel("Gain");
|
||||
SmGui::FillWidth();
|
||||
if (SmGui::SliderInt(CONCAT("##_airspy_lin_gain_", _this->name), &_this->linearGain, 0, 21)) {
|
||||
if (_this->running) {
|
||||
airspy_set_linearity_gain(_this->openDev, _this->linearGain);
|
||||
}
|
||||
if (_this->selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][_this->selectedSerStr]["linearGain"] = _this->linearGain;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_this->gainMode == 2) {
|
||||
// TODO: Switch to a table for alignment
|
||||
if (_this->lnaAgc) { SmGui::BeginDisabled(); }
|
||||
SmGui::LeftLabel("LNA Gain");
|
||||
SmGui::FillWidth();
|
||||
if (SmGui::SliderInt(CONCAT("##_airspy_lna_gain_", _this->name), &_this->lnaGain, 0, 15)) {
|
||||
if (_this->running) {
|
||||
airspy_set_lna_gain(_this->openDev, _this->lnaGain);
|
||||
}
|
||||
if (_this->selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][_this->selectedSerStr]["lnaGain"] = _this->lnaGain;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
if (_this->lnaAgc) { SmGui::EndDisabled(); }
|
||||
|
||||
if (_this->mixerAgc) { SmGui::BeginDisabled(); }
|
||||
SmGui::LeftLabel("Mixer Gain");
|
||||
SmGui::FillWidth();
|
||||
if (SmGui::SliderInt(CONCAT("##_airspy_mix_gain_", _this->name), &_this->mixerGain, 0, 15)) {
|
||||
if (_this->running) {
|
||||
airspy_set_mixer_gain(_this->openDev, _this->mixerGain);
|
||||
}
|
||||
if (_this->selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][_this->selectedSerStr]["mixerGain"] = _this->mixerGain;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
if (_this->mixerAgc) { SmGui::EndDisabled(); }
|
||||
|
||||
SmGui::LeftLabel("VGA Gain");
|
||||
SmGui::FillWidth();
|
||||
if (SmGui::SliderInt(CONCAT("##_airspy_vga_gain_", _this->name), &_this->vgaGain, 0, 15)) {
|
||||
if (_this->running) {
|
||||
airspy_set_vga_gain(_this->openDev, _this->vgaGain);
|
||||
}
|
||||
if (_this->selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][_this->selectedSerStr]["vgaGain"] = _this->vgaGain;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
|
||||
// AGC Control
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::Checkbox(CONCAT("LNA AGC##_airspy_", _this->name), &_this->lnaAgc)) {
|
||||
if (_this->running) {
|
||||
if (_this->lnaAgc) {
|
||||
airspy_set_lna_agc(_this->openDev, 1);
|
||||
}
|
||||
else {
|
||||
airspy_set_lna_agc(_this->openDev, 0);
|
||||
airspy_set_lna_gain(_this->openDev, _this->lnaGain);
|
||||
}
|
||||
}
|
||||
if (_this->selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][_this->selectedSerStr]["lnaAgc"] = _this->lnaAgc;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::Checkbox(CONCAT("Mixer AGC##_airspy_", _this->name), &_this->mixerAgc)) {
|
||||
if (_this->running) {
|
||||
if (_this->mixerAgc) {
|
||||
airspy_set_mixer_agc(_this->openDev, 1);
|
||||
}
|
||||
else {
|
||||
airspy_set_mixer_agc(_this->openDev, 0);
|
||||
airspy_set_mixer_gain(_this->openDev, _this->mixerGain);
|
||||
}
|
||||
}
|
||||
if (_this->selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][_this->selectedSerStr]["mixerAgc"] = _this->mixerAgc;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bias T
|
||||
if (SmGui::Checkbox(CONCAT("Bias T##_airspy_", _this->name), &_this->biasT)) {
|
||||
if (_this->running) {
|
||||
airspy_set_rf_bias(_this->openDev, _this->biasT);
|
||||
}
|
||||
if (_this->selectedSerStr != "") {
|
||||
config.acquire();
|
||||
config.conf["devices"][_this->selectedSerStr]["biasT"] = _this->biasT;
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int callback(airspy_transfer_t* transfer) {
|
||||
AirspySourceModule* _this = (AirspySourceModule*)transfer->ctx;
|
||||
memcpy(_this->stream.writeBuf, transfer->samples, transfer->sample_count * sizeof(dsp::complex_t));
|
||||
|
@ -574,7 +558,6 @@ private:
|
|||
bool enabled = true;
|
||||
dsp::stream<dsp::complex_t> stream;
|
||||
double sampleRate;
|
||||
SourceManager::SourceHandler handler;
|
||||
bool running = false;
|
||||
double freq;
|
||||
uint64_t selectedSerial = 0;
|
||||
|
|
Ładowanie…
Reference in New Issue