ML307A.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119
  1. #include "ML307A.h"
  2. #include "usart.h"
  3. #include "circle_buffer.h"
  4. #include "rtc.h"
  5. #include <stdio.h> //printf
  6. #include <string.h>
  7. #include <stdbool.h> // bool
  8. #include "cmsis_os.h"
  9. #include "main.h"
  10. #include "queue.h"
  11. #include "uType.h"
  12. #include "remote.h"
  13. extern circle_buf_t uart3CircleBuf; // 环形缓冲区管理结构体
  14. //extern circle_buf_t_2 uart3CircleBuf_2; // 环形缓冲区管理结构体
  15. #define BUFFER_SIZE4G 512
  16. extern uint8_t receiveBuff4G[BUFFER_SIZE4G];
  17. char responseBuf[256]; // AT指令应答的局部缓冲区
  18. char responseBuf_2[256]; // AT指令应答的局部缓冲区
  19. //static uint8_t uart3ParseBuf[BUFFER_SIZE4G]; // 解析+MIPURC: "rtcp"的缓冲区
  20. //static uint16_t parseIndex = 0; // 解析+MIPURC: "rtcp"的缓冲区指针
  21. extern uint8_t receiveBuff4G_MIPURC[BUFFER_SIZE4G];
  22. extern osMessageQueueId_t uart3rxqueueHandle;
  23. bool MgnssFlag = false;// GNSS定位信息上报成功标志位
  24. uint8_t Reset4G_flag = 0;
  25. #define MAX_HEX_DATA_LEN 256 // 假设最多解析 256 字节的 HEX 数据
  26. uint8_t parsed_4GMIPURC_Data[MAX_HEX_DATA_LEN];
  27. extern bool flash_save_parameter_flag;
  28. uint16_t msg_serial = 0;
  29. extern volatile bool heartbeat_reply_received;
  30. extern volatile bool unixtime_reply_received;
  31. /**
  32. * @breaf 封装串口发送4G AT命令函数
  33. */
  34. void USART_SendString(UART_HandleTypeDef *huart,char *str)
  35. {
  36. // HAL_UART_Transmit(huart, (uint8_t*)str, strlen(str), 0xFFFF);
  37. HAL_UART_Transmit_DMA(huart, (uint8_t*)str, strlen(str));
  38. }
  39. /**
  40. * @breaf 发送4G串口命令
  41. */
  42. /*
  43. uint8_t sendCmd_4G(char *pCmd, char *pRes, uint32_t timeOut, uint8_t sendNum)
  44. {
  45. uint8_t i = 0;
  46. uint32_t time;
  47. // uint8_t found = 0;
  48. for (i = 0; i < sendNum; i++)
  49. {
  50. time = timeOut * 10; // 将超时时间转换为循环次数
  51. memset(receiveBuff4G, 0, sizeof(receiveBuff4G)); // 清空接收缓冲区
  52. USART_SendString(&huart3, pCmd); // 发送命令字符串
  53. // HAL_Delay(100);
  54. osDelay(100);
  55. while (time--)
  56. {
  57. if (strstr((const char *)receiveBuff4G, pRes) != NULL)
  58. {
  59. printf("-- %s\n", receiveBuff4G); // 打印接收到的内容
  60. //如果接收缓冲区包含预期的响应
  61. return 1;
  62. }
  63. // HAL_Delay(100);
  64. osDelay(100);
  65. }
  66. printf("! %s\n", receiveBuff4G);
  67. }
  68. return 0;
  69. }
  70. */
  71. uint8_t sendCmd_4G(char *pCmd, char *pRes1, uint32_t timeOut, uint8_t sendNum)
  72. {
  73. uint8_t i;
  74. uint32_t time;
  75. uint8_t receivedByte;
  76. memset(responseBuf, 0, sizeof(responseBuf)); // 清空临时缓冲区
  77. for (i = 0; i < sendNum; i++)
  78. {
  79. time = timeOut * 10; // 计算超时时间
  80. // ★ 发送前丢弃旧数据 ★
  81. __HAL_UART_DISABLE_IT(&huart3, UART_IT_IDLE); // 可选:保护指针修改
  82. uart3CircleBuf.r = uart3CircleBuf.w; // 丢弃旧数据
  83. __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
  84. //printf("send command: %s\r\n", pCmd);
  85. USART_SendString(&huart3, pCmd); // 发送 AT 指令
  86. osDelay(100); // 等待模块返回(短暂延时)
  87. while (time--)
  88. {
  89. uint8_t gotNewData = 0;
  90. // 读取环形缓冲区内的新数据
  91. while (circle_buf_read(&uart3CircleBuf, &receivedByte) == 0)
  92. {
  93. gotNewData = 1;
  94. uint16_t len = strlen(responseBuf);
  95. if (len < sizeof(responseBuf) - 1)
  96. {
  97. responseBuf[len] = receivedByte;
  98. responseBuf[len + 1] = '\0'; // 字符串结束符
  99. }
  100. }
  101. if (gotNewData)
  102. {
  103. // ★ 判断是否匹配 ★
  104. if (pRes1 && strstr(responseBuf, pRes1) != NULL)
  105. {
  106. // printf("-: %s\n", responseBuf);
  107. return 1; // 任意一个匹配成功
  108. }
  109. }
  110. osDelay(10);
  111. }
  112. printf("Timeout_!: %s\n", responseBuf); // 超时打印
  113. }
  114. return 0;
  115. }
  116. uint8_t sendCmd_4G_2(char *pCmd, char *pRes1, char *pRes2, uint32_t timeOut, uint8_t sendNum)
  117. {
  118. uint8_t i;
  119. uint32_t time;
  120. uint8_t receivedByte;
  121. memset(responseBuf_2, 0, sizeof(responseBuf_2)); // 清空临时缓冲区
  122. for (i = 0; i < sendNum; i++)
  123. {
  124. time = timeOut * 10; // 计算超时时间
  125. // ★ 发送前丢弃旧数据 ★
  126. __HAL_UART_DISABLE_IT(&huart3, UART_IT_IDLE); // 可选:保护指针修改
  127. uart3CircleBuf.r = uart3CircleBuf.w; // 丢弃旧数据
  128. __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
  129. //printf("send command: %s\r\n", pCmd);
  130. USART_SendString(&huart3, pCmd); // 发送 AT 指令
  131. osDelay(100); // 等待模块返回(短暂延时)
  132. while (time--)
  133. {
  134. uint8_t gotNewData = 0;
  135. // 读取环形缓冲区内的新数据
  136. while (circle_buf_read(&uart3CircleBuf, &receivedByte) == 0)
  137. {
  138. gotNewData = 1;
  139. uint16_t len = strlen(responseBuf_2);
  140. if (len < sizeof(responseBuf_2) - 1)
  141. {
  142. responseBuf_2[len] = receivedByte;
  143. responseBuf_2[len + 1] = '\0'; // 字符串结束符
  144. }
  145. }
  146. if (gotNewData)
  147. {
  148. // ★ 判断是否匹配 ★
  149. if ((pRes1 && strstr(responseBuf_2, pRes1) != NULL) ||
  150. (pRes2 && strstr(responseBuf_2, pRes2) != NULL))
  151. {
  152. // printf("-: %s\n", responseBuf_2);
  153. return 1; // 任意一个匹配成功
  154. }
  155. }
  156. osDelay(10);
  157. }
  158. printf("Timeout_!: %s\n", responseBuf_2); // 超时打印
  159. }
  160. return 0;
  161. }
  162. uint8_t sendCmd_4G_3(char *pCmd, char *pRes1, char *pRes2, uint32_t timeOut, uint8_t sendNum)
  163. {
  164. uint8_t i;
  165. uint32_t time;
  166. uint8_t receivedByte;
  167. memset(responseBuf_2, 0, sizeof(responseBuf_2)); // 清空临时缓冲区
  168. for (i = 0; i < sendNum; i++)
  169. {
  170. time = timeOut * 10; // 计算超时时间
  171. // ★ 发送前丢弃旧数据 ★
  172. __HAL_UART_DISABLE_IT(&huart3, UART_IT_IDLE); // 可选:保护指针修改
  173. uart3CircleBuf.r = uart3CircleBuf.w; // 丢弃旧数据
  174. __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
  175. USART_SendString(&huart3, pCmd); // 发送 AT 指令
  176. osDelay(100); // 等待模块返回(短暂延时)
  177. uint8_t matchFlag = 0;
  178. while (time--)
  179. {
  180. uint8_t gotNewData = 0;
  181. // 读取环形缓冲区内的新数据
  182. while (circle_buf_read(&uart3CircleBuf, &receivedByte) == 0)
  183. {
  184. gotNewData = 1;
  185. uint16_t len = strlen(responseBuf_2);
  186. if (len < sizeof(responseBuf_2) - 1)
  187. {
  188. responseBuf_2[len] = receivedByte;
  189. responseBuf_2[len + 1] = '\0'; // 字符串结束符
  190. }
  191. }
  192. if (gotNewData)
  193. {
  194. // 每次有新数据都检测是否有完整的行
  195. char *lineStart = responseBuf_2;
  196. while (1)
  197. {
  198. // 查找是否有一行结束符
  199. char *lineEnd = strstr(lineStart, "\r\n");
  200. if (lineEnd == NULL)
  201. break; // 没有完整行,等待更多数据
  202. // 截断这一行,形成完整字符串
  203. *lineEnd = '\0';
  204. // 打印完整行
  205. // printf("%s\n", lineStart);
  206. // // 重点:如果是+MIPURC开头的数据
  207. // if (strstr(lineStart, "+MIPURC: \"rtcp\"") != NULL)
  208. // {
  209. // printf("MIPURC Data: %s\n", lineStart);
  210. // }
  211. // 判断是否有匹配到成功应答
  212. if ((pRes1 && strstr(lineStart, pRes1) != NULL) ||
  213. (pRes2 && strstr(lineStart, pRes2) != NULL))
  214. {
  215. matchFlag = 1;
  216. }
  217. // 移动到下一行
  218. lineStart = lineEnd + 2;
  219. }
  220. // 剩下的内容移动到buffer头部(继续拼接未完整行)
  221. uint16_t remainLen = strlen(lineStart);
  222. memmove(responseBuf_2, lineStart, remainLen + 1); // +1 包含结束符
  223. }
  224. osDelay(10);
  225. }
  226. if (matchFlag)
  227. {
  228. // printf("%s\n", responseBuf_2); // 打印剩余数据
  229. return 1; // 任意一个匹配成功
  230. }
  231. printf("Timeout_!: %s\n", responseBuf_2); // 超时打印
  232. }
  233. return 0;
  234. }
  235. void process_uart3_buffer(void)
  236. {
  237. Uart3Rx_msg uart3_msg;
  238. if (xQueueReceive(uart3rxqueueHandle, &uart3_msg, (TickType_t)500) == pdPASS) // portMAX_DELAY (TickType_t)0
  239. {
  240. uint16_t len = (uart3_msg.length < sizeof(receiveBuff4G_MIPURC)) ? uart3_msg.length : (sizeof(receiveBuff4G_MIPURC) - 1);
  241. memcpy(receiveBuff4G_MIPURC, uart3_msg.data, len);
  242. receiveBuff4G_MIPURC[len] = '\0'; // 确保字符串结尾
  243. printf("Queue Data: %s\n", receiveBuff4G_MIPURC);
  244. if(system_cloud_mode == Cloud_4G_MODE)
  245. {
  246. process_MIPURC_data(receiveBuff4G_MIPURC, len);
  247. }
  248. }
  249. }
  250. void process_MIPURC_data(uint8_t *buf, uint16_t len)
  251. {
  252. const char *mipurcStr = "+MIPURC: \"rtcp\",0,";
  253. uint16_t mipurcLen = strlen(mipurcStr);
  254. int mipurcPos = -1;
  255. // **查找 "+MIPURC: \"rtcp\",0," 位置**
  256. for (uint16_t i = 0; i <= len - mipurcLen; i++) {
  257. if (memcmp(buf + i, mipurcStr, mipurcLen) == 0) {
  258. mipurcPos = i;
  259. break;
  260. }
  261. }
  262. // **如果找到 "+MIPURC: \"rtcp\",0,"**
  263. if (mipurcPos != -1)
  264. {
  265. uint8_t *dataStart = buf + mipurcPos + mipurcLen; // `+MIPURC: "rtcp",0,` 后的数据
  266. // **提取数据长度**
  267. char *commaPos = strchr((char *)dataStart, ',');
  268. if (commaPos == NULL) {
  269. printf("Invalid MIPURC format (missing length)\n");
  270. return;
  271. }
  272. int expectedDataLen = 0;
  273. if (sscanf(commaPos - 2, "%d,", &expectedDataLen) != 1) { // **修正解析**
  274. printf("Invalid MIPURC format (length parse error)\n");
  275. return;
  276. }
  277. // 找到实际数据部分(跳过逗号后面的空格)
  278. char *hexDataStr = commaPos + 3; // 这里 +3 是跳过 ", ",确保指向 HEX 数据
  279. // **转换 HEX 字符串到二进制**
  280. int actualDataLen = hexStringToBytes(hexDataStr-2, parsed_4GMIPURC_Data, MAX_HEX_DATA_LEN);
  281. if (actualDataLen < 0) {
  282. printf("HEX Data parse error! Code: %d\n", actualDataLen);
  283. return;
  284. }
  285. // **检查长度是否匹配**
  286. if (expectedDataLen == actualDataLen-1)
  287. {
  288. // printf("Extracted JT808 Data (%d bytes): ", expectedDataLen);
  289. // for (int i = 0; i < expectedDataLen; i++) {
  290. // printf("%02X ", parsed_4GMIPURC_Data[i]);
  291. // }
  292. // printf("\n");
  293. // 直接解析 JT808 数据
  294. parse_JT808_frame(parsed_4GMIPURC_Data, expectedDataLen);
  295. } else {
  296. printf("Length mismatch: expected %d, got %d. Ignoring.\n", expectedDataLen, actualDataLen);
  297. }
  298. }
  299. }
  300. /**
  301. * @brief 等待UART3接收预期字符串中的任意一个 WIFI用
  302. * @param keywords 关键词数组(多个字符串)
  303. * @param keyword_count 关键词数量
  304. * @param buffer 存储接收数据的缓冲区
  305. * @param buffer_len 缓冲区长度
  306. * @param timeout_ms 等待超时时间(毫秒)
  307. * @return 匹配到的关键词索引(0 ~ keyword_count-1),否则返回 -1
  308. */
  309. int wait_uart3_multi_response(const char* keywords[], int keyword_count, char* buffer, uint16_t buffer_len, uint32_t timeout_ms)
  310. {
  311. TickType_t start_tick = xTaskGetTickCount();
  312. uint16_t total_len = 0;
  313. Uart3Rx_msg uart3_msg;
  314. while ((xTaskGetTickCount() - start_tick) < pdMS_TO_TICKS(timeout_ms))
  315. {
  316. if (xQueueReceive(uart3rxqueueHandle, &uart3_msg, pdMS_TO_TICKS(300)) == pdPASS)
  317. {
  318. uint16_t copy_len = (uart3_msg.length < (buffer_len - total_len - 1)) ? uart3_msg.length : (buffer_len - total_len - 1);
  319. memcpy(buffer + total_len, uart3_msg.data, copy_len);
  320. total_len += copy_len;
  321. buffer[total_len] = '\0';
  322. printf("Recv: %s\r\n", buffer);
  323. // 检查并提取 +TRDTC: 数据
  324. extract_and_parse_trdtc(buffer);
  325. for (int i = 0; i < keyword_count; ++i)
  326. {
  327. if (strstr(buffer, keywords[i]) != NULL)
  328. {
  329. // printf("Matched keyword[%d]: %s\r\n", i, keywords[i]);
  330. return i;
  331. }
  332. }
  333. }
  334. }
  335. printf("Timeout\r\n");
  336. return -1;
  337. }
  338. /**
  339. * @brief 从 UART 数据中提取并解析 +TRDTC: 开头的 JT808 帧数据
  340. * @param buffer 接收到的完整字符串(含 +TRDTC:)
  341. */
  342. void extract_and_parse_trdtc(const char* buffer)
  343. {
  344. const char* trdtc_start = strstr(buffer, "+TRDTC:");
  345. if (!trdtc_start)
  346. return;
  347. // 查找第一个 "7E" 作为帧起始
  348. const char* frame_start = strstr(trdtc_start, "7E");
  349. if (!frame_start)
  350. return;
  351. // printf("first 7E \r\n");
  352. const char* frame_end = strstr(frame_start + 2, "7E"); // 查找第二个 7E
  353. if (frame_end)
  354. {
  355. frame_end += 2; // 包含结束 7E
  356. }
  357. else
  358. {
  359. // 如果没找到第二个7E,尝试查找\r\n作为帧尾
  360. frame_end = strstr(frame_start, "\r\n");
  361. if (!frame_end)
  362. return; // 没有找到帧尾,退出
  363. // 不包括 \r\n,只处理到前面为止
  364. }
  365. // printf("frame_end 7E \r\n");
  366. int hex_len = frame_end - frame_start;
  367. if (hex_len <= 0 || hex_len > 512)
  368. return;
  369. uint8_t jt808_frame[256];
  370. int byte_len = 0;
  371. char byte_str[3] = {0};
  372. for (int i = 0; i < hex_len; i += 2)
  373. {
  374. if (frame_start[i] == '\0' || frame_start[i + 1] == '\0')
  375. break;
  376. byte_str[0] = frame_start[i];
  377. byte_str[1] = frame_start[i + 1];
  378. jt808_frame[byte_len++] = (uint8_t)strtol(byte_str, NULL, 16);
  379. }
  380. if (byte_len > 0)
  381. parse_JT808_frame(jt808_frame, byte_len);
  382. }
  383. void parse_JT808_frame(uint8_t *frame, uint16_t length)
  384. {
  385. // printf("JT808 Frame Received (Len: %d): ", length);
  386. // for (uint16_t i = 0; i < length; i++)
  387. // {
  388. // printf("%02X ", frame[i]);
  389. // }
  390. // printf("\n");
  391. uint16_t msg_id = (frame[1] << 8) | frame[2]; // 消息 ID
  392. // uint16_t msg_length = (frame[3] << 8) | frame[4]; // 消息体长度
  393. // uint8_t *phone_number = &frame[5]; // 手机号 (BCD 编码)
  394. msg_serial = (frame[11] << 8) | frame[12]; // 消息流水号
  395. uint8_t *payload = &frame[13]; // 消息体数据
  396. uint8_t received_checksum = frame[length - 2]; // 校验码
  397. uint8_t calculated_checksum = Calculate_Checksum(&frame[1], length - 3);
  398. if (calculated_checksum != received_checksum )
  399. {
  400. printf("Checksum Mismatch! Expected: %02X, Received: %02X\n", calculated_checksum, received_checksum);
  401. return;
  402. }
  403. // printf("JT808 Frame Received (Len: %d)\n", length);
  404. // printf("Message ID: 0x%04X, Length: %d, Serial: %d\n", msg_id, msg_length, msg_serial);
  405. switch (msg_id)
  406. {
  407. case 0x80FF: // 服务器下发unix时间
  408. if ((length - 13) >= 4) // 数据体长度至少 4 字节
  409. {
  410. // 从 payload 中提取 4 字节,转成 uint32_t
  411. uint32_t timestamp =
  412. ((uint32_t)payload[0] << 24) |
  413. ((uint32_t)payload[1] << 16) |
  414. ((uint32_t)payload[2] << 8) |
  415. ((uint32_t)payload[3]);
  416. // printf("Received UNIX Timestamp: %lu\r\n", timestamp);
  417. // 设置 RTC 时间
  418. Set_RTC_Time((time_t)timestamp);
  419. unixtime_reply_received = true;
  420. }
  421. else
  422. {
  423. printf("Invalid 0x80FF payload length: %d\r\n", length - 13);
  424. }
  425. break;
  426. case 0x8001: // 终端通用应答
  427. if (length > 18 && frame[17] == 0)
  428. printf("Heart_callback_OK\n");
  429. heartbeat_reply_received = true;
  430. break;
  431. case 0x8100: // 终端注册应答
  432. if (length > 14 && frame[13] == 0)
  433. printf("Cloud_Register_callback_OK\n");
  434. break;
  435. case 0x8103: // 终端参数设置
  436. parse_JT808_8103(payload, length);
  437. Send_General_response();
  438. break;
  439. default:
  440. printf("Unknown Message ID: 0x%04X\n", msg_id);
  441. break;
  442. }
  443. }
  444. // 解析 JT808 0x8103 终端参数设置
  445. void parse_JT808_8103(uint8_t *payload, uint16_t length)
  446. {
  447. printf("Terminal Parameter Settings Received:\n");
  448. for (uint16_t i = 1; i < length;)
  449. {
  450. uint16_t param_id = (payload[i] << 8) | payload[i + 1]; // 参数 ID
  451. uint8_t param_length = payload[i + 2]; // 参数长度
  452. uint8_t param_value = payload[i + 3]; // 只支持 1 字节参数
  453. printf("Param ID: 0x%04X, Length: %d, Value: %d\n", param_id, param_length, param_value);
  454. switch (param_id)
  455. {
  456. case 0xF101: flash_data.controltransmit_flag = param_value; break;
  457. case 0xF102: flash_data.temp_first_threshold = param_value; break;
  458. case 0xF103: flash_data.temp_second_threshold = param_value; break;
  459. case 0xF104: flash_data.pressure_threshold = param_value; break;
  460. case 0xF105: flash_data.co_threshold = param_value; break;
  461. case 0xF106: flash_data.h2_threshold = param_value; break;
  462. case 0xF107: flash_data.smallboard_upload_frequency = param_value; break;
  463. case 0xF108: flash_data.heart_upload_frequency = param_value; break;
  464. case 0xF109: flash_data.mainboard_upload_frequency = param_value; break;
  465. default:
  466. printf("Unknown Parameter ID: 0x%04X\n", param_id);
  467. break;
  468. }
  469. i += (3 + param_length); // 跳过已解析的参数
  470. }
  471. CAN_Send_Parameter(0x00110000, &flash_data, 8);
  472. flash_save_parameter_flag = true;
  473. printf("Updated flash_data:\n");
  474. printf("Control Transmit Flag: %d\n", flash_data.controltransmit_flag);
  475. printf("Temp First Threshold: %d°C\n", flash_data.temp_first_threshold);
  476. printf("Temp Second Threshold: %d°C\n", flash_data.temp_second_threshold);
  477. printf("Pressure Threshold: %d Pa\n", flash_data.pressure_threshold);
  478. printf("CO Threshold: %d ppm\n", flash_data.co_threshold);
  479. printf("H2 Threshold: %d ppm\n", flash_data.h2_threshold);
  480. printf("Smallboard Upload Frequency: %d s\n", flash_data.smallboard_upload_frequency);
  481. printf("Heart Upload Frequency: %d s\n", flash_data.heart_upload_frequency);
  482. printf("Mainboard Upload Frequency: %d s\n", flash_data.mainboard_upload_frequency);
  483. }
  484. // HEX 字符串转换为二进制数据
  485. int hexStringToBytes(const char *hexStr, uint8_t *outBytes, int maxLen)
  486. {
  487. int hexStrLen = strlen(hexStr);
  488. if (hexStrLen % 2 != 0) {
  489. return -1; // HEX 字符串长度必须是偶数
  490. }
  491. int byteLen = hexStrLen / 2;
  492. if (byteLen > maxLen) {
  493. return -2; // 数据超出缓冲区
  494. }
  495. for (int i = 0; i < byteLen; i++) {
  496. sscanf(hexStr + 2 * i, "%2hhx", &outBytes[i]); // 每两个字符转换成 1 个字节
  497. }
  498. return byteLen;
  499. }
  500. /**
  501. * @breaf MQTT连接至MQTT服务器,订阅,发布消息
  502. */
  503. // 封装MQTT连接至MQTT服务器
  504. uint8_t mqttconn(char *IpAddr, uint16_t port, char *ID, char *User, char *Passwd, char* pRes)
  505. {
  506. char MQTT_Sendbuf[128];
  507. sprintf((char *)MQTT_Sendbuf,"AT+MQTTCONN=0,\"%s\",\"%d\",\"%s\",\"%s\",\"%s\"\r\n",IpAddr, port, ID,User, Passwd);
  508. sendCmd_4G(MQTT_Sendbuf,pRes,1,1);
  509. if(sendCmd_4G(MQTT_Sendbuf,pRes,1,1))
  510. {
  511. return 1;
  512. }
  513. return 0;
  514. }
  515. // 连接至MQTT服务器,订阅
  516. void MQTTCONN(void)
  517. {
  518. char MQTT_SUBbuf[50]; // 订阅字符缓冲区
  519. char topicb[50];//*服务器发布主题B
  520. // 连接至MQTT服务器
  521. mqttconn((char*)MQTTADDR,MQTTPORT,"DCCJC",(char*)MQTTUSER,(char*)MQTTPSWD,"+MQTTURC: \"conn\",0,0");// printf("#连接MQTT成功\r\n");
  522. // 订阅主题
  523. snprintf(MQTT_SUBbuf, 50, "AT+MQTTSUB=0,\"%s\",1\r\n", topicb);
  524. // 发送订阅指令并检查结果
  525. sendCmd_4G(MQTT_SUBbuf, "+MQTTURC: \"suback\"", 1, 1);// printf("#订阅成功\r\n");
  526. }
  527. // 发布消息QoS=0;
  528. uint8_t MQTT_PUB(uint8_t connect_id, char *topic, char *mesg, char* pRes)
  529. {
  530. char MQTT_Sendbuf[200];
  531. uint8_t length = strlen(mesg);
  532. sprintf((char *)MQTT_Sendbuf,"AT+MQTTPUB=%d,\"%s\",0,0,0,%d,\"%s\"\r\n",connect_id, topic, length, mesg);
  533. sendCmd_4G(MQTT_Sendbuf,pRes,1,1);
  534. // if(sendCmd_4G(MQTT_Sendbuf,pRes,1,1)){// printf("#发布心跳成功\r\n");
  535. // return 1;
  536. // }
  537. return 1;
  538. }
  539. // 断开MQTT连接
  540. void MQTTDISCONN(void)
  541. {
  542. sendCmd_4G("AT+MQTTDISC=0\r\n", "OK", 1, 1);// printf("#断开MQTT连接成功\r\n");
  543. }
  544. /**
  545. * @breaf 建立TCP连接
  546. */
  547. // 封装建立TCP连接函数
  548. void tcpconn(char *value, uint8_t cid, char *IPaddr, uint16_t port, uint8_t tcpConnmode)
  549. {
  550. char *ptr = value;
  551. ptr += sprintf(ptr, "AT+MIPOPEN=%d,\"TCP\",\"%s\",%d,60,%d\r\n",cid,IPaddr,port,tcpConnmode);
  552. }
  553. // 建立TCP连接平台端IP及端口号
  554. void TCPCONN(void)
  555. {
  556. char TCPconnvalue[100];
  557. tcpconn(TCPconnvalue, 1, JIALONGip, JIALONGport,0); //cid=1 tcpConnmode=0 普通模式
  558. }
  559. /**
  560. * @breaf 连续定位信息上报
  561. */
  562. void GNSSLOC(void)
  563. {
  564. // sendCmd_4G("AT+MIPCFG=\"encoding\",1,1,1\r\n", "OK", 1, 1);//默认输入输出为ASCII,0 发16,1 接16,1
  565. sendCmd_4G("AT+MGNSSCFG=\"nmea/mask\",0\r\n", "OK", 1, 1);
  566. sendCmd_4G("AT+MGNSSLOC=0\r\n", "OK", 1, 1);
  567. sendCmd_4G("AT+MGNSS=1\r\n", "OK", 1, 1);
  568. if(sendCmd_4G("AT+MGNSSCFG=\"nmea/mask\",0\r\n", "OK", 1, 1))
  569. { // printf("#使能NMEA信息\r\n");
  570. if(sendCmd_4G("AT+MGNSSLOC=0\r\n", "OK", 1, 1))
  571. {// printf("#关闭自动定位上报\r\n");
  572. if(sendCmd_4G("AT+MGNSS=1\r\n", "OK", 1, 1))
  573. {// printf("开启MGNSS\r\n");
  574. MgnssFlag=true;
  575. }
  576. }
  577. }
  578. }
  579. /**
  580. * @breaf 4G模块初始化
  581. */
  582. void ML307A_INIT(void)
  583. {
  584. if (sendCmd_4G("AT\r\n", "OK", 1, 5))
  585. {
  586. printf("AT_OK\r\n");
  587. }else
  588. {
  589. printf("AT_fail\r\n");
  590. ML307AReset();
  591. }
  592. if (sendCmd_4G("AT+CPIN?\r\n", "+CPIN: READY", 1, 5))
  593. {
  594. printf("CPIN_OK\r\n");
  595. }
  596. if (sendCmd_4G("AT+CEREG?\r\n", "+CEREG: 0,1", 1, 5))
  597. {
  598. printf("CEREG_OK\r\n");
  599. }
  600. if(sendCmd_4G("AT+MIPCLOSE=1\r\n", "+MIPSEND:", 1, 1))//关闭TCP连接
  601. {
  602. printf("MIPCLOSE_OK\r\n");
  603. }
  604. ML307A_MQTT_Init();
  605. }
  606. void ML307A_Init(void)
  607. {
  608. for (int attempt_count = 0; attempt_count < 3; attempt_count++)
  609. {
  610. sendCmd_4G("AT\r\n", "OK", 1, 5);
  611. HAL_Delay(10);
  612. sendCmd_4G("AT+CPIN?\r\n", "+CPIN: READY", 1, 5);
  613. printf("CPIN_OK\r\n");
  614. HAL_Delay(10);
  615. sendCmd_4G("AT+CEREG?\r\n", "+CEREG: 0,1", 1, 5);
  616. printf("Network ing...\r\n");
  617. if (sendCmd_4G("AT+CPIN?\r\n", "+CPIN: READY", 1, 5))
  618. {
  619. printf("PIN认证成功\r\n");
  620. if (sendCmd_4G("AT+CEREG?\r\n", "+CEREG: 0,1", 1, 5))
  621. {
  622. printf("驻网成功\r\n");
  623. break;
  624. }
  625. } else {
  626. ML307AReset();
  627. }
  628. break;
  629. }
  630. }
  631. /*
  632. char TCPconnvalue[100];// TCP的IP地址端口号缓冲区
  633. case 2:
  634. // tcpconn(TCPconnvalue, 1, JIALONGip, JIALONGport,0); //cid=1 tcpConnmode=0 普通模式
  635. // if (sendCmd_4G(TCPconnvalue, "+MIPOPEN: 1,0", 1, 1)) {
  636. // step4g++;
  637. // }
  638. step4g=3;
  639. break;
  640. case 3:
  641. sendCmd_4G("AT+MIPCFG=\"encoding\",0,2,0\r\n", "OK", 1, 1);////输入配置为转义字符模式
  642. if (!reset4Gmodule) {
  643. if (sendCmd_4G("AT+MGNSSCFG=\"nmea/mask\",0\r\n", "OK", 1, 1)) {
  644. printf("#使能NMEA信息\r\n");
  645. if (sendCmd_4G("AT+MGNSSLOC=0\r\n", "OK", 1, 1)) {
  646. printf("#关闭自动定位上报\r\n");
  647. if (sendCmd_4G("AT+MGNSS=1\r\n", "OK", 1, 1)) {
  648. printf("#开启MGNSS\r\n");
  649. MgnssFlag = true;
  650. }
  651. }
  652. }
  653. step4g++;
  654. } else {
  655. reset4Gmodule = false;
  656. }
  657. break;
  658. case 4:
  659. MQTTCONN();
  660. char data_buff[256]; //组合JSON报文数据
  661. uint8_t run_state = 0;
  662. sprintf((char *)data_buff,"{\"temperature\":{\"ID\":180}}");
  663. run_state=MQTT_PUB(0,Publish_Topic,data_buff,"+MQTTURC: \"puback\"");//上报
  664. if(run_state==1)
  665. {
  666. printf("4G模块发布数据至MQTT成功\r\n");
  667. run_state = 0;
  668. }
  669. */
  670. void Send_AT_Command(char *command)
  671. {
  672. // 发送AT指令时添加换行符
  673. char command_with_newline[256];
  674. snprintf(command_with_newline, sizeof(command_with_newline), "%s\r\n", command);
  675. // 发送指令
  676. HAL_UART_Transmit(&huart3, (uint8_t *)command_with_newline, strlen(command_with_newline),1000);
  677. }
  678. void Receive_Response(char *buffer, uint16_t size)
  679. {
  680. // 接收数据
  681. HAL_UART_Receive_DMA(&huart3, (uint8_t *)buffer, size - 1);
  682. // 添加字符串结束符
  683. buffer[size - 1] = '\0';
  684. memset(buffer, 0, size); // 清空接收缓冲区
  685. }
  686. int Check_Response(char *buffer, uint16_t size)
  687. {
  688. Receive_Response(buffer, size);
  689. // 判断是否为错误响应
  690. if (strstr(buffer, "+CME ERROR") != NULL) {
  691. return 0; // 失败
  692. }
  693. // 判断是否为特定成功响应
  694. if (strstr(buffer, "+MQTTREAD") != NULL ||
  695. strstr(buffer, "+MQTTPUB") != NULL ||
  696. strstr(buffer, "+MQTTSUB") != NULL ||
  697. strstr(buffer, "+MQTTURC") != NULL ||
  698. strstr(buffer, "+CEREG:0,1") != NULL
  699. ) {
  700. return 1; // 成功
  701. }
  702. // 判断是否为OK响应
  703. if (strstr(buffer, "OK") != NULL) {
  704. return 1; // 成功
  705. }
  706. return 0; // 其他情况视为失败
  707. }
  708. int Send_Command_Check_Response(char *command, char *response_buffer, uint16_t buffer_size)
  709. {
  710. Send_AT_Command(command);
  711. return Check_Response(response_buffer, buffer_size);
  712. }
  713. void MQTT_Process(void)
  714. {
  715. char response[256]; // 存放接收的响应数据
  716. int total_attempt = 0; // 总共跳回清除会话模式的次数
  717. int attempt = 0; // 每个步骤的重试次数
  718. int success = 0; // 是否成功标志位
  719. while (total_attempt < 5) { // 最多尝试5次清除会话模式
  720. total_attempt++; // 每次从头开始都计为一次清除会话模式的执行
  721. // 1. 清除会话模式
  722. attempt = 0; // 重置步骤重试计数
  723. while (attempt < 3) { // 每个步骤最多重试3次
  724. success = Send_Command_Check_Response("AT+MQTTCFG=\"clean\",0,1", response, sizeof(response));
  725. if (success)
  726. // printf("清除会话模式成功\n");
  727. break; // 成功则继续下一个步骤
  728. attempt++;
  729. }
  730. if (!success) continue; // 如果重试3次仍然失败,则重新开始整个流程
  731. HAL_Delay(1);
  732. // 2. 配置为接收缓存模式
  733. attempt = 0; // 重置步骤重试计数
  734. while (attempt < 3) {
  735. success = Send_Command_Check_Response("AT+MQTTCFG=\"cached\",0,1", response, sizeof(response));
  736. if (success) {
  737. printf("配置为接收缓存模式成功\n");
  738. break;
  739. }
  740. attempt++;
  741. }
  742. if (!success) continue; // 如果失败则重新开始整个流程
  743. HAL_Delay(1);
  744. // 3. 连接至MQTT服务器
  745. attempt = 0;
  746. while (attempt < 3) {
  747. 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));
  748. if (success) {
  749. printf("连接至MQTT服务器成功\n");
  750. break;
  751. }
  752. attempt++;
  753. }
  754. if (!success) continue;
  755. HAL_Delay(1);
  756. // 4. 订阅主题
  757. attempt = 0;
  758. while (attempt < 3) {
  759. success = Send_Command_Check_Response("AT+MQTTSUB=0,\"$sys/0w8A8Kloxm/test0923_1/#\",1", response, sizeof(response));
  760. if (success) {
  761. printf("订阅主题成功\n");
  762. break;
  763. }
  764. attempt++;
  765. }
  766. if (!success) continue;
  767. HAL_Delay(1);
  768. // 5. 发布消息
  769. attempt = 0;
  770. while (attempt < 3) {
  771. 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));
  772. if (success){
  773. printf("发布消息成功\n");
  774. break;
  775. }
  776. attempt++;
  777. }
  778. if (!success) continue;
  779. // // 6. 读取缓存数据
  780. // attempt = 0;
  781. // while (attempt < 3) {
  782. // success = Send_Command_Check_Response("AT+MQTTREAD=0,1", response, sizeof(response));
  783. // if (success) {
  784. // printf("读取缓存数据成功");
  785. // break;
  786. // }
  787. // attempt++;
  788. // }
  789. // if (!success) continue;
  790. // // 7. 断开连接
  791. // attempt = 0;
  792. // while (attempt < 3) {
  793. // success = Send_Command_Check_Response("AT+MQTTDISC=0", response, sizeof(response));
  794. // if (success) {
  795. // printf("断开连接成功");
  796. // break;
  797. // }
  798. // attempt++;
  799. // }
  800. // if (!success) continue;
  801. // 如果所有步骤都成功,则退出函数
  802. break;
  803. }
  804. // 如果达到5次还不成功,可以输出日志或执行其他错误处理
  805. if (total_attempt >= 5) {
  806. // 错误处理
  807. printf("MQTT连接失败,达到最大重试次数。\n");
  808. }
  809. }
  810. void ML307A_MQTT_Init(void)
  811. {
  812. // check_network_connection();
  813. char response[256]; // 存放接收的响应数据
  814. Send_Command_Check_Response("AT+MQTTDISC=0", response, sizeof(response));
  815. HAL_Delay(100);
  816. Send_Command_Check_Response("AT+MQTTCFG=\"clean\",0,1", response, sizeof(response));
  817. HAL_Delay(100);
  818. Send_Command_Check_Response("AT+MQTTCFG=\"cached\",0,1", response, sizeof(response));
  819. HAL_Delay(100);
  820. 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));
  821. HAL_Delay(100);
  822. Send_Command_Check_Response("AT+MQTTSUB=0,\"/sys/k1vccLJvsUy/BATT/thing/service/property/set\",1", response, sizeof(response));
  823. }
  824. int cpin_attempts = 0; // AT+CPIN计数3次的计数器
  825. void ML307A_NET_Init(void)
  826. {
  827. HAL_Delay(100);
  828. uint8_t step4g = 0;// 模组4G初始化步骤标志位
  829. char response[256]; // 存放接收的响应数据
  830. // if(Reset4G_flag)
  831. // {
  832. // Reset4G_flag = 0;
  833. // step4g = 0;
  834. // }
  835. switch(step4g)
  836. {
  837. case 0:
  838. {
  839. // if (sendCmd_4G("AT\r\n", "OK", 1, 4))
  840. HAL_Delay(10);
  841. if (Send_Command_Check_Response("AT", response, sizeof(response)))
  842. {
  843. printf("AT_OK\r\n");
  844. step4g++; // 进入下一步
  845. }else
  846. {
  847. printf("AT_fail\r\n");
  848. step4g++;
  849. }
  850. }
  851. case 1:
  852. {
  853. HAL_Delay(10);
  854. // if (sendCmd_4G("AT+CEREG?\r\n", "+CEREG:0,1", 1, 5))
  855. if (Send_Command_Check_Response("AT+CEREG?", response, sizeof(response)))
  856. {
  857. printf("CEREG_OK\r\n");
  858. HAL_Delay(500);
  859. step4g++; // 进入下一步
  860. cpin_attempts = 0; // 重置计数器
  861. }
  862. else
  863. {
  864. // cpin_attempts++; // 增加计数
  865. // if (cpin_attempts >= 3) // 如果已经发送了3次
  866. // {
  867. //// sendCmd_4G("AT+CGATT=1\r\n", "OK", 1, 5); // 手动驻网
  868. // Send_Command_Check_Response("AT+CGATT=1", response, sizeof(response));
  869. // HAL_Delay(100);
  870. // printf("CEREG_fail\r\n");
  871. // cpin_attempts = 0; // 重置计数器
  872. // }
  873. // Send_Command_Check_Response("AT+CGATT=1", response, sizeof(response));
  874. HAL_Delay(100);
  875. printf("CEREG_fail\r\n");
  876. step4g ++;
  877. }
  878. }
  879. case 2:
  880. {
  881. HAL_Delay(10);
  882. // sendCmd_4G("AT+CFUN=1\r\n", "OK", 1, 5); // 确保CFUN为1
  883. // if(Send_Command_Check_Response("AT+CFUN=1", response, sizeof(response)))
  884. // {
  885. // HAL_Delay(100);
  886. // step4g++; // 进入下一步
  887. // printf("AT+CFUN_ok\r\n");
  888. // }
  889. step4g++; // 进入下一步
  890. // else
  891. // {
  892. // step4g++; // 进入下一步
  893. // printf("AT+CFUN_fail\r\n");
  894. // }
  895. }
  896. case 3:
  897. {
  898. HAL_Delay(10);
  899. // 配置为自动连网(模组应用层网络)
  900. if(Send_Command_Check_Response("AT+MUECONFIG=\"autoconn\",1", response, sizeof(response)))
  901. {
  902. HAL_Delay(100);
  903. printf("AT+MUECONFIG_ok\r\n");
  904. step4g++; // 进入下一步
  905. }
  906. else
  907. {
  908. step4g++; // 进入下一步
  909. printf("AT+MUECONFIG_fail\r\n");
  910. }
  911. }
  912. case 4:
  913. {
  914. HAL_Delay(10);
  915. // 配置为自动拨号(上位机网卡拨号)
  916. if(Send_Command_Check_Response("AT+MDIALUPCFG=\"auto\",1", response, sizeof(response)))
  917. {
  918. HAL_Delay(100);
  919. step4g++; // 进入下一步
  920. printf("AT+MDIALUPCFG_ok\r\n");
  921. }
  922. else
  923. {
  924. step4g++; // 进入下一步
  925. printf("AT+MDIALUPCFG_fail\r\n");
  926. }
  927. }
  928. case 5:
  929. {
  930. HAL_Delay(10);
  931. ML307A_MQTT_Init(); // 初始化MQTT
  932. break;
  933. }
  934. case 7:
  935. {
  936. break;
  937. }
  938. }
  939. }
  940. /**
  941. * @breaf 重启模块
  942. */
  943. void ML307AReset(void)
  944. {
  945. HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
  946. HAL_Delay(500);
  947. HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
  948. HAL_Delay(2000);
  949. Reset4G_flag = 1;
  950. printf("Reset_4G\n");
  951. }
  952. void check_network_connection(void)
  953. {
  954. char response[100];
  955. // 发送 AT+CREG? 查询网络注册状态
  956. Send_Command_Check_Response("AT+CREG?", response, sizeof(response));
  957. HAL_Delay(10);
  958. // 检查是否已注册到网络,通常返回 0,1 或 0,5 代表已连接
  959. if (strstr(response, "0,1") == NULL && strstr(response, "0,5") == NULL) {
  960. // 如果未联网,执行联网操作
  961. Send_Command_Check_Response("AT+CGATT=1", response, sizeof(response));
  962. HAL_Delay(10);
  963. // 检查联网是否成功
  964. Send_Command_Check_Response("AT+CGATT?", response, sizeof(response));
  965. HAL_Delay(10);
  966. }else
  967. {
  968. ML307A_MQTT_Init();
  969. }
  970. }
  971. void ML307A_GNSS(void)
  972. {
  973. sendCmd_4G("AT+CPIN?\r\n", "+CPIN: READY", 1, 5);
  974. }