#include "ML307A.h" #include "usart.h" #include "circle_buffer.h" #include "rtc.h" #include //printf #include #include // bool #include "cmsis_os.h" #include "main.h" #include "queue.h" #include "uType.h" #include "remote.h" extern circle_buf_t uart3CircleBuf; // 环形缓冲区管理结构体 //extern circle_buf_t_2 uart3CircleBuf_2; // 环形缓冲区管理结构体 #define BUFFER_SIZE4G 512 extern uint8_t receiveBuff4G[BUFFER_SIZE4G]; char responseBuf[256]; // AT指令应答的局部缓冲区 char responseBuf_2[256]; // AT指令应答的局部缓冲区 //static uint8_t uart3ParseBuf[BUFFER_SIZE4G]; // 解析+MIPURC: "rtcp"的缓冲区 //static uint16_t parseIndex = 0; // 解析+MIPURC: "rtcp"的缓冲区指针 extern uint8_t receiveBuff4G_MIPURC[BUFFER_SIZE4G]; extern osMessageQueueId_t uart3rxqueueHandle; bool MgnssFlag = false;// GNSS定位信息上报成功标志位 uint8_t Reset4G_flag = 0; #define MAX_HEX_DATA_LEN 256 // 假设最多解析 256 字节的 HEX 数据 uint8_t parsed_4GMIPURC_Data[MAX_HEX_DATA_LEN]; extern bool flash_save_parameter_flag; uint16_t msg_serial = 0; extern volatile bool heartbeat_reply_received; extern volatile bool unixtime_reply_received; /** * @breaf 封装串口发送4G AT命令函数 */ void USART_SendString(UART_HandleTypeDef *huart,char *str) { // HAL_UART_Transmit(huart, (uint8_t*)str, strlen(str), 0xFFFF); HAL_UART_Transmit_DMA(huart, (uint8_t*)str, strlen(str)); } /** * @breaf 发送4G串口命令 */ /* uint8_t sendCmd_4G(char *pCmd, char *pRes, uint32_t timeOut, uint8_t sendNum) { uint8_t i = 0; uint32_t time; // uint8_t found = 0; for (i = 0; i < sendNum; i++) { time = timeOut * 10; // 将超时时间转换为循环次数 memset(receiveBuff4G, 0, sizeof(receiveBuff4G)); // 清空接收缓冲区 USART_SendString(&huart3, pCmd); // 发送命令字符串 // HAL_Delay(100); osDelay(100); while (time--) { if (strstr((const char *)receiveBuff4G, pRes) != NULL) { printf("-- %s\n", receiveBuff4G); // 打印接收到的内容 //如果接收缓冲区包含预期的响应 return 1; } // HAL_Delay(100); osDelay(100); } printf("! %s\n", receiveBuff4G); } return 0; } */ uint8_t sendCmd_4G(char *pCmd, char *pRes1, uint32_t timeOut, uint8_t sendNum) { uint8_t i; uint32_t time; uint8_t receivedByte; memset(responseBuf, 0, sizeof(responseBuf)); // 清空临时缓冲区 for (i = 0; i < sendNum; i++) { time = timeOut * 10; // 计算超时时间 // ★ 发送前丢弃旧数据 ★ __HAL_UART_DISABLE_IT(&huart3, UART_IT_IDLE); // 可选:保护指针修改 uart3CircleBuf.r = uart3CircleBuf.w; // 丢弃旧数据 __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE); //printf("send command: %s\r\n", pCmd); USART_SendString(&huart3, pCmd); // 发送 AT 指令 osDelay(100); // 等待模块返回(短暂延时) while (time--) { uint8_t gotNewData = 0; // 读取环形缓冲区内的新数据 while (circle_buf_read(&uart3CircleBuf, &receivedByte) == 0) { gotNewData = 1; uint16_t len = strlen(responseBuf); if (len < sizeof(responseBuf) - 1) { responseBuf[len] = receivedByte; responseBuf[len + 1] = '\0'; // 字符串结束符 } } if (gotNewData) { // ★ 判断是否匹配 ★ if (pRes1 && strstr(responseBuf, pRes1) != NULL) { // printf("-: %s\n", responseBuf); return 1; // 任意一个匹配成功 } } osDelay(10); } printf("Timeout_!: %s\n", responseBuf); // 超时打印 } return 0; } uint8_t sendCmd_4G_2(char *pCmd, char *pRes1, char *pRes2, uint32_t timeOut, uint8_t sendNum) { uint8_t i; uint32_t time; uint8_t receivedByte; memset(responseBuf_2, 0, sizeof(responseBuf_2)); // 清空临时缓冲区 for (i = 0; i < sendNum; i++) { time = timeOut * 10; // 计算超时时间 // ★ 发送前丢弃旧数据 ★ __HAL_UART_DISABLE_IT(&huart3, UART_IT_IDLE); // 可选:保护指针修改 uart3CircleBuf.r = uart3CircleBuf.w; // 丢弃旧数据 __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE); //printf("send command: %s\r\n", pCmd); USART_SendString(&huart3, pCmd); // 发送 AT 指令 osDelay(100); // 等待模块返回(短暂延时) while (time--) { uint8_t gotNewData = 0; // 读取环形缓冲区内的新数据 while (circle_buf_read(&uart3CircleBuf, &receivedByte) == 0) { gotNewData = 1; uint16_t len = strlen(responseBuf_2); if (len < sizeof(responseBuf_2) - 1) { responseBuf_2[len] = receivedByte; responseBuf_2[len + 1] = '\0'; // 字符串结束符 } } if (gotNewData) { // ★ 判断是否匹配 ★ if ((pRes1 && strstr(responseBuf_2, pRes1) != NULL) || (pRes2 && strstr(responseBuf_2, pRes2) != NULL)) { // printf("-: %s\n", responseBuf_2); return 1; // 任意一个匹配成功 } } osDelay(10); } printf("Timeout_!: %s\n", responseBuf_2); // 超时打印 } return 0; } uint8_t sendCmd_4G_3(char *pCmd, char *pRes1, char *pRes2, uint32_t timeOut, uint8_t sendNum) { uint8_t i; uint32_t time; uint8_t receivedByte; memset(responseBuf_2, 0, sizeof(responseBuf_2)); // 清空临时缓冲区 for (i = 0; i < sendNum; i++) { time = timeOut * 10; // 计算超时时间 // ★ 发送前丢弃旧数据 ★ __HAL_UART_DISABLE_IT(&huart3, UART_IT_IDLE); // 可选:保护指针修改 uart3CircleBuf.r = uart3CircleBuf.w; // 丢弃旧数据 __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE); USART_SendString(&huart3, pCmd); // 发送 AT 指令 osDelay(100); // 等待模块返回(短暂延时) uint8_t matchFlag = 0; while (time--) { uint8_t gotNewData = 0; // 读取环形缓冲区内的新数据 while (circle_buf_read(&uart3CircleBuf, &receivedByte) == 0) { gotNewData = 1; uint16_t len = strlen(responseBuf_2); if (len < sizeof(responseBuf_2) - 1) { responseBuf_2[len] = receivedByte; responseBuf_2[len + 1] = '\0'; // 字符串结束符 } } if (gotNewData) { // 每次有新数据都检测是否有完整的行 char *lineStart = responseBuf_2; while (1) { // 查找是否有一行结束符 char *lineEnd = strstr(lineStart, "\r\n"); if (lineEnd == NULL) break; // 没有完整行,等待更多数据 // 截断这一行,形成完整字符串 *lineEnd = '\0'; // 打印完整行 // printf("%s\n", lineStart); // // 重点:如果是+MIPURC开头的数据 // if (strstr(lineStart, "+MIPURC: \"rtcp\"") != NULL) // { // printf("MIPURC Data: %s\n", lineStart); // } // 判断是否有匹配到成功应答 if ((pRes1 && strstr(lineStart, pRes1) != NULL) || (pRes2 && strstr(lineStart, pRes2) != NULL)) { matchFlag = 1; } // 移动到下一行 lineStart = lineEnd + 2; } // 剩下的内容移动到buffer头部(继续拼接未完整行) uint16_t remainLen = strlen(lineStart); memmove(responseBuf_2, lineStart, remainLen + 1); // +1 包含结束符 } osDelay(10); } if (matchFlag) { // printf("%s\n", responseBuf_2); // 打印剩余数据 return 1; // 任意一个匹配成功 } printf("Timeout_!: %s\n", responseBuf_2); // 超时打印 } return 0; } void process_uart3_buffer(void) { Uart3Rx_msg uart3_msg; if (xQueueReceive(uart3rxqueueHandle, &uart3_msg, (TickType_t)500) == pdPASS) // portMAX_DELAY (TickType_t)0 { uint16_t len = (uart3_msg.length < sizeof(receiveBuff4G_MIPURC)) ? uart3_msg.length : (sizeof(receiveBuff4G_MIPURC) - 1); memcpy(receiveBuff4G_MIPURC, uart3_msg.data, len); receiveBuff4G_MIPURC[len] = '\0'; // 确保字符串结尾 printf("Queue Data: %s\n", receiveBuff4G_MIPURC); if(system_cloud_mode == Cloud_4G_MODE) { process_MIPURC_data(receiveBuff4G_MIPURC, len); } } } void process_MIPURC_data(uint8_t *buf, uint16_t len) { const char *mipurcStr = "+MIPURC: \"rtcp\",0,"; uint16_t mipurcLen = strlen(mipurcStr); int mipurcPos = -1; // **查找 "+MIPURC: \"rtcp\",0," 位置** for (uint16_t i = 0; i <= len - mipurcLen; i++) { if (memcmp(buf + i, mipurcStr, mipurcLen) == 0) { mipurcPos = i; break; } } // **如果找到 "+MIPURC: \"rtcp\",0,"** if (mipurcPos != -1) { uint8_t *dataStart = buf + mipurcPos + mipurcLen; // `+MIPURC: "rtcp",0,` 后的数据 // **提取数据长度** char *commaPos = strchr((char *)dataStart, ','); if (commaPos == NULL) { printf("Invalid MIPURC format (missing length)\n"); return; } int expectedDataLen = 0; if (sscanf(commaPos - 2, "%d,", &expectedDataLen) != 1) { // **修正解析** printf("Invalid MIPURC format (length parse error)\n"); return; } // 找到实际数据部分(跳过逗号后面的空格) char *hexDataStr = commaPos + 3; // 这里 +3 是跳过 ", ",确保指向 HEX 数据 // **转换 HEX 字符串到二进制** int actualDataLen = hexStringToBytes(hexDataStr-2, parsed_4GMIPURC_Data, MAX_HEX_DATA_LEN); if (actualDataLen < 0) { printf("HEX Data parse error! Code: %d\n", actualDataLen); return; } // **检查长度是否匹配** if (expectedDataLen == actualDataLen-1) { // printf("Extracted JT808 Data (%d bytes): ", expectedDataLen); // for (int i = 0; i < expectedDataLen; i++) { // printf("%02X ", parsed_4GMIPURC_Data[i]); // } // printf("\n"); // 直接解析 JT808 数据 parse_JT808_frame(parsed_4GMIPURC_Data, expectedDataLen); } else { printf("Length mismatch: expected %d, got %d. Ignoring.\n", expectedDataLen, actualDataLen); } } } /** * @brief 等待UART3接收预期字符串中的任意一个 WIFI用 * @param keywords 关键词数组(多个字符串) * @param keyword_count 关键词数量 * @param buffer 存储接收数据的缓冲区 * @param buffer_len 缓冲区长度 * @param timeout_ms 等待超时时间(毫秒) * @return 匹配到的关键词索引(0 ~ keyword_count-1),否则返回 -1 */ int wait_uart3_multi_response(const char* keywords[], int keyword_count, char* buffer, uint16_t buffer_len, uint32_t timeout_ms) { TickType_t start_tick = xTaskGetTickCount(); uint16_t total_len = 0; Uart3Rx_msg uart3_msg; while ((xTaskGetTickCount() - start_tick) < pdMS_TO_TICKS(timeout_ms)) { if (xQueueReceive(uart3rxqueueHandle, &uart3_msg, pdMS_TO_TICKS(300)) == pdPASS) { uint16_t copy_len = (uart3_msg.length < (buffer_len - total_len - 1)) ? uart3_msg.length : (buffer_len - total_len - 1); memcpy(buffer + total_len, uart3_msg.data, copy_len); total_len += copy_len; buffer[total_len] = '\0'; printf("Recv: %s\r\n", buffer); // 检查并提取 +TRDTC: 数据 extract_and_parse_trdtc(buffer); for (int i = 0; i < keyword_count; ++i) { if (strstr(buffer, keywords[i]) != NULL) { // printf("Matched keyword[%d]: %s\r\n", i, keywords[i]); return i; } } } } printf("Timeout\r\n"); return -1; } /** * @brief 从 UART 数据中提取并解析 +TRDTC: 开头的 JT808 帧数据 * @param buffer 接收到的完整字符串(含 +TRDTC:) */ void extract_and_parse_trdtc(const char* buffer) { const char* trdtc_start = strstr(buffer, "+TRDTC:"); if (!trdtc_start) return; // 查找第一个 "7E" 作为帧起始 const char* frame_start = strstr(trdtc_start, "7E"); if (!frame_start) return; // printf("first 7E \r\n"); const char* frame_end = strstr(frame_start + 2, "7E"); // 查找第二个 7E if (frame_end) { frame_end += 2; // 包含结束 7E } else { // 如果没找到第二个7E,尝试查找\r\n作为帧尾 frame_end = strstr(frame_start, "\r\n"); if (!frame_end) return; // 没有找到帧尾,退出 // 不包括 \r\n,只处理到前面为止 } // printf("frame_end 7E \r\n"); int hex_len = frame_end - frame_start; if (hex_len <= 0 || hex_len > 512) return; uint8_t jt808_frame[256]; int byte_len = 0; char byte_str[3] = {0}; for (int i = 0; i < hex_len; i += 2) { if (frame_start[i] == '\0' || frame_start[i + 1] == '\0') break; byte_str[0] = frame_start[i]; byte_str[1] = frame_start[i + 1]; jt808_frame[byte_len++] = (uint8_t)strtol(byte_str, NULL, 16); } if (byte_len > 0) parse_JT808_frame(jt808_frame, byte_len); } void parse_JT808_frame(uint8_t *frame, uint16_t length) { // printf("JT808 Frame Received (Len: %d): ", length); // for (uint16_t i = 0; i < length; i++) // { // printf("%02X ", frame[i]); // } // printf("\n"); uint16_t msg_id = (frame[1] << 8) | frame[2]; // 消息 ID // uint16_t msg_length = (frame[3] << 8) | frame[4]; // 消息体长度 // uint8_t *phone_number = &frame[5]; // 手机号 (BCD 编码) msg_serial = (frame[11] << 8) | frame[12]; // 消息流水号 uint8_t *payload = &frame[13]; // 消息体数据 uint8_t received_checksum = frame[length - 2]; // 校验码 uint8_t calculated_checksum = Calculate_Checksum(&frame[1], length - 3); if (calculated_checksum != received_checksum ) { printf("Checksum Mismatch! Expected: %02X, Received: %02X\n", calculated_checksum, received_checksum); return; } // printf("JT808 Frame Received (Len: %d)\n", length); // printf("Message ID: 0x%04X, Length: %d, Serial: %d\n", msg_id, msg_length, msg_serial); switch (msg_id) { case 0x80FF: // 服务器下发unix时间 if ((length - 13) >= 4) // 数据体长度至少 4 字节 { // 从 payload 中提取 4 字节,转成 uint32_t uint32_t timestamp = ((uint32_t)payload[0] << 24) | ((uint32_t)payload[1] << 16) | ((uint32_t)payload[2] << 8) | ((uint32_t)payload[3]); // printf("Received UNIX Timestamp: %lu\r\n", timestamp); // 设置 RTC 时间 Set_RTC_Time((time_t)timestamp); unixtime_reply_received = true; } else { printf("Invalid 0x80FF payload length: %d\r\n", length - 13); } break; case 0x8001: // 终端通用应答 if (length > 18 && frame[17] == 0) printf("Heart_callback_OK\n"); heartbeat_reply_received = true; break; case 0x8100: // 终端注册应答 if (length > 14 && frame[13] == 0) printf("Cloud_Register_callback_OK\n"); break; case 0x8103: // 终端参数设置 parse_JT808_8103(payload, length); Send_General_response(); break; default: printf("Unknown Message ID: 0x%04X\n", msg_id); break; } } // 解析 JT808 0x8103 终端参数设置 void parse_JT808_8103(uint8_t *payload, uint16_t length) { printf("Terminal Parameter Settings Received:\n"); for (uint16_t i = 1; i < length;) { uint16_t param_id = (payload[i] << 8) | payload[i + 1]; // 参数 ID uint8_t param_length = payload[i + 2]; // 参数长度 uint8_t param_value = payload[i + 3]; // 只支持 1 字节参数 printf("Param ID: 0x%04X, Length: %d, Value: %d\n", param_id, param_length, param_value); switch (param_id) { case 0xF101: flash_data.controltransmit_flag = param_value; break; case 0xF102: flash_data.temp_first_threshold = param_value; break; case 0xF103: flash_data.temp_second_threshold = param_value; break; case 0xF104: flash_data.pressure_threshold = param_value; break; case 0xF105: flash_data.co_threshold = param_value; break; case 0xF106: flash_data.h2_threshold = param_value; break; case 0xF107: flash_data.smallboard_upload_frequency = param_value; break; case 0xF108: flash_data.heart_upload_frequency = param_value; break; case 0xF109: flash_data.mainboard_upload_frequency = param_value; break; default: printf("Unknown Parameter ID: 0x%04X\n", param_id); break; } i += (3 + param_length); // 跳过已解析的参数 } CAN_Send_Parameter(0x00110000, &flash_data, 8); flash_save_parameter_flag = true; printf("Updated flash_data:\n"); printf("Control Transmit Flag: %d\n", flash_data.controltransmit_flag); printf("Temp First Threshold: %d°C\n", flash_data.temp_first_threshold); printf("Temp Second Threshold: %d°C\n", flash_data.temp_second_threshold); printf("Pressure Threshold: %d Pa\n", flash_data.pressure_threshold); printf("CO Threshold: %d ppm\n", flash_data.co_threshold); printf("H2 Threshold: %d ppm\n", flash_data.h2_threshold); printf("Smallboard Upload Frequency: %d s\n", flash_data.smallboard_upload_frequency); printf("Heart Upload Frequency: %d s\n", flash_data.heart_upload_frequency); printf("Mainboard Upload Frequency: %d s\n", flash_data.mainboard_upload_frequency); } // HEX 字符串转换为二进制数据 int hexStringToBytes(const char *hexStr, uint8_t *outBytes, int maxLen) { int hexStrLen = strlen(hexStr); if (hexStrLen % 2 != 0) { return -1; // HEX 字符串长度必须是偶数 } int byteLen = hexStrLen / 2; if (byteLen > maxLen) { return -2; // 数据超出缓冲区 } for (int i = 0; i < byteLen; i++) { sscanf(hexStr + 2 * i, "%2hhx", &outBytes[i]); // 每两个字符转换成 1 个字节 } return byteLen; } /** * @breaf MQTT连接至MQTT服务器,订阅,发布消息 */ // 封装MQTT连接至MQTT服务器 uint8_t mqttconn(char *IpAddr, uint16_t port, char *ID, char *User, char *Passwd, char* pRes) { char MQTT_Sendbuf[128]; sprintf((char *)MQTT_Sendbuf,"AT+MQTTCONN=0,\"%s\",\"%d\",\"%s\",\"%s\",\"%s\"\r\n",IpAddr, port, ID,User, Passwd); sendCmd_4G(MQTT_Sendbuf,pRes,1,1); if(sendCmd_4G(MQTT_Sendbuf,pRes,1,1)) { return 1; } return 0; } // 连接至MQTT服务器,订阅 void MQTTCONN(void) { char MQTT_SUBbuf[50]; // 订阅字符缓冲区 char topicb[50];//*服务器发布主题B // 连接至MQTT服务器 mqttconn((char*)MQTTADDR,MQTTPORT,"DCCJC",(char*)MQTTUSER,(char*)MQTTPSWD,"+MQTTURC: \"conn\",0,0");// printf("#连接MQTT成功\r\n"); // 订阅主题 snprintf(MQTT_SUBbuf, 50, "AT+MQTTSUB=0,\"%s\",1\r\n", topicb); // 发送订阅指令并检查结果 sendCmd_4G(MQTT_SUBbuf, "+MQTTURC: \"suback\"", 1, 1);// printf("#订阅成功\r\n"); } // 发布消息QoS=0; uint8_t MQTT_PUB(uint8_t connect_id, char *topic, char *mesg, char* pRes) { char MQTT_Sendbuf[200]; uint8_t length = strlen(mesg); sprintf((char *)MQTT_Sendbuf,"AT+MQTTPUB=%d,\"%s\",0,0,0,%d,\"%s\"\r\n",connect_id, topic, length, mesg); sendCmd_4G(MQTT_Sendbuf,pRes,1,1); // if(sendCmd_4G(MQTT_Sendbuf,pRes,1,1)){// printf("#发布心跳成功\r\n"); // return 1; // } return 1; } // 断开MQTT连接 void MQTTDISCONN(void) { sendCmd_4G("AT+MQTTDISC=0\r\n", "OK", 1, 1);// printf("#断开MQTT连接成功\r\n"); } /** * @breaf 建立TCP连接 */ // 封装建立TCP连接函数 void tcpconn(char *value, uint8_t cid, char *IPaddr, uint16_t port, uint8_t tcpConnmode) { char *ptr = value; ptr += sprintf(ptr, "AT+MIPOPEN=%d,\"TCP\",\"%s\",%d,60,%d\r\n",cid,IPaddr,port,tcpConnmode); } // 建立TCP连接平台端IP及端口号 void TCPCONN(void) { char TCPconnvalue[100]; tcpconn(TCPconnvalue, 1, JIALONGip, JIALONGport,0); //cid=1 tcpConnmode=0 普通模式 } /** * @breaf 连续定位信息上报 */ void GNSSLOC(void) { // sendCmd_4G("AT+MIPCFG=\"encoding\",1,1,1\r\n", "OK", 1, 1);//默认输入输出为ASCII,0 发16,1 接16,1 sendCmd_4G("AT+MGNSSCFG=\"nmea/mask\",0\r\n", "OK", 1, 1); sendCmd_4G("AT+MGNSSLOC=0\r\n", "OK", 1, 1); sendCmd_4G("AT+MGNSS=1\r\n", "OK", 1, 1); if(sendCmd_4G("AT+MGNSSCFG=\"nmea/mask\",0\r\n", "OK", 1, 1)) { // printf("#使能NMEA信息\r\n"); if(sendCmd_4G("AT+MGNSSLOC=0\r\n", "OK", 1, 1)) {// printf("#关闭自动定位上报\r\n"); if(sendCmd_4G("AT+MGNSS=1\r\n", "OK", 1, 1)) {// printf("开启MGNSS\r\n"); MgnssFlag=true; } } } } /** * @breaf 4G模块初始化 */ void ML307A_INIT(void) { if (sendCmd_4G("AT\r\n", "OK", 1, 5)) { printf("AT_OK\r\n"); }else { printf("AT_fail\r\n"); ML307AReset(); } if (sendCmd_4G("AT+CPIN?\r\n", "+CPIN: READY", 1, 5)) { printf("CPIN_OK\r\n"); } if (sendCmd_4G("AT+CEREG?\r\n", "+CEREG: 0,1", 1, 5)) { printf("CEREG_OK\r\n"); } if(sendCmd_4G("AT+MIPCLOSE=1\r\n", "+MIPSEND:", 1, 1))//关闭TCP连接 { printf("MIPCLOSE_OK\r\n"); } ML307A_MQTT_Init(); } void ML307A_Init(void) { for (int attempt_count = 0; attempt_count < 3; attempt_count++) { sendCmd_4G("AT\r\n", "OK", 1, 5); HAL_Delay(10); sendCmd_4G("AT+CPIN?\r\n", "+CPIN: READY", 1, 5); printf("CPIN_OK\r\n"); HAL_Delay(10); sendCmd_4G("AT+CEREG?\r\n", "+CEREG: 0,1", 1, 5); printf("Network ing...\r\n"); if (sendCmd_4G("AT+CPIN?\r\n", "+CPIN: READY", 1, 5)) { printf("PIN认证成功\r\n"); if (sendCmd_4G("AT+CEREG?\r\n", "+CEREG: 0,1", 1, 5)) { printf("驻网成功\r\n"); break; } } else { ML307AReset(); } break; } } /* char TCPconnvalue[100];// TCP的IP地址端口号缓冲区 case 2: // tcpconn(TCPconnvalue, 1, JIALONGip, JIALONGport,0); //cid=1 tcpConnmode=0 普通模式 // if (sendCmd_4G(TCPconnvalue, "+MIPOPEN: 1,0", 1, 1)) { // step4g++; // } step4g=3; break; case 3: sendCmd_4G("AT+MIPCFG=\"encoding\",0,2,0\r\n", "OK", 1, 1);////输入配置为转义字符模式 if (!reset4Gmodule) { if (sendCmd_4G("AT+MGNSSCFG=\"nmea/mask\",0\r\n", "OK", 1, 1)) { printf("#使能NMEA信息\r\n"); if (sendCmd_4G("AT+MGNSSLOC=0\r\n", "OK", 1, 1)) { printf("#关闭自动定位上报\r\n"); if (sendCmd_4G("AT+MGNSS=1\r\n", "OK", 1, 1)) { printf("#开启MGNSS\r\n"); MgnssFlag = true; } } } step4g++; } else { reset4Gmodule = false; } break; case 4: MQTTCONN(); char data_buff[256]; //组合JSON报文数据 uint8_t run_state = 0; sprintf((char *)data_buff,"{\"temperature\":{\"ID\":180}}"); run_state=MQTT_PUB(0,Publish_Topic,data_buff,"+MQTTURC: \"puback\"");//上报 if(run_state==1) { printf("4G模块发布数据至MQTT成功\r\n"); run_state = 0; } */ void Send_AT_Command(char *command) { // 发送AT指令时添加换行符 char command_with_newline[256]; snprintf(command_with_newline, sizeof(command_with_newline), "%s\r\n", command); // 发送指令 HAL_UART_Transmit(&huart3, (uint8_t *)command_with_newline, strlen(command_with_newline),1000); } void Receive_Response(char *buffer, uint16_t size) { // 接收数据 HAL_UART_Receive_DMA(&huart3, (uint8_t *)buffer, size - 1); // 添加字符串结束符 buffer[size - 1] = '\0'; memset(buffer, 0, size); // 清空接收缓冲区 } int Check_Response(char *buffer, uint16_t size) { Receive_Response(buffer, size); // 判断是否为错误响应 if (strstr(buffer, "+CME ERROR") != NULL) { return 0; // 失败 } // 判断是否为特定成功响应 if (strstr(buffer, "+MQTTREAD") != NULL || strstr(buffer, "+MQTTPUB") != NULL || strstr(buffer, "+MQTTSUB") != NULL || strstr(buffer, "+MQTTURC") != NULL || strstr(buffer, "+CEREG:0,1") != NULL ) { return 1; // 成功 } // 判断是否为OK响应 if (strstr(buffer, "OK") != NULL) { return 1; // 成功 } return 0; // 其他情况视为失败 } int Send_Command_Check_Response(char *command, char *response_buffer, uint16_t buffer_size) { Send_AT_Command(command); return Check_Response(response_buffer, buffer_size); } void MQTT_Process(void) { char response[256]; // 存放接收的响应数据 int total_attempt = 0; // 总共跳回清除会话模式的次数 int attempt = 0; // 每个步骤的重试次数 int success = 0; // 是否成功标志位 while (total_attempt < 5) { // 最多尝试5次清除会话模式 total_attempt++; // 每次从头开始都计为一次清除会话模式的执行 // 1. 清除会话模式 attempt = 0; // 重置步骤重试计数 while (attempt < 3) { // 每个步骤最多重试3次 success = Send_Command_Check_Response("AT+MQTTCFG=\"clean\",0,1", response, sizeof(response)); if (success) // printf("清除会话模式成功\n"); break; // 成功则继续下一个步骤 attempt++; } if (!success) continue; // 如果重试3次仍然失败,则重新开始整个流程 HAL_Delay(1); // 2. 配置为接收缓存模式 attempt = 0; // 重置步骤重试计数 while (attempt < 3) { success = Send_Command_Check_Response("AT+MQTTCFG=\"cached\",0,1", response, sizeof(response)); if (success) { printf("配置为接收缓存模式成功\n"); break; } attempt++; } if (!success) continue; // 如果失败则重新开始整个流程 HAL_Delay(1); // 3. 连接至MQTT服务器 attempt = 0; while (attempt < 3) { success = Send_Command_Check_Response("AT+MQTTCONN=0,\"183.230.40.96\",1883,\"test0923_1\",\"0w8A8Kloxm\",\"version=2018-10-31&res=products%2F0w8A8Kloxm%2Fdevices%2Ftest0923_1&et=1853416411&method=md5&sign=VBoBVpruRrjQA6LjW2KEXw%3D%3D\"", response, sizeof(response)); if (success) { printf("连接至MQTT服务器成功\n"); break; } attempt++; } if (!success) continue; HAL_Delay(1); // 4. 订阅主题 attempt = 0; while (attempt < 3) { success = Send_Command_Check_Response("AT+MQTTSUB=0,\"$sys/0w8A8Kloxm/test0923_1/#\",1", response, sizeof(response)); if (success) { printf("订阅主题成功\n"); break; } attempt++; } if (!success) continue; HAL_Delay(1); // 5. 发布消息 attempt = 0; while (attempt < 3) { success = Send_Command_Check_Response("AT+MQTTPUB=0,\"$sys/0w8A8Kloxm/test0923_1/dp/post/json\",0,0,0,65,\"{\"id\":123,\"dp\":{\"gps\":[{\"v\":{\"lon\":20.898888,\"lat\":15.268888}}]}}\"", response, sizeof(response)); if (success){ printf("发布消息成功\n"); break; } attempt++; } if (!success) continue; // // 6. 读取缓存数据 // attempt = 0; // while (attempt < 3) { // success = Send_Command_Check_Response("AT+MQTTREAD=0,1", response, sizeof(response)); // if (success) { // printf("读取缓存数据成功"); // break; // } // attempt++; // } // if (!success) continue; // // 7. 断开连接 // attempt = 0; // while (attempt < 3) { // success = Send_Command_Check_Response("AT+MQTTDISC=0", response, sizeof(response)); // if (success) { // printf("断开连接成功"); // break; // } // attempt++; // } // if (!success) continue; // 如果所有步骤都成功,则退出函数 break; } // 如果达到5次还不成功,可以输出日志或执行其他错误处理 if (total_attempt >= 5) { // 错误处理 printf("MQTT连接失败,达到最大重试次数。\n"); } } void ML307A_MQTT_Init(void) { // check_network_connection(); char response[256]; // 存放接收的响应数据 Send_Command_Check_Response("AT+MQTTDISC=0", response, sizeof(response)); HAL_Delay(100); Send_Command_Check_Response("AT+MQTTCFG=\"clean\",0,1", response, sizeof(response)); HAL_Delay(100); Send_Command_Check_Response("AT+MQTTCFG=\"cached\",0,1", response, sizeof(response)); HAL_Delay(100); Send_Command_Check_Response("AT+MQTTCONN=0,\"106.14.207.159\",1883,\"BATT|securemode=2,signmethod=hmacsha1,timestamp=1729351701003|\",\"BATT&k1vccLJvsUy\",\"E664F110C5752BDB294C14ADC5594A673C6552B8\"", response, sizeof(response)); HAL_Delay(100); Send_Command_Check_Response("AT+MQTTSUB=0,\"/sys/k1vccLJvsUy/BATT/thing/service/property/set\",1", response, sizeof(response)); } int cpin_attempts = 0; // AT+CPIN计数3次的计数器 void ML307A_NET_Init(void) { HAL_Delay(100); uint8_t step4g = 0;// 模组4G初始化步骤标志位 char response[256]; // 存放接收的响应数据 // if(Reset4G_flag) // { // Reset4G_flag = 0; // step4g = 0; // } switch(step4g) { case 0: { // if (sendCmd_4G("AT\r\n", "OK", 1, 4)) HAL_Delay(10); if (Send_Command_Check_Response("AT", response, sizeof(response))) { printf("AT_OK\r\n"); step4g++; // 进入下一步 }else { printf("AT_fail\r\n"); step4g++; } } case 1: { HAL_Delay(10); // if (sendCmd_4G("AT+CEREG?\r\n", "+CEREG:0,1", 1, 5)) if (Send_Command_Check_Response("AT+CEREG?", response, sizeof(response))) { printf("CEREG_OK\r\n"); HAL_Delay(500); step4g++; // 进入下一步 cpin_attempts = 0; // 重置计数器 } else { // cpin_attempts++; // 增加计数 // if (cpin_attempts >= 3) // 如果已经发送了3次 // { //// sendCmd_4G("AT+CGATT=1\r\n", "OK", 1, 5); // 手动驻网 // Send_Command_Check_Response("AT+CGATT=1", response, sizeof(response)); // HAL_Delay(100); // printf("CEREG_fail\r\n"); // cpin_attempts = 0; // 重置计数器 // } // Send_Command_Check_Response("AT+CGATT=1", response, sizeof(response)); HAL_Delay(100); printf("CEREG_fail\r\n"); step4g ++; } } case 2: { HAL_Delay(10); // sendCmd_4G("AT+CFUN=1\r\n", "OK", 1, 5); // 确保CFUN为1 // if(Send_Command_Check_Response("AT+CFUN=1", response, sizeof(response))) // { // HAL_Delay(100); // step4g++; // 进入下一步 // printf("AT+CFUN_ok\r\n"); // } step4g++; // 进入下一步 // else // { // step4g++; // 进入下一步 // printf("AT+CFUN_fail\r\n"); // } } case 3: { HAL_Delay(10); // 配置为自动连网(模组应用层网络) if(Send_Command_Check_Response("AT+MUECONFIG=\"autoconn\",1", response, sizeof(response))) { HAL_Delay(100); printf("AT+MUECONFIG_ok\r\n"); step4g++; // 进入下一步 } else { step4g++; // 进入下一步 printf("AT+MUECONFIG_fail\r\n"); } } case 4: { HAL_Delay(10); // 配置为自动拨号(上位机网卡拨号) if(Send_Command_Check_Response("AT+MDIALUPCFG=\"auto\",1", response, sizeof(response))) { HAL_Delay(100); step4g++; // 进入下一步 printf("AT+MDIALUPCFG_ok\r\n"); } else { step4g++; // 进入下一步 printf("AT+MDIALUPCFG_fail\r\n"); } } case 5: { HAL_Delay(10); ML307A_MQTT_Init(); // 初始化MQTT break; } case 7: { break; } } } /** * @breaf 重启模块 */ void ML307AReset(void) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET); HAL_Delay(500); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET); HAL_Delay(2000); Reset4G_flag = 1; printf("Reset_4G\n"); } void check_network_connection(void) { char response[100]; // 发送 AT+CREG? 查询网络注册状态 Send_Command_Check_Response("AT+CREG?", response, sizeof(response)); HAL_Delay(10); // 检查是否已注册到网络,通常返回 0,1 或 0,5 代表已连接 if (strstr(response, "0,1") == NULL && strstr(response, "0,5") == NULL) { // 如果未联网,执行联网操作 Send_Command_Check_Response("AT+CGATT=1", response, sizeof(response)); HAL_Delay(10); // 检查联网是否成功 Send_Command_Check_Response("AT+CGATT?", response, sizeof(response)); HAL_Delay(10); }else { ML307A_MQTT_Init(); } } void ML307A_GNSS(void) { sendCmd_4G("AT+CPIN?\r\n", "+CPIN: READY", 1, 5); }