#include "parseDeviceMessage.h" #include "cJson.h" #include "systick.h" #include "usart.h" #include "string.h" #include #include "mqttRecv.h" #include "log.h" #include "ec800m.h" #include "main.h" #define MQTT_SUB_CMD_WRITE 0 #define MQTT_SUB_CMD_READ 1 ring_buffer mqttRecv; uint8_t protocol; void processHTTPjson(cJSON *json); char *processStringData(cJSON *data_obj, const char *key); int processIntData(cJSON *data_obj, const char *key); static void extract_data_from_buffer(const char *buffer, uint32_t *len_ptr, uint16_t *checkCode_ptr); //static void extract_data_from_buffer232(const char *buffer, uint32_t *len_ptr, uint16_t *checkCode_ptr); static uint16_t checksum(const char *str, uint16_t len); // json解析字符串 char *processStringData(cJSON *data_obj, const char *key) { cJSON *json_data = cJSON_GetObjectItemCaseSensitive(data_obj, key); if (cJSON_IsString(json_data) && (json_data->valuestring != NULL)) { return json_data->valuestring; } else { return NULL; } } // json解析int int processIntData(cJSON *data_obj, const char *key) { cJSON *json_data = cJSON_GetObjectItemCaseSensitive(data_obj, key); // if (cJSON_IsNumber(json_data) && (json_data->valueint != NULL)) 解决寄存器地址为0问题 if (cJSON_IsNumber(json_data)) { return json_data->valueint; } else { // gateway.data_valid_flag = 0; // 如果任意数据为NULL则此次数据为无效 return -1; } } /* * 函数名:void WaitForUpData(void) * 输入参数:无 * 输出参数:无 * 返回值:无 * 函数作用:等待更新本地flash信息 */ bool WaitForUpData(char *dmaBuffer) { if (UART0_RX_STAT > 0) { UART0_RX_STAT = 0; uint32_t len; uint16_t checkCode; char *temp; extract_data_from_buffer(dmaBuffer, &len, &checkCode); uint16_t jsonCheck = checksum(dmaBuffer, len); if (checkCode == jsonCheck) { addGatewayParams(dmaBuffer); return true; } else { return false; } } } /* * 函数名:static void extract_data_from_buffer(const char* buffer, uint32_t *len_ptr, uint16_t *checkCode_ptr) * 输入参数:buffer字符串 * 输出参数:json有效字符串长度len_ptr,checkCode_ptr校验码指针 * 返回值:无 * 函数作用:eg. QFDWL: 621,3e23 从json信息最后端取出这段json的有效长度和校验码 */ static void extract_data_from_buffer(const char *buffer, uint32_t *len_ptr, uint16_t *checkCode_ptr) { char *start = strstr(buffer, "+QFDWL:"); if (start != NULL) { start += 8; // 跳过"+QFDWL:" uint32_t len = 0; sscanf(start, "%u,", &len); // 读取长度 start = strchr(start, ',') + 1; // 跳过逗号 uint16_t checkCode = 0; sscanf(start, "%hx", &checkCode); // 读取16进制数据 // 将提取的数据存入形参 *len_ptr = len; *checkCode_ptr = checkCode; } } /* * 函数名:void dlt645_read(CONFIG_PARAMS *gateway) * 输入参数:设备地址*address 数据标识 readCode * 输出参数:无 * 返回值:无 * 函数作用:读取645协议内部数据 备注:dlt645协议为网上下载,返回值为数据长度 现在要加读日期信息YYMMDDhhmm 对源代码改动不多的方法是通过返回的数据长度去做判断 当数据长度为2、3、4时此时 read_buf数据包内仅含采集到的浮点数数据、 把float值4个字节直接拷贝出即可 当数据长度为5时 read_buf数据包为日期数据 其中5个字节分别为YYMMDDhhmm直接拷贝出来 当数据长度大于5时 read_buf内既包含浮点数又包含日期时间 其中前4个字节为浮点数数据后五个字节为日期信息 */ #if 0 void dlt645_read(CONFIG_PARAMS *gateway) { uint8_t read_buf[10]; for (int i = 0; i < gateway->device_read_data_num; i++) { gateway->device_read_data[i].rxLen = 0; memset(read_buf, 0, 10); memset(gateway->device_read_data[i].data, 0, 10); dlt645_set_addr(&dlt645, gateway->device_read_data[i].deviceID645); int8_t rs; if(gateway->dataType645==DLT645_2007){ rs = dlt645_read_data(&dlt645, gateway->device_read_data[i].dataType645, read_buf, DLT645_2007); } else { rs = dlt645_read_data(&dlt645, gateway->device_read_data[i].dataType645, read_buf, DLT645_1997); } if (rs != -1) { if (rs <= 4) { memcpy(gateway->device_read_data[i].data, read_buf, 4); gateway->device_read_data[i].rxLen = rs; } else if (rs == 5) { memcpy(gateway->device_read_data[i].data, read_buf, 5); gateway->device_read_data[i].rxLen = rs; } else if (rs > 5) { memcpy(gateway->device_read_data[i].data, read_buf, 9); gateway->device_read_data[i].rxLen = rs; } } else { gateway->device_read_data[i].rxLen = 0; } task_fwdgt_reload(); } } #endif /* * 函数名: void Read_Data(GATEWAY_PARAMS *gateway) * 输入参数:gateway网关存储的配置参数 * 输出参数:网关结构体指针 * 返回值:无 * 函数作用:根据存储的设备信息发送modbus信息返回值存储到gateway->device_read_data[i].data中 * modbusRead读数据只考虑读16位寄存器和32位寄存器这两种情况,但对其返回值进行处理后返回值一律为float型4个字节存储在内部 dlt645根据其返回长度判断其具体是否挈带了日期数据 */ void Read_Data() { GATEWAY_PARAMS *gateway; gateway=get_gateway_config_params(); DEVICE_PARAMS *currentDevice=gateway->device_params; READ_MODBUS_COMMAND *read_modbus_command=NULL; READ_DLT645_COMMAND *read_dlt645_command=NULL; switch(currentDevice->protocol) { case DLT645_07: case DLT645_97: protocol=1; read_dlt645_command=currentDevice->params->node_read_dlt645_command; break; case MODBUS: protocol=2; read_modbus_command=currentDevice->params->node_read_modbus_command; mmodbus_set16bitOrder(currentDevice->MDBbigLittleFormat); //设置大小端 break; } while(1)//进入轮询 { __START__WHILE: delay_1ms(10); switch(currentDevice->protocol) { case DLT645_07: case DLT645_97: { uint8_t read_buf[10]; memset(read_buf, 0, 10); dlt645_set_addr(&dlt645,read_dlt645_command->deviceID645); int8_t rs; if(currentDevice->protocol==DLT645_97) { rs = dlt645_read_data(&dlt645, read_dlt645_command->Identification, read_buf, DLT645_1997); } else if(currentDevice->protocol==DLT645_07) { rs = dlt645_read_data(&dlt645, read_dlt645_command->Identification, read_buf, DLT645_2007); } if (rs != -1) { if (rs <= 4) { memcpy(read_dlt645_command->data, read_buf, 4); read_dlt645_command->rxLen = 4; } else if (rs == 5) { memcpy(read_dlt645_command->data, read_buf, 5); read_dlt645_command->rxLen = 5; } else if (rs > 5) { memcpy(read_dlt645_command->data, read_buf, 9); read_dlt645_command->rxLen = 9; } } else { read_dlt645_command->rxLen = 0; } } break; case MODBUS: { uint16_t data[read_modbus_command->registerByteNum/2]; switch(read_modbus_command->functionCode) { case 0x03://读寄存器 { bool success=mmodbus_readHoldingRegisters16i(read_modbus_command->slaveAddress, read_modbus_command->registerAddress, read_modbus_command->registerByteNum/2, data); if(success) { uint32_t value; if(read_modbus_command->registerByteNum==4) { value = (uint32_t)data[0] << 16 | data[1]; read_modbus_command->rxLen=4; } else if(read_modbus_command->registerByteNum==2) { value = data[0]; read_modbus_command->rxLen=4; } if(read_modbus_command->decimalPoint!=0) { float convertedValue =(float)value/pow(10,read_modbus_command->decimalPoint); memcpy(read_modbus_command->value,&convertedValue,4); } else { memcpy(read_modbus_command->value,&value,4); } } else { read_modbus_command->rxLen=0; } } break; case 0x01://读线圈 { uint8_t data[2]; bool success = mmodbus_readCoils(read_modbus_command->slaveAddress, read_modbus_command->registerAddress, read_modbus_command->registerByteNum/2, data); if(success) { read_modbus_command->rxLen=4; uint32_t value = (uint32_t)data[0] << 8 | data[1]; memcpy(read_modbus_command->value,&value,4); } else { read_modbus_command->rxLen=0; } } break; default: break; } } break; } switch(currentDevice->protocol) { case DLT645_07: case DLT645_97: read_dlt645_command=read_dlt645_command->nextParams; break; case MODBUS: read_modbus_command=read_modbus_command->nextParams; break; } if((read_dlt645_command==NULL&&protocol==1)||(read_modbus_command==NULL&&protocol==2)) { currentDevice=currentDevice->nextDevice; switch(currentDevice->protocol) { case DLT645_97: case DLT645_07: protocol=1; break; case MODBUS: protocol=2; break; } if(currentDevice==NULL) { return;//一直到没有设备时跳出循环 } else { read_dlt645_command=currentDevice->params->node_read_dlt645_command; read_modbus_command=currentDevice->params->node_read_modbus_command; } } task_fwdgt_reload();//喂狗 goto __START__WHILE; } } /* * 函数名:void parseMQTTData(CONFIG_PARAMS *gateway) * 输入参数:device存储的各类产品信息 * 输出参数:无 * 返回值:无 * 函数作用:从环形缓冲区中一个个把json信息读出,与存储的gateway内的子设备信息匹配后将对应指令匹配执行并返回相应的值 * 查询逻辑现在有两套数组read数组和write数组,当接收中断产生时先判断是进行读还是写、之后在查询此网关支持的协议MODBUS还是 * 645,后根据协议去不同数组查询不同的本地存储信息、组装发送给子设备,然后根据查询的值进行采集上传数据 */ void parseMQTTData(GATEWAY_PARAMS *gateway) { while (UART0_RX_MQTT_SUB_STAT == 1) { UART0_RX_MQTT_SUB_STAT = 0; char payload_out[200]; memset(payload_out,0,200); char mqtt_publish[200]; char json[128]; while (MQTT_BUFFER_READ(json)) { LogPrint(LOG_INFO, __func__, __LINE__, "Received JSON: %s", json); cJSON *mqtt_sub_json = cJSON_Parse(json); if (mqtt_sub_json != NULL) { uint8_t action1[1]; uint8_t action; strcpy(action1, processStringData(mqtt_sub_json, "action")); // 解决字符串为 if (action1[0] == '0') { action = 0; } else if (action1[0] == '1') { action = 1; } char identifier[20]; strcpy(identifier, processStringData(mqtt_sub_json, "identifier")); char deviceId[20]; strcpy(deviceId, processStringData(mqtt_sub_json, "deviceId")); uint16_t value = processIntData(mqtt_sub_json, "parameter"); char messageId[10]; strcpy(messageId, processStringData(mqtt_sub_json, "messageId")); DEVICE_PARAMS *currentDevice=gateway->device_params; WRITE_MODBUS_COMMAND *write_modbus_command=NULL; READ_MODBUS_COMMAND *read_modbus_command=NULL; READ_DLT645_COMMAND *read_dlt645_command=NULL; // 判断其指令过来是读还是写 if (action == MQTT_SUB_CMD_WRITE)//写指令目前只支持modbus { while(1) { if(strcmp((char *)¤tDevice->deviceID,deviceId)!=0) { currentDevice=currentDevice->nextDevice; if(currentDevice==NULL) { break; //如果找不到所属设备则跳出 } } else { protocol=2;//决定当前使用modbus回调函数还是dlt645 if(write_modbus_command==NULL) { write_modbus_command=currentDevice->params->node_write_modbus_command; } if(strcmp((char*)&write_modbus_command->keyword,identifier)!=0)//寻找设备层内所属属性名称 { write_modbus_command=write_modbus_command->nextParams; if(write_modbus_command==NULL) { break; } } else //找到所属于的属性了 { mmodbus_set16bitOrder(currentDevice->MDBbigLittleFormat); if(write_modbus_command->functionCode==0x05) { bool success = mmodbus_writeCoil(write_modbus_command->slaveAddress, write_modbus_command->registerAddress, (uint8_t)value); // 成功 if (success) { sprintf((char *)payload_out, "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d}", action1, write_modbus_command->keyword, currentDevice->deviceID, messageId, success); break; } else { sprintf((char *)payload_out, "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d}", action1, write_modbus_command->keyword, currentDevice->deviceID, messageId, success); break; } } else if(write_modbus_command->functionCode==0x06) { bool success = mmodbus_writeHoldingRegister16i(write_modbus_command->slaveAddress, write_modbus_command->registerAddress, (uint16_t)value); if (success) { sprintf((char *)payload_out, "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d}", action1, write_modbus_command->keyword, currentDevice->deviceID, messageId, success); break; } else { sprintf((char *)payload_out, "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d}", action1, write_modbus_command->keyword, currentDevice->deviceID, messageId, success); break; } } } } } } // 指令是来读某属性值的 else if (action == MQTT_SUB_CMD_READ) { while(1) { if(strcmp((char *)¤tDevice->deviceID,deviceId)!=0) { currentDevice=currentDevice->nextDevice; if(currentDevice==NULL) { break; //如果找不到所属设备则跳出 } } else //找到了设备 { if(currentDevice->protocol==MODBUS) { protocol=2;//决定当前使用modbus=2回调函数还是dlt645=1 if(read_modbus_command==NULL)read_modbus_command=currentDevice->params->node_read_modbus_command; if(strcmp((char *)&read_modbus_command->keyword,identifier)!=0) { read_modbus_command=read_modbus_command->nextParams; if(read_modbus_command==NULL)break; } else//找到了属性 { mmodbus_set16bitOrder(currentDevice->MDBbigLittleFormat); if(read_modbus_command->functionCode==0x01) { uint8_t data[2]; bool success = mmodbus_readCoils(read_modbus_command->slaveAddress, read_modbus_command->registerAddress, read_modbus_command->registerByteNum/2, data); uint8_t value1; if (success) { uint16_t value1 = (uint16_t)data[0] << 8 | data[1]; if (value1 == 0xFF00) { value1 = 1; } else if (value1 == 0x0000) { value1 = 0; } // 读线圈成功的json sprintf((char *)payload_out, "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d,\"parameter\":%d}", action1, read_modbus_command->keyword, currentDevice->deviceID, messageId, success, value); break; } // 读线圈失败的json else { sprintf((char *)payload_out, "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d}", action1, read_modbus_command->keyword, currentDevice->deviceID, messageId, success); break; } } } } else//dlt645读取指令 { protocol=1;//决定当前使用modbus=2回调函数还是dlt645=1 float value; uint8_t minute, hour, day, month, year; uint8_t read_buf[10]; memset(read_buf, 0, 10); if(read_dlt645_command==NULL)read_dlt645_command=currentDevice->params->node_read_dlt645_command; dlt645_set_addr(&dlt645, read_dlt645_command->deviceID645); int8_t rs ; if(currentDevice->protocol==DLT645_07) { rs = dlt645_read_data(&dlt645, read_dlt645_command->Identification, read_buf, DLT645_2007); }else if(currentDevice->protocol==DLT645_97) { rs = dlt645_read_data(&dlt645, read_dlt645_command->Identification, read_buf, DLT645_1997); } if (rs != -1) { if (rs <= 4) { memcpy(&value, read_buf, 4); sprintf((char *)payload_out, "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d,\"value\":%.2f}", action1, read_dlt645_command->keyword, currentDevice->deviceID, messageId, 1, value); break; } else if (rs == 5) { year = read_buf[4]; month = read_buf[3]; day = read_buf[2]; hour = read_buf[1]; minute = read_buf[0]; sprintf((char *)payload_out, "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d,\"value\":\"%02X%02X%02X%02X%02X\"}", action1, read_dlt645_command->keyword, currentDevice->deviceID, messageId, 1, year, month, day, hour, minute); break; } else if (rs > 5) { memcpy(&value, read_buf, 4); year = read_buf[8]; month = read_buf[7]; day = read_buf[6]; hour = read_buf[5]; minute = read_buf[4]; sprintf((char *)payload_out, "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d,\"value\":\"%02X%02X%02X%02X%02X%.2f\"}", action1, read_dlt645_command->keyword, currentDevice->deviceID, messageId, 1, year, month, day, hour, minute, value); break; } } else { // dlt645读取失败的json组成 sprintf((char *)payload_out, "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d}", action1, read_dlt645_command->keyword, currentDevice->deviceID, messageId, 0); break; } } } } } // 上传对应的响应信息 sprintf((char *)mqtt_publish, "AT+QMTPUBEX=0,0,0,0,\"%s\",%d\r\n", gateway->messageTopic, strlen(payload_out)); EC800MSendCmd(mqtt_publish, strlen(mqtt_publish)); WaitResponse("<", 1000); EC800MSendCmd(payload_out, strlen(payload_out)); WaitResponse(RSP_OK, 1000); } cJSON_Delete(mqtt_sub_json); } } } // 模块下载download校验值 static uint16_t checksum(const char *str, uint16_t len) { uint16_t sum = 0; uint8_t odd = 0; // 如果字符串长度为奇数,则将最后一个字符设置为高8位,低8位设置为0 if (len % 2 == 1) { odd = 1; len--; } // 将每两个字符作为一个16位的数值进行异或操作 for (uint16_t i = 0; i < len; i += 2) { sum ^= ((uint16_t)str[i] << 8) | (uint16_t)str[i + 1]; } // 如果字符串长度为奇数,则还需要将最后一个字符与0xFF00异或 if (odd) { sum ^= (uint16_t)str[len] << 8; } // 返回校验和 return sum; } //比较本次数据和上次数据是否相同如果相同则不进行数据的更新 int compareWithLastData(char *old_data,const char* new_data,uint8_t dataLen) { if (memcmp(new_data, old_data,dataLen) == 0) { return 0; } else { memcpy(old_data,&new_data,dataLen);; return 1; } }