#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)
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×tampMs=%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)
{
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"},
{(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)
--- /dev/null
+#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);
+ }
+}