/*
 * @Author: zhy
 * @Date: 2022-09-14 09:14:01
 * @LastEditors: qianziyang qianzy@bmser.com
 * @LastEditTime: 2023-12-26 15:48:00
 * @Description: 
 */
#include <stdio.h>
#include <string.h> 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include "dev.h"
#include "bmser_dev.h"
#include "cJSON.h"
#include "bmser_cjson.h"
#include "bmser_error_code.h"
#include "bmser_project_para.h"

#define MAX_EMG_CNT 16
//#define LOCAL_DEBUG

#define PIN_485_LIST_NAME    "485_pin_list"
#define PIN_IO_LIST_NAME     "io_pin_list"

static DEV_EMG_DOMAIN_ALL_DEV_INFO_S m_emg_dev[MAX_EMG_DEV_CNT] = {0};

static DEV_PIN_MAP_LIST_INFO_S m_pin_list = {0};

typedef struct
{
    bool init;
    uint16_t count;
    BMSER_EMS_MAP_INFO_NODE_S node[MAX_EMG_CNT];
} BMSER_EMS_MAP_INFO_S;

static BMSER_EMS_MAP_INFO_S g_ems_map = {0};

static char g_snvalue[512] = {0};
static int32_t g_snvalue_valid = 0;

/**
 * @description: 获取设备的sn
 * @param {char} *sn
 * @param {uint16_t} sn_size
 * @return {*} 0:success, others:fail.
 */
int bmser_dev_get_board_sn_ex(char *sn, uint16_t sn_size)
{
    FILE *fp = NULL;
    int ret = -1;
    char buf[512] = {0};

    if (sn == NULL || 0 == sn_size) {
        return -1;
    }
    
    if (g_snvalue_valid)
    {
        snprintf(sn, sn_size, "%s", g_snvalue);
        return 0;
    }

    fp = fopen(BOARD_INFO_PATH, "r");
    if (fp == NULL) {
        /* The file could not be opened */
        strcpy(g_snvalue, "21012C00FFFF");
        g_snvalue_valid = 1;
        goto out;
    }

    while (fgets(buf, sizeof(buf), fp) != NULL) {
        if (strstr(buf, "sn = ") != NULL) {
            sscanf(buf, "sn = %" STR(SN_MAX_LEN) "[a-zA-Z0-9]", sn);
            ret = 0;
            break;
        }
    }

    memmove(g_snvalue, sn, strlen(buf) < sn_size ? strlen(buf) : sn_size - 1);
    g_snvalue_valid = 1;
out:
    if (fp != NULL) {
        fclose(fp);
    }
    return ret;
}


/**
 * @description: 获取dev_sn,一个8位设备地址(十进制),代表意义为deviceID
 * @param {const struct mosquitto_message} *message
 * @return {int} dev_sn
 */
int bmser_dev_get_dev_sn(char* topic)
{
    if (topic == NULL || strlen(topic) == 0) {
        // 处理空指针或者非法字符串的情况
        return -1;
    }
    
    int ret = 0 , dev_sn = 0;
    ret = sscanf(topic, "%*[^/]/%*[^/]/%*[^/]/%d", &dev_sn);
    if (1 != ret)
    {
        return -1;//解析失败
    }
    return dev_sn;    
}

/**
 * @description: 获取设备sn号，设备sn号 = sn + 设备id
 * @param {char} *dev_sn
 * @param {int} len
 * @param {int} devid
 * @return {*}
 */
int bmser_dev_get_board_dev_sn(char *dev_sn, int len, int devid)
{
    if (NULL == dev_sn || len <= 0 || devid < 0) {
        return -1;
    }
    int ret = 0;
    ret = bmser_dev_get_board_sn(dev_sn);
    if (0 != ret) {
        return ret;
    }
    
    snprintf(dev_sn + strlen(dev_sn), len - strlen(dev_sn), "%02d", devid);
    return 0;
}

// 获取本机ip  eth_inf网卡名称 调用方法get_local_ip("apcli0", ip);
int bmser_dev_get_local_ip(const char *eth_inf, char *ip)
{
    if (NULL == eth_inf || NULL == ip) {
        return -1;
    }

#ifdef WIN32
    char* local_ip = "10.30.1.30";
    strcpy(ip, local_ip);
#else

    int sd;
    struct ifreq ifr;
    char emsg[128] = {0};
 
    sd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sd) {
        strerror_r(errno, emsg, sizeof(emsg));
        dy_syslog(LOG_ERR, "socket error: %s.", emsg);
        return -1;
    }
 
    strncpy(ifr.ifr_name, eth_inf, IFNAMSIZ);
    ifr.ifr_name[IFNAMSIZ - 1] = 0;
 
    // if error: No such device  
    if (ioctl(sd, SIOCGIFADDR, &ifr) < 0) {
        strerror_r(errno, emsg, sizeof(emsg));
        dy_syslog(LOG_ERR, "ioctl error: %s", emsg);
        close(sd);
        return -1;
    }
    
    dy_syslog(LOG_DEBUG, "interfac: %s, ip: %s.", eth_inf, inet_ntoa(((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr)); 
    strcpy(ip, inet_ntoa(((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr));
    close(sd);
#endif
    return 0;
}

int bmser_dev_get_network_ip(const char *eth_inf, char *netwrok_addr, int size)
{
    if (eth_inf == NULL || netwrok_addr == NULL) {
        return -1;
    }

#ifdef WIN32
    char* local_ip = "10.30.1.30";
    int sockfd = 0, len = 0, i = 0;
    char ip[16] = { 0 };
    char netmask[16] = { 0 };
    int sock_netmask;
    int ip_addr[4], mask_addr[4];
    //获取网络id
    sscanf(ip, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3]);
    sscanf(netmask, "%d.%d.%d.%d", &mask_addr[0], &mask_addr[1], &mask_addr[2], &mask_addr[3]);

    for (i = 0; i < sizeof(ip_addr) / sizeof(ip_addr[0]); i++) {
        len += snprintf(netwrok_addr + len, size - len, "%d.", ip_addr[i] & mask_addr[i]);
    }
#else

    struct ifreq ifr;
    int sockfd = 0, len = 0, i = 0;
    char ip[16] = {0};
    char netmask[16] = {0};

    int sock_netmask;   
    struct ifreq ifr_mask;  
    struct sockaddr_in *net_mask;  
    int ip_addr[4], mask_addr[4];

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    strcpy(ifr.ifr_name, eth_inf);

    if (ioctl(sockfd, SIOCGIFADDR, &ifr) == -1) {
        perror("ioctl error");
        close(sockfd);
        return -1;
    }
 
    strcpy(ip, inet_ntoa(((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr));
    dy_syslog(LOG_DEBUG, "get cur ip %s.", ip);
    close(sockfd);
          
    sock_netmask = socket(AF_INET, SOCK_STREAM, 0);  
    if (sock_netmask == -1) {  
        dy_syslog(LOG_ERR, "create socket failture...");  
        return -1;  
    }  
      
    memset(&ifr_mask, 0, sizeof(ifr_mask));     
    strncpy(ifr_mask.ifr_name, eth_inf, sizeof(ifr_mask.ifr_name )-1);     
  
    if ((ioctl( sock_netmask, SIOCGIFNETMASK, &ifr_mask)) < 0) {  
        dy_syslog(LOG_ERR, "mac ioctl error");
        close(sock_netmask); 
        return -1;  
    }  
      
    net_mask = (struct sockaddr_in * )&(ifr_mask.ifr_netmask);  
    strcpy(netmask, inet_ntoa(net_mask->sin_addr));             
    close(sock_netmask); 
    dy_syslog(LOG_DEBUG, "get cur dev mask %s.", netmask);

    //获取网络id
    sscanf(ip, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3]);
    sscanf(netmask, "%d.%d.%d.%d", &mask_addr[0], &mask_addr[1], &mask_addr[2], &mask_addr[3]);

    for (i = 0; i < sizeof(ip_addr)/sizeof(ip_addr[0]); i++) {
        len += snprintf(netwrok_addr + len, size - len, "%d.", ip_addr[i] & mask_addr[i]);
    }

    netwrok_addr[len - 1] = '\0';
    dy_syslog(LOG_DEBUG, "get network id %s.", netwrok_addr);
#endif
    return 0;
}

static int32_t get_dev_channel_id(const char *pin_name, uint16_t *channel_id, uint16_t *active_level, uint16_t *default_level, uint16_t *dir, char *drv_type)
{
    BMSER_CHECK_PARA_NULL_RETURN_VAL(pin_name, OPRT_PARA_NULL);
    BMSER_CHECK_PARA_NULL_RETURN_VAL(channel_id, OPRT_PARA_NULL);

    uint16_t i = 0;
    for (i = 0; i < m_pin_list.node_cnt; i++) {
        if (!strcmp(pin_name, m_pin_list.node[i].pin_name)) {
            *channel_id = m_pin_list.node[i].channel_id;
            if (active_level) {
                *active_level = m_pin_list.node[i].active_level;
            }
            if (default_level) {
                *default_level = m_pin_list.node[i].default_level;
            }

            if (dir) {
                *dir = m_pin_list.node[i].dir;
            }

            if (drv_type) {
                snprintf(drv_type, MAX_DEV_STR_LEN + 1, "%s", m_pin_list.node[i].drv_type);
            }
            return 0;
        }
    }
    return OPRT_NOT_FOUND;
}

static int32_t add_dev_pin_map(void *json_root)
{
    if (!json_root) {
        return OPRT_PARA_NULL;
    }

    JsonValue result;
    int32_t i = 0, idx = 0, ret = 0;
    int32_t pin_485_cnt = 0, pin_io_cnt = 0;
    char json_path[128] = {0}, list_name[32] = {0};

    pin_485_cnt = json_get_array_length_by_json(json_root, PIN_485_LIST_NAME);
    pin_io_cnt = json_get_array_length_by_json(json_root, PIN_IO_LIST_NAME);
    if (0 == pin_485_cnt && 0 == pin_io_cnt) {
        return OPRT_NOT_FOUND;
    }

    DEV_PIN_MAP_NODE_INFO_S *node = OS_Dynamic_Malloc((pin_485_cnt + pin_io_cnt) * sizeof(DEV_PIN_MAP_NODE_INFO_S));
    BMSER_CHECK_PARA_NULL_RETURN_VAL(node, OPRT_MALLOC_FAIL);
    memset(node, 0, (pin_485_cnt + pin_io_cnt) * sizeof(DEV_PIN_MAP_NODE_INFO_S));

    for (i = 0; i < pin_485_cnt + pin_io_cnt; i++) {
        
        memset(list_name, 0, sizeof(list_name));
        if (i < pin_485_cnt) {
            idx = i;
            snprintf(list_name, sizeof(list_name), "%s", PIN_485_LIST_NAME);
        } else {
            idx = i - pin_485_cnt;
            snprintf(list_name, sizeof(list_name), "%s", PIN_IO_LIST_NAME);
        }
        
        //type
        memset(json_path, 0, sizeof(json_path));
        snprintf(json_path, sizeof(json_path), "%s[%d].type",  list_name, idx);
        BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, json_path, &result));
        if (JSON_VALUE_STRING != result.type) {
            goto ERR_EXIT;
        }
        strncpy(node[i].type, result.stringVal, MAX_DEV_STR_LEN + 1);

        if (!strcmp(node[i].type, "DI")) {
            node[i].dir = 0;
        } else if (!strcmp(node[i].type, "DO") || !strcmp(node[i].type, "HSD")) {
            node[i].dir = 1;
        } else {}
        
        //pin
        memset(json_path, 0, sizeof(json_path));
        snprintf(json_path, sizeof(json_path), "%s[%d].pin", list_name, idx);
        BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, json_path, &result));
        if (JSON_VALUE_STRING != result.type) {
            goto ERR_EXIT;
        }
        strncpy(node[i].pin_name, result.stringVal, MAX_PIN_NAME_LEN + 1);

        //channel_id
        memset(json_path, 0, sizeof(json_path));
        snprintf(json_path, sizeof(json_path), "%s[%d].channel_id", list_name, idx);
        BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, json_path, &result));
        if (JSON_VALUE_NUMBER != result.type) {
            goto ERR_EXIT;
        }
        node[i].channel_id = result.doubleVal;

        //driver_type
        memset(json_path, 0, sizeof(json_path));
        snprintf(json_path, sizeof(json_path), "%s[%d].driver_type", list_name, idx);
		ret = json_value_get_by_json(json_root, json_path, &result);
		if (0 == ret && JSON_VALUE_STRING == result.type) {
       	    strncpy(node[i].drv_type, result.stringVal, MAX_DEV_STR_LEN);
        }

        if (i < pin_485_cnt) {
#ifdef LOCAL_DEBUG
        dy_syslog(LOG_DEBUG, "i = %d, type = %s, pin = %s, channel_id = %d.", i, node[i].type, node[i].pin_name, node[i].channel_id);
#endif
            continue;   
        }

        //active_level
        memset(json_path, 0, sizeof(json_path));
        snprintf(json_path, sizeof(json_path), "%s[%d].active_level", list_name, idx);
        BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, json_path, &result));
        if (JSON_VALUE_NUMBER != result.type) {
            goto ERR_EXIT;
        }
        node[i].active_level = result.doubleVal;

        //default_level
        memset(json_path, 0, sizeof(json_path));
        snprintf(json_path, sizeof(json_path), "%s[%d].default_level", list_name, idx);
        BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, json_path, &result));
        if (JSON_VALUE_NUMBER != result.type) {
            goto ERR_EXIT;
        }
        node[i].default_level = result.doubleVal;

#ifdef LOCAL_DEBUG
        dy_syslog(LOG_DEBUG, "i = %d, type = %s, pin = %s, channel_id = %d, active = %d, default = %d.", i, node[i].type, node[i].pin_name, node[i].channel_id,\
        node[i].active_level, node[i].default_level);
#endif
    }

    m_pin_list.node = node;
    m_pin_list.node_cnt = pin_485_cnt + pin_io_cnt;
    return 0;

ERR_EXIT:
    OS_Dynamic_Free(node);
    return OPRT_COMM_ERROR;
}

static int32_t parse_dev_pin_map_file(const char *file)
{
    BMSER_CHECK_PARA_NULL_RETURN_VAL(file, OPRT_PARA_NULL);
    void *json_root = get_jsonItem_by_fileContent(file);
    BMSER_CHECK_PARA_NULL_RETURN_VAL(json_root, OPRT_PARA_NULL);

    add_dev_pin_map(json_root);
    
    free_jsonFileContent(json_root);
    return 0;
}

static int32_t parse_hw_port_data(DEV_CONNECT_TYPE_E type, DEV_COMM_CONNECT_INFO_U *conn_info,  void *json_root, char *json_path)
{
    if (!conn_info || !json_root || !json_path) {
        return OPRT_PARA_NULL;
    }

    JsonValue result;
    int32_t ret = 0;
    uint16_t channel_id = 0;
    char drv_type[MAX_DEV_STR_LEN + 1] = {0};
    char all_dev_path[512] = {0};

    switch (type)
    {
        case DIR_SOC_ETHER_CONNECT:
        {
            //ip
            memset(all_dev_path, 0, sizeof(all_dev_path));
            snprintf(all_dev_path, sizeof(all_dev_path), "%s.ip", json_path);
            BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, all_dev_path, &result));
            if (JSON_VALUE_STRING != result.type) {
                goto ERR_EXIT;
            }
            strncpy(conn_info->soc_eth_conn.ip, result.stringVal, IP_STR_LEN);

            //port
            memset(all_dev_path, 0, sizeof(all_dev_path));
            snprintf(all_dev_path, sizeof(all_dev_path), "%s.port", json_path);
            BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, all_dev_path, &result));
            if (JSON_VALUE_NUMBER != result.type) {
                goto ERR_EXIT;
            }
            conn_info->soc_eth_conn.port = result.doubleVal;
        } break;

        case DIR_SOC_IO_CONNECT:
        case EXT_MCU_IO_CONNECT:
        {
            //pin
            memset(all_dev_path, 0, sizeof(all_dev_path));
            snprintf(all_dev_path, sizeof(all_dev_path), "%s.pin", json_path);
            BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, all_dev_path, &result));
            if (JSON_VALUE_STRING != result.type) {
                goto ERR_EXIT;
            }
            if (EXT_MCU_IO_CONNECT == type) {
                strncpy(conn_info->mcu_io_conn.pin_name, result.stringVal, MAX_PIN_NAME_LEN + 1);
            } else {
                strncpy(conn_info->soc_io_conn.pin_name, result.stringVal, MAX_PIN_NAME_LEN + 1); 
            }

            if (EXT_MCU_IO_CONNECT == type) {
                //udp port
                memset(all_dev_path, 0, sizeof(all_dev_path));
                snprintf(all_dev_path, sizeof(all_dev_path), "%s.udp_port", json_path);
                BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, all_dev_path, &result));
                if (JSON_VALUE_NUMBER != result.type) {
                    goto ERR_EXIT;
                }
                conn_info->mcu_io_conn.udp_port = result.doubleVal;

                //通道号
                BMSER_CALL_FUNC_GOTO_ERR_EXIT(get_dev_channel_id(conn_info->mcu_io_conn.pin_name, &conn_info->mcu_io_conn.channel_id,\
                 &conn_info->mcu_io_conn.active_level, &conn_info->mcu_io_conn.default_level, &conn_info->mcu_io_conn.dir, NULL));
            } else {
                //通道号
                BMSER_CALL_FUNC_GOTO_ERR_EXIT(get_dev_channel_id(conn_info->soc_io_conn.pin_name, &conn_info->soc_io_conn.channel_id,\
                &conn_info->soc_io_conn.active_level, &conn_info->soc_io_conn.default_level, &conn_info->soc_io_conn.dir, NULL));
            }

        } break;
        
        case DIR_SOC_485_CONNECT:
        case EXT_MCU_485_CONNECT:
        {
            //pin
            memset(all_dev_path, 0, sizeof(all_dev_path));
            snprintf(all_dev_path, sizeof(all_dev_path), "%s.pin", json_path);
            BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, all_dev_path, &result));
            if (JSON_VALUE_STRING != result.type) {
                goto ERR_EXIT;
            }
            if (EXT_MCU_485_CONNECT == type) {
                strncpy(conn_info->mcu_485_conn.pin_name, result.stringVal, MAX_PIN_NAME_LEN + 1);
            } else {
                strncpy(conn_info->soc_485_conn.pin_name, result.stringVal, MAX_PIN_NAME_LEN + 1);
            }

            //波特率
            memset(all_dev_path, 0, sizeof(all_dev_path));
            snprintf(all_dev_path, sizeof(all_dev_path), "%s.baud", json_path);
            BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, all_dev_path, &result));
            if (JSON_VALUE_NUMBER != result.type) {
                goto ERR_EXIT;
            }
            if (EXT_MCU_485_CONNECT == type) {
                conn_info->mcu_485_conn.baud = result.doubleVal;
            } else {
                conn_info->soc_485_conn.baud = result.doubleVal;
            }

            //校验位
            memset(all_dev_path, 0, sizeof(all_dev_path));
            snprintf(all_dev_path, sizeof(all_dev_path), "%s.parity", json_path);
            BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, all_dev_path, &result));
            if (JSON_VALUE_STRING != result.type) {
                goto ERR_EXIT;
            }
            if (EXT_MCU_485_CONNECT == type) {
                strncpy(conn_info->mcu_485_conn.parity, result.stringVal, MAX_PARITY_NAME_LEN + 1);    
            } else {
                strncpy(conn_info->soc_485_conn.parity, result.stringVal, MAX_PARITY_NAME_LEN + 1);
            }

            //数据位
            memset(all_dev_path, 0, sizeof(all_dev_path));
            snprintf(all_dev_path, sizeof(all_dev_path), "%s.data_bit", json_path);
            BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, all_dev_path, &result));
            if (JSON_VALUE_NUMBER != result.type) {
                goto ERR_EXIT;
            }
            if (EXT_MCU_485_CONNECT == type) {
                conn_info->mcu_485_conn.data_bit = result.doubleVal;
            } else {
                conn_info->soc_485_conn.data_bit = result.doubleVal;
            }

            //停止位
            memset(all_dev_path, 0, sizeof(all_dev_path));
            snprintf(all_dev_path, sizeof(all_dev_path), "%s.stop_bit", json_path);
            BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, all_dev_path, &result));
            if (JSON_VALUE_NUMBER != result.type) {
                goto ERR_EXIT;
            }
            if (EXT_MCU_485_CONNECT == type) {
                conn_info->mcu_485_conn.stop_bit = result.doubleVal;
            } else {
                conn_info->soc_485_conn.stop_bit = result.doubleVal;
            }

            if (EXT_MCU_485_CONNECT == type) {
                //udp port
                memset(all_dev_path, 0, sizeof(all_dev_path));
                snprintf(all_dev_path, sizeof(all_dev_path), "%s.udp_port", json_path);
                BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, all_dev_path, &result));
                if (JSON_VALUE_NUMBER != result.type) {
                    goto ERR_EXIT;
                }
                conn_info->mcu_485_conn.udp_port = result.doubleVal;
                //通道号
                BMSER_CALL_FUNC_GOTO_ERR_EXIT(get_dev_channel_id(conn_info->mcu_485_conn.pin_name, &conn_info->mcu_485_conn.channel_id, NULL, NULL, NULL, NULL));
            } else {
                //通道号
                BMSER_CALL_FUNC_GOTO_ERR_EXIT(get_dev_channel_id(conn_info->soc_485_conn.pin_name, &channel_id, NULL, NULL, NULL, drv_type));
                #ifndef WIN32 //默认是/dev/ttyS, 支持配置文件配置
                snprintf(conn_info->soc_485_conn.devices, MAX_PIN_NAME_LEN + 1, "%s%s%hu", DEV_HW_PORT_PREFIX, strlen(drv_type) > 0 ? drv_type : "S", channel_id);
                #else
                snprintf(conn_info->soc_485_conn.devices, MAX_PIN_NAME_LEN + 1, "%s%hu", DEV_HW_PORT_PREFIX, channel_id);
                #endif    
            }
        } break;
        default:
            return OPRT_DATA_INVALID;
    }
    return 0;

ERR_EXIT:
    return OPRT_COMM_ERROR;
}

static int32_t parse_ems_dev_domain(const char *file)
{
    BMSER_CHECK_PARA_NULL_RETURN_VAL(file, OPRT_PARA_NULL);
    void *json_root = get_jsonItem_by_fileContent(file);
    BMSER_CHECK_PARA_NULL_RETURN_VAL(json_root, OPRT_PARA_NULL);

    JsonValue result;
    bool is_ext = false;
    char dev_type[MAX_DEV_STR_LEN + 1] = {0};
    char properity[MAX_DEV_STR_LEN + 1] = {0};
    int32_t emg_cnt, dev_cnt = 0, all_dev_cnt = 0;
    int32_t i = 0, j = 0, k = 0, ret = 0;
    DEV_DOMAIN_ALL_DEV_INFO_S *dev = NULL;
    char json_path[128] = {0}, sub_json_path[256] = {0}, all_dev_path[256 + 32] = {0};
   
    //获取emg个数    
    emg_cnt = json_get_array_length_by_json(json_root, "devDomain");
    if (0 == emg_cnt) {
        goto ERR_EXIT;
    }

    for (i = 0; i < emg_cnt; i++) {
        //获取emg sn
        memset(json_path, 0, sizeof(json_path));
        snprintf(json_path, sizeof(json_path), "devDomain[%d].top.emgSn", i);
        BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, json_path, &result));
        if (JSON_VALUE_STRING != result.type) {
            goto ERR_EXIT;
        }
        strncpy(m_emg_dev[i].emg_sn, result.stringVal, SN_MAX_LEN);

        memset(json_path, 0, sizeof(json_path));
        snprintf(json_path, sizeof(json_path), "devDomain[%d].dev", i);
        //获取设备个数
        dev_cnt = json_get_array_length_by_json(json_root, json_path);
        if (0 == dev_cnt) {
            continue;
        }

        dev = OS_Dynamic_Malloc(dev_cnt * sizeof(DEV_DOMAIN_ALL_DEV_INFO_S));
        BMSER_CHECK_PARA_NULL_GOTO(dev, ERR_EXIT);
        memset(dev, 0, dev_cnt * sizeof(DEV_DOMAIN_ALL_DEV_INFO_S));
        
        for (j = 0; j < dev_cnt && j < MAX_DEV_CNT_LEN; j++) {
            
            DEV_DOMAIN_ALL_DEV_INFO_S *node = &dev[j];

            //获取设备属性
            snprintf(sub_json_path, sizeof(sub_json_path), "%s[%d].properity", json_path, j);
            BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, sub_json_path, &result));
            if (JSON_VALUE_STRING != result.type) {
                goto ERR_EXIT;
            }
            memset(properity, 0, MAX_DEV_STR_LEN + 1);
            strncpy(properity, result.stringVal, MAX_DEV_STR_LEN + 1);

            //获取设备类型,扩展设备还是直连设备
            snprintf(sub_json_path, sizeof(sub_json_path), "%s[%d].devType", json_path, j);
            BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, sub_json_path, &result));
            if (JSON_VALUE_STRING != result.type) {
                goto ERR_EXIT;
            }
            memset(dev_type, 0, MAX_DEV_STR_LEN + 1);
            strncpy(dev_type, result.stringVal, MAX_DEV_STR_LEN + 1);

            //获取每一个设备下所有设备的个数
            memset(sub_json_path, 0, sizeof(sub_json_path));
            snprintf(sub_json_path, sizeof(sub_json_path), "%s[%d].allDev", json_path, j);
            all_dev_cnt = json_get_array_length_by_json(json_root, sub_json_path);

            for (k = 0; k < all_dev_cnt; k++) {
                //将设备类型和属性拷贝到all_dev中
                strncpy(node->all_dev[k].dev_type, dev_type, MAX_DEV_STR_LEN + 1);
                strncpy(node->all_dev[k].properity, properity, MAX_DEV_STR_LEN + 1);

                //获取设备名称
                memset(all_dev_path, 0, sizeof(all_dev_path));
                snprintf(all_dev_path, sizeof(all_dev_path), "%s[%d].devName", sub_json_path, k);
                BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, all_dev_path, &result));
                if (JSON_VALUE_STRING != result.type) {
                    goto ERR_EXIT;
                }
                strncpy(node->all_dev[k].dev_name, result.stringVal, MAX_PIN_NAME_LEN + 1);

                //判断是否为扩展设备
                if (!strcmp(node->all_dev[k].dev_type, "ExtDevice")) {
                    is_ext = true;
                } else {
                    is_ext = false;
                }

                //获取设备的通信协议
                memset(all_dev_path, 0, sizeof(all_dev_path));
                snprintf(all_dev_path, sizeof(all_dev_path), "%s[%d].protocol", sub_json_path, k);
                BMSER_CALL_FUNC_GOTO_ERR_EXIT(json_value_get_by_json(json_root, all_dev_path, &result));
                if (JSON_VALUE_STRING != result.type) {
                    goto ERR_EXIT;
                }
                strncpy(node->all_dev[k].pro, result.stringVal, MAX_DEV_STR_LEN + 1);

                //设备连接类型
                if (!strcmp(node->all_dev[k].pro, "ModbusRTU") || !strcmp(node->all_dev[k].pro, "DLT645")) {
                    node->all_dev[k].type = (is_ext == true ? EXT_MCU_485_CONNECT : DIR_SOC_485_CONNECT);
                } else if (!strcmp(node->all_dev[k].pro, "ModbusTCP")) {
                    node->all_dev[k].type = DIR_SOC_ETHER_CONNECT;
                } else if (!strcmp(node->all_dev[k].pro, "IO")) {
                    node->all_dev[k].type = (is_ext == true ? EXT_MCU_IO_CONNECT : DIR_SOC_IO_CONNECT);
                } else {
                    continue;
                }

                //解析hwPort   
                memset(all_dev_path, 0, sizeof(all_dev_path));
                snprintf(all_dev_path, sizeof(all_dev_path), "%s[%d].hwPort", sub_json_path, k);
                BMSER_CALL_FUNC_GOTO_ERR_EXIT(parse_hw_port_data(node->all_dev[k].type, &node->all_dev[k].dev_conn_info, json_root, all_dev_path));
            }
            node->all_dev_cnt = all_dev_cnt;
        }
        //emg数据指向
        m_emg_dev[i].dev = dev;
        m_emg_dev[i].dev_cnt = dev_cnt;
    }

#ifdef LOCAL_DEBUG
    for (i = 0; i < MAX_EMG_DEV_CNT; i++) {
        for (j = 0; j < m_emg_dev[i].dev_cnt; j++) {
            DEV_DOMAIN_ALL_DEV_INFO_S *node = m_emg_dev[i].dev + j;
            for (k = 0; k < node->all_dev_cnt; k++) {
                dy_syslog(LOG_DEBUG, "i=%d, j=%d, k=%d, name=%s, devType=%s, pro=%s, type=%d.", i, j, k, node->all_dev[k].dev_name, node->all_dev[k].dev_type, node->all_dev[k].pro, node->all_dev[k].type);
            }
        }
    }
#endif

    free_jsonItem(json_root);
    return 0;

ERR_EXIT:
    dy_syslog(LOG_ERR, "parse file fail, i = %d, j = %d, k = %d.", i, j, k);
    if (dev) {
        OS_Dynamic_Free(dev);
    }
    free_jsonItem(json_root);
    return OPRT_COMM_ERROR;
}

static int32_t parse_ems_map_file(const char* file)
{
    BMSER_CHECK_PARA_NULL_RETURN_VAL(file, OPRT_PARA_NULL);

    char *p = NULL;
    FILE *fd = NULL;
    int len = 0, read_len = 0;
    uint16_t index = 0;
    BMSER_EMS_MAP_INFO_NODE_S ems_map[MAX_EMG_CNT] = {0};

    cJSON *root = NULL, *ems = NULL, *item = NULL, *tmp_key = NULL;

    fd = fopen(file, "r");
    BMSER_CHECK_PARA_NULL_RETURN_VAL(fd, OPRT_OPEN_FILE_FAIL);

    fseek(fd, 0, SEEK_END);
    len = ftell(fd);
    if (len <= 0) {
        goto ERR_EXIT;
    }
    
    fseek(fd, 0, SEEK_SET);

    p = (char *)OS_Dynamic_Malloc(len + 1);
    BMSER_CHECK_PARA_NULL_GOTO(p, ERR_EXIT);

    memset(p, 0, len + 1);
    read_len = fread(p, 1, len, fd);
    if (read_len != len) {
        goto ERR_EXIT;
    }
    fclose(fd);
    fd = NULL;

    root = cJSON_Parse((const char *)p);
    BMSER_CHECK_PARA_NULL_GOTO(root, ERR_EXIT);
    free(p);
    p = NULL;

    ems = cJSON_GetObjectItem(root, "emsDeploy");
    BMSER_CHECK_PARA_NULL_GOTO(ems, ERR_EXIT);

    item = ems->child;
    while (item != NULL) {
        tmp_key = cJSON_GetObjectItem(item, "devSn");
        if (!tmp_key || !cJSON_IsString(tmp_key) || !cJSON_GetStringValue(tmp_key)) {
            goto ERR_EXIT;
        }
        snprintf(ems_map[index].devSn, sizeof(ems_map[index].devSn), "%s", cJSON_GetStringValue(tmp_key));

        tmp_key = cJSON_GetObjectItem(item, "ip");
        if (!tmp_key || !cJSON_IsString(tmp_key) || !cJSON_GetStringValue(tmp_key)) {
            goto ERR_EXIT;
        }
        snprintf(ems_map[index].ip, sizeof(ems_map[index].ip), "%s", cJSON_GetStringValue(tmp_key));

        tmp_key = cJSON_GetObjectItem(item, "isHost");
        if (!tmp_key || !cJSON_IsNumber(tmp_key)) {
            goto ERR_EXIT;
        }
        ems_map[index].isHost = (int)cJSON_GetNumberValue(tmp_key);

        tmp_key = cJSON_GetObjectItem(item, "serialId");
        if (!tmp_key || !cJSON_IsNumber(tmp_key)) {
            goto ERR_EXIT;
        }
        ems_map[index].serialId = (int)cJSON_GetNumberValue(tmp_key);

        dy_syslog(LOG_DEBUG, "devSn = %s, ip = %s, ishost = %d, serialId = %u.", ems_map[index].devSn, \
        ems_map[index].ip, ems_map[index].isHost, ems_map[index].serialId);
        
        if (index >= MAX_EMG_CNT - 1) {
            break;
        } else {
            index++;
        }
        item = item->next;
    }

    g_ems_map.count = index;
    memcpy(g_ems_map.node, ems_map, sizeof(g_ems_map.node));

    cJSON_Delete(root);
    return OPRT_OK;

ERR_EXIT:
    if (root) {
        cJSON_Delete(root);
        root = NULL;
    }    
    if (p) {
        OS_Dynamic_Free(p);
        p = NULL;
    }
    if (fd) {
        fclose(fd);
        fd = NULL;
    }
    return OPRT_COMM_ERROR;
}

/**
 * @brief       获取配置的EMG数量
 * @param[in]
 * @return      int32_t
 * @retval      EMG数量
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023-10-26           zhy        创建初始版本          \n
*/
int32_t bmser_dev_get_ems_emg_conut()
{
    if (false == g_ems_map.init) {
        return OPRT_NOT_INIT;
    }

    return g_ems_map.count;
}


/**
 * @brief       获取EMG单个节点信息
 * @param[out]  BMSER_EMS_MAP_INFO_NODE_S* emsMap 
 * @param[in]   int32_t index EMG设备下标
 * @return      int32_t
 * @retval      0:正常  !0:错误
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023-10-26           zhy        创建初始版本          \n
*/
int32_t bmser_dev_get_ems_map_config(BMSER_EMS_MAP_INFO_NODE_S* emsMap, int32_t index)
{
    if (false == g_ems_map.init) {
        return OPRT_NOT_INIT;
    }

    if (!emsMap || index < 0 || g_ems_map.count <= index) {
        return OPRT_PARA_NULL;
    }

    memcpy(emsMap, &g_ems_map.node[index], sizeof(BMSER_EMS_MAP_INFO_NODE_S));

    return OPRT_OK;
}


/**
 * @brief       判断设备是否主柜
 * @param[in]   void
 * @return      bool
 * @retval      true:主柜  false:从柜
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023-11-02           JML        创建初始版本          \n
*/
bool bmser_dev_is_host_cabinet(void)
{
    char host_sn[64] = {0};
    char dev_sn[64] = {0};
    int i = 0;
    bool ret = false;
    
    for (i = 0; i < bmser_dev_get_ems_emg_conut(); i++) {
        if (g_ems_map.node[i].isHost) {
            memcpy(host_sn, g_ems_map.node[i].devSn, sizeof(g_ems_map.node[i].devSn));
            break;
        }
    }

    bmser_dev_get_board_sn_ex(dev_sn, sizeof(dev_sn));
    if (strncmp(dev_sn, host_sn, sizeof(dev_sn)) == 0) {
        ret = true;
    }
    return ret;
}

/**
 * @brief       获取主柜设备ip
 * @param[in]   char *ipAddr
 * @param[in]   uint16_t len
 * @return      int32_t
 * @retval      0:成功  other:失败
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023-11-09           ZHY        创建初始版本          \n
*/
int32_t bmser_dev_get_host_cabinet_ip(char *ipAddr, uint16_t len)
{
    if (NULL == ipAddr || len == 0) {
        return OPRT_PARA_NULL;
    }
    
    int32_t i = 0;
    
    for (i = 0; i < bmser_dev_get_ems_emg_conut(); i++) {
        if (g_ems_map.node[i].isHost) {
            snprintf(ipAddr, len, "%s", g_ems_map.node[i].ip);
            return OPRT_OK;
        }
    }

    return OPRT_NOT_FOUND;
}

/**
 * @brief       根据topic中devsn截取bankId以及rackId
 * @param[in]   char *topic
 * @param[out]  uint16_t *bankId
 * @param[out]  uint16_t *rackId
 * @return      int32_t
 * @retval      0:正常  !0:错误
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023-12-19           JHC        创建初始版本          \n
*/
int32_t bmser_dev_get_bankid_from_topic(char *topic, uint16_t *bankId, uint16_t *rackId)
{
    if (!topic || 0 == strlen(topic) || !bankId || !rackId) {
        return OPRT_PARA_NULL;
    }

    int32_t ret = 0, devSn = 0;
    uint16_t bank_id = 0, rack_id = 0;
    ret = sscanf(topic, "%*[^/]/%*[^/]/%*[^/]/%08d", &devSn);
    if (1 != ret) {
        return OPRT_DATA_INVALID;
    }

    rack_id = devSn % 1000;
    bank_id = (devSn / 1000 % 100);
    *bankId = bank_id;
    *rackId = rack_id;

    return OPRT_OK;
}

/**
 * @brief       根据bankid与rackid计算实际设备的设备ID
 * @param[in]    uint16_t bankId
 * @param[in]    uint16_t rackId
 * @param[out]   uint16_t *actualDevAddr
 * @return      int32_t
 * @retval      0:正常  !0:错误
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023-12-19           JHC        创建初始版本          \n
 * 2023-12-19           JHC        通过单堆下簇数接口计算实际物理设备ID   \n
 *  2024-01-31           QZY        rackID为0时，返回实际物理设备ID为0    \n
 *  2024-07-15           zhy        rackID为62动环设备时，返回实际物理设备ID为62    \n
*/
int32_t bmser_dev_calcActualDeviceAddress(uint16_t bankId, uint16_t rackId, uint16_t *actualDevAddr)
{
    if(actualDevAddr == NULL) { return -1; }
    if(rackId == 0) {
        *actualDevAddr = 0;
        return 0;
    } else if (62 == rackId) {
        *actualDevAddr = 62;
        return 0;
    } else if (63 == rackId) {
        *actualDevAddr = 63;
        return 0;
    } 
    uint16_t singleBankRacks = bmser_jsonGetSingleBankRackNum();
    *actualDevAddr = bankId * singleBankRacks + rackId;
    return 0;
}

/**
 * @brief        根据设备实际ID计算堆id和簇id
 * @param[in]   uint16_t devId
 * @param[out]  uint16_t *bankId
 * @param[out]  uint16_t *rackId
 * @return      int32_t
 * @retval      0:正常  !0:错误
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023-12-21           ZHY        创建初始版本          \n
 * 2023-12-26           QZY        添加对动环(第62簇)的特殊处理  \n
*/
int32_t bmser_dev_calcBankIdAndRackIdByDevId(uint16_t devId, uint16_t *bankId, uint16_t *rackId)
{
    BMSER_CHECK_PARA_NULL_RETURN_VAL(bankId, OPRT_PARA_NULL);
    BMSER_CHECK_PARA_NULL_RETURN_VAL(rackId, OPRT_PARA_NULL);

    int32_t singleBankRacks = bmser_jsonGetSingleBankRackNum();
    //devId为0表示为堆，bankId与rackId都应为0，rackId有效地址从1开始
    if (0 == devId) {
       *bankId = 0;
       *rackId = 0;
    } else if(62 == devId) {
        //devId为62表示为动环信息，rackId固定为62，bankId单柜时为0，多柜时为实际柜编号
        *bankId = 0;
        *rackId = devId;
    } else if(63 == devId) {
        //devId为63表示为广播
        *bankId = 0;
        *rackId = devId;
    } else {
        *bankId = (devId - 1) / singleBankRacks;
        *rackId = devId - (singleBankRacks*(*bankId));
    }

    return 0;
}

/**
 * @brief        dev参数初始化
 * @return      int32_t
 * @retval      0:正常  !0:错误
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2024-01-01           ZHY        创建初始版本          \n
*/
int32_t bmser_dev_para_init()
{
    if (g_ems_map.init) {
        return 0;
    }

    int32_t ret = 0;
    BMSER_CALL_FUNC_RETURN_VAL(parse_ems_map_file(DEV_MAP_CFG_FILE));
    parse_dev_pin_map_file(DEV_PIN_MAP_CFG_FILE);
    parse_ems_dev_domain(DEV_MAP_CFG_FILE);
    g_ems_map.init = true;

    return 0;
}

static int32_t bmser_dev_get_connect_info(DEV_CONNECT_TYPE_E start_type, DEV_CONNECT_TYPE_E end_type, DEV_COMM_CONNECT_INFO_NODE_S *info, uint16_t info_size, uint16_t *real_cnt)
{
    BMSER_CHECK_PARA_NULL_RETURN_VAL(info, OPRT_PARA_NULL);
    BMSER_CHECK_PARA_NULL_RETURN_VAL(real_cnt, OPRT_PARA_NULL);
    
    char sn[SN_MAX_LEN] = {0};
    uint16_t i = 0, j = 0, k = 0, idx = 0;
    bmser_dev_get_board_sn_ex(sn, SN_MAX_LEN);

    for (i = 0; i < MAX_EMG_DEV_CNT; i++) {
        if (bmser_dev_is_host_cabinet() && (0 == strlen(m_emg_dev[i].emg_sn) || strcmp(m_emg_dev[i].emg_sn, sn))) {
            continue;
        }
        for (j = 0; j < m_emg_dev[i].dev_cnt; j++) {
            DEV_DOMAIN_ALL_DEV_INFO_S *dev = &m_emg_dev[i].dev[j];
            if (dev) {
                for (k = 0; k < dev->all_dev_cnt; k++) {
                    if (dev->all_dev[k].type >= start_type && dev->all_dev[k].type <= end_type) {
                        memcpy(&info[idx], &dev->all_dev[k], sizeof(DEV_COMM_CONNECT_INFO_NODE_S));
                        idx++;
                        if (idx >= (info_size / sizeof(DEV_COMM_CONNECT_INFO_NODE_S))) {
                            *real_cnt = idx;
                            return 0;
                        }
                    }
                }
            }
        }
        *real_cnt = idx;
        return 0;
    }

    return OPRT_NOT_FOUND;
}

/**
 * @brief        获取所有直连设备连接信息
 * @param[in]    DEV_COMM_CONNECT_INFO_NODE_S *info
 * @param[in]    uint16_t info_size 传入的数据长度
 * @param[out]   uint16_t *real_cnt 实际返回的设备个数
 * @return       int32_t
 * @retval       0:正常  !0:错误
 * @par          修改日志:
 * Date                Author     Description           \n
 * 2024-04-09           ZHY        创建初始版本          \n
*/
int32_t bmser_dev_get_all_dir_connect_info(DEV_COMM_CONNECT_INFO_NODE_S *info, uint16_t info_size, uint16_t *real_cnt)
{
    return bmser_dev_get_connect_info(DIR_SOC_ETHER_CONNECT, DIR_SOC_485_CONNECT, info, info_size, real_cnt);
}

/**
 * @brief        获取所有扩展设备连接信息
 * @param[in]    DEV_COMM_CONNECT_INFO_NODE_S *info
 * @param[in]    uint16_t info_size 传入的数据长度
 * @param[out]   uint16_t *real_cnt 实际返回的设备个数
 * @return       int32_t
 * @retval       0:正常  !0:错误
 * @par          修改日志:
 * Date                Author     Description           \n
 * 2024-04-09           ZHY        创建初始版本          \n
*/
int32_t bmser_dev_get_all_ext_connect_info(DEV_COMM_CONNECT_INFO_NODE_S *info, uint16_t info_size, uint16_t *real_cnt)
{
    return bmser_dev_get_connect_info(EXT_MCU_IO_CONNECT, EXT_MCU_485_CONNECT, info, info_size, real_cnt);
}

/**
 * @brief        获取指定type的设备连接信息
 * @param[in]    DEV_CONNECT_TYPE_E type 指定的设备类型
 * @param[in]    DEV_COMM_CONNECT_INFO_NODE_S *info
 * @param[in]    uint16_t info_size 传入的数据长度
 * @param[out]   uint16_t *real_cnt 实际返回的设备个数
 * @return       int32_t
 * @retval       0:正常  !0:错误
 * @par          修改日志:
 * Date                Author     Description           \n
 * 2024-04-09           ZHY        创建初始版本          \n
*/
int32_t bmser_dev_get_connect_info_by_type(DEV_CONNECT_TYPE_E type, DEV_COMM_CONNECT_INFO_NODE_S *info, uint16_t info_size, uint16_t *real_cnt)
{
    return bmser_dev_get_connect_info(type, type, info, info_size, real_cnt); 
}

/**
 * @brief        获取所有设备连接信息
 * @param[in]    DEV_COMM_CONNECT_INFO_NODE_S *info
 * @param[in]    uint16_t info_size 传入的数据长度
 * @param[out]   uint16_t *real_cnt 实际返回的设备个数
 * @return       int32_t
 * @retval       0:正常  !0:错误
 * @par          修改日志:
 * Date                Author     Description           \n
 * 2024-04-09           ZHY        创建初始版本          \n
*/
int32_t bmser_dev_get_all_connect_info(DEV_COMM_CONNECT_INFO_NODE_S *info, uint16_t info_size, uint16_t *real_cnt)
{
    return bmser_dev_get_connect_info(DIR_SOC_ETHER_CONNECT, EXT_MCU_485_CONNECT, info, info_size, real_cnt); 
}