Implemented tuner manager

This commit is contained in:
Ezra Taimuty-Loomis 2021-02-10 12:30:11 -05:00
parent 7a82f67528
commit 002121cff1
11 changed files with 229 additions and 44 deletions

View File

@ -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 */

View File

@ -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

View File

@ -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,

View File

@ -1,5 +1,6 @@
add_library(sigproc
${CMAKE_CURRENT_SOURCE_DIR}/Demodulator.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TunerManager.cpp
)
add_subdirectory(test)

View File

@ -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();

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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;
};
}
}

View File

@ -25,5 +25,6 @@ namespace sigproc {
};
class Demodulator;
class TunerManager;
}
}

View File

@ -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
)

View File