/* * YM310 Module Initialization - STABLE v5.3 (No Network Check) * * Core principles: * - AT core init only once, no re-init on retries * - Init thread created once, never restart * - After init complete, enter idle state, network maintenance by maintain thread * - Do not modify at_core.c to keep stability */ #define DBG_TAG "Y-INT" #define DBG_LVL DBG_INFO #include #include "ym310_mqtt.h" #include #include /*============================================================================= * Global Variables *=============================================================================*/ rt_thread_t g_init_thread = RT_NULL; static volatile rt_bool_t s_init_thread_running = RT_FALSE; static volatile rt_bool_t s_module_initialized = RT_FALSE; static volatile rt_bool_t s_network_ready = RT_FALSE; static volatile rt_bool_t s_at_core_initialized = RT_FALSE; /* Retry state machine */ typedef enum { INIT_STATE_STARTING = 0, /* Starting */ INIT_STATE_POWER_ON, /* Power on */ INIT_STATE_BASIC_CONFIG, /* Basic config (including SIM detection) */ INIT_STATE_WAIT_NETWORK, /* Wait for network registration */ INIT_STATE_ACTIVATE_PDP, /* Activate PDP */ INIT_STATE_COMPLETE, /* Init complete */ INIT_STATE_RETRY_WAIT /* Wait for retry */ } init_state_t; static init_state_t s_init_state = INIT_STATE_STARTING; static int s_retry_count = 0; static rt_tick_t s_retry_start_tick = 0; /* 配置参数 */ #define RETRY_DELAY_MS 30000 /* 重试间隔30秒 */ #define SIM_WAIT_MAX 30 /* SIM等待最多30秒 */ #define NETWORK_WAIT_MAX 60 /* 网络等待最多60秒 */ /* 日志记录阈值 */ #define FAIL_THRESHOLD 3 /* 连续失败3次才记录 */ #define LOG_INTERVAL_MS (10 * 60 * 1000) /* 日志记录间隔10分钟 */ /* 故障类型枚举 - 细化原因 */ typedef enum { FAIL_TYPE_SIM_NOT_INSERT = 1, /* SIM未插入 */ FAIL_TYPE_SIM_INVALID, /* SIM失效/损坏 */ FAIL_TYPE_SIM_UNKNOWN, /* SIM其他错误 */ FAIL_TYPE_NETWORK_REG, /* 网络注册失败 */ FAIL_TYPE_PDP_ACT /* PDP激活失败 */ } fail_type_t; /* 各故障类型的记录状态 */ typedef struct { fail_type_t type; const char *desc; int consecutive_count; /* 当前连续失败次数 */ rt_tick_t last_log_tick; /* 上次记录时间 */ } fail_status_t; static fail_status_t s_fail_status[] = { {FAIL_TYPE_SIM_NOT_INSERT, "SIM未插入", 0, 0}, {FAIL_TYPE_SIM_INVALID, "SIM失效", 0, 0}, {FAIL_TYPE_SIM_UNKNOWN, "SIM错误", 0, 0}, {FAIL_TYPE_NETWORK_REG, "网络注册", 0, 0}, {FAIL_TYPE_PDP_ACT, "PDP激活", 0, 0}}; /* 外部函数声明 */ #include "ecode.h" extern void Recode_e_code(ecode_list code, uint16_t para, char *detail); extern int ym310_at_core_init(void); /*============================================================================= * SIM Card Status Detection *=============================================================================*/ static int check_sim_status(char *error_detail, int detail_size) { at_resp_type_t resp; char resp_buf[128]; resp = ym310_at_exec_cmd("AT+CPIN?", resp_buf, sizeof(resp_buf), YM310_AT_CMD_TIMEOUT_MS); if (resp != AT_RESP_OK) { rt_snprintf(error_detail, detail_size, "Query failed"); return -1; } if (rt_strstr(resp_buf, "READY") != RT_NULL) { return 0; } else if (rt_strstr(resp_buf, "SIM NOT INSERTED") != RT_NULL || rt_strstr(resp_buf, "NOT INSERTED") != RT_NULL) { rt_snprintf(error_detail, detail_size, "SIM not inserted"); return FAIL_TYPE_SIM_NOT_INSERT; } else if (rt_strstr(resp_buf, "SIM PIN") != RT_NULL) { rt_snprintf(error_detail, detail_size, "PIN required"); return FAIL_TYPE_SIM_INVALID; } else if (rt_strstr(resp_buf, "SIM PUK") != RT_NULL) { rt_snprintf(error_detail, detail_size, "PUK required"); return FAIL_TYPE_SIM_INVALID; } else if (rt_strstr(resp_buf, "SIM ERROR") != RT_NULL || rt_strstr(resp_buf, "ERROR") != RT_NULL) { rt_snprintf(error_detail, detail_size, "SIM card error"); return FAIL_TYPE_SIM_INVALID; } else { rt_snprintf(error_detail, detail_size, "Unknown status"); return FAIL_TYPE_SIM_UNKNOWN; } } /*============================================================================= * Smart Log Recording - 10 minute interval *=============================================================================*/ static void log_persistent_failure(fail_type_t type, int fail_count, const char *extra_info) { char detail[128]; rt_tick_t now = rt_tick_get(); rt_tick_t log_interval = rt_tick_from_millisecond(LOG_INTERVAL_MS); for (int i = 0; i < sizeof(s_fail_status) / sizeof(s_fail_status[0]); i++) { if (s_fail_status[i].type == type) { if (now - s_fail_status[i].last_log_tick < log_interval) { LOG_D("Skip logging %s: within %d min", s_fail_status[i].desc, LOG_INTERVAL_MS / 60000); return; } s_fail_status[i].last_log_tick = now; if (extra_info && extra_info[0] != '\0') { rt_snprintf(detail, sizeof(detail), "%s(%d次) %s", s_fail_status[i].desc, fail_count, extra_info); } else { rt_snprintf(detail, sizeof(detail), "%s(%d次)", s_fail_status[i].desc, fail_count); } LOG_W("%s", detail); Recode_e_code(e_NET_INIT_FAIL, fail_count, detail); return; } } } static void reset_fail_counter(fail_type_t type) { for (int i = 0; i < sizeof(s_fail_status) / sizeof(s_fail_status[0]); i++) { if (s_fail_status[i].type == type) { s_fail_status[i].consecutive_count = 0; break; } } } static void increment_fail_counter(fail_type_t type, const char *extra_info) { for (int i = 0; i < sizeof(s_fail_status) / sizeof(s_fail_status[0]); i++) { if (s_fail_status[i].type == type) { s_fail_status[i].consecutive_count++; if (s_fail_status[i].consecutive_count >= FAIL_THRESHOLD) { log_persistent_failure(type, s_fail_status[i].consecutive_count, extra_info); s_fail_status[i].consecutive_count = 0; } break; } } } extern void gpio_lte_ctrl(rt_bool_t on); /*============================================================================= * Module Power Control *=============================================================================*/ static int ym310_power_on(void) { LOG_I("Powering on YM310 module..."); gpio_lte_ctrl(1); rt_thread_mdelay(1000); int retry = 0; while (retry < 10) { at_resp_type_t resp; char buf[64]; resp = ym310_at_exec_cmd("AT", buf, sizeof(buf), 3000); if (resp == AT_RESP_OK) { LOG_I("Module responded to AT"); rt_thread_mdelay(500); return RT_EOK; } retry++; rt_thread_mdelay(500); } LOG_W("Module may not be fully ready, continuing anyway"); return RT_EOK; } /*============================================================================= * Module Basic Configuration *=============================================================================*/ static int ym310_basic_config(void) { at_resp_type_t resp; char resp_buf[128]; int sim_retry = 0; char sim_error[32]; ym310_at_exec_cmd_with_retry("ATE0", RT_NULL, 0, YM310_AT_CMD_TIMEOUT_MS, 3); ym310_at_exec_cmd_with_retry("AT+CMEE=2", RT_NULL, 0, YM310_AT_CMD_TIMEOUT_MS, 3); while (sim_retry < SIM_WAIT_MAX) { resp = ym310_at_exec_cmd("AT+CPIN?", resp_buf, sizeof(resp_buf), YM310_AT_CMD_TIMEOUT_MS); if (resp == AT_RESP_OK && rt_strstr(resp_buf, "READY") != RT_NULL) { LOG_I("SIM card ready"); reset_fail_counter(FAIL_TYPE_SIM_NOT_INSERT); reset_fail_counter(FAIL_TYPE_SIM_INVALID); reset_fail_counter(FAIL_TYPE_SIM_UNKNOWN); return RT_EOK; } sim_retry++; rt_thread_mdelay(1000); } int sim_status = check_sim_status(sim_error, sizeof(sim_error)); if (sim_status > 0) { increment_fail_counter((fail_type_t)sim_status, sim_error); } else { increment_fail_counter(FAIL_TYPE_SIM_UNKNOWN, "SIM not ready"); } LOG_W("SIM not ready after %d retries >>>%s<<<", SIM_WAIT_MAX, resp_buf); return -RT_ERROR; } /*============================================================================= * Network Registration *=============================================================================*/ static int ym310_wait_for_network(void) { int retry_count = 0; LOG_D("Waiting for network registration..."); while (retry_count < NETWORK_WAIT_MAX) { if (ym310_check_network_connected() == RT_TRUE) { LOG_D("Network registered and GPRS attached"); reset_fail_counter(FAIL_TYPE_NETWORK_REG); return RT_EOK; } retry_count++; if (retry_count % 10 == 0) { LOG_D("Waiting for network... (%d/%d)", retry_count, NETWORK_WAIT_MAX); } rt_thread_mdelay(1000); } LOG_W("Network registration timeout"); increment_fail_counter(FAIL_TYPE_NETWORK_REG, NULL); return -RT_ERROR; } /*============================================================================= * PDP Context Activation *=============================================================================*/ static int ym310_activate_pdp(void) { at_resp_type_t resp; LOG_D("Activating PDP context..."); if (ym310_check_network_connected() == RT_TRUE) { LOG_D("PDP already active"); reset_fail_counter(FAIL_TYPE_PDP_ACT); return RT_EOK; } resp = ym310_at_exec_cmd("AT+QIPACT=1", RT_NULL, 0, YM310_AT_LONG_TIMEOUT_MS); if (resp != AT_RESP_OK) { rt_thread_mdelay(2000); if (ym310_check_network_connected() == RT_TRUE) { LOG_I("PDP activated successfully (verified)"); reset_fail_counter(FAIL_TYPE_PDP_ACT); return RT_EOK; } LOG_W("PDP activation failed"); increment_fail_counter(FAIL_TYPE_PDP_ACT, NULL); return -RT_ERROR; } rt_thread_mdelay(2000); if (ym310_check_network_connected() == RT_TRUE) { LOG_I("PDP activated"); reset_fail_counter(FAIL_TYPE_PDP_ACT); return RT_EOK; } increment_fail_counter(FAIL_TYPE_PDP_ACT, NULL); return -RT_ERROR; } /*============================================================================= * Init Thread - Only handles init, enters idle state after completion *=============================================================================*/ static void ym310_init_thread_entry(void *param) { int ret; // LOG_I("========================================"); // LOG_I("INITIALIZATION THREAD STARTED"); // LOG_I("========================================"); s_init_thread_running = RT_TRUE; s_init_state = INIT_STATE_STARTING; /* Main loop - only handles init, enters idle sleep after completion */ while (s_init_thread_running) { switch (s_init_state) { case INIT_STATE_STARTING: if (!s_at_core_initialized) { LOG_I("Initializing AT core..."); if (ym310_at_core_init() == RT_EOK) { s_at_core_initialized = RT_TRUE; // LOG_I("AT core initialized"); s_init_state = INIT_STATE_POWER_ON; } else { LOG_E("AT core init failed, will retry later"); s_init_state = INIT_STATE_RETRY_WAIT; s_retry_start_tick = rt_tick_get(); } } else { s_init_state = INIT_STATE_POWER_ON; } rt_thread_mdelay(100); break; case INIT_STATE_RETRY_WAIT: if ((rt_tick_get() - s_retry_start_tick) >= rt_tick_from_millisecond(RETRY_DELAY_MS)) { s_retry_count++; LOG_I("Retry configuration (%d)...", s_retry_count + 1); if (s_at_core_initialized) { s_init_state = INIT_STATE_POWER_ON; } else { if (ym310_at_core_init() == RT_EOK) { s_at_core_initialized = RT_TRUE; s_init_state = INIT_STATE_POWER_ON; } else { LOG_E("AT core init failed again"); s_retry_start_tick = rt_tick_get(); } } } rt_thread_mdelay(1000); break; case INIT_STATE_POWER_ON: ret = ym310_power_on(); if (ret == RT_EOK) { s_init_state = INIT_STATE_BASIC_CONFIG; } else { LOG_W("Power on failed, retry later"); s_init_state = INIT_STATE_RETRY_WAIT; s_retry_start_tick = rt_tick_get(); } rt_thread_mdelay(100); break; case INIT_STATE_BASIC_CONFIG: ret = ym310_basic_config(); if (ret == RT_EOK) { s_init_state = INIT_STATE_WAIT_NETWORK; } else { LOG_W("Basic config failed (SIM issue), will retry later"); s_init_state = INIT_STATE_RETRY_WAIT; s_retry_start_tick = rt_tick_get(); } rt_thread_mdelay(100); break; case INIT_STATE_WAIT_NETWORK: ret = ym310_wait_for_network(); if (ret == RT_EOK) { s_init_state = INIT_STATE_ACTIVATE_PDP; } else { LOG_W("Network not ready, will retry later"); s_init_state = INIT_STATE_RETRY_WAIT; s_retry_start_tick = rt_tick_get(); } rt_thread_mdelay(100); break; case INIT_STATE_ACTIVATE_PDP: ret = ym310_activate_pdp(); if (ret == RT_EOK) { /* ===== 新增:PDP激活成功后立即同步NTP时间 ===== */ LOG_I("PDP activated, syncing NTP time..."); if (ym310_ntp_sync_time() == RT_EOK) { LOG_I("NTP sync successful during init"); } else { LOG_W("NTP sync failed during init, will retry later"); } /* ============================================= */ s_init_state = INIT_STATE_COMPLETE; s_module_initialized = RT_TRUE; s_network_ready = RT_TRUE; s_retry_count = 0; LOG_D("========================================"); LOG_D("MODULE INITIALIZATION COMPLETE"); LOG_D("========================================"); /* Start MQTT thread (only once) */ if (g_mqtt_thread == RT_NULL) { g_mqtt_thread = ym310_start_mqtt_thread(); if (g_mqtt_thread == RT_NULL) { LOG_E("Failed to start MQTT thread!"); } } /* Start maintenance thread (only once) */ if (g_maintain_thread == RT_NULL) { g_maintain_thread = ym310_start_maintain_thread(); if (g_maintain_thread == RT_NULL) { LOG_E("Failed to start maintenance thread!"); } } /* Init complete, enter idle state, no more checks (maintain thread handles) */ s_init_state = INIT_STATE_COMPLETE; } else { LOG_W("PDP activation failed, will retry later"); s_init_state = INIT_STATE_RETRY_WAIT; s_retry_start_tick = rt_tick_get(); } rt_thread_mdelay(100); break; case INIT_STATE_COMPLETE: /* Init complete, thread sleeps, no more work */ rt_thread_mdelay(1000); /* Wake once per minute, do nothing, keep thread alive */ s_init_thread_running = RT_FALSE; break; default: break; } } LOG_I("Initialization thread exit"); } /*============================================================================= * Public API *=============================================================================*/ rt_thread_t ym310_start_init_thread(void) { if (g_init_thread != RT_NULL) { LOG_D("Init thread already running"); return g_init_thread; } if (ym310_mqtt_init() != RT_EOK) { LOG_E("MQTT init failed!"); return RT_NULL; } g_init_thread = rt_thread_create("ym310_init", ym310_init_thread_entry, RT_NULL, INIT_THREAD_STACK_SIZE, INIT_THREAD_PRIORITY, 10); if (g_init_thread == RT_NULL) { LOG_E("Failed to create init thread!"); return RT_NULL; } rt_thread_startup(g_init_thread); LOG_D("Initialization thread created"); return g_init_thread; } void ym310_init_thread_stop(void) { s_init_thread_running = RT_FALSE; } rt_bool_t ym310_is_module_initialized(void) { return s_module_initialized; } rt_bool_t ym310_is_network_ready(void) { return s_network_ready; }