#include "app_config.h"
#if(USER_UART_UPDATE_ENABLE) && (UART_UPDATE_ROLE == UART_UPDATE_SLAVE)
#include "typedef.h"
#include "update_loader_download.h"
#include "os/os_api.h"
#include "system/task.h"
#include "update.h"
#include "gpio.h"
#include "uart_update.h"
#include "asm/uart_dev.h"
#include "asm/clock.h"

static volatile u32 uart_to_cnt = 0;
static volatile u32 uart_file_offset = 0;
static volatile u16 rx_cnt;  //收数据计数
static void (*uart_update_resume_hdl)(void *priv) = NULL;
static int (*uart_update_sleep_hdl)(void *priv) = NULL;

#define LOG_TAG             "[UART_UPDATE]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
#define LOG_CLI_ENABLE
#include "debug.h"

#define RETRY_TIME          4//重试n次
#define PACKET_TIMEOUT      200//ms

//命令
#define CMD_UPDATE_START    0x01
#define CMD_UPDATE_READ     0x02
#define CMD_UPDATE_END      0x03
#define CMD_SEND_UPDATE_LEN 0x04
#define CMD_KEEP_ALIVE      0x05


#define READ_LIT_U16(a)   (*((u8*)(a))  + (*((u8*)(a)+1)<<8))
#define READ_LIT_U32(a)   (*((u8*)(a))  + (*((u8*)(a)+1)<<8) + (*((u8*)(a)+2)<<16) + (*((u8*)(a)+3)<<24))

#define WRITE_LIT_U16(a,src)   {*((u8*)(a)+1) = (u8)(src>>8); *((u8*)(a)+0) = (u8)(src&0xff); }
#define WRITE_LIT_U32(a,src)   {*((u8*)(a)+3) = (u8)((src)>>24);  *((u8*)(a)+2) = (u8)(((src)>>16)&0xff);*((u8*)(a)+1) = (u8)(((src)>>8)&0xff);*((u8*)(a)+0) = (u8)((src)&0xff);}

#define THIS_TASK_NAME "uart_update"


static protocal_frame_t protocal_frame __attribute__((aligned(4)));
u32 update_baudrate = 9600;             //初始波特率
static uart_update_cfg  update_cfg;

u32 uart_dev_receive_data(void *buf, u32 relen, u32 addr);
void uart_set_dir(u8 mode);
void uart_update_write(u8 *data, u32 len);
void uart_update_set_baud(u32 baudrate);
void uart_close_deal(void);
void uart_hw_init(uart_update_cfg update_cfg, void (*cb)(void *, u32));
void uart_data_decode(u8 *buf, u16 len);
void updata_parm_set(UPDATA_TYPE up_type, void *priv, u32 len);

enum {
    SEEK_SET = 0x0,
    SEEK_CUR = 0x1,
    SEEK_END = 0X2,
};

enum {
    CMD_UART_UPDATE_START = 0x1,
    CMD_UART_UPDATE_READ,
    CMD_UART_UPDATE_END,
    CMD_UART_UPDATE_UPDATE_LEN,
    CMD_UART_JEEP_ALIVE,
    CMD_UART_UPDATE_READY,
};


static void uart_update_hdl_register(void (*resume_hdl)(void *priv), int (*sleep_hdl)(void *priv))
{
    uart_update_resume_hdl = resume_hdl;
    uart_update_sleep_hdl  = sleep_hdl;
}

void sava_uart_update_param(void)
{
    UPDATA_UART uart_param = {.control_baud = update_baudrate, .control_io_tx = update_cfg.tx, .control_io_rx = update_cfg.rx};
    updata_parm_set(UART_UPDATA, (u8 *)&uart_param, sizeof(UPDATA_UART));
}

static void uart_update_callback(void *priv, u8 type, u8 cmd)
{
    if (cmd == UPDATE_LOADER_OK) {
        update_mode_api(type, update_baudrate, update_cfg.tx, update_cfg.rx);
    } else {
        //失败将波特率设置回初始,并重置变量
        rx_cnt = 0;
        update_baudrate = 9600;
        uart_file_offset = 0;
        uart_update_set_baud(update_baudrate);
        //uart_hw_init(update_cfg, uart_data_decode);
    }
}

void uart_data_decode(u8 *buf, u16 len)
{
    u16 crc, crc0, i, ch;
    /* printf("decode_len:%d\n", len); */
    /* put_buf(buf, len); */
    for (i = 0; i < len; i++) {
        ch = buf[i];
__recheck:
        if (rx_cnt == 0) {
            if (ch == SYNC_MARK0) {
                protocal_frame.raw_data[rx_cnt++] = ch;
            }
        } else if (rx_cnt == 1) {
            protocal_frame.raw_data[rx_cnt++] = ch;
            if (ch != SYNC_MARK1) {
                rx_cnt = 0;
                goto __recheck;
            }
        } else if (rx_cnt < 4) {
            protocal_frame.raw_data[rx_cnt++] = ch;
        } else {
            protocal_frame.raw_data[rx_cnt++] = ch;
            if (rx_cnt == (protocal_frame.data.length + SYNC_SIZE)) {
                rx_cnt = 0;
                extern u16 CRC16(void *ptr, u32 len);
                crc = CRC16(protocal_frame.raw_data, protocal_frame.data.length + SYNC_SIZE - 2);
                memcpy(&crc0, &protocal_frame.raw_data[protocal_frame.data.length + SYNC_SIZE - 2], 2);
                if (crc0 == crc) {
                    switch (protocal_frame.data.data[0]) {
                    case CMD_UART_UPDATE_START:
                        log_info("CMD_UART_UPDATE_START\n");
                        os_taskq_post_msg(THIS_TASK_NAME, 1, MSG_UART_UPDATE_START_RSP);
                        break;
                    case CMD_UART_UPDATE_READ:
                        log_info("CMD_UART_UPDATE_READ\n");
                        if (uart_update_resume_hdl) {
                            uart_update_resume_hdl(NULL);
                        }
                        break;
                    case CMD_UART_UPDATE_END:
                        log_info("CMD_UART_UPDATE_END\n");
                        break;
                    case CMD_UART_UPDATE_UPDATE_LEN:
                        log_info("CMD_UART_UPDATE_LEN\n");
                        break;
                    case CMD_UART_JEEP_ALIVE:
                        log_info("CMD_UART_KEEP_ALIVE\n");
                        break;
                    case CMD_UART_UPDATE_READY:
                        log_info("CMD_UART_UPDATE_READY\n");
                        os_taskq_post_msg(THIS_TASK_NAME, 1, MSG_UART_UPDATE_READY);
                        break;
                    default:
                        log_info("unkown cmd...\n");
                        break;
                    }
                } else {
                    rx_cnt = 0;
                }
            }
        }
    }
}

static bool uart_send_packet(u8 *buf, u16 length)
{
    bool ret;
    u16 crc;
    u8 *buffer;

    buffer = (u8 *)&protocal_frame;
    protocal_frame.data.mark0 = SYNC_MARK0;
    protocal_frame.data.mark1 = SYNC_MARK1;
    protocal_frame.data.length = length;
    memcpy((char *)&buffer[4], buf, length);
    crc = CRC16(buffer, length + SYNC_SIZE - 2);
    memcpy(buffer + 4 + length, &crc, 2);
    uart_set_dir(0);//设为输出
    uart_update_write((u8 *)&protocal_frame, length + SYNC_SIZE);
    uart_set_dir(1);
    return ret;
}

u32 uart_dev_receive_data(void *buf, u32 relen, u32 addr)
{
    u8 i;
    struct file_info file_cmd;
    for (i = 0; i < RETRY_TIME; i++) {
        if (i > 0) {
            putchar('r');
        }
        file_cmd.cmd = CMD_UPDATE_READ;
        file_cmd.addr = addr;
        file_cmd.len = relen;
        uart_send_packet(&file_cmd, sizeof(file_cmd));
        if (uart_update_sleep_hdl) {
            if (uart_update_sleep_hdl(NULL) == OS_TIMEOUT) {
                continue;
            }
        }
        memcpy(&file_cmd, protocal_frame.data.data, sizeof(file_cmd));
        if ((file_cmd.cmd != CMD_UPDATE_READ) || (file_cmd.addr != addr) || (file_cmd.len != relen)) {
            continue;
        }
        memcpy(buf, &protocal_frame.data.data[sizeof(file_cmd)], protocal_frame.data.length - sizeof(file_cmd));
        return (protocal_frame.data.length - sizeof(file_cmd));
    }
    putchar('R');
    return relen;
}

bool uart_update_cmd(u8 cmd, u8 *buf, u32 len)
{
    u8 *pbuf, i;
    //for (i = 0; i < RETRY_TIME; i++)
    {
        pbuf = protocal_frame.data.data;
        pbuf[0] = cmd;
        if (buf) {
            memcpy(pbuf + 1, buf, len);
        }
        uart_send_packet(pbuf, len + 1);
    }
    return TRUE;
}

extern const update_op_api_t uart_ch_update_op;
void uart_update_recv(u8 cmd, u8 *buf, u32 len)
{
    u32 baudrate = 9600;
    switch (cmd) {
    case CMD_UPDATE_START:
        memcpy(&baudrate, buf, 4);
        if (update_baudrate != baudrate) {
            update_baudrate = baudrate;
            uart_update_set_baud(baudrate);
            uart_update_cmd(CMD_UPDATE_START, &update_baudrate, 4);
        } else {
            app_update_loader_downloader_init(              //设置完波特率后开始升级
                UART_UPDATA,
                uart_update_callback,
                NULL,
                &uart_ch_update_op);
        }
        break;

    case CMD_UPDATE_END:
        break;

    case CMD_SEND_UPDATE_LEN:
        break;

    default:
        break;
    }
}


bool uart_send_update_len(u32 update_len)
{
    u8 cmd[4];
    WRITE_LIT_U32(&cmd[0], update_len);
    return uart_update_cmd(CMD_SEND_UPDATE_LEN, cmd, 4);
}


u16 uart_f_open(void)
{
    return 1;
}

u16 uart_f_read(void *handle, void *buf, u32 relen)
{
    u32 len;
    len = uart_dev_receive_data(buf, relen, uart_file_offset);
    if (len == -1) {
        log_info("uart_f_read err\n");
        return -1;
    }
    uart_file_offset += len;
    return len;
}

int uart_f_seek(void *fp, u8 type, u32 offset)
{
    if (type == SEEK_SET) {
        uart_file_offset = offset;
    } else if (type == SEEK_CUR) {
        uart_file_offset += offset;
    }
    return 0;//FR_OK;
}

u16 uart_f_stop(u8 err)
{
    uart_update_cmd(CMD_UPDATE_END, &err, 1);
    update_baudrate = 9600;             //把波特率设置回9600
    return 0;
}



const update_op_api_t uart_ch_update_op = {
    .ch_init = uart_update_hdl_register,
    .f_open  = uart_f_open,
    .f_read  = uart_f_read,
    .f_seek  = uart_f_seek,
    .f_stop  = uart_f_stop,
};

static void update_loader_download_task(void *p)
{
    int ret;
    int msg[8];
    static u8 update_start = 0;
    const uart_bus_t *uart_bus;
    u32 uart_rxcnt = 0;

    while (1) {
        ret = os_task_pend("taskq", msg, ARRAY_SIZE(msg));
        if (ret != OS_TASKQ) {
            continue;
        }
        if (msg[0] != Q_MSG) {
            continue;
        }
        switch (msg[1]) {
        case MSG_UART_UPDATE_READY:
            uart_update_cmd(CMD_UPDATE_START, NULL, 0);
            break;

        case MSG_UART_UPDATE_START_RSP:         //收到START_RSP 进行波特率设置设置
            log_info("MSG_UART_UPDATE_START_RSP\n");
            uart_update_recv(protocal_frame.data.data[0], &protocal_frame.data.data[1], protocal_frame.data.length - 1);
            break;

        case MSG_UART_UPDATE_READ_RSP:
            log_info("MSG_UART_UPDATE_READ_RSP\n");
            break;

        default:
            log_info("unkown msg..............\n");
            break;
        }
    }
}

void uart_update_init(uart_update_cfg *cfg)
{
    memcpy(&update_cfg, cfg, sizeof(uart_update_cfg));
    task_create(update_loader_download_task, NULL, THIS_TASK_NAME);
    uart_hw_init(update_cfg, uart_data_decode);
    printf(">>>%s\n", __func__);
}


static void clock_critical_enter(void)
{
}

static void clock_critical_exit(void)
{
    uart_update_set_baud(update_baudrate);
}
CLOCK_CRITICAL_HANDLE_REG(uart_update, clock_critical_enter, clock_critical_exit)







#endif
