/******************************************************************************
版权所有：	
文件名称：	ustimer.c
文件版本：	01.01
创建作者:	sunxi
创建日期：	2009-06-04
功能说明：	US定时器模块驱动程序。
其它说明：  
修改记录：
*/
#include "bspconfig.h"
#include "bsp.h"
#include "rt.h"
#include <semaphore.h>
#include <signal.h>
#include <time.h>
#include <sys/prctl.h>


#if CFG_BSP_DEBUG

#define DTIM_DEBUG

#endif

#define DTIM_DELAY_MAX_US	(10UL*60*USTIMER_SEC) //10分钟	

#ifdef __LIGHT_DIFF_ACT_PRO__ // sunxi 20190904 光差保护
#define DTIM_CLOCK_12_5M		(CFG_CPU_CLK/2/12500000)	// 12.5M的频率，80纳秒一次计数
#endif // __LIGHT_DIFF_ACT_PRO__

void ustimer_isr(void);

pthread_t  UsTimerPthread;
sem_t      UsCounterSem;

timer_t timerid;

volatile unsigned int uscounter=0;

static 	pthread_t thread_id = 0;
static int exit_flag = 0; 

//返回us
unsigned int GetUsCounterValue(void)
{
    unsigned int us;
    us=uscounter*500;   //定时器精度在500us
    return us;
}

#if 0
void timer_thread(union sigval v)
{
		static int cnt = 0;//sunxi for test

        uscounter++; 

		if(++cnt >= 20)
		{
			cnt = 0;
			_led_run_err();//sunxi for test
		}
}
#endif

static void *timer_thread(void *arg)
{

    struct sched_param sch_par;
    sch_par.sched_priority = 11;

	pthread_setschedparam(pthread_self(), SCHED_RR, &sch_par);	 // 设置当前线程优先级

	prctl(PR_SET_NAME, "timer_thread");
    while(!exit_flag)
    {

	  	usleep(500);//定时器精度在500us

		uscounter++; 


	  
    }
    printf("timer_thread exit\r\n");    
    pthread_exit(NULL);
}


/******************************************************************************
函数名称：	dtim_init
函数版本：	01.01
创建作者:	sunxi
创建日期：	2008-06-26
函数说明：	dtim初始化。使用dtim0做为延时函数参考定时器。
参数说明：	无
返回值：  	无
修改记录：	
*/
int ustimer_init(void)
{

#if 0
    //int ret;
    struct sigevent evp;
    struct itimerspec it;

    memset(&evp, 0, sizeof(struct sigevent));   //清零初始化

    evp.sigev_value.sival_int = 0x5A5A;        //也是标识定时器的，这和timerid有什么区别？回调函数可以获得
    evp.sigev_notify = SIGEV_THREAD;            //线程通知的方式，派驻新线程
    evp.sigev_notify_function = timer_thread;   //线程函数地址

    if (timer_create(CLOCK_REALTIME, &evp, &timerid) == -1)
    {
        rt_printf("fail to timer_create\r\n");
        return -1;
    }


    it.it_interval.tv_sec =  0;  
    it.it_interval.tv_nsec = 500000;  //间隔500US //sunxi for test 20220411 暂时精度定为500us
    it.it_value.tv_sec = 1;
    it.it_value.tv_nsec = 0;

    if (timer_settime(timerid, 0, &it, NULL) == -1)
    {
        rt_printf("fail to timer_settime\r\n");
        return -1;
    }


#ifdef __LIGHT_DIFF_ACT_PRO__ // sunxi 20190904 光差保护
	//设置DTIM扩展模式寄存器。
	MCF_REG08(MCF_DTIM_DTXMR(CFG_DTIM_80NSTIMER)) = 0;

	MCF_REG16(MCF_DTIM_DTMR(CFG_DTIM_80NSTIMER)) = (unsigned short)(0
					| MCF_DTIM_DTMR_RST			//允许定时器
					| MCF_DTIM_DTMR_CLK_DIV1	//输入clock除1
					| MCF_DTIM_DTMR_PS(DTIM_CLOCK_12_5M - 1));//将定时器clock周期设为80ns。

#endif // __LIGHT_DIFF_ACT_PRO__

#endif

//noted by sunxi: 经测试，这种RR线程比定时器还要准确。
	int ret;

	ret = pthread_create(&thread_id, NULL, timer_thread, NULL);
	if(ret)
	{
		printf("thread timer_thread fail ret=%d\r\n", ret);
		thread_id = 0;
		return ret;
	}


	return 0;	
}

int ustimer_exit(void)
{
	//timer_delete(timerid);
	exit_flag = 1;

	pthread_join(thread_id, NULL);
	return 0;

}


//us定时器函数
/******************************************************************************
函数名称：	ustimer_get_origin
函数版本：	01.01
创建作者:	sunxi
创建日期：	2008-07-01
函数说明：	得到当前时刻定时器的值，用作ustimer_get_duration、
			ustimer_delay_origin函数的origin参数。
参数说明：	无
返回值：  	当前时刻定时器的值。
修改记录：	
*/
uint32_t ustimer_get_origin(void)
{
	return GetUsCounterValue();
}

#ifdef __LIGHT_DIFF_ACT_PRO__ // sunxi 20190904 光差保护
// 8纳秒定时器，每8纳秒一个单位
uint32_t timer80ns_get_origin(void)
{
	return MCF_REG32(MCF_DTIM_DTCN(CFG_DTIM_80NSTIMER));
}
uint32_t timer80ns_get_duration(uint32_t origin);

#endif // __LIGHT_DIFF_ACT_PRO__


/******************************************************************************
函数名称：	ustimer_get_duration
函数版本：	01.01
创建作者:	sunxi
创建日期：	2008-06-26
函数说明：	得到当前时刻相对于指定时间原点的时间间隔，以us为单位。
参数说明：
	origin:	时间原点，以us为单位。
返回值：  	当前时刻相对于原点的的时间间隔。
修改记录：	
*/
uint32_t ustimer_get_duration(uint32_t origin)
{
    return GetUsCounterValue()- origin;
}

#ifdef __LIGHT_DIFF_ACT_PRO__ // sunxi 20190904 光差保护
// 80纳秒定时器，每80纳秒一个单位
uint32_t timer80ns_get_duration(uint32_t origin)
{
	//返回差值(根据C语言算法，会自动处理回绕问题)
	return MCF_REG32(MCF_DTIM_DTCN(CFG_DTIM_80NSTIMER)) - origin;
}

#endif // __LIGHT_DIFF_ACT_PRO__

/******************************************************************************
函数名称：	ustimer_delay_origin
函数版本：	01.01
创建作者:	sunxi
创建日期：	2008-06-26
函数说明：	以us为单位的延时函数。最大延时值为10分钟和
			ustimer_delay函数不同的是ustimer_delay_origin函数的延时计算的时间
			原点为origin，而不是函数被调用的时刻。当这个函数退出时，会确保延时
			大于等于设定值。如果需要高精度的延时，调用这个函数时应先屏蔽中断。
参数说明：
	origin:	延时计算的时间原点，以us为单位，通常通过ustimer_get_origin函数获得。
	us：	延时us数。
返回值：  	
	0：		成功
	其它：	失败
修改记录：	
*/
int ustimer_delay_origin(uint32_t origin,uint32_t us)
{
    //检查参数
    if(us > DTIM_DELAY_MAX_US)
    {
        return -1;
    }

    //循环等待
    while(GetUsCounterValue()- origin < us)
    	;     //jack.liu 20200907  us计时暂时替换

	return 0;
}

/******************************************************************************
函数名称：	ustimer_delay_origin2
函数版本：	01.01
创建作者:	sunxi
创建日期：	2008-06-26
函数说明：	
参数说明：
	origin:	延时计算的时间原点，以us为单位，通常通过ustimer_get_origin函数获得。
	us：	延时us数。
返回值：  	
	0：		成功
	其它：	失败
修改记录：	
*/
int ustimer_delay_origin2(uint32_t *us0,uint32_t us)
{
	uint32_t us1;

	if(us0 == NULL)
	{
		return -1;
	}
	
	us1 = ustimer_get_origin();
	if(us1 - *us0 < us)
	{

		return 0;
	}
	
	*us0 = us1;
	return 1;
}


/******************************************************************************
函数名称：	ustimer_delay
函数版本：	01.01
创建作者:	sunxi
创建日期：	2008-06-26
函数说明：	以us为单位的延时函数。最大延时值为1小时（3600000000us）。
			当这个函数退出时，会确保延时大于等于设定值。如果需要高精度的延时，
			调用这个函数时应先屏蔽中断。
参数说明：	
	us：	延时us数。
返回值：  	
	0：	成功
	其它：	失败
修改记录：	
*/
int ustimer_delay(uint32_t us)
{
	uint32_t origin;
	
	//检查参数
	if(us > DTIM_DELAY_MAX_US)
	{
		return -1;
	}
	
	//得到原点
	origin = ustimer_get_origin();
	
	//开始延时
	ustimer_delay_origin(origin,us);
	
	return 0;
}

 
/*------------------------------ 测试函数 -------------------------------------
*/
 
#ifdef DTIM_DEBUG

#include "rt.h"
int ustimer_test(void)
{
	uint32_t us0,us1;
	
	rt_printf("\r\n");
	rt_printf("dtim_test start!\r\n");
	
	//测试函数ustimer_get_duration
	us0 = ustimer_get_origin();
	us1 = ustimer_get_duration(0xffffff00);
	rt_printf("ustimer_get_duration(us0=0x%lx,us1=0x%lx,diff=%lu)!\r\n",us0,us1,us1 - us0);
	
	//测试函数ustimer_delay_origin
	us0 = ustimer_get_origin();
	ustimer_delay_origin(0xffffff00,10000000);
	us1 = ustimer_get_origin();
	rt_printf("ustimer_delay_origin(us0=0x%lx,us1=0x%lx,diff=%lu)!\r\n",us0,us1,us1 - us0);
	
	//测试函数ustimer_delay
	us0 = ustimer_get_origin();
	ustimer_delay(10*USTIMER_SEC);
	us1 = ustimer_get_origin();
	
	rt_printf("ustimer_delay(us0=0x%lx,us1=0x%lx,diff=%lu)!\r\n",us0,us1,us1 - us0);
	
	rt_printf("dtim_test end!\r\n");
	rt_printf("\r\n");
	
	return 0;

}
#endif


