laforge
/
openbts-osmo
Archived
1
0
Fork 0

uhd: one-off code cleanup and evisceration of camel casing

Because I can't take it anymore...

Actually, I've been manually converting names to camel
case before checking in, which was an error prone process
in and of itself.

The interface is unchanged, so nobody should complain.

Signed-off-by: Thomas Tsou <ttsou@vt.edu>
This commit is contained in:
Thomas Tsou 2011-05-04 14:46:08 -04:00
parent 1c21ffd51b
commit 47faafb525
1 changed files with 290 additions and 272 deletions

View File

@ -22,52 +22,66 @@
*/ */
#include "Device.h" #include "Device.h"
#include "Threads.h" #include "Threads.h"
#include "Logger.h" #include "Logger.h"
#include <uhd/usrp/single_usrp.hpp> #include <uhd/usrp/single_usrp.hpp>
#include <uhd/utils/thread_priority.hpp> #include <uhd/utils/thread_priority.hpp>
/* /*
enableExternalRef - Enable external 10MHz clock reference use_ext_ref - Enable external 10MHz clock reference
masterClockRate - Master clock frequency master_clk_rt - Master clock frequency
rxTimingOffset - Timing correction in seconds between receive and rx_smpl_offset - Timing correction in seconds between receive and
transmit timestamps. This value corrects for delays on transmit timestamps. This value corrects for delays on
on the RF side of the timestamping point of the device. on the RF side of the timestamping point of the device.
sampleBufSize - The receive sample buffer size in bytes. smpl_buf_sz - The receive sample buffer size in bytes.
*/ */
const bool enableExternalRef = false; const bool use_ext_ref = false;
const double masterClockRate = 100.0e6; const double master_clk_rt = 100e6;
const double rxTimingOffset = .00005; const double rx_smpl_offset = .00005;
const size_t sampleBufSize = (1 << 20); const size_t smpl_buf_sz = (1 << 20);
/** Timestamp conversion
@param timestamp a UHD or OpenBTS timestamp
@param rate sample rate
@return the converted timestamp
*/
uhd::time_spec_t convert_time(TIMESTAMP ticks, double rate)
{
double secs = (double) ticks / rate;
return uhd::time_spec_t(secs);
}
TIMESTAMP convert_time(uhd::time_spec_t ts, double rate)
{
size_t ticks = ts.get_full_secs() * rate;
return ts.get_tick_count(rate) + ticks;
}
/* /*
Sample Buffer - Allows reading and writing of timed samples using OpenBTS Sample Buffer - Allows reading and writing of timed samples using OpenBTS
or UHD style timestamps. Time conversions are handled or UHD style timestamps. Time conversions are handled
internally or accessable through the static convert calls. internally or accessable through the static convert calls.
*/ */
class SampleBuffer { class smpl_buf {
public: public:
/** Sample buffer constructor /** Sample buffer constructor
@param len number of 32-bit samples the buffer should hold @param len number of 32-bit samples the buffer should hold
@param rate sample clockrate @param rate sample clockrate
@param timestamp @param timestamp
*/ */
SampleBuffer(size_t len, double rate); smpl_buf(size_t len, double rate);
~SampleBuffer(); ~smpl_buf();
/** Query number of samples available for reading /** Query number of samples available for reading
@param timestamp time of first sample @param timestamp time of first sample
@return number of available samples or error @return number of available samples or error
*/ */
ssize_t availableSamples(TIMESTAMP timestamp) const; ssize_t avail_smpls(TIMESTAMP timestamp) const;
ssize_t availableSamples(uhd::time_spec_t timestamp) const; ssize_t avail_smpls(uhd::time_spec_t timestamp) const;
/** Read and write /** Read and write
@param buf pointer to buffer @param buf pointer to buffer
@ -83,23 +97,15 @@ public:
/** Buffer status string /** Buffer status string
@return a formatted string describing internal buffer state @return a formatted string describing internal buffer state
*/ */
std::string stringStatus() const; std::string str_status() const;
/** Timestamp conversion
@param timestamp a UHD or OpenBTS timestamp
@param rate sample rate
@return the converted timestamp
*/
static uhd::time_spec_t convertTime(TIMESTAMP timestamp, double rate);
static TIMESTAMP convertTime(uhd::time_spec_t timestamp, double rate);
/** Formatted error string /** Formatted error string
@param code an error code @param code an error code
@return a formatted error string @return a formatted error string
*/ */
static std::string stringCode(ssize_t code); static std::string str_code(ssize_t code);
enum errorCode { enum err_code {
ERROR_TIMESTAMP = -1, ERROR_TIMESTAMP = -1,
ERROR_READ = -2, ERROR_READ = -2,
ERROR_WRITE = -3, ERROR_WRITE = -3,
@ -108,29 +114,28 @@ public:
private: private:
uint32_t *data; uint32_t *data;
size_t bufferLen; size_t buf_len;
double clockRate; double clk_rt;
TIMESTAMP timeStart; TIMESTAMP time_start;
TIMESTAMP timeEnd; TIMESTAMP time_end;
size_t dataStart; size_t data_start;
size_t dataEnd; size_t data_end;
}; };
/* /*
UHDDevice - UHD implementation of the Device interface. Timestamped samples uhd_device - UHD implementation of the Device interface. Timestamped samples
are sent to and received from the device. An intermediate buffer are sent to and received from the device. An intermediate buffer
on the receive side collects and aligns packets of samples. on the receive side collects and aligns packets of samples.
Events and errors such as underruns are reported asynchronously Events and errors such as underruns are reported asynchronously
by the device and received in a separate thread. by the device and received in a separate thread.
*/ */
class UHDDevice : public Device { class uhd_device : public Device {
public: public:
UHDDevice(double desiredSampleRate, bool skipRx); uhd_device(double rate, bool skip_rx);
~UHDDevice(); ~uhd_device();
bool open(); bool open();
bool start(); bool start();
@ -141,84 +146,127 @@ public:
TIMESTAMP timestamp, bool *underrun, unsigned *RSSI); TIMESTAMP timestamp, bool *underrun, unsigned *RSSI);
int writeSamples(short *buf, int len, bool *underrun, int writeSamples(short *buf, int len, bool *underrun,
TIMESTAMP timestamp, bool isControl); TIMESTAMP timestamp, bool isControl);
bool updateAlignment(TIMESTAMP timestamp); bool updateAlignment(TIMESTAMP timestamp);
bool setTxFreq(double wFreq); bool setTxFreq(double wFreq);
bool setRxFreq(double wFreq); bool setRxFreq(double wFreq);
inline double getSampleRate() { return actualSampleRate; } inline double getSampleRate() { return actual_smpl_rt; }
inline double numberRead() { return 0; } inline double numberRead() { return rx_pkt_cnt; }
inline double numberWritten() { return 0; } inline double numberWritten() { return 0; }
/** Receive and process asynchronous message /** Receive and process asynchronous message
@return true if message received or false on timeout or error @return true if message received or false on timeout or error
*/ */
bool recvAsyncMesg(); bool recv_async_msg();
private: private:
uhd::usrp::single_usrp::sptr usrpDevice; uhd::usrp::single_usrp::sptr usrp_dev;
double desiredSampleRate; double desired_smpl_rt;
double actualSampleRate; double actual_smpl_rt;
size_t sendSamplesPerPacket; size_t tx_spp;
size_t recvSamplesPerPacket; size_t rx_spp;
bool started; bool started;
bool aligned; bool aligned;
bool skipRx; bool skip_rx;
size_t dropCount; size_t rx_pkt_cnt;
size_t drop_cnt;
uhd::time_spec_t prev_ts;
TIMESTAMP timestampOffset; TIMESTAMP ts_offset;
SampleBuffer *recvBuffer; smpl_buf *rx_smpl_buf;
std::string stringCode(uhd::rx_metadata_t metadata); std::string str_code(uhd::rx_metadata_t metadata);
std::string stringCode(uhd::async_metadata_t metadata); std::string str_code(uhd::async_metadata_t metadata);
Thread asyncEventServiceLoopThread; Thread async_event_thrd;
friend void *AsyncMesgServiceLoopAdapter();
}; };
void *async_event_loop(uhd_device *dev)
void *AsyncEventServiceLoopAdapter(UHDDevice *dev)
{ {
while (1) { while (1) {
dev->recvAsyncMesg(); dev->recv_async_msg();
pthread_testcancel(); pthread_testcancel();
} }
} }
uhd_device::uhd_device(double rate, bool skip_rx)
UHDDevice::UHDDevice(double desiredSampleRate, bool skipRx) : desired_smpl_rt(rate), actual_smpl_rt(0), tx_spp(0), rx_spp(0),
: actualSampleRate(0), sendSamplesPerPacket(0), recvSamplesPerPacket(0), started(false), aligned(true), rx_pkt_cnt(0), drop_cnt(0),
started(false), aligned(true), timestampOffset(0), recvBuffer(NULL), prev_ts(0,0), ts_offset(0), rx_smpl_buf(NULL)
dropCount(0)
{ {
this->desiredSampleRate = desiredSampleRate; this->skip_rx = skip_rx;
this->skipRx = skipRx;
} }
uhd_device::~uhd_device()
UHDDevice::~UHDDevice()
{ {
stop(); stop();
if (recvBuffer) if (rx_smpl_buf)
delete recvBuffer; delete rx_smpl_buf;
} }
static double set_usrp_rates(uhd::usrp::single_usrp::sptr dev, double rate)
{
double actual_rate;
bool UHDDevice::open() dev->set_tx_rate(rate);
dev->set_rx_rate(rate);
actual_rate = dev->get_tx_rate();
if (actual_rate != rate) {
LOG(ERROR) << "Actual sample rate differs from desired rate";
return -1.0;
}
if (dev->get_rx_rate() != actual_rate) {
LOG(ERROR) << "Transmit and receive sample rates do not match";
return -1.0;
}
return actual_rate;
}
static void set_usrp_tx_gain(uhd::usrp::single_usrp::sptr dev, double)
{
uhd::gain_range_t range = dev->get_tx_gain_range();
dev->set_tx_gain((range.start() + range.stop()) / 2);
}
static void set_usrp_rx_gain(uhd::usrp::single_usrp::sptr dev, double)
{
uhd::gain_range_t range = dev->get_rx_gain_range();
dev->set_rx_gain((range.start() + range.stop()) / 2);
}
static void set_usrp_ref_clk(uhd::usrp::single_usrp::sptr dev, bool ext_clk)
{
uhd::clock_config_t clk_cfg;
clk_cfg.pps_source = uhd::clock_config_t::PPS_SMA;
clk_cfg.pps_polarity = uhd::clock_config_t::PPS_NEG;
if (ext_clk)
clk_cfg.ref_source = uhd::clock_config_t::REF_SMA;
else
clk_cfg.ref_source = uhd::clock_config_t::REF_INT;
dev->set_clock_config(clk_cfg);
}
bool uhd_device::open()
{ {
LOG(INFO) << "creating USRP device..."; LOG(INFO) << "creating USRP device...";
// Use the first USRP2 // Use the first available USRP2 / N210
uhd::device_addr_t dev_addr("type=usrp2"); uhd::device_addr_t dev_addr("type=usrp2");
try { try {
usrpDevice = uhd::usrp::single_usrp::make(dev_addr); usrp_dev = uhd::usrp::single_usrp::make(dev_addr);
} }
catch(...) { catch(...) {
@ -226,59 +274,38 @@ bool UHDDevice::open()
return false; return false;
} }
// Set master clock rate
usrp_dev->set_master_clock_rate(master_clk_rt);
// Number of samples per over-the-wire packet // Number of samples per over-the-wire packet
sendSamplesPerPacket = tx_spp = usrp_dev->get_device()->get_max_send_samps_per_packet();
usrpDevice->get_device()->get_max_send_samps_per_packet(); rx_spp = usrp_dev->get_device()->get_max_recv_samps_per_packet();
recvSamplesPerPacket =
usrpDevice->get_device()->get_max_recv_samps_per_packet();
// Set device sample rates // Set rates
usrpDevice->set_tx_rate(desiredSampleRate); actual_smpl_rt = set_usrp_rates(usrp_dev, desired_smpl_rt);
usrpDevice->set_rx_rate(desiredSampleRate); if (actual_smpl_rt < 0)
actualSampleRate = usrpDevice->get_tx_rate();
if (actualSampleRate != desiredSampleRate) {
LOG(ERROR) << "Actual sample rate differs from desired rate";
return false; return false;
}
if (usrpDevice->get_rx_rate() != actualSampleRate) {
LOG(ERROR) << "Transmit and receive sample rates do not match";
return false;
}
// Create receive buffer // Create receive buffer
size_t bufferLen = sampleBufSize / sizeof(uint32_t); size_t buf_len = smpl_buf_sz / sizeof(uint32_t);
recvBuffer = new SampleBuffer(bufferLen, actualSampleRate); rx_smpl_buf = new smpl_buf(buf_len, actual_smpl_rt);
// Set receive chain sample offset // Set receive chain sample offset
timestampOffset = (TIMESTAMP)(rxTimingOffset * actualSampleRate); ts_offset = (TIMESTAMP)(rx_smpl_offset * actual_smpl_rt);
// Set gains to midpoint // Set gains to midpoint
uhd::gain_range_t txGainRange = usrpDevice->get_tx_gain_range(); set_usrp_tx_gain(usrp_dev, 0.0);
usrpDevice->set_tx_gain((txGainRange.start() + txGainRange.stop()) / 2);
uhd::gain_range_t rxGainRange = usrpDevice->get_rx_gain_range();
usrpDevice->set_rx_gain((rxGainRange.start() + rxGainRange.stop()) / 2);
// Set reference clock // Set reference clock
uhd::clock_config_t clock_config; set_usrp_ref_clk(usrp_dev, use_ext_ref);
clock_config.pps_source = uhd::clock_config_t::PPS_SMA;
clock_config.pps_polarity = uhd::clock_config_t::PPS_NEG;
if (enableExternalRef)
clock_config.ref_source = uhd::clock_config_t::REF_SMA;
else
clock_config.ref_source = uhd::clock_config_t::REF_INT;
usrpDevice->set_clock_config(clock_config);
// Print configuration // Print configuration
LOG(INFO) << usrpDevice->get_pp_string(); LOG(INFO) << usrp_dev->get_pp_string();
return true; return true;
} }
bool uhd_device::start()
bool UHDDevice::start()
{ {
LOG(INFO) << "Starting USRP..."; LOG(INFO) << "Starting USRP...";
@ -290,134 +317,156 @@ bool UHDDevice::start()
setPriority(); setPriority();
// Start asynchronous event (underrun check) loop // Start asynchronous event (underrun check) loop
asyncEventServiceLoopThread.start( async_event_thrd.start((void * (*)(void*))async_event_loop, (void*)this);
(void * (*)(void*))AsyncEventServiceLoopAdapter, (void*)this);
// Start streaming // Start streaming
uhd::stream_cmd_t cmd = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS; uhd::stream_cmd_t cmd = uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
cmd.stream_now = true; cmd.stream_now = true;
usrpDevice->set_time_now(uhd::time_spec_t(0.0)); usrp_dev->set_time_now(uhd::time_spec_t(0.0));
if (!skipRx) if (!skip_rx)
usrpDevice->issue_stream_cmd(cmd); usrp_dev->issue_stream_cmd(cmd);
// Display usrp time // Display usrp time
double timeNow = usrpDevice->get_time_now().get_real_secs(); double time_now = usrp_dev->get_time_now().get_real_secs();
LOG(INFO) << "The current time is " << timeNow << " seconds"; LOG(INFO) << "The current time is " << time_now << " seconds";
started = true; started = true;
return true; return true;
} }
bool uhd_device::stop()
bool UHDDevice::stop()
{ {
// Stop streaming uhd::stream_cmd_t stream_cmd =
uhd::stream_cmd_t stream_cmd =
uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS; uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS;
usrpDevice->issue_stream_cmd(stream_cmd);
usrp_dev->issue_stream_cmd(stream_cmd);
started = false; started = false;
return true; return true;
} }
void uhd_device::setPriority()
void UHDDevice::setPriority()
{ {
uhd::set_thread_priority_safe(); uhd::set_thread_priority_safe();
return; return;
} }
int UHDDevice::readSamples(short *buf, int len, bool *overrun, static int check_rx_md_err(uhd::rx_metadata_t &md, uhd::time_spec_t &prev_ts)
{
// Missing timestamp
if (!md.has_time_spec) {
LOG(ERROR) << "UHD: Received packet missing timestamp";
return -1;
}
// Monotonicity check
if (md.time_spec < prev_ts) {
LOG(ERROR) << "Loss of monotonicity";
return -1;
} else {
prev_ts = md.time_spec;
}
return 0;
}
int uhd_device::readSamples(short *buf, int len, bool *overrun,
TIMESTAMP timestamp, bool *underrun, unsigned *RSSI) TIMESTAMP timestamp, bool *underrun, unsigned *RSSI)
{ {
if (skipRx) ssize_t rc;
uhd::time_spec_t ts;
uhd::rx_metadata_t metadata;
uint32_t pkt_buf[rx_spp];
if (skip_rx)
return 0; return 0;
// Shift read time with respect to transmit clock // Shift read time with respect to transmit clock
timestamp += timestampOffset; timestamp += ts_offset;
ts = convert_time(timestamp, actual_smpl_rt);
LOG(DEEPDEBUG) << "Requested timestamp = " << ts.get_real_secs();
// Check that timestamp is valid // Check that timestamp is valid
ssize_t ret = recvBuffer->availableSamples(timestamp); rc = rx_smpl_buf->avail_smpls(timestamp);
if (ret < 0) { if (rc < 0) {
LOG(ERROR) << recvBuffer->stringCode(ret); LOG(ERROR) << rx_smpl_buf->str_code(rc);
LOG(ERROR) << recvBuffer->stringStatus(); LOG(ERROR) << rx_smpl_buf->str_status();
return 0; return 0;
} }
// Receive samples from the usrp until we have enough // Receive samples from the usrp until we have enough
while (recvBuffer->availableSamples(timestamp) < len) { while (rx_smpl_buf->avail_smpls(timestamp) < len) {
uhd::rx_metadata_t metadata; size_t num_smpls = usrp_dev->get_device()->recv(
uint32_t recvBuf[recvSamplesPerPacket]; (void*)pkt_buf,
rx_spp,
size_t numSamples = usrpDevice->get_device()->recv(
(void*)recvBuf,
recvSamplesPerPacket,
metadata, metadata,
uhd::io_type_t::COMPLEX_INT16, uhd::io_type_t::COMPLEX_INT16,
uhd::device::RECV_MODE_ONE_PACKET); uhd::device::RECV_MODE_ONE_PACKET);
rx_pkt_cnt++;
// Recv error in UHD // Recv error in UHD
if (!numSamples) { if (!num_smpls) {
LOG(ERROR) << stringCode(metadata); LOG(ERROR) << str_code(metadata);
return 0; return 0;
} }
// Missing timestamp // Other metadata timing checks
if (!metadata.has_time_spec) { if (check_rx_md_err(metadata, prev_ts) < 0)
LOG(ERROR) << "UHD: Received packet missing timestamp";
return 0; return 0;
}
ssize_t ret = recvBuffer->write(recvBuf, ts = metadata.time_spec;
numSamples, LOG(DEEPDEBUG) << "Received timestamp = " << ts.get_real_secs();
metadata.time_spec);
rc = rx_smpl_buf->write(pkt_buf,
num_smpls,
metadata.time_spec);
// Continue on local overrun, exit on other errors // Continue on local overrun, exit on other errors
if ((ret < 0)) { if ((rc < 0)) {
LOG(ERROR) << recvBuffer->stringCode(ret); LOG(ERROR) << rx_smpl_buf->str_code(rc);
LOG(ERROR) << recvBuffer->stringStatus(); LOG(ERROR) << rx_smpl_buf->str_status();
if (ret != SampleBuffer::ERROR_OVERFLOW) if (rc != smpl_buf::ERROR_OVERFLOW)
return 0; return 0;
} }
} }
// We have enough samples // We have enough samples
ret = recvBuffer->read(buf, len, timestamp); rc = rx_smpl_buf->read(buf, len, timestamp);
if ((ret < 0) || (ret != len)) { if ((rc < 0) || (rc != len)) {
LOG(ERROR) << recvBuffer->stringCode(ret); LOG(ERROR) << rx_smpl_buf->str_code(rc);
LOG(ERROR) << recvBuffer->stringStatus(); LOG(ERROR) << rx_smpl_buf->str_status();
return 0; return 0;
} }
return len; return len;
} }
int uhd_device::writeSamples(short *buf, int len, bool *underrun,
int UHDDevice::writeSamples(short *buf, int len, bool *underrun,
unsigned long long timestamp,bool isControl) unsigned long long timestamp,bool isControl)
{ {
uhd::tx_metadata_t metadata;
metadata.has_time_spec = true;
metadata.start_of_burst = false;
metadata.end_of_burst = false;
metadata.time_spec = convert_time(timestamp, actual_smpl_rt);
// No control packets // No control packets
if (isControl) { if (isControl) {
LOG(ERROR) << "Control packets not supported"; LOG(ERROR) << "Control packets not supported";
return 0; return 0;
} }
uhd::tx_metadata_t metadata;
metadata.has_time_spec = true;
metadata.start_of_burst = false;
metadata.end_of_burst = false;
metadata.time_spec =
SampleBuffer::convertTime(timestamp, actualSampleRate);
// Drop a fixed number of packets (magic value) // Drop a fixed number of packets (magic value)
if (!aligned) { if (!aligned) {
dropCount++; drop_cnt++;
if (dropCount == 1) { if (drop_cnt == 1) {
LOG(DEBUG) << "Aligning transmitter: stop burst"; LOG(DEBUG) << "Aligning transmitter: stop burst";
metadata.end_of_burst = true; metadata.end_of_burst = true;
} else if (dropCount < 30) { } else if (drop_cnt < 30) {
LOG(DEEPDEBUG) << "Aligning transmitter: packet advance"; LOG(DEEPDEBUG) << "Aligning transmitter: packet advance";
*underrun = true; *underrun = true;
return len; return len;
@ -425,61 +474,58 @@ int UHDDevice::writeSamples(short *buf, int len, bool *underrun,
LOG(DEBUG) << "Aligning transmitter: start burst"; LOG(DEBUG) << "Aligning transmitter: start burst";
metadata.start_of_burst = true; metadata.start_of_burst = true;
aligned = true; aligned = true;
dropCount = 0; drop_cnt = 0;
} }
} }
size_t samplesSent = usrpDevice->get_device()->send(buf, size_t num_smpls = usrp_dev->get_device()->send(buf,
len, len,
metadata, metadata,
uhd::io_type_t::COMPLEX_INT16, uhd::io_type_t::COMPLEX_INT16,
uhd::device::SEND_MODE_FULL_BUFF); uhd::device::SEND_MODE_FULL_BUFF);
if (samplesSent != (unsigned)len) if (num_smpls != (unsigned)len)
LOG(ERROR) << "Sent fewer samples than requested"; LOG(ERROR) << "UHD: Sent fewer samples than requested";
return samplesSent; return num_smpls;
} }
bool uhd_device::updateAlignment(TIMESTAMP timestamp)
bool UHDDevice::updateAlignment(TIMESTAMP timestamp)
{ {
/* NOP */ /* NOP */
return true; return true;
} }
bool uhd_device::setTxFreq(double wFreq)
bool UHDDevice::setTxFreq(double wFreq) { {
uhd::tune_result_t tr = usrpDevice->set_tx_freq(wFreq); uhd::tune_result_t tr = usrp_dev->set_tx_freq(wFreq);
LOG(INFO) << tr.to_pp_string(); LOG(INFO) << tr.to_pp_string();
return true; return true;
} }
bool uhd_device::setRxFreq(double wFreq)
bool UHDDevice::setRxFreq(double wFreq) { {
uhd::tune_result_t tr = usrpDevice->set_rx_freq(wFreq); uhd::tune_result_t tr = usrp_dev->set_rx_freq(wFreq);
LOG(INFO) << tr.to_pp_string(); LOG(INFO) << tr.to_pp_string();
return true; return true;
} }
bool uhd_device::recv_async_msg()
bool UHDDevice::recvAsyncMesg()
{ {
uhd::async_metadata_t metadata; uhd::async_metadata_t metadata;
if (!usrpDevice->get_device()->recv_async_msg(metadata)) if (!usrp_dev->get_device()->recv_async_msg(metadata))
return false; return false;
// Assume that any error requires resynchronization // Assume that any error requires resynchronization
if (metadata.event_code != uhd::async_metadata_t::EVENT_CODE_BURST_ACK) { if (metadata.event_code != uhd::async_metadata_t::EVENT_CODE_BURST_ACK) {
aligned = false; aligned = false;
LOG(INFO) << stringCode(metadata); LOG(INFO) << str_code(metadata);
} }
return true; return true;
} }
std::string uhd_device::str_code(uhd::rx_metadata_t metadata)
std::string UHDDevice::stringCode(uhd::rx_metadata_t metadata)
{ {
std::ostringstream ost("UHD: "); std::ostringstream ost("UHD: ");
@ -512,8 +558,7 @@ std::string UHDDevice::stringCode(uhd::rx_metadata_t metadata)
return ost.str(); return ost.str();
} }
std::string uhd_device::str_code(uhd::async_metadata_t metadata)
std::string UHDDevice::stringCode(uhd::async_metadata_t metadata)
{ {
std::ostringstream ost("UHD: "); std::ostringstream ost("UHD: ");
@ -546,156 +591,130 @@ std::string UHDDevice::stringCode(uhd::async_metadata_t metadata)
return ost.str(); return ost.str();
} }
smpl_buf::smpl_buf(size_t len, double rate)
SampleBuffer::SampleBuffer(size_t len, double rate) : buf_len(len), clk_rt(rate),
: bufferLen(len), clockRate(rate), time_start(0), time_end(0), data_start(0), data_end(0)
timeStart(0), timeEnd(0), dataStart(0), dataEnd(0)
{ {
data = new uint32_t[len]; data = new uint32_t[len];
} }
smpl_buf::~smpl_buf()
SampleBuffer::~SampleBuffer()
{ {
delete[] data; delete[] data;
} }
ssize_t smpl_buf::avail_smpls(TIMESTAMP timestamp) const
ssize_t SampleBuffer::availableSamples(TIMESTAMP timestamp) const
{ {
if (timestamp < timeStart) if (timestamp < time_start)
return ERROR_TIMESTAMP; return ERROR_TIMESTAMP;
else if (timestamp >= timeEnd) else if (timestamp >= time_end)
return 0; return 0;
else else
return timeEnd - timestamp; return time_end - timestamp;
} }
ssize_t smpl_buf::avail_smpls(uhd::time_spec_t timespec) const
ssize_t SampleBuffer::availableSamples(uhd::time_spec_t timespec) const
{ {
return availableSamples(convertTime(timespec, clockRate)); return avail_smpls(convert_time(timespec, clk_rt));
} }
ssize_t smpl_buf::read(void *buf, size_t len, TIMESTAMP timestamp)
ssize_t SampleBuffer::read(void *buf, size_t len, TIMESTAMP timestamp)
{ {
// Check for valid read // Check for valid read
if (timestamp < timeStart) if (timestamp < time_start)
return ERROR_TIMESTAMP; return ERROR_TIMESTAMP;
if (timestamp >= timeEnd) if (timestamp >= time_end)
return 0; return 0;
if (len >= bufferLen) if (len >= buf_len)
return ERROR_READ; return ERROR_READ;
// How many samples should be copied // How many samples should be copied
size_t numSamples = timeEnd - timestamp; size_t num_smpls = time_end - timestamp;
if (numSamples > len); if (num_smpls > len);
numSamples = len; num_smpls = len;
// Starting index // Starting index
size_t readStart = dataStart + (timestamp - timeStart); size_t read_start = data_start + (timestamp - time_start);
// Read it // Read it
if (readStart + numSamples < bufferLen) { if (read_start + num_smpls < buf_len) {
size_t numBytes = len * 2 * sizeof(short); size_t numBytes = len * 2 * sizeof(short);
memcpy(buf, data + readStart, numBytes); memcpy(buf, data + read_start, numBytes);
} } else {
else { size_t first_cp = (buf_len - read_start) * 2 * sizeof(short);
size_t firstCopy = (bufferLen - readStart) * 2 * sizeof(short); size_t second_cp = len * 2 * sizeof(short) - first_cp;
size_t secondCopy = len * 2 * sizeof(short) - firstCopy;
memcpy(buf, data + readStart, firstCopy); memcpy(buf, data + read_start, first_cp);
memcpy((char*) buf + firstCopy, data, secondCopy); memcpy((char*) buf + first_cp, data, second_cp);
} }
dataStart = (readStart + len) % bufferLen; data_start = (read_start + len) % buf_len;
timeStart = timestamp + len; time_start = timestamp + len;
if (timeStart > timeEnd) if (time_start > time_end)
return ERROR_READ; return ERROR_READ;
else else
return numSamples; return num_smpls;
} }
ssize_t smpl_buf::read(void *buf, size_t len, uhd::time_spec_t ts)
ssize_t SampleBuffer::read(void *buf, size_t len, uhd::time_spec_t timeSpec)
{ {
return read(buf, len, convertTime(timeSpec, clockRate)); return read(buf, len, convert_time(ts, clk_rt));
} }
ssize_t smpl_buf::write(void *buf, size_t len, TIMESTAMP timestamp)
ssize_t SampleBuffer::write(void *buf, size_t len, TIMESTAMP timestamp)
{ {
// Check for valid write // Check for valid write
if ((len == 0) || (len >= bufferLen)) if ((len == 0) || (len >= buf_len))
return ERROR_WRITE; return ERROR_WRITE;
if ((timestamp + len) <= timeEnd) if ((timestamp + len) <= time_end)
return ERROR_TIMESTAMP; return ERROR_TIMESTAMP;
// Starting index // Starting index
size_t writeStart = (dataStart + (timestamp - timeStart)) % bufferLen; size_t write_start = (data_start + (timestamp - time_start)) % buf_len;
// Write it // Write it
if ((writeStart + len) < bufferLen) { if ((write_start + len) < buf_len) {
size_t numBytes = len * 2 * sizeof(short); size_t numBytes = len * 2 * sizeof(short);
memcpy(data + writeStart, buf, numBytes); memcpy(data + write_start, buf, numBytes);
} } else {
else { size_t first_cp = (buf_len - write_start) * 2 * sizeof(short);
size_t firstCopy = (bufferLen - writeStart) * 2 * sizeof(short); size_t second_cp = len * 2 * sizeof(short) - first_cp;
size_t secondCopy = len * 2 * sizeof(short) - firstCopy;
memcpy(data + writeStart, buf, firstCopy); memcpy(data + write_start, buf, first_cp);
memcpy(data, (char*) buf + firstCopy, secondCopy); memcpy(data, (char*) buf + first_cp, second_cp);
} }
dataEnd = (writeStart + len) % bufferLen; data_end = (write_start + len) % buf_len;
timeEnd = timestamp + len; time_end = timestamp + len;
if (((writeStart + len) > bufferLen) && (dataEnd > dataStart)) if (((write_start + len) > buf_len) && (data_end > data_start))
return ERROR_OVERFLOW; return ERROR_OVERFLOW;
else if (timeEnd <= timeStart) else if (time_end <= time_start)
return ERROR_WRITE; return ERROR_WRITE;
else else
return len; return len;
} }
ssize_t smpl_buf::write(void *buf, size_t len, uhd::time_spec_t ts)
ssize_t SampleBuffer::write(void *buf, size_t len, uhd::time_spec_t timeSpec)
{ {
return write(buf, len, convertTime(timeSpec, clockRate)); return write(buf, len, convert_time(ts, clk_rt));
} }
std::string smpl_buf::str_status() const
uhd::time_spec_t SampleBuffer::convertTime(TIMESTAMP ticks, double rate)
{
double secs = (double) ticks / rate;
return uhd::time_spec_t(secs);
}
TIMESTAMP SampleBuffer::convertTime(uhd::time_spec_t timeSpec, double rate)
{
size_t secTicks = timeSpec.get_full_secs() * rate;
return timeSpec.get_tick_count(rate) + secTicks;
}
std::string SampleBuffer::stringStatus() const
{ {
std::ostringstream ost("Sample buffer: "); std::ostringstream ost("Sample buffer: ");
ost << "length = " << bufferLen; ost << "length = " << buf_len;
ost << ", timeStart = " << timeStart; ost << ", time_start = " << time_start;
ost << ", timeEnd = " << timeEnd; ost << ", time_end = " << time_end;
ost << ", dataStart = " << dataStart; ost << ", data_start = " << data_start;
ost << ", dataEnd = " << dataEnd; ost << ", data_end = " << data_end;
return ost.str(); return ost.str();
} }
std::string smpl_buf::str_code(ssize_t code)
std::string SampleBuffer::stringCode(ssize_t code)
{ {
switch (code) { switch (code) {
case ERROR_TIMESTAMP: case ERROR_TIMESTAMP:
@ -711,8 +730,7 @@ std::string SampleBuffer::stringCode(ssize_t code)
} }
} }
Device *Device::make(double smpl_rt, bool skip_rx)
Device *Device::make(double sampleRate, bool skipRx)
{ {
return new UHDDevice(sampleRate, skipRx); return new uhd_device(smpl_rt, skip_rx);
} }