/**
 * @file time_clock.c
 * @author Chen Jihang (embedded@eseaoptics.com)
 * @brief 提供与时间和时钟相关函数
 * @version 0.1
 * @date 2022-07-18
 * 
 * @copyright ESEA (c) 2020
 * 
 */
#include "time_clock.h"
struct time_clock
{
    volatile uint64_t time_s;
    volatile uint32_t time_ms;
    volatile int64_t time_offset_ms;
};
static struct time_clock tc={0};
/**
 * @brief 获取当前时间戳(秒)
 * 
 * @return uint64_t 当前时间戳(秒)
 */
uint64_t time_clock_get_time_s(void)
{
    return tc.time_s;
}
/**
 * @brief 获取当前时间戳(毫秒)
 * 
 * @return uint32_t 当前时间戳(毫秒)
 */
uint32_t time_clock_get_time_ms(void)
{
    return tc.time_ms;
}
/**
 * @brief 获取当前时间
 * 
 * @param ptime struct time_clock_time 结构指针
 * @return struct time_clock_time* ptime
 */
struct time_clock_time *time_clock_get_time(struct time_clock_time *ptime)
{
    ptime->time_s=tc.time_s;
    ptime->time_ms=tc.time_ms;
    if(ptime->time_s!=tc.time_s){
        ptime->time_ms=0;
        ptime->time_s++;
    }
    return ptime;
}
/**
 * @brief 获取struct time_clock_time 结构存储的时间与当前时间的偏移量(毫秒)
 * 
 * @param ptime struct time_clock_time 结构指针
 * @return int64_t 偏移量(毫秒)
 */
int64_t time_clock_get_time_offset_ms(struct time_clock_time *ptime)
{
    int64_t time_s;
    int32_t time_ms;
    time_s=tc.time_s;
    time_ms=tc.time_ms;
    if(time_s!=tc.time_s){
        time_s++;
        time_ms=0;
    }
    return ((int64_t)time_s-(int64_t)ptime->time_s)*1000+((int32_t)time_ms-(int32_t)ptime->time_ms);
}
/**
 * @brief 获取给定时间与当前时间的偏移量(秒)
 * 
 * @param time_s 给定时间(秒)
 * @return int64_t 偏移量(秒)
 */
int64_t time_clock_get_time_offset_s(uint64_t time_s)
{
    return (int64_t)tc.time_s-(int64_t)time_s;
}
/**
 * @brief 设置时间
 * 
 * @param time_to_set 当前时间
 * @param ptime 基础时间
 */
void time_clock_set_time(struct time_clock_time *time_to_set,struct time_clock_time *ptime)
{
    int64_t time_offset_ms;
    time_offset_ms=time_clock_get_time_offset_ms(time_to_set);
    time_offset_ms-=time_clock_get_time_offset_ms(ptime);
    tc.time_offset_ms=time_offset_ms;
}
/**
 * @brief 时间戳转日期
 * 
 * @param time_s 当前时间戳(秒)
 * @param date 日期结构
 * @param time_zone 时区
 * @return struct time_clock_date* date
 */
struct time_clock_date *time_clock_time_to_date(uint64_t time_s,struct time_clock_date *date,int8_t time_zone)
{
    struct tm *time_tm;
    time_t time_tmp=time_s+(int64_t)time_zone*60*60;
    time_tm=gmtime(&time_tmp);
    date->year=time_tm->tm_year+1900;
    date->mon=time_tm->tm_mon+1;
    date->mday=time_tm->tm_mday;
    date->hour=time_tm->tm_hour;
    date->min=time_tm->tm_min;
    date->sec=time_tm->tm_sec;
    date->wday=time_tm->tm_wday;
    date->yday=time_tm->tm_yday+1;
    return date;
}
/**
 * @brief 日期转时间戳(秒)
 * 
 * @param date 日期结构
 * @param time_zone 时区
 * @return uint64_t 时间戳(秒)
 */
uint64_t time_clock_date_to_time(struct time_clock_date *date,int8_t time_zone)
{
    struct tm time_tm;
    time_tm.tm_year=date->year-1900;
    time_tm.tm_mon=date->mon-1;
    time_tm.tm_mday=date->mday;
    time_tm.tm_hour=date->hour;
    time_tm.tm_min=date->min;
    time_tm.tm_sec=date->sec;
    time_tm.tm_wday=date->wday-1;
    time_tm.tm_yday=date->yday-1;
    time_tm.tm_isdst=0;
    return mktime(&time_tm)-(int64_t)time_zone*60*60;
}
/**
 * @brief 获取当前时间的字符串形式
 * 
 * @param buf 缓冲区
 * @param time_zone 时区
 * @return uint32_t 字符串长度
 */
uint32_t time_clock_get_time_str(char *buf,int8_t time_zone)
{
    int i=0;
    struct time_clock_date date_tmp;
    struct time_clock_time time_tmp;
    time_clock_get_time(&time_tmp);
    time_clock_time_to_date(time_tmp.time_s,&date_tmp,time_zone);
    buf[i++]=date_tmp.year/1000+'0';
    buf[i++]=(date_tmp.year/100)%10+'0';
    buf[i++]=(date_tmp.year/10)%10+'0';
    buf[i++]=date_tmp.year%10+'0';
    buf[i++]='/';
    buf[i++]=date_tmp.mon/10+'0';
    buf[i++]=date_tmp.mon%10+'0';
    buf[i++]='/';
    buf[i++]=date_tmp.mday/10+'0';
    buf[i++]=date_tmp.mday%10+'0';
    buf[i++]=' ';
    buf[i++]=date_tmp.hour/10+'0';
    buf[i++]=date_tmp.hour%10+'0';
    buf[i++]=':';
    buf[i++]=date_tmp.min/10+'0';
    buf[i++]=date_tmp.min%10+'0';
    buf[i++]=':';
    buf[i++]=date_tmp.sec/10+'0';
    buf[i++]=date_tmp.sec%10+'0';
    buf[i++]='.';
    buf[i++]=time_tmp.time_ms/100+'0';
    buf[i++]=(time_tmp.time_ms/10)%10+'0';
    buf[i++]=time_tmp.time_ms%10+'0';
    buf[i++]='\0';
    return i;
}
/**
 * @brief 回调函数 每1ms调用一次
 * 
 */
void time_clock_tick_callback(void)
{
    tc.time_ms++;
    if(tc.time_offset_ms!=0){
        tc.time_s-=tc.time_offset_ms/1000;
        tc.time_s--;
        tc.time_ms+=1000;
        tc.time_ms-=tc.time_offset_ms%1000;
        tc.time_offset_ms=0;
    }
    while(tc.time_ms>=1000){
        tc.time_s++;
        tc.time_ms-=1000;
    }
}