#include "bsp/bsp.h"
#include "timer_count32.h"
#include "os/os_task.h"
//#define ENABLE_32TIMER 

#ifdef ENABLE_32TIMER
static void init_master_timer(void);
static void init_slave_timer(void);

#define MASTER TIMER3
#define MASTER_CK RCU_TIMER3

#define SLAVE  TIMER4
#define SLAVE_CK RCU_TIMER4

void timer_count32_init(void) {

	init_master_timer();
	init_slave_timer();

	timer_enable(MASTER);
	timer_enable(SLAVE);
}

static void init_master_timer(void){
	timer_parameter_struct timer_initpara;
	
	rcu_periph_clock_enable(MASTER_CK);

	timer_deinit(MASTER);

	memset(&timer_initpara, 0, sizeof(timer_initpara));
	timer_initpara.prescaler		= TIM_CLOCK/COUNT_CLK - 1; //clk 200KHz, 5us
	timer_initpara.alignedmode		= TIMER_COUNTER_EDGE;
	timer_initpara.counterdirection = TIMER_COUNTER_UP;
	timer_initpara.period		   = 0xFFFF;
	timer_initpara.clockdivision	= TIMER_CKDIV_DIV1;
	timer_initpara.repetitioncounter = 0;
	timer_init(MASTER,&timer_initpara);
	timer_counter_value_config(MASTER, 0);
	timer_autoreload_value_config(MASTER, 0xFFFF);
	timer_counter_up_direction(MASTER);
	timer_auto_reload_shadow_enable(MASTER);
	timer_master_slave_mode_config(MASTER, TIMER_MASTER_SLAVE_MODE_ENABLE);
	timer_master_output_trigger_source_select(MASTER, TIMER_TRI_OUT_SRC_UPDATE);
}

static void init_slave_timer(void) {
	timer_parameter_struct timer_initpara;
	
	rcu_periph_clock_enable(SLAVE_CK);

	timer_deinit(SLAVE);

	memset(&timer_initpara, 0, sizeof(timer_initpara));
	timer_initpara.prescaler		= 0; //clk 10MHz/65535
	timer_initpara.alignedmode		= TIMER_COUNTER_EDGE;
	timer_initpara.counterdirection = TIMER_COUNTER_UP;
	timer_initpara.period		   = 0xFFFF;
	timer_initpara.clockdivision	= TIMER_CKDIV_DIV1;
	timer_initpara.repetitioncounter = 0;
	timer_init(SLAVE,&timer_initpara);
	timer_counter_value_config(SLAVE, 0);
	timer_autoreload_value_config(SLAVE, 0xFFFF);
	timer_counter_up_direction(SLAVE);
	timer_auto_reload_shadow_enable(SLAVE);
	timer_master_slave_mode_config(SLAVE, TIMER_MASTER_SLAVE_MODE_ENABLE);
	timer_slave_mode_select(SLAVE, TIMER_SLAVE_MODE_EXTERNAL0);
	timer_input_trigger_source_select(SLAVE, TIMER_SMCFG_TRGSEL_ITI1); //select timer1 output as the trigger input

}

static __inline__ u32 _timer_count32_get(void) {
#if 0
	u16 high;
	u16 low;
	do {
		high = TIMER_CNT(SLAVE);
		low = TIMER_CNT(MASTER);
	}while((high != TIMER_CNT(SLAVE)) /*|| (low != TIMER_CNT(MASTER))*/);
	return (high<<16) | low;
#else
	return task_ticks_abs()/120;
#endif
}

#else
void timer_count32_init(void){
}
#endif
u32 timer_count32_get(void) {
	return task_ticks_abs();
}

u32 timer_count32_delta(u32 now, u32 prev) {
	if (now >= prev) {
		return (now - prev)/120;
	}
	return ((u32)0xFFFFFFFF - prev + now + 1)/120;
}
