#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "./SYSTEM/usart/usart.h"
#include "./hmi/hmi_rx_parse.h"
#include "./BSP/USART2/usart2.h"
#include "./SYSTEM/delay/delay.h"
#include "./hmi/hmi_hex_parse.h"


#define  RX_TIMEOUT   100   /*  串口缓冲区100ms内没有数据，复位接收解析器  */
#define  RX_END_CHAR       ";\r\n"  /*  字符串指令结尾  */


/*  串口屏有返回的指令  */
static const char *ret_cmd_tab[] =
{
    "err:",
    "war:",
    "-prints:",
    "-get",
    "-rst;",
    "-ack;",
    "-version:",
    "-caddt:",
    "-get_code:",
};

struct hmi_rx_parse
{
    enum back_cmd only_parse; /*  发送带返回的指令后等待返回时，设置该值解析器仅判断是否为该指令  */
    cmd_res_t res; /*  保存返回结果  */

#define UART_PARSE_BUF_SIZE   (1024)
    uint8_t rx_buf[UART_PARSE_BUF_SIZE];
    uint32_t rx_cnt;

    uint32_t tick;
};

static struct hmi_rx_parse mgr;

static void _buf_rest(void);
static void _buf_save_res_buf(char *valid_buf);
static int _cmd_return_parse(const char *rx_buf);
static int _cmd_rx_parse_task(uint8_t byte);



/**
 * @brief    从串口接收缓缓冲区获取一个字节逐字节解析（解析字符串指令 + HEX十六进制指令）
 * @return   -3:无任何有效指令
 *           -2:串口接收缓存无数据
 *           -1:接收到十六进制指令，并解析成功
 *           >=0:接收到字符串指令，并解析成功
 *
 * @note     注意：此函数必须放在while循环内调用
 */
int hmi_rx_parse_task(void)
{
    int ret = -3;
    uint8_t c;
    int res;

    res = usart2_get_rx_data(&c, 1);

    if (res == 0) /*  串口缓冲区没数据  */
    {
        if (HAL_GetTick() - mgr.tick > RX_TIMEOUT)  /*  100ms内没接收到新数据说明断帧了，复位解析器  */
        {
            mgr.tick = HAL_GetTick();
            hmi_hex_parse_reest();
            _buf_rest();
        }

        return -2;
    }

    res = _cmd_rx_parse_task(c); /*  字符串指令解析  */
    if (res >= 0) ret = res;

    res = hmi_hex_parse_byte_to_byte(c); /*  hex十六进制指令解析  */
    if (res == 0) ret = -1;

    mgr.tick = HAL_GetTick();

    return ret;
}

/**
 * @brief    发送带返回的指令后等待返回时，设置code，解析器仅判断是否为该指令的返回
 *           用于提升判断效率
 */
void hmi_rx_parse_set_cmd_code(enum back_cmd code)
{
    mgr.only_parse = code;
}

/**
 * @brief    解析字符串成功，调用该指令获取结果
 */
cmd_res_t *hmi_rx_parse_get_res(void)
{
    return &mgr.res;
};

static const char *prints_cmd_tab[] =
{
    "cur_page=",
};

/**
 * @brief    串口屏发送prints指令解析回调
 */
__weak void hmi_str_cmd_parse(char *str_cmd)
{
    uint16_t tab_cnt = sizeof(prints_cmd_tab) / sizeof(prints_cmd_tab[0]);

    for (int i = 0; i < tab_cnt; i++)
    {
        const char *cmd = prints_cmd_tab[i];
        if (strstr(str_cmd,cmd ))
        {
            /*  用户补充自己的代码  */
        }
    }
}
/***************************************************************************/

/**
 * @brief    逐字节接收，并解析是否为字符串指令
 * @return   -1:无完整指令
 *           0~n:解析指令成功，n代表返回指令的编号（编号参考 enum back_cmd）
 */
int _cmd_rx_parse_task(uint8_t byte)
{
    int ret = -1;

    if (mgr.rx_cnt < UART_PARSE_BUF_SIZE - 1) /*  缓冲区最后一个留作固定位，为0  */
    {
        mgr.rx_buf[mgr.rx_cnt++] = byte;
    }
    else
    {
        _buf_rest(); /*  清除缓存  */
    }

    if (byte == 0)
    {
        _buf_rest(); /*  清除缓存  */
    }

    /*  字符串指令解析  */
    if (mgr.rx_cnt >= 3)
    {
        char *src = (char *)&mgr.rx_buf[mgr.rx_cnt - 1];
        if (*src == RX_END_CHAR[2] && *(--src) == RX_END_CHAR[1]) /*  判断到有帧尾:\r\n  */
        {
            mgr.rx_buf[mgr.rx_cnt] = '\0';
            ret = _cmd_return_parse((char *)mgr.rx_buf);
            _buf_rest(); /*  清除缓存  */
            return ret;
        }
    }

    return ret;
}

static void _buf_rest(void)
{
    mgr.rx_cnt = 0;
}

static void _buf_save_res_buf(char *valid_buf)
{
    char *pos = strchr((const char *)valid_buf, ':'); /*  查找出现冒号的位置  */
    if (pos == NULL) return;

    pos++; /*  偏移掉冒号  */
    uint16_t len = strlen(pos) - strlen(RX_END_CHAR); /*  冒号后有效字符串总数(去除帧尾)  */
    memmove(&mgr.rx_buf[0], pos, len);
    mgr.rx_buf[len] = '\0';
}

static int _cmd_return_parse(const char *rx_buf)
{
    int i;
    char *valid_buf;
    uint16_t tab_cnt = sizeof(ret_cmd_tab) / sizeof(ret_cmd_tab[0]);

    for (i = 0; i < tab_cnt; i++)
    {
        if (i == 0 || i == 1 || i == 2 || i == mgr.only_parse) /*  判断：执行出错-err、执行警告-war、prints、指定指令  */
        {
            const char *cmd = ret_cmd_tab[i];
            valid_buf = strstr(rx_buf, cmd);
            if (valid_buf)
            {
                break;
            }
        }
    }
    if (i >= tab_cnt) return -1;

    switch (i)
    {
    case RET_ERR:
        mgr.res.type = TYPE_INT;
        sscanf(valid_buf, "%*4s%d", &mgr.res.val.value); /*  串口屏发送原型-err:x (x定义参考下方 enum _ps_err_code) */
        // printf("%s", valid_buf);  /*  调试用  */
        break;

    case RET_WAR:
        mgr.res.type = TYPE_INT;
        sscanf(valid_buf, "%*4s%d", &mgr.res.val.value); /*  串口屏发送原型-war:x (x定义参考下方 enum _ps_war_code) */
        // printf("%s", valid_buf);  /*  调试用  */
        break;

    case RET_GET:
        if (valid_buf[4] == 'n') /*  串口屏发送原型-getn:%d;\r\n, 返回数值型  */
        {
            mgr.res.type = TYPE_INT;
            sscanf(valid_buf, "%*6s%d", &mgr.res.val.value);
        }
        else if (valid_buf[4] == 's') /*  串口屏发送原型-gets:%s;\r\n，返回字符串型  */
        {
            _buf_save_res_buf(valid_buf);
            mgr.res.type = TYPE_STR;
            mgr.res.val.str = (char *)mgr.rx_buf;
        }
        break;

    case RET_RST:
        break;

    case RET_ACK:
        break;

    case RET_VERSION:
    case RET_CADDT:
    case RET_GET_CODE:
        _buf_save_res_buf(valid_buf);
        mgr.res.type = TYPE_STR;
        mgr.res.val.str = (char *)mgr.rx_buf;
        break;

    case RET_PRINTS:
        _buf_save_res_buf(valid_buf);
        mgr.res.type = TYPE_STR;
        mgr.res.val.str = (char *)mgr.rx_buf;
        hmi_str_cmd_parse((char *)mgr.rx_buf); /*  串口屏发送原型-prints指令解析  */
        break;
    }

    mgr.res.code = (enum back_cmd)i;

    return i;
}


/*  -err:x表示执行脚本出错，x为以下列举的误码定义  */
enum _ps_err_code
{
    PS_EXIT_OK = 0,                         /*  脚本执行完毕  */

    /*  错误类（执行过程遇到报错直接退出当前脚本）  */
    PS_EXIT_UNK_ATTR,                       /*  未识别变量名称或指令  */
    PS_EXIT_ASSIGN_TYPE_ERR,                /*  赋值失败：变量只读、类型不一致  */

    PS_EXIT_PARAM_CNT_ERR,                  /*  指令参数个数错误  */
    PS_EXIT_PARAM_TYPE_ERR,                 /*  指令参数类型错误  */

    PS_EXIT_ALREADY_DEF,                    /*  变量名已定义 */
    PS_EXIT_STR_TO_LONG,                    /*  变量名过长  */

    PS_EXIT_SYNTAX_UNK_TOKEN,               /*  未识别符号  */
    PS_EXIT_SYNTAX_EXPECTED_TOKEN,          /*  缺少符号  */
    PS_EXIT_SYNTAX_NEED_EXP,                /*  括号内缺少表达式  */

    PS_EXIT_SYNTAX_EXP_TYPE,                /*  运算出错：变量类型错误  */
    PS_EXIT_SYNTAX_ERR,                     /*  运算出错：除数为零、常量数值大于2147483648  */
    PS_EXIT_SYNTAX_STR_EXP_PARAM_CNT,       /*  运算出错：字符串运算个数大于10个  */

    PS_EXIT_SYSTEM_ERR,                     /*  系统错误：内存申请出错  */

};


/*  -war:x表示执行脚本有警告，x为以下列举的误码定义  */
enum _ps_war_code
{
    /*  警告类（执行过程遇到警告，输出警告后继续执行）  */
    PS_EXIT_ASSIGN_WAR = 128,               /*  赋值超范围，已被限制为最大值或最小值  */
    PS_EXIT_API_PAGE_ID_INVAILD,            /*  page指令页面ID无效  */
    PS_EXIT_API_WID_ID_INVAILD,             /*  指令参数中控件ID无效  */
    PS_EXIT_API_PARAM_ERR,                  /*  指令参数超范围  */
    PS_EXIT_API_PLAY_FAIL,                  /*  play播放失败，请检查资源路径或ID  */
    PS_EXIT_API_COVX_FAIL,                  /*  covx失败，源变量和目标变量类型一致  */
    PS_EXIT_API_CLICK,                      /*  click指令不能自己激活自己  */
    PS_EXIT_REC,                            /*  click指令造成死循环，已退出  */
};


