Linux App Improvements
- Fix some memory access bugs - Add optional support for CUDA FFTs - Compile a shared library, as part of a gnuradio integration project
This commit is contained in:
parent
fb08e15328
commit
4a753eff6a
@ -2,3 +2,4 @@
|
|||||||
rftoolui
|
rftoolui
|
||||||
ftd3xx/*
|
ftd3xx/*
|
||||||
!ftd3xx/PLACEHOLDER
|
!ftd3xx/PLACEHOLDER
|
||||||
|
vgcore.*
|
@ -1,21 +1,30 @@
|
|||||||
src = $(wildcard *.cpp ad9361/*.cpp)
|
src = $(wildcard ad9361/*.cpp rftool/*.cpp)
|
||||||
obj = $(src:.cpp=.o)
|
obj = $(src:.cpp=.o)
|
||||||
|
|
||||||
csrc = $(wildcard *.c ad9361/*.c)
|
csrc = $(wildcard ad9361/*.c rftool/*.c)
|
||||||
cobj = $(csrc:.c=.o)
|
cobj = $(csrc:.c=.o)
|
||||||
|
|
||||||
|
appsrc = main.cpp FFTRenderer.cpp
|
||||||
|
appobj = $(appsrc:.cpp=.o)
|
||||||
|
|
||||||
|
libsrc = librftool.cpp
|
||||||
|
libobj = $(libsrc:.cpp=.o)
|
||||||
|
|
||||||
GTKINC = -I/usr/include/gtkmm-3.0 -I/usr/lib/gtkmm-3.0/include -I/usr/include/atkmm-1.6 -I/usr/include/gtk-3.0/unix-print -I/usr/include/gdkmm-3.0 -I/usr/lib/gdkmm-3.0/include -I/usr/include/giomm-2.4 -I/usr/lib/giomm-2.4/include -I/usr/include/pangomm-1.4 -I/usr/lib/pangomm-1.4/include -I/usr/include/glibmm-2.4 -I/usr/lib/glibmm-2.4/include -I/usr/include/gtk-3.0 -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include -I/usr/include/gtk-3.0 -I/usr/include/gio-unix-2.0/ -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/cairomm-1.0 -I/usr/lib/cairomm-1.0/include -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/harfbuzz -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/freetype2 -I/usr/include/harfbuzz -I/usr/include/libdrm -I/usr/include/libpng16 -I/usr/include/sigc++-2.0 -I/usr/lib/sigc++-2.0/include -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libpng16 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
|
GTKINC = -I/usr/include/gtkmm-3.0 -I/usr/lib/gtkmm-3.0/include -I/usr/include/atkmm-1.6 -I/usr/include/gtk-3.0/unix-print -I/usr/include/gdkmm-3.0 -I/usr/lib/gdkmm-3.0/include -I/usr/include/giomm-2.4 -I/usr/lib/giomm-2.4/include -I/usr/include/pangomm-1.4 -I/usr/lib/pangomm-1.4/include -I/usr/include/glibmm-2.4 -I/usr/lib/glibmm-2.4/include -I/usr/include/gtk-3.0 -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include -I/usr/include/gtk-3.0 -I/usr/include/gio-unix-2.0/ -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/cairomm-1.0 -I/usr/lib/cairomm-1.0/include -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/harfbuzz -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/freetype2 -I/usr/include/harfbuzz -I/usr/include/libdrm -I/usr/include/libpng16 -I/usr/include/sigc++-2.0 -I/usr/lib/sigc++-2.0/include -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libpng16 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
|
||||||
GTKLIBS = -lgtkmm-3.0 -latkmm-1.6 -lgdkmm-3.0 -lgiomm-2.4 -lpangomm-1.4 -lglibmm-2.4 -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lgio-2.0 -lcairomm-1.0 -lcairo -lsigc-2.0 -lgdk_pixbuf-2.0 -lgobject-2.0 -lglib-2.0
|
GTKLIBS = -lgtkmm-3.0 -latkmm-1.6 -lgdkmm-3.0 -lgiomm-2.4 -lpangomm-1.4 -lglibmm-2.4 -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lgio-2.0 -lcairomm-1.0 -lcairo -lsigc-2.0 -lgdk_pixbuf-2.0 -lgobject-2.0 -lglib-2.0
|
||||||
|
|
||||||
CFLAGS = -g -O3 -m64 -I ad9361/platform $(GTKINC)
|
CFLAGS = -fPIC -g -m64 -I ad9361/platform -I rftool -I . $(GTKINC)
|
||||||
CXXFLAGS = -std=c++11 -g -O3 -m64 -I ad9361/platform $(GTKINC)
|
CXXFLAGS = -fPIC -std=gnu++11 -g -O3 -m64 -I ad9361/platform -I rftool -I . $(GTKINC)
|
||||||
LDFLAGS = -L ftd3xx/ -lftd3xx $(GTKLIBS) -lfftw3 -lm -pthread -lrt -m64
|
LDFLAGS = -L ftd3xx/ -lftd3xx $(GTKLIBS) -lfftw3 -lm -pthread -lrt -m64
|
||||||
all: rftoolui
|
LIB_LDFLAGS = -L ftd3xx/ -lftd3xx -lfftw3 -lm -pthread -lrt -m64
|
||||||
|
all: rftoolui librftool.so
|
||||||
|
|
||||||
rftoolui: $(obj) $(cobj)
|
rftoolui: $(obj) $(cobj) $(appobj)
|
||||||
$(CXX) -o $@ $^ $(LDFLAGS)
|
$(CXX) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
librftool.so: $(obj) $(cobj) $(libobj)
|
||||||
|
$(CXX) -shared -o $@ $^ $(LIB_LDFLAGS)
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -f $(obj) $(cobj) rftoolui
|
rm -f $(obj) $(cobj) $(appobj) $(libobj) rftoolui librftool.so
|
30
linux-app/spectrum-analyser/Makefile.CUDA
Normal file
30
linux-app/spectrum-analyser/Makefile.CUDA
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
src = $(wildcard ad9361/*.cpp rftool/*.cpp)
|
||||||
|
obj = $(src:.cpp=.o)
|
||||||
|
|
||||||
|
csrc = $(wildcard ad9361/*.c rftool/*.c)
|
||||||
|
cobj = $(csrc:.c=.o)
|
||||||
|
|
||||||
|
appsrc = main.cpp FFTRenderer.cpp
|
||||||
|
appobj = $(appsrc:.cpp=.o)
|
||||||
|
|
||||||
|
libsrc = librftool.cpp
|
||||||
|
libobj = $(libsrc:.cpp=.o)
|
||||||
|
|
||||||
|
GTKINC = -I/usr/include/gtkmm-3.0 -I/usr/lib/gtkmm-3.0/include -I/usr/include/atkmm-1.6 -I/usr/include/gtk-3.0/unix-print -I/usr/include/gdkmm-3.0 -I/usr/lib/gdkmm-3.0/include -I/usr/include/giomm-2.4 -I/usr/lib/giomm-2.4/include -I/usr/include/pangomm-1.4 -I/usr/lib/pangomm-1.4/include -I/usr/include/glibmm-2.4 -I/usr/lib/glibmm-2.4/include -I/usr/include/gtk-3.0 -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include -I/usr/include/gtk-3.0 -I/usr/include/gio-unix-2.0/ -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/cairomm-1.0 -I/usr/lib/cairomm-1.0/include -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/harfbuzz -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/freetype2 -I/usr/include/harfbuzz -I/usr/include/libdrm -I/usr/include/libpng16 -I/usr/include/sigc++-2.0 -I/usr/lib/sigc++-2.0/include -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libpng16 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
|
||||||
|
GTKLIBS = -lgtkmm-3.0 -latkmm-1.6 -lgdkmm-3.0 -lgiomm-2.4 -lpangomm-1.4 -lglibmm-2.4 -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lgio-2.0 -lcairomm-1.0 -lcairo -lsigc-2.0 -lgdk_pixbuf-2.0 -lgobject-2.0 -lglib-2.0
|
||||||
|
|
||||||
|
CFLAGS = -fPIC -g -m64 -I ad9361/platform -I rftool -I . $(GTKINC)
|
||||||
|
CXXFLAGS = -fPIC -DCUDA_FFT -std=gnu++11 -g -O3 -m64 -I ad9361/platform -I rftool -I . -I/opt/cuda/include $(GTKINC)
|
||||||
|
LDFLAGS = -L ftd3xx/ -lftd3xx $(GTKLIBS) -L/opt/cuda/lib64 -lcufft -lcufftw -lm -pthread -lrt -m64
|
||||||
|
LIB_LDFLAGS = -L ftd3xx/ -lftd3xx -lfftw3 -lm -pthread -lrt -m64
|
||||||
|
all: rftoolui librftool.so
|
||||||
|
|
||||||
|
rftoolui: $(obj) $(cobj) $(appobj)
|
||||||
|
$(CXX) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
librftool.so: $(obj) $(cobj) $(libobj)
|
||||||
|
$(CXX) -shared -o $@ $^ $(LIB_LDFLAGS)
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -f $(obj) $(cobj) $(appobj) $(libobj) rftoolui librftool.so
|
@ -640,7 +640,7 @@ static int32_t __ad9361_spi_readf(struct spi_device *spi, uint32_t reg,
|
|||||||
* @return The bits value or negative error code in case of failure.
|
* @return The bits value or negative error code in case of failure.
|
||||||
*/
|
*/
|
||||||
#define ad9361_spi_readf(spi, reg, mask) \
|
#define ad9361_spi_readf(spi, reg, mask) \
|
||||||
__ad9361_spi_readf(spi, reg, mask, __ffs(mask))
|
__ad9361_spi_readf(spi, reg, mask, __the_real_ffs(mask))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SPI register write.
|
* SPI register write.
|
||||||
@ -686,6 +686,7 @@ int32_t ad9361_spi_write(struct spi_device *spi,
|
|||||||
static int32_t __ad9361_spi_writef(struct spi_device *spi, uint32_t reg,
|
static int32_t __ad9361_spi_writef(struct spi_device *spi, uint32_t reg,
|
||||||
uint32_t mask, uint32_t offset, uint32_t val)
|
uint32_t mask, uint32_t offset, uint32_t val)
|
||||||
{
|
{
|
||||||
|
//printf("writef %04x %02x %02x %02x\n", reg, mask, offset, val);
|
||||||
uint8_t buf;
|
uint8_t buf;
|
||||||
int32_t ret;
|
int32_t ret;
|
||||||
|
|
||||||
@ -695,6 +696,7 @@ static int32_t __ad9361_spi_writef(struct spi_device *spi, uint32_t reg,
|
|||||||
ret = ad9361_spi_readm(spi, reg, &buf, 1);
|
ret = ad9361_spi_readm(spi, reg, &buf, 1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
//printf("orig %02x\n", buf);
|
||||||
|
|
||||||
buf &= ~mask;
|
buf &= ~mask;
|
||||||
buf |= ((val << offset) & mask);
|
buf |= ((val << offset) & mask);
|
||||||
@ -711,7 +713,7 @@ static int32_t __ad9361_spi_writef(struct spi_device *spi, uint32_t reg,
|
|||||||
* @return 0 in case of success, negative error code otherwise.
|
* @return 0 in case of success, negative error code otherwise.
|
||||||
*/
|
*/
|
||||||
#define ad9361_spi_writef(spi, reg, mask, val) \
|
#define ad9361_spi_writef(spi, reg, mask, val) \
|
||||||
__ad9361_spi_writef(spi, reg, mask, __ffs(mask), val)
|
__ad9361_spi_writef(spi, reg, mask, __the_real_ffs(mask), val)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SPI multiple bytes register write.
|
* SPI multiple bytes register write.
|
@ -286,10 +286,11 @@ uint64_t do_div(uint64_t* n, uint64_t base)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************//**
|
/***************************************************************************//**
|
||||||
* @brief __ffs
|
* @brief __the_real_ffs
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
uint32_t __ffs(uint32_t word)
|
uint32_t __the_real_ffs(uint32_t word)
|
||||||
{
|
{
|
||||||
|
//printf("ffs %08x\n", word);
|
||||||
int32_t num = 0;
|
int32_t num = 0;
|
||||||
|
|
||||||
if ((word & 0xffff) == 0) {
|
if ((word & 0xffff) == 0) {
|
||||||
@ -310,6 +311,7 @@ uint32_t __ffs(uint32_t word)
|
|||||||
}
|
}
|
||||||
if ((word & 0x1) == 0)
|
if ((word & 0x1) == 0)
|
||||||
num += 1;
|
num += 1;
|
||||||
|
//printf("== %d\n", num);
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
@ -129,7 +129,7 @@ uint32_t int_sqrt(uint32_t x);
|
|||||||
int32_t ilog2(int32_t x);
|
int32_t ilog2(int32_t x);
|
||||||
uint64_t do_div(uint64_t* n,
|
uint64_t do_div(uint64_t* n,
|
||||||
uint64_t base);
|
uint64_t base);
|
||||||
uint32_t __ffs(uint32_t word);
|
uint32_t __the_real_ffs(uint32_t word);
|
||||||
void * ERR_PTR(long error);
|
void * ERR_PTR(long error);
|
||||||
void *zmalloc(size_t size);
|
void *zmalloc(size_t size);
|
||||||
|
|
BIN
linux-app/spectrum-analyser/libftd3xx.so
Executable file
BIN
linux-app/spectrum-analyser/libftd3xx.so
Executable file
Binary file not shown.
58
linux-app/spectrum-analyser/librftool.cpp
Normal file
58
linux-app/spectrum-analyser/librftool.cpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include "librftool.h"
|
||||||
|
#include "rftool/RFThread.hpp"
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
struct RFToolDev {
|
||||||
|
RFThread thrd;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
HRFTool rftool_begin() {
|
||||||
|
HRFTool dev = new RFToolDev();
|
||||||
|
dev->thrd.start();
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rftool_end(HRFTool dev) { dev->thrd.stop(); }
|
||||||
|
|
||||||
|
void rftool_set_center_freq(HRFTool dev, uint64_t freq) {
|
||||||
|
dev->thrd.setCenterFreq(freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t rftool_get_center_freq(HRFTool dev) {
|
||||||
|
return dev->thrd.getCenterFreq();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rftool_set_bandwidth(HRFTool dev, uint32_t bw) {
|
||||||
|
dev->thrd.setBandwidth(bw);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t rftool_get_bandwidth(HRFTool dev) {
|
||||||
|
return dev->thrd.getCurrentSampleRate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rftool_set_gain(HRFTool dev, int gain) { dev->thrd.setGain(gain); }
|
||||||
|
|
||||||
|
int rftool_get_gain(HRFTool dev) { return dev->thrd.getGain(); }
|
||||||
|
|
||||||
|
void rftool_set_agc_enabled(HRFTool dev, bool en) {
|
||||||
|
dev->thrd.setAgcEnable(en);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rftool_get_agc_enabled(HRFTool dev) { return dev->thrd.getAgcEnable(); }
|
||||||
|
|
||||||
|
void rftool_set_input(HRFTool dev, int inp) { dev->thrd.setInputPort(inp); }
|
||||||
|
|
||||||
|
int rftool_get_input(HRFTool dev) { return dev->thrd.getInputPort(); }
|
||||||
|
|
||||||
|
void rftool_get_samples(HRFTool dev, double _Complex *buf, int n) {
|
||||||
|
return dev->thrd.getSamples(buf, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int rftool_get_new_samples(HRFTool dev, double _Complex *buf, int n) {
|
||||||
|
return dev->thrd.getRecentSamples(buf, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
39
linux-app/spectrum-analyser/librftool.h
Normal file
39
linux-app/spectrum-analyser/librftool.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#ifndef LIBRFTOOL_H
|
||||||
|
#define LIBRFTOOL_H
|
||||||
|
|
||||||
|
#include <complex.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct RFToolDev;
|
||||||
|
|
||||||
|
typedef RFToolDev *HRFTool;
|
||||||
|
|
||||||
|
extern HRFTool rftool_begin();
|
||||||
|
extern void rftool_end(HRFTool dev);
|
||||||
|
|
||||||
|
extern void rftool_set_center_freq(HRFTool dev, uint64_t freq);
|
||||||
|
extern uint64_t rftool_get_center_freq(HRFTool dev);
|
||||||
|
|
||||||
|
extern void rftool_set_bandwidth(HRFTool dev, uint32_t bw);
|
||||||
|
extern uint32_t rftool_get_bandwidth(HRFTool dev);
|
||||||
|
|
||||||
|
extern void rftool_set_gain(HRFTool dev, int gain);
|
||||||
|
extern int rftool_get_gain(HRFTool dev);
|
||||||
|
|
||||||
|
extern void rftool_set_agc_enabled(HRFTool dev, bool en);
|
||||||
|
extern bool rftool_get_agc_enabled(HRFTool dev);
|
||||||
|
|
||||||
|
extern void rftool_set_input(HRFTool dev, int inp);
|
||||||
|
extern int rftool_get_input(HRFTool dev);
|
||||||
|
|
||||||
|
extern void rftool_get_samples(HRFTool dev, double _Complex *buf, int n);
|
||||||
|
extern int rftool_get_new_samples(HRFTool dev, double _Complex *buf, int n);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* end of include guard: LIBRFTOOL_H */
|
BIN
linux-app/spectrum-analyser/librftool.so
Executable file
BIN
linux-app/spectrum-analyser/librftool.so
Executable file
Binary file not shown.
@ -8,12 +8,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "FFTRenderer.hpp"
|
#include "FFTRenderer.hpp"
|
||||||
#include "RFThread.hpp"
|
#include "rftool/RFThread.hpp"
|
||||||
#include <ccomplex>
|
#include <ccomplex>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#define complex
|
#define complex
|
||||||
|
#ifdef CUDA_FFT
|
||||||
|
#include <cufftw.h>
|
||||||
|
#else
|
||||||
#include <fftw3.h>
|
#include <fftw3.h>
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@ -54,7 +58,7 @@ const size_t max_fftLength = 16777216;
|
|||||||
_Complex double *x_buf, *y_buf;
|
_Complex double *x_buf, *y_buf;
|
||||||
atomic<bool> draw_done{false};
|
atomic<bool> draw_done{false};
|
||||||
atomic<ulong> fftLength{524288};
|
atomic<ulong> fftLength{524288};
|
||||||
|
double *fft_window;
|
||||||
// Waterfall display points
|
// Waterfall display points
|
||||||
const int waterfall_wmax = 3840, waterfall_hmax = 2160;
|
const int waterfall_wmax = 3840, waterfall_hmax = 2160;
|
||||||
float waterfall_points[waterfall_hmax][waterfall_wmax] = {{0.0}};
|
float waterfall_points[waterfall_hmax][waterfall_wmax] = {{0.0}};
|
||||||
@ -65,11 +69,20 @@ void update_fft() {
|
|||||||
|
|
||||||
rft->getSamples(x_buf, fftLength);
|
rft->getSamples(x_buf, fftLength);
|
||||||
|
|
||||||
|
if ((fftplan == nullptr) || (fftLength != last_fftLength)) {
|
||||||
|
//Build/rebuild window
|
||||||
|
const double a0 = 0.42, a1 = 0.5, a2 = 0.08, pi = 3.1415;
|
||||||
|
for(int ii = 0; ii < fftLength; ii++) {
|
||||||
|
fft_window[ii] = a0 - a1 * cos((2 * pi * ii) / (fftLength - 1)) + a2 * cos((4 * pi * ii) / (fftLength - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int ii = 0; ii < fftLength; ii++) {
|
for (int ii = 0; ii < fftLength; ii++) {
|
||||||
// Multiplying by -1^ii puts centre at origin
|
// Multiplying by -1^ii puts centre at origin
|
||||||
if ((ii % 2) == 1) {
|
if ((ii % 2) == 1) {
|
||||||
x_buf[ii] *= -1;
|
x_buf[ii] *= -1;
|
||||||
}
|
}
|
||||||
|
x_buf[ii] *= fft_window[ii];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fftplan == nullptr) || (fftLength != last_fftLength)) {
|
if ((fftplan == nullptr) || (fftLength != last_fftLength)) {
|
||||||
@ -220,8 +233,14 @@ bool on_wf_draw(const Cairo::RefPtr<Cairo::Context> &cr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
#ifdef CUDA_FFT
|
||||||
|
x_buf = (_Complex double*)malloc(max_fftLength * sizeof(_Complex double));
|
||||||
|
y_buf = (_Complex double*)malloc(max_fftLength * sizeof(_Complex double));
|
||||||
|
#else
|
||||||
x_buf = fftw_alloc_complex(max_fftLength);
|
x_buf = fftw_alloc_complex(max_fftLength);
|
||||||
y_buf = fftw_alloc_complex(max_fftLength);
|
y_buf = fftw_alloc_complex(max_fftLength);
|
||||||
|
#endif
|
||||||
|
fft_window = new double[max_fftLength];
|
||||||
fftr = new FFTRenderer();
|
fftr = new FFTRenderer();
|
||||||
|
|
||||||
Gtk::Main kit(argc, argv);
|
Gtk::Main kit(argc, argv);
|
558
linux-app/spectrum-analyser/rftool/RFThread.cpp
Normal file
558
linux-app/spectrum-analyser/rftool/RFThread.cpp
Normal file
@ -0,0 +1,558 @@
|
|||||||
|
#include "RFThread.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
AD9361_InitParam default_init_param = {
|
||||||
|
/* Identification number */
|
||||||
|
0, // id_no;
|
||||||
|
/* Reference Clock */
|
||||||
|
40000000UL, // reference_clk_rate
|
||||||
|
/* Base Configuration */
|
||||||
|
0, // two_rx_two_tx_mode_enable *** adi,2rx-2tx-mode-enable
|
||||||
|
0, // frequency_division_duplex_mode_enable ***
|
||||||
|
// adi,frequency-division-duplex-mode-enable
|
||||||
|
0, // frequency_division_duplex_independent_mode_enable ***
|
||||||
|
// adi,frequency-division-duplex-independent-mode-enable
|
||||||
|
1, // tdd_use_dual_synth_mode_enable *** adi,tdd-use-dual-synth-mode-enable
|
||||||
|
0, // tdd_skip_vco_cal_enable *** adi,tdd-skip-vco-cal-enable
|
||||||
|
0, // tx_fastlock_delay_ns *** adi,tx-fastlock-delay-ns
|
||||||
|
0, // rx_fastlock_delay_ns *** adi,rx-fastlock-delay-ns
|
||||||
|
0, // rx_fastlock_pincontrol_enable *** adi,rx-fastlock-pincontrol-enable
|
||||||
|
0, // tx_fastlock_pincontrol_enable *** adi,tx-fastlock-pincontrol-enable
|
||||||
|
0, // external_rx_lo_enable *** adi,external-rx-lo-enable
|
||||||
|
0, // external_tx_lo_enable *** adi,external-tx-lo-enable
|
||||||
|
5, // dc_offset_tracking_update_event_mask ***
|
||||||
|
// adi,dc-offset-tracking-update-event-mask
|
||||||
|
6, // dc_offset_attenuation_high_range ***
|
||||||
|
// adi,dc-offset-tracking-update-event-mask
|
||||||
|
5, // dc_offset_attenuation_low_range ***
|
||||||
|
// adi,dc-offset-tracking-update-event-mask
|
||||||
|
0x28, // dc_offset_count_high_range ***
|
||||||
|
// adi,dc-offset-tracking-update-event-mask
|
||||||
|
0x32, // dc_offset_count_low_range ***
|
||||||
|
// adi,dc-offset-tracking-update-event-mask
|
||||||
|
0, // tdd_use_fdd_vco_tables_enable *** adi,tdd-use-fdd-vco-tables-enable
|
||||||
|
0, // split_gain_table_mode_enable *** adi,split-gain-table-mode-enable
|
||||||
|
40000000UL, // trx_synthesizer_target_fref_overwrite_hz ***
|
||||||
|
// adi,trx-synthesizer-target-fref-overwrite-hz
|
||||||
|
0, // qec_tracking_slow_mode_enable *** adi,qec-tracking-slow-mode-enable
|
||||||
|
/* ENSM Control */
|
||||||
|
0, // ensm_enable_pin_pulse_mode_enable ***
|
||||||
|
// adi,ensm-enable-pin-pulse-mode-enable
|
||||||
|
0, // ensm_enable_txnrx_control_enable ***
|
||||||
|
// adi,ensm-enable-txnrx-control-enable
|
||||||
|
/* LO Control */
|
||||||
|
2400000000UL, // rx_synthesizer_frequency_hz ***
|
||||||
|
// adi,rx-synthesizer-frequency-hz
|
||||||
|
2400000000UL, // tx_synthesizer_frequency_hz ***
|
||||||
|
// adi,tx-synthesizer-frequency-hz
|
||||||
|
/* Rate & BW Control */
|
||||||
|
{983040000, 245760000, 122880000, 61440000, 30720000,
|
||||||
|
30720000}, // uint32_t rx_path_clock_frequencies[6] ***
|
||||||
|
// adi,rx-path-clock-frequencies
|
||||||
|
{983040000, 122880000, 122880000, 61440000, 30720000,
|
||||||
|
30720000}, // uint32_t tx_path_clock_frequencies[6] ***
|
||||||
|
// adi,tx-path-clock-frequencies
|
||||||
|
30720000, // rf_rx_bandwidth_hz *** adi,rf-rx-bandwidth-hz
|
||||||
|
30720000, // rf_tx_bandwidth_hz *** adi,rf-tx-bandwidth-hz
|
||||||
|
/* RF Port Control */
|
||||||
|
0, // rx_rf_port_input_select *** adi,rx-rf-port-input-select
|
||||||
|
0, // tx_rf_port_input_select *** adi,tx-rf-port-input-select
|
||||||
|
/* TX Attenuation Control */
|
||||||
|
10000, // tx_attenuation_mdB *** adi,tx-attenuation-mdB
|
||||||
|
0, // update_tx_gain_in_alert_enable *** adi,update-tx-gain-in-alert-enable
|
||||||
|
/* Reference Clock Control */
|
||||||
|
1, // xo_disable_use_ext_refclk_enable ***
|
||||||
|
// adi,xo-disable-use-ext-refclk-enable
|
||||||
|
{8, 5920}, // dcxo_coarse_and_fine_tune[2] *** adi,dcxo-coarse-and-fine-tune
|
||||||
|
0, // clk_output_mode_select *** adi,clk-output-mode-select
|
||||||
|
/* Gain Control */
|
||||||
|
2, // gc_rx1_mode *** adi,gc-rx1-mode
|
||||||
|
2, // gc_rx2_mode *** adi,gc-rx2-mode
|
||||||
|
58, // gc_adc_large_overload_thresh *** adi,gc-adc-large-overload-thresh
|
||||||
|
4, // gc_adc_ovr_sample_size *** adi,gc-adc-ovr-sample-size
|
||||||
|
47, // gc_adc_small_overload_thresh *** adi,gc-adc-small-overload-thresh
|
||||||
|
8192, // gc_dec_pow_measurement_duration ***
|
||||||
|
// adi,gc-dec-pow-measurement-duration
|
||||||
|
0, // gc_dig_gain_enable *** adi,gc-dig-gain-enable
|
||||||
|
800, // gc_lmt_overload_high_thresh *** adi,gc-lmt-overload-high-thresh
|
||||||
|
704, // gc_lmt_overload_low_thresh *** adi,gc-lmt-overload-low-thresh
|
||||||
|
24, // gc_low_power_thresh *** adi,gc-low-power-thresh
|
||||||
|
15, // gc_max_dig_gain *** adi,gc-max-dig-gain
|
||||||
|
/* Gain MGC Control */
|
||||||
|
2, // mgc_dec_gain_step *** adi,mgc-dec-gain-step
|
||||||
|
2, // mgc_inc_gain_step *** adi,mgc-inc-gain-step
|
||||||
|
0, // mgc_rx1_ctrl_inp_enable *** adi,mgc-rx1-ctrl-inp-enable
|
||||||
|
0, // mgc_rx2_ctrl_inp_enable *** adi,mgc-rx2-ctrl-inp-enable
|
||||||
|
0, // mgc_split_table_ctrl_inp_gain_mode ***
|
||||||
|
// adi,mgc-split-table-ctrl-inp-gain-mode
|
||||||
|
/* Gain AGC Control */
|
||||||
|
10, // agc_adc_large_overload_exceed_counter ***
|
||||||
|
// adi,agc-adc-large-overload-exceed-counter
|
||||||
|
2, // agc_adc_large_overload_inc_steps ***
|
||||||
|
// adi,agc-adc-large-overload-inc-steps
|
||||||
|
0, // agc_adc_lmt_small_overload_prevent_gain_inc_enable ***
|
||||||
|
// adi,agc-adc-lmt-small-overload-prevent-gain-inc-enable
|
||||||
|
10, // agc_adc_small_overload_exceed_counter ***
|
||||||
|
// adi,agc-adc-small-overload-exceed-counter
|
||||||
|
4, // agc_dig_gain_step_size *** adi,agc-dig-gain-step-size
|
||||||
|
3, // agc_dig_saturation_exceed_counter ***
|
||||||
|
// adi,agc-dig-saturation-exceed-counter
|
||||||
|
1000, // agc_gain_update_interval_us *** adi,agc-gain-update-interval-us
|
||||||
|
0, // agc_immed_gain_change_if_large_adc_overload_enable ***
|
||||||
|
// adi,agc-immed-gain-change-if-large-adc-overload-enable
|
||||||
|
0, // agc_immed_gain_change_if_large_lmt_overload_enable ***
|
||||||
|
// adi,agc-immed-gain-change-if-large-lmt-overload-enable
|
||||||
|
10, // agc_inner_thresh_high *** adi,agc-inner-thresh-high
|
||||||
|
1, // agc_inner_thresh_high_dec_steps ***
|
||||||
|
// adi,agc-inner-thresh-high-dec-steps
|
||||||
|
12, // agc_inner_thresh_low *** adi,agc-inner-thresh-low
|
||||||
|
1, // agc_inner_thresh_low_inc_steps *** adi,agc-inner-thresh-low-inc-steps
|
||||||
|
10, // agc_lmt_overload_large_exceed_counter ***
|
||||||
|
// adi,agc-lmt-overload-large-exceed-counter
|
||||||
|
2, // agc_lmt_overload_large_inc_steps ***
|
||||||
|
// adi,agc-lmt-overload-large-inc-steps
|
||||||
|
10, // agc_lmt_overload_small_exceed_counter ***
|
||||||
|
// adi,agc-lmt-overload-small-exceed-counter
|
||||||
|
5, // agc_outer_thresh_high *** adi,agc-outer-thresh-high
|
||||||
|
2, // agc_outer_thresh_high_dec_steps ***
|
||||||
|
// adi,agc-outer-thresh-high-dec-steps
|
||||||
|
18, // agc_outer_thresh_low *** adi,agc-outer-thresh-low
|
||||||
|
2, // agc_outer_thresh_low_inc_steps *** adi,agc-outer-thresh-low-inc-steps
|
||||||
|
1, // agc_attack_delay_extra_margin_us; ***
|
||||||
|
// adi,agc-attack-delay-extra-margin-us
|
||||||
|
0, // agc_sync_for_gain_counter_enable ***
|
||||||
|
// adi,agc-sync-for-gain-counter-enable
|
||||||
|
/* Fast AGC */
|
||||||
|
64, // fagc_dec_pow_measuremnt_duration ***
|
||||||
|
// adi,fagc-dec-pow-measurement-duration
|
||||||
|
260, // fagc_state_wait_time_ns *** adi,fagc-state-wait-time-ns
|
||||||
|
/* Fast AGC - Low Power */
|
||||||
|
0, // fagc_allow_agc_gain_increase ***
|
||||||
|
// adi,fagc-allow-agc-gain-increase-enable
|
||||||
|
5, // fagc_lp_thresh_increment_time *** adi,fagc-lp-thresh-increment-time
|
||||||
|
1, // fagc_lp_thresh_increment_steps *** adi,fagc-lp-thresh-increment-steps
|
||||||
|
/* Fast AGC - Lock Level */
|
||||||
|
10, // fagc_lock_level *** adi,fagc-lock-level */
|
||||||
|
1, // fagc_lock_level_lmt_gain_increase_en ***
|
||||||
|
// adi,fagc-lock-level-lmt-gain-increase-enable
|
||||||
|
5, // fagc_lock_level_gain_increase_upper_limit ***
|
||||||
|
// adi,fagc-lock-level-gain-increase-upper-limit
|
||||||
|
/* Fast AGC - Peak Detectors and Final Settling */
|
||||||
|
1, // fagc_lpf_final_settling_steps *** adi,fagc-lpf-final-settling-steps
|
||||||
|
1, // fagc_lmt_final_settling_steps *** adi,fagc-lmt-final-settling-steps
|
||||||
|
3, // fagc_final_overrange_count *** adi,fagc-final-overrange-count
|
||||||
|
/* Fast AGC - Final Power Test */
|
||||||
|
0, // fagc_gain_increase_after_gain_lock_en ***
|
||||||
|
// adi,fagc-gain-increase-after-gain-lock-enable
|
||||||
|
/* Fast AGC - Unlocking the Gain */
|
||||||
|
0, // fagc_gain_index_type_after_exit_rx_mode ***
|
||||||
|
// adi,fagc-gain-index-type-after-exit-rx-mode
|
||||||
|
1, // fagc_use_last_lock_level_for_set_gain_en ***
|
||||||
|
// adi,fagc-use-last-lock-level-for-set-gain-enable
|
||||||
|
1, // fagc_rst_gla_stronger_sig_thresh_exceeded_en ***
|
||||||
|
// adi,fagc-rst-gla-stronger-sig-thresh-exceeded-enable
|
||||||
|
5, // fagc_optimized_gain_offset *** adi,fagc-optimized-gain-offset
|
||||||
|
10, // fagc_rst_gla_stronger_sig_thresh_above_ll ***
|
||||||
|
// adi,fagc-rst-gla-stronger-sig-thresh-above-ll
|
||||||
|
1, // fagc_rst_gla_engergy_lost_sig_thresh_exceeded_en ***
|
||||||
|
// adi,fagc-rst-gla-engergy-lost-sig-thresh-exceeded-enable
|
||||||
|
1, // fagc_rst_gla_engergy_lost_goto_optim_gain_en ***
|
||||||
|
// adi,fagc-rst-gla-engergy-lost-goto-optim-gain-enable
|
||||||
|
10, // fagc_rst_gla_engergy_lost_sig_thresh_below_ll ***
|
||||||
|
// adi,fagc-rst-gla-engergy-lost-sig-thresh-below-ll
|
||||||
|
8, // fagc_energy_lost_stronger_sig_gain_lock_exit_cnt ***
|
||||||
|
// adi,fagc-energy-lost-stronger-sig-gain-lock-exit-cnt
|
||||||
|
1, // fagc_rst_gla_large_adc_overload_en ***
|
||||||
|
// adi,fagc-rst-gla-large-adc-overload-enable
|
||||||
|
1, // fagc_rst_gla_large_lmt_overload_en ***
|
||||||
|
// adi,fagc-rst-gla-large-lmt-overload-enable
|
||||||
|
0, // fagc_rst_gla_en_agc_pulled_high_en ***
|
||||||
|
// adi,fagc-rst-gla-en-agc-pulled-high-enable
|
||||||
|
0, // fagc_rst_gla_if_en_agc_pulled_high_mode ***
|
||||||
|
// adi,fagc-rst-gla-if-en-agc-pulled-high-mode
|
||||||
|
64, // fagc_power_measurement_duration_in_state5 ***
|
||||||
|
// adi,fagc-power-measurement-duration-in-state5
|
||||||
|
/* RSSI Control */
|
||||||
|
1, // rssi_delay *** adi,rssi-delay
|
||||||
|
1000, // rssi_duration *** adi,rssi-duration
|
||||||
|
3, // rssi_restart_mode *** adi,rssi-restart-mode
|
||||||
|
0, // rssi_unit_is_rx_samples_enable *** adi,rssi-unit-is-rx-samples-enable
|
||||||
|
1, // rssi_wait *** adi,rssi-wait
|
||||||
|
/* Aux ADC Control */
|
||||||
|
256, // aux_adc_decimation *** adi,aux-adc-decimation
|
||||||
|
40000000UL, // aux_adc_rate *** adi,aux-adc-rate
|
||||||
|
/* AuxDAC Control */
|
||||||
|
1, // aux_dac_manual_mode_enable *** adi,aux-dac-manual-mode-enable
|
||||||
|
1500, // aux_dac1_default_value_mV *** adi,aux-dac1-default-value-mV
|
||||||
|
1, // aux_dac1_active_in_rx_enable *** adi,aux-dac1-active-in-rx-enable
|
||||||
|
1, // aux_dac1_active_in_tx_enable *** adi,aux-dac1-active-in-tx-enable
|
||||||
|
1, // aux_dac1_active_in_alert_enable ***
|
||||||
|
// adi,aux-dac1-active-in-alert-enable
|
||||||
|
0, // aux_dac1_rx_delay_us *** adi,aux-dac1-rx-delay-us
|
||||||
|
0, // aux_dac1_tx_delay_us *** adi,aux-dac1-tx-delay-us
|
||||||
|
0, // aux_dac2_default_value_mV *** adi,aux-dac2-default-value-mV
|
||||||
|
0, // aux_dac2_active_in_rx_enable *** adi,aux-dac2-active-in-rx-enable
|
||||||
|
0, // aux_dac2_active_in_tx_enable *** adi,aux-dac2-active-in-tx-enable
|
||||||
|
0, // aux_dac2_active_in_alert_enable ***
|
||||||
|
// adi,aux-dac2-active-in-alert-enable
|
||||||
|
0, // aux_dac2_rx_delay_us *** adi,aux-dac2-rx-delay-us
|
||||||
|
0, // aux_dac2_tx_delay_us *** adi,aux-dac2-tx-delay-us
|
||||||
|
/* Temperature Sensor Control */
|
||||||
|
256, // temp_sense_decimation *** adi,temp-sense-decimation
|
||||||
|
1000, // temp_sense_measurement_interval_ms ***
|
||||||
|
// adi,temp-sense-measurement-interval-ms
|
||||||
|
int8_t(0xCE), // temp_sense_offset_signed *** adi,temp-sense-offset-signed
|
||||||
|
1, // temp_sense_periodic_measurement_enable ***
|
||||||
|
// adi,temp-sense-periodic-measurement-enable
|
||||||
|
/* Control Out Setup */
|
||||||
|
0xFF, // ctrl_outs_enable_mask *** adi,ctrl-outs-enable-mask
|
||||||
|
0, // ctrl_outs_index *** adi,ctrl-outs-index
|
||||||
|
/* External LNA Control */
|
||||||
|
0, // elna_settling_delay_ns *** adi,elna-settling-delay-ns
|
||||||
|
0, // elna_gain_mdB *** adi,elna-gain-mdB
|
||||||
|
0, // elna_bypass_loss_mdB *** adi,elna-bypass-loss-mdB
|
||||||
|
0, // elna_rx1_gpo0_control_enable *** adi,elna-rx1-gpo0-control-enable
|
||||||
|
0, // elna_rx2_gpo1_control_enable *** adi,elna-rx2-gpo1-control-enable
|
||||||
|
0, // elna_gaintable_all_index_enable ***
|
||||||
|
// adi,elna-gaintable-all-index-enable
|
||||||
|
/* Digital Interface Control */
|
||||||
|
0, // digital_interface_tune_skip_mode ***
|
||||||
|
// adi,digital-interface-tune-skip-mode
|
||||||
|
1, // digital_interface_tune_fir_disable ***
|
||||||
|
// adi,digital-interface-tune-fir-disable
|
||||||
|
1, // pp_tx_swap_enable *** adi,pp-tx-swap-enable
|
||||||
|
1, // pp_rx_swap_enable *** adi,pp-rx-swap-enable
|
||||||
|
0, // tx_channel_swap_enable *** adi,tx-channel-swap-enable
|
||||||
|
0, // rx_channel_swap_enable *** adi,rx-channel-swap-enable
|
||||||
|
1, // rx_frame_pulse_mode_enable *** adi,rx-frame-pulse-mode-enable
|
||||||
|
0, // two_t_two_r_timing_enable *** adi,2t2r-timing-enable
|
||||||
|
0, // invert_data_bus_enable *** adi,invert-data-bus-enable
|
||||||
|
0, // invert_data_clk_enable *** adi,invert-data-clk-enable
|
||||||
|
0, // fdd_alt_word_order_enable *** adi,fdd-alt-word-order-enable
|
||||||
|
0, // invert_rx_frame_enable *** adi,invert-rx-frame-enable
|
||||||
|
0, // fdd_rx_rate_2tx_enable *** adi,fdd-rx-rate-2tx-enable
|
||||||
|
0, // swap_ports_enable *** adi,swap-ports-enable
|
||||||
|
0, // single_data_rate_enable *** adi,single-data-rate-enable
|
||||||
|
1, // lvds_mode_enable *** adi,lvds-mode-enable
|
||||||
|
0, // half_duplex_mode_enable *** adi,half-duplex-mode-enable
|
||||||
|
0, // single_port_mode_enable *** adi,single-port-mode-enable
|
||||||
|
0, // full_port_enable *** adi,full-port-enable
|
||||||
|
0, // full_duplex_swap_bits_enable *** adi,full-duplex-swap-bits-enable
|
||||||
|
0, // delay_rx_data *** adi,delay-rx-data
|
||||||
|
0, // rx_data_clock_delay *** adi,rx-data-clock-delay
|
||||||
|
8, // rx_data_delay *** adi,rx-data-delay
|
||||||
|
7, // tx_fb_clock_delay *** adi,tx-fb-clock-delay
|
||||||
|
0, // tx_data_delay *** adi,tx-data-delay
|
||||||
|
75, // lvds_bias_mV *** adi,lvds-bias-mV
|
||||||
|
1, // lvds_rx_onchip_termination_enable ***
|
||||||
|
// adi,lvds-rx-onchip-termination-enable
|
||||||
|
0, // rx1rx2_phase_inversion_en *** adi,rx1-rx2-phase-inversion-enable
|
||||||
|
0xFF, // lvds_invert1_control *** adi,lvds-invert1-control
|
||||||
|
0x0F, // lvds_invert2_control *** adi,lvds-invert2-control
|
||||||
|
/* GPO Control */
|
||||||
|
0, // gpo0_inactive_state_high_enable ***
|
||||||
|
// adi,gpo0-inactive-state-high-enable
|
||||||
|
0, // gpo1_inactive_state_high_enable ***
|
||||||
|
// adi,gpo1-inactive-state-high-enable
|
||||||
|
0, // gpo2_inactive_state_high_enable ***
|
||||||
|
// adi,gpo2-inactive-state-high-enable
|
||||||
|
0, // gpo3_inactive_state_high_enable ***
|
||||||
|
// adi,gpo3-inactive-state-high-enable
|
||||||
|
0, // gpo0_slave_rx_enable *** adi,gpo0-slave-rx-enable
|
||||||
|
0, // gpo0_slave_tx_enable *** adi,gpo0-slave-tx-enable
|
||||||
|
0, // gpo1_slave_rx_enable *** adi,gpo1-slave-rx-enable
|
||||||
|
0, // gpo1_slave_tx_enable *** adi,gpo1-slave-tx-enable
|
||||||
|
0, // gpo2_slave_rx_enable *** adi,gpo2-slave-rx-enable
|
||||||
|
0, // gpo2_slave_tx_enable *** adi,gpo2-slave-tx-enable
|
||||||
|
0, // gpo3_slave_rx_enable *** adi,gpo3-slave-rx-enable
|
||||||
|
0, // gpo3_slave_tx_enable *** adi,gpo3-slave-tx-enable
|
||||||
|
0, // gpo0_rx_delay_us *** adi,gpo0-rx-delay-us
|
||||||
|
0, // gpo0_tx_delay_us *** adi,gpo0-tx-delay-us
|
||||||
|
0, // gpo1_rx_delay_us *** adi,gpo1-rx-delay-us
|
||||||
|
0, // gpo1_tx_delay_us *** adi,gpo1-tx-delay-us
|
||||||
|
0, // gpo2_rx_delay_us *** adi,gpo2-rx-delay-us
|
||||||
|
0, // gpo2_tx_delay_us *** adi,gpo2-tx-delay-us
|
||||||
|
0, // gpo3_rx_delay_us *** adi,gpo3-rx-delay-us
|
||||||
|
0, // gpo3_tx_delay_us *** adi,gpo3-tx-delay-us
|
||||||
|
/* Tx Monitor Control */
|
||||||
|
37000, // low_high_gain_threshold_mdB *** adi,txmon-low-high-thresh
|
||||||
|
0, // low_gain_dB *** adi,txmon-low-gain
|
||||||
|
24, // high_gain_dB *** adi,txmon-high-gain
|
||||||
|
0, // tx_mon_track_en *** adi,txmon-dc-tracking-enable
|
||||||
|
0, // one_shot_mode_en *** adi,txmon-one-shot-mode-enable
|
||||||
|
511, // tx_mon_delay *** adi,txmon-delay
|
||||||
|
8192, // tx_mon_duration *** adi,txmon-duration
|
||||||
|
2, // tx1_mon_front_end_gain *** adi,txmon-1-front-end-gain
|
||||||
|
2, // tx2_mon_front_end_gain *** adi,txmon-2-front-end-gain
|
||||||
|
48, // tx1_mon_lo_cm *** adi,txmon-1-lo-cm
|
||||||
|
48, // tx2_mon_lo_cm *** adi,txmon-2-lo-cm
|
||||||
|
/* GPIO definitions */
|
||||||
|
-1, // gpio_resetb *** reset-gpios
|
||||||
|
/* MCS Sync */
|
||||||
|
-1, // gpio_sync *** sync-gpios
|
||||||
|
-1, // gpio_cal_sw1 *** cal-sw1-gpios
|
||||||
|
-1, // gpio_cal_sw2 *** cal-sw2-gpios
|
||||||
|
/* External LO clocks */
|
||||||
|
NULL, //(*ad9361_rfpll_ext_recalc_rate)()
|
||||||
|
NULL, //(*ad9361_rfpll_ext_round_rate)()
|
||||||
|
NULL //(*ad9361_rfpll_ext_set_rate)()
|
||||||
|
};
|
||||||
|
|
||||||
|
AD9361_RXFIRConfig rx_fir_config = {
|
||||||
|
// BPF PASSBAND 3/20 fs to 1/4 fs
|
||||||
|
3, // rx;
|
||||||
|
0, // rx_gain;
|
||||||
|
1, // rx_dec;
|
||||||
|
{-4, -6, -37, 35, 186, 86, -284, -315, 107, 219,
|
||||||
|
-4, 271, 558, -307, -1182, -356, 658, 157, 207, 1648,
|
||||||
|
790, -2525, -2553, 748, 865, -476, 3737, 6560, -3583, -14731,
|
||||||
|
-5278, 14819, 14819, -5278, -14731, -3583, 6560, 3737, -476, 865,
|
||||||
|
748, -2553, -2525, 790, 1648, 207, 157, 658, -356, -1182,
|
||||||
|
-307, 558, 271, -4, 219, 107, -315, -284, 86, 186,
|
||||||
|
35, -37, -6, -4, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0}, // rx_coef[128];
|
||||||
|
64 // rx_coef_size
|
||||||
|
};
|
||||||
|
|
||||||
|
AD9361_TXFIRConfig tx_fir_config = {
|
||||||
|
// BPF PASSBAND 3/20 fs to 1/4 fs
|
||||||
|
3, // tx;
|
||||||
|
-6, // tx_gain;
|
||||||
|
1, // tx_int;
|
||||||
|
{-4, -6, -37, 35, 186, 86, -284, -315, 107, 219,
|
||||||
|
-4, 271, 558, -307, -1182, -356, 658, 157, 207, 1648,
|
||||||
|
790, -2525, -2553, 748, 865, -476, 3737, 6560, -3583, -14731,
|
||||||
|
-5278, 14819, 14819, -5278, -14731, -3583, 6560, 3737, -476, 865,
|
||||||
|
748, -2553, -2525, 790, 1648, 207, 157, 658, -356, -1182,
|
||||||
|
-307, 558, 271, -4, 219, 107, -315, -284, 86, 186,
|
||||||
|
35, -37, -6, -4, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0}, // tx_coef[128];
|
||||||
|
64 // tx_coef_size
|
||||||
|
};
|
||||||
|
|
||||||
|
void RFThread::thread_main() {
|
||||||
|
iq_sample temp_buf[256000];
|
||||||
|
iq_sample *temp_buf_ptr;
|
||||||
|
init_device();
|
||||||
|
startStreaming();
|
||||||
|
while (!stopRF) {
|
||||||
|
// check for changed settings
|
||||||
|
if (centerFreqChanged) {
|
||||||
|
beginSettingChange();
|
||||||
|
centerFreqChanged = false;
|
||||||
|
cout << "center freq == " << centerFreq << endl;
|
||||||
|
ad9361_set_rx_lo_freq(ad9361_phy, centerFreq);
|
||||||
|
endSettingChange();
|
||||||
|
}
|
||||||
|
if (bandwidthChanged) {
|
||||||
|
beginSettingChange();
|
||||||
|
bandwidthChanged = false;
|
||||||
|
uint32_t targetSampleRate = getSampleRateFromBw(bandwidth);
|
||||||
|
ad9361_set_rx_rf_bandwidth(ad9361_phy, bandwidth);
|
||||||
|
ad9361_set_rx_sampling_freq(ad9361_phy, targetSampleRate);
|
||||||
|
uint32_t actualSampleRate;
|
||||||
|
ad9361_get_rx_sampling_freq(ad9361_phy, &actualSampleRate);
|
||||||
|
cout << "actual sample rate = " << (actualSampleRate / 1.0e6) << "MSPS"
|
||||||
|
<< endl;
|
||||||
|
currentSampleRate = actualSampleRate;
|
||||||
|
|
||||||
|
endSettingChange();
|
||||||
|
}
|
||||||
|
if (gainChanged) {
|
||||||
|
beginSettingChange();
|
||||||
|
gainChanged = false;
|
||||||
|
ad9361_set_rx_rf_gain(ad9361_phy, 0, gain);
|
||||||
|
endSettingChange();
|
||||||
|
}
|
||||||
|
if (agcEnabledChanged) {
|
||||||
|
beginSettingChange();
|
||||||
|
agcEnabledChanged = false;
|
||||||
|
if (agcEnabled) {
|
||||||
|
ad9361_set_rx_gain_control_mode(ad9361_phy, 0, RF_GAIN_SLOWATTACK_AGC);
|
||||||
|
} else {
|
||||||
|
ad9361_set_rx_gain_control_mode(ad9361_phy, 0, RF_GAIN_MGC);
|
||||||
|
}
|
||||||
|
endSettingChange();
|
||||||
|
}
|
||||||
|
if (inputPortChanged) {
|
||||||
|
beginSettingChange();
|
||||||
|
inputPortChanged = false;
|
||||||
|
ad9361_set_rx_rf_port_input(ad9361_phy, inputPort);
|
||||||
|
endSettingChange();
|
||||||
|
}
|
||||||
|
// do Rx
|
||||||
|
// get up to 256k samples per iteration; but don't spend more than 20ms
|
||||||
|
// doing so
|
||||||
|
auto rxstart = chrono::steady_clock::now();
|
||||||
|
temp_buf_ptr = temp_buf;
|
||||||
|
for (int i = 0; i < 250; i++) {
|
||||||
|
temp_buf_ptr += rx_get_data(temp_buf_ptr);
|
||||||
|
if ((chrono::steady_clock::now() - rxstart) > chrono::milliseconds(20))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
lock_guard<mutex> guard(sample_buf_mutex);
|
||||||
|
for (auto ptr = temp_buf; ptr < temp_buf_ptr; ptr++) {
|
||||||
|
sample_buf[sample_buf_idx] = *ptr;
|
||||||
|
sample_buf_idx++;
|
||||||
|
if(sample_buf_read_offset < sample_buf_size)
|
||||||
|
sample_buf_read_offset++;
|
||||||
|
if (sample_buf_idx >= sample_buf_size) {
|
||||||
|
long long us = chrono::duration_cast<chrono::microseconds>(
|
||||||
|
(chrono::high_resolution_clock::now() - last_wrap))
|
||||||
|
.count();
|
||||||
|
cout << "throughput = " << sample_buf_size / double(us) << "MSPS"
|
||||||
|
<< endl;
|
||||||
|
sample_buf_idx = 0;
|
||||||
|
last_wrap = chrono::high_resolution_clock::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stopStreaming();
|
||||||
|
ad9361_set_en_state_machine_mode(ad9361_phy, ENSM_MODE_ALERT);
|
||||||
|
ad9361_set_en_state_machine_mode(ad9361_phy, ENSM_MODE_WAIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RFThread::init_device() {
|
||||||
|
stopStreaming();
|
||||||
|
default_init_param.gpio_resetb = GPIO_RESET_PIN;
|
||||||
|
default_init_param.gpio_sync = -1;
|
||||||
|
default_init_param.gpio_cal_sw1 = -1;
|
||||||
|
default_init_param.gpio_cal_sw2 = -1;
|
||||||
|
gpio_init(GPIO_DEVICE_ID);
|
||||||
|
gpio_direction(default_init_param.gpio_resetb, 1);
|
||||||
|
|
||||||
|
spi_init(SPI_DEVICE_ID, 1, 0);
|
||||||
|
|
||||||
|
ad9361_init(&ad9361_phy, &default_init_param);
|
||||||
|
|
||||||
|
ad9361_set_tx_fir_config(ad9361_phy, tx_fir_config);
|
||||||
|
ad9361_set_rx_fir_config(ad9361_phy, rx_fir_config);
|
||||||
|
ad9361_set_trx_fir_en_dis(ad9361_phy, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
void RFThread::startStreaming() {
|
||||||
|
ad9361_set_en_state_machine_mode(ad9361_phy, ENSM_MODE_ALERT);
|
||||||
|
ad9361_set_en_state_machine_mode(ad9361_phy, ENSM_MODE_RX);
|
||||||
|
enter_rx_streaming_mode();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RFThread::stopStreaming() {
|
||||||
|
iq_sample temp_buf[1024];
|
||||||
|
leave_rx_streaming_mode();
|
||||||
|
// Clear FTDI buffer
|
||||||
|
while (rx_get_data(temp_buf))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RFThread::beginSettingChange() {
|
||||||
|
/* ad9361_set_en_state_machine_mode(ad9361_phy, ENSM_MODE_ALERT);
|
||||||
|
ad9361_set_en_state_machine_mode(ad9361_phy, ENSM_MODE_WAIT);*/
|
||||||
|
stopStreaming();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RFThread::endSettingChange() {
|
||||||
|
ad9361_set_en_state_machine_mode(ad9361_phy, ENSM_MODE_ALERT);
|
||||||
|
ad9361_set_en_state_machine_mode(ad9361_phy, ENSM_MODE_WAIT);
|
||||||
|
ad9361_do_calib(ad9361_phy, RFDC_CAL, 0);
|
||||||
|
ad9361_do_calib(ad9361_phy, RX_QUAD_CAL, 0);
|
||||||
|
ad9361_do_calib(ad9361_phy, RX_BB_TUNE_CAL, 0);
|
||||||
|
startStreaming();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t RFThread::getSampleRateFromBw(uint32_t bw) {
|
||||||
|
const uint32_t max_fs = 61440000;
|
||||||
|
const uint32_t min_fs = 1920000;
|
||||||
|
uint32_t result_fs = 61440000;
|
||||||
|
while ((result_fs > min_fs) && ((result_fs / 2) >= bw))
|
||||||
|
result_fs /= 2;
|
||||||
|
return result_fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t RFThread::getCurrentSampleRate() { return currentSampleRate; };
|
||||||
|
|
||||||
|
void RFThread::getSamples(double _Complex *buf, int n) {
|
||||||
|
{
|
||||||
|
lock_guard<mutex> guard(sample_buf_mutex);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
int idx = (sample_buf_idx + i - n) % sample_buf_size;
|
||||||
|
if (idx < 0)
|
||||||
|
idx += sample_buf_size;
|
||||||
|
buf[i] = sample_buf[idx].i + _Complex_I * sample_buf[idx].q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int RFThread::getRecentSamples(double _Complex *buf, int n) {
|
||||||
|
{
|
||||||
|
lock_guard<mutex> guard(sample_buf_mutex);
|
||||||
|
int available_samples = sample_buf_read_offset;
|
||||||
|
//cout << n << " " << available_samples << endl;
|
||||||
|
n = min(n, available_samples);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
int idx = (sample_buf_idx + i - sample_buf_read_offset) % sample_buf_size;
|
||||||
|
if (idx < 0)
|
||||||
|
idx += sample_buf_size;
|
||||||
|
buf[i] = sample_buf[idx].i + _Complex_I * sample_buf[idx].q;
|
||||||
|
}
|
||||||
|
sample_buf_read_offset -= n;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RFThread::setCenterFreq(uint64_t freq) {
|
||||||
|
centerFreq = freq;
|
||||||
|
centerFreqChanged = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RFThread::setBandwidth(uint32_t bw) {
|
||||||
|
bandwidth = bw;
|
||||||
|
bandwidthChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RFThread::setGain(int rxgain) {
|
||||||
|
gain = rxgain;
|
||||||
|
gainChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RFThread::setAgcEnable(bool agcEn) {
|
||||||
|
agcEnabled = agcEn;
|
||||||
|
agcEnabledChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RFThread::setInputPort(int port) {
|
||||||
|
inputPort = port;
|
||||||
|
inputPortChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t RFThread::getCenterFreq() { return centerFreq; }
|
||||||
|
int RFThread::getGain() { return gain; };
|
||||||
|
bool RFThread::getAgcEnable() { return agcEnabled; };
|
||||||
|
int RFThread::getInputPort() { return inputPort; };
|
||||||
|
|
||||||
|
void RFThread::start() {
|
||||||
|
centerFreqChanged = true;
|
||||||
|
bandwidthChanged = true;
|
||||||
|
gainChanged = true;
|
||||||
|
agcEnabledChanged = true;
|
||||||
|
inputPortChanged = true;
|
||||||
|
stopRF = false;
|
||||||
|
rf_thread = thread([this]() { this->thread_main(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void RFThread::stop() {
|
||||||
|
stopRF = true;
|
||||||
|
rf_thread.join();
|
||||||
|
}
|
75
linux-app/spectrum-analyser/rftool/RFThread.hpp
Normal file
75
linux-app/spectrum-analyser/rftool/RFThread.hpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
|
#include <complex.h>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
extern "C" {
|
||||||
|
#include "../ad9361/ad9361_api.h"
|
||||||
|
#include "../ad9361/platform/parameters.h"
|
||||||
|
#include "../ad9361/platform/platform.h"
|
||||||
|
#include "usb_platform.h"
|
||||||
|
};
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class RFThread {
|
||||||
|
public:
|
||||||
|
// Start and stop the AD9361 interfacing thread
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
// Set various parameters
|
||||||
|
void setCenterFreq(uint64_t freq); // set rx center freq in Hz
|
||||||
|
void setBandwidth(uint32_t bw); // set rf rx bandwidth in Hz
|
||||||
|
void setGain(int rxgain); // set rx rf gain in dB
|
||||||
|
void setAgcEnable(bool agcEn); // set AGC on or off
|
||||||
|
void setInputPort(int port); // set rx rf input port (0 or 1)
|
||||||
|
// Copy the n most recent samples into a buffer (C style complex used for
|
||||||
|
// compatibility reasons)
|
||||||
|
void getSamples(double _Complex *buf, int n);
|
||||||
|
//As above but only get new samples, returning the actual number of samples obtained
|
||||||
|
int getRecentSamples(double _Complex *buf, int n);
|
||||||
|
|
||||||
|
uint32_t getCurrentSampleRate();
|
||||||
|
uint64_t getCenterFreq();
|
||||||
|
int getGain();
|
||||||
|
bool getAgcEnable();
|
||||||
|
int getInputPort();
|
||||||
|
|
||||||
|
private:
|
||||||
|
thread rf_thread;
|
||||||
|
atomic<uint64_t> centerFreq{2450000000UL};
|
||||||
|
atomic<bool> centerFreqChanged{true};
|
||||||
|
atomic<uint32_t> bandwidth{20000000};
|
||||||
|
atomic<bool> bandwidthChanged{true};
|
||||||
|
atomic<int> gain{40};
|
||||||
|
atomic<bool> gainChanged{true};
|
||||||
|
atomic<bool> agcEnabled{false};
|
||||||
|
atomic<bool> agcEnabledChanged{true};
|
||||||
|
atomic<int> inputPort{0};
|
||||||
|
atomic<bool> inputPortChanged;
|
||||||
|
atomic<bool> stopRF{false};
|
||||||
|
|
||||||
|
mutex sample_buf_mutex;
|
||||||
|
static const size_t sample_buf_size = 33554432;
|
||||||
|
iq_sample sample_buf[sample_buf_size];
|
||||||
|
int sample_buf_idx = 0;
|
||||||
|
int sample_buf_read_offset = 0;
|
||||||
|
|
||||||
|
ad9361_rf_phy *ad9361_phy;
|
||||||
|
void thread_main();
|
||||||
|
void init_device();
|
||||||
|
|
||||||
|
atomic<uint32_t> currentSampleRate{20000000};
|
||||||
|
|
||||||
|
uint32_t getSampleRateFromBw(uint32_t bw);
|
||||||
|
void beginSettingChange();
|
||||||
|
void startStreaming();
|
||||||
|
void stopStreaming();
|
||||||
|
void endSettingChange();
|
||||||
|
|
||||||
|
chrono::high_resolution_clock::time_point last_wrap =
|
||||||
|
chrono::high_resolution_clock::now();
|
||||||
|
};
|
381
linux-app/spectrum-analyser/rftool/usb_if.cpp
Normal file
381
linux-app/spectrum-analyser/rftool/usb_if.cpp
Normal file
@ -0,0 +1,381 @@
|
|||||||
|
#include "usb_if.hpp"
|
||||||
|
#include "ftd3xx/ftd3xx.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
|
#include <csignal>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <thread>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace RFTool {
|
||||||
|
|
||||||
|
static const bool debug_enable = false;
|
||||||
|
|
||||||
|
void USBInterface::flush() { FT_FlushPipe(handle, 0); }
|
||||||
|
|
||||||
|
// Build a 32-byte command from command type and payload
|
||||||
|
void USBInterface::build_command(uint8_t cmd_type,
|
||||||
|
const vector<uint8_t> &payload,
|
||||||
|
uint8_t *buffer) {
|
||||||
|
fill(buffer, buffer + command_len, 0);
|
||||||
|
// Magic
|
||||||
|
buffer[0] = 0x43;
|
||||||
|
buffer[1] = 0x4d;
|
||||||
|
buffer[2] = 0x4e;
|
||||||
|
buffer[3] = 0x44;
|
||||||
|
// Cmd type
|
||||||
|
buffer[4] = cmd_type;
|
||||||
|
for (size_t i = 0; i < min(payload.size(), size_t(command_len - 5)); i++) {
|
||||||
|
buffer[i + 5] = payload[i];
|
||||||
|
}
|
||||||
|
swap_endian(buffer, command_len);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool USBInterface::exec_command(uint8_t *command, bool get_response,
|
||||||
|
uint8_t *response) {
|
||||||
|
flush();
|
||||||
|
FT_STATUS err;
|
||||||
|
ULONG count;
|
||||||
|
if(debug_enable)
|
||||||
|
cout << "---------------------" << endl;
|
||||||
|
print_command(command);
|
||||||
|
err = FT_WritePipeEx(handle, 0, command, command_len, &count, timeout);
|
||||||
|
if (err != FT_OK) {
|
||||||
|
cerr << "write cmd returned error code " << int(err) << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (get_response) {
|
||||||
|
err = FT_ReadPipeEx(handle, 0, response, response_len, &count, timeout);
|
||||||
|
if (err != FT_OK) {
|
||||||
|
cerr << "read resp returned error code " << int(err) << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
print_response(response);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Print the response to cout
|
||||||
|
void USBInterface::print_response(uint8_t *resp) {
|
||||||
|
if (debug_enable) {
|
||||||
|
const int line_width = 16;
|
||||||
|
// Save and restore cout state
|
||||||
|
ios::fmtflags f(cout.flags());
|
||||||
|
cout << "Response:" << endl;
|
||||||
|
for (int i = 0; i < response_len; i++) {
|
||||||
|
cout << hex << setw(2) << setfill('0') << int(resp[i]);
|
||||||
|
if ((i % line_width) == (line_width - 1)) {
|
||||||
|
cout << endl;
|
||||||
|
} else {
|
||||||
|
cout << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
cout.flags(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBInterface::print_command(uint8_t *resp) {
|
||||||
|
if (debug_enable) {
|
||||||
|
const int line_width = 16;
|
||||||
|
// Save and restore cout state
|
||||||
|
ios::fmtflags f(cout.flags());
|
||||||
|
cout << "Command:" << endl;
|
||||||
|
for (int i = 0; i < command_len; i++) {
|
||||||
|
cout << hex << setw(2) << setfill('0') << int(resp[i]);
|
||||||
|
if ((i % line_width) == (line_width - 1)) {
|
||||||
|
cout << endl;
|
||||||
|
} else {
|
||||||
|
cout << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
cout.flags(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USBInterface::spi_transfer(bool is_read, int len, uint16_t addr,
|
||||||
|
uint8_t *buf) {
|
||||||
|
uint8_t cmd[command_len], resp[response_len];
|
||||||
|
for (int i = 0; i < command_len; i++)
|
||||||
|
cmd[i] = 0;
|
||||||
|
uint16_t hdr = 0;
|
||||||
|
hdr |= is_read ? 0x0000 : 0x8000;
|
||||||
|
hdr |= ((len - 1) & 0x07) << 12;
|
||||||
|
hdr |= addr & 0x3FF;
|
||||||
|
vector<uint8_t> payload;
|
||||||
|
payload.push_back(uint8_t(len + 2)); // 2 byte hdr + user data
|
||||||
|
payload.push_back((hdr >> 8) & 0xFF);
|
||||||
|
payload.push_back(hdr & 0xFF);
|
||||||
|
if (!is_read)
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
payload.push_back(buf[i]);
|
||||||
|
build_command(0x10, payload, cmd);
|
||||||
|
bool res = exec_command(cmd, true, resp);
|
||||||
|
swap_endian(resp, response_len);
|
||||||
|
if (res)
|
||||||
|
print_response(resp);
|
||||||
|
if (is_read)
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
buf[i] = resp[8 + i];
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool USBInterface::set_fpga_ctrl(uint8_t ctrl_val) {
|
||||||
|
uint8_t cmd[command_len], resp[response_len];
|
||||||
|
build_command(0x20, vector<uint8_t>{ctrl_val}, cmd);
|
||||||
|
bool res = exec_command(cmd, true, resp);
|
||||||
|
if (res)
|
||||||
|
print_response(resp);
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool USBInterface::get_rx_packet(uint8_t *buffer) {
|
||||||
|
ULONG count;
|
||||||
|
FT_STATUS err =
|
||||||
|
FT_ReadPipeEx(handle, 0, buffer, rx_packet_len, &count, timeout);
|
||||||
|
if (err != FT_OK) {
|
||||||
|
cerr << "read rx returned error code " << int(err) << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// cout << count << endl;
|
||||||
|
// swap_endian(buffer, rx_packet_len);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void USBInterface::get_version(void) {
|
||||||
|
DWORD dwVersion;
|
||||||
|
|
||||||
|
FT_GetDriverVersion(NULL, &dwVersion);
|
||||||
|
printf("Driver version:%d.%d.%d.%d\r\n", dwVersion >> 24,
|
||||||
|
(uint8_t)(dwVersion >> 16), (uint8_t)(dwVersion >> 8),
|
||||||
|
dwVersion & 0xFF);
|
||||||
|
|
||||||
|
FT_GetLibraryVersion(&dwVersion);
|
||||||
|
printf("Library version:%d.%d.%d\r\n", dwVersion >> 24,
|
||||||
|
(uint8_t)(dwVersion >> 16), dwVersion & 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBInterface::get_vid_pid() {
|
||||||
|
WORD vid, pid;
|
||||||
|
|
||||||
|
if (FT_OK != FT_GetVIDPID(handle, &vid, &pid))
|
||||||
|
return;
|
||||||
|
printf("VID:%04X PID:%04X\r\n", vid, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBInterface::turn_off_all_pipes() {
|
||||||
|
FT_TRANSFER_CONF conf;
|
||||||
|
|
||||||
|
memset(&conf, 0, sizeof(FT_TRANSFER_CONF));
|
||||||
|
conf.wStructSize = sizeof(FT_TRANSFER_CONF);
|
||||||
|
conf.pipe[FT_PIPE_DIR_IN].fPipeNotUsed = true;
|
||||||
|
conf.pipe[FT_PIPE_DIR_OUT].fPipeNotUsed = true;
|
||||||
|
for (DWORD i = 0; i < 4; i++)
|
||||||
|
FT_SetTransferParams(&conf, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USBInterface::get_device_lists(int timeout_ms) {
|
||||||
|
DWORD count;
|
||||||
|
FT_DEVICE_LIST_INFO_NODE nodes[16];
|
||||||
|
|
||||||
|
chrono::steady_clock::time_point const timeout =
|
||||||
|
chrono::steady_clock::now() + chrono::milliseconds(timeout_ms);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (FT_OK == FT_CreateDeviceInfoList(&count))
|
||||||
|
break;
|
||||||
|
this_thread::sleep_for(chrono::microseconds(10));
|
||||||
|
} while (chrono::steady_clock::now() < timeout);
|
||||||
|
printf("Total %u device(s)\r\n", count);
|
||||||
|
if (!count)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (FT_OK != FT_GetDeviceInfoList(nodes, &count))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USBInterface::set_ft600_channel_config(FT_60XCONFIGURATION *cfg,
|
||||||
|
CONFIGURATION_FIFO_CLK clock,
|
||||||
|
bool is_600_mode) {
|
||||||
|
bool needs_update = false;
|
||||||
|
bool current_is_600mode;
|
||||||
|
|
||||||
|
if (cfg->OptionalFeatureSupport &
|
||||||
|
CONFIGURATION_OPTIONAL_FEATURE_ENABLENOTIFICATIONMESSAGE_INCHALL) {
|
||||||
|
/* Notification in D3XX for Linux is implemented at OS level
|
||||||
|
* Turn off notification feature in firmware */
|
||||||
|
cfg->OptionalFeatureSupport &=
|
||||||
|
~CONFIGURATION_OPTIONAL_FEATURE_ENABLENOTIFICATIONMESSAGE_INCHALL;
|
||||||
|
needs_update = true;
|
||||||
|
printf("Turn off firmware notification feature\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cfg->OptionalFeatureSupport &
|
||||||
|
CONFIGURATION_OPTIONAL_FEATURE_DISABLECANCELSESSIONUNDERRUN)) {
|
||||||
|
/* Turn off feature not supported by D3XX for Linux */
|
||||||
|
cfg->OptionalFeatureSupport |=
|
||||||
|
CONFIGURATION_OPTIONAL_FEATURE_DISABLECANCELSESSIONUNDERRUN;
|
||||||
|
needs_update = true;
|
||||||
|
printf("disable cancel session on FIFO underrun 0x%X\r\n",
|
||||||
|
cfg->OptionalFeatureSupport);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg->FIFOClock != clock)
|
||||||
|
needs_update = true;
|
||||||
|
|
||||||
|
if (cfg->FIFOMode == CONFIGURATION_FIFO_MODE_245) {
|
||||||
|
printf("FIFO is running at FT245 mode\r\n");
|
||||||
|
current_is_600mode = false;
|
||||||
|
} else if (cfg->FIFOMode == CONFIGURATION_FIFO_MODE_600) {
|
||||||
|
printf("FIFO is running at FT600 mode\r\n");
|
||||||
|
current_is_600mode = true;
|
||||||
|
} else {
|
||||||
|
printf("FIFO is running at unknown mode\r\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
UCHAR ch;
|
||||||
|
|
||||||
|
if (in_ch_cnt == 1 && out_ch_cnt == 0)
|
||||||
|
ch = CONFIGURATION_CHANNEL_CONFIG_1_INPIPE;
|
||||||
|
else if (in_ch_cnt == 0 && out_ch_cnt == 1)
|
||||||
|
ch = CONFIGURATION_CHANNEL_CONFIG_1_OUTPIPE;
|
||||||
|
else {
|
||||||
|
UCHAR total = in_ch_cnt < out_ch_cnt ? out_ch_cnt : in_ch_cnt;
|
||||||
|
|
||||||
|
if (total == 4)
|
||||||
|
ch = CONFIGURATION_CHANNEL_CONFIG_4;
|
||||||
|
else if (total == 2)
|
||||||
|
ch = CONFIGURATION_CHANNEL_CONFIG_2;
|
||||||
|
else
|
||||||
|
ch = CONFIGURATION_CHANNEL_CONFIG_1;
|
||||||
|
|
||||||
|
if (cfg->FIFOMode == CONFIGURATION_FIFO_MODE_245 && total > 1) {
|
||||||
|
printf("245 mode only support single channel\r\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg->ChannelConfig == ch && current_is_600mode == is_600_mode &&
|
||||||
|
!needs_update)
|
||||||
|
return false;
|
||||||
|
cfg->ChannelConfig = ch;
|
||||||
|
cfg->FIFOClock = clock;
|
||||||
|
cfg->FIFOMode =
|
||||||
|
is_600_mode ? CONFIGURATION_FIFO_MODE_600 : CONFIGURATION_FIFO_MODE_245;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USBInterface::set_channel_config(bool is_600_mode,
|
||||||
|
CONFIGURATION_FIFO_CLK clock) {
|
||||||
|
DWORD dwType;
|
||||||
|
|
||||||
|
/* Must turn off all pipes before changing chip configuration */
|
||||||
|
turn_off_all_pipes();
|
||||||
|
|
||||||
|
FT_GetDeviceInfoDetail(0, NULL, &dwType, NULL, NULL, NULL, NULL, &handle);
|
||||||
|
if (!handle)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
get_vid_pid();
|
||||||
|
|
||||||
|
union {
|
||||||
|
FT_60XCONFIGURATION ft600;
|
||||||
|
} cfg;
|
||||||
|
if (FT_OK != FT_GetChipConfiguration(handle, &cfg)) {
|
||||||
|
printf("Failed to get chip conf\r\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool needs_update;
|
||||||
|
needs_update = set_ft600_channel_config(&cfg.ft600, clock, is_600_mode);
|
||||||
|
if (needs_update) {
|
||||||
|
if (FT_OK != FT_SetChipConfiguration(handle, &cfg))
|
||||||
|
printf("Failed to set chip conf\r\n");
|
||||||
|
else {
|
||||||
|
printf("Configuration changed\r\n");
|
||||||
|
this_thread::sleep_for(chrono::seconds(1));
|
||||||
|
get_device_lists(6000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dwType == FT_DEVICE_600 || dwType == FT_DEVICE_601) {
|
||||||
|
bool rev_a_chip;
|
||||||
|
DWORD dwVersion;
|
||||||
|
|
||||||
|
FT_GetFirmwareVersion(handle, &dwVersion);
|
||||||
|
rev_a_chip = dwVersion <= 0x105;
|
||||||
|
|
||||||
|
FT_Close(handle);
|
||||||
|
return rev_a_chip;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Close(handle);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBInterface::turn_off_thread_safe() {
|
||||||
|
FT_TRANSFER_CONF conf;
|
||||||
|
|
||||||
|
memset(&conf, 0, sizeof(FT_TRANSFER_CONF));
|
||||||
|
conf.wStructSize = sizeof(FT_TRANSFER_CONF);
|
||||||
|
conf.pipe[FT_PIPE_DIR_IN].fNonThreadSafeTransfer = true;
|
||||||
|
conf.pipe[FT_PIPE_DIR_OUT].fNonThreadSafeTransfer = true;
|
||||||
|
for (DWORD i = 0; i < 4; i++)
|
||||||
|
FT_SetTransferParams(&conf, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBInterface::get_queue_status() {
|
||||||
|
for (uint8_t channel = 0; channel < out_ch_cnt; channel++) {
|
||||||
|
DWORD dwBufferred;
|
||||||
|
|
||||||
|
if (FT_OK != FT_GetUnsentBuffer(handle, channel, NULL, &dwBufferred)) {
|
||||||
|
printf("Failed to get unsent buffer size\r\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
unique_ptr<uint8_t[]> p(new uint8_t[dwBufferred]);
|
||||||
|
|
||||||
|
printf("CH%d OUT unsent buffer size in queue:%u\r\n", channel, dwBufferred);
|
||||||
|
if (FT_OK != FT_GetUnsentBuffer(handle, channel, p.get(), &dwBufferred)) {
|
||||||
|
printf("Failed to read unsent buffer size\r\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t channel = 0; channel < in_ch_cnt; channel++) {
|
||||||
|
DWORD dwBufferred;
|
||||||
|
|
||||||
|
if (FT_OK != FT_GetReadQueueStatus(handle, channel, &dwBufferred))
|
||||||
|
continue;
|
||||||
|
printf("CH%d IN unread buffer size in queue:%u\r\n", channel, dwBufferred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
USBInterface::USBInterface() {
|
||||||
|
get_version();
|
||||||
|
|
||||||
|
if (!get_device_lists(500))
|
||||||
|
throw runtime_error("failed to get device lists");
|
||||||
|
rev_a_chip = set_channel_config(fifo_600mode, CONFIGURATION_FIFO_CLK_100);
|
||||||
|
// turn_off_thread_safe(); // Check this?
|
||||||
|
FT_Create(0, FT_OPEN_BY_INDEX, &handle);
|
||||||
|
|
||||||
|
if (!handle) {
|
||||||
|
throw runtime_error("failed to create device");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
USBInterface::~USBInterface() {
|
||||||
|
if (rev_a_chip)
|
||||||
|
FT_ResetDevicePort(handle);
|
||||||
|
FT_Close(handle);
|
||||||
|
};
|
||||||
|
}
|
68
linux-app/spectrum-analyser/rftool/usb_if.hpp
Normal file
68
linux-app/spectrum-analyser/rftool/usb_if.hpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
using namespace std;
|
||||||
|
#include "../ftd3xx/ftd3xx.h"
|
||||||
|
|
||||||
|
namespace RFTool {
|
||||||
|
|
||||||
|
class USBInterface {
|
||||||
|
public:
|
||||||
|
USBInterface(); // Constructor opens FTDI device
|
||||||
|
~USBInterface(); // Destructor closes FTDI device
|
||||||
|
|
||||||
|
/* Write a 32-byte command to the device; and store the 32-byte response in a
|
||||||
|
buffer if received and requested. Returns false on failure*/
|
||||||
|
bool exec_command(uint8_t *command, bool get_response,
|
||||||
|
uint8_t *response = nullptr);
|
||||||
|
|
||||||
|
/*Perform an SPI transaction with the AD9361. Returns false on failure*/
|
||||||
|
bool spi_transfer(bool is_read, int len, uint16_t addr, uint8_t *buf);
|
||||||
|
|
||||||
|
/* Set the FPGA control signals register */
|
||||||
|
bool set_fpga_ctrl(uint8_t ctrl_val);
|
||||||
|
// Build a 32-byte command from command type and payload
|
||||||
|
void build_command(uint8_t cmd_type, const vector<uint8_t> &payload,
|
||||||
|
uint8_t *buffer);
|
||||||
|
/* Try and receive an rx data packet, copying the raw packet into a buffer
|
||||||
|
and returning false on failure*/
|
||||||
|
bool get_rx_packet(uint8_t *buffer);
|
||||||
|
|
||||||
|
// Flush buffers
|
||||||
|
void flush();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Print a 32-byte response to cout in hex for debug purposes
|
||||||
|
void print_response(uint8_t *resp);
|
||||||
|
void print_command(uint8_t *resp);
|
||||||
|
// These functions are base code from the FTDI supplied demo
|
||||||
|
void get_version();
|
||||||
|
void get_vid_pid();
|
||||||
|
void turn_off_all_pipes();
|
||||||
|
bool get_device_lists(int timeout_ms);
|
||||||
|
bool set_ft600_channel_config(FT_60XCONFIGURATION *cfg,
|
||||||
|
CONFIGURATION_FIFO_CLK clock, bool is_600_mode);
|
||||||
|
bool set_channel_config(bool is_600_mode, CONFIGURATION_FIFO_CLK clock);
|
||||||
|
void turn_off_thread_safe();
|
||||||
|
void get_queue_status();
|
||||||
|
FT_HANDLE handle;
|
||||||
|
bool rev_a_chip;
|
||||||
|
|
||||||
|
bool fifo_600mode = false;
|
||||||
|
uint8_t in_ch_cnt = 1;
|
||||||
|
uint8_t out_ch_cnt = 1;
|
||||||
|
|
||||||
|
const int command_len = 32;
|
||||||
|
const int response_len = 32;
|
||||||
|
const int rx_packet_len = 4096;
|
||||||
|
const int timeout = 1000;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Swap the word endianness of a byte array
|
||||||
|
inline void swap_endian(uint8_t *buffer, int len) {
|
||||||
|
for (int i = 0; i < len; i += 4) {
|
||||||
|
swap(buffer[i + 3], buffer[i]);
|
||||||
|
swap(buffer[i + 2], buffer[i + 1]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
170
linux-app/spectrum-analyser/rftool/usb_platform.cpp
Normal file
170
linux-app/spectrum-analyser/rftool/usb_platform.cpp
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
#include "usb_if.hpp"
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <thread>
|
||||||
|
#include <time.h>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// AD9361 driver platform shim
|
||||||
|
|
||||||
|
static RFTool::USBInterface *usb = nullptr;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "../ad9361/platform/platform.h"
|
||||||
|
#include "usb_platform.h"
|
||||||
|
|
||||||
|
int32_t spi_init(uint32_t device_id, uint8_t clk_pha, uint8_t clk_pol) {
|
||||||
|
if (usb == nullptr)
|
||||||
|
usb = new RFTool::USBInterface();
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
int32_t spi_read(uint8_t *data, uint8_t bytes_number) {
|
||||||
|
throw runtime_error("spi_read not supported, use spi_write_then_read");
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t cmd_resp_magic[5] = {0x52, 0x45, 0x53, 0x50, 0x10};
|
||||||
|
|
||||||
|
int spi_write_then_read(struct spi_device *spi, const unsigned char *txbuf,
|
||||||
|
unsigned n_tx, unsigned char *rxbuf, unsigned n_rx) {
|
||||||
|
if (usb == nullptr)
|
||||||
|
return -1;
|
||||||
|
if (n_tx < 2)
|
||||||
|
throw runtime_error("n_tx must be >= 2");
|
||||||
|
usb->flush();
|
||||||
|
vector<uint8_t> payload;
|
||||||
|
payload.push_back(uint8_t(n_tx + n_rx));
|
||||||
|
for (int i = 0; i < n_tx; i++)
|
||||||
|
payload.push_back(txbuf[i]);
|
||||||
|
for (int i = 0; i < n_rx; i++)
|
||||||
|
payload.push_back(0);
|
||||||
|
uint8_t cmd_buf[32], resp_buf[32];
|
||||||
|
usb->build_command(0x10, payload, cmd_buf);
|
||||||
|
if (!usb->exec_command(cmd_buf, true, resp_buf))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
RFTool::swap_endian(resp_buf, 32);
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
if (resp_buf[i] != cmd_resp_magic[i])
|
||||||
|
cerr << "bad spi resp packet" << endl;
|
||||||
|
}
|
||||||
|
if (resp_buf[5] != (n_tx + n_rx))
|
||||||
|
cerr << "mismatched spi resp packet" << endl;
|
||||||
|
|
||||||
|
for (int i = 0; i < n_rx; i++) {
|
||||||
|
rxbuf[i] = resp_buf[6 + n_tx + i];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void gpio_init(uint32_t device_id) {
|
||||||
|
if (usb == nullptr)
|
||||||
|
usb = new RFTool::USBInterface();
|
||||||
|
};
|
||||||
|
|
||||||
|
void gpio_direction(uint8_t pin, uint8_t direction){};
|
||||||
|
|
||||||
|
bool gpio_is_valid(int number) { return (number == 0); };
|
||||||
|
|
||||||
|
void gpio_set_value(unsigned gpio, int value) {
|
||||||
|
// resetn is ctrl sig bit 1 and inverted (so active high)
|
||||||
|
if (usb == nullptr)
|
||||||
|
return;
|
||||||
|
if (gpio == 0) {
|
||||||
|
if (value == 0) {
|
||||||
|
usb->set_fpga_ctrl(0x02);
|
||||||
|
} else {
|
||||||
|
usb->set_fpga_ctrl(0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void enter_rx_streaming_mode() {
|
||||||
|
uint8_t cmd_buf[32], resp_buf[32];
|
||||||
|
if (usb == nullptr)
|
||||||
|
return;
|
||||||
|
usb->build_command(0x30, vector<uint8_t>{}, cmd_buf);
|
||||||
|
usb->exec_command(cmd_buf, false, resp_buf);
|
||||||
|
};
|
||||||
|
|
||||||
|
void leave_rx_streaming_mode() {
|
||||||
|
uint8_t cmd_buf[32], resp_buf[32];
|
||||||
|
if (usb == nullptr)
|
||||||
|
return;
|
||||||
|
usb->build_command(0x31, vector<uint8_t>{}, cmd_buf);
|
||||||
|
usb->flush();
|
||||||
|
usb->exec_command(cmd_buf, true, resp_buf);
|
||||||
|
usb->flush();
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t rx_magic[4] = {0x52, 0x58, 0x49, 0x51};
|
||||||
|
// static const uint8_t rx_magic[4] = {0x51, 0x49, 0x58, 0x52};
|
||||||
|
const int rx_packet_len = 4096;
|
||||||
|
static bool first_rx_get = true;
|
||||||
|
static uint8_t rx_buffer_a[rx_packet_len], rx_buffer_b[rx_packet_len];
|
||||||
|
static uint8_t *current_packet = rx_buffer_a;
|
||||||
|
static uint8_t *last_packet = rx_buffer_b;
|
||||||
|
|
||||||
|
void rx_purge() { first_rx_get = true; };
|
||||||
|
|
||||||
|
int rx_get_data(iq_sample *buf) {
|
||||||
|
if (usb == nullptr)
|
||||||
|
return 0;
|
||||||
|
if (!usb->get_rx_packet(current_packet))
|
||||||
|
return 0;
|
||||||
|
int out_idx = 0;
|
||||||
|
// Workaround for a broken USB interface ATM
|
||||||
|
for (int i = 0; i < (rx_packet_len - 4); i++) {
|
||||||
|
|
||||||
|
if (((current_packet[i + 0] & 0xC0) == 0x00) &&
|
||||||
|
((current_packet[i + 1] & 0xC0) == 0x40) &&
|
||||||
|
((current_packet[i + 2] & 0xC0) == 0x80) &&
|
||||||
|
((current_packet[i + 3] & 0xC0) == 0xC0)) {
|
||||||
|
// Extract I and Q
|
||||||
|
uint16_t i_raw = (uint16_t(current_packet[i + 1] & 0x3F) << 6) |
|
||||||
|
(uint16_t(current_packet[i]) & 0x3F);
|
||||||
|
uint16_t q_raw = (uint16_t(current_packet[i + 3] & 0x3F) << 6) |
|
||||||
|
(uint16_t(current_packet[i + 2]) & 0x3F);
|
||||||
|
// Sign extend
|
||||||
|
buf[out_idx].i = ((i_raw & 0x800) == 0x800) ? (i_raw | 0xF000) : i_raw;
|
||||||
|
buf[out_idx].q = ((q_raw & 0x800) == 0x800) ? (q_raw | 0xF000) : q_raw;
|
||||||
|
out_idx++;
|
||||||
|
i += 3;
|
||||||
|
} else {
|
||||||
|
// cout << "bad alignment" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void udelay(unsigned long usecs) {
|
||||||
|
timespec dly;
|
||||||
|
dly.tv_sec = 0;
|
||||||
|
dly.tv_nsec = usecs * 1000;
|
||||||
|
nanosleep(&dly, nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
void mdelay(unsigned long msecs) { msleep_interruptible(msecs); }
|
||||||
|
|
||||||
|
unsigned long msleep_interruptible(unsigned int msecs) {
|
||||||
|
this_thread::sleep_for(chrono::milliseconds(msecs));
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// AXIADC functions are not yet implemented and dummies to prevent linker errors
|
||||||
|
void axiadc_init(struct ad9361_rf_phy *phy){};
|
||||||
|
int axiadc_post_setup(struct ad9361_rf_phy *phy) { return 0; };
|
||||||
|
unsigned int axiadc_read(struct axiadc_state *st, unsigned long reg) {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
void axiadc_write(struct axiadc_state *st, unsigned reg, unsigned val){};
|
||||||
|
int axiadc_set_pnsel(struct axiadc_state *st, int channel,
|
||||||
|
enum adc_pn_sel sel) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void axiadc_idelay_set(struct axiadc_state *st, unsigned lane, unsigned val){};
|
||||||
|
};
|
11
linux-app/spectrum-analyser/usb_platform.h
Normal file
11
linux-app/spectrum-analyser/usb_platform.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
// Custom platform functions, in addition to the standard AD ones
|
||||||
|
void enter_rx_streaming_mode();
|
||||||
|
void leave_rx_streaming_mode();
|
||||||
|
|
||||||
|
struct iq_sample {
|
||||||
|
int16_t i, q;
|
||||||
|
};
|
||||||
|
|
||||||
|
int rx_get_data(struct iq_sample *buf);
|
Loading…
Reference in New Issue
Block a user