ym310_init.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. /*
  2. * YM310 Module Initialization - STABLE v5.3 (No Network Check)
  3. *
  4. * Core principles:
  5. * - AT core init only once, no re-init on retries
  6. * - Init thread created once, never restart
  7. * - After init complete, enter idle state, network maintenance by maintain thread
  8. * - Do not modify at_core.c to keep stability
  9. */
  10. #define DBG_TAG "Y-INT"
  11. #define DBG_LVL DBG_INFO
  12. #include <rtdbg.h>
  13. #include "ym310_mqtt.h"
  14. #include <string.h>
  15. #include <stdio.h>
  16. /*=============================================================================
  17. * Global Variables
  18. *=============================================================================*/
  19. rt_thread_t g_init_thread = RT_NULL;
  20. static volatile rt_bool_t s_init_thread_running = RT_FALSE;
  21. static volatile rt_bool_t s_module_initialized = RT_FALSE;
  22. static volatile rt_bool_t s_network_ready = RT_FALSE;
  23. static volatile rt_bool_t s_at_core_initialized = RT_FALSE;
  24. /* Retry state machine */
  25. typedef enum
  26. {
  27. INIT_STATE_STARTING = 0, /* Starting */
  28. INIT_STATE_POWER_ON, /* Power on */
  29. INIT_STATE_BASIC_CONFIG, /* Basic config (including SIM detection) */
  30. INIT_STATE_WAIT_NETWORK, /* Wait for network registration */
  31. INIT_STATE_ACTIVATE_PDP, /* Activate PDP */
  32. INIT_STATE_COMPLETE, /* Init complete */
  33. INIT_STATE_RETRY_WAIT /* Wait for retry */
  34. } init_state_t;
  35. static init_state_t s_init_state = INIT_STATE_STARTING;
  36. static int s_retry_count = 0;
  37. static rt_tick_t s_retry_start_tick = 0;
  38. /* 配置参数 */
  39. #define RETRY_DELAY_MS 30000 /* 重试间隔30秒 */
  40. #define SIM_WAIT_MAX 30 /* SIM等待最多30秒 */
  41. #define NETWORK_WAIT_MAX 60 /* 网络等待最多60秒 */
  42. /* 日志记录阈值 */
  43. #define FAIL_THRESHOLD 3 /* 连续失败3次才记录 */
  44. #define LOG_INTERVAL_MS (10 * 60 * 1000) /* 日志记录间隔10分钟 */
  45. /* 故障类型枚举 - 细化原因 */
  46. typedef enum
  47. {
  48. FAIL_TYPE_SIM_NOT_INSERT = 1, /* SIM未插入 */
  49. FAIL_TYPE_SIM_INVALID, /* SIM失效/损坏 */
  50. FAIL_TYPE_SIM_UNKNOWN, /* SIM其他错误 */
  51. FAIL_TYPE_NETWORK_REG, /* 网络注册失败 */
  52. FAIL_TYPE_PDP_ACT /* PDP激活失败 */
  53. } fail_type_t;
  54. /* 各故障类型的记录状态 */
  55. typedef struct
  56. {
  57. fail_type_t type;
  58. const char *desc;
  59. int consecutive_count; /* 当前连续失败次数 */
  60. rt_tick_t last_log_tick; /* 上次记录时间 */
  61. } fail_status_t;
  62. static fail_status_t s_fail_status[] = {
  63. {FAIL_TYPE_SIM_NOT_INSERT, "SIM未插入", 0, 0},
  64. {FAIL_TYPE_SIM_INVALID, "SIM失效", 0, 0},
  65. {FAIL_TYPE_SIM_UNKNOWN, "SIM错误", 0, 0},
  66. {FAIL_TYPE_NETWORK_REG, "网络注册", 0, 0},
  67. {FAIL_TYPE_PDP_ACT, "PDP激活", 0, 0}};
  68. /* 外部函数声明 */
  69. #include "ecode.h"
  70. extern void Recode_e_code(ecode_list code, uint16_t para, char *detail);
  71. extern int ym310_at_core_init(void);
  72. /*=============================================================================
  73. * SIM Card Status Detection
  74. *=============================================================================*/
  75. static int check_sim_status(char *error_detail, int detail_size)
  76. {
  77. at_resp_type_t resp;
  78. char resp_buf[128];
  79. resp = ym310_at_exec_cmd("AT+CPIN?", resp_buf, sizeof(resp_buf), YM310_AT_CMD_TIMEOUT_MS);
  80. if (resp != AT_RESP_OK)
  81. {
  82. rt_snprintf(error_detail, detail_size, "Query failed");
  83. return -1;
  84. }
  85. if (rt_strstr(resp_buf, "READY") != RT_NULL)
  86. {
  87. return 0;
  88. }
  89. else if (rt_strstr(resp_buf, "SIM NOT INSERTED") != RT_NULL ||
  90. rt_strstr(resp_buf, "NOT INSERTED") != RT_NULL)
  91. {
  92. rt_snprintf(error_detail, detail_size, "SIM not inserted");
  93. return FAIL_TYPE_SIM_NOT_INSERT;
  94. }
  95. else if (rt_strstr(resp_buf, "SIM PIN") != RT_NULL)
  96. {
  97. rt_snprintf(error_detail, detail_size, "PIN required");
  98. return FAIL_TYPE_SIM_INVALID;
  99. }
  100. else if (rt_strstr(resp_buf, "SIM PUK") != RT_NULL)
  101. {
  102. rt_snprintf(error_detail, detail_size, "PUK required");
  103. return FAIL_TYPE_SIM_INVALID;
  104. }
  105. else if (rt_strstr(resp_buf, "SIM ERROR") != RT_NULL ||
  106. rt_strstr(resp_buf, "ERROR") != RT_NULL)
  107. {
  108. rt_snprintf(error_detail, detail_size, "SIM card error");
  109. return FAIL_TYPE_SIM_INVALID;
  110. }
  111. else
  112. {
  113. rt_snprintf(error_detail, detail_size, "Unknown status");
  114. return FAIL_TYPE_SIM_UNKNOWN;
  115. }
  116. }
  117. /*=============================================================================
  118. * Smart Log Recording - 10 minute interval
  119. *=============================================================================*/
  120. static void log_persistent_failure(fail_type_t type, int fail_count, const char *extra_info)
  121. {
  122. char detail[128];
  123. rt_tick_t now = rt_tick_get();
  124. rt_tick_t log_interval = rt_tick_from_millisecond(LOG_INTERVAL_MS);
  125. for (int i = 0; i < sizeof(s_fail_status) / sizeof(s_fail_status[0]); i++)
  126. {
  127. if (s_fail_status[i].type == type)
  128. {
  129. if (now - s_fail_status[i].last_log_tick < log_interval)
  130. {
  131. LOG_D("Skip logging %s: within %d min",
  132. s_fail_status[i].desc, LOG_INTERVAL_MS / 60000);
  133. return;
  134. }
  135. s_fail_status[i].last_log_tick = now;
  136. if (extra_info && extra_info[0] != '\0')
  137. {
  138. rt_snprintf(detail, sizeof(detail), "%s(%d次) %s",
  139. s_fail_status[i].desc, fail_count, extra_info);
  140. }
  141. else
  142. {
  143. rt_snprintf(detail, sizeof(detail), "%s(%d次)",
  144. s_fail_status[i].desc, fail_count);
  145. }
  146. LOG_W("%s", detail);
  147. Recode_e_code(e_NET_INIT_FAIL, fail_count, detail);
  148. return;
  149. }
  150. }
  151. }
  152. static void reset_fail_counter(fail_type_t type)
  153. {
  154. for (int i = 0; i < sizeof(s_fail_status) / sizeof(s_fail_status[0]); i++)
  155. {
  156. if (s_fail_status[i].type == type)
  157. {
  158. s_fail_status[i].consecutive_count = 0;
  159. break;
  160. }
  161. }
  162. }
  163. static void increment_fail_counter(fail_type_t type, const char *extra_info)
  164. {
  165. for (int i = 0; i < sizeof(s_fail_status) / sizeof(s_fail_status[0]); i++)
  166. {
  167. if (s_fail_status[i].type == type)
  168. {
  169. s_fail_status[i].consecutive_count++;
  170. if (s_fail_status[i].consecutive_count >= FAIL_THRESHOLD)
  171. {
  172. log_persistent_failure(type, s_fail_status[i].consecutive_count, extra_info);
  173. s_fail_status[i].consecutive_count = 0;
  174. }
  175. break;
  176. }
  177. }
  178. }
  179. extern void gpio_lte_ctrl(rt_bool_t on);
  180. /*=============================================================================
  181. * Module Power Control
  182. *=============================================================================*/
  183. static int ym310_power_on(void)
  184. {
  185. LOG_I("Powering on YM310 module...");
  186. gpio_lte_ctrl(1);
  187. rt_thread_mdelay(1000);
  188. int retry = 0;
  189. while (retry < 10)
  190. {
  191. at_resp_type_t resp;
  192. char buf[64];
  193. resp = ym310_at_exec_cmd("AT", buf, sizeof(buf), 3000);
  194. if (resp == AT_RESP_OK)
  195. {
  196. LOG_I("Module responded to AT");
  197. rt_thread_mdelay(500);
  198. return RT_EOK;
  199. }
  200. retry++;
  201. rt_thread_mdelay(500);
  202. }
  203. LOG_W("Module may not be fully ready, continuing anyway");
  204. return RT_EOK;
  205. }
  206. /*=============================================================================
  207. * Module Basic Configuration
  208. *=============================================================================*/
  209. static int ym310_basic_config(void)
  210. {
  211. at_resp_type_t resp;
  212. char resp_buf[128];
  213. int sim_retry = 0;
  214. char sim_error[32];
  215. ym310_at_exec_cmd_with_retry("ATE0", RT_NULL, 0, YM310_AT_CMD_TIMEOUT_MS, 3);
  216. ym310_at_exec_cmd_with_retry("AT+CMEE=2", RT_NULL, 0, YM310_AT_CMD_TIMEOUT_MS, 3);
  217. while (sim_retry < SIM_WAIT_MAX)
  218. {
  219. resp = ym310_at_exec_cmd("AT+CPIN?", resp_buf, sizeof(resp_buf), YM310_AT_CMD_TIMEOUT_MS);
  220. if (resp == AT_RESP_OK && rt_strstr(resp_buf, "READY") != RT_NULL)
  221. {
  222. LOG_I("SIM card ready");
  223. reset_fail_counter(FAIL_TYPE_SIM_NOT_INSERT);
  224. reset_fail_counter(FAIL_TYPE_SIM_INVALID);
  225. reset_fail_counter(FAIL_TYPE_SIM_UNKNOWN);
  226. return RT_EOK;
  227. }
  228. sim_retry++;
  229. rt_thread_mdelay(1000);
  230. }
  231. int sim_status = check_sim_status(sim_error, sizeof(sim_error));
  232. if (sim_status > 0)
  233. {
  234. increment_fail_counter((fail_type_t)sim_status, sim_error);
  235. }
  236. else
  237. {
  238. increment_fail_counter(FAIL_TYPE_SIM_UNKNOWN, "SIM not ready");
  239. }
  240. LOG_W("SIM not ready after %d retries >>>%s<<<", SIM_WAIT_MAX, resp_buf);
  241. return -RT_ERROR;
  242. }
  243. /*=============================================================================
  244. * Network Registration
  245. *=============================================================================*/
  246. static int ym310_wait_for_network(void)
  247. {
  248. int retry_count = 0;
  249. LOG_D("Waiting for network registration...");
  250. while (retry_count < NETWORK_WAIT_MAX)
  251. {
  252. if (ym310_check_network_connected() == RT_TRUE)
  253. {
  254. LOG_D("Network registered and GPRS attached");
  255. reset_fail_counter(FAIL_TYPE_NETWORK_REG);
  256. return RT_EOK;
  257. }
  258. retry_count++;
  259. if (retry_count % 10 == 0)
  260. {
  261. LOG_D("Waiting for network... (%d/%d)", retry_count, NETWORK_WAIT_MAX);
  262. }
  263. rt_thread_mdelay(1000);
  264. }
  265. LOG_W("Network registration timeout");
  266. increment_fail_counter(FAIL_TYPE_NETWORK_REG, NULL);
  267. return -RT_ERROR;
  268. }
  269. /*=============================================================================
  270. * PDP Context Activation
  271. *=============================================================================*/
  272. static int ym310_activate_pdp(void)
  273. {
  274. at_resp_type_t resp;
  275. LOG_D("Activating PDP context...");
  276. if (ym310_check_network_connected() == RT_TRUE)
  277. {
  278. LOG_D("PDP already active");
  279. reset_fail_counter(FAIL_TYPE_PDP_ACT);
  280. return RT_EOK;
  281. }
  282. resp = ym310_at_exec_cmd("AT+QIPACT=1", RT_NULL, 0, YM310_AT_LONG_TIMEOUT_MS);
  283. if (resp != AT_RESP_OK)
  284. {
  285. rt_thread_mdelay(2000);
  286. if (ym310_check_network_connected() == RT_TRUE)
  287. {
  288. LOG_I("PDP activated successfully (verified)");
  289. reset_fail_counter(FAIL_TYPE_PDP_ACT);
  290. return RT_EOK;
  291. }
  292. LOG_W("PDP activation failed");
  293. increment_fail_counter(FAIL_TYPE_PDP_ACT, NULL);
  294. return -RT_ERROR;
  295. }
  296. rt_thread_mdelay(2000);
  297. if (ym310_check_network_connected() == RT_TRUE)
  298. {
  299. LOG_I("PDP activated");
  300. reset_fail_counter(FAIL_TYPE_PDP_ACT);
  301. return RT_EOK;
  302. }
  303. increment_fail_counter(FAIL_TYPE_PDP_ACT, NULL);
  304. return -RT_ERROR;
  305. }
  306. /*=============================================================================
  307. * Init Thread - Only handles init, enters idle state after completion
  308. *=============================================================================*/
  309. static void ym310_init_thread_entry(void *param)
  310. {
  311. int ret;
  312. // LOG_I("========================================");
  313. // LOG_I("INITIALIZATION THREAD STARTED");
  314. // LOG_I("========================================");
  315. s_init_thread_running = RT_TRUE;
  316. s_init_state = INIT_STATE_STARTING;
  317. /* Main loop - only handles init, enters idle sleep after completion */
  318. while (s_init_thread_running)
  319. {
  320. switch (s_init_state)
  321. {
  322. case INIT_STATE_STARTING:
  323. if (!s_at_core_initialized)
  324. {
  325. LOG_I("Initializing AT core...");
  326. if (ym310_at_core_init() == RT_EOK)
  327. {
  328. s_at_core_initialized = RT_TRUE;
  329. // LOG_I("AT core initialized");
  330. s_init_state = INIT_STATE_POWER_ON;
  331. }
  332. else
  333. {
  334. LOG_E("AT core init failed, will retry later");
  335. s_init_state = INIT_STATE_RETRY_WAIT;
  336. s_retry_start_tick = rt_tick_get();
  337. }
  338. }
  339. else
  340. {
  341. s_init_state = INIT_STATE_POWER_ON;
  342. }
  343. rt_thread_mdelay(100);
  344. break;
  345. case INIT_STATE_RETRY_WAIT:
  346. if ((rt_tick_get() - s_retry_start_tick) >= rt_tick_from_millisecond(RETRY_DELAY_MS))
  347. {
  348. s_retry_count++;
  349. LOG_I("Retry configuration (%d)...", s_retry_count + 1);
  350. if (s_at_core_initialized)
  351. {
  352. s_init_state = INIT_STATE_POWER_ON;
  353. }
  354. else
  355. {
  356. if (ym310_at_core_init() == RT_EOK)
  357. {
  358. s_at_core_initialized = RT_TRUE;
  359. s_init_state = INIT_STATE_POWER_ON;
  360. }
  361. else
  362. {
  363. LOG_E("AT core init failed again");
  364. s_retry_start_tick = rt_tick_get();
  365. }
  366. }
  367. }
  368. rt_thread_mdelay(1000);
  369. break;
  370. case INIT_STATE_POWER_ON:
  371. ret = ym310_power_on();
  372. if (ret == RT_EOK)
  373. {
  374. s_init_state = INIT_STATE_BASIC_CONFIG;
  375. }
  376. else
  377. {
  378. LOG_W("Power on failed, retry later");
  379. s_init_state = INIT_STATE_RETRY_WAIT;
  380. s_retry_start_tick = rt_tick_get();
  381. }
  382. rt_thread_mdelay(100);
  383. break;
  384. case INIT_STATE_BASIC_CONFIG:
  385. ret = ym310_basic_config();
  386. if (ret == RT_EOK)
  387. {
  388. s_init_state = INIT_STATE_WAIT_NETWORK;
  389. }
  390. else
  391. {
  392. LOG_W("Basic config failed (SIM issue), will retry later");
  393. s_init_state = INIT_STATE_RETRY_WAIT;
  394. s_retry_start_tick = rt_tick_get();
  395. }
  396. rt_thread_mdelay(100);
  397. break;
  398. case INIT_STATE_WAIT_NETWORK:
  399. ret = ym310_wait_for_network();
  400. if (ret == RT_EOK)
  401. {
  402. s_init_state = INIT_STATE_ACTIVATE_PDP;
  403. }
  404. else
  405. {
  406. LOG_W("Network not ready, will retry later");
  407. s_init_state = INIT_STATE_RETRY_WAIT;
  408. s_retry_start_tick = rt_tick_get();
  409. }
  410. rt_thread_mdelay(100);
  411. break;
  412. case INIT_STATE_ACTIVATE_PDP:
  413. ret = ym310_activate_pdp();
  414. if (ret == RT_EOK)
  415. {
  416. /* ===== 新增:PDP激活成功后立即同步NTP时间 ===== */
  417. LOG_I("PDP activated, syncing NTP time...");
  418. if (ym310_ntp_sync_time() == RT_EOK)
  419. {
  420. LOG_I("NTP sync successful during init");
  421. }
  422. else
  423. {
  424. LOG_W("NTP sync failed during init, will retry later");
  425. }
  426. /* ============================================= */
  427. s_init_state = INIT_STATE_COMPLETE;
  428. s_module_initialized = RT_TRUE;
  429. s_network_ready = RT_TRUE;
  430. s_retry_count = 0;
  431. LOG_D("========================================");
  432. LOG_D("MODULE INITIALIZATION COMPLETE");
  433. LOG_D("========================================");
  434. /* Start MQTT thread (only once) */
  435. if (g_mqtt_thread == RT_NULL)
  436. {
  437. g_mqtt_thread = ym310_start_mqtt_thread();
  438. if (g_mqtt_thread == RT_NULL)
  439. {
  440. LOG_E("Failed to start MQTT thread!");
  441. }
  442. }
  443. /* Start maintenance thread (only once) */
  444. if (g_maintain_thread == RT_NULL)
  445. {
  446. g_maintain_thread = ym310_start_maintain_thread();
  447. if (g_maintain_thread == RT_NULL)
  448. {
  449. LOG_E("Failed to start maintenance thread!");
  450. }
  451. }
  452. /* Init complete, enter idle state, no more checks (maintain thread handles) */
  453. s_init_state = INIT_STATE_COMPLETE;
  454. }
  455. else
  456. {
  457. LOG_W("PDP activation failed, will retry later");
  458. s_init_state = INIT_STATE_RETRY_WAIT;
  459. s_retry_start_tick = rt_tick_get();
  460. }
  461. rt_thread_mdelay(100);
  462. break;
  463. case INIT_STATE_COMPLETE:
  464. /* Init complete, thread sleeps, no more work */
  465. rt_thread_mdelay(1000); /* Wake once per minute, do nothing, keep thread alive */
  466. s_init_thread_running = RT_FALSE;
  467. break;
  468. default:
  469. break;
  470. }
  471. }
  472. LOG_I("Initialization thread exit");
  473. }
  474. /*=============================================================================
  475. * Public API
  476. *=============================================================================*/
  477. rt_thread_t ym310_start_init_thread(void)
  478. {
  479. if (g_init_thread != RT_NULL)
  480. {
  481. LOG_D("Init thread already running");
  482. return g_init_thread;
  483. }
  484. if (ym310_mqtt_init() != RT_EOK)
  485. {
  486. LOG_E("MQTT init failed!");
  487. return RT_NULL;
  488. }
  489. g_init_thread = rt_thread_create("ym310_init", ym310_init_thread_entry,
  490. RT_NULL, INIT_THREAD_STACK_SIZE,
  491. INIT_THREAD_PRIORITY, 10);
  492. if (g_init_thread == RT_NULL)
  493. {
  494. LOG_E("Failed to create init thread!");
  495. return RT_NULL;
  496. }
  497. rt_thread_startup(g_init_thread);
  498. LOG_D("Initialization thread created");
  499. return g_init_thread;
  500. }
  501. void ym310_init_thread_stop(void)
  502. {
  503. s_init_thread_running = RT_FALSE;
  504. }
  505. rt_bool_t ym310_is_module_initialized(void)
  506. {
  507. return s_module_initialized;
  508. }
  509. rt_bool_t ym310_is_network_ready(void)
  510. {
  511. return s_network_ready;
  512. }