//
// AVR (ATmega128) timers common operations
// Homelab library
//
// Department of Mechatronics
// Tallinn University of Technology
// © Copyrights 2009
//

//
// Include timer.h only once
//
#ifndef _TIMER128_H_
#define _TIMER128_H_

#ifndef _TIMER_H_
#warning "Do not include timer128.h directly, use timer.h instead"
#endif

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

//
// Include avrlibc files
//
#include <avr/io.h>

//
// Take use of bit manipulation operations
//
#include "bit.h"

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

//
// Configuration types
//
typedef enum
{
	TIMER0_NO_PRESCALE         = 0x01,
	TIMER0_PRESCALE_8          = 0x02,
	TIMER0_PRESCALE_32         = 0x03,
	TIMER0_PRESCALE_64         = 0x04,
	TIMER0_PRESCALE_128        = 0x05,
	TIMER0_PRESCALE_256        = 0x06,
	TIMER0_PRESCALE_1024       = 0x07
}
timer0_prescale;

typedef enum 
{
	TIMER2_NO_PRESCALE         = 0x01,
	TIMER2_PRESCALE_8          = 0x02,
	TIMER2_PRESCALE_64         = 0x03,
	TIMER2_PRESCALE_256        = 0x04,
	TIMER2_PRESCALE_1024       = 0x05,
	TIMER2_PRESCALE_T2_FALLING = 0x06,
	TIMER2_PRESCALE_T2_RISING  = 0x07
}
timer2_prescale;

#define TIMER13_PRESCALE(index) \
typedef enum \
{ \
	TIMER ## index ## _NO_PRESCALE          = 0x01, \
	TIMER ## index ## _PRESCALE_8           = 0x02, \
	TIMER ## index ## _PRESCALE_64          = 0x03, \
	TIMER ## index ## _PRESCALE_256         = 0x04, \
	TIMER ## index ## _PRESCALE_1024        = 0x05, \
	TIMER ## index ## _PRESCALE_T ## index ## _FALLING = 0x06, \
	TIMER ## index ## _PRESCALE_T ## index ## _RISING  = 0x07 \
} \
timer ## index ## _prescale;

TIMER13_PRESCALE(1)
TIMER13_PRESCALE(3)

#define TIMER13_CTC_TOP(index) \
typedef enum \
{ \
	TIMER ## index ## _CTC_TOP_OCRA = 0x04, \
	TIMER ## index ## _CTC_TOP_ICR  = 0x0C, \
} \
timer ## index ## _ctc_top;

TIMER13_CTC_TOP(1)
TIMER13_CTC_TOP(3)

#define TIMER13_FAST_PWM_TOP(index) \
typedef enum \
{ \
	TIMER ## index ## _FAST_PWM_TOP_256  = 0x01, \
	TIMER ## index ## _FAST_PWM_TOP_512  = 0x02, \
	TIMER ## index ## _FAST_PWM_TOP_1024 = 0x03, \
	TIMER ## index ## _FAST_PWM_TOP_ICR  = 0x0E, \
	TIMER ## index ## _PAST_PWM_TOP_OCRA = 0x0F, \
} \
timer ## index ## _fast_pwm_top;

TIMER13_FAST_PWM_TOP(1)
TIMER13_FAST_PWM_TOP(3)

#define TIMER13_FAST_PWM_OUTPUT_MODE(index) \
typedef enum \
{ \
	TIMER ## index ## _FAST_PWM_OUTPUT_DISABLE         = 0x00, \
	TIMER ## index ## _FAST_PWM_OUTPUT_TOGGLE_ON_MATCH = 0x01, \
	TIMER ## index ## _FAST_PWM_OUTPUT_CLEAR_ON_MATCH  = 0x02, \
	TIMER ## index ## _FAST_PWM_OUTPUT_SET_ON_MATCH    = 0x03, \
} \
timer ## index ## _fast_pwm_output_mode;

TIMER13_FAST_PWM_OUTPUT_MODE(1)
TIMER13_FAST_PWM_OUTPUT_MODE(3)

// -----------------------------------------------------------------------------------------------------

//
// Initializing timer0/2 for normal operation
//
inline void timer0_init_normal(timer0_prescale prescale) { TCCR0 = prescale & 0x07; }
inline void timer2_init_normal(timer2_prescale prescale) { TCCR2 = prescale & 0x07; }

//
// Stopping timer0/2
//
inline void timer0_stop() { TCCR0 = 0x00; }
inline void timer2_stop() { TCCR2 = 0x00; }

//
// Getting timer0/2 counter value
//
inline unsigned char timer0_get_value(void) { return TCNT0; }
inline unsigned char timer2_get_value(void) { return TCNT2; }

//
// Setting timer0/2 counter value
//
inline void timer0_set_value(unsigned char value) { TCNT0 = value; }
inline void timer2_set_value(unsigned char value) { TCNT2 = value; }

//
// Timer0/2 overflow interrupt configuration
//
inline void timer0_overflow_interrupt_enable(bool enable) { bit_set_to(TIMSK, TOIE0, enable); }
inline void timer2_overflow_interrupt_enable(bool enable) { bit_set_to(TIMSK, TOIE2, enable); }

//
// Timer0/2 overflow flag getting
//
inline bool timer0_overflow_flag_is_set(void) { return (bit_is_set(TIFR, TOV0) ? true : false); }
inline bool timer2_overflow_flag_is_set(void) { return (bit_is_set(TIFR, TOV2) ? true : false); }

//
// Timer0/2 overflow flag clearing
//
inline void timer0_overflow_flag_clear(void) { bit_set(TIFR, TOV0); }
inline void timer2_overflow_flag_clear(void) { bit_set(TIFR, TOV2); }

// -----------------------------------------------------------------------------------------------------

//
// Initializing timer1/3 for normal operation
//
inline void timer1_init_normal(timer1_prescale prescale) { TCCR1A = 0x00; TCCR1B = (prescale & 0x07); TCCR1C = 0x00; }
inline void timer3_init_normal(timer3_prescale prescale) { TCCR3A = 0x00; TCCR3B = (prescale & 0x07); TCCR3C = 0x00; }

//
// Initializing timer1/3 for CTC operation
//
inline void timer1_init_ctc(timer1_prescale prescale, timer1_ctc_top top)
	{ TCCR1A = (top & 0x03); TCCR1B = ((top & 0x0C) << 1) | (prescale & 0x07); TCCR1C = 0x00; }
inline void timer3_init_ctc(timer3_prescale prescale, timer3_ctc_top top)
	{ TCCR3A = (top & 0x03); TCCR3B = ((top & 0x0C) << 1) | (prescale & 0x07); TCCR3C = 0x00; }

//
// Initializing timer1 for fast PWM operation
//
inline void timer1_init_fast_pwm(
		timer1_prescale prescale,
		timer1_fast_pwm_top top,
		timer1_fast_pwm_output_mode output_a,
		timer1_fast_pwm_output_mode output_b,
		timer1_fast_pwm_output_mode output_c) 
{
	TCCR1A =
		((output_a & 0x03) << 6) |
		((output_b & 0x03) << 4) |
		((output_c & 0x03) << 2) |
		(top & 0x03); \
	TCCR1B = ((top & 0x0C) << 1) | (prescale & 0x07);
	TCCR1C = 0x00;
}

//
// Initializing timer3 for fast PWM operation
//
inline void timer3_init_fast_pwm(
		timer3_prescale prescale,
		timer3_fast_pwm_top top,
		timer3_fast_pwm_output_mode output_a,
		timer3_fast_pwm_output_mode output_b,
		timer3_fast_pwm_output_mode output_c) 
{
	TCCR3A =
		((output_a & 0x03) << 6) |
		((output_b & 0x03) << 4) |
		((output_c & 0x03) << 2) |
		(top & 0x03); \
	TCCR3B = ((top & 0x0C) << 1) | (prescale & 0x07);
	TCCR3C = 0x00;
}

//
// Stopping timer1/3
//
inline void timer1_stop() { TCCR1A = 0x00; TCCR1B = 0x00; TCCR1C = 0x00; }
inline void timer3_stop() { TCCR3A = 0x00; TCCR3B = 0x00; TCCR3C = 0x00; }

//
// Getting timer1/3 counter value
//
inline unsigned short timer1_get_value(void) { return TCNT1; }
inline unsigned short timer3_get_value(void) { return TCNT3; }

//
// Setting timer1/3 counter value
//
inline void timer1_set_value(unsigned short value) { TCNT1 = value; }
inline void timer3_set_value(unsigned short value) { TCNT3 = value; }

//
// Getting timer1/3 compare match unit values
//
inline unsigned short timer1_get_compare_match_unitA_value(void) { return OCR1A; }
inline unsigned short timer1_get_compare_match_unitB_value(void) { return OCR1B; }
inline unsigned short timer1_get_compare_match_unitC_value(void) { return OCR1C; }
inline unsigned short timer3_get_compare_match_unitA_value(void) { return OCR3A; }
inline unsigned short timer3_get_compare_match_unitB_value(void) { return OCR3B; }
inline unsigned short timer3_get_compare_match_unitC_value(void) { return OCR3C; }

//
// Setting timer1/3 compare match unit values
//
inline void timer1_set_compare_match_unitA_value(unsigned short value) { OCR1A = value; }
inline void timer1_set_compare_match_unitB_value(unsigned short value) { OCR1B = value; }
inline void timer1_set_compare_match_unitC_value(unsigned short value) { OCR1C = value; }
inline void timer3_set_compare_match_unitA_value(unsigned short value) { OCR3A = value; }
inline void timer3_set_compare_match_unitB_value(unsigned short value) { OCR3B = value; }
inline void timer3_set_compare_match_unitC_value(unsigned short value) { OCR3C = value; }

//
// Getting timer1/3 input capture counter value
//
inline unsigned short timer1_get_input_capture_value(void) { return ICR1; }
inline unsigned short timer3_get_input_capture_value(void) { return ICR3; }

//
// Setting timer1/3 input capture counter value
//
inline void timer1_set_input_capture_value(unsigned short value) { ICR1 = value; }
inline void timer3_set_input_capture_value(unsigned short value) { ICR3 = value; }

//
// Timer1/3 overflow interrupt configuration
//
inline void timer1_overflow_interrupt_enable(bool enable) { bit_set_to(TIMSK, TOIE1, enable); }
inline void timer3_overflow_interrupt_enable(bool enable) { bit_set_to(ETIMSK, TOIE3, enable); }

//
// Timer1/3 compare match interrupt configuration
//
inline void timer1_compare_match_unitA_interrupt_enable(bool enable) { bit_set_to(TIMSK, OCIE1A, enable); }
inline void timer1_compare_match_unitB_interrupt_enable(bool enable) { bit_set_to(TIMSK, OCIE1B, enable); }
inline void timer1_compare_match_unitC_interrupt_enable(bool enable) { bit_set_to(TIMSK, OCIE1C, enable); }
inline void timer3_compare_match_unitA_interrupt_enable(bool enable) { bit_set_to(ETIMSK, OCIE3A, enable); }
inline void timer3_compare_match_unitB_interrupt_enable(bool enable) { bit_set_to(ETIMSK, OCIE3B, enable); }
inline void timer3_compare_match_unitC_interrupt_enable(bool enable) { bit_set_to(ETIMSK, OCIE3C, enable); }

//
// Timer1/3 input capture interrupt configuration
//
inline void timer1_input_capture_interrupt_enable(bool enable) { bit_set_to(TIMSK, TICIE1, enable); }
inline void timer3_input_capture_interrupt_enable(bool enable) { bit_set_to(ETIMSK, TICIE3, enable); }

//
// Timer1/3 overflow flag getting
//
inline bool timer1_overflow_flag_is_set(void) { return (bit_is_set(TIFR, TOV1) ? true : false); }
inline bool timer3_overflow_flag_is_set(void) { return (bit_is_set(ETIFR, TOV3) ? true : false); }

//
// Timer1/3 overflow flag clearing
//
inline void timer1_overflow_flag_clear(void) { bit_set(TIFR, TOV1); }
inline void timer3_overflow_flag_clear(void) { bit_set(ETIFR, TOV3); }

//
// Timer1/3 input capture flag getting
//
inline bool timer1_input_capture_flag_is_set(void) { return (bit_is_set(TIFR, ICF1) ? true : false); }
inline bool timer3_input_capture_flag_is_set(void) { return (bit_is_set(ETIFR, ICF3) ? true : false); }

//
// Timer1/3 input capture flag clearing
//
inline void timer1_input_capture_flag_clear(void) { bit_set(TIFR, ICF1); }
inline void timer3_input_capture_flag_clear(void) { bit_set(ETIFR, ICF3); }

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

#endif
