/*----------------------------------------------------------------
* FileName    : toolkit.h
* Create Date : 2013-12-24
*               顶层头文件
*---------------------------------------------------------------*/

#ifndef TOOLKIT_H__
#define TOOLKIT_H__
/*#include <stdint.h>*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "platmacro.h"
#include <stdarg.h>
#ifdef UNIT_TEST
    #include "cpptest.h"
#endif

/*-------------------------------------------------------------------------------*/
/* public define */

#define MIN(a, b) ((a) > (b) ? (b) : (a))
#define MAX(a, b) ((a) > (b) ? (a) : (b))

#define MAX_CMD_LINE 256
#define MAX_PRINT_BUF_SIZE 128


#define BMS_DEV_WORK_STATE_OK   0
#define BMS_DEV_WORK_STATE_ERR  1

#define BMS_VALUED_STATE        0
#define BMS_INVALUED_STATE      1

/**********消息入口信息，记录下来，处理resp消息时找出口********/
typedef struct
{
    uint32_t infType; /*接口类型*/
    uint32_t infId;   /*接口ID*/
    uint8_t  isEnHierService;       ////<是否分层管理模式
} INF_STRU;

extern INF_STRU g_input;

/*-----------------------------------------------------------------------------------------
 Discription: CRC校验
 Param:       @param1:待校验的数据的起始地址
              @param2:待校验的数据长度
 Return:      校验结果
*-----------------------------------------------------------------------------------------*/
uint8_t BmsMsg_Crc8(uint8_t *arr_buff, uint8_t len);


/*-----------------------------------------------------------------------------------------
 Discription: CRC校验
 Param:       @param1:待校验的数据的起始地址
              @param2:待校验的数据长度
 Return:      校验结果
*-----------------------------------------------------------------------------------------*/
uint16_t BmsMsg_Crc16(uint8_t *arr_buff, uint8_t len);
uint8_t* GetGlobalTmpBuf(void);
typedef enum{
    USER_DEF_UINT16,
    USER_DEF_INT16
}DATA_TYPE;

/*操作均衡时，加上铜牌偏移,64位状态方式*/
uint64_t RecoverCopper_U64State(uint64_t state, uint64_t copperMask);
/*操作均衡时，加上铜牌偏移,数组状态方式*/
uint32_t RecoverCopper_ArrayState(uint32_t index, uint64_t copperMask);

/*-----------------------------------------------------------------------------------------
 Discription: 元素为四个字节表示的数组的CRC校验
 Param:       @param1:待校验的数据的起始地址
              @param2:待校验的数据的长度
 Return:      校验的结果
*-----------------------------------------------------------------------------------------*/
uint32_t CalculateXorCrc(uint8_t *arr_buff, uint32_t len);
/*-----------------------------------------------------------------------------------------
 Discription: 元素为两个字节表示的数组的CRC校验
 Param:       @param1:待校验的数据的起始地址
              @param2:待校验的数据的长度
 Return:      校验的结果
*-----------------------------------------------------------------------------------------*/
uint16_t CalculateU16XorCrc(uint8_t *arr_buff, uint32_t len);

/*-----------------------------------------------------------------------------------------
 Discription: 置BMS是否初始化成功标志位
 Param:       @param1:  BMS_CONFIG_STATE_INIT:初始化未成功，BMS_CONFIG_STATE_INIT_OVER:初始化成功
 Return:      校验的结果
*-----------------------------------------------------------------------------------------*/
void SetBmsConfigState(uint32_t state);
/*-----------------------------------------------------------------------------------------
 Discription: 获取BMS是否初始化成功标志位
 Param:       无
 Return:      0:初始化未成功，1:初始化成功
*-----------------------------------------------------------------------------------------*/
uint32_t GetBmsConfigState(void);
uint32_t TestCpuLoadUpdateWorkTime(uint32_t state,uint32_t value);
int32_t small_vsprintf(char *buf, const char *format, va_list args);
int32_t small_vsnprintf(char *buf,  uint32_t size,const char *fmt, va_list args);

int32_t atoi10(uint8_t *buf);
int32_t atoi16(uint8_t *buf);

#define my_vsprintf small_vsprintf
#define my_vsnprintf small_vsnprintf

#define ENDIAN_TYPE_CONVERT_16(num)  ((((uint16_t)(num) & 0xff00U) >> 8) | \
                                      (((uint16_t)(num) & 0x00ffU) << 8))
#define ENDIAN_TYPE_CONVERT_32(num)  ((((uint32_t)(num) & 0xff000000U) >> 24) | \
                                      (((uint32_t)(num) & 0x00ff0000U) >> 8) | \
                                      (((uint32_t)(num) & 0x0000ff00U) << 8) | \
                                      (((uint32_t)(num) & 0x000000ffU) << 24))

#define BIG_TO_LITTLE_ENDIAN_16  ENDIAN_TYPE_CONVERT_16
#define BIG_TO_LITTLE_ENDIAN_32  ENDIAN_TYPE_CONVERT_32

#define LITTLE_TO_BIG_ENDIAN_16  BIG_TO_LITTLE_ENDIAN_16
#define LITTLE_TO_BIG_ENDIAN_32  BIG_TO_LITTLE_ENDIAN_32

#if (HOST_ENDIAN_TYPE == BIG_ENDIAN_TYPE)

#define HOST_TO_SLAVE_CAN_NET_16 BIG_TO_LITTLE_ENDIAN_16
#define HOST_TO_SLAVE_CAN_NET_32 BIG_TO_LITTLE_ENDIAN_32
#define HOST_TO_MODBUS_NET_16(num) (num)
#define HOST_TO_MODBUS_NET_32(num) (num)
#define HOST_TO_BIGENDIAN_16(num) (num)
#define HOST_TO_BIGENDIAN_32(num) (num)
#define BIG_ENDIAN_TO_HOST_16(num) (num)
#define BIG_ENDIAN_TO_HOST_32(num) (num)
#define HOST_TO_LITTLE_ENDIAN_16  BIG_TO_LITTLE_ENDIAN_16
#define HOST_TO_LITTLE_ENDIAN_32  BIG_TO_LITTLE_ENDIAN_32
#define LITTLE_ENDIAN_TO_HOST_16  LITTLE_TO_BIG_ENDIAN_16
#define LITTLE_ENDIAN_TO_HOST_32  LITTLE_TO_BIG_ENDIAN_32
/*国标协议大小端转换*/
#define HOST_TO_COMPROL_16(num)  (num)
#define HOST_TO_COMPROL_32  BIG_TO_LITTLE_ENDIAN_32
#define COMPROL_TO_HOST_16(num)  (num)
#define COMPROL_TO_HOST_32  LITTLE_TO_BIG_ENDIAN_32
#else
#define HOST_TO_SLAVE_CAN_NET_16(num) (num)
#define HOST_TO_SLAVE_CAN_NET_32(num) (num)
#define HOST_TO_MODBUS_NET_16 LITTLE_TO_BIG_ENDIAN_16
#define HOST_TO_MODBUS_NET_32 LITTLE_TO_BIG_ENDIAN_32
#define HOST_TO_BIGENDIAN_16  LITTLE_TO_BIG_ENDIAN_16
#define HOST_TO_BIGENDIAN_32  LITTLE_TO_BIG_ENDIAN_32
#define BIG_ENDIAN_TO_HOST_16  BIG_TO_LITTLE_ENDIAN_16
#define BIG_ENDIAN_TO_HOST_32  BIG_TO_LITTLE_ENDIAN_32
#define HOST_TO_LITTLE_ENDIAN_16(num) (num)
#define HOST_TO_LITTLE_ENDIAN_32(num) (num)
#define LITTLE_ENDIAN_TO_HOST_16(num) (num)
#define LITTLE_ENDIAN_TO_HOST_32(num) (num)
/*国标协议大小端转换*/
#define HOST_TO_COMPROL_16  LITTLE_TO_BIG_ENDIAN_16
#define HOST_TO_COMPROL_32(num)  (num)
#define COMPROL_TO_HOST_16  BIG_TO_LITTLE_ENDIAN_16
#define COMPROL_TO_HOST_32(num)  (num)
#endif

#define MODBUS_NET_TO_HOST_16 HOST_TO_MODBUS_NET_16
#define MODBUS_NET_TO_HOST_32 HOST_TO_MODBUS_NET_32

#define SIZE_OF_ARRAY(array_t) (sizeof(array_t)/sizeof(array_t[0]))

#define SIZE_OF_TYPE_NOT_LARGER_THAN(type, size) \
    char size_of_##type##_not_larger_than_##size() \
    { \
        char __dummy1[size - sizeof(type) + 1] = {0}; \
        return __dummy1[0]; \
    }

#define SIZE_OF_TYPE_NOT_EQUAL(type, size) \
    char size_of_##type##_not_equal() \
    { \
        char __dummy3[size - sizeof(type) + 1] = {0}; \
        char __dummy4[sizeof(type) - size + 1] = {0}; \
        return __dummy3[0] + __dummy4[0]; \
    }

#define SIZE_OF_ARRAY_NOT_LARGER_THAN(array_t, size) \
    char size_of_##array_t##_not_larger_than_##size() \
    { \
        char __dummy1[size - SIZE_OF_ARRAY(array_t) + 1] = {0}; \
        return __dummy1[0]; \
    }

#define SIZE_OF_ARRAY_NOT_EQUAL(array_1, array_2) \
    char size_of_##array_1##array_2##_not_equal_##size() \
    { \
        char __dummy1[SIZE_OF_ARRAY(array_1) - SIZE_OF_ARRAY(array_2) + 1] = {0}; \
        char __dummy2[SIZE_OF_ARRAY(array_2) - SIZE_OF_ARRAY(array_1) + 1] = {0}; \
        return __dummy1[0] + __dummy2[0]; \
    }

#define SIZE_OF_ARRAY_NOT_EQUAL_SIZE(array_1, size) \
    char size_of_##array_1##array_2##_not_equal_##size() \
    { \
        char __dummy1[SIZE_OF_ARRAY(array_1) - size + 1] = {0}; \
        char __dummy2[size - SIZE_OF_ARRAY(array_1) + 1] = {0}; \
        return __dummy1[0] + __dummy2[0]; \
    }

#define CHECK_IS_DIVISOR(dividend, divisor) \
    char check_is_##dividend##_divisible() \
    { \
        char __dummy1[(-1 * ((int32_t)(dividend) % (int32_t)(divisor))) + 1] = {0}; \
        char __dummy2[dividend] = {0}; \
        return __dummy1[0] + __dummy2[0]; \
    }


#ifdef WIN32
//#define FIELD_OFFSET(type_t, field)    ((LONG)(LONG_PTR)&(((type_t *)0)->field))
#define FIELD_OFFSET(TYPE, MEMBER) ((uint32_t) &((TYPE *)0)->MEMBER)
#define GET_SYS_TICK SysTick->VAL
#else
#define FIELD_OFFSET(TYPE, MEMBER) ((uint32_t) &((TYPE *)0)->MEMBER)
#endif

#ifdef UNIT_TEST
#define OPEN_REPORT()  freopen("E:\\unit_test_report.txt","ab+",stdout)
#define CLOSE_REPORT() fclose(stdout)

#endif


#ifdef UNIT_TEST
#define DEBUG_MSG(format,...)  \
    do{                        \
        printf(format,__VA_ARGS__) ;   \
    }while(0)

#define ASSERT_POINTER(a) \
    do{                     \
        CPPTEST_ASSERT(a != NULL);\
        if(a == NULL)           \
        {                       \
        printf("%s = NULL", #a); \
        return; \
        }                       \
    }while(0)

#define UT_DEBUG_ASSERT(a, format,...) \
        do{                      \
            CPPTEST_ASSERT((a) == 0); \
            if(a)                \
            {                    \
            printf(format,__VA_ARGS__) ;   \
            return; \
            }                   \
        }while(0)

#define DEBUG_ASSERT(...)

#define MEM_MANAGER_Free()  \
    do{                     \
        memset(&g_MemManagement, 0x00, sizeof(MEM_MANAGE_STRU));\
        }while(0)
#else

#ifdef _DEBUG
#define DEBUG_MSG(format,...)  \
    do{                        \
    printf(format,__VA_ARGS__) ;   \
    }while(0)

#define ASSERT_POINTER(a) \
    do{                     \
    if((a) == (void *)NULL)     \
    {                   \
      while(1) {}      \
    }                   \
    }while(0)

#define DEBUG_ASSERT(a, format,...) \
    do{                      \
    if(a)                \
    {                    \
        while(1)        \
        {                \
        }                \
    }                    \
    }while(0)

#else

#define ASSERT_POINTER(...)
#define DEBUG_ASSERT(...)
#define DEBUG_MSG(...)
#endif
#endif

extern void DebugPrintf(char *fmt,...);

#endif /* __TOOLKIT_H__ */

