/* mbed Microcontroller Library * Copyright (c) 2018 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef BLE_COMMON_DURATION_H_ #define BLE_COMMON_DURATION_H_ #include #include #include "platform/mbed_assert.h" namespace ble { /** * Define a compile time range. * @tparam Min left-bound * @tparam Max right-bound */ template struct Range { static const uint32_t MIN = Min; static const uint32_t MAX = Max; }; /** * Deduce default range for C++ basic integer types. * * * @tparam Rep The C++ integer type. */ template struct DefaultRange; /** * DefaultRange specialization for uint8_t. */ template<> struct DefaultRange { typedef Range<0, 0xFF> type; }; /** * DefaultRange specialization for uint16_t. */ template<> struct DefaultRange { typedef Range<0, 0xFFFF> type; }; /** * DefaultRange specialization for uint32_t */ template<> struct DefaultRange { typedef Range<0, 0xFFFFFFFF> type; }; /** * Represent the forever value that can be used in Duration. * * @tparam V The integer value representing a never ending duration. */ template struct Forever { static const uint32_t VALUE = V; }; /** * Model BLE durations. * * @tparam Rep The representation type of the duration. * @tparam TB The time base in us. * @tparam Range Closed interval of the duration * @tparam Forever The special value (if applicable) that represents a forever * duration. */ template< typename Rep, uint32_t TB, typename Range = typename DefaultRange::type, typename Forever = void* > struct Duration { /** * Construct a default Duration. * * It is initialized with the minimum value acceptable. */ Duration() : duration(Range::MIN) { } /** * Construct a Duration from an integer value. * * @param v The value of the duration in TN units. */ explicit Duration(Rep v) : duration(clamp(v)) { } /** * Construct a Duration from another Duration. * * @note The operation fail at compile time of there is a loss of precision. * * @tparam OtherRep The type used to represent the other duration. * @tparam OtherTB The time base in us units of the other duration. * @tparam OtherRange The range of the other duration. * @tparam OtherF The forever value of the other type. * * @param other The duration used to construct this object. */ template Duration(Duration other) : duration(clamp(other.value() * (OtherTB / TB))) { MBED_STATIC_ASSERT(OtherTB >= TB && (OtherTB % TB) == 0, "Incompatible units"); } /** * Construct a new Duration from a Duration in milliseconds. * * @note The result of the conversion is rounded up. * * @tparam OtherRep The representation type used by other_ms. * @tparam OtherRange The range used by other_ms. * @tparam OtherF The forever value used by other_ms. * * @param other_ms The duration in ms to convert. */ template explicit Duration(Duration other_ms, void* = NULL) : duration(clamp(((other_ms.value() * 1000) + TB - 1) / TB)) { } /** * Return the duration in TB units. * * @return The duration in TB units. */ Rep value() const { return duration; } /** * Return the duration in milliseconds. * * @return The duration in milliseconds. */ uint32_t valueInMs() const { return ((uint32_t)duration * TB) / 1000; } /** * The time base. */ static const uint32_t TIME_BASE = TB; /** * Left-bound of the Duration range. */ static const Rep MIN = Range::MIN; /** * Right bound of the duration range. */ static const Rep MAX = Range::MAX; /** * Return the minimum duration. * * @return The minimum duration. */ static Duration min() { return Duration(MIN); } /** * Return the maximum duration. * * @return The maximum duration. */ static Duration max() { return Duration(MAX); } /** * Return a pointer to the value of the duration. * * @return a pointer to the value of the duration. */ const Rep* storage() const { return &duration; } /** * Return the duration value meaning forever. * @return the duration value meaning forever. */ static Duration forever() { return Duration(Forever::VALUE); } private: static Rep clamp(Rep in) { if (in < MIN) { return MIN; } else if (in > MAX) { return MAX; } else { return in; } } Rep duration; }; /** * Type that represents micro seconds. */ typedef Duration microsecond_t; /** * Type that represents milliseconds. */ typedef Duration millisecond_t; /** * Type that represents seconds. */ typedef Duration second_t; /** * Cast a duration to another. * * @tparam DurationOut Type of the Duration in output. * @tparam RepIn The representation type of duration. * @tparam TBIn The timebase of duration. * @tparam RangeIn The range of duration. * @tparam FIn The Forever value of duration. * @param duration The duration to convert. * @return The converted duration. It is rounded up if precision is loss. */ template DurationOut durationCast(Duration duration) { return DurationOut(((duration.value() * TBIn) + DurationOut::TIME_BASE - 1) / DurationOut::TIME_BASE); } /** * Add two durations together and return the result in microseconds. * @param lhs Left hand side operand. * @param rhs Right hand side operand. * @return The result of the addition of the two durations in microseconds. */ template< typename RepLHS, uint32_t TBLHS, typename RangeLHS, typename FLHS, typename RepRHS, uint32_t TBRHS, typename RangeRHS, typename FRHS> microsecond_t operator+( Duration lhs, Duration rhs ) { return microsecond_t((lhs.value() * lhs.TIME_BASE) + (rhs.value() * rhs.TIME_BASE)); } /** * Add two durations together. * @param lhs Left hand side operand. * @param rhs Right hand side operand. * @return The addition of the two durations in input. */ template Duration operator+( Duration lhs, Duration rhs ) { return Duration(lhs.value() + rhs.value()); } /** * Multiply a duration and a positive integer. * * @param lhs The duration. * @param rhs The integer. * * @return A duration that represents the multiplication of lhs with rhs. */ template Duration operator*(Duration lhs, uint32_t rhs) { return Duration(lhs.value() * rhs); } /** * Multiply a duration and a positive integer. * * @param lhs The integer. * @param rhs The multiplication. * * @return A duration that represents the multiplication of lhs with rhs. */ template Duration operator*(uint32_t lhs, Duration rhs) { return Duration(lhs * rhs.value()); } /** * Indicate if the duration lhs is less than the duration rhs. * @param lhs Left hand side operand. * @param rhs Right hand side operand. * @return true if lhs is less than rhs and false otherwise. */ template< typename RepLHS, uint32_t TBLHS, typename RangeLHS, typename FLHS, typename RepRHS, uint32_t TBRHS, typename RangeRHS, typename FRHS > bool operator<(Duration lhs, Duration rhs) { return lhs.value() * lhs.TIME_BASE < rhs.value() * rhs.TIME_BASE; } /** * Indicate if the duration lhs is less than the duration rhs. * @param lhs Left hand side operand. * @param rhs Right hand side operand. * @return true if lhs is less than rhs and false otherwise. */ template bool operator<(Duration lhs, Duration rhs) { return lhs.value() < rhs.value(); } /** * Indicate if the duration lhs is less than or equal to the duration rhs. * @param lhs Left hand side operand. * @param rhs Right hand side operand. * @return true if lhs is less than or equal to rhs and false otherwise. */ template< typename RepLHS, uint32_t TBLHS, typename RangeLHS, typename FLHS, typename RepRHS, uint32_t TBRHS, typename RangeRHS, typename FRHS > bool operator<=( Duration lhs, Duration rhs ) { return lhs.value() * lhs.TIME_BASE <= rhs.value() * rhs.TIME_BASE; } /** * Indicate if the duration lhs is less than or equal to the duration rhs. * @param lhs Left hand side operand. * @param rhs Right hand side operand. * @return true if lhs is less than or equal to rhs and false otherwise. */ template bool operator<=(Duration lhs, Duration rhs) { return lhs.value() <= rhs.value(); } /** * Indicate if the duration lhs is equal to the duration rhs. * @param lhs Left hand side operand. * @param rhs Right hand side operand. * @return true if lhs is equal to rhs and false otherwise. */ template< typename RepLHS, uint32_t TBLHS, typename RangeLHS, typename FLHS, typename RepRHS, uint32_t TBRHS, typename RangeRHS, typename FRHS > bool operator==( Duration lhs, Duration rhs ) { return lhs.value() * lhs.TIME_BASE == rhs.value() * rhs.TIME_BASE; } /** * Indicate if the duration lhs is equal to the duration rhs. * @param lhs Left hand side operand. * @param rhs Right hand side operand. * @return true if lhs is equal to rhs and false otherwise. */ template bool operator==(Duration lhs, Duration rhs) { return lhs.value() == rhs.value(); } /** * Indicate if the duration lhs is not equal to the duration rhs. * @param lhs Left hand side operand. * @param rhs Right hand side operand. * @return true if lhs is not equal to rhs and false otherwise. */ template< typename RepLHS, uint32_t TBLHS, typename RangeLHS, typename FLHS, typename RepRHS, uint32_t TBRHS, typename RangeRHS, typename FRHS > bool operator!=( Duration lhs, Duration rhs ) { return !(lhs == rhs); } /** * Indicate if the duration lhs is not equal to the duration rhs. * @param lhs Left hand side operand. * @param rhs Right hand side operand. * @return true if lhs is not equal to rhs and false otherwise. */ template bool operator!=(Duration lhs, Duration rhs) { return !(lhs == rhs); } /** * Indicate if the duration lhs greater or equal to the duration rhs. * @param lhs Left hand side operand. * @param rhs Right hand side operand. * @return true if lhs is greater or equal to rhs and false otherwise. */ template< typename RepLHS, uint32_t TBLHS, typename RangeLHS, typename FLHS, typename RepRHS, uint32_t TBRHS, typename RangeRHS, typename FRHS > bool operator>=( Duration lhs, Duration rhs ) { return rhs <= lhs; } /** * Indicate if the duration lhs greater or equal to the duration rhs. * @param lhs Left hand side operand. * @param rhs Right hand side operand. * @return true if lhs is greater or equal to rhs and false otherwise. */ template bool operator>=(Duration lhs, Duration rhs) { return rhs <= lhs; } /** * Indicate if the duration lhs greater than the duration rhs. * @param lhs Left hand side operand. * @param rhs Right hand side operand. * @return true if lhs is greater than rhs and false otherwise. */ template< typename RepLHS, uint32_t TBLHS, typename RangeLHS, typename FLHS, typename RepRHS, uint32_t TBRHS, typename RangeRHS, typename FRHS > bool operator>( Duration lhs, Duration rhs ) { return rhs < lhs; } /** * Indicate if the duration lhs greater than the duration rhs. * @param lhs Left hand side operand. * @param rhs Right hand side operand. * @return true if lhs is greater than rhs and false otherwise. */ template bool operator>(Duration lhs, Duration rhs) { return rhs < lhs; } /* ---------------------- Static variable initialization -------------------- */ template const uint32_t Range::MIN; template const uint32_t Range::MAX; template const uint32_t Forever::VALUE; template const uint32_t Duration::TIME_BASE; template const Rep Duration::MIN; template const Rep Duration::MAX; } #endif //BLE_COMMON_DURATION_H_