优化时间线逻辑 3424/1 3424/head 3425/target/1
authorxue <2144439972@qq.com>
Wed, 27 May 2026 02:13:54 +0000 (10:13 +0800)
committerxue <2144439972@qq.com>
Wed, 27 May 2026 02:13:54 +0000 (10:13 +0800)
15 files changed:
code/sdk/application/wearable/ln/nativeapp/nativeui/alarmclocktimerconfig/src/AlarmClockTimerConfig.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/ota/src/OtaModel.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp
code/sdk/application/wearable/ln/service/power_manager/CMakeLists.txt
code/sdk/application/wearable/ln/service/power_manager/src/actions/display_action.c
code/sdk/zhihui/4g/cat1Service/Service/cat1_server.c
code/sdk/zhihui/4g/cat1Service/Service/cat1_tcpServer.c
code/sdk/zhihui/4g/cat1Service/include/cat1_pub_api.h
code/sdk/zhihui/leiniao/imsl_ln/CMakeLists.txt
code/sdk/zhihui/leiniao/imsl_ln/ln_api.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api.h
code/sdk/zhihui/leiniao/imsl_ln/ln_api_ota.c
code/sdk/zhihui/leiniao/ln_api_cpp/CMakeLists.txt
code/sdk/zhihui/leiniao/ln_api_cpp/ln_api_interface.cpp
code/sdk/zhihui/leiniao/ln_api_cpp/ln_api_interface.h

index b70d034..1053140 100644 (file)
@@ -102,14 +102,9 @@ static void LN_OPERATE_AlarmCallBackProcC(struct tm curTime)
     if (curTime.tm_hour == 0 && curTime.tm_min == 0 && curTime.tm_sec == 0) {\r
         do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_EMOJI_REPORT_ALL, NULL, 0);\r
     }\r
-    //整点上报时间线状态\r
-    if(curTime.tm_min == 0 && curTime.tm_sec == 0)\r
-    {\r
-        //获取是否绑定\r
-        if(uapi_ln_is_device_bound()) \r
-        {\r
-            do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_TIMELINE_GET_STATUS, NULL, 0);\r
-        }\r
+    //整点上报时间线状态(亮屏立即获取,息屏推迟到按键亮屏后补拉)\r
+    if (curTime.tm_min == 0 && curTime.tm_sec == 0) {\r
+        ln_timeline_scheduled_hourly_fetch();\r
     }\r
     //每天凌晨2点检查夜间更新状态\r
     if(curTime.tm_hour == 2 && curTime.tm_min == 0 && curTime.tm_sec == 0)\r
index e2131f1..c6f3b99 100644 (file)
@@ -299,6 +299,8 @@ namespace OHOS
             }
             if (OtaSuccessView::GetInstance()) {
                 OtaSuccessView::GetInstance()->UpdateDownloadSuccess("模组升级失败");
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+                    "[ota]CheckOtaResult: Cat1 failed, update failed");
             }
         } else if (status == 4) {
 #ifdef SUPPORT_CAT1_SERVICE
@@ -307,11 +309,14 @@ namespace OHOS
             uint8_t min = 0;
             const bool still_1047 = (uapi_get_fw_version(&maj, &mid, &min) == ERRCODE_SUCC && maj == 1 && mid == 0 &&
                 min == 47);
-            const bool py_not_34 = (uapi_get_py_ver() != 34);
-            if (still_1047 && py_not_34) {
+            char kv_mark[8] = {0};
+            (void)UtilsGetValue("cat1_py34_upgrade_done", kv_mark, sizeof(kv_mark));
+            const bool py34_prereq = (uapi_get_py_ver() >= 34) &&
+                ((strcmp(kv_mark, "1") == 0) || uapi_cat1_ota_is_py34_verified());
+            if (still_1047 && !py34_prereq) {
                 WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
-                    "CheckOtaResult: Cat1 ok, sw still 1.0.47 py=%u(!=34), stay updating for next round",
-                    (unsigned)uapi_get_py_ver());
+                    "[ota]CheckOtaResult: Cat1 round done but py34 prereq not met, py=%u kv=%s verified=%d, stay updating",
+                    (unsigned)uapi_get_py_ver(), kv_mark, uapi_cat1_ota_is_py34_verified());
                 SetOtaStatus(OTA_UI_STATUS_CAT1_START);
                 ThunderBirdModel::GetInstance()->PrepareCat1NextRoundAfterSuccess();
                 if (OtaUpdatingView::GetInstance()) {
@@ -327,11 +332,13 @@ namespace OHOS
                 OtaSuccessView::GetInstance()->UpdateDownloadSuccess("模组升级成功");
             }
 #ifdef SUPPORT_CAT1_SERVICE
-            /* 以 g_ln_last_package_url_new2/new1(getTask 写入)中的 PY_SRV_Vxx 为准 */
-            if (status == 4 && ln_cat1_last_package_urls_target_py() == 34) {
+            /* 本次 Cat1 真升:URL 目标 V34 + 当前 py>=34 + OTA 前基线 < 34 */
+            if (status == 4 && ln_cat1_last_package_urls_target_py() == 34 && uapi_get_py_ver() >= 34 &&
+                uapi_cat1_ota_get_py_baseline() < 34) {
                 (void)UtilsSetValue("cat1_py34_upgrade_done", "1");
                 WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
-                    "CheckOtaResult: Cat1 success, URL target py=34, KV cat1_py34_upgrade_done=1");
+                    "[ota]CheckOtaResult: Cat1 verified py34, baseline=%u->%u, KV cat1_py34_upgrade_done=1",
+                    (unsigned)uapi_cat1_ota_get_py_baseline(), (unsigned)uapi_get_py_ver());
             }
 #endif
         }
index 40cb8a1..8f0dc44 100644 (file)
@@ -101,7 +101,13 @@ static bool IsSoftwareVersion_1_0_47(void)
     char mark[8] = {0};
     (void)UtilsGetValue(kKvCat1Py34UpgradeDone, mark, sizeof(mark));
     if (strcmp(mark, "1") == 0) {
-        return false;
+        if (uapi_get_py_ver() >= 34) {
+            return false;
+        }
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+            "[ota]IsSoftwareVersion_1_0_47: KV py34 set but runtime py=%u, clear KV",
+            (unsigned)uapi_get_py_ver());
+        (void)UtilsDeleteValue(kKvCat1Py34UpgradeDone);
     }
     uint8_t major = 0;
     uint8_t mid = 0;
index bb829f8..f14150c 100644 (file)
@@ -32,6 +32,9 @@
 #if defined(CUSTOM_UTILS) && defined(BOARD_LEINIAO)\r
 #include "custom_utils.h"\r
 #endif\r
+#if defined(BOARD_LEINIAO)\r
+#include "ln_api.h"\r
+#endif\r
 /* GBL_CTL_M中SOFT_RST_4寄存器 */\r
 #define DISPLAY_LOGIC_CRG_RESET 0x570000c0\r
 /**\r
@@ -244,8 +247,6 @@ static uint32_t action_display_lcd_off()
 \r
 int32_t action_display_execute_entry(uint16_t action_bitmap, uint16_t new_state, event_type_t type, uint32_t event)\r
 {\r
-    unused(type);\r
-    unused(event);\r
 \r
     screen_context_t *sc = power_display_get_screen_context();\r
     uint32_t ret;\r
@@ -264,6 +265,12 @@ int32_t action_display_execute_entry(uint16_t action_bitmap, uint16_t new_state,
             return ret;\r
         }\r
         POWER_DISPLAY_PRINT_DEBUG(0, "turn on success.");\r
+#if defined(BOARD_LEINIAO)\r
+        /* 按键亮屏时补拉整点因息屏未获取的时间线 */\r
+        if (type == GUI_EVENT && (event & GUI_EVENT_TYPE_MASK) == KEY) {\r
+            ln_timeline_try_fetch_pending_on_wakeup();\r
+        }\r
+#endif\r
     }\r
 \r
     if ((action_bitmap & GET_ACTION_MASK(SET_DISPLAY_TO_IDLE_MODE)) != 0) {\r
index 9e34a71..10a40f9 100644 (file)
@@ -413,6 +413,29 @@ uint8_t uapi_get_py_ver(void)
     return g_py_ver;
 }
 
+static uint8_t g_cat1_ota_py_baseline = 0;
+static uint8_t g_cat1_py34_session_verified = 0;
+
+void uapi_cat1_ota_begin(uint8_t baseline_py)
+{
+    g_cat1_ota_py_baseline = baseline_py;
+    g_cat1_py34_session_verified = 0;
+}
+
+uint8_t uapi_cat1_ota_get_py_baseline(void)
+{
+    return g_cat1_ota_py_baseline;
+}
+
+void uapi_cat1_ota_mark_py34_verified(void)
+{
+    g_cat1_py34_session_verified = 1;
+}
+
+int uapi_cat1_ota_is_py34_verified(void)
+{
+    return g_cat1_py34_session_verified ? 1 : 0;
+}
 
 static osTimerId_t g_timer_time_answer = NULL;
 
index 13cbada..7a79b4a 100644 (file)
@@ -1372,18 +1372,39 @@ static uint16 mode_ota_count=0;
 #ifdef BOARD_LEINIAO
 #include "ln_api_interface.h"
 int cat1_model_oat_suc_flag = 0;//模组升级标志
+
+static uint8_t cat1_ota_resolve_target_py(void)
+{
+    int target = ln_cat1_last_package_urls_target_py();
+    if (target > 0 && target <= 255) {
+        return (uint8_t)target;
+    }
+    return 34;
+}
 #endif
 static void  modem_ota_timer_CallBack(int data_tmp)
 {
-    printf("modem_ota_timer_CallBack %d old_model_ver %d g_py_ver %d\n",mode_ota_count,old_model_ver,uapi_get_py_ver());
-    if(old_model_ver!=uapi_get_py_ver())
+    int cat1_ota_ok = 0;
+    printf("modem_ota_timer_CallBack %d old_model_ver %d g_py_ver %d baseline %u\n", mode_ota_count,
+        old_model_ver, uapi_get_py_ver(), (unsigned)uapi_cat1_ota_get_py_baseline());
+#ifdef BOARD_LEINIAO
     {
+        uint8_t cur_py = uapi_get_py_ver();
+        uint8_t target_py = cat1_ota_resolve_target_py();
+        uint8_t baseline_py = uapi_cat1_ota_get_py_baseline();
+        cat1_ota_ok = (cur_py >= target_py && cur_py > baseline_py) ? 1 : 0;
+    }
+#else
+    cat1_ota_ok = (old_model_ver != uapi_get_py_ver()) ? 1 : 0;
+#endif
+    if (cat1_ota_ok) {
         uint8_t TRANSMIT_DATA=TRANS_FREE;
 
         #ifdef BOARD_LEINIAO
+        uapi_cat1_ota_mark_py34_verified();
         push_ota_status(OTA_UI_STATUS_SUCCESS);
         /* 不在 4G 模组 OTA 成功后立即重启,便于继续后续手表 OTA(原 shutdown_reboot_prejobs(REBOOT_TYPE)) */
-        printf("[OTA] Cat1 OTA py_ver changed: skip immediate reboot\r\n");
+        printf("[OTA] Cat1 OTA ok: cur>baseline and >= target, skip immediate reboot\r\n");
         #else
         CustomEventPublish(TOPIC_EVENT_BLE_TRANSMIT,&TRANSMIT_DATA,1);
         #endif
@@ -1394,14 +1415,18 @@ static void  modem_ota_timer_CallBack(int data_tmp)
         modem_ota_timer = NULL;
     }
 
-    }
-    else
-    {
+    } else {
         mode_ota_count++;
         if(mode_ota_count>120 || g_py_ver_new==0)
         {
             uint8_t TRANSMIT_DATA=OTA_UPDATA_FAIL;
             CustomEventPublish(TOPIC_EVENT_BLE_TRANSMIT,&TRANSMIT_DATA,1);
+#ifdef BOARD_LEINIAO
+            push_ota_status(OTA_UI_STATUS_FAILED);
+            printf("[OTA] Cat1 OTA timeout/fail py=%u baseline=%u target=%u\r\n",
+                (unsigned)uapi_get_py_ver(), (unsigned)uapi_cat1_ota_get_py_baseline(),
+                (unsigned)cat1_ota_resolve_target_py());
+#endif
 
             if(modem_ota_timer){
             osTimerStop(modem_ota_timer);
@@ -1467,6 +1492,7 @@ void star_http_ota_updata(char*buf_1,char* buf_2,uint8_t ver)
     CustomEventPublish(TOPIC_EVENT_BLE_TRANSMIT,&TRANSMIT_DATA,1);
     #endif
 
+    uapi_cat1_ota_begin(ver);
     old_model_ver=ver;
 
 
index 941db21..1033243 100644 (file)
@@ -131,6 +131,14 @@ char* cat1_api_runtime_get_cat1_pyver(void);
  * @return 返回Python服务版本号,例如:4, 16, 28, 29等
  * */
 uint8_t uapi_get_py_ver(void);
+
+/** Cat1 OTA 开始前记录 Py 基线(star_http_ota_updata 调用) */
+void uapi_cat1_ota_begin(uint8_t baseline_py);
+uint8_t uapi_cat1_ota_get_py_baseline(void);
+/** 本次会话 Cat1 已确认升到目标 Py(非仅口播已是高版本) */
+void uapi_cat1_ota_mark_py34_verified(void);
+int uapi_cat1_ota_is_py34_verified(void);
+
 /**
  * @brief 获取modem版本
  * @return modem版本字符串,sdk当下版本唯一 EG810MCNLAR06A01M08_VOLTE_OCPU_QPY_BETA0312
index 8cd23ff..9a38fe6 100644 (file)
@@ -63,7 +63,6 @@ set(PUBLIC_DEFINES
 
 # 私有头文件路径(仅当前组件内部使用)
 set(PRIVATE_HEADER
-    # 如无特殊私有头文件,可留空
     ${CMAKE_CURRENT_SOURCE_DIR}/
 )
 
index f26a519..e557823 100644 (file)
@@ -1587,6 +1587,42 @@ errcode_t uapi_ln_http_server_init(void)
     return ERRCODE_SUCC;
 }
 
+/* 整点时间线获取:息屏时置位,按键亮屏后补拉 */
+static uint8_t g_ln_timeline_fetch_pending = 0;
+
+
+static void ln_timeline_do_get_status(void)
+{
+    if (!uapi_ln_is_device_bound()) {
+        return;
+    }
+    do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_TIMELINE_GET_STATUS, NULL, 0);
+    g_ln_timeline_fetch_pending = 0;
+}
+
+void ln_timeline_scheduled_hourly_fetch(void)
+{
+    if (!uapi_ln_is_device_bound()) {
+        return;
+    }
+    /* uapi_get_screen_state: 0=亮屏, 1=息屏 */
+    if (uapi_get_screen_state() == 0) {
+        ln_timeline_do_get_status();
+    } else {
+        g_ln_timeline_fetch_pending = 1;
+    }
+}
+
+void ln_timeline_try_fetch_pending_on_wakeup(void)
+{
+    if (g_ln_timeline_fetch_pending == 0) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[时间线] g_ln_timeline_fetch_pending == 0");    
+    return;
+    }
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[时间线] g_ln_timeline_fetch_pending == 1");
+    ln_timeline_do_get_status();
+}
+
 /* 获取设备业务忙状态(返回业务忙描述字符串,如果设备空闲则返回NULL) */
 const char* uapi_ln_get_device_busy_status(void)
 {
index 6d8c6b0..6736e58 100644 (file)
@@ -28,7 +28,7 @@ typedef struct
 
 /* ============================== 公共宏与URL路径 ============================== */
 #define LN_VOICE_CHAT_ENABLED 0  //声纹锁开启宏
-#define LN_ENV_PRODUCTION 1  //正式环境
+#define LN_ENV_PRODUCTION 0  //正式环境
 /* 接口基础配置 - 如需切换环境/密钥,在此调整 */
 #if LN_ENV_PRODUCTION
 #define LN_BASE_URL "https://ambybox-o.api.leiniao.com/ambybox-device-api"   //正式环境服务器地址
@@ -426,6 +426,9 @@ int ln_ws_send_bluetooth_unbind_ack(const char *bluetooth_address, const char *b
 /* 查询时间线状态(GET /v1/timeline/getStatus)*/
 uint32_t ln_timeline_get_status_http(const char *device_id,
                                      const char *device_token);
+/* 整点获取时间线:亮屏立即拉取,息屏置待获取标志,按键亮屏后补拉 */
+void ln_timeline_scheduled_hourly_fetch(void);
+void ln_timeline_try_fetch_pending_on_wakeup(void);
 
 /* ============================== 各接口函数声明 ============================== */
 uint32_t ln_get_device_token_http(const char *device_id,
index 9dc055e..aad8ae3 100644 (file)
@@ -12,9 +12,7 @@
 #include "cat1_pub_api.h"
 #endif
 #include "cat1_pub_api.h"  /* 包含 uapi_get_py_ver() 函数声明 */
-
-// static int ln_ota_reject_1047_if_not_py34(const char *target);
-
+#include "ln_api_interface.h"
 
 /* OTA下载状态枚举(对应时序图中的下载阶段)*/
 typedef enum
@@ -187,10 +185,10 @@ static int ln_ota_target_is_1047(const char *target)
     return 0;
 }
 
-/* 1.0.47 仅当 Cat1 已先升到 Py 版 34 后才允许,否则需先走 Py 升级再继续 */
+/* 1.0.47 手表 OTA:须满足 Py34 前置(KV 或本次 Cat1 会话真升),不能仅口播已是 V34 */
 static int ln_ota_reject_1047_if_not_py34(const char *target)
 {
-    return ln_ota_target_is_1047(target) && (uapi_get_py_ver() <34 && uapi_get_py_ver() != 32);
+    return ln_ota_target_is_1047(target) && !ln_cat1_py34_prereq_met();
 }
 
 //解析 OTA 任务 JSON,决定是否触发下载
@@ -199,8 +197,9 @@ static void ln_handle_ota_task_response(const char *json_buf, int json_len)
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"解析OTA升级任务JSON");
     if (ln_ota_reject_1047_if_not_py34(uapi_ln_get_device_version()))
     {
-        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[OTA] task rejected: 1.0.47 requires py version 34 first, current=%u",
-            (unsigned int)uapi_get_py_ver());
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+            "[OTA] task rejected: 1.0.47 requires cat1 py34 (KV or verified session), py=%u kv=%d verified=%d",
+            (unsigned int)uapi_get_py_ver(), ln_kv_cat1_py34_upgrade_done(), uapi_cat1_ota_is_py34_verified());
         return;
     }
 
@@ -1523,14 +1522,24 @@ void ln_is_cat1_ota_upgrade_check(void)
     // 直接获取CAT1 modem版本(如果版本还未获取,会在后续处理中处理)
     char *text = cat1_api_runtime_get_cat1_modemver();
     if (!text || strlen(text) == 0) {
-        printf("[OTA] cat1 modem版本为空,执行普通OTA升级\n");
+        if (!ln_cat1_py34_prereq_met()) {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+                "[OTA] modem ver empty: py34 prereq not met, skip host OTA");
+            return;
+        }
+        printf("[OTA] cat1 modem版本为空且py34已确认,执行普通OTA升级\n");
         do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_OTA_GET_TASK, NULL, 0);
         return;
     }
     
     char version[16] = {0};
     if (get_modem_fw_version_c(text, version) != 0) {
-        printf("[OTA] 无法解析modem版本,执行普通OTA升级\n");
+        if (!ln_cat1_py34_prereq_met()) {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+                "[OTA] modem ver parse fail: py34 prereq not met, skip host OTA");
+            return;
+        }
+        printf("[OTA] 无法解析modem版本且py34已确认,执行普通OTA升级\n");
         do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_OTA_GET_TASK, NULL, 0);
         return;
     }
@@ -1567,7 +1576,13 @@ void ln_is_cat1_ota_upgrade_check(void)
     
     // 检查cat1模组升级url是否为空
     if(strlen(g_ln_last_package_url_new1) == 0 || strlen(g_ln_last_package_url_new2) == 0) {
-        printf("[OTA] cat1模组升级url为空,执行普通OTA升级\n");
+        if (!ln_cat1_py34_prereq_met()) {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+                "[OTA] cat1 url empty: py34 prereq not met, skip host OTA (py=%u kv=%d verified=%d)",
+                (unsigned)uapi_get_py_ver(), ln_kv_cat1_py34_upgrade_done(), uapi_cat1_ota_is_py34_verified());
+            return;
+        }
+        printf("[OTA] cat1模组升级url为空且py34已确认,执行普通OTA升级\n");
         do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_OTA_GET_TASK, NULL, 0);
     } else {
         printf("[OTA] cat1模组升级url不为空,触发CAT1升级\n");
index 2ca54bd..5bcba15 100644 (file)
@@ -10,6 +10,8 @@ set(PUBLIC_HEADER
 
 
 set(PRIVATE_HEADER
+${ROOT_DIR}/open_source/openharmony/utils/native/lite/include
+${ROOT_DIR}/zhihui/4g/cat1Service/include
 ${ROOT_DIR}/middleware/services/media/foundation/audiomanager/interfaces/kits/audiomanager
 ${ROOT_DIR}/middleware/services/media/foundation/audiomanager/interfaces/kits/audiocommon
 ${ROOT_DIR}/middleware/services/media/foundation/audiomanager/frameworks/audiostream/include
index aa01a03..cd57e09 100644 (file)
@@ -15,6 +15,28 @@ extern "C"
 
 #include <stdlib.h>
 #include <cstdio>
+#include <cstring>
+#include "kv_store.h"
+#include "cat1_pub_api.h"
+
+#define LN_CAT1_PY34_MIN_VER         34
+#define LN_KV_CAT1_PY34_UPGRADE_DONE "cat1_py34_upgrade_done"
+
+int ln_kv_cat1_py34_upgrade_done(void)
+{
+    char mark[8] = {0};
+    (void)UtilsGetValue(LN_KV_CAT1_PY34_UPGRADE_DONE, mark, sizeof(mark));
+    return (strcmp(mark, "1") == 0) ? 1 : 0;
+}
+
+int ln_cat1_py34_prereq_met(void)
+{
+    uint8_t py = uapi_get_py_ver();
+    if (py < LN_CAT1_PY34_MIN_VER && py != 32) {
+        return 0;
+    }
+    return ln_kv_cat1_py34_upgrade_done() || uapi_cat1_ota_is_py34_verified();
+}
 
 // 推送文本给ui
 void push_text_to_ui(const char *text)
index 4a86abe..51777a0 100644 (file)
@@ -134,6 +134,17 @@ void push_vad_initialized_notification(void);
 void push_bluetooth_connect_notification(const char *bluetoothAddress);
 //获取UI中设置的音量值(未真正设置到系统的音量)
 int32_t get_ui_volume(void);
+
+/* Cat1 OTA 双包 URL(ln_api_ota 写入,cat1 模块可读目标 Py 版本) */
+extern char g_ln_last_package_url_new1[256];
+extern char g_ln_last_package_url_new2[256];
+/** 从 URL 路径解析 PY_SRV_Vxx,优先 new2;失败返回 -1 */
+int ln_cat1_last_package_urls_target_py(void);
+/** KV cat1_py34_upgrade_done 是否为 1 */
+int ln_kv_cat1_py34_upgrade_done(void);
+/** Cat1 已真升到 Py34:KV 或本次 OTA verified */
+int ln_cat1_py34_prereq_met(void);
+
 #ifdef __cplusplus
 }
 #endif