2020-06-10 04:13:56 +02:00
|
|
|
#include <main_window.h>
|
|
|
|
#include <imgui_plot.h>
|
|
|
|
#include <hackrf.h>
|
|
|
|
#include <cdsp/hackrf.h>
|
|
|
|
#include <cdsp/resampling.h>
|
|
|
|
#include <cdsp/demodulation.h>
|
|
|
|
#include <cdsp/filter.h>
|
|
|
|
#include <thread>
|
|
|
|
#include <complex>
|
|
|
|
#include <cdsp/generator.h>
|
|
|
|
#include <cdsp/math.h>
|
|
|
|
#include <waterfall.h>
|
|
|
|
#include <fftw3.h>
|
2020-06-10 18:52:07 +02:00
|
|
|
#include <signal_path.h>
|
2020-06-10 04:13:56 +02:00
|
|
|
|
|
|
|
std::thread worker;
|
|
|
|
std::mutex fft_mtx;
|
|
|
|
ImGui::WaterFall wtf;
|
|
|
|
hackrf_device* dev;
|
2020-06-10 18:52:07 +02:00
|
|
|
fftwf_complex *fft_in, *fft_out;
|
|
|
|
fftwf_plan p;
|
2020-06-15 15:53:45 +02:00
|
|
|
float* tempData;
|
2020-06-10 18:52:07 +02:00
|
|
|
|
2020-06-15 15:53:45 +02:00
|
|
|
int fftSize = 8192 * 8;
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-06-15 15:53:45 +02:00
|
|
|
bool dcbias = true;
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-06-15 15:53:45 +02:00
|
|
|
cdsp::HackRFSource src;
|
|
|
|
SignalPath sigPath;
|
|
|
|
std::vector<float> _data;
|
|
|
|
std::vector<float> fftTaps;
|
|
|
|
void fftHandler(cdsp::complex_t* samples) {
|
|
|
|
fftwf_execute(p);
|
|
|
|
int half = fftSize / 2;
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-06-15 15:53:45 +02:00
|
|
|
for (int i = 0; i < half; i++) {
|
|
|
|
_data.push_back(log10(std::abs(std::complex<float>(fft_out[half + i][0], fft_out[half + i][1])) / (float)fftSize) * 10.0f);
|
|
|
|
}
|
|
|
|
for (int i = 0; i < half; i++) {
|
|
|
|
_data.push_back(log10(std::abs(std::complex<float>(fft_out[i][0], fft_out[i][1])) / (float)fftSize) * 10.0f);
|
|
|
|
}
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-06-15 15:53:45 +02:00
|
|
|
for (int i = 5; i < fftSize; i++) {
|
|
|
|
_data[i] = (_data[i - 4] + _data[i - 3] + _data[i - 2] + _data[i - 1] + _data[i]) / 5.0f;
|
|
|
|
}
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-06-15 15:53:45 +02:00
|
|
|
wtf.pushFFT(_data, fftSize);
|
|
|
|
_data.clear();
|
|
|
|
}
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-06-15 15:53:45 +02:00
|
|
|
void windowInit() {
|
|
|
|
int sampleRate = 2000000;
|
|
|
|
wtf.bandWidth = sampleRate;
|
|
|
|
wtf.range = 500000;
|
|
|
|
wtf.centerFrequency = 90500000;
|
|
|
|
printf("fft taps: %d\n", fftTaps.size());
|
|
|
|
|
|
|
|
fft_in = (fftwf_complex*) fftw_malloc(sizeof(fftwf_complex) * fftSize);
|
|
|
|
fft_out = (fftwf_complex*) fftw_malloc(sizeof(fftwf_complex) * fftSize);
|
|
|
|
p = fftwf_plan_dft_1d(fftSize, fft_in, fft_out, FFTW_FORWARD, FFTW_ESTIMATE);
|
2020-06-10 04:13:56 +02:00
|
|
|
|
2020-06-15 15:53:45 +02:00
|
|
|
printf("Starting DSP Thread!\n");
|
2020-06-10 18:52:07 +02:00
|
|
|
|
2020-06-15 15:53:45 +02:00
|
|
|
hackrf_init();
|
|
|
|
hackrf_device_list_t* list = hackrf_device_list();
|
|
|
|
|
|
|
|
int err = hackrf_device_list_open(list, 0, &dev);
|
|
|
|
if (err != 0) {
|
|
|
|
printf("Error while opening HackRF: %d\n", err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
hackrf_set_freq(dev, 90500000);
|
|
|
|
//hackrf_set_txvga_gain(dev, 10);
|
|
|
|
hackrf_set_amp_enable(dev, 1);
|
|
|
|
hackrf_set_lna_gain(dev, 24);
|
|
|
|
hackrf_set_vga_gain(dev, 20);
|
|
|
|
hackrf_set_baseband_filter_bandwidth(dev, sampleRate);
|
|
|
|
hackrf_set_sample_rate(dev, sampleRate);
|
|
|
|
|
|
|
|
src.init(dev, 64000);
|
|
|
|
|
|
|
|
sigPath.init(sampleRate, 20, fftSize, &src.output, (cdsp::complex_t*)fft_in, fftHandler);
|
|
|
|
sigPath.start();
|
2020-06-10 04:13:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int Current = 0;
|
|
|
|
bool showExample = false;
|
|
|
|
|
2020-06-15 15:53:45 +02:00
|
|
|
int freq = 90500;
|
|
|
|
int _freq = 90500;
|
|
|
|
|
|
|
|
bool state = false;
|
|
|
|
bool mulstate = true;
|
|
|
|
|
|
|
|
float vfoFreq = 92000000.0f;
|
|
|
|
float lastVfoFreq = 92000000.0f;
|
|
|
|
|
|
|
|
float volume = 1.0f;
|
|
|
|
float lastVolume = 1.0f;
|
2020-06-10 04:13:56 +02:00
|
|
|
|
|
|
|
void drawWindow() {
|
|
|
|
if (freq != _freq) {
|
|
|
|
_freq = freq;
|
2020-06-10 18:52:07 +02:00
|
|
|
wtf.centerFrequency = freq * 1000;
|
2020-06-10 04:13:56 +02:00
|
|
|
hackrf_set_freq(dev, freq * 1000);
|
|
|
|
}
|
|
|
|
|
2020-06-15 15:53:45 +02:00
|
|
|
if (vfoFreq != lastVfoFreq) {
|
|
|
|
lastVfoFreq = vfoFreq;
|
|
|
|
sigPath.setVFOFrequency(vfoFreq - (freq * 1000));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (volume != lastVolume) {
|
|
|
|
lastVolume = volume;
|
|
|
|
sigPath.setVolume(volume);
|
|
|
|
}
|
|
|
|
|
2020-06-10 04:13:56 +02:00
|
|
|
|
|
|
|
if (ImGui::BeginMenuBar())
|
|
|
|
{
|
|
|
|
if (ImGui::BeginMenu("File"))
|
|
|
|
{
|
|
|
|
ImGui::EndMenu();
|
|
|
|
}
|
|
|
|
if (ImGui::BeginMenu("Edit"))
|
|
|
|
{
|
|
|
|
ImGui::MenuItem("Show Example Window", "", &showExample);
|
|
|
|
ImGui::EndMenu();
|
|
|
|
}
|
|
|
|
ImGui::EndMenuBar();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (showExample) {
|
|
|
|
ImGui::ShowDemoWindow();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ImVec2 vMin = ImGui::GetWindowContentRegionMin();
|
|
|
|
ImVec2 vMax = ImGui::GetWindowContentRegionMax();
|
|
|
|
|
|
|
|
int width = vMax.x - vMin.x;
|
|
|
|
int height = vMax.y - vMin.y;
|
|
|
|
|
|
|
|
ImGui::Columns(2, "WindowColumns", false);
|
|
|
|
ImGui::SetColumnWidth(0, 300);
|
|
|
|
|
|
|
|
// Left Column
|
|
|
|
ImGui::BeginChild("Left Column");
|
|
|
|
|
|
|
|
if (ImGui::CollapsingHeader("Source")) {
|
|
|
|
|
2020-06-15 15:53:45 +02:00
|
|
|
//ImGui::Combo("Source", &Current, "HackRF One\0RTL-SDR");
|
|
|
|
ImGui::SliderFloat("Volume", &volume, 0.0f, 1.0f);
|
|
|
|
if (ImGui::Button("Start") && !state) {
|
|
|
|
state = true;
|
|
|
|
src.start();
|
|
|
|
}
|
|
|
|
if (ImGui::Button("Stop") && state) {
|
|
|
|
state = false;
|
|
|
|
src.stop();
|
|
|
|
}
|
2020-06-10 04:13:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::CollapsingHeader("Radio")) {
|
|
|
|
ImGui::BeginGroup();
|
|
|
|
|
|
|
|
ImGui::Columns(4, "RadioModeColumns", false);
|
|
|
|
ImGui::RadioButton("NFM", false);
|
|
|
|
ImGui::RadioButton("WFM", true);
|
|
|
|
ImGui::NextColumn();
|
|
|
|
ImGui::RadioButton("AM", false);
|
|
|
|
ImGui::RadioButton("DSB", false);
|
|
|
|
ImGui::NextColumn();
|
|
|
|
ImGui::RadioButton("USB", false);
|
|
|
|
ImGui::RadioButton("CW", false);
|
|
|
|
ImGui::NextColumn();
|
|
|
|
ImGui::RadioButton("LSB", false);
|
|
|
|
ImGui::RadioButton("RAW", false);
|
|
|
|
ImGui::Columns(1, "EndRadioModeColumns", false);
|
|
|
|
|
|
|
|
ImGui::InputInt("Frequency (kHz)", &freq);
|
2020-06-10 18:52:07 +02:00
|
|
|
ImGui::Checkbox("DC Bias Removal", &dcbias);
|
2020-06-10 04:13:56 +02:00
|
|
|
|
|
|
|
ImGui::EndGroup();
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::CollapsingHeader("Audio");
|
|
|
|
|
|
|
|
ImGui::CollapsingHeader("Display");
|
|
|
|
|
|
|
|
ImGui::CollapsingHeader("Recording");
|
|
|
|
|
|
|
|
if(ImGui::CollapsingHeader("Debug")) {
|
|
|
|
ImGui::Text("Frame time: %.3f ms/frame", 1000.0f / ImGui::GetIO().Framerate);
|
|
|
|
ImGui::Text("Framerate: %.1f FPS", ImGui::GetIO().Framerate);
|
2020-06-15 15:53:45 +02:00
|
|
|
|
|
|
|
if (ImGui::Button("FM demod")) {
|
|
|
|
sigPath.setDemodulator(SignalPath::DEMOD_FM);
|
|
|
|
}
|
|
|
|
if (ImGui::Button("AM demod")) {
|
|
|
|
sigPath.setDemodulator(SignalPath::DEMOD_AM);
|
|
|
|
}
|
2020-06-10 04:13:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndChild();
|
|
|
|
|
|
|
|
// Right Column
|
|
|
|
ImGui::NextColumn();
|
|
|
|
|
|
|
|
ImGui::BeginChild("Waterfall");
|
2020-06-15 15:53:45 +02:00
|
|
|
wtf.draw(&vfoFreq);
|
2020-06-10 04:13:56 +02:00
|
|
|
ImGui::EndChild();
|
|
|
|
}
|