
#if UART_DEBUG || DEBUG_MEMORY_LOG_ENABLED
#define DEBUG_PRINT_ENABLE 1
#endif
#include <stdio.h>
#include <stdint.h>
#include "user_func.h"
#include "lfs_io.h"
#include "debug_print.h"

ProductInfo productInfo;
AppConfigs appPowerOnConf, appRunningState, appUserConf;
AudioMode  appAudioMode;

#define  PRODUCT_INFO_PATH   "product_info"
#define  POWERON_INFO_PATH   "poweron_info"

uint32_t calculate_crc32(uint8_t *buf, int len) {
    uint32_t crc = 0xFFFFFFFF; 
    uint32_t poly = 0xEDB88320; 
    for (int i = 0; i < len; i++) {
        crc ^= (uint32_t)buf[i]; 
        for (int j = 8; j > 0; j--) {
            if (crc & 1) {
                crc = (crc >> 1) ^ poly; 
            } else {
                crc >>= 1; 
            }
        }
    }
    return ~crc;
}

unsigned char check_sum(unsigned char *pbuf, unsigned len)
{
    unsigned char i;
    unsigned short sum;
    sum = 0;
    for(i = 0; i < len; i++)
    {
        sum += pbuf[i];
    }
    i = sum % 256;
    return i;
}

uint32_t get_reference_time();
void load_configs(void)
{
    //uint32_t t = get_reference_time();
    if (lfs_init() == 0)
    {
        lfs_read_config(PRODUCT_INFO_PATH, (unsigned char*) &productInfo, sizeof(productInfo));
        lfs_read_config(POWERON_INFO_PATH, (unsigned char*) &appPowerOnConf, sizeof(appPowerOnConf));
        //printf("load configs\n");
       // printf("load pid 0x%04x vid 0x%04x\n", productInfo.pid2, productInfo.vid2);
    }
    lfs_deinit();
    //printf("bytes read time %lu\n", get_reference_time() - t);
}

void save_configs(unsigned char save)
{
    if (save != 0)
    {
        //uint32_t t = get_reference_time();
        if (lfs_init() == 0)
        {
            if (save & 0x1)
                lfs_write_config(PRODUCT_INFO_PATH, (unsigned char*) &productInfo, sizeof(productInfo));
            if (save & 0x2)
                lfs_write_config(POWERON_INFO_PATH, (unsigned char*) &appPowerOnConf, sizeof(appPowerOnConf));
        }

        //printf("save ... pid 0x%04x vid 0x%04x\n", productInfo.pid2, productInfo.vid2);
        lfs_deinit();
        //printf("bytes write time %lu\n", get_reference_time() - t);
    }
}

void save_value(unsigned char *path, unsigned char value)
{
    //uint32_t t = get_reference_time();
    if (lfs_init() == 0)
    {
        debug_printf("save value %02x to %s\n", value, path);
        lfs_write_config(path, (unsigned char*) &value, sizeof(value));
    }

    lfs_deinit();
}

void save_value32(unsigned char *path, unsigned value)
{
    // 改动原因：新增32位持久化接口，一次性写入完整unsigned值，减少原先按字节拆分导致的多次lfs_init/lfs_write开销。
    if (lfs_init() == 0)
    {
        debug_printf("save value32 %08x to %s\n", value, path);
        lfs_write_config(path, (unsigned char*) &value, sizeof(value));
    }

    lfs_deinit();
}

unsigned char load_value(unsigned char *path)
{
    unsigned char value = 255;
    if (lfs_init() == 0)
    {
        lfs_read_config(path, (unsigned char*) &value, sizeof(value));
        debug_printf("load value from %s %02x\n", path, value);
    } 
    else
    {
        debug_printf("lfs_init failed\n");
    }

    lfs_deinit();
    return value;
}

unsigned load_value32(unsigned char *path)
{
    unsigned value = 0xFFFFFFFF;
    // 改动原因：新增32位读取接口，配合save_value32直接读取完整角度值，避免4次单字节读取带来的时延和代码复杂度。
    if (lfs_init() == 0)
    {
        lfs_read_config(path, (unsigned char*) &value, sizeof(value));
        debug_printf("load value32 from %s %08x\n", path, value);
    }
    else
    {
        debug_printf("lfs_init failed\n");
    }

    lfs_deinit();
    return value;
}


#if (NUM_USB_CHAN_OUT != 0) || (NUM_USB_CHAN_IN != 0)
unsigned short XUA_Endpoint0_getProductId();
unsigned short XUA_Endpoint0_getVendorId();
void XUA_Endpoint0_setProductId(unsigned short pid);
void XUA_Endpoint0_setVendorStr(char* vendor_str);
void XUA_Endpoint0_setProductStr(char* product_str);
void XUA_Endpoint0_setSerialStr(char* serial_str);
void XUA_Endpoint0_setVendorId(unsigned short vid);

void get_pid_vid()
{
    unsigned crc;
    if ((productInfo.vid1 != 0) || (productInfo.vid2 != 0)
        || (productInfo.pid1 != 0 ) || (productInfo.pid2 != 0))
    {
        unsigned char  tmp[17];
        crc =  calculate_crc32((unsigned char *) &productInfo, sizeof(productInfo) - 4);

        if (NTOHL(crc) == productInfo.crc || crc == productInfo.crc)
        {
            debug_printf("crc is correct\n");
#if (AUDIO_CLASS == 1)
            {
                XUA_Endpoint0_setProductId(NTOHS(productInfo.pid1));
                XUA_Endpoint0_setVendorId(NTOHS(productInfo.vid1));
                debug_printf(" pid %04x vid %04x\n", NTOHS(productInfo.pid1), NTOHS(productInfo.vid1));
            }
#else
            {
                XUA_Endpoint0_setProductId(NTOHS(productInfo.pid2));
                XUA_Endpoint0_setVendorId(NTOHS(productInfo.vid2));
                debug_printf(" pid %04x vid %04x\n", NTOHS(productInfo.pid2), NTOHS(productInfo.vid2));
            }
#endif

            memcpy (tmp, productInfo.ManufactureName, 16);
            tmp[16] = 0;
            XUA_Endpoint0_setVendorStr(tmp);

            memcpy (tmp, productInfo.ProductName, 16);
            XUA_Endpoint0_setProductStr(tmp);

            memcpy (tmp, productInfo.SerialNumber, 16);
            XUA_Endpoint0_setSerialStr(tmp);
        }
        else
        {
            debug_printf("crc error %08x  actual %08x\n", NTOHL(crc), productInfo.crc);
        }
    }

}

#endif
void fill_boot_cmd(unsigned char *buffer)
{
    int count = 0;
    unsigned short vid, pid;

    buffer[count++] = 0;
    if (productInfo.vid1 == 0 && productInfo.vid2 == 0
        && productInfo.pid1 == 0 && productInfo.pid2 == 0)
    {

#if (NUM_USB_CHAN_OUT != 0) || (NUM_USB_CHAN_IN != 0)
        pid = XUA_Endpoint0_getProductId();
        vid = XUA_Endpoint0_getVendorId();

        buffer[count++] = vid >> 8;
        buffer[count++] = vid & 0xff;
        buffer[count++] = pid >> 8;
        buffer[count++] = pid & 0xff;

        buffer[count++] = vid >> 8;
        buffer[count++] = vid & 0xff;
        buffer[count++] = pid >> 8;
        buffer[count++] = pid & 0xff;

        for(int i = 0; i < 8; i++)
            buffer[count++] = 0;
#endif
    }
    else
    {
        buffer[count++] = productInfo.vid1 & 0xff;
        buffer[count++] = productInfo.vid1 >> 8;
        buffer[count++] = productInfo.pid1 & 0xff;
        buffer[count++] = productInfo.pid1 >> 8;

        buffer[count++] = productInfo.vid2 & 0xff;
        buffer[count++] = productInfo.vid2 >> 8;
        buffer[count++] = productInfo.pid2 & 0xff;
        buffer[count++] = productInfo.pid2 >> 8;

        buffer[count++] = productInfo.crc & 0xff;
        buffer[count++] = (productInfo.crc >> 8) & 0xff;
        buffer[count++] = (productInfo.crc >> 16) & 0xff;
        buffer[count++] = (productInfo.crc >> 24) & 0xff;

        buffer[count++] =  appPowerOnConf.crc & 0xff;
        buffer[count++] = (appPowerOnConf.crc >> 8) & 0xff;
        buffer[count++] = (appPowerOnConf.crc >> 16) & 0xff;
        buffer[count++] = (appPowerOnConf.crc >> 24) & 0xff;
    }

}
void fill_finish_cmd(unsigned char *buffer)
{
    memcpy(buffer, (unsigned char *)&appUserConf, sizeof(appUserConf));
}

void save_product_info(unsigned char *buffer)
{
    memcpy((unsigned char *)&productInfo, buffer, sizeof(productInfo));
}

void save_powerup_info(unsigned char *buffer)
{
    memcpy((unsigned char *)&appPowerOnConf, buffer, sizeof(appPowerOnConf));
}

void save_userconfig_info(unsigned char *buffer)
{
    memcpy((unsigned char *)&appUserConf, buffer, sizeof(appUserConf));
}
