/***************************************************************************** * @copyright Copyright (c) 2025-2055 Gary. All rights reserved. * @file app_parse.c * @brief 解析所有配置文件的入口 * @author Gary * @date 2024-09-04 * @remark *****************************************************************************/ #include "app_parse.h" // 设备管理数组全局变量 proto_dev_point_map_t protoTable[kProto_Master_End] = {0}; // 北向配置协议数组全局变量 north_config_t NorthProtoTable[kProto_Slave_End] = {0}; // 高级设置数组全局变量 advanced_setting_t AdvancedSettingTable[kAdvanced_Setting_Type_End] = {0}; static void parse_protocol_type_TCP(cJSON *json_obj, dev_protocol_u *protocol_u); static void parse_protocol_type_RTU(cJSON *json_obj, dev_protocol_u *protocol_u); static dev_protocol_u parse_json(const char protoContent[MAX_CONFIG_CONTENT_LEN], protocol_type_master_e protocolType); static north_protocol_u parse_json_north(const char protoContent[MAX_CONFIG_CONTENT_LEN], protocol_type_slave_e protocolType); // 接入EMS的所有设备类型数量 uint16_t gStDevTypeNum[kDev_Type_End] = {0}; uint16_t gStDevTypePointNum[kDev_Type_End] = { kEms_DataEnd, kPccMeter_DataEnd, kBsMeter_DataEnd, kBsu_DataEnd, kBcu_DataEnd, kPcs_DataEnd, kAcLiquidMac_DataEnd, kTHSenor_DataEnd, kWater_DataEnd, kYg_DataEnd, kFireprotect_DataEnd, kDiDoSign_DataEnd, kUps_DataEnd, kRev2_DataEnd, kRev3_DataEnd, kRev4_DataEnd, kRev5_DataEnd }; /********************************************************************* * @brief 累加设备数量 * @param[in] typeNo: 协议类型 * @return devNum:设备数量 *********************************************************************/ void addDevType_Num(dev_type_e typeNo) { if (typeNo >= kDev_Type_End) { return; } gStDevTypeNum[typeNo]++; } /********************************************************************* * @brief 读取系统配置的设备数量 * @return 0-成功 1-失败 *********************************************************************/ int initDevInfo() { UT_array *devPointInfo = NULL; // 获取数据库ID、设备类型、设备编号、协议类型 if (0 != kit_get_dev_db_data(&devPointInfo)) { KITLOG(LOG_APP_EN, ERROR_EN, "kit_get_dev_db_data 执行失败!"); return 1; } // 遍历设备 utarray_foreach(devPointInfo, dev_info_t *, p_dev) { UT_array *points = NULL; char protoContent[MAX_CONFIG_CONTENT_LEN]; // 通过设备数据库Id获取到对应协议配置内容 if (0 != kit_get_protocol_db_data(kTemplate_Type_Device, p_dev->devDbId, protoContent)) { printf("load protoContent fail\n"); if (devPointInfo != NULL) { utarray_free(devPointInfo); // 释放已分配的内存 devPointInfo = NULL; } return 1; } // 解析协议配置内容 p_dev->devProtocol = parse_json(protoContent, p_dev->protocolType); // 通过设备使用的模板Id获取到对应设备的所有点位 if (0 != kit_get_point_db_data(p_dev->templateId, &points)) { printf("load protoContent fail"); if (devPointInfo != NULL) { utarray_free(devPointInfo); // 释放已分配的内存 devPointInfo = NULL; } return 1; } // 获取点位数量 p_dev->pointNum = utarray_len(points); if(p_dev->pointNum <= 0) { if (points != NULL) { utarray_free(points); // 释放已分配的内存 points = NULL; } continue; } p_dev->pointArr = calloc(p_dev->pointNum, sizeof(point_t)); if (p_dev->pointArr == NULL) { printf("Memory allocation for pointArr failed\n"); if (points != NULL) { utarray_free(points); // 释放已分配的内存 points = NULL; } if (devPointInfo != NULL) { utarray_free(devPointInfo); // 释放已分配的内存 devPointInfo = NULL; } return 1; } int i = 0; // 遍历点位 utarray_foreach(points, point_t *, tag) { if(i < p_dev->pointNum) { p_dev->pointArr[i] = *tag; // 使用结构体直接赋值 //strncpy((char *)p_dev->pointArr[i].pointName, (char *)tag->pointName, MAX_POINT_NAME_LEN); i++; } } if (points != NULL) { utarray_free(points); // 释放已分配的内存 points = NULL; } // 将设备信息存储到 protoTable 中 protocol_type_master_e protocolType = p_dev->protocolType; proto_dev_point_map_t *protoEntry = &protoTable[protocolType]; // 检查并动态扩展设备数组 if (protoEntry->devNum == 0) { protoEntry->devPointMapArr = (dev_info_t *)calloc(1, sizeof(dev_info_t)); if (protoEntry->devPointMapArr == NULL) { printf("Memory allocation failed for devPointMapArr\n"); if (devPointInfo != NULL) { utarray_free(devPointInfo); // 释放已分配的内存 devPointInfo = NULL; } return 1; } } else { // 动态扩展设备数组的大小以存储新设备 dev_info_t *newArr = (dev_info_t *)realloc(protoEntry->devPointMapArr, (protoEntry->devNum + 1) * sizeof(dev_info_t)); if (newArr == NULL) { printf("Memory allocation failed during realloc"); if (devPointInfo != NULL) { utarray_free(devPointInfo); // 释放已分配的内存 devPointInfo = NULL; } return 1; } protoEntry->devPointMapArr = newArr; } // 防止配置端并没有配置任何的测点也导致设备加1 if (p_dev->pointNum > 0) { addDevType_Num(p_dev->devType); // 将设备信息复制到协议设备数组 memcpy(&protoEntry->devPointMapArr[protoEntry->devNum], p_dev, sizeof(dev_info_t)); protoEntry->devNum++; } } if (devPointInfo != NULL) { utarray_free(devPointInfo); // 释放已分配的内存 devPointInfo = NULL; } return 0; } /********************************************************************* * @brief 读取系统配置的北向协议 * @return 0-成功 1-失败 *********************************************************************/ int initNorthInfo() { UT_array *northInfoArr = NULL; // 获取数据库ID、设备类型、设备编号、协议类型 if (0 != kit_get_north_config_arr(&northInfoArr)) { return 1; } // 遍历设备 utarray_foreach(northInfoArr, north_config_t *, p_northInfo) { char protoContent[MAX_CONFIG_CONTENT_LEN]; // 通过设备数据库Id获取到对应协议配置内容 if (0 != kit_get_protocol_db_data(kTemplate_Type_North, p_northInfo->dbId, protoContent)) { KITLOG(LOG_APP_EN, ERROR_EN, "获取北向协议连接配置失败!"); if (northInfoArr != NULL) { utarray_free(northInfoArr); // 释放已分配的内存 northInfoArr = NULL; } return 1; } // 解析协议配置内容 p_northInfo->northProtocol = parse_json_north(protoContent, p_northInfo->protocolType); // 将查到的北向配置数据复制给全局变量 north_config_t *protoEntry = &NorthProtoTable[p_northInfo->protocolType]; memcpy(protoEntry, p_northInfo, sizeof(north_config_t)); } return 0; } /********************************************************************* * @brief 读取高级设置的信息 * @return 0-成功 1-失败 *********************************************************************/ int initAdvancedSettingInfo() { UT_array *advancedSettings = NULL; //给个默认值 snprintf((char *)AdvancedSettingTable[kLinux_Password].value, MAX_VALUE_LEN, "%s", "forlinx"); // value值 // 获取高级设置项 if (0 != kit_get_advanced_setting(&advancedSettings)) { return 1; } // 遍历设备 utarray_foreach(advancedSettings, advanced_setting_t *, p_advancedSetting) { // EMS工作模式 if (strncmp((const char *)p_advancedSetting->key, "ems_mode", 8) == 0) { snprintf((char *)AdvancedSettingTable[kEms_Mode].key, MAX_KEY_LEN, "%s", p_advancedSetting->key); // key值 snprintf((char *)AdvancedSettingTable[kEms_Mode].value, MAX_VALUE_LEN, "%s", p_advancedSetting->value); // value值 } // Linux密码 else if (strncmp((const char *)p_advancedSetting->key, "linux_password", 14) == 0) { snprintf((char *)AdvancedSettingTable[kLinux_Password].key, MAX_KEY_LEN, "%s", p_advancedSetting->key); // key值 snprintf((char *)AdvancedSettingTable[kLinux_Password].value, MAX_VALUE_LEN, "%s", p_advancedSetting->value); // value值 } } return 0; } /********************************************************************* * @brief 解析协议类型 TCP 的 JSON 字符串,并将解析结果赋值给联合体 * @param[in] json_obj: JSON 对象 * @param[out] protocol_u: 联合体指针,存储解析结果 * @return none *********************************************************************/ static void parse_protocol_type_TCP(cJSON *json_obj, dev_protocol_u *protocol_u) { cJSON *host = cJSON_GetObjectItem(json_obj, "ip"); cJSON *port = cJSON_GetObjectItem(json_obj, "port"); cJSON *netId = cJSON_GetObjectItem(json_obj, "netId"); cJSON *timeout = cJSON_GetObjectItem(json_obj, "timeout"); cJSON *uId = cJSON_GetObjectItem(json_obj, "uId"); if (host && cJSON_IsString(host)) { // 赋值给联合体的 tcpClientLib 成员的 host 字段 strcpy(protocol_u->tcpClientLib.ip, host->valuestring); } if (port && cJSON_IsNumber(port)) { // 赋值给联合体的 tcpClientLib 成员的 port 字段 protocol_u->tcpClientLib.port = port->valueint; } if (netId && cJSON_IsNumber(netId)) { // 赋值给联合体的 tcpClientLib 成员的 port 字段 protocol_u->tcpClientLib.netId = netId->valueint; } if (timeout && cJSON_IsNumber(timeout)) { // 赋值给联合体的 tcpClientLib 成员的 timeout 字段 protocol_u->tcpClientLib.timeout = timeout->valueint; } if (uId && cJSON_IsNumber(uId)) { protocol_u->tcpClientLib.uId = uId->valueint; } } /********************************************************************* * @brief 解析协议类型 RTU 的 JSON 字符串,并将解析结果赋值给联合体 * @param[in] json_obj: JSON 对象 * @param[out] protocol_u: 联合体指针,存储解析结果 * @return none *********************************************************************/ static void parse_protocol_type_RTU(cJSON *json_obj, dev_protocol_u *protocol_u) { cJSON *address = cJSON_GetObjectItem(json_obj, "address"); cJSON *timeout = cJSON_GetObjectItem(json_obj, "timeout"); cJSON *stop = cJSON_GetObjectItem(json_obj, "stop"); cJSON *parity = cJSON_GetObjectItem(json_obj, "parity"); cJSON *baud = cJSON_GetObjectItem(json_obj, "baud"); cJSON *data = cJSON_GetObjectItem(json_obj, "data"); cJSON *uartId = cJSON_GetObjectItem(json_obj, "uartId"); cJSON *uId = cJSON_GetObjectItem(json_obj, "uId"); if (address && cJSON_IsString(address)) { // 赋值给联合体的 uartLib 成员的 address 字段 strncpy((char *)protocol_u->uartLib.address, address->valuestring, MAX_ADDR_LEN - 1); protocol_u->uartLib.address[MAX_ADDR_LEN - 1] = '\0'; // 确保以 null 结尾 } if (uId && cJSON_IsNumber(uId)) { // 赋值给联合体的 uartLib 成员的 timeout 字段 protocol_u->uartLib.uId = uId->valueint; } if (timeout && cJSON_IsNumber(timeout)) { // 赋值给联合体的 uartLib 成员的 timeout 字段 protocol_u->uartLib.timeout = timeout->valueint; } if (stop && cJSON_IsNumber(stop)) { // 赋值给联合体的 uartLib 成员的 stop 字段 protocol_u->uartLib.stop = stop->valueint; } if (parity && cJSON_IsNumber(parity)) { // 赋值给联合体的 uartLib 成员的 parity 字段 protocol_u->uartLib.parity = parity->valueint; } if (baud && cJSON_IsNumber(baud)) { // 赋值给联合体的 uartLib 成员的 baud 字段 protocol_u->uartLib.baud = baud->valueint; } if (data && cJSON_IsNumber(data)) { // 赋值给联合体的 uartLib 成员的 data 字段 protocol_u->uartLib.data = data->valueint; } if (uartId && cJSON_IsNumber(uartId)) { // 赋值给联合体的 uartLib 成员的 串口号 字段 protocol_u->uartLib.uartId = uartId->valueint; } } /********************************************************************* * @brief 解析 JSON 字符串 * @param[in] protoContent: JSON 字符串 * @param[in] protocolType: 协议类型 * @return none *********************************************************************/ static dev_protocol_u parse_json(const char protoContent[MAX_CONFIG_CONTENT_LEN], protocol_type_master_e protocolType) { // 解析 JSON 字符串 cJSON *json_obj = cJSON_Parse(protoContent); if (json_obj == NULL) { fprintf(stderr, "Error parsing JSON\n"); dev_protocol_u emptyProtocol = {0}; // 如果解析失败,返回一个空的联合体 return emptyProtocol; } dev_protocol_u tempProtocol_u = {0}; switch (protocolType) { case kProto_ModbusTCP_Master: parse_protocol_type_TCP(json_obj, &tempProtocol_u); break; case kProto_ModbusRTU_Master: parse_protocol_type_RTU(json_obj, &tempProtocol_u); break; default: fprintf(stderr, "Unsupported protocol type: %d\n", protocolType); break; } // 释放 JSON 解析对象 cJSON_Delete(json_obj); return tempProtocol_u; // 返回解析后的联合体 } /********************************************************************* * @brief 用指定内容替换源字符串中的指定位置 * @param[in] source: 源字符串 * @param[in] replacement: 需要写入源字符串的字符串 * @param[in] wordIndex: 被分隔符分割的子串索引,例如a/b/c/d,abcd的索引依次为1234 * @param[in] divide: 分隔符 * @return 修改后的字符串 *********************************************************************/ char *replaceSubStrByIndexAndTag(const char *source, const char *replacement, int wordIndex, char divide) { if (wordIndex <= 0) { // 如果wordIndex无效,返回source的副本 size_t source_len = strlen(source); char *result = (char *)malloc(source_len + 1); if (result) { strcpy(result, source); } return result; } const char *start_position = source, *end_position = NULL; int current_word = 0; // 定位要替换部分的起始和结束位置 for (const char *p = source; *p != '\0'; p++) { if (*p == divide) { current_word++; if (current_word == wordIndex - 1) { start_position = p + 1; } else if (current_word == wordIndex) { end_position = p; break; } } } // 如果在字符串中找不到足够多的分隔符 if (current_word < wordIndex) { end_position = source + strlen(source); } // 计算新字符串的长度 size_t new_length = (start_position - source) + strlen(replacement) + strlen(end_position); // 为新字符串分配内存 char *result = (char *)malloc(new_length + 1); if (!result) { return NULL; // 处理内存分配错误 } // 复制第一部分 strncpy(result, source, start_position - source); result[start_position - source] = '\0'; // null终止新字符串 // 连接替换字符串 strcat(result, replacement); // 连接第二部分 strcat(result, end_position); return result; } /********************************************************************* * @brief 读取设备序列号填入主题 * @param[in] src:源字符串 * @return 带EMS序列号的主题 *********************************************************************/ static char *getTopicWithEMSSN(char *const src) { char serial[128]; int rc = kit_get_ems_sn(serial); if (rc != 0) { return src; } char *topic = (char *)malloc(MAX_TOPIC_LEN); // 动态分配内存 if (!topic) { return NULL; // 内存分配失败处理 } topic[0] = '\0'; // 初始化第一个字符为 null,以防止拷贝操作中读到未初始化的数据 if (src) { char *modifiedString = replaceSubStrByIndexAndTag(src, serial, 3, '/'); if (modifiedString) { strncpy(topic, modifiedString, MAX_TOPIC_LEN - 1); topic[MAX_TOPIC_LEN - 1] = '\0'; // 确保字符串以 null 结尾 free(modifiedString); // 不要忘记释放动态内存 } } #ifdef MQTTPRINT printf("topic is %s\n", topic); printf("topic length is %ld\n", strlen(topic)); #endif return topic; // 返回 heap 分配的指针给调用者,这样它在退出后依然有效 } /********************************************************************* * @brief 解析协议类型 MQTT_Slave 的 JSON 字符串,并将解析结果赋值给联合体 * @param[in] json_obj: JSON 对象 * @param[out] protocol_u: 联合体指针,存储解析结果 * @return none *********************************************************************/ static void parse_protocol_type_MQTT_slave(cJSON *json_obj, north_protocol_u *protocol_u) { cJSON *clientId = cJSON_GetObjectItem(json_obj, "clientId"); cJSON *rootTopic = cJSON_GetObjectItem(json_obj, "rootTopic"); cJSON *periodTopic = cJSON_GetObjectItem(json_obj, "periodTopic"); cJSON *changeTopic = cJSON_GetObjectItem(json_obj, "changeTopic"); cJSON *historyTopic = cJSON_GetObjectItem(json_obj, "historyTopic"); cJSON *controlTopic = cJSON_GetObjectItem(json_obj, "controlTopic"); cJSON *readTopic = cJSON_GetObjectItem(json_obj, "readTopic"); cJSON *replyControlTopic = cJSON_GetObjectItem(json_obj, "replyControlTopic"); cJSON *replyReadTopic = cJSON_GetObjectItem(json_obj, "replyReadTopic"); cJSON *tSendTaskPeriod = cJSON_GetObjectItem(json_obj, "tSendTaskPeriod"); cJSON *ip = cJSON_GetObjectItem(json_obj, "ip"); cJSON *qos = cJSON_GetObjectItem(json_obj, "qos"); cJSON *port = cJSON_GetObjectItem(json_obj, "port"); cJSON *isSsl = cJSON_GetObjectItem(json_obj, "isSsl"); cJSON *username = cJSON_GetObjectItem(json_obj, "username"); cJSON *password = cJSON_GetObjectItem(json_obj, "password"); cJSON *caCert = cJSON_GetObjectItem(json_obj, "caCert"); cJSON *x509Cert = cJSON_GetObjectItem(json_obj, "x509Cert"); cJSON *keyCert = cJSON_GetObjectItem(json_obj, "keyCert"); if (clientId && cJSON_IsString(clientId)) { strcpy((char *)protocol_u->mqttLib.clientId, clientId->valuestring); } char *strwithsn = getTopicWithEMSSN(rootTopic->valuestring); strcpy((char *)protocol_u->mqttLib.rootTopic, strwithsn); strwithsn = getTopicWithEMSSN(periodTopic->valuestring); strcpy((char *)protocol_u->mqttLib.periodTopic, strwithsn); strwithsn = getTopicWithEMSSN(changeTopic->valuestring); strcpy((char *)protocol_u->mqttLib.changeTopic, strwithsn); strwithsn = getTopicWithEMSSN(historyTopic->valuestring); strcpy((char *)protocol_u->mqttLib.historyTopic, strwithsn); strwithsn = getTopicWithEMSSN(controlTopic->valuestring); strcpy((char *)protocol_u->mqttLib.controlTopic, strwithsn); strwithsn = getTopicWithEMSSN(readTopic->valuestring); strcpy((char *)protocol_u->mqttLib.readTopic, strwithsn); strwithsn = getTopicWithEMSSN(replyControlTopic->valuestring); strcpy((char *)protocol_u->mqttLib.replycontrolTopic, strwithsn); strwithsn = getTopicWithEMSSN(replyReadTopic->valuestring); strcpy((char *)protocol_u->mqttLib.replyreadTopic, strwithsn); #ifdef MQTTPRINT printf("%s\n", protocol_u->mqttLib.rootTopic); printf("%s\n", protocol_u->mqttLib.periodTopic); printf("%s\n", protocol_u->mqttLib.changeTopic); printf("%s\n", protocol_u->mqttLib.controlTopic); printf("%s\n", protocol_u->mqttLib.readTopic); printf("%s\n", protocol_u->mqttLib.replycontrolTopic); printf("%s\n", protocol_u->mqttLib.replyreadTopic); #endif // if (rootTopic && cJSON_IsString(rootTopic)) // { // strcpy((char *)protocol_u->mqttLib.rootTopic, rootTopic->valuestring); // } // if (periodTopic && cJSON_IsString(periodTopic)) // { // strcpy((char *)protocol_u->mqttLib.periodTopic, periodTopic->valuestring); // } // if (changeTopic && cJSON_IsString(changeTopic)) // { // strcpy((char *)protocol_u->mqttLib.changeTopic, changeTopic->valuestring); // } // if (historyTopic && cJSON_IsString(historyTopic)) // { // strcpy((char *)protocol_u->mqttLib.historyTopic, historyTopic->valuestring); // } // if (controlTopic && cJSON_IsString(controlTopic)) // { // strcpy((char *)protocol_u->mqttLib.controlTopic, controlTopic->valuestring); // } // if (readTopic && cJSON_IsString(readTopic)) // { // strcpy((char *)protocol_u->mqttLib.readTopic, readTopic->valuestring); // } // if (replyControlTopic && cJSON_IsString(replyControlTopic)) // { // strcpy((char *)protocol_u->mqttLib.replycontrolTopic, replyControlTopic->valuestring); // } // if (replyReadTopic && cJSON_IsString(replyReadTopic)) // { // strcpy((char*)protocol_u->mqttLib.replyreadTopic, replyReadTopic->valuestring); // } if (tSendTaskPeriod && cJSON_IsNumber(tSendTaskPeriod)) { protocol_u->mqttLib.tSendTaskPeriod = tSendTaskPeriod->valueint; } else { protocol_u->mqttLib.tSendTaskPeriod = 5; // 先给个默认值5s } if (ip && cJSON_IsString(ip)) { strcpy((char *)protocol_u->mqttLib.url, ip->valuestring); } if (qos && cJSON_IsNumber(qos)) { protocol_u->mqttLib.qos = qos->valueint; } if (port && cJSON_IsNumber(port)) { protocol_u->mqttLib.port = port->valueint; } if (isSsl && cJSON_IsNumber(isSsl)) { protocol_u->mqttLib.isSsl = isSsl->valueint; } if (username && cJSON_IsString(username)) { strcpy((char *)protocol_u->mqttLib.username, username->valuestring); } if (password && cJSON_IsString(password)) { strcpy((char *)protocol_u->mqttLib.password, password->valuestring); } if (caCert && cJSON_IsString(caCert)) { strcpy((char *)protocol_u->mqttLib.caCert, caCert->valuestring); } if (x509Cert && cJSON_IsString(x509Cert)) { strcpy((char *)protocol_u->mqttLib.x509Cert, x509Cert->valuestring); } if (keyCert && cJSON_IsString(keyCert)) { strcpy((char *)protocol_u->mqttLib.keyCert, keyCert->valuestring); } } /********************************************************************* * @brief 解析 JSON 字符串 * @param[in] protoContent: JSON 字符串 * @param[in] protocolType: 协议类型 * @return none *********************************************************************/ static north_protocol_u parse_json_north(const char protoContent[MAX_CONFIG_CONTENT_LEN], protocol_type_slave_e protocolType) { // 解析 JSON 字符串 cJSON *json = cJSON_Parse(protoContent); if (json == NULL) { fprintf(stderr, "Error parsing JSON\n"); north_protocol_u emptyProtocol = {0}; // 如果解析失败,返回一个空的联合体 return emptyProtocol; } north_protocol_u tempProtocol = {0}; switch (protocolType) { case kProto_MQTT_Slave: { parse_protocol_type_MQTT_slave(json, &tempProtocol); break; } // Add other cases for different protocol types default: fprintf(stderr, "Unsupported protocol type: %d\n", protocolType); break; } // 释放 JSON 解析对象 cJSON_Delete(json); return tempProtocol; // 返回解析后的联合体 } /********************************************************************* * @brief 根据设备类型和设备ID获取设备的点位数组 * @param[in] devType 设备类型 * @param[in] devId 设备ID * @return 返回匹配设备的点位数组,未找到返回 NULL *********************************************************************/ point_t *get_pointArr(dev_type_e devType, uint16_t devArrayId) { for (int i = 0; i < kProto_Master_End; i++) { if (protoTable[i].devPointMapArr == NULL) { continue; // 跳过空协议 } for (int j = 0; j < protoTable[i].devNum; j++) { if (protoTable[i].devPointMapArr[j].devType == devType && (protoTable[i].devPointMapArr[j].devId == devArrayId + 1)) { return protoTable[i].devPointMapArr[j].pointArr; // 返回匹配设备的 pointArr } } } return NULL; // 未找到匹配设备,返回 NULL } /********************************************************************* * @brief 根据设备类型和设备ID获取设备的点位数组 * @param[in] devType 设备类型 * @param[in] devId 设备ID * @return 返回匹配设备的点位数组,未找到返回 NULL *********************************************************************/ dev_info_t *get_devPointMapArr(dev_type_e devType, uint16_t devArrayId) { for (int i = 0; i < kProto_Master_End; i++) { if (protoTable[i].devPointMapArr == NULL) { continue; // 跳过空协议 } for (int j = 0; j < protoTable[i].devNum; j++) { if (protoTable[i].devPointMapArr[j].devType == devType && (protoTable[i].devPointMapArr[j].devId == devArrayId + 1)) { return &protoTable[i].devPointMapArr[j]; // 返回匹配设备的 pointArr } } } return NULL; // 未找到匹配设备,返回 NULL }