+/** Convert \a ms [ms] to ticks. */
+INLINE ticks_t ms_to_ticks(mtime_t ms)
+{
+#if TIMER_TICKS_PER_SEC < 1000
+ /* Slow timer: avoid rounding down too much. */
+ return (ms * TIMER_TICKS_PER_SEC) / 1000;
+#else
+ /* Fast timer: don't overflow ticks_t. */
+ return ms * DIV_ROUND(TIMER_TICKS_PER_SEC, 1000);
+#endif
+}
+
+/** Convert \a us [us] to ticks. */
+INLINE ticks_t us_to_ticks(utime_t us)
+{
+#if TIMER_TICKS_PER_SEC < 1000
+ /* Slow timer: avoid rounding down too much. */
+ return ((us / 1000) * TIMER_TICKS_PER_SEC) / 1000;
+#else
+ /* Fast timer: don't overflow ticks_t. */
+ return (us * DIV_ROUND(TIMER_TICKS_PER_SEC, 1000)) / 1000;
+#endif
+}
+
+/** Convert \a ticks [ticks] to ms. */
+INLINE mtime_t ticks_to_ms(ticks_t ticks)
+{
+#if TIMER_TICKS_PER_SEC < 1000
+ /* Slow timer: avoid rounding down too much. */
+ return (ticks * 1000) / TIMER_TICKS_PER_SEC;
+#else
+ /* Fast timer: avoid overflowing ticks_t. */
+ return ticks / (TIMER_TICKS_PER_SEC / 1000);
+#endif
+}
+
+/** Convert \a ticks [ticks] to us. */
+INLINE utime_t ticks_to_us(ticks_t ticks)
+{
+#if TIMER_TICKS_PER_SEC < 1000
+ /* Slow timer: avoid rounding down too much. */
+ return ((ticks * 1000) / TIMER_TICKS_PER_SEC) * 1000;
+#else
+ /* Fast timer: avoid overflowing ticks_t. */
+ return (ticks / (TIMER_TICKS_PER_SEC / 1000)) * 1000;
+#endif
+}
+
+/** Convert \a us [us] to hpticks */
+INLINE hptime_t us_to_hptime(utime_t us)
+{
+#if TIMER_HW_HPTICKS_PER_SEC > 10000000UL
+ return us * DIV_ROUND(TIMER_HW_HPTICKS_PER_SEC, 1000000UL);
+#else
+ return (us * ((TIMER_HW_HPTICKS_PER_SEC + 500) / 1000UL) + 500) / 1000UL;
+#endif
+}
+
+/** Convert \a hpticks [hptime] to usec */
+INLINE utime_t hptime_to_us(hptime_t hpticks)
+{
+#if TIMER_HW_HPTICKS_PER_SEC < 100000UL
+ return hpticks * DIV_ROUND(1000000UL, TIMER_HW_HPTICKS_PER_SEC);
+#else
+ return (hpticks * 1000UL) / DIV_ROUND(TIMER_HW_HPTICKS_PER_SEC, 1000UL);
+#endif /* TIMER_HW_HPTICKS_PER_SEC < 100000UL */
+}
+
+
+void timer_init(void);
+void timer_delayTicks(ticks_t delay);
+INLINE void timer_delay(mtime_t delay)
+{
+ timer_delayTicks(ms_to_ticks(delay));
+}
+
+#if !defined(CONFIG_TIMER_DISABLE_UDELAY)
+void timer_busyWait(hptime_t delay);
+void timer_delayHp(hptime_t delay);
+INLINE void timer_udelay(utime_t delay)
+{
+ timer_delayHp(us_to_hptime(delay));
+}
+#endif
+
+#ifndef CONFIG_TIMER_DISABLE_EVENTS
+
+#include <mware/event.h>
+
+/**
+ * The timer driver supports multiple synchronous timers
+ * that can trigger an event when they expire.
+ *
+ * \sa timer_add()
+ * \sa timer_abort()
+ */
+typedef struct Timer
+{
+ Node link; /**< Link into timers queue */
+ ticks_t _delay; /**< Timer delay in ms */
+ ticks_t tick; /**< Timer will expire at this tick */
+ Event expire; /**< Event to execute when the timer expires */
+ DB(uint16_t magic;)
+} Timer;
+
+/** Timer is active when Timer.magic contains this value (for debugging purposes). */
+#define TIMER_MAGIC_ACTIVE 0xABBA
+#define TIMER_MAGIC_INACTIVE 0xBAAB
+
+extern void timer_add(Timer *timer);
+extern Timer *timer_abort(Timer *timer);
+
+/** Set the timer so that it calls an user hook when it expires */
+INLINE void timer_set_event_softint(Timer *timer, Hook func, iptr_t user_data)
+{
+ event_initSoftInt(&timer->expire, func, user_data);
+}
+
+/** Set the timer delay (the time before the event will be triggered) */
+INLINE void timer_setDelay(Timer *timer, ticks_t delay)
+{
+ timer->_delay = delay;
+}
+
+#endif /* CONFIG_TIMER_DISABLE_EVENTS */
+
+#if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS
+
+/** Set the timer so that it sends a signal when it expires */
+INLINE void timer_set_event_signal(Timer *timer, struct Process *proc, sigmask_t sigs)
+{
+ event_initSignal(&timer->expire, proc, sigs);
+}
+
+#endif /* CONFIG_KERN_SIGNALS */
+
+