//
// Software delay function
// Homelab library
//
// Department of Mechatronics
// Tallinn University of Technology
// © Copyrights 2009
//

#ifndef HL_DELAY_H
#define HL_DELAY_H

//
// Include common library
//
#include "common.h"

//
// C++ compatibility
//
#ifdef __cplusplus
extern "C" {
#endif

//
// Declare function only once
//
#ifndef sw_delay_ms

#include <util/delay.h>

//
// Software millisecond delay
//
static inline void sw_delay_ms(unsigned short count)
{
	// Loop until countdown complete
	while (count-- > 0)
	{
		// Do 1ms delay cycle
		_delay_ms(1);
	}
}

#else

extern void sw_delay_ms(unsigned short count);

#endif

//
// Declare function only once
//
#ifndef sw_delay_us

#include <util/delay.h>

//
// Software microsecond delay
//
static inline void sw_delay_us(unsigned short count)
{
	// Loop until countdown complete
	while (count-- > 0)
	{
		// Do 1us delay cycle
		_delay_us(1);
	}
}

#else

extern void sw_delay_us(unsigned short count);

#endif

#if defined (__AVR_ATxmega128A1U__)
#ifndef hw_delay_ms

#include "xmega/TC_driver.h"
#include "xmega/clksys_driver.h"
//
// Hardware millisecond delay
// Actually it's 0.998ms delay
// This function uses 8-bit timer 0
//
static inline void hw_delay_ms(unsigned short count)
{
	if(_sys_freq == 2)
		Homelab_clock_init();

	TC_Restart(&TCD1);
	// Seame taimer D1 perioodi
	TC_SetPeriod(&TCD1, 500);
	// Seame taimer D1 töötama normaalrežiimis
	TC1_ConfigWGM(&TCD1, TC_WGMODE_NORMAL_gc);
	// Seame taimer D1 taktsageduse 0.5MHz
	TC1_ConfigClockSource(&TCD1, TC_CLKSEL_DIV64_gc);

	//Loendame millisekundeid
	while(count-- > 0)
	{
		while(!TC_GetOverflowFlag(&TCD1));
		TC_ClearOverflowFlag(&TCD1);
	}
	TC1_Reset(&TCD1);
}

#else
extern void hw_delay_ms(unsigned short count);
#endif
#endif

#if defined (__AVR_ATmega2561__) || defined (__AVR_ATmega128__)
// Declare function only once
//

//
// Take use of timer operations
//

#include <avr/io.h>
#include "timer.h"

#ifndef hw_delay_ms

//
// Hardware millisecond delay
// Actually it's 0.998ms delay
// This function uses 8-bit timer 0
//
static inline void hw_delay_ms(unsigned short count)
{
	#if F_CPU < 1000 * 256 * 8

	// Calculate prescaler and timer value for < ~2MHz clock
	register timer0_prescale prescale = TIMER0_PRESCALE_8;
	register unsigned char timer_start = 256 - F_CPU / 1000 / 8;

	#elif F_CPU < 1000 * 256 * 32

	// Calculate prescaler and timer value for < ~8MHz clock
	register timer0_prescale prescale = TIMER0_PRESCALE_32;
	register unsigned char timer_start = 256 - F_CPU / 1000 / 32;

	#elif F_CPU < 1000 * 256 * 64

	// Calculate prescaler and timer value for < ~16MHz clock
	register timer0_prescale prescale = TIMER0_PRESCALE_64;
	register unsigned char timer_start = 256 - F_CPU / 1000 / 64;

	#elif F_CPU < 1000 * 256 * 128

	// Calculate prescaler and timer value for < ~32MHz clock
	register timer0_prescale prescale = TIMER0_PRESCALE_128;
	register unsigned char timer_start = 256 - F_CPU / 1000 / 128;

	#endif

	// Initialize timer
	timer0_init_normal(prescale);

	// Loop until countdown complete
	while (count-- > 0)
	{
		// Set counter initial value
		timer0_set_value(timer_start);

		// Clear overflow
		timer0_overflow_flag_clear();

		// Wait for overflow
		while (!timer0_overflow_flag_is_set())
			;
	}

	// Clear overflow
	timer0_overflow_flag_clear();

	// Stop timer operation
	timer0_stop();
}

#else
extern void hw_delay_ms(unsigned short count);
#endif
#endif


//
// C++ compatibility
//
#ifdef __cplusplus
}
#endif

#endif //HL_DELAY