/* Copyright (c) 2002, Marek Michalkiewicz
   Copyright (c) 2004,2005,2007 Joerg Wunsch
   Copyright (c) 2007  Florin-Viorel Petrov
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.

   * Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
     distribution.

   * Neither the name of the copyright holders nor the names of
     contributors may be used to endorse or promote products derived
     from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  POSSIBILITY OF SUCH DAMAGE. */

/* include/util/delay.h.  Generated from delay.h.in by configure. */

#ifndef _UTIL_DELAY_H_
#define _UTIL_DELAY_H_ 1

#ifndef __DOXYGEN__
#  ifndef __HAS_DELAY_CYCLES
#    define __HAS_DELAY_CYCLES 1
#  endif

#endif  /* __DOXYGEN__ */

#include <stdint.h>
#include <util/delay_basic.h>
#include <bits/attribs.h>

/** \file */
/** \defgroup util_delay <util/delay.h>: Convenience functions for busy-wait delay loops
    \code
    #define F_CPU 1000000UL  // 1 MHz
    //#define F_CPU 14.7456e6
    #include <util/delay.h>
    \endcode

    The functions in this header are meant as convenience functions where
    actual time values can be specified as a delay time,
    rather than a number of cycles to wait for.

    This requires that the clock frequency of the device is provided
    in the \c #F_CPU macro in units of Hertz.  The macro must be defined
    before including the <util/delay.h> header.  It can be defined
    in the source code like indicated above, or it can be defined on the
    command line / in a Makefile by means of <tt>-D F_CPU=...</tt>

    The functions in this header file are wrappers around the basic
    busy-wait functions from <tt>\<util/delay_basic.h\></tt>, or, when
    supported by the compiler, then
    <a href="https://gcc.gnu.org/onlinedocs/gcc/AVR-Built-in-Functions.html#index-_005f_005fbuiltin_005favr_005fdelay_005fcycles"
    >__builtin_avr_delay_cycles()</a> is used instead.

    In any case, the delay functions provided by this header will not disable
    interrupts, which means hat the delay time will be longer than
    specified when interrupts occur while a delay function is running.

    In order for these functions to work as intended, compiler
    optimizations <em>must</em> be enabled, and the delay time
    <em>must</em> be an expression that is a known constant at
    compile-time.  If these requirements are not met, the resulting
    delay will be much longer (and basically unpredictable), and
    applications that otherwise do not use floating-point calculations
    will experience severe code bloat by the floating-point library
    routines linked into the application.
    The idea is
    that compile-time constant expressions will be eliminated by
    compiler optimization so floating-point expressions can be used
    to calculate the number of delay cycles needed based on the CPU
    frequency passed by the macro F_CPU.

    The functions available allow the specification of microsecond, and
    millisecond delays directly, using the application-supplied macro
    F_CPU as the CPU clock frequency in Hertz.
*/


#ifndef F_CPU
/* prevent compiler error by supplying a default */
# warning "F_CPU not defined for <util/delay.h>"
/** \ingroup util_delay
    \def F_CPU
    \brief CPU frequency in Hz

    The macro F_CPU specifies the CPU frequency in Hertz to be considered by
    the delay functions.  This macro is normally supplied by the
    environment (e.g. from within a project header, or the project's
    Makefile).  The value 1 MHz here is only provided as a
    fallback default if no such user-provided definition could be found.

    In terms of the delay functions, the CPU frequency can be given as
    a floating-point constant (e.g. 3.6864e6 for 3.6864 MHz).
    However, the macros in <util/setbaud.h> require it to be an
    integer value.
 */
# define F_CPU 1000000UL
#endif

#ifndef __OPTIMIZE__
# warning "Compiler optimizations disabled; functions from <util/delay.h> won't work as designed"
#endif

/**
   \ingroup util_delay

   Perform a delay of \c __ms milliseconds.

   The macro #F_CPU is supposed to be defined to a
   constant defining the CPU clock frequency in Hertz.

-  If \c __builtin_avr_delay_cycles() is
\if GIT_BRANCH_IS_ONLINEDOCS
   supported
\else
   \ref faq_toolchain_support "supported"
\endif
   by the compiler, then
   the maximal possible delay is 4294967.04 / f<sub>CPU</sub> milliseconds
   where f<sub>CPU</sub> denotes the CPU frequency in units of 1 MHz.
   This is around 71 minutes / f<sub>CPU</sub>.
   Values greater than that are saturated to this value.

-  Otherwise, _delay_loop_2() is used as a fallback, and the maximal
   possible delay is 262.14 / f<sub>CPU</sub> milliseconds.
   When the user requests a delay which exceeds the maximum possible one,
   _delay_ms() provides a decreased resolution functionality. In this
   mode _delay_ms() will work with a resolution of 1/10&nbsp;ms, providing
   delays up to 6.5535 seconds (independent from CPU frequency).  The
   user will not be informed about decreased resolution.
.

   Conversion of \c __ms into clock cycles may not always result in
   an integral value.  By default, the clock cycles are rounded up to the next
   integer. This ensures that the user gets at least \c __ms
   microseconds of delay.
   Alternatively, by defining the macro \c __DELAY_ROUND_DOWN__, or
   \c __DELAY_ROUND_CLOSEST__, before including this header file, the
   algorithm can be made to round down, or round to closest integer,
   respectively.

   \note The implementation of _delay_ms() based on
   \c __builtin_avr_delay_cycles() is not backward compatible with older
   implementations.  In order to get a functionality backward compatible
   with previous versions, the macro \c __DELAY_BACKWARD_COMPATIBLE__
   must be defined before including this header file.
 */
static __ATTR_ALWAYS_INLINE__ void
_delay_ms(double __ms)
{
#if (__HAS_DELAY_CYCLES \
     && defined(__OPTIMIZE__) \
     && !defined(__DELAY_BACKWARD_COMPATIBLE__))
    uint32_t __ticks_dc;
    double __tmp = ((F_CPU) / 1e3) * __ms;

    #if defined(__DELAY_ROUND_DOWN__)
        __tmp = __builtin_fabs (__tmp);
    #elif defined(__DELAY_ROUND_CLOSEST__)
        __tmp = __builtin_fabs (__tmp) + 0.5;
    #else
        /* Round up by default */
        __tmp = __builtin_ceil (__builtin_fabs (__tmp));
    #endif

    /* Saturate.  Notice that the largest representable float
       in this context is 0xffffff00.   */
    __ticks_dc = __tmp >= 4294967040.0 ? 0xffffff00 : (uint32_t) __tmp;
    __builtin_avr_delay_cycles(__ticks_dc);
#else
    uint16_t __ticks;
    double __tmp = ((F_CPU) / 4e3) * __ms;
    if (__tmp < 1.0)
        __ticks = 1;
    else if (__tmp > 65535)
    {
        //  __ticks = requested delay in 1/10 ms
        __ticks = (uint16_t) (__ms * 10.0);
        while(__ticks)
        {
            // wait 1/10 ms
            _delay_loop_2(((F_CPU) / 4e3) / 10);
            __ticks--;
        }
        return;
    }
    else
        __ticks = (uint16_t)__tmp;
    _delay_loop_2(__ticks);
#endif
}

/**
   \ingroup util_delay

   Perform a delay of \c __us microseconds.

   The macro #F_CPU is supposed to be defined to a
   constant defining the CPU clock frequency in Hertz.

-  If \c __builtin_avr_delay_cycles() is
\if GIT_BRANCH_IS_ONLINEDOCS
   supported
\else
   \ref faq_toolchain_support "supported"
\endif
   by the compiler, then
   the maximal possible delay is 4294967040 / f<sub>CPU</sub> microseconds
   where f<sub>CPU</sub> denotes the CPU frequency in units of 1 MHz.
   This is around 71 minutes / f<sub>CPU</sub>.
   Values greater than that are saturated to this value.

-  Otherwise, _delay_loop_1() is used as a fallback, and the maximal
   possible delay is 768 / f<sub>CPU</sub> microseconds.
   If the user requests a delay greater than the maximal possible one,
   _delay_us() will automatically call _delay_ms() instead.  The user
   will not be informed about this case.
.

   Conversion of \c __us into clock cycles may not always result in an
   integral value.  By default, the clock cycles are rounded up to next
   integer. This ensures that the user gets at least \c __us
   microseconds of delay.
   Alternatively, by defining the macro \c __DELAY_ROUND_DOWN__, or
   \c __DELAY_ROUND_CLOSEST__, before including this header file, the
   algorithm can be made to round down, or round to closest integer,
   respectively.

   \note The implementation of _delay_us() based on
   \c __builtin_avr_delay_cycles() is not backward compatible with older
   implementations.  In order to get a functionality backward compatible
   with previous versions, the macro \c __DELAY_BACKWARD_COMPATIBLE__
   must be defined before including this header file.
 */
static __ATTR_ALWAYS_INLINE__ void
_delay_us(double __us)
{
#if (__HAS_DELAY_CYCLES \
     && defined(__OPTIMIZE__) \
     && !defined(__DELAY_BACKWARD_COMPATIBLE__))
    uint32_t __ticks_dc;
    double __tmp = ((F_CPU) / 1e6) * __us;

    #if defined(__DELAY_ROUND_DOWN__)
        __tmp = __builtin_fabs (__tmp);
    #elif defined(__DELAY_ROUND_CLOSEST__)
        __tmp = __builtin_fabs (__tmp) + 0.5;
    #else
        /* Round up by default */
        __tmp = __builtin_ceil (__builtin_fabs (__tmp));
    #endif

    /* Saturate.  Notice that the largest representable float
       in this context is 0xffffff00.   */
    __ticks_dc = __tmp >= 4294967040.0 ? 0xffffff00 : (uint32_t) __tmp;
    __builtin_avr_delay_cycles(__ticks_dc);
#else
    uint8_t __ticks;
    double __tmp = ((F_CPU) / 3e6) * __us;
    double __tmp2 = ((F_CPU) / 4e6) * __us;
    if (__tmp < 1.0)
        __ticks = 1;
    else if (__tmp2 > 65535)
    {
        _delay_ms(__us / 1000.0);
        return;
    }
    else if (__tmp > 255)
    {
        uint16_t __ticks=(uint16_t)__tmp2;
        _delay_loop_2(__ticks);
        return;
    }
    else
        __ticks = (uint8_t)__tmp;
    _delay_loop_1(__ticks);
#endif
}

#endif /* _UTIL_DELAY_H_ */
