添加ai_old代码
author孙春阳 <snickersun@163.com>
Fri, 5 Sep 2025 12:35:07 +0000 (20:35 +0800)
committer孙春阳 <snickersun@163.com>
Fri, 5 Sep 2025 12:35:07 +0000 (20:35 +0800)
26 files changed:
code/sdk/application/brandy/brandy_standard/service_init.c
code/sdk/build/config/target_config/brandy/config.py
code/sdk/kernel/liteos/liteos_v207.1.0/Huawei_LiteOS/open_source/musl/include/endian.h
code/sdk/zhihui/CMakeLists.txt
code/sdk/zhihui/ai/CMakeLists.txt
code/sdk/zhihui/ai/example/ai_at_cmd.c
code/sdk/zhihui/ai/include/ai_core_types.h
code/sdk/zhihui/ai/src/ai_connection_manager.c
code/sdk/zhihui/ai/src/ai_services.c
code/sdk/zhihui/ai/src/http_getfile.c [new file with mode: 0644]
code/sdk/zhihui/ai_old/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/ai_old/ai_old_at_cmd.cpp [new file with mode: 0644]
code/sdk/zhihui/ai_old/ai_old_at_cmd.h [new file with mode: 0644]
code/sdk/zhihui/ai_old/asr_websocket_server.cpp [new file with mode: 0644]
code/sdk/zhihui/ai_old/asr_websocket_server.h [new file with mode: 0644]
code/sdk/zhihui/ai_old/bk_websocket.h [new file with mode: 0644]
code/sdk/zhihui/ai_old/chat_websocket_server.cpp [new file with mode: 0644]
code/sdk/zhihui/ai_old/chat_websocket_server.h [new file with mode: 0644]
code/sdk/zhihui/ai_old/tts_websocket_server.cpp [new file with mode: 0644]
code/sdk/zhihui/ai_old/tts_websocket_server.h [new file with mode: 0644]
code/sdk/zhihui/ai_old/voicechat_websocket_server.cpp [new file with mode: 0644]
code/sdk/zhihui/ai_old/voicechat_websocket_server.h [new file with mode: 0644]
code/sdk/zhihui/ai_old/ws_queue_common.h [new file with mode: 0644]
code/sdk/zhihui/ai_old/zhihui_ai_server.cpp [new file with mode: 0644]
code/sdk/zhihui/ai_old/zhihui_ws.cpp [new file with mode: 0644]
code/sdk/zhihui/ai_old/zhihui_ws.h [new file with mode: 0644]

index 5b7a125..5f6ea91 100644 (file)
 #ifdef SUPPORT_ZHIHUI_AI_SERVICE\r
 #include "ai_at_cmd.h"\r
 #endif\r
+#ifdef SUPPORT_ZHIHUI_AI_OLD\r
+#include "ai_old_at_cmd.h"\r
+#endif\r
 \r
 static void register_at_service(void)\r
 {\r
@@ -171,6 +174,12 @@ static void register_at_service(void)
     at_cmd_add_moudle(cat1_table, cat1_cmd_count);\r
 #endif\r
 \r
+#ifdef SUPPORT_ZHIHUI_AI_OLD\r
+    uint32_t ai_old_cmd_count;\r
+    at_cmd_table_t *ai_old_table = get_ai_old_cmd_table(&ai_old_cmd_count);\r
+    at_cmd_add_moudle(ai_old_table, ai_old_cmd_count);\r
+#endif\r
+\r
 #ifdef SUPPORT_AT_LIS2DOC\r
     uint32_t lis2doc_cmd_count;\r
     at_cmd_table_t *lis2doc_table = get_lis2doc_cmd_table(&lis2doc_cmd_count);\r
index 366c61c..450ee36 100644 (file)
@@ -1010,6 +1010,8 @@ target = {
             #ai 相关配置
             "aiMediaService",       
             "aiService",
+            #ai_old相关配置
+            "zhihui_ai_old",
             #音频相关配置
             "audio_manager",
             "CustomUIcomponentTool",
index 70a6ff0..c85fcc5 100644 (file)
 
 #define __PDP_ENDIAN 3412
 
+#ifndef BIG_ENDIAN
 #define BIG_ENDIAN __BIG_ENDIAN
+#endif
+#ifndef LITTLE_ENDIAN
 #define LITTLE_ENDIAN __LITTLE_ENDIAN
+#endif
+#ifndef PDP_ENDIAN
 #define PDP_ENDIAN __PDP_ENDIAN
+#endif
+#ifndef BYTE_ORDER
 #define BYTE_ORDER __BYTE_ORDER
+#endif
 
 static __inline uint16_t __bswap16(uint16_t __x)
 {
index 1ad204a..f378de1 100644 (file)
@@ -19,5 +19,6 @@ else()
 endif()
 add_subdirectory_if_exist(4gTest)
 add_subdirectory_if_exist(ai)
+add_subdirectory_if_exist(ai_old)
 add_subdirectory_if_exist(ai/media)
 add_subdirectory_if_exist(websocket)
index 4cd9974..95a6ebb 100644 (file)
@@ -14,6 +14,8 @@ ${ROOT_DIR}/zhihui/4gTest
 ${ROOT_DIR}/application/wearable/ohos_deps
 ${ROOT_DIR}/open_source/openharmony/third_party/cJSON
 ${ROOT_DIR}/open_source/openharmony/foundation/ace/ace_engine_lite/modules/netstack/websocket/include
+${ROOT_DIR}/open_source/openharmony/third_party/lwip/lwip_v2.1.3/src/include
+${ROOT_DIR}/open_source/openharmony/third_party/lwip/lwip_adapter/liteos/src/include
 )
 
 # 新的AI服务架构源文件 (LiteOS-M优化版v2)
@@ -26,6 +28,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/src/ai_chat_service.c
 ${CMAKE_CURRENT_SOURCE_DIR}/src/ai_tts_service.c
 ${CMAKE_CURRENT_SOURCE_DIR}/src/ai_event_manager.c
 ${CMAKE_CURRENT_SOURCE_DIR}/src/dev_authentication.c
+${CMAKE_CURRENT_SOURCE_DIR}/src/http_getfile.c
 ${CMAKE_CURRENT_SOURCE_DIR}/example/ai_at_cmd.c
 # ${CMAKE_CURRENT_SOURCE_DIR}/example/ai_demo.c
 )
index fab2c58..66e346b 100644 (file)
@@ -5,6 +5,57 @@
  * @date 2024-09-02
  * 
  * 本文件提供AI服务的AT命令功能,集成到LiteOS AT指令系统中
+ * 
+ * 支持的AT命令列表:
+ * 
+ * === 基础服务命令 ===
+ * AT^AIINIT        - 初始化AI服务
+ * AT^AICONNECT     - 连接AI服务
+ * AT^AISTATUS      - 查询AI服务状态
+ * AT^AICLEANUP     - 清理AI服务
+ * 
+ * === AI功能测试命令 ===
+ * AT^AIASR=duration_ms          - 测试ASR服务(语音识别)
+ * AT^AICHAT=message             - 测试Chat服务(对话)
+ * AT^AITTS=text                 - 测试TTS服务(语音合成)
+ * AT^AIALLTEST                  - 运行所有服务的综合测试
+ * 
+ * === 媒体录音播放命令 ===
+ * AT^AIRECORD=filename,duration - 录音到文件
+ *   参数:filename - 录音文件名(如:record.mp3)
+ *        duration - 录音时长(秒,1-3600)
+ *   示例:AT^AIRECORD=test.mp3,30
+ * 
+ * AT^AIPLAY=filename           - 播放音频文件
+ *   参数:filename - 音频文件名
+ *   示例:AT^AIPLAY=test.mp3
+ * 
+ * AT^AIRECORDSTOP              - 停止录音
+ * AT^AIPLAYSTOP                - 停止播放
+ * 
+ * AT^AIMEDIATEST=duration      - 媒体服务测试(边录边放)
+ * AT^AIMEDIASTOP               - 停止媒体测试
+ * 
+ * === 系统管理命令 ===
+ * AT^AIMEMORY=pool_type        - 测试内存池
+ * AT^AIPERF                    - 性能测试
+ * AT^AISTATS                   - 显示测试统计信息
+ * AT^AIRECONNECT=service_type  - 重连指定AI服务
+ * 
+ * === 使用示例 ===
+ * 1. 初始化并连接:
+ *    AT^AIINIT
+ *    AT^AICONNECT
+ * 
+ * 2. 录音30秒到文件:
+ *    AT^AIRECORD=my_voice.mp3,30
+ * 
+ * 3. 播放录音文件:
+ *    AT^AIPLAY=my_voice.mp3
+ * 
+ * 4. 停止录音或播放:
+ *    AT^AIRECORDSTOP
+ *    AT^AIPLAYSTOP
  */
 
 #ifdef __TEST_MODE__
@@ -95,6 +146,23 @@ typedef struct {
 
 static ai_media_test_context_t g_media_test_ctx = {0};
 
+/* 文件录音/播放状态 */
+typedef struct {
+    bool is_recording;
+    bool is_playing;
+    char record_filename[256];
+    char play_filename[256];
+    uint32_t record_start_time;
+    uint32_t play_start_time;
+    uint32_t record_duration;  // 录音持续时间(秒)
+    uint32_t recorded_size;    // 已录音数据大小
+    uint32_t played_size;      // 已播放数据大小
+    FILE* record_file;
+    FILE* play_file;
+} ai_file_media_context_t;
+
+static ai_file_media_context_t g_file_media_ctx = {0};
+
 /**
  * @brief 媒体测试录音回调函数 - 边录边放
  */
@@ -126,6 +194,39 @@ static void media_test_record_callback(uint8_t *data, uint32_t size)
     }
 }
 
+/**
+ * @brief 文件录音回调函数
+ */
+static void file_record_callback(uint8_t *data, uint32_t size)
+{
+    if (!g_file_media_ctx.is_recording || g_file_media_ctx.record_file == NULL) {
+        return;
+    }
+    
+    // 写入录音数据到文件
+    size_t written = fwrite(data, 1, size, g_file_media_ctx.record_file);
+    if (written == size) {
+        g_file_media_ctx.recorded_size += size;
+        
+        // 每1000个数据包打印一次状态
+        static uint32_t record_packet_count = 0;
+        record_packet_count++;
+        if (record_packet_count % 1000 == 0) {
+            printf("[AI_FILE_RECORD] 已录音: %u字节, 数据包: %u\n", 
+                   g_file_media_ctx.recorded_size, record_packet_count);
+        }
+    } else {
+        printf("[AI_FILE_RECORD] 文件写入错误: 期望%u字节, 实际写入%zu字节\n", size, written);
+    }
+    
+    // 检查录音时间是否到达
+    uint32_t current_time = get_timestamp_ms();
+    if (current_time - g_file_media_ctx.record_start_time >= g_file_media_ctx.record_duration * 1000) {
+        printf("[AI_FILE_RECORD] 录音时间到达,准备停止录音\n");
+        g_file_media_ctx.is_recording = false;
+    }
+}
+
 /* ================================ 内部函数 ================================ */
 
 /**
@@ -905,6 +1006,387 @@ static uint32_t at_ai_reconnect(uint8_t *para, uint32_t paraLen, char *strCommon
     }
 }
 
+/**
+ * @brief AT^AIRECORD - 录音到文件
+ * @param para 参数:filename,duration_seconds
+ * @param paraLen 参数长度
+ * @param strCommonCmd 通用命令字符串
+ * @return ERRCODE_SUCC 成功,ERRCODE_FAIL 失败
+ * 
+ * 格式: AT^AIRECORD=filename,duration
+ * 示例: AT^AIRECORD=test_record.mp3,30
+ */
+static uint32_t at_ai_record_to_file(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    
+    printf("[AI_AT] 执行 AT^AIRECORD - 录音到文件\n");
+    
+    // 检查是否已经在录音
+    if (g_file_media_ctx.is_recording) {
+        printf("[AI_AT] 录音已在进行中,请先停止当前录音\n");
+        return ERRCODE_FAIL;
+    }
+    
+    // 解析参数:文件名和录音时长
+    char filename[256] = "ai_record.mp3";  // 默认文件名
+    uint32_t duration = 30;  // 默认30秒
+    
+    if (para != NULL && paraLen > 0) {
+        uint8_t argv[AI_AT_MAX_ARGC][AI_AT_MAX_ARGV_LEN] = { 0 };
+        uint32_t argc = 0;
+        
+        int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+        if (ret == AI_AT_SUCCESS && argc > 0) {
+            // 第一个参数:文件名
+            if (strlen((char*)argv[0]) > 0) {
+                strncpy(filename, (char*)argv[0], sizeof(filename) - 1);
+                filename[sizeof(filename) - 1] = '\0';
+            }
+            
+            // 第二个参数:录音时长
+            if (argc > 1) {
+                int dur = atoi((char*)argv[1]);
+                if (dur > 0 && dur <= 3600) {  // 最大1小时
+                    duration = (uint32_t)dur;
+                } else {
+                    printf("[AI_AT] 无效的录音时长: %d (有效范围: 1-3600秒)\n", dur);
+                    return ERRCODE_FAIL;
+                }
+            }
+        }
+    }
+    
+    printf("[AI_AT] 开始录音到文件: %s, 时长: %u秒\n", filename, duration);
+    
+    // 初始化文件录音上下文
+    memset(&g_file_media_ctx, 0, sizeof(g_file_media_ctx));
+    strncpy(g_file_media_ctx.record_filename, filename, sizeof(g_file_media_ctx.record_filename) - 1);
+    g_file_media_ctx.record_duration = duration;
+    g_file_media_ctx.is_recording = true;
+    g_file_media_ctx.record_start_time = get_timestamp_ms();
+    
+    // 打开录音文件
+    g_file_media_ctx.record_file = fopen(filename, "wb");
+    if (g_file_media_ctx.record_file == NULL) {
+        printf("[AI_AT] 无法创建录音文件: %s\n", filename);
+        g_file_media_ctx.is_recording = false;
+        return ERRCODE_FAIL;
+    }
+    
+    // 初始化媒体服务
+    int32_t init_ret = ai_media_service_init();
+    if (init_ret != 0) {
+        printf("[AI_AT] 媒体服务初始化失败: %d\n", init_ret);
+        fclose(g_file_media_ctx.record_file);
+        g_file_media_ctx.record_file = NULL;
+        g_file_media_ctx.is_recording = false;
+        return ERRCODE_FAIL;
+    }
+    
+    // 设置录音回调
+    ai_media_set_record_callback(file_record_callback);
+    
+    // 启动录音服务
+    printf("[AI_AT] 启动录音服务...\n");
+    uint8_t record_format[] = "mp3";
+    ai_media_record_start(record_format);
+    
+    // 检查录音状态
+    if (!ai_media_get_record_status()) {
+        printf("[AI_AT] 录音服务启动失败\n");
+        fclose(g_file_media_ctx.record_file);
+        g_file_media_ctx.record_file = NULL;
+        ai_media_service_deinit();
+        g_file_media_ctx.is_recording = false;
+        return ERRCODE_FAIL;
+    }
+    
+    printf("[AI_AT] 录音已启动!录音将保存到文件: %s\n", filename);
+    printf("[AI_AT] 录音将在%u秒后自动停止\n", duration);
+    
+    // 等待录音完成
+    uint32_t check_interval = 1000;  // 每秒检查一次
+    uint32_t elapsed_time = 0;
+    
+    while (g_file_media_ctx.is_recording && elapsed_time < duration * 1000) {
+#ifndef __TEST_MODE__
+        osDelay(check_interval);
+#else
+        usleep(check_interval * 1000);
+#endif
+        elapsed_time += check_interval;
+        
+        // 每5秒打印一次状态
+        if (elapsed_time % 5000 == 0) {
+            printf("[AI_AT] 录音进行中... 已录制: %u字节, 剩余时间: %u秒\n",
+                   g_file_media_ctx.recorded_size, (duration * 1000 - elapsed_time) / 1000);
+        }
+    }
+    
+    // 停止录音
+    printf("[AI_AT] 停止录音...\n");
+    g_file_media_ctx.is_recording = false;
+    
+    // 停止录音服务
+    ai_media_record_stop();
+    
+    // 关闭文件
+    if (g_file_media_ctx.record_file != NULL) {
+        fclose(g_file_media_ctx.record_file);
+        g_file_media_ctx.record_file = NULL;
+    }
+    
+    // 反初始化媒体服务
+    ai_media_service_deinit();
+    
+    // 打印录音结果
+    printf("[AI_AT] 录音完成!\n");
+    printf("[AI_AT] 文件: %s\n", filename);
+    printf("[AI_AT] 录音时长: %u秒\n", duration);
+    printf("[AI_AT] 文件大小: %u字节\n", g_file_media_ctx.recorded_size);
+    
+    return ERRCODE_SUCC;
+}
+
+/**
+ * @brief AT^AIPLAY - 播放音频文件
+ * @param para 参数:filename
+ * @param paraLen 参数长度
+ * @param strCommonCmd 通用命令字符串
+ * @return ERRCODE_SUCC 成功,ERRCODE_FAIL 失败
+ * 
+ * 格式: AT^AIPLAY=filename
+ * 示例: AT^AIPLAY=test_record.mp3
+ */
+static uint32_t at_ai_play_from_file(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    
+    printf("[AI_AT] 执行 AT^AIPLAY - 播放音频文件\n");
+    
+    // 检查是否已经在播放
+    if (g_file_media_ctx.is_playing) {
+        printf("[AI_AT] 播放已在进行中,请先停止当前播放\n");
+        return ERRCODE_FAIL;
+    }
+    
+    // 解析参数:文件名
+    char filename[256] = "ai_record.mp3";  // 默认文件名
+    
+    if (para != NULL && paraLen > 0) {
+        uint8_t argv[AI_AT_MAX_ARGC][AI_AT_MAX_ARGV_LEN] = { 0 };
+        uint32_t argc = 0;
+        
+        int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+        if (ret == AI_AT_SUCCESS && argc > 0) {
+            if (strlen((char*)argv[0]) > 0) {
+                strncpy(filename, (char*)argv[0], sizeof(filename) - 1);
+                filename[sizeof(filename) - 1] = '\0';
+            }
+        }
+    }
+    
+    printf("[AI_AT] 开始播放文件: %s\n", filename);
+    
+    // 检查文件是否存在
+    FILE* test_file = fopen(filename, "rb");
+    if (test_file == NULL) {
+        printf("[AI_AT] 无法打开音频文件: %s\n", filename);
+        return ERRCODE_FAIL;
+    }
+    
+    // 获取文件大小
+    fseek(test_file, 0, SEEK_END);
+    long file_size = ftell(test_file);
+    fseek(test_file, 0, SEEK_SET);
+    fclose(test_file);
+    
+    if (file_size <= 0) {
+        printf("[AI_AT] 音频文件为空或无效: %s\n", filename);
+        return ERRCODE_FAIL;
+    }
+    
+    printf("[AI_AT] 文件大小: %ld字节\n", file_size);
+    
+    // 初始化文件播放上下文
+    strncpy(g_file_media_ctx.play_filename, filename, sizeof(g_file_media_ctx.play_filename) - 1);
+    g_file_media_ctx.is_playing = true;
+    g_file_media_ctx.play_start_time = get_timestamp_ms();
+    g_file_media_ctx.played_size = 0;
+    
+    // 打开播放文件
+    g_file_media_ctx.play_file = fopen(filename, "rb");
+    if (g_file_media_ctx.play_file == NULL) {
+        printf("[AI_AT] 无法打开播放文件: %s\n", filename);
+        g_file_media_ctx.is_playing = false;
+        return ERRCODE_FAIL;
+    }
+    
+    // 初始化媒体服务
+    int32_t init_ret = ai_media_service_init();
+    if (init_ret != 0) {
+        printf("[AI_AT] 媒体服务初始化失败: %d\n", init_ret);
+        fclose(g_file_media_ctx.play_file);
+        g_file_media_ctx.play_file = NULL;
+        g_file_media_ctx.is_playing = false;
+        return ERRCODE_FAIL;
+    }
+    
+    // 启动播放服务
+    printf("[AI_AT] 启动播放服务...\n");
+    uint8_t play_format[] = "mp3";
+    ai_media_play_start(play_format);
+    
+    // 检查播放状态
+    if (!ai_media_get_play_status()) {
+        printf("[AI_AT] 播放服务启动失败\n");
+        fclose(g_file_media_ctx.play_file);
+        g_file_media_ctx.play_file = NULL;
+        ai_media_service_deinit();
+        g_file_media_ctx.is_playing = false;
+        return ERRCODE_FAIL;
+    }
+    
+    printf("[AI_AT] 开始播放文件: %s\n", filename);
+    
+    // 读取并播放文件数据
+    uint8_t buffer[1024];  // 1KB缓冲区
+    size_t bytes_read;
+    uint32_t total_played = 0;
+    
+    while (g_file_media_ctx.is_playing && (bytes_read = fread(buffer, 1, sizeof(buffer), g_file_media_ctx.play_file)) > 0) {
+        // 播放数据
+        ai_media_play_buffer(buffer, bytes_read);
+        total_played += bytes_read;
+        g_file_media_ctx.played_size = total_played;
+        
+        // 每播放100KB打印一次状态
+        if (total_played % (100 * 1024) == 0) {
+            printf("[AI_AT] 播放进度: %u/%ld字节 (%.1f%%)\n", 
+                   total_played, file_size, (float)total_played * 100.0f / file_size);
+        }
+        
+        // 控制播放速度,避免播放过快
+#ifndef __TEST_MODE__
+        osDelay(50);  // 延时50ms
+#else
+        usleep(50000);  // 测试模式延时50ms
+#endif
+    }
+    
+    // 停止播放
+    printf("[AI_AT] 停止播放...\n");
+    g_file_media_ctx.is_playing = false;
+    
+    // 停止播放服务
+    ai_media_play_stop();
+    
+    // 关闭文件
+    if (g_file_media_ctx.play_file != NULL) {
+        fclose(g_file_media_ctx.play_file);
+        g_file_media_ctx.play_file = NULL;
+    }
+    
+    // 反初始化媒体服务
+    ai_media_service_deinit();
+    
+    // 打印播放结果
+    uint32_t play_duration = get_timestamp_ms() - g_file_media_ctx.play_start_time;
+    printf("[AI_AT] 播放完成!\n");
+    printf("[AI_AT] 文件: %s\n", filename);
+    printf("[AI_AT] 播放时长: %u毫秒\n", play_duration);
+    printf("[AI_AT] 播放数据: %u字节\n", total_played);
+    
+    return ERRCODE_SUCC;
+}
+
+/**
+ * @brief AT^AIRECORDSTOP - 停止录音
+ * @param para 参数(未使用)
+ * @param paraLen 参数长度
+ * @param strCommonCmd 通用命令字符串
+ * @return ERRCODE_SUCC 成功,ERRCODE_FAIL 失败
+ */
+static uint32_t at_ai_record_stop(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(para);
+    UNUSED(paraLen);
+    UNUSED(strCommonCmd);
+    
+    printf("[AI_AT] 执行 AT^AIRECORDSTOP - 停止录音\n");
+    
+    if (!g_file_media_ctx.is_recording) {
+        printf("[AI_AT] 当前没有进行中的录音\n");
+        return ERRCODE_SUCC;
+    }
+    
+    // 停止录音
+    printf("[AI_AT] 强制停止录音...\n");
+    g_file_media_ctx.is_recording = false;
+    
+    // 停止录音服务
+    ai_media_record_stop();
+    
+    // 关闭文件
+    if (g_file_media_ctx.record_file != NULL) {
+        fclose(g_file_media_ctx.record_file);
+        g_file_media_ctx.record_file = NULL;
+    }
+    
+    // 反初始化媒体服务
+    ai_media_service_deinit();
+    
+    printf("[AI_AT] 录音已停止\n");
+    printf("[AI_AT] 文件: %s\n", g_file_media_ctx.record_filename);
+    printf("[AI_AT] 录制数据: %u字节\n", g_file_media_ctx.recorded_size);
+    
+    return ERRCODE_SUCC;
+}
+
+/**
+ * @brief AT^AIPLAYSTOP - 停止播放
+ * @param para 参数(未使用)
+ * @param paraLen 参数长度
+ * @param strCommonCmd 通用命令字符串
+ * @return ERRCODE_SUCC 成功,ERRCODE_FAIL 失败
+ */
+static uint32_t at_ai_play_stop(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(para);
+    UNUSED(paraLen);
+    UNUSED(strCommonCmd);
+    
+    printf("[AI_AT] 执行 AT^AIPLAYSTOP - 停止播放\n");
+    
+    if (!g_file_media_ctx.is_playing) {
+        printf("[AI_AT] 当前没有进行中的播放\n");
+        return ERRCODE_SUCC;
+    }
+    
+    // 停止播放
+    printf("[AI_AT] 强制停止播放...\n");
+    g_file_media_ctx.is_playing = false;
+    
+    // 停止播放服务
+    ai_media_play_stop();
+    
+    // 关闭文件
+    if (g_file_media_ctx.play_file != NULL) {
+        fclose(g_file_media_ctx.play_file);
+        g_file_media_ctx.play_file = NULL;
+    }
+    
+    // 反初始化媒体服务
+    ai_media_service_deinit();
+    
+    printf("[AI_AT] 播放已停止\n");
+    printf("[AI_AT] 文件: %s\n", g_file_media_ctx.play_filename);
+    printf("[AI_AT] 播放数据: %u字节\n", g_file_media_ctx.played_size);
+    
+    return ERRCODE_SUCC;
+}
+
 /**
  * @brief AT^AIMEDIATEST - 媒体服务测试(边录边放)
  * @param para 参数:测试持续时间(秒),默认10秒
@@ -1086,6 +1568,10 @@ static const at_cmd_table_t g_ai_cmd[] = {
     { (char *)"AT^AISTATS",      at_ai_stats, (char *)"Show test statistics" },
     { (char *)"AT^AICLEANUP",    at_ai_cleanup, (char *)"Cleanup AI services" },
     { (char *)"AT^AIRECONNECT",  at_ai_reconnect, (char *)"service_type (0=ASR,1=Chat,2=TTS)" },
+    { (char *)"AT^AIRECORD",     at_ai_record_to_file, (char *)"filename,duration_seconds" },
+    { (char *)"AT^AIPLAY",      at_ai_play_from_file, (char *)"filename" },
+    { (char *)"AT^AIRECORDSTOP", at_ai_record_stop, (char *)"Stop recording" },
+    { (char *)"AT^AIPLAYSTOP",  at_ai_play_stop, (char *)"Stop playback" },
     { (char *)"AT^AIMEDIATEST",  at_ai_media_test, (char *)"duration_seconds (default=10, max=300)" },
     { (char *)"AT^AIMEDIASTOP",  at_ai_media_stop, (char *)"Stop media test" },
 };
@@ -1169,16 +1655,34 @@ int main(void)
     result = at_ai_performance_test(NULL, 0, NULL);
     printf("   结果: %s\n", result == ERRCODE_SUCC ? "✅ 成功" : "❌ 失败");
     
-    printf("\n9. 测试 AT^AIMEDIATEST=5 - 媒体服务测试(边录边放5秒)\n");
+    printf("\n9. 测试 AT^AIRECORD=test_record.mp3,30 - 录音到文件\n");
+    uint8_t record_para[] = "test_record.mp3,30";
+    result = at_ai_record_to_file(record_para, sizeof(record_para) - 1, NULL);
+    printf("   结果: %s\n", result == ERRCODE_SUCC ? "✅ 成功" : "❌ 失败");
+    
+    printf("\n10. 测试 AT^AIPLAY=test_record.mp3 - 播放音频文件\n");
+    uint8_t play_para[] = "test_record.mp3";
+    result = at_ai_play_from_file(play_para, sizeof(play_para) - 1, NULL);
+    printf("   结果: %s\n", result == ERRCODE_SUCC ? "✅ 成功" : "❌ 失败");
+    
+    printf("\n11. 测试 AT^AIRECORDSTOP - 停止录音\n");
+    result = at_ai_record_stop(NULL, 0, NULL);
+    printf("   结果: %s\n", result == ERRCODE_SUCC ? "✅ 成功" : "❌ 失败");
+    
+    printf("\n12. 测试 AT^AIPLAYSTOP - 停止播放\n");
+    result = at_ai_play_stop(NULL, 0, NULL);
+    printf("   结果: %s\n", result == ERRCODE_SUCC ? "✅ 成功" : "❌ 失败");
+    
+    printf("\n13. 测试 AT^AIMEDIATEST=5 - 媒体服务测试(边录边放5秒)\n");
     uint8_t media_para[] = "5";
     result = at_ai_media_test(media_para, sizeof(media_para) - 1, NULL);
     printf("   结果: %s\n", result == ERRCODE_SUCC ? "✅ 成功" : "❌ 失败");
     
-    printf("\n10. 最终统计和清理\n");
+    printf("\n14. 最终统计和清理\n");
     result = at_ai_stats(NULL, 0, NULL);
     printf("   统计结果: %s\n", result == ERRCODE_SUCC ? "✅ 成功" : "❌ 失败");
     
-    printf("\n11. 测试 AT^AICLEANUP - 清理AI服务\n");
+    printf("\n15. 测试 AT^AICLEANUP - 清理AI服务\n");
     result = at_ai_cleanup(NULL, 0, NULL);
     printf("   结果: %s\n", result == ERRCODE_SUCC ? "✅ 成功" : "❌ 失败");
     
@@ -1186,6 +1690,12 @@ int main(void)
     printf("✓ 所有命令表注册成功\n");
     printf("✓ 命令处理函数正常工作\n");
     printf("✓ 可以集成到LiteOS AT系统中\n");
+    printf("✓ 新增文件录音和播放功能\n");
+    printf("✓ 支持以下新AT命令:\n");
+    printf("  - AT^AIRECORD=filename,duration - 录音到文件\n");
+    printf("  - AT^AIPLAY=filename - 播放音频文件\n");
+    printf("  - AT^AIRECORDSTOP - 停止录音\n");
+    printf("  - AT^AIPLAYSTOP - 停止播放\n");
     
     return 0;
 }
index 49b3d50..13e2656 100644 (file)
@@ -27,7 +27,7 @@ extern "C" {
 /* WebSocket相关头文件 */
 #ifdef SUPPORT_ZHIHUI_AI_SERVICE
 // 宏定义:USE_ZHIHUI_WEBSOCKET = 1 使用新的zhihui接口,= 0 使用海思原有接口
-#define USE_ZHIHUI_WEBSOCKET 0
+#define USE_ZHIHUI_WEBSOCKET 1
 #ifndef USE_ZHIHUI_WEBSOCKET
 #define USE_ZHIHUI_WEBSOCKET 0  // 默认使用原有接口
 #endif
index ea7f6e1..37a845f 100644 (file)
@@ -509,7 +509,8 @@ ai_error_t ai_connection_manager_send_rawdata(ai_service_type_t service_type,
     ai_error_t result = AI_OK;
 
     if (conn->state != AI_CONN_STATE_CONNECTED || conn->websocket < 0) {
-        AI_LOGW("Service %s not connected, cannot send raw data", g_service_names[service_type]);
+        AI_LOGW("Service %s not ready for sending: state=%d, websocket=%d", 
+               g_service_names[service_type], conn->state, conn->websocket);
         result = AI_ERROR_SERVICE_UNAVAILABLE;
     } else {
         // 检查缓冲区空间
@@ -519,9 +520,12 @@ ai_error_t ai_connection_manager_send_rawdata(ai_service_type_t service_type,
 
 #ifndef __TEST_MODE__
             // 发送二进制数据
+            AI_LOGI("Sending %lu bytes to service %s (websocket=%d)", 
+                   (unsigned long)length, g_service_names[service_type], conn->websocket);
             int ret = WebSocketClientSendBinStart(conn->websocket, (const char*)conn->send_buffer->buffer, length);
             if (ret < 0) {
-                AI_LOGE("Failed to send raw data to service %s", g_service_names[service_type]);
+                AI_LOGE("Failed to send raw data to service %s: WebSocket error=%d", 
+                       g_service_names[service_type], ret);
                 result = AI_ERROR_WEBSOCKET;
             } else {
                 // 更新统计
@@ -569,7 +573,8 @@ ai_error_t ai_connection_manager_send_data(ai_service_type_t service_type,
     ai_error_t result = AI_OK;
     
     if (conn->state != AI_CONN_STATE_CONNECTED || conn->websocket < 0) {
-        AI_LOGW("Service %s not connected, cannot send data", g_service_names[service_type]);
+        AI_LOGW("Service %s not ready for sending: state=%d, websocket=%d", 
+               g_service_names[service_type], conn->state, conn->websocket);
         result = AI_ERROR_SERVICE_UNAVAILABLE;
     } else {
         /* 检查缓冲区空间 */
@@ -579,9 +584,12 @@ ai_error_t ai_connection_manager_send_data(ai_service_type_t service_type,
             
 #ifndef __TEST_MODE__
             /* 发送数据 */
+            AI_LOGI("Sending %lu bytes (text) to service %s (websocket=%d)", 
+                   (unsigned long)length, g_service_names[service_type], conn->websocket);
             int ret = WebSocketClientSendText(conn->websocket, (const char*)conn->send_buffer->buffer, length);
             if (ret < 0) {
-                AI_LOGE("Failed to send data to service %s", g_service_names[service_type]);
+                AI_LOGE("Failed to send text data to service %s: WebSocket error=%d", 
+                       g_service_names[service_type], ret);
                 result = AI_ERROR_WEBSOCKET;
             } else {
                 /* 更新统计 */
index 263466a..4dee203 100644 (file)
@@ -111,6 +111,13 @@ ai_error_t ai_services_init(ai_services_context_t *context)
     /* 生成统一会话ID */
     ai_services_generate_session_id(context->current_session_id, sizeof(context->current_session_id));
     
+    // 检查并打印录音和播放服务器状态
+    uint8_t record_status = ai_media_get_record_status();
+    AI_LOGI("ai_media_get_record_status: %d", record_status);
+
+    uint8_t play_status = ai_media_get_play_status();
+    AI_LOGI("ai_media_get_play_status: %d", play_status);
+
     context->last_activity_time = get_current_timestamp();
     context->is_initialized = true;
     
diff --git a/code/sdk/zhihui/ai/src/http_getfile.c b/code/sdk/zhihui/ai/src/http_getfile.c
new file mode 100644 (file)
index 0000000..00a77b0
--- /dev/null
@@ -0,0 +1,175 @@
+#include "http_client.h"
+
+
+#include <sys/time.h>
+
+#include "custom_utils.h"
+#include "custom_runtime.h"
+#include "bleANCS.h"
+#include "custom_utils.h"
+#include "cmsis_os2.h"
+#include "wearable_log.h"
+#include "dev_authentication.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define HTTP_JSON_SERVER_NAME "app-api.raisound.com"//"test.app.api.thisiot.com"//获取升级服务器
+#define PORT (80)// (80)http端口号  (443)//https端口号
+#define PUT_URL "/dev/auth/active"//激活接口
+#define POST_URL "/dev/auth/sign_in"//登录接口
+
+
+osSemaphoreId_t put_done_sem;
+
+static uint32_t  put_srv_res=0;
+
+
+osSemaphoreId_t post_done_sem;
+
+static uint32_t  post_srv_res=0;
+
+static httpc_connection_t settings = {0};
+
+
+    static err_t httpc_download_headers_done_ui(httpc_state_t *connection, void *arg, struct pbuf *hdr, u16_t hdr_len, u32_t content_len)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "httpc_download_headers_done_ui hdrlen %d, file len %d\r\n",hdr_len,content_len); 
+        // file_total_len = content_len;
+        return 0;
+    }
+    static err_t httpc_download_file_recv_ui(httpc_state_t *connection, u32_t rx_len,u32_t rx_total_len)
+    {
+        // WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "httpc_download_file_recv_ui recv %d bytes total received %d filelen %d\r\n",rx_len,rx_total_len,file_total_len);
+        return 0;
+    }
+
+    static void httpc_download_result_data_put(void *arg, httpc_result_t httpc_result, u32_t rx_content_len, u32_t srv_res, err_t err)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "httpc_download_result_ui");
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"httpc_download_result , httpc_result_t %d, rx_content_len %d , srv_res %d, err %d\n",
+            httpc_result,rx_content_len,srv_res,err);
+        // if(srv_res==200)
+        {
+            put_srv_res=srv_res;
+
+            (void)osSemaphoreRelease(put_done_sem);
+            //激活成功
+        }
+        return ;
+    }
+    // {"success":true,"msg":"登录成功","code":20001,"data":{"deviceId":"28110601009b","token":"95fc6dcdf5a3e9a48df535453efd097c19"}}
+
+    static void httpc_download_result_data_post(void *arg, httpc_result_t httpc_result, u32_t rx_content_len, u32_t srv_res, err_t err)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "httpc_download_result_ui");
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"httpc_download_result , httpc_result_t %d, rx_content_len %d , srv_res %d, err %d\n",
+            httpc_result,rx_content_len,srv_res,err);
+        // if(srv_res==200)
+        {
+             post_srv_res=srv_res;
+            
+            (void)osSemaphoreRelease(post_done_sem);
+
+            //登录成功
+        }
+        return ;
+    }
+
+
+
+uint32_t put_data_by_get_file(char *data,uint16_t data_len)
+{
+   
+    memset_s(&settings,sizeof(settings),0,sizeof(settings));
+    settings.use_proxy=0;
+    
+    settings.use_post=1;
+    settings.args=(u8_t*)data;
+    settings.arglen=data_len;
+    uint8_t *otadatapath =(uint8_t *)AUTH_ACTIVE;
+
+    settings.result_fn=httpc_download_result_data_put;
+    settings.file_rx_fn = httpc_download_file_recv_ui;
+    settings.headers_done_fn = httpc_download_headers_done_ui;
+
+    httpc_state_t* connection=NULL;
+    err_t rett= httpc_get_file_dns_to_disk(
+        HTTP_JSON_SERVER_NAME,
+        PORT,
+        PUT_URL,
+        &settings, 
+        NULL, 
+        (const char*) otadatapath, 
+            &connection);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"custom_start_ota_download %d \r\n",rett);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "use_put");
+
+    if(rett==0)
+    {
+        put_done_sem = osSemaphoreNew(1, 0, NULL);
+    
+        osSemaphoreAcquire(put_done_sem, 1000*30);
+        
+        osSemaphoreDelete(put_done_sem);
+        return put_srv_res;
+    }
+    else
+    {
+        return rett;
+    }   
+}
+
+
+uint32_t post_data_by_get_file(char *data,uint16_t data_len)
+{
+    memset_s(&settings,sizeof(settings),0,sizeof(settings));
+    settings.use_proxy=0;
+    
+    settings.use_post=1;
+    settings.args=(u8_t*)data;
+    settings.arglen=data_len;
+    uint8_t *otadatapath =(uint8_t *)AUTH_SIGN_IN;
+
+    settings.result_fn=httpc_download_result_data_post;
+    settings.file_rx_fn = httpc_download_file_recv_ui;
+    settings.headers_done_fn = httpc_download_headers_done_ui;
+
+    httpc_state_t* connection=NULL;
+    err_t rett= httpc_get_file_dns_to_disk(
+        HTTP_JSON_SERVER_NAME,
+        PORT,
+        POST_URL,
+        &settings, 
+        NULL, 
+        (const char*) otadatapath, 
+            &connection);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"custom_start_ota_download %d \r\n",rett);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "use_post");      
+
+     if(rett==0)
+    {
+        post_done_sem = osSemaphoreNew(1, 0, NULL);
+    
+        osSemaphoreAcquire(post_done_sem, 1000*30);
+        
+        osSemaphoreDelete(post_done_sem);
+        
+        return post_srv_res;
+    }
+    else
+    {
+        return rett;
+    }   
+}
+
+
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
\ No newline at end of file
diff --git a/code/sdk/zhihui/ai_old/CMakeLists.txt b/code/sdk/zhihui/ai_old/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ae9d840
--- /dev/null
@@ -0,0 +1,62 @@
+#===============================================================================
+# @brief    cmake file
+# Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved.
+#===============================================================================
+
+set(COMPONENT_NAME "zhihui_ai_old")
+
+set(PUBLIC_HEADER
+${CMAKE_CURRENT_SOURCE_DIR}
+)
+set(PRIVATE_HEADER
+${ROOT_DIR}/open_source/openharmony/third_party/cJSON
+${ROOT_DIR}/open_source/openharmony/foundation/ace/ace_engine_lite/modules/netstack/websocket/include
+${ROOT_DIR}/open_source/openharmony/third_party/lwip/lwip_v2.1.3/src/include
+${ROOT_DIR}/open_source/openharmony/third_party/lwip/lwip_adapter/liteos/src/include
+)
+
+set(SOURCES
+${CMAKE_CURRENT_SOURCE_DIR}/ai_old_at_cmd.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/zhihui_ws.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/zhihui_ai_server.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/asr_websocket_server.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/tts_websocket_server.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/chat_websocket_server.cpp
+)
+
+set(COMPONENT_PUBLIC_CCFLAGS
+)
+
+set(COMPONENT_CCFLAGS
+    -std=c++11
+    -Wno-error
+    -Wno-unused-parameter
+    -fno-exceptions
+    -fno-unwind-tables
+    -fno-asynchronous-unwind-tables
+    -Wno-undef
+    -Wno-bitwise-op-parentheses
+    -Wno-shift-op-parentheses
+    -nostdlibinc
+    -nostdinc
+    -nostdlib
+    -Wno-c++11-narrowing
+    -Wno-error=unused-function
+)
+
+set(WHOLE_LINK
+    true
+)
+
+set(MAIN_COMPONENT
+    false
+)
+
+set(PUBLIC_DEFINES
+SUPPORT_ZHIHUI_AI_OLD
+)
+
+set(PRIVATE_DEFINES
+)
+
+build_component()
diff --git a/code/sdk/zhihui/ai_old/ai_old_at_cmd.cpp b/code/sdk/zhihui/ai_old/ai_old_at_cmd.cpp
new file mode 100644 (file)
index 0000000..fdc572b
--- /dev/null
@@ -0,0 +1,383 @@
+
+#include "at_cmd_api.h"
+#include "pm_control.h"
+#include "cat1_server.h"
+#include "ai_old_at_cmd.h"
+#include "cat1_ctl.h"
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+// #include "phoneaddressmodel.h" // Commented out due to missing header
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
+#define PPG_MAX_ARGC            8
+#define PPG_MAX_ARGV_LEN        64
+
+#define PPG_SUCCESS             0
+#define PPG_FAILED              (-1)
+
+#include "app_at_process.h"
+// #include "cat1_ws.h" // Commented out due to missing header
+#include "zhihui_ws.h"
+#include "websocket_test.h"
+#include "cmsis_os2.h"
+
+static int ConvertCmdToParam(uint8_t *para, uint32_t paraLen,
+        uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN], uint32_t* argc)
+{
+    uint32_t pos = 0;
+    *argc = 0;
+
+    for (uint32_t i = 0; i < paraLen; i++) {
+        if ((para[i] == ' ' || para[i] == '\n') && pos != 0) {
+            argv[*argc][pos] = '\0';
+            *argc += 1;
+            pos = 0;
+            if (*argc >= PPG_MAX_ARGC) {
+                return PPG_FAILED;
+            }
+        } else {
+            argv[*argc][pos] = para[i];
+            pos++;
+            if (pos >= PPG_MAX_ARGV_LEN) {
+                return PPG_FAILED;
+            }
+        }
+    }
+    if (pos != 0) {
+        *argc += 1;
+    }
+
+    return PPG_SUCCESS;
+}
+
+#include "audio_manager_c_wrapper.h"
+#include "cat1_tcpServer.h"
+#include "audio_capture_wrapper.h"
+#include "dev_authentication.h"
+
+extern void uapi_set4GCapability(bool isopen);
+extern bool init_ai_task(uint8_t type);
+extern errcode_t chat_server_init(void);
+extern bool ai_chat_send_txt(uint8_t type,char *msg);
+extern bool uapi_start_tts(void);
+extern void uapi_start_tts_single();
+extern void uapi_UI_start_asr(uint8_t type);
+extern void read_file_put(void);
+extern bool deinit_ai_task(void);
+
+// 定义缺失的全局变量和函数
+int g_test_server_index = 0;
+
+// 缺失函数的空实现
+void start_send_voice(void) { printf("start_send_voice: not implemented\n"); }
+void uapi_UI_start_asr(uint8_t type) { printf("uapi_UI_start_asr: not implemented\n"); }
+void uapi_start_tts_single(void) { printf("uapi_start_tts_single: not implemented\n"); }
+int get_websocket_test_state(void) { printf("get_websocket_test_state: not implemented\n"); return 0; }
+int at_test_websocket_handler(const char *cmd, const char *params) { printf("at_test_websocket_handler: not implemented\n"); return 0; }
+void stop_websocket_test(void) { printf("stop_websocket_test: not implemented\n"); }
+void get_websocket_test_stats(uint32_t *send_count, uint32_t *recv_count, uint32_t *lost_count) { 
+    printf("get_websocket_test_stats: not implemented\n"); 
+    if(send_count) *send_count = 0;
+    if(recv_count) *recv_count = 0;
+    if(lost_count) *lost_count = 0;
+}
+void startAudioCaptureTask(void) { printf("startAudioCaptureTask: not implemented\n"); }
+void set_AIStreamend(uint8_t state) { printf("set_AIStreamend: not implemented\n"); }
+
+static uint32_t wstest(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+
+    // g_test_server_index already defined above
+    if( argc == 1)
+    {
+        g_test_server_index = atoi((char*)argv[0]);
+    }
+    printf("AT^WSTEST g_test_server_index %d\n",g_test_server_index);
+    init_ai_task(AI_TYPE_JIU);
+    return 0;
+}
+
+static uint32_t ai_msg(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    ai_chat_send_txt(0,(char *)argv[0]);
+    return 0;
+}
+
+static uint32_t start_record(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    uapi_start_asr();
+    streamingRecordAndSend_AI(0);
+    return 0;
+}
+
+static uint32_t start_asr(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    start_send_voice();
+    return 0;
+}
+
+static uint32_t sendbindata(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    // uapi_cat1_keep_wakeup(1); // Function not available, commented out
+    uapi_UI_start_asr(AI_TYPE_JIU);
+    return 0;
+}
+
+static uint32_t sendfilebindata(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    // uapi_cat1_keep_wakeup(1); // Function not available, commented out
+    return 0;
+}
+
+static uint32_t active(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    aut_active();
+    return 0;
+}
+
+static uint32_t readfileput(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    read_file_put();
+    return 0;
+}
+
+static uint32_t autlogin(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    pre_AI_init();
+    return 0;
+}
+
+static uint32_t stopwstest(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    deinit_ai_task();
+    return 0;
+}
+
+static uint32_t starttts(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    uapi_start_tts();
+    return 0;
+}
+
+static uint32_t sendttstxt(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    uapi_start_tts_single();
+    return 0;
+}
+
+static uint32_t sendfotaurl(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[PPG_MAX_ARGC][PPG_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+    printf("ai_msg\n");
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != PPG_SUCCESS) {
+        printf("CAT1TEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+    return 0;
+}
+
+static uint32_t test_websocket(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    char params[256] = {0};
+    if (paraLen > 0 && paraLen < sizeof(params)) {
+        memcpy(params, para, paraLen);
+        params[paraLen] = '\0';
+    }
+    printf("WebSocket测试命令: AT^TESTWEBSOCKET=%s\n", params);
+    int current_state = get_websocket_test_state();
+    printf("当前测试状态: %d\n", current_state);
+    if (current_state != 1)
+    {
+        int result = at_test_websocket_handler("AT^TESTWEBSOCKET", params);
+        if (result == 0) {
+            printf("WebSocket测试启动成功\n");
+        } else {
+            printf("WebSocket测试启动失败,错误码: %d\n", result);
+        }
+    }else{
+        printf("WebSocket测试已经运行\n");
+    }
+    return ERRCODE_SUCC;
+}
+
+static uint32_t stop_websocket_test_cmd(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    UNUSED(para);
+    UNUSED(paraLen);
+    printf("WebSocket停止测试命令: AT^STOPWEBSOCKET\n");
+    int current_state = get_websocket_test_state();
+    printf("停止前测试状态: %d\n", current_state);
+    stop_websocket_test();
+    printf("停止后测试状态: %d\n", get_websocket_test_state());
+    printf("WebSocket测试已停止\n");
+    return ERRCODE_SUCC;
+}
+
+static uint32_t websocket_status(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    UNUSED(para);
+    UNUSED(paraLen);
+    printf("WebSocket状态查询命令: AT^WEBSOCKETSTATUS\n");
+    int state = get_websocket_test_state();
+    uint32_t send_count, recv_count, lost_count;
+    get_websocket_test_stats(&send_count, &recv_count, &lost_count);
+    const char *state_str[] = {"空闲", "运行中", "已完成", "错误"};
+    printf("测试状态: %s\n", state_str[state]);
+    printf("发送数据包: %u\n", send_count);
+    printf("接收数据包: %u\n", recv_count);
+    printf("丢失数据包: %u\n", lost_count);
+    return ERRCODE_SUCC;
+}
+
+static const at_cmd_table_t g_ai_old_cmd[] = {
+    { (char *)"AT^WSTEST",      wstest, (char *)"1" },
+    { (char *)"AT^AI_MSG",      ai_msg, (char *)"1" },
+    { (char *)"AT^AI_ASR",      start_record, (char *)"1" },
+    { (char *)"AT^STARTASR",      start_asr, (char *)"1" },
+    { (char *)"AT^SENDBINDATA",      sendbindata, (char *)"1" },
+    { (char *)"AT^SENDFILEDATA",      sendfilebindata, (char *)"1" },
+    { (char *)"AT^ACTIVE",      active, (char *)"1" },
+    { (char *)"AT^READPUT",      readfileput, (char *)"1" },
+    { (char *)"AT^LOGIN",      autlogin, (char *)"1" },
+    { (char *)"AT^STARTTTS",      starttts, (char *)"1" },
+    { (char *)"AT^SENDTTTS",      sendttstxt, (char *)"1" },
+    { (char *)"AT^STOPTEST",      stopwstest, (char *)"1" },
+    { (char *)"AT^OTAHTTP",      sendfotaurl, (char *)"1" },
+    { (char *)"AT^TESTWEBSOCKET", test_websocket, (char *)"1" },
+    { (char *)"AT^STOPWEBSOCKET", stop_websocket_test_cmd, (char *)"1" },
+    { (char *)"AT^WEBSOCKETSTATUS", websocket_status, (char *)"1" },
+};
+
+at_cmd_table_t *get_ai_old_cmd_table(uint32_t *cmd_count)
+{
+    *cmd_count = ARRAY_COUNT(g_ai_old_cmd);
+    return (at_cmd_table_t *)g_ai_old_cmd;
+}
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
\ No newline at end of file
diff --git a/code/sdk/zhihui/ai_old/ai_old_at_cmd.h b/code/sdk/zhihui/ai_old/ai_old_at_cmd.h
new file mode 100644 (file)
index 0000000..391cd9b
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n
+ *
+ * Description: Provides at cmd register func \n
+ * Author: @CompanyNameTag \n
+ * History: \n
+ * 2022-07-20, Create file. \n
+ */
+#ifndef AI_OLD_AT_CMD_H
+#define AI_OLD_AT_CMD_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include "errcode.h"
+#include "soc_osal.h"
+#include "at_cmd_api.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+at_cmd_table_t *get_cat1_cmd_table(uint32_t *cmd_count);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
diff --git a/code/sdk/zhihui/ai_old/asr_websocket_server.cpp b/code/sdk/zhihui/ai_old/asr_websocket_server.cpp
new file mode 100644 (file)
index 0000000..840675b
--- /dev/null
@@ -0,0 +1,440 @@
+/**
+ * @file asr_websocket_server.cpp
+ * @brief ASR WebSocket服务器实现
+ * @version 1.0.0
+ * @date 2024-09-05
+ * 
+ * 从 zhihui_ai_server.cpp 中提取的 ASR 相关功能
+ */
+
+#include "asr_websocket_server.h"
+#include "zhihui_ws.h"
+#include "bk_websocket.h"
+#include "ws_queue_common.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include "wearable_log.h"
+#include "custom_runtime.h"
+#include "cmsis_os2.h"
+#include "osal_msgqueue.h"
+#include "thread_init.h"
+#include "soc_osal.h"
+#include "common_def.h"
+#include "los_printf.h"
+#include "../../../../../open_source/openharmony/third_party/cJSON/cJSON.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ASR 相关全局变量 */
+char *asr_recv_buf = NULL;
+WebSocketClient *asr_client = NULL;
+static ws_message_queue_t asr_msg_queue = {0};
+static uint8_t asr_need_stop = 0;
+static uint8_t asr_is_stop = 0;
+static uint8_t is_bk_websocket_asr = 0;
+static uint8_t ai_asr_service_init_flag = 0;
+static uint8_t asr_is_ready_start = 0;
+static uint8_t asr_client_ping = 0;
+
+/* 外部函数声明 */
+extern bool read_dev_token(char *data_token);
+extern bool get_dev_id(char *device_id);
+// extern void uapi_cat1_keep_wakeup(uint8_t state); // Commented out due to missing implementation
+extern void startAudioCaptureTask(void);
+extern bool stop_AudioCaptureProcess_AI(void);
+extern void ble_set_ai_Question_str(char *str);
+extern int send_msg_data_into_Ai_msg_queue(void *data, uint16_t len, uint16_t type);
+extern void msleep(uint32_t ms);
+
+/* ASR 配置和常量 */
+#define AI_RESULT_STR_LEN  512
+#define AI_MAX_RETRY_COUNT 3
+#define AI_WS_TCP_CHECK_INTERVAL_MS 100
+#define AI_WS_HANDSHAKE_TIMEOUT_MS 10000
+#define AI_RECEIVE_TIMEOUT_MS 30000
+
+static char result_str_asr[AI_RESULT_STR_LEN] = {0};
+static uint8_t type_ai = 0;
+
+/**
+ * @brief ASR WebSocket数据包回调函数
+ */
+void asr_on_ws_packet_callback(uint8_t* data, size_t datalen, WebSocketMessageType type)
+{
+    if(asr_client != NULL && asr_client->msg_queue != NULL)
+    {
+        ws_queue_put(asr_client->msg_queue, data, datalen, type);
+    }
+}
+
+/**
+ * @brief 获取ASR服务初始化标志
+ */
+uint8_t get_ai_asr_service_init_flag(void)
+{
+    return ai_asr_service_init_flag;
+}
+
+/**
+ * @brief 设置ASR服务初始化标志
+ */
+void set_ai_asr_service_init_flag(uint8_t flag)
+{
+    ai_asr_service_init_flag = flag;
+}
+
+/**
+ * @brief 获取ASR准备开始标志
+ */
+uint8_t get_asr_is_ready_start(void)
+{
+    return asr_is_ready_start;
+}
+
+/**
+ * @brief ASR URL初始化
+ */
+bool asr_ws_url_init(char * put_buf)
+{
+    char token[64] = {0};
+    if(read_dev_token(token))
+    {
+        sprintf(put_buf, "ws://amp.raisound.com/asr/ws?dt=%s&platform=aliyun&noCache=1", token);
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+/**
+ * @brief ASR结果分析
+ */
+bool asr_result_analysis(char *buf)
+{
+    // 这里可以添加ASR结果解析逻辑
+    if (buf && strlen(buf) > 0) {
+        strncpy(result_str_asr, buf, AI_RESULT_STR_LEN - 1);
+        result_str_asr[AI_RESULT_STR_LEN - 1] = '\0';
+        return true;
+    }
+    return false;
+}
+
+/**
+ * @brief 启动ASR服务
+ */
+void uapi_start_asr(void)
+{
+    startAudioCaptureTask();
+    asr_is_ready_start = 1;
+}
+
+/**
+ * @brief 停止ASR服务
+ */
+void uapi_UI_stop_asr(void)
+{
+    if(strlen(result_str_asr))
+    {
+        // 发送ASR结果到聊天服务
+        extern bool ai_chat_send_txt(uint8_t type, char *msg);
+        ai_chat_send_txt(0, result_str_asr);
+        ble_set_ai_Question_str(result_str_asr);
+        
+        memset(result_str_asr, 0, AI_RESULT_STR_LEN);
+    }
+    
+    // 启动TTS服务
+    extern bool uapi_start_tts(void);
+    uapi_start_tts();
+    
+    if(stop_AudioCaptureProcess_AI())
+    {
+        asr_is_stop = 1;
+    }
+}
+
+/**
+ * @brief 启动ASR任务
+ */
+void uapi_start_asr_task(void)
+{
+    // ASR任务启动逻辑
+    asr_is_ready_start = 1;
+}
+
+/**
+ * @brief ASR录音测试
+ */
+void asr_record_test(void)
+{
+    // ASR录音测试逻辑
+    printf("ASR record test started\n");
+}
+
+/**
+ * @brief ASR WebSocket主线程
+ */
+void bk_websocket_asr(void *data) 
+{
+    uint32_t start_time = (uint32_t)osKernelGetTickCount();
+    uint32_t retry_count = 0;
+    
+    if (asr_msg_queue.initialized) {
+        ws_queue_deinit(&asr_msg_queue);
+    }
+    ws_queue_init(&asr_msg_queue, 0);
+    
+ASR_START:
+    // uapi_cat1_keep_wakeup(1); // Commented out due to missing implementation
+    ws_queue_cleanup(&asr_msg_queue);
+    WebSocketMessageType type;
+    bool state = true;
+    
+    is_bk_websocket_asr = 1;
+    
+    uint8_t is_raisound_url = 0;
+    
+    {
+        char url_buf[124] = {0};
+        
+        if (asr_ws_url_init(url_buf)) {
+            printf("ASR URL: %s\n", url_buf);
+            is_raisound_url = 1;
+        } else {
+            is_raisound_url = 0;
+        }
+        
+        uint8_t client_count = AI_MAX_RETRY_COUNT;
+        
+        while (client_count > 0 && asr_need_stop == 0) {
+            uint32_t connect_start = (uint32_t)osKernelGetTickCount();
+            
+            // 根据测试服务器索引选择URL
+            extern uint8_t g_test_server_index;
+            if (g_test_server_index == 1) {
+                asr_client = init_websocket_client("ws://118.145.158.207:22080/asr/ws", NULL, 0);
+                if (asr_client != NULL) {
+                    asr_client->msg_queue = &asr_msg_queue;
+                    ws_set_packet_callback(asr_client, asr_on_ws_packet_callback);
+                }
+            } else if (g_test_server_index == 2) {
+                asr_client = init_websocket_client("ws://110.42.224.129:8910/asr/ws", NULL, 0);
+                if (asr_client != NULL) {
+                    asr_client->msg_queue = &asr_msg_queue;
+                    ws_set_packet_callback(asr_client, asr_on_ws_packet_callback);
+                }
+            } else if (is_raisound_url == 1) {
+                asr_client = init_websocket_client(url_buf, NULL, 1);
+                if (asr_client != NULL) {
+                    asr_client->msg_queue = &asr_msg_queue;
+                    ws_set_packet_callback(asr_client, asr_on_ws_packet_callback);
+                }
+            } else {
+                asr_client = init_websocket_client("ws://118.145.158.207:22080/asr/ws", NULL, 0);
+                if (asr_client != NULL) {
+                    asr_client->msg_queue = &asr_msg_queue;
+                    ws_set_packet_callback(asr_client, asr_on_ws_packet_callback);
+                }
+            }
+            
+            if (asr_client == NULL) {
+                printf("ASR WebSocket client creation failed, retrying... (%d/%d)\n", 
+                       AI_MAX_RETRY_COUNT - client_count + 1, AI_MAX_RETRY_COUNT);
+                client_count--;
+                msleep(2000);
+                continue;
+            }
+            
+            printf("ASR WebSocket client created successfully\n");
+            break;
+        }
+        
+        if (asr_client == NULL) {
+            printf("ASR WebSocket: Failed to create client after %d retries\n", AI_MAX_RETRY_COUNT);
+            goto asr_cleanup_and_exit;
+        }
+        
+        printf("ASR WebSocket: 连接建立成功,开始握手等待\n");
+        
+        // 等待握手完成
+        uint32_t asr_handshake_start_time = (uint32_t)osKernelGetTickCount();
+        const uint32_t asr_handshake_timeout_ms = AI_WS_HANDSHAKE_TIMEOUT_MS;
+        
+        while (asr_client->handshake == 0) {
+            if ((uint32_t)osKernelGetTickCount() - asr_handshake_start_time > asr_handshake_timeout_ms) {
+                printf("ASR WebSocket握手超时 (%d ms),重新连接\n", asr_handshake_timeout_ms);
+                close_websocket_client(asr_client);
+                asr_client = NULL;
+                goto asr_cleanup_and_exit;
+            }
+            
+            msleep(1000);
+            printf("等待ASR WebSocket握手完成... (%d ms)\n", 
+                   (uint32_t)osKernelGetTickCount() - asr_handshake_start_time);
+        }
+        
+        printf("ASR WebSocket握手完成,耗时 %d ms\n", 
+               (uint32_t)osKernelGetTickCount() - asr_handshake_start_time);
+    }
+    
+    // uapi_cat1_keep_wakeup(1); // Commented out due to missing implementation
+    
+    // 声明变量在goto标签之前
+    WebSocketMessageType msg_type;
+    uint32_t last_activity;
+    
+    // 分配ASR接收缓冲区
+    asr_recv_buf = (char *)malloc(0x400);
+    if (!asr_recv_buf) {
+        printf("Failed to allocate ASR receive buffer\n");
+        goto asr_cleanup_and_exit;
+    }
+    
+    set_ai_asr_service_init_flag(1);
+    
+    printf("ASR client initialized successfully\n");
+    
+    last_activity = (uint32_t)osKernelGetTickCount();
+    
+    while (asr_need_stop == 0) {
+        // 检查超时
+        if ((uint32_t)osKernelGetTickCount() - last_activity > AI_RECEIVE_TIMEOUT_MS) {
+            printf("ASR receive timeout, reconnecting...\n");
+            break;
+        }
+        
+        memset(asr_recv_buf, 0, 0x400);
+        extern int receive_websocket_message_from_queue(ws_message_queue_t* queue, uint8_t* buffer, 
+                                                       uint16_t buffer_size, WebSocketMessageType* type, uint32_t timeout_ms);
+        int len = receive_websocket_message_from_queue(&asr_msg_queue, (unsigned char *)asr_recv_buf, 
+                                                      0x400, &msg_type, AI_RECEIVE_TIMEOUT_MS);
+        
+        if (len < 0x400) {
+            asr_recv_buf[len] = '\0';
+        }
+        
+        if (len == -1 || msg_type == WS_CLOSE) {
+            printf("ASR WebSocket connection closed\n");
+            break;
+        }
+        
+        if (len > 0) {
+            last_activity = (uint32_t)osKernelGetTickCount();
+            
+            if (msg_type == WS_TEXT) {
+                printf("ASR text data received: %s\n", asr_recv_buf);
+                asr_result_analysis(asr_recv_buf);
+            } else if (msg_type == WS_BINARY) {
+                printf("ASR binary data received: %d bytes\n", len);
+                send_msg_data_into_Ai_msg_queue((uint8_t *)asr_recv_buf, len, 100);
+            }
+        }
+        
+        msleep(10);
+    }
+    
+asr_cleanup_and_exit:
+    printf("ASR WebSocket cleanup and exit\n");
+    
+    if (asr_recv_buf) {
+        free(asr_recv_buf);
+        asr_recv_buf = NULL;
+    }
+    
+    if (asr_client) {
+        close_websocket_client(asr_client);
+        asr_client = NULL;
+    }
+    
+    ws_queue_deinit(&asr_msg_queue);
+    is_bk_websocket_asr = 0;
+    set_ai_asr_service_init_flag(0);
+    
+    printf("ASR WebSocket thread ended\n");
+}
+
+/**
+ * @brief ASR服务器初始化
+ */
+errcode_t asr_server_init(void)
+{
+    app_task_definition_t asr_taskcfg;
+    
+    osThreadState_t osThreadGetState_t = osThreadGetState(asr_taskcfg.task_handle);
+    const char *buf = osThreadGetName(asr_taskcfg.task_handle);
+    
+    printf("ASR osThreadGetState_t %d %s!\r\n", osThreadGetState_t, buf);
+    
+    if(strcmp("asr_server_init", buf) == 0)
+    {
+        if(osThreadGetState_t != osThreadReady && osThreadGetState_t != osThreadError && 
+           osThreadGetState_t != osThreadInactive)
+        {
+            printf("ASR osThreadGetState is %d!\r\n", osThreadGetState_t);
+            return ERRCODE_FAIL;
+        }
+    }
+    
+    if(is_bk_websocket_asr || asr_client != NULL)
+    {
+        printf("ASR server is already connected!\r\n");
+        return ERRCODE_FAIL;
+    }
+    
+    printf("asr_server_init!\r\n");
+    
+    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.stack_size = 0x1000;
+    asr_taskcfg.func = bk_websocket_asr;
+    asr_taskcfg.use_mem = USE_EXTEND_MEM;
+    
+    extern errcode_t uapi_create_osThread_custom(app_task_definition_t* task_cfg);
+    errcode_t ret = uapi_create_osThread_custom(&asr_taskcfg);
+    
+    if(ret != ERRCODE_SUCC)
+    {
+        printf("create ASR service thread failed %d!\r\n", ret);
+        return ERRCODE_FAIL;
+    }
+    
+    return ERRCODE_SUCC;
+}
+
+/**
+ * @brief ASR服务器反初始化
+ */
+void asr_server_deinit(void)
+{
+    printf("asr_server_deinit\n");
+    
+    // 发送关闭消息
+    if (asr_client) {
+        if(send_websocket_message(asr_client, (uint8_t *)"WS_CLOSE", strlen("WS_CLOSE"), WS_CLOSE))
+        {
+            printf("ASR WS_CLOSE sent\n");
+        }
+    }
+    
+    asr_need_stop = 1;
+    
+    if (asr_client) {
+        close_websocket_client(asr_client);
+        asr_client = NULL;
+    }
+    
+    is_bk_websocket_asr = 0;
+    set_ai_asr_service_init_flag(0);
+}
+
+#ifdef __cplusplus
+}
+#endif 
\ No newline at end of file
diff --git a/code/sdk/zhihui/ai_old/asr_websocket_server.h b/code/sdk/zhihui/ai_old/asr_websocket_server.h
new file mode 100644 (file)
index 0000000..5023af2
--- /dev/null
@@ -0,0 +1,116 @@
+/**
+ * @file asr_websocket_server.h
+ * @brief ASR WebSocket服务器头文件
+ * @version 1.0.0
+ * @date 2024-09-05
+ */
+
+#ifndef __ASR_WEBSOCKET_SERVER_H__
+#define __ASR_WEBSOCKET_SERVER_H__
+
+#include "bk_websocket.h"
+#include <stdint.h>
+#include <stdbool.h>
+#include "errcode.h"
+#include "thread_init.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ASR 服务相关类型定义 - errcode_t is defined in errcode.h */
+
+/* 任务配置结构体 - 使用系统定义的 app_task_definition_t */
+
+/* 常量定义 */
+#define TASK_PRIORITY_APP 24
+#define USE_EXTEND_MEM 1
+
+/* ASR 服务接口函数 */
+
+/**
+ * @brief ASR WebSocket数据包回调函数
+ * @param data 数据指针
+ * @param datalen 数据长度
+ * @param type WebSocket消息类型
+ */
+void asr_on_ws_packet_callback(uint8_t* data, size_t datalen, WebSocketMessageType type);
+
+/**
+ * @brief 获取ASR服务初始化标志
+ * @return 初始化标志
+ */
+uint8_t get_ai_asr_service_init_flag(void);
+
+/**
+ * @brief 设置ASR服务初始化标志
+ * @param flag 标志值
+ */
+void set_ai_asr_service_init_flag(uint8_t flag);
+
+/**
+ * @brief 获取ASR准备开始标志
+ * @return 准备开始标志
+ */
+uint8_t get_asr_is_ready_start(void);
+
+/**
+ * @brief ASR URL初始化
+ * @param put_buf 输出缓冲区
+ * @return 成功返回true,失败返回false
+ */
+bool asr_ws_url_init(char * put_buf);
+
+/**
+ * @brief ASR结果分析
+ * @param buf 结果字符串
+ * @return 成功返回true,失败返回false
+ */
+bool asr_result_analysis(char *buf);
+
+/**
+ * @brief 启动ASR服务
+ */
+void uapi_start_asr(void);
+
+/**
+ * @brief 停止ASR服务
+ */
+void uapi_UI_stop_asr(void);
+
+/**
+ * @brief 启动ASR任务
+ */
+void uapi_start_asr_task(void);
+
+/**
+ * @brief ASR录音测试
+ */
+void asr_record_test(void);
+
+/**
+ * @brief ASR WebSocket主线程
+ * @param data 线程参数
+ */
+void bk_websocket_asr(void *data);
+
+/**
+ * @brief ASR服务器初始化
+ * @return 成功返回ERRCODE_SUCC,失败返回ERRCODE_FAIL
+ */
+errcode_t asr_server_init(void);
+
+/**
+ * @brief ASR服务器反初始化
+ */
+void asr_server_deinit(void);
+
+/* 全局变量声明 */
+extern char *asr_recv_buf;
+extern WebSocketClient *asr_client;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ASR_WEBSOCKET_SERVER_H__ */ 
\ No newline at end of file
diff --git a/code/sdk/zhihui/ai_old/bk_websocket.h b/code/sdk/zhihui/ai_old/bk_websocket.h
new file mode 100644 (file)
index 0000000..0af58d5
--- /dev/null
@@ -0,0 +1,94 @@
+
+#ifndef __BK_WEBSOCKET_H__
+#define __BK_WEBSOCKET_H__
+
+// 包含新的WebSocket解析器接口
+#include "websocket_parser_wrapper.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+// 使用websocket_parser_wrapper.h中的枚举值,避免重复定义
+// 为保持向后兼容性,创建类型别名
+typedef ws_opcode_t WebSocketMessageType;
+
+// 定义向后兼容的常量(如果需要的话)
+#define WS_CONT WS_CONTINUATION
+
+/* WebSocket数据包回调函数类型 */
+typedef void (*on_ws_packet_callback)(uint8_t* data, size_t datalen, WebSocketMessageType type);
+
+/* WebSocket消息队列系统 */
+#define WS_QUEUE_SIZE 128
+#define WS_MESSAGE_MAX_SIZE 1024
+
+typedef struct {
+    uint8_t *data;//data[WS_MESSAGE_MAX_SIZE];
+    uint16_t length;
+    WebSocketMessageType type;
+    uint32_t timestamp;
+    bool in_use;
+} ws_message_item_t;
+
+typedef struct {
+#ifdef SUPPORT_WEBSOCKET_TEST
+    // ws_message_item_t messages[WS_QUEUE_SIZE];
+    // uint8_t head;
+    // uint8_t tail;
+    // uint8_t count;
+    // osMutexId_t mutex;
+    // osSemaphoreId_t semaphore;
+#endif
+    unsigned long queue_id;  // osal消息队列ID
+    bool initialized;
+} ws_message_queue_t;
+
+// WebSocket 客户端结构体
+typedef struct {
+    void* tcp_handle;
+    ws_message_queue_t *msg_queue;
+    char host[128];
+    char path[128];
+    char query[128];
+    int port;
+
+    int handshake;
+    
+    /* WebSocket解析器 */
+    ws_parser_t* parser;
+    int sockfd;  /* socket文件描述符 */
+    
+    /* 数据包回调函数 */
+    on_ws_packet_callback packet_callback;
+} WebSocketClient;
+
+// 初始化 WebSocket 客户端
+WebSocketClient *init_websocket_client(const char *url, const char *headers,uint8_t use_dns);
+
+// 设置WebSocket数据包回调函数
+void ws_set_packet_callback(WebSocketClient *client, on_ws_packet_callback callback);
+
+// 处理接收到的原始数据
+int ws_process_received_data(WebSocketClient *client, const uint8_t *data, size_t len);
+
+// 关闭 WebSocket 客户端
+void close_websocket_client(WebSocketClient *client) ;
+
+// 接收 WebSocket 消息
+int  receive_websocket_message(WebSocketClient *client, unsigned char *buf,int len,WebSocketMessageType *code);
+int send_websocket_message(WebSocketClient *client, uint8_t *message, size_t message_len, WebSocketMessageType type) ;
+
+// WebSocket测试客户端(当SUPPORT_WEBSOCKET_TEST定义时可用)
+#ifdef SUPPORT_WEBSOCKET_TEST
+extern WebSocketClient *test_client;
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+// 发送 WebSocket 消息
+// int send_websocket_message(WebSocketClient *client, uint8_t *message, size_t message_len, WebSocketMessageType type) ;
+
+#endif
diff --git a/code/sdk/zhihui/ai_old/chat_websocket_server.cpp b/code/sdk/zhihui/ai_old/chat_websocket_server.cpp
new file mode 100644 (file)
index 0000000..e9339d7
--- /dev/null
@@ -0,0 +1,497 @@
+/**
+ * @file chat_websocket_server.cpp
+ * @brief Chat WebSocket服务器实现
+ * @version 1.0.0
+ * @date 2024-09-05
+ * 
+ * 从 zhihui_ai_server.cpp 中提取的 Chat 相关功能
+ */
+
+#include "chat_websocket_server.h"
+#include "zhihui_ws.h"
+#include "bk_websocket.h"
+#include "ws_queue_common.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include "wearable_log.h"
+#include "custom_runtime.h"
+#include "cmsis_os2.h"
+#include "osal_msgqueue.h"
+#include "thread_init.h"
+#include "soc_osal.h"
+#include "common_def.h"
+#include "los_printf.h"
+#include "../../../../../open_source/openharmony/third_party/cJSON/cJSON.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Chat 相关全局变量 */
+WebSocketClient *chat_client = NULL;
+static ws_message_queue_t chat_msg_queue = {0};
+static uint8_t chat_reconnect = 0;
+static uint8_t is_bk_websocket_chat = 0;
+static uint8_t ai_chat_service_init_flag = 0;
+static uint8_t chat_client_ping = 0;
+
+/* 外部函数声明 */
+extern bool read_dev_token(char *data_token);
+extern bool get_dev_id(char *device_id);
+// extern void uapi_cat1_keep_wakeup(uint8_t state); // Commented out due to missing implementation
+extern void ble_set_ai_Answer_str(char *str, uint8_t type);
+extern void msleep(uint32_t ms);
+
+/* Chat 配置和常量 */
+#define AI_MAX_RETRY_COUNT 3
+#define AI_WS_HANDSHAKE_TIMEOUT_MS 10000
+#define AI_RECEIVE_TIMEOUT_MS 30000
+
+static uint8_t type_ai = 0;
+static char recv_buf[1024] = {0};
+
+/**
+ * @brief Chat WebSocket数据包回调函数
+ */
+void chat_on_ws_packet_callback(uint8_t* data, size_t datalen, WebSocketMessageType type)
+{
+    if(chat_client != NULL && chat_client->msg_queue != NULL)
+    {
+        ws_queue_put(chat_client->msg_queue, data, datalen, type);
+    }
+}
+
+/**
+ * @brief 获取Chat服务初始化标志
+ */
+uint8_t get_ai_chat_service_init_flag(void)
+{
+    return ai_chat_service_init_flag;
+}
+
+/**
+ * @brief 设置Chat服务初始化标志
+ */
+void set_ai_chat_service_init_flag(uint8_t flag)
+{
+    ai_chat_service_init_flag = flag;
+}
+
+/**
+ * @brief Chat结果分析
+ */
+bool chat_result_analysis(char *buf)
+{
+    extern cJSON* cJSON_Parse(const char *value);
+    extern cJSON* cJSON_GetObjectItem(const cJSON * const object, const char * const string);
+    extern int cJSON_IsString(const cJSON * const item);
+    extern void cJSON_Delete(cJSON *c);
+    
+    cJSON* root = cJSON_Parse((const char *)buf);
+    if (root == NULL) {
+        printf("Chat result parse failed\n");
+        return false;
+    }
+    
+    char *type_str = NULL;
+    char *content_str = NULL;
+
+    cJSON* type = cJSON_GetObjectItem(root, "type");
+    if (type && cJSON_IsString(type)) {
+        type_str = type->valuestring;
+    }
+    
+    cJSON* content = cJSON_GetObjectItem(root, "content");
+    if (content && cJSON_IsString(content)) {
+        content_str = content->valuestring;
+    }
+    
+    if(strcmp("middle", type_str) == 0)
+    {   
+        if(strlen(content_str) > 0) 
+        {
+            char *content_str_chat = (char *)malloc(strlen(content_str) + 1);
+            strcpy(content_str_chat, content_str);
+            ble_set_ai_Answer_str(content_str_chat, 2);
+            free(content_str_chat);
+        }
+    }
+    
+    if(strcmp("end", type_str) == 0)
+    {   
+        char end_str_chat[128] = {0};
+        if(strlen(content_str) > 0) 
+        {
+            memset(end_str_chat, 0, 128); 
+            memcpy(end_str_chat, content_str, strlen(content_str)); 
+            ble_set_ai_Answer_str(end_str_chat, 2);
+        }
+    }
+
+    cJSON_Delete(root);
+    return true;
+}
+
+/**
+ * @brief Chat URL初始化
+ */
+bool chat_ws_url_init(char * put_buf, uint8_t type)
+{
+    char token[64] = {0};
+    if(read_dev_token(token))
+    {
+        char device_id[128] = {0};
+        get_dev_id(device_id);
+        
+        char * product_id = "1927646275585744898";
+        sprintf(put_buf, "ws://amp.raisound.com/chat/ws?device_id=%s&product_id=%s&dt=%s&platform=aliyun&noCache=1", 
+                device_id, product_id, token);
+        return true;
+    }
+    else
+    {
+        char * Service_url = "118.145.158.207:22080";
+        char device_id[128] = {0};
+        get_dev_id(device_id);
+        char * product_id = "1927646275585744898";
+        
+        if(type_ai == AI_TYPE_JIU)
+        {
+            sprintf(put_buf, "ws://%s/chat/ws?device_id=%s&product_id=%s&platform=chinamobiledevice&bot_type=jiutian-lan", 
+                    Service_url, device_id, product_id);
+        }
+        else if(type_ai == AI_TYPE_DOU)
+        {
+            sprintf(put_buf, "ws://%s/chat/ws?platform=huoshan", Service_url);
+        }
+        else if(type_ai == AI_TYPE_WEN)
+        {
+            sprintf(put_buf, "ws://%s/chat/ws?platform=baidu", Service_url);
+        }
+        else if(type_ai == AI_TYPE_KIMI)
+        {
+            sprintf(put_buf, "ws://%s/chat/ws?platform=moonshot", Service_url);
+        }
+        else if(type_ai == AI_TYPE_DE)
+        {
+            sprintf(put_buf, "ws://%s/chat/ws?platform=huoshan&model=ep-20250205103849-582m7", Service_url);
+        }
+        else 
+        {
+            sprintf(put_buf, "ws://%s/chat/ws?platform=aliyun", Service_url);
+        }
+        return false;
+    }
+}
+
+/**
+ * @brief 发送聊天文本
+ */
+bool ai_chat_send_txt(uint8_t type, char *msg)
+{   
+    if(msg)
+        printf("ai_chat_send_txt message: %s\n", msg);
+
+    extern cJSON* cJSON_CreateObject(void);
+    extern cJSON* cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
+    extern char* cJSON_PrintUnformatted(const cJSON *item);
+    extern void cJSON_free(void *ptr);
+    extern void cJSON_Delete(cJSON *c);
+    
+    cJSON* dataJSON = cJSON_CreateObject();
+    
+    if (dataJSON == NULL) {
+        printf("Error creating JSON object\n");
+        return false;
+    }
+    
+    cJSON_AddStringToObject(dataJSON, "type", "jiutian-lan");
+    cJSON_AddStringToObject(dataJSON, "content", msg);
+
+    char *jsonString = cJSON_PrintUnformatted(dataJSON);
+    
+    if (jsonString == NULL) {
+        printf("Error printing JSON to string\n");
+        cJSON_Delete(dataJSON);
+        return false;
+    }
+    
+    uint32_t data_len = strlen(jsonString);
+    cJSON_Delete(dataJSON);
+    
+    if (data_len == 0) {
+        printf("Error: JSON string length is 0\n");
+        cJSON_free(jsonString);
+        return false;
+    }
+    
+    if (send_websocket_message(chat_client, (uint8_t *)jsonString, strlen(jsonString), WS_TEXT) == 0)
+    {
+        chat_reconnect = 0;
+        printf("Chat message sent successfully\n");
+        cJSON_free(jsonString);
+        return true;
+    }
+    else
+    {
+        if(chat_client == NULL)
+        {
+            printf("chat_client is NULL\n");
+        }
+        cJSON_free(jsonString);
+        printf("Chat message send failed\n");
+        return false;
+    }
+}
+
+/**
+ * @brief Chat WebSocket主线程
+ */
+void bk_websocket_demo(void *data) 
+{
+    // 声明所有变量在函数开始,避免goto跳转问题
+    uint32_t start_time = (uint32_t)osKernelGetTickCount();
+    uint32_t retry_count = 0;
+    WebSocketMessageType type;
+    bool state = true;
+    WebSocketMessageType msg_type;
+    uint32_t last_activity;
+    uint32_t chat_handshake_start_time;
+    uint32_t chat_handshake_timeout_ms;
+    
+    if (chat_msg_queue.initialized) {
+        ws_queue_deinit(&chat_msg_queue);
+    }
+    ws_queue_init(&chat_msg_queue, 0);
+
+CHAT_START:
+    // uapi_cat1_keep_wakeup(1); // Commented out due to missing implementation
+    ws_queue_cleanup(&chat_msg_queue);
+    state = true;
+    
+    is_bk_websocket_chat = 1;
+    
+    uint8_t is_raisound_url = 0;
+
+    {
+        char url_buf[124] = {0};
+        
+        if (chat_ws_url_init(url_buf, type_ai)) {
+            printf("Chat URL: %s\n", url_buf);
+            is_raisound_url = 1;
+        } else {
+            is_raisound_url = 0;
+        }
+        
+        uint8_t client_count = AI_MAX_RETRY_COUNT;
+
+        while (client_count > 0) {
+            uint32_t connect_start = (uint32_t)osKernelGetTickCount();
+            
+            // 根据测试服务器索引选择URL
+            extern uint8_t g_test_server_index;
+            if (g_test_server_index == 1) {
+                chat_client = init_websocket_client("ws://118.145.158.207:22080/chat/ws", NULL, 0);
+                if (chat_client != NULL) {
+                    chat_client->msg_queue = &chat_msg_queue;
+                    ws_set_packet_callback(chat_client, chat_on_ws_packet_callback);
+                }
+            } else if (g_test_server_index == 2) {
+                chat_client = init_websocket_client("ws://110.42.224.129:8910/chat/ws", NULL, 0);
+                if (chat_client != NULL) {
+                    chat_client->msg_queue = &chat_msg_queue;
+                    ws_set_packet_callback(chat_client, chat_on_ws_packet_callback);
+                }
+            } else if (is_raisound_url == 1) {
+                chat_client = init_websocket_client(url_buf, NULL, 1);
+                if (chat_client != NULL) {
+                    chat_client->msg_queue = &chat_msg_queue;
+                    ws_set_packet_callback(chat_client, chat_on_ws_packet_callback);
+                }
+            } else {
+                chat_client = init_websocket_client("ws://118.145.158.207:22080/chat/ws", NULL, 0);
+                if (chat_client != NULL) {
+                    chat_client->msg_queue = &chat_msg_queue;
+                    ws_set_packet_callback(chat_client, chat_on_ws_packet_callback);
+                }
+            }
+
+            if (chat_client == NULL) {
+                printf("Chat WebSocket client creation failed, retrying... (%d/%d)\n", 
+                       AI_MAX_RETRY_COUNT - client_count + 1, AI_MAX_RETRY_COUNT);
+                client_count--;
+                msleep(2000);
+                continue;
+            }
+
+            printf("Chat WebSocket client created successfully\n");
+            break;
+        }
+
+        if (chat_client == NULL) {
+            printf("Chat WebSocket: Failed to create client after %d retries\n", AI_MAX_RETRY_COUNT);
+            goto chat_cleanup_and_exit;
+        }
+
+        printf("Chat WebSocket: 连接建立成功,开始握手等待\n");
+        
+        // 等待握手完成
+        chat_handshake_start_time = (uint32_t)osKernelGetTickCount();
+        chat_handshake_timeout_ms = AI_WS_HANDSHAKE_TIMEOUT_MS;
+        
+        while (chat_client->handshake == 0) {
+            if ((uint32_t)osKernelGetTickCount() - chat_handshake_start_time > chat_handshake_timeout_ms) {
+                printf("Chat WebSocket握手超时 (%d ms),重新连接\n", chat_handshake_timeout_ms);
+                close_websocket_client(chat_client);
+                chat_client = NULL;
+                goto chat_cleanup_and_exit;
+            }
+            
+            msleep(1000);
+            printf("等待Chat WebSocket握手完成... (%d ms)\n", 
+                   (uint32_t)osKernelGetTickCount() - chat_handshake_start_time);
+        }
+        
+        printf("Chat WebSocket握手完成,耗时 %d ms\n", 
+               (uint32_t)osKernelGetTickCount() - chat_handshake_start_time);
+    }
+
+    // uapi_cat1_keep_wakeup(1); // Commented out due to missing implementation
+    set_ai_chat_service_init_flag(1);
+    
+    printf("Chat client initialized successfully\n");
+    
+    // 初始化变量
+    last_activity = (uint32_t)osKernelGetTickCount();
+    
+    extern uint8_t disconnect_server;
+    while (disconnect_server == 0) {
+        // 检查超时
+        if ((uint32_t)osKernelGetTickCount() - last_activity > AI_RECEIVE_TIMEOUT_MS) {
+            printf("Chat receive timeout, reconnecting...\n");
+            break;
+        }
+        
+        memset(recv_buf, 0, 1024);
+        extern int receive_websocket_message_from_queue(ws_message_queue_t* queue, uint8_t* buffer, 
+                                                       uint16_t buffer_size, WebSocketMessageType* type, uint32_t timeout_ms);
+        int len = receive_websocket_message_from_queue(&chat_msg_queue, (unsigned char *)recv_buf, 
+                                                      1024, &msg_type, AI_RECEIVE_TIMEOUT_MS);
+        if (len < 1024)
+        {
+            recv_buf[len] = '\0';
+        }
+        
+        if (len == -1 || msg_type == WS_CLOSE) {
+            printf("Chat WebSocket connection closed\n");
+            break;
+        }
+        
+        if (len > 0)
+        {
+            last_activity = (uint32_t)osKernelGetTickCount();
+            
+            if (msg_type == WS_TEXT) {
+                printf("Chat text data received: %s\n", recv_buf);
+                chat_result_analysis(recv_buf);
+            } else if (msg_type == WS_BINARY) {
+                printf("Chat binary data received: %d bytes\n", len);
+            }
+        }
+        
+        msleep(10);
+    }
+
+chat_cleanup_and_exit:
+    printf("Chat WebSocket cleanup and exit\n");
+    
+    if (chat_client) {
+        close_websocket_client(chat_client);
+        chat_client = NULL;
+    }
+    
+    ws_queue_deinit(&chat_msg_queue);
+    is_bk_websocket_chat = 0;
+    set_ai_chat_service_init_flag(0);
+    
+    printf("Chat WebSocket thread ended\n");
+}
+
+/**
+ * @brief Chat服务器初始化
+ */
+errcode_t chat_server_init(void)
+{
+    app_task_definition_t chat_taskcfg;
+    
+    int osThreadGetState_t = osThreadGetState(chat_taskcfg.task_handle);
+    const char *buf = osThreadGetName(chat_taskcfg.task_handle);
+
+    printf("Chat osThreadGetState_t %d %s!\r\n", osThreadGetState_t, buf);
+    
+    if(strcmp("chat_server_init", buf) == 0)
+    {
+        if(osThreadGetState_t != osThreadReady && osThreadGetState_t != osThreadError && 
+           osThreadGetState_t != osThreadInactive)
+        {
+            printf("Chat osThreadGetState is %d!\r\n", osThreadGetState_t);
+            return ERRCODE_FAIL;
+        }
+    }
+
+    if(is_bk_websocket_chat || chat_client != NULL)
+    {
+        printf("Chat server is already connected!\r\n");
+        return ERRCODE_FAIL;
+    }
+    
+    printf("chat_server_init!\r\n");
+   
+    chat_taskcfg.create_queue_handle = NULL;
+    chat_taskcfg.attr.name = "chat_server_init";
+    chat_taskcfg.attr.priority = (osPriority_t)TASK_PRIORITY_APP;
+    chat_taskcfg.attr.stack_size = 0x1000;
+    chat_taskcfg.func = bk_websocket_demo;
+    chat_taskcfg.use_mem = USE_EXTEND_MEM;
+  
+    extern errcode_t uapi_create_osThread_custom(app_task_definition_t* task_cfg);
+    errcode_t ret = uapi_create_osThread_custom(&chat_taskcfg);
+
+    if(ret != ERRCODE_SUCC)
+    {
+        printf("create Chat service thread failed %d!\r\n", ret);
+        return ERRCODE_FAIL;
+    }
+    
+    return ERRCODE_SUCC;
+}
+
+/**
+ * @brief Chat服务器反初始化
+ */
+void chat_server_deinit(void)
+{
+    printf("chat_server_deinit\n");
+    
+    // 发送关闭消息
+    if (chat_client) {
+        if(send_websocket_message(chat_client, (uint8_t *)"WS_CLOSE", strlen("WS_CLOSE"), WS_CLOSE))
+        {
+            printf("Chat WS_CLOSE sent\n");
+        }
+    }
+    
+    if (chat_client) {
+        close_websocket_client(chat_client);
+        chat_client = NULL;
+    }
+    
+    is_bk_websocket_chat = 0;
+    set_ai_chat_service_init_flag(0);
+}
+
+#ifdef __cplusplus
+}
+#endif 
\ No newline at end of file
diff --git a/code/sdk/zhihui/ai_old/chat_websocket_server.h b/code/sdk/zhihui/ai_old/chat_websocket_server.h
new file mode 100644 (file)
index 0000000..9d50a0e
--- /dev/null
@@ -0,0 +1,102 @@
+/**
+ * @file chat_websocket_server.h
+ * @brief Chat WebSocket服务器头文件
+ * @version 1.0.0
+ * @date 2024-09-05
+ */
+
+#ifndef __CHAT_WEBSOCKET_SERVER_H__
+#define __CHAT_WEBSOCKET_SERVER_H__
+
+#include "bk_websocket.h"
+#include <stdint.h>
+#include <stdbool.h>
+#include "zhihui_ws.h"
+#include "errcode.h"
+#include "thread_init.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Chat 服务相关类型定义 */
+// errcode_t is defined in errcode.h
+
+/* AI类型枚举 - 使用zhihui_ws.h中的定义 */
+
+/* 任务配置结构体 - 使用系统定义的 app_task_definition_t */
+
+/* 常量定义 */
+#define TASK_PRIORITY_APP 24
+#define USE_EXTEND_MEM 1
+
+/* Chat 服务接口函数 */
+
+/**
+ * @brief Chat WebSocket数据包回调函数
+ * @param data 数据指针
+ * @param datalen 数据长度
+ * @param type WebSocket消息类型
+ */
+void chat_on_ws_packet_callback(uint8_t* data, size_t datalen, WebSocketMessageType type);
+
+/**
+ * @brief 获取Chat服务初始化标志
+ * @return 初始化标志
+ */
+uint8_t get_ai_chat_service_init_flag(void);
+
+/**
+ * @brief 设置Chat服务初始化标志
+ * @param flag 标志值
+ */
+void set_ai_chat_service_init_flag(uint8_t flag);
+
+/**
+ * @brief Chat结果分析
+ * @param buf 结果字符串
+ * @return 成功返回true,失败返回false
+ */
+bool chat_result_analysis(char *buf);
+
+/**
+ * @brief Chat URL初始化
+ * @param put_buf 输出缓冲区
+ * @param type AI类型
+ * @return 成功返回true,失败返回false
+ */
+bool chat_ws_url_init(char * put_buf, uint8_t type);
+
+/**
+ * @brief 发送聊天文本
+ * @param type 消息类型
+ * @param msg 消息内容
+ * @return 成功返回true,失败返回false
+ */
+bool ai_chat_send_txt(uint8_t type, char *msg);
+
+/**
+ * @brief Chat WebSocket主线程
+ * @param data 线程参数
+ */
+void bk_websocket_demo(void *data);
+
+/**
+ * @brief Chat服务器初始化
+ * @return 成功返回ERRCODE_SUCC,失败返回ERRCODE_FAIL
+ */
+errcode_t chat_server_init(void);
+
+/**
+ * @brief Chat服务器反初始化
+ */
+void chat_server_deinit(void);
+
+/* 全局变量声明 */
+extern WebSocketClient *chat_client;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CHAT_WEBSOCKET_SERVER_H__ */ 
\ No newline at end of file
diff --git a/code/sdk/zhihui/ai_old/tts_websocket_server.cpp b/code/sdk/zhihui/ai_old/tts_websocket_server.cpp
new file mode 100644 (file)
index 0000000..ee6afb3
--- /dev/null
@@ -0,0 +1,515 @@
+/**
+ * @file tts_websocket_server.cpp
+ * @brief TTS WebSocket服务器实现
+ * @version 1.0.0
+ * @date 2024-09-05
+ * 
+ * 从 zhihui_ai_server.cpp 中提取的 TTS 相关功能
+ */
+
+#include "tts_websocket_server.h"
+#include "zhihui_ws.h"
+#include "bk_websocket.h"
+#include "ws_queue_common.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include "wearable_log.h"
+#include "custom_runtime.h"
+#include "cmsis_os2.h"
+#include "osal_msgqueue.h"
+#include "thread_init.h"
+#include "soc_osal.h"
+#include "common_def.h"
+#include "los_printf.h"
+#include "../../../../../open_source/openharmony/third_party/cJSON/cJSON.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* TTS 相关全局变量 */
+WebSocketClient *tts_client = NULL;
+static ws_message_queue_t tts_msg_queue = {0};
+static uint8_t tts_break = 0;
+static uint8_t tts_reconnect = 0;
+static uint8_t is_bk_websocket_tts = 0;
+static uint8_t ai_tts_server_init_flag = 0;
+static uint8_t tts_is_ready = 0;
+static uint8_t tts_client_ping = 0;
+static uint32_t bk_websocket_tts_tick = 0;
+
+/* 外部函数声明 */
+extern bool read_dev_token(char *data_token);
+// extern void uapi_cat1_keep_wakeup(uint8_t state); // Commented out due to missing implementation
+extern void set_AIStreamend(uint8_t state);
+extern int send_msg_data_into_Ai_msg_queue(void *data, uint16_t len, uint16_t type);
+extern void msleep(uint32_t ms);
+extern int32_t VoiceCallVolteSample(int32_t argc, const char **argv);
+
+/* TTS 配置和常量 */
+#define AI_MAX_RETRY_COUNT 3
+#define AI_WS_HANDSHAKE_TIMEOUT_MS 10000
+#define AI_RECEIVE_TIMEOUT_MS 30000
+
+static char tts_task_id_buf[128] = {0};
+
+/**
+ * @brief TTS WebSocket数据包回调函数
+ */
+void tts_on_ws_packet_callback(uint8_t* data, size_t datalen, WebSocketMessageType type)
+{
+    if(tts_client != NULL && tts_client->msg_queue != NULL)
+    {
+        ws_queue_put(tts_client->msg_queue, data, datalen, type);
+    }
+}
+
+/**
+ * @brief 设置TTS中断标志
+ */
+void uapi_set_tts_break(uint8_t data)
+{
+    tts_break = data;
+}
+
+/**
+ * @brief 获取TTS中断标志
+ */
+uint8_t uapi_get_tts_break(void)
+{
+    return tts_break;
+}
+
+/**
+ * @brief 获取TTS服务初始化标志
+ */
+uint8_t get_ai_tts_server_init_flag(void)
+{
+    return ai_tts_server_init_flag;
+}
+
+/**
+ * @brief 设置TTS服务初始化标志
+ */
+void set_ai_tts_server_init_flag(uint8_t flag)
+{
+    ai_tts_server_init_flag = flag;
+}
+
+/**
+ * @brief 获取TTS时间戳
+ */
+uint32_t get_bk_websocket_tts_tick(void)
+{
+    return bk_websocket_tts_tick;
+}
+
+/**
+ * @brief TTS URL初始化
+ */
+bool tts_ws_url_init(char * put_buf)
+{
+    char token[64] = {0};
+    if(read_dev_token(token))
+    {
+        sprintf(put_buf, "ws://amp.raisound.com/tts/stream?dt=%s&platform=aliyun&noCache=1", token);
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+/**
+ * @brief TTS播放初始化
+ */
+int32_t uapi_tts_paly_init(void)
+{
+    printf("uapi_tts_paly_init\n");
+
+    int32_t ret = ERRCODE_FAIL;
+    int32_t argc = 1;
+    uint8_t *argv = (uint8_t *)"StartAIpaly";
+    {
+        ret = VoiceCallVolteSample(argc, (const char **)&argv);
+    }
+    
+    printf("TTS play init ret: %d\n", ret);
+    
+    return ret;   
+}
+
+/**
+ * @brief TTS播放停止
+ */
+int32_t uapi_tts_paly_stop(void)
+{
+    printf("uapi_tts_paly_stop\n");
+
+    int32_t ret = ERRCODE_FAIL;
+    int32_t argc = 1;
+    uint8_t *argv = (uint8_t *)"StopAIpaly";
+    {
+        ret = VoiceCallVolteSample(argc, (const char **)&argv);
+    }
+    
+    printf("TTS play stop ret: %d\n", ret);
+    
+    return ret;   
+}
+
+/**
+ * @brief 启动TTS服务
+ */
+bool uapi_start_tts(void)
+{
+    char *jsonString =
+        "{"
+        "\"type\":\"start\","
+        "\"task_id\":\"\","
+        "\"audio_config\":{"
+        "\"sample_rate\":16000,"
+        "\"format\":\"mp3\","
+        "\"channel\":1"
+        "},"
+        "\"request_config\":{"
+        "\"protocol\":1,"
+        "\"audio_buffer_size\":1024"
+        "}"
+        "}";
+    
+    if (tts_client == NULL) {
+        printf("TTS client is NULL\n");
+        return false;
+    }
+    
+    if (send_websocket_message(tts_client, (uint8_t *)jsonString, strlen(jsonString), WS_TEXT) == 0) {
+        tts_reconnect = 0;
+        printf("TTS start message sent successfully\n");
+        return true;
+    } else {
+        printf("TTS start message send failed\n");
+        return false;
+    }
+}
+
+/**
+ * @brief 启动单个TTS文本合成
+ */
+bool uapi_start_tts_single_txt(char *buf)
+{
+    if (!buf || strlen(buf) == 0) {
+        printf("TTS text buffer is empty\n");
+        return false;
+    }
+    
+    if (tts_client == NULL) {
+        printf("TTS client is NULL\n");
+        return false;
+    }
+    
+    // 构建TTS请求JSON
+    char *json_template = 
+        "{"
+        "\"type\":\"text\","
+        "\"task_id\":\"%s\","
+        "\"text\":\"%s\""
+        "}";
+    
+    char *jsonString = (char *)malloc(strlen(json_template) + strlen(buf) + strlen(tts_task_id_buf) + 100);
+    if (!jsonString) {
+        printf("Failed to allocate memory for TTS JSON\n");
+        return false;
+    }
+    
+    sprintf(jsonString, json_template, tts_task_id_buf, buf);
+    
+    bool result = false;
+    if (send_websocket_message(tts_client, (uint8_t *)jsonString, strlen(jsonString), WS_TEXT) == 0) {
+        printf("TTS text message sent successfully: %s\n", buf);
+        result = true;
+    } else {
+        printf("TTS text message send failed\n");
+    }
+    
+    free(jsonString);
+    return result;
+}
+
+/**
+ * @brief 停止TTS服务
+ */
+void uapi_stop_tts(void)
+{
+    tts_break = 1;
+    
+    if (tts_client) {
+        char *stop_json = "{\"type\":\"stop\",\"task_id\":\"\"}";
+        send_websocket_message(tts_client, (uint8_t *)stop_json, strlen(stop_json), WS_TEXT);
+    }
+    
+    uapi_tts_paly_stop();
+}
+
+/**
+ * @brief TTS WebSocket主线程
+ */
+void bk_websocket_tts(void *data) 
+{
+    // 声明所有变量在函数开始,避免goto跳转问题
+    uint32_t start_time = (uint32_t)osKernelGetTickCount();
+    uint32_t retry_count = 0;
+    WebSocketMessageType type;
+    bool state = true;
+    WebSocketMessageType msg_type;
+    uint32_t last_activity;
+    char *tts_recv_buf = NULL;
+
+    if (tts_msg_queue.initialized) {
+        ws_queue_deinit(&tts_msg_queue);
+    }
+    ws_queue_init(&tts_msg_queue, 0);
+
+TTS_START:
+    // uapi_cat1_keep_wakeup(1); // Commented out due to missing implementation
+    ws_queue_cleanup(&tts_msg_queue);
+    state = true;
+    
+    is_bk_websocket_tts = 1;
+    
+    uint8_t is_raisound_url = 0;
+
+    {
+        char url_buf[124] = {0};
+        if (tts_ws_url_init(url_buf)) {
+            printf("TTS URL: %s\n", url_buf);
+            is_raisound_url = 1;
+        } else {
+            is_raisound_url = 0;
+        }
+
+        uint8_t client_count = AI_MAX_RETRY_COUNT;
+
+        while (client_count > 0) {
+            uint32_t connect_start = (uint32_t)osKernelGetTickCount();
+            
+            // 根据测试服务器索引选择URL
+            extern uint8_t g_test_server_index;
+            if (g_test_server_index == 1) {
+                tts_client = init_websocket_client("ws://118.145.158.207:22080/tts/stream", NULL, 0);
+                if (tts_client != NULL) {
+                    tts_client->msg_queue = &tts_msg_queue;
+                    ws_set_packet_callback(tts_client, tts_on_ws_packet_callback);
+                }
+            } else if (g_test_server_index == 2) {
+                tts_client = init_websocket_client("ws://110.42.224.129:8910/tts/stream", NULL, 0);
+                if (tts_client != NULL) {
+                    tts_client->msg_queue = &tts_msg_queue;
+                    ws_set_packet_callback(tts_client, tts_on_ws_packet_callback);
+                }
+            } else if (is_raisound_url == 1) {
+                tts_client = init_websocket_client(url_buf, NULL, 1);
+                if (tts_client != NULL) {
+                    tts_client->msg_queue = &tts_msg_queue;
+                    ws_set_packet_callback(tts_client, tts_on_ws_packet_callback);
+                }
+            } else {
+                tts_client = init_websocket_client("ws://118.145.158.207:22080/tts/stream", NULL, 0);
+                if (tts_client != NULL) {
+                    tts_client->msg_queue = &tts_msg_queue;
+                    ws_set_packet_callback(tts_client, tts_on_ws_packet_callback);
+                }
+            }
+
+            if (tts_client == NULL) {
+                printf("TTS WebSocket client creation failed, retrying... (%d/%d)\n", 
+                       AI_MAX_RETRY_COUNT - client_count + 1, AI_MAX_RETRY_COUNT);
+                client_count--;
+                msleep(2000);
+                continue;
+            }
+
+            printf("TTS WebSocket client created successfully\n");
+            break;
+        }
+
+        if (tts_client == NULL) {
+            printf("TTS WebSocket: Failed to create client after %d retries\n", AI_MAX_RETRY_COUNT);
+            goto tts_cleanup_and_exit;
+        }
+
+        printf("TTS WebSocket: 连接建立成功,开始握手等待\n");
+        
+        // 等待握手完成
+        uint32_t tts_handshake_start_time = (uint32_t)osKernelGetTickCount();
+        const uint32_t tts_handshake_timeout_ms = AI_WS_HANDSHAKE_TIMEOUT_MS;
+        
+        while (tts_client->handshake == 0) {
+            if ((uint32_t)osKernelGetTickCount() - tts_handshake_start_time > tts_handshake_timeout_ms) {
+                printf("TTS WebSocket握手超时 (%d ms),重新连接\n", tts_handshake_timeout_ms);
+                close_websocket_client(tts_client);
+                tts_client = NULL;
+                goto tts_cleanup_and_exit;
+            }
+            
+            msleep(1000);
+            printf("等待TTS WebSocket握手完成... (%d ms)\n", 
+                   (uint32_t)osKernelGetTickCount() - tts_handshake_start_time);
+        }
+        
+        printf("TTS WebSocket握手完成,耗时 %d ms\n", 
+               (uint32_t)osKernelGetTickCount() - tts_handshake_start_time);
+    }
+
+    // uapi_cat1_keep_wakeup(1); // Commented out due to missing implementation
+    set_ai_tts_server_init_flag(1);
+    
+    printf("TTS client initialized successfully\n");
+    
+    // 分配接收缓冲区
+    tts_recv_buf = (char *)malloc(1024 * 4);
+    last_activity = (uint32_t)osKernelGetTickCount();
+    
+    if (!tts_recv_buf) {
+        printf("Failed to allocate TTS receive buffer\n");
+        goto tts_cleanup_and_exit;
+    }
+
+    while (tts_break == 0) {
+        // 检查超时
+        if ((uint32_t)osKernelGetTickCount() - last_activity > AI_RECEIVE_TIMEOUT_MS) {
+            printf("TTS receive timeout, reconnecting...\n");
+            break;
+        }
+
+        memset(tts_recv_buf, 0, 1024 * 4);
+        extern int receive_websocket_message_from_queue(ws_message_queue_t* queue, uint8_t* buffer, 
+                                                       uint16_t buffer_size, WebSocketMessageType* type, uint32_t timeout_ms);
+        int len = receive_websocket_message_from_queue(&tts_msg_queue, (unsigned char *)tts_recv_buf, 
+                                                      1024 * 4, &msg_type, AI_RECEIVE_TIMEOUT_MS);
+
+        if (len == -1 || msg_type == WS_CLOSE) {
+            printf("TTS WebSocket connection closed\n");
+            break;
+        }
+
+        if (len > 0) {
+            last_activity = (uint32_t)osKernelGetTickCount();
+            
+            if (msg_type == WS_BINARY) {
+                if (bk_websocket_tts_tick == 0) {
+                    set_AIStreamend(0);
+                    bk_websocket_tts_tick = (uint32_t)osKernelGetTickCount();
+                }
+                send_msg_data_into_Ai_msg_queue((uint8_t *)tts_recv_buf, len, 200);
+                printf("TTS binary data received: %d bytes\n", len);
+                msleep(1);
+            } else if (msg_type == WS_TEXT) {
+                printf("TTS text data received: %s\n", tts_recv_buf);
+            }
+        }
+
+        msleep(10);
+    }
+
+tts_cleanup_and_exit:
+    printf("TTS WebSocket cleanup and exit\n");
+    
+    if (tts_recv_buf) {
+        free(tts_recv_buf);
+    }
+    
+    if (tts_client) {
+        close_websocket_client(tts_client);
+        tts_client = NULL;
+    }
+    
+    ws_queue_deinit(&tts_msg_queue);
+    is_bk_websocket_tts = 0;
+    set_ai_tts_server_init_flag(0);
+    bk_websocket_tts_tick = 0;
+    
+    printf("TTS WebSocket thread ended\n");
+}
+
+/**
+ * @brief TTS服务器初始化
+ */
+errcode_t tts_server_init(void)
+{
+    app_task_definition_t tts_taskcfg;
+    
+    osThreadState_t osThreadGetState_t = osThreadGetState(tts_taskcfg.task_handle);
+    const char *buf = osThreadGetName(tts_taskcfg.task_handle);
+
+    printf("TTS osThreadGetState_t %d!\r\n", osThreadGetState_t);
+    
+    if(strcmp("tts_server_init", buf) == 0)
+    {
+        if(osThreadGetState_t != osThreadReady && osThreadGetState_t != osThreadError && 
+           osThreadGetState_t != osThreadInactive)
+        {
+            printf("TTS osThreadGetState is %d!\r\n", osThreadGetState_t);
+            return ERRCODE_FAIL;
+        }
+    }
+
+    if(tts_client != NULL || is_bk_websocket_tts)
+    {
+        printf("TTS server is already connected!\r\n");
+        return ERRCODE_FAIL;
+    }
+    
+    printf("tts_server_init!\r\n");
+   
+    tts_taskcfg.create_queue_handle = NULL;
+    tts_taskcfg.attr.name = "tts_server_init";
+    tts_taskcfg.attr.priority = (osPriority_t)TASK_PRIORITY_APP;
+    tts_taskcfg.attr.stack_size = 0x2000;
+    tts_taskcfg.func = bk_websocket_tts;
+    tts_taskcfg.use_mem = USE_EXTEND_MEM;
+  
+    extern errcode_t uapi_create_osThread_custom(app_task_definition_t* task_cfg);
+    errcode_t ret = uapi_create_osThread_custom(&tts_taskcfg);
+
+    if(ret != ERRCODE_SUCC)
+    {
+        printf("create TTS service thread failed %d!\r\n", ret);
+        return ERRCODE_FAIL;
+    }
+    
+    return ERRCODE_SUCC;
+}
+
+/**
+ * @brief TTS服务器反初始化
+ */
+void tts_server_deinit(void)
+{
+    printf("tts_server_deinit\n");
+    
+    // 发送关闭消息
+    if (tts_client) {
+        if(send_websocket_message(tts_client, (uint8_t *)"WS_CLOSE", strlen("WS_CLOSE"), WS_CLOSE))
+        {
+            printf("TTS WS_CLOSE sent\n");
+        }
+    }
+    
+    tts_break = 1;
+    
+    if (tts_client) {
+        close_websocket_client(tts_client);
+        tts_client = NULL;
+    }
+    
+    is_bk_websocket_tts = 0;
+    set_ai_tts_server_init_flag(0);
+}
+
+#ifdef __cplusplus
+}
+#endif 
\ No newline at end of file
diff --git a/code/sdk/zhihui/ai_old/tts_websocket_server.h b/code/sdk/zhihui/ai_old/tts_websocket_server.h
new file mode 100644 (file)
index 0000000..b08e766
--- /dev/null
@@ -0,0 +1,130 @@
+/**
+ * @file tts_websocket_server.h
+ * @brief TTS WebSocket服务器头文件
+ * @version 1.0.0
+ * @date 2024-09-05
+ */
+
+#ifndef __TTS_WEBSOCKET_SERVER_H__
+#define __TTS_WEBSOCKET_SERVER_H__
+
+#include "bk_websocket.h"
+#include <stdint.h>
+#include <stdbool.h>
+#include "errcode.h"
+#include "thread_init.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* TTS 服务相关类型定义 - errcode_t is defined in errcode.h */
+
+/* 任务配置结构体 - 使用系统定义的 app_task_definition_t */
+
+/* 常量定义 */
+#define TASK_PRIORITY_APP 24
+#define USE_EXTEND_MEM 1
+
+/* TTS 服务接口函数 */
+
+/**
+ * @brief TTS WebSocket数据包回调函数
+ * @param data 数据指针
+ * @param datalen 数据长度
+ * @param type WebSocket消息类型
+ */
+void tts_on_ws_packet_callback(uint8_t* data, size_t datalen, WebSocketMessageType type);
+
+/**
+ * @brief 设置TTS中断标志
+ * @param data 标志值
+ */
+void uapi_set_tts_break(uint8_t data);
+
+/**
+ * @brief 获取TTS中断标志
+ * @return 中断标志
+ */
+uint8_t uapi_get_tts_break(void);
+
+/**
+ * @brief 获取TTS服务初始化标志
+ * @return 初始化标志
+ */
+uint8_t get_ai_tts_server_init_flag(void);
+
+/**
+ * @brief 设置TTS服务初始化标志
+ * @param flag 标志值
+ */
+void set_ai_tts_server_init_flag(uint8_t flag);
+
+/**
+ * @brief 获取TTS时间戳
+ * @return 时间戳
+ */
+uint32_t get_bk_websocket_tts_tick(void);
+
+/**
+ * @brief TTS URL初始化
+ * @param put_buf 输出缓冲区
+ * @return 成功返回true,失败返回false
+ */
+bool tts_ws_url_init(char * put_buf);
+
+/**
+ * @brief TTS播放初始化
+ * @return 成功返回ERRCODE_SUCC,失败返回ERRCODE_FAIL
+ */
+int32_t uapi_tts_paly_init(void);
+
+/**
+ * @brief TTS播放停止
+ * @return 成功返回ERRCODE_SUCC,失败返回ERRCODE_FAIL
+ */
+int32_t uapi_tts_paly_stop(void);
+
+/**
+ * @brief 启动TTS服务
+ * @return 成功返回true,失败返回false
+ */
+bool uapi_start_tts(void);
+
+/**
+ * @brief 启动单个TTS文本合成
+ * @param buf 文本内容
+ * @return 成功返回true,失败返回false
+ */
+bool uapi_start_tts_single_txt(char *buf);
+
+/**
+ * @brief 停止TTS服务
+ */
+void uapi_stop_tts(void);
+
+/**
+ * @brief TTS WebSocket主线程
+ * @param data 线程参数
+ */
+void bk_websocket_tts(void *data);
+
+/**
+ * @brief TTS服务器初始化
+ * @return 成功返回ERRCODE_SUCC,失败返回ERRCODE_FAIL
+ */
+errcode_t tts_server_init(void);
+
+/**
+ * @brief TTS服务器反初始化
+ */
+void tts_server_deinit(void);
+
+/* 全局变量声明 */
+extern WebSocketClient *tts_client;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TTS_WEBSOCKET_SERVER_H__ */ 
\ No newline at end of file
diff --git a/code/sdk/zhihui/ai_old/voicechat_websocket_server.cpp b/code/sdk/zhihui/ai_old/voicechat_websocket_server.cpp
new file mode 100644 (file)
index 0000000..32127f7
--- /dev/null
@@ -0,0 +1,511 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "lwip/sockets.h"
+#include "lwip/sys.h"
+#include <lwip/netdb.h>
+#include "lwip/inet.h"
+
+#include "../../../../../open_source/openharmony/third_party/cJSON/cJSON.h"
+#include "wearable_log.h"
+#include "custom_runtime.h"
+#include "cmsis_os2.h"
+#include "bk_websocket.h"
+#include "voicechat_websocket_server.h"
+#include "ws_queue_common.h"
+#include "osal_msgqueue.h"
+#include "thread_init.h"
+#include "soc_osal.h"
+#include "common_def.h"
+#include "los_printf.h"
+
+// 内存管理和错误处理优化
+#define AI_SAFE_MALLOC(size) ({ \
+    void* ptr = malloc(size); \
+    if (!ptr) { \
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Memory allocation failed: %s:%d", __FILE__, __LINE__); \
+    } \
+    ptr; \
+})
+
+#define AI_SAFE_FREE(ptr) do { \
+    if (ptr) { \
+        free(ptr); \
+        ptr = NULL; \
+    } \
+} while(0)
+
+// 超时和重试配置
+#define AI_CONNECT_TIMEOUT_MS    30000  // 30秒连接超时
+#define AI_RECEIVE_TIMEOUT_MS    10000  // 10秒接收超时
+#define AI_MAX_RETRY_COUNT       3      // 最大重试次数
+
+// 外部变量声明
+extern uint32_t disconnect_server;
+extern uint32_t bk_websocket_tts_tick;
+extern osMutexId_t g_ai_mutex;
+static uint32_t g_ai_memory_usage = 0;
+static uint32_t g_ai_max_memory = 1024 * 1024; // 1MB内存限制
+
+// 外部函数声明
+extern bool ai_is_json_string(const char *str, size_t len);
+extern WebSocketClient* init_websocket_client(const char* url, const char* protocol, uint8_t is_ssl);
+extern int send_websocket_message(WebSocketClient* client, const uint8_t* data, size_t length, WebSocketMessageType type);
+extern void close_websocket_client(WebSocketClient* client);
+
+// 内存使用监控
+static inline bool ai_check_memory_limit(uint32_t size) {
+    if (g_ai_memory_usage + size > g_ai_max_memory) {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Memory limit exceeded: %u + %u > %u", 
+                      g_ai_memory_usage, size, g_ai_max_memory);
+        return false;
+    }
+    return true;
+}
+
+static inline void ai_update_memory_usage(int32_t delta) {
+    if (delta > 0) {
+        g_ai_memory_usage += delta;
+    } else {
+        g_ai_memory_usage = (g_ai_memory_usage > (uint32_t)(-delta)) ? 
+                           g_ai_memory_usage + delta : 0;
+    }
+}
+// 线程安全保护
+#define AI_LOCK() do { \
+    if (g_ai_mutex) { \
+        osMutexAcquire(g_ai_mutex, osWaitForever); \
+    } \
+} while(0)
+
+#define AI_UNLOCK() do { \
+    if (g_ai_mutex) { \
+        osMutexRelease(g_ai_mutex); \
+    } \
+} while(0)
+
+// VoiceChat server global variables
+WebSocketClient *voice_chat_client = NULL;
+uint8_t is_bk_websocket_voice_chat = 0;
+char dialog_id_str_buf[128] = {0};
+uint8_t ai_voice_chat_state = 0;
+
+
+/**
+ * @brief 处理WebSocket连接失败的统一函数
+ * @param client_type 客户端类型字符串
+ * @param retry_count 当前重试次数
+ * @param max_retries 最大重试次数
+ * @return true 如果应该继续重试,false 如果应该停止重试
+ */
+static bool handle_websocket_connection_failure(const char* client_type, uint8_t retry_count, uint8_t max_retries) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "%s WebSocket connection failed, retries left: %d", client_type, max_retries - retry_count);
+    
+    if (retry_count >= max_retries) {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "%s WebSocket connection failed after %d retries, giving up", client_type, max_retries);
+        return false; // 停止重试
+    }
+    
+    // 等待一段时间后重试
+    msleep(1000);
+    return true; // 继续重试
+}
+
+// VoiceChat server global variables access functions
+WebSocketClient* get_voice_chat_client(void) {
+    return voice_chat_client;
+}
+
+uint8_t get_is_bk_websocket_voice_chat(void) {
+    return is_bk_websocket_voice_chat;
+}
+
+void set_is_bk_websocket_voice_chat(uint8_t flag) {
+    is_bk_websocket_voice_chat = flag;
+}
+
+char* get_dialog_id_str_buf(void) {
+    return dialog_id_str_buf;
+}
+
+uint8_t get_ai_voice_chat_state(void) {
+    return ai_voice_chat_state;
+}
+
+void set_ai_voice_chat_state(uint8_t state) {
+    ai_voice_chat_state = state;
+}
+
+// VoiceChat server functions
+void ai_asr_send_bin(uint8_t *buf, uint32_t len)
+{
+    WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"ai_asr_send_bin %d\n",len);
+    // voice_chat_client
+    
+    // if (send_websocket_message(asr_client,( uint8_t  *)buf,len,WS_BINARY)==0)
+    extern WebSocketClient *asr_client;
+    if (send_websocket_message(asr_client,( uint8_t  *)buf,len,WS_BINARY)==0)
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"send_websocket_message succ 0\n");
+        msleep(100);
+    }
+    else
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"send_websocket_message fail 0\n");
+    }
+}
+
+bool start_ai_voice_chat()
+{
+    unsigned char deviceId[20] = {0};
+    memset(deviceId, 0, 6); 
+
+    bluetooth_get_local_addr(&deviceId[0], 6);
+
+    char deviceId_temp[20] = {0};
+    sprintf(deviceId_temp, "%02X%02x%02X%02x%02X%02x", deviceId[5], deviceId[4], deviceId[3], deviceId[2], deviceId[1], deviceId[0]);
+
+    time_t timestamp;
+    timestamp = time(NULL);
+    long long timestamp_ms = (long long)timestamp;
+
+    char* timestamp_str_2 = (char *)AI_SAFE_MALLOC(20);
+    if (!timestamp_str_2) {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to allocate timestamp buffer");
+        return false;
+    }
+    ai_update_memory_usage(20);
+    
+    memset(timestamp_str_2, 0, 20);
+    sprintf(timestamp_str_2, "%lld", timestamp_ms);
+
+    char md5_buf[33] = {0};
+    active_md5_buf((char *)timestamp_str_2, md5_buf);
+    WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "MD5 buffer: %s", md5_buf);
+
+    // 释放timestamp_str_2内存
+    AI_SAFE_FREE(timestamp_str_2);
+    ai_update_memory_usage(-20);
+
+    char jsonString[800] = {0}; 
+    sprintf(jsonString, "{ \
+        \"header\": { \
+            \"trace_id\": \"%s\", \
+            \"event\":\"Start\" \
+        }, \
+        \"payload\": { \
+            \"device_id\": \"%s\", \
+            \"user_agent\": \"python\", \
+            \"dialog_id\":\"\", \
+            \"in_format\": \"pcm\", \
+            \"out_format\": \"mp3\",  \
+            \"in_sample_rate\": 16000, \
+            \"volume\": \"10\", \
+            \"sample_rate\": 16000, \
+            \"voice\": \"zh_female_shuangkuaisisi_moon_bigtts\", \
+            \"voice_detection\": \"disable\" \
+        } \
+        } ", md5_buf, deviceId_temp);
+    
+    if (send_websocket_message(voice_chat_client, (uint8_t *)jsonString, strlen(jsonString), WS_TEXT) == 0) {
+        WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "Voice chat start message sent successfully: %s", jsonString);
+        return true;
+    } else {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to send voice chat start message");
+        return false;
+    }
+}
+
+void start_send_voice(void)
+{
+    char *jsonString = (char *)malloc(150);// [512] ={0};
+    memset(jsonString,0,150);
+ 
+    sprintf(jsonString,
+     "{\"header\":{\"trace_id\":\"ailaqbo0r6o\",\"event\":\"SendSpeech\"},\
+    \"payload\":{\"dialog_id\":\"%s\"}}"
+     
+     ,dialog_id_str_buf);
+
+     printf("start_send_voice : %s\r\n",jsonString);
+
+    if (send_websocket_message(voice_chat_client,( uint8_t *)jsonString,strlen(jsonString),WS_TEXT)==0)
+    {
+        startAudioCaptureTask();
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"send_websocket_message succ 0\n");
+
+    }
+
+    free(jsonString); 
+}
+
+void back_voice_RequestToSpeak(void)
+{
+    char *jsonString = (char *)malloc(150);// [512] ={0};
+ 
+    sprintf(jsonString,
+
+     "{\"header\":{\"trace_id\":\"ailaqbo0r6o\",\"event\":\"RequestToSpeak\"},\
+    \"payload\":{\"dialog_id\":\"%s\"}}"
+     
+     ,dialog_id_str_buf);
+
+     printf("uapi_start_tts : %s\r\n",jsonString);
+
+    if (send_websocket_message(voice_chat_client,( uint8_t *)jsonString,strlen(jsonString),WS_TEXT)==0)
+    WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,"send_websocket_message succ 0\n");
+    free(jsonString); 
+}
+
+bool voice_chat_analysis(char *buf)
+{
+    cJSON* root = cJSON_Parse((const char *)buf);
+    if (root == NULL) {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"解析失败\n");
+        return false;
+    }
+    char *event_str=NULL;
+    char *dialog_id_str=NULL;
+    char *state_str=NULL;
+    char *text_str=NULL;
+
+    cJSON* event = cJSON_GetObjectItem(root, "event");
+    if (event && cJSON_IsString(event)) {
+         event_str= event->valuestring;
+    }
+    
+
+     cJSON* payload = cJSON_GetObjectItem(root, "payload");
+     if(payload)
+     {
+         cJSON* dialog_id = cJSON_GetObjectItem(payload, "dialog_id");
+        if (dialog_id && cJSON_IsString(dialog_id)) {
+            dialog_id_str= dialog_id->valuestring;
+            memset(dialog_id_str_buf,0,128);
+            memcpy(dialog_id_str_buf,dialog_id_str,strlen(dialog_id_str));
+        }
+
+        cJSON* state = cJSON_GetObjectItem(payload, "state");
+        if (state && cJSON_IsString(state)) {
+            state_str= dialog_id->valuestring;
+
+            if(strcmp("Responding",state_str)==0)
+            {   
+                ai_voice_chat_state=Responding;
+            }
+            else if (strcmp("Listening",state_str)==0)
+            {
+                ai_voice_chat_state=Listening;
+            }
+            else if (strcmp("Thinking",state_str)==0)
+            {
+                ai_voice_chat_state=Thinking;
+            }
+        }
+
+        cJSON* text = cJSON_GetObjectItem(payload, "text");
+
+        if (text && cJSON_IsString(state)) {
+            state_str= dialog_id->valuestring;
+        }
+
+     }
+
+    if(strcmp("Started",event_str)==0)
+    {   
+        
+    }
+
+    if(strcmp("SpeechEnded",event_str)==0)
+    {   
+        stop_AudioCaptureProcess_AI();
+    }
+    
+
+    cJSON_Delete(root);
+    return true;
+}
+
+void voice_chat_websocket(void *data) {
+    uint32_t start_time = (uint32_t)osKernelGetTickCount();
+    uint32_t retry_count = 0;
+    
+    uapi_cat1_keep_wakeup(1);
+
+    WebSocketMessageType type;
+    bool state = true;
+    
+    AI_LOCK();
+    is_bk_websocket_voice_chat = 1;
+    AI_UNLOCK();
+    
+    uint8_t is_raisound_url = 0;
+
+    {
+        char url_buf[124] = {0};
+        
+        uint8_t client_count = AI_MAX_RETRY_COUNT;
+        
+        // 检查内存使用情况
+        if (!ai_check_memory_limit(1024 * 4)) {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Memory limit exceeded for voice chat buffer");
+            goto voice_chat_cleanup_and_exit;
+        }
+
+        while (client_count > 0) {
+            uint32_t connect_start = (uint32_t)osKernelGetTickCount();
+            
+            if (is_raisound_url == 1) {
+                voice_chat_client = init_websocket_client(url_buf, NULL, 1);
+                if (voice_chat_client != NULL) {
+                    // voice_chat_client->msg_queue = &voice_msg_queue;
+                }
+            } else {
+                voice_chat_client = init_websocket_client("ws://118.145.158.207:22080/voice-chat/v2/ws?platform=huoshan", NULL, 0);
+                if (voice_chat_client != NULL) {
+                    // voice_chat_client->msg_queue = &voice_msg_queue;
+                }
+            }
+
+            if (voice_chat_client == NULL) {
+                client_count--;
+                
+                // 使用统一的错误处理函数
+                if (!handle_websocket_connection_failure("Voice chat", AI_MAX_RETRY_COUNT - client_count, AI_MAX_RETRY_COUNT)) {
+                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Voice chat WebSocket connection failed after all retries");
+                    break;
+                }
+                
+                // 检查超时
+                if ((uint32_t)osKernelGetTickCount() - connect_start > AI_CONNECT_TIMEOUT_MS) {
+                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Voice chat connection timeout");
+                    break;
+                }
+                
+                continue;
+            } else {
+                WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "Voice chat WebSocket connection established");
+                break;
+            }
+        }
+        
+        if (voice_chat_client == NULL) {
+            goto voice_chat_cleanup_and_exit;
+        }
+        
+        // 安全分配voice chat接收缓冲区
+        char* voice_chat_client_buf = (char *)AI_SAFE_MALLOC(1024 * 4);
+        if (!voice_chat_client_buf) {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to allocate voice chat receive buffer");
+            goto voice_chat_cleanup_and_exit;
+        }
+        ai_update_memory_usage(1024 * 4);
+
+        // 设置socket超时
+        // struct timeval timeout;
+        // timeout.tv_sec = AI_RECEIVE_TIMEOUT_MS / 1000;
+        // timeout.tv_usec = (AI_RECEIVE_TIMEOUT_MS % 1000) * 1000;
+        // lwip_setsockopt(voice_chat_client->sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+
+        if (!start_ai_voice_chat()) {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to start AI voice chat");
+            AI_SAFE_FREE(voice_chat_client_buf);
+            ai_update_memory_usage(-1024 * 4);
+            goto voice_chat_cleanup_and_exit;
+        }
+
+        uint32_t last_activity = (uint32_t)osKernelGetTickCount();
+        
+        while (disconnect_server == 0) {
+            // 检查超时
+            if ((uint32_t)osKernelGetTickCount() - last_activity > AI_RECEIVE_TIMEOUT_MS) {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Voice chat receive timeout, reconnecting...");
+                break;
+            }
+            
+            memset_s(voice_chat_client_buf, 1024 * 4, 0, 1024 * 4);
+            int len = -1;
+            // len = receive_websocket_message_from_queue(&voice_msg_queue, (unsigned char *)voice_chat_client_buf, 1024 * 4, &type, AI_RECEIVE_TIMEOUT_MS);
+            
+            if (type == WS_CLOSE || len == -1) {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Voice chat WebSocket connection closed");
+                break;
+            }
+            
+            if (len > 0) {
+                last_activity = (uint32_t)osKernelGetTickCount();
+                
+                if (type == WS_BINARY) {
+                    if (bk_websocket_tts_tick == 0) {
+                        set_AIStreamend(0);
+                        bk_websocket_tts_tick = (uint32_t)osKernelGetTickCount();
+                    }
+                    if(ai_is_json_string(voice_chat_client_buf, len))
+                    {
+                        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Voice chat bin received: buffer %s\n",voice_chat_client_buf);
+                    }
+                    send_msg_data_into_Ai_msg_queue((uint8_t *)voice_chat_client_buf, len, 200);
+                    WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "Voice chat binary data received: %d bytes", len);
+                    msleep(1);
+                } else if (type == WS_TEXT) {
+                    WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "Voice chat text data received: %s", voice_chat_client_buf);
+                    voice_chat_analysis(voice_chat_client_buf);
+                }
+            }
+            
+            // 定期检查资源状态
+            if (retry_count++ % 100 == 0) {
+                ai_update_memory_usage(0);
+            }
+            
+            msleep(1); // 避免过度占用CPU
+        }
+
+        bk_websocket_tts_tick = 0;
+        close_websocket_client(voice_chat_client);
+        voice_chat_client = NULL;
+
+        // 释放voice_chat_client_buf内存
+        AI_SAFE_FREE(voice_chat_client_buf);
+        ai_update_memory_usage(-1024 * 4);
+    }
+    
+voice_chat_cleanup_and_exit:
+    AI_LOCK();
+    is_bk_websocket_voice_chat = 0;
+    AI_UNLOCK();
+    
+    WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "Voice chat WebSocket ended");
+    return;
+}
+
+errcode_t voice_chat_server_init(void)
+{
+    extern WebSocketClient *tts_client;
+    extern uint8_t is_bk_websocket_tts;
+    
+    if(tts_client!=NULL || is_bk_websocket_tts)
+    {
+        return ERRCODE_FAIL;
+    }
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"voice_chat_server_init !\r\n");
+    app_task_definition_t taskcfg={0};
+    taskcfg.create_queue_handle = NULL;
+    taskcfg.attr.name="voice_chat_server_init";
+    taskcfg.attr.priority = TASK_PRIORITY_APP;
+    taskcfg.attr.stack_size = 0x2000;
+    taskcfg.func = voice_chat_websocket;
+    taskcfg.use_mem = USE_EXTEND_MEM;
+  
+    errcode_t ret=uapi_create_osThread_custom(&taskcfg);
+
+    if(ret != ERRCODE_SUCC)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"create voice_chat_service_file failed %d!\r\n",ret);
+        return ERRCODE_FAIL;
+    }
+    return ERRCODE_SUCC;
+} 
\ No newline at end of file
diff --git a/code/sdk/zhihui/ai_old/voicechat_websocket_server.h b/code/sdk/zhihui/ai_old/voicechat_websocket_server.h
new file mode 100644 (file)
index 0000000..1b2e5af
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef VOICECHAT_WEBSOCKET_SERVER_H
+#define VOICECHAT_WEBSOCKET_SERVER_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "bk_websocket.h"
+#include "common_def.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// VoiceChat server state enum
+typedef enum
+{
+    AI_STATE_0=0,
+    Listening,
+    Responding,
+    Thinking,
+} AI_VOICE_STATE;
+
+// External function declarations
+extern void bluetooth_get_local_addr(unsigned char *addr, int len);
+extern int active_md5_buf(char *input, char *output);
+extern void uapi_cat1_keep_wakeup(uint8_t state);
+extern void set_AIStreamend(uint8_t state);
+extern void startAudioCaptureTask(void);
+extern void stop_AudioCaptureProcess_AI(void);
+extern int send_msg_data_into_Ai_msg_queue(void *data, uint16_t len, uint8_t type);
+extern errcode_t uapi_create_osThread_custom(app_task_definition_t *task_cfg);
+
+// VoiceChat server global variables access functions
+extern WebSocketClient* get_voice_chat_client(void);
+extern uint8_t get_is_bk_websocket_voice_chat(void);
+extern void set_is_bk_websocket_voice_chat(uint8_t flag);
+extern char* get_dialog_id_str_buf(void);
+extern uint8_t get_ai_voice_chat_state(void);
+extern void set_ai_voice_chat_state(uint8_t state);
+
+// VoiceChat server functions
+extern void ai_asr_send_bin(uint8_t *buf, uint32_t len);
+extern bool start_ai_voice_chat(void);
+extern void start_send_voice(void);
+extern void back_voice_RequestToSpeak(void);
+extern bool voice_chat_analysis(char *buf);
+extern void voice_chat_websocket(void *data);
+extern errcode_t voice_chat_server_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // VOICECHAT_WEBSOCKET_SERVER_H 
\ No newline at end of file
diff --git a/code/sdk/zhihui/ai_old/ws_queue_common.h b/code/sdk/zhihui/ai_old/ws_queue_common.h
new file mode 100644 (file)
index 0000000..5e6712c
--- /dev/null
@@ -0,0 +1,170 @@
+#ifndef WS_QUEUE_COMMON_H
+#define WS_QUEUE_COMMON_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include "bk_websocket.h"
+#include "osal_msgqueue.h"
+#include "cmsis_os2.h"
+#include "wearable_log.h"
+#include "soc_osal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* WebSocket消息队列管理函数 */
+
+/**
+ * @brief 初始化WebSocket消息队列
+ */
+static inline int ws_queue_init(ws_message_queue_t* queue, uint32_t queue_size)
+{
+    if (!queue) return -1;
+    
+    memset(queue, 0, sizeof(ws_message_queue_t));
+    
+    /* 创建osal消息队列 */
+    uint32_t true_queue_size;
+    if(queue_size != 0)
+        true_queue_size = queue_size;
+    else
+        true_queue_size = WS_QUEUE_SIZE;
+
+    int ret = osal_msg_queue_create("ws_queue", true_queue_size, &queue->queue_id, 0, sizeof(ws_message_item_t));
+    if (ret != OSAL_SUCCESS) {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to create osal message queue for ws queue");
+        return -1;
+    }
+    
+    queue->initialized = true;
+    WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WebSocket queue initialized successfully");
+    return 0;
+}
+
+/**
+ * @brief 反初始化WebSocket消息队列
+ */
+static inline void ws_queue_deinit(ws_message_queue_t* queue)
+{
+    if (!queue || !queue->initialized) return;
+    queue->initialized = false;
+
+    if (queue->queue_id != 0) {
+        osal_msg_queue_delete(queue->queue_id);
+        queue->queue_id = 0;
+    }
+    
+    memset(queue, 0, sizeof(ws_message_queue_t));
+    WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WebSocket queue deinitialized");
+}
+
+/**
+ * @brief 向队列中添加消息
+ */
+static inline int ws_queue_put(ws_message_queue_t* queue, const uint8_t* data, uint16_t length, WebSocketMessageType type)
+{
+    if (!queue || !queue->initialized || !data || length == 0 || length > WS_MESSAGE_MAX_SIZE) {
+        return -1;
+    }
+    
+    /* 创建消息项 */
+    ws_message_item_t item;
+    item.data = (uint8_t*)malloc(length);
+    if (item.data == NULL) {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to malloc message data");
+        return -1;
+    }
+    
+    memcpy(item.data, data, length);
+    item.length = length;
+    item.type = type;
+    item.timestamp = osKernelGetTickCount();
+    item.in_use = true;
+    
+    /* 将消息写入osal消息队列 */
+    int ret = osal_msg_queue_write_copy(queue->queue_id, &item, sizeof(ws_message_item_t), 0);
+    if (ret != OSAL_SUCCESS) {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to write message to osal queue");
+        free(item.data);
+        return -1;
+    }
+    
+    return 0;
+}
+
+/**
+ * @brief 从队列中获取消息
+ */
+static inline int ws_queue_get(ws_message_queue_t* queue, uint8_t* data, uint16_t max_length, WebSocketMessageType* type, uint32_t timeout_ms)
+{
+    if (!queue || !queue->initialized || !data || !type) {
+        return -1;
+    }
+    
+    /* 从osal消息队列读取消息 */
+    ws_message_item_t item;
+    unsigned int buffer_size = sizeof(ws_message_item_t);
+    int ret = osal_msg_queue_read_copy(queue->queue_id, &item, &buffer_size, timeout_ms);
+    if (ret != OSAL_SUCCESS) {
+        return 0; /* 超时或错误 */
+    }
+    
+    /* 检查消息是否有效 */
+    if (!item.in_use || item.data == NULL) {
+        return 0;
+    }
+    
+    /* 复制数据 */
+    uint16_t copy_len = (item.length > max_length) ? max_length : item.length;
+    memcpy(data, item.data, copy_len);
+    *type = item.type;
+    
+    /* 释放消息数据 */
+    free(item.data);
+    
+    return copy_len;
+}
+
+static inline int ws_queue_cleanup(ws_message_queue_t* queue) {
+    if (!queue) {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ws_queue_cleanup: queue is NULL");
+        return -1;
+    }
+    
+    WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "开始清理WebSocket消息队列...");
+    
+    // 清空osal消息队列中的所有消息
+    ws_message_item_t item;
+    unsigned int buffer_size = sizeof(ws_message_item_t);
+    while (osal_msg_queue_read_copy(queue->queue_id, &item, &buffer_size, 0) == OSAL_SUCCESS) {
+        if (item.data != NULL) {
+            free(item.data);
+            WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "清理队列消息: type=%d, length=%d", item.type, item.length);
+        }
+    }
+    
+    WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "WebSocket消息队列清理完成");
+    return 0;
+}
+
+/**
+ * @brief 从队列中接收WebSocket消息(替代原来的receive_websocket_message)
+ */
+static inline int receive_websocket_message_from_queue(ws_message_queue_t* queue, uint8_t* buffer, uint16_t buffer_size, WebSocketMessageType* type, uint32_t timeout_ms)
+{
+    if (!queue || !buffer || !type) {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "!queue || !buffer || !type");
+        return -1;
+    }
+    
+    return ws_queue_get(queue, buffer, buffer_size, type, timeout_ms);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // WS_QUEUE_COMMON_H 
\ No newline at end of file
diff --git a/code/sdk/zhihui/ai_old/zhihui_ai_server.cpp b/code/sdk/zhihui/ai_old/zhihui_ai_server.cpp
new file mode 100644 (file)
index 0000000..9f58dce
--- /dev/null
@@ -0,0 +1,246 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+// #include "../tcpmanager/tcp_simple_manager.h" // Removed as not needed in simplified version
+
+#include "../../../../../open_source/openharmony/third_party/cJSON/cJSON.h"
+#include "ConfigModelC.h"
+#include "ConfigModel.h"
+#include "wearable_log.h"
+#include "custom_runtime.h"
+#include "osal_timer.h"
+// #include "lwip/apps/sntp.h" // Commented out due to missing header
+
+#include <sys/time.h>
+#include <time.h>
+
+#include "cmsis_os2.h"
+
+// #include "bletest.h" // Commented out due to missing header
+#include "custom_utils.h"
+#include "custom_runtime.h"
+#include "bleANCS.h"
+#include "cat1_tcpServer.h"
+#include "custom_utils.h"
+#include "broadcast_feature.h"
+#include "cmsis_os2.h"
+#include "cat1_ctl.h"
+#include "voice_call_volte_sample_wrapper.h"
+
+#include "audio_capture_wrapper.h"
+// #include <ui_service.h> // Commented out due to missing header
+#include <bleService.h>
+// #include "cat1_ws.h" // Commented out due to missing header
+#include "dev_authentication.h"
+#include "bk_websocket.h"
+#include "voicechat_websocket_server.h"
+
+// Include separate server headers
+#include "asr_websocket_server.h"
+#include "tts_websocket_server.h"
+#include "chat_websocket_server.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "cmsis_os2.h"
+#include "bk_websocket.h"
+
+#include <stdint.h>
+#include <stdint.h>
+#include <asm/delay.h>
+// #include "bts_br_gap.h"
+
+
+// 资源保护
+static osMutexId_t g_ai_mutex = NULL;
+
+
+/**
+ * @brief 更合理判断字符串是否为JSON语句(只判断前20字节,忽略前导空白,要求以'{'或'['开头,且'{'后20字节内必须有'"',以判断为对象属性)
+ * @param str 字符串指针
+ * @param len 字符串长度
+ * @return 如果字符串看起来像JSON,则返回true,否则返回false
+ */
+static bool ai_is_json_string(const char *str, size_t len)
+{
+    if (!str || len == 0) return false;
+    size_t max_check = len < 20 ? len : 20;
+    size_t i = 0;
+    // 跳过前导空白
+    while (i < max_check && (str[i] == ' ' || str[i] == '\t' || str[i] == '\n' || str[i] == '\r')) {
+        i++;
+    }
+    if (i >= max_check) return false;
+
+    char start = str[i];
+    if (start == '{') {
+        // 对象类型,20字节内必须有'"'
+        for (size_t j = i + 1; j < len && j < max_check; ++j) {
+            if (str[j] == '"') {
+                return true;
+            }
+        }
+        return false;
+    }
+    return false;
+}
+
+
+#define AI_RESULT_STR_LEN  512
+
+extern bool read_dev_token(char *data_token);
+
+errcode_t ai_system_init(void);
+
+// 外部函数声明
+extern void bluetooth_get_local_addr(unsigned char *addr, int len);
+extern int active_md5_buf(char *input, char *output);
+extern void uapi_cat1_keep_wakeup(uint8_t state);
+extern void set_AIStreamend(uint8_t state);
+extern void set_clear_queue_stream(uint8_t state);
+extern void startAudioCaptureTask(void);
+extern void stop_AudioCaptureProcess_AI(void);
+extern void ble_set_ai_Question_str(char *str);
+extern void ble_set_ai_Answer_str(char *str, uint8_t type);
+extern void SendMsgToUIService(uint32_t msg_id, uint32_t param, void *data, uint32_t len);
+extern int send_msg_data_into_Ai_msg_queue(void *data, uint16_t len, uint8_t type);
+extern bool aut_login(void);
+extern void get_dev_id(char *device_id);
+extern void AIStreamFlush(void);
+extern void AIStreamWrite(uint8_t *buf, uint32_t len);
+
+static osTimerId_t g_timer_time_sync = NULL;
+
+static uint8_t server_state = 0;
+uint8_t disconnect_server = 0;
+static uint8_t type_ai = 0;
+
+// External server init functions - now implemented in separate files
+extern errcode_t chat_server_init(void);
+extern errcode_t tts_server_init(void);
+extern errcode_t asr_server_init(void);
+
+// External server deinit functions
+extern void asr_server_deinit(void);
+extern void chat_server_deinit(void);
+extern void tts_server_deinit(void);
+
+// External TTS functions
+extern int32_t uapi_tts_paly_init(void);
+extern int32_t uapi_tts_paly_stop(void);
+
+// External ASR functions
+extern void uapi_start_asr(void);
+
+// External TTS functions
+extern bool uapi_start_tts(void);
+
+static uint8_t is_init_ai = 1;
+
+bool init_ai_task(uint8_t type)
+{
+    if (is_init_ai) {
+        // 初始化AI系统
+        if (ai_system_init() != ERRCODE_SUCC) {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to initialize AI system");
+            return false;
+        }
+        
+        
+        disconnect_server = 0;
+
+        type_ai = type;
+        
+        // 初始化TTS播放
+        if (uapi_tts_paly_init() != ERRCODE_SUCC) {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to initialize TTS playback");
+        }
+
+        // 初始化TTS服务器
+        if (tts_server_init() != ERRCODE_SUCC) {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to initialize TTS server");
+        }
+        
+        // 初始化聊天服务器
+        if (chat_server_init() != ERRCODE_SUCC) {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to initialize chat server");
+        }
+        
+        // 初始化ASR服务器
+        if (asr_server_init() != ERRCODE_SUCC) {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to initialize asr server");
+        }
+        
+        WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "AI task initialized successfully, type: %d", type);
+    }
+
+    return true;
+}
+
+bool deinit_ai_task(void)
+{
+    if (is_init_ai) {
+        WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "Deinitializing AI task...");
+        
+        disconnect_server = 1;
+
+        if (g_timer_time_sync) {
+            osTimerDelete(g_timer_time_sync);
+            g_timer_time_sync = NULL;
+        }
+
+        // 停止TTS播放
+        if (uapi_tts_paly_stop() != ERRCODE_SUCC) {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to stop TTS playback");
+        }
+
+        // 清理服务器连接
+        asr_server_deinit();
+        chat_server_deinit();
+        tts_server_deinit();
+        
+        WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "AI task deinitialized successfully");
+    }
+
+    return true;
+}
+
+// // 预初始化AI
+// bool pre_AI_init(void)
+// {
+//     if(read_dev_token(NULL) == false)
+//     {
+//         return aut_login();
+//     }
+//     return true;
+// }
+
+// 初始化AI系统
+errcode_t ai_system_init(void) {
+    
+    // 创建互斥锁(检查是否已存在)
+    if (!g_ai_mutex) {
+        g_ai_mutex = osMutexNew(NULL);
+        if (!g_ai_mutex) {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to create AI mutex");
+            return ERRCODE_FAIL;
+        }
+        WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "AI mutex created in ai_system_init");
+    } else {
+        WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "AI mutex already exists, reusing");
+    }
+    
+    WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "AI system initialized successfully");
+    return ERRCODE_SUCC;
+}
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
diff --git a/code/sdk/zhihui/ai_old/zhihui_ws.cpp b/code/sdk/zhihui/ai_old/zhihui_ws.cpp
new file mode 100644 (file)
index 0000000..a8adc55
--- /dev/null
@@ -0,0 +1,1341 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <fcntl.h>
+// Standard socket headers commented out to avoid conflicts with lwIP
+// #include <sys/socket.h>
+// #include <netinet/in.h>
+// #include <arpa/inet.h>
+// #include <netdb.h>
+
+#include <dirent.h>
+// lwip headers commented out due to compilation issues
+// #include "lwip/netif.h"
+// #include "lwip/init.h"
+// #include "lwip/inet_chksum.h"
+// #include "lwip/dns.h"
+// #include "lwip/err.h"
+// #include "lwip/sockets.h"
+// #include "lwip/sys.h"
+// #include <lwip/netdb.h>
+
+/* 添加缺失的定义 */
+#ifndef SHUT_RDWR
+#define SHUT_RDWR 2
+#endif
+// #include <netinet/in.h>
+// #include "lwip/inet.h"
+#include <stdio.h>
+// #include <string.h>
+// #include <sys/param.h>
+#include <string.h>
+
+#include "../../../../../open_source/openharmony/third_party/cJSON/cJSON.h"
+#include "ConfigModelC.h"
+#include "ConfigModel.h"
+#include "wearable_log.h"
+#include "custom_runtime.h"
+#include "osal_timer.h"
+// #include "lwip/apps/sntp.h" // Commented out due to missing header
+
+#include <sys/time.h>
+
+// #include "bletest.h" // Commented out due to missing header
+#include "custom_utils.h"
+#include "custom_runtime.h"
+#include "bleANCS.h"
+#include "custom_utils.h"
+#include "broadcast_feature.h"
+#include "cmsis_os2.h"
+#include "cat1_ctl.h"
+#include "voice_call_volte_sample_wrapper.h"
+
+#include "audio_capture_wrapper.h"
+// #include <ui_service.h> // Commented out due to missing header
+#include <bleService.h>
+#include "zhihui_ws.h"
+#include "dev_authentication.h"
+// #include "tcp_simple_manager.h" // Commented out due to missing header
+
+// 包含新的WebSocket解析器
+#include "websocket_parser_wrapper.h"
+
+#define TEST_AI_WS 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+// Define to avoid timeval redefinition
+#define LWIP_TIMEVAL_PRIVATE 0
+#include "lwip/sockets.h"
+#include "lwip/netdb.h"
+#include "lwip/inet.h"
+#include "cmsis_os2.h"
+#ifdef CONFIG_CRYPTO_MBEDTLS
+#ifdef CONFIG_CRYPTO_MBEDTLS_2
+#include "mbedtls/net.h"
+#else
+#include "mbedtls/net_sockets.h"
+#endif
+#include <mbedtls/ssl.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/error.h>
+#include <mbedtls/x509_crt.h>
+
+#endif
+
+#include "mbedtls/base64.h"
+#include "mbedtls/sha1.h"
+
+
+#define BUFFER_SIZE 1024
+#define WEBSOCKET_KEY_LEN 24
+#define WEBSOCKET_GUID "1234567890123456"
+
+
+#include "bk_websocket.h"
+
+// 函数声明
+static int start_websocket_receive_thread(WebSocketClient* client);
+
+#include <stdint.h>
+#include <stdint.h>
+#include <asm/delay.h>
+
+#if 0
+// WebSocket日志控制宏
+#define WS_LOG_ERROR(fmt, ...)   printf("[WS_ERROR] " fmt "\n", ##__VA_ARGS__)
+#define WS_LOG_WARNING(fmt, ...) printf("[WS_WARN] " fmt "\n", ##__VA_ARGS__)
+#define WS_LOG_INFO(fmt, ...)    printf("[WS_INFO] " fmt "\n", ##__VA_ARGS__)
+#define WS_LOG_DEBUG(fmt, ...)   printf("[WS_DEBUG] " fmt "\n", ##__VA_ARGS__)
+#else
+// 可以通过注释/取消注释来控制日志级别
+#define WS_LOG_ERROR(fmt, ...)   printf("[WS_ERROR] " fmt "\n", ##__VA_ARGS__)
+#define WS_LOG_WARNING(fmt, ...) printf("[WS_WARN] " fmt "\n", ##__VA_ARGS__)
+#define WS_LOG_INFO(fmt, ...)    printf("[WS_INFO] " fmt "\n", ##__VA_ARGS__)
+#define WS_LOG_DEBUG(fmt, ...)   
+#endif
+extern osStatus_t osDelay(uint32_t ticks);
+#define cat1_msleep(ms) LOS_Msleep(ms) /* osDelay(1) : 1ms */
+
+// 旧的解析器函数声明已移除
+
+
+void bk_sleep(uint32_t time)
+{
+    msleep(time);
+}
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+void * aic_zalloc(unsigned int len)
+{
+    return malloc(len);
+}
+
+
+
+// 定义一个结构体来存储解析后的URL部分
+typedef struct {
+    char *protocol;
+    char *host;
+    int port;
+    char *path;
+    char *query;
+    int error;
+    char *error_message;
+} BK_URL;
+
+// 自定义的 strdup 函数,添加错误处理
+char* bk_strdup(const char* str) {
+    if (str == NULL) {
+        return NULL;
+    }
+    size_t len = strlen(str) + 1;
+    char* new_str = (char*)aic_zalloc(len);
+    if (new_str == NULL) {
+        return NULL;
+    }
+    return (char*)memcpy(new_str, str, len);
+}
+
+// 设置错误信息
+void set_url_error(BK_URL *url, const char *error_msg) {
+    url->error = 1;
+    url->error_message = bk_strdup(error_msg);
+    if (!url->error_message) {
+        // 若分配失败,输出提示信息
+        WS_LOG_ERROR("Memory allocation failed for error message.");
+    }
+
+}
+
+// 解析URL的函数
+BK_URL parse_url(const char *url) {
+    WS_LOG_WARNING("parse_url url=%s", url);
+    BK_URL result = {NULL, NULL, 0, NULL, NULL, 0, NULL};
+    char *temp_url_t = bk_strdup(url);
+    char *temp_url = temp_url_t;
+    if (!temp_url) {
+        set_url_error(&result, "Failed to allocate memory for temp_url");
+        return result;
+    }
+
+    // 解析协议
+    char *colon = strchr(temp_url, ':');
+    if (!colon) {
+        set_url_error(&result, "Invalid URL: No protocol specified");
+        free(temp_url_t);
+        return result;
+    }
+    *colon = '\0';
+    result.protocol = bk_strdup(temp_url);
+    if (!result.protocol) {
+        set_url_error(&result, "Failed to allocate memory for protocol");
+        free(temp_url_t);
+        return result;
+    }
+    temp_url = colon + 3;  // 跳过 "://"
+
+    // 解析主机和端口
+    char *slash = strchr(temp_url, '/');
+    if (!slash) {
+        set_url_error(&result, "Invalid URL: No path specified");
+        free(temp_url_t);
+        return result;
+    }
+    *slash = '\0';
+    char *at = strchr(temp_url, '@');
+    if (at) {
+        temp_url = at + 1;  // 跳过用户名和密码部分
+    }
+    char *colon_port = strchr(temp_url, ':');
+    if (colon_port) {
+        *colon_port = '\0';
+        result.host = bk_strdup(temp_url);
+        if (!result.host) {
+            set_url_error(&result, "Failed to allocate memory for host");
+            free(temp_url_t);
+            return result;
+        }
+        result.port = atoi(colon_port + 1);
+        if (!result.port) {
+            set_url_error(&result, "Invalid port number");
+            free(temp_url_t);
+            return result;
+        }
+    } else {
+        result.host = bk_strdup(temp_url);
+        if (!result.host) {
+            set_url_error(&result, "Failed to allocate memory for host");
+            free(temp_url_t);
+            return result;
+        }
+        if (!strcmp(result.protocol, "http") || !strcmp(result.protocol, "ws")) {
+            result.port = 80;
+        } else if (!strcmp(result.protocol, "https")|| !strcmp(result.protocol, "wss")) {
+            result.port = 443;
+        }
+    }
+    temp_url = slash+1;
+    //printf("parse_url slash=%s\n",temp_url);
+    // 解析路径和查询字符串
+    char *question = strchr(temp_url, '?');
+    if (question) {
+        *question = '\0';
+        result.path = bk_strdup(temp_url);
+        if (!result.path) {
+            set_url_error(&result, "Failed to allocate memory for path");
+            free(temp_url_t);
+            return result;
+        }
+        result.query = bk_strdup(question + 1);
+        if (!result.query) {
+            set_url_error(&result, "Failed to allocate memory for query");
+            free(temp_url_t);
+            return result;
+        }
+    } else {
+        result.path = bk_strdup(temp_url);
+        if (!result.path) {
+            set_url_error(&result, "Failed to allocate memory for path");
+            free(temp_url_t);
+            return result;
+        }
+        result.query = NULL;
+    }
+
+    free(temp_url_t);
+
+    return result;
+}
+
+// 释放URL结构体中分配的内存
+void free_url(BK_URL url) {
+
+    // 释放已分配的内存
+
+    if (url.protocol) {
+        free(url.protocol);
+        url.protocol = NULL;
+    }
+    if (url.host) {
+        free(url.host);
+        url.host = NULL;
+    }
+    if (url.path) {
+        free(url.path);
+        url.path = NULL;
+    }
+    if (url.query) {
+        free(url.query);
+        url.query = NULL;
+    }
+    if (url.error_message) {
+        free(url.error_message);
+        url.error_message = NULL;
+    }
+
+}
+
+// // 仿写 htonll 函数
+static uint64_t htonll(uint64_t hostlonglong) {
+    // 检查主机是否为大端字节序
+    static const union {
+        uint32_t i;
+        char c[4];
+    } test = {0x01000000};
+    if (test.c[0] == 0x01) {
+        // 主机是大端字节序,不需要转换
+        return hostlonglong;
+    }
+
+    // 将 64 位整数拆分为两个 32 位整数
+    uint32_t high = (hostlonglong >> 32) & 0xFFFFFFFF;
+    uint32_t low = hostlonglong & 0xFFFFFFFF;
+
+    // 分别转换两个 32 位整数的字节序
+    high = htonl(high);
+    low = htonl(low);
+
+    // 合并转换后的两个 32 位整数
+    return ((uint64_t)low << 32) | high;
+}
+// // 仿写 ntohll 函数
+static uint64_t ntohll(uint64_t netlonglong) {
+    // 将 64 位整数拆分为两个 32 位整数
+    uint32_t high = (netlonglong >> 32) & 0xFFFFFFFF;
+    uint32_t low = netlonglong & 0xFFFFFFFF;
+
+    // 分别转换两个 32 位整数的字节序
+    high = ntohl(high);
+    low = ntohl(low);
+
+    // 合并转换后的两个 32 位整数
+    return ((uint64_t)high << 32) | low;
+}
+// 生成随机的 WebSocket 密钥
+void generate_websocket_key(char *key) {
+    static const char charset[] =
+        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+    for (int i = 0; i < WEBSOCKET_KEY_LEN - 1; ++i) {
+        key[i] = charset[rand() % (sizeof(charset) - 1)];
+    }
+    key[WEBSOCKET_KEY_LEN] = '\0';
+
+    unsigned char encoded[WEBSOCKET_KEY_LEN * 2];
+    size_t olen;
+    mbedtls_base64_encode(encoded, sizeof(encoded), &olen, (const unsigned char *)key, strlen(key));
+    WS_LOG_WARNING("generate_websocket_key %s %d", encoded, olen);
+
+    if(olen>=(WEBSOCKET_KEY_LEN))
+    olen=WEBSOCKET_KEY_LEN;
+
+    strncpy(key, (const char *)encoded, olen);
+
+    key[olen] = '\0';
+}
+
+// 生成 WebSocket 握手响应密钥
+void generate_accept_key(const char *key, char *accept_key) {
+    char combined[128]={0};
+    strcpy(combined, key);
+    strcat(combined, WEBSOCKET_GUID);
+
+    unsigned char sha1_result[20]={0};
+    mbedtls_sha1((const unsigned char *)combined, strlen(combined), sha1_result);
+
+    unsigned char encoded[64]={0};
+    size_t olen;
+    mbedtls_base64_encode(encoded, sizeof(encoded), &olen, sha1_result, 16);//sizeof(sha1_result));
+    strncpy(accept_key, (const char *)encoded, olen);
+    accept_key[olen] = '\0';
+}
+
+// 发送 WebSocket 握手请求
+/**
+ * @brief 发送 WebSocket 握手请求
+ * @param client 客户端指针
+ * @param headers 头信息
+ * @return 成功返回0,失败返回-1
+ */
+#if (TEST_AI_WS==0)
+int send_handshake(WebSocketClient *client,const char *headers,char *response,int response_len) {
+    char key[WEBSOCKET_KEY_LEN+1];
+    WS_LOG_INFO("send_handshake1");
+
+    if(client==NULL|| response==NULL || response_len<=0)
+    {
+        WS_LOG_ERROR("send_handshake client or response is NULL , or response_len <= 0");
+        return -1;
+    }
+
+    generate_websocket_key(key);
+    char accept_key[64];
+    int ret = 0;
+    generate_accept_key(key, accept_key);
+    WS_LOG_INFO("send_handshake2");
+
+    char *request =( char *)aic_zalloc(BUFFER_SIZE);
+  
+    if(request==NULL)
+    {
+        WS_LOG_ERROR("request aic_zalloc error");
+        return -1;
+    }
+
+    memset(request,0,BUFFER_SIZE);
+
+    if(headers!= NULL)
+    {
+        snprintf(request, BUFFER_SIZE,
+            "GET /%s?%s HTTP/1.1\r\n"
+            "Host: %s:%d\r\n"
+            "Upgrade: websocket\r\n"
+            "Connection: Upgrade\r\n"
+            "Sec-WebSocket-Key: %s\r\n"
+            "Sec-WebSocket-Version: 13\r\n"
+            "Origin: http://%s:%d\r\n"
+            "%s\r\n"
+            "\r\n",
+            client->path,client->query  ,client->host,client->port, accept_key,client->host,client->port,headers);
+    }else
+    {
+        snprintf(request, BUFFER_SIZE,
+            "GET /%s?%s HTTP/1.1\r\n"
+            "Host: %s:%d\r\n"
+            "Upgrade: websocket\r\n"
+            "Connection: Upgrade\r\n"
+            "Sec-WebSocket-Key: %s\r\n"
+            "Sec-WebSocket-Version: 13\r\n"
+            "Origin: http://%s:%d\r\n"
+            "\r\n",
+            client->path,client->query , client->host,client->port, accept_key,client->host,client->port);
+    }
+    
+    WS_LOG_WARNING("send_handshake request:\r\n%s", request);
+    
+    // 发送WebSocket握手请求并等待响应
+    WS_LOG_INFO("发送WebSocket握手请求...");
+    
+    // 发送握手请求
+    int send_ret = lwip_send(client->sockfd, request, strlen(request), 0);
+    if (send_ret < 0) {
+        WS_LOG_ERROR("发送握手请求失败: %d", send_ret);
+        ret = -1;
+    } else {
+        // 接收响应
+        ret = lwip_recv(client->sockfd, response, response_len - 1, 0);
+        if (ret > 0) {
+            response[ret] = '\0'; // 确保字符串结束
+        }
+    }
+    
+    if (ret < 0) {
+        WS_LOG_ERROR("WebSocket握手发送失败: %d", ret);
+        ret = -1;
+    } else {
+        WS_LOG_INFO("WebSocket握手发送成功,接收到 %d 字节响应", ret);
+        
+        // 检查响应内容
+        if (ret > 0 && response[0] != '\0') {
+            WS_LOG_WARNING("WebSocket %s:\r\n", client->path);
+            WS_LOG_WARNING("WebSocket握手响应:\r\n%s", response);
+            
+            // 检查是否包含"HTTP/1.1 101"
+            if (strstr(response, "HTTP/1.1 101") != NULL) {
+                WS_LOG_INFO("WebSocket握手成功!");
+                client->handshake = 1;
+            } else {
+                WS_LOG_ERROR("WebSocket握手失败:响应不是101状态码");
+                ret = -1;
+            }
+        } else {
+            WS_LOG_ERROR("WebSocket握手失败:无响应数据");
+            ret = -1;
+        }
+    }
+    
+    free(request);
+    WS_LOG_INFO("send_handshake3 返回: %d", ret);
+    return ret;
+}
+#else
+
+int send_handshake(WebSocketClient *client,const char *headers) {
+    char key[WEBSOCKET_KEY_LEN+1];
+    printf("send_handshake1");
+    generate_websocket_key(key);
+    char accept_key[64];
+    int ret = 0;
+    generate_accept_key(key, accept_key);
+    printf("send_handshake2");
+    char *request =( char *)aic_zalloc(BUFFER_SIZE);
+    if(request==NULL)
+    {
+        printf("request aic_zalloc erro");
+        return -1;
+    }
+    
+
+    if(headers!= NULL)
+    {
+        snprintf(request, BUFFER_SIZE,
+            "GET /%s?%s HTTP/1.1\r\n"
+            "Host: %s:%d\r\n"
+            "Upgrade: websocket\r\n"
+            "Connection: Upgrade\r\n"
+            "Sec-WebSocket-Key: %s\r\n"
+            "Sec-WebSocket-Version: 13\r\n"
+            "Origin: http://%s:%d\r\n"
+            "%s\r\n"
+            "\r\n",
+            client->path,client->query  ,client->host,client->port, accept_key,client->host,client->port,headers);
+    }else
+    {
+        snprintf(request, BUFFER_SIZE,
+            "GET /%s?%s HTTP/1.1\r\n"
+            "Host: %s:%d\r\n"
+            "Upgrade: websocket\r\n"
+            "Connection: Upgrade\r\n"
+            "Sec-WebSocket-Key: %s\r\n"
+            "Sec-WebSocket-Version: 13\r\n"
+            "Origin: http://%s:%d\r\n"
+            "\r\n",
+            client->path,client->query , client->host,client->port, accept_key,client->host,client->port);
+    }
+    
+    printf("send_handshake request:\r\n%s",request);
+    if (lwip_send(client->sockfd, request, strlen(request), 0) < 0) {
+        printf("send handshake failed");
+        ret = -1;
+    }
+   
+    free(request);
+    printf("send_handshake3 %d",ret);
+    return ret;
+}
+#endif
+
+
+// 发送 WebSocket 消息
+int send_websocket_message(WebSocketClient *client, uint8_t *message, size_t message_len, WebSocketMessageType type) {
+
+    int ret_tcp_send_data=0;
+    if(client==NULL||message==NULL )
+    {
+         WS_LOG_ERROR("send_websocket_message client or message is NULL %s %s", client, message);
+        return -1;
+    }
+    
+    // 检查连接状态
+    if (client->sockfd < 0) {
+        WS_LOG_ERROR("send_websocket_message: Socket is invalid");
+        return -1;
+    }
+    
+    if (client->handshake == 0) {
+        WS_LOG_ERROR("send_websocket_message: WebSocket handshake not completed");
+        return -1;
+    }
+    uint8_t* frame=( uint8_t *)aic_zalloc(message_len + 50);
+    int offset = 0;
+    int ret = -1;
+    if(!frame)
+    {
+        WS_LOG_ERROR("send_websocket_message zalloc error");
+        return -1;
+    }
+    // 第一个字节:FIN = 1, 设置 opcode
+    frame[offset++] = 0x80 | type;
+
+    // 第二个字节:设置掩码位和负载长度
+    if (message_len < 126) {
+
+        frame[offset++] = 0x80 | message_len;
+
+    }
+     else if (message_len < 65536) 
+     {
+        frame[offset++] = 0x80 | 126;
+        uint16_t len = htons((uint16_t)message_len);
+        memcpy(frame + offset, &len, 2);
+        offset += 2;
+    } else {
+        frame[offset++] = 0x80 | 127;
+        uint64_t len = htonll(message_len);
+        memcpy(frame + offset, &len, 8);
+        offset += 8;
+    }
+
+    // 生成掩码密钥
+    unsigned char masking_key[4];
+    for (int i = 0; i < 4; ++i) {
+        masking_key[i] = (unsigned char)rand();
+    }
+    memcpy(frame + offset, masking_key, 4);
+    offset += 4;
+
+    // 掩码处理消息
+    for (size_t i = 0; i < message_len; ++i) {
+        frame[offset + i] = message[i] ^ masking_key[i % 4];
+    }
+    offset += message_len;
+
+    // 发送帧
+    WS_LOG_INFO("offset %d", offset);
+    
+    // 再次检查socket有效性
+    if (client->sockfd < 0) {
+        WS_LOG_ERROR("send_websocket_message: Socket became invalid before send");
+        ret = -1;
+        goto send_websocket_message_ERROR;
+    }
+
+    
+    
+    ret_tcp_send_data = lwip_send(client->sockfd, frame, offset, 0);
+    if (ret_tcp_send_data < 0) {
+        WS_LOG_ERROR("send message failed %d", ret_tcp_send_data);
+        ret =  -1;
+        goto send_websocket_message_ERROR;
+    }
+    ret = 0;
+
+send_websocket_message_ERROR:
+    bk_sleep(message_len/1000+1);
+    free(frame);
+    // bk_sleep(message_len/1000+1);
+    return ret;
+}
+
+// TCP回调函数已废弃,现在使用标准socket和接收线程
+/*
+void _tcp_on_connect_cb(tcp_handle_t handle, bool success)
+{
+    // 此函数已废弃,现在使用标准socket连接
+}
+*/
+/*
+void _tcp_on_disconnect_cb(tcp_handle_t handle)
+{
+    // 此函数已废弃,现在使用标准socket
+}
+*/
+/*
+void _tcp_on_data_received_cb(tcp_handle_t handle, uint8_t* data, uint16_t datalen)
+{
+    // 此函数已废弃,现在使用接收线程处理数据
+}
+*/
+#if TEST_AI_WS
+
+struct cat1_ws_init_t
+{
+    osSemaphoreId_t dns_done_sem;
+    ip_addr_t ip;
+};
+WebSocketClient *init_websocket_client(const char *url, const char *headers,uint8_t use_dns) {
+    //printf("init_websocket_client 1\n");
+    char *buffer = NULL;
+    WebSocketClient *client  =NULL;
+    BK_URL parsed_url = {0};
+    struct sockaddr_in server_addr;
+    ssize_t bytes_received;
+    struct in_addr in_addr_t={0};
+    ip_addr_t  ip;
+    struct cat1_ws_init_t ip_sem={0};
+    int opt = 1;
+    int sockfd = -1;
+
+    int ret=0;
+
+    parsed_url = parse_url(url);//解析url
+
+    if (parsed_url.error) {
+        printf("init_websocket_client Error: %s", parsed_url.error_message);
+        goto client_ERROR;
+    } else {
+        printf("Protocol: %s", parsed_url.protocol);
+        printf("Host: %s\n", parsed_url.host);
+        printf("Port: %d\n", parsed_url.port);
+        printf("Path: %s\n", parsed_url.path);
+        printf("Query: %s\n", parsed_url.query);
+
+    }
+    client = (WebSocketClient *)aic_zalloc(sizeof(WebSocketClient)) ;
+    if(!client)
+    {
+        printf("init_websocket_client alloc error");
+        goto client_ERROR;
+    }
+
+    
+
+    sockfd = lwip_socket(AF_INET, SOCK_STREAM, 0);
+    client->sockfd=sockfd;
+
+    if (sockfd < 0) {
+        
+        printf("socket creation failed %d errno: %d\r\n",sockfd,errno);
+        goto client_ERROR;
+    }
+    lwip_setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (const void*)&opt, sizeof(opt));
+    lwip_setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,(const void*)&opt, sizeof(opt));
+   // printf("init_websocket_client 3\n");
+    if(use_dns)
+    {
+        // ip_sem.dns_done_sem= osSemaphoreNew(1, 0, NULL);
+        // if(ip_sem.dns_done_sem==0)
+        // {
+        //     goto client_ERROR;
+        // }
+
+        // ret =dns_gethostbyname(parsed_url.host,&ip,dns_found,&ip_sem);
+        // // if(ERR_OK==ret)
+        // {
+        //     osSemaphoreAcquire(ip_sem.dns_done_sem, 1000*30);
+        // }
+        // osSemaphoreDelete(ip_sem.dns_done_sem);
+        // printf("dns_gethostbyname %d\r\n",ip_sem.ip.u_addr.ip4);
+        // memcpy(&server_addr.sin_addr.s_addr, &ip_sem.ip.u_addr.ip4, 4);
+
+    }
+    else
+    {
+        inet_pton(AF_INET, parsed_url.host, &server_addr.sin_addr);
+    }
+   
+
+   
+    server_addr.sin_family = AF_INET;
+
+    server_addr.sin_port = htons(parsed_url.port);
+   
+
+    // 
+
+    if (lwip_connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
+        printf("init_websocket_client connection failed\r\n");
+        msleep(100);
+        close(sockfd);
+
+        goto client_ERROR;
+
+    }
+     printf("socket creation succ\r\n");
+
+
+    strcpy(client->host, parsed_url.host);
+    strcpy(client->path, parsed_url.path);
+    strcpy(client->query, parsed_url.query);
+    client->port = parsed_url.port;
+
+
+    if (send_handshake(client,headers) < 0) { //发送头
+        printf("socket send_handshake client_ERROR");
+
+        close(sockfd);
+        goto client_ERROR;
+    }
+
+    buffer=(char *)aic_zalloc(BUFFER_SIZE);
+    
+    if(buffer==NULL)
+    {
+         printf("aic_zalloc(BUFFER_SIZE);null ");
+          goto client_ERROR;
+    }
+    printf("recv: ???  ");
+
+    bytes_received = lwip_recv(sockfd, buffer, BUFFER_SIZE - 1, 0);
+
+    printf("recv; ");
+
+    if (bytes_received > 0) {
+        buffer[bytes_received] = '\0';
+        printf("Received handshake response:\n%s\n", buffer);
+    }
+    
+  
+
+    if(strstr(buffer,"HTTP/1.1 101") == NULL)
+    {
+        
+        goto client_ERROR;
+    }
+     printf("init_websocket_client end 1");
+  
+
+     printf("init_websocket_client end 2");
+
+    client->tcp_handle = tcp_add_existing_connection(sockfd, parsed_url.host, parsed_url.port,
+                                                    _tcp_on_connect_cb, _tcp_on_disconnect_cb, _tcp_on_data_received_cb);
+    
+    client->parser = ws_parser_init();
+
+    free(buffer);
+    free_url(parsed_url);
+
+    client->handshake=1;
+
+    if (!client->parser) {
+        WS_LOG_ERROR("init_websocket_client Error: Failed to initialize WebSocket parser");
+        close(sockfd);
+        goto client_ERROR;
+    }
+
+    return client;
+client_ERROR:
+    WS_LOG_ERROR("init_websocket_client Error: client_ERROR");
+    if(buffer) {
+        free(buffer);
+        buffer=NULL;
+    }
+    if(client){
+        free(client);
+        client = NULL;
+    }
+    free_url(parsed_url);
+    
+    return NULL;
+}
+#else
+// 初始化 WebSocket 客户端
+WebSocketClient *init_websocket_client(const char *url, const char *headers,uint8_t use_dns) {
+    //printf("init_websocket_client 1\n");
+    WebSocketClient *client = NULL;
+    BK_URL parsed_url = {0};
+    int opt = 1;
+    int ret = 0;
+    int opt_val = 1;
+    struct sockaddr_in server_addr;
+    struct hostent *host_entry;
+    int connect_result;
+    fd_set write_fds;
+    struct timeval timeout;
+    int select_result;
+    int error = 0;
+    socklen_t len = sizeof(error);
+    int flags;
+    
+    if (!url) {
+        WS_LOG_ERROR("init_websocket_client Error: URL is NULL");
+        return NULL;
+    }
+
+    parsed_url = parse_url(url);//解析url
+
+    if (parsed_url.error) {
+        WS_LOG_ERROR("init_websocket_client Error: %s", parsed_url.error_message);
+        goto client_ERROR;
+    } else {
+        WS_LOG_INFO("Protocol: %s", parsed_url.protocol);
+        WS_LOG_INFO("Host: %s", parsed_url.host);
+        WS_LOG_INFO("Port: %d", parsed_url.port);
+        WS_LOG_INFO("Path: %s", parsed_url.path);
+        WS_LOG_INFO("Query: %s", parsed_url.query);
+    }
+    
+    client = (WebSocketClient *)aic_zalloc(sizeof(WebSocketClient)) ;
+    memset_s(client,sizeof(WebSocketClient),0,sizeof(WebSocketClient));
+    if(!client)
+    {
+        WS_LOG_ERROR("init_websocket_client alloc error: Failed to allocate memory for WebSocketClient");
+        goto client_ERROR;
+    }
+    
+    // 使用标准 socket 替代 TCP 管理器
+    client->sockfd = lwip_socket(AF_INET, SOCK_STREAM, 0);
+    if (client->sockfd < 0) {
+        WS_LOG_ERROR("init_websocket_client Error: Socket creation failed");
+        goto client_ERROR;
+    }
+    
+    // 设置 socket 选项
+    lwip_setsockopt(client->sockfd, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(opt_val));
+    
+    // 设置非阻塞模式
+    flags = fcntl(client->sockfd, F_GETFL, 0);
+    fcntl(client->sockfd, F_SETFL, flags | O_NONBLOCK);
+    
+    // 解析主机地址
+    memset(&server_addr, 0, sizeof(server_addr));
+    server_addr.sin_family = AF_INET;
+    server_addr.sin_port = htons(parsed_url.port);
+    
+    // DNS 解析或直接使用 IP
+    if (use_dns || !inet_aton(parsed_url.host, &server_addr.sin_addr)) {
+        host_entry = lwip_gethostbyname(parsed_url.host);
+        if (host_entry == NULL) {
+            WS_LOG_ERROR("init_websocket_client Error: DNS resolution failed for %s", parsed_url.host);
+            goto client_ERROR;
+        }
+        memcpy(&server_addr.sin_addr, host_entry->h_addr_list[0], host_entry->h_length);
+    }
+    
+    // 连接到服务器
+    connect_result = lwip_connect(client->sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
+    if (connect_result < 0 && errno != EINPROGRESS) {
+        WS_LOG_ERROR("init_websocket_client Error: Socket connection failed for %s:%d", parsed_url.host, parsed_url.port);
+        goto client_ERROR;
+    }
+    
+    // 等待连接完成
+    if (connect_result == 0 || errno == EINPROGRESS) {
+        FD_ZERO(&write_fds);
+        FD_SET(client->sockfd, &write_fds);
+        timeout.tv_sec = 10;  // 10秒超时
+        timeout.tv_usec = 0;
+        
+        select_result = lwip_select(client->sockfd + 1, NULL, &write_fds, NULL, &timeout);
+        if (select_result > 0 && FD_ISSET(client->sockfd, &write_fds)) {
+            // 检查连接是否成功
+            if (lwip_getsockopt(client->sockfd, SOL_SOCKET, SO_ERROR, &error, &len) == 0 && error == 0) {
+                WS_LOG_INFO("Socket connected successfully");
+                
+                // 发送 WebSocket 握手
+                char *buffer = (char *)aic_zalloc(BUFFER_SIZE);
+                if (buffer != NULL) {
+                    int bytes_received = send_handshake(client, NULL, buffer, BUFFER_SIZE);
+                    if (bytes_received >= 0) {
+                        client->handshake = 1;
+                        WS_LOG_INFO("WebSocket handshake completed");
+                    } else {
+                        WS_LOG_ERROR("WebSocket handshake failed");
+                    }
+                    free(buffer);
+                }
+            } else {
+                WS_LOG_ERROR("Socket connection failed with error: %d", error);
+                goto client_ERROR;
+            }
+        } else {
+            WS_LOG_ERROR("Socket connection timeout or failed");
+            goto client_ERROR;
+        }
+    }
+    
+    // 设置回阻塞模式用于后续通信
+    flags = fcntl(client->sockfd, F_GETFL, 0);
+    fcntl(client->sockfd, F_SETFL, flags & ~O_NONBLOCK);
+    WS_LOG_INFO("socket creation success");
+
+    strcpy(client->host, parsed_url.host);
+    strcpy(client->path, parsed_url.path);
+    strcpy(client->query, parsed_url.query);
+    client->port = parsed_url.port;
+    
+    /* 初始化WebSocket解析器 */
+    client->parser = ws_parser_init();
+    if (!client->parser) {
+        WS_LOG_ERROR("init_websocket_client Error: Failed to initialize WebSocket parser");
+        goto client_ERROR;
+    }
+    
+    /* 启动数据接收线程 */
+    WS_LOG_INFO("WebSocket客户端初始化完成,启动数据接收线程");
+    
+    // 启动数据接收线程
+    if (start_websocket_receive_thread(client) != 0) {
+        WS_LOG_ERROR("Failed to start WebSocket receive thread");
+        goto client_ERROR;
+    }
+    
+// if(strstr(buffer,"HTTP/1.1 101") == NULL)
+    // {
+        
+    //     goto client_ERROR;
+    // }
+    //  printf("init_websocket_client end 1");
+    // free(buffer);
+    free_url(parsed_url);
+
+     WS_LOG_INFO("init_websocket_client end 2");
+    return client;
+
+client_ERROR:
+    WS_LOG_ERROR("init_websocket_client Error: Initialization failed, cleaning up...");
+    if(client){
+        free(client);
+        client = NULL;
+    }
+    free_url(parsed_url);
+    
+    return NULL;
+}
+#endif
+
+// 关闭 WebSocket 客户端
+void close_websocket_client(WebSocketClient *client) {
+    if(client)
+    {
+        // 使用标准 socket 关闭替代 TCP 管理器
+
+        WS_LOG_INFO("close_websocket_client %s %s", client->host, client->path);
+        
+        // 先关闭socket连接,避免数据继续流入
+        if (client->sockfd >= 0) {
+            close(client->sockfd);
+            client->sockfd = -1;
+        }
+        
+        // 释放WebSocket解析器
+        if (client->parser) {
+            ws_parser_destroy(client->parser);
+            client->parser = NULL;
+        }
+        
+        // 清理客户端状态
+        client->handshake = 0;
+        client->packet_callback = NULL;
+        
+        free(client);
+    }
+}
+
+// 旧的WebSocket解析器函数已移除,现在使用新的解析器
+
+/**
+ * @brief 设置WebSocket数据包回调函数
+ */
+void ws_set_packet_callback(WebSocketClient *client, on_ws_packet_callback callback)
+{
+    if (!client) return;
+    
+    client->packet_callback = callback;
+}
+
+/**
+ * @brief 处理接收到的原始数据
+ */
+int ws_process_received_data(WebSocketClient *client, const uint8_t *data, size_t len)
+{
+    if (!client || !data || len == 0 || !client->parser) {
+        WS_LOG_ERROR("ws_process_received_data: invalid parameters - client=%p, data=%p, len=%zu, parser=%p", 
+               client, data, len, client->parser);
+        return -1;
+    }
+    
+    // ========== 新增:打印收到的所有原始数据 ==========
+    // printf("\n=== WebSocket Raw Data Received ===\n");
+    // printf("Client: %s:%s\n", client->host, client->path);
+    // WS_LOG_WARNING("Total bytes: %zu", len);
+    // printf("Raw data (hex): ");
+    // // 打印所有数据的十六进制表示
+    // for (size_t i = 0; i < len; i++) {
+        //     printf("%02X ", data[i]);
+        //     // 每16字节换行,提高可读性
+        //     if ((i + 1) % 16 == 0) {
+            //         printf("\n                    ");
+        //     }
+    // }
+    // printf("\n");
+    
+    // // 打印ASCII表示(可打印字符)
+    // printf("Raw data (ASCII): ");
+    // for (size_t i = 0; i < len; i++) {
+    //     if (data[i] >= 32 && data[i] <= 126) {
+    //         printf("%c", data[i]);
+    //     } else if (data[i] == '\r') {
+    //         printf("\\r");
+    //     } else if (data[i] == '\n') {
+    //         printf("\\n");
+    //     } else if (data[i] == '\t') {
+    //         printf("\\t");
+    //     } else {
+    //         printf(".");
+    //     }
+    // }
+    // printf("\n");
+    
+    // 打印数据统计信息
+    // printf("Data analysis:\n");
+    // printf("  - Total bytes: %zu\n", len);
+    // printf("  - First byte: 0x%02X\n", len > 0 ? data[0] : 0);
+    // printf("  - Last byte:  0x%02X\n", len > 0 ? data[len-1] : 0);
+    
+    // 检查是否可能是WebSocket帧头
+    // if (len >= 2) {
+    //     uint8_t first_byte = data[0];
+    //     uint8_t second_byte = data[1];
+    //     uint8_t fin = (first_byte >> 7) & 0x1;
+    //     uint8_t rsv = (first_byte >> 4) & 0x7;
+    //     uint8_t opcode = first_byte & 0x0F;
+    //     uint8_t mask = (second_byte >> 7) & 0x1;
+    //     uint8_t payload_len = second_byte & 0x7F;
+        
+    //     printf("  - Potential WebSocket frame:\n");
+    //     printf("    * FIN: %d\n", fin);
+    //     printf("    * RSV: %d%d%d\n", (rsv >> 2) & 1, (rsv >> 1) & 1, rsv & 1);
+    //     printf("    * Opcode: 0x%02X\n", opcode);
+    //     printf("    * Mask: %d\n", mask);
+    //     printf("    * Payload length: %d\n", payload_len);
+        
+    //     // 验证opcode是否有效
+    //     bool valid_opcode = ((opcode <= 0x2) || (opcode >= 0x8 && opcode <= 0xA));
+    //     printf("    * Valid opcode: %s\n", valid_opcode ? "YES" : "NO");
+        
+    //     // 验证RSV位
+    //     bool valid_rsv = (rsv == 0);
+    //     printf("    * Valid RSV: %s\n", valid_rsv ? "YES" : "NO");
+    // }
+    // WS_LOG_WARNING("=====================================");
+    
+    ws_parser_t* parser = client->parser;
+    int total_processed = 0;
+    const uint8_t* current_data = data;
+    size_t remaining_len = len;
+    
+    WS_LOG_DEBUG("ws_process_received_data: processing %zu bytes for client %s:%s", 
+           len, client->host, client->path);
+    
+    // 循环处理数据,支持连续帧
+    size_t original_len = remaining_len;
+    size_t loop_count = 0;
+    const size_t max_loops = original_len + 10; // 防止无限循环
+    
+    while (remaining_len > 0 && loop_count < max_loops) {
+        loop_count++;
+        WS_LOG_DEBUG("ws_process_received_data: processing remaining %d bytes, current offset: %zu, loop %d", 
+               remaining_len, current_data - data, loop_count);
+        
+        // 在解析前打印当前解析器状态
+        WS_LOG_DEBUG("ws_process_received_data: parser state before parsing:");
+        // ws_parser_debug_state(parser);
+        
+        // 使用新的解析器处理当前数据段
+        int result = ws_parse_stream(parser, current_data, remaining_len);
+
+        if(result <= 0)
+        {
+            WS_LOG_ERROR("ws_process_received_data: parsing error, reset parser,find next frame. Remaining: %zu bytes", remaining_len);
+            ws_parser_reset(parser);
+            // 不要立即返回,尝试跳过错误数据继续处理
+            current_data++;
+            remaining_len--;
+            continue;
+        }
+
+        // 更新处理进度
+        total_processed += result;
+        current_data += result;
+        remaining_len -= result;
+
+        // 在解析后打印解析器状态
+        WS_LOG_DEBUG("ws_process_received_data: parser state after parsing:");
+        // ws_parser_debug_state(parser);
+        ws_parse_state_t ws_stat =  ws_parser_get_state(parser);
+        
+        if (ws_stat == WS_STATE_COMPLETE) {
+            // 解析完成一个完整的WebSocket帧
+            const ws_header_t* header = ws_get_header(parser);
+            const uint8_t* payload = ws_get_payload(parser);
+            size_t payload_len = ws_get_payload_length(parser);
+            
+            WS_LOG_DEBUG("ws_process_received_data: frame complete, total bytes: %d, payload bytes: %zu %s", 
+                   result, payload_len,client->path);
+            
+            if (header && payload) {
+                WS_LOG_DEBUG("WebSocket frame received: opcode=0x%02X, fin=%d, payload_len=%llu", 
+                       header->opcode, header->fin, header->payload_len);
+                // printf("payload = %s\n",payload);
+                
+                // 打印载荷数据的前几个字节(用于调试)
+                // if (payload_len > 0) {
+                //     printf("Payload data (first 32 bytes): ");
+                //     for (size_t i = 0; i < payload_len && i < 32; i++) {
+                //         printf("%02X ", payload[i]);
+                //     }
+                //     if (payload_len > 32) printf("...");
+                //     printf("\n");
+                // }
+                
+                // 根据操作码处理不同类型的消息
+                switch (header->opcode) {
+                    case WS_PING:
+                        WS_LOG_WARNING("Received WebSocket PING");
+                        // TODO: 自动回复PONG
+                        send_websocket_message(client,( uint8_t  *)"PONG",strlen("PONG"),WS_PONG);
+                        break;
+                        
+                    case WS_PONG:
+                        WS_LOG_WARNING("Received WebSocket PONG");
+                        break;
+                        
+                    case WS_CLOSE:
+                        WS_LOG_WARNING("Received WebSocket CLOSE");
+                        // 调用回调函数处理关闭帧
+                        if (client->packet_callback) {
+                            client->packet_callback((uint8_t*)payload, payload_len, (WebSocketMessageType)WS_CLOSE);
+                        }
+                        break;
+                        
+                    case WS_TEXT:
+                    case WS_BINARY:
+                    case WS_CONTINUATION:
+                        // 调用回调函数处理数据包
+                        if (client->packet_callback) {
+                            WebSocketMessageType ws_type = (header->opcode == WS_TEXT) ? (WebSocketMessageType)WS_TEXT : 
+                                                          (header->opcode == WS_BINARY) ? (WebSocketMessageType)WS_BINARY : (WebSocketMessageType)WS_CONT;
+                            client->packet_callback((uint8_t*)payload, payload_len, ws_type);
+                        }
+                      
+                        break;
+                        
+                    default:
+                        WS_LOG_DEBUG("Unknown WebSocket opcode: 0x%02X", header->opcode);
+                        break;
+                }
+                
+                // 重要:在数据处理完成后再重置解析器状态
+                // 这样可以确保数据被正确处理后再清理状态
+                WS_LOG_DEBUG("ws_process_received_data: data processing complete, resetting parser");
+                ws_parser_reset(parser);
+                
+                
+                
+                WS_LOG_DEBUG("ws_process_received_data: frame processed, moving to next frame. Remaining: %d bytes", remaining_len);
+                
+            } else {
+                WS_LOG_DEBUG("ws_process_received_data: invalid payload data - header=%p, payload=%p, payload_len=%zu", 
+                       header, payload, payload_len);
+                return -1;
+            }
+            
+        } else if (ws_stat == WS_STATE_ERROR) {           
+            // 解析错误,重置parser
+            ws_parser_reset(parser);
+        
+            WS_LOG_ERROR("ws_process_received_data: ws_stat == WS_STATE_ERROR parsing error, find next frame. Remaining: %zu bytes", remaining_len);
+            
+        } else {
+             // 数据不完整,继续等待更多数据
+             WS_LOG_DEBUG("ws_process_received_data: frame incomplete, waiting for more data");
+        }
+    }
+    
+    // 检查是否达到循环限制
+    if (loop_count >= max_loops) {
+        WS_LOG_ERROR("ws_process_received_data: reached maximum loop count %zu, forcing exit", max_loops);
+        ws_parser_reset(parser);
+    }
+    
+    WS_LOG_DEBUG("ws_process_received_data: total processed: %d bytes", total_processed);
+    return total_processed;
+}
+
+// 多余的函数已移除,现在只使用一个统一的解析器
+
+/**
+ * @brief WebSocket数据接收线程
+ */
+static void* websocket_receive_thread(void* arg) {
+    WebSocketClient* client = (WebSocketClient*)arg;
+    if (!client || client->sockfd < 0) {
+        WS_LOG_ERROR("websocket_receive_thread: invalid client");
+        return NULL;
+    }
+    
+    WS_LOG_INFO("WebSocket receive thread started for %s:%s", client->host, client->path);
+    
+    uint8_t buffer[4096];  // 接收缓冲区
+    
+    while (client->sockfd >= 0) {
+        // 使用 select 检查数据可用性
+        fd_set read_fds;
+        struct timeval timeout;
+        FD_ZERO(&read_fds);
+        FD_SET(client->sockfd, &read_fds);
+        timeout.tv_sec = 1;  // 1秒超时
+        timeout.tv_usec = 0;
+        
+        int select_result = lwip_select(client->sockfd + 1, &read_fds, NULL, NULL, &timeout);
+        if (select_result < 0) {
+            WS_LOG_ERROR("websocket_receive_thread: select error");
+            break;
+        }
+        
+        if (select_result == 0) {
+            // 超时,继续循环
+            continue;
+        }
+        
+        if (FD_ISSET(client->sockfd, &read_fds)) {
+            // 有数据可读
+            int bytes_received = lwip_recv(client->sockfd, buffer, sizeof(buffer), 0);
+            if (bytes_received <= 0) {
+                WS_LOG_ERROR("websocket_receive_thread: connection closed or error");
+                break;
+            }
+            
+            // 处理接收到的数据
+            int processed = ws_process_received_data(client, buffer, bytes_received);
+            if (processed < 0) {
+                WS_LOG_ERROR("websocket_receive_thread: data processing failed");
+                // 继续接收,不要因为一次解析失败就退出
+            }
+        }
+    }
+    
+    WS_LOG_INFO("WebSocket receive thread ended for %s:%s", client->host, client->path);
+    return NULL;
+}
+
+/**
+ * @brief 启动WebSocket数据接收线程
+ */
+static int start_websocket_receive_thread(WebSocketClient* client) {
+    if (!client) {
+        return -1;
+    }
+    
+    // 创建接收线程
+    osThreadAttr_t thread_attr = {0};
+    thread_attr.name = "ws_recv";
+    thread_attr.stack_size = 4096;
+    thread_attr.priority = osPriorityNormal;
+    
+    osThreadId_t thread_id = osThreadNew((osThreadFunc_t)websocket_receive_thread, client, &thread_attr);
+    if (thread_id == NULL) {
+        WS_LOG_ERROR("Failed to create WebSocket receive thread");
+        return -1;
+    }
+    
+    WS_LOG_INFO("WebSocket receive thread created successfully");
+    return 0;
+}
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
\ No newline at end of file
diff --git a/code/sdk/zhihui/ai_old/zhihui_ws.h b/code/sdk/zhihui/ai_old/zhihui_ws.h
new file mode 100644 (file)
index 0000000..7b5908b
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef ZHIHUI_WS_H_
+#define ZHIHUI_WS_H_
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+////////////////////////// UI 使用接口/////////////////////////////////
+bool init_ai_task(uint8_t type);
+
+bool deinit_ai_task(void);
+
+void uapi_UI_start_asr(uint8_t type);
+
+void uapi_UI_stop_asr(void);
+
+bool uapi_start_tts(void);
+
+void uapi_stop_tts(void);
+
+bool uapi_start_tts_single_txt(char *buf);
+
+void uapi_UI_stop_start_asr_timeout(void);
+
+void ai_cleanup_resources(void);
+typedef enum
+{
+    AI_TYPE_0=0,
+    AI_TYPE_JIU, //九天
+    AI_TYPE_DE, //deepseek
+    AI_TYPE_DOU,//豆包
+    AI_TYPE_WEN,//文心一言
+    AI_TYPE_KIMI,//KIMI
+}G_AI_TYPE;
+
+bool pre_AI_init(void);
+
+
+////////////////////////////////////////////////////////////////////////
+
+void start_send_voice(void);
+
+void tts_server_deinit(void);
+
+void asr_server_deinit(void);
+
+
+void chat_server_deinit(void);
+
+void uapi_set_tts_break(uint8_t data);
+
+uint8_t uapi_get_tts_break(void);
+
+uint8_t get_ai_asr_service_init_flag(void);
+void set_ai_asr_service_init_flag(uint8_t flag);
+uint8_t get_ai_chat_service_init_flag(void);
+void set_ai_chat_service_init_flag(uint8_t flag);
+uint8_t get_ai_tts_server_init_flag(void);
+void set_ai_tts_server_init_flag(uint8_t flag);
+uint32_t get_bk_websocket_tts_tick(void);
+uint8_t get_asr_is_ready_start(void);
+
+void uapi_start_asr_task(void);
+
+void asr_record_test(void);
+
+bool ai_chat_send_txt(uint8_t type,char *msg);
+
+void uapi_start_asr(void);
+
+void uapi_stop_tts(void);
+
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif
\ No newline at end of file