/**
 * @file menu.c
 * @author Chen Jihang (embedded@eseaoptics.com)
 * @brief 串口菜单
 * @note 须配合对应版本的menu_builder使用
 * @version 1.0
 * @date 2023-01-04
 * 
 * @copyright ESEA (c) 2020
 * 
 */
#include <string.h>
#include "menu.h"
#include "convert.h"
/**
 * @brief 将指定的数据转换为字符串
 * 
 * @param pnode 菜单节点
 * @param num 计数
 * @param buf 字符串缓冲区
 * @param size 缓冲区大小
 * @return uint32_t 使用的缓冲区大小
 */
static inline uint32_t menu_convert_data_to_str(const struct menu_tree_node *pnode,uint16_t num,char *buf,uint32_t size)
{
    uint32_t i=0;
    switch(pnode->data_type)
    {
    case MENU_DATA_TYPE_CHAR:
    case MENU_DATA_TYPE_RO_CHAR:
        if(((char*)pnode->data)[num]!='\0'){
            buf[i++]=((char*)pnode->data)[num];
        }
        break;
    case MENU_DATA_TYPE_UINT8:
    case MENU_DATA_TYPE_RO_UINT8:
        i+=convert_u32_to_s(((uint8_t*)pnode->data)[num],buf,size);
        break;
    case MENU_DATA_TYPE_INT8:
    case MENU_DATA_TYPE_RO_INT8:
        i+=convert_i32_to_s(((int8_t*)pnode->data)[num],buf,size);
        break;
    case MENU_DATA_TYPE_UINT16:
    case MENU_DATA_TYPE_RO_UINT16:
        i+=convert_u32_to_s(((uint16_t*)pnode->data)[num],buf,size);
        break;
    case MENU_DATA_TYPE_INT16:
    case MENU_DATA_TYPE_RO_INT16:
        i+=convert_i32_to_s(((int16_t*)pnode->data)[num],buf,size);
        break;
    case MENU_DATA_TYPE_UINT32:
    case MENU_DATA_TYPE_RO_UINT32:
        i+=convert_u32_to_s(((uint32_t*)pnode->data)[num],buf,size);
        break;
    case MENU_DATA_TYPE_INT32:
    case MENU_DATA_TYPE_RO_INT32:
        i+=convert_i32_to_s(((int32_t*)pnode->data)[num],buf,size);
        break;
    case MENU_DATA_TYPE_IPV4:
    case MENU_DATA_TYPE_RO_IPV4:
        i+=convert_ip2ips(((uint32_t*)pnode->data)[num],buf,size);
        break;
    default:
        return 0;
        break;
    }
    return i;
}
/**
 * @brief 将字符串转换为数据
 * 
 * @param pnode 菜单节点
 * @param num 计数
 * @param buf 字符串
 * @param size 字符串长度
 * @return uint32_t 转换的字符串长度
 */
static inline uint32_t menu_convert_str_to_data(const struct menu_tree_node *pnode,uint16_t num,char *buf,uint32_t size)
{
    uint32_t i=0;
    uint32_t tmp_u32;
    int32_t tmp_i32;
    if(pnode->data_type==MENU_DATA_TYPE_UINT8 || pnode->data_type==MENU_DATA_TYPE_UINT16 || pnode->data_type==MENU_DATA_TYPE_UINT32){
        i+=convert_s_to_u32(&tmp_u32,buf,size);
        if(tmp_u32<(uint32_t)pnode->min_value || tmp_u32>(uint32_t)pnode->max_value){
            return 0;
        }
    }
    else if(pnode->data_type==MENU_DATA_TYPE_INT8 || pnode->data_type==MENU_DATA_TYPE_INT16 || pnode->data_type==MENU_DATA_TYPE_INT32){
        i+=convert_s_to_i32(&tmp_i32,buf,size);
        if(tmp_i32<(int32_t)pnode->min_value || tmp_i32>(int32_t)pnode->max_value){
            return 0;
        }
    }
    switch(pnode->data_type)
    {
    case MENU_DATA_TYPE_CHAR:
        ((char*)pnode->data)[num]=buf[i++];
        break;
    case MENU_DATA_TYPE_UINT8:
        ((uint8_t*)pnode->data)[num]=tmp_u32;
        break;
    case MENU_DATA_TYPE_INT8:
        ((int8_t*)pnode->data)[num]=tmp_i32;
        break;
    case MENU_DATA_TYPE_UINT16:
        ((uint16_t*)pnode->data)[num]=tmp_u32;
        break;
    case MENU_DATA_TYPE_INT16:
        ((int16_t*)pnode->data)[num]=tmp_i32;
        break;
    case MENU_DATA_TYPE_UINT32:
        ((uint32_t*)pnode->data)[num]=tmp_u32;
        break;
    case MENU_DATA_TYPE_INT32:
        ((int32_t*)pnode->data)[num]=tmp_i32;
        break;
    case MENU_DATA_TYPE_IPV4:
        i+=convert_ips2ip((&((uint32_t*)pnode->data)[num]),buf,size);
        break;
    default:
        break;
    }
    return i;
}
/**
 * @brief 使用字符串中的数据设置菜单节点中的数据
 * 
 * @param pnode 菜单节点
 * @param buf 字符串
 * @param size 字符串长度
 * @return uint32_t 转换的字符串长度
 */
static inline uint32_t menu_set_data(const struct menu_tree_node *pnode,char *buf,uint32_t size)
{
    uint32_t i,j;
    uint16_t num_con;
    num_con=0;
    i=0;
    if(pnode->data==NULL){
        return 0;
    }
    do{
        if(buf[i]==' '){
            i++;
        }
        j=menu_convert_str_to_data(pnode,num_con,&buf[i],size-i);
        if(j==0){
            return 0;
        }
        i+=j;
        num_con++;
    }while(num_con<pnode->num);
    return i;
}
/**
 * @brief 从菜单节点中获取数据
 * 
 * @param pnode 菜单节点
 * @param buf 字符串缓冲区
 * @param size 缓冲区大小
 * @return uint32_t 使用的缓冲区大小
 */
static inline uint32_t menu_get_data(const struct menu_tree_node *pnode,char *buf,uint32_t size)
{
    uint32_t i,j;
    uint16_t num_con;
    num_con=0;
    if(pnode->data==NULL){
        return 0;
    }
    if(size<4){
        return 0;
    }
    i=0;
    do{
        j=menu_convert_data_to_str(pnode,num_con,&buf[i],size-i-4);
        if(j==0 && (pnode->data_type==MENU_DATA_TYPE_CHAR || pnode->data_type==MENU_DATA_TYPE_RO_CHAR)){
            break;
        }
        if(j==0 || i+j>=size-5){
            buf[i++]=' ';
            buf[i++]='.';
            buf[i++]='.';
            buf[i++]='.';
            break;
        }
        i+=j;
        if(pnode->data_type!=MENU_DATA_TYPE_CHAR && pnode->data_type!=MENU_DATA_TYPE_RO_CHAR){
            buf[i++]=' ';
        }
        num_con++;
    }while(num_con<pnode->num);
    return i;
}
/**
 * @brief 从菜单节点中获取信息
 * 
 * @param pnode 菜单节点
 * @param buf 缓冲区
 * @param width 允许使用的宽度
 * @param size 缓冲区大小
 * @return uint32_t 使用的缓冲区大小
 */
static inline uint32_t menu_get_info(const struct menu_tree_node *pnode,char *buf,uint32_t width,uint32_t size)
{
    uint32_t i,j;
    uint32_t p_lc=0;
    if(size<4 || width<4){
        return 0;
    }
    for(i=0,j=0;pnode->info_str[i]!='\0' && pnode->info_str[i]!='\r' && pnode->info_str[i]!='\n';i++){
        if(j>width-5 || i>=size-5){
            if((pnode->info_str[i]&0xc0)==0x80){
                i=p_lc;
                j--;
            }
            buf[i++]=' ';
            buf[i++]='.';
            buf[i++]='.';
            buf[i++]='.';
            j+=4;
            break;
        }
        if((pnode->info_str[i]&0x80)==0){       //普通字符
            p_lc=i;
            j++;
        }
        if((pnode->info_str[i]&0xc0)==0xc0){    //多字节字符
            p_lc=i;
            j+=MENU_CHINESE_CHARACTER_WIDTH;
        }
        buf[i]=pnode->info_str[i];
    }
    for(;j<=width && i<size;j++,i++){
        buf[i]=' ';
    }
    return i;
}
/**
 * @brief 构建菜单条目
 * 
 * @param menu struct menu 结构
 * @return uint32_t 使用的缓冲区大小
 */
static inline uint32_t menu_build_item(struct menu *menu)
{
    uint32_t i,j;
    uint32_t info_size;
    uint32_t data_size;
    info_size=(menu->terminal_width*(uint32_t)5)/8;
    data_size=menu->terminal_width-info_size;
    i=0;
    menu->output_buf[i++]='\r';
    menu->output_buf[i++]='\n';
    menu->output_buf[i++]='[';
    j=convert_u2s(menu->child_con,&menu->output_buf[i],info_size-i-3);
    if(j==0){
        return 0;
    }
    i+=j;
    menu->output_buf[i++]=']';
    menu->output_buf[i++]=' ';
    if(menu->child_con==0){
        if(menu->node==1){
            memcpy(&menu->output_buf[i],"退出",6);
            i+=6;
        }
        else{
            memcpy(&menu->output_buf[i],"返回上一级",15);
            i+=15;
        }
        return i;
    }
    j=menu_get_info(&menu->menu_tree[menu->child_node],&menu->output_buf[i],info_size+2-i,MENU_OUTPUT_BUF_SIZE-i);
    if(j==0){
        return 0;
    }
    i+=j;
    j=menu_get_data(&menu->menu_tree[menu->child_node],&menu->output_buf[i],data_size);
    i+=j;
    return i;
}
/**
 * @brief 初始化菜单
 * 
 * @param menu struct menu 结构
 * @param menu_tree 由程序生成的菜单树
 * @param send_class send函数的第一个参数
 * @param send send函数
 * @return struct menu* 成功:menu 失败:NULL
 */
struct menu *menu_init(struct menu *menu,const struct menu_tree_node *menu_tree,void *send_class,menu_send_function_type send)
{
    if(menu==NULL || menu_tree==NULL || send_class==NULL || send==NULL){
        return NULL;
    }
    menu->menu_tree=menu_tree;
    menu->send_class=send_class;
    menu->send=send;
    menu->check_passwd=NULL;
    menu->node=0;
    menu->child_node=0;
    menu->child_con=0;
    menu->input_con=0;
    menu->flag_ready=0;
    menu->flag_flush=0;
    menu->terminal_width=MENU_TERMINAL_WIDTH;
    return menu;
}
/**
 * @brief 设置终端的宽度
 * 
 * @param menu struct menu 结构
 * @param terminal_width 终端宽度
 * @return int 成功:0 失败:负值
 */
int menu_set_terminal_width(struct menu *menu,uint8_t terminal_width)
{
    if(menu==NULL){
        return -1;
    }
    menu->terminal_width=terminal_width;
    return 0;
}
/**
 * @brief 设置check_passwd钩子
 * 
 * @param menu struct menu 结构
 * @param check_passwd check_passwd函数指针
 * @return int 成功:0 失败:负值
 */
int menu_set_hook_passwd(struct menu *menu,menu_check_passwd_function_type check_passwd)
{
    if(menu==NULL || check_passwd==NULL){
        return -1;
    }
    menu->check_passwd=check_passwd;
    return 0;
}
/**
 * @brief 使用menu结构中的发送函数发送
 * 
 * @param menu struct menu 结构
 * @param buf 要发送的数据
 * @param size 要发送数据的大小
 * @return int 成功:0 失败:负值
 */
int menu_send(struct menu *menu,char *buf,uint32_t size)
{
    return menu->send(menu->send_class,buf,size);
}
/**
 * @brief 获取menu当前的状态
 * @note menu在收到回车或密码后会使能 未使能的菜单不会主动发送信息
 * @param menu struct menu 结构
 * @return int 0:未使能 1:使能
 */
int menu_get_state(struct menu *menu)
{
    return menu->node==0?0:1;
}
/**
 * @brief 菜单打印函数 需要放在循环中,在send函数可用时执行
 * 
 * @param menu struct menu 结构
 */
void menu_print_callback(struct menu *menu)
{
    uint32_t len;
    uint32_t i,j;
    uint32_t tmp;
    if(menu->node==0){
        if(menu->flag_ready!=1){
            menu->flag_flush=0;
            return;
        }
        if(menu->check_passwd==NULL || menu->check_passwd(menu,menu->input_buf,menu->input_con)==1){
            menu->send(menu->send_class,menu->menu_tree[menu->node].info_str,strlen(menu->menu_tree[menu->node].info_str));
            menu->node=1;
            menu->flag_flush=1;
            menu->flag_ready=2;
        }
        else{
            menu->flag_ready=2;
            return;
        }
    }
    if(menu->flag_flush==1){
        menu->flag_flush=0;
        menu->send(menu->send_class,menu->menu_tree[menu->node].info_str,strlen(menu->menu_tree[menu->node].info_str));
        if(menu->menu_tree[menu->node].child!=0){
            menu->output_buf[0]='\r';
            menu->output_buf[1]='\n';
            menu->output_buf[menu->terminal_width+2]='\r';
            menu->output_buf[menu->terminal_width+3]='\n';
            memset(&menu->output_buf[2],MENU_FILL_CHARACTER,menu->terminal_width);
            menu->send(menu->send_class,menu->output_buf,menu->terminal_width+4);
            menu->child_con=0;
            menu->child_node=menu->menu_tree[menu->node].child;
            return;
        }
        menu->send(menu->send_class,"\r\n当前值:\r\n",14);
        i=menu_get_data(&menu->menu_tree[menu->node],menu->output_buf,menu->terminal_width);
        if(i==0){
            return; // 错误
        }
        menu->output_buf[i++]='\r';
        menu->output_buf[i++]='\n';
        menu->send(menu->send_class,menu->output_buf,i);
        if((menu->menu_tree[menu->node].data_type&1)==1){
            menu->node=menu->menu_tree[menu->node].father;
            menu->flag_flush=1;
            return;
        }
        menu->send(menu->send_class,"请输入:\r\n",12);
        j=i;
        switch(menu->menu_tree[menu->node].data_type)
        {
        case MENU_DATA_TYPE_CHAR:
            break;
        case MENU_DATA_TYPE_UINT8:
        case MENU_DATA_TYPE_UINT16:
        case MENU_DATA_TYPE_UINT32:
            menu->output_buf[j++]='[';
            j+=convert_u2s(menu->menu_tree[menu->node].min_value,&menu->output_buf[j],MENU_OUTPUT_BUF_SIZE-j);
            menu->output_buf[j++]=',';
            j+=convert_u2s(menu->menu_tree[menu->node].max_value,&menu->output_buf[j],MENU_OUTPUT_BUF_SIZE-j);
            menu->output_buf[j++]=']';
            break;
        case MENU_DATA_TYPE_INT8:
        case MENU_DATA_TYPE_INT16:
        case MENU_DATA_TYPE_INT32:
            menu->output_buf[j++]='[';
            j+=convert_i2s(menu->menu_tree[menu->node].min_value,&menu->output_buf[j],MENU_OUTPUT_BUF_SIZE-j);
            menu->output_buf[j++]=',';
            j+=convert_i2s(menu->menu_tree[menu->node].max_value,&menu->output_buf[j],MENU_OUTPUT_BUF_SIZE-j);
            menu->output_buf[j++]=']';
            break;
        case MENU_DATA_TYPE_IPV4:
            break;
        default:
            break;
        }
        if(menu->menu_tree[menu->node].num!=0){
            menu->output_buf[j++]=' ';
            menu->output_buf[j++]='X';
            j+=convert_u2s(menu->menu_tree[menu->node].num,&menu->output_buf[j],MENU_OUTPUT_BUF_SIZE-j);
        }
        menu->output_buf[j++]='>';
        menu->send(menu->send_class,&menu->output_buf[i],j-i);
        return;
    }
    if(menu->child_node!=0){
        len=0;
        len+=menu_build_item(menu);
        if(len==0){
            return; // 出现错误
        }
        menu->send(menu->send_class,menu->output_buf,len);
        menu->child_con++;
        if(menu->child_con!=1){
            menu->child_node=menu->menu_tree[menu->child_node].next;
        }
        return;
    }
    if(menu->child_con!=0){
        menu->child_con=0;
        menu->output_buf[0]='\r';
        menu->output_buf[1]='\n';
        menu->output_buf[menu->terminal_width+2]='\n';
        memset(&menu->output_buf[2],MENU_FILL_CHARACTER,menu->terminal_width);
        menu->send(menu->send_class,menu->output_buf,menu->terminal_width+2);
        menu->send(menu->send_class,"\r\n>",3);
    }
    if(menu->flag_ready!=1){
        return;
    }
    menu->flag_ready=2;
    menu->send(menu->send_class,"\r\n",2);
    if(menu->menu_tree[menu->node].child!=0){
        len=convert_s_to_u32(&tmp,menu->input_buf,menu->input_con);
        if(len==0){
            menu->flag_flush=1;
            return;
        }
        if(tmp==0){
            menu->node=menu->menu_tree[menu->node].father;
            menu->flag_flush=1;
            return;
        }
        menu->child_node=menu->menu_tree[menu->node].child;
        for(menu->child_con=1;menu->child_con<tmp;menu->child_con++){
            menu->child_node=menu->menu_tree[menu->child_node].next;
            if(menu->child_node==0){
                menu->send(menu->send_class,"\r\n错误:没有这个选项!\r\n",30);
                menu->child_node=menu->node;
                break;
            }
        }
        menu->node=menu->child_node;
        menu->child_node=0;
        menu->child_con=0;
        menu->flag_flush=1;
    }
    else{
        j=menu_set_data(&menu->menu_tree[menu->node],menu->input_buf,menu->input_con);
        if(j==0){
            menu->send(menu->send_class,"\r\n不匹配的值!\r\n",20);
            menu->flag_flush=1;
        }
        else{
            menu->node=menu->menu_tree[menu->node].father;
            menu->flag_flush=1;
        }
    }
}
/**
 * @brief 菜单用户输入回调
 * 
 * @param menu struct menu 结构
 * @param buf 用户输入的数据
 * @param size 用户输入数据长度
 */
void menu_parse_callback(struct menu *menu,char *buf,uint32_t size)
{
    int i;
    if(menu->flag_ready==2){
        menu->flag_ready=0;
        menu->input_con=0;
    }
    if(menu->flag_ready!=0){
        return;
    }
#if MENU_ECHO==1
    if(menu_get_state(menu)==1){
        menu->send(menu->send_class,buf,size);
    }
#endif
    for(i=0;i<size;i++){
        if(menu->input_con==MENU_INPUT_BUF_SIZE-1 || buf[i]=='\n' || buf[i]=='\r'){
            menu->input_buf[menu->input_con]='\0';
            menu->flag_ready=1;
            return;
        }
        menu->input_buf[menu->input_con++]=buf[i];
    }
}



void menu_exit(struct menu *menu) {
    menu->node=0;
    menu->child_node=0;
    menu->child_con=0;
    menu->input_con=0;
    menu->flag_ready=0;
    menu->flag_flush=0;

}

// /**
//  * @file menu.c
//  * @author Chen Jihang (embedded@eseaoptics.com)
//  * @brief 串口菜单
//  * @note 须配合对应版本的menu_builder使用
//  * @version 1.0
//  * @date 2023-01-04
//  * 
//  * @copyright ESEA (c) 2020
//  * 
//  */
// #include <stdio.h>
// #include <string.h>
// #include "menu.h"
// #include "convert.h"
// #include "cmsis_os2.h"
// #include "FreeRTOSConfig.h"
// extern UART_HandleTypeDef huart1;
// extern osSemaphoreId_t elog_dma_lockHandle;
// /**
//  * @brief 将指定的数据转换为字符串
//  * 
//  * @param pnode 菜单节点
//  * @param num 计数
//  * @param buf 字符串缓冲区
//  * @param size 缓冲区大小
//  * @return uint32_t 使用的缓冲区大小
//  */
// static inline uint32_t menu_convert_data_to_str(const struct menu_tree_node *pnode,uint16_t num,char *buf,uint32_t size)
// {
//     uint32_t i=0;
//     switch(pnode->data_type)
//     {
//     case MENU_DATA_TYPE_CHAR:
//     case MENU_DATA_TYPE_RO_CHAR:
//         if(((char*)pnode->data)[num]!='\0'){
//             buf[i++]=((char*)pnode->data)[num];
//         }
//         break;
//     case MENU_DATA_TYPE_UINT8:
//     case MENU_DATA_TYPE_RO_UINT8:
//         i+=convert_u32_to_s(((uint8_t*)pnode->data)[num],buf,size);
//         break;
//     case MENU_DATA_TYPE_INT8:
//     case MENU_DATA_TYPE_RO_INT8:
//         i+=convert_i32_to_s(((int8_t*)pnode->data)[num],buf,size);
//         break;
//     case MENU_DATA_TYPE_UINT16:
//     case MENU_DATA_TYPE_RO_UINT16:
//         i+=convert_u32_to_s(((uint16_t*)pnode->data)[num],buf,size);
//         break;
//     case MENU_DATA_TYPE_INT16:
//     case MENU_DATA_TYPE_RO_INT16:
//         i+=convert_i32_to_s(((int16_t*)pnode->data)[num],buf,size);
//         break;
//     case MENU_DATA_TYPE_UINT32:
//     case MENU_DATA_TYPE_RO_UINT32:
//         i+=convert_u32_to_s(((uint32_t*)pnode->data)[num],buf,size);
//         break;
//     case MENU_DATA_TYPE_INT32:
//     case MENU_DATA_TYPE_RO_INT32:
//         i+=convert_i32_to_s(((int32_t*)pnode->data)[num],buf,size);
//         break;
//     case MENU_DATA_TYPE_IPV4:
//     case MENU_DATA_TYPE_RO_IPV4:
//         i+=convert_ip2ips(((uint32_t*)pnode->data)[num],buf,size);
//         break;
//     default:
//         return 0;
//         break;
//     }
//     return i;
// }
// /**
//  * @brief 将字符串转换为数据
//  * 
//  * @param pnode 菜单节点
//  * @param num 计数
//  * @param buf 字符串
//  * @param size 字符串长度
//  * @return uint32_t 转换的字符串长度
//  */
// static inline uint32_t menu_convert_str_to_data(const struct menu_tree_node *pnode,uint16_t num,char *buf,uint32_t size)
// {
//     uint32_t i=0;
//     uint32_t tmp_u32;
//     int32_t tmp_i32;
//     if(pnode->data_type==MENU_DATA_TYPE_UINT8 || pnode->data_type==MENU_DATA_TYPE_UINT16 || pnode->data_type==MENU_DATA_TYPE_UINT32){
//         i+=convert_s_to_u32(&tmp_u32,buf,size);
//         if(tmp_u32<(uint32_t)pnode->min_value || tmp_u32>(uint32_t)pnode->max_value){
//             return 0;
//         }
//     }
//     else if(pnode->data_type==MENU_DATA_TYPE_INT8 || pnode->data_type==MENU_DATA_TYPE_INT16 || pnode->data_type==MENU_DATA_TYPE_INT32){
//         i+=convert_s_to_i32(&tmp_i32,buf,size);
//         if(tmp_i32<(int32_t)pnode->min_value || tmp_i32>(int32_t)pnode->max_value){
//             return 0;
//         }
//     }
//     switch(pnode->data_type)
//     {
//     case MENU_DATA_TYPE_CHAR:
//         ((char*)pnode->data)[num]=buf[i++];
//         break;
//     case MENU_DATA_TYPE_UINT8:
//         ((uint8_t*)pnode->data)[num]=tmp_u32;
//         break;
//     case MENU_DATA_TYPE_INT8:
//         ((int8_t*)pnode->data)[num]=tmp_i32;
//         break;
//     case MENU_DATA_TYPE_UINT16:
//         ((uint16_t*)pnode->data)[num]=tmp_u32;
//         break;
//     case MENU_DATA_TYPE_INT16:
//         ((int16_t*)pnode->data)[num]=tmp_i32;
//         break;
//     case MENU_DATA_TYPE_UINT32:
//         ((uint32_t*)pnode->data)[num]=tmp_u32;
//         break;
//     case MENU_DATA_TYPE_INT32:
//         ((int32_t*)pnode->data)[num]=tmp_i32;
//         break;
//     case MENU_DATA_TYPE_IPV4:
//         i+=convert_ips2ip((&((uint32_t*)pnode->data)[num]),buf,size);
//         break;
//     default:
//         break;
//     }
//     return i;
// }
// /**
//  * @brief 使用字符串中的数据设置菜单节点中的数据
//  * 
//  * @param pnode 菜单节点
//  * @param buf 字符串
//  * @param size 字符串长度
//  * @return uint32_t 转换的字符串长度
//  */
// static inline uint32_t menu_set_data(const struct menu_tree_node *pnode,char *buf,uint32_t size)
// {
//     uint32_t i,j;
//     uint16_t num_con;
//     num_con=0;
//     i=0;
//     if(pnode->data==NULL){
//         return 0;
//     }
//     do{
//         if(buf[i]==' '){
//             i++;
//         }
//         j=menu_convert_str_to_data(pnode,num_con,&buf[i],size-i);
//         if(j==0){
//             return 0;
//         }
//         i+=j;
//         num_con++;
//     }while(num_con<pnode->num);
//     return i;
// }
// /**
//  * @brief 从菜单节点中获取数据
//  * 
//  * @param pnode 菜单节点
//  * @param buf 字符串缓冲区
//  * @param size 缓冲区大小
//  * @return uint32_t 使用的缓冲区大小
//  */
// static inline uint32_t menu_get_data(const struct menu_tree_node *pnode,char *buf,uint32_t size)
// {
//     uint32_t i,j;
//     uint16_t num_con;
//     num_con=0;
//     if(pnode->data==NULL){
//         return 0;
//     }
//     if(size<4){
//         return 0;
//     }
//     i=0;
//     do{
//         j=menu_convert_data_to_str(pnode,num_con,&buf[i],size-i-4);
//         if(j==0 && (pnode->data_type==MENU_DATA_TYPE_CHAR || pnode->data_type==MENU_DATA_TYPE_RO_CHAR)){
//             break;
//         }
//         if(j==0 || i+j>=size-5){
//             buf[i++]=' ';
//             buf[i++]='.';
//             buf[i++]='.';
//             buf[i++]='.';
//             break;
//         }
//         i+=j;
//         if(pnode->data_type!=MENU_DATA_TYPE_CHAR && pnode->data_type!=MENU_DATA_TYPE_RO_CHAR){
//             buf[i++]=' ';
//         }
//         num_con++;
//     }while(num_con<pnode->num);
//     return i;
// }
// /**
//  * @brief 从菜单节点中获取信息
//  * 
//  * @param pnode 菜单节点
//  * @param buf 缓冲区
//  * @param width 允许使用的宽度
//  * @param size 缓冲区大小
//  * @return uint32_t 使用的缓冲区大小
//  */
// static inline uint32_t menu_get_info(const struct menu_tree_node *pnode,char *buf,uint32_t width,uint32_t size)
// {
//     uint32_t i,j;
//     uint32_t p_lc=0;
//     if(size<4 || width<4){
//         return 0;
//     }
//     for(i=0,j=0;pnode->info_str[i]!='\0' && pnode->info_str[i]!='\r' && pnode->info_str[i]!='\n';i++){
//         if(j>width-5 || i>=size-5){
//             if((pnode->info_str[i]&0xc0)==0x80){
//                 i=p_lc;
//                 j--;
//             }
//             buf[i++]=' ';
//             buf[i++]='.';
//             buf[i++]='.';
//             buf[i++]='.';
//             j+=4;
//             break;
//         }
//         if((pnode->info_str[i]&0x80)==0){       //普通字符
//             p_lc=i;
//             j++;
//         }
//         if((pnode->info_str[i]&0xc0)==0xc0){    //多字节字符
//             p_lc=i;
//             j+=MENU_CHINESE_CHARACTER_WIDTH;
//         }
//         buf[i]=pnode->info_str[i];
//     }
//     for(;j<=width && i<size;j++,i++){
//         buf[i]=' ';
//     }
//     return i;
// }
// /**
//  * @brief 构建菜单条目
//  * 
//  * @param menu struct menu 结构
//  * @return uint32_t 使用的缓冲区大小
//  */
// static inline uint32_t menu_build_item(struct menu *menu)
// {
//     uint32_t i,j;
//     uint32_t info_size;
//     uint32_t data_size;
//     info_size=(menu->terminal_width*(uint32_t)5)/8;
//     data_size=menu->terminal_width-info_size;
//     i=0;
//     menu->output_buf[i++]='\r';
//     menu->output_buf[i++]='\n';
//     menu->output_buf[i++]='[';
//     j=convert_u2s(menu->child_con,&menu->output_buf[i],info_size-i-3);
//     if(j==0){
//         return 0;
//     }
//     i+=j;
//     menu->output_buf[i++]=']';
//     menu->output_buf[i++]=' ';
//     if(menu->child_con==0){
//         if(menu->node==1){
//             memcpy(&menu->output_buf[i],"退出",6);
//             i+=6;
//         }
//         else{
//             memcpy(&menu->output_buf[i],"返回上一级",15);
//             i+=15;
//         }
//         return i;
//     }
//     j=menu_get_info(&menu->menu_tree[menu->child_node],&menu->output_buf[i],info_size+2-i,MENU_OUTPUT_BUF_SIZE-i);
//     if(j==0){
//         return 0;
//     }
//     i+=j;
//     j=menu_get_data(&menu->menu_tree[menu->child_node],&menu->output_buf[i],data_size);
//     i+=j;
//     return i;
// }
// /**
//  * @brief 初始化菜单
//  * 
//  * @param menu struct menu 结构
//  * @param menu_tree 由程序生成的菜单树
//  * @param send_class send函数的第一个参数
//  * @param send send函数
//  * @return struct menu* 成功:menu 失败:NULL
//  */
// // struct menu *menu_init(struct menu *menu,const struct menu_tree_node *menu_tree,void *send_class,menu_send_function_type send)
// struct menu *menu_init(struct menu *menu,const struct menu_tree_node *menu_tree )
// {
//     // if(menu==NULL || menu_tree==NULL || send_class==NULL || send==NULL){
//     if(menu==NULL || menu_tree==NULL  ){
//         return NULL;
//     }
//     menu->menu_tree=menu_tree;
//     // menu->send_class=send_class;
//     // menu->send=send;
//     menu->check_passwd=NULL;
//     menu->node=0;
//     menu->child_node=0;
//     menu->child_con=0;
//     menu->input_con=0;
//     menu->flag_ready=0;
//     menu->flag_flush=0;
//     menu->terminal_width=MENU_TERMINAL_WIDTH;
//     return menu;
// }
// /**
//  * @brief 设置终端的宽度
//  * 
//  * @param menu struct menu 结构
//  * @param terminal_width 终端宽度
//  * @return int 成功:0 失败:负值
//  */
// int menu_set_terminal_width(struct menu *menu,uint8_t terminal_width)
// {
//     if(menu==NULL){
//         return -1;
//     }
//     menu->terminal_width=terminal_width;
//     return 0;
// }
// /**
//  * @brief 设置check_passwd钩子
//  * 
//  * @param menu struct menu 结构
//  * @param check_passwd check_passwd函数指针
//  * @return int 成功:0 失败:负值
//  */
// int menu_set_hook_passwd(struct menu *menu,menu_check_passwd_function_type check_passwd)
// {
//     if(menu==NULL || check_passwd==NULL){
//         return -1;
//     }
//     menu->check_passwd=check_passwd;
//     return 0;
// }
// /**
//  * @brief 使用menu结构中的发送函数发送
//  * 
//  * @param menu struct menu 结构
//  * @param buf 要发送的数据
//  * @param size 要发送数据的大小
//  * @return int 成功:0 失败:负值
//  */
// int menu_send(struct menu *menu,char *buf,uint32_t size)
// {
//     // return menu->send(menu->send_class,buf,size);
// 	if (osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever)) 
//         HAL_UART_Transmit_DMA(&huart1, buf, size );
// 		// printf( "%s", buf, size); 
// 		return 0;
// 	return -1;

//     // return printf( "%s", buf, size); 
// }
// /**
//  * @brief 获取menu当前的状态
//  * @note menu在收到回车或密码后会使能 未使能的菜单不会主动发送信息
//  * @param menu struct menu 结构
//  * @return int 0:未使能 1:使能
//  */
// int menu_get_state(struct menu *menu)
// {
//     return menu->node==0?0:1;
// }
// /**
//  * @brief 菜单打印函数 需要放在循环中,在send函数可用时执行
//  * 
//  * @param menu struct menu 结构
//  */
// void menu_print_callback(struct menu *menu)
// {
//     uint32_t len;
//     uint32_t i,j;
//     uint32_t tmp;
//     if(menu->node==0){  /*  节点0 */
//         if(menu->flag_ready!=1){
//             menu->flag_flush=0;
//             return;
//         }
//         if(menu->check_passwd==NULL || menu->check_passwd(menu,menu->input_buf,menu->input_con)==1){
//             // menu->send(menu->send_class,menu->menu_tree[menu->node].info_str,strlen(menu->menu_tree[menu->node].info_str));
// 			if (osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever)) 
// 				HAL_UART_Transmit_DMA(&huart1, (uint8_t *)(menu->menu_tree[menu->node].info_str),strlen(menu->menu_tree[menu->node].info_str) );
//             menu->node=1;
//             menu->flag_flush=1;
//             menu->flag_ready=2;
//         }
//         else{
//             menu->flag_ready=2;
//             return;
//         }
//     }
//     if(menu->flag_flush==1){  /* 输出当前节点info_str 及格式， 有字节的处理子节点，没有输出当前值等待输入*/
//         menu->flag_flush=0;
//         // menu->send(menu->send_class,menu->menu_tree[menu->node].info_str,strlen(menu->menu_tree[menu->node].info_str));
// 		if (osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever)) 
// 			HAL_UART_Transmit_DMA(&huart1, menu->menu_tree[menu->node].info_str, strlen(menu->menu_tree[menu->node].info_str) );
// 			// printf( "%s", menu->menu_tree[menu->node].info_str, strlen(menu->menu_tree[menu->node].info_str)); 
//         if(menu->menu_tree[menu->node].child!=0){
//             menu->output_buf[0]='\r';
//             menu->output_buf[1]='\n';
//             menu->output_buf[menu->terminal_width+2]='\r';
//             menu->output_buf[menu->terminal_width+3]='\n';
//             memset(&menu->output_buf[2],MENU_FILL_CHARACTER,menu->terminal_width);
//             // menu->send(menu->send_class,menu->output_buf,menu->terminal_width+4);
// 			if (osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever)) 
// 				HAL_UART_Transmit_DMA(&huart1, menu->output_buf,menu->terminal_width+4 );
// 			// printf( "%s", menu->output_buf, menu->terminal_width+4); 
//             menu->child_con=0;
//             menu->child_node=menu->menu_tree[menu->node].child;
//             return;
//         }
//         // menu->send(menu->send_class,"\r\n当前值:\r\n",14);
// 		if (osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever)) 
// 			HAL_UART_Transmit_DMA(&huart1, "\r\n当前值:\r\n",14 );
// 			// printf( "%s", "\r\n当前值:\r\n",14); 
//         i=menu_get_data(&menu->menu_tree[menu->node],menu->output_buf,menu->terminal_width);
//         if(i==0){
//             return; // 错误
//         }
//         menu->output_buf[i++]='\r';
//         menu->output_buf[i++]='\n';
//         // menu->send(menu->send_class,menu->output_buf,i);
// 		if (osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever)) 
// 			HAL_UART_Transmit_DMA(&huart1, menu->output_buf, i );
// 			// printf( "%s", menu->output_buf, i); 
//         if((menu->menu_tree[menu->node].data_type&1)==1){
//             menu->node=menu->menu_tree[menu->node].father;
//             menu->flag_flush=1;
//             return;
//         }
//         // menu->send(menu->send_class,"请输入:\r\n",12);
// 		if (osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever)) 
// 			HAL_UART_Transmit_DMA(&huart1, "请输入:\r\n",12);
// 			// printf( "%s", "请输入:\r\n",12); 
//         j=i;
//         switch(menu->menu_tree[menu->node].data_type)
//         {
//         case MENU_DATA_TYPE_CHAR:
//             break;
//         case MENU_DATA_TYPE_UINT8:
//         case MENU_DATA_TYPE_UINT16:
//         case MENU_DATA_TYPE_UINT32:
//             menu->output_buf[j++]='[';
//             j+=convert_u2s(menu->menu_tree[menu->node].min_value,&menu->output_buf[j],MENU_OUTPUT_BUF_SIZE-j);
//             menu->output_buf[j++]=',';
//             j+=convert_u2s(menu->menu_tree[menu->node].max_value,&menu->output_buf[j],MENU_OUTPUT_BUF_SIZE-j);
//             menu->output_buf[j++]=']';
//             break;
//         case MENU_DATA_TYPE_INT8:
//         case MENU_DATA_TYPE_INT16:
//         case MENU_DATA_TYPE_INT32:
//             menu->output_buf[j++]='[';
//             j+=convert_i2s(menu->menu_tree[menu->node].min_value,&menu->output_buf[j],MENU_OUTPUT_BUF_SIZE-j);
//             menu->output_buf[j++]=',';
//             j+=convert_i2s(menu->menu_tree[menu->node].max_value,&menu->output_buf[j],MENU_OUTPUT_BUF_SIZE-j);
//             menu->output_buf[j++]=']';
//             break;
//         case MENU_DATA_TYPE_IPV4:
//             break;
//         default:
//             break;
//         }
//         if(menu->menu_tree[menu->node].num!=0){
//             menu->output_buf[j++]=' ';
//             menu->output_buf[j++]='X';
//             j+=convert_u2s(menu->menu_tree[menu->node].num,&menu->output_buf[j],MENU_OUTPUT_BUF_SIZE-j);
//         }
//         menu->output_buf[j++]='>';
//         // menu->send(menu->send_class,&menu->output_buf[i],j-i);
// 		if (osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever)) 
// 			HAL_UART_Transmit_DMA(&huart1, &menu->output_buf[i],j-i);
// 			// printf( "%s", &menu->output_buf[i],j-i); 
//         return;
//     }
//     if(menu->child_node!=0){  /*处理子节点- 处理一次return 一次直到为0 */
//         len=0;
//         len+=menu_build_item(menu);
//         if(len==0){
//             return; // 出现错误
//         }
//         // menu->send(menu->send_class,menu->output_buf,len);
// 		if (osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever)) 
// 			HAL_UART_Transmit_DMA(&huart1,  menu->output_buf,len);
// 			// printf( "%s", menu->output_buf,len); 
//         menu->child_con++;
//         if(menu->child_con!=1){
//             menu->child_node=menu->menu_tree[menu->child_node].next;
//         }
//         return;
//     }
//     if(menu->child_con!=0){  /* 一次处理 输出 填充字符*/
//         menu->child_con=0;
//         menu->output_buf[0]='\r';
//         menu->output_buf[1]='\n';
//         menu->output_buf[menu->terminal_width+2]='\n';
//         memset(&menu->output_buf[2],MENU_FILL_CHARACTER,menu->terminal_width);
//         // menu->send(menu->send_class,menu->output_buf,menu->terminal_width+2);
// 		if (osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever)) 
// 			HAL_UART_Transmit_DMA(&huart1,  menu->output_buf,menu->terminal_width+2);
// 			// printf( "%s",menu->output_buf,menu->terminal_width+2); 
//         // menu->send(menu->send_class,"\r\n>",3);
// 		if (osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever)) 
// 			HAL_UART_Transmit_DMA(&huart1,  "\r\n>", 3);
// 			// printf( "%s", "\r\n>",3); 
//     }

//     /* 处理完以上标记，进入数据输入 */
//     if(menu->flag_ready!=1){
//         return;
//     }
//     menu->flag_ready=2;  
//     // menu->send(menu->send_class,"\r\n",2);
// 	if (osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever)) 
// 		HAL_UART_Transmit_DMA(&huart1,  "\r\n>",3);
// 		// printf( "%s", "\r\n>",2); 
//     if(menu->menu_tree[menu->node].child!=0){
//         len=convert_s_to_u32(&tmp,menu->input_buf,menu->input_con);
//         if(len==0){
//             menu->flag_flush=1;
//             return;
//         }
//         if(tmp==0){
//             menu->node=menu->menu_tree[menu->node].father;
//             menu->flag_flush=1;
//             return;
//         }
//         menu->child_node=menu->menu_tree[menu->node].child;
//         for(menu->child_con=1;menu->child_con<tmp;menu->child_con++){
//             menu->child_node=menu->menu_tree[menu->child_node].next;
//             if(menu->child_node==0){
//                 // menu->send(menu->send_class,"\r\n错误:没有这个选项!\r\n",30);
// 				if ( osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever) ) 
// 					HAL_UART_Transmit_DMA(&huart1,  "\r\n错误:没有这个选项!\r\n",30);
// 				// printf( "%s", "\r\n错误:没有这个选项!\r\n",30); 
//                 menu->child_node=menu->node;
//                 break;
//             }
//         }
//         menu->node=menu->child_node;
//         menu->child_node=0;
//         menu->child_con=0;
//         menu->flag_flush=1;
//     }
//     else{
//         j=menu_set_data(&menu->menu_tree[menu->node],menu->input_buf,menu->input_con);
//         if(j==0){
//             // menu->send(menu->send_class,"\r\n不匹配的值!\r\n",20);
// 			if ( osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever) ) 
// 				HAL_UART_Transmit_DMA( &huart1,  "\r\n不匹配的值!\r\n", 20 );
// 			// printf( "%s", "\r\n不匹配的值!\r\n",20); 
//             menu->flag_flush=1;
//         }
//         else{
//             menu->node=menu->menu_tree[menu->node].father;
//             menu->flag_flush=1;
//         }
//     }
// }
// /**
//  * @brief 菜单用户输入回调
//  * 
//  * @param menu struct menu 结构
//  * @param buf 用户输入的数据
//  * @param size 用户输入数据长度
//  */
// void menu_parse_callback(struct menu *menu,char *buf,uint32_t size)
// {
//     int i;
//     if(menu->flag_ready==2){
//         menu->flag_ready=0;
//         menu->input_con=0;
//     }
//     if(menu->flag_ready!=0){
//         return;
//     }
// #if MENU_ECHO==1
//     if(menu_get_state(menu)==1){
//         // menu->send(menu->send_class,buf,size);
// 		if (osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever)) 
// 			HAL_UART_Transmit_DMA(&huart1,   buf, size);
// 		// printf( "%s", buf, size); 

//     }
// #endif
//     for(i=0;i<size;i++){
//         if(menu->input_con==MENU_INPUT_BUF_SIZE-1 || buf[i]=='\n' || buf[i]=='\r'){
//             menu->input_buf[menu->input_con]='\0';
//             menu->flag_ready=1;
//             return;
//         }
//         menu->input_buf[menu->input_con++]=buf[i];
//     }
// }