雷鸟添加"设备信息接口"at测试 2201/target/2 2202/1 2202/head 2203/target/1
authorluozheng <1732036298@qq.com>
Wed, 3 Sep 2025 08:24:52 +0000 (16:24 +0800)
committerluozheng <1732036298@qq.com>
Wed, 3 Sep 2025 08:24:52 +0000 (16:24 +0800)
code/sdk/zhihui/leiniao/imsl_ln/leiniao_api_at.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api.h

index 09bfcec..f46655b 100644 (file)
@@ -516,6 +516,17 @@ static uint32_t ln_get_device_token_at(uint8_t *para, uint32_t paraLen, char *st
     return ERRCODE_SUCC;
 }
 
+/* AT^LN_CLEAR_TOKEN */
+//清除设备Token
+static uint32_t ln_clear_device_token_at(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    VAD_UNUSED(para);
+    VAD_UNUSED(paraLen);
+    VAD_UNUSED(strCommonCmd);
+    uapi_ln_clear_device_token();
+    return ERRCODE_SUCC;
+}
+
 // AT^LN_SPEECH_CHAT=deviceId,deviceToken[,audioPath]
 static uint32_t ln_speech_chat_stream_at(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
 {
@@ -586,6 +597,24 @@ static uint32_t ln_story_finish_at(uint8_t *para, uint32_t paraLen, char *strCom
     return ERRCODE_SUCC;
 }
 
+/* 设备-获取角色信息:AT^LN_DEV_CHARACTER */
+static uint32_t ln_device_get_character_at(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    VAD_UNUSED(para); VAD_UNUSED(paraLen); VAD_UNUSED(strCommonCmd);
+    printf("[LN][DEVICE_GET_CHARACTER]\n");
+    do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_GET_CHARACTER, NULL, 0);
+    return ERRCODE_SUCC;
+}
+
+/* 设备-获取绑定用户ID:AT^LN_DEV_USERID */
+static uint32_t ln_device_get_userid_at(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    VAD_UNUSED(para); VAD_UNUSED(paraLen); VAD_UNUSED(strCommonCmd);
+    printf("[LN][DEVICE_GET_USER_ID]\n");
+    do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_GET_USER_ID, NULL, 0);
+    return ERRCODE_SUCC;
+}
+
 
 static const at_cmd_table_t g_ln_api_cmd[] = {
     /* ----------------------------------- VAD ---------------------------------- */
@@ -599,12 +628,15 @@ static const at_cmd_table_t g_ln_api_cmd[] = {
     {(char *)"AT^VAD_HELP", vad_help, (char *)"显示帮助信息"},
     /* ---------------------------------- 雷鸟API --------------------------------- */
     {(char *)"AT^LN_GET_TOKEN", ln_get_device_token_at, (char *)"获取雷鸟设备Token: AT^LN_GET_TOKEN[=deviceId,deviceIccid,deviceModel,deviceVersion]"},
+    {(char *)"AT^LN_CLEAR_TOKEN", ln_clear_device_token_at, (char *)"清除雷鸟设备Token: AT^LN_CLEAR_TOKEN"},
     {(char *)"AT^LN_SPEECH_CHAT", ln_speech_chat_stream_at, (char *)"语音对话流: AT^LN_SPEECH_CHAT"},
     /* 故事相关 AT 指令 */
     {(char *)"AT^LN_STORY_CHOOSE", ln_story_choose_at, (char *)"选择故事(SSE): AT^LN_STORY_CHOOSE=user/story_request.mp3"},
     {(char *)"AT^LN_STORY_RANDOM", ln_story_random_at, (char *)"随机故事(SSE): AT^LN_STORY_RANDOM=童话故事"},
     {(char *)"AT^LN_STORY_EXIT", ln_story_exit_inquiry_at, (char *)"获取退出哄睡询问(JSON): AT^LN_STORY_EXIT"},
     {(char *)"AT^LN_STORY_FINISH", ln_story_finish_at, (char *)"确认结束哄睡(JSON): AT^LN_STORY_FINISH"},
+    {(char *)"AT^LN_DEV_CHARACTER", ln_device_get_character_at, (char *)"获取设备角色信息(JSON,GET): AT^LN_DEV_CHARACTER"},
+    {(char *)"AT^LN_DEV_USERID", ln_device_get_userid_at, (char *)"获取设备绑定用户ID(JSON,GET): AT^LN_DEV_USERID"},
 };
 
 at_cmd_table_t *get_leiniao_api_cmd_table(uint32_t *cmd_count)
index 48e1d7a..0f7f763 100644 (file)
@@ -18,7 +18,7 @@ static unsigned long g_ln_send_queue = 0xFFFFFFFF;
 static unsigned long g_ln_recv_queue = 0xFFFFFFFF;
 
 static char *g_device_id = NULL;
-static char *g_device_token = NULL;
+static char *g_device_token = NULL;//设备token,服务器获取
 static char *g_device_iccid = NULL;
 static char *g_device_model = NULL;
 static char *g_device_version = NULL;
@@ -57,6 +57,16 @@ char *uapi_ln_get_device_token(void)
     }
     return g_device_token;
 }
+/* 清除设备token */
+void uapi_ln_clear_device_token(void)
+{
+    if(g_device_token != NULL)
+    {
+        printf("clear device token\n");
+        free(g_device_token);
+        g_device_token = NULL;
+    }
+}
 
 /* ============================== 雷鸟设备Token获取 ============================== */
 
@@ -71,10 +81,14 @@ char *uapi_ln_get_device_token(void)
 #define LN_STORY_RANDOM_PATH "/v1/story/randomStory"
 #define LN_STORY_EXIT_INQUIRY_PATH "/v1/story/getExitSleepInquiry"
 #define LN_STORY_FINISH_PATH "/v1/story/finishSleepMode"
+#define LN_DEVICE_GET_CHARACTER_PATH "/v1/device/getCharacter"
+#define LN_DEVICE_GET_USER_ID_PATH "/v1/device/getUserId"
 #define LN_STORY_CHOOSE_URL LN_BASE_URL LN_STORY_CHOOSE_PATH
 #define LN_STORY_RANDOM_URL LN_BASE_URL LN_STORY_RANDOM_PATH
 #define LN_STORY_EXIT_INQUIRY_URL LN_BASE_URL LN_STORY_EXIT_INQUIRY_PATH
 #define LN_STORY_FINISH_URL LN_BASE_URL LN_STORY_FINISH_PATH
+#define LN_DEVICE_GET_CHARACTER_URL LN_BASE_URL LN_DEVICE_GET_CHARACTER_PATH
+#define LN_DEVICE_GET_USER_ID_URL LN_BASE_URL LN_DEVICE_GET_USER_ID_PATH
 #define LN_SIGN_SECRET "vDdXVXgPUEUM6_piUjz5AEhMvYTSFzQdPaN-ogKnSus="
 
 /* 生成[a-zA-Z0-9]随机串 */
@@ -525,21 +539,6 @@ static void ln_sse_accumulate_and_dispatch(int cmd, const char *data, int data_l
     }
 }
 
-/* 通用:设置SSE头(deviceId/deviceToken/Accept) */
-static int ln_set_sse_header(HttpClient *client, const char *device_id, const char *device_token)
-{
-    char header_buf[512];
-    int hdr = snprintf(header_buf, sizeof(header_buf),
-        "deviceId: %s\r\n"
-        "deviceToken: %s\r\n"
-        "Accept: text/event-stream\r\n"
-        "Cache-Control: no-cache\r\n",
-        device_id, device_token);
-    if (hdr <= 0 || hdr >= (int)sizeof(header_buf)) return -1;
-    HttpClientSetCustomHeader(client, header_buf);
-    return 0;
-}
-
 /* 故事-选择故事(SSE,multipart)*/
 static uint32_t ln_story_choose_http(const char *device_id,
                                      const char *device_token,
@@ -864,6 +863,7 @@ static uint32_t ln_story_random_http(const char *device_id,
 static uint32_t ln_story_exit_inquiry_http(const char *device_id,
                                            const char *device_token)
 {
+    if (!device_id || !device_token) return ERRCODE_FAIL;
     /* CAT1 保活 */
     cat1_api_add_cat1_vote(); cat1_api_wakeup_cat1(1); cat1_api_keep_wakeup(1); cat1_api_disable_cat1_cmd(0);
 
@@ -926,9 +926,12 @@ static uint32_t ln_story_exit_inquiry_http(const char *device_id,
             }
             free(json_text);
         }
-        do_ln_http_server_recv_data(LN_HTTP_RECV_STORY_EXIT,
-                                   clientData.responseBuf,
-                                   (uint32_t)clientData.responseBufLen);
+        // clientData.responseBufLen 表示的是缓冲区的总大小(提前分配的内存大小),而非实际有效的响应数据长度。
+        // 实际有效的响应数据长度应使用 clientData.responseContentLen(HTTP 响应体的真实长度)。
+        // 当 responseBufLen 大于 responseContentLen 时,responseBuf 中从 responseContentLen 到 responseBufLen 的部分是未使用的内存(可能残留之前的垃圾数据),
+        // 这些数据被当作有效内容传递并打印,导致乱码。
+        int real_len = clientData.responseContentLen > 0 ? clientData.responseContentLen : clientData.responseBufLen;
+        do_ln_http_server_recv_data(LN_HTTP_RECV_STORY_EXIT,clientData.responseBuf,(uint32_t)real_len);
     }
 
 end:
@@ -939,6 +942,7 @@ end:
 static uint32_t ln_story_finish_http(const char *device_id,
                                      const char *device_token)
 {
+    if (!device_id || !device_token) return ERRCODE_FAIL;
     /* CAT1 保活 */
     cat1_api_add_cat1_vote(); cat1_api_wakeup_cat1(1); cat1_api_keep_wakeup(1); cat1_api_disable_cat1_cmd(0);
 
@@ -985,10 +989,10 @@ static uint32_t ln_story_finish_http(const char *device_id,
         goto end;
     }
 
-    if (clientData.responseBuf && clientData.responseBufLen > 0) {
-        do_ln_http_server_recv_data(LN_HTTP_RECV_STORY_FINISH,
-                                   clientData.responseBuf,
-                                   (uint32_t)clientData.responseBufLen);
+    if (clientData.responseBuf && clientData.responseBufLen > 0) 
+    {
+        int real_len = clientData.responseContentLen > 0 ? clientData.responseContentLen : clientData.responseBufLen;
+        do_ln_http_server_recv_data(LN_HTTP_RECV_STORY_FINISH,clientData.responseBuf,(uint32_t)real_len);
     }
 
 end:
@@ -998,6 +1002,124 @@ end:
 /* ============================ 故事相关接口 End ============================ */
 
 
+/* ============================ 设备信息接口 start ============================ */
+/* 设备-获取角色信息(GET, JSON)*/
+static uint32_t ln_device_get_character_http(const char *device_id,
+                                             const char *device_token)
+{
+    if (!device_id || !device_token) return ERRCODE_FAIL;
+
+    /* CAT1 保活 */
+    cat1_api_add_cat1_vote(); cat1_api_wakeup_cat1(1); cat1_api_keep_wakeup(1); cat1_api_disable_cat1_cmd(0);
+
+    HttpClient client = (HttpClient){0}; HttpClientData clientData = (HttpClientData){0};
+    client.isHttp = false; client.remotePort = 443;
+
+    char header_buf[512]; int hdr = snprintf(header_buf, sizeof(header_buf),
+        "deviceId: %s\r\n""deviceToken: %s\r\n""Content-Type: application/json\r\n",
+        device_id, device_token);
+    if (hdr <= 0 || hdr >= (int)sizeof(header_buf)) return ERRCODE_FAIL;
+    HttpClientSetCustomHeader(&client, header_buf);
+
+    HTTPC_RESULT prep = ln_http_prepare_auto(&clientData, 2048, 8 * 1024);
+    if (prep != HTTP_SUCCESS) return ERRCODE_FAIL;
+
+    HTTPC_RESULT res = HttpClientGetRequest(&client, LN_DEVICE_GET_CHARACTER_URL, &clientData);
+    if (res != HTTP_SUCCESS) { printf("device getCharacter get failed %d\n", res); goto end; }
+    if (HttpClientGetResponseCode(&client) != 200) 
+    {
+        printf("device getCharacter HTTP %d\n", HttpClientGetResponseCode(&client));
+        // 解析非200响应中的错误信息
+        if (clientData.responseBuf && clientData.responseBufLen > 0)
+        {
+            char *json_text = (char *)malloc(clientData.responseBufLen + 1);
+            if (json_text)
+            {
+                memcpy(json_text, clientData.responseBuf, clientData.responseBufLen);
+                json_text[clientData.responseBufLen] = '\0';
+                cJSON *root = cJSON_Parse(json_text);
+                if (root)
+                {
+                    cJSON *errorCode = cJSON_GetObjectItem(root, "errorCode");
+                    if (errorCode && cJSON_IsString(errorCode))
+                    {
+                        printf("[STORY_FINISH] Error: %s\n", errorCode->valuestring);
+                    }
+                    cJSON_Delete(root);
+                }
+                free(json_text);
+            }
+        }
+        goto end;
+    }
+
+    if (clientData.responseBuf && clientData.responseBufLen > 0) {
+        int real_len = clientData.responseContentLen > 0 ? clientData.responseContentLen : clientData.responseBufLen;
+        do_ln_http_server_recv_data(LN_HTTP_RECV_DEVICE_CHARACTER, clientData.responseBuf, (uint32_t)real_len);
+    }
+
+end:
+    HttpClientUnprepare(&clientData); HttpClientClse(&client); return ERRCODE_SUCC;
+}
+
+/* 设备-获取绑定用户ID(GET, JSON)*/
+static uint32_t ln_device_get_user_id_http(const char *device_id,
+                                          const char *device_token)
+{
+    if (!device_id || !device_token) return ERRCODE_FAIL;
+
+    /* CAT1 保活 */
+    cat1_api_add_cat1_vote(); cat1_api_wakeup_cat1(1); cat1_api_keep_wakeup(1); cat1_api_disable_cat1_cmd(0);
+
+    HttpClient client = (HttpClient){0}; HttpClientData clientData = (HttpClientData){0};
+    client.isHttp = false; client.remotePort = 443;
+
+    char header_buf[512]; int hdr = snprintf(header_buf, sizeof(header_buf),
+        "deviceId: %s\r\n""deviceToken: %s\r\n""Content-Type: application/json\r\n",
+        device_id, device_token);
+    if (hdr <= 0 || hdr >= (int)sizeof(header_buf)) return ERRCODE_FAIL;
+    HttpClientSetCustomHeader(&client, header_buf);
+
+    HTTPC_RESULT prep = ln_http_prepare_auto(&clientData, 2048, 8 * 1024);
+    if (prep != HTTP_SUCCESS) return ERRCODE_FAIL;
+
+    HTTPC_RESULT res = HttpClientGetRequest(&client, LN_DEVICE_GET_USER_ID_URL, &clientData);
+    if (res != HTTP_SUCCESS) { printf("device getUserId get failed %d\n", res); goto end; }
+    if (HttpClientGetResponseCode(&client) != 200) {
+        printf("device getUserId HTTP %d\n", HttpClientGetResponseCode(&client));
+        // 解析非200响应中的错误信息
+        if (clientData.responseBuf && clientData.responseBufLen > 0)
+        {
+            char *json_text = (char *)malloc(clientData.responseBufLen + 1);
+            if (json_text)
+            {
+                memcpy(json_text, clientData.responseBuf, clientData.responseBufLen);
+                json_text[clientData.responseBufLen] = '\0';
+                cJSON *root = cJSON_Parse(json_text);
+                if (root)
+                {
+                    cJSON *errorCode = cJSON_GetObjectItem(root, "errorCode");
+                    if (errorCode && cJSON_IsString(errorCode))
+                    {
+                        printf("[STORY_FINISH] Error: %s\n", errorCode->valuestring);
+                    }
+                    cJSON_Delete(root);
+                }
+                free(json_text);
+            }
+        }
+        goto end;
+    }
+
+    if (clientData.responseBuf && clientData.responseBufLen > 0) {
+        int real_len = clientData.responseContentLen > 0 ? clientData.responseContentLen : clientData.responseBufLen;
+        do_ln_http_server_recv_data(LN_HTTP_RECV_DEVICE_USER_ID, clientData.responseBuf, (uint32_t)real_len);
+    }
+
+end:
+    HttpClientUnprepare(&clientData); HttpClientClse(&client); return ERRCODE_SUCC;
+}
+/* ============================ 设备信息接口 End ============================ */
 
 
 
@@ -1031,6 +1153,7 @@ static void ln_http_server_send_task(void const *arg)
         {
             if (mail.data != NULL && mail.len == sizeof(ln_speech_chat_req_t))
             {
+                printf("LN_HTTP_SERVICE_CMD_SPEECH_CHAT_STREAM\n");
                 ln_speech_chat_req_t req;
                 memcpy(&req, mail.data, sizeof(req));
                 ln_speech_chat_stream_http(req.device_id, req.device_token, req.audio_path);
@@ -1039,6 +1162,7 @@ static void ln_http_server_send_task(void const *arg)
         else if (mail.cmd == LN_HTTP_SERVICE_CMD_STORY_CHOOSE)
         {
             if (mail.data && mail.len == sizeof(ln_story_choose_req_t)) {
+                printf("LN_HTTP_SERVICE_CMD_STORY_CHOOSE\n");
                 ln_story_choose_req_t req; memcpy(&req, mail.data, sizeof(req));
                 ln_story_choose_http(uapi_ln_get_device_id(), uapi_ln_get_device_token(), req.audio_path);
             }
@@ -1046,18 +1170,31 @@ static void ln_http_server_send_task(void const *arg)
         else if (mail.cmd == LN_HTTP_SERVICE_CMD_STORY_RANDOM)
         {
             if (mail.data && mail.len == sizeof(ln_story_random_req_t)) {
+                printf("LN_HTTP_SERVICE_CMD_STORY_RANDOM\n");
                 ln_story_random_req_t req; memcpy(&req, mail.data, sizeof(req));
                 ln_story_random_http(uapi_ln_get_device_id(), uapi_ln_get_device_token(), req.story_theme[0] ? req.story_theme : NULL);
             }
         }
         else if (mail.cmd == LN_HTTP_SERVICE_CMD_STORY_EXIT_INQUIRY)
         {
+            printf("LN_HTTP_SERVICE_CMD_STORY_EXIT_INQUIRY\n");
             ln_story_exit_inquiry_http(uapi_ln_get_device_id(), uapi_ln_get_device_token());
         }
         else if (mail.cmd == LN_HTTP_SERVICE_CMD_STORY_FINISH)
         {
+            printf("LN_HTTP_SERVICE_CMD_STORY_FINISH\n");
             ln_story_finish_http(uapi_ln_get_device_id(), uapi_ln_get_device_token());
         }
+        else if (mail.cmd == LN_HTTP_SERVICE_CMD_GET_CHARACTER)
+        {
+            printf("LN_HTTP_SERVICE_CMD_GET_CHARACTER\n");
+            ln_device_get_character_http(uapi_ln_get_device_id(), uapi_ln_get_device_token());
+        }
+        else if (mail.cmd == LN_HTTP_SERVICE_CMD_GET_USER_ID)
+        {
+            printf("LN_HTTP_SERVICE_CMD_GET_USER_ID\n");
+            ln_device_get_user_id_http(uapi_ln_get_device_id(), uapi_ln_get_device_token());
+        }
         if (mail.data != NULL)
         {
             printf("free(mail.data)\n");
@@ -1086,7 +1223,9 @@ static void ln_http_server_recv_task(void const *arg)
             || mail.cmd == LN_HTTP_RECV_STORY_CHOOSE
             || mail.cmd == LN_HTTP_RECV_STORY_RANDOM
             || mail.cmd == LN_HTTP_RECV_STORY_EXIT
-            || mail.cmd == LN_HTTP_RECV_STORY_FINISH)
+            || mail.cmd == LN_HTTP_RECV_STORY_FINISH
+            || mail.cmd == LN_HTTP_RECV_DEVICE_CHARACTER
+            || mail.cmd == LN_HTTP_RECV_DEVICE_USER_ID)
         {
             if (mail.data && mail.len)
             {
@@ -1095,7 +1234,9 @@ static void ln_http_server_recv_task(void const *arg)
                                   (mail.cmd == LN_HTTP_RECV_STORY_CHOOSE) ? "STORY_CHOOSE" :
                                   (mail.cmd == LN_HTTP_RECV_STORY_RANDOM) ? "STORY_RANDOM" :
                                   (mail.cmd == LN_HTTP_RECV_STORY_EXIT)   ? "STORY_EXIT"   :
-                                  (mail.cmd == LN_HTTP_RECV_STORY_FINISH) ? "STORY_FINISH" : "UNKNOWN";
+                                  (mail.cmd == LN_HTTP_RECV_STORY_FINISH) ? "STORY_FINISH" :
+                                  (mail.cmd == LN_HTTP_RECV_DEVICE_CHARACTER) ? "DEVICE_CHARACTER" :
+                                  (mail.cmd == LN_HTTP_RECV_DEVICE_USER_ID)  ? "DEVICE_USER_ID" : "UNKNOWN";
                 printf("[%s] SSE raw len=%u\n", tag, mail.len);
                 /* 确保可打印:追加\0 */
                 char *buf = (char *)malloc(mail.len + 1);
index 53b7c5c..9cd6a8d 100644 (file)
@@ -29,6 +29,12 @@ typedef struct
 #define LN_HTTP_RECV_STORY_RANDOM 0x21 /* 故事-随机故事 接收 */
 #define LN_HTTP_RECV_STORY_EXIT   0x22 /* 故事-退出哄睡询问 接收 */
 #define LN_HTTP_RECV_STORY_FINISH 0x23 /* 故事-确认结束哄睡模式 接收 */
+/* 设备信息相关命令 */
+#define LN_HTTP_SERVICE_CMD_GET_CHARACTER 0x30 /* 获取设备角色信息(JSON, GET)*/
+#define LN_HTTP_SERVICE_CMD_GET_USER_ID  0x31 /* 获取设备绑定用户ID(JSON, GET)*/
+/* 设备信息相关接收命令 */
+#define LN_HTTP_RECV_DEVICE_CHARACTER 0x40 /* 设备角色信息 接收 */
+#define LN_HTTP_RECV_DEVICE_USER_ID  0x41 /* 设备绑定用户ID 接收 */
 
 typedef struct
 {
@@ -74,7 +80,8 @@ char *uapi_ln_get_device_model(void);
 char *uapi_ln_get_device_version(void);
 /* 获取设备token */
 char *uapi_ln_get_device_token(void);
-
+/* 清除设备token */
+void uapi_ln_clear_device_token(void);
 #ifdef __cplusplus
 }
 #endif