/*
 * ul_timing.h
 *
 *  Created on: Sep 29, 2011
 *      Author: qwer1
 */

#ifndef UL_TIMING_H_
#define UL_TIMING_H_

#include "ul_other.h"

/** delay using simple loop */
#ifdef __ARM_ARCH_7M__
	void _delay_loops(U32 loops);
	#define delay_us( US ) _delay_loops( (U32)((double)US * F_CPU / 3000000.0) )
	#define delay_ms( MS ) _delay_loops( (U32)((double)MS * F_CPU / 3000.0) )
	#define delay_s( S )   _delay_loops( (U32)((double)S  * F_CPU / 3.0) )
#endif

#ifdef __AVR
	#include <util/delay.h>
	#define delay_us( US ) { for (U8 us=(US / 30UL); us; us--) _delay_us(30); _delay_us( US % 30UL ); }
	#define delay_ms( MS ) { for (U8 ms=(MS / 10UL); ms; ms--) _delay_ms(10); _delay_ms( MS % 10UL ); }
	#define delay_s( S ) { for (U8 s=S; s; s--) for (U8 ms=100; ms; ms--) delay_ms(10); }
#endif

extern volatile U8 t_flags;      /**< timing flags*/
extern volatile U8 t_flags_sync; /**< synchronyzed timing flags*/
#define T_1S    1
#define T_100MS 2
#define T_10MS  4
#define T_1MS   8
#define T_RTC   16
#define T_TICK  32

#define t_tick  (t_flags_sync & T_TICK)  /**< system tick flag */
#define t_rtc   (t_flags_sync & T_RTC)   /**< RTC tick flag */
#define t_1s    (t_flags_sync & T_1S)    /**< 1Hz tick flag */
#define t_100ms (t_flags_sync & T_100MS) /**< 10Hz tick flag */
#define t_10ms  (t_flags_sync & T_10MS)  /**< 100Hz tick flag */
#define t_1ms   (t_flags_sync & T_1MS)   /**< 1000Hz tick flag */

#define t_is_tick()  (t_flags & T_TICK)
#define t_do_tick()  t_flags |= T_TICK
#define t_clr_tick() {cli(); t_flags &= ~T_TICK; sei();}

extern volatile U8 t_1_cnt;
extern volatile U8 t_10_cnt;
extern volatile U8 t_100_cnt;
extern volatile U8 t_1000_cnt;
extern volatile U8 t_tick_cnt;

/** update timers every millisecond */
#define t_update() { \
	U8 t_f = t_flags; /* cache t_flags */ \
	t_f |= T_1MS;    /* set 1000Hz flag */ \
	if ((++t_100_cnt) >= 10) { /* update 100Hz timer/flag */ \
		t_100_cnt = 0; \
		t_f |= T_10MS; \
		if ((++t_10_cnt) >= 10) { /* update 10Hz timer/flag */ \
			t_10_cnt = 0; \
			t_f |= T_100MS; \
			if ((++t_1_cnt) >= 10) { /* update 1Hz timer/flag */ \
				t_1_cnt = 0; \
				t_f |= T_1S; \
			} \
		} \
	} \
	t_flags = t_f; \
}

#define t_sync() { \
	cli(); \
	t_flags_sync = 0; \
	U8 t_f = t_flags; \
	if (t_f & T_1MS) { \
		t_f &= ~T_1MS; \
		t_flags_sync |= T_1MS | T_TICK; \
		if (t_f & T_RTC) { \
			t_f &= ~T_RTC; \
			t_flags_sync |= T_RTC; \
		} \
		if (t_f & T_10MS) { \
			t_f &= ~T_10MS; \
			t_flags_sync |= T_10MS; \
			if (t_f & T_100MS) { \
				t_f &= ~T_100MS; \
				t_flags_sync |= T_100MS; \
				if (t_f & T_1S) { \
					t_f &= ~T_1S; \
					t_flags_sync |= T_1S; \
				} \
			} \
		} \
	} \
	t_flags = t_f; \
	sei(); \
}

/** setup timing module */
void setup_timing( void );

#endif /* UL_TIMING_H_ */
