//----------------------------说明 // 程序使用hal库,数据传输使用的串口,串口设置为发送+dma,接收+dma+空闲中断的模式 #include "EC800.h" //-----------------------------变量定义 //--------- ec800Date s_ec800Date = { .ip = "39.98.37.180", .port = 32449, .clientid = "NULL", .username = "hechun", .password = "admin123", // .username = "SZC30010-AE01", // .password = "qazSZC30010-AE01", }; messageDate s_messageDate = {0}; typedef struct{ uint8_t maxSpeed; // 服务器下发的允许最大车速 uint16_t year; // 上传时间 年 uint8_t month; // 上传时间 月 uint8_t day; // 上传时间 日 uint8_t hour; // 上传时间 时 uint8_t minute; // 上传时间 分 uint8_t sec; // 上传时间 秒 }recDate; recDate s_recDate = {0}; nmea_msg s_nmea_msg = {0}; nmea_utc_time s_nmea_utc_time = {0}; // AT指令响应超时时间定义 #define REC_TIMEOUT (10000) // 1ms /** * @brief 计算字符串的长度 * @param str: 所需计算字符串的指针 * @note * @retval 无 */ int EC800_calculateStringLength(const char* str) { int length = 0; while (str[length] != '\0') { length++; } return length; } /** * @brief 发送指令函数 * @param command: 指令 * @param enterNum: 进入函数次数,只有第一次的时候清除buff * @note * @retval 无 */ void EC800M_SendCommand(const char* command) { uint32_t stringLen = 0; stringLen = EC800_calculateStringLength(command); // 使用DMA // //等待发送状态OK // while(HAL_DMA_GetState(&hdma_usart3_tx) == HAL_DMA_STATE_BUSY) osDelay(1); // //发送数据 // HAL_UART_Transmit_DMA(&huart3, (uint8_t*)command, stringLen); // 不使用发送dma HAL_UART_Transmit(&huart4, (uint8_t*)command, stringLen, 1000); } /** * @brief 接收指令回复函数 * @param haystack: 接收的字符串数据 * @param needle: 正确回复的数据 * @note * @retval 无 */ char* EC800M_RecRespond(char *haystack, const char *needle ){ char* p = NULL; HAL_UART_Receive_DMA(&huart4, (uint8_t*)g_usart4_rx_buf, USART4_REC_LEN); //设置接收缓冲区 // __HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE); while(g_usart4_rx_sta == 0) osDelay(1); // __HAL_UART_DISABLE_IT(&huart4, UART_IT_IDLE); // 关闭空闲中断 g_usart4_rx_sta= 0; p = strstr(haystack, needle); memset(haystack, 0, USART4_REC_LEN); // 清除数据buff HAL_UART_DMAStop(&huart4); return p; } // 自定义的搜索函数 void* search_sequence(const void* haystack, size_t haystack_len, const void* needle, size_t needle_len) { const unsigned char* h = (const unsigned char*)haystack; const unsigned char* n = (const unsigned char*)needle; // 如果needle为空或haystack长度小于needle长度,则直接返回NULL if (needle_len == 0 || haystack_len < needle_len) { return NULL; } for (size_t i = 0; i <= haystack_len - needle_len; ++i) { size_t j; for (j = 0; j < needle_len; ++j) { if (h[i + j] != n[j]) { break; // 如果当前字符不匹配,则跳出内层循环 } } if (j == needle_len) { return (void*)(h + i); // 找到匹配的序列,返回其在haystack中的位置 } } // 如果遍历了整个haystack都没有找到匹配的序列,则返回NULL return NULL; } // 接收并比较响应字符串 uint8_t Accept_and_Compare_Str(const char* needle){ uint8_t temp = 0; static uint16_t timeOutCnt = 0; // 超时计数 HAL_UART_Receive_DMA(&huart4, (uint8_t*)g_usart4_rx_buf, USART4_REC_LEN); //设置接收缓冲区 // __HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE); while(!temp) { osDelay(1); if(search_sequence(g_usart4_rx_buf, USART4_REC_LEN, needle, strlen(needle))){ temp = 1; } if(search_sequence(g_usart4_rx_buf, USART4_REC_LEN, "ERROR", strlen("ERROR"))){ temp = 2; } if(timeOutCnt < REC_TIMEOUT){ timeOutCnt++; }else{ timeOutCnt = 0; temp = 3; } } g_usart4_rx_sta = 0; HAL_UART_DMAStop(&huart4); // __HAL_UART_DISABLE_IT(&huart4, UART_IT_IDLE); // 关闭空闲中断 return temp; } /** * @brief 接收使能函数 * @note * @retval 无 */ void EC800_recEnable(void){ HAL_UART_Receive_DMA(&huart4, (uint8_t*)g_usart4_rx_buf, USART4_REC_LEN); //设置接收缓冲区 __HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE); while(g_usart4_rx_sta == 0) osDelay(1); } /** * @brief 提取检查信号响应字符串字段中的信号量并进行信号判断 * @param data: 响应的信号量指针 * @note * @retval 无 */ static uint8_t EC800_extractSignal(char *data){ char *token; int field_1; // 使用strtok函数提取字段 token = strtok(data, ":,"); while (token != NULL) { field_1 = atoi(token); // 转换为整数类型 token = strtok(NULL, ":,"); memset(data, 0, USART4_REC_LEN); // 清除数据buff g_usart4_rx_sta = 0; // 清除接收状态 if (field_1 < 31) { return 1; } else { return 0; } } return 0; } /** * @brief 获取IMSI号 * @param 无 * @note * @retval 1: imsi没有获取到 0;imsi获取到 */ uint8_t EC800_getIMSI(void){ char* found = NULL; char number[16]; // 15 digits + 1 for null terminator int numberIndex = 0; int numberFound = 0; EC800M_SendCommand(AT_CIMI); EC800_recEnable(); found = strstr(g_usart4_rx_buf, AT_RESP_OK); if (found != NULL) { printf("IMSI is get\r\n"); }else{ printf("IMSI is not get\r\n"); return 1; } for (int i = 0; i < strlen(g_usart4_rx_buf); i++) { if (isdigit(g_usart4_rx_buf[i])) { number[numberIndex] = g_usart4_rx_buf[i]; numberIndex++; if (numberIndex >= 15) { numberFound = 1; break; } } } number[numberIndex] = '\0'; if (numberFound) { memcpy(s_messageDate.imsi, number, strlen(number)); printf("IMSI is: %s\n", number); } else { printf("Error: Unable to extract the number\n"); } return 0; } /** * @brief EC800M确认网络并链接MQTT服务器 * @param NONE * @note * @retval 无 */ uint8_t linkStep = 0; void EC800M_link(void){ uint8_t temp = 0; char command[100] = {0}; char errrCnt = 0; // 错误计数 switch(linkStep){ case 0: // 基础配置 EC800M_SendCommand(AT_CMD_TEST); if (Accept_and_Compare_Str(AT_RESP_OK) == 1) { printf("Module status normal\r\n"); }else{ errrCnt++; printf("Module status abnormal\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清除数据buff if(errrCnt == 0){ linkStep = 1; }else{ errrCnt = 0; } break; case 1: // 获取ISMI号 errrCnt = EC800_getIMSI(); if(errrCnt == 0){ linkStep = 2; }else{ errrCnt = 0; } break; case 2: EC800M_SendCommand(AT_CMD_ATE0); if (Accept_and_Compare_Str(AT_RESP_OK) == 1) { printf("Cancel module echo\r\n"); }else{ errrCnt++; printf("Failed to cancel module echo\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清除数据buff if(errrCnt == 0){ linkStep = 3; }else{ errrCnt = 0; } break; case 3: EC800M_SendCommand(AT_CMD_CPIN); if (Accept_and_Compare_Str(AT_RESP_CPIN_READY) == 1) { printf("SIM card normal\r\n"); }else{ errrCnt++; printf("SIM card abnormal\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清除数据buff if(errrCnt == 0){ linkStep = 4; }else{ errrCnt = 0; } break; case 4: EC800M_SendCommand(AT_CMD_CSQ); EC800_recEnable(); temp = EC800_extractSignal(g_usart4_rx_buf); if (temp) { printf("signal normal\r\n"); }else{ errrCnt++; printf("signal abnormal\r\n"); } if(errrCnt == 0){ linkStep = 5; }else{ errrCnt = 0; } break; case 5: EC800M_SendCommand(AT_CMD_CREG); // EC800_recEnable(); // // 使用字符串处理函数判断是否为正常状态 // if (strstr(g_usart4_rx_buf, "1") != NULL || strstr(g_usart4_rx_buf, "5") != NULL) { // printf("The module successfully registered on the GSM network\r\n"); // } else { // errrCnt++; // printf("The module failed to register on the GSM network\r\n"); // } if((Accept_and_Compare_Str("+CREG: 0,1") == 1) || (Accept_and_Compare_Str("+CREG: 0,5") == 1)){ printf("The module successfully registered on the GSM network\r\n"); }else{ errrCnt++; printf("The module failed to register on the GSM network\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清除数据buff g_usart4_rx_sta = 0; // 清除接收状态 if(errrCnt == 0){ linkStep = 6; }else{ errrCnt = 0; } break; case 6: EC800M_SendCommand(AT_CMD_QIDEACT); if (Accept_and_Compare_Str(AT_RESP_OK) == 1) { printf("Successfully disabled mobile scene\r\n"); }else{ errrCnt++; printf("Failed to disable mobile scene\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清除数据buff if(errrCnt == 0){ linkStep = 7; }else{ errrCnt = 0; } break; case 7: EC800M_SendCommand(AT_CMD_QIACT); if (Accept_and_Compare_Str(AT_RESP_OK) == 1) { printf("Successfully enabled mobile scene\r\n"); }else{ errrCnt++; printf("Failed to enable mobile scene\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清除数据buff if(errrCnt == 0){ linkStep = 8; }else{ errrCnt = 0; } break; case 8: // 连接mqtt服务器 sprintf(command, "AT+QMTCFG=\"qmtping\",0,%d\r\n", 30); EC800M_SendCommand(command); if (Accept_and_Compare_Str(AT_RESP_OK) == 1) { printf("MQTT heartbeat set successfully\r\n"); }else{ errrCnt++; printf("Failed to set MQTT heartbeat\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清除数据buff if(errrCnt == 0){ linkStep = 9; }else{ errrCnt = 0; } break; case 9: EC800M_SendCommand(AT_CMD_QMTCFG_SET_DATA_MODE); if (Accept_and_Compare_Str(AT_RESP_OK) == 1) { printf("Data receiving mode set successfully.\r\n"); }else{ errrCnt++; printf("Failed to set data receiving mode\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清除数据buff if(errrCnt == 0){ linkStep = 10; }else{ errrCnt = 0; } break; case 10: sprintf(command,"AT+QMTOPEN=0,\"%s\",%d\r\n", s_ec800Date.ip, s_ec800Date.port); EC800M_SendCommand(command); // found = EC800M_RecRespond(g_usart3_rx_buf, AT_RESP_OK); // found = EC800M_RecRespond(g_usart3_rx_buf, AT_RESP_QMTOPEN); // // if (found != NULL) { // printf("Successfully opened a network for the module\r\n"); // }else{ // errrCnt++; // printf("Failed to open a network for the module\r\n"); // } temp = Accept_and_Compare_Str(AT_RESP_QMTOPEN); memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清空输入缓冲区 if (temp == 1) { printf("Successfully opened a network for the module\r\n"); }else{ errrCnt++; printf("Failed to open a network for the module\r\n"); } if(errrCnt == 0){ linkStep = 11; }else{ errrCnt = 0; } break; case 11: sprintf(command,"AT+QMTCONN=0,%s,%s,%s\r\n",s_ec800Date.clientid, s_ec800Date.username, s_ec800Date.password); EC800M_SendCommand(command); if (Accept_and_Compare_Str(AT_RESP_QMTCONN) == 1) { printf("Successfully connected to the MQTT server\r\n"); }else{ errrCnt++; printf("Failed to connect to the MQTT server\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清空输入缓冲区 if(errrCnt == 0){ linkStep = 12; }else{ errrCnt = 0; } break; default: break; } } /** * @brief EC800M初始化GNSS * @param NONE * @note * @retval 无 */ uint8_t gnssStep = 0; void EC800_gnss_init(void){ char errrCnt = 0; // 错误计数 switch(gnssStep){ case 6: EC800M_SendCommand(AT_QGPS_0); if (Accept_and_Compare_Str(AT_RESP_OK) == 1) { printf("Turn off the GNSS module\r\n"); }else{ errrCnt++; printf("Failed to turn off the GNSS module\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清空输入缓冲区 if(errrCnt == 0){ gnssStep = 7; }else{ gnssStep = 7; } break; case 7: EC800M_SendCommand(AT_QGPS_1); if (Accept_and_Compare_Str(AT_RESP_OK) == 1) { printf("Turn on the GNSS module\r\n"); }else{ errrCnt++; printf("Failed to turn on the GNSS module\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清空输入缓冲区 if(errrCnt == 0){ gnssStep = 8; }else{ errrCnt = 0; } break; case 0: EC800M_SendCommand(AT_QGPSCFG_out_port); if (Accept_and_Compare_Str(AT_RESP_OK) == 1) { printf("Outputting NMEA Sentences via Serial Debugging\r\n"); }else{ errrCnt++; printf("The NMEA sentence output is set incorrectly\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清空输入缓冲区 if(errrCnt == 0){ gnssStep = 1; }else{ errrCnt = 0; } break; case 1: EC800M_SendCommand(AT_QGPSCFG_nmeasrc); if (Accept_and_Compare_Str(AT_RESP_OK) == 1) { printf("Enabling NMEA sentence retrieval via AT+QGPSGNMEA\r\n"); }else{ errrCnt++; printf("Failed to enable retrieving NMEA sentences via AT+QGPSGNMEA\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清空输入缓冲区 if(errrCnt == 0){ gnssStep = 2; }else{ errrCnt = 0; } break; case 2: EC800M_SendCommand(AT_QGPSCFG_gpsnmeatype); if (Accept_and_Compare_Str(AT_RESP_OK) == 1) { printf("Configuring the output type of NMEA sentences to all formats\r\n"); }else{ errrCnt++; printf("Failed to configure the output type of NMEA sentences to all formats\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清空输入缓冲区 if(errrCnt == 0){ gnssStep = 3; }else{ errrCnt = 0; } break; case 3: EC800M_SendCommand(AT_QGPSCFG_gnssconfig); if (Accept_and_Compare_Str(AT_RESP_OK) == 1) { printf("Configuring the supported GNSS satellite navigation systems to GPS+BeiDou\r\n"); }else{ errrCnt++; printf("Failed to configure the supported GNSS satellite navigation systems to GPS+BeiDou\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清空输入缓冲区 if(errrCnt == 0){ gnssStep = 4; }else{ errrCnt = 0; } break; case 4: EC800M_SendCommand(AT_QGPSCFG_autogps); if (Accept_and_Compare_Str(AT_RESP_OK) == 1) { printf("Disable GNSS auto-start\r\n"); }else{ errrCnt++; printf("Failed to disable GNSS auto-start\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清空输入缓冲区 if(errrCnt == 0){ gnssStep = 5; }else{ errrCnt = 0; } break; case 5: EC800M_SendCommand(AT_QGPSCFG_apflash); if (Accept_and_Compare_Str(AT_RESP_OK) == 1) { printf("Disable AP-Flash quick start function\r\n"); }else{ errrCnt++; printf("Failed to disable AP-Flash quick start function\r\n"); } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清空输入缓冲区 if(errrCnt == 0){ gnssStep = 6; }else{ errrCnt = 0; } break; default: break; } } //UTC时间转换为任意时区时间,如果是转换为北京时间,timezone传8即可 void utc_to_local_time(nmea_utc_time* utc_time, int8_t timezone, nmea_utc_time* local_time) { int year,month,day,hour; int lastday = 0; //last day of this month 本月天数 int lastlastday = 0; //last day of last month 上个月天数 year = utc_time->year; //utc time month = utc_time->month; day = utc_time->date; hour = utc_time->hour + timezone; //1月大,2月小,3月大,4月小,5月大,6月小,7月大,8月大,9月小,10月大,11月小,12月大 if(month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12) { lastday = 31;//本月天数 lastlastday = 30;//这里应该补上上个月的天数 if(month == 3) { if((year%400 == 0)||(year%4 == 0 && year%100 != 0))//if this is lunar year lastlastday = 29; else lastlastday = 28; } if(month == 8 || month == 1)//这里应该是8月和1月,因为8月和1月的上一个月(7月和12月)的天数是31天的 lastlastday = 31; } else if(month == 4 || month == 6 || month == 9 || month == 11) { lastday = 30; lastlastday = 31; } else { lastlastday = 31; if((year%400 == 0)||(year%4 == 0 && year%100 != 0)) lastday = 29; else lastday = 28; } if(hour >= 24)// if >24, day+1 { hour -= 24; day += 1; if(day > lastday)// next month, day-lastday of this month { day -= lastday; month += 1; if(month > 12)// next year, month-12 { month -= 12; year += 1; } } } if(hour < 0)// if <0, day-1 { hour += 24; day -= 1; if(day < 1)// month-1, day=last day of last month { day = lastlastday; month -= 1; if(month < 1)// last year, month=12 { month = 12; year -= 1; } } } // transfer value to local_time local_time->year = year; local_time->month = month; local_time->date = day; local_time->hour = hour; local_time->min = utc_time->min; local_time->sec = utc_time->sec; } /** * @brief 常用时间格式转时间戳 * @param NONE * @note * @retval 无 */ uint32_t EC800_mktime (unsigned int year, unsigned int mon, unsigned int day, unsigned int hour, unsigned int min, unsigned int sec) { if (0 >= (int) (mon -= 2)){ /**//* 1..12 -> 11,12,1..10 */ mon += 12; /**//* Puts Feb last since it has leap day */ year -= 1; } return ((( (unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) + year*365 - 719499 )*24 + hour /**//* now have hours */ )*60 + min /**//* now have minutes */ )*60 + sec; /**//* finally seconds */ } /** * @brief 读取GNSS的数据 * @param NONE * @note * @retval 无 */ void EC800_readGnssDate(void){ EC800M_SendCommand(AT_QGPSGNMEA_RMC); // EC800_recEnable(); // found = strstr(g_usart4_rx_buf, AT_RESP_OK); if (Accept_and_Compare_Str(AT_RESP_OK) == 1) { printf("Location information received successfully\r\n"); }else{ printf("Location information reception failed\r\n"); return ; } printf("Location information:%s\r\n", g_usart4_rx_buf); NMEA_GNRMC_Analysis(&s_nmea_msg, (uint8_t*)g_usart4_rx_buf); utc_to_local_time(&(s_nmea_msg.utc), 8, &s_nmea_utc_time); printf("timer-%d/%d/%d %d:%d:%d\r\n",s_nmea_utc_time.year,s_nmea_utc_time.month,s_nmea_utc_time.date,s_nmea_utc_time.hour,s_nmea_utc_time.min,s_nmea_utc_time.sec); s_messageDate.Timestamp = EC800_mktime(s_nmea_utc_time.year,s_nmea_utc_time.month,s_nmea_utc_time.date,s_nmea_utc_time.hour,s_nmea_utc_time.min,s_nmea_utc_time.sec); g_usart3_rx_sta= 0; memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清除数据buff printf("latitude:%d%d--longitude:%d%d\r\n", s_nmea_msg.latitude, s_nmea_msg.nshemi, s_nmea_msg.longitude, s_nmea_msg.ewhemi); /* 尝试获取互斥量,等待无限长时间 */ if(osMutexAcquire(s_messageDate_locationHandle, osWaitForever) == osOK) { /* 安全地访问s_rs485RecDate结构体 */ s_messageDate.latitude = s_nmea_msg.latitude; s_messageDate.nshemi = s_nmea_msg.nshemi; s_messageDate.longitude = s_nmea_msg.longitude; s_messageDate.ewhemi = s_nmea_msg.ewhemi; /* 访问完成,释放互斥量 */ osMutexRelease(s_messageDate_locationHandle); } } /** * @brief EC800M订阅主题 * @param topic1: 订阅的主题名称1字符串形式 * @param topic2: 订阅的主题名称2字符串形式 * @note * @retval 无 */ uint8_t EC800_subscribeToTopic(const char* topic1){ char command[100] = {0}; uint8_t recTemp = 0; sprintf(command, "AT+QMTSUB=0,1,\"%s\",0\r\n", topic1); EC800M_SendCommand(command); recTemp = Accept_and_Compare_Str(AT_RESP_QMTSUB); memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清空输入缓冲区 if (recTemp == 1) { printf("Subscription to the topic successful\r\n"); return 1; }else if (recTemp == 2){ printf("Subscription to the topic failed\r\n"); return 0; } return 0; } /** * @brief EC800M发布消息 * @param topic: 消息发布的主题 字符串形式 * @param message: 发布的消息 字符串形式 * @param len: 发布消息的字节长度 * @note * @retval 无 */ uint8_t EC800_publishMessage(const char* topic, const char* message, uint16_t len){ char command[100] = {0}; char* responseCmd = ">"; static uint8_t publishStep = 0; uint8_t recBack = 0; switch(publishStep){ case 0: sprintf(command,"AT+QMTPUBEX=0,0,0,0,\"%s\",%d\r\n",topic,len); EC800M_SendCommand(command); // found = EC800M_RecRespond(g_usart4_rx_buf, responseCmd); if (Accept_and_Compare_Str(responseCmd) == 1) { printf("The topic has been linked\r\n"); publishStep = 1; }else{ printf("The topic link failed\r\n"); publishStep = 0; } // break; case 1: EC800M_SendCommand(message); // found = EC800M_RecRespond(g_usart3_rx_buf, AT_RESP_OK); // found = EC800M_RecRespond(g_usart3_rx_buf, AT_RESP_QMTPUBEX); // if (found != NULL) { // printf("The message has been successfully posted\r\n"); // publishStep = 0; // }else{ // printf("Message publication failed\r\n"); // publishStep = 0; // } recBack = Accept_and_Compare_Str(AT_RESP_QMTPUBEX); memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清空输入缓冲区 if (recBack == 1) { publishStep = 0; printf("The message has been successfully posted\r\n"); }else{ printf("Message publication failed\r\n"); publishStep = 0; } break; default: break; } return recBack; } /** * @brief 登录 topic * @param NONE * @note topic 101 * @retval 无 */ uint8_t Login_Topic(void){ cJSON *root = NULL; char *jsonString = NULL; uint8_t temp = 0; char command[50] = {0}; // 定义对象 { } root = cJSON_CreateObject(); // 插入元素,对应 键值对 cJSON_AddItemToObject(root, "msgType", cJSON_CreateString("json")); cJSON_AddItemToObject(root, "imsi", cJSON_CreateString(s_messageDate.imsi)); cJSON_AddItemToObject(root, "hardVersion", cJSON_CreateString(HARD_VERSION)); cJSON_AddItemToObject(root, "softVersion", cJSON_CreateString(SOFT_VERSION)); sprintf(command, "%x%x%x", s_messageDate.devId[0], s_messageDate.devId[1], s_messageDate.devId[2]); cJSON_AddItemToObject(root, "devId", cJSON_CreateString(command)); cJSON_AddItemToObject(root, "protocolVersion", cJSON_CreateString(PROTOCOL_VERSION)); cJSON_AddItemToObject(root, "devType", cJSON_CreateNumber(DEV_TYPE)); cJSON_AddItemToObject(root, "txnNo", cJSON_CreateNumber(s_messageDate.Timestamp)); // 将 JSON 对象转换为字符串 jsonString = cJSON_Print(root); cJSON_Delete(root); temp = EC800_publishMessage("toServer/mqtt/101", jsonString, strlen(jsonString)); free(jsonString); return temp; } /** * @brief 下位机请求围栏数据 * @param NONE * @note topic 604 * @retval 无 */ uint8_t requesting_Fence_Data(void){ cJSON *root = NULL; char *jsonString = NULL; uint8_t temp = 0; char command[50] = {0}; // 定义对象 { } root = cJSON_CreateObject(); // 插入元素,对应 键值对 cJSON_AddItemToObject(root, "msgType", cJSON_CreateString("json")); cJSON_AddItemToObject(root, "imsi", cJSON_CreateString(s_messageDate.imsi)); cJSON_AddItemToObject(root, "hardVersion", cJSON_CreateString(HARD_VERSION)); cJSON_AddItemToObject(root, "softVersion", cJSON_CreateString(SOFT_VERSION)); sprintf(command, "%x%x%x", s_messageDate.devId[0], s_messageDate.devId[1], s_messageDate.devId[2]); cJSON_AddItemToObject(root, "devId", cJSON_CreateString(command)); // cJSON_AddItemToObject(root, "vin", cJSON_CreateString((char *)s_messageDate.VIN)); cJSON_AddItemToObject(root, "vin", cJSON_CreateString("5Xt2Aq8Jb9L")); cJSON_AddItemToObject(root, "protocolVersion", cJSON_CreateString(PROTOCOL_VERSION)); cJSON_AddItemToObject(root, "txnNo", cJSON_CreateNumber(s_messageDate.Timestamp)); cJSON_AddItemToObject(root, "devType", cJSON_CreateNumber(DEV_TYPE)); // 将 JSON 对象转换为字符串 jsonString = cJSON_Print(root); cJSON_Delete(root); temp = EC800_publishMessage("toServer/mqtt/604", jsonString, strlen(jsonString)); free(jsonString); return temp; } /** * @brief EC800M与服务器进行时间对时 * @note * @retval 无 */ uint8_t EC800_time_calibration(void){ cJSON *root = NULL; char *jsonString = NULL; uint8_t temp = 0; char command[50] = {0}; // 定义对象 { } root = cJSON_CreateObject(); // 插入元素,对应 键值对 cJSON_AddItemToObject(root, "msgType", cJSON_CreateString("json")); cJSON_AddItemToObject(root, "imsi", cJSON_CreateString(s_messageDate.imsi)); cJSON_AddItemToObject(root, "hardVersion", cJSON_CreateString(HARD_VERSION)); cJSON_AddItemToObject(root, "softVersion", cJSON_CreateString(SOFT_VERSION)); sprintf(command, "%x%x%x", s_messageDate.devId[0], s_messageDate.devId[1], s_messageDate.devId[2]); cJSON_AddItemToObject(root, "devId", cJSON_CreateString(command)); cJSON_AddItemToObject(root, "protocolVersion", cJSON_CreateString(PROTOCOL_VERSION)); cJSON_AddItemToObject(root, "txnNo", cJSON_CreateNumber(s_messageDate.Timestamp)); cJSON_AddItemToObject(root, "devType", cJSON_CreateNumber(DEV_TYPE)); // 将 JSON 对象转换为字符串 jsonString = cJSON_Print(root); cJSON_Delete(root); temp = EC800_publishMessage("toServer/mqtt/105", jsonString, strlen(jsonString)); free(jsonString); return temp; } /** * @brief 将服务器响应的字符串中的年月日进行分离 * @note * @retval 无 */ void parseServerTime(char* str){ char year[5]; char month[3]; char day[3]; char hour[3]; char minute[3]; char second[3]; strncpy(year, str, 4); year[4] = '\0'; strncpy(month, str + 4, 2); month[2] = '\0'; strncpy(day, str + 6, 2); day[2] = '\0'; strncpy(hour, str + 8, 2); hour[2] = '\0'; strncpy(minute, str + 10, 2); minute[2] = '\0'; strncpy(second, str + 12, 2); second[2] = '\0'; s_recDate.year = atoi(year); s_recDate.month = atoi(month); s_recDate.day = atoi(day); s_recDate.hour = atoi(hour); s_recDate.minute = atoi(minute); s_recDate.sec = atoi(second); s_messageDate.Timestamp = EC800_mktime(s_recDate.year,s_recDate.month,s_recDate.day,s_recDate.hour,s_recDate.minute,s_recDate.sec); printf("Year (int): %d\n", s_recDate.year); printf("Month (int): %d\n", s_recDate.month); printf("Day (int): %d\n", s_recDate.day); printf("Hour (int): %d\n", s_recDate.hour); printf("Minute (int): %d\n", s_recDate.minute); printf("Second (int): %d\n", s_recDate.sec); } /** * @brief 解析对时数据帧的响应 * @note * @retval 无 */ void EC800_parseRespondTime(cJSON *root, cJSON *item){ uint8_t temp = 0; // 获取"resultCode"字段的值 item = cJSON_GetObjectItem(root, "resultCode"); if (item == NULL) { printf("Field \"resultCode\" not found\n"); }else{ // 打印"resultCode"字段的值 printf("resultCode: %d\n", item->valueint); if((item->valueint) == 1){ printf("The upload of synchronized data was successful.\n"); temp = 1; // 上传成功 }else{ printf("The upload of synchronized data has failed.\n"); } } if(temp == 1){ item = cJSON_GetObjectItem(root, "serverTime"); if (item == NULL) { printf("Field \"serverTime\" not found\n"); }else{ // 打印"serverTime"字段的值 printf("serverTime: %s\n", item->valuestring); parseServerTime(item->valuestring); } } } /** * @brief EC800M上传实时数据 * @note * @retval 无 */ uint8_t EC800_uploadRealDate(void){ cJSON *root = NULL; char *jsonString = NULL; cJSON *rt000 = NULL; cJSON *rt000Object1 = NULL; uint8_t temp = 0; char command[50] = {0}; // 定义对象 { } root = cJSON_CreateObject(); // // 插入元素,对应 键值对 cJSON_AddItemToObject(root, "msgType", cJSON_CreateString("json")); cJSON_AddItemToObject(root, "imsi", cJSON_CreateString(s_messageDate.imsi)); cJSON_AddItemToObject(root, "hardVersion", cJSON_CreateString(HARD_VERSION)); cJSON_AddItemToObject(root, "softVersion", cJSON_CreateString(SOFT_VERSION)); sprintf(command, "%x%x%x", s_messageDate.devId[0], s_messageDate.devId[1], s_messageDate.devId[2]); cJSON_AddItemToObject(root, "devId", cJSON_CreateString(command)); cJSON_AddItemToObject(root, "protocolVersion", cJSON_CreateString(PROTOCOL_VERSION)); cJSON_AddItemToObject(root, "txnNo", cJSON_CreateNumber(s_messageDate.Timestamp)); cJSON_AddItemToObject(root, "devType", cJSON_CreateNumber(DEV_TYPE)); // 定义 { } 对象 rt000Object1 = cJSON_CreateObject(); cJSON_AddItemToObject(rt000Object1, "rt003", cJSON_CreateNumber(s_messageDate.vehicleStatus)); cJSON_AddItemToObject(rt000Object1, "rt025", cJSON_CreateNumber(s_messageDate.demandVol)); cJSON_AddItemToObject(rt000Object1, "rt026", cJSON_CreateNumber(s_messageDate.demandCur)); cJSON_AddItemToObject(rt000Object1, "rt027", cJSON_CreateString((char *)s_messageDate.VIN)); cJSON_AddItemToObject(rt000Object1, "rt028", cJSON_CreateString(s_messageDate.lat_long_data)); cJSON_AddItemToObject(rt000Object1, "rt029", cJSON_CreateNumber(s_messageDate.drivDirection)); cJSON_AddItemToObject(rt000Object1, "rt030", cJSON_CreateNumber(s_messageDate.vehicleSpeed)); cJSON_AddItemToObject(rt000Object1, "rt031", cJSON_CreateNumber(s_messageDate.dailyDrivTime)); cJSON_AddItemToObject(rt000Object1, "rt032", cJSON_CreateNumber(s_messageDate.dailyDrivMileage)); cJSON_AddItemToObject(rt000Object1, "rt033", cJSON_CreateNumber(s_messageDate.accTotalDrivTime_h_min)); cJSON_AddItemToObject(rt000Object1, "rt034", cJSON_CreateNumber((s_messageDate.accTotalMileage_h << 16) + s_messageDate.accTotalMileage_l)); cJSON_AddItemToObject(rt000Object1, "rt035", cJSON_CreateNumber(s_messageDate.runTime)); // 定义 [ ] 数组 rt000 = cJSON_CreateArray(); // 往数组中添加元素 cJSON_AddItemToArray(rt000, rt000Object1); // 将子项插入根项中 cJSON_AddItemToObject(root, "rt000", rt000); // // 将 JSON 对象转换为字符串 jsonString = cJSON_Print(root); cJSON_Delete(root); temp = EC800_publishMessage("toServer/mqtt/201", jsonString, strlen(jsonString)); free(jsonString); return temp; } /** * @brief 解析实时数据响应 * @note * @retval 无 */ void EC800_respondRealDate(cJSON *root, cJSON *item){ // 获取"name"字段的值 item = cJSON_GetObjectItem(root, "resultCode"); if (item == NULL) { printf("Field \"resultCode\" not found\n"); }else{ // 打印"name"字段的值 printf("resultCode: %d\n", item->valueint); if((item->valueint) == 1){ printf("Uploaded real-time data successfully\n"); }else{ printf("The upload of real-time data has failed\n"); } } } /** * @brief 解析升級数据 * @note * @retval 无 */ void EC800_respondUpdateDate(cJSON *root, cJSON *item, ftpInfo *p_ftpInfo){ /* 获取address对象 */ cJSON *hardwareUpdate = cJSON_GetObjectItem(root, "paramList"); if (hardwareUpdate == NULL) { printf("Failed to parse paramList data\n"); return ; } // 获取"name"字段的值 item = cJSON_GetObjectItem(hardwareUpdate, "function"); if (item == NULL) { printf("Field \"update\" not found\n"); }else{ // 打印"name"字段的值 printf("function: %d\n", item->valueint); // 1:表示固件更新 当后台下发升级指令,并且行车状态为静止态允许更新固件 if(((item->valueint) == 1) && (s_comData.driveStatus == 0x02)){ s_ec800Date.hardwareUpdate = 1; // 更新固件 printf("update begin\n"); }else{ printf("no update\n"); } } // 获取"ftpAddr"字段的值 item = cJSON_GetObjectItem(hardwareUpdate, "ftpAddr"); if (item == NULL) { printf("Field \"ftpAddr\" not found\n"); }else{ printf("ftpAddr: %s\n", item->valuestring); /* 复制字符串到ftpInfo结构体的ftpAddr成员 */ strncpy(p_ftpInfo->ftpAddr, item->valuestring, sizeof(p_ftpInfo->ftpAddr) - 1); /* 确保字符串以空字符结尾 */ p_ftpInfo->ftpAddr[sizeof(p_ftpInfo->ftpAddr) - 1] = '\0'; } // 获取"ftpPort"字段的值 item = cJSON_GetObjectItem(hardwareUpdate, "ftpPort"); if (item == NULL) { printf("Field \"ftpPort\" not found\n"); }else{ // 打印"name"字段的值 printf("ftpPort: %d\n", item->valueint); p_ftpInfo->ftpPort = item->valueint; } // 获取"account"字段的值 item = cJSON_GetObjectItem(hardwareUpdate, "account"); if (item == NULL) { printf("Field \"account\" not found\n"); }else{ printf("account: %s\n", item->valuestring); /* 复制字符串到ftpInfo结构体的ftpAddr成员 */ strncpy(p_ftpInfo->account, item->valuestring, sizeof(p_ftpInfo->ftpAddr) - 1); /* 确保字符串以空字符结尾 */ p_ftpInfo->ftpAddr[sizeof(p_ftpInfo->account) - 1] = '\0'; } // 获取"passWord"字段的值 item = cJSON_GetObjectItem(hardwareUpdate, "passWord"); if (item == NULL) { printf("Field \"passWord\" not found\n"); }else{ printf("account: %s\n", item->valuestring); /* 复制字符串到ftpInfo结构体的ftpAddr成员 */ strncpy(p_ftpInfo->passWord, item->valuestring, sizeof(p_ftpInfo->ftpAddr) - 1); /* 确保字符串以空字符结尾 */ p_ftpInfo->ftpAddr[sizeof(p_ftpInfo->passWord) - 1] = '\0'; } // 获取"passWord"字段的值 item = cJSON_GetObjectItem(hardwareUpdate, "textDirectory"); if (item == NULL) { printf("Field \"textDirectory\" not found\n"); }else{ printf("textDirectory: %s\n", item->valuestring); /* 复制字符串到ftpInfo结构体的ftpAddr成员 */ strncpy(p_ftpInfo->textDirectory, item->valuestring, sizeof(p_ftpInfo->ftpAddr) - 1); /* 确保字符串以空字符结尾 */ p_ftpInfo->ftpAddr[sizeof(p_ftpInfo->textDirectory) - 1] = '\0'; } // 获取"passWord"字段的值 item = cJSON_GetObjectItem(hardwareUpdate, "textName"); if (item == NULL) { printf("Field \"textName\" not found\n"); }else{ printf("textName: %s\n", item->valuestring); /* 复制字符串到ftpInfo结构体的ftpAddr成员 */ strncpy(p_ftpInfo->textName, item->valuestring, sizeof(p_ftpInfo->ftpAddr) - 1); /* 确保字符串以空字符结尾 */ p_ftpInfo->ftpAddr[sizeof(p_ftpInfo->textName) - 1] = '\0'; } } /** * @brief 解析围栏经纬度数据 * @note * @param root: cJSON 根对象 * @param Latitude: 纬度数组 * @param Longitude: 经度数组 * @retval 成功返回1,失败返回0 */ int parse_Latitude_Longitude_Data(cJSON *root, double Latitude[], double Longitude[]) { // 确保输入不为空 if (root == NULL) { printf("Root object is NULL\n"); return 0; } // 获取 polygonLat 数组 cJSON *polygonLat = cJSON_GetObjectItem(root, "polygonLat"); if (polygonLat == NULL || polygonLat->type != cJSON_Array) { printf("polygonLat is not an array or is missing\n"); return 0; } // 获取 polygonLng 数组 cJSON *polygonLng = cJSON_GetObjectItem(root, "polygonLon"); if (polygonLng == NULL || polygonLat->type != cJSON_Array) { printf("polygonLng is not an array or is missing\n"); return 0; } // 获取数组大小并检查是否匹配和是否超出预定义的最大大小 int polygonLatSize = cJSON_GetArraySize(polygonLat); int polygonLngSize = cJSON_GetArraySize(polygonLng); if (polygonLatSize != polygonLngSize || polygonLatSize > REC_COORDINATE_DEPTH) { printf("Array sizes mismatch or exceed maximum allowed size\n"); return 0; } // 解析 polygonLat 数组 for (int i = 0; i < polygonLatSize; ++i) { cJSON *latItem = cJSON_GetArrayItem(polygonLat, i); if (latItem == NULL || latItem->type != cJSON_Number) { printf("Lat item is not a number or is missing\n"); return 0; } Latitude[i] = latItem->valuedouble; } // 解析 polygonLng 数组 for (int i = 0; i < polygonLngSize; ++i) { cJSON *lngItem = cJSON_GetArrayItem(polygonLng, i); if (lngItem == NULL || lngItem->type != cJSON_Number) { printf("Lng item is not a number or is missing\n"); return 0; } Longitude[i] = lngItem->valuedouble; } return 1; // 成功 } /** * @brief 解析登录响应 * @note * @return */ void parse_Login_Response(cJSON *root, cJSON *item){ // 获取"name"字段的值 item = cJSON_GetObjectItem(root, "resultCode"); if (item == NULL) { printf("Field \"resultCode\" not found\n"); }else{ // 打印"name"字段的值 printf("resultCode: %d\n", item->valueint); if((item->valueint) == 1){ s_messageDate.loginResult = 1; // 登录成功 printf("Login response data successfully\n"); }else{ printf("Login response has failed\n"); } } } /** * @brief 通信响应解析 * @param p_ec800Date: ec800Date结构体的指针数据 * @note * @return 当前的控制命令 */ short EC800_respondParse(ec800Date *p_ec800Date){ cJSON *root = NULL; cJSON *item = NULL; uint8_t rec_back = 0; uint16_t cmd = 0; // 找到JSON数据的起始位置 const char* start = strchr(g_usart4_rx_buf, '{'); if (start == NULL) { printf("JSON data not found\n"); return 0; } // 解析JSON数据 root = cJSON_Parse(start); if (root == NULL) { printf("Failed to parse JSON data\n"); cJSON_Delete(root); return 0; } // 获取"controlCode"字段的值 item = cJSON_GetObjectItem(root, "controlCode"); if (item == NULL) { printf("Field \"devId\" not found\n"); }else{ // 打印"controlCode"字段的值 printf("controlCode: %d\n", item->valueint); cmd = item->valueint; } // 解析对应命令的对应数据 switch(cmd){ case 102: parse_Login_Response(root, item); break; case 106: EC800_parseRespondTime(root, item); break; case 202: EC800_respondRealDate(root, item); break; case 602: EC800_respondUpdateDate(root, item, &s_ftpInfo); break; case 605: rec_back = parse_Latitude_Longitude_Data(root, polygonLat, polygonLng); if(rec_back == 1){ // 接收成功 p_ec800Date->fenceRecSuccess = 1; } break; default : break; } cJSON_Delete(root); return (cmd); } /** * @brief EC800M状态转换与使用 * @note * @retval 无 */ uint8_t stateStep = 0; void EC800_stateTransition_use(void){ uint16_t right = 1; // 返回是否为正确 static uint16_t timesCnt = 0; static uint8_t tudeErrcnt = 0; // 定位信息错误计数 ec800Date *p_ec800Date = &s_ec800Date; char command[100] = {0}; static uint8_t respondSt = 0; // 响应状态指示 1: 为等待响应 2:成功响应 static uint8_t timeoutCnt = 0; // 超时计数 switch(stateStep){ case 0: // 初始化模块 EC800M_link(); if(linkStep == 12){ stateStep = 1; p_ec800Date->ec800InitFlag = 1; // 初始化完成 }else{ p_ec800Date->ec800InitFlag = 0; // 初始化未完成 } break; case 1: // 初始化GNSS EC800_gnss_init(); if(gnssStep == 8){ stateStep = 2; } break; case 2: // 订阅主题 sprintf(command, "toclient/%d/%x%x%x", DEV_TYPE, s_messageDate.devId[0], s_messageDate.devId[1], s_messageDate.devId[2]); right = EC800_subscribeToTopic(command); if(right != 1){ // 发布消息失败,可能断开链接 // stateStep = 0; // 重新初始化 }else{ stateStep = 3; } break; case 3: // 登录服务器主题 right = Login_Topic(); if(right == 1){ respondSt = 1; // 等待响应 stateStep = 8; // 去步骤6等待登录响应 收到登录响应后,发布实时消息 } break; case 4: // 下位机请求围栏数据 if(s_comData.vinRecSuccess == 1){ // 成功接收到车辆vin right = requesting_Fence_Data(); if(right == 1){ respondSt = 1; // 等待响应 stateStep = 8; // 去步骤6等待登录响应 收到登录响应后,发布实时消息 } }else{ // 初始化时与车通信故障 跳转上传实时信息,上报故障,跳过围栏获取 if(BIT_CHECK(s_comData.Malfunction, com485)){ stateStep = 5; } } break; case 5: // 获取定位信息 EC800_readGnssDate(); // 没有获取到定位信息 重复获取三次 if((s_messageDate.latitude == 0) && (s_messageDate.longitude == 0)){ tudeErrcnt++; if(tudeErrcnt == 4){ tudeErrcnt = 0; stateStep = 6; } }else{ tudeErrcnt = 0; stateStep = 6; } break; case 6: // 与服务器对时 right = EC800_time_calibration(); if(right == 1){ respondSt = 1; // 等待响应 stateStep = 8; // 去步骤6等待对时响应 收到对时响应后,发布实时消息 } break; case 7: // 发布消息 right = EC800_uploadRealDate(); stateStep = 8; // if(right == 0){ // 发布消息失败,可能断开链接 // stateStep = 0; // 重新初始化 // linkStep = 0; // stateStep = 6; // }else if(right == 1){ // stateStep = 6; // } break; case 8: // 接收消息 HAL_UART_Receive_DMA(&huart4, (uint8_t*)g_usart4_rx_buf, USART4_REC_LEN); //设置接收缓冲区 // __HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE); if(g_usart4_rx_sta!=0){ HAL_UART_Transmit(&huart1, (uint8_t*)g_usart4_rx_buf, strlen(g_usart4_rx_buf), HAL_MAX_DELAY); // 打印数据除去URC right = EC800_respondParse(&s_ec800Date); if((right == CTR_CODE_LOGIN) && (s_messageDate.loginResult == 1)){ // 登录响应 stateStep = 4; right = 0; timesCnt = 0; respondSt = 2; // 成功响应 }else if(right == CTR_CODE_LOGIN){ // 登录响应 未登录成功 stateStep = 3; right = 0; timesCnt = 0; respondSt = 2; // 成功响应 }else if(right == CTR_CODE_FENCES){ // 围栏数据响应 stateStep = 5; right = 0; timesCnt = 0; respondSt = 2; // 成功响应 } else if(right == CTR_CODE_JUDETIME){ // 对时响应 stateStep = 7; right = 0; timesCnt = 0; respondSt = 2; // 成功响应 }else if(right == CTR_CODE_REMOTE){ // 固件更新 stateStep = 0xff; // 停止占用4G模块 } memset(g_usart4_rx_buf, 0, USART4_REC_LEN); // 清除数据buff,接收新的数据 g_usart4_rx_sta = 0; // 清除接收状态 } // 转弯行驶中 if(turnFlag == 1){ if(timesCnt < TURN_INTERVAL_TIME_MS){ timesCnt++; }else{ timesCnt= 0; stateStep = 5; HAL_UART_DMAStop(&huart4); // __HAL_UART_DISABLE_IT(&huart4, UART_IT_IDLE); } }else{ // 正常行驶中 if(timesCnt < PUBLISH_TIME_MS){ timesCnt++; }else{ timesCnt= 0; stateStep = 5; HAL_UART_DMAStop(&huart4); // __HAL_UART_DISABLE_IT(&huart4, UART_IT_IDLE); } } // 通信超时判断 if(respondSt == 1){ // 等待响应状态 if(timeoutCnt < PUBLISH_TIME_MS){ timeoutCnt ++; }else{ timeoutCnt = PUBLISH_TIME_MS; BIT_SET(s_comData.Malfunction, errorMqtt); // 置位MQTT故障 } } break; default: break; } }