/* * Copyright (C) 2014 Pavel Kirienko */ #ifndef UAVCAN_TIME_HPP_INCLUDED #define UAVCAN_TIME_HPP_INCLUDED #include #include #include #include #include namespace uavcan { template class DurationBase { int64_t usec_; protected: ~DurationBase() { } DurationBase() : usec_(0) { StaticAssert<(sizeof(D) == 8)>::check(); } public: static D getInfinite() { return fromUSec(NumericTraits::max()); } static D fromUSec(int64_t us) { D d; d.usec_ = us; return d; } static D fromMSec(int64_t ms) { return fromUSec(ms * 1000); } int64_t toUSec() const { return usec_; } int64_t toMSec() const { return usec_ / 1000; } D getAbs() const { return D::fromUSec((usec_ < 0) ? (-usec_) : usec_); } bool isPositive() const { return usec_ > 0; } bool isNegative() const { return usec_ < 0; } bool isZero() const { return usec_ == 0; } bool operator==(const D& r) const { return usec_ == r.usec_; } bool operator!=(const D& r) const { return !operator==(r); } bool operator<(const D& r) const { return usec_ < r.usec_; } bool operator>(const D& r) const { return usec_ > r.usec_; } bool operator<=(const D& r) const { return usec_ <= r.usec_; } bool operator>=(const D& r) const { return usec_ >= r.usec_; } D operator+(const D& r) const { return fromUSec(usec_ + r.usec_); } // TODO: overflow check D operator-(const D& r) const { return fromUSec(usec_ - r.usec_); } // ditto D operator-() const { return fromUSec(-usec_); } D& operator+=(const D& r) { *this = *this + r; return *static_cast(this); } D& operator-=(const D& r) { *this = *this - r; return *static_cast(this); } template D operator*(Scale scale) const { return fromUSec(usec_ * scale); } template D& operator*=(Scale scale) { *this = *this * scale; return *static_cast(this); } static const unsigned StringBufSize = 32; void toString(char buf[StringBufSize]) const; ///< Prints time in seconds with microsecond resolution #if UAVCAN_TOSTRING std::string toString() const; ///< Prints time in seconds with microsecond resolution #endif }; template class TimeBase { uint64_t usec_; protected: ~TimeBase() { } TimeBase() : usec_(0) { StaticAssert<(sizeof(T) == 8)>::check(); StaticAssert<(sizeof(D) == 8)>::check(); } public: static T getMax() { return fromUSec(NumericTraits::max()); } static T fromUSec(uint64_t us) { T d; d.usec_ = us; return d; } static T fromMSec(uint64_t ms) { return fromUSec(ms * 1000); } uint64_t toUSec() const { return usec_; } uint64_t toMSec() const { return usec_ / 1000; } bool isZero() const { return usec_ == 0; } bool operator==(const T& r) const { return usec_ == r.usec_; } bool operator!=(const T& r) const { return !operator==(r); } bool operator<(const T& r) const { return usec_ < r.usec_; } bool operator>(const T& r) const { return usec_ > r.usec_; } bool operator<=(const T& r) const { return usec_ <= r.usec_; } bool operator>=(const T& r) const { return usec_ >= r.usec_; } T operator+(const D& r) const { if (r.isNegative()) { if (uint64_t(r.getAbs().toUSec()) > usec_) { return fromUSec(0); } } else { if (uint64_t(int64_t(usec_) + r.toUSec()) < usec_) { return fromUSec(NumericTraits::max()); } } return fromUSec(uint64_t(int64_t(usec_) + r.toUSec())); } T operator-(const D& r) const { return *static_cast(this) + (-r); } D operator-(const T& r) const { return D::fromUSec((usec_ > r.usec_) ? int64_t(usec_ - r.usec_) : -int64_t(r.usec_ - usec_)); } T& operator+=(const D& r) { *this = *this + r; return *static_cast(this); } T& operator-=(const D& r) { *this = *this - r; return *static_cast(this); } static const unsigned StringBufSize = 32; void toString(char buf[StringBufSize]) const; ///< Prints time in seconds with microsecond resolution #if UAVCAN_TOSTRING std::string toString() const; ///< Prints time in seconds with microsecond resolution #endif }; /* * Monotonic */ class UAVCAN_EXPORT MonotonicDuration : public DurationBase { }; class UAVCAN_EXPORT MonotonicTime : public TimeBase { }; /* * UTC */ class UAVCAN_EXPORT UtcDuration : public DurationBase { }; class UAVCAN_EXPORT UtcTime : public TimeBase /// Implicitly convertible to/from uavcan.Timestamp { public: UtcTime() { } UtcTime(const Timestamp& ts) // Implicit { operator=(ts); } UtcTime& operator=(const Timestamp& ts) { *this = fromUSec(ts.husec * Timestamp::USEC_PER_LSB); return *this; } operator Timestamp() const { Timestamp ts; ts.husec = toUSec() / Timestamp::USEC_PER_LSB; return ts; } }; // ---------------------------------------------------------------------------- template const unsigned DurationBase::StringBufSize; template const unsigned TimeBase::StringBufSize; template void DurationBase::toString(char buf[StringBufSize]) const { char* ptr = buf; if (isNegative()) { *ptr++ = '-'; } (void)snprintf(ptr, StringBufSize - 1, "%llu.%06lu", static_cast(getAbs().toUSec() / 1000000L), static_cast(getAbs().toUSec() % 1000000L)); } template void TimeBase::toString(char buf[StringBufSize]) const { (void)snprintf(buf, StringBufSize, "%llu.%06lu", static_cast(toUSec() / 1000000UL), static_cast(toUSec() % 1000000UL)); } #if UAVCAN_TOSTRING template std::string DurationBase::toString() const { char buf[StringBufSize]; toString(buf); return std::string(buf); } template std::string TimeBase::toString() const { char buf[StringBufSize]; toString(buf); return std::string(buf); } #endif template UAVCAN_EXPORT Stream& operator<<(Stream& s, const DurationBase& d) { char buf[DurationBase::StringBufSize]; d.toString(buf); s << buf; return s; } template UAVCAN_EXPORT Stream& operator<<(Stream& s, const TimeBase& t) { char buf[TimeBase::StringBufSize]; t.toString(buf); s << buf; return s; } } #endif // UAVCAN_TIME_HPP_INCLUDED