RadioberrySoapySDR

pull/6/head
pa3gsb 2020-03-31 15:22:10 +02:00
rodzic b672443d96
commit 46d29375b8
8 zmienionych plików z 595 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,43 @@
########################################################################
# Project setup -- only needed if device support is a stand-alone build
# We recommend that the support module be built in-tree with the driver.
########################################################################
cmake_minimum_required(VERSION 2.8.9)
project(SoapyRadioberrySupport CXX)
enable_testing()
#select the release build type by default to get optimization flags
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
message(STATUS "Build type not specified: defaulting to release.")
endif(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "")
########################################################################
# Header and library resources needed to communicate with the device.
# These may be found within the build tree or in an external project.
########################################################################
#set(MY_DEVICE_INCLUDE_DIRS ...)
#set(MY_DEVICE_LIBRARIES ...)
########################################################################
# build the module
########################################################################
find_package(SoapySDR CONFIG)
if (NOT SoapySDR_FOUND)
message(WARNING "SoapySDR development files not found - skipping support")
return()
endif ()
#include_directories(${MY_DEVICE_INCLUDE_DIRS})
SOAPY_SDR_MODULE_UTIL(
TARGET SoapyRadioberrySDR
SOURCES
SoapyRadioberry.cpp
SoapyRadioberrySettings.cpp
SoapyRadioberryStreaming.cpp
radioberry_ioctl.h
)
#LIBRARIES ${MY_DEVICE_LIBRARIES}

Wyświetl plik

@ -0,0 +1,21 @@
# Soapy SDR module for Radioberry SDR
## Installation instructions
```
git clone <>
cd <sub folder>
mkdir build
cd build
cmake ..
make
sudo make install
```
## Dependencies
Need the radioberry device driver.
## Documentation
Initial version supporting RX.

Wyświetl plik

@ -0,0 +1,34 @@
#include <SoapySDR/Device.hpp>
#include <SoapySDR/Registry.hpp>
#include "SoapyRadioberry.hpp"
/***********************************************************************
* Find available devices
**********************************************************************/
SoapySDR::KwargsList findMyRadioberry(const SoapySDR::Kwargs &args)
{
SoapySDR::Kwargs options;
static std::vector<SoapySDR::Kwargs> results;
options["driver"] = "radioberry";
results.push_back(options);
return results;
}
/***********************************************************************
* Make device instance
**********************************************************************/
SoapySDR::Device *makeMyRadioberry(const SoapySDR::Kwargs &args)
{
return new SoapyRadioberry(args);
}
/***********************************************************************
* Registration
**********************************************************************/
static SoapySDR::Registry registerRadioberry("radioberry", &findMyRadioberry, &makeMyRadioberry, SOAPY_SDR_ABI_VERSION);

Wyświetl plik

@ -0,0 +1,134 @@
#include <SoapySDR/Device.hpp>
#include <SoapySDR/Logger.hpp>
#include <SoapySDR/Formats.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "radioberry_ioctl.h"
class SoapyRadioberry : public SoapySDR::Device{
public:
SoapyRadioberry( const SoapySDR::Kwargs & args );
~SoapyRadioberry();
/*******************************************************************
* Identification API
******************************************************************/
std::string getDriverKey( void ) const;
std::string getHardwareKey( void ) const;
SoapySDR::Kwargs getHardwareInfo( void ) const;
/*******************************************************************
* Channels API
******************************************************************/
size_t getNumChannels( const int direction ) const;
bool getFullDuplex( const int direction, const size_t channel ) const;
/*******************************************************************
* Stream API
******************************************************************/
SoapySDR::RangeList getSampleRateRange(const int direction, const size_t channel) const;
std::vector<std::string> getStreamFormats(const int direction, const size_t channel) const;
std::string getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const;
SoapySDR::ArgInfoList getStreamArgsInfo(const int direction, const size_t channel) const;
SoapySDR::Stream *setupStream(
const int direction,
const std::string &format,
const std::vector<size_t> &channels = std::vector<size_t>(),
const SoapySDR::Kwargs &args = SoapySDR::Kwargs() );
int readStream(
SoapySDR::Stream *stream,
void * const *buffs,
const size_t numElems,
int &flags,
long long &timeNs,
const long timeoutUs = 100000 );
/*
int writeStream(
SoapySDR::Stream *stream,
const void * const *buffs,
const size_t numElems,
int &flags,
const long long timeNs = 0,
const long timeoutUs = 100000);
*/
/*******************************************************************
* Sample Rate API
******************************************************************/
void setSampleRate( const int direction, const size_t channel, const double rate );
double getBandwidth( const int direction, const size_t channel ) const;
std::vector<double> listBandwidths( const int direction, const size_t channel ) const;
/*******************************************************************
* Frequency API
******************************************************************/
void setFrequency(
const int direction,
const size_t channel,
const double frequency,
const SoapySDR::Kwargs &args = SoapySDR::Kwargs());
SoapySDR::RangeList getFrequencyRange( const int direction, const size_t channel) const;
/*******************************************************************
* Antenna API
******************************************************************/
std::vector<std::string> listAntennas( const int direction, const size_t channel ) const;
/*******************************************************************
* Gain API
******************************************************************/
std::vector<std::string> listGains( const int direction, const size_t channel ) const;
void setGain( const int direction, const size_t channel, const double value );
SoapySDR::Range getGainRange( const int direction, const size_t channel, const std::string &name ) const;
void controlRadioberry(uint32_t command, uint32_t command_data);
private:
int fd_rb;
int sample_rate;
int rx_frequency;
struct rb_info_arg_t rb_control;
};

Wyświetl plik

@ -0,0 +1,222 @@
#include "SoapyRadioberry.hpp"
/***********************************************************************
* Device interface
**********************************************************************/
SoapyRadioberry::SoapyRadioberry( const SoapySDR::Kwargs &args ){
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::SoapyRadioberry constructor called");
fd_rb = open("/dev/radioberry", O_RDWR);
}
SoapyRadioberry::~SoapyRadioberry(void){
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::SoapyRadioberry destructor called");
if (fd_rb != 0) close(fd_rb);
}
void SoapyRadioberry::controlRadioberry(uint32_t command, uint32_t command_data) {
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::controlRadioberry called");
uint32_t CWX =0;
uint32_t running = 1;
rb_control.rb_command = (((CWX << 1) & 0x02) | (running & 0x01));
rb_control.command = command;
rb_control.command_data = command_data;
fprintf(stderr, "Command = %02X command_data = %08X\n", command, command_data);
if (ioctl(fd_rb, RADIOBERRY_IOC_COMMAND, &rb_control) == -1) {
SoapySDR_log(SOAPY_SDR_INFO, "Could not sent command to radioberry device.");
} else SoapySDR_log(SOAPY_SDR_INFO, "Command sent succesfull to radioberry device.");
}
std::string SoapyRadioberry::getDriverKey( void ) const
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::getDriverKey called");
return "radioberry";
}
std::string SoapyRadioberry::getHardwareKey( void ) const
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::getHardwareKey called");
return "v2.0-beta4";
}
SoapySDR::Kwargs SoapyRadioberry::getHardwareInfo( void ) const
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::getHardwareInfo called");
SoapySDR::Kwargs info;
struct rb_info_arg_t rb_info;
if (ioctl(fd_rb, RADIOBERRY_IOC_COMMAND, &rb_info) == -1) {
rb_info.major = 0;
rb_info.minor = 0;
}
unsigned int major, minor;
major = rb_info.major;
minor = rb_info.minor;
char firmware_version[100];
snprintf(firmware_version, 100, "%u.%u", 0, 1); //0.1
info["firmwareVersion"] = firmware_version;
char gateware_version[100];
snprintf(gateware_version, 100, "%u.%u ", major, minor);
info["gatewareVersion"] = gateware_version;
char hardware_version[100];
snprintf(hardware_version, 100, "%u.%u", 2, 4); //2.4 beta
info["hardwareVersion"] = hardware_version;
char protocol_version[100];
snprintf(protocol_version, 100, "%u.%u ", 1, 58); //1.58 protocol 1
info["protocolVersion"] = protocol_version;
return info;
}
size_t SoapyRadioberry::getNumChannels( const int direction ) const
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::getNumChannels called");
//if (direction == SOAPY_SDR_RX) return(4);
return(1); //1 RX and 1 TX channel; making this for standalone radioberry!
}
bool SoapyRadioberry::getFullDuplex( const int direction, const size_t channel ) const
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::getFullDuplex called");
return(true);
}
std::vector<double> SoapyRadioberry::listBandwidths( const int direction, const size_t channel ) const
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::listBandwidths called");
std::vector<double> options;
if (direction == SOAPY_SDR_RX) {
options.push_back(0.048e6);
options.push_back(0.096e6);
options.push_back(0.192e6);
}
if (direction == SOAPY_SDR_TX) {
options.push_back(0.048e6);
}
return(options);
}
double SoapyRadioberry::getBandwidth( const int direction, const size_t channel ) const
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::getBandwidth called");
long long bandwidth = 48000.0;
if(direction==SOAPY_SDR_RX){
//depends on settings.. TODO
}
else if(direction==SOAPY_SDR_TX){
bandwidth = 48000.0;
}
return double(bandwidth);
}
SoapySDR::RangeList SoapyRadioberry::getFrequencyRange( const int direction, const size_t channel) const
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::getFrequencyRange called");
SoapySDR::RangeList rangeList;
rangeList.push_back(SoapySDR::Range(10000.0, 30000000.0, 1.0));
return rangeList;
}
std::vector<std::string> SoapyRadioberry::listAntennas( const int direction, const size_t channel ) const
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::listAntennas called");
std::vector<std::string> options;
if(direction == SOAPY_SDR_RX) options.push_back( "ANTENNA RX" );
if(direction == SOAPY_SDR_TX) options.push_back( "ANTENNA TX" );
return(options);
}
/*******************************************************************
* Gain API
******************************************************************/
std::vector<std::string> SoapyRadioberry::listGains( const int direction, const size_t channel ) const
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::listGains called");
std::vector<std::string> options;
//options.push_back("PGA"); in pihpsdr no additional gain settings.
return(options);
}
SoapySDR::Range SoapyRadioberry::getGainRange( const int direction, const size_t channel, const std::string &name ) const
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::getGainRange called");
if(direction==SOAPY_SDR_RX)
return(SoapySDR::Range(0, 60));
return(SoapySDR::Range(0,18));
}
void SoapyRadioberry::setGain( const int direction, const size_t channel, const double value ) {
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::setGain called");
uint32_t command = 0;
uint32_t command_data = 0x40100000 + (0x40 | (((uint32_t) (value + 12.0)) & 0x3F));
if(direction==SOAPY_SDR_RX) command = 0x14;
if(direction==SOAPY_SDR_TX) { command = 2; }
this->SoapyRadioberry::controlRadioberry(command, command_data);
}
/*******************************************************************
* Frequency API
******************************************************************/
void SoapyRadioberry::setFrequency( const int direction, const size_t channel, const double frequency, const SoapySDR::Kwargs &args ) {
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::setFrequency called");
uint32_t command = 0;
if(direction==SOAPY_SDR_RX) command = 4;
if(direction==SOAPY_SDR_TX) command = 2;
uint32_t command_data = (uint32_t) frequency;
this->SoapyRadioberry::controlRadioberry(command, command_data);
}
// end of source.

Wyświetl plik

@ -0,0 +1,118 @@
#include "SoapyRadioberry.hpp"
void SoapyRadioberry::setSampleRate( const int direction, const size_t channel, const double rate ) {
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::setSampleRate called");
this->SoapyRadioberry::controlRadioberry(0, 0x00000004);
}
SoapySDR::RangeList SoapyRadioberry::getSampleRateRange(const int direction, const size_t channel) const
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::getSampleRateRange called");
SoapySDR::RangeList rangeList;
if (direction == SOAPY_SDR_RX) rangeList.push_back(SoapySDR::Range(48000.0, 192000.0, 1.0));
if (direction == SOAPY_SDR_TX) rangeList.push_back(SoapySDR::Range(48000.0, 48000.0, 1.0));
return rangeList;
}
std::vector<std::string> SoapyRadioberry::getStreamFormats(const int direction, const size_t channel) const
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::getStreamFormats called");
std::vector<std::string> formats;
formats.push_back(SOAPY_SDR_CF32);
return formats;
}
std::string SoapyRadioberry::getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::getNativeStreamFormat called");
if (direction == SOAPY_SDR_RX) {
fullScale = 2048; // RX expects 12 bit samples LSB aligned
}
else if (direction == SOAPY_SDR_TX) {
fullScale = 32768; // TX expects 12 bit samples MSB aligned
}
return SOAPY_SDR_CF32;
}
SoapySDR::ArgInfoList SoapyRadioberry::getStreamArgsInfo(const int direction, const size_t channel) const
{
SoapySDR::ArgInfoList streamArgs;
SoapySDR::ArgInfo bufflenArg;
bufflenArg.key = "bufflen";
bufflenArg.value = "64";
bufflenArg.name = "Buffer Size";
bufflenArg.description = "Number of bytes per buffer, multiples of 512 only.";
bufflenArg.units = "bytes";
bufflenArg.type = SoapySDR::ArgInfo::INT;
streamArgs.push_back(bufflenArg);
return streamArgs;
}
SoapySDR::Stream *SoapyRadioberry::setupStream(
const int direction,
const std::string &format,
const std::vector<size_t> &channels,
const SoapySDR::Kwargs &args )
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::setupStream called");
//check the format
if (format == SOAPY_SDR_CF32) {
SoapySDR_log(SOAPY_SDR_INFO, "Using format CF32.");
}
else {
throw std::runtime_error(
"setupStream invalid format '" + format + "' -- Only CF32 is supported by SoapyRadioberrySDR module.");
}
return (SoapySDR::Stream *) this;
}
int SoapyRadioberry::readStream(
SoapySDR::Stream *handle,
void * const *buffs,
const size_t numElems,
int &flags,
long long &timeNs,
const long timeoutUs )
{
int i;
int iq = 0;
int left_sample;
int right_sample;
int nr_samples;
void *buff_base = buffs[0];
float *target_buffer = (float *) buff_base;
char rx_buffer[512];
while ((nr_samples = read(fd_rb , rx_buffer , sizeof(rx_buffer)))==0) {usleep(1); return -1;}
for(i=0; i< nr_samples ; i+=6) {
left_sample = (int)((signed char) rx_buffer[i])<<16;
left_sample |= (int)((((unsigned char)rx_buffer[i+1])<<8)&0xFF00);
left_sample |= (int)((unsigned char)rx_buffer[i+2]&0xFF);
right_sample = (int)((signed char)rx_buffer[i+3]) << 16;
right_sample |= (int)((((unsigned char)rx_buffer[i+4])<<8)&0xFF00);
right_sample |= (int)((unsigned char)rx_buffer[i+5]&0xFF);
target_buffer[iq++]=(float)left_sample/8388607.0; // 24 bit sample 2^23-1
target_buffer[iq++]=(float)right_sample/8388607.0; // 24 bit sample 2^23-1
}
return (nr_samples / 6); //return the number of IQ samples
}

Wyświetl plik

@ -0,0 +1,21 @@
#ifndef __RADIOBERRY_IOCTL_H__
#define __RADIOBERRY_IOCTL_H__
#include <linux/types.h>
#include <linux/ioctl.h>
#define RADIOBERRY_MAGIC ('x')
#define RADIOBERRY_IOC_COMMAND _IOW(RADIOBERRY_MAGIC, 1, __u8)
struct rb_info_arg_t
{
int major, minor;
int rb_command;
int command;
int command_data;
} ;
#endif

Wyświetl plik

@ -379,6 +379,8 @@ void send_control(unsigned char command) {
rb_info.command = command;
rb_info.command_data = command_data;
fprintf(stderr, "Command = %02X command_data = %08X\n", command, command_data);
if (ioctl(fd_rb, RADIOBERRY_IOC_COMMAND, &rb_info) == -1) {
fprintf(stderr, "Could not sent commando to radioberry device.");
}