From 5d413f16caeab6b3a6f7a2d62fa4f9af5164e6a2 Mon Sep 17 00:00:00 2001 From: hcj <1224667075@qq.com> Date: Tue, 16 Sep 2025 17:30:18 +0800 Subject: [PATCH] =?utf8?q?=E4=BF=AE=E6=94=B9230=20ai=E5=AF=B9=E8=AF=9D?= =?utf8?q?=E4=BB=A3=E7=A0=81,=E5=A2=9E=E5=8A=A0=E6=89=93=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../nativeui/aivoice/src/AiVoiceModel.cpp | 22 +- .../nativeui/aivoice/src/AiVoicePresenter.cpp | 31 ++- .../config/target_config/brandy/config.py | 12 ++ .../wrapper/audio_manager_c_wrapper.cpp | 14 +- .../sample/wrapper/audio_manager_c_wrapper.h | 2 + code/sdk/zhihui/ai/include/ai_media.h | 19 ++ .../zhihui/ai/media/ai_media_service_ext.cpp | 189 +++++++++++++++++- code/sdk/zhihui/ai_old/ai_old_at_cmd.cpp | 8 +- .../zhihui/ai_old/asr_websocket_server.cpp | 2 +- code/sdk/zhihui/ai_old/asr_websocket_server.h | 4 +- .../zhihui/ai_old/chat_websocket_server.cpp | 15 -- .../zhihui/ai_old/tts_websocket_server.cpp | 52 ++++- code/sdk/zhihui/ai_old/tts_websocket_server.h | 8 + .../ai_old/websocket_server_example.cpp | 26 ++- .../ai_old/websocket_server_manager.cpp | 91 ++++++++- .../zhihui/ai_old/websocket_server_manager.h | 28 ++- code/sdk/zhihui/utils/custom_cmd_service.c | 116 ++++++++++- code/sdk/zhihui/utils/custom_utils.c | 33 +++ code/sdk/zhihui/utils/custom_utils.h | 46 +++++ 19 files changed, 664 insertions(+), 54 deletions(-) diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceModel.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceModel.cpp index 7620f26e8..cfa8550e3 100644 --- a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceModel.cpp +++ b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoiceModel.cpp @@ -180,7 +180,9 @@ namespace OHOS WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GetSelect4gorbt() == AI_SELECT_4G"); if (GetInit_4gai_task()) { +#ifdef SUPPORT_AI_SERVICE uapi_start_AI_asr(); +#endif } else { @@ -970,7 +972,9 @@ namespace OHOS WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "停止录音"); if (GetSelect4gorbt() == AI_SELECT_4G) // 选的是4G需要关闭asr { +#ifdef SUPPORT_AI_SERVICE uapi_stop_AI_asr(); +#endif } else if (GetSelect4gorbt() == AI_SELECT_BT) { @@ -1038,8 +1042,10 @@ namespace OHOS if (AiVoiceModel::GetInstance().GetSelect4gorbt() == AI_SELECT_4G) { // dinit_ai_task(); // 所有服务都删除重新连一下服务器 - stop_all_websocket_servers(); - destroy_all_websocket_servers(); +#ifdef SUPPORT_AI_SERVICE + uapi_stop_all_websocket_servers(); + uapi_destroy_all_websocket_servers(); +#endif } SendMsgToUIService(UI_AI_JUMP_TO_RESPONDERR_VIEW, 0, (void *)str.c_str(), str.length()); @@ -1331,8 +1337,10 @@ namespace OHOS if (AiVoiceModel::GetInstance().GetSelect4gorbt() == AI_SELECT_4G) { // dinit_ai_task(); // 所有服务都删除重新连一下服务器 - stop_all_websocket_servers(); - destroy_all_websocket_servers(); +#ifdef SUPPORT_AI_SERVICE + uapi_stop_all_websocket_servers(); + uapi_destroy_all_websocket_servers(); +#endif } p_AiVoicePresenter->ChangeViewAndLogicOperator(AIVOICE_AIMODE_CONNECTING, AIVOICE_AIMODEL_CONNECT_FAILED_VIEWID); } @@ -1436,8 +1444,10 @@ namespace OHOS (view_->GetAiVoiceScrollView(AIVOICE_4GSERVICECON_VIEW)->IsVisible())) { // dinit_ai_task(); // 所有服务都删除重新连一下服务器 - stop_all_websocket_servers(); - destroy_all_websocket_servers(); +#ifdef SUPPORT_AI_SERVICE + uapi_stop_all_websocket_servers(); + uapi_destroy_all_websocket_servers(); +#endif p_AiVoicePresenter->ChangeViewAndLogicOperator(AIVOICE_4GSERVICECON_VIEW, AIVOICE_AIMODEL_CONNECT_FAILED_VIEWID); } } diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoicePresenter.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoicePresenter.cpp index 289f5194d..b236bb1fc 100644 --- a/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoicePresenter.cpp +++ b/code/sdk/application/wearable/fd230/nativeapp/nativeui/aivoice/src/AiVoicePresenter.cpp @@ -29,6 +29,7 @@ #include "aivoice/include/AiVoiceSelectView.h" #include "graphic_service.h" #include "websocket_server_manager.h" +#include "custom_utils.h" namespace OHOS { @@ -124,8 +125,10 @@ namespace OHOS model->stop_uapi_stop_tts_timer(); remove_4GAI_vote(); // 移除4g投票 - stop_all_websocket_servers(); - destroy_all_websocket_servers(); +#ifdef SUPPORT_AI_SERVICE + uapi_stop_all_websocket_servers(); + uapi_destroy_all_websocket_servers(); +#endif // dinit_ai_task(); // ai_cleanup_resources(); @@ -500,8 +503,10 @@ namespace OHOS { /* -------------------------------------------------------------------------- */ // init_ai_task(AiVoiceModel::GetInstance().GetCurUsing4GAiModelType()); - init_all_websocket_servers(); - start_all_websocket_servers(); // 连接服务器 +#ifdef SUPPORT_AI_SERVICE + uapi_init_all_websocket_servers(); + uapi_start_all_websocket_servers(); // 连接服务器 +#endif /* -------------------------------------------------------------------------- */ model->start_ai4g_connect_timer(); ChangeViewAndLogicOperator(AIVOICE_STARTCHAT_VIEWID, AIVOICE_4GSERVICECON_VIEW); // LOADING @@ -542,8 +547,10 @@ namespace OHOS if (!model->GetInit_4gai_task()) { // init_ai_task(AiVoiceModel::GetInstance().GetCurUsing4GAiModelType()); - init_all_websocket_servers(); - start_all_websocket_servers(); // 连接服务器 +#ifdef SUPPORT_AI_SERVICE + uapi_init_all_websocket_servers(); + uapi_start_all_websocket_servers(); // 连接服务器 +#endif model->start_ai4g_connect_timer(); ChangeViewAndLogicOperator(model->GetCurView(), AIVOICE_4GSERVICECON_VIEW); // LOADING } @@ -591,8 +598,10 @@ namespace OHOS { AiVoiceModel::GetInstance().stop_ai4g_tts_play_timer(); AiVoiceModel::GetInstance().stop_uapi_stop_tts_timer(); - stop_all_websocket_servers(); - destroy_all_websocket_servers(); +#ifdef SUPPORT_AI_SERVICE + uapi_stop_all_websocket_servers(); + uapi_destroy_all_websocket_servers(); +#endif } } ChangeViewAndLogicOperator(it->second.first, it->second.second); @@ -614,8 +623,10 @@ namespace OHOS if (model->GetSelect4gorbt() == AI_SELECT_4G) { // dinit_ai_task(); - stop_all_websocket_servers(); - destroy_all_websocket_servers(); +#ifdef SUPPORT_AI_SERVICE + uapi_stop_all_websocket_servers(); + uapi_destroy_all_websocket_servers(); +#endif } } ChangeViewAndLogicOperator(it->second.first, it->second.second); diff --git a/code/sdk/build/config/target_config/brandy/config.py b/code/sdk/build/config/target_config/brandy/config.py index d98a52c00..46583a2fb 100644 --- a/code/sdk/build/config/target_config/brandy/config.py +++ b/code/sdk/build/config/target_config/brandy/config.py @@ -414,6 +414,7 @@ target = { # 'AILPAY_SUPPORT', 'SUPPORT_FACTORY_SERVICE', # 'MEMORY_CORRUPTION', + 'SUPPORT_AI_SERVICE', ], #添加自定义应用 @@ -452,6 +453,17 @@ target = { "transspecard", "factorytest_service", # "hid_service", + + #websocket 相关配置 + "zhihui_websocket", + #ai 相关配置 + "aiMediaService", + "aiService", + #ai_old相关配置 + "zhihui_ai_old", + #音频相关配置 + "audio_manager", + "producttest", "ppg_hal", "mag_service", diff --git a/code/sdk/middleware/services/media/foundation/sample/wrapper/audio_manager_c_wrapper.cpp b/code/sdk/middleware/services/media/foundation/sample/wrapper/audio_manager_c_wrapper.cpp index 77838057c..6c00d37f4 100644 --- a/code/sdk/middleware/services/media/foundation/sample/wrapper/audio_manager_c_wrapper.cpp +++ b/code/sdk/middleware/services/media/foundation/sample/wrapper/audio_manager_c_wrapper.cpp @@ -334,6 +334,18 @@ int32_t AudioStreamOutPlay(void) return AUDIO_SUCCESS; } +int32_t AudioStreamOutFlush(void) +{ + int32_t ret = g_streamOut->Flush(); + if (ret != AUDIO_SUCCESS) { + ALOGE("audio stream out Flush failed 0x%x", ret); + return AUDIO_ERROR; + } + + ALOGD("success"); + return AUDIO_SUCCESS; +} + int32_t AudioStreamOutStreamWrite(const uint8_t *data, uint32_t size) { uint64_t writtenSize = 0; @@ -350,7 +362,7 @@ int32_t AudioStreamOutStreamWrite(const uint8_t *data, uint32_t size) int32_t AudioStreamOutStop(void) { - int32_t ret = g_streamOut->Stop(); + int32_t ret = g_streamOut->Pause(); if (ret != AUDIO_SUCCESS) { ALOGE("audio stream out stop failed 0x%x", ret); return AUDIO_ERROR; diff --git a/code/sdk/middleware/services/media/foundation/sample/wrapper/audio_manager_c_wrapper.h b/code/sdk/middleware/services/media/foundation/sample/wrapper/audio_manager_c_wrapper.h index 32e29f6cc..9a70782f5 100644 --- a/code/sdk/middleware/services/media/foundation/sample/wrapper/audio_manager_c_wrapper.h +++ b/code/sdk/middleware/services/media/foundation/sample/wrapper/audio_manager_c_wrapper.h @@ -60,6 +60,8 @@ int32_t AudioStreamOutStop(void); int32_t AudioStreamOutDeinit(void); +int32_t AudioStreamOutFlush(void); + /** * @brief Sets audio effect algorithm parameters. * diff --git a/code/sdk/zhihui/ai/include/ai_media.h b/code/sdk/zhihui/ai/include/ai_media.h index 34f8a74ae..89a8db4d2 100644 --- a/code/sdk/zhihui/ai/include/ai_media.h +++ b/code/sdk/zhihui/ai/include/ai_media.h @@ -120,6 +120,25 @@ int32_t StopAIVoice(void); int32_t AI_SendAudioDataToQueue(const uint8_t* data, uint32_t size); +/* + * @brief 设置AI语音打断标志 + * @param interrupt 打断标志,true表示需要清空队列并恢复输出流,false表示清除标志 + * @return 0 成功,-1 失败 + */ +int32_t AI_SetInterruptFlag(bool interrupt); + +/* + * @brief 获取AI语音打断标志 + * @return true 打断标志已设置,false 打断标志未设置或服务未运行 + */ +bool AI_GetInterruptFlag(void); + +/* + * @brief 强制清空AI语音队列并恢复输出流 + * @return 0 成功,-1 失败 + */ +int32_t AI_ForceInterrupt(void); + #ifdef __cplusplus }; #endif diff --git a/code/sdk/zhihui/ai/media/ai_media_service_ext.cpp b/code/sdk/zhihui/ai/media/ai_media_service_ext.cpp index f1adfc5df..b8611d8ba 100644 --- a/code/sdk/zhihui/ai/media/ai_media_service_ext.cpp +++ b/code/sdk/zhihui/ai/media/ai_media_service_ext.cpp @@ -61,6 +61,7 @@ typedef struct { typedef struct { AudioSession sessionId; bool isAIVoiceStopped; + bool interruptFlag; // 打断标志,设置时清空队列并重置流 MediaThreadCondHandle cond; // 保留条件变量用于线程同步 MediaThreadIdHandle taskHandle; char threadName[32]; // 线程名称,用于验证线程ID @@ -417,6 +418,15 @@ static int32_t RunAIVoice(AIVoiceContext *context) MEDIA_INFO_LOG("RunAIVoice: waiting for queue data..."); while (!context->isAIVoiceStopped) { +// 检查打断标志 + if (context->interruptFlag) { + MEDIA_INFO_LOG("Interrupt flag set, clearing queue and resuming output stream..."); + // 清除打断标志 + context->interruptFlag = false; + + MEDIA_INFO_LOG("Interrupt processing completed"); + } + if (context->inputQueue != NULL) { AIVoiceQueueMessage msg; osStatus_t status = osMessageQueueGet(context->inputQueue, &msg, NULL, 100); // 100ms超时 @@ -497,6 +507,91 @@ static bool ReleaseAudioFocus(void) return true; } +/** + * @brief 暂停音频输出流 + * @return 0 成功,-1 失败 + */ +static int32_t PauseAudioStreams(void) +{ + int32_t ret = 0; + + // 只暂停输出流 + ret = AudioStreamOutStop(); + if (ret != 0) { + MEDIA_ERR_LOG("audio stream out stop failed: %d", ret); + } + + MEDIA_INFO_LOG("Audio output stream paused"); + return 0; +} + +/** + * @brief 清空音频输出流缓冲区 + * @return 0 成功,-1 失败 + */ +static int32_t ClearAudioStreams(void) +{ + int32_t ret = 0; + + // 只清空输出流缓冲区 + ret = AudioStreamOutFlush(); + if (ret != 0) { + MEDIA_ERR_LOG("audio stream out flush failed: %d", ret); + } + + MEDIA_INFO_LOG("Audio output stream cleared"); + return 0; +} + +/** + * @brief 恢复音频输出流 + * @return 0 成功,-1 失败 + */ +static int32_t ResetAudioStreams(void) +{ + int32_t ret = 0; + + // 只恢复输出流,不进行销毁重建 + ret = AudioStreamOutPlay(); + if (ret != 0) { + MEDIA_ERR_LOG("audio stream out resume failed: %d", ret); + } + + MEDIA_INFO_LOG("Audio output stream resumed"); + return 0; +} + +/** + * @brief 清空AI语音队列 + * @param context AI语音上下文 + * @return 0 成功,-1 失败 + */ +static int32_t ClearAIVoiceQueue(AIVoiceContext *context) +{ + if (context == nullptr || context->inputQueue == NULL) { + MEDIA_ERR_LOG("AI voice context or queue is null"); + return -1; + } + + AIVoiceQueueMessage msg; + uint32_t clearedCount = 0; + + // 清空队列中的所有消息 + while (osMessageQueueGet(context->inputQueue, &msg, NULL, 0) == osOK) { + if (msg.data != nullptr) { + free(msg.data); + msg.data = nullptr; + } + clearedCount++; + } + + // 重置队列消息计数 + context->queueMsgCount = 0; + + MEDIA_INFO_LOG("AI voice queue cleared: %u messages removed", clearedCount); + return 0; +} + static void AIVoiceThread(void *priv) { @@ -752,6 +847,8 @@ int32_t AI_WriteAudioData(const uint8_t* data, uint32_t size) return -1; } AI_WRITE: + if(g_aiVoiceContext->interruptFlag) + return -1; // 获取全局互斥锁(自动初始化) MediaMutexHandle mutex = GetGlobalMutex(); if (mutex == nullptr) { @@ -770,14 +867,15 @@ int32_t AI_WriteAudioData(const uint8_t* data, uint32_t size) // 写入音频数据到输出流 int32_t ret = AudioStreamOutStreamWrite(data, size); + usleep(50*size); if (ret != 0) { // MEDIA_ERR_LOG("Failed to write audio data to output stream, ret=%d", ret); - usleep(100000); // return -1; + usleep(10000); goto AI_WRITE; } - MEDIA_INFO_LOG("Successfully wrote %u bytes of audio data to output stream", size); + // MEDIA_INFO_LOG("Successfully wrote %u bytes of audio data to output stream", size); return 0; } @@ -939,6 +1037,93 @@ int32_t AI_CleanupModule(void) return 0; } +/** + * @brief 设置AI语音打断标志 + * @param interrupt 打断标志,true表示需要清空队列并重置流,false表示清除标志 + * @return 0 成功,-1 失败 + */ +int32_t AI_SetInterruptFlag(bool interrupt) +{ + MediaMutexHandle mutex = GetGlobalMutex(); + if (mutex == nullptr) { + MEDIA_ERR_LOG("Failed to get global mutex"); + return -1; + } + + MediaMutexLock(mutex); + if (g_aiVoiceContext == nullptr) { + MEDIA_ERR_LOG("AI voice context is null, please start AI voice first"); + MediaMutexUnLock(mutex); + return -1; + } + + g_aiVoiceContext->interruptFlag = interrupt; + MEDIA_INFO_LOG("AI voice interrupt flag set: %s", interrupt ? "true" : "false"); + + MediaMutexUnLock(mutex); + return 0; +} + +/** + * @brief 获取AI语音打断标志 + * @return true 打断标志已设置,false 打断标志未设置或服务未运行 + */ +bool AI_GetInterruptFlag(void) +{ + bool interruptFlag = false; + + MediaMutexHandle mutex = GetGlobalMutex(); + if (mutex == nullptr) { + return false; + } + + MediaMutexLock(mutex); + if (g_aiVoiceContext != nullptr) { + interruptFlag = g_aiVoiceContext->interruptFlag; + } + MediaMutexUnLock(mutex); + + return interruptFlag; +} + +/** + * @brief 强制清空AI语音队列并重置流 + * @return 0 成功,-1 失败 + */ +int32_t AI_ForceInterrupt(void) +{ + MediaMutexHandle mutex = GetGlobalMutex(); + if (mutex == nullptr) { + MEDIA_ERR_LOG("Failed to get global mutex"); + return -1; + } + + MediaMutexLock(mutex); + if (g_aiVoiceContext == nullptr) { + MEDIA_ERR_LOG("AI voice context is null, please start AI voice first"); + MediaMutexUnLock(mutex); + return -1; + } + + // 设置打断标志 + g_aiVoiceContext->interruptFlag = true; + + // 立即清空队列 + ClearAIVoiceQueue(g_aiVoiceContext); + + // 立即暂停和清空输出流 + PauseAudioStreams(); + ClearAudioStreams(); + + // 立即恢复输出流 + ResetAudioStreams(); + + MEDIA_INFO_LOG("AI voice force interrupt completed"); + + MediaMutexUnLock(mutex); + return 0; +} + #ifdef __cplusplus }; #endif diff --git a/code/sdk/zhihui/ai_old/ai_old_at_cmd.cpp b/code/sdk/zhihui/ai_old/ai_old_at_cmd.cpp index 9e665a652..ccc03dad7 100644 --- a/code/sdk/zhihui/ai_old/ai_old_at_cmd.cpp +++ b/code/sdk/zhihui/ai_old/ai_old_at_cmd.cpp @@ -349,8 +349,10 @@ static uint32_t startserver(uint8_t *para, uint32_t paraLen, char *strCommonCmd) printf("CAT1TEST ATCMD Convert Command Failed\n"); return ERRCODE_FAIL; } +#ifdef SUPPORT_AI_SERVICE init_all_websocket_servers(); start_all_websocket_servers(); +#endif return 0; } @@ -366,7 +368,7 @@ static uint32_t StartTranscription(uint8_t *para, uint32_t paraLen, char *strCom printf("CAT1TEST ATCMD Convert Command Failed\n"); return ERRCODE_FAIL; } - uapi_start_AI_asr(); + uapi_start_AI_asr_(); return 0; } @@ -382,7 +384,7 @@ static uint32_t STOPTranscription(uint8_t *para, uint32_t paraLen, char *strComm printf("CAT1TEST ATCMD Convert Command Failed\n"); return ERRCODE_FAIL; } - uapi_stop_AI_asr(); + uapi_stop_AI_asr_(); return 0; } extern void msleep(uint32_t ms); @@ -398,9 +400,11 @@ static uint32_t STOPserver(uint8_t *para, uint32_t paraLen, char *strCommonCmd) printf("CAT1TEST ATCMD Convert Command Failed\n"); return ERRCODE_FAIL; } +#ifdef SUPPORT_AI_SERVICE stop_all_websocket_servers(); msleep(1000); destroy_all_websocket_servers(); +#endif return 0; } diff --git a/code/sdk/zhihui/ai_old/asr_websocket_server.cpp b/code/sdk/zhihui/ai_old/asr_websocket_server.cpp index 683483971..df876247e 100644 --- a/code/sdk/zhihui/ai_old/asr_websocket_server.cpp +++ b/code/sdk/zhihui/ai_old/asr_websocket_server.cpp @@ -378,7 +378,7 @@ errcode_t asr_server_init(void) asr_taskcfg.create_queue_handle = NULL; asr_taskcfg.attr.name = "asr_server_init"; - asr_taskcfg.attr.priority = (osPriority_t)TASK_PRIORITY_APP; + asr_taskcfg.attr.priority = (osPriority_t)16; asr_taskcfg.attr.stack_size = 0x1000; asr_taskcfg.func = bk_websocket_asr; asr_taskcfg.use_mem = USE_EXTEND_MEM; diff --git a/code/sdk/zhihui/ai_old/asr_websocket_server.h b/code/sdk/zhihui/ai_old/asr_websocket_server.h index bc616dac2..7e08b9d69 100644 --- a/code/sdk/zhihui/ai_old/asr_websocket_server.h +++ b/code/sdk/zhihui/ai_old/asr_websocket_server.h @@ -48,8 +48,8 @@ typedef struct { /* 任务配置结构体 - 使用系统定义的 app_task_definition_t */ /* 常量定义 */ -#define TASK_PRIORITY_APP 24 -#define USE_EXTEND_MEM 1 +// #define TASK_PRIORITY_APP 24 +// #define USE_EXTEND_MEM 1 /* ASR 服务接口函数 */ diff --git a/code/sdk/zhihui/ai_old/chat_websocket_server.cpp b/code/sdk/zhihui/ai_old/chat_websocket_server.cpp index bf0dd93c3..0071fc176 100644 --- a/code/sdk/zhihui/ai_old/chat_websocket_server.cpp +++ b/code/sdk/zhihui/ai_old/chat_websocket_server.cpp @@ -207,21 +207,6 @@ chat_event_type_t chat_result_analysis(char *buf, char *out_put, size_t out_put_ strncpy(out_put, content_str, copy_size); out_put[copy_size] = '\0'; } - - // 原有的处理逻辑保持不变 - if (event_type == CHAT_EVENT_MIDDLE) { - char *content_str_chat = (char *)malloc(strlen(content_str) + 1); - if (content_str_chat != NULL) { - strcpy(content_str_chat, content_str); - ble_set_ai_Answer_str(content_str_chat, 2); - free(content_str_chat); - } - } else if (event_type == CHAT_EVENT_END) { - char end_str_chat[128] = {0}; - memset(end_str_chat, 0, 128); - memcpy(end_str_chat, content_str, strlen(content_str) < 127 ? strlen(content_str) : 127); - ble_set_ai_Answer_str(end_str_chat, 2); - } } cJSON_Delete(root); diff --git a/code/sdk/zhihui/ai_old/tts_websocket_server.cpp b/code/sdk/zhihui/ai_old/tts_websocket_server.cpp index 647fb75a2..2d16b39dc 100644 --- a/code/sdk/zhihui/ai_old/tts_websocket_server.cpp +++ b/code/sdk/zhihui/ai_old/tts_websocket_server.cpp @@ -62,6 +62,7 @@ static char tts_task_id_buf[128] = {0}; static char *tts_cached_text = NULL; // 缓存待发送的文本字符串(动态分配) static int tts_cached_length = 0; // 当前缓存的文本长度 static int tts_cached_capacity = 0; // 当前分配的内存容量 +static bool tts_has_stop_cached = false; // 是否缓存了stop命令 // static bool tts_is_ready = false; // TTS是否准备就绪 /** @@ -321,6 +322,13 @@ bool uapi_tts_process_text(WebSocketClient *tts_client, char *buf, bool ready) tts_cached_length = 0; } + // 检查是否有缓存的stop命令需要发送 + if (tts_has_stop_cached) { + printf("TTS ready, sending cached stop command\n"); + uapi_stop_tts_type_stop(tts_client); + tts_has_stop_cached = false; // 重置标志 + } + // 发送本次携带的内容 if (buf && strlen(buf) > 0) { printf("TTS ready, sending current text: %s\n", buf); @@ -475,9 +483,36 @@ void uapi_clear_tts_cache(void) memset(tts_cached_text, 0, tts_cached_capacity); } tts_cached_length = 0; + tts_has_stop_cached = false; // 同时清空stop缓存标志 printf("TTS cache cleared\n"); } +/** + * @brief 缓存stop命令 + * @param tts_client TTS WebSocket客户端 + * @param ready true: 如果TTS就绪则直接发送stop命令, false: 缓存stop命令等待TTS就绪 + * @return true 成功,false 失败 + */ +bool uapi_cache_stop_command(WebSocketClient *tts_client, bool ready) +{ + if (ready) { + // 如果TTS就绪,直接发送stop命令 + if (tts_client != NULL) { + uapi_stop_tts_type_stop(tts_client); + printf("TTS ready, stop command sent directly\n"); + return true; + } else { + printf("TTS client is NULL, cannot send stop command\n"); + return false; + } + } else { + // 如果TTS未就绪,缓存stop命令 + tts_has_stop_cached = true; + printf("TTS not ready, stop command cached\n"); + return true; + } +} + /** * @brief 初始化TTS缓存内存 * @return true 成功,false 失败 @@ -949,7 +984,7 @@ bool uapi_start_tts_type_start(WebSocketClient *client) goto cleanup; } - if (cJSON_AddNumberToObject(payload, "volume", 80) == NULL) { + if (cJSON_AddNumberToObject(payload, "volume", 50) == NULL) { printf("Failed to add volume field\n"); goto cleanup; } @@ -1029,6 +1064,21 @@ void uapi_stop_tts_type_stop(WebSocketClient *client) * * // 或者使用全局客户端停止 * uapi_stop_tts_type_stop(g_tts_server->client); + * + * // 新增功能:智能stop命令处理 + * // 检查TTS是否就绪 + * tts_ready_status_t ready_status = uapi_get_tts_ready(); + * bool is_ready = (ready_status == TTS_READY_SUCCESS_READY); + * + * // 如果就绪则直接发送stop命令,否则缓存等待就绪 + * uapi_cache_stop_command(client, is_ready); + * + * // 或者手动处理文本和stop命令 + * // 添加文本到缓存(TTS未就绪时) + * uapi_tts_process_text(client, "Hello world", false); + * + * // 当TTS就绪时,清理缓存并发送所有内容(包括stop命令) + * uapi_tts_process_text(client, "", true); // 空字符串表示只清理缓存 */ #ifdef __cplusplus diff --git a/code/sdk/zhihui/ai_old/tts_websocket_server.h b/code/sdk/zhihui/ai_old/tts_websocket_server.h index 5ee5199ea..dce84f013 100644 --- a/code/sdk/zhihui/ai_old/tts_websocket_server.h +++ b/code/sdk/zhihui/ai_old/tts_websocket_server.h @@ -147,6 +147,14 @@ int uapi_get_cached_text_count(void); */ void uapi_clear_tts_cache(void); +/** + * @brief 缓存stop命令 + * @param tts_client TTS WebSocket客户端 + * @param ready true: 如果TTS就绪则直接发送stop命令, false: 缓存stop命令等待TTS就绪 + * @return true 成功,false 失败 + */ +bool uapi_cache_stop_command(WebSocketClient *tts_client, bool ready); + /** * @brief 初始化TTS缓存内存 * @return true 成功,false 失败 diff --git a/code/sdk/zhihui/ai_old/websocket_server_example.cpp b/code/sdk/zhihui/ai_old/websocket_server_example.cpp index 77988074e..0cac1e780 100644 --- a/code/sdk/zhihui/ai_old/websocket_server_example.cpp +++ b/code/sdk/zhihui/ai_old/websocket_server_example.cpp @@ -182,6 +182,7 @@ void handle_asr_data(const ws_event_data_t *event_data) break; case ASR_EVENT_TRANSCRIPTION_COMPLETED: + g_chat_server->interrupt_flag=0; ai_chat_send_txt(0, "", g_chat_server->client,true); asr_is_ready=0; break; @@ -205,9 +206,7 @@ void handle_tts_data(const ws_event_data_t *event_data) if (event_data->msg_type == WS_BINARY) { printf("TTS binary data: %d bytes\n", event_data->data_len); set_AIStreamend(0); - // AI_WriteAudioData(event_data->data, event_data->data_len); AI_SendAudioDataToQueue(event_data->data,event_data->data_len); - // send_msg_data_into_Ai_msg_queue(event_data->data, event_data->data_len, 200); } else if (event_data->msg_type == WS_TEXT) { printf("TTS text data: %s\n", (char *)event_data->data); tts_event_type_t event = tts_analysis((char *)event_data->data); @@ -216,6 +215,7 @@ void handle_tts_data(const ws_event_data_t *event_data) case TTS_EVENT_STARTED_SYNTHESIS: printf("TTS synthesis started successfully\n"); tts_is_ready = TTS_READY_SUCCESS_READY; + uapi_tts_process_text(g_tts_server->client,"",(tts_is_ready == TTS_READY_SUCCESS_READY)); break; case TTS_EVENT_END_SYNTHESIS: @@ -270,6 +270,7 @@ void handle_chat_data(const ws_event_data_t *event_data) if(tts_is_ready == TTS_READY_NOT_SENT) { tts_is_ready = TTS_READY_SENT_SUCCESS; + g_tts_server->interrupt_flag=0; uapi_start_tts_type_start(g_tts_server->client); } @@ -283,7 +284,11 @@ void handle_chat_data(const ws_event_data_t *event_data) case CHAT_EVENT_END: printf("Chat event: END - Final content: %s\n", buf); - uapi_stop_tts_type_stop(g_tts_server->client); + ble_set_ai_Answer_str(buf, 2); + + uapi_tts_process_text(g_tts_server->client,buf,(tts_is_ready == TTS_READY_SUCCESS_READY)); + uapi_cache_stop_command(g_tts_server->client,(tts_is_ready == TTS_READY_SUCCESS_READY)); + break; case CHAT_EVENT_ERROR: @@ -418,7 +423,7 @@ errcode_t init_all_websocket_servers(void) // 创建ASR服务器 ws_server_config_t asr_config = ws_server_get_default_config(WS_SERVER_TYPE_ASR); asr_config.disconnect_strategy = WS_DISCONNECT_RECONNECT; // 设置自动重连 - asr_config.reconnect_interval_ms = 3000; // 3秒重连间隔 + asr_config.reconnect_interval_ms = 500; // 3秒重连间隔 g_asr_server = ws_server_create(&asr_config, websocket_event_callback, NULL); if (!g_asr_server) { printf("Failed to create ASR server\n"); @@ -428,7 +433,7 @@ errcode_t init_all_websocket_servers(void) // 创建TTS服务器 ws_server_config_t tts_config = ws_server_get_default_config(WS_SERVER_TYPE_TTS); tts_config.disconnect_strategy = WS_DISCONNECT_RECONNECT; // 设置自动重连 - tts_config.reconnect_interval_ms = 5000; // 5秒重连间隔 + tts_config.reconnect_interval_ms = 500; // 5秒重连间隔 g_tts_server = ws_server_create(&tts_config, websocket_event_callback, NULL); if (!g_tts_server) { printf("Failed to create TTS server\n"); @@ -439,7 +444,7 @@ errcode_t init_all_websocket_servers(void) // 创建Chat服务器 ws_server_config_t chat_config = ws_server_get_default_config(WS_SERVER_TYPE_CHAT); chat_config.disconnect_strategy = WS_DISCONNECT_RECONNECT; // 设置自动重连 - chat_config.reconnect_interval_ms = 2000; // 2秒重连间隔 + chat_config.reconnect_interval_ms = 500; // 2秒重连间隔 g_chat_server = ws_server_create(&chat_config, websocket_event_callback, NULL); if (!g_chat_server) { printf("Failed to create Chat server\n"); @@ -737,13 +742,18 @@ void ai_media_init(void) } -void uapi_start_AI_asr(void) +void uapi_start_AI_asr_(void) { + if(g_asr_server) uapi_start_asr_StartTranscription(g_asr_server->client); + g_tts_server->interrupt_flag=1; + g_chat_server->interrupt_flag=1; + AI_ForceInterrupt(); } -void uapi_stop_AI_asr(void) +void uapi_stop_AI_asr_(void) { + if(g_asr_server) uapi_stop_asr_StopTranscription(g_asr_server->client); } diff --git a/code/sdk/zhihui/ai_old/websocket_server_manager.cpp b/code/sdk/zhihui/ai_old/websocket_server_manager.cpp index 0ddd3f61d..b406eee0b 100644 --- a/code/sdk/zhihui/ai_old/websocket_server_manager.cpp +++ b/code/sdk/zhihui/ai_old/websocket_server_manager.cpp @@ -329,7 +329,7 @@ ws_server_config_t ws_server_get_default_config(ws_server_type_t type) config.type = type; config.handshake_timeout_ms = 10000; config.receive_timeout_ms = 30000; - config.max_retry_count = 3; + config.max_retry_count = 0x1000; config.buffer_size = 4096; config.url_callback = NULL; config.url_user_data = NULL; @@ -455,6 +455,27 @@ static void ws_server_thread_func(void *data) handle->is_initialized = 1; while (!handle->need_stop) { + // 检查打断标志,如果设置了则主动重连 + if (handle->interrupt_flag && !handle->need_stop ) { + printf("Interrupt flag set, attempting reconnect...\n"); + handle->interrupt_flag = 0; // 清除打断标志 + ws_server_trigger_event(handle, WS_EVENT_RECONNECTING, NULL, 0, WS_TEXT, 0); + + if (ws_server_should_reconnect(handle)) { + if (ws_server_attempt_reconnect(handle)) { + last_activity = (uint32_t)osKernelGetTickCount(); + printf("Reconnect successful after interrupt\n"); + continue; + } else { + printf("Reconnect failed after interrupt\n"); + break; + } + } else { + printf("Reconnect not allowed after interrupt\n"); + break; + } + } + // 检查超时 if ((uint32_t)osKernelGetTickCount() - last_activity > handle->config.receive_timeout_ms) { printf("Receive timeout, checking reconnect strategy...\n"); @@ -479,6 +500,26 @@ static void ws_server_thread_func(void *data) // handle->config.receive_timeout_ms); int len = receive_websocket_message(handle->client,(unsigned char *)handle->recv_buffer,handle->config.buffer_size, &msg_type, handle->config.receive_timeout_ms); + if (handle->interrupt_flag && !handle->need_stop ) { + printf("Interrupt flag set, attempting reconnect...\n"); + handle->interrupt_flag = 0; // 清除打断标志 + ws_server_trigger_event(handle, WS_EVENT_RECONNECTING, NULL, 0, WS_TEXT, 0); + + if (ws_server_should_reconnect(handle)) { + if (ws_server_attempt_reconnect(handle)) { + last_activity = (uint32_t)osKernelGetTickCount(); + printf("Reconnect successful after interrupt\n"); + continue; + } else { + printf("Reconnect failed after interrupt\n"); + break; + } + } else { + printf("Reconnect not allowed after interrupt\n"); + break; + } + } + if (len == -1 || msg_type == WS_CLOSE) { printf("WebSocket connection closed, checking reconnect strategy...\n"); ws_server_trigger_event(handle, WS_EVENT_DISCONNECTED, NULL, 0, WS_TEXT, 0); @@ -609,7 +650,7 @@ static bool ws_server_connect(ws_server_handle_t *handle) printf("Connecting to: %s\n", url_buf); // 创建WebSocket客户端 - uint8_t client_count = handle->config.max_retry_count; + uint32_t client_count = handle->config.max_retry_count; while (client_count > 0) { handle->client = init_websocket_client(url_buf, NULL, 0); if (handle->client) { @@ -784,6 +825,52 @@ static bool ws_server_attempt_reconnect(ws_server_handle_t *handle) return success; } +/** + * @brief 设置WebSocket服务器打断标志 + * @param server_type 服务器类型 + * @param interrupt 打断标志,1表示需要重连,0表示清除标志 + * @return errcode_t 错误码 + */ +errcode_t ws_server_set_interrupt_flag(ws_server_type_t server_type, uint8_t interrupt) +{ + if (server_type >= WS_SERVER_TYPE_MAX) { + printf("Invalid server type: %d\n", server_type); + return ERRCODE_FAIL; + } + + ws_server_handle_t *handle = g_thread_handles[server_type]; + if (!handle) { + printf("Server handle not found for type: %d\n", server_type); + return ERRCODE_FAIL; + } + + handle->interrupt_flag = interrupt; + printf("WebSocket server interrupt flag set: type=%d, interrupt=%d\n", server_type, interrupt); + + return ERRCODE_SUCC; +} + +/** + * @brief 获取WebSocket服务器打断标志 + * @param server_type 服务器类型 + * @return uint8_t 打断标志状态 + */ +uint8_t ws_server_get_interrupt_flag(ws_server_type_t server_type) +{ + if (server_type >= WS_SERVER_TYPE_MAX) { + printf("Invalid server type: %d\n", server_type); + return 0; + } + + ws_server_handle_t *handle = g_thread_handles[server_type]; + if (!handle) { + printf("Server handle not found for type: %d\n", server_type); + return 0; + } + + return handle->interrupt_flag; +} + #ifdef __cplusplus } #endif diff --git a/code/sdk/zhihui/ai_old/websocket_server_manager.h b/code/sdk/zhihui/ai_old/websocket_server_manager.h index 78afb3a95..6c0c2d071 100644 --- a/code/sdk/zhihui/ai_old/websocket_server_manager.h +++ b/code/sdk/zhihui/ai_old/websocket_server_manager.h @@ -106,6 +106,7 @@ typedef struct { uint8_t is_running; // 运行标志 uint8_t need_stop; // 停止标志 uint8_t is_initialized; // 初始化标志 + uint8_t interrupt_flag; // 打断标志,设置时主动重连 char *recv_buffer; // 接收缓冲区 uint32_t reconnect_count; // 重连次数 uint32_t last_reconnect_time; // 上次重连时间 @@ -235,17 +236,38 @@ errcode_t start_all_websocket_servers(void); errcode_t init_all_websocket_servers(void); -void uapi_start_AI_asr(void); -void uapi_stop_AI_asr(void); void stop_all_websocket_servers(void); +void destroy_all_websocket_servers(void); + + + bool are_all_services_ready(void); uint8_t get_asr_is_ready_start_old(void); -void destroy_all_websocket_servers(void); + + +void uapi_start_AI_asr_(void); + +void uapi_stop_AI_asr_(void); + +/** + * @brief 设置WebSocket服务器打断标志 + * @param server_type 服务器类型 + * @param interrupt 打断标志,1表示需要重连,0表示清除标志 + * @return errcode_t 错误码 + */ +errcode_t ws_server_set_interrupt_flag(ws_server_type_t server_type, uint8_t interrupt); + +/** + * @brief 获取WebSocket服务器打断标志 + * @param server_type 服务器类型 + * @return uint8_t 打断标志状态 + */ +uint8_t ws_server_get_interrupt_flag(ws_server_type_t server_type); #ifdef __cplusplus diff --git a/code/sdk/zhihui/utils/custom_cmd_service.c b/code/sdk/zhihui/utils/custom_cmd_service.c index a3910999c..ba5fe03a6 100644 --- a/code/sdk/zhihui/utils/custom_cmd_service.c +++ b/code/sdk/zhihui/utils/custom_cmd_service.c @@ -31,6 +31,14 @@ #include "custom_utils.h" +#ifdef SUPPORT_AI_SERVICE +#include "asr_websocket_server.h" +#endif + +#ifdef SUPPORT_AI_SERVICE +#include "websocket_server_manager.h" +#endif + #ifdef FD230_650 #include "ui_serviceC.h" #include "alarm/include/AlarmClockModelC.h" @@ -398,6 +406,60 @@ static void custom_cmd_service_check_task(void const *arg) uapi_check_mic(0); break; +case CUSTOM_CMD_MSG_START_AI_ASR: +#ifdef SUPPORT_AI_SERVICE + uapi_start_AI_asr_(); + PRINT("AI ASR started via custom cmd\n"); +#else + PRINT("AI ASR service not supported\n"); +#endif + break; + + case CUSTOM_CMD_MSG_STOP_AI_ASR: +#ifdef SUPPORT_AI_SERVICE + uapi_stop_AI_asr_(); + PRINT("AI ASR stopped via custom cmd\n"); +#else + PRINT("AI ASR service not supported\n"); +#endif + break; + + case CUSTOM_CMD_MSG_START_ALL_WEBSOCKET_SERVERS: +#ifdef SUPPORT_AI_SERVICE + start_all_websocket_servers(); + PRINT("All WebSocket servers started via custom cmd\n"); +#else + PRINT("WebSocket service not supported\n"); +#endif + break; + + case CUSTOM_CMD_MSG_INIT_ALL_WEBSOCKET_SERVERS: +#ifdef SUPPORT_AI_SERVICE + init_all_websocket_servers(); + PRINT("All WebSocket servers initialized via custom cmd\n"); +#else + PRINT("WebSocket service not supported\n"); +#endif + break; + + case CUSTOM_CMD_MSG_STOP_ALL_WEBSOCKET_SERVERS: +#ifdef SUPPORT_AI_SERVICE + stop_all_websocket_servers(); + PRINT("All WebSocket servers stopped via custom cmd\n"); +#else + PRINT("WebSocket service not supported\n"); +#endif + break; + + case CUSTOM_CMD_MSG_DESTROY_ALL_WEBSOCKET_SERVERS: +#ifdef SUPPORT_AI_SERVICE + destroy_all_websocket_servers(); + PRINT("All WebSocket servers destroyed via custom cmd\n"); +#else + PRINT("WebSocket service not supported\n"); +#endif + break; + default: PRINT("Unknown CUSTOM_CMD_MSG cmd 0x%02X \r\n", mail.cmd); break; @@ -462,4 +524,56 @@ errcode_t uapi_custom_cmd_service_init(void) // void custom_cmd_service_service_suspend(void) // { // PRINT("custom_cmd_service_service suspend!\r\n"); -// } \ No newline at end of file +// } + +#ifdef SUPPORT_AI_SERVICE +/** + * @brief 启动AI ASR服务 + */ +void uapi_start_AI_asr(void) +{ + do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_START_AI_ASR, NULL, 0); +} + +/** + * @brief 停止AI ASR服务 + */ +void uapi_stop_AI_asr(void) +{ + do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_STOP_AI_ASR, NULL, 0); +} + +#ifdef SUPPORT_AI_SERVICE +/** + * @brief 启动所有WebSocket服务器 + */ +void uapi_start_all_websocket_servers(void) +{ + do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_START_ALL_WEBSOCKET_SERVERS, NULL, 0); +} + +/** + * @brief 初始化所有WebSocket服务器 + */ +void uapi_init_all_websocket_servers(void) +{ + do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_INIT_ALL_WEBSOCKET_SERVERS, NULL, 0); +} + +/** + * @brief 停止所有WebSocket服务器 + */ +void uapi_stop_all_websocket_servers(void) +{ + do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_STOP_ALL_WEBSOCKET_SERVERS, NULL, 0); +} + +/** + * @brief 销毁所有WebSocket服务器 + */ +void uapi_destroy_all_websocket_servers(void) +{ + do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_DESTROY_ALL_WEBSOCKET_SERVERS, NULL, 0); +} +#endif +#endif \ No newline at end of file diff --git a/code/sdk/zhihui/utils/custom_utils.c b/code/sdk/zhihui/utils/custom_utils.c index b9c93d7ff..9c6d1426f 100644 --- a/code/sdk/zhihui/utils/custom_utils.c +++ b/code/sdk/zhihui/utils/custom_utils.c @@ -171,6 +171,39 @@ errcode_t uapi_create_osThread_custom(app_task_definition_t *task_cfg) return ERRCODE_SUCC; } +/** + * @brief 扩展的任务定义结构体,支持传入实例参数 + */ +/** + * @brief 创建带实例参数的自定义线程 + * @param task_cfg 扩展的任务配置结构体,包含inst_args参数 + * @return 成功返回ERRCODE_SUCC,失败返回ERRCODE_FAIL + */ +errcode_t uapi_create_osThread_custom_with_args(app_task_definition_ext_t *task_cfg) +{ + if (task_cfg == NULL) { + return ERRCODE_FAIL; + } + + /* Create queues before tasks in case they are used during initialisation. */ + if (task_cfg->create_queue_handle) { + task_cfg->create_queue_handle(); + } + + /* Create tasks */ + if (task_cfg->use_mem == USE_EXTEND_MEM) { + task_cfg->attr.stack_mem = memalign(16, task_cfg->attr.stack_size); // 16字节对齐 + } + + /* 创建线程,传入inst_args作为参数 */ + task_cfg->task_handle = osThreadNew(task_cfg->func, task_cfg->inst_args, &(task_cfg->attr)); + if (task_cfg->task_handle == NULL) { + return ERRCODE_FAIL; + } + + return ERRCODE_SUCC; +} + errcode_t uapi_terminate_thread(void* thread_id) { osStatus_t ret = osThreadTerminate((osThreadId_t)thread_id); diff --git a/code/sdk/zhihui/utils/custom_utils.h b/code/sdk/zhihui/utils/custom_utils.h index cfbd24cb3..7936ef9ab 100644 --- a/code/sdk/zhihui/utils/custom_utils.h +++ b/code/sdk/zhihui/utils/custom_utils.h @@ -243,6 +243,18 @@ uint32_t uapi_calendar_store_date(void); #define CUSTOM_CMD_MSG_CONNECT_AG 0x1F +#define CUSTOM_CMD_MSG_START_AI_ASR 0x20 + +#define CUSTOM_CMD_MSG_STOP_AI_ASR 0x21 + +#define CUSTOM_CMD_MSG_START_ALL_WEBSOCKET_SERVERS 0x22 + +#define CUSTOM_CMD_MSG_INIT_ALL_WEBSOCKET_SERVERS 0x23 + +#define CUSTOM_CMD_MSG_STOP_ALL_WEBSOCKET_SERVERS 0x24 + +#define CUSTOM_CMD_MSG_DESTROY_ALL_WEBSOCKET_SERVERS 0x25 + typedef enum { BR_HFP_CONNECT=1, BR_HFP_DISCONNECT, @@ -257,6 +269,18 @@ errcode_t uapi_custom_cmd_service_init(void); errcode_t do_custom_cmd_service_check_msg(int cmd, void *params, int paramlen); errcode_t do_custom_cmd_service_check_msg_head(int cmd, void *params, int paramlen); +#ifdef SUPPORT_AI_SERVICE +void uapi_start_AI_asr(void); +void uapi_stop_AI_asr(void); +#endif + +#ifdef SUPPORT_AI_SERVICE +void uapi_start_all_websocket_servers(void); +void uapi_init_all_websocket_servers(void); +void uapi_stop_all_websocket_servers(void); +void uapi_destroy_all_websocket_servers(void); +#endif + /***custom file operate cmd service*/ #define CUSTOM_FILEOPERATE_MSG_TYPE_SPORTDATA_SAVE 0x01 //运动数据 #define CUSTOM_FILEOPERATE_MSG_TYPE_HEARTRATE_SAVE 0x02 //心率数据 @@ -445,6 +469,28 @@ void uapi_get_lcd_id(uint32_t *id); void uapi_lcd_backlight_on(uint8_t brightness); void uapi_lcd_backlight_off(void); + +/** + * @brief 扩展的任务定义结构体,支持传入实例参数 + */ +typedef struct { + osThreadAttr_t attr; // 线程属性 + osThreadFunc_t func; // 线程函数 + uint32_t *task_handle; // 任务句柄 + CreateQueueFunction_t create_queue_handle; // 队列创建函数 + uint32_t use_mem; // 内存使用类型 + void *inst_args; // 实例参数指针 +} app_task_definition_ext_t; + +/** + * @brief 创建带实例参数的自定义线程 + * @param task_cfg 扩展的任务配置结构体,包含inst_args参数 + * @return 成功返回ERRCODE_SUCC,失败返回ERRCODE_FAIL + */ +errcode_t uapi_create_osThread_custom_with_args(app_task_definition_ext_t *task_cfg); + + + #include "custom_utilscpp.h" -- 2.17.1