summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2012-02-06 16:40:42 -0800
committerJosh Blum <josh@joshknows.com>2012-02-06 16:40:42 -0800
commit5eec31fab45649b529428cda756d04bcdaeb3134 (patch)
treef130af1d4c7cdacef74a4918a1d72d3f3facadec
parent5c56ca574ffdf7ad469ab3a3f54def944a978bee (diff)
downloaduhd-5eec31fab45649b529428cda756d04bcdaeb3134.tar.gz
uhd-5eec31fab45649b529428cda756d04bcdaeb3134.tar.bz2
uhd-5eec31fab45649b529428cda756d04bcdaeb3134.zip
dsp rework: implement 64 bit ticks, no seconds
-rw-r--r--host/include/uhd/types/time_spec.hpp20
-rw-r--r--host/lib/transport/super_recv_packet_handler.hpp8
-rw-r--r--host/lib/transport/super_send_packet_handler.hpp12
-rw-r--r--host/lib/types/time_spec.cpp29
-rw-r--r--host/lib/usrp/b100/b100_impl.cpp8
-rw-r--r--host/lib/usrp/b100/b100_regs.hpp8
-rw-r--r--host/lib/usrp/b100/io_impl.cpp8
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_200.cpp10
-rw-r--r--host/lib/usrp/cores/time64_core_200.cpp34
-rw-r--r--host/lib/usrp/cores/time64_core_200.hpp4
-rw-r--r--host/lib/usrp/e100/e100_impl.cpp8
-rw-r--r--host/lib/usrp/e100/e100_regs.hpp8
-rw-r--r--host/lib/usrp/e100/io_impl.cpp8
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp8
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp4
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp8
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp8
-rw-r--r--host/tests/sph_recv_test.cpp24
-rw-r--r--host/tests/sph_send_test.cpp6
-rw-r--r--host/tests/time_spec_test.cpp6
20 files changed, 120 insertions, 109 deletions
diff --git a/host/include/uhd/types/time_spec.hpp b/host/include/uhd/types/time_spec.hpp
index 02de20ea1..cf8588c5b 100644
--- a/host/include/uhd/types/time_spec.hpp
+++ b/host/include/uhd/types/time_spec.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -60,7 +60,7 @@ namespace uhd{
time_spec_t(time_t full_secs, double frac_secs = 0);
/*!
- * Create a time_spec_t from whole and fractional seconds.
+ * Create a time_spec_t from whole seconds and fractional ticks.
* Translation from clock-domain specific units.
* \param full_secs the whole/integer seconds count
* \param tick_count the fractional seconds tick count
@@ -69,6 +69,14 @@ namespace uhd{
time_spec_t(time_t full_secs, long tick_count, double tick_rate);
/*!
+ * Create a time_spec_t from a 64-bit tick count.
+ * Translation from clock-domain specific units.
+ * \param ticks an integer count of ticks
+ * \param tick_rate the number of ticks per second
+ */
+ static time_spec_t from_ticks(long long ticks, double tick_rate);
+
+ /*!
* Convert the fractional seconds to clock ticks.
* Translation into clock-domain specific units.
* \param tick_rate the number of ticks per second
@@ -77,6 +85,14 @@ namespace uhd{
long get_tick_count(double tick_rate) const;
/*!
+ * Convert the time spec into a 64-bit tick count.
+ * Translation into clock-domain specific units.
+ * \param tick_rate the number of ticks per second
+ * \return an integer number of ticks
+ */
+ long long to_ticks(const double tick_rate) const;
+
+ /*!
* 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.
diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp
index a5876c8bf..939e7aeb3 100644
--- a/host/lib/transport/super_recv_packet_handler.hpp
+++ b/host/lib/transport/super_recv_packet_handler.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -283,7 +283,7 @@ private:
info.ifpi.num_packet_words32 = num_packet_words32 - _header_offset_words32;
info.vrt_hdr = buff->cast<const boost::uint32_t *>() + _header_offset_words32;
_vrt_unpacker(info.vrt_hdr, info.ifpi);
- info.time = time_spec_t(time_t(info.ifpi.tsi), size_t(info.ifpi.tsf), _tick_rate); //assumes has_tsi and has_tsf are true
+ info.time = time_spec_t::from_ticks(info.ifpi.tsf, _tick_rate); //assumes has_tsf is true
info.copy_buff = reinterpret_cast<const char *>(info.vrt_hdr + info.ifpi.num_header_words32);
//--------------------------------------------------------------
@@ -436,7 +436,7 @@ private:
alignment_check(index, curr_info);
std::swap(curr_info, next_info); //save progress from curr -> next
curr_info.metadata.has_time_spec = prev_info.metadata.has_time_spec;
- curr_info.metadata.time_spec = prev_info.metadata.time_spec + time_spec_t(0,
+ curr_info.metadata.time_spec = prev_info.metadata.time_spec + time_spec_t::from_ticks(
prev_info[index].ifpi.num_payload_words32*sizeof(boost::uint32_t)/_bytes_per_otw_item, _samp_rate);
curr_info.metadata.more_fragments = false;
curr_info.metadata.fragment_offset = 0;
@@ -508,7 +508,7 @@ private:
metadata = info.metadata;
//interpolate the time spec (useful when this is a fragment)
- metadata.time_spec += time_spec_t(0, info.fragment_offset_in_samps, _samp_rate);
+ metadata.time_spec += time_spec_t::from_ticks(info.fragment_offset_in_samps, _samp_rate);
//extract the number of samples available to copy
const size_t nsamps_available = info.data_bytes_to_copy/_bytes_per_otw_item;
diff --git a/host/lib/transport/super_send_packet_handler.hpp b/host/lib/transport/super_send_packet_handler.hpp
index 57304a7d4..3d68507ed 100644
--- a/host/lib/transport/super_send_packet_handler.hpp
+++ b/host/lib/transport/super_send_packet_handler.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -135,10 +135,9 @@ public:
if_packet_info.has_sid = false;
if_packet_info.has_cid = false;
if_packet_info.has_tlr = true;
- if_packet_info.has_tsi = metadata.has_time_spec;
+ if_packet_info.has_tsi = false;
if_packet_info.has_tsf = metadata.has_time_spec;
- if_packet_info.tsi = boost::uint32_t(metadata.time_spec.get_full_secs());
- if_packet_info.tsf = boost::uint64_t(metadata.time_spec.get_tick_count(_tick_rate));
+ if_packet_info.tsf = metadata.time_spec.to_ticks(_tick_rate);
if_packet_info.sob = metadata.start_of_burst;
if_packet_info.eob = metadata.end_of_burst;
@@ -174,9 +173,8 @@ public:
if (num_samps_sent == 0) return total_num_samps_sent;
//setup metadata for the next fragment
- const time_spec_t time_spec = metadata.time_spec + time_spec_t(0, total_num_samps_sent, _samp_rate);
- if_packet_info.tsi = boost::uint32_t(time_spec.get_full_secs());
- if_packet_info.tsf = boost::uint64_t(time_spec.get_tick_count(_tick_rate));
+ const time_spec_t time_spec = metadata.time_spec + time_spec_t::from_ticks(total_num_samps_sent, _samp_rate);
+ if_packet_info.tsf = time_spec.to_ticks(_tick_rate);
if_packet_info.sob = false;
}
diff --git a/host/lib/types/time_spec.cpp b/host/lib/types/time_spec.cpp
index 8e540c14c..176ee8079 100644
--- a/host/lib/types/time_spec.cpp
+++ b/host/lib/types/time_spec.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
//
#include <uhd/types/time_spec.hpp>
+#include <inttypes.h> //imaxdiv, intmax_t
using namespace uhd;
@@ -23,18 +24,6 @@ using namespace uhd;
* Time spec system time
**********************************************************************/
-/*!
- * Creates a time spec from system counts:
- * TODO make part of API as a static factory function
- * The counts type is 64 bits and will overflow the ticks type of long.
- * Therefore, divmod the counts into seconds + sub-second counts first.
- */
-#include <inttypes.h> //imaxdiv, intmax_t
-static UHD_INLINE time_spec_t time_spec_t_from_counts(intmax_t counts, intmax_t freq){
- imaxdiv_t divres = imaxdiv(counts, freq);
- return time_spec_t(time_t(divres.quot), double(divres.rem)/freq);
-}
-
#ifdef HAVE_CLOCK_GETTIME
#include <time.h>
time_spec_t time_spec_t::get_system_time(void){
@@ -49,7 +38,7 @@ time_spec_t time_spec_t::get_system_time(void){
time_spec_t time_spec_t::get_system_time(void){
mach_timebase_info_data_t info; mach_timebase_info(&info);
intmax_t nanosecs = mach_absolute_time()*info.numer/info.denom;
- return time_spec_t_from_counts(nanosecs, intmax_t(1e9));
+ return time_spec_t::from_ticks(nanosecs, intmax_t(1e9));
}
#endif /* HAVE_MACH_ABSOLUTE_TIME */
@@ -60,7 +49,7 @@ time_spec_t time_spec_t::get_system_time(void){
LARGE_INTEGER counts, freq;
QueryPerformanceCounter(&counts);
QueryPerformanceFrequency(&freq);
- return time_spec_t_from_counts(counts.QuadPart, freq.QuadPart);
+ return time_spec_t::from_ticks(counts.QuadPart, freq.QuadPart);
}
#endif /* HAVE_QUERY_PERFORMANCE_COUNTER */
@@ -104,6 +93,11 @@ time_spec_t::time_spec_t(time_t full_secs, long tick_count, double tick_rate){
time_spec_init(full_secs, frac_secs);
}
+time_spec_t time_spec_t::from_ticks(long long ticks, double tick_rate){
+ const imaxdiv_t divres = imaxdiv(ticks, tick_rate);
+ return time_spec_t(time_t(divres.quot), double(divres.rem)/tick_rate);
+}
+
/***********************************************************************
* Time spec accessors
**********************************************************************/
@@ -111,6 +105,11 @@ long time_spec_t::get_tick_count(double tick_rate) const{
return long(this->get_frac_secs()*tick_rate + 0.5);
}
+long long time_spec_t::to_ticks(double tick_rate) const{
+ return (long long)(this->get_frac_secs()*tick_rate + 0.5) + \
+ (long long)((this->get_full_secs()) * (long long)(tick_rate));
+}
+
double time_spec_t::get_real_secs(void) const{
return this->_full_secs + this->_frac_secs;
}
diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp
index 08a2cdeec..ce0b9453b 100644
--- a/host/lib/usrp/b100/b100_impl.cpp
+++ b/host/lib/usrp/b100/b100_impl.cpp
@@ -364,10 +364,10 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
// create time control objects
////////////////////////////////////////////////////////////////////
time64_core_200::readback_bases_type time64_rb_bases;
- time64_rb_bases.rb_secs_now = B100_REG_RB_TIME_NOW_SECS;
- time64_rb_bases.rb_ticks_now = B100_REG_RB_TIME_NOW_TICKS;
- time64_rb_bases.rb_secs_pps = B100_REG_RB_TIME_PPS_SECS;
- time64_rb_bases.rb_ticks_pps = B100_REG_RB_TIME_PPS_TICKS;
+ time64_rb_bases.rb_hi_now = B100_REG_RB_TIME_NOW_HI;
+ time64_rb_bases.rb_lo_now = B100_REG_RB_TIME_NOW_LO;
+ time64_rb_bases.rb_hi_pps = B100_REG_RB_TIME_PPS_HI;
+ time64_rb_bases.rb_lo_pps = B100_REG_RB_TIME_PPS_LO;
_time64 = time64_core_200::make(
_fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TIME64), time64_rb_bases
);
diff --git a/host/lib/usrp/b100/b100_regs.hpp b/host/lib/usrp/b100/b100_regs.hpp
index 77b643372..987a09f03 100644
--- a/host/lib/usrp/b100/b100_regs.hpp
+++ b/host/lib/usrp/b100/b100_regs.hpp
@@ -76,10 +76,10 @@
#define B100_REG_RB_MUX_32_BASE B100_REG_SLAVE(7)
-#define B100_REG_RB_TIME_NOW_SECS B100_REG_RB_MUX_32_BASE + 0
-#define B100_REG_RB_TIME_NOW_TICKS B100_REG_RB_MUX_32_BASE + 4
-#define B100_REG_RB_TIME_PPS_SECS B100_REG_RB_MUX_32_BASE + 8
-#define B100_REG_RB_TIME_PPS_TICKS B100_REG_RB_MUX_32_BASE + 12
+#define B100_REG_RB_TIME_NOW_HI B100_REG_RB_MUX_32_BASE + 0
+#define B100_REG_RB_TIME_NOW_LO B100_REG_RB_MUX_32_BASE + 4
+#define B100_REG_RB_TIME_PPS_HI B100_REG_RB_MUX_32_BASE + 8
+#define B100_REG_RB_TIME_PPS_LO B100_REG_RB_MUX_32_BASE + 12
#define B100_REG_RB_MISC_TEST32 B100_REG_RB_MUX_32_BASE + 16
#define B100_REG_RB_COMPAT B100_REG_RB_MUX_32_BASE + 24
#define B100_REG_RB_GPIO B100_REG_RB_MUX_32_BASE + 28
diff --git a/host/lib/usrp/b100/io_impl.cpp b/host/lib/usrp/b100/io_impl.cpp
index ac7c860d2..bd60e75cf 100644
--- a/host/lib/usrp/b100/io_impl.cpp
+++ b/host/lib/usrp/b100/io_impl.cpp
@@ -84,10 +84,8 @@ void b100_impl::handle_async_message(managed_recv_buffer::sptr rbuf){
//fill in the async metadata
async_metadata_t metadata;
metadata.channel = 0;
- metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf;
- metadata.time_spec = time_spec_t(
- time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), _clock_ctrl->get_fpga_clock_rate()
- );
+ metadata.has_time_spec = if_packet_info.has_tsf;
+ metadata.time_spec = time_spec_t::from_ticks(if_packet_info.tsf, _clock_ctrl->get_fpga_clock_rate());
metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info));
_io_impl->async_msg_fifo.push_with_pop_on_full(metadata);
if (metadata.event_code &
@@ -206,6 +204,7 @@ rx_streamer::sptr b100_impl::get_rx_stream(const uhd::stream_args_t &args_){
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
+ sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
const size_t bpp = B100_MAX_PKT_BYTE_LIMIT - hdr_size;
const size_t bpi = convert::get_bytes_per_item(args.otw_format);
@@ -262,6 +261,7 @@ tx_streamer::sptr b100_impl::get_tx_stream(const uhd::stream_args_t &args_){
+ sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- sizeof(vrt::if_packet_info_t().sid) //no stream id ever used
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
static const size_t bpp = B100_MAX_PKT_BYTE_LIMIT - hdr_size;
const size_t spp = bpp/convert::get_bytes_per_item(args.otw_format);
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.cpp b/host/lib/usrp/cores/rx_dsp_core_200.cpp
index d9ca84e0f..ea0384dbe 100644
--- a/host/lib/usrp/cores/rx_dsp_core_200.cpp
+++ b/host/lib/usrp/cores/rx_dsp_core_200.cpp
@@ -36,8 +36,8 @@
#define FLAG_DSP_RX_MUX_REAL_MODE (1 << 1)
#define REG_RX_CTRL_STREAM_CMD _ctrl_base + 0
-#define REG_RX_CTRL_TIME_SECS _ctrl_base + 4
-#define REG_RX_CTRL_TIME_TICKS _ctrl_base + 8
+#define REG_RX_CTRL_TIME_HI _ctrl_base + 4
+#define REG_RX_CTRL_TIME_LO _ctrl_base + 8
#define REG_RX_CTRL_CLEAR _ctrl_base + 12
#define REG_RX_CTRL_VRT_HDR _ctrl_base + 16
#define REG_RX_CTRL_VRT_SID _ctrl_base + 20
@@ -83,7 +83,6 @@ public:
_iface->poke32(REG_RX_CTRL_VRT_HDR, 0
| (0x1 << 28) //if data with stream id
| (0x1 << 26) //has trailer
- | (0x3 << 22) //integer time other
| (0x1 << 20) //fractional time sample count
);
_iface->poke32(REG_RX_CTRL_VRT_SID, _sid);
@@ -122,8 +121,9 @@ public:
//issue the stream command
_iface->poke32(REG_RX_CTRL_STREAM_CMD, cmd_word);
- _iface->poke32(REG_RX_CTRL_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs()));
- _iface->poke32(REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(_tick_rate)); //latches the command
+ const boost::uint64_t ticks = stream_cmd.time_spec.to_ticks(_tick_rate);
+ _iface->poke32(REG_RX_CTRL_TIME_HI, boost::uint32_t(ticks >> 32));
+ _iface->poke32(REG_RX_CTRL_TIME_LO, boost::uint32_t(ticks >> 0)); //latches the command
}
void set_mux(const std::string &mode, const bool fe_swapped){
diff --git a/host/lib/usrp/cores/time64_core_200.cpp b/host/lib/usrp/cores/time64_core_200.cpp
index 23d1bdea2..e460d1106 100644
--- a/host/lib/usrp/cores/time64_core_200.cpp
+++ b/host/lib/usrp/cores/time64_core_200.cpp
@@ -20,11 +20,10 @@
#include <uhd/utils/assert_has.hpp>
#include <boost/math/special_functions/round.hpp>
-#define REG_TIME64_SECS _base + 0
-#define REG_TIME64_TICKS _base + 4
+#define REG_TIME64_TICKS_HI _base + 0
+#define REG_TIME64_TICKS_LO _base + 4
#define REG_TIME64_FLAGS _base + 8
#define REG_TIME64_IMM _base + 12
-#define REG_TIME64_TPS _base + 16
#define REG_TIME64_MIMO_SYNC _base + 20 //lower byte is delay cycles
//pps flags (see above)
@@ -59,39 +58,42 @@ public:
void set_tick_rate(const double rate){
_tick_rate = rate;
- _iface->poke32(REG_TIME64_TPS, boost::math::iround(rate));
}
uhd::time_spec_t get_time_now(void){
for (size_t i = 0; i < 3; i++){ //special algorithm because we cant read 64 bits synchronously
- const boost::uint32_t secs = _iface->peek32(_readback_bases.rb_secs_now);
- const boost::uint32_t ticks = _iface->peek32(_readback_bases.rb_ticks_now);
- if (secs != _iface->peek32(_readback_bases.rb_secs_now)) continue;
- return time_spec_t(secs, ticks, _tick_rate);
+ const boost::uint32_t ticks_hi = _iface->peek32(_readback_bases.rb_hi_now);
+ const boost::uint32_t ticks_lo = _iface->peek32(_readback_bases.rb_lo_now);
+ if (ticks_hi != _iface->peek32(_readback_bases.rb_hi_now)) continue;
+ const boost::uint64_t ticks = (boost::uint64_t(ticks_hi) << 32) | ticks_lo;
+ return time_spec_t::from_ticks(ticks, _tick_rate);
}
throw uhd::runtime_error("time64_core_200: get time now timeout");
}
uhd::time_spec_t get_time_last_pps(void){
for (size_t i = 0; i < 3; i++){ //special algorithm because we cant read 64 bits synchronously
- const boost::uint32_t secs = _iface->peek32(_readback_bases.rb_secs_pps);
- const boost::uint32_t ticks = _iface->peek32(_readback_bases.rb_ticks_pps);
- if (secs != _iface->peek32(_readback_bases.rb_secs_pps)) continue;
- return time_spec_t(secs, ticks, _tick_rate);
+ const boost::uint32_t ticks_hi = _iface->peek32(_readback_bases.rb_hi_pps);
+ const boost::uint32_t ticks_lo = _iface->peek32(_readback_bases.rb_lo_pps);
+ if (ticks_hi != _iface->peek32(_readback_bases.rb_hi_pps)) continue;
+ const boost::uint64_t ticks = (boost::uint64_t(ticks_hi) << 32) | ticks_lo;
+ return time_spec_t::from_ticks(ticks, _tick_rate);
}
throw uhd::runtime_error("time64_core_200: get time last pps timeout");
}
void set_time_now(const uhd::time_spec_t &time){
- _iface->poke32(REG_TIME64_TICKS, time.get_tick_count(_tick_rate));
+ const boost::uint64_t ticks = time.to_ticks(_tick_rate);
+ _iface->poke32(REG_TIME64_TICKS_LO, boost::uint32_t(ticks >> 0));
_iface->poke32(REG_TIME64_IMM, FLAG_TIME64_LATCH_NOW);
- _iface->poke32(REG_TIME64_SECS, boost::uint32_t(time.get_full_secs())); //latches all 3
+ _iface->poke32(REG_TIME64_TICKS_HI, boost::uint32_t(ticks >> 32)); //latches all 3
}
void set_time_next_pps(const uhd::time_spec_t &time){
- _iface->poke32(REG_TIME64_TICKS, time.get_tick_count(_tick_rate));
+ const boost::uint64_t ticks = time.to_ticks(_tick_rate);
+ _iface->poke32(REG_TIME64_TICKS_LO, boost::uint32_t(ticks >> 0));
_iface->poke32(REG_TIME64_IMM, FLAG_TIME64_LATCH_NEXT_PPS);
- _iface->poke32(REG_TIME64_SECS, boost::uint32_t(time.get_full_secs())); //latches all 3
+ _iface->poke32(REG_TIME64_TICKS_HI, boost::uint32_t(ticks >> 32)); //latches all 3
}
void set_time_source(const std::string &source){
diff --git a/host/lib/usrp/cores/time64_core_200.hpp b/host/lib/usrp/cores/time64_core_200.hpp
index ebd51a02f..7571573a5 100644
--- a/host/lib/usrp/cores/time64_core_200.hpp
+++ b/host/lib/usrp/cores/time64_core_200.hpp
@@ -31,8 +31,8 @@ public:
typedef boost::shared_ptr<time64_core_200> sptr;
struct readback_bases_type{
- size_t rb_secs_now, rb_ticks_now;
- size_t rb_secs_pps, rb_ticks_pps;
+ size_t rb_hi_now, rb_lo_now;
+ size_t rb_hi_pps, rb_lo_pps;
};
//! makes a new time64 core from iface and slave base
diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp
index 8ab6ab533..a01ce4a7b 100644
--- a/host/lib/usrp/e100/e100_impl.cpp
+++ b/host/lib/usrp/e100/e100_impl.cpp
@@ -326,10 +326,10 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
// create time control objects
////////////////////////////////////////////////////////////////////
time64_core_200::readback_bases_type time64_rb_bases;
- time64_rb_bases.rb_secs_now = E100_REG_RB_TIME_NOW_SECS;
- time64_rb_bases.rb_ticks_now = E100_REG_RB_TIME_NOW_TICKS;
- time64_rb_bases.rb_secs_pps = E100_REG_RB_TIME_PPS_SECS;
- time64_rb_bases.rb_ticks_pps = E100_REG_RB_TIME_PPS_TICKS;
+ time64_rb_bases.rb_hi_now = E100_REG_RB_TIME_NOW_HI;
+ time64_rb_bases.rb_lo_now = E100_REG_RB_TIME_NOW_LO;
+ time64_rb_bases.rb_hi_pps = E100_REG_RB_TIME_PPS_HI;
+ time64_rb_bases.rb_lo_pps = E100_REG_RB_TIME_PPS_LO;
_time64 = time64_core_200::make(
_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TIME64), time64_rb_bases
);
diff --git a/host/lib/usrp/e100/e100_regs.hpp b/host/lib/usrp/e100/e100_regs.hpp
index 0ec5f4de3..75be2cfbe 100644
--- a/host/lib/usrp/e100/e100_regs.hpp
+++ b/host/lib/usrp/e100/e100_regs.hpp
@@ -86,10 +86,10 @@
#define E100_REG_RB_MUX_32_BASE E100_REG_SLAVE(7)
-#define E100_REG_RB_TIME_NOW_SECS E100_REG_RB_MUX_32_BASE + 0
-#define E100_REG_RB_TIME_NOW_TICKS E100_REG_RB_MUX_32_BASE + 4
-#define E100_REG_RB_TIME_PPS_SECS E100_REG_RB_MUX_32_BASE + 8
-#define E100_REG_RB_TIME_PPS_TICKS E100_REG_RB_MUX_32_BASE + 12
+#define E100_REG_RB_TIME_NOW_HI E100_REG_RB_MUX_32_BASE + 0
+#define E100_REG_RB_TIME_NOW_LO E100_REG_RB_MUX_32_BASE + 4
+#define E100_REG_RB_TIME_PPS_HI E100_REG_RB_MUX_32_BASE + 8
+#define E100_REG_RB_TIME_PPS_LO E100_REG_RB_MUX_32_BASE + 12
#define E100_REG_RB_MISC_TEST32 E100_REG_RB_MUX_32_BASE + 16
#define E100_REG_RB_ERR_STATUS E100_REG_RB_MUX_32_BASE + 20
#define E100_REG_RB_COMPAT E100_REG_RB_MUX_32_BASE + 24
diff --git a/host/lib/usrp/e100/io_impl.cpp b/host/lib/usrp/e100/io_impl.cpp
index 8c7f5e742..f8e15f3fd 100644
--- a/host/lib/usrp/e100/io_impl.cpp
+++ b/host/lib/usrp/e100/io_impl.cpp
@@ -124,10 +124,8 @@ void e100_impl::io_impl::handle_irq(void){
//fill in the async metadata
async_metadata_t metadata;
metadata.channel = 0;
- metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf;
- metadata.time_spec = time_spec_t(
- time_t(if_packet_info.tsi), long(if_packet_info.tsf), tick_rate
- );
+ metadata.has_time_spec = if_packet_info.has_tsf;
+ metadata.time_spec = time_spec_t::from_ticks(if_packet_info.tsf, tick_rate);
metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(data.buf, if_packet_info));
//push the message onto the queue
@@ -285,6 +283,7 @@ rx_streamer::sptr e100_impl::get_rx_stream(const uhd::stream_args_t &args_){
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
+ sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
const size_t bpp = _data_transport->get_recv_frame_size() - hdr_size;
const size_t bpi = convert::get_bytes_per_item(args.otw_format);
@@ -341,6 +340,7 @@ tx_streamer::sptr e100_impl::get_tx_stream(const uhd::stream_args_t &args_){
+ sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- sizeof(vrt::if_packet_info_t().sid) //no stream id ever used
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
static const size_t bpp = _data_transport->get_send_frame_size() - hdr_size;
const size_t spp = bpp/convert::get_bytes_per_item(args.otw_format);
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index f19f49e28..f0c159f16 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -202,10 +202,8 @@ void usrp2_impl::io_impl::recv_pirate_loop(
//fill in the async metadata
async_metadata_t metadata;
metadata.channel = index;
- metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf;
- metadata.time_spec = time_spec_t(
- time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), tick_rate
- );
+ metadata.has_time_spec = if_packet_info.has_tsf;
+ metadata.time_spec = time_spec_t::from_ticks(if_packet_info.tsf, tick_rate);
metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info));
//catch the flow control packets and react
@@ -388,6 +386,7 @@ rx_streamer::sptr usrp2_impl::get_rx_stream(const uhd::stream_args_t &args_){
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
+ sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
const size_t bpp = _mbc[_mbc.keys().front()].rx_dsp_xports[0]->get_recv_frame_size() - hdr_size;
const size_t bpi = convert::get_bytes_per_item(args.otw_format);
@@ -454,6 +453,7 @@ tx_streamer::sptr usrp2_impl::get_tx_stream(const uhd::stream_args_t &args_){
+ sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
- sizeof(vrt::if_packet_info_t().sid) //no stream id ever used
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
const size_t bpp = _mbc[_mbc.keys().front()].tx_dsp_xport->get_send_frame_size() - hdr_size;
const size_t spp = bpp/convert::get_bytes_per_item(args.otw_format);
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index 4830c10d9..f3d474a2d 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -126,7 +126,7 @@ public:
bool is_device_locked(void){
boost::uint32_t lock_secs = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_LOCK_TIME);
boost::uint32_t lock_gpid = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_LOCK_GPID);
- boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_SECS_RB_IMM);
+ boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_LO_RB_IMM)/100e6;
//if the difference is larger, assume not locked anymore
if (curr_secs - lock_secs >= 3) return false;
@@ -137,7 +137,7 @@ public:
void lock_task(void){
//re-lock in task
- boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_SECS_RB_IMM);
+ boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_LO_RB_IMM)/100e6;
this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, curr_secs);
//sleep for a bit
boost::this_thread::sleep(boost::posix_time::milliseconds(1500));
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 7101e040a..2077ab009 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -546,10 +546,10 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
// create time control objects
////////////////////////////////////////////////////////////////
time64_core_200::readback_bases_type time64_rb_bases;
- time64_rb_bases.rb_secs_now = U2_REG_TIME64_SECS_RB_IMM;
- time64_rb_bases.rb_ticks_now = U2_REG_TIME64_TICKS_RB_IMM;
- time64_rb_bases.rb_secs_pps = U2_REG_TIME64_SECS_RB_PPS;
- time64_rb_bases.rb_ticks_pps = U2_REG_TIME64_TICKS_RB_PPS;
+ time64_rb_bases.rb_hi_now = U2_REG_TIME64_HI_RB_IMM;
+ time64_rb_bases.rb_lo_now = U2_REG_TIME64_LO_RB_IMM;
+ time64_rb_bases.rb_hi_pps = U2_REG_TIME64_HI_RB_PPS;
+ time64_rb_bases.rb_lo_pps = U2_REG_TIME64_LO_RB_PPS;
_mbc[mb].time64 = time64_core_200::make(
_mbc[mb].iface, U2_REG_SR_ADDR(SR_TIME64), time64_rb_bases, mimo_clock_sync_delay_cycles
);
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index 5d39e527d..e14798ecb 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -97,11 +97,11 @@
////////////////////////////////////////////////
#define U2_REG_STATUS READBACK_BASE + 4*8
#define U2_REG_GPIO_RB READBACK_BASE + 4*9
-#define U2_REG_TIME64_SECS_RB_IMM READBACK_BASE + 4*10
-#define U2_REG_TIME64_TICKS_RB_IMM READBACK_BASE + 4*11
+#define U2_REG_TIME64_HI_RB_IMM READBACK_BASE + 4*10
+#define U2_REG_TIME64_LO_RB_IMM READBACK_BASE + 4*11
#define U2_REG_COMPAT_NUM_RB READBACK_BASE + 4*12
#define U2_REG_IRQ_RB READBACK_BASE + 4*13
-#define U2_REG_TIME64_SECS_RB_PPS READBACK_BASE + 4*14
-#define U2_REG_TIME64_TICKS_RB_PPS READBACK_BASE + 4*15
+#define U2_REG_TIME64_HI_RB_PPS READBACK_BASE + 4*14
+#define U2_REG_TIME64_LO_RB_PPS READBACK_BASE + 4*15
#endif /* INCLUDED_USRP2_REGS_HPP */
diff --git a/host/tests/sph_recv_test.cpp b/host/tests/sph_recv_test.cpp
index 85d06aa0d..9b45d7016 100644
--- a/host/tests/sph_recv_test.cpp
+++ b/host/tests/sph_recv_test.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_normal){
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
}
@@ -232,14 +232,14 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_sequence_error){
if (i == NUM_PKTS_TO_TEST/2){
//must get the soft overflow here
BOOST_REQUIRE(metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
num_accum_samps += 10 + i%10;
}
else{
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
}
@@ -323,7 +323,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_inline_message){
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
if (i == NUM_PKTS_TO_TEST/2){
@@ -332,7 +332,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_inline_message){
);
std::cout << "metadata.error_code " << metadata.error_code << std::endl;
BOOST_REQUIRE(metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(overflow_handler.num_overflow, size_t(1));
}
}
@@ -414,7 +414,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_normal){
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
}
@@ -500,14 +500,14 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_sequence_error){
if (i == NUM_PKTS_TO_TEST/2){
//must get the soft overflow here
BOOST_REQUIRE(metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
num_accum_samps += 10 + i%10;
}
else{
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
}
@@ -593,7 +593,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_time_error){
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
if (i == NUM_PKTS_TO_TEST/2){
@@ -677,7 +677,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_fragment){
);
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10);
num_accum_samps += num_samps_ret;
@@ -690,7 +690,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_fragment){
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK_EQUAL(metadata.fragment_offset, 10);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, i%10);
num_accum_samps += num_samps_ret;
}
diff --git a/host/tests/sph_send_test.cpp b/host/tests/sph_send_test.cpp
index 25a3f97ee..c31399d12 100644
--- a/host/tests/sph_send_test.cpp
+++ b/host/tests/sph_send_test.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -136,9 +136,7 @@ BOOST_AUTO_TEST_CASE(test_sph_send_one_channel_one_packet_mode){
std::cout << "data check " << i << std::endl;
dummy_send_xport.pop_front_packet(ifpi);
BOOST_CHECK_EQUAL(ifpi.num_payload_words32, 10+i%10);
- BOOST_CHECK(ifpi.has_tsi);
BOOST_CHECK(ifpi.has_tsf);
- BOOST_CHECK_EQUAL(ifpi.tsi, 0);
BOOST_CHECK_EQUAL(ifpi.tsf, num_accum_samps*TICK_RATE/SAMP_RATE);
BOOST_CHECK_EQUAL(ifpi.sob, i == 0);
BOOST_CHECK_EQUAL(ifpi.eob, i == NUM_PKTS_TO_TEST-1);
@@ -191,9 +189,7 @@ BOOST_AUTO_TEST_CASE(test_sph_send_one_channel_full_buffer_mode){
std::cout << "data check " << i << std::endl;
dummy_send_xport.pop_front_packet(ifpi);
BOOST_CHECK_EQUAL(ifpi.num_payload_words32, 20);
- BOOST_CHECK(ifpi.has_tsi);
BOOST_CHECK(ifpi.has_tsf);
- BOOST_CHECK_EQUAL(ifpi.tsi, 0);
BOOST_CHECK_EQUAL(ifpi.tsf, num_accum_samps*TICK_RATE/SAMP_RATE);
BOOST_CHECK_EQUAL(ifpi.sob, i == 0);
BOOST_CHECK_EQUAL(ifpi.eob, i == NUM_PKTS_TO_TEST-1);
diff --git a/host/tests/time_spec_test.cpp b/host/tests/time_spec_test.cpp
index 467da5c18..102b7cda3 100644
--- a/host/tests/time_spec_test.cpp
+++ b/host/tests/time_spec_test.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -54,11 +54,11 @@ BOOST_AUTO_TEST_CASE(test_time_spec_parts){
BOOST_CHECK_EQUAL(uhd::time_spec_t(1.1).get_full_secs(), 1);
BOOST_CHECK_CLOSE(uhd::time_spec_t(1.1).get_frac_secs(), 0.1, 0.001);
- BOOST_CHECK_EQUAL(uhd::time_spec_t(1.1).get_tick_count(100), 10);
+ BOOST_CHECK_EQUAL(uhd::time_spec_t(1.1).to_ticks(100), 110);
BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).get_full_secs(), -2);
BOOST_CHECK_CLOSE(uhd::time_spec_t(-1.1).get_frac_secs(), 0.9, 0.001);
- BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).get_tick_count(100), 90);
+ BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).to_ticks(100), -110);
}
BOOST_AUTO_TEST_CASE(test_time_spec_get_system_time){