#include "protocol.h" #include "stdint.h" #include "stdlib.h" #include "string.h" #include "node_message.h" #include "sys_mqtt.h" /*****************************protocol主要为主网关与子节点通讯的协议使用**********************************/ /*****************************其主要作用主网关给子节点轮询发送数据的编码**********************************/ /*****************************子节点解析该主网关发送的数据 **********************************/ /*****************************子节点回应对应的响应 **********************************/ /*****************************子节点回应对应的响应的解析 **********************************/ static volatile int deviceNum = 0; // 记录轮询读取设备的结束位置 static volatile int paramsNum = 0; // 记录轮询读取属性的结束位置 static volatile int startDeviceNum = 0; // 记录轮询读取设备的开始位置 static volatile int startParamsNum = 0; // 记录轮询读取设备属性的开始位置 void insertHexData(uint8_t *String, const uint8_t *hexData, uint8_t insertIndex, uint8_t length); enum { protocol_dlt645_97 = 0x08, protocol_modbus_read, protocol_dlt645_07 } PROTOCOL_LENGTH; // 每个协议的数据包长度用于最开始区分不同协议 // 枚举采集数据的存储个数 enum { typeInt = 1, typeFloat, typeDouble } DATAType; // 枚举MODBUS协议具体功能 enum { READ_COIL = 0x01, WRITE_COIL = 0x05, WRITE_COILS = 0x0F, READ_REGISTER = 0x03, WRITE_REFISTER = 0x06, WRITE_REGISTERS = 0x10 } MODBUS_COMMAND; // 大小端 typedef enum { MModBus_16bitOrder_AB = 1, // 大端 MModBus_16bitOrder_BA, } MModBus_16bitOrder_t; /* ********************************************************************************************************* * 函 数 名: void masterSendNodeString(uint8_t nodeIndex)Index下标从0开始 * 功能说明: 负责取出网关第nodeIndex下的数据组成下发格式的数据,注:此处没有对node是否为NULL进行判断,请确保有该节点的信息 * 形 参:nodeIndex第几个节点数据、string所总成的传递的字符串、size组成的字符串大小 * 返 回 值: 0:该节点下已经没有属性需要在去读出了,1:该节点下还拥有其他属性等待读出。 注:其一次性只能传输20条属性的值若超出其范围还有数据则要多次组成发送 逻辑:每次调用该函数都会总成一条string,属性足够的时候会组成一条具有20个属性的指令,并记录结束的设备链表位置,属性链表位置,下次再调用从结束位置再开始,到最后可能就组成不了20个属性的string了,此时将开始的设备num,属性都归位 且也要记录每次开始的设备位置和属性位置,方便接收应答信号的解析 ********************************************************************************************************* */ int masterSendNodeString(uint8_t nodeIndex, uint8_t *string, uint16_t *size) { startDeviceNum = deviceNum; // 起始位置等于上次结束的位置 startParamsNum = paramsNum; // 起始位置等于上次结束的位置 int nowDeviceNum = deviceNum; int nowparamsNum = paramsNum; GATEWAY_PARAMS *gateway; gateway = get_gateway_config_params(); // 找到当前的设备结束位置 DEVICE_PARAMS *currentDevice = gateway->device_params; while (nowDeviceNum) { currentDevice = currentDevice->nextDevice; nowDeviceNum--; } // 移动位置到结束位置属性的下一位 GATEWAY_READ_MODBUS_COMMAND *currentModbusParams = currentDevice->params->gateway_read_modbus_command; GATEWAY_READ_DLT645_COMMAND *currentDlt645Params = currentDevice->params->gateway_read_dlt645_command; switch (currentDevice->protocol) { case MODBUS: while (nowparamsNum) { currentModbusParams = currentModbusParams->nextParams; nowparamsNum--; } break; case DLT645_07: case DLT645_97: while (nowparamsNum) { currentDlt645Params = currentDlt645Params->nextParams; nowparamsNum--; } break; default: break; } // 最多进行20次循环组成下发数据 int i = 0; int len; len = strlen((char*)string); do { switch (currentDevice->protocol) { case MODBUS_READ: { uint8_t protocolHexData = protocol_modbus_read; insertHexData(string, &protocolHexData, len, 1); // 插入modbus长度 len++; insertHexData(string, ¤tModbusParams->functionCode, len, 1); // 插入读取功能码 len++; insertHexData(string, ¤tDevice->MDBdataType, len, 1); // 插入读取的数据格式 len++; insertHexData(string, ¤tModbusParams->slaveAddress, len, 1); // 插入modbus从站地址 len++; insertHexData(string, (uint8_t *)¤tModbusParams->registerAddress, len, 2); // 插入modbus寄存器地址 len += 2; insertHexData(string, ¤tModbusParams->decimalPoint, len, 1); // 插入小数点位数 len++; insertHexData(string, ¤tDevice->MDBbigLittleFormat, len, 1); // 插入大小端 len++; // 属性读取完毕,移位到下一个属性 i++; currentModbusParams = currentModbusParams->nextParams; if (currentModbusParams == NULL) { currentDevice = currentDevice->nextDevice; if (currentModbusParams == NULL) { deviceNum = 0; // 将结束位置全部归0 paramsNum = 0; *size = len; return 1; } currentModbusParams = currentDevice->params->gateway_read_modbus_command; nowDeviceNum++; nowparamsNum = 0; } break; } case DLT645_07: { uint8_t protocolHexData = protocol_dlt645_07; insertHexData(string, &protocolHexData, len, 1); // 插入dlt645_07数据长度 len++; insertHexData(string, (uint8_t *)¤tDlt645Params->deviceID645, len, 6); // 插入dlt645地址域 len += 6; insertHexData(string, (uint8_t *)¤tDlt645Params->Identification, len, 4); len += 4; // 属性读取完毕,移位到下一个属性 i++; currentDlt645Params = currentDlt645Params->nextParams; if (currentDlt645Params == NULL) { currentDevice = currentDevice->nextDevice; if (currentDevice == NULL) { deviceNum = 0; // 将结束位置全部归0 paramsNum = 0; *size = len; return 1; } currentDlt645Params = currentDevice->params->gateway_read_dlt645_command; nowDeviceNum++; nowparamsNum = 0; } break; } case DLT645_97: { uint8_t protocolHexData = protocol_dlt645_97; insertHexData(string, &protocolHexData, len, 1); // 插入dlt645_97数据长度 len++; insertHexData(string, (uint8_t *)¤tDlt645Params->deviceID645, len, 6); // 插入dlt645_97地址域 len += 6; insertHexData(string, (uint8_t *)¤tDlt645Params->Identification, len, 4); // 插入dlt645_97数据标识 len += 4; // 属性读取完毕,移位到下一个属性 i++; currentDlt645Params = currentDlt645Params->nextParams; if (currentDlt645Params == NULL) { currentDevice = currentDevice->nextDevice; currentDlt645Params = currentDevice->params->gateway_read_dlt645_command; if (currentDlt645Params == NULL) { deviceNum = 0; // 将结束位置全部归0 paramsNum = 0; *size = len; return 1; } currentDlt645Params = currentDevice->params->gateway_read_dlt645_command; // 还有属性则更新位置 nowDeviceNum++; nowparamsNum = 0; } break; } default: goto end_while; } nowparamsNum++; } while (i != 20); end_while: // 更新结束的位置分为两种情况,一种还在当前设备的属性中轮询此时nowDeviceNum没有改变过,另外一种情况设备内的属性 if (nowDeviceNum == 0) { deviceNum = startDeviceNum; paramsNum = startParamsNum + nowparamsNum; } else { deviceNum = startDeviceNum + nowDeviceNum; paramsNum = nowparamsNum - 1; } *size = len; return 0; } /* ********************************************************************************************************* * 函 数 名: void insertHexData(uint8_t *originalString,const uint8_t *hexData,int position) * 形 参:uint8_t *String需要插入的字符串,hexData插入的hex数据,insertIndex插入的下标位置,length插入的数据长度 * 返 回 值: 无 注:插入的数据以被插入的字符串都可能包含0x00不要使用strlen ********************************************************************************************************* */ void insertHexData(uint8_t *String, const uint8_t *hexData, uint8_t insertIndex, uint8_t length) { memcpy(String + insertIndex, hexData, length); } /* ********************************************************************************************************* * 函 数 名: uint8_t SlaveProtocolAnalysis(uint8_t *buff,uint16_t len) * 形 参:uint8_t *buff等待解析的字符串数据, * 返 回 值: 0:不是该节点的消息,数据没有进行任何处理。1:为该节点信息,接收到要进行的相应的切换工作 解析这段数据时要先判断是否为该节点的消息,stuct B *p=malloc(sizeof(struct B); ********************************************************************************************************* */ uint16_t LocalAddress=0x1F6E; uint8_t SlaveProtocolAnalysis(uint8_t *buff, uint16_t len) { NODE_DEVICE_PARAMS *node_receive_params; free_all_node_params(); node_receive_params = get_node_receive_params(); uint16_t slaveAdress = buff[0] << 8 | buff[1]; int protocol_location = 2; // 起始的协议所处位置 uint8_t i = 0; while (1) { if (slaveAdress == LocalAddress) // 判断此消息是否为该节点的消息,如果不是则跳出 { switch (buff[protocol_location]) // 读取接收到的数据属于什么协议 { case protocol_modbus_read: protocol_location++; node_receive_params->params[i].protcol = MODBUS_READ; node_receive_params->params[i].dlt645_params = NULL; node_receive_params->params[i].modbus_read = malloc(sizeof(NODE_MODBUS_READ)); node_receive_params->params[i].modbus_write = NULL; node_receive_params->params[i].modbus_read->functionCode = buff[protocol_location + 1]; // 读出functionCode node_receive_params->params[i].modbus_read->dataType = buff[protocol_location + 2]; // 读出数据格式 node_receive_params->params[i].modbus_read->slaveAddress = buff[protocol_location + 3]; // 读出从站地址 node_receive_params->params[i].modbus_read->registerAddress = buff[protocol_location + 5] << 8 || buff[protocol_location + 4]; // 读出寄存器地址 node_receive_params->params[i].modbus_read->registerLength = buff[protocol_location + 7] << 8 || buff[protocol_location + 6]; // 读出要读的寄存器长度 node_receive_params->params[i].modbus_read->precision = buff[protocol_location + 8]; // 读出小数点精度 node_receive_params->params[i].modbus_read->bigLittleFormat = buff[protocol_location + 9]; // 读出数据大小端格式 protocol_location += protocol_modbus_read; break; case protocol_dlt645_07: protocol_location++; node_receive_params->params[i].protcol = DLT645_07; node_receive_params->params[i].dlt645_params = malloc(sizeof(NODE_DLT645_PARAMS)); node_receive_params->params[i].modbus_read = NULL; node_receive_params->params[i].modbus_write = NULL; memcpy(node_receive_params->params[i].dlt645_params->deviceType645, buff + protocol_location, 6); memcpy((uint8_t *)&node_receive_params->params[i].dlt645_params->dataType645, buff + protocol_location + 6, 4); protocol_location += protocol_dlt645_07; break; case protocol_dlt645_97: protocol_location++; node_receive_params->params[i].protcol = DLT645_97; node_receive_params->params[i].dlt645_params = malloc(sizeof(NODE_DLT645_PARAMS)); node_receive_params->params[i].modbus_read = NULL; node_receive_params->params[i].modbus_write = NULL; memcpy(node_receive_params->params[i].dlt645_params->deviceType645, buff + protocol_location, 6); memcpy((uint8_t *)&node_receive_params->params[i].dlt645_params->dataType645, buff + protocol_location + 6, 2); protocol_location += protocol_dlt645_97; break; default: // 解析没满20个属性 return 1; } } else { node_receive_params->Index = i; // 记录本次有多少数据传输过来了 return 0; } i++; if (protocol_location > len) // 判断数据解析是否越界了,越界则跳转出 { return 1; } } } /* ********************************************************************************************************* * 函 数 名: nodeSendReadValue(uint8_t *string) * 形 参:组成node回传数据,传输数据为 * 返 回 值: 无 ********************************************************************************************************* */ void nodeSendReaddValue(uint8_t *string,uint16_t *size) { NODE_DEVICE_PARAMS *node_receive_params; node_receive_params = get_node_receive_params(); int i = 0; int len=0; //先加载node的地址node地址暂时本地写死后续加载 string[len]= LocalAddress>>8; string[len+1]=LocalAddress; len+=2; while (i != 20) { switch (node_receive_params->params[i].protcol) { case DLT645_07: case DLT645_97: if (node_receive_params->params[i].dlt645_params->rxLen <= 4) { string[len] = 0x04; len++; memcpy(&string[len], node_receive_params->params[i].dlt645_params->value, 4); len += 4; } else if (node_receive_params->params[i].dlt645_params->rxLen == 5) { string[len] = 0x05; len++; memcpy(&string[len], node_receive_params->params[i].dlt645_params->value, 5); len += 5; } else if (node_receive_params->params[i].dlt645_params->rxLen == 9) { string[len] = 0x09; len++; memcpy(&string[len], node_receive_params->params[i].dlt645_params->value, 9); len += 9; } else { string[len] = 0x00; len++; } break; case MODBUS: if (node_receive_params->params[i].modbus_read->rxLen == 4) { string[len] = 0x04; len++; memcpy(&string[len], node_receive_params->params[i].dlt645_params->value, 4); len += 4; } else { string[len] = 0x00; len++; } break; default: *size=len; return; } i++; } *size=len; } /* ********************************************************************************************************* * 函 数 名: GatewayProtocolAnalysis(uint8_t *string) * 形 参:将节点应答信息依次解析为json数据 * 返 回 值: 0未读到json数据,1读到了json数据 ********************************************************************************************************* */ int GatewayProtocolAnalysis(uint8_t *string, uint16_t len) { // 读取上次循环最终停止位置 int nowDeviceNum = startDeviceNum; int nowparamsNum = startParamsNum; GATEWAY_PARAMS *gateway; gateway = get_gateway_config_params(); // 找到该节点进行轮询 DEVICE_PARAMS *currentDevice = gateway->device_params; while (nowDeviceNum) { currentDevice = currentDevice->nextDevice; nowDeviceNum--; } // 移动位置到开始属性 GATEWAY_READ_MODBUS_COMMAND *currentModbusParams = currentDevice->params->gateway_read_modbus_command; GATEWAY_READ_DLT645_COMMAND *currentDlt645Params = currentDevice->params->gateway_read_dlt645_command; switch (currentDevice->protocol) { case MODBUS: while (nowparamsNum) { currentModbusParams = currentModbusParams->nextParams; nowparamsNum--; } break; case DLT645_07: case DLT645_97: while (nowparamsNum) { currentDlt645Params = currentDlt645Params->nextParams; nowparamsNum--; } break; default: break; } memset(pubJsonString,0,jsonMaxSize); sprintf(pubJsonString, "{\"data\":["); int index = 2; // 子节点地址 while (index protocol) { case MODBUS: // modbus协议 switch (*(string + index)) { case 0x00: // 没有数据 index++; break; case 0x04: if (currentDevice->MDBdataType == 0x01 && currentModbusParams->decimalPoint == 0x00) // modbus底层存储的数据类型 1INT 2float { uint32_t data; data = string[index + 1] + (string[index + 2] >> 8) + (string[index + 3] >> 16) + (string[index + 4] >> 24); sprintf(pubJsonString + strlen(pubJsonString), "{\"deviceId\":\"%s\",\"%s\":%d},", currentDevice->deviceID, currentModbusParams->keyword, data); } else // 如果是int且有小数点,或者底层就是float按照float来计算 { float value; memcpy(&value,string+index+1,4); sprintf(pubJsonString + strlen(pubJsonString), "{\"deviceId\":\"%s\",\"%s\":%.2f},", currentDevice->deviceID,currentModbusParams->keyword,value); } index += 4; break; default: break; } currentModbusParams = currentModbusParams->nextParams; if (currentModbusParams == NULL) { currentDevice = currentDevice->nextDevice; if(currentDevice->protocol==MODBUS) { currentModbusParams=currentModbusParams->nextParams; } else { currentDlt645Params=currentDlt645Params->nextParams; } } break; case DLT645_07: case DLT645_97: switch (*(string + index)) { case 0x00: index++; break; case 0x04: { index++; float value; memcpy(&value,string+index,sizeof(float)); sprintf(pubJsonString + strlen(pubJsonString), "{\"deviceId\":\"%s\",\"%s\": %.2f},", currentDevice->deviceID, currentDlt645Params->keyword,value); index += 4; } break; case 0x05: { index++; //%02依次为年月日时分 sprintf(pubJsonString + strlen(pubJsonString), "{\"deviceId\":\"%s\",\"%s\": \"%02X%02X%02X%02X%02X\"},", currentDevice->deviceID, currentDlt645Params->keyword, string[index + 4], string[index + 3], string[index + 2], string[index + 1], string[index]); index += 5; } break; case 9: { index++; float value; memcpy(&value, &string[index], 4); sprintf(pubJsonString + strlen(pubJsonString), "{\"deviceId\":\"%s\",\"%s\":\"%02X%02X%02X%02X%02X%.2f\"},", currentDevice->deviceID, currentDlt645Params->keyword, string[index + 8], string[index + 7], string[index + 6], string[index + 5], string[index + 4], value); index+=9; } break; default: break; } //移动到下个属性 switch (currentDevice->protocol) { case DLT645_97: case DLT645_07: currentDlt645Params = currentDlt645Params->nextParams; if (currentDlt645Params == NULL) { currentDevice = currentDevice->nextDevice; currentDlt645Params=currentDevice->params->gateway_read_dlt645_command; } break; case MODBUS: currentModbusParams=currentModbusParams->nextParams; if(currentModbusParams==NULL) { currentDevice=currentDevice->nextDevice; currentDlt645Params=currentDevice->params->gateway_read_dlt645_command; } break; } break; default: break; } } if(strlen(pubJsonString)<10) { return 0; } sprintf(pubJsonString+strlen(pubJsonString)-1,"]}"); //组装完成json数据开始向mqtt邮箱发送完成标识 int msg = MBOX_USER_PUBLISHQOS2; if(mqtt_connectFlag==1) OSMboxPost(mqtt_sendMseeageMbox, &msg); return 1; }