forked from sdr/gr-osmosdr
bladerf: add support for MIMO
Squashed commit of rtucker-bladerf-hierarchy branch: commit 35442da7d390919f6f9cbae3f69d6dc32ca595bb through commit 9026136cfdbc7116f55af18cb06d1731330fa13fgr3.7
parent
c4a0781367
commit
8f8b137cee
File diff suppressed because it is too large
Load Diff
|
@ -21,21 +21,14 @@
|
|||
#ifndef INCLUDED_BLADERF_COMMON_H
|
||||
#define INCLUDED_BLADERF_COMMON_H
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/circular_buffer.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/assign.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/weak_ptr.hpp>
|
||||
|
||||
#include <gnuradio/thread/thread.h>
|
||||
#include <gnuradio/gr_complex.h>
|
||||
|
||||
#include <libbladeRF.h>
|
||||
|
||||
#include "osmosdr/ranges.h"
|
||||
|
@ -44,103 +37,256 @@
|
|||
#ifdef _MSC_VER
|
||||
#include <cstddef>
|
||||
typedef ptrdiff_t ssize_t;
|
||||
#endif //_MSC_VER
|
||||
#endif //_MSC_VER
|
||||
|
||||
typedef boost::shared_ptr < struct bladerf >bladerf_sptr;
|
||||
#define BLADERF_DEBUG_ENABLE
|
||||
|
||||
typedef boost::shared_ptr<struct bladerf> bladerf_sptr;
|
||||
|
||||
/* Identification of the bladeRF hardware in use */
|
||||
typedef enum {
|
||||
BLADERF_REV_INVALID,
|
||||
BLADERF_REV_1,
|
||||
BLADERF_REV_2
|
||||
BOARD_TYPE_UNKNOWN, /**< Board type is unknown */
|
||||
BOARD_TYPE_NONE, /**< Uninitialized or no board present */
|
||||
BOARD_TYPE_BLADERF_1, /**< bladeRF 1 (LMS6002D-based, 1RX/1TX) */
|
||||
BOARD_TYPE_BLADERF_2, /**< bladeRF 2 (AD9361-based, 2RX/2TX) */
|
||||
} bladerf_board_type;
|
||||
|
||||
/* Mapping of bladerf_channel to bool */
|
||||
typedef std::map<bladerf_channel, bool> bladerf_channel_enable_map;
|
||||
|
||||
/* Mapping of bladerf_channel to gnuradio port/chan */
|
||||
typedef std::map<bladerf_channel, int> bladerf_channel_map;
|
||||
|
||||
/* Convenience macros for throwing a runtime error */
|
||||
#define BLADERF_THROW(message) \
|
||||
{ \
|
||||
throw std::runtime_error(std::string(__FUNCTION__) + ": " + message); \
|
||||
}
|
||||
|
||||
#define BLADERF_THROW_STATUS(status, message) \
|
||||
{ \
|
||||
BLADERF_THROW(boost::str(boost::format("%s: %s (%d)") % message \
|
||||
% bladerf_strerror(status) % status)); \
|
||||
}
|
||||
|
||||
/* Convenience macros for printing a warning message to stderr */
|
||||
#define BLADERF_WARNING(message) \
|
||||
{ \
|
||||
std::cerr << _pfx << __FUNCTION__ << ": " << message << std::endl; \
|
||||
}
|
||||
|
||||
#define BLADERF_WARN_STATUS(status, message) \
|
||||
{ \
|
||||
BLADERF_WARNING(message << ": " << bladerf_strerror(status)); \
|
||||
} \
|
||||
|
||||
/* Convenience macro for printing an informational message to stdout */
|
||||
#define BLADERF_INFO(message) \
|
||||
{ \
|
||||
std::cout << _pfx << __FUNCTION__ << ": " << message << std::endl; \
|
||||
}
|
||||
|
||||
/* Convenience macro for printing a debug message to stdout */
|
||||
#ifdef BLADERF_DEBUG_ENABLE
|
||||
#define BLADERF_DEBUG(message) BLADERF_INFO("DEBUG: " << message)
|
||||
#else
|
||||
#define BLADERF_DEBUG(message)
|
||||
#endif // BLADERF_DEBUG_ENABLE
|
||||
|
||||
/* Given a bladerf_channel_layout, calculate the number of streams */
|
||||
size_t num_streams(bladerf_channel_layout layout);
|
||||
|
||||
/**
|
||||
* Common class for bladeRF interaction
|
||||
*/
|
||||
class bladerf_common
|
||||
{
|
||||
public:
|
||||
/*****************************************************************************
|
||||
* Public methods
|
||||
****************************************************************************/
|
||||
bladerf_common();
|
||||
virtual ~ bladerf_common();
|
||||
|
||||
protected:
|
||||
/*****************************************************************************
|
||||
* Protected methods
|
||||
****************************************************************************/
|
||||
|
||||
/* Handle initialized and parameters common to both source & sink */
|
||||
void init(dict_t &dict, bladerf_direction direction);
|
||||
/**
|
||||
* Handle initialization and parameters common to both source & sink
|
||||
*
|
||||
* Specify arguments in key=value,key=value format, e.g.
|
||||
* bladerf=0,buffers=512
|
||||
*
|
||||
* Recognized arguments:
|
||||
* Key Allowed values
|
||||
* ---------------------------------------------------------------------------
|
||||
* REQUIRED:
|
||||
* bladerf a valid instance or serial number
|
||||
* USB INTERFACE CONTROL:
|
||||
* buffers (default: NUM_BUFFERS)
|
||||
* buflen (default: NUM_SAMPLES_PER_BUFFER)
|
||||
* stream_timeout valid time in milliseconds (default: 3000)
|
||||
* transfers (default: NUM_TRANSFERS)
|
||||
* FPGA CONTROL:
|
||||
* enable_metadata 1 to enable metadata
|
||||
* fpga a path to a valid .rbf file
|
||||
* fpga-reload 1 to force reloading the FPGA unconditionally
|
||||
* RF CONTROL:
|
||||
* agc 1 to enable, 0 to disable (default: hardware-dependent)
|
||||
* agc_mode default, manual, fast, slow, hybrid (default: default)
|
||||
* loopback bb_txlpf_rxvga2, bb_txlpf_rxlpf, bb_txvga1_rxvga2,
|
||||
* bb_txvga1_rxlpf, rf_lna1, rf_lna2, rf_lna3, firmware,
|
||||
* ad9361_bist, none (default: none)
|
||||
* ** Note: valid on receive channels only
|
||||
* rxmux baseband, 12bit, 32bit, digital (default: baseband)
|
||||
* ** Note: valid on receive channels only
|
||||
* smb a valid frequency
|
||||
* tamer internal, external_1pps, external (default: internal)
|
||||
* xb200 auto, auto3db, 50M, 144M, 222M, custom (default: auto)
|
||||
* MISC:
|
||||
* verbosity verbose, debug, info, warning, error, critical, silent
|
||||
* (default: info)
|
||||
* ** Note: applies only to libbladeRF logging
|
||||
*/
|
||||
void init(dict_t const &dict, bladerf_direction direction);
|
||||
|
||||
bool start(bladerf_direction direction);
|
||||
bool stop(bladerf_direction direction);
|
||||
/* Get a vector of available devices */
|
||||
static std::vector<std::string> devices();
|
||||
/* Get the type of the open bladeRF board */
|
||||
bladerf_board_type get_board_type();
|
||||
/* Get the maximum number of channels supported in a given direction */
|
||||
size_t get_max_channels(bladerf_direction direction);
|
||||
|
||||
bladerf_board_type get_board_type(struct bladerf *dev);
|
||||
void set_channel_enable(bladerf_channel ch, bool enable);
|
||||
bool get_channel_enable(bladerf_channel ch);
|
||||
|
||||
double set_sample_rate(bladerf_direction direction, double rate);
|
||||
double get_sample_rate(bladerf_direction direction);
|
||||
/* Set libbladeRF verbosity */
|
||||
void set_verbosity(std::string const &verbosity);
|
||||
|
||||
osmosdr::freq_range_t get_freq_range(size_t chan = 0);
|
||||
double set_center_freq(double freq, size_t chan = 0);
|
||||
double get_center_freq(size_t chan = 0);
|
||||
/* Convert an antenna/channel name (e.g. "RX2") to a bladerf_channel */
|
||||
bladerf_channel str2channel(std::string const &ch);
|
||||
/* Convert a bladerf_channel to an antenna/channel name (e.g. "RX2") */
|
||||
std::string channel2str(bladerf_channel ch);
|
||||
/* Convert a bladerf_channel to a hardware port identifier */
|
||||
int channel2rfport(bladerf_channel ch);
|
||||
|
||||
std::vector < std::string > get_gain_names(size_t chan = 0);
|
||||
osmosdr::gain_range_t get_gain_range(size_t chan = 0);
|
||||
osmosdr::gain_range_t get_gain_range(const std::string &name, size_t chan =
|
||||
0);
|
||||
bool set_gain_mode(bool automatic, size_t chan = 0);
|
||||
bool get_gain_mode(size_t chan = 0);
|
||||
double set_gain(double gain, size_t chan = 0);
|
||||
double set_gain(double gain, const std::string &name, size_t chan = 0);
|
||||
double get_gain(size_t chan = 0);
|
||||
double get_gain(const std::string &name, size_t chan = 0);
|
||||
/* Using the channel map, get the bladerf_channel for a gnuradio chan */
|
||||
bladerf_channel chan2channel(bladerf_direction direction, size_t chan = 0);
|
||||
|
||||
int set_dc_offset(bladerf_direction direction,
|
||||
const std::complex < double > &offset, size_t chan);
|
||||
int set_iq_balance(bladerf_direction direction,
|
||||
const std::complex < double > &balance, size_t chan);
|
||||
/* Get range of supported sampling rates for channel ch */
|
||||
osmosdr::meta_range_t sample_rates(bladerf_channel ch);
|
||||
/* Set sampling rate on channel ch to rate */
|
||||
double set_sample_rate(double rate, bladerf_channel ch);
|
||||
/* Get the current sampling rate on channel ch */
|
||||
double get_sample_rate(bladerf_channel ch);
|
||||
|
||||
void set_clock_source(const std::string &source, const size_t mboard = 0);
|
||||
std::string get_clock_source(const size_t mboard = 0);
|
||||
std::vector < std::string > get_clock_sources(const size_t mboard = 0);
|
||||
/* Get range of supported RF frequencies for channel ch */
|
||||
osmosdr::freq_range_t freq_range(bladerf_channel ch);
|
||||
/* Set center RF frequency of channel ch to freq */
|
||||
double set_center_freq(double freq, bladerf_channel ch);
|
||||
/* Get the center RF frequency of channel ch */
|
||||
double get_center_freq(bladerf_channel ch);
|
||||
|
||||
/* Get range of supported bandwidths for channel ch */
|
||||
osmosdr::freq_range_t filter_bandwidths(bladerf_channel ch);
|
||||
/* Set the bandwidth on channel ch to bandwidth */
|
||||
double set_bandwidth(double bandwidth, bladerf_channel ch);
|
||||
/* Get the current bandwidth of channel ch */
|
||||
double get_bandwidth(bladerf_channel ch);
|
||||
|
||||
/* Get the names of gain stages on channel ch */
|
||||
std::vector<std::string> get_gain_names(bladerf_channel ch);
|
||||
/* Get range of supported overall gain values on channel ch */
|
||||
osmosdr::gain_range_t get_gain_range(bladerf_channel ch);
|
||||
/* Get range of supported gain values for gain stage 'name' on channel ch */
|
||||
osmosdr::gain_range_t get_gain_range(std::string const &name,
|
||||
bladerf_channel ch);
|
||||
|
||||
/* Enable or disable the automatic gain control on channel ch */
|
||||
bool set_gain_mode(bool automatic, bladerf_channel ch,
|
||||
bladerf_gain_mode agc_mode = BLADERF_GAIN_DEFAULT);
|
||||
/* Get the current automatic gain control status on channel ch */
|
||||
bool get_gain_mode(bladerf_channel ch);
|
||||
|
||||
/* Set the overall gain value on channel ch */
|
||||
double set_gain(double gain, bladerf_channel ch);
|
||||
/* Set the gain of stage 'name' on channel ch */
|
||||
double set_gain(double gain, std::string const &name, bladerf_channel ch);
|
||||
/* Get the overall gain value on channel ch */
|
||||
double get_gain(bladerf_channel ch);
|
||||
/* Get the gain of stage 'name' on channel ch */
|
||||
double get_gain(std::string const &name, bladerf_channel ch);
|
||||
|
||||
/* Get the list of antennas supported by a channel */
|
||||
std::vector<std::string> get_antennas(bladerf_direction dir);
|
||||
bool set_antenna(bladerf_direction dir, size_t chan, const std::string &antenna);
|
||||
|
||||
/* Set the DC offset on channel ch */
|
||||
int set_dc_offset(std::complex<double> const &offset, bladerf_channel ch);
|
||||
/* Set the IQ balance on channel ch */
|
||||
int set_iq_balance(std::complex<double> const &balance, bladerf_channel ch);
|
||||
|
||||
/* Get the list of supported clock sources */
|
||||
std::vector<std::string> get_clock_sources(size_t mboard = 0);
|
||||
/* Set the clock source to */
|
||||
void set_clock_source(std::string const &source, size_t mboard = 0);
|
||||
/* Get the name of the current clock source */
|
||||
std::string get_clock_source(size_t mboard = 0);
|
||||
|
||||
/* Set the SMB frequency */
|
||||
void set_smb_frequency(double frequency);
|
||||
/* Get the current SMB frequency */
|
||||
double get_smb_frequency();
|
||||
|
||||
osmosdr::freq_range_t freq_range(bladerf_channel chan);
|
||||
osmosdr::meta_range_t sample_rates();
|
||||
osmosdr::freq_range_t filter_bandwidths();
|
||||
/*****************************************************************************
|
||||
* Protected members
|
||||
****************************************************************************/
|
||||
bladerf_sptr _dev; /**< shared pointer for the active device */
|
||||
std::string _pfx; /**< prefix for console messages */
|
||||
unsigned int _failures; /**< counter for consecutive rx/tx failures */
|
||||
|
||||
static std::vector < std::string > devices();
|
||||
size_t _num_buffers; /**< number of buffers to allocate */
|
||||
size_t _samples_per_buffer; /**< how many samples per buffer */
|
||||
size_t _num_transfers; /**< number of active backend transfers */
|
||||
unsigned int _stream_timeout; /**< timeout for backend transfers */
|
||||
|
||||
bladerf_sptr _dev;
|
||||
bladerf_format _format; /**< sample format to use */
|
||||
|
||||
size_t _num_buffers;
|
||||
size_t _samples_per_buffer;
|
||||
size_t _num_transfers;
|
||||
unsigned int _stream_timeout_ms;
|
||||
bladerf_channel_map _chanmap; /**< map of antennas to channels */
|
||||
bladerf_channel_enable_map _enables; /**< enabled channels */
|
||||
|
||||
int16_t *_conv_buf;
|
||||
int _conv_buf_size; /* In units of samples */
|
||||
|
||||
bool _use_metadata;
|
||||
bool _use_mimo;
|
||||
|
||||
std::string _pfx;
|
||||
|
||||
bool _xb_200_attached;
|
||||
unsigned int _consecutive_failures;
|
||||
/*****************************************************************************
|
||||
* Protected constants
|
||||
****************************************************************************/
|
||||
/* Maximum bladerf_sync_{rx,tx} failures to allow before giving up */
|
||||
static const unsigned int MAX_CONSECUTIVE_FAILURES = 3;
|
||||
|
||||
/* BladeRF IQ correction parameters */
|
||||
static const int16_t DCOFF_SCALE = 2048;
|
||||
static const int16_t GAIN_SCALE = 4096;
|
||||
static const int16_t PHASE_SCALE = 4096;
|
||||
|
||||
static const unsigned int MAX_CONSECUTIVE_FAILURES = 3;
|
||||
|
||||
private:
|
||||
/*****************************************************************************
|
||||
* Private methods
|
||||
****************************************************************************/
|
||||
/* Open the bladeRF described by device_name. Returns a sptr if successful */
|
||||
bladerf_sptr open(const std::string &device_name);
|
||||
static void close(void *dev); /* called by shared_ptr */
|
||||
/* Called by shared_ptr when a bladerf_sptr hits a refcount of 0 */
|
||||
static void close(void *dev);
|
||||
/* If a device described by devinfo is open, this returns a sptr to it */
|
||||
static bladerf_sptr get_cached_device(struct bladerf_devinfo devinfo);
|
||||
/* Prints a summary of device information */
|
||||
void print_device_info();
|
||||
|
||||
void set_verbosity(const std::string &verbosity);
|
||||
void set_loopback_mode(const std::string &loopback);
|
||||
void set_rx_mux_mode(const std::string &rxmux);
|
||||
bool is_antenna_valid(bladerf_direction dir, const std::string &antenna);
|
||||
|
||||
static boost::mutex _devs_mutex;
|
||||
static std::list < boost::weak_ptr < struct bladerf >>_devs;
|
||||
/*****************************************************************************
|
||||
* Private members
|
||||
****************************************************************************/
|
||||
static boost::mutex _devs_mutex; /**< mutex for access to _devs */
|
||||
static std::list<boost::weak_ptr<struct bladerf>> _devs; /**< dev cache */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -35,23 +35,19 @@
|
|||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <gnuradio/io_signature.h>
|
||||
#include <gnuradio/tags.h>
|
||||
#include <gnuradio/sync_block.h>
|
||||
|
||||
#include <volk/volk.h>
|
||||
|
||||
#include "arg_helpers.h"
|
||||
#include "bladerf_sink_c.h"
|
||||
|
||||
//#define DEBUG_BLADERF_SINK
|
||||
#ifdef DEBUG_BLADERF_SINK
|
||||
#define DBG(input) std::cerr << _pfx << input << std::endl
|
||||
#else
|
||||
#define DBG(input)
|
||||
#endif
|
||||
#include "osmosdr/sink.h"
|
||||
|
||||
using namespace boost::assign;
|
||||
|
||||
/******************************************************************************
|
||||
* Functions
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Create a new instance of bladerf_sink_c and return
|
||||
* a boost shared_ptr. This is effectively the public constructor.
|
||||
|
@ -61,54 +57,233 @@ bladerf_sink_c_sptr make_bladerf_sink_c(const std::string &args)
|
|||
return gnuradio::get_initial_sptr(new bladerf_sink_c(args));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Private methods
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
bladerf_sink_c::bladerf_sink_c(const std::string &args)
|
||||
:gr::sync_block("bladerf_sink_c",
|
||||
bladerf_sink_c::bladerf_sink_c(const std::string &args) :
|
||||
gr::sync_block( "bladerf_sink_c",
|
||||
args_to_io_signature(args),
|
||||
gr::io_signature::make(0, 0, 0))
|
||||
gr::io_signature::make(0, 0, 0)),
|
||||
_16icbuf(NULL),
|
||||
_32fcbuf(NULL),
|
||||
_in_burst(false),
|
||||
_running(false)
|
||||
{
|
||||
dict_t dict = params_to_dict(args);
|
||||
|
||||
/* Perform src/sink agnostic initializations */
|
||||
init(dict, BLADERF_TX);
|
||||
|
||||
/* Bounds-checking input signature depending on our underlying hardware */
|
||||
size_t max_nchan = 1;
|
||||
|
||||
if (get_board_type(_dev.get()) == BLADERF_REV_2) {
|
||||
max_nchan = 2;
|
||||
/* Check for RX-only params */
|
||||
if (dict.count("loopback")) {
|
||||
BLADERF_WARNING("Warning: 'loopback' has been specified on a bladeRF "
|
||||
"sink, and will have no effect. This parameter should be "
|
||||
"specified on the associated bladeRF source.");
|
||||
}
|
||||
|
||||
if (get_num_channels() > max_nchan) {
|
||||
std::cerr << _pfx
|
||||
<< "Warning: number of channels specified on command line ("
|
||||
<< get_num_channels() << ") is greater than the maximum number "
|
||||
<< "supported by this device (" << max_nchan << "). Resetting "
|
||||
<< "to " << max_nchan << "."
|
||||
<< std::endl;
|
||||
|
||||
set_input_signature( gr::io_signature::make(max_nchan, max_nchan, sizeof(gr_complex) ) );
|
||||
if (dict.count("rxmux")) {
|
||||
BLADERF_WARNING("Warning: 'rxmux' has been specified on a bladeRF sink, "
|
||||
"and will have no effect.");
|
||||
}
|
||||
|
||||
_use_mimo = get_num_channels() > 1;
|
||||
/* Initialize channel <-> antenna map */
|
||||
BOOST_FOREACH(std::string ant, get_antennas()) {
|
||||
_chanmap[str2channel(ant)] = -1;
|
||||
}
|
||||
|
||||
/* Bounds-checking output signature depending on our underlying hardware */
|
||||
if (get_num_channels() > get_max_channels()) {
|
||||
BLADERF_WARNING("Warning: number of channels specified on command line ("
|
||||
<< get_num_channels() << ") is greater than the maximum "
|
||||
"number supported by this device (" << get_max_channels()
|
||||
<< "). Resetting to " << get_max_channels() << ".");
|
||||
|
||||
set_input_signature(gr::io_signature::make(get_max_channels(),
|
||||
get_max_channels(),
|
||||
sizeof(gr_complex)));
|
||||
}
|
||||
|
||||
/* Set up constraints */
|
||||
int const alignment_multiple = volk_get_alignment() / sizeof(gr_complex);
|
||||
set_alignment(std::max(1,alignment_multiple));
|
||||
set_max_noutput_items(_samples_per_buffer);
|
||||
set_output_multiple(get_num_channels());
|
||||
|
||||
/* Set channel layout */
|
||||
_layout = (get_num_channels() > 1) ? BLADERF_TX_X2 : BLADERF_TX_X1;
|
||||
|
||||
/* Initial wiring of antennas to channels */
|
||||
for (size_t ch = 0; ch < get_num_channels(); ++ch) {
|
||||
set_channel_enable(BLADERF_CHANNEL_TX(ch), true);
|
||||
_chanmap[BLADERF_CHANNEL_TX(ch)] = ch;
|
||||
}
|
||||
|
||||
BLADERF_DEBUG("initialization complete");
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Public methods
|
||||
******************************************************************************/
|
||||
|
||||
std::string bladerf_sink_c::name()
|
||||
{
|
||||
return "bladeRF transmitter";
|
||||
}
|
||||
|
||||
std::vector<std::string> bladerf_sink_c::get_devices()
|
||||
{
|
||||
return bladerf_common::devices();
|
||||
}
|
||||
|
||||
size_t bladerf_sink_c::get_max_channels()
|
||||
{
|
||||
return bladerf_common::get_max_channels(BLADERF_TX);
|
||||
}
|
||||
|
||||
size_t bladerf_sink_c::get_num_channels()
|
||||
{
|
||||
return input_signature()->max_streams();
|
||||
}
|
||||
|
||||
bool bladerf_sink_c::start()
|
||||
{
|
||||
int status;
|
||||
|
||||
BLADERF_DEBUG("starting sink");
|
||||
|
||||
gr::thread::scoped_lock guard(d_mutex);
|
||||
|
||||
_in_burst = false;
|
||||
return bladerf_common::start(BLADERF_TX);
|
||||
|
||||
status = bladerf_sync_config(_dev.get(), _layout, _format, _num_buffers,
|
||||
_samples_per_buffer, _num_transfers,
|
||||
_stream_timeout);
|
||||
if (status != 0) {
|
||||
BLADERF_THROW_STATUS(status, "bladerf_sync_config failed");
|
||||
}
|
||||
|
||||
for (size_t ch = 0; ch < get_max_channels(); ++ch) {
|
||||
bladerf_channel brfch = BLADERF_CHANNEL_TX(ch);
|
||||
if (get_channel_enable(brfch)) {
|
||||
status = bladerf_enable_module(_dev.get(), brfch, true);
|
||||
if (status != 0) {
|
||||
BLADERF_THROW_STATUS(status, "bladerf_enable_module failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate memory for conversions in work() */
|
||||
size_t alignment = volk_get_alignment();
|
||||
|
||||
_16icbuf = reinterpret_cast<int16_t *>(volk_malloc(2*_samples_per_buffer*sizeof(int16_t), alignment));
|
||||
_32fcbuf = reinterpret_cast<gr_complex *>(volk_malloc(_samples_per_buffer*sizeof(gr_complex), alignment));
|
||||
|
||||
_running = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bladerf_sink_c::stop()
|
||||
{
|
||||
return bladerf_common::stop(BLADERF_TX);
|
||||
int status;
|
||||
|
||||
BLADERF_DEBUG("stopping sink");
|
||||
|
||||
gr::thread::scoped_lock guard(d_mutex);
|
||||
|
||||
if (!_running) {
|
||||
BLADERF_WARNING("sink already stopped, nothing to do here");
|
||||
return true;
|
||||
}
|
||||
|
||||
_running = false;
|
||||
|
||||
for (size_t ch = 0; ch < get_max_channels(); ++ch) {
|
||||
bladerf_channel brfch = BLADERF_CHANNEL_TX(ch);
|
||||
if (get_channel_enable(brfch)) {
|
||||
status = bladerf_enable_module(_dev.get(), brfch, false);
|
||||
if (status != 0) {
|
||||
BLADERF_THROW_STATUS(status, "bladerf_enable_module failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Deallocate conversion memory */
|
||||
volk_free(_16icbuf);
|
||||
volk_free(_32fcbuf);
|
||||
_16icbuf = NULL;
|
||||
_32fcbuf = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define INVALID_IDX -1
|
||||
int bladerf_sink_c::work(int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
{
|
||||
int status;
|
||||
size_t nstreams = num_streams(_layout);
|
||||
|
||||
int bladerf_sink_c::transmit_with_tags(int noutput_items)
|
||||
gr::thread::scoped_lock guard(d_mutex);
|
||||
|
||||
// if we aren't running, nothing to do here
|
||||
if (!_running) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// copy the samples from input_items
|
||||
gr_complex const **in = reinterpret_cast<gr_complex const **>(&input_items[0]);
|
||||
|
||||
if (nstreams > 1) {
|
||||
// we need to interleave the streams as we copy
|
||||
gr_complex *intl_out = _32fcbuf;
|
||||
|
||||
for (size_t i = 0; i < (noutput_items/nstreams); ++i) {
|
||||
for (size_t n = 0; n < nstreams; ++n) {
|
||||
memcpy(intl_out++, in[n]++, sizeof(gr_complex));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no interleaving to do: simply copy everything
|
||||
memcpy(_32fcbuf, in[0], noutput_items * sizeof(gr_complex));
|
||||
}
|
||||
|
||||
// convert floating point to fixed point and scale
|
||||
// input_items is gr_complex (2x float), so num_points is 2*noutput_items
|
||||
volk_32f_s32f_convert_16i(_16icbuf, reinterpret_cast<float const *>(_32fcbuf),
|
||||
SCALING_FACTOR, 2*noutput_items);
|
||||
|
||||
// transmit the samples from the temp buffer
|
||||
if (BLADERF_FORMAT_SC16_Q11_META == _format) {
|
||||
status = transmit_with_tags(_16icbuf, noutput_items);
|
||||
} else {
|
||||
status = bladerf_sync_tx(_dev.get(), static_cast<void const *>(_16icbuf),
|
||||
noutput_items, NULL, _stream_timeout);
|
||||
}
|
||||
|
||||
// handle failure
|
||||
if (status != 0) {
|
||||
BLADERF_WARNING("bladerf_sync_tx error: " << bladerf_strerror(status));
|
||||
++_failures;
|
||||
|
||||
if (_failures >= MAX_CONSECUTIVE_FAILURES) {
|
||||
BLADERF_WARNING("Consecutive error limit hit. Shutting down.");
|
||||
return WORK_DONE;
|
||||
}
|
||||
} else {
|
||||
_failures = 0;
|
||||
}
|
||||
|
||||
return noutput_items;
|
||||
}
|
||||
|
||||
int bladerf_sink_c::transmit_with_tags(int16_t const *samples,
|
||||
int noutput_items)
|
||||
{
|
||||
int status;
|
||||
int count = 0;
|
||||
|
@ -120,13 +295,14 @@ int bladerf_sink_c::transmit_with_tags(int noutput_items)
|
|||
int end_idx = (noutput_items - 1);
|
||||
|
||||
struct bladerf_metadata meta;
|
||||
std::vector < gr::tag_t > tags;
|
||||
std::vector<gr::tag_t> tags;
|
||||
|
||||
int16_t zeros[8] = { 0 };
|
||||
int const INVALID_IDX = -1;
|
||||
int16_t const zeros[8] = { 0 };
|
||||
|
||||
memset(&meta, 0, sizeof(meta));
|
||||
|
||||
DBG("transmit_with_tags(" << noutput_items << ")");
|
||||
BLADERF_DEBUG("transmit_with_tags(" << noutput_items << ")");
|
||||
|
||||
// Important Note: We assume that these tags are ordered by their offsets.
|
||||
// This is true for GNU Radio 3.7.7.x, since the GR runtime libs store
|
||||
|
@ -138,57 +314,56 @@ int bladerf_sink_c::transmit_with_tags(int noutput_items)
|
|||
|
||||
if (tags.size() == 0) {
|
||||
if (_in_burst) {
|
||||
DBG("TX'ing " << noutput_items << " samples in within a burst...");
|
||||
BLADERF_DEBUG("TX'ing " << noutput_items << " samples within a burst...");
|
||||
|
||||
return bladerf_sync_tx(_dev.get(),
|
||||
static_cast < void *>(_conv_buf),
|
||||
noutput_items, &meta, _stream_timeout_ms);
|
||||
return bladerf_sync_tx(_dev.get(), samples, noutput_items,
|
||||
&meta, _stream_timeout);
|
||||
} else {
|
||||
std::cerr << _pfx
|
||||
<< "Dropping " << noutput_items << " samples not in a burst."
|
||||
<< std::endl;
|
||||
BLADERF_WARNING("Dropping " << noutput_items
|
||||
<< " samples not in a burst.");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH(gr::tag_t tag, tags) {
|
||||
|
||||
// Upon seeing an SOB tag, update our offset. We'll TX the start of the
|
||||
// burst when we see an EOB or at the end of this function - whichever
|
||||
// occurs first.
|
||||
if (pmt::symbol_to_string(tag.key) == "tx_sob") {
|
||||
if (_in_burst) {
|
||||
std::cerr << ("Got SOB while already within a burst") << std::endl;
|
||||
BLADERF_WARNING("Got SOB while already within a burst");
|
||||
|
||||
return BLADERF_ERR_INVAL;
|
||||
} else {
|
||||
start_idx = static_cast < int >(tag.offset - nitems_read(0));
|
||||
DBG("Got SOB " << start_idx << " samples into work payload");
|
||||
start_idx = static_cast<int>(tag.offset - nitems_read(0));
|
||||
|
||||
meta.flags |=
|
||||
(BLADERF_META_FLAG_TX_NOW | BLADERF_META_FLAG_TX_BURST_START);
|
||||
BLADERF_DEBUG("Got SOB " << start_idx << " samples into work payload");
|
||||
|
||||
meta.flags |= (BLADERF_META_FLAG_TX_NOW | BLADERF_META_FLAG_TX_BURST_START);
|
||||
_in_burst = true;
|
||||
|
||||
}
|
||||
|
||||
} else if (pmt::symbol_to_string(tag.key) == "tx_eob") {
|
||||
if (!_in_burst) {
|
||||
std::cerr << _pfx << "Got EOB while not in burst" << std::endl;
|
||||
BLADERF_WARNING("Got EOB while not in burst");
|
||||
return BLADERF_ERR_INVAL;
|
||||
}
|
||||
|
||||
// Upon seeing an EOB, transmit what we have and reset our state
|
||||
end_idx = static_cast < int >(tag.offset - nitems_read(0));
|
||||
DBG("Got EOB " << end_idx << " samples into work payload");
|
||||
end_idx = static_cast<int>(tag.offset - nitems_read(0));
|
||||
BLADERF_DEBUG("Got EOB " << end_idx << " samples into work payload");
|
||||
|
||||
if ((start_idx == INVALID_IDX) || (start_idx > end_idx)) {
|
||||
DBG("Buffer indicies are in an invalid state!");
|
||||
BLADERF_DEBUG("Buffer indicies are in an invalid state!");
|
||||
return BLADERF_ERR_INVAL;
|
||||
}
|
||||
|
||||
count = end_idx - start_idx + 1;
|
||||
|
||||
DBG("TXing @ EOB [" << start_idx << ":" << end_idx << "]");
|
||||
BLADERF_DEBUG("TXing @ EOB [" << start_idx << ":" << end_idx << "]");
|
||||
|
||||
status = bladerf_sync_tx(_dev.get(),
|
||||
static_cast < void *>(&_conv_buf[2 * start_idx]),
|
||||
count, &meta, _stream_timeout_ms);
|
||||
static_cast<void const *>(&samples[2 * start_idx]),
|
||||
count, &meta, _stream_timeout);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
@ -197,16 +372,15 @@ int bladerf_sink_c::transmit_with_tags(int noutput_items)
|
|||
* as of the libbladeRF version that includes the
|
||||
* TX_UPDATE_TIMESTAMP flag. Verify this potentially remove this.
|
||||
* (The meta.flags changes would then be applied to the previous
|
||||
* bladerf_sync_tx() call.)
|
||||
* bladerf_sync_tx() call.)
|
||||
*/
|
||||
DBG("TXing Zeros with burst end flag");
|
||||
BLADERF_DEBUG("TXing Zeros with burst end flag");
|
||||
|
||||
meta.flags &= ~(BLADERF_META_FLAG_TX_NOW | BLADERF_META_FLAG_TX_BURST_START);
|
||||
meta.flags |= BLADERF_META_FLAG_TX_BURST_END;
|
||||
|
||||
status = bladerf_sync_tx(_dev.get(),
|
||||
static_cast < void *>(zeros),
|
||||
4, &meta, _stream_timeout_ms);
|
||||
status = bladerf_sync_tx(_dev.get(), static_cast<void const *>(zeros),
|
||||
4, &meta, _stream_timeout);
|
||||
|
||||
/* Reset our state */
|
||||
start_idx = INVALID_IDX;
|
||||
|
@ -215,7 +389,7 @@ int bladerf_sink_c::transmit_with_tags(int noutput_items)
|
|||
_in_burst = false;
|
||||
|
||||
if (status != 0) {
|
||||
DBG("Failed to send zero samples to flush EOB");
|
||||
BLADERF_DEBUG("Failed to send zero samples to flush EOB");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
@ -225,113 +399,51 @@ int bladerf_sink_c::transmit_with_tags(int noutput_items)
|
|||
if (_in_burst) {
|
||||
count = end_idx - start_idx + 1;
|
||||
|
||||
DBG("TXing SOB [" << start_idx << ":" << end_idx << "]");
|
||||
BLADERF_DEBUG("TXing SOB [" << start_idx << ":" << end_idx << "]");
|
||||
|
||||
status = bladerf_sync_tx(_dev.get(),
|
||||
static_cast < void *>(&_conv_buf[2 * start_idx]),
|
||||
count, &meta, _stream_timeout_ms);
|
||||
static_cast<void const *>(&samples[2 * start_idx]),
|
||||
count, &meta, _stream_timeout);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int bladerf_sink_c::work(int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
{
|
||||
const gr_complex *in = (const gr_complex *) input_items[0];
|
||||
const float scaling = 2000.0f;
|
||||
int status;
|
||||
|
||||
if (noutput_items > _conv_buf_size) {
|
||||
void *tmp;
|
||||
|
||||
_conv_buf_size = noutput_items;
|
||||
tmp = realloc(_conv_buf, _conv_buf_size * 2 * sizeof(int16_t));
|
||||
if (tmp == NULL) {
|
||||
throw std::runtime_error(_pfx + "Failed to realloc _conv_buf");
|
||||
} else {
|
||||
DBG("Resized _conv_buf to " << _conv_buf_size << " samples");
|
||||
}
|
||||
|
||||
_conv_buf = static_cast < int16_t * >(tmp);
|
||||
}
|
||||
|
||||
/* Convert floating point samples into fixed point */
|
||||
volk_32f_s32f_convert_16i(_conv_buf, (float *) in, scaling,
|
||||
2 * noutput_items);
|
||||
|
||||
if (_use_metadata) {
|
||||
status = transmit_with_tags(noutput_items);
|
||||
} else {
|
||||
status = bladerf_sync_tx(_dev.get(), static_cast < void *>(_conv_buf),
|
||||
noutput_items, NULL, _stream_timeout_ms);
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
std::cerr << _pfx
|
||||
<< "bladerf_sync_tx error: " << bladerf_strerror(status)
|
||||
<< std::endl;
|
||||
|
||||
_consecutive_failures++;
|
||||
|
||||
if (_consecutive_failures >= MAX_CONSECUTIVE_FAILURES) {
|
||||
noutput_items = WORK_DONE;
|
||||
std::cerr << _pfx
|
||||
<< "Consecutive error limit hit. Shutting down."
|
||||
<< std::endl;
|
||||
}
|
||||
} else {
|
||||
_consecutive_failures = 0;
|
||||
}
|
||||
|
||||
return noutput_items;
|
||||
}
|
||||
|
||||
std::vector < std::string > bladerf_sink_c::get_devices()
|
||||
{
|
||||
return bladerf_common::devices();
|
||||
}
|
||||
|
||||
size_t bladerf_sink_c::get_num_channels()
|
||||
{
|
||||
return input_signature()->max_streams();
|
||||
}
|
||||
|
||||
osmosdr::meta_range_t bladerf_sink_c::get_sample_rates()
|
||||
{
|
||||
return sample_rates();
|
||||
return sample_rates(chan2channel(BLADERF_TX, 0));
|
||||
}
|
||||
|
||||
double bladerf_sink_c::set_sample_rate(double rate)
|
||||
{
|
||||
return bladerf_common::set_sample_rate(BLADERF_TX, rate);
|
||||
return bladerf_common::set_sample_rate(rate, chan2channel(BLADERF_TX, 0));
|
||||
}
|
||||
|
||||
double bladerf_sink_c::get_sample_rate()
|
||||
{
|
||||
return bladerf_common::get_sample_rate(BLADERF_TX);
|
||||
return bladerf_common::get_sample_rate(chan2channel(BLADERF_TX, 0));
|
||||
}
|
||||
|
||||
osmosdr::freq_range_t bladerf_sink_c::get_freq_range(size_t chan)
|
||||
{
|
||||
return bladerf_common::get_freq_range(BLADERF_CHANNEL_TX(chan));
|
||||
return bladerf_common::freq_range(chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
double bladerf_sink_c::set_center_freq(double freq, size_t chan)
|
||||
{
|
||||
return bladerf_common::set_center_freq(freq, BLADERF_CHANNEL_TX(chan));
|
||||
return bladerf_common::set_center_freq(freq, chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
double bladerf_sink_c::get_center_freq(size_t chan)
|
||||
{
|
||||
return bladerf_common::get_center_freq(BLADERF_CHANNEL_TX(chan));
|
||||
return bladerf_common::get_center_freq(chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
double bladerf_sink_c::set_freq_corr(double ppm, size_t chan)
|
||||
{
|
||||
/* TODO: Write the VCTCXO with a correction value (also changes RX ppm value!) */
|
||||
return get_freq_corr(BLADERF_CHANNEL_TX(chan));
|
||||
BLADERF_WARNING("Frequency correction is not implemented.");
|
||||
return get_freq_corr(chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
double bladerf_sink_c::get_freq_corr(size_t chan)
|
||||
|
@ -340,77 +452,80 @@ double bladerf_sink_c::get_freq_corr(size_t chan)
|
|||
return 0;
|
||||
}
|
||||
|
||||
std::vector < std::string > bladerf_sink_c::get_gain_names(size_t chan)
|
||||
std::vector<std::string> bladerf_sink_c::get_gain_names(size_t chan)
|
||||
{
|
||||
return bladerf_common::get_gain_names(BLADERF_CHANNEL_TX(chan));
|
||||
return bladerf_common::get_gain_names(chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
osmosdr::gain_range_t bladerf_sink_c::get_gain_range(size_t chan)
|
||||
{
|
||||
return bladerf_common::get_gain_range(BLADERF_CHANNEL_TX(chan));
|
||||
return bladerf_common::get_gain_range(chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
osmosdr::gain_range_t bladerf_sink_c::get_gain_range(const std::string &name,
|
||||
size_t chan)
|
||||
{
|
||||
return bladerf_common::get_gain_range(name, BLADERF_CHANNEL_TX(chan));
|
||||
return bladerf_common::get_gain_range(name, chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
bool bladerf_sink_c::set_gain_mode(bool automatic, size_t chan)
|
||||
{
|
||||
return bladerf_common::set_gain_mode(automatic, BLADERF_CHANNEL_TX(chan));
|
||||
return bladerf_common::set_gain_mode(automatic,
|
||||
chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
bool bladerf_sink_c::get_gain_mode(size_t chan)
|
||||
{
|
||||
return bladerf_common::get_gain_mode(BLADERF_CHANNEL_TX(chan));
|
||||
return bladerf_common::get_gain_mode(chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
double bladerf_sink_c::set_gain(double gain, size_t chan)
|
||||
{
|
||||
return bladerf_common::set_gain(gain, BLADERF_CHANNEL_TX(chan));
|
||||
return bladerf_common::set_gain(gain, chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
double bladerf_sink_c::set_gain(double gain, const std::string &name,
|
||||
size_t chan)
|
||||
{
|
||||
return bladerf_common::set_gain(gain, name, BLADERF_CHANNEL_TX(chan));
|
||||
return bladerf_common::set_gain(gain, name, chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
double bladerf_sink_c::get_gain(size_t chan)
|
||||
{
|
||||
return bladerf_common::get_gain(BLADERF_CHANNEL_TX(chan));
|
||||
return bladerf_common::get_gain(chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
double bladerf_sink_c::get_gain(const std::string &name, size_t chan)
|
||||
{
|
||||
return bladerf_common::get_gain(name, BLADERF_CHANNEL_TX(chan));
|
||||
return bladerf_common::get_gain(name, chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
std::vector < std::string > bladerf_sink_c::get_antennas(size_t chan)
|
||||
std::vector<std::string> bladerf_sink_c::get_antennas(size_t chan)
|
||||
{
|
||||
std::vector < std::string > antennas;
|
||||
|
||||
antennas += "TX0";
|
||||
|
||||
if (BLADERF_REV_2 == get_board_type(_dev.get())) {
|
||||
antennas += "TX1";
|
||||
}
|
||||
|
||||
return antennas;
|
||||
return bladerf_common::get_antennas(BLADERF_TX);
|
||||
}
|
||||
|
||||
std::string bladerf_sink_c::set_antenna(const std::string &antenna,
|
||||
size_t chan)
|
||||
{
|
||||
return get_antenna(BLADERF_CHANNEL_TX(chan));
|
||||
bool _was_running = _running;
|
||||
|
||||
if (_was_running) {
|
||||
stop();
|
||||
}
|
||||
|
||||
bladerf_common::set_antenna(BLADERF_TX, chan, antenna);
|
||||
|
||||
if (_was_running) {
|
||||
start();
|
||||
}
|
||||
|
||||
return get_antenna(chan);
|
||||
}
|
||||
|
||||
std::string bladerf_sink_c::get_antenna(size_t chan)
|
||||
{
|
||||
/* We only have a single transmit antenna here */
|
||||
// TODO: the above is a lie
|
||||
return "TX0";
|
||||
return channel2str(chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
void bladerf_sink_c::set_dc_offset(const std::complex < double > &offset,
|
||||
|
@ -418,11 +533,10 @@ void bladerf_sink_c::set_dc_offset(const std::complex < double > &offset,
|
|||
{
|
||||
int status;
|
||||
|
||||
status = bladerf_common::set_dc_offset(BLADERF_TX, offset, chan);
|
||||
status = bladerf_common::set_dc_offset(offset, chan2channel(BLADERF_TX, chan));
|
||||
|
||||
if (status != 0) {
|
||||
throw std::runtime_error(_pfx + "could not set dc offset: " +
|
||||
bladerf_strerror(status));
|
||||
BLADERF_THROW_STATUS(status, "could not set dc offset");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,66 +545,40 @@ void bladerf_sink_c::set_iq_balance(const std::complex < double > &balance,
|
|||
{
|
||||
int status;
|
||||
|
||||
status = bladerf_common::set_iq_balance(BLADERF_TX, balance, chan);
|
||||
status = bladerf_common::set_iq_balance(balance, chan2channel(BLADERF_TX, chan));
|
||||
|
||||
if (status != 0) {
|
||||
throw std::runtime_error(_pfx + "could not set iq balance: " +
|
||||
bladerf_strerror(status));
|
||||
BLADERF_THROW_STATUS(status, "could not set iq balance");
|
||||
}
|
||||
}
|
||||
|
||||
double bladerf_sink_c::set_bandwidth(double bandwidth, size_t chan)
|
||||
{
|
||||
int status;
|
||||
uint32_t actual;
|
||||
|
||||
if (bandwidth == 0.0) {
|
||||
/* bandwidth of 0 means automatic filter selection */
|
||||
/* select narrower filters to prevent aliasing */
|
||||
bandwidth = get_sample_rate() * 0.75;
|
||||
}
|
||||
|
||||
status = bladerf_set_bandwidth(_dev.get(), BLADERF_TX, (uint32_t) bandwidth,
|
||||
&actual);
|
||||
if (status != 0) {
|
||||
throw std::runtime_error(_pfx + "could not set bandwidth:" +
|
||||
bladerf_strerror(status));
|
||||
}
|
||||
|
||||
return get_bandwidth();
|
||||
}
|
||||
|
||||
double bladerf_sink_c::get_bandwidth(size_t chan)
|
||||
{
|
||||
int status;
|
||||
uint32_t bandwidth;
|
||||
|
||||
status = bladerf_get_bandwidth(_dev.get(), BLADERF_TX, &bandwidth);
|
||||
if (status != 0) {
|
||||
throw std::runtime_error(_pfx + "could not get bandwidth: " +
|
||||
bladerf_strerror(status));
|
||||
}
|
||||
|
||||
return (double) bandwidth;
|
||||
}
|
||||
|
||||
osmosdr::freq_range_t bladerf_sink_c::get_bandwidth_range(size_t chan)
|
||||
{
|
||||
return filter_bandwidths();
|
||||
return filter_bandwidths(chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
double bladerf_sink_c::set_bandwidth(double bandwidth, size_t chan)
|
||||
{
|
||||
return bladerf_common::set_bandwidth(bandwidth, chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
double bladerf_sink_c::get_bandwidth(size_t chan)
|
||||
{
|
||||
return bladerf_common::get_bandwidth(chan2channel(BLADERF_TX, chan));
|
||||
}
|
||||
|
||||
std::vector < std::string > bladerf_sink_c::get_clock_sources(size_t mboard)
|
||||
{
|
||||
return bladerf_common::get_clock_sources(mboard);
|
||||
}
|
||||
|
||||
void bladerf_sink_c::set_clock_source(const std::string &source,
|
||||
const size_t mboard)
|
||||
size_t mboard)
|
||||
{
|
||||
bladerf_common::set_clock_source(source, mboard);
|
||||
}
|
||||
|
||||
std::string bladerf_sink_c::get_clock_source(const size_t mboard)
|
||||
std::string bladerf_sink_c::get_clock_source(size_t mboard)
|
||||
{
|
||||
return bladerf_common::get_clock_source(mboard);
|
||||
}
|
||||
|
||||
std::vector < std::string > bladerf_sink_c::get_clock_sources(const size_t mboard)
|
||||
{
|
||||
return bladerf_common::get_clock_sources(mboard);
|
||||
}
|
||||
|
|
|
@ -21,14 +21,12 @@
|
|||
#ifndef INCLUDED_BLADERF_SINK_C_H
|
||||
#define INCLUDED_BLADERF_SINK_C_H
|
||||
|
||||
#include <gnuradio/thread/thread.h>
|
||||
#include <gnuradio/block.h>
|
||||
#include <gnuradio/sync_block.h>
|
||||
|
||||
#include "osmosdr/ranges.h"
|
||||
#include "sink_iface.h"
|
||||
#include "bladerf_common.h"
|
||||
|
||||
#include "osmosdr/ranges.h"
|
||||
|
||||
class bladerf_sink_c;
|
||||
|
||||
/*
|
||||
|
@ -42,7 +40,7 @@ class bladerf_sink_c;
|
|||
*
|
||||
* As a convention, the _sptr suffix indicates a boost::shared_ptr
|
||||
*/
|
||||
typedef boost::shared_ptr < bladerf_sink_c > bladerf_sink_c_sptr;
|
||||
typedef boost::shared_ptr<bladerf_sink_c> bladerf_sink_c_sptr;
|
||||
|
||||
/*!
|
||||
* \brief Return a shared_ptr to a new instance of bladerf_sink_c.
|
||||
|
@ -53,25 +51,28 @@ typedef boost::shared_ptr < bladerf_sink_c > bladerf_sink_c_sptr;
|
|||
*/
|
||||
bladerf_sink_c_sptr make_bladerf_sink_c(const std::string &args = "");
|
||||
|
||||
class bladerf_sink_c:public gr::sync_block,
|
||||
public sink_iface, protected bladerf_common
|
||||
class bladerf_sink_c :
|
||||
public gr::sync_block,
|
||||
public sink_iface,
|
||||
protected bladerf_common
|
||||
{
|
||||
private:
|
||||
// The friend declaration allows bladerf_make_sink_c to
|
||||
// access the private constructor.
|
||||
friend bladerf_sink_c_sptr make_bladerf_sink_c(const std::string &args);
|
||||
|
||||
bladerf_sink_c(const std::string &args); // private constructor
|
||||
bladerf_sink_c(const std::string &args);
|
||||
|
||||
// Transmit converted samples stored in _conv_buf, applying SOB and EOB
|
||||
// based upon the provided tags
|
||||
//
|
||||
// Returns bladeRF error code
|
||||
int transmit_with_tags(int noutput_items);
|
||||
|
||||
bool _in_burst;
|
||||
bool is_antenna_valid(const std::string &antenna);
|
||||
|
||||
public:
|
||||
std::string name();
|
||||
|
||||
static std::vector<std::string> get_devices();
|
||||
|
||||
size_t get_max_channels(void);
|
||||
size_t get_num_channels(void);
|
||||
|
||||
bool start();
|
||||
bool stop();
|
||||
|
||||
|
@ -79,10 +80,6 @@ public:
|
|||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
|
||||
static std::vector < std::string > get_devices();
|
||||
|
||||
size_t get_num_channels(void);
|
||||
|
||||
osmosdr::meta_range_t get_sample_rates(void);
|
||||
double set_sample_rate(double rate);
|
||||
double get_sample_rate(void);
|
||||
|
@ -94,10 +91,10 @@ public:
|
|||
double set_freq_corr(double ppm, size_t chan = 0);
|
||||
double get_freq_corr(size_t chan = 0);
|
||||
|
||||
std::vector < std::string > get_gain_names(size_t chan = 0);
|
||||
std::vector<std::string> get_gain_names(size_t chan = 0);
|
||||
osmosdr::gain_range_t get_gain_range(size_t chan = 0);
|
||||
osmosdr::gain_range_t get_gain_range(const std::string &name, size_t chan =
|
||||
0);
|
||||
osmosdr::gain_range_t get_gain_range(const std::string &name,
|
||||
size_t chan = 0);
|
||||
bool set_gain_mode(bool automatic, size_t chan = 0);
|
||||
bool get_gain_mode(size_t chan = 0);
|
||||
double set_gain(double gain, size_t chan = 0);
|
||||
|
@ -105,20 +102,36 @@ public:
|
|||
double get_gain(size_t chan = 0);
|
||||
double get_gain(const std::string &name, size_t chan = 0);
|
||||
|
||||
std::vector < std::string > get_antennas(size_t chan = 0);
|
||||
std::vector<std::string> get_antennas(size_t chan = 0);
|
||||
std::string set_antenna(const std::string &antenna, size_t chan = 0);
|
||||
std::string get_antenna(size_t chan = 0);
|
||||
|
||||
void set_dc_offset(const std::complex < double > &offset, size_t chan);
|
||||
void set_iq_balance(const std::complex < double > &balance, size_t chan);
|
||||
void set_dc_offset(const std::complex<double> &offset, size_t chan);
|
||||
void set_iq_balance(const std::complex<double> &balance, size_t chan);
|
||||
|
||||
osmosdr::freq_range_t get_bandwidth_range(size_t chan = 0);
|
||||
double set_bandwidth(double bandwidth, size_t chan = 0);
|
||||
double get_bandwidth(size_t chan = 0);
|
||||
osmosdr::freq_range_t get_bandwidth_range(size_t chan = 0);
|
||||
|
||||
void set_clock_source(const std::string &source, const size_t mboard = 0);
|
||||
std::string get_clock_source(const size_t mboard);
|
||||
std::vector < std::string > get_clock_sources(const size_t mboard);
|
||||
std::vector<std::string> get_clock_sources(size_t mboard);
|
||||
void set_clock_source(const std::string &source, size_t mboard = 0);
|
||||
std::string get_clock_source(size_t mboard);
|
||||
|
||||
private:
|
||||
int transmit_with_tags(int16_t const *samples, int noutput_items);
|
||||
|
||||
// Sample-handling buffers
|
||||
int16_t *_16icbuf; /**< raw samples to bladeRF */
|
||||
gr_complex *_32fcbuf; /**< intermediate buffer for conversions */
|
||||
|
||||
bool _in_burst; /**< are we currently in a burst? */
|
||||
bool _running; /**< is the sink running? */
|
||||
bladerf_channel_layout _layout; /**< channel layout */
|
||||
|
||||
gr::thread::mutex d_mutex; /**< mutex to protect set/work access */
|
||||
|
||||
/* Scaling factor used when converting from float to int16_t */
|
||||
const float SCALING_FACTOR = 2048.0f;
|
||||
};
|
||||
|
||||
#endif /* INCLUDED_BLADERF_SINK_C_H */
|
||||
#endif // INCLUDED_BLADERF_SINK_C_H
|
||||
|
|
|
@ -44,6 +44,10 @@
|
|||
|
||||
using namespace boost::assign;
|
||||
|
||||
/******************************************************************************
|
||||
* Functions
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Create a new instance of bladerf_source_c and return
|
||||
* a boost shared_ptr. This is effectively the public constructor.
|
||||
|
@ -53,195 +57,326 @@ bladerf_source_c_sptr make_bladerf_source_c(const std::string &args)
|
|||
return gnuradio::get_initial_sptr(new bladerf_source_c(args));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Private methods
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
bladerf_source_c::bladerf_source_c(const std::string &args)
|
||||
:gr::sync_block("bladerf_source_c",
|
||||
bladerf_source_c::bladerf_source_c(const std::string &args) :
|
||||
gr::sync_block( "bladerf_source_c",
|
||||
gr::io_signature::make(0, 0, 0),
|
||||
args_to_io_signature(args))
|
||||
args_to_io_signature(args)),
|
||||
_16icbuf(NULL),
|
||||
_32fcbuf(NULL),
|
||||
_running(false),
|
||||
_agcmode(BLADERF_GAIN_DEFAULT)
|
||||
{
|
||||
int status;
|
||||
std::string device_name;
|
||||
struct bladerf_version fpga_version;
|
||||
|
||||
dict_t dict = params_to_dict(args);
|
||||
|
||||
/* Perform src/sink agnostic initializations */
|
||||
init(dict, BLADERF_RX);
|
||||
|
||||
/* Handle setting of sampling mode */
|
||||
if (dict.count("sampling")) {
|
||||
std::string sampling = dict["sampling"];
|
||||
|
||||
std::cerr << _pfx
|
||||
<< "Setting bladerf sampling to " << sampling
|
||||
<< std::endl;
|
||||
|
||||
if (sampling == "internal") {
|
||||
status = bladerf_set_sampling(_dev.get(), BLADERF_SAMPLING_INTERNAL);
|
||||
if (status != 0) {
|
||||
std::cerr << _pfx
|
||||
<< "Problem while setting sampling mode: "
|
||||
<< bladerf_strerror(status)
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
} else if (sampling == "external") {
|
||||
status = bladerf_set_sampling(_dev.get(), BLADERF_SAMPLING_EXTERNAL);
|
||||
if (status != 0) {
|
||||
std::cerr << _pfx
|
||||
<< "Problem while setting sampling mode: "
|
||||
<< bladerf_strerror(status)
|
||||
<< std::endl;
|
||||
}
|
||||
bladerf_sampling sampling = BLADERF_SAMPLING_UNKNOWN;
|
||||
|
||||
if (dict["sampling"] == "internal") {
|
||||
sampling = BLADERF_SAMPLING_INTERNAL;
|
||||
} else if (dict["sampling"] == "external") {
|
||||
sampling = BLADERF_SAMPLING_EXTERNAL;
|
||||
} else {
|
||||
std::cerr << _pfx << "Invalid sampling mode " << sampling << std::endl;
|
||||
BLADERF_WARNING("Invalid sampling mode: " + dict["sampling"]);
|
||||
}
|
||||
|
||||
if (sampling != BLADERF_SAMPLING_UNKNOWN) {
|
||||
status = bladerf_set_sampling(_dev.get(), sampling);
|
||||
if (status != 0) {
|
||||
BLADERF_WARNING("Problem while setting sampling mode: " <<
|
||||
bladerf_strerror(status));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Loopback */
|
||||
set_loopback_mode(dict.count("loopback") ? dict["loopback"] : "none");
|
||||
|
||||
/* RX Mux */
|
||||
set_rx_mux_mode(dict.count("rxmux") ? dict["rxmux"] : "baseband");
|
||||
|
||||
/* AGC mode */
|
||||
if (dict.count("agc_mode")) {
|
||||
set_agc_mode(dict["agc_mode"]);
|
||||
}
|
||||
|
||||
/* Specify initial gain mode */
|
||||
if (dict.count("agc")) {
|
||||
for (size_t i = 0; i < get_max_channels(); ++i) {
|
||||
set_gain_mode(boost::lexical_cast<bool>(dict["agc"]), BLADERF_CHANNEL_RX(i));
|
||||
BLADERF_INFO(boost::str(boost::format("%s gain mode set to '%s'")
|
||||
% channel2str(BLADERF_CHANNEL_RX(i))
|
||||
% get_gain_mode(BLADERF_CHANNEL_RX(i))));
|
||||
}
|
||||
}
|
||||
|
||||
/* Warn user about using an old FPGA version, as we no longer strip off the
|
||||
* markers that were pressent in the pre-v0.0.1 FPGA */
|
||||
if (bladerf_fpga_version(_dev.get(), &fpga_version) != 0) {
|
||||
std::cerr << _pfx << "Failed to get FPGA version" << std::endl;
|
||||
} else if (fpga_version.major <= 0 &&
|
||||
fpga_version.minor <= 0 && fpga_version.patch < 1) {
|
||||
{
|
||||
struct bladerf_version fpga_version;
|
||||
|
||||
std::cerr << _pfx
|
||||
<< "Warning: FPGA version v0.0.1 or later is required. Using an "
|
||||
<< "earlier FPGA version will result in misinterpeted samples."
|
||||
<< std::endl;
|
||||
if (bladerf_fpga_version(_dev.get(), &fpga_version) != 0) {
|
||||
BLADERF_WARNING("Failed to get FPGA version");
|
||||
} else if (fpga_version.major <= 0 &&
|
||||
fpga_version.minor <= 0 &&
|
||||
fpga_version.patch < 1) {
|
||||
BLADERF_WARNING("Warning: FPGA version v0.0.1 or later is required. "
|
||||
"Using an earlier FPGA version will result in "
|
||||
"misinterpeted samples.");
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize channel <-> antenna map */
|
||||
BOOST_FOREACH(std::string ant, get_antennas()) {
|
||||
_chanmap[str2channel(ant)] = -1;
|
||||
}
|
||||
|
||||
/* Bounds-checking output signature depending on our underlying hardware */
|
||||
size_t max_nchan = 1;
|
||||
if (get_num_channels() > get_max_channels()) {
|
||||
BLADERF_WARNING("Warning: number of channels specified on command line ("
|
||||
<< get_num_channels() << ") is greater than the maximum "
|
||||
"number supported by this device (" << get_max_channels()
|
||||
<< "). Resetting to " << get_max_channels() << ".");
|
||||
|
||||
if (get_board_type(_dev.get()) == BLADERF_REV_2) {
|
||||
max_nchan = 2;
|
||||
set_output_signature(gr::io_signature::make(get_max_channels(),
|
||||
get_max_channels(),
|
||||
sizeof(gr_complex)));
|
||||
}
|
||||
|
||||
if (get_num_channels() > max_nchan) {
|
||||
std::cerr << _pfx
|
||||
<< "Warning: number of channels specified on command line ("
|
||||
<< get_num_channels() << ") is greater than the maximum number "
|
||||
<< "supported by this device (" << max_nchan << "). Resetting "
|
||||
<< "to " << max_nchan << "."
|
||||
<< std::endl;
|
||||
/* Set up constraints */
|
||||
int const alignment_multiple = volk_get_alignment() / sizeof(gr_complex);
|
||||
set_alignment(std::max(1,alignment_multiple));
|
||||
set_max_noutput_items(_samples_per_buffer);
|
||||
set_output_multiple(get_num_channels());
|
||||
|
||||
set_output_signature( gr::io_signature::make(max_nchan, max_nchan, sizeof(gr_complex) ) );
|
||||
/* Set channel layout */
|
||||
_layout = (get_num_channels() > 1) ? BLADERF_RX_X2 : BLADERF_RX_X1;
|
||||
|
||||
/* Initial wiring of antennas to channels */
|
||||
for (size_t ch = 0; ch < get_num_channels(); ++ch) {
|
||||
set_channel_enable(BLADERF_CHANNEL_RX(ch), true);
|
||||
_chanmap[BLADERF_CHANNEL_RX(ch)] = ch;
|
||||
}
|
||||
|
||||
_use_mimo = get_num_channels() > 1;
|
||||
BLADERF_DEBUG("initialization complete");
|
||||
}
|
||||
|
||||