Fixed resampling bug + added waterfall colormap selection + general bugfix

pull/60/head
Ryzerth 2020-12-31 14:26:12 +01:00
rodzic 7c4e442432
commit 979928ded8
21 zmienionych plików z 399 dodań i 46 usunięć

Wyświetl plik

@ -102,6 +102,7 @@ int sdrpp_main(int argc, char *argv[]) {
defConfig["bandPlan"] = "General";
defConfig["bandPlanEnabled"] = true;
defConfig["centerTuning"] = false;
defConfig["colorMap"] = "Classic";
defConfig["fftHeight"] = 300;
defConfig["frequency"] = 100000000.0;
defConfig["max"] = 0.0;
@ -156,6 +157,16 @@ int sdrpp_main(int argc, char *argv[]) {
core::configManager.load(defConfig);
core::configManager.enableAutoSave();
// Fix config
core::configManager.aquire();
for (auto const& item : defConfig.items()) {
if (!core::configManager.conf.contains(item.key())) {
spdlog::warn("Missing key in config {0}, repairing", item.key());
core::configManager.conf[item.key()] = defConfig[item.key()];
}
}
core::configManager.release(true);
// Setup window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit()) {

Wyświetl plik

@ -132,4 +132,54 @@ namespace dsp {
stream<complex_t>* _in;
};
class RealToComplex : public generic_block<RealToComplex> {
public:
RealToComplex() {}
RealToComplex(stream<float>* in) { init(in); }
~RealToComplex() {
delete[] nullBuffer;
generic_block<RealToComplex>::stop();
}
void init(stream<float>* in) {
_in = in;
nullBuffer = new float[STREAM_BUFFER_SIZE];
memset(nullBuffer, 0, STREAM_BUFFER_SIZE * sizeof(float));
generic_block<RealToComplex>::registerInput(_in);
generic_block<RealToComplex>::registerOutput(&out);
}
void setInput(stream<float>* in) {
std::lock_guard<std::mutex> lck(generic_block<RealToComplex>::ctrlMtx);
generic_block<RealToComplex>::tempStop();
generic_block<RealToComplex>::unregisterInput(_in);
_in = in;
generic_block<RealToComplex>::registerInput(_in);
generic_block<RealToComplex>::tempStart();
}
int run() {
count = _in->read();
if (count < 0) { return -1; }
volk_32f_x2_interleave_32fc((lv_32fc_t*)out.writeBuf, _in->readBuf, nullBuffer, count);
_in->flush();
if (!out.swap(count)) { return -1; }
return count;
}
stream<complex_t> out;
private:
float avg;
int count;
float* nullBuffer;
stream<float>* _in;
};
}

Wyświetl plik

@ -1,6 +1,5 @@
#pragma once
#include <dsp/block.h>
#include <fftw3.h>
#include <volk/volk.h>
#include <spdlog/spdlog.h>
#include <string.h>
@ -89,13 +88,15 @@ namespace dsp {
public:
AGC() {}
AGC(stream<float>* in, float ratio) { init(in, ratio); }
AGC(stream<float>* in, float fallRate, float sampleRate) { init(in, fallRate, sampleRate); }
~AGC() { generic_block<AGC>::stop(); }
void init(stream<float>* in, float ratio) {
void init(stream<float>* in, float fallRate, float sampleRate) {
_in = in;
_ratio = ratio;
_sampleRate = sampleRate;
_fallRate = fallRate;
_CorrectedFallRate = _fallRate / _sampleRate;
generic_block<AGC>::registerInput(_in);
generic_block<AGC>::registerOutput(&out);
}
@ -109,15 +110,30 @@ namespace dsp {
generic_block<AGC>::tempStart();
}
void setSampleRate(float sampleRate) {
std::lock_guard<std::mutex> lck(generic_block<AGC>::ctrlMtx);
_sampleRate = sampleRate;
_CorrectedFallRate = _fallRate / _sampleRate;
}
void setFallRate(float fallRate) {
std::lock_guard<std::mutex> lck(generic_block<AGC>::ctrlMtx);
_fallRate = fallRate;
_CorrectedFallRate = _fallRate / _sampleRate;
}
int run() {
count = _in->read();
if (count < 0) { return -1; }
level = pow(10, ((10.0f * log10f(level)) - (_CorrectedFallRate * count)) / 10.0f);
for (int i = 0; i < count; i++) {
level = (fabsf(_in->readBuf[i]) * _ratio) + (level * (1.0f - _ratio));
out.writeBuf[i] = _in->readBuf[i] / level;
if (_in->readBuf[i] > level) { level = _in->readBuf[i]; }
}
volk_32f_s32f_multiply_32f(out.writeBuf, _in->readBuf, 1.0f / level, count);
_in->flush();
if (!out.swap(count)) { return -1; }
return count;
@ -127,8 +143,10 @@ namespace dsp {
private:
int count;
float level = 1.0f;
float _ratio;
float level = 0.0f;
float _fallRate;
float _CorrectedFallRate;
float _sampleRate;
stream<float>* _in;
};

Wyświetl plik

@ -109,6 +109,7 @@ namespace dsp {
// Write to output
int outIndex = 0;
int _interp_m_1 = _interp - 1;
if constexpr (std::is_same_v<T, float>) {
for (int i = 0; outIndex < outCount; i += _decim) {
int phase = i % _interp;
@ -155,10 +156,10 @@ namespace dsp {
for(int tap = 0; tap < tapsPerPhase; tap++) {
for (int phase = 0; phase < phases; phase++) {
if(currentTap < tapCount) {
tapPhases[phase][tap] = taps[currentTap++];
tapPhases[(_interp - 1) - phase][tap] = taps[currentTap++];
}
else{
tapPhases[phase][tap] = 0;
tapPhases[(_interp - 1) - phase][tap] = 0;
}
}
}
@ -187,4 +188,80 @@ namespace dsp {
std::vector<float*> tapPhases;
};
class PowerDecimator : public generic_block<PowerDecimator> {
public:
PowerDecimator() {}
PowerDecimator(stream<complex_t>* in, unsigned int power) { init(in, power); }
~PowerDecimator() {
generic_block<PowerDecimator>::stop();
}
void init(stream<complex_t>* in, unsigned int power) {
_in = in;
_power = power;
generic_block<PowerDecimator>::registerInput(_in);
generic_block<PowerDecimator>::registerOutput(&out);
}
void setInput(stream<complex_t>* in) {
std::lock_guard<std::mutex> lck(generic_block<PowerDecimator>::ctrlMtx);
generic_block<PowerDecimator>::tempStop();
generic_block<PowerDecimator>::unregisterInput(_in);
_in = in;
generic_block<PowerDecimator>::registerInput(_in);
generic_block<PowerDecimator>::tempStart();
}
void setPower(unsigned int power) {
std::lock_guard<std::mutex> lck(generic_block<PowerDecimator>::ctrlMtx);
generic_block<PowerDecimator>::tempStop();
generic_block<PowerDecimator>::unregisterInput(_in);
_power = power;
generic_block<PowerDecimator>::registerInput(_in);
generic_block<PowerDecimator>::tempStart();
}
int run() {
count = _in->read();
if (count < 0) { return -1; }
if (_power == 0) {
memcpy(out.writeBuf, _in->readBuf, count * sizeof(complex_t));
}
else if (_power == 1) {
for (int j = 0; j < count; j += 2) {
out.writeBuf[j / 2].i = (_in->readBuf[j].i + _in->readBuf[j + 1].i) * 0.5f;
out.writeBuf[j / 2].q = (_in->readBuf[j].q + _in->readBuf[j + 1].q) * 0.5f;
}
count /= 2;
}
_in->flush();
if (_power > 1) {
for (int i = 1; i < _power; i++) {
for (int j = 0; j < count; j += 2) {
out.writeBuf[j / 2].i = (_in->readBuf[j].i + _in->readBuf[j + 1].i) * 0.5f;
out.writeBuf[j / 2].q = (_in->readBuf[j].q + _in->readBuf[j + 1].q) * 0.5f;
}
count /= 2;
}
}
if (!out.swap(count)) { return -1; }
return count;
}
stream<complex_t> out;
private:
int count;
unsigned int _power = 0;
stream<complex_t>* _in;
};
}

Wyświetl plik

@ -0,0 +1,49 @@
#include <gui/colormaps.h>
#include <filesystem>
#include <spdlog/spdlog.h>
#include <fstream>
#include <json.hpp>
using nlohmann::json;
namespace colormaps {
std::map<std::string, Map> maps;
void loadMap(std::string path) {
if (!std::filesystem::is_regular_file(path)) {
spdlog::error("Could not load {0}, file doesn't exist", path);
return;
}
std::ifstream file(path.c_str());
json data;
file >> data;
file.close();
Map map;
std::vector<std::string> mapTxt;
try {
map.name = data["name"];
map.author = data["author"];
mapTxt = data["map"].get<std::vector<std::string>>();
}
catch (const std::exception&) {
spdlog::error("Could not load {0}", path);
return;
}
map.entryCount = mapTxt.size();
map.map = new float[mapTxt.size() * 3];
int i = 0;
for(auto const& col : mapTxt) {
uint8_t r, g, b, a;
map.map[i * 3] = std::stoi(col.substr(1, 2), NULL, 16);
map.map[(i * 3) + 1] = std::stoi(col.substr(3, 2), NULL, 16);
map.map[(i * 3) + 2] = std::stoi(col.substr(5, 2), NULL, 16);
i++;
}
maps[map.name] = map;
}
}

Wyświetl plik

@ -0,0 +1,18 @@
#pragma once
#include <string>
#include <vector>
#include <module.h>
#include <map>
namespace colormaps {
struct Map {
std::string name;
std::string author;
float* map;
int entryCount;
};
void loadMap(std::string path);
SDRPP_EXPORT std::map<std::string, Map> maps;
}

Wyświetl plik

@ -31,6 +31,7 @@
#include <signal_path/source.h>
#include <gui/dialogs/loading_screen.h>
#include <options.h>
#include <gui/colormaps.h>
// const int FFTSizes[] = {
// 65536,
@ -121,6 +122,7 @@ void windowInit() {
core::configManager.aquire();
gui::menu.order = core::configManager.conf["menuOrder"].get<std::vector<std::string>>();
std::string modulesDir = core::configManager.conf["modulesDirectory"];
std::string resourcesDir = core::configManager.conf["resourcesDirectory"];
core::configManager.release();
gui::menu.registerEntry("Source", sourecmenu::draw, NULL);
@ -181,6 +183,27 @@ void windowInit() {
core::moduleManager.createInstance(name, module);
}
// Load color maps
LoadingScreen::show("Loading color maps");
spdlog::info("Loading color maps");
if (std::filesystem::is_directory(resourcesDir + "/colormaps")) {
for (const auto & file : std::filesystem::directory_iterator(resourcesDir + "/colormaps")) {
std::string path = file.path().generic_string();
LoadingScreen::show("Loading " + path);
spdlog::info("Loading {0}", path);
if (file.path().extension().generic_string() != ".json") {
continue;
}
if (!file.is_regular_file()) { continue; }
colormaps::loadMap(path);
}
}
else {
spdlog::warn("Color map directory {0} does not exist, not loading modules from directory", modulesDir);
}
gui::waterfall.updatePalletteFromArray(colormaps::maps["Turbo"].map, colormaps::maps["Turbo"].entryCount);
sourecmenu::init();
sinkmenu::init();
scriptingmenu::init();

Wyświetl plik

@ -2,21 +2,58 @@
#include <imgui.h>
#include <gui/gui.h>
#include <core.h>
#include <gui/colormaps.h>
#include <gui/gui.h>
namespace displaymenu {
bool showWaterfall;
int colorMapId = 0;
std::vector<std::string> colorMapNames;
std::string colorMapNamesTxt = "";
std::string colorMapAuthor = "";
void init() {
showWaterfall = core::configManager.conf["showWaterfall"];
showWaterfall ? gui::waterfall.showWaterfall() : gui::waterfall.hideWaterfall();
std::string colormapName = core::configManager.conf["colorMap"];
if (colormaps::maps.find(colormapName) != colormaps::maps.end()) {
colormaps::Map map = colormaps::maps[colormapName];
gui::waterfall.updatePalletteFromArray(map.map, map.entryCount);
}
for (auto const& [name, map] : colormaps::maps) {
colorMapNames.push_back(name);
colorMapNamesTxt += name;
colorMapNamesTxt += '\0';
if (name == colormapName) {
colorMapId = (colorMapNames.size() - 1);
colorMapAuthor = map.author;
}
}
}
void draw(void* ctx) {
float menuWidth = ImGui::GetContentRegionAvailWidth();
if (ImGui::Checkbox("Show Waterfall", &showWaterfall)) {
showWaterfall ? gui::waterfall.showWaterfall() : gui::waterfall.hideWaterfall();
core::configManager.aquire();
core::configManager.conf["showWaterfall"] = showWaterfall;
core::configManager.release(true);
}
if (colorMapNames.size() > 0) {
ImGui::Text("Color Map");
ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::Combo("##_sdrpp_color_map_sel", &colorMapId, colorMapNamesTxt.c_str())) {
colormaps::Map map = colormaps::maps[colorMapNames[colorMapId]];
gui::waterfall.updatePalletteFromArray(map.map, map.entryCount);
core::configManager.aquire();
core::configManager.conf["colorMap"] = colorMapNames[colorMapId];
core::configManager.release(true);
colorMapAuthor = map.author;
}
ImGui::Text("Color map Author: %s", colorMapAuthor.c_str());
}
}
}

Wyświetl plik

@ -7,7 +7,7 @@
#include <spdlog/spdlog.h>
float COLOR_MAP[][3] = {
float DEFAULT_COLOR_MAP[][3] = {
{0x00, 0x00, 0x20},
{0x00, 0x00, 0x30},
{0x00, 0x00, 0x50},
@ -106,7 +106,7 @@ namespace ImGui {
viewBandwidth = 1.0;
wholeBandwidth = 1.0;
updatePallette(COLOR_MAP, 13);
updatePallette(DEFAULT_COLOR_MAP, 13);
}
void WaterFall::init() {
@ -568,6 +568,7 @@ namespace ImGui {
}
void WaterFall::updatePallette(float colors[][3], int colorCount) {
std::lock_guard<std::mutex> lck(buf_mtx);
for (int i = 0; i < WATERFALL_RESOLUTION; i++) {
int lowerId = floorf(((float)i / (float)WATERFALL_RESOLUTION) * colorCount);
int upperId = ceilf(((float)i / (float)WATERFALL_RESOLUTION) * colorCount);
@ -579,6 +580,23 @@ namespace ImGui {
float b = (colors[lowerId][2] * (1.0 - ratio)) + (colors[upperId][2] * (ratio));
waterfallPallet[i] = ((uint32_t)255 << 24) | ((uint32_t)b << 16) | ((uint32_t)g << 8) | (uint32_t)r;
}
updateWaterfallFb();
}
void WaterFall::updatePalletteFromArray(float* colors, int colorCount) {
std::lock_guard<std::mutex> lck(buf_mtx);
for (int i = 0; i < WATERFALL_RESOLUTION; i++) {
int lowerId = floorf(((float)i / (float)WATERFALL_RESOLUTION) * colorCount);
int upperId = ceilf(((float)i / (float)WATERFALL_RESOLUTION) * colorCount);
lowerId = std::clamp<int>(lowerId, 0, colorCount - 1);
upperId = std::clamp<int>(upperId, 0, colorCount - 1);
float ratio = (((float)i / (float)WATERFALL_RESOLUTION) * colorCount) - lowerId;
float r = (colors[(lowerId * 3) + 0] * (1.0 - ratio)) + (colors[(upperId * 3) + 0] * (ratio));
float g = (colors[(lowerId * 3) + 1] * (1.0 - ratio)) + (colors[(upperId * 3) + 1] * (ratio));
float b = (colors[(lowerId * 3) + 2] * (1.0 - ratio)) + (colors[(upperId * 3) + 2] * (ratio));
waterfallPallet[i] = ((uint32_t)255 << 24) | ((uint32_t)b << 16) | ((uint32_t)g << 8) | (uint32_t)r;
}
updateWaterfallFb();
}
void WaterFall::autoRange() {
@ -627,6 +645,7 @@ namespace ImGui {
}
void WaterFall::setViewBandwidth(double bandWidth) {
std::lock_guard<std::mutex> lck(buf_mtx);
if (bandWidth == viewBandwidth) {
return;
}
@ -651,6 +670,7 @@ namespace ImGui {
}
void WaterFall::setViewOffset(double offset) {
std::lock_guard<std::mutex> lck(buf_mtx);
if (offset == viewOffset) {
return;
}
@ -690,6 +710,7 @@ namespace ImGui {
}
void WaterFall::setWaterfallMin(float min) {
std::lock_guard<std::mutex> lck(buf_mtx);
if (min == waterfallMin) {
return;
}
@ -702,6 +723,7 @@ namespace ImGui {
}
void WaterFall::setWaterfallMax(float max) {
std::lock_guard<std::mutex> lck(buf_mtx);
if (max == waterfallMax) {
return;
}
@ -720,7 +742,7 @@ namespace ImGui {
}
void WaterFall::setRawFFTSize(int size, bool lock) {
if (lock) { buf_mtx.lock(); }
std::lock_guard<std::mutex> lck(buf_mtx);
rawFFTSize = size;
if (rawFFTs != NULL) {
rawFFTs = (float*)realloc(rawFFTs, rawFFTSize * waterfallHeight * sizeof(float));
@ -729,7 +751,6 @@ namespace ImGui {
rawFFTs = (float*)malloc(rawFFTSize * waterfallHeight * sizeof(float));
}
memset(rawFFTs, 0, rawFFTSize * waterfallHeight * sizeof(float));
if (lock) { buf_mtx.unlock(); }
}
void WaterfallVFO::setOffset(double offset) {

Wyświetl plik

@ -57,6 +57,7 @@ namespace ImGui {
void pushFFT();
void updatePallette(float colors[][3], int colorCount);
void updatePalletteFromArray(float* colors, int colorCount);
void setCenterFrequency(double freq);
double getCenterFrequency();

Wyświetl plik

@ -80,7 +80,7 @@ private:
static void worker(void* ctx) {
FileSourceModule* _this = (FileSourceModule*)ctx;
double sampleRate = _this->reader->getSampleRate();
int blockSize = sampleRate / 200.0;
int blockSize = sampleRate / 200.0f;
int16_t* inBuf = new int16_t[blockSize * 2];
while (true) {

Wyświetl plik

@ -205,7 +205,7 @@ private:
static void worker(void* ctx) {
PlutoSDRSourceModule* _this = (PlutoSDRSourceModule*)ctx;
int blockSize = _this->sampleRate / 200.0;
int blockSize = _this->sampleRate / 200.0f;
struct iio_channel *rx0_i, *rx0_q;
struct iio_buffer *rxbuf;

Wyświetl plik

@ -42,7 +42,7 @@ public:
demod.init(&squelch.out);
agc.init(&demod.out, 1.0f / 125.0f);
agc.init(&demod.out, 20.0f, bbSampRate);
float audioBW = std::min<float>(audioSampRate / 2.0f, bw / 2.0f);
win.init(audioBW, audioBW, bbSampRate);
@ -151,6 +151,11 @@ private:
void setBandwidth(float bandWidth) {
bw = bandWidth;
_vfo->setBandwidth(bw);
float audioBW = std::min<float>(audioSampRate / 2.0f, bw / 2.0f);
win.setSampleRate(bbSampRate * resamp.getInterpolation());
win.setCutoff(audioBW);
win.setTransWidth(audioBW);
resamp.updateWindow(&win);
}
void setSnapInterval(float snapInt) {

Wyświetl plik

@ -53,7 +53,7 @@ public:
c2r.init(&xlator.out);
agc.init(&c2r.out, 1.0f / 125.0f);
agc.init(&c2r.out, 20.0f, audioSampRate);
m2s.init(&agc.out);
}
@ -104,6 +104,7 @@ public:
}
audioSampRate = sampleRate;
float audioBW = std::min<float>(audioSampRate / 2.0f, bw / 2.0f);
agc.setSampleRate(audioSampRate);
resamp.setOutSampleRate(audioSampRate);
win.setSampleRate(bbSampRate * resamp.getInterpolation());
win.setCutoff(audioBW);
@ -170,7 +171,7 @@ private:
const float bwMax = 500;
const float bwMin = 100;
const float bbSampRate = 500;
const float bbSampRate = 6000;
std::string uiPrefix;
float snapInterval = 10;

Wyświetl plik

@ -42,7 +42,7 @@ public:
demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_DSB);
agc.init(&demod.out, 1.0f / 125.0f);
agc.init(&demod.out, 20.0f, bbSampRate);
float audioBW = std::min<float>(audioSampRate / 2.0f, bw / 2.0f);
win.init(audioBW, audioBW, bbSampRate);

Wyświetl plik

@ -42,7 +42,7 @@ public:
demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_LSB);
agc.init(&demod.out, 1.0f / 125.0f);
agc.init(&demod.out, 20.0f, bbSampRate);
float audioBW = std::min<float>(audioSampRate / 2.0f, bw);
win.init(audioBW, audioBW, bbSampRate);
@ -151,6 +151,12 @@ private:
void setBandwidth(float bandWidth) {
bw = bandWidth;
_vfo->setBandwidth(bw);
demod.setBandWidth(bw);
float audioBW = std::min<float>(audioSampRate / 2.0f, bw);
win.setSampleRate(bbSampRate * resamp.getInterpolation());
win.setCutoff(audioBW);
win.setTransWidth(audioBW);
resamp.updateWindow(&win);
}
void setSnapInterval(float snapInt) {

Wyświetl plik

@ -42,7 +42,7 @@ public:
demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_USB);
agc.init(&demod.out, 1.0f / 125.0f);
agc.init(&demod.out, 20.0f, bbSampRate);
float audioBW = std::min<float>(audioSampRate / 2.0f, bw);
win.init(audioBW, audioBW, bbSampRate);
@ -151,6 +151,12 @@ private:
void setBandwidth(float bandWidth) {
bw = bandWidth;
_vfo->setBandwidth(bw);
demod.setBandWidth(bw);
float audioBW = std::min<float>(audioSampRate / 2.0f, bw);
win.setSampleRate(bbSampRate * resamp.getInterpolation());
win.setCutoff(audioBW);
win.setTransWidth(audioBW);
resamp.updateWindow(&win);
}
void setSnapInterval(float snapInt) {

Wyświetl plik

@ -253,8 +253,8 @@ private:
int count = _this->audioStream->read();
if (count < 0) { break; }
for (int i = 0; i < count; i++) {
sampleBuf[(i * 2) + 0] = _this->audioStream->readBuf[i].l * 0x7FFF;
sampleBuf[(i * 2) + 1] = _this->audioStream->readBuf[i].r * 0x7FFF;
sampleBuf[(i * 2) + 0] = _this->audioStream->readBuf[i].l * 512;
sampleBuf[(i * 2) + 1] = _this->audioStream->readBuf[i].r * 512;
}
_this->audioStream->flush();
_this->samplesWritten += count;

Wyświetl plik

@ -0,0 +1,19 @@
{
"name": "Classic",
"author": "Youssef Touil",
"map": [
"#4A0000",
"#750000",
"#9F0000",
"#C60000",
"#FF0000",
"#FE6D16",
"#FFFF00",
"#FFFFFF",
"#1E90FF",
"#000091",
"#000050",
"#000030",
"#000020"
]
}

Wyświetl plik

@ -212,7 +212,7 @@ private:
static void worker(void* ctx) {
RTLTCPSourceModule* _this = (RTLTCPSourceModule*)ctx;
int blockSize = _this->sampleRate / 200.0;
int blockSize = _this->sampleRate / 200.0f;
uint8_t* inBuf = new uint8_t[blockSize * 2];
while (true) {

Wyświetl plik

@ -11,20 +11,21 @@
#define CONCAT(a, b) ((std::string(a) + b).c_str())
#define ADC_RATE 128000000
#define ADC_RATE 64000000
#define XFER_TIMEOUT 5000
#define SEL0 (8) // SEL0 GPIO26
#define SEL1 (16) // SEL1 GPIO27
MOD_INFO {
/* Name: */ "rx888_source",
/* Description: */ "RX888 input module for SDR++",
/* Author: */ "Ryzerth",
/* Version: */ "0.1.0"
SDRPP_MOD_INFO {
/* Name: */ "rx888_source",
/* Description: */ "RX888 source module for SDR++",
/* Author: */ "Ryzerth",
/* Version: */ 0, 1, 0,
/* Max instances */ 1
};
class RX888SourceModule {
class RX888SourceModule : public ModuleManager::Instance {
public:
RX888SourceModule(std::string name) {
this->name = name;
@ -58,6 +59,18 @@ public:
spdlog::info("RX888SourceModule '{0}': Instance deleted!", name);
}
void enable() {
enabled = true;
}
void disable() {
enabled = false;
}
bool isEnabled() {
return enabled;
}
private:
static void menuSelected(void* ctx) {
@ -125,7 +138,7 @@ private:
static void _usbWorker(RX888SourceModule* _this) {
// Calculate hardware block siz
int realBlockSize = ADC_RATE / 200;
int realBlockSize = ADC_RATE / 100;
int i;
for (i = 1; i < realBlockSize; i = (i << 1));
realBlockSize = (i >> 1);
@ -170,9 +183,8 @@ private:
// Check if the incomming data is bulk I/Q and end transfer
if (EndPt->Attributes == 2) {
if (EndPt->FinishDataXfer((PUCHAR)buffer, rLen, &inOvLap, context)) {
if (_this->realStream.aquire() < 0) { break; }
memcpy(_this->realStream.data, buffer, rLen);
_this->realStream.write(rLen / 2);
memcpy(_this->realStream.writeBuf, buffer, rLen);
_this->realStream.swap(rLen / 2);
}
}
@ -196,7 +208,7 @@ private:
while (count >= 0) {
for (int i = 0; i < count; i++) {
iqbuffer[i].q = (float)_this->realStream.data[i] / 32768.0f;
iqbuffer[i].q = (float)_this->realStream.readBuf[i] / 32768.0f;
}
_this->realStream.flush();
@ -205,21 +217,20 @@ private:
lv_32fc_t phaseDelta = lv_cmake(std::cos(delta), std::sin(delta));
// Apply translation
if (_this->stream.aquire() < 0) { break; }
volk_32fc_s32fc_x2_rotator_32fc((lv_32fc_t*)_this->stream.data, (lv_32fc_t*)iqbuffer, phaseDelta, &phase, count);
volk_32fc_s32fc_x2_rotator_32fc((lv_32fc_t*)_this->stream.writeBuf, (lv_32fc_t*)iqbuffer, phaseDelta, &phase, count);
// Decimate
blockSize = count;
for (int d = 0; d < (_this->decimation - 1); d++) {
blockSize = (blockSize >> 1);
for (int i = 0; i < blockSize; i++) {
_this->stream.data[i].i = (_this->stream.data[i*2].i + _this->stream.data[(i*2)+1].i) * 0.5f;
_this->stream.data[i].q = (_this->stream.data[i*2].q + _this->stream.data[(i*2)+1].q) * 0.5f;
_this->stream.writeBuf[i].i = (_this->stream.writeBuf[i*2].i + _this->stream.writeBuf[(i*2)+1].i) * 0.5f;
_this->stream.writeBuf[i].q = (_this->stream.writeBuf[i*2].q + _this->stream.writeBuf[(i*2)+1].q) * 0.5f;
}
}
// Write to output stream
_this->stream.write(blockSize);
_this->stream.swap(blockSize);
// Read from real stream
count = _this->realStream.read();
@ -242,20 +253,20 @@ private:
double sampleRate;
int decimation;
bool running = false;
bool enabled = true;
};
MOD_EXPORT void _INIT_() {
}
MOD_EXPORT void* _CREATE_INSTANCE_(std::string name) {
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
return new RX888SourceModule(name);
}
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) {
delete (RX888SourceModule*)instance;
}
MOD_EXPORT void _STOP_() {
MOD_EXPORT void _END_() {
}