/**
 * @file    sastime.h
 * @brief   Time function.
 *
 * @version $Revision: 1.1 $
 * @date    $Date: 2018/11/24 06:54:50 $
 * @author  $Author: lizhongming $
 * @state   $State: Exp $
 *
 */

#ifndef _SAS_TIME_H
#define _SAS_TIME_H

/* Leap year is any year divisible by four, but not by 100 unless also
 * divisible by 400
 */
#define IsLeapYear(y) ((!(y % 4)) ? (((!(y % 400)) && (y % 100)) ? 1 : 0) : 0)

/**< 64-bits int, number of microseconds since 00:00:00 january 1, 1970 UTC */
typedef apr_time_t ticks_t;  

#define CP56Time2a_YEAR_BASE (2000)
#define WEEK_NOTUSED (8)

#ifdef _OS_WIN32_
#pragma pack(push,1)   
#endif  

APR_DECLARE_DATA extern int  g_gmt_offset; /** seconds east of UTC */

typedef struct cp56time2a_t cp56time2a_t;
/** IEC60870-5 standard time format - CP56Time2a struct */
#ifdef PPC_LINUX
struct cp56time2a_t {
	uint16_t ms   :16;   /**< Milliseconds 0..59,999 ms     */
	uint16_t IV   :1;    /**< Invalid time                  */
	uint16_t RES1 :1;    /**< Spare bit                     */
    uint16_t min  :6;    /**< Minutes 0..59 min             */
    uint16_t su   :1;    /**< Summer time                   */
	uint16_t RES2 :2;    /**< Spare bit                     */
    uint16_t hour :5;    /**< Hours 0..23h                  */
    uint16_t week :3;    /**< Days of week 1..7(Not used 0) */
    uint16_t day  :5;    /**< Days of month 1..31           */
    uint16_t RES3 :4;    /**< Spare bit                     */
    uint16_t month:4;    /**< Months 1..12                  */
    byte_t   RES4 :1;    /**< Spare bit                     */
    byte_t   year :7;    /**< Years 0..99 since 2000        */
}ALIGNPACKED;
#else
struct cp56time2a_t {
    uint16_t ms   :16;   /**< Milliseconds 0..59,999 ms     */
    uint16_t min  :6;    /**< Minutes 0..59 min             */
    uint16_t RES1 :1;    /**< Spare bit                     */
    uint16_t IV   :1;    /**< Invalid time                  */
    uint16_t hour :5;    /**< Hours 0..23h                  */
    uint16_t RES2 :2;    /**< Spare bit                     */
    uint16_t su   :1;    /**< Summer time                   */
    uint16_t day  :5;    /**< Days of month 1..31           */
    uint16_t week :3;    /**< Days of week 1..7(Not used 0) */
    uint16_t month:4;    /**< Months 1..12                  */
    uint16_t RES3 :4;    /**< Spare bit                     */
    byte_t   year :7;    /**< Years 0..99 since 2000        */
    byte_t   RES4 :1;    /**< Spare bit                     */
}ALIGNPACKED;
#endif

typedef union CP56Time2a CP56Time2a;
/** IEC60870-5 standard time format - CP56Time2a union */
union CP56Time2a {
	byte_t       bits[7];
	cp56time2a_t parts;
}ALIGNPACKED;

typedef struct cp32time2a_t cp32time2a_t;
/** IEC60870-5 standard time format - CP32Time2a struct */
#ifdef PPC_LINUX
struct cp32time2a_t {
    uint16_t ms   :16;   /**< Milliseconds 0..59,999 ms     */
	uint16_t IV   :1;    /**< Invalid time                  */
	uint16_t RES1 :1;    /**< Spare bit                     */
    uint16_t min  :6;    /**< Minutes 0..59 min             */ 
	uint16_t su   :1;    /**< Summer time                   */
	uint16_t RES2 :2;    /**< Spare bit                     */
    uint16_t hour :5;    /**< Hours 0..23h                  */ 
}ALIGNPACKED;
#else
struct cp32time2a_t {
	uint16_t ms   :16;   /**< Milliseconds 0..59,999 ms     */
    uint16_t min  :6;    /**< Minutes 0..59 min             */
    uint16_t RES1 :1;    /**< Spare bit                     */
    uint16_t IV   :1;    /**< Invalid time                  */
    uint16_t hour :5;    /**< Hours 0..23h                  */
    uint16_t RES2 :2;    /**< Spare bit                     */
    uint16_t su   :1;    /**< Summer time                   */
}ALIGNPACKED;
#endif

typedef union CP32Time2a CP32Time2a;
/** IEC60870-5 standard time format - CP32Time2a union */
union CP32Time2a {
	byte_t       bits[4];
	uint32_t     words;
	cp32time2a_t parts;
}ALIGNPACKED;

typedef struct cp24time2a_t cp24time2a_t;
/** IEC60870-5 standard time format - CP24Time2a struct */
#ifdef PPC_LINUX
struct cp24time2a_t {      
    uint16_t ms   :16;   /**< Milliseconds 0..59,999 ms */
	byte_t   IV   :1;    /**< Invalid time              */
	byte_t   RES1 :1;    /**< Spare bit                 */
    byte_t   min  :6;    /**< Minutes 0..59 min         */
}ALIGNPACKED;
#else
struct cp24time2a_t {      
    uint16_t ms   :16;   /**< Milliseconds 0..59,999 ms */
    byte_t   min  :6;    /**< Minutes 0..59 min         */
    byte_t   RES1 :1;    /**< Spare bit                 */
    byte_t   IV   :1;    /**< Invalid time              */
}ALIGNPACKED;
#endif

typedef union CP24Time2a CP24Time2a;
/** IEC60870-5 standard time format - CP24Time2a union */
union CP24Time2a {
	byte_t       bits[3];
	cp24time2a_t parts;
}ALIGNPACKED;

typedef struct cp16time2a_t cp16time2a_t;
/** IEC60870-5 standard time format - CP16Time2a struct */
struct cp16time2a_t {      
    uint16_t  ms;        /**< Milliseconds 0..59,999 ms */
}ALIGNPACKED;

typedef union CP16Time2a CP16Time2a;
/** IEC60870-5 standard time format - CP16Time2a union */
union CP16Time2a {
	byte_t       bits[2];
	uint16_t     words;
	cp16time2a_t parts;
}ALIGNPACKED;

typedef struct CPXXX CPXXX;
struct CPXXX{
	byte_t       bits[13];
}ALIGNPACKED;

typedef struct systime_t systime_t;
/** EYE Linux internal time format */
struct systime_t {     /**< EYE-LINUX系统使用的标准时间结构 */
    uint32_t usec;     /**< microseconds(μs) past msec      */
    uint32_t msec;     /**< milliseconds(ms) past sec       */
    uint32_t sec;      /**< (0-59) seconds past tm_min      */
    uint32_t min;      /**< (0-59) minutes past tm_hour     */
    uint32_t hour;     /**< (0-23) hours past midnight      */
    uint32_t mday;     /**< (1-31) day of the month         */
    uint32_t mon;      /**< (0-11) month of the year        */
    uint32_t year;     /**< (1900-2099)year                 */
    uint32_t wday;     /**< (0-6) days since sunday         */
    uint32_t yday;     /**< (0-365) days since jan 1        */
    uint32_t isdst;    /**< daylight saving time            */
    uint32_t gmtoff;   /**< seconds east of UTC             */
}ALIGNPACKED;

#ifdef _OS_WIN32_
#pragma pack(pop)    
#endif

#ifdef __cplusplus
extern "C" {
#endif

APR_DECLARE(float) Test_float_call(float nothing);
APR_DECLARE(int)	Test_int_call(int nothing);
APR_DECLARE(int) test_call(int a,uint16_t b,char c,int *d,char *e,int16_t f,CP24Time2a *tm24,CP56Time2a* tm56, CPXXX TM24);

/**
 * Obtain the number of microseconds since 00:00:00 january 1, 1970 UTC
 */
APR_DECLARE(ticks_t) get_ticks(void);

/**
 * 依据ticks设定当前系统时钟
 * @param ticks The number of microseconds since 00:00:00 january 1, 1970 UTC
 */
APR_DECLARE(int) set_ticks(ticks_t ticks);

/**
 * Convert the deferent format time data.
 */
APR_DECLARE(int) CP16Time2a_to_CP56Time2a(CP16Time2a *tm16,CP56Time2a* tm56);
APR_DECLARE(int) CP24Time2a_to_CP56Time2a(CP24Time2a *tm24,CP56Time2a* tm56);
APR_DECLARE(int) SystemTime_to_CP56Time2a(systime_t *systm,CP56Time2a* tm56);
APR_DECLARE(int) SystemTime_to_CP24Time2a(systime_t *systm,CP24Time2a* tm24);
APR_DECLARE(int) CP56Time2a_to_SystemTime(CP56Time2a* tm56,systime_t *systm);

/**
 * Obtain the deferent format time data.
 */
APR_DECLARE(int) getCP56Time2a(CP56Time2a *now);
APR_DECLARE(int) getCP32Time2a(CP32Time2a *now);
APR_DECLARE(int) getCP24Time2a(CP24Time2a *now);
APR_DECLARE(int) getCP16Time2a(CP16Time2a *now);
APR_DECLARE(int) getSystemTime(systime_t *now);

/**
 * Set the system time using the deferent format time.
 */
APR_DECLARE(int) setSystemTime(systime_t *now);
APR_DECLARE(int) setCP56Time2a(CP56Time2a *now);

/**
 * 针对PS640系列的103规约中上送事件只有小时(CP32Time2a)，在晚24时日期交替时
 * 会发生事件日期退后一天而编写的函数，根据需要选择使用。
 * 函数输出时间tm比输入时间tm的早一天，其他时间分量不变
 */
APR_DECLARE(int) getYesterday(systime_t* tm);

/** Initialize the seconds east of UTC */
APR_DECLARE(int) initTimezoneOffset(void);

/** Return the seconds east of UTC */
APR_DECLARE(int) getTimezoneOffset(void);

/** Return the ticks converted from systime */
APR_DECLARE(ticks_t) getTicksOfSystemTime(systime_t *tm);

/** Return the ticks converted from CP56Time2a */
APR_DECLARE(ticks_t) getTicksOfCP56Time2a(CP56Time2a *tm);

/** Obtain the systime_t converted from ticks_t */
APR_DECLARE(int) getSystemTimeFromTicks(systime_t *tm, ticks_t ticks);

/** Obtain the CP56Time2a converted from ticks_t */
APR_DECLARE(int) getCP56Time2aFromTicks(CP56Time2a *tm, ticks_t ticks);

/** Obtain the systime_t converted from ticks_t by china time zone */
APR_DECLARE(int) getSystemTimeFromTicksByTimeZoneCH(systime_t *tm, ticks_t ticks);

/** Obtain the CP56Time2a converted from ticks_t by china time zone */
APR_DECLARE(int) getCP56Time2aFromTicksByTimeZoneCH(CP56Time2a *tm, ticks_t ticks);

/**
 * Adjust the local system time using delay milliseconds.
 * 调整本地主机时间
 * @param now 输入时钟
 * @param delay_ms 本地时钟与输入时钟的差值
 */
APR_DECLARE(int) adjustSystemTime(systime_t  *now, int32_t delay_ms);
APR_DECLARE(int) adjustCP56Time2a(CP56Time2a *now, int32_t delay_ms);

/**
 * 得到当前时间的文字形式的描述,主要用于调试.
 * @param desc 文字描述缓冲区(传入)
 * @param len  文字描述缓冲区大小(传入)
 */
APR_DECLARE (void) getSystemTimeDescription( char *desc, int len );

#ifdef __cplusplus
}
#endif

#endif //_SAS_TIME_H
