mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2024-11-10 04:37:37 +01:00
Add badgesdr source and add logging to spectran source
This commit is contained in:
parent
bcadb36232
commit
118e1fbff0
@ -23,9 +23,9 @@ SDRPP_MOD_INFO{
|
|||||||
/* Max instances */ -1
|
/* Max instances */ -1
|
||||||
};
|
};
|
||||||
|
|
||||||
#define INPUT_BANDWIDTH 800000
|
#define INPUT_BANDWIDTH 138e3
|
||||||
#define INPUT_SAMPLE_RATE 1500000
|
#define INPUT_SAMPLE_RATE 250e3
|
||||||
#define INPUT_BAUDRATE 720000
|
#define INPUT_BAUDRATE 125e3
|
||||||
|
|
||||||
#define SYMBOL_DIAG_RATE 30
|
#define SYMBOL_DIAG_RATE 30
|
||||||
#define SYMBOL_DIAG_COUNT 1024
|
#define SYMBOL_DIAG_COUNT 1024
|
||||||
|
@ -93,7 +93,7 @@ namespace ryfi {
|
|||||||
// If the frames aren't consecutive
|
// If the frames aren't consecutive
|
||||||
int frameRead = 0;
|
int frameRead = 0;
|
||||||
if (frame.counter != expectedCounter) {
|
if (frame.counter != expectedCounter) {
|
||||||
//flog::warn("Lost at least {} frames", ((int)frame.counter - (int)expectedCounter + 0x10000) % 0x10000);
|
flog::warn("Lost at least {} frames", ((int)frame.counter - (int)expectedCounter + 0x10000) % 0x10000);
|
||||||
|
|
||||||
// Cancel the partial packet if there was one
|
// Cancel the partial packet if there was one
|
||||||
pktExpected = 0;
|
pktExpected = 0;
|
||||||
|
25
source_modules/badgesdr_source/CMakeLists.txt
Normal file
25
source_modules/badgesdr_source/CMakeLists.txt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
project(badgesdr_source)
|
||||||
|
|
||||||
|
file(GLOB SRC "src/*.cpp")
|
||||||
|
|
||||||
|
include(${SDRPP_MODULE_CMAKE})
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
find_package(libusb CONFIG REQUIRED)
|
||||||
|
target_include_directories(badgesdr_source PRIVATE ${LIBUSB_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(badgesdr_source PRIVATE ${LIBUSB_LIBRARIES})
|
||||||
|
elseif (ANDROID)
|
||||||
|
target_link_libraries(badgesdr_source PUBLIC
|
||||||
|
/sdr-kit/${ANDROID_ABI}/lib/libusb1.0.so
|
||||||
|
/sdr-kit/${ANDROID_ABI}/lib/librtlsdr.so
|
||||||
|
)
|
||||||
|
else (MSVC)
|
||||||
|
find_package(PkgConfig)
|
||||||
|
|
||||||
|
pkg_check_modules(LIBUSB REQUIRED libusb-1.0)
|
||||||
|
|
||||||
|
target_include_directories(badgesdr_source PRIVATE ${LIBUSB_INCLUDE_DIRS})
|
||||||
|
target_link_directories(badgesdr_source PRIVATE ${LIBUSB_LIBRARY_DIRS})
|
||||||
|
target_link_libraries(badgesdr_source PRIVATE ${LIBUSB_LIBRARIES})
|
||||||
|
endif ()
|
309
source_modules/badgesdr_source/src/badgesdr.cpp
Normal file
309
source_modules/badgesdr_source/src/badgesdr.cpp
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
#include "badgesdr.h"
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <utils/flog.h>
|
||||||
|
|
||||||
|
#define R820T_I2C_ADDR 0x1A
|
||||||
|
|
||||||
|
namespace BadgeSDR {
|
||||||
|
enum Commands {
|
||||||
|
CMD_I2C_RW,
|
||||||
|
CMD_I2C_STATUS,
|
||||||
|
CMD_ADC_START,
|
||||||
|
CMD_ADC_STOP,
|
||||||
|
CMD_ADC_GET_SAMP_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
libusb_context* ctx = NULL;
|
||||||
|
|
||||||
|
bool DeviceInfo::operator==(const DeviceInfo& b) const {
|
||||||
|
return serialNumber == b.serialNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::write_reg(uint8_t reg, uint8_t value, void* ctx) {
|
||||||
|
Device* dev = (Device*)ctx;
|
||||||
|
dev->writeR820TReg(reg, value);
|
||||||
|
dev->writeR820TReg(0x1F, 0); // TODO: Figure out why this is needed
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::read_reg(uint8_t* data, int len, void* ctx) {
|
||||||
|
Device* dev = (Device*)ctx;
|
||||||
|
dev->readI2C(R820T_I2C_ADDR, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::Device(libusb_device_handle* dev) {
|
||||||
|
// Save device handle
|
||||||
|
this->dev = dev;
|
||||||
|
|
||||||
|
// Init tuner
|
||||||
|
r820t = {
|
||||||
|
16000000, // xtal_freq => 16MHz
|
||||||
|
3000000, // Set at boot to airspy_m0_m4_conf_t conf0 -> r820t_if_freq
|
||||||
|
100000000, /* Default Freq 100Mhz */
|
||||||
|
{
|
||||||
|
/* 05 */ 0x9F, // LNA manual gain mode, init to 0
|
||||||
|
/* 06 */ 0x80,
|
||||||
|
/* 07 */ 0x60,
|
||||||
|
/* 08 */ 0x80, // Image Gain Adjustment
|
||||||
|
/* 09 */ 0x40, // Image Phase Adjustment
|
||||||
|
/* 0A */ 0xA8, // Channel filter [0..3]: 0 = widest, f = narrowest - Optimal. Don't touch!
|
||||||
|
/* 0B */ 0x0F, // High pass filter - Optimal. Don't touch!
|
||||||
|
/* 0C */ 0x4F, // VGA control by code, init at 0
|
||||||
|
/* 0D */ 0x63, // LNA AGC settings: [0..3]: Lower threshold; [4..7]: High threshold
|
||||||
|
/* 0E */ 0x75,
|
||||||
|
/* 0F */ 0xE8, // Filter Widest, LDO_5V OFF, clk out ON,
|
||||||
|
/* 10 */ 0x7C,
|
||||||
|
/* 11 */ 0x42,
|
||||||
|
/* 12 */ 0x06,
|
||||||
|
/* 13 */ 0x00,
|
||||||
|
/* 14 */ 0x0F,
|
||||||
|
/* 15 */ 0x00,
|
||||||
|
/* 16 */ 0xC0,
|
||||||
|
/* 17 */ 0xA0,
|
||||||
|
/* 18 */ 0x48,
|
||||||
|
/* 19 */ 0xCC,
|
||||||
|
/* 1A */ 0x60,
|
||||||
|
/* 1B */ 0x00,
|
||||||
|
/* 1C */ 0x54,
|
||||||
|
/* 1D */ 0xAE,
|
||||||
|
/* 1E */ 0x0A,
|
||||||
|
/* 1F */ 0xC0
|
||||||
|
},
|
||||||
|
0 /* uint16_t padding */
|
||||||
|
};
|
||||||
|
r820t_init(&r820t, 3000000, write_reg, read_reg, this);
|
||||||
|
r820t_set_mixer_gain(&r820t, 15);
|
||||||
|
r820t_set_vga_gain(&r820t, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::~Device() {
|
||||||
|
// Release the bulk interface
|
||||||
|
libusb_release_interface(dev, 0);
|
||||||
|
|
||||||
|
// Close device
|
||||||
|
libusb_close(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::setFrequency(double freq) {
|
||||||
|
r820t_set_freq(&r820t, freq - 2125000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::setLNAGain(int gain) {
|
||||||
|
r820t_set_lna_gain(&r820t, gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::setMixerGain(int gain) {
|
||||||
|
r820t_set_mixer_gain(&r820t, gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::setVGAGain(int gain) {
|
||||||
|
r820t_set_vga_gain(&r820t, gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Device::start(void (*callback)(const uint8_t* samples, int count, void* ctx), void* ctx, int minBufferSize) {
|
||||||
|
// Do nothing if already running
|
||||||
|
if (run) { return; }
|
||||||
|
|
||||||
|
// Save handler
|
||||||
|
this->callback = callback;
|
||||||
|
this->ctx = ctx;
|
||||||
|
|
||||||
|
// Compute buffer size
|
||||||
|
int bufCount = minBufferSize / 64;
|
||||||
|
if (minBufferSize % 64) { bufCount++; }
|
||||||
|
bufferSize = bufCount * 64;
|
||||||
|
|
||||||
|
// Mark as running
|
||||||
|
run = true;
|
||||||
|
|
||||||
|
// Start the ADC
|
||||||
|
startADC();
|
||||||
|
|
||||||
|
// Start worker thread
|
||||||
|
workerThread = std::thread(&Device::worker, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::stop() {
|
||||||
|
// Do nothing if already stopped
|
||||||
|
if (!run) { return; }
|
||||||
|
|
||||||
|
// Mark as stopped
|
||||||
|
run = false;
|
||||||
|
|
||||||
|
// Wait for the worker to exit
|
||||||
|
if (workerThread.joinable()) { workerThread.join(); }
|
||||||
|
|
||||||
|
// Stop the ADC
|
||||||
|
stopADC();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Device::getI2CStatus() {
|
||||||
|
int status;
|
||||||
|
int ret = libusb_control_transfer(dev, (1 << 7) | (2 << 5), CMD_I2C_STATUS, 0, 0, (uint8_t*)&status, sizeof(status), 1000);
|
||||||
|
if (ret <= 0 || status < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Device::readI2C(uint8_t addr, uint8_t* data, int len) {
|
||||||
|
// Do read
|
||||||
|
int bytes = libusb_control_transfer(dev, (1 << 7) | (2 << 5), CMD_I2C_RW, 0, addr, data, len, 1000);
|
||||||
|
if (bytes < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get status (TODO: Use function)
|
||||||
|
int status;
|
||||||
|
int ret = libusb_control_transfer(dev, (1 << 7) | (2 << 5), CMD_I2C_STATUS, 0, 0, (uint8_t*)&status, sizeof(status), 1000);
|
||||||
|
if (ret <= 0 || status < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Device::writeI2C(uint8_t addr, const uint8_t* data, int len) {
|
||||||
|
// Do write
|
||||||
|
int bytes = libusb_control_transfer(dev, (2 << 5), CMD_I2C_RW, 0, addr, (uint8_t*)data, len, 1000);
|
||||||
|
if (bytes < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get status (TODO: Use function)
|
||||||
|
int status;
|
||||||
|
int ret = libusb_control_transfer(dev, (1 << 7) | (2 << 5), CMD_I2C_STATUS, 0, 0, (uint8_t*)&status, sizeof(status), 1000);
|
||||||
|
if (ret <= 0 || status < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t bitrev(uint8_t val) {
|
||||||
|
return ((val & 0x01) << 7) | ((val & 0x02) << 5) | ((val & 0x04) << 3) | ((val & 0x08) << 1) | ((val & 0x10) >> 1) | ((val & 0x20) >> 3) | ((val & 0x40) >> 5) | ((val & 0x80) >> 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Device::readR820TReg(uint8_t reg) {
|
||||||
|
// Read registers up to it (can't read single)
|
||||||
|
uint8_t regs[0x20];
|
||||||
|
readI2C(R820T_I2C_ADDR, regs, reg+1);
|
||||||
|
|
||||||
|
// Invert bit order
|
||||||
|
return bitrev(regs[reg]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::writeR820TReg(uint8_t reg, uint8_t val) {
|
||||||
|
// Write register id then value
|
||||||
|
uint8_t cmd[2] = { reg, val };
|
||||||
|
writeI2C(R820T_I2C_ADDR, cmd, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Device::startADC() {
|
||||||
|
return libusb_control_transfer(dev, (2 << 5), CMD_ADC_START, 0, 0, NULL, 0, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Device::stopADC() {
|
||||||
|
return libusb_control_transfer(dev, (2 << 5), CMD_ADC_STOP, 0, 0, NULL, 0, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::worker() {
|
||||||
|
// Allocate sample buffer
|
||||||
|
uint8_t* buffer = new uint8_t[bufferSize];
|
||||||
|
int sampleCount = 0;
|
||||||
|
|
||||||
|
while (run) {
|
||||||
|
// Receive data with bulk transfer
|
||||||
|
int recvLen = 0;
|
||||||
|
int val = libusb_bulk_transfer(dev, LIBUSB_ENDPOINT_IN | 1, &buffer[sampleCount], bufferSize - sampleCount, &recvLen, 1000);
|
||||||
|
|
||||||
|
// If timed out, try again. Otherwise, if an error occur, stop the thread
|
||||||
|
if (val == LIBUSB_ERROR_TIMEOUT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (val) {
|
||||||
|
flog::error("USB Error: {}", val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment sample count
|
||||||
|
if (recvLen) { sampleCount += recvLen; }
|
||||||
|
|
||||||
|
// If the buffer is full, call handler and reset sample count
|
||||||
|
if (sampleCount >= bufferSize) {
|
||||||
|
callback(buffer, sampleCount, ctx);
|
||||||
|
sampleCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free buffer
|
||||||
|
delete[] buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<DeviceInfo> list() {
|
||||||
|
// Init libusb if done yet
|
||||||
|
if (!ctx) {
|
||||||
|
libusb_init(&ctx);
|
||||||
|
libusb_set_debug(ctx, LIBUSB_LOG_LEVEL_WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
// List devices
|
||||||
|
std::vector<DeviceInfo> devList;
|
||||||
|
libusb_device** devices;
|
||||||
|
int devCount = libusb_get_device_list(ctx, &devices);
|
||||||
|
for (int i = 0; i < devCount; i++) {
|
||||||
|
// Get device info
|
||||||
|
DeviceInfo devInfo;
|
||||||
|
devInfo.dev = devices[i];
|
||||||
|
libusb_device_descriptor desc;
|
||||||
|
libusb_get_device_descriptor(devInfo.dev, &desc);
|
||||||
|
|
||||||
|
// Check the VID/PID and give up if not the right ones
|
||||||
|
if (desc.idVendor != 0xCAFE || desc.idProduct != 0x4010) {
|
||||||
|
libusb_unref_device(devInfo.dev);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open devices
|
||||||
|
libusb_device_handle* openDev;
|
||||||
|
int err = libusb_open(devInfo.dev, &openDev);
|
||||||
|
if (err) {
|
||||||
|
libusb_unref_device(devInfo.dev);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get serial number
|
||||||
|
char serial[128];
|
||||||
|
libusb_get_string_descriptor_ascii(openDev, desc.iSerialNumber, (uint8_t*)serial, sizeof(serial));
|
||||||
|
devInfo.serialNumber = serial;
|
||||||
|
|
||||||
|
// TODO: The libusb device should be unreffed but would need to know when the list disappears
|
||||||
|
|
||||||
|
// Close device
|
||||||
|
libusb_close(openDev);
|
||||||
|
|
||||||
|
// Add to list
|
||||||
|
devList.push_back(devInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return devices
|
||||||
|
return devList;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Device> open(const DeviceInfo& dev) {
|
||||||
|
// Open device
|
||||||
|
libusb_device_handle* openDev;
|
||||||
|
int err = libusb_open(dev.dev, &openDev);
|
||||||
|
if (err) {
|
||||||
|
throw std::runtime_error("Failed to open device");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Claim the bulk transfer interface
|
||||||
|
if (libusb_claim_interface(openDev, 0)) {
|
||||||
|
throw std::runtime_error("Failed to claim bulk interface");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create device
|
||||||
|
return std::make_shared<Device>(openDev);
|
||||||
|
}
|
||||||
|
}
|
53
source_modules/badgesdr_source/src/badgesdr.h
Normal file
53
source_modules/badgesdr_source/src/badgesdr.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <thread>
|
||||||
|
#include <libusb.h>
|
||||||
|
#include "r820t.h"
|
||||||
|
|
||||||
|
namespace BadgeSDR {
|
||||||
|
struct DeviceInfo {
|
||||||
|
std::string serialNumber;
|
||||||
|
libusb_device* dev;
|
||||||
|
bool operator==(const DeviceInfo& b) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Device {
|
||||||
|
public:
|
||||||
|
Device(libusb_device_handle* dev);
|
||||||
|
~Device();
|
||||||
|
|
||||||
|
void setFrequency(double freq);
|
||||||
|
void setLNAGain(int gain);
|
||||||
|
void setMixerGain(int gain);
|
||||||
|
void setVGAGain(int gain);
|
||||||
|
|
||||||
|
void start(void (*callback)(const uint8_t* samples, int count, void* ctx), void* ctx = NULL, int minBufferSize = 2500);
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int getI2CStatus();
|
||||||
|
int readI2C(uint8_t addr, uint8_t* data, int len);
|
||||||
|
int writeI2C(uint8_t addr, const uint8_t* data, int len);
|
||||||
|
uint8_t readR820TReg(uint8_t reg);
|
||||||
|
void writeR820TReg(uint8_t reg, uint8_t val);
|
||||||
|
int startADC();
|
||||||
|
int stopADC();
|
||||||
|
void worker();
|
||||||
|
|
||||||
|
libusb_device_handle* dev;
|
||||||
|
std::thread workerThread;
|
||||||
|
bool run = false;
|
||||||
|
int bufferSize = 0; // Must be multiple of 64 for best performance
|
||||||
|
void* ctx = NULL;
|
||||||
|
void (*callback)(const uint8_t* samples, int count, void* ctx);
|
||||||
|
|
||||||
|
static void write_reg(uint8_t reg, uint8_t value, void* ctx);
|
||||||
|
static void read_reg(uint8_t* data, int len, void* ctx);
|
||||||
|
r820t_priv_t r820t;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<DeviceInfo> list();
|
||||||
|
std::shared_ptr<Device> open(const DeviceInfo& dev);
|
||||||
|
}
|
272
source_modules/badgesdr_source/src/main.cpp
Normal file
272
source_modules/badgesdr_source/src/main.cpp
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
#include <imgui.h>
|
||||||
|
#include <module.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <gui/smgui.h>
|
||||||
|
#include <signal_path/signal_path.h>
|
||||||
|
#include <core.h>
|
||||||
|
#include <utils/optionlist.h>
|
||||||
|
#include <dsp/channel/rx_vfo.h>
|
||||||
|
#include <dsp/correction/dc_blocker.h>
|
||||||
|
#include "badgesdr.h"
|
||||||
|
|
||||||
|
SDRPP_MOD_INFO{
|
||||||
|
/* Name: */ "badgesdr_source",
|
||||||
|
/* Description: */ "BadgeSDR Source Module",
|
||||||
|
/* Author: */ "Ryzerth",
|
||||||
|
/* Version: */ 0, 1, 0,
|
||||||
|
/* Max instances */ -1
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||||
|
|
||||||
|
class BadgeSDRSourceModule : public ModuleManager::Instance {
|
||||||
|
public:
|
||||||
|
BadgeSDRSourceModule(std::string name) {
|
||||||
|
this->name = name;
|
||||||
|
|
||||||
|
sampleRate = 250000.0;
|
||||||
|
|
||||||
|
// Initialize DSP
|
||||||
|
dcBlock.init(&input, 0.001);
|
||||||
|
ddc.init(&dcBlock.out, 500000, 250000, 250000, 125000);
|
||||||
|
|
||||||
|
handler.ctx = this;
|
||||||
|
handler.selectHandler = menuSelected;
|
||||||
|
handler.deselectHandler = menuDeselected;
|
||||||
|
handler.menuHandler = menuHandler;
|
||||||
|
handler.startHandler = start;
|
||||||
|
handler.stopHandler = stop;
|
||||||
|
handler.tuneHandler = tune;
|
||||||
|
handler.stream = &ddc.out;
|
||||||
|
|
||||||
|
// Refresh devices
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
// Select first (TODO: Select from config)
|
||||||
|
select("");
|
||||||
|
|
||||||
|
sigpath::sourceManager.registerSource("BadgeSDR", &handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
~BadgeSDRSourceModule() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void postInit() {}
|
||||||
|
|
||||||
|
void enable() {
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void disable() {
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void refresh() {
|
||||||
|
devices.clear();
|
||||||
|
auto list = BadgeSDR::list();
|
||||||
|
for (const auto& info : list) {
|
||||||
|
// Format device name
|
||||||
|
std::string devName = "BadgeSDR ";
|
||||||
|
devName += " [";
|
||||||
|
devName += info.serialNumber;
|
||||||
|
devName += ']';
|
||||||
|
|
||||||
|
// Save device
|
||||||
|
devices.define(info.serialNumber, devName, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void select(const std::string& serial) {
|
||||||
|
// If there are no devices, give up
|
||||||
|
if (devices.empty()) {
|
||||||
|
selectedSerial.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the serial was not found, select the first available serial
|
||||||
|
if (!devices.keyExists(serial)) {
|
||||||
|
select(devices.key(0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save serial number
|
||||||
|
selectedSerial = serial;
|
||||||
|
selectedDev = devices.value(devices.keyId(serial));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void menuSelected(void* ctx) {
|
||||||
|
BadgeSDRSourceModule* _this = (BadgeSDRSourceModule*)ctx;
|
||||||
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
|
flog::info("BadgeSDRSourceModule '{0}': Menu Select!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void menuDeselected(void* ctx) {
|
||||||
|
BadgeSDRSourceModule* _this = (BadgeSDRSourceModule*)ctx;
|
||||||
|
flog::info("BadgeSDRSourceModule '{0}': Menu Deselect!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void start(void* ctx) {
|
||||||
|
BadgeSDRSourceModule* _this = (BadgeSDRSourceModule*)ctx;
|
||||||
|
if (_this->running) { return; }
|
||||||
|
|
||||||
|
// Open the device
|
||||||
|
_this->openDev = BadgeSDR::open(_this->selectedDev);
|
||||||
|
|
||||||
|
// Configure the device
|
||||||
|
_this->openDev->setFrequency(_this->freq);
|
||||||
|
_this->openDev->setLNAGain(_this->lnaGain);
|
||||||
|
_this->openDev->setMixerGain(_this->mixerGain);
|
||||||
|
_this->openDev->setVGAGain(_this->vgaGain);
|
||||||
|
|
||||||
|
// Start DSP
|
||||||
|
_this->dcBlock.start();
|
||||||
|
_this->ddc.start();
|
||||||
|
|
||||||
|
// Start device
|
||||||
|
_this->openDev->start(callback, _this, 500000/200);
|
||||||
|
|
||||||
|
_this->running = true;
|
||||||
|
flog::info("BadgeSDRSourceModule '{0}': Start!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stop(void* ctx) {
|
||||||
|
BadgeSDRSourceModule* _this = (BadgeSDRSourceModule*)ctx;
|
||||||
|
if (!_this->running) { return; }
|
||||||
|
_this->running = false;
|
||||||
|
|
||||||
|
// Stop worker
|
||||||
|
_this->openDev->stop();
|
||||||
|
|
||||||
|
// Stop DSP
|
||||||
|
_this->dcBlock.stop();
|
||||||
|
_this->ddc.stop();
|
||||||
|
|
||||||
|
// Close device
|
||||||
|
_this->openDev.reset();
|
||||||
|
|
||||||
|
flog::info("BadgeSDRSourceModule '{0}': Stop!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tune(double freq, void* ctx) {
|
||||||
|
BadgeSDRSourceModule* _this = (BadgeSDRSourceModule*)ctx;
|
||||||
|
if (_this->running) {
|
||||||
|
_this->openDev->setFrequency(freq);
|
||||||
|
}
|
||||||
|
_this->freq = freq;
|
||||||
|
flog::info("BadgeSDRSourceModule '{0}': Tune: {1}!", _this->name, freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void menuHandler(void* ctx) {
|
||||||
|
BadgeSDRSourceModule* _this = (BadgeSDRSourceModule*)ctx;
|
||||||
|
|
||||||
|
if (_this->running) { SmGui::BeginDisabled(); }
|
||||||
|
|
||||||
|
SmGui::FillWidth();
|
||||||
|
SmGui::ForceSync();
|
||||||
|
if (SmGui::Combo(CONCAT("##_badgesdr_dev_sel_", _this->name), &_this->devId, _this->devices.txt)) {
|
||||||
|
_this->select(_this->devices.key(_this->devId));
|
||||||
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
|
// TODO: Save
|
||||||
|
}
|
||||||
|
|
||||||
|
SmGui::FillWidth();
|
||||||
|
SmGui::ForceSync();
|
||||||
|
if (SmGui::Button(CONCAT("Refresh##_badgesdr_refr_", _this->name))) {
|
||||||
|
_this->refresh();
|
||||||
|
_this->select(_this->selectedSerial);
|
||||||
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_this->running) { SmGui::EndDisabled(); }
|
||||||
|
|
||||||
|
SmGui::LeftLabel("LNA Gain");
|
||||||
|
SmGui::FillWidth();
|
||||||
|
if (SmGui::SliderInt(CONCAT("##_badgesdr_lna_gain_", _this->name), &_this->lnaGain, 0, 15)) {
|
||||||
|
if (_this->running) {
|
||||||
|
_this->openDev->setLNAGain(_this->lnaGain);
|
||||||
|
}
|
||||||
|
// TODO: Save
|
||||||
|
}
|
||||||
|
|
||||||
|
SmGui::LeftLabel("Mixer Gain");
|
||||||
|
SmGui::FillWidth();
|
||||||
|
if (SmGui::SliderInt(CONCAT("##_badgesdr_mixer_gain_", _this->name), &_this->mixerGain, 0, 15)) {
|
||||||
|
if (_this->running) {
|
||||||
|
_this->openDev->setMixerGain(_this->mixerGain);
|
||||||
|
}
|
||||||
|
// TODO: Save
|
||||||
|
}
|
||||||
|
|
||||||
|
SmGui::LeftLabel("VGA Gain");
|
||||||
|
SmGui::FillWidth();
|
||||||
|
if (SmGui::SliderInt(CONCAT("##_badgesdr_vga_gain_", _this->name), &_this->vgaGain, 0, 15)) {
|
||||||
|
if (_this->running) {
|
||||||
|
_this->openDev->setVGAGain(_this->vgaGain);
|
||||||
|
}
|
||||||
|
// TODO: Save
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void callback(const uint8_t* samples, int count, void* ctx) {
|
||||||
|
BadgeSDRSourceModule* _this = (BadgeSDRSourceModule*)ctx;
|
||||||
|
|
||||||
|
// Convert samples to float
|
||||||
|
dsp::complex_t* out = _this->input.writeBuf;
|
||||||
|
int min = 255, max = 0;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (samples[i] < min) { min = samples[i]; }
|
||||||
|
if (samples[i] > max) { max = samples[i]; }
|
||||||
|
|
||||||
|
out[i].re = ((float)samples[i] - 127.5f) * (1.0f/127.0f);
|
||||||
|
out[i].im = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send out samples
|
||||||
|
_this->input.swap(count);
|
||||||
|
|
||||||
|
flog::debug("Amplitudes: {} -> {}", min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
bool enabled = true;
|
||||||
|
double sampleRate;
|
||||||
|
SourceManager::SourceHandler handler;
|
||||||
|
bool running = false;
|
||||||
|
double freq;
|
||||||
|
|
||||||
|
OptionList<std::string, BadgeSDR::DeviceInfo> devices;
|
||||||
|
|
||||||
|
int devId = 0;
|
||||||
|
int lnaGain = 0;
|
||||||
|
int mixerGain = 0;
|
||||||
|
int vgaGain = 0;
|
||||||
|
std::string selectedSerial;
|
||||||
|
BadgeSDR::DeviceInfo selectedDev;
|
||||||
|
std::shared_ptr<BadgeSDR::Device> openDev;
|
||||||
|
|
||||||
|
dsp::stream<dsp::complex_t> input;
|
||||||
|
dsp::correction::DCBlocker<dsp::complex_t> dcBlock;
|
||||||
|
dsp::channel::RxVFO ddc;
|
||||||
|
};
|
||||||
|
|
||||||
|
MOD_EXPORT void _INIT_() {
|
||||||
|
// Nothing here
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
||||||
|
return new BadgeSDRSourceModule(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
|
||||||
|
delete (BadgeSDRSourceModule*)instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD_EXPORT void _END_() {
|
||||||
|
// Nothing here
|
||||||
|
}
|
622
source_modules/badgesdr_source/src/r820t.cpp
Normal file
622
source_modules/badgesdr_source/src/r820t.cpp
Normal file
@ -0,0 +1,622 @@
|
|||||||
|
/*
|
||||||
|
* Rafael Micro R820T driver for AIRSPY
|
||||||
|
*
|
||||||
|
* Copyright 2013 Youssef Touil <youssef@airspy.com>
|
||||||
|
* Copyright 2014-2016 Benjamin Vernoux <bvernoux@airspy.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "r820t.h"
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
static int r820t_read_cache_reg(r820t_priv_t *priv, int reg);
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
|
|
||||||
|
/* Tuner frequency ranges */
|
||||||
|
struct r820t_freq_range
|
||||||
|
{
|
||||||
|
uint8_t open_d;
|
||||||
|
uint8_t rf_mux_ploy;
|
||||||
|
uint8_t tf_c;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define R820T_READ_MAX_DATA 32
|
||||||
|
#define R820T_INIT_NB_REGS (32-5)
|
||||||
|
uint8_t r820t_read_data[R820T_READ_MAX_DATA]; /* Buffer for data read from I2C */
|
||||||
|
uint8_t r820t_state_standby = 1; /* 1=standby/power off 0=r820t initialized/power on */
|
||||||
|
|
||||||
|
/* Tuner frequency ranges
|
||||||
|
"Copyright (C) 2013 Mauro Carvalho Chehab"
|
||||||
|
https://stuff.mit.edu/afs/sipb/contrib/linux/drivers/media/tuners/r820t.c
|
||||||
|
part of freq_ranges()
|
||||||
|
*/
|
||||||
|
const struct r820t_freq_range freq_ranges[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
/* 0 MHz */
|
||||||
|
/* .open_d = */ 0x08, /* low */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0xdf, /* R27[7:0] band2,band0 */
|
||||||
|
}, {
|
||||||
|
/* 50 MHz */
|
||||||
|
/* .open_d = */ 0x08, /* low */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0xbe, /* R27[7:0] band4,band1 */
|
||||||
|
}, {
|
||||||
|
/* 55 MHz */
|
||||||
|
/* .open_d = */ 0x08, /* low */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x8b, /* R27[7:0] band7,band4 */
|
||||||
|
}, {
|
||||||
|
/* 60 MHz */
|
||||||
|
/* .open_d = */ 0x08, /* low */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x7b, /* R27[7:0] band8,band4 */
|
||||||
|
}, {
|
||||||
|
/* 65 MHz */
|
||||||
|
/* .open_d = */ 0x08, /* low */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x69, /* R27[7:0] band9,band6 */
|
||||||
|
}, {
|
||||||
|
/* 70 MHz */
|
||||||
|
/* .open_d = */ 0x08, /* low */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x58, /* R27[7:0] band10,band7 */
|
||||||
|
}, {
|
||||||
|
/* 75 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x44, /* R27[7:0] band11,band11 */
|
||||||
|
}, {
|
||||||
|
/* 80 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x44, /* R27[7:0] band11,band11 */
|
||||||
|
}, {
|
||||||
|
/* 90 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x34, /* R27[7:0] band12,band11 */
|
||||||
|
}, {
|
||||||
|
/* 100 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x34, /* R27[7:0] band12,band11 */
|
||||||
|
}, {
|
||||||
|
/* 110 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x24, /* R27[7:0] band13,band11 */
|
||||||
|
}, {
|
||||||
|
/* 120 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x24, /* R27[7:0] band13,band11 */
|
||||||
|
}, {
|
||||||
|
/* 140 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x14, /* R27[7:0] band14,band11 */
|
||||||
|
}, {
|
||||||
|
/* 180 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x13, /* R27[7:0] band14,band12 */
|
||||||
|
}, {
|
||||||
|
/* 220 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x13, /* R27[7:0] band14,band12 */
|
||||||
|
}, {
|
||||||
|
/* 250 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x11, /* R27[7:0] highest,highest */
|
||||||
|
}, {
|
||||||
|
/* 280 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
|
||||||
|
/* .tf_c = */ 0x00, /* R27[7:0] highest,highest */
|
||||||
|
}, {
|
||||||
|
/* 310 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x41, /* R26[7:6]=1 (bypass) R26[1:0]=1 (middle) */
|
||||||
|
/* .tf_c = */ 0x00, /* R27[7:0] highest,highest */
|
||||||
|
}, {
|
||||||
|
/* 450 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x41, /* R26[7:6]=1 (bypass) R26[1:0]=1 (middle) */
|
||||||
|
/* .tf_c = */ 0x00, /* R27[7:0] highest,highest */
|
||||||
|
}, {
|
||||||
|
/* 588 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x40, /* R26[7:6]=1 (bypass) R26[1:0]=0 (highest) */
|
||||||
|
/* .tf_c = */ 0x00, /* R27[7:0] highest,highest */
|
||||||
|
}, {
|
||||||
|
/* 650 MHz */
|
||||||
|
/* .open_d = */ 0x00, /* high */
|
||||||
|
/* .rf_mux_ploy = */ 0x40, /* R26[7:6]=1 (bypass) R26[1:0]=0 (highest) */
|
||||||
|
/* .tf_c = */ 0x00, /* R27[7:0] highest,highest */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FREQ_TO_IDX_SIZE (600)
|
||||||
|
const uint8_t freq_to_idx[FREQ_TO_IDX_SIZE]=
|
||||||
|
{
|
||||||
|
/* 50 */ 1,/* 51 */ 1,/* 52 */ 1,/* 53 */ 1,/* 54 */ 1,
|
||||||
|
/* 55 */ 2,/* 56 */ 2,/* 57 */ 2,/* 58 */ 2,/* 59 */ 2,
|
||||||
|
/* 60 */ 3,/* 61 */ 3,/* 62 */ 3,/* 63 */ 3,/* 64 */ 3,
|
||||||
|
/* 65 */ 4,/* 66 */ 4,/* 67 */ 4,/* 68 */ 4,/* 69 */ 4,
|
||||||
|
/* 70 */ 5,/* 71 */ 5,/* 72 */ 5,/* 73 */ 5,/* 74 */ 5,
|
||||||
|
/* 75 */ 6,/* 76 */ 6,/* 77 */ 6,/* 78 */ 6,/* 79 */ 6,
|
||||||
|
/* 80 */ 7,/* 81 */ 7,/* 82 */ 7,/* 83 */ 7,/* 84 */ 7,/* 85 */ 7,/* 86 */ 7,/* 87 */ 7,/* 88 */ 7,/* 89 */ 7,
|
||||||
|
/* 90 */ 8,/* 91 */ 8,/* 92 */ 8,/* 93 */ 8,/* 94 */ 8,/* 95 */ 8,/* 96 */ 8,/* 97 */ 8,/* 98 */ 8,/* 99 */ 8,
|
||||||
|
/* 100 */ 9,/* 101 */ 9,/* 102 */ 9,/* 103 */ 9,/* 104 */ 9,/* 105 */ 9,/* 106 */ 9,/* 107 */ 9,/* 108 */ 9,/* 109 */ 9,
|
||||||
|
/* 110 */ 10,/* 111 */ 10,/* 112 */ 10,/* 113 */ 10,/* 114 */ 10,/* 115 */ 10,/* 116 */ 10,/* 117 */ 10,/* 118 */ 10,/* 119 */ 10,
|
||||||
|
/* 120 */ 11,/* 121 */ 11,/* 122 */ 11,/* 123 */ 11,/* 124 */ 11,/* 125 */ 11,/* 126 */ 11,/* 127 */ 11,/* 128 */ 11,/* 129 */ 11,
|
||||||
|
/* 130 */ 11,/* 131 */ 11,/* 132 */ 11,/* 133 */ 11,/* 134 */ 11,/* 135 */ 11,/* 136 */ 11,/* 137 */ 11,/* 138 */ 11,/* 139 */ 11,
|
||||||
|
/* 140 */ 12,/* 141 */ 12,/* 142 */ 12,/* 143 */ 12,/* 144 */ 12,/* 145 */ 12,/* 146 */ 12,/* 147 */ 12,/* 148 */ 12,/* 149 */ 12,
|
||||||
|
/* 150 */ 12,/* 151 */ 12,/* 152 */ 12,/* 153 */ 12,/* 154 */ 12,/* 155 */ 12,/* 156 */ 12,/* 157 */ 12,/* 158 */ 12,/* 159 */ 12,
|
||||||
|
/* 160 */ 12,/* 161 */ 12,/* 162 */ 12,/* 163 */ 12,/* 164 */ 12,/* 165 */ 12,/* 166 */ 12,/* 167 */ 12,/* 168 */ 12,/* 169 */ 12,
|
||||||
|
/* 170 */ 12,/* 171 */ 12,/* 172 */ 12,/* 173 */ 12,/* 174 */ 12,/* 175 */ 12,/* 176 */ 12,/* 177 */ 12,/* 178 */ 12,/* 179 */ 12,
|
||||||
|
/* 180 */ 13,/* 181 */ 13,/* 182 */ 13,/* 183 */ 13,/* 184 */ 13,/* 185 */ 13,/* 186 */ 13,/* 187 */ 13,/* 188 */ 13,/* 189 */ 13,
|
||||||
|
/* 190 */ 13,/* 191 */ 13,/* 192 */ 13,/* 193 */ 13,/* 194 */ 13,/* 195 */ 13,/* 196 */ 13,/* 197 */ 13,/* 198 */ 13,/* 199 */ 13,
|
||||||
|
/* 200 */ 13,/* 201 */ 13,/* 202 */ 13,/* 203 */ 13,/* 204 */ 13,/* 205 */ 13,/* 206 */ 13,/* 207 */ 13,/* 208 */ 13,/* 209 */ 13,
|
||||||
|
/* 210 */ 13,/* 211 */ 13,/* 212 */ 13,/* 213 */ 13,/* 214 */ 13,/* 215 */ 13,/* 216 */ 13,/* 217 */ 13,/* 218 */ 13,/* 219 */ 13,
|
||||||
|
/* 220 */ 14,/* 221 */ 14,/* 222 */ 14,/* 223 */ 14,/* 224 */ 14,/* 225 */ 14,/* 226 */ 14,/* 227 */ 14,/* 228 */ 14,/* 229 */ 14,
|
||||||
|
/* 230 */ 14,/* 231 */ 14,/* 232 */ 14,/* 233 */ 14,/* 234 */ 14,/* 235 */ 14,/* 236 */ 14,/* 237 */ 14,/* 238 */ 14,/* 239 */ 14,
|
||||||
|
/* 240 */ 14,/* 241 */ 14,/* 242 */ 14,/* 243 */ 14,/* 244 */ 14,/* 245 */ 14,/* 246 */ 14,/* 247 */ 14,/* 248 */ 14,/* 249 */ 14,
|
||||||
|
/* 250 */ 15,/* 251 */ 15,/* 252 */ 15,/* 253 */ 15,/* 254 */ 15,/* 255 */ 15,/* 256 */ 15,/* 257 */ 15,/* 258 */ 15,/* 259 */ 15,
|
||||||
|
/* 260 */ 15,/* 261 */ 15,/* 262 */ 15,/* 263 */ 15,/* 264 */ 15,/* 265 */ 15,/* 266 */ 15,/* 267 */ 15,/* 268 */ 15,/* 269 */ 15,
|
||||||
|
/* 270 */ 15,/* 271 */ 15,/* 272 */ 15,/* 273 */ 15,/* 274 */ 15,/* 275 */ 15,/* 276 */ 15,/* 277 */ 15,/* 278 */ 15,/* 279 */ 15,
|
||||||
|
/* 280 */ 16,/* 281 */ 16,/* 282 */ 16,/* 283 */ 16,/* 284 */ 16,/* 285 */ 16,/* 286 */ 16,/* 287 */ 16,/* 288 */ 16,/* 289 */ 16,
|
||||||
|
/* 290 */ 16,/* 291 */ 16,/* 292 */ 16,/* 293 */ 16,/* 294 */ 16,/* 295 */ 16,/* 296 */ 16,/* 297 */ 16,/* 298 */ 16,/* 299 */ 16,
|
||||||
|
/* 300 */ 16,/* 301 */ 16,/* 302 */ 16,/* 303 */ 16,/* 304 */ 16,/* 305 */ 16,/* 306 */ 16,/* 307 */ 16,/* 308 */ 16,/* 309 */ 16,
|
||||||
|
/* 310 */ 17,/* 311 */ 17,/* 312 */ 17,/* 313 */ 17,/* 314 */ 17,/* 315 */ 17,/* 316 */ 17,/* 317 */ 17,/* 318 */ 17,/* 319 */ 17,
|
||||||
|
/* 320 */ 17,/* 321 */ 17,/* 322 */ 17,/* 323 */ 17,/* 324 */ 17,/* 325 */ 17,/* 326 */ 17,/* 327 */ 17,/* 328 */ 17,/* 329 */ 17,
|
||||||
|
/* 330 */ 17,/* 331 */ 17,/* 332 */ 17,/* 333 */ 17,/* 334 */ 17,/* 335 */ 17,/* 336 */ 17,/* 337 */ 17,/* 338 */ 17,/* 339 */ 17,
|
||||||
|
/* 340 */ 17,/* 341 */ 17,/* 342 */ 17,/* 343 */ 17,/* 344 */ 17,/* 345 */ 17,/* 346 */ 17,/* 347 */ 17,/* 348 */ 17,/* 349 */ 17,
|
||||||
|
/* 350 */ 17,/* 351 */ 17,/* 352 */ 17,/* 353 */ 17,/* 354 */ 17,/* 355 */ 17,/* 356 */ 17,/* 357 */ 17,/* 358 */ 17,/* 359 */ 17,
|
||||||
|
/* 360 */ 17,/* 361 */ 17,/* 362 */ 17,/* 363 */ 17,/* 364 */ 17,/* 365 */ 17,/* 366 */ 17,/* 367 */ 17,/* 368 */ 17,/* 369 */ 17,
|
||||||
|
/* 370 */ 17,/* 371 */ 17,/* 372 */ 17,/* 373 */ 17,/* 374 */ 17,/* 375 */ 17,/* 376 */ 17,/* 377 */ 17,/* 378 */ 17,/* 379 */ 17,
|
||||||
|
/* 380 */ 17,/* 381 */ 17,/* 382 */ 17,/* 383 */ 17,/* 384 */ 17,/* 385 */ 17,/* 386 */ 17,/* 387 */ 17,/* 388 */ 17,/* 389 */ 17,
|
||||||
|
/* 390 */ 17,/* 391 */ 17,/* 392 */ 17,/* 393 */ 17,/* 394 */ 17,/* 395 */ 17,/* 396 */ 17,/* 397 */ 17,/* 398 */ 17,/* 399 */ 17,
|
||||||
|
/* 400 */ 17,/* 401 */ 17,/* 402 */ 17,/* 403 */ 17,/* 404 */ 17,/* 405 */ 17,/* 406 */ 17,/* 407 */ 17,/* 408 */ 17,/* 409 */ 17,
|
||||||
|
/* 410 */ 17,/* 411 */ 17,/* 412 */ 17,/* 413 */ 17,/* 414 */ 17,/* 415 */ 17,/* 416 */ 17,/* 417 */ 17,/* 418 */ 17,/* 419 */ 17,
|
||||||
|
/* 420 */ 17,/* 421 */ 17,/* 422 */ 17,/* 423 */ 17,/* 424 */ 17,/* 425 */ 17,/* 426 */ 17,/* 427 */ 17,/* 428 */ 17,/* 429 */ 17,
|
||||||
|
/* 430 */ 17,/* 431 */ 17,/* 432 */ 17,/* 433 */ 17,/* 434 */ 17,/* 435 */ 17,/* 436 */ 17,/* 437 */ 17,/* 438 */ 17,/* 439 */ 17,
|
||||||
|
/* 440 */ 17,/* 441 */ 17,/* 442 */ 17,/* 443 */ 17,/* 444 */ 17,/* 445 */ 17,/* 446 */ 17,/* 447 */ 17,/* 448 */ 17,/* 449 */ 17,
|
||||||
|
/* 450 */ 18,/* 451 */ 18,/* 452 */ 18,/* 453 */ 18,/* 454 */ 18,/* 455 */ 18,/* 456 */ 18,/* 457 */ 18,/* 458 */ 18,/* 459 */ 18,
|
||||||
|
/* 460 */ 18,/* 461 */ 18,/* 462 */ 18,/* 463 */ 18,/* 464 */ 18,/* 465 */ 18,/* 466 */ 18,/* 467 */ 18,/* 468 */ 18,/* 469 */ 18,
|
||||||
|
/* 470 */ 18,/* 471 */ 18,/* 472 */ 18,/* 473 */ 18,/* 474 */ 18,/* 475 */ 18,/* 476 */ 18,/* 477 */ 18,/* 478 */ 18,/* 479 */ 18,
|
||||||
|
/* 480 */ 18,/* 481 */ 18,/* 482 */ 18,/* 483 */ 18,/* 484 */ 18,/* 485 */ 18,/* 486 */ 18,/* 487 */ 18,/* 488 */ 18,/* 489 */ 18,
|
||||||
|
/* 490 */ 18,/* 491 */ 18,/* 492 */ 18,/* 493 */ 18,/* 494 */ 18,/* 495 */ 18,/* 496 */ 18,/* 497 */ 18,/* 498 */ 18,/* 499 */ 18,
|
||||||
|
/* 500 */ 18,/* 501 */ 18,/* 502 */ 18,/* 503 */ 18,/* 504 */ 18,/* 505 */ 18,/* 506 */ 18,/* 507 */ 18,/* 508 */ 18,/* 509 */ 18,
|
||||||
|
/* 510 */ 18,/* 511 */ 18,/* 512 */ 18,/* 513 */ 18,/* 514 */ 18,/* 515 */ 18,/* 516 */ 18,/* 517 */ 18,/* 518 */ 18,/* 519 */ 18,
|
||||||
|
/* 520 */ 18,/* 521 */ 18,/* 522 */ 18,/* 523 */ 18,/* 524 */ 18,/* 525 */ 18,/* 526 */ 18,/* 527 */ 18,/* 528 */ 18,/* 529 */ 18,
|
||||||
|
/* 530 */ 18,/* 531 */ 18,/* 532 */ 18,/* 533 */ 18,/* 534 */ 18,/* 535 */ 18,/* 536 */ 18,/* 537 */ 18,/* 538 */ 18,/* 539 */ 18,
|
||||||
|
/* 540 */ 18,/* 541 */ 18,/* 542 */ 18,/* 543 */ 18,/* 544 */ 18,/* 545 */ 18,/* 546 */ 18,/* 547 */ 18,/* 548 */ 18,/* 549 */ 18,
|
||||||
|
/* 550 */ 18,/* 551 */ 18,/* 552 */ 18,/* 553 */ 18,/* 554 */ 18,/* 555 */ 18,/* 556 */ 18,/* 557 */ 18,/* 558 */ 18,/* 559 */ 18,
|
||||||
|
/* 560 */ 18,/* 561 */ 18,/* 562 */ 18,/* 563 */ 18,/* 564 */ 18,/* 565 */ 18,/* 566 */ 18,/* 567 */ 18,/* 568 */ 18,/* 569 */ 18,
|
||||||
|
/* 570 */ 18,/* 571 */ 18,/* 572 */ 18,/* 573 */ 18,/* 574 */ 18,/* 575 */ 18,/* 576 */ 18,/* 577 */ 18,/* 578 */ 18,/* 579 */ 18,
|
||||||
|
/* 580 */ 18,/* 581 */ 18,/* 582 */ 18,/* 583 */ 18,/* 584 */ 18,/* 585 */ 18,/* 586 */ 18,/* 587 */ 18,
|
||||||
|
/* 588 */ 19,/* 589 */ 19,/* 590 */ 19,/* 591 */ 19,/* 592 */ 19,/* 593 */ 19,/* 594 */ 19,/* 595 */ 19,/* 596 */ 19,/* 597 */ 19,
|
||||||
|
/* 598 */ 19,/* 599 */ 19,/* 600 */ 19,/* 601 */ 19,/* 602 */ 19,/* 603 */ 19,/* 604 */ 19,/* 605 */ 19,/* 606 */ 19,/* 607 */ 19,
|
||||||
|
/* 608 */ 19,/* 609 */ 19,/* 610 */ 19,/* 611 */ 19,/* 612 */ 19,/* 613 */ 19,/* 614 */ 19,/* 615 */ 19,/* 616 */ 19,/* 617 */ 19,
|
||||||
|
/* 618 */ 19,/* 619 */ 19,/* 620 */ 19,/* 621 */ 19,/* 622 */ 19,/* 623 */ 19,/* 624 */ 19,/* 625 */ 19,/* 626 */ 19,/* 627 */ 19,
|
||||||
|
/* 628 */ 19,/* 629 */ 19,/* 630 */ 19,/* 631 */ 19,/* 632 */ 19,/* 633 */ 19,/* 634 */ 19,/* 635 */ 19,/* 636 */ 19,/* 637 */ 19,
|
||||||
|
/* 638 */ 19,/* 639 */ 19,/* 640 */ 19,/* 641 */ 19,/* 642 */ 19,/* 643 */ 19,/* 644 */ 19,/* 645 */ 19,/* 646 */ 19,/* 647 */ 19,
|
||||||
|
/* 648 */ 19,/* 649 */ 19
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FREQ_50MHZ (50)
|
||||||
|
#define FREQ_TO_IDX_0_TO_49MHZ (0)
|
||||||
|
#define FREQ_TO_IDX_650_TO_1800MHZ (20)
|
||||||
|
|
||||||
|
int r820t_freq_get_idx(uint32_t freq_mhz)
|
||||||
|
{
|
||||||
|
uint32_t freq_mhz_fix;
|
||||||
|
|
||||||
|
if(freq_mhz < FREQ_50MHZ)
|
||||||
|
{
|
||||||
|
/* Frequency Less than 50MHz */
|
||||||
|
return FREQ_TO_IDX_0_TO_49MHZ;
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
/* Frequency Between 50 to 649MHz use table */
|
||||||
|
/* Fix the frequency for the table */
|
||||||
|
freq_mhz_fix = freq_mhz - FREQ_50MHZ;
|
||||||
|
if(freq_mhz_fix < FREQ_TO_IDX_SIZE)
|
||||||
|
{
|
||||||
|
|
||||||
|
return freq_to_idx[freq_mhz_fix];
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
/* Frequency Between 650 to 1800MHz */
|
||||||
|
return FREQ_TO_IDX_650_TO_1800MHZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool r820t_is_power_enabled(void)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write regs 5 to 32 (R820T_INIT_NB_REGS values) using data parameter and write last reg to 0
|
||||||
|
*/
|
||||||
|
void airspy_r820t_write_init(r820t_priv_t *priv, const uint8_t* data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < R820T_INIT_NB_REGS; i++) {
|
||||||
|
priv->write_reg(i+REG_SHADOW_START, data[i], priv->ctx);
|
||||||
|
}
|
||||||
|
priv->write_reg(0x1F, 0, priv->ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read from one or more contiguous registers. data[0] should be the first
|
||||||
|
* register number, one or more values follow.
|
||||||
|
*/
|
||||||
|
const uint8_t lut[16] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
|
||||||
|
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };
|
||||||
|
|
||||||
|
static uint8_t r82xx_bitrev(uint8_t byte)
|
||||||
|
{
|
||||||
|
return (lut[byte & 0xf] << 4) | lut[byte >> 4];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int r820t_write_reg(r820t_priv_t *priv, uint8_t reg, uint8_t val)
|
||||||
|
{
|
||||||
|
if (r820t_read_cache_reg(priv, reg) == val)
|
||||||
|
return 0;
|
||||||
|
priv->write_reg(reg, val, priv->ctx);
|
||||||
|
priv->regs[reg - REG_SHADOW_START] = val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int r820t_read_cache_reg(r820t_priv_t *priv, int reg)
|
||||||
|
{
|
||||||
|
reg -= REG_SHADOW_START;
|
||||||
|
|
||||||
|
if (reg >= 0 && reg < NUM_REGS)
|
||||||
|
return priv->regs[reg];
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int r820t_write_reg_mask(r820t_priv_t *priv, uint8_t reg, uint8_t val, uint8_t bit_mask)
|
||||||
|
{
|
||||||
|
int rc = r820t_read_cache_reg(priv, reg);
|
||||||
|
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
val = (rc & ~bit_mask) | (val & bit_mask);
|
||||||
|
|
||||||
|
return r820t_write_reg(priv, reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int r820t_read(r820t_priv_t *priv, uint8_t *val, int len)
|
||||||
|
{
|
||||||
|
/* reg not used and assumed to be always 0 because start from reg0 to reg0+len */
|
||||||
|
priv->read_reg(val, len, priv->ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* r820t tuning logic
|
||||||
|
*/
|
||||||
|
#ifdef OPTIM_SET_MUX
|
||||||
|
int r820t_set_mux_freq_idx = -1; /* Default set to invalid value in order to force set_mux */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
"inspired by Mauro Carvalho Chehab set_mux technique"
|
||||||
|
https://stuff.mit.edu/afs/sipb/contrib/linux/drivers/media/tuners/r820t.c
|
||||||
|
part of r820t_set_mux() (set tracking filter)
|
||||||
|
*/
|
||||||
|
static int r820t_set_tf(r820t_priv_t *priv, uint32_t freq)
|
||||||
|
{
|
||||||
|
const struct r820t_freq_range *range;
|
||||||
|
int freq_idx;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
/* Get the proper frequency range in MHz instead of Hz */
|
||||||
|
/* Fast divide freq by 1000000 */
|
||||||
|
freq = (uint32_t)((uint64_t)freq * 4295 >> 32);
|
||||||
|
|
||||||
|
freq_idx = r820t_freq_get_idx(freq);
|
||||||
|
range = &freq_ranges[freq_idx];
|
||||||
|
|
||||||
|
/* Only reconfigure mux freq if modified vs previous range */
|
||||||
|
#ifdef OPTIM_SET_MUX
|
||||||
|
if(freq_idx != r820t_set_mux_freq_idx)
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
/* Open Drain */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x17, range->open_d, 0x08);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* RF_MUX,Polymux */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x1a, range->rf_mux_ploy, 0xc3);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* TF BAND */
|
||||||
|
rc = r820t_write_reg(priv, 0x1b, range->tf_c);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* XTAL CAP & Drive */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x10, 0x08, 0x0b);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x08, 0x00, 0x3f);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x09, 0x00, 0x3f);
|
||||||
|
#ifdef OPTIM_SET_MUX
|
||||||
|
}
|
||||||
|
r820t_set_mux_freq_idx = freq_idx;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_set_pll(r820t_priv_t *priv, uint32_t freq)
|
||||||
|
{
|
||||||
|
const uint32_t vco_min = 1770000000;
|
||||||
|
const uint32_t vco_max = 3900000000;
|
||||||
|
uint32_t ref = priv->xtal_freq >> 1;
|
||||||
|
|
||||||
|
int rc;
|
||||||
|
uint32_t div_num;
|
||||||
|
uint32_t vco;
|
||||||
|
uint32_t rem;
|
||||||
|
uint32_t mask;
|
||||||
|
uint16_t sdm;
|
||||||
|
uint8_t nint;
|
||||||
|
uint8_t ni;
|
||||||
|
uint8_t si;
|
||||||
|
uint8_t div_found;
|
||||||
|
|
||||||
|
/* Find a suitable divider */
|
||||||
|
div_found = 0;
|
||||||
|
for (div_num = 0; div_num <= 5; div_num++)
|
||||||
|
{
|
||||||
|
vco = freq << (div_num + 1);
|
||||||
|
if (vco >= vco_min && vco <= vco_max)
|
||||||
|
{
|
||||||
|
div_found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!div_found)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
vco += ref >> 16;
|
||||||
|
ref <<= 8;
|
||||||
|
mask = 1 << 23;
|
||||||
|
rem = 0;
|
||||||
|
while (mask > 0 && vco > 0)
|
||||||
|
{
|
||||||
|
if (vco >= ref)
|
||||||
|
{
|
||||||
|
rem |= mask;
|
||||||
|
vco -= ref;
|
||||||
|
}
|
||||||
|
ref >>= 1;
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nint = rem >> 16;
|
||||||
|
sdm = rem & 0xffff;
|
||||||
|
|
||||||
|
nint -= 13;
|
||||||
|
ni = nint >> 2;
|
||||||
|
si = nint & 3;
|
||||||
|
|
||||||
|
/* Set the phase splitter */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x10, (uint8_t) (div_num << 5), 0xe0);
|
||||||
|
if(rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Set the integer part of the PLL */
|
||||||
|
rc = r820t_write_reg(priv, 0x14, (uint8_t) (ni + (si << 6)));
|
||||||
|
if(rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (sdm == 0)
|
||||||
|
{
|
||||||
|
/* Disable SDM */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x12, 0x08, 0x08);
|
||||||
|
if(rc < 0)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Write SDM */
|
||||||
|
rc = r820t_write_reg(priv, 0x15, (uint8_t)(sdm & 0xff));
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = r820t_write_reg(priv, 0x16, (uint8_t)(sdm >> 8));
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Enable SDM */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x12, 0x00, 0x08);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_set_freq(r820t_priv_t *priv, uint32_t freq)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
uint32_t lo_freq = freq + priv->if_freq;
|
||||||
|
|
||||||
|
rc = r820t_set_tf(priv, freq);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = r820t_set_pll(priv, lo_freq);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
priv->freq = freq;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_set_lna_gain(r820t_priv_t *priv, uint8_t gain_index)
|
||||||
|
{
|
||||||
|
return r820t_write_reg_mask(priv, 0x05, gain_index, 0x0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_set_mixer_gain(r820t_priv_t *priv, uint8_t gain_index)
|
||||||
|
{
|
||||||
|
return r820t_write_reg_mask(priv, 0x07, gain_index, 0x0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_set_vga_gain(r820t_priv_t *priv, uint8_t gain_index)
|
||||||
|
{
|
||||||
|
return r820t_write_reg_mask(priv, 0x0c, gain_index, 0x0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_set_lna_agc(r820t_priv_t *priv, uint8_t value)
|
||||||
|
{
|
||||||
|
value = value != 0 ? 0x00 : 0x10;
|
||||||
|
return r820t_write_reg_mask(priv, 0x05, value, 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_set_mixer_agc(r820t_priv_t *priv, uint8_t value)
|
||||||
|
{
|
||||||
|
value = value != 0 ? 0x10 : 0x00;
|
||||||
|
return r820t_write_reg_mask(priv, 0x07, value, 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
"inspired by Mauro Carvalho Chehab calibration technique"
|
||||||
|
https://stuff.mit.edu/afs/sipb/contrib/linux/drivers/media/tuners/r820t.c
|
||||||
|
part of r820t_set_tv_standard()
|
||||||
|
*/
|
||||||
|
int r820t_calibrate(r820t_priv_t *priv)
|
||||||
|
{
|
||||||
|
int i, rc, cal_code;
|
||||||
|
uint8_t data[5];
|
||||||
|
|
||||||
|
for (i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
/* Set filt_cap */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x0b, 0x08, 0x60);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* set cali clk =on */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x0f, 0x04, 0x04);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* X'tal cap 0pF for PLL */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x10, 0x00, 0x03);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = r820t_set_pll(priv, CALIBRATION_LO * 1000);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Start Trigger */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x0b, 0x10, 0x10);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
|
||||||
|
/* Stop Trigger */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x0b, 0x00, 0x10);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* set cali clk =off */
|
||||||
|
rc = r820t_write_reg_mask(priv, 0x0f, 0x00, 0x04);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Check if calibration worked */
|
||||||
|
rc = r820t_read(priv, data, sizeof(data));
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
cal_code = data[4] & 0x0f;
|
||||||
|
if (cal_code && cal_code != 0x0f)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r820t_init(r820t_priv_t *priv, const uint32_t if_freq, r820t_write_reg_f write_reg, r820t_read_f read_reg, void* ctx)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
uint32_t saved_freq;
|
||||||
|
|
||||||
|
r820t_state_standby = 0;
|
||||||
|
priv->if_freq = if_freq;
|
||||||
|
priv->write_reg = write_reg;
|
||||||
|
priv->read_reg = read_reg;
|
||||||
|
priv->ctx = ctx;
|
||||||
|
/* Initialize registers */
|
||||||
|
airspy_r820t_write_init(priv, priv->regs);
|
||||||
|
|
||||||
|
r820t_set_freq(priv, priv->freq);
|
||||||
|
|
||||||
|
/* Calibrate the IF filter */
|
||||||
|
saved_freq = priv->freq;
|
||||||
|
rc = r820t_calibrate(priv);
|
||||||
|
priv->freq = saved_freq;
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
saved_freq = priv->freq;
|
||||||
|
r820t_calibrate(priv);
|
||||||
|
priv->freq = saved_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore freq as it has been modified by r820t_calibrate() */
|
||||||
|
rc = r820t_set_freq(priv, priv->freq);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void r820t_set_if_bandwidth(r820t_priv_t *priv, uint8_t bw)
|
||||||
|
{
|
||||||
|
const uint8_t modes[] = { 0xE0, 0x80, 0x60, 0x00 };
|
||||||
|
const uint8_t opt[] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
|
||||||
|
uint8_t a = 0xB0 | opt[bw & 0x0F];
|
||||||
|
uint8_t b = 0x0F | modes[bw >> 4];
|
||||||
|
r820t_write_reg(priv, 0x0A, a);
|
||||||
|
r820t_write_reg(priv, 0x0B, b);
|
||||||
|
}
|
58
source_modules/badgesdr_source/src/r820t.h
Normal file
58
source_modules/badgesdr_source/src/r820t.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013-2016 Benjamin Vernoux <bvernoux@airspy.com>
|
||||||
|
*
|
||||||
|
* This file is part of AirSpy.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define REG_SHADOW_START 5
|
||||||
|
#define NUM_REGS 30
|
||||||
|
|
||||||
|
/* R820T Clock */
|
||||||
|
#define CALIBRATION_LO 88000
|
||||||
|
|
||||||
|
typedef void (*r820t_write_reg_f)(uint8_t reg, uint8_t value, void* ctx);
|
||||||
|
typedef void (*r820t_read_f)(uint8_t* data, int len, void* ctx);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t xtal_freq; /* XTAL_FREQ_HZ */
|
||||||
|
uint32_t freq;
|
||||||
|
uint32_t if_freq;
|
||||||
|
uint8_t regs[NUM_REGS];
|
||||||
|
uint16_t padding;
|
||||||
|
|
||||||
|
r820t_write_reg_f write_reg;
|
||||||
|
r820t_read_f read_reg;
|
||||||
|
void* ctx;
|
||||||
|
|
||||||
|
} r820t_priv_t;
|
||||||
|
|
||||||
|
void airspy_r820t_write_single(r820t_priv_t *priv, uint8_t reg, uint8_t val);
|
||||||
|
uint8_t airspy_r820t_read_single(r820t_priv_t *priv, uint8_t reg);
|
||||||
|
|
||||||
|
int r820t_init(r820t_priv_t *priv, const uint32_t if_freq, r820t_write_reg_f write_reg, r820t_read_f read_reg, void* ctx);
|
||||||
|
int r820t_set_freq(r820t_priv_t *priv, uint32_t freq);
|
||||||
|
int r820t_set_lna_gain(r820t_priv_t *priv, uint8_t gain_index);
|
||||||
|
int r820t_set_mixer_gain(r820t_priv_t *priv, uint8_t gain_index);
|
||||||
|
int r820t_set_vga_gain(r820t_priv_t *priv, uint8_t gain_index);
|
||||||
|
int r820t_set_lna_agc(r820t_priv_t *priv, uint8_t value);
|
||||||
|
int r820t_set_mixer_agc(r820t_priv_t *priv, uint8_t value);
|
||||||
|
void r820t_set_if_bandwidth(r820t_priv_t *priv, uint8_t bw);
|
@ -33,10 +33,13 @@ public:
|
|||||||
SpectranSourceModule(std::string name) {
|
SpectranSourceModule(std::string name) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
|
|
||||||
if (AARTSAAPI_Init(AARTSAAPI_MEMORY_MEDIUM) != AARTSAAPI_OK) {
|
AARTSAAPI_Result res;
|
||||||
|
if ((res = AARTSAAPI_Init(AARTSAAPI_MEMORY_MEDIUM)) != AARTSAAPI_OK) {
|
||||||
|
flog::error("Failed to initialize the RTSAAPI: {}", (uint32_t)res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (AARTSAAPI_Open(&api) != AARTSAAPI_OK) {
|
if ((res = AARTSAAPI_Open(&api)) != AARTSAAPI_OK) {
|
||||||
|
flog::error("Failed to open the RTSAAPI: {}", (uint32_t)res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,13 +455,16 @@ private:
|
|||||||
|
|
||||||
void updateRef() {
|
void updateRef() {
|
||||||
// Get and update bounds
|
// Get and update bounds
|
||||||
AARTSAAPI_Config config;
|
AARTSAAPI_Config config = {};
|
||||||
AARTSAAPI_ConfigInfo refInfo;
|
AARTSAAPI_ConfigInfo refInfo = {};
|
||||||
AARTSAAPI_ConfigFind(&dev, &croot, &config, L"main/reflevel");
|
auto res = AARTSAAPI_ConfigFind(&dev, &croot, &config, L"main/reflevel");
|
||||||
AARTSAAPI_ConfigGetInfo(&dev, &config, &refInfo);
|
flog::debug("Res A: {}", res);
|
||||||
|
res = AARTSAAPI_ConfigGetInfo(&dev, &config, &refInfo);
|
||||||
|
flog::debug("Res B: {}", res);
|
||||||
minRef = refInfo.minValue;
|
minRef = refInfo.minValue;
|
||||||
maxRef = refInfo.maxValue;
|
maxRef = refInfo.maxValue;
|
||||||
refStep = refInfo.stepValue;
|
refStep = refInfo.stepValue;
|
||||||
|
flog::debug("Gain: {} -> {}", refInfo.minValue, refInfo.maxValue);
|
||||||
refLevel = std::clamp<float>(refLevel, minRef, maxRef);
|
refLevel = std::clamp<float>(refLevel, minRef, maxRef);
|
||||||
|
|
||||||
// Apply new ref level
|
// Apply new ref level
|
||||||
|
Loading…
Reference in New Issue
Block a user