OpenRTX/lib/miosix-kernel/miosix/kernel/timeconversion.h

194 wiersze
7.2 KiB
C++

/***************************************************************************
* 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 <http://www.gnu.org/licenses/> *
***************************************************************************/
#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<unsigned long long>(tick);
return static_cast<long long>(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