1.雷鸟协议设备端at服务搭建,目前是测试阶段,服务默认不开启 2191/1 2191/head 2192/target/1 2193/target/1
authorluozheng <1732036298@qq.com>
Mon, 1 Sep 2025 03:49:57 +0000 (11:49 +0800)
committerluozheng <1732036298@qq.com>
Mon, 1 Sep 2025 03:49:57 +0000 (11:49 +0800)
2.雷鸟协议验证:1.获取设备Token接口,已验证成功

code/sdk/zhihui/leiniao/imsl_ln/CMakeLists.txt
code/sdk/zhihui/leiniao/imsl_ln/leiniao_api_at.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api.c [new file with mode: 0644]
code/sdk/zhihui/leiniao/imsl_ln/ln_api.h [new file with mode: 0644]

index 158fde8..c165ad4 100644 (file)
@@ -8,6 +8,7 @@ set(COMPONENT_NAME "thunderbird_toys")
 set(SOURCES
     ${CMAKE_CURRENT_SOURCE_DIR}/imsl_system_adapter.c
     ${CMAKE_CURRENT_SOURCE_DIR}/leiniao_api_at.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/ln_api.c
 )
 
 # 公共头文件路径(供其他模块引用)
@@ -16,6 +17,7 @@ set(PUBLIC_HEADER
     ${ROOT_DIR}/zhihui/4g/cat1Service/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
+    ${ROOT_DIR}/open_source/openharmony/third_party/cJSON/
 
 )
 
index 5810130..c3c4ab5 100644 (file)
 #include <errno.h>
 #include "imsl_vad.h"
 #include "media_thread_adapt.h"
-#include "http_client.h"
-#include "cat1_pub_api.h"
+#include "ln_api.h"
 
 #define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
 #define VAD_MAX_ARGC 8
 #define VAD_MAX_ARGV_LEN 64
 #define LN_MAX_ARGC 8
-#define LN_MAX_ARGV_LEN 256
+#define LN_MAX_ARGV_LEN 512
 #define VAD_FAILED (-1)
 #define VAD_SUCCESS (0)
 
@@ -465,164 +464,6 @@ static uint32_t vad_cleanup(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
     return ERRCODE_SUCC;
 }
 
-/*
- * 中文说明:打印签名预览,便于 PC 侧用 curl 验证。
- * 用法:AT^LN_SIGN_PREVIEW=DEVICE_001,123456...
- */
-/* 构建签名原始字符串(示例版):按约定拼接关键字段 */
-static void ln_build_sign_data_c(const char *deviceId, const char *iccid, const char *timestampMs, const char *nonce,
-                                 char *out_buf, size_t out_buf_size)
-{
-    if (out_buf == NULL || out_buf_size == 0)
-    {
-        return;
-    }
-    /* 具体拼接规则以雷鸟后台要求为准;这里采用常见的 key=value&key=value 形式 */
-    (void)snprintf(out_buf, out_buf_size,
-                   "deviceId=%s&deviceIccid=%s&timestampMs=%s&nonce=%s",
-                   (deviceId ? deviceId : ""), (iccid ? iccid : ""),
-                   (timestampMs ? timestampMs : ""), (nonce ? nonce : ""));
-}
-
-/* 计算签名(占位实现):真实实现应为 HMAC-SHA256(signData, secret) 输出16进制 */
-static void ln_build_signature_hex_c(const char *sign_data, const char *secret,
-                                     char *out_hex, size_t out_hex_size)
-{
-    (void)sign_data;
-    (void)secret;
-    if (out_hex == NULL || out_hex_size == 0)
-    {
-        return;
-    }
-    /* TODO: 接入实际加密库后替换此占位实现 */
-    (void)snprintf(out_hex, out_hex_size, "%s", "0000000000000000000000000000000000000000000000000000000000000000");
-}
-
-static uint32_t ln_sign_preview(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
-{
-    (void)strCommonCmd;
-    uint8_t argv[VAD_MAX_ARGC][VAD_MAX_ARGV_LEN] = {0};
-    uint32_t argc = 0;
-    if (ConvertCmdToParam(para, paraLen, argv, &argc) != 0 || argc != 2)
-    {
-        printf("用法: AT^LN_SIGN_PREVIEW=<deviceId>,<iccid>\n");
-        return ERRCODE_FAIL;
-    }
-    const char *deviceId = (const char *)argv[0];
-    const char *iccid = (const char *)argv[1];
-
-    /* 注意:示例中时间戳应替换为真实毫秒时间戳,nonce 应为随机字符串 */
-    char ts[32];
-    (void)snprintf(ts, sizeof(ts), "%llu", (unsigned long long)0ULL);
-    const char *nonce = "nonce";
-    const char *signSecret = "vDdXVXgPUEUM6_piUjz5AEhMvYTSFzQdPaN-ogKnSus=";
-
-    char signData[256] = {0};
-    ln_build_sign_data_c(deviceId, iccid, ts, nonce, signData, sizeof(signData));
-    char signature_hex[128] = {0};
-    ln_build_signature_hex_c(signData, signSecret, signature_hex, sizeof(signature_hex));
-
-    printf("signData: %s\n", signData);
-    printf("signature(hex): %s\n", signature_hex);
-    printf("timestamp(ms): %s, nonce: %s\n", ts, nonce);
-    return ERRCODE_SUCC;
-}
-
-/* HTTP 回调:下载结果 */
-static void ln_http_result(void *arg, httpc_result_t httpc_result, u32_t rx_content_len, u32_t srv_res, err_t err)
-{
-    (void)arg;
-    printf("HTTP结束: result=%d, bodyLen=%u, http=%u, err=%d\n", (int)httpc_result, (unsigned)rx_content_len, (unsigned)srv_res, (int)err);
-    // 通讯结束:允许 CAT1 休眠
-    cat1_api_remove_cat1_vote();
-    cat1_api_keep_wakeup(0);
-    cat1_api_wakeup_cat1(0);
-    cat1_api_disable_cat1_cmd(0);
-}
-
-/* HTTP 回调:收到响应头 */
-static err_t ln_http_headers(httpc_state_t *connection, void *arg, struct pbuf *hdr, u16_t hdr_len, u32_t content_len)
-{
-    (void)connection;
-    (void)arg;
-    (void)hdr;
-    printf("HTTP头: hdr_len=%u content_len=%u\n", (unsigned)hdr_len, (unsigned)content_len);
-    return 0;
-}
-
-/* HTTP 回调:接收到 body 数据(增量打印前 512 字节以内) */
-static err_t ln_http_body(httpc_state_t *connection, u32_t rx_len, u32_t rx_total_len)
-{
-    (void)connection;
-    (void)rx_len;
-    printf("HTTP body 收到: total=%u\n", (unsigned)rx_total_len);
-    return 0;
-}
-
-/*
- * 中文说明:获取设备 Token 的 AT 指令。
- * 用法:AT^LN_GET_TOKEN=<deviceId>,<iccid>
- * 步骤:
- * 1) 生成 timestamp(毫秒)、nonce(随机) 和签名 signature
- * 2) 唤醒 CAT1,发起 HTTP GET(当前走 80 端口便于调试;TLS 需另行使能)
- * 3) 串口打印 HTTP 状态码与 body 接收进度
- */
-static uint32_t ln_get_token(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
-{
-    (void)strCommonCmd;
-    uint8_t argv[VAD_MAX_ARGC][VAD_MAX_ARGV_LEN] = {0};
-    uint32_t argc = 0;
-    if (ConvertCmdToParam(para, paraLen, argv, &argc) != 0 || argc != 2)
-    {
-        printf("用法: AT^LN_GET_TOKEN=<deviceId>,<iccid>\n");
-        return ERRCODE_FAIL;
-    }
-    const char *deviceId = (const char *)argv[0];
-    const char *iccid = (const char *)argv[1];
-
-    // 1) 生成签名参数
-    char ts[32];
-    (void)snprintf(ts, sizeof(ts), "%llu", (unsigned long long)0ULL); // TODO: 替换为真实毫秒
-    const char *nonce = "nonce";                                      // TODO: 替换为随机数
-    const char *signSecret = "vDdXVXgPUEUM6_piUjz5AEhMvYTSFzQdPaN-ogKnSus=";
-    char signData[256] = {0};
-    ln_build_sign_data_c(deviceId, iccid, ts, nonce, signData, sizeof(signData));
-    char signature_hex[128] = {0};
-    ln_build_signature_hex_c(signData, signSecret, signature_hex, sizeof(signature_hex));
-
-    // 2) 组装 HTTP 请求
-    httpc_connection_t settings = {0};
-    settings.result_fn = ln_http_result;
-    settings.headers_done_fn = ln_http_headers;
-    settings.file_rx_fn = ln_http_body;
-    settings.use_post = 0;
-
-    const char *server = "ambybox-api.test.leiniao.com";
-    uint16_t port = 80; // 调试用;如需 TLS,请切到 443 并配置 altcp_tls
-    const char *uri = "/ambybox-device-api/v1/auth/getDeviceToken";
-
-    printf("开始获取 Token: %s %s\n", deviceId, iccid);
-    cat1_api_add_cat1_vote();
-    cat1_api_wakeup_cat1(1);
-    cat1_api_keep_wakeup(1);
-    cat1_api_disable_cat1_cmd(1);
-
-    httpc_state_t *connection = NULL;
-    err_t rett = httpc_get_file_dns(server, port, uri, &settings, NULL, NULL, &connection);
-    if (rett != ERRCODE_SUCC)
-    {
-        printf("HTTP 启动失败: %d\n", (int)rett);
-        // 失败也释放 CAT1 约束
-        cat1_api_remove_cat1_vote();
-        cat1_api_keep_wakeup(0);
-        cat1_api_wakeup_cat1(0);
-        cat1_api_disable_cat1_cmd(0);
-        return ERRCODE_FAIL;
-    }
-    printf("HTTP 已发起,等待回调...\n");
-    return ERRCODE_SUCC;
-}
-
 // AT^VAD_HELP - 显示帮助信息
 static uint32_t vad_help(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
 {
@@ -652,6 +493,30 @@ static uint32_t vad_help(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
     return ERRCODE_SUCC;
 }
 
+/* AT^LN_GET_TOKEN[=deviceId,deviceIccid,deviceModel,deviceVersion] */
+//获取设备Token
+static uint32_t ln_get_device_token_at(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    VAD_UNUSED(strCommonCmd);
+    uint8_t argv[LN_MAX_ARGC][LN_MAX_ARGV_LEN] = {0};
+    uint32_t argc = 0;
+    (void)ConvertCmdToParam(para, paraLen, argv, &argc);
+
+    const char *device_id = (argc >= 1) ? (const char *)argv[0] : "DEVICE_PC_TEST_001";
+    const char *device_iccid = (argc >= 2) ? (const char *)argv[1] : "86123456789012345678";
+    const char *device_model = (argc >= 3) ? (const char *)argv[2] : "abmybox_1";
+    const char *device_ver = (argc >= 4) ? (const char *)argv[3] : "1.0.0";
+    printf("[LN] GetDeviceToken start id=%s iccid=%s\n", device_id, device_iccid);
+    ln_device_token_req_t req = {0};
+    strcpy(req.device_id, device_id);
+    strcpy(req.device_iccid, device_iccid);
+    strcpy(req.device_model, device_model);
+    strcpy(req.device_version, device_ver);
+    do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_GET_DEVICE_TOKEN, (char *)&req, sizeof(req));
+    return ERRCODE_SUCC;
+}
+
+
 static const at_cmd_table_t g_ln_api_cmd[] = {
     /* ----------------------------------- VAD ---------------------------------- */
     {(char *)"AT^VAD_INIT", vad_init, (char *)"初始化 VAD"},
@@ -663,8 +528,7 @@ static const at_cmd_table_t g_ln_api_cmd[] = {
     {(char *)"AT^VAD_CLEANUP", vad_cleanup, (char *)"清理 VAD 资源"},
     {(char *)"AT^VAD_HELP", vad_help, (char *)"显示帮助信息"},
     /* ---------------------------------- 雷鸟API --------------------------------- */
-    {(char *)"AT^LN_SIGN_PREVIEW", ln_sign_preview, (char *)"签名预览: 参数=deviceId,iccid"},
-    {(char *)"AT^LN_GET_TOKEN", ln_get_token, (char *)"获取设备Token: 参数=deviceId,iccid"},
+    {(char *)"AT^LN_GET_TOKEN", ln_get_device_token_at, (char *)"获取雷鸟设备Token: AT^LN_GET_TOKEN[=deviceId,deviceIccid,deviceModel,deviceVersion]"},
 };
 
 at_cmd_table_t *get_leiniao_api_cmd_table(uint32_t *cmd_count)
diff --git a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c
new file mode 100644 (file)
index 0000000..0cf227e
--- /dev/null
@@ -0,0 +1,373 @@
+#include "ln_api.h"
+/* for https/http client */
+#include "netstack/http/include/httpclient.h"
+/* for HMAC-SHA256 */
+#include "mbedtls/md.h"
+/* for JSON parsing */
+#include "cJSON.h"
+#include <thread_init.h>
+#include <osal_msgqueue.h>
+#include <soc_osal.h>
+
+static app_task_definition_t ln_send_taskcfg = {0};
+static app_task_definition_t ln_recv_taskcfg = {0};
+#define LN_HTTP_BOARD_TASK_SIZE 0x2000
+
+static unsigned long g_ln_send_queue = 0xFFFFFFFF;
+static unsigned long g_ln_recv_queue = 0xFFFFFFFF;
+
+/* ============================== 雷鸟设备Token获取 ============================== */
+
+/* 接口基础配置 - 如需切换环境/密钥,在此调整 */
+#define LN_BASE_URL "https://ambybox-api.test.leiniao.com/ambybox-device-api"
+#define LN_INTERFACE_PATH "/v1/auth/getDeviceToken"
+#define LN_FULL_URL LN_BASE_URL LN_INTERFACE_PATH
+#define LN_SIGN_SECRET "vDdXVXgPUEUM6_piUjz5AEhMvYTSFzQdPaN-ogKnSus="
+
+/* 生成[a-zA-Z0-9]随机串 */
+static void ln_gen_nonce(char *out, size_t len)
+{
+    static const char table[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+    if (out == NULL || len == 0)
+    {
+        return;
+    }
+    /* 使用时间作为随机种子,避免强依赖标准rand种子 */
+    uint32_t ts_s = 0;
+    uapi_get_timestampe_ss(&ts_s);
+    srand((unsigned int)(ts_s ^ (unsigned int)uapi_tcxo_get_ms()));
+    for (size_t i = 0; i + 1 < len; i++)
+    {
+        out[i] = table[rand() % (sizeof(table) - 1)];
+    }
+    out[len - 1] = '\0';
+}
+
+static void ln_to_hex_lower(const uint8_t *in, size_t in_len, char *out)
+{
+    static const char hex[] = "0123456789abcdef";
+    for (size_t i = 0; i < in_len; i++)
+    {
+        out[i * 2] = hex[(in[i] >> 4) & 0x0F];
+        out[i * 2 + 1] = hex[in[i] & 0x0F];
+    }
+    out[in_len * 2] = '\0';
+}
+
+/* 计算 HMAC-SHA256 并输出小写hex字符串 */
+static int ln_hmac_sha256_hex(const char *key, const char *msg, char *out_hex, size_t out_hex_size)
+{
+    if (out_hex_size < 65)
+    { /* 32 bytes -> 64 hex chars + NUL */
+        return -1;
+    }
+    const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
+    if (md_info == NULL)
+    {
+        return -1;
+    }
+    uint8_t digest[32];
+    int ret = mbedtls_md_hmac(md_info, (const unsigned char *)key, strlen(key),
+                              (const unsigned char *)msg, strlen(msg), digest);
+    if (ret != 0)
+    {
+        return -1;
+    }
+    ln_to_hex_lower(digest, sizeof(digest), out_hex);
+    return 0;
+}
+
+/* 发送HTTPS GET请求,携带定制Header,解析返回token */
+static uint32_t ln_get_device_token_http(const char *device_id,
+                                         const char *device_iccid,
+                                         const char *device_model,
+                                         const char *device_version)
+{
+    if (device_id == NULL || device_iccid == NULL)
+    {
+        printf("LN token: invalid parameters\n");
+        return ERRCODE_FAIL;
+    }
+
+    /* 1. 生成时间戳(ms)与nonce */
+    uint32_t ts_s = 0; /* epoch seconds */
+    uapi_get_timestampe_ss(&ts_s);
+    char timestamp[32] = {0};
+    (void)snprintf(timestamp, sizeof(timestamp), "%u000", ts_s); /* 转毫秒字符串 */
+
+    char nonce[17] = {0}; /* 12~16位,取固定16以简化 */
+    ln_gen_nonce(nonce, sizeof(nonce));
+
+    /* 2. 计算签名: deviceId:deviceIccid:timestamp:nonce */
+    char sign_data[256] = {0};
+    (void)snprintf(sign_data, sizeof(sign_data), "%s:%s:%s:%s", device_id, device_iccid, timestamp, nonce);
+    char signature[65] = {0};
+    if (ln_hmac_sha256_hex(LN_SIGN_SECRET, sign_data, signature, sizeof(signature)) != 0)
+    {
+        printf("LN token: hmac calc failed\n");
+        return ERRCODE_FAIL;
+    }
+
+    /* 3. 组织自定义请求头 */
+    char header_buf[1024] = {0};
+    int hdr_len = snprintf(header_buf, sizeof(header_buf),
+                           "deviceId: %s\r\n"
+                           "deviceIccid: %s\r\n"
+                           "timestamp: %s\r\n"
+                           "nonce: %s\r\n"
+                           "signature: %s\r\n"
+                           "deviceModel: %s\r\n"
+                           "deviceVersion: %s\r\n"
+                           "Content-Type: application/json\r\n",
+                           device_id, device_iccid, timestamp, nonce, signature,
+                           (device_model && device_model[0]) ? device_model : "abmybox_1",
+                           (device_version && device_version[0]) ? device_version : "1.0.0");
+    if (hdr_len <= 0 || hdr_len >= (int)sizeof(header_buf))
+    {
+        printf("LN token: header build failed\n");
+        return ERRCODE_FAIL;
+    }
+
+    /* 4. 保活CAT1,准备网络 */
+    cat1_api_add_cat1_vote();
+    cat1_api_wakeup_cat1(1);
+    cat1_api_keep_wakeup(1);
+    cat1_api_disable_cat1_cmd(1);
+    LOS_Msleep(500);
+
+    /* 5. 发起HTTPS GET */
+    HttpClient client = (HttpClient){0};
+    HttpClientData clientData = (HttpClientData){0};
+    client.isHttp = false; /* https */
+    client.remotePort = 443;
+    HttpClientSetCustomHeader(&client, header_buf);
+
+    HTTPC_RESULT prep = HttpClientPrepare(&clientData, 2048, 4096);
+    if (prep != HTTP_SUCCESS)
+    {
+        printf("LN token: HttpClientPrepare failed %d\n", prep);
+        return ERRCODE_FAIL;
+    }
+
+    HTTPC_RESULT res = HttpClientGetRequest(&client, LN_FULL_URL, &clientData);
+    if (res != HTTP_SUCCESS)
+    {
+        printf("LN token: request failed %d\n", res);
+        HttpClientUnprepare(&clientData);
+        HttpClientClse(&client);
+        return ERRCODE_FAIL;
+    }
+
+    int code = HttpClientGetResponseCode(&client);
+    if (code != 200)
+    {
+        printf("LN token: HTTP %d\n", code);
+        HttpClientUnprepare(&clientData);
+        HttpClientClse(&client);
+        return ERRCODE_FAIL;
+    }
+
+    /* 6. 解析响应JSON */
+    if (clientData.responseBuf == NULL || clientData.responseBufLen <= 0)
+    {
+        printf("LN token: empty body\n");
+        HttpClientUnprepare(&clientData);
+        HttpClientClse(&client);
+        return ERRCODE_FAIL;
+    }
+
+    int body_len = clientData.responseContentLen > 0 ? clientData.responseContentLen : clientData.responseBufLen;
+    if (body_len <= 0)
+        body_len = (int)strlen(clientData.responseBuf);
+
+    char *json_text = (char *)malloc((size_t)body_len + 1);
+    if (json_text == NULL)
+    {
+        HttpClientUnprepare(&clientData);
+        HttpClientClse(&client);
+        return ERRCODE_FAIL;
+    }
+    memcpy(json_text, clientData.responseBuf, (size_t)body_len);
+    json_text[body_len] = '\0';
+
+    cJSON *root = cJSON_Parse(json_text);
+    if (!root)
+    {
+        printf("LN token: JSON parse failed\n");
+        free(json_text);
+        HttpClientUnprepare(&clientData);
+        HttpClientClse(&client);
+        return ERRCODE_FAIL;
+    }
+
+    cJSON *errorCode = cJSON_GetObjectItem(root, "errorCode");
+    if (errorCode != NULL && !cJSON_IsNull(errorCode))
+    {
+        cJSON *msg = cJSON_GetObjectItem(root, "message");
+        printf("LN token: failed, err=%s\n", msg && cJSON_IsString(msg) ? msg->valuestring : "unknown");
+        cJSON_Delete(root);
+        free(json_text);
+        HttpClientUnprepare(&clientData);
+        HttpClientClse(&client);
+        return ERRCODE_FAIL;
+    }
+
+    cJSON *data = cJSON_GetObjectItem(root, "data");
+    if (data && cJSON_IsObject(data))
+    {
+        cJSON *token = cJSON_GetObjectItem(data, "token");
+        cJSON *expire = cJSON_GetObjectItem(data, "expireTime");
+        printf("LN Device Token: %s\n", (token && cJSON_IsString(token)) ? token->valuestring : "<null>");
+        if (expire && cJSON_IsNumber(expire))
+        {
+            printf("Token expireTime: %lld\n", (long long)expire->valuedouble);
+        }
+    }
+    else
+    {
+        printf("LN token: no data field\n");
+    }
+
+    cJSON_Delete(root);
+    free(json_text);
+    HttpClientUnprepare(&clientData);
+    HttpClientClse(&client);
+    return ERRCODE_SUCC;
+}
+
+/* ============================ 雷鸟设备Token获取 End ============================ */
+
+// 发送队列
+static void ln_http_server_send_task(void const *arg)
+{
+    errcode_t ret;
+
+    ln_http_data_mail_t mail = {0};
+    uint32_t msgsize = sizeof(ln_http_data_mail_t);
+
+    while (1)
+    {
+        ret = osal_msg_queue_read_copy(g_ln_send_queue, (void *)&mail, &msgsize,
+                                       OSAL_MSGQ_WAIT_FOREVER);
+        if (ret != OSAL_SUCCESS)
+        {
+            continue;
+        }
+        if (mail.cmd == LN_HTTP_SERVICE_CMD_GET_DEVICE_TOKEN)
+        {
+            if (mail.data != NULL && mail.len == sizeof(ln_device_token_req_t))
+            {
+                printf("LN_HTTP_SERVICE_CMD_GET_DEVICE_TOKEN\n");
+                ln_device_token_req_t req;
+                memcpy(&req, mail.data, sizeof(req));
+                ln_get_device_token_http(req.device_id, req.device_iccid, req.device_model, req.device_version);
+            }
+        }
+        if (mail.data != NULL)
+        {
+            printf("free(mail.data)\n");
+            free(mail.data);
+        }
+    }
+}
+
+// 接收队列
+static void ln_http_server_recv_task(void const *arg)
+{
+    errcode_t ret;
+
+    ln_http_data_mail_t mail = {0};
+    uint32_t msgsize = sizeof(ln_http_data_mail_t);
+
+    while (1)
+    {
+        ret = osal_msg_queue_read_copy(g_ln_recv_queue, (void *)&mail, &msgsize,
+                                       OSAL_MSGQ_WAIT_FOREVER);
+        if (ret != OSAL_SUCCESS)
+        {
+            continue;
+        }
+    }
+}
+
+static void create_ln_http_send_queue(void)
+{
+    if (osal_msg_queue_create("ln_http_send_queue", 24, &g_ln_send_queue,
+                              0, sizeof(ln_http_data_mail_t)) != ERRCODE_SUCC)
+    {
+        printf("[ln][service] app create mail fail\n");
+    }
+}
+
+static void create_ln_http_recv_queue(void)
+{
+    if (osal_msg_queue_create("ln_http_recv_queue", 24, &g_ln_recv_queue,
+                              0, sizeof(ln_http_data_mail_t)) != ERRCODE_SUCC)
+    {
+        printf("[ln][service] app create mail fail\n");
+    }
+}
+
+// 雷鸟http服务初始化
+errcode_t uapi_ln_http_server_init(void)
+{
+    printf("uapi_ln_http_server_init !\r\n");
+
+    ln_send_taskcfg.create_queue_handle = create_ln_http_send_queue;
+    ln_send_taskcfg.attr.name = "ln_http_server_send_task";
+    ln_send_taskcfg.attr.priority = osPriorityNormal;
+    ln_send_taskcfg.attr.stack_size = LN_HTTP_BOARD_TASK_SIZE;
+    ln_send_taskcfg.func = ln_http_server_send_task;
+    ln_send_taskcfg.use_mem = USE_EXTEND_MEM;
+
+    errcode_t ret = uapi_create_osThread_custom(&ln_send_taskcfg);
+    if (ret != ERRCODE_SUCC)
+    {
+        printf("create ln_send_service failed %d!\r\n", ret);
+        return ERRCODE_FAIL;
+    }
+
+    ln_recv_taskcfg.create_queue_handle = create_ln_http_recv_queue;
+    ln_recv_taskcfg.attr.name = "ln_http_server_recv_task";
+    ln_recv_taskcfg.attr.priority = osPriorityNormal;
+    ln_recv_taskcfg.attr.stack_size = LN_HTTP_BOARD_TASK_SIZE;
+    ln_recv_taskcfg.func = ln_http_server_recv_task;
+    ln_recv_taskcfg.use_mem = USE_EXTEND_MEM;
+
+    ret = uapi_create_osThread_custom(&ln_recv_taskcfg);
+    if (ret != ERRCODE_SUCC)
+    {
+        printf("create gnss_recv_service failed %d!\r\n", ret);
+        return ERRCODE_FAIL;
+    }
+
+    return ERRCODE_SUCC;
+}
+
+/* 通用发送接口:向 LN HTTP 发送队列投递消息 */
+void do_ln_http_server_send_data(int cmd, char *data, uint32_t len)
+{
+    errcode_t ret;
+    ln_http_data_mail_t send_data = {0};
+    send_data.cmd = cmd;
+    if (len && data)
+    {
+        send_data.len = len;
+        send_data.data = (char *)malloc(len);
+        if (send_data.data == NULL)
+        {
+            printf("malloc failed\n");
+            return;
+        }
+        memcpy(send_data.data, data, len);
+    }
+
+    uint32_t send_len = sizeof(send_data);
+
+    ret = osal_msg_queue_write_copy(g_ln_send_queue, (void *)&send_data,
+                                    send_len, 0);
+    if (ret != OSAL_SUCCESS)
+    {
+        printf("Error ln http send failed! err=0x%x! \r\n", ret);
+    }
+}
diff --git a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.h b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.h
new file mode 100644 (file)
index 0000000..33a9939
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef LN_API_H
+#define LN_API_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "stdint.h"
+#include "errcode.h"
+
+typedef struct
+{
+    int cmd;
+    char *data;
+    uint32_t len;
+} ln_http_data_mail_t;
+
+#define LN_HTTP_SERVICE_CMD_GET_DEVICE_TOKEN 0x1
+
+typedef struct
+{
+    char device_id[64];
+    char device_iccid[32];
+    char device_model[32];
+    char device_version[16];
+} ln_device_token_req_t;
+
+errcode_t uapi_ln_http_server_init(void);
+
+/* 通用发送接口:向 LN HTTP 发送队列投递消息 */
+void do_ln_http_server_send_data(int cmd, char *data, uint32_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LN_API_H */