/**
* @file CM_Time.c
* @brief 时钟相关处理
* @author GT-BU
* @date 2021.08.01
* @version V1.0
* @copyright TCT
* @par 修改日志
* <table>
* <tr><th>Date        <th>Version  <th>Author     <th>Description
* <tr><td>2021.08.01  <td>V1.0     <td>GT-BU      <td>TSCP项目集成、更新
* </table>
*/
#include "CM_Time.h"
#include "PFM_Log.h"
#if QNX
#include "sys/select.h"
#include "sys/time.h"
#else
#include <time.h>
#endif

/**
* @brief 获取精确上电时间
* @return 系统上电至调用时刻的ns数
* @details 从系统上电开始计时，不受时钟同步等操作的影响。
*/
CM_UINT64 CM_GetTick(void)
{
    /*- 变量初始化 */
    CM_UINT64 tick = 0u;
    CM_TIMESPEC_T ts = { 0 };
    CM_INT8 ret = 0u;
    /*- 获取精确时间 */
    ret = clock_gettime(CLOCK_MONOTONIC, &ts);
    if(ret == -1)
    {
    	MSCP_LOG_MSG("pipe error. errno = %d. %s\n", errno,strerror(errno));
    }

    /*- 将时间格式转换为ns数 */
    tick = ((CM_UINT64)ts.tv_sec * 1000000000u) + (CM_UINT64)ts.tv_nsec;
    /*- 返回精确时间 */
    return tick;
}

/**
* @brief 获取精确上电时间
* @return 系统上电至调用时刻的s数
* @details 从系统上电开始计时，不受时钟同步等操作的影响。
*/
CM_UINT64 CM_GetSecTick(void)
{
    /*- 变量初始化 */
    CM_UINT64 tick = 0u;
    CM_TIMESPEC_T ts = { 0 };
    CM_INT8 ret = 0u;
    /*- 获取精确时间 */
#ifdef WIN32
    (void)timespec_get(&ts, TIME_UTC);
#elif QNX
    ret = clock_gettime(CLOCK_MONOTONIC, &ts);
    if(ret == -1)
    {
    	MSCP_LOG_MSG("pipe error. errno = %d. %s\n", errno,strerror(errno));
    }
#endif
    /*- 将时间格式转换为s数 */
    tick = ts.tv_sec;
    /*- 返回精确时间 */
    return tick;
}

/**
* @brief 获取精确的UTC时间
* @return 系统上电至调用时刻的us数
* @details 从系统上电开始计时，不受时钟同步等操作的影响。
*/
CM_UINT64 CM_GetUTCTick(void)
{
	int ret = 0;
    /*- 变量初始化 */
    CM_UINT64 timestamp = 0u;
	/* 获取本地utc时间 */
	struct timeval tv = { 0 };
#ifdef WIN32
    struct timespec ts = { 0 };
    ret = clock_gettime(CLOCK_MONOTONIC, &ts);
    tv.tv_sec = (CM_UINT32)ts.tv_sec;
    tv.tv_usec = ts.tv_nsec/ (1000 * 1000);
#elif QNX
	ret = gettimeofday(&tv, NULL);
#endif
	if(0 == ret)
	{
		/* utc时间 单位 微秒 */
		timestamp = (CM_UINT64)tv.tv_sec*1000u*1000u + (CM_UINT64)tv.tv_usec;
	}
	else
	{
		timestamp = 0u;
	}
    /*- 返回精确微妙时间 */
    return timestamp;
}
/**
* @brief sleep延时
* @param ms 要延时的ms数
* @details 实际延时偏差在1ms量级
*/
void CM_Sleep(CM_UINT32 ms)
{
    /*- 延时指定时间 */
#ifdef WIN32
    Sleep((unsigned long)ms);
#else

    CM_delayUs(ms * 1000u);
#endif
}
/*精准延时函数*/
void CM_delayUs(CM_UINT64 us)
{
    CM_TIMESPEC_T tv;
    tv.tv_sec = (time_t)CM_UNSIGNED_LONG_INT_EXP(us / 1000000U);
    tv.tv_nsec = (long)CM_UNSIGNED_LONG_INT_EXP(us % 1000000U);
    (void)select(0, NULL, NULL, NULL, &tv);
}
