Implemented tuner manager
This commit is contained in:
parent
7a82f67528
commit
002121cff1
|
|
@ -49,6 +49,7 @@ void setDemodSquelch(float level);
|
|||
piscan::server::context::DemodContext getDemodContext();
|
||||
void squelchBreak(bool mute = true);
|
||||
long long getTunerSampleRate();
|
||||
//void setTunerPPM(int ppm);
|
||||
}
|
||||
|
||||
/* server functions */
|
||||
|
|
|
|||
|
|
@ -59,6 +59,20 @@ struct DemodConfig {
|
|||
int squelchType = DEFAULT_SQUELCH_MODE;
|
||||
};
|
||||
|
||||
#define DEFAULT_RANK 0
|
||||
#define DEFAULT_DESC "NULL"
|
||||
#define DEFAULT_DRIVER "null"
|
||||
#define DEFAULT_PPM 0
|
||||
#define DEFAULT_TUNER_SAMPLE_RATE 2048000
|
||||
|
||||
struct TunerConfig {
|
||||
int rank = DEFAULT_RANK;
|
||||
std::string description = DEFAULT_DESC;
|
||||
std::string driver = DEFAULT_DRIVER;
|
||||
int ppmCorrection = DEFAULT_PPM;
|
||||
long int sampleRate = DEFAULT_TUNER_SAMPLE_RATE;
|
||||
};
|
||||
|
||||
#define DEFAULT_RTSP_PORT 8554
|
||||
#define DEFAULT_RTSP_OVER_HTTP false
|
||||
|
||||
|
|
|
|||
|
|
@ -150,6 +150,10 @@ long long app::demod::getTunerSampleRate() {
|
|||
return demodInst.getTunerSampleRate();
|
||||
}
|
||||
|
||||
/*void app::demod::setTunerPPM(int ppm) {
|
||||
// TODO
|
||||
}*/
|
||||
|
||||
const piscan::server::context::SystemInfo app::system::getSystemInfo(){
|
||||
piscan::server::context::SystemInfo info = {
|
||||
.version = PISCAN_VERSION,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
add_library(sigproc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Demodulator.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TunerManager.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(test)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
#include "Demodulator.h"
|
||||
#include "loguru.hpp"
|
||||
|
||||
#define DEFAULT_SDR_SAMPLE_RATE 2048000
|
||||
#define INIT_FREQUENCY 100000000
|
||||
#define NUM_RATES_DEFAULT 4
|
||||
#define SIGLEVEL_REFRESH_INTERVAL 100 // milliseconds
|
||||
|
|
@ -20,56 +19,19 @@
|
|||
namespace piscan {
|
||||
namespace sigproc {
|
||||
|
||||
Demodulator::Demodulator() : _cubic(makeCubic()), _demodMgr(_cubic->getDemodMgr()) {};
|
||||
Demodulator::Demodulator() : _cubic(makeCubic()), _demodMgr(_cubic->getDemodMgr()), _tunerManager(_cubic) {};
|
||||
|
||||
void Demodulator::start(){
|
||||
piscan::config::DemodState& state = app::system::getConfig().getDemodState();
|
||||
_squelchLevel = state.squelch;
|
||||
_gain = state.gain;
|
||||
|
||||
// TODO assertions will be used until a soft abort is made available
|
||||
CHECK_F(_cubic->OnInit());
|
||||
|
||||
while(_cubic->areDevicesEnumerating());
|
||||
|
||||
std::vector<SDRDeviceInfo*>* devs = _cubic->getDevices();
|
||||
|
||||
CHECK_F(devs->size() > 0, "No SDR devices are available");
|
||||
|
||||
//TODO config file for this
|
||||
LOG_F(INFO, "Auto-selecting SDR device");
|
||||
size_t i;
|
||||
for(i = 0; i < devs->size();){
|
||||
if(devs->at(i)->getDriver() != "audio" && devs->at(i)->isAvailable())
|
||||
break;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
CHECK_F(i < devs->size(), "No valid or available devices found");
|
||||
|
||||
auto dev = devs->at(i);
|
||||
|
||||
CHECK_F(dev->getDriver() != "audio");
|
||||
|
||||
LOG_F(INFO, "Auto selected: %s", dev->getName().c_str());
|
||||
|
||||
LOG_F(INFO, "Auto selecting sample rate");
|
||||
std::vector<long> srates = dev->getSampleRates(SOAPY_SDR_RX, 0);
|
||||
long srate = 0;
|
||||
for(i = 0; i < srates.size() - 1; i++){
|
||||
if(srates[i] <= DEFAULT_SDR_SAMPLE_RATE && srates[i+1] > DEFAULT_SDR_SAMPLE_RATE){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
srate = srates[i];
|
||||
LOG_F(INFO, "Setting device sample rate to %li", srate);
|
||||
|
||||
//_cubic->setGain(name, gain_in);
|
||||
|
||||
_cubic->setDevice(dev, 2000);
|
||||
_cubic->setSampleRate(srate);
|
||||
|
||||
CHECK_F(_tunerManager.enumerateDevices());
|
||||
CHECK_F(_tunerManager.autoSelectTuner());
|
||||
CHECK_F(_tunerManager.startSelectedTuner());
|
||||
|
||||
//sets sample rate for outputs - imported from cubic
|
||||
unsigned int desired_rates[NUM_RATES_DEFAULT] = { 48000, 44100, 96000, 192000 };
|
||||
|
|
@ -166,7 +128,8 @@ void Demodulator::stop(){
|
|||
_sigLevelRefresher.stop();
|
||||
//delete _sigLevelRefresher;
|
||||
|
||||
_cubic->stopDevice(false, 2000);
|
||||
//_cubic->stopDevice(false, 2000);
|
||||
_tunerManager.stopSelectedTuner();
|
||||
_cubic->OnExit();
|
||||
|
||||
piscan::config::DemodState& state = app::system::getConfig().getDemodState();
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "Configuration.h"
|
||||
#include "synchronize.h"
|
||||
#include "IntervalTimer.h"
|
||||
#include "TunerManager.h"
|
||||
|
||||
|
||||
namespace piscan {
|
||||
|
|
@ -56,6 +57,7 @@ private:
|
|||
|
||||
std::shared_ptr<CubicSDR> _cubic;
|
||||
DemodulatorMgr& _demodMgr;
|
||||
TunerManager _tunerManager;
|
||||
|
||||
std::map<Modulation, DemodulatorInstancePtr> _demods;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,149 @@
|
|||
#include <functional>
|
||||
|
||||
#include "TunerManager.h"
|
||||
#include "CubicSDR.h"
|
||||
#include "loguru.hpp"
|
||||
|
||||
#define AUDIO_DRIVER "audio"
|
||||
|
||||
|
||||
namespace piscan{
|
||||
namespace sigproc {
|
||||
|
||||
/*
|
||||
* @param cubic pointer to CubicSDR instance
|
||||
*/
|
||||
TunerManager::TunerManager(std::shared_ptr<CubicSDR> cubic) : _cubic(cubic) {
|
||||
}
|
||||
|
||||
/*
|
||||
* @return True if at least one SDR device was discovered and is available,
|
||||
* False if no SDRs are available or if an error occured
|
||||
*/
|
||||
bool TunerManager::enumerateDevices() {
|
||||
while(_cubic->areDevicesEnumerating()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
|
||||
std::vector<SDRDeviceInfo*>* devs = _cubic->getDevices();
|
||||
|
||||
//CHECK_F(devs->size() > 0, "No SDR devices are available");
|
||||
if (devs->empty()) {
|
||||
LOG_F(WARNING, "No devices are available");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Place devices into map by serial number and filter out audio devices
|
||||
for (auto device : *devs) {
|
||||
if (device->getDriver() != AUDIO_DRIVER) {
|
||||
const std::string& name = device->getName();
|
||||
if (name.size()) {
|
||||
_devs[name] = device;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TunerManager::deviceAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TunerManager::selectFirstAvailableDevice() {
|
||||
//TODO this is temporary - will eventually be replaced by a config interface
|
||||
LOG_F(INFO, "Selecting first available device");
|
||||
SDRDeviceInfo* device = (*(_devs.begin())).second;
|
||||
_selectedTuner.device = device;
|
||||
_selectedTuner.config.driver = device->getDriver();
|
||||
_selectedTuner.config.description = device->getName();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*std::vector<SDRDeviceInfo*> TunerManager::getKnownDevices() {
|
||||
|
||||
}
|
||||
|
||||
std::vector<SDRDeviceInfo*> TunerManager::getAllDevices() {
|
||||
|
||||
}*/
|
||||
|
||||
/*
|
||||
* @param desired The desired sample rate
|
||||
* @param supportedRates Vector containing all sample rates supported by a tuner
|
||||
* @return The supported sample rate closest to desired, or -1 if no rates are supported
|
||||
*/
|
||||
long TunerManager::nearestSampleRate(long desired, std::vector<long>& supportedRates) {
|
||||
long minDiff = LONG_MAX;
|
||||
long result = -1;
|
||||
long diff;
|
||||
|
||||
for (long rate : supportedRates) {
|
||||
diff = std::abs(desired - rate);
|
||||
if (diff < minDiff) {
|
||||
result = rate;
|
||||
minDiff = diff;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow the tuner to choose the tuner to use - by default the first available tuner found in config
|
||||
* @return False if a tuner could not be selected
|
||||
*/
|
||||
bool TunerManager::autoSelectTuner() {
|
||||
if(_devs.empty()) {
|
||||
LOG_F(WARNING, "No SDR devices were found");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_savedTuners.empty()) {
|
||||
LOG_F(INFO, "No saved tuners found in config, defaulting to first available");
|
||||
selectFirstAvailableDevice();
|
||||
|
||||
LOG_F(INFO, "New tuner will be saved to config");
|
||||
_savedTuners.push(_selectedTuner.config);
|
||||
}
|
||||
|
||||
LOG_F(INFO, "Auto selecting sample rate");
|
||||
std::vector<long> srates(std::move(_selectedTuner.device->getSampleRates(SOAPY_SDR_RX, 0)));
|
||||
|
||||
RAW_LOG_F(1, "Supported sample rates for tuner:");
|
||||
for (long rate : srates)
|
||||
RAW_LOG_F(1, "\t%li", rate);
|
||||
|
||||
_selectedTuner.config.sampleRate = nearestSampleRate(DEFAULT_TUNER_SAMPLE_RATE, srates); // TODO hardcoded sample rate temporary
|
||||
|
||||
LOG_F(INFO, "Auto selected: %s", _selectedTuner.device->getName().c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the tuner's operation
|
||||
* @return False if no tuner is selected or an error occured during init
|
||||
*/
|
||||
bool TunerManager::startSelectedTuner() {
|
||||
LOG_F(INFO, "Starting tuner %s", _selectedTuner.device->getName().c_str());
|
||||
_cubic->setDevice(_selectedTuner.device, 2000);
|
||||
LOG_F(INFO, "Setting tuner PPM correction to %i", _selectedTuner.config.ppmCorrection);
|
||||
_cubic->setPPM(_selectedTuner.config.ppmCorrection);
|
||||
LOG_F(INFO, "Setting device sample rate to %li", _selectedTuner.config.sampleRate);
|
||||
_cubic->setSampleRate(_selectedTuner.config.sampleRate);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop the tuner's operation
|
||||
* @return False if no tuner is selected, the tuner wasn't started, or an error occured during deinit
|
||||
*/
|
||||
bool TunerManager::stopSelectedTuner() {
|
||||
_cubic->stopDevice(false, 2000);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
|
||||
#include "Configuration.h"
|
||||
|
||||
class CubicSDR;
|
||||
class SDRDeviceInfo;
|
||||
|
||||
namespace piscan {
|
||||
namespace sigproc {
|
||||
class TunerComparator : public std::less<piscan::config::TunerConfig> {
|
||||
constexpr bool operator()(piscan::config::TunerConfig& left, piscan::config::TunerConfig& right) const {
|
||||
return left.rank < right.rank;
|
||||
}
|
||||
};
|
||||
|
||||
struct ConfiguredTuner {
|
||||
piscan::config::TunerConfig config; // TODO may be changed to ref or shared_ptr
|
||||
SDRDeviceInfo* device;
|
||||
};
|
||||
|
||||
class TunerManager {
|
||||
public:
|
||||
TunerManager(std::shared_ptr<CubicSDR> cubic);
|
||||
|
||||
bool enumerateDevices();
|
||||
bool deviceAvailable();
|
||||
bool selectFirstAvailableDevice();
|
||||
/*std::vector<SDRDeviceInfo*> getKnownDevices();
|
||||
std::vector<SDRDeviceInfo*> getAllDevices();*/
|
||||
|
||||
static long nearestSampleRate(long desired, std::vector<long>& supportedRates);
|
||||
|
||||
bool autoSelectTuner();
|
||||
bool startSelectedTuner();
|
||||
bool stopSelectedTuner();
|
||||
|
||||
private:
|
||||
std::shared_ptr<CubicSDR> _cubic;
|
||||
std::unordered_map<std::string, SDRDeviceInfo*> _devs;
|
||||
std::priority_queue<piscan::config::TunerConfig, std::vector<piscan::config::TunerConfig>, TunerComparator> _savedTuners;
|
||||
ConfiguredTuner _selectedTuner;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -25,5 +25,6 @@ namespace sigproc {
|
|||
};
|
||||
|
||||
class Demodulator;
|
||||
class TunerManager;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
package_add_test(sigproc_tests
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/AudioManager_test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Demodulator_test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TunerManager_test.cpp
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue