/**
  ******************************************************************************
  * @file    mylib.c
  * @author  eming
  * @version V1.0.0
  * @date    2022-03-21
  * @brief   定义一些公用函数
  ******************************************************************************
  */
#include "stdint.h"
#include "ustdio.h"
#include "stdlib.h"
#include "string.h"
#include "time.h"
#include "type.h"

/**
 * @brief 和校验
 * @details 字节数组的和校验函数
 *
 * @param *p 数组指针
 * @param size 数组长度
 * @return 求和结果
 *   @retval 无
 */
uint32_t mylib_sum(const uint8_t *p, uint16_t size)
{
    uint32_t sum = 0;

    while(size--)
    {
        sum += *(p++);
    }
    return(sum);
}

/**
 * @brief 数据比较
 * @details 字节数组的数据比较
 *
 * @param *p1 数组1指针
 * @param *p2 数组2指针
 * @param size 比较的数据块大小
 * @return 比较结果
 *   @retval TRUE 相等
 *   @retval FALSE 不相等
 */
int mylib_memcmp(const void *p1, const void *p2, int size)
{
    uint8_t *bp1, *bp2;
    
    bp1 = (uint8_t*)p1;
    bp2 = (uint8_t*)p2;
    while(size--)
    {
        if(*(bp1++) != *(bp2++))return(FALSE);
    }
    return(TRUE);
}

/**
 * @brief 数据比较
 * @details 字节数组与指定数据比较
 *
 * @param *p1 数组指针
 * @param value 被比较的数值
 * @param size 比较的数据块大小
 * @return 比较结果
 *   @retval TRUE 相等
 *   @retval FALSE 不相等
 */
int mylib_memcmp_b(uint8_t *p1, uint8_t value, int size)
{
    while(size--)
    {
        if(*(p1++) != value)return(FALSE);
    }
    return(TRUE);
}

/**
 * @brief 延时函数
 * @details 大概为1uS的延时函数
 *
 * @param us 需要延时的微秒数
 * @return 无
 *   @retval 无
 */
void mylib_uDelay(uint32_t us)
{
    int i;
    
    for(; us > 0; us--)
    {
        for(i = 0; i < 40; i++);
    }
}

/**
 * @brief CRC16函数
 * @details 计算字节数组的CRC16
 *
 * @param *p 数组指针
 * @param size 数组长度
 * @return 计算结果
 *   @retval uint16_t CRC16值
 */
uint16_t mylib_crc16(uint8_t *p, uint16_t size)
{
    uint16_t crc;                        //校验码
    uint16_t i;
    uint16_t j;
    crc = 0xFFFF;
    for (i = 0; i < size; i++)
    {
        crc ^= *p;
        for (j = 0; j < 8; j++)
        {
            if ((crc & 1) == 1)
            {
                crc >>= 1;
                crc ^= 0xA001;
            }
            else
            {
                crc >>= 1;
            }
        }
        p++;
    }
    return(crc);
}

/**
 * @brief 16位大小端转换
 * @details 数据大端小段互相转换函数
 *
 * @param *frm 源数组指针
 * @param *to 目标数组指针
 * @param size 转换的数据个数(半字)
 * @return 无
 *   @retval 无
 */
void mylib_BigtoLittle16(const void *frm, void *to, uint16_t size)
{
    uint8_t  buff[2];
    uint8_t 	*fp, *tp;

    fp = (uint8_t *)frm;
    tp = (uint8_t *)to;
    while(size--)
    {
        buff[0] = fp[0];
        buff[1] = fp[1];
        tp[0] 	= buff[1];
        tp[1] 	= buff[0];

        tp  += 2;
        fp += 2;
    }
}

/**
 * @brief 32位大小端转换
 * @details 数据大端小段互相转换函数
 *
 * @param *frm 源数组指针
 * @param *to 目标数组指针
 * @param size 转换的数据个数(字)
 * @return 无
 *   @retval 无
 */
void mylib_BigtoLittle32(const void *frm, void *to, uint16_t size)
{
    uint8_t buff[4];
    uint8_t *fp, *tp;

    fp = (uint8_t *)frm;
    tp = (uint8_t *)to;
    while(size--)
    {
        buff[0] = fp[0];
        buff[1] = fp[1];
        buff[2] = fp[2];
        buff[3] = fp[3];
        tp[0] 	= buff[3];
        tp[1] 	= buff[2];
        tp[2] 	= buff[1];
        tp[3] 	= buff[0];

        tp  += 4;
        fp += 4;
    }
}

/**
 * @brief 64位浮点数大小端转换
 * @details 数据大端小段互相转换函数
 *
 * @param dat 浮点数
 * @return 转换结果
 *   @retval 转换后的浮点数
 */
double mylib_BigtoLittle_fp64(double dat)
{
    F64_U8 tmp1, tmp2;

    tmp1.f64 = dat;
    tmp2.d8[0] = tmp1.d8[7];
    tmp2.d8[1] = tmp1.d8[6];
    tmp2.d8[2] = tmp1.d8[5];
    tmp2.d8[3] = tmp1.d8[4];
    tmp2.d8[4] = tmp1.d8[3];
    tmp2.d8[5] = tmp1.d8[2];
    tmp2.d8[6] = tmp1.d8[1];
    tmp2.d8[7] = tmp1.d8[0];
    
    return(tmp2.f64);
}

/**
 * @brief BCD编码函数
 * @details 二进制数据转BCD码
 *
 * @param hex 二进制数据
 * @return 转换结果
 *   @retval BCD码
 */
uint8_t mylib_HEXtoBCD(uint8_t hex)
{
    uint8_t bcd = 0;

    bcd = hex / 10;
    bcd <<= 4;
    bcd += hex % 10;

    return(bcd);
}

/**
 * @brief BCD解码函数
 * @details BCD码转二进制数据
 *
 * @param bcd BCD码数据
 * @return 转换结果
 *   @retval 二进制数据
 */
uint8_t mylib_BCDtoHEX(uint8_t bcd)
{
    uint8_t hex = 0;

    hex = ((bcd >> 4) & 0x0F) * 10 + (bcd & 0x0F);
    return(hex);
}

/**
 * @brief 数值转字符串
 * @details 整形数值转字符串
 *
 * @param value 整形数值
 * @param *str 转换结果字符串指针
 * @param radix 进制
 * @return 换结果字符串指针
 */
char *itoa_(int value, char *str, uint8_t radix)
{
    static char szMap[] =
    {
        '0', '1', '2', '3', '4', '5',
        '6', '7', '8', '9', 'a', 'b',
        'c', 'd', 'e', 'f', 'g', 'h',
        'i', 'j', 'k', 'l', 'm', 'n',
        'o', 'p', 'q', 'r', 's', 't',
        'u', 'v', 'w', 'x', 'y', 'z'
    };  // 字符映射表
    int nCount = -1, nIndex;
    char *pStr = str, nTemp;
    unsigned int nValue = *(unsigned *)&value;

    if(radix >= 2 && radix <= 36 )          //限制radix必须在2到36之间
    {
        if(value < 0 && radix == 10)        //如果是负数就在首位添加负号，并将字符串前移
        {
            *pStr++ = '-';
            value = -value;                 //转为正数，
        }
        do                                  //循环转换每一个数字，直到结束
        {
            pStr[++nCount] = szMap[nValue % radix];
            nValue /= radix;
        }
        while(nValue > 0);                  //转换结束后字符串是翻的
        nIndex = (nCount + 1) / 2;          //计算出一半的长度
        while(nIndex-- > 0)                 //将字符串的字符序翻转
        {
            nTemp = pStr[nIndex];
            pStr[nIndex] = pStr[nCount - nIndex];
            pStr[nCount - nIndex] = nTemp;
        }
    }
    pStr[nCount + 1] = '\0';                // 置结束符
    return str;
}

/**
 * @brief 数组转字符串
 * @details 字节数组转字符串
 *
 * @param *str 转换后的字符串
 * @param bytes 被转换的字节数组
 * @param size 被转换的字节数组长度
 * @return 转换出的字符串长度
 */
int mylib_bytes_to_string(char *str, const uint8_t *bytes, int size)
{
    int i;

    char hexArray[] = "0123456789ABCDEF";

    for (i = 0; i < size; i++)
    {
        int v = bytes[i] & 0xFF;
        str[i * 2] = hexArray[v >> 4];
        str[i * 2 + 1] = hexArray[v & 0x0F];
    }
    str[size * 2] = '\0';

    return (size * 2);
}

/**
 * @brief 字符串转数组
 * @details 字符串转字节数组
 *
 * @param *str 被转换的字符串
 * @param bytes 转换出的字节数组
 * @return 转换出的字节数组长度
 */
int mylib_string_to_bytes(char *str, uint8_t *bytes)
{
    uint8_t 	tmp, tmp1;
    uint16_t len;
    uint16_t dat_len;

    len = strlen(str);
    if(len % 2)				  			//检查是否为偶数
    {
        str[len] = '0';					//补0
        len++;
        str[len] = '\0';
    }
    dat_len = len / 2;
    while(len)
    {
        if((*str > 47) && (*str < 58))	  	//0~9
        {
            tmp = *str - 48;
        }
        else if((*str > 64) && (*str < 71))	//A~F
        {
            tmp = *str - 55;
        }
        else if((*str > 96) && (*str < 103))	//a~f
        {
            tmp = *str - 87;
        }
        else
        {
            tmp = 32;
        }
        tmp <<= 4;
        str++;
        if((*str > 47) && (*str < 58))	  	//0~9
        {
            tmp1 = *str - 48;
        }
        else if((*str > 64) && (*str < 71))	//A~F
        {
            tmp1 = *str - 55;
        }
        else if((*str > 96) && (*str < 103))	//a~f
        {
            tmp1 = *str - 87;
        }
        else
        {
            tmp1 = 32;
        }
        tmp += tmp1;
        *(bytes++) = tmp;
        str++;
        len -= 2;
    }
    
    return(dat_len);
}

/**
 * @brief 大小写转换
 * @details 将字符串中的大写字符变为小写字符
 *
 * @param *str 被转换的字符串
 * @return 转换出的字符串
 */
char *strlwr(char *str)
{
    uint16_t len;
    char   *p;

    len = strlen(str);
    p = str;
    while(len--)
    {
        if((*p > 64) && (*p < 91))
        {
            *p += 32;
        }
        p++;
    }
    return(str);
}

/**
 * @brief 字符串提取数字
 * @details 字符串提取数字字符,去除其他符号
 *
 * @param *str 被处理的字符串
 * @param *num 结果字符串
 * @return 提取出的字符串长度
 */
int strval(char *str, char *num)
{
    int len = 0;

    while(*str != '\0')
    {
        if((*str > 47) && (*str < 58))
        {
            *num = *str;
            num++;
            len++;
        }
        str++;
    }
    *num = '\0';
    
    return(len);
}

/**
 * @brief 打印16进制数据
 * @details 由于调试时输出二进制数据
 *
 * @param *p 二进制数据指针
 * @param size 数据长度
 * @return 无
 */
void printk_hex(const uint8_t *p, int size)
{
    int i;

    for(i = 0; i < size; i++)
    {
        printk(" %02X", *(p++));
    }
}

/**
 * @brief utc秒转时间
 * @details 包含时区参数
 *
 * @param utc_s utc秒
 * @param *t 转换结果
 * @param tz 时区
 * @return 无
 */
void utc_to_time(uint32_t utc_s, struct tm *t, int tz)
{
    #define SECOND_OF_DAY     86400      		    //1天的秒数    
    uint16_t i, j, iDay;
    uint32_t lDay;
    const uint8_t DayOfMon[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    utc_s += 3600 * tz;    //时区

    lDay = utc_s / SECOND_OF_DAY;
    utc_s = utc_s % SECOND_OF_DAY;

    i = 1970;										//星期取值为0-6
    t->tm_wday = (lDay + 3) % 7;					//1970年1月1号是星期4
    while(lDay > 365)
    {
        if(((i % 4 == 0) && (i % 100 != 0)) || (i % 400 == 0))    	// 闰年
            lDay -= 366;
        else
            lDay -= 365;
        i++;
    }
    if((lDay == 365) && !(((i % 4 == 0) && (i % 100 != 0)) || (i % 400 == 0))) //平年
    {
        lDay -= 365;
        i++;
    }
    t->tm_year = i - 1900;     					//得到年份
    for(j = 0; j < 12; j++)     		        //计算月份
    {
        if((j == 1) && (((i % 4 == 0) && (i % 100 != 0)) || (i % 400 == 0)))
            iDay = 29;
        else
            iDay = DayOfMon[j];
        if(lDay >= iDay) lDay -= iDay;
        else break;
    }
    t->tm_mon  = j;
    t->tm_mday = lDay + 1;
    t->tm_hour = utc_s / 3600;
    t->tm_min  = (utc_s % 3600) / 60;
    t->tm_sec  = (utc_s % 3600) % 60;
}

/**
 * @brief 计算日期是一年中的那一天
 * @details 计算日期的年索引,2月当做29天算
 *
 * @param utc_s utc秒
 * @param *t 转换结果
 * @param tz 时区
 * @return 无
 */
int mylib_day_index(uint8_t mon, uint8_t day)
{
    const  uint8_t  Line_Mon_Len[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int index = 0;
    int  i;

    if((mon < 1) || (mon > 12))return(0); //参数判断
    if((day < 1) || (day > 31))return(0);

    for(i = 1; i < mon; i++)
    {
        index += Line_Mon_Len[i - 1];
    }
    index += day - 1;

    return(index);
}

/**
 * @brief 16进制字符串转数据
 * @details 16进制字符串转数据,可以包含"0x"头
 *
 * @param *s 字符串
 * @return 提取的数值
 */
int tolower(int c)  
{  
    if (c >= 'A' && c <= 'Z')  
    {  
        return c + 'a' - 'A';  
    }  
    else  
    {  
        return c;  
    }  
}

uint32_t htoi(const char *s)  
{  
    int i;  
    uint32_t n = 0; 

    if (s[0] == '0' && (s[1]=='x' || s[1]=='X'))  
    {  
        i = 2;  
    }  
    else  
    {  
        i = 0;  
    }  
    for (; (s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'z') || (s[i] >='A' && s[i] <= 'Z');++i)  
    {  
        if (tolower(s[i]) > '9')  
        {  
            n = 16 * n + (10 + tolower(s[i]) - 'a');  
        }  
        else  
        {  
            n = 16 * n + (tolower(s[i]) - '0');  
        }  
    }  
    return n;  
} 

/**
 * @brief 返回堆内存的大小
 * @details 返回堆内存的大小
 *
 * @param *mp 堆内存指针
 * @return 堆内存的大小
 */
uint32_t _msize(const void *mp)
{
    return(*((int*)((uint32_t)mp - 4)));
}

/*******************************************************************************************************
**                            End Of File
********************************************************************************************************/


