#include "update_file.h"
#include "stdio.h"

#define UPUS_Printf printf
char *g_pPath = NULL;
FILE *g_pFile = NULL;

uint16_t Bin_Crc16 (uint16_t crc_init, uint8_t *arr_buff, uint32_t len)
{
	int i, j;
	uint16_t crc = crc_init;
    for ( j=0; j < len; j++)
    {
        crc = (uint16_t)(crc^*arr_buff++);
        for (i = 0; i < 8; i++)
        {
            if((crc & 0x0001) > 0)
            {
                crc = crc >> 1;
                crc = crc ^ 0xa001;
            }
            else
            {
                crc = crc >> 1;
            }
        }
    }
    return (crc);
}

#define ONCE_LEN 64
#define CRC_LEN 4
/*
    计算文件CRC查看文件是否正确
    */
Std_Bool_Enum UPFile_ISCRCCorrect(void *fileInfor)
{
    FILE *bin = g_pFile;
    uint16_t crc1 = 0x0;
    uint16_t crc2 = 0x0;
    uint16_t crc = 0xffff;
    uint32_t bin_crc = 0;

    uint8_t softVer[40] = {0};
    char *project_num = NULL;
    uint8_t readArray[2 * ONCE_LEN] = {0};
    uint32_t realLen = 0, total_realLen = 0, len = 0, crc1_len = 0;

    if (NULL == g_pFile) {
        return Std_False;
    }

    fseek(g_pFile, 0, SEEK_END);
    len = ftell(g_pFile);
    fseek(g_pFile, 0, SEEK_SET);
    crc1_len = len - CRC_LEN;
    if (crc1_len <= 0) {
        return Std_False;
    }

    while (1)
    {
        if (crc1_len - total_realLen > 2 * ONCE_LEN) {
            realLen = fread(readArray, 1, ONCE_LEN, bin);    
            crc = Bin_Crc16(crc, readArray, realLen);
        } else { //一次读到crc1的长度
            realLen = fread(readArray, 1, crc1_len - total_realLen, bin);
            crc1 = Bin_Crc16(crc, readArray, realLen);
            memcpy(softVer, readArray + realLen - sizeof(softVer), sizeof(softVer)); //readArray低40字节保存着工程版本(4B)、主版本号(4B)、工程编号(32B)
        }
        total_realLen += realLen; 
        if (total_realLen >= crc1_len) {
            break;
        }
    }
    
    //计算crc2
    project_num = (char *)(softVer + 8); //工程版本(4B)、主版本号(4B)
    if (NULL == project_num) {
        return Std_False;
    }
    crc2 = Bin_Crc16(crc1, softVer, 8 + strlen(project_num));//去掉工程编号多余的尾零

    //读bin文件中的crc, 此时文件指针已经指向了crc
    realLen = fread(&bin_crc, 1, sizeof(bin_crc), bin);
    if (realLen != CRC_LEN) {
        return Std_False;
    }
    fseek(bin, 0, SEEK_SET);
    printf("crc2 is 0x%x, read crc:0x%x\n", crc2, bin_crc);

    return crc2 == bin_crc;
}

/*!
 * @brief      打开文件
 *
 * @param[in]   path
 * @return
 * @retval      None
 *
 * @par         modify    log
 * Date        Author     Description             \n
 * 2022-8-25     dfs      Create             \n
 *
 */
File_Op_Ret_Enum UPFile_OpenFile(void* path, uint32_t *size)
{
    g_pFile = fopen( path, "rb");
    if (g_pFile == NULL){
        UPUS_Printf("root open failed  (%s) \n", (char *)path);
        return File_Opr_Err;
    }
    fseek(g_pFile, 0, SEEK_END);
    *size = ftell(g_pFile);
    fseek(g_pFile, 0, SEEK_SET);

    return File_Opr_Ok;
}

/*-----------------------------------------------------------------------------------------
 Discription:  查找文件是否有匹配文件名的文件
               可以顺序读取
               如果需要选择位置使用seek
 Author:       DFS
 Date:         2019-08-27
 Param:
               @Param1:read buffer
               @Param2:len
               @Param3:read len
 Return:       操作结果
 Modify:
*-----------------------------------------------------------------------------------------*/
File_Op_Ret_Enum UPFile_ReadFile(void* buff, Std_Base_Type len, Std_Base_Type* realLen)
{
    DEBUG_ASSERT((g_pFile == NULL), "update file err \r\n");
    *realLen = fread(buff, 1, len, g_pFile);
    if(*realLen == 0)
    {
        UPUS_Printf("file read encount err \r\n");
        return File_Opr_Err;
    }
    return File_Opr_Ok;
}


/*!
 * @brief       关闭文件
 *
 * @param[in]   void
 * @return
 * @retval      None
 *
 * @par         modify    log
 * Date        Author     Description             \n
 * 2022-8-25     dfs      Create             \n
 *
 */
File_Op_Ret_Enum UPFile_CloseFile(void)
{
    int32_t result = 0;
    if(NULL == g_pFile)
        return File_Opr_Err;

    result = fclose(g_pFile);
    g_pFile = NULL;
    if(result != 0){
        UPUS_Printf("file close encount err \r\n");
        return File_Opr_Err;
    }
    return File_Opr_Ok;
}


/*!
 * @brief    查找文件位置
 *
 * @param[in]   offset
 * @return
 * @retval      None
 *
 * @par         modify    log
 * Date        Author     Description             \n
 * 2022-8-25     dfs      Create             \n
 *
 */
File_Op_Ret_Enum UPFile_SeekFile(Std_Base_Type offset)
{
    int32_t result = 0;

    DEBUG_ASSERT((g_pFile == NULL), "update file err \r\n");
    result = fseek(g_pFile, offset, SEEK_SET);
    if(result != 0)
    {
        UPUS_Printf("file read encount err \r\n");
        return File_Opr_Err;
    }
    return File_Opr_Ok;
}

