#define LOW_FREQUENCE 18
//最高视频帧率
#define HIGH_FREQUENCE 30
+
+// uapi_get_py_ver() 函数声明已在 cat1_pub_api.h 中
+
namespace OHOS
{
enum OTA_STATUS
}
// 启动定时器(5秒 = 5000毫秒)
- osStatus_t ret = osTimerStart(m_storyAudioPlaybackTimeoutTimer, 5000);
+ osStatus_t ret = osTimerStart(m_storyAudioPlaybackTimeoutTimer, 10000);
if (ret != osOK) {
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to start story audio playback timeout timer, ret=%d", ret);
osTimerDelete(m_storyAudioPlaybackTimeoutTimer);
return 0;
}
- extern uint8_t g_py_ver;
bool ThunderBirdModel::is_Cat1_OtaUpgrade()
{
// 发送命令到后台线程执行,避免阻塞UI线程
// }
#ifdef SUPPORT_CAT1_SERVICE
- star_http_ota_updata(g_ln_last_package_url_new1,g_ln_last_package_url_new2,g_py_ver);
+ star_http_ota_updata(g_ln_last_package_url_new1,g_ln_last_package_url_new2,uapi_get_py_ver());
#endif
// push_ota_status(OTA_UI_STATUS_FORCE_START);
}
// 切换表情
bool ThunderBirdModel::SwitchExpressionVideo(const char* videoPath)
{
- // 参数验证
if (videoPath == nullptr) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: videoPath is null");
return false;
}
- // 检查文件是否存在(宽松检查)
if (access(videoPath, F_OK) != 0) {
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: file does not exist: %s", videoPath);
return false;
}
- // 尝试检查文件大小(非强制)
struct stat fileStat;
if (stat(videoPath, &fileStat) == 0) {
if (fileStat.st_size == 0) {
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: file is empty: %s", videoPath);
return false;
}
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: file size: %ld bytes", fileStat.st_size);
- } else {
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: cannot get file stat for %s, proceeding anyway", videoPath);
}
- // 预处理文件路径,确保realpath能够成功
std::string normalizedPath = videoPath;
-
- // 尝试使用realpath规范化路径
char resolvedPath[PATH_MAX];
if (realpath(videoPath, resolvedPath) != nullptr) {
normalizedPath = std::string(resolvedPath);
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: normalized path: %s", normalizedPath.c_str());
- } else {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: realpath failed for %s, using original path", videoPath);
- // 如果realpath失败,使用原始路径
- normalizedPath = std::string(videoPath);
}
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: switching to video: %s", normalizedPath.c_str());
-
- // 检查 ThunderBirdMainView 是否已初始化
- // 如果未初始化,直接返回,避免在启动时出现问题
if (ThunderBirdMainView::GetInstance() == nullptr)
{
WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: ThunderBirdMainView not initialized yet, skipping switch");
return false;
}
- // 如果正在切换视频,等待完成(最多等待2秒)
- // 这样可以避免快速进入/退出对话模式时导致的表情切换冲突
if (ThunderBirdMainView::IsSwitchingVideo())
{
WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: Video switch in progress, waiting for completion...");
auto pathPtr = std::make_shared<std::string>(normalizedPath);
GraphicService::GetInstance()->PostGraphicEvent(
[pathPtr]() {
- // 等待之前的切换完成
ThunderBirdMainView* mainView = ThunderBirdMainView::GetInstance();
if (mainView != nullptr) {
ThunderBirdMainView::WaitForVideoSwitchComplete(2000);
- // 再次检查是否还在切换(防止超时后仍在切换)
if (!ThunderBirdMainView::IsSwitchingVideo()) {
- // 再次检查对象有效性,防止在执行过程中被销毁
ThunderBirdMainView* view = ThunderBirdMainView::GetInstance();
if (view != nullptr && pathPtr != nullptr) {
view->SwitchVideo(pathPtr->c_str());
- } else {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: Object invalidated during execution");
}
- } else {
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: Video switch still in progress after wait, skipping this switch");
}
- } else {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: ThunderBirdMainView instance is null");
}
});
} else {
- // 通过图形服务调用 ThunderBirdMainView 的 SwitchVideo 函数
- // 注意:PostGraphicEvent 是异步的,这里直接返回 true 表示调用已提交
- // 使用 shared_ptr 确保字符串生命周期,避免 lambda 执行时对象已销毁
auto pathPtr = std::make_shared<std::string>(normalizedPath);
GraphicService::GetInstance()->PostGraphicEvent(
[pathPtr]() {
ThunderBirdMainView* mainView = ThunderBirdMainView::GetInstance();
if (mainView != nullptr && pathPtr != nullptr) {
mainView->SwitchVideo(pathPtr->c_str());
- } else {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: ThunderBirdMainView instance is null or path invalid");
}
});
}
-
return true; // 异步调用,返回 true 表示调用已提交
}
void ThunderBirdModel::HandleSleepModeEnd()
{
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleSleepModeEnd");
+ // 清除哄睡模式激活标志位(防止后续SleepModeStart被拒绝)
+ uapi_set_sleep_mode_active(false);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleSleepModeEnd: sleep mode flag cleared");
// 停止故事模式超时定时器
StopStoryModeTimeoutTimer();
// 停止故事模式音频播放超时定时器
void ThunderBirdModel::HandleSleepModeEnd_BlueView()
{
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleSleepModeEnd");
+ // 清除哄睡模式激活标志位(防止后续SleepModeStart被拒绝)
+ uapi_set_sleep_mode_active(false);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleSleepModeEnd_BlueView: sleep mode flag cleared");
// 停止故事模式超时定时器
StopStoryModeTimeoutTimer();
// 重置故事模式finished标志
{
int currentView = ThunderBirdMainView::GetInstance()->GetCurrentView();
int currentSubView = ThunderBirdMainView::GetInstance()->GetCurrentSubView();
+
//切换状态文本
//亮屏
uapi_set_screen_on_api(); // 亮屏
+
if(currentView == THUNDERBIRD_DIALOGUEVIEW && currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_STATUS_SHOW)
{
ThunderBirdDialogueView::GetInstance()->UpdateDialogueText(m_currentStatusText.c_str());
std::string expressionPath;
std::string targetExpression = expression;
int screenImageMode = ReadlocalScreenImage();
+
// 如果ReadlocalScreenImage() == 1(有屏保但不是作为对话表情),在发呆中界面不切换表情,保持屏保显示
if(screenImageMode == 1 && currentView == THUNDERBIRD_DIALOGUEVIEW && currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_STATUS_SHOW)
{
RegisterFuncKeyOnClick_6_timesEvent();
}
-}
+
}
\ No newline at end of file
#define PY_SRV_VER_5 "PY_SRV_V5"
#define PY_SRV_VER_6 "PY_SRV_V6"
-uint8_t g_py_ver = 4;
+static uint8_t g_py_ver = 4;
+
+/**
+ * @brief 获取Cat1 Python服务版本号
+ * @return 返回Python服务版本号
+ */
+uint8_t uapi_get_py_ver(void)
+{
+ return g_py_ver;
+}
static osTimerId_t g_timer_time_answer = NULL;
#include "cat1_server.h"
#include "cat1_server_hal.h"
#include "cat1_ctl.h"
+#include "cat1_pub_api.h" /* 包含 uapi_get_py_ver() 函数声明 */
#include "tcxo.h"
#include "custom_utils.h"
#include "cmsis_os.h"
uint8_t errno_count=0;
static uint8_t IS_need_ota=1;
-extern uint8_t g_py_ver;
void cat1_server_file_task(void *pvParameters)
if(IS_need_ota)
{
IS_need_ota=0;
- if(g_py_ver==16)
+ if(uapi_get_py_ver()==16)
{
uint8_t TRANSMIT_DATA=IS_NEED_CAT1_OTA;
CustomEventPublish(TOPIC_EVENT_BLE_TRANSMIT,&TRANSMIT_DATA,1);
}
- else if(g_py_ver==17)
+ else if(uapi_get_py_ver()==17)
{
Cat1_OTA(CAT1_TCP_START_OTA);
}
- else if(g_py_ver==18)
+ else if(uapi_get_py_ver()==18)
{
uint8_t TRANSMIT_DATA=IS_NEED_CAT1_OTA;
CustomEventPublish(TOPIC_EVENT_BLE_TRANSMIT,&TRANSMIT_DATA,1);
}
- else if (g_py_ver>=19 && (uapi_dev_runtime_get_cat1_networkstat()) )
+ else if (uapi_get_py_ver()>=19 && (uapi_dev_runtime_get_cat1_networkstat()) )
{
char * cat1_modemver = uapi_dev_runtime_get_cat1_modemver();
taskcfg.func = cat1_server_file_task;
taskcfg.use_mem = USE_EXTEND_MEM;
- if(g_py_ver<=16)
+ if(uapi_get_py_ver()<=16)
{
is_need_udp_updata=1;
}
static uint8_t old_model_ver=0;
-extern uint8_t g_py_ver;
-
extern uint8_t g_py_ver_new;
static osTimerId_t modem_ota_timer=NULL;
#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,g_py_ver);
- if(old_model_ver!=g_py_ver)
+ 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())
{
uint8_t TRANSMIT_DATA=TRANS_FREE;
/* 前向声明 */
extern void udp_send_msg_toCat1(uint8_t cmd, char *content);
-extern uint8_t g_py_ver; /* Python服务版本号 */
+#include "cat1_pub_api.h" /* 包含 uapi_get_py_ver() 函数声明 */
/**
* @brief 下载超时定时器回调函数
error_info->error_type == CUSTOM_SPI_ERROR_INVALID_DATA_LEN ||
error_info->error_type == CUSTOM_SPI_ERROR_CALLBACK_FAILED) {
// 版本28跳过SPI重新初始化逻辑
- if (g_py_ver == 28) {
+ if (uapi_get_py_ver() == 28) {
cat1_print_info("HTTP download: Critical error detected (v28), skipping SPI reinitialization\n");
http_file_download_notify_complete(0); // 通知下载失败
}
}
- if(g_py_ver==28)
+ if(uapi_get_py_ver()==28)
{
if(data_len!=SPI_PACKET_DATA_SIZE+4)
{
char udp_msg[1024] = {0};
int msg_len;
- if(g_py_ver==28)
+ if(uapi_get_py_ver()==28)
{
msg_len = snprintf(udp_msg, sizeof(udp_msg), "%s", url);
}
* @return 返回主应用版本号,sdk当下最低版本PY_SRV_V16
* */
char* cat1_api_runtime_get_cat1_pyver(void);
+/**
+ * @brief 获取Cat1 Python服务版本号(数值)
+ * @return 返回Python服务版本号,例如:4, 16, 28, 29等
+ * */
+uint8_t uapi_get_py_ver(void);
/**
* @brief 获取modem版本
* @return modem版本字符串,sdk当下版本唯一 EG810MCNLAR06A01M08_VOLTE_OCPU_QPY_BETA0312
#ifdef SUPPORT_CAT1_SERVICE
#include "cat1_pub_api.h"
#endif
-extern uint8_t g_py_ver; /* Python服务版本号 */
+#include "cat1_pub_api.h" /* 包含 uapi_get_py_ver() 函数声明 */
/* OTA下载状态枚举(对应时序图中的下载阶段)*/
typedef enum
// 构建版本字符串
char version1_str[64] = {0};
char version2_str[64] = {0};
- snprintf(version1_str, sizeof(version1_str), "%sV%d_1", version, g_py_ver);
- snprintf(version2_str, sizeof(version2_str), "%sV%d_2", version, g_py_ver);
+ snprintf(version1_str, sizeof(version1_str), "%sV%d_1", version, uapi_get_py_ver());
+ snprintf(version2_str, sizeof(version2_str), "%sV%d_2", version, uapi_get_py_ver());
// 获取CAT1 OTA升级URL
ret = ln_ota_get_task_http_CAT1(uapi_ln_get_device_id(), uapi_ln_get_device_token(), version1_str, g_ln_last_package_url_new1);
/* 解析哄睡模式开始:提取data.storyTheme并触发随机故事 */
void ln_parse_sleep_mode_start(const char *json_str, int json_len)
{
- // 设备层面保护机制:如果已经开启哄睡,直接返回,防止重复开始故事
+ // 设备层面保护机制:如果已经开启哄睡,发送失败应答并返回,防止重复开始故事
if(uapi_get_sleep_mode_active())
{
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[LN][SLEEP_START] sleep mode already active, return directly\n");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[LN][SLEEP_START] sleep mode already active, sending failure ack\n");
+ ln_ws_send_sleep_mode_start_ack(false, "哄睡模式已在运行中,无法重复启动");
return;
}
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[LN][SLEEP_START] parse json\n");
extern uint32_t g_audio_playback_start_tick ; // 音频播放开始时间tick
-/* Python服务版本号声明 */
-extern uint8_t g_py_ver; /* Python服务版本号 */
+#include "cat1_pub_api.h" /* 包含 uapi_get_py_ver() 函数声明 */
/* 版本检查:需要g_py_ver >= 29才能使用HTTP文件下载功能 */
#define LN_HTTP_DOWNLOAD_MIN_PY_VER 29
int ln_http_download_init(void)
{
// 版本检查:需要g_py_ver >= 29
- if (g_py_ver < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
+ if (uapi_get_py_ver() < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[HTTP_DL] Python version %u is too low, requires >= %d",
- g_py_ver, LN_HTTP_DOWNLOAD_MIN_PY_VER);
+ uapi_get_py_ver(), LN_HTTP_DOWNLOAD_MIN_PY_VER);
return -1;
}
void ln_http_download_deinit(void)
{
// 版本检查:需要g_py_ver >= 29
- if (g_py_ver < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
+ if (uapi_get_py_ver() < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[HTTP_DL] Python version %u is too low, requires >= %d",
- g_py_ver, LN_HTTP_DOWNLOAD_MIN_PY_VER);
+ uapi_get_py_ver(), LN_HTTP_DOWNLOAD_MIN_PY_VER);
return;
}
cat_sync_timer_control(1);
int ln_http_download_file_do(const char *url, uint32_t timeout_ms)
{
// 版本检查:需要g_py_ver >= 29
- if (g_py_ver < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
+ if (uapi_get_py_ver() < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[HTTP_DL] Python version %u is too low, requires >= %d",
- g_py_ver, LN_HTTP_DOWNLOAD_MIN_PY_VER);
+ uapi_get_py_ver(), LN_HTTP_DOWNLOAD_MIN_PY_VER);
return -1;
}
int ln_http_download_file(const char *url, uint32_t timeout_ms)
{
// 版本检查:需要g_py_ver >= 29
- if (g_py_ver < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
+ if (uapi_get_py_ver() < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[HTTP_DL] Python version %u is too low, requires >= %d",
- g_py_ver, LN_HTTP_DOWNLOAD_MIN_PY_VER);
+ uapi_get_py_ver(), LN_HTTP_DOWNLOAD_MIN_PY_VER);
return -1;
}
int ln_http_download_file_with_resume(const char *url, uint32_t resume_from_byte, uint32_t timeout_ms)
{
// 版本检查:需要g_py_ver >= 29
- if (g_py_ver < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
+ if (uapi_get_py_ver() < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[HTTP_DL] Python version %u is too low, requires >= %d",
- g_py_ver, LN_HTTP_DOWNLOAD_MIN_PY_VER);
+ uapi_get_py_ver(), LN_HTTP_DOWNLOAD_MIN_PY_VER);
return -1;
}
http_download_state_t ln_http_download_get_state(void)
{
// 版本检查:需要g_py_ver >= 29
- if (g_py_ver < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
+ if (uapi_get_py_ver() < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[HTTP_DL] Python version %u is too low, requires >= %d",
- g_py_ver, LN_HTTP_DOWNLOAD_MIN_PY_VER);
+ uapi_get_py_ver(), LN_HTTP_DOWNLOAD_MIN_PY_VER);
return HTTP_DOWNLOAD_STATE_IDLE;
}
int ln_http_download_get_stats(uint32_t *total_bytes, uint32_t *total_packets)
{
// 版本检查:需要g_py_ver >= 29
- if (g_py_ver < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
+ if (uapi_get_py_ver() < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[HTTP_DL] Python version %u is too low, requires >= %d",
- g_py_ver, LN_HTTP_DOWNLOAD_MIN_PY_VER);
+ uapi_get_py_ver(), LN_HTTP_DOWNLOAD_MIN_PY_VER);
return -1;
}
uint8_t ln_http_download_is_initialized(void)
{
// 版本检查:需要g_py_ver >= 29
- if (g_py_ver < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
+ if (uapi_get_py_ver() < LN_HTTP_DOWNLOAD_MIN_PY_VER) {
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[HTTP_DL] Python version %u is too low, requires >= %d",
- g_py_ver, LN_HTTP_DOWNLOAD_MIN_PY_VER);
+ uapi_get_py_ver(), LN_HTTP_DOWNLOAD_MIN_PY_VER);
return 0;
}
+#ifndef LN_API_INTERFACE_H
+#define LN_API_INTERFACE_H
+
#ifdef __cplusplus
extern "C"
{
#endif
-#ifndef LN_API_INTERFACE_H
-#define LN_API_INTERFACE_H
#include <stdint.h>
#ifdef __cplusplus
}
#endif
-#endif // AUDIO_STREAM_PLAYER_H
\ No newline at end of file
+#endif // LN_API_INTERFACE_H
\ No newline at end of file
void custom_spi_start(void);
-/* 外部变量:Python服务版本号 */
-#ifdef SUPPORT_CAT1_SERVICE
-extern uint8_t g_py_ver;
-#else
-uint8_t g_py_ver = 28;
-#endif
+/* Python服务版本号获取函数 - 使用 cat1_pub_api.h 中的声明 */
+#include "cat1_pub_api.h"
static osSemaphoreId_t g_semaphore_spi_id = NULL;
static app_task_definition_t taskcfg={0};
// 统计总接收字节数(仅统计实际数据长度,不包括包头)
total_cnt += data_len;
- if(g_py_ver==28)
+ if(uapi_get_py_ver()==28)
{
if(data_len != SPI_PACKET_DATA_SIZE+4)
{
*/
void custom_spi_read(void)
{
- if (g_py_ver == 28) {
+ if (uapi_get_py_ver() == 28) {
custom_spi_read_v28();
} else {
custom_spi_read_normal();
// 4. 信号量获取成功:根据版本调用对应的SPI读取函数
// printf("获取信号量成功,开始读取SPI数据...\r\n");
- if (g_py_ver == 28) {
+ if (uapi_get_py_ver() == 28) {
custom_spi_read_v28();
} else {
custom_spi_read_normal();