#define LN_HTTP_BOARD_TASK_SIZE 0x2500
static char *s_cached_device_id = NULL;
-char *g_device_token = NULL;//设备token,服务器获取
+char *g_device_token = NULL; // 设备token,服务器获取
static char *s_cached_device_iccid = NULL;
static char *g_device_model = NULL;
static char g_device_version[128] = {0};
char *g_ln_last_target_version = NULL; // 最近一次查询到的 OTA 包目标版本(动态分配)
char *g_ln_last_package_md5 = NULL; // 最近一次查询到的 OTA 包 MD5(动态分配)
int g_ln_last_package_size = 0; // 最近一次查询到的 OTA 包大小(字节)
-int g_ln_is_device_bound = 0; /* 设备绑定状态 */
+int g_ln_is_device_bound = 0; /* 设备绑定状态 */
char g_ln_device_user_id[64] = {0}; // 设备绑定用户ID
static int g_ln_is_file_downloading = 0; // 是否正在下载文件
/* 简单的字符串读写(以.bin形式读写原始字节,末尾补'\0')*/
static int ln_read_string_file(const char *file_path, char **out_str)
{
- if (out_str) *out_str = NULL;
- if (!file_path || !out_str) return -1;
- FILE *fp = fopen(file_path, "rb");
- if (!fp) return -1;
- if (fseek(fp, 0, SEEK_END) != 0) { fclose(fp); return -1; }
- long len = ftell(fp);
- if (len <= 0 || len > 4096) { fclose(fp); return -1; }
- if (fseek(fp, 0, SEEK_SET) != 0) { fclose(fp); return -1; }
- char *buf = (char*)malloc((size_t)len + 1);
- if (!buf) { fclose(fp); return -1; }
- size_t n = fread(buf, 1, (size_t)len, fp);
- fclose(fp);
- buf[n] = '\0';
- *out_str = buf;
- return 0;
+ if (out_str)
+ *out_str = NULL;
+ if (!file_path || !out_str)
+ return -1;
+ FILE *fp = fopen(file_path, "rb");
+ if (!fp)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[READ_STRING_FILE] fopen failed");
+ return -1;
+ }
+ if (fseek(fp, 0, SEEK_END) != 0)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[READ_STRING_FILE] fseek failed, SEEK_END");
+ fclose(fp);
+ return -1;
+ }
+ long len = ftell(fp);
+ if (len <= 0 || len > 4096)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[READ_STRING_FILE] len <= 0 or len > 4096");
+ fclose(fp);
+ return -1;
+ }
+ if (fseek(fp, 0, SEEK_SET) != 0)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[READ_STRING_FILE] fseek failed, SEEK_SET");
+ fclose(fp);
+ return -1;
+ }
+ char *buf = (char *)malloc((size_t)len + 1);
+ if (!buf)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[READ_STRING_FILE] malloc failed");
+ fclose(fp);
+ return -1;
+ }
+ size_t n = fread(buf, 1, (size_t)len, fp);
+ if (n != (size_t)len)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[READ_STRING_FILE] fread failed, len=%zu, expected=%d", n, len);
+ free(buf);
+ fclose(fp);
+ return -1;
+ }
+ fclose(fp);
+ buf[n] = '\0';
+ *out_str = buf;
+ return 0;
}
static int ln_write_string_file(const char *file_path, const char *str)
{
- if (!file_path || !str) return -1;
- /* 确保目录存在 */
- uapi_create_folder((char*)LN_DATA_PATH);
- FILE *fp = fopen(file_path, "wb");
- if (!fp) return -1;
- size_t len = strlen(str);
- /* 写入原始字节(不强制写入'\0')*/
- size_t n = fwrite(str, 1, len, fp);
- fclose(fp);
- return (n == len) ? 0 : -1;
+ if (!file_path || !str)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[WRITE_STRING_FILE] file_path or str is NULL");
+ return -1;
+ }
+ /* 确保目录存在 */
+ uapi_create_folder((char *)LN_DATA_PATH);
+ FILE *fp = fopen(file_path, "wb");
+ if (!fp)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[WRITE_STRING_FILE] fopen failed");
+ return -1;
+ }
+ size_t len = strlen(str);
+ /* 写入原始字节(不强制写入'\0')*/
+ size_t n = fwrite(str, 1, len, fp);
+ if (n != len)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[WRITE_STRING_FILE] fwrite failed");
+ fclose(fp);
+ return -1;
+ }
+ fclose(fp);
+ return (n == len) ? 0 : -1;
}
/* 获取设备id: 优先读本地缓存文件 /user/userdata/leiniao/device_id.bin*/
{
// return "DEVICE_PC_TEST_001";
- if (s_cached_device_id && s_cached_device_id[0]) {
+ if (s_cached_device_id && s_cached_device_id[0])
+ {
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "device_id cached: %s", s_cached_device_id);
- return s_cached_device_id;
- }
- /* 1. 尝试从文件读取 */
- char *loaded = NULL;
- if (ln_read_string_file(LN_DEVICE_ID_FILE, &loaded) == 0 && loaded && loaded[0]) {
- s_cached_device_id = loaded; /* 接管指针 */
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "device_id loaded from %s: %s", LN_DEVICE_ID_FILE, s_cached_device_id);
- return s_cached_device_id;
- }
- if (loaded) free(loaded);
- /* 2. 文件不存在或读取失败,则通过CAT1获取并落盘 */
- char *imei = cat1_api_runtime_get_cat1_imei();
- if (imei && imei[0]) {
- (void)ln_write_string_file(LN_DEVICE_ID_FILE, imei);
- size_t tlen = strlen(imei);
- s_cached_device_id = (char*)malloc(tlen + 1);
- if (s_cached_device_id) memcpy(s_cached_device_id, imei, tlen + 1);
- return s_cached_device_id;
- }
- return NULL;
+ return s_cached_device_id;
+ }
+ /* 1. 尝试从文件读取 */
+ char *loaded = NULL;
+ if (ln_read_string_file(LN_DEVICE_ID_FILE, &loaded) == 0 && loaded && loaded[0])
+ {
+ s_cached_device_id = loaded; /* 接管指针 */
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "device_id loaded from %s: %s", LN_DEVICE_ID_FILE, s_cached_device_id);
+ return s_cached_device_id;
+ }
+ if (loaded)
+ free(loaded);
+ /* 2. 文件不存在或读取失败,则通过CAT1获取并落盘 */
+ char *imei = cat1_api_runtime_get_cat1_imei();
+ if (imei && imei[0])
+ {
+ (void)ln_write_string_file(LN_DEVICE_ID_FILE, imei);
+ size_t tlen = strlen(imei);
+ s_cached_device_id = (char *)malloc(tlen + 1);
+ if (s_cached_device_id)
+ memcpy(s_cached_device_id, imei, tlen + 1);
+ return s_cached_device_id;
+ }
+ return NULL;
}
/* 获取设备iccid: 优先读本地缓存文件 /user/userdata/leiniao/device_iccid.bin,不存在则调用CAT1接口并落盘 */
char *uapi_ln_get_device_iccid(void)
{
- if (s_cached_device_iccid && s_cached_device_iccid[0]) {
- return s_cached_device_iccid;
- }
- /* 1. 尝试从文件读取 */
- char *loaded = NULL;
- if (ln_read_string_file(LN_DEVICE_ICCID_FILE, &loaded) == 0 && loaded && loaded[0]) {
- s_cached_device_iccid = loaded; /* 接管指针 */
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "device_iccid loaded from %s: %s", LN_DEVICE_ICCID_FILE, s_cached_device_iccid);
- return s_cached_device_iccid;
- }
- if (loaded) free(loaded);
- /* 2. 文件不存在或读取失败,则通过CAT1获取并落盘 */
- char *iccid = cat1_api_runtime_get_cat1_iccid();
- if (iccid && iccid[0]) {
- (void)ln_write_string_file(LN_DEVICE_ICCID_FILE, iccid);
- size_t tlen = strlen(iccid);
- s_cached_device_iccid = (char*)malloc(tlen + 1);
- if (s_cached_device_iccid) memcpy(s_cached_device_iccid, iccid, tlen + 1);
- return s_cached_device_iccid;
- }
- return NULL;
+ if (s_cached_device_iccid && s_cached_device_iccid[0])
+ {
+ return s_cached_device_iccid;
+ }
+ /* 1. 尝试从文件读取 */
+ char *loaded = NULL;
+ if (ln_read_string_file(LN_DEVICE_ICCID_FILE, &loaded) == 0 && loaded && loaded[0])
+ {
+ s_cached_device_iccid = loaded; /* 接管指针 */
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "device_iccid loaded from %s: %s", LN_DEVICE_ICCID_FILE, s_cached_device_iccid);
+ return s_cached_device_iccid;
+ }
+ if (loaded)
+ free(loaded);
+ /* 2. 文件不存在或读取失败,则通过CAT1获取并落盘 */
+ char *iccid = cat1_api_runtime_get_cat1_iccid();
+ if (iccid && iccid[0])
+ {
+ (void)ln_write_string_file(LN_DEVICE_ICCID_FILE, iccid);
+ size_t tlen = strlen(iccid);
+ s_cached_device_iccid = (char *)malloc(tlen + 1);
+ if (s_cached_device_iccid)
+ memcpy(s_cached_device_iccid, iccid, tlen + 1);
+ return s_cached_device_iccid;
+ }
+ return NULL;
}
/* 获取设备model */
char *uapi_ln_get_device_model(void)
char *uapi_ln_get_device_version(void)
{
char version_buf[128] = {0};
- uint32_t version_len = sizeof(version_buf) - 1; // 预留1字节给字符串结束符
+ uint32_t version_len = sizeof(version_buf) - 1; // 预留1字节给字符串结束符
uapi_get_buildversion((uint8_t *)version_buf, version_len);
-
+
// 原始格式:V1.0.0_20250920_222554,目标:V1.0.0_20250920
// 步骤1:找到第一个下划线(分隔版本号和日期)
char *first_underline = strstr(version_buf, "_");
- if (!first_underline) {
+ if (!first_underline)
+ {
// 无下划线,直接使用原始版本号(异常情况处理)
snprintf(g_device_version, sizeof(g_device_version), "%s", version_buf);
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"g_device_version (no underline): %s", g_device_version);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "g_device_version (no underline): %s", g_device_version);
return g_device_version;
}
-
+
// 步骤2:找到第二个下划线(分隔日期和时间)
char *second_underline = strstr(first_underline + 1, "_");
- if (!second_underline) {
+ if (!second_underline)
+ {
// 只有一个下划线(如 "V1.0.0_20250920"),直接使用
snprintf(g_device_version, sizeof(g_device_version), "%s", version_buf);
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"g_device_version (only one underline): %s", g_device_version);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "g_device_version (only one underline): %s", g_device_version);
return g_device_version;
}
-
+
// 步骤3:截断第二个下划线后的内容(保留版本号+日期)
- size_t target_len = second_underline - version_buf; // 计算目标字符串长度(不含时间)
- if (target_len >= sizeof(g_device_version)) {
+ size_t target_len = second_underline - version_buf; // 计算目标字符串长度(不含时间)
+ if (target_len >= sizeof(g_device_version))
+ {
// 防止缓冲区溢出,取最大可容纳长度
target_len = sizeof(g_device_version) - 1;
}
-
+
// 复制并构造目标格式字符串
strncpy(g_device_version, version_buf, target_len);
- g_device_version[target_len] = '\0'; // 手动添加字符串结束符
-
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"g_device_version: %s", g_device_version);
+ g_device_version[target_len] = '\0'; // 手动添加字符串结束符
+
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "g_device_version: %s", g_device_version);
return g_device_version;
}
/* 获取设备token: 优先读本地缓存,判断过期,否则刷新 */
{
// return "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJXWVNaIiwiZGV2aWNlTW9kZWwiOiJhYm15Ym94XzEiLCJkZXZpY2VWZXJzaW9uIjoiMS4wLjAiLCJkZXZpY2VJZCI6IkRFVklDRV9QQ19URVNUXzAwMSIsImV4cCI6MTc2MTQ2MjQ5Mn0.Oeyu8BDopDTvtAcdNpzz46U2w1UwzEzqcvPwD3Dp08Y";
/* 若内存已有且非占位,直接返回 */
- if (g_device_token && strcmp(g_device_token, "<null>") != 0) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"uapi_ln_get_device_token: cached token=%s", g_device_token);
+ if (g_device_token && strcmp(g_device_token, "<null>") != 0)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "uapi_ln_get_device_token: cached token=%s", g_device_token);
return g_device_token;
}
/* 尝试从本地加载 */
char *cached = NULL;
uint64_t exp_ts = 0;
- if (ln_token_load_json(&cached, &exp_ts) == ERRCODE_SUCC && cached && cached[0]) {
+ if (ln_token_load_json(&cached, &exp_ts) == ERRCODE_SUCC && cached && cached[0])
+ {
int expired = 1;
(void)ln_token_is_expired(&expired);
- if (!expired) {
- if (g_device_token) free(g_device_token);
+ if (!expired)
+ {
+ if (g_device_token)
+ free(g_device_token);
g_device_token = cached; /* 接管指针 */
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"uapi_ln_get_device_token: loaded from file, not expired(未过期)");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "uapi_ln_get_device_token: loaded from file, not expired(未过期)");
return g_device_token;
}
/* 已过期:释放缓存并尝试刷新 */
free(cached);
- if (uapi_ln_refresh_device_token() == ERRCODE_SUCC) {
- if (g_device_token && strcmp(g_device_token, "<null>") != 0) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"uapi_ln_get_device_token: refreshed expired token");
+ if (uapi_ln_refresh_device_token() == ERRCODE_SUCC)
+ {
+ if (g_device_token && strcmp(g_device_token, "<null>") != 0)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "uapi_ln_get_device_token: refreshed expired token");
return g_device_token;
}
}
}
/* 没有,尝试获取 Token */
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[TOKEN] 刷新 Token");
- if(uapi_dev_runtime_get_cat1_networkstat())
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[TOKEN] 刷新 Token");
+ if (uapi_dev_runtime_get_cat1_networkstat())
{
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[TOKEN] 网络在线,刷新 Token");
- if(uapi_ln_refresh_device_token() == ERRCODE_SUCC)
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[TOKEN] 网络在线,刷新 Token");
+ if (uapi_ln_refresh_device_token() == ERRCODE_SUCC)
{
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[TOKEN] 刷新 Token 成功");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[TOKEN] 刷新 Token 成功");
return g_device_token;
}
else
{
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[TOKEN] 刷新 Token 失败");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[TOKEN] 刷新 Token 失败");
return NULL;
}
}
else
{
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[TOKEN] 网络离线,无法刷新 Token");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[TOKEN] 网络离线,无法刷新 Token");
}
return NULL;
}
/* 清除设备token */
void uapi_ln_clear_device_token(void)
{
- if(g_device_token != NULL)
+ if (g_device_token != NULL)
{
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"clear device token");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "clear device token");
free(g_device_token);
g_device_token = NULL;
}
}
/* 获取设备绑定用户ID */
-const char* uapi_ln_get_user_id(void)
+const char *uapi_ln_get_user_id(void)
{
return g_ln_device_user_id;
}
-
-/* 下载文件
+/* 下载文件
@param url 文件URL
@param save_path 保存路径
@return ERRCODE_SUCC 成功,ERRCODE_FAIL 失败
return ERRCODE_FAIL;
}
- if(g_ln_is_file_downloading == 1)
+ if (g_ln_is_file_downloading == 1)
{
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 已有文件正在下载中");
return ERRCODE_FAIL;
total_written += written;
}
}
- else
+ else
{
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] recv_res = %d, break", recv_res);
break;
return ret;
}
+/* 下载函数封装:带重试,不做UI通知与资源释放 */
+int uapi_ln_download_with_retry(const char *url, const char *save_path, int max_retries)
+{
+ if (url == NULL || save_path == NULL) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] invalid params");
+ return ERRCODE_FAIL;
+ }
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] start: %s -> %s", url, save_path);
+ int ret = uapi_ln_download_file(url, save_path);
+ if (ERRCODE_SUCC != ret) {
+ for (int i = 1; i <= max_retries; i++) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] retry %d/%d", i, max_retries);
+ ret = uapi_ln_download_file(url, save_path);
+ if (ERRCODE_SUCC == ret) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] success on retry %d", i);
+ break;
+ }
+ }
+ }
+ return ret;
+}
/* 自适应申请HttpClient缓冲(保证header>=2048),失败则逐步扩容重试 */
HTTPC_RESULT ln_http_prepare_auto(HttpClientData *clientData, int header_size, int resp_size)
{
- if (header_size < 2048) header_size = 2048;
- if (resp_size < 2048) resp_size = 2048;
+ if (header_size < 2048)
+ header_size = 2048;
+ if (resp_size < 2048)
+ resp_size = 2048;
HTTPC_RESULT ret = HttpClientPrepare(clientData, header_size, resp_size);
- if (ret == HTTP_SUCCESS) return ret;
+ if (ret == HTTP_SUCCESS)
+ return ret;
int tries = 0;
- while (ret != HTTP_SUCCESS && tries < 3) {
+ while (ret != HTTP_SUCCESS && tries < 3)
+ {
header_size = header_size < 4096 ? 4096 : header_size * 2;
resp_size = resp_size < (16 * 1024) ? (16 * 1024) : resp_size * 2;
- if (resp_size > (256 * 1024)) resp_size = (256 * 1024);
+ if (resp_size > (256 * 1024))
+ resp_size = (256 * 1024);
ret = HttpClientPrepare(clientData, header_size, resp_size);
tries++;
}
/* ============================ WebSocket 业务消息 上层处理 ============================ */
void ln_ws_process_message(const ws_data_msg_t *data_msg, ws_command_t type)
{
- if(type == WS_CMD_CONNECTED)
+ if (type == WS_CMD_CONNECTED)
{
printf("[LN][WS] Processing WebSocket Connected event\n");
set_is_ln_get_device_network_success(1);
}
- else if(type == WS_CMD_DISCONNECTED)
+ else if (type == WS_CMD_DISCONNECTED)
{
printf("[LN][WS] Processing WebSocket Disconnected event\n");
set_is_ln_get_device_network_success(0);
}
-
+
if (!data_msg || !data_msg->raw_json)
{
printf("[WS] invalid data message\n");
printf("[WS] cmd=%d message_id=%s cmd_str=%s\n", (int)type, message_id ? message_id : "", cmd_str ? cmd_str : "");
- switch (type) {
- case WS_CMD_CHARACTER_CHANGE: {
- printf("[WS] CharacterChange:角色切换\n");
- if(json_str)
- {
- ln_parse_character_config(json_str, (int)strlen(json_str));
- }
- break;
- }
- case WS_CMD_CHARACTER_CONFIG_CHANGE: {
- printf("[WS] CharacterConfigChange:角色配置更改(CharacterConfigChange)\n");
- if(json_str)
- {
- ln_parse_character_config(json_str, (int)strlen(json_str));
- }
- break;
- }
- case WS_CMD_SLEEP_MODE_START: {
- printf("[WS] SleepModeStart:哄睡模式开始\n");
- if(json_str)
- {
- ln_parse_sleep_mode_start(json_str, (int)strlen(json_str));
- }
- break;
- }
- case WS_CMD_SLEEP_MODE_END: {
- printf("[WS] SleepModeEnd:哄睡模式结束\n");
- if(json_str)
- {
- ln_parse_sleep_mode_end(json_str, (int)strlen(json_str));
- }
- break;
- }
- case WS_CMD_DEVICE_BIND: {
- printf("[WS] DeviceBind:设备绑定\n");
- push_bind_and_unbind_notification(LN_DEVICE_BIND_STATUS_BOUND);
- break;
- }
- case WS_CMD_DEVICE_UNBIND: {
- printf("[WS] DeviceUnbind:设备解绑\n");
- push_bind_and_unbind_notification(LN_DEVICE_BIND_STATUS_UNBOUND);
- break;
- }
- case WS_CMD_SCHEDULE_REMINDER: {
- printf("[WS] ScheduleReminder:日程提醒\n");
- if(json_str)
- {
- ln_parse_schedule_reminder(json_str, (int)strlen(json_str));
- }
- break;
- }
- case WS_CMD_SCHEDULE_REMINDER_CFG: {
- printf("[WS] ScheduleReminderConfig:日程提醒配置\n");
- if(json_str)
- {
- ln_parse_schedule_reminder_config(json_str, (int)strlen(json_str));
- }
- break;
+ switch (type)
+ {
+ case WS_CMD_CHARACTER_CHANGE:
+ {
+ printf("[WS] CharacterChange:角色切换\n");
+ if (json_str)
+ {
+ ln_parse_character_config(json_str, (int)strlen(json_str));
}
- case WS_CMD_DOWNLOAD_EMOJI: {
- printf("[WS] DownloadEmoji:下载表情\n");
- if(json_str)
- {
- // ln_parse_download_emoji(json_str, (int)strlen(json_str));
- }
- break;
+ break;
+ }
+ case WS_CMD_CHARACTER_CONFIG_CHANGE:
+ {
+ printf("[WS] CharacterConfigChange:角色配置更改(CharacterConfigChange)\n");
+ if (json_str)
+ {
+ ln_parse_character_config(json_str, (int)strlen(json_str));
}
- case WS_CMD_DELETE_EMOJI: {
- printf("[WS] DeleteEmoji:删除表情\n");
- if(json_str)
- {
- ln_parse_delete_emoji(json_str, (int)strlen(json_str));
- }
- break;
+ break;
+ }
+ case WS_CMD_SLEEP_MODE_START:
+ {
+ printf("[WS] SleepModeStart:哄睡模式开始\n");
+ if (json_str)
+ {
+ ln_parse_sleep_mode_start(json_str, (int)strlen(json_str));
}
- case WS_CMD_PING: {
- printf("[WS] Ping\n");
- break;
+ break;
+ }
+ case WS_CMD_SLEEP_MODE_END:
+ {
+ printf("[WS] SleepModeEnd:哄睡模式结束\n");
+ if (json_str)
+ {
+ ln_parse_sleep_mode_end(json_str, (int)strlen(json_str));
}
- case WS_CMD_PONG: {
- printf("[WS] Pong\n");
- break;
+ break;
+ }
+ case WS_CMD_DEVICE_BIND:
+ {
+ printf("[WS] DeviceBind:设备绑定\n");
+ push_bind_and_unbind_notification(LN_DEVICE_BIND_STATUS_BOUND);
+ break;
+ }
+ case WS_CMD_DEVICE_UNBIND:
+ {
+ printf("[WS] DeviceUnbind:设备解绑\n");
+ push_bind_and_unbind_notification(LN_DEVICE_BIND_STATUS_UNBOUND);
+ break;
+ }
+ case WS_CMD_SCHEDULE_REMINDER:
+ {
+ printf("[WS] ScheduleReminder:日程提醒\n");
+ if (json_str)
+ {
+ do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_SCHEDULE_REMINDER, NULL, 0);
}
- case WS_CMD_VOICE_CHAT_RESPONSE:{
- push_text_to_ui(data_msg->text_content);
- break;
+ break;
+ }
+ case WS_CMD_SCHEDULE_REMINDER_CFG:
+ {
+ printf("[WS] ScheduleReminderConfig:日程提醒配置\n");
+ if (json_str)
+ {
+ ln_parse_schedule_reminder_config(json_str, (int)strlen(json_str));
}
- case WS_CMD_CHOOSE_STORY_RESPONSE:{
- push_text_to_ui(data_msg->text_content);
- break;
+ break;
+ }
+ case WS_CMD_DOWNLOAD_EMOJI:
+ {
+ printf("[WS] DownloadEmoji:下载表情\n");
+ if (json_str)
+ {
+ // ln_parse_download_emoji(json_str, (int)strlen(json_str));
}
- default: {
- printf("[WS] Unknown command=%s\n", cmd_str ? cmd_str : "");
- break;
+ break;
+ }
+ case WS_CMD_DELETE_EMOJI:
+ {
+ printf("[WS] DeleteEmoji:删除表情\n");
+ if (json_str)
+ {
+ ln_parse_delete_emoji(json_str, (int)strlen(json_str));
}
+ break;
+ }
+ case WS_CMD_PING:
+ {
+ printf("[WS] Ping\n");
+ break;
+ }
+ case WS_CMD_PONG:
+ {
+ printf("[WS] Pong\n");
+ break;
+ }
+ case WS_CMD_VOICE_CHAT_RESPONSE:
+ {
+ push_text_to_ui(data_msg->text_content);
+ break;
+ }
+ case WS_CMD_CHOOSE_STORY_RESPONSE:
+ {
+ push_text_to_ui(data_msg->text_content);
+ break;
+ }
+ default:
+ {
+ printf("[WS] Unknown command=%s\n", cmd_str ? cmd_str : "");
+ break;
+ }
}
}
/* ============================ WebSocket 业务消息 上层处理 End============================ */
-
-
-
/* ============================ mp3下载功能 ============================ */
/**
// 构建完整保存路径
size_t sp_cap = strlen(save_dir) + 1 + strlen(filename) + 1;
- char *save_path = (char*)malloc(sp_cap);
+ char *save_path = (char *)malloc(sp_cap);
if (!save_path)
{
printf("[SSE] malloc save_path failed\n");
printf("[SSE] downloading MP3: %s -> %s\n", audio_url, save_path);
- #ifdef SUPPORT_CAT1_SERVICE
+#ifdef SUPPORT_CAT1_SERVICE
/* CAT1 网络保活处理 */
cat1_api_add_cat1_vote();
cat1_api_wakeup_cat1(1);
cat1_api_keep_wakeup(1);
cat1_api_disable_cat1_cmd(0);
LOS_Msleep(300);
- #endif
+#endif
HttpClient client = {0};
HttpClientData client_data = {0};
int ret = -1;
size_t total_written = 0;
- #if TEST_MP3_DOWNLOAD
+#if TEST_MP3_DOWNLOAD
// 打开文件准备写入
FILE *fd = fopen(save_path, "wb");
if (!fd)
printf("[SSE] fopen failed for %s\n", save_path);
return ERRCODE_FAIL;
}
- #endif
+#endif
HTTPC_RESULT prep = ln_http_prepare_auto(&client_data, 2048, LN_CLIENT_PREPARE_SIZE * 2);
if (prep != HTTP_SUCCESS)
{
printf("[SSE] prepare failed: %d\n", prep);
- #if TEST_MP3_DOWNLOAD
+#if TEST_MP3_DOWNLOAD
fclose(fd);
- #endif
+#endif
free(save_path);
return ERRCODE_FAIL;
}
if (ret != 0)
{
printf("[SSE] connection failed, ret=0x%x\n", ret);
- #if TEST_MP3_DOWNLOAD
+#if TEST_MP3_DOWNLOAD
fclose(fd);
- #endif
+#endif
HttpClientUnprepare(&client_data);
free(save_path);
return ERRCODE_FAIL;
if (ret != 0)
{
printf("[SSE] send request failed, ret=0x%x\n", ret);
- #if TEST_MP3_DOWNLOAD
+#if TEST_MP3_DOWNLOAD
fclose(fd);
- #endif
+#endif
HttpClientClse(&client);
HttpClientUnprepare(&client_data);
free(save_path);
if (client_data.contentBlockLen > 0)
{
printf("download mp3 file advanced: contentBlockLen=%d\n", client_data.contentBlockLen);
- #if TEST_MP3_DOWNLOAD
+#if TEST_MP3_DOWNLOAD
/* 一边下载到文件,一边推送到播放器队列,尝试边下边播 */
size_t written = fwrite(client_data.responseBuf, 1, client_data.contentBlockLen, fd);
if (written != client_data.contentBlockLen)
return ERRCODE_FAIL;
}
total_written += written;
- #endif
- ret = AI_SendAudioDataToQueue((const uint8_t*)client_data.responseBuf, client_data.contentBlockLen);
+#endif
+ ret = AI_SendAudioDataToQueue((const uint8_t *)client_data.responseBuf, client_data.contentBlockLen);
if (ret != 0)
{
printf("download mp3 file advanced: write failed1, ret=%d\n", ret);
// 写失败重新写
LOS_Msleep(100);
- ret = AI_SendAudioDataToQueue((const uint8_t*)client_data.responseBuf, (uint32_t)client_data.contentBlockLen);
+ ret = AI_SendAudioDataToQueue((const uint8_t *)client_data.responseBuf, (uint32_t)client_data.contentBlockLen);
if (ret != 0)
{
printf("download mp3 file advanced: write failed2, ret=%d\n", ret);
LOS_Msleep(100);
- ret = AI_SendAudioDataToQueue((const uint8_t*)client_data.responseBuf, (uint32_t)client_data.contentBlockLen);
+ ret = AI_SendAudioDataToQueue((const uint8_t *)client_data.responseBuf, (uint32_t)client_data.contentBlockLen);
if (ret != 0)
{
printf("download mp3 file advanced: write failed3, ret=%d\n", ret);
}
} while (client_data.isMore);
- #if TEST_MP3_DOWNLOAD
+#if TEST_MP3_DOWNLOAD
fclose(fd);
- #endif
+#endif
HttpClientUnprepare(&client_data);
HttpClientClse(&client);
free(save_path);
char *save_dir, size_t save_dir_len,
char *filename, size_t filename_len)
{
- if (!save_dir || !filename) return;
+ if (!save_dir || !filename)
+ return;
if (interface_type == LN_HTTP_SERVICE_CMD_SSE_RECV)
{
(void)snprintf(save_dir, save_dir_len, "%s/speech", LN_DATA_PATH);
/* 辅助函数:提取音频URL */
static const char *ln_get_audio_url_for_interface(cJSON *data, int interface_type)
{
- if (!data) return NULL;
+ if (!data)
+ return NULL;
if (interface_type == LN_HTTP_SERVICE_CMD_SSE_RECV)
{
cJSON *audioUrl = cJSON_GetObjectItem(data, "audioUrl");
- if (audioUrl && cJSON_IsString(audioUrl)) return audioUrl->valuestring;
+ if (audioUrl && cJSON_IsString(audioUrl))
+ return audioUrl->valuestring;
return NULL;
}
if (interface_type == LN_HTTP_RECV_STORY_CHOOSE || interface_type == LN_HTTP_RECV_STORY_RANDOM)
{
cJSON *storyAudioUrl = cJSON_GetObjectItem(data, "storyAudioUrl");
- if (storyAudioUrl && cJSON_IsString(storyAudioUrl)) return storyAudioUrl->valuestring;
+ if (storyAudioUrl && cJSON_IsString(storyAudioUrl))
+ return storyAudioUrl->valuestring;
return NULL;
}
cJSON *audioUrl = cJSON_GetObjectItem(data, "audioUrl");
- if (audioUrl && cJSON_IsString(audioUrl)) return audioUrl->valuestring;
+ if (audioUrl && cJSON_IsString(audioUrl))
+ return audioUrl->valuestring;
return NULL;
}
/* 辅助函数:若存在音频URL则执行下载 */
static void ln_download_audio_if_present(const char *audio_url, int interface_type, int segment_index, int is_error)
{
- if (!audio_url || strlen(audio_url) == 0) return;
+ if (!audio_url || strlen(audio_url) == 0)
+ return;
char save_dir[256];
char filename[128];
ln_build_audio_save_path(interface_type, segment_index, is_error, save_dir, sizeof(save_dir), filename, sizeof(filename));
{
if (!json_data)
{
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[JSON_PARSE] invalid json_data\n");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[JSON_PARSE] invalid json_data\n");
return ERRCODE_FAIL;
}
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[JSON_PARSE] parsing JSON data (interface_type=%d, segment=%d): %s\n",
- interface_type, segment_index, json_data);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[JSON_PARSE] parsing JSON data (interface_type=%d, segment=%d): %s\n",
+ interface_type, segment_index, json_data);
// 解析JSON数据
cJSON *root = cJSON_Parse(json_data);
if (!root)
{
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[JSON_PARSE] JSON parse failed: %s\n", json_data);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[JSON_PARSE] JSON parse failed: %s\n", json_data);
return ERRCODE_FAIL;
}
const char *err = cJSON_IsString(errorCode) ? errorCode->valuestring : "unknown";
cJSON *message = cJSON_GetObjectItem(root, "message");
const char *msg_str = (message && cJSON_IsString(message)) ? message->valuestring : "";
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[JSON_PARSE] server error: %s, message=%s\n", err, msg_str);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[JSON_PARSE] server error: %s, message=%s\n", err, msg_str);
const char *audio_url_err = NULL;
const char *text_content_err = NULL;
if (data_err && cJSON_IsObject(data_err))
{
cJSON *audioUrl = cJSON_GetObjectItem(data_err, "audioUrl");
- if (audioUrl && cJSON_IsString(audioUrl)) audio_url_err = audioUrl->valuestring;
+ if (audioUrl && cJSON_IsString(audioUrl))
+ audio_url_err = audioUrl->valuestring;
cJSON *textContent = cJSON_GetObjectItem(data_err, "textContent");
- if (textContent && cJSON_IsString(textContent)) text_content_err = textContent->valuestring;
+ if (textContent && cJSON_IsString(textContent))
+ text_content_err = textContent->valuestring;
}
if (text_content_err && strlen(text_content_err) > 0)
cJSON *data = cJSON_GetObjectItem(root, "data");
if (!data || !cJSON_IsObject(data))
{
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[JSON_PARSE] no data field found\n");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[JSON_PARSE] no data field found\n");
cJSON_Delete(root);
return ERRCODE_FAIL;
}
while (fgets(line, 2048, fp))
{
line_count++;
-
+
// 去除行尾的换行符
size_t len = strlen(line);
if (len > 0 && line[len - 1] == '\n')
{
json_start++;
}
-
+
uint32_t result = ln_parse_and_process_json_data(json_start, interface_type, line_count);
if (result == ERRCODE_SUCC)
{
fclose(fp);
free(line);
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[FILE_PARSE] processing completed: total lines=%d, success=%d, errors=%d\n",
- line_count, success_count, error_count);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[FILE_PARSE] processing completed: total lines=%d, success=%d, errors=%d\n",
+ line_count, success_count, error_count);
/* 向UI上报结束状态 */
if (interface_type == LN_HTTP_SERVICE_CMD_SSE_RECV)
}
else if (mail.cmd == LN_HTTP_SERVICE_CMD_STORY_RANDOM)
{
- if (mail.data && mail.len == sizeof(ln_story_random_req_t))
+ 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_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_EMOJI_REPORT)
{
printf("LN_HTTP_SERVICE_CMD_EMOJI_REPORT:上报角色表情组下载状态\n");
- if(mail.data)
+ if (mail.data)
{
ln_emoji_report_status(mail.data);
}
else if (mail.cmd == LN_HTTP_SERVICE_CMD_DOWNLOAD_SCREEN_IMAGE)
{
printf("LN_HTTP_SERVICE_CMD_DOWNLOAD_SCREEN_IMAGE:下载屏保文件\n");
- if(mail.data)
+ if (mail.data)
{
ln_download_file_req_t req;
memcpy(&req, mail.data, sizeof(req));
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] 屏保下载URL: %s, 保存路径: %s", req.url, req.save_path);
- errcode_t ret = uapi_ln_download_file(req.url, req.save_path);
- if (ERRCODE_SUCC != ret)
- {
- int i = 1;
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] 屏保下载失败,重试3次,第%d次", i);
- // 如果下载失败重试3次
- for (i = 1; i <= 3; i++)
- {
- ret = uapi_ln_download_file(req.url, req.save_path);
- if (ERRCODE_SUCC == ret)
- {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] 屏保下载成功,第%d次", i);
- break;
- }
- }
- }
- if(ret == ERRCODE_SUCC)
+ errcode_t ret = uapi_ln_download_with_retry(req.url, req.save_path, 3);
+ if (ret == ERRCODE_SUCC)
{
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] 屏保下载成功,通知去切换屏保");
push_screen_image_download_success_notification();
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] 屏保下载失败");
}
/* 释放由发送方分配的指针 */
- if (req.url) { free(req.url); req.url = NULL; }
- if (req.save_path) { free(req.save_path); req.save_path = NULL; }
+ if (req.url)
+ {
+ free(req.url);
+ req.url = NULL;
+ }
+ if (req.save_path)
+ {
+ free(req.save_path);
+ req.save_path = NULL;
+ }
}
}
+ else if (mail.cmd == LN_HTTP_SERVICE_CMD_SCHEDULE_REMINDER)
+ {
+ printf("LN_HTTP_SERVICE_CMD_SCHEDULE_REMINDER:日程提醒\n");
+ ln_parse_schedule_reminder(mail.data, mail.len);
+ }
if (mail.data != NULL)
{
printf("free(mail.data)\n");
free(mail.data);
}
-
}
}
{
const char *dirs[] = {
LN_DATA_PATH,
- LN_DATA_PATH "/token", //存放token的
+ LN_DATA_PATH "/token", // 存放token的
LN_DATA_PATH "/speech",
LN_DATA_PATH "/story",
LN_DATA_PATH "/character",
}
}
-//初始化一些配置信息
+// 初始化一些配置信息
static void ln_load_init_config(void)
{
ln_read_character_config();