aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2010-06-24 20:29:11 -0700
committerJosh Blum <josh@joshknows.com>2010-06-24 20:29:11 -0700
commit51cb8da5837adacbc626ee20aa58264e1b4b7a78 (patch)
treef83bd594377bcafd7e42b92be82ccc157f6e888c
parentfadd3a44a84e061412accd35c1c97db820190df8 (diff)
downloaduhd-51cb8da5837adacbc626ee20aa58264e1b4b7a78.tar.gz
uhd-51cb8da5837adacbc626ee20aa58264e1b4b7a78.tar.bz2
uhd-51cb8da5837adacbc626ee20aa58264e1b4b7a78.zip
uhd: reworked time_spec_t to be more flexible: arithmetic, comparison operators...
Replaced nsecs with fractional seconds in units of seconds. Replaced nsecs and secs members with public function members. time_spec_t has a more diverse set of constructors and methods. It can handle the cases where frac secs are greater than 1 second.
-rw-r--r--host/examples/benchmark_rx_rate.cpp13
-rw-r--r--host/examples/rx_timed_samples.cpp10
-rw-r--r--host/examples/tx_timed_samples.cpp6
-rw-r--r--host/include/uhd/types/time_spec.hpp82
-rwxr-xr-xhost/lib/transport/gen_vrt.py10
-rw-r--r--host/lib/types.cpp52
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp8
-rw-r--r--host/test/vrt_test.cpp10
8 files changed, 105 insertions, 86 deletions
diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp
index 2ab98bc22..53f4a3c68 100644
--- a/host/examples/benchmark_rx_rate.cpp
+++ b/host/examples/benchmark_rx_rate.cpp
@@ -26,15 +26,6 @@
namespace po = boost::program_options;
-//TODO add time spec diff to API
-static inline double time_spec_diff(
- uhd::time_spec_t time_spec_begin,
- uhd::time_spec_t time_spec_end
-){
- return (time_spec_end.secs - time_spec_begin.secs) + \
- ((time_spec_end.nsecs - time_spec_begin.nsecs)*1e-9);
-}
-
static inline void test_device(
uhd::usrp::simple_usrp::sptr sdev,
double rx_rate_sps,
@@ -80,10 +71,10 @@ static inline void test_device(
got_first_packet = true;
}
- total_lost_samples += boost::math::iround(rx_rate_sps*time_spec_diff(next_expected_time_spec, md.time_spec));
+ total_lost_samples += boost::math::iround(rx_rate_sps*(md.time_spec - next_expected_time_spec).get_real_secs());
next_expected_time_spec = md.time_spec + uhd::time_spec_t(0, num_rx_samps, rx_rate_sps);
- } while(time_spec_diff(initial_time_spec, next_expected_time_spec) < duration_secs);
+ } while((next_expected_time_spec - initial_time_spec) < uhd::time_spec_t(duration_secs));
sdev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
//flush the buffers
diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp
index adc745024..8db312690 100644
--- a/host/examples/rx_timed_samples.cpp
+++ b/host/examples/rx_timed_samples.cpp
@@ -30,7 +30,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//variables to be set by po
std::string args;
- int seconds_in_future;
+ time_t seconds_in_future;
size_t total_num_samps;
double rx_rate, freq;
@@ -39,7 +39,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
desc.add_options()
("help", "help message")
("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args")
- ("secs", po::value<int>(&seconds_in_future)->default_value(3), "number of seconds in the future to receive")
+ ("secs", po::value<time_t>(&seconds_in_future)->default_value(3), "number of seconds in the future to receive")
("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to receive")
("rxrate", po::value<double>(&rx_rate)->default_value(100e6/16), "rate of incoming samples")
("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")
@@ -67,7 +67,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << boost::format("Actual RX Rate: %f Msps...") % (sdev->get_rx_rate()/1e6) << std::endl;
std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
sdev->set_rx_freq(freq);
- sdev->set_time_now(uhd::time_spec_t(0));
+ sdev->set_time_now(uhd::time_spec_t(0.0));
//setup streaming
std::cout << std::endl;
@@ -95,8 +95,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
}
if (num_rx_samps == 0) continue; //wait for packets with contents
- std::cout << boost::format("Got packet: %u samples, %u secs, %u nsecs")
- % num_rx_samps % md.time_spec.secs % md.time_spec.nsecs << std::endl;
+ std::cout << boost::format("Got packet: %u samples, %u full secs, %f frac secs")
+ % num_rx_samps % md.time_spec.get_full_secs() % md.time_spec.get_frac_secs() << std::endl;
num_acc_samps += num_rx_samps;
}
diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp
index 28fd2ee67..333f03fbe 100644
--- a/host/examples/tx_timed_samples.cpp
+++ b/host/examples/tx_timed_samples.cpp
@@ -30,7 +30,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//variables to be set by po
std::string args;
- int seconds_in_future;
+ time_t seconds_in_future;
size_t total_num_samps;
double tx_rate, freq;
float ampl;
@@ -40,7 +40,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
desc.add_options()
("help", "help message")
("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args")
- ("secs", po::value<int>(&seconds_in_future)->default_value(3), "number of seconds in the future to transmit")
+ ("secs", po::value<time_t>(&seconds_in_future)->default_value(3), "number of seconds in the future to transmit")
("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to transmit")
("txrate", po::value<double>(&tx_rate)->default_value(100e6/16), "rate of outgoing samples")
("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")
@@ -69,7 +69,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << boost::format("Actual TX Rate: %f Msps...") % (sdev->get_tx_rate()/1e6) << std::endl;
std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
sdev->set_tx_freq(freq);
- sdev->set_time_now(uhd::time_spec_t(0));
+ sdev->set_time_now(uhd::time_spec_t(0.0));
//data to send
std::vector<std::complex<float> > buff(total_num_samps, std::complex<float>(ampl, ampl));
diff --git a/host/include/uhd/types/time_spec.hpp b/host/include/uhd/types/time_spec.hpp
index 7353c6e25..59b85f4b7 100644
--- a/host/include/uhd/types/time_spec.hpp
+++ b/host/include/uhd/types/time_spec.hpp
@@ -19,68 +19,75 @@
#define INCLUDED_UHD_TYPES_TIME_SPEC_HPP
#include <uhd/config.hpp>
-#include <boost/cstdint.hpp>
#include <boost/operators.hpp>
+#include <ctime>
namespace uhd{
/*!
- * A time_spec_t holds a seconds and fractional seconds time value.
- * The time_spec_t can be used when setting the time on devices,
- * and for dealing with time stamped samples though the metadata.
- * and for controlling the start of streaming for applicable dsps.
+ * A time_spec_t holds a seconds and a fractional seconds time value.
+ * Depending upon usage, the time_spec_t can represent absolute times,
+ * relative times, or time differences (between absolute times).
*
- * The fractional seconds are represented in units of nanoseconds,
- * which provide a clock-domain independent unit of time storage.
- * The methods "get_ticks" and "set_ticks" can be used to convert
- * the fractional seconds to and from clock-domain specific units.
+ * The time_spec_t provides clock-domain independent time storage,
+ * but can convert fractional seconds to/from clock-domain specific units.
*
- * The nanoseconds count is stored as double precision floating point.
+ * The fractional seconds are stored as double precision floating point.
* This gives the fractional seconds enough precision to unambiguously
* specify a clock-tick/sample-count up to rates of several petahertz.
*/
- struct UHD_API time_spec_t:
- boost::addable<time_spec_t>,
- boost::subtractable<time_spec_t>,
- boost::equality_comparable<time_spec_t>{
+ class UHD_API time_spec_t : boost::additive<time_spec_t>, boost::totally_ordered<time_spec_t>{
+ public:
- //! whole/integer seconds count in seconds
- boost::uint32_t secs;
+ /*!
+ * Create a time_spec_t from a real-valued seconds count.
+ * \param secs the real-valued seconds count (default = 0)
+ */
+ time_spec_t(double secs = 0);
- //! fractional seconds count in nano-seconds
- double nsecs;
+ /*!
+ * Create a time_spec_t from whole and fractional seconds.
+ * \param full_secs the whole/integer seconds count
+ * \param frac_secs the fractional seconds count (default = 0)
+ */
+ time_spec_t(time_t full_secs, double frac_secs = 0);
+
+ /*!
+ * Create a time_spec_t from whole and fractional seconds.
+ * Translation from clock-domain specific units.
+ * \param full_secs the whole/integer seconds count
+ * \param tick_count the fractional seconds tick count
+ * \param tick_rate the number of ticks per second
+ */
+ time_spec_t(time_t full_secs, size_t tick_count, double tick_rate);
/*!
- * Convert the fractional nsecs to clock ticks.
+ * Convert the fractional seconds to clock ticks.
* Translation into clock-domain specific units.
* \param tick_rate the number of ticks per second
* \return the fractional seconds tick count
*/
- boost::uint32_t get_ticks(double tick_rate) const;
+ size_t get_tick_count(double tick_rate) const;
/*!
- * Set the fractional nsecs from clock ticks.
- * Translation from clock-domain specific units.
- * \param ticks the fractional seconds tick count
- * \param tick_rate the number of ticks per second
+ * Get the time as a real-valued seconds count.
+ * Note: If this time_spec_t represents an absolute time,
+ * the precision of the fractional seconds may be lost.
+ * \return the real-valued seconds
*/
- void set_ticks(boost::uint32_t ticks, double tick_rate);
+ double get_real_secs(void) const;
/*!
- * Create a time_spec_t from whole and fractional seconds.
- * \param secs the whole/integer seconds count in seconds (default = 0)
- * \param nsecs the fractional seconds count in nanoseconds (default = 0)
+ * Get the whole/integer part of the time in seconds.
+ * \return the whole/integer seconds
*/
- time_spec_t(boost::uint32_t secs = 0, double nsecs = 0);
+ time_t get_full_secs(void) const;
/*!
- * Create a time_spec_t from whole and fractional seconds.
- * Translation from clock-domain specific units.
- * \param secs the whole/integer seconds count in seconds
- * \param ticks the fractional seconds tick count
- * \param tick_rate the number of ticks per second
+ * Get the fractional part of the time in seconds.
+ * \return the fractional seconds
*/
- time_spec_t(boost::uint32_t secs, boost::uint32_t ticks, double tick_rate);
+ double get_frac_secs(void) const;
//! Implement addable interface
time_spec_t &operator+=(const time_spec_t &);
@@ -88,11 +95,16 @@ namespace uhd{
//! Implement subtractable interface
time_spec_t &operator-=(const time_spec_t &);
+ //private time storage details
+ private: time_t _full_secs; double _frac_secs;
};
//! Implement equality_comparable interface
UHD_API bool operator==(const time_spec_t &, const time_spec_t &);
+ //! Implement less_than_comparable interface
+ UHD_API bool operator<(const time_spec_t &, const time_spec_t &);
+
} //namespace uhd
#endif /* INCLUDED_UHD_TYPES_TIME_SPEC_HPP */
diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py
index d1e553c41..8e0fce9ff 100755
--- a/host/lib/transport/gen_vrt.py
+++ b/host/lib/transport/gen_vrt.py
@@ -97,7 +97,7 @@ void vrt::pack_$(suffix)(
#end if
########## Integer Time ##########
#if $pred & $tsi_p
- header_buff[$num_header_words] = $(XE_MACRO)(metadata.time_spec.secs);
+ header_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(metadata.time_spec.get_full_secs()));
#set $num_header_words += 1
#set $flags |= (0x3 << 22);
#end if
@@ -105,7 +105,7 @@ void vrt::pack_$(suffix)(
#if $pred & $tsf_p
header_buff[$num_header_words] = 0;
#set $num_header_words += 1
- header_buff[$num_header_words] = $(XE_MACRO)(metadata.time_spec.get_ticks(tick_rate));
+ header_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(metadata.time_spec.get_tick_count(tick_rate)));
#set $num_header_words += 1
#set $flags |= (0x1 << 20);
#end if
@@ -147,6 +147,7 @@ void vrt::unpack_$(suffix)(
){
//clear the metadata
metadata = rx_metadata_t();
+ boost::uint32_t secs = 0, ticks = 0;
//extract vrt header
boost::uint32_t vrt_hdr_word = $(XE_MACRO)(header_buff[0]);
@@ -185,18 +186,19 @@ void vrt::unpack_$(suffix)(
########## Integer Time ##########
#if $pred & $tsi_p
#set $has_time_spec = True
- metadata.time_spec.secs = $(XE_MACRO)(header_buff[$num_header_words]);
+ secs = $(XE_MACRO)(header_buff[$num_header_words]);
#set $num_header_words += 1
#end if
########## Fractional Time ##########
#if $pred & $tsf_p
#set $has_time_spec = True
#set $num_header_words += 1
- metadata.time_spec.set_ticks($(XE_MACRO)(header_buff[$num_header_words]), tick_rate);
+ ticks = $(XE_MACRO)(header_buff[$num_header_words]);
#set $num_header_words += 1
#end if
#if $has_time_spec
metadata.has_time_spec = true;
+ metadata.time_spec = time_spec_t(secs, ticks, tick_rate);
#end if
########## Trailer ##########
#if $pred & $tlr_p
diff --git a/host/lib/types.cpp b/host/lib/types.cpp
index 78a3d22ce..6a9fcf5b5 100644
--- a/host/lib/types.cpp
+++ b/host/lib/types.cpp
@@ -120,47 +120,63 @@ tx_metadata_t::tx_metadata_t(void):
/***********************************************************************
* time spec
**********************************************************************/
-static inline void time_spec_normalize(time_spec_t &time_spec){
- time_spec.secs += boost::uint32_t(std::ceil(time_spec.nsecs/1e9));
- time_spec.nsecs = std::fmod(time_spec.nsecs, 1e9);
+time_spec_t::time_spec_t(double secs):
+ _full_secs(0),
+ _frac_secs(secs)
+{
+ /* NOP */
}
-time_spec_t::time_spec_t(boost::uint32_t secs, double nsecs):
- secs(secs),
- nsecs(nsecs)
+time_spec_t::time_spec_t(time_t full_secs, double frac_secs):
+ _full_secs(full_secs),
+ _frac_secs(frac_secs)
{
/* NOP */
}
-time_spec_t::time_spec_t(boost::uint32_t secs, boost::uint32_t ticks, double tick_rate):
- secs(secs),
- nsecs(double(ticks)*1e9/tick_rate)
+time_spec_t::time_spec_t(time_t full_secs, size_t tick_count, double tick_rate):
+ _full_secs(full_secs),
+ _frac_secs(double(tick_count)/tick_rate)
{
/* NOP */
}
-boost::uint32_t time_spec_t::get_ticks(double tick_rate) const{
- return boost::math::iround(nsecs*tick_rate*1e-9);
+size_t time_spec_t::get_tick_count(double tick_rate) const{
+ return boost::math::iround(this->get_frac_secs()*tick_rate);
+}
+
+double time_spec_t::get_real_secs(void) const{
+ return this->_full_secs + this->_frac_secs;
}
-void time_spec_t::set_ticks(boost::uint32_t ticks, double tick_rate){
- nsecs = double(ticks)*1e9/tick_rate;
+time_t time_spec_t::get_full_secs(void) const{
+ return this->_full_secs + time_t(std::floor(this->_frac_secs));
+}
+
+double time_spec_t::get_frac_secs(void) const{
+ return std::fmod(this->_frac_secs, 1.0);
}
time_spec_t &time_spec_t::operator+=(const time_spec_t &rhs){
- this->secs += rhs.secs;
- this->nsecs += rhs.nsecs;
+ this->_full_secs += rhs.get_full_secs();
+ this->_frac_secs += rhs.get_frac_secs();
return *this;
}
time_spec_t &time_spec_t::operator-=(const time_spec_t &rhs){
- this->secs -= rhs.secs;
- this->nsecs -= rhs.nsecs;
+ this->_full_secs -= rhs.get_full_secs();
+ this->_frac_secs -= rhs.get_frac_secs();
return *this;
}
bool uhd::operator==(const time_spec_t &lhs, const time_spec_t &rhs){
- return lhs.secs == rhs.secs and lhs.nsecs == rhs.nsecs;
+ return lhs.get_full_secs() == rhs.get_full_secs() and lhs.get_frac_secs() == rhs.get_frac_secs();
+}
+
+bool uhd::operator<(const time_spec_t &lhs, const time_spec_t &rhs){
+ if (lhs.get_full_secs() < rhs.get_full_secs()) return true;
+ if (lhs.get_full_secs() > rhs.get_full_secs()) return false;
+ return lhs.get_frac_secs() < rhs.get_frac_secs();
}
/***********************************************************************
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index 78fc5dc23..1a0f9916b 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -84,14 +84,14 @@ void usrp2_impl::update_clock_config(void){
void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){
//set the ticks
- _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_ticks(get_master_clock_freq()));
+ _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_tick_count(get_master_clock_freq()));
//set the flags register
boost::uint32_t imm_flags = (now)? U2_FLAG_TIME64_LATCH_NOW : U2_FLAG_TIME64_LATCH_NEXT_PPS;
_iface->poke32(U2_REG_TIME64_IMM, imm_flags);
//set the seconds (latches in all 3 registers)
- _iface->poke32(U2_REG_TIME64_SECS, time_spec.secs);
+ _iface->poke32(U2_REG_TIME64_SECS, time_spec.get_full_secs());
}
void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
@@ -118,8 +118,8 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
(inst_chain)? 1 : 0,
(inst_reload)? 1 : 0
));
- _iface->poke32(U2_REG_RX_CTRL_TIME_SECS, stream_cmd.time_spec.secs);
- _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_ticks(get_master_clock_freq()));
+ _iface->poke32(U2_REG_RX_CTRL_TIME_SECS, stream_cmd.time_spec.get_full_secs());
+ _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(get_master_clock_freq()));
}
/***********************************************************************
diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp
index 3e596164c..3776e33aa 100644
--- a/host/test/vrt_test.cpp
+++ b/host/test/vrt_test.cpp
@@ -66,8 +66,8 @@ static void pack_and_unpack(
}
BOOST_CHECK_EQUAL(metadata.has_time_spec, metadata_out.has_time_spec);
if (metadata.has_time_spec and metadata_out.has_time_spec){
- BOOST_CHECK_EQUAL(metadata.time_spec.secs, metadata_out.time_spec.secs);
- BOOST_CHECK_EQUAL(metadata.time_spec.nsecs, metadata_out.time_spec.nsecs);
+ BOOST_CHECK_EQUAL(metadata.time_spec.get_full_secs(), metadata_out.time_spec.get_full_secs());
+ BOOST_CHECK_EQUAL(metadata.time_spec.get_frac_secs(), metadata_out.time_spec.get_frac_secs());
}
}
@@ -86,8 +86,7 @@ BOOST_AUTO_TEST_CASE(test_with_sid){
BOOST_AUTO_TEST_CASE(test_with_time_spec){
uhd::tx_metadata_t metadata;
metadata.has_time_spec = true;
- metadata.time_spec.secs = 7;
- metadata.time_spec.nsecs = 2000;
+ metadata.time_spec = uhd::time_spec_t(7, 0.2);
pack_and_unpack(metadata, 500, 3);
}
@@ -96,7 +95,6 @@ BOOST_AUTO_TEST_CASE(test_with_sid_and_time_spec){
metadata.has_stream_id = true;
metadata.stream_id = 2;
metadata.has_time_spec = true;
- metadata.time_spec.secs = 5;
- metadata.time_spec.nsecs = 1000;
+ metadata.time_spec = uhd::time_spec_t(5, 0.1);
pack_and_unpack(metadata, 600, 4);
}