/*************************************************************************** * Copyright (C) 2015, 2016 by Terraneo Federico * * * * 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 * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * As a special exception, if other files instantiate templates or use * * macros or inline functions from this file, or you compile this file * * and link it with other works to produce a work based on this file, * * this file does not by itself cause the resulting work to be covered * * by the GNU General Public License. However the source code for this * * file must still be made available in accordance with the GNU General * * Public License. This exception does not invalidate any other reasons * * why a work based on this file might be covered by the GNU General * * Public License. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see * ***************************************************************************/ #ifndef TIMECONVERSION_H #define TIMECONVERSION_H namespace miosix { /** * Multiplication between a 64 bit integer and a 32.32 fixed point number, * * The caller must guarantee that the result of the multiplication fits in * 64 bits. Otherwise the behaviour is unspecified. * * \param a the 64 bit integer number. * \param bi the 32 bit integer part of the fixed point number * \param bf the 32 bit fractional part of the fixed point number * \return the result of the multiplication. The fractional part is discarded. */ unsigned long long mul64x32d32(unsigned long long a, unsigned int bi, unsigned int bf); /** * This class holds a 32.32 fixed point number used for time conversion */ class TimeConversionFactor { public: /** * Default constructor. Leaves the factors unintialized. */ TimeConversionFactor() {} /** * Constructor * \param i integer part * \param f fractional part */ TimeConversionFactor(unsigned int i, unsigned int f) : i(i), f(f) {} /** * \return the integer part of the fixed point number */ inline unsigned int integerPart() const { return i; } /** * \return the fractional part of the fixed point number */ inline unsigned int fractionalPart() const { return f; } /** * \param x value to add to the fractional part * \return a TimeConversionFactor with the same integer part and the * fractional part corrected by delta */ TimeConversionFactor operator+(int delta) const { return TimeConversionFactor(i,f+delta); } private: unsigned int i; unsigned int f; }; /** * Instances of this class can be used by timer drivers to convert from ticks * in the timer resolution to nanoseconds and back. */ class TimeConversion { public: /** * Constructor * Set the conversion factors based on the tick frequency. * \param hz tick frequency in Hz. The range of timer frequencies that are * supported is 10KHz to 1GHz. The algorithms in this class may not work * outside this range */ TimeConversion(unsigned int hz); /** * \param tick time point in timer ticks * \return the equivalent time point in the nanosecond timescale */ inline long long tick2ns(long long tick) const { //Negative numbers for tick are not allowed, cast is safe auto utick=static_cast(tick); return static_cast(convert(utick,toNs)); } /** * \param ns time point in nanoseconds * \return the equivalent time point in the timer tick timescale * * As this function may modify some class variables as part of the * internal online adjustment process, it is not reentrant. The caller * is responsible to prevent concurrent calls */ long long ns2tick(long long ns); /** * \return the conversion factor from ticks to ns */ inline TimeConversionFactor getTick2nsConversion() const { return toNs; } /** * \return the conversion factor from ns to tick */ inline TimeConversionFactor getNs2tickConversion() const { return toTick; } /** * \return the time interval in ns from the last online round trip * adjustment for ns2tick() where the adjust offset is cached. * This should not matter to you unless you are working on the inner * details of the round trip adjustment code, otherwise you can safely * ignore this value */ unsigned long long getAdjustInterval() const { return adjustIntervalNs; } /** * \return the cached online round trip adjust offset in ns for ns2tick(). * This should not matter to you unless you are working on the inner * details of the round trip adjustment code, otherwise you can safely * ignore this value */ long long getAdjustOffset() const { return adjustOffsetNs; } private: /** * Compute the error in ticks of an unadjusted conversion from tick to ns * and back (a "round trip"), when the toTick conversion coefficient * is adjusted by delta and at the given time point. * This function is used internally to compute adjust coefficients. * \param tick time point in ticks on which to do the round trip * \param delta signed value to add the the fractional part of toTick * to obtain a temporary coefficient on which the round trip error is * computed * \return the round trip error in ticks */ long long __attribute__((noinline)) computeRoundTripError(unsigned long long tick, int delta) const; /** * \param x time point to convert * \return the converted time point */ static inline unsigned long long convert(unsigned long long x, TimeConversionFactor tcf) { return mul64x32d32(x,tcf.integerPart(),tcf.fractionalPart()); } /** * \param float a floar number * \return the number in 32.32 fixed point format */ static TimeConversionFactor __attribute__((noinline)) floatToFactor(float x); TimeConversionFactor toNs, toTick; unsigned long long adjustIntervalNs, lastAdjustTimeNs; long long adjustOffsetNs; }; } //namespace miosix #endif //TIMECONVERSION_H