typedef int int_arry[4]

本文详细解析了C++中指针的使用方法,包括自定义数据类型、二维数组的指针操作、指针的递增含义等内容。
#include <iostream>
using namespace std;
int main()
{
 int ia[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
 typedef int int_array[4];
    for (int_array *p =ia;p!= ia+3;++p)
    {
  for (int *q=*p;q!=*p+4;++q)
  {
   cout<<*q<<"   ";
  }
  cout<<endl;
    }
 return 0;
}
一、先解释typedef int int_array[4]; 关键字typedef用来自定义数据类型,这是所有教材都这样讲的,但不要理解为新创建了一个数据类型,而是将已有的一个类型赋予个新名称而已,即起一个别名。 具体对这个语句来说,别名就是:int_array。而[4]不属于名字,而表示一种已有的数据类型,即:给一个大小为4的int数组取一个别名为int_array。 那如何知道是这样定义的呢?很简单。 首先,int a[4];这可是常见的定义格式。再在其前面添加关键字typedef,变成 typedef int a[4];最后将数组名a改为自己想要的一个别名int_array即可。注意:原本的a本意是数组名,属于变量范畴,而int_array则是新数据类型名(即别名),本质不一样了哦。祥见谭浩强的那本经典教材。二、语句int_array *p =ia;的含义 首先,它是一个定义语句,即用自定义的数据类型int_array来定义一个该类型的一个指针变量ia。 ia是一个什么东东呢?它是一个二维数组名。 对于一维数组a,我们有:&a[0]等价于a,即都表示该一维数组首元地址。 那么,对于二维数组这个性质还成立吗?没错,同样成立。即: &ia[0]等价于ia。 所以,int_array *p =ia;与int_array *p =&ia[0];是等价的。 但是,&a[0]与&ia[0]含义是不一样的。前者代表了一维数组中首元地址,而后者则代表二维数组中第一行的行首地址。 行首地址与行首元地址,它们的值用cout输出来那肯定是一样的。但它们与指针的操作扯上关系时,就不一样了,前者以行为基本单位,后者以一个元素为基本单位,切记。 现在我们应该明白了,语句int_array *p =ia;的作用是定义p后,并初始化p,即用p来指向二维数组的第一行(整个这一行),即ia[0],不是第一行的首元ia[0][0]哦。当然,对p这样初始化是正确的,因为p要指向的正是大小为4的一维数组,而二维数组ia的每一行正好就是4个元素。 ia[0]可认为是首行的数组名。ia[1]、ia[2]类推。三、语句++p的含义 由上可知,p既然首先指向第一行ia[0],那么(p+1)不就指向第二行ia[1]吗?正是如此。 于是外循环的终止条件就应该是不存在的第四行,即ia[3],所以终止条件就是:p!= ia+3。四、语句int *q=*p;的含义 如上所述,先定义整型指针q,并初始化为*p。 *p是什么意思? 前面已得到:p 被初始化为ia,即&ia[0]。那么*p就代表ia[0]。 即:p存储的是首行地址,于是,*p就直接代表了该行,即整个这一行。 而前面已经明确的讲了ia[0]代表的是首行的数组名,当然它是一维的。而一维数组名不就代表了这一行的首元地址吗?于是,就有 q=*p等价于q=ia[0],也等价于q=&ia[0][0]。 再于是,q指向了一个一维数组的首元。切记,不能说q指向了一个一维数组。再再于是,++q就表示&ia[0][1]。当然了,再执行一遍++q,就表示&ia[0][2]了。 在解释一下*p+4。 刚刚讲了*p直接代表了某一行,即ia[0]或ia[1]或ia[2],也讲了这些ia[0]或ia[1]或ia[2]就代表该行的行数组名。当然,都是一维的。 回忆一下,一维数组名加一个数字代表什么呢?例如a是一个一维数组名,a+4表示什么呢?答案是:&a[4],即该一维数组的第五个元素a[4]的地址。 所以*p+4表示:p所指那一行的第五个元素,当然这对于本题来说是不存在的,所以就做为内循环的终止条件咯。 *q代表什么呢? q指向的是一个具体的元素,那么*q就直接代表了该元素的内存空间。那么,cout它就是输出该元素的值。五、总结 外循环的步长是行,共3行,内循环是行中的各个具体元素,每行4个。 结果就是使用指针的方式将二维数组输出来。
 
转自:http://zhidao.baidu.com/question/198017816.html
#include<stdio.h> #include<stdlib.h> #include<sys/ipc.h> #include<sys/shm.h> #include<sys/sem.h> #include<string.h> typedef struct _test{ int a_val; int b_val; int a_flag; int b_flag; int game_no; int stage; }test; int pk[3][3] = {0,-1,1,1,0,-1,-1,1,0}; void sem_p(); void sem_v(); void set_sem(); void del_sem(); int sem_id; union semun{ int val; struct semid_ds *buf; unsigned short *arry; }; int main(){ int shmid; test* shm; shmid = shmget((key_t)1236,sizeof(test),0666|IPC_CREAT); if(shmid == -1){ printf("shmget failed\n"); exit(EXIT_FAILURE); } printf("%d",shmid); shm = shmat(shmid,0,0); if (shm == (void*)-1){ printf("shmat failed\n"); exit(EXIT_FAILURE); } printf("\nMemory attached at %X\n",(int)shm); sem_id = semget((key_t)3000,1,0666|IPC_CREAT); set_sem(); int no=0,debug=0,a,b; shm->a_flag=0; shm->a_val = -2; shm->b_flag=0; shm->b_val = -2; shm->game_no=1; shm->stage=0; while(1){ sem_p(); //printf("a:%d b:%d\n",shm->a_val,shm->b_val); sleep(1); if(shm->game_no==-1){ sem_v(); break; } if (shm->stage==0){ if(no!=shm->game_no){ no = shm->game_no; printf("-------------------\n"); printf("game_no:%d\n",no); } if(shm->a_flag==1 && shm->b_flag==1) shm->stage=1; } else if(shm->stage==1){ printf("a:%d\n",shm->a_val); printf("b:%d\n",shm->b_val); a = pk[shm->a_val][shm->b_val]; b = pk[shm->b_val][shm->a_val]; shm->a_val=a; shm->b_val=b; shm->a_flag=0; shm->b_flag=0; shm->stage=2; } else if(shm->stage==2){ if(shm->a_flag==1 && shm->b_flag==1){ shm->stage=0; shm->game_no++; shm->a_flag=0; shm->b_flag=0; printf("-------------------\n"); if(shm->game_no > 100) shm->game_no=-1; } } sem_v(); } shmdt(shm); int ret=0; ret = shmctl(shmid,IPC_RMID,NULL); if(ret<0){ printf("shmctl error!\n"); } del_sem(); printf("finish"); } void set_sem(){ union semun sem_union; sem_union.val=1; semctl(sem_id,0,SETVAL,sem_union); } void del_sem(){ union semun sem_union; semctl(sem_id,0,IPC_RMID,sem_union); } void sem_p(){ struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = -1; sem_b.sem_flg = SEM_UNDO; semop(sem_id,&sem_b,1); } void sem_v(){ struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1; sem_b.sem_flg = SEM_UNDO; semop(sem_id,&sem_b,1); }
06-08
/****************************************************************************** * Copyright(c) 2019-2024 TP-Link Systems Inc. * * Filename: hub_manage.c * Note: hub_manage模块注册,主要对外接口 * * Author Jiang Changfu <jiangchangfu@tp-link.com.hk> * Date: 2023-08-19 * Version: v0.1 Create file ******************************************************************************/ #include <netinet/if_ether.h> #include <linux/filter.h> #include <linux/if_packet.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include "nsd_common.h" #include "hub_manage.h" #include "hub_manage_login.h" #include "hub_manage_http_client.h" #include "hub_manage_request_handle.h" #include "hub_man_debug.h" #include "libdms.h" #include "libds.h" #include "ai_enhance.h" /**************************************************************************************************/ /* DEFINES */ /**************************************************************************************************/ SYSTEM_SYS g_sys_info = {{0}}; LOCAL S32 g_resync_timer_id = -1; LOCAL S32 resync_delay_sec = 0; LOCAL FLIP_TYPE g_last_flip_type = FLIP_OFF; HUB_PWD_UNIT g_hub_sto_passwd_list[HUB_PASSWD_LIST_NUM] = {{0}}; HUB_PWD_UNIT g_hub_wifi_passwd_list[HUB_PASSWD_LIST_NUM] = {{0}}; hub_keepalive_client_ctx hub_client = {0}; /* 和AI_ENHANCE_TYPE顺序保持一致 */ LOCAL char *g_detect_list[] = { "detection", "personDetection", "petDetection", "vehicleDetection", NULL, "packageDetection", "tamperDetection", "babyCryDetection", "intrusionDetection", "linecrossingDetection", "glassDetection", "alarmDetection", "meowDetection", "barkDetection" }; LOCAL U32 g_detect_support = 0; extern int g_hub_force_port; extern char g_hub_force_ip[20]; extern int camera_force_hub_configuration_synchronization_flag; /**************************************************************************************************/ /* LOCAL_FUNCTIONS */ /**************************************************************************************************/ LOCAL void detect_support_load() { JSON_OBJPTR res_array = NULL, recv = NULL; int i = 0, j = 0, comp_arry_len = 0; int arraylen = ARRAY_SIZE(g_detect_list); HUB_MANAGE_AI_ENHANCE_DYN ai_enhence_info = {0}; if(NULL == (res_array = jso_new_array())) { return; } if(get_app_component_list(res_array, "name", "version")) { jso_free_obj(res_array); return; } comp_arry_len = json_object_array_length(res_array); for(j = 0; j < arraylen; j++) { if (NULL == g_detect_list[j]) { continue; } for(i = 0; i < comp_arry_len; i++) { recv = json_object_array_get_idx(res_array, i); if(strstr(jso_obj_get_string_origin(recv, "name"), g_detect_list[j])) { g_detect_support |= (1 << j); HUB_MANAGE_INFO("support %s", g_detect_list[j]); break; } } } jso_free_obj(res_array); if (ds_read(HUB_MANAGE_AI_ENHANCE_DYN_PATH, (U8 *)&ai_enhence_info, sizeof(HUB_MANAGE_AI_ENHANCE_DYN)) == 0) { HUB_MANAGE_ERROR("read ai_enhence_info fail."); return; } ai_enhence_info.ai_camera_support = g_detect_support; if (ds_write(HUB_MANAGE_AI_ENHANCE_DYN_PATH, &ai_enhence_info, sizeof(HUB_MANAGE_AI_ENHANCE_DYN)) == 0) { HUB_MANAGE_ERROR("write [ai_enhence_info] error"); return; } } U32 get_detect_support() { return g_detect_support; } LOCAL S32 hub_config_check() { int write_flag = 0, ret = 0; HUB_MANAGE_STORAGE_INFO hub_info = {0}; HUB_MANAGE_WIFI_BACKUP wifi_backup = {0}; BIND_HUB_REPORT bind_report = {0}; HUB_MANAGE_CFG_ASYNC_RECORD async_record = {0}; /* 初始化异步记录结构体 */ if (ds_read(HUB_MANAGE_STORAGE_INFO_PATH, (U8 *)&hub_info, sizeof(HUB_MANAGE_STORAGE_INFO)) == 0) { HUB_MANAGE_ERROR("read hub_info fail."); return SLP_ESYSTEM; } /* 从配置文件读取当前的wifi_backup配置 */ if (0 == ds_read(HUB_MANAGE_WIFI_BACKUP_PATH, &wifi_backup, sizeof(HUB_MANAGE_WIFI_BACKUP))) { HUB_MANAGE_ERROR("hub_info Parameter could not be NULL."); return SLP_ESYSTEM; } if (0 == ds_read(HUB_MANAGE_CFG_ASYNC_RECORD_PATH, (U8 *)&async_record, sizeof(HUB_MANAGE_CFG_ASYNC_RECORD))) { HUB_MANAGE_ERROR("read async cfg info fail."); return SLP_ESYSTEM; } if (0 == ds_read(CLOUD_CONFIG_BIND_HUB_REPORT_PATH, &bind_report, sizeof(BIND_HUB_REPORT))) { HUB_MANAGE_ERROR("read device status fail!"); return SLP_ESYSTEM; } if (hub_info.enabled && 0 >= strlen(hub_info.hub_mac)) { HUB_MANAGE_ERROR("missing key parameters,hub_mac"); clear_hub_storage_info(); write_flag = 0; goto end; } if (('\0' == hub_info.asyncMac[0] || '\0' == hub_info.asyncIp[0] || '\0' == hub_info.asyncPsw[0]) && 0 != (async_record.async_cfg & (1 << HUB_MAN_ASYNC_TYPE_UNBIND_CONFIG))) { async_record.async_cfg &= ~(1 << HUB_MAN_ASYNC_TYPE_UNBIND_CONFIG); ds_advanced_write(HUB_MANAGE_CFG_ASYNC_RECORD_PATH, (U8 *)&async_record, sizeof(HUB_MANAGE_CFG_ASYNC_RECORD), DS_FLAG_SAVE_FLASH); } end: if (!write_flag) { return ret; } if (ds_advanced_write(HUB_MANAGE_STORAGE_INFO_PATH, (U8 *)&hub_info, sizeof(HUB_MANAGE_STORAGE_INFO), DS_FLAG_SAVE_FLASH) == 0) { HUB_MANAGE_ERROR("ds_write hub_storage error."); ret = SLP_ESYSTEM; } if (ds_advanced_write(HUB_MANAGE_WIFI_BACKUP_PATH, (U8 *)&wifi_backup, sizeof(HUB_MANAGE_WIFI_BACKUP), DS_FLAG_SAVE_FLASH) == 0) { HUB_MANAGE_ERROR("wifi_backup write fail."); ret = SLP_ESYSTEM; } return ret; } LOCAL S32 hub_manage_sync_retry(int retry_time) { S32 new_retry_time = 0; srand(time(0)); if (0 == retry_time) { new_retry_time = rand() % (RANDOM_RETRY_TIME_SEC - 1) + 2; //2s~8s } else { new_retry_time = 2 * retry_time; if (new_retry_time > MAX_TIMEOUT_RETRY_SEC) new_retry_time = MAX_TIMEOUT_RETRY_SEC; } HUB_MANAGE_INFO("connect retry time update to %ds", new_retry_time); return new_retry_time; //sec } /* 广播与hub间长连接状态的消息 */ void broadcast_hub_connect_status(int status) { HUB_CLIENT_CONNECT_MSG conn_msg = {0}; conn_msg.long_connection_sta = (status?1:0); NSD_SEND(HUB_CLIENT_CONNECT_MSG_ID, (U8 *)&conn_msg, sizeof(HUB_CLIENT_CONNECT_MSG)); return; } S32 token_update_timer_handler() { HUB_MANAGE_STORAGE_INFO hub_storage = {0}; if (ds_read(HUB_MANAGE_STORAGE_INFO_PATH, (U8 *)&hub_storage, sizeof(HUB_MANAGE_STORAGE_INFO)) == 0) { HUB_MANAGE_ERROR("read hub_info fail."); return ERROR; } if (ERROR != hub_client.token_update_timer) { inet_del_timer(hub_client.token_update_timer); hub_client.token_update_timer = ERROR; } if (!hub_client.http_ctx) { HUB_MANAGE_ERROR("keepalive connection not alive"); return ERROR; } hub_client_msg_send(hub_client.http_ctx, HUB_MAN_REQ_TYPE_LOGIN); hub_client.token_update_timer = inet_add_timer(token_update_timer_handler, 0, TOKEN_UPDATE_PERIOD, EXECUTE_SINGLE); return SLP_ENONE; } S32 set_login_timer() { if (ERROR != hub_client.token_update_timer) { inet_del_timer(hub_client.token_update_timer); hub_client.token_update_timer = ERROR; } hub_client.token_update_timer = inet_add_timer(token_update_timer_handler, 0, TOKEN_UPDATE_PERIOD, EXECUTE_SINGLE); return SLP_ENONE; } /**************************************************************************** * Function : hub_manage_set_offline * Description: * Input : N/A * Output : N/A * Return : 0(OK)/-1(ERROR) ****************************************************************************/ void hub_manage_set_offline() { STORAGE_TMP_INFO storage_tmp = {0}; if (ds_read(HUB_MANAGE_STORAGE_TMP_PATH, &storage_tmp, sizeof(STORAGE_TMP_INFO)) == 0) { HUB_MANAGE_ERROR("read hub storage info fail."); return; } if (TURN_OFFLINE_BOUND_TIMES > storage_tmp.offline) { storage_tmp.offline = TURN_OFFLINE_BOUND_TIMES; ds_write(HUB_MANAGE_STORAGE_TMP_PATH, &storage_tmp, sizeof(STORAGE_TMP_INFO)); } return; } LOCAL S32 dev_dyn_info_init() { BACKUP_TMP_INFO backup_tmp = {0}; HUB_MANAGE_WIFI_BACKUP wifi_info = {0}; HUB_MANAGE_STORAGE_INFO hub_storage = {0}; STORAGE_TMP_INFO storage_tmp = {0}; IMAGE_SWITCH image_switch = {0}; if (ds_read(HUB_MANAGE_WIFI_BACKUP_PATH, (U8 *)&wifi_info, sizeof(HUB_MANAGE_WIFI_BACKUP)) == 0) { HUB_MANAGE_ERROR("tdpd read factory info fail."); return ERROR; } if (wifi_info.enabled && 0 < strlen(wifi_info.ipaddr)) { backup_tmp.backup_tmp_enabled = wifi_info.enabled; strncpy(backup_tmp.backup, wifi_info.backup, BACKUP_STR_MAX_LEN); ds_write(HUB_MANAGE_BACKUP_TMP_PATH, &backup_tmp, sizeof(BACKUP_TMP_INFO)); } if (0 == ds_read(HUB_MANAGE_STORAGE_INFO_PATH, &hub_storage, sizeof(HUB_MANAGE_STORAGE_INFO))) { HUB_MANAGE_ERROR("hub_storage Parameter could not be NULL."); return ERROR; } if (hub_storage.enabled && 0 < strlen(hub_storage.ipaddr)) { storage_tmp.storage_tmp_enabled = hub_storage.enabled; ds_write(HUB_MANAGE_STORAGE_TMP_PATH, &storage_tmp, sizeof(STORAGE_TMP_INFO)); } if (0 == ds_read(SYSTEM_SYS_PATH, &g_sys_info, sizeof(SYSTEM_SYS))) { HUB_MANAGE_ERROR("g_sys_info Parameter could not be NULL."); return ERROR; } if (0 == ds_read(IMAGE_SWITCH_PATH, &image_switch, sizeof(IMAGE_SWITCH))) { HUB_MANAGE_ERROR("g_sys_info Parameter could not be NULL."); return ERROR; } g_last_flip_type = image_switch.flip_type; return OK; } /** * 设置hub存储功能函数 * * 此函数用于根据输入参数设置hub存储功能的状态,并在必要时更新存储IP地址。同时,它还会根据用户登录状态及密码信息, * 通过HTTP客户端发送请求以更新hub存储的相关配置。 * * @param storage_enable 字符串指针,表示存储是否启用。如果为"on"则启用存储,若为"off"则禁用存储。 * @param loginSta 登录状态枚举值,用于指示当前用户的登录情况。 * @param is_first_login 布尔型变量,标识用户是否首次登录。 * @param loginPwd 指向包含登录密码信息结构体的指针。 * @param storage_ipaddr 字符串指针,用于存储或更新hub的存储IP地址。 * @return 返回整型数值,OK表示操作成功,ERROR表示操作失败。 */ LOCAL S32 set_hub_storage(S32 storage_enable, const char *storage_mac, LOGIN_STATUS loginSta, U8 is_first_login, HUB_PWD_UNIT *loginPwd, char *storage_ipaddr) { S32 ret = OK; STORAGE_TMP_INFO storage_tmp = {0}; HUB_MANAGE_STORAGE_INFO hub_storage_info = {0}; ds_read(HUB_MANAGE_STORAGE_TMP_PATH, &storage_tmp, sizeof(STORAGE_TMP_INFO)); /* 从指定路径读取hub_storage */ if (0 == ds_read(HUB_MANAGE_STORAGE_INFO_PATH, &hub_storage_info, sizeof(HUB_MANAGE_STORAGE_INFO))) { HUB_MANAGE_ERROR("hub_info should not be null"); return SLP_ESYSTEM; } /* 处理存储使能状态 */ if (storage_enable) { storage_tmp.storage_tmp_enabled = TRUE; storage_tmp.sync_hub_state = SYNC_HUB_SYNCING; strncpy(storage_tmp.storage_mac, storage_mac, HUB_MAC_STR_LEN); } else if (!storage_enable) { storage_tmp.storage_tmp_enabled = FALSE; storage_tmp.sync_hub_state = SYNC_HUB_SUCCESS; hub_storage_info.enabled = FALSE; report_cloud_msg_check((U8)storage_tmp.storage_tmp_enabled, &hub_storage_info); ds_advanced_write(HUB_MANAGE_STORAGE_INFO_PATH, &hub_storage_info, sizeof(HUB_MANAGE_STORAGE_INFO), DS_FLAG_NOTIFY | DS_FLAG_SAVE_FLASH); /* 当存储关闭时,检查并复制已配置的存储IP地址 */ if (0 >= strlen(hub_storage_info.ipaddr)) { ret = ERROR; goto out; } strncpy(storage_ipaddr, hub_storage_info.ipaddr, IP_STR_MAX_LEN); } else { HUB_MANAGE_ERROR("The parameter [storage_enable] error"); ret = ERROR; goto ERR; } out: /* 将临时存储配置写回指定路径 */ if (ds_write(HUB_MANAGE_STORAGE_TMP_PATH, &storage_tmp, sizeof(STORAGE_TMP_INFO)) == 0) { HUB_MANAGE_ERROR("The parameter [hub_storage] error"); ret = ERROR; goto ERR; } /* 向hub同步配置 */ if (!hub_client.http_ctx) { hub_client.http_ctx = http_client_request_hub(is_first_login, CONN_WANT_KEEPALIVE, loginSta, loginPwd, TRUE, storage_ipaddr, HUB_POST_PORT, HUB_MAN_REQ_TYPE_HUB_STORAGE, hub_http_message_handler); } else { if (0 != strcmp(hub_client.http_ctx->host, storage_ipaddr)) { /* 先断开长链接是否会有隐患? */ // hub_client.http_ctx = NULL; hub_client_session_free(hub_client.http_ctx); hub_client.http_ctx = http_client_request_hub(is_first_login, CONN_WANT_KEEPALIVE, loginSta, loginPwd, TRUE, storage_ipaddr, HUB_POST_PORT, HUB_MAN_REQ_TYPE_HUB_STORAGE, hub_http_message_handler); } else { hub_client_msg_send(hub_client.http_ctx, HUB_MAN_REQ_TYPE_HUB_STORAGE); } } ERR: if (OK != ret) { storage_tmp.sync_hub_state = SYNC_HUB_OTHER_ERR; } /* 返回执行结果 */ return ret; } /**************************************************************************** * 函数名称 : set_wifi_backup * 功能描述 : 此函数用于设置wifi_backup配置,包括读取当前功能配置信息、处理wifi_backup使能状态, * 并根据使能状态启动与hub的连接以及保存临时配置到内存ds模型中。 * 输入参数 : * backup_enable - 字符串指针,表示wifi_backup使能状态,接受"on"(启用)和"off"(关闭)。 * backup - 字符串指针,表示备份类型,可为"hub"、"router"或"auto"。 * loginSta - 登录状态枚举变量。 * is_first_login - 布尔型变量,标识是否为首次登录。 * loginPwd - 登录密码单元结构体指针。 * backup_ipaddr - 字符串指针,用于存储备份连接的IP地址。 * 输出参数 : 无 * 返回值 : * OK - 表示设置成功。 * ERROR - 表示在处理过程中发生错误。 * note : 该函数会根据备份使能状态进行一系列的操作,并在退出前将临时配置保存至内存ds模型中。 ****************************************************************************/ LOCAL S32 set_wifi_backup(S32 backup_enable, const char *backup, LOGIN_STATUS loginSta, U8 is_first_login, HUB_PWD_UNIT *loginPwd, char *backup_ipaddr) { S32 ret = OK; BACKUP_TMP_INFO backup_tmp = {0}; HUB_MANAGE_WIFI_BACKUP wifi_backup = {0}; memset(&wifi_backup, 0, sizeof(HUB_MANAGE_WIFI_BACKUP)); /* 从配置文件读取当前的wifi_backup配置 */ if (0 == ds_read(HUB_MANAGE_WIFI_BACKUP_PATH, &wifi_backup, sizeof(HUB_MANAGE_WIFI_BACKUP))) { HUB_MANAGE_ERROR("hub_info Parameter could not be NULL."); return SLP_ESYSTEM; } /* 处理wifi_backup使能状态 */ if (backup_enable) { backup_tmp.backup_tmp_enabled = TRUE; if (!backup || (0 != strcmp(backup,"hub") && 0 != strcmp(backup,"router") && 0 != strcmp(backup,"auto"))) { HUB_MANAGE_ERROR("The parameter [backup] error,%s,%s",backup,backup_enable?"on":"off"); ret = ERROR; goto ERR; } strncpy(backup_tmp.backup, backup, BACKUP_STR_MAX_LEN); strncpy(wifi_backup.backup, backup, BACKUP_STR_MAX_LEN); } else if (!backup_enable) { backup_tmp.backup_tmp_enabled = FALSE; wifi_backup.enabled = FALSE; if (0 >= strlen(wifi_backup.ipaddr)) { ret = ERROR; goto out; } strncpy(backup_ipaddr, wifi_backup.ipaddr, IP_STR_MAX_LEN); } out: /* 将临时配置保存至内存ds模型 */ ds_write(HUB_MANAGE_BACKUP_TMP_PATH, &backup_tmp, sizeof(BACKUP_TMP_INFO)); ds_advanced_write(HUB_MANAGE_WIFI_BACKUP_PATH, &wifi_backup, sizeof(HUB_MANAGE_WIFI_BACKUP), DS_FLAG_SAVE_FLASH | DS_FLAG_NOTIFY); if (OK != ret) { goto ERR; } /* 向hub同步配置 */ if (!hub_client.http_ctx || 0 != strcmp(backup_ipaddr,hub_client.http_ctx->host)) { http_client_request_hub(is_first_login, CONN_NOT_KEEPALIVE, loginSta, loginPwd, TRUE, backup_ipaddr, HUB_POST_PORT, HUB_MAN_REQ_TYPE_WIFI_BACKUP, hub_http_message_handler); } else { hub_client_msg_send(hub_client.http_ctx, HUB_MAN_REQ_TYPE_WIFI_BACKUP); } ERR: return ret; } /**************************************************************************** * Function : get_passwd_list * Description: * Input : * Output : N/A * Return : OK/ERROR ****************************************************************************/ LOCAL S32 get_passwd_list(JSON_OBJPTR param, HUB_PWD_UNIT *pwd_list) { S32 ret = OK; S32 index = 0; S32 array_len = 0; S32 encrypt_type = 0; const char *pwd = NULL; JSON_OBJPTR pwd_arr = NULL; JSON_OBJPTR pwd_list_obj = NULL; /* 检查param中hub_password_list是否存在 */ if (NULL == (pwd_list_obj = jso_obj_get(param, "hub_password_list"))) { ret = SLP_EENTRYNOTEXIST; goto out; } array_len = jso_array_length(pwd_list_obj); /* 防止数组访问越界 */ if (array_len > HUB_PASSWD_LIST_NUM) { array_len = HUB_PASSWD_LIST_NUM; } for(index = 0; index < array_len; index++) { pwd_arr = jso_array_get_idx(pwd_list_obj, index); if (NULL ==(pwd = jso_obj_get_string_origin(pwd_arr,"password"))) { ret = SLP_EINVARG; goto out; } strncpy(pwd_list[index].passwd, pwd, SHA256_BLOCK_SIZE); if (-1 == jso_obj_get_int(pwd_arr, "encrypt_type", &encrypt_type)) { ret = SLP_EINVARG; goto out; } pwd_list[index].encrypt_type = encrypt_type; HUB_MANAGE_WARNING("get passwd:%s, encrypt_type: %d", pwd_list[index].passwd, pwd_list[index].encrypt_type); } out: return ret; } /**************************************************************************** * Function : search_scan_list * Description: * Input : * Output : N/A * Return : OK/ERROR ****************************************************************************/ LOCAL S32 search_scan_list(const char *hub_mac, char *ipaddr) { S32 ret = 0; S32 hub_count = 0; S32 index_hs = 0; char item_path_hs[HUB_TDP_SCAN_LIST_PATH_SIZE] = {0}; TDP_SCAN_LIST_INFO scan_list = {{0}}; if (!ipaddr) { HUB_MANAGE_ERROR("ipaddr ptr is null"); ret = ERROR; goto out; } if (0 == (hub_count = ds_section_list_count(HUB_TDP_SCAN_LIST_PATH))) { HUB_MANAGE_ERROR("section num of %s cann't be 0", HUB_TDP_SCAN_LIST_PATH); ret = ERROR; goto out; } /* 遍历所有scan list参数 */ for (index_hs = 0; index_hs < hub_count; index_hs++) { snprintf(item_path_hs, HUB_TDP_SCAN_LIST_PATH_SIZE, "%s%d", HUB_TDP_SCAN_LIST_PATH_PREFIX, index_hs + 1); HUB_MANAGE_ERROR("path is %s, path size is %d.", item_path_hs, HUB_TDP_SCAN_LIST_PATH_SIZE); if (0 != ds_read(item_path_hs, &scan_list, sizeof(TDP_SCAN_LIST_INFO))) { if (!scan_list.mac[0] || HUB_MAC_STR_LEN != strlen(scan_list.mac)) { HUB_MANAGE_ERROR("hub scan mac is null"); ret = ERROR; goto out; } if (0 == strcmp(scan_list.mac, hub_mac) && '\0' != scan_list.ipaddr[0]) { strncpy(ipaddr, scan_list.ipaddr, IP_STR_MAX_LEN); break; } } } if (0 == strlen(ipaddr)) { HUB_MANAGE_ERROR("don't find corresponding scan info!"); ret = ERROR; } out: return ret; } /**************************************************************************** * Function : tdp_scan_timer_handle * Description: * Input : * Output : N/A * Return : OK/ERROR ****************************************************************************/ LOCAL S32 wifi_backup_info_parse(JSON_OBJPTR wifi_backup_obj) { S32 ret = OK; S32 index = OK; U8 is_first_login = 0; S32 is_backup_enable = 0; const char *backup_enable = NULL; const char *wifi_mac = NULL; const char *backup = NULL; const char *ip_supply = NULL; char backup_ipaddr[IP_STR_MAX_LEN + 1] = {0}; LOGIN_STATUS loginSta = STATUS_NOT_LOGIN; HUB_MANAGE_WIFI_BACKUP wifi_backup; HUB_PWD_UNIT hub_wifi_passwd_list[HUB_PASSWD_LIST_NUM] = {{0}}; memset(&wifi_backup, 0, sizeof(HUB_MANAGE_WIFI_BACKUP)); if (0 == ds_read(HUB_MANAGE_WIFI_BACKUP_PATH, &wifi_backup, sizeof(HUB_MANAGE_WIFI_BACKUP))) { HUB_MANAGE_ERROR("hub_info Parameter could not be NULL."); return SLP_ESYSTEM; } backup_enable = jso_obj_get_string_origin(wifi_backup_obj, "backup_enabled"); if (!backup_enable) { HUB_MANAGE_ERROR("The parameter [backup_enabled] error"); ret = ERROR; goto ERR; } else if (0 == strcmp(backup_enable, "on")) { is_backup_enable = 1; } else if (0 == strcmp(backup_enable, "off")) { is_backup_enable = 0; } else { HUB_MANAGE_ERROR("The value of [backup_enable] is unexpected"); ret = ERROR; goto ERR; } if (is_backup_enable) { wifi_mac = jso_obj_get_string_origin(wifi_backup_obj, "wifi_mac"); if (!wifi_mac || HUB_MAC_STR_LEN != strlen(wifi_mac)) { HUB_MANAGE_ERROR("The parameter [wifi_mac] error"); ret = ERROR; goto ERR; } backup = jso_obj_get_string_origin(wifi_backup_obj, "backup"); if (!backup) { HUB_MANAGE_ERROR("The parameter [backup] error"); ret = ERROR; goto ERR; } if (0 > get_passwd_list(wifi_backup_obj, hub_wifi_passwd_list)) { HUB_MANAGE_ERROR("get hub passwd error"); ret = ERROR; goto ERR; } if (hub_wifi_passwd_list[0].passwd[0] == '\0') { if (g_hub_wifi_passwd_list[0].passwd[0] != '\0') { for(index = 0; index < HUB_PASSWD_LIST_NUM && g_hub_wifi_passwd_list[0].passwd[0] != '\0'; index++) { //添加hub password信息 strncpy(hub_wifi_passwd_list[0].passwd, g_hub_wifi_passwd_list[0].passwd, SHA256_BLOCK_SIZE); } } } is_first_login = 1; ip_supply = jso_obj_get_string_origin(wifi_backup_obj, "ipaddr"); if (NULL == ip_supply) { /* 当app传入ip为空时,搜索扫描列表,获取存储设备IP */ ret = search_scan_list(wifi_mac, backup_ipaddr); if (OK != ret) { HUB_MANAGE_ERROR("parse ipaddr err and search scan list err"); ret = SLP_ELACKARG; goto ERR; } } else { strncpy(backup_ipaddr, ip_supply, IP_STR_MAX_LEN); } } set_wifi_backup(is_backup_enable, backup, loginSta, is_first_login, hub_wifi_passwd_list, backup_ipaddr); ERR: return ret; } /**************************************************************************** * 函数名称 : hub_storage_info_parse * 功能描述 : 解析hubhub_storage * 输入参数 : hub_storage_obj - 存储配置的JSON对象指针 * 输出参数 : 无 * 返回值 : OK表示成功,ERROR表示失败 ****************************************************************************/ LOCAL S32 hub_storage_info_parse(JSON_OBJPTR hub_storage_obj) { S32 ret = OK; S32 index = OK; S32 is_first_login = 0; S32 is_storage_enable = 0; LOGIN_STATUS loginSta = STATUS_NOT_LOGIN; const char *storage_enable = NULL; /* 存储是否启用 */ const char *storage_mac = NULL; /* 存储设备的MAC地址 */ const char *ip_supply = NULL; char storage_ipaddr[IP_STR_MAX_LEN + 1] = {0}; /* 存储设备的IP地址 */ HUB_PWD_UNIT hub_sto_passwd_list[HUB_PASSWD_LIST_NUM] = {{0}}; /* 存储设备的密码列表 */ /* 获取并校验"storage_enabled"参数 */ storage_enable = jso_obj_get_string_origin(hub_storage_obj, "storage_enabled"); if (!storage_enable) { HUB_MANAGE_ERROR("The parameter [storage_enabled] null"); ret = ERROR; goto ERR; } else if (0 == strcmp(storage_enable, "on")) { is_storage_enable = 1; } else if (0 == strcmp(storage_enable, "off")) { is_storage_enable = 0; } else { HUB_MANAGE_ERROR("The value of [storage_enabled] is unexpected"); ret = ERROR; goto ERR; } /* 当存储启用时,进一步解析配置 */ if (is_storage_enable) { /* 获取并校验hub_storage mac合法性 */ storage_mac = jso_obj_get_string_origin(hub_storage_obj, "storage_mac"); if (!storage_mac || HUB_MAC_STR_LEN != strlen(storage_mac)) { HUB_MANAGE_ERROR("The parameter [storage_mac] error"); ret = ERROR; goto ERR; } /* 获取密码列表 */ if (0 > get_passwd_list(hub_storage_obj, hub_sto_passwd_list)) { HUB_MANAGE_ERROR("get hub passwd error"); ret = ERROR; goto ERR; } /* 用于Debug接口,手动设置hub login秘钥 */ if (hub_sto_passwd_list[0].passwd[0] == '\0') { if (g_hub_sto_passwd_list[0].passwd[0] != '\0') { for(index = 0; index < HUB_PASSWD_LIST_NUM && g_hub_sto_passwd_list[0].passwd[0] != '\0'; index++) { /* 添加hub password信息 */ strncpy(hub_sto_passwd_list[0].passwd, g_hub_sto_passwd_list[0].passwd, SHA256_BLOCK_SIZE); } } } is_first_login = 1; /* 标记为首次登录 */ ip_supply = jso_obj_get_string_origin(hub_storage_obj, "ipaddr"); if (NULL == ip_supply || !ip_supply[0]) { /* 当app传入ip为空时,搜索扫描列表,获取存储设备IP */ ret = search_scan_list(storage_mac, storage_ipaddr); if (OK != ret) { HUB_MANAGE_ERROR("parse ipaddr err and get scan list err"); ret = SLP_ELACKARG; goto ERR; } } else { strncpy(storage_ipaddr, ip_supply, IP_STR_MAX_LEN); } } /* 设置hub存储配置 */ set_hub_storage(is_storage_enable, storage_mac, loginSta, is_first_login, hub_sto_passwd_list, storage_ipaddr); ERR: return ret; } /***************************************************************************** * 函数名称 : hub_config_resync_handle * 功能描述 :处理异常情况的重新同步流程 * 输入参数 : 无 * 输出参数 : 无 * 返回值 : OK - 表示成功执行,ERROR - 表示执行失败 ****************************************************************************/ S32 hub_config_resync_handle(S32 resetSync) { HUB_MANAGE_STORAGE_INFO hub_info = {0}; /* 初始化hub_storage结构体 */ HUB_MANAGE_CFG_ASYNC_RECORD async_record = {0}; /* 初始化未同步信息结构体 */ /* 若存在未完成的重新同步定时器,则删除并重置其ID */ if (ERROR != g_resync_timer_id) { inet_del_timer(g_resync_timer_id); g_resync_timer_id = ERROR; } if (ds_read(HUB_MANAGE_CFG_ASYNC_RECORD_PATH, (U8 *)&async_record, sizeof(HUB_MANAGE_CFG_ASYNC_RECORD)) == 0) { HUB_MANAGE_ERROR("read async cfg info fail."); return ERROR; } if (0 == async_record.async_cfg) { HUB_MANAGE_INFO("none config is async."); return OK; } if (ds_read(HUB_MANAGE_STORAGE_INFO_PATH, (U8 *)&hub_info, sizeof(HUB_MANAGE_STORAGE_INFO)) == 0) { HUB_MANAGE_ERROR("read hub_info fail."); return ERROR; } /* 如果存在未处理的异步配置请求,如解绑失败,则进行同步 */ if (0 != (async_record.async_cfg & (1 << HUB_MAN_ASYNC_TYPE_SYNC_CONFIG))) { HUB_MANAGE_INFO("read async cfg: %d", async_record.async_cfg); /* 检查并处理待同步的配置请求 */ if (hub_client.http_ctx) { hub_client_msg_send(hub_client.http_ctx, HUB_MAN_REQ_TYPE_SYNC_CONFIG); } else if ('\0' != hub_info.ipaddr[0] && hub_info.enabled) { hub_client.http_ctx = http_client_request_hub(0, CONN_WANT_KEEPALIVE, STATUS_NOT_LOGIN, NULL, TRUE, hub_info.ipaddr, HUB_POST_PORT, HUB_MAN_REQ_TYPE_SYNC_CONFIG, hub_http_message_handler); } else if ('\0' != hub_info.ipaddr[0] && !hub_info.enabled) { http_client_request_hub(0, CONN_NOT_KEEPALIVE, STATUS_NOT_LOGIN, NULL, TRUE, hub_info.ipaddr, HUB_POST_PORT, HUB_MAN_REQ_TYPE_SYNC_CONFIG, hub_http_message_handler); } } else if (0 != (async_record.async_cfg & (1 << HUB_MAN_ASYNC_TYPE_UNBIND_CONFIG)) && 0 == (async_record.async_cfg & (1 << HUB_MAN_ASYNC_TYPE_SYNC_CONFIG))) { /* 当存在已换绑但未同步的配置时,进行配置同步 */ sync_info_to_unbind_hub(); } return OK; } LOCAL S32 http_client_resync_hub_handle() { HUB_MANAGE_CFG_ASYNC_RECORD async_record = {0}; /* 初始化异步记录结构体 */ if (ds_read(HUB_MANAGE_CFG_ASYNC_RECORD_PATH, (U8 *)&async_record, sizeof(HUB_MANAGE_CFG_ASYNC_RECORD)) == 0) { HUB_MANAGE_ERROR("read async cfg info fail."); return ERROR; } if (0 == (async_record.async_cfg & (1 << HUB_MAN_ASYNC_TYPE_SYNC_CONFIG))) { async_record.async_cfg |= (1 << HUB_MAN_ASYNC_TYPE_SYNC_CONFIG); if (ds_advanced_write(HUB_MANAGE_CFG_ASYNC_RECORD_PATH, &async_record, sizeof(HUB_MANAGE_CFG_ASYNC_RECORD), DS_FLAG_SAVE_FLASH) == 0) { HUB_MANAGE_ERROR("write async_record fail."); return ERROR; } } hub_resync_prepare(FALSE); return OK; /* 函数执行结束,返回结果状态 */ } void hub_resync_param_reset() { HUB_MANAGE_CFG_ASYNC_RECORD async_record = {0}; /* 初始化未同步信息结构体 */ /* 若存在未完成的重新同步定时器,则删除并重置其ID */ resync_delay_sec = 0; hub_client.recon_delay = 0; if (ERROR != g_resync_timer_id) { inet_del_timer(g_resync_timer_id); g_resync_timer_id = ERROR; } if (ds_read(HUB_MANAGE_CFG_ASYNC_RECORD_PATH, (U8 *)&async_record, sizeof(HUB_MANAGE_CFG_ASYNC_RECORD)) == 0) { HUB_MANAGE_ERROR("read async cfg info fail."); return; } if (0 != (async_record.async_cfg)) { /* 设置新的同步定时器 */ resync_delay_sec = hub_manage_sync_retry(resync_delay_sec); g_resync_timer_id = inet_add_timer(hub_config_resync_handle, 0, resync_delay_sec, EXECUTE_SINGLE); } return; } void hub_resync_prepare(S32 refresh) { if (refresh || ERROR != g_resync_timer_id) { inet_del_timer(g_resync_timer_id); g_resync_timer_id = ERROR; } /* 设置新的同步定时器 */ resync_delay_sec = hub_manage_sync_retry(resync_delay_sec); g_resync_timer_id = inet_add_timer(hub_config_resync_handle, 0, resync_delay_sec, EXECUTE_SINGLE); return; } /*------------------------------------------------------------------------------------------------*/ /* ds注册接口回调 */ /*------------------------------------------------------------------------------------------------*/ /**************************************************************************** * 函数名称:tdp_scan_timer_handle * 功能描述:处理扫描列表的定时器事件,读取并组装扫描到的设备信息 * 输入参数: * context - 上下文结构体指针,包含相关资源对象 * params - 参数JSON对象指针 * 输出参数:无 * 返回值:OK表示成功,ERROR表示失败 ****************************************************************************/ LOCAL S32 hub_list_handle(DS_HANDLE_CONTEXT *context, JSON_OBJPTR params) { S32 ret = 0; S32 hub_count = 0; S32 index_hs = 0; JSON_OBJPTR hub_list = NULL; JSON_OBJPTR hub_scan_info = NULL; char item_path_hs[HUB_TDP_SCAN_LIST_PATH_SIZE] = {0}; TDP_SCAN_LIST_INFO scan_list = {{0}}; TDPC_SRCH_STATUS srch_sta = {0}; /* 检查输入参数是否有效 */ if (NULL == context || NULL == context->res_obj || NULL == params) { HUB_MANAGE_ERROR("ipaddr ptr is null"); ret = ERROR; goto out; } /* 创建并初始化hub_list数组,用于存储扫描结果 */ if (NULL == (hub_list = jso_new_array())) { ret = SLP_ENOMEMORY; goto out; } jso_obj_add(context->res_obj, "hub_list", hub_list); /* 获取待扫描的设备数量 */ hub_count = ds_section_list_count(HUB_TDP_SCAN_LIST_PATH); HUB_MANAGE_DEBUG("section num of %s is %d", HUB_TDP_SCAN_LIST_PATH, hub_count); /* 遍历所有待扫描设备,并将其信息添加至hub_list数组 */ for (index_hs = 0; index_hs < hub_count; index_hs++) { snprintf(item_path_hs, HUB_TDP_SCAN_LIST_PATH_SIZE, "%s%d", HUB_TDP_SCAN_LIST_PATH_PREFIX, index_hs + 1); HUB_MANAGE_DEBUG("path is %s, path size is %d.", item_path_hs, HUB_TDP_SCAN_LIST_PATH_SIZE); /* 读取单个设备扫描信息 */ if (0 != ds_read(item_path_hs, &scan_list, sizeof(TDP_SCAN_LIST_INFO))) { /* 如果MAC地址无效,则跳过该设备 */ if (!scan_list.mac[0] || HUB_MAC_STR_LEN != strlen(scan_list.mac)) { HUB_MANAGE_ERROR("hub scan mac error"); continue; } /* 创建并初始化一个用于存储设备详细扫描信息的对象 */ if (NULL == (hub_scan_info = jso_new_obj())) { HUB_MANAGE_ERROR("[Error] failed to create hub_scan_info"); ret = SLP_ENOMEMORY; break; } /* 将扫描信息对象添加至hub_list数组 */ jso_array_add(hub_list, hub_scan_info); /* 添加设备的基本信息至扫描信息对象 */ jso_add_string(hub_scan_info, "mac", scan_list.mac); jso_add_string(hub_scan_info, "type", scan_list.type); jso_add_string(hub_scan_info, "model", scan_list.model); jso_add_string(hub_scan_info, "alias", scan_list.alias); jso_add_int(hub_scan_info, "ai_hub_support", scan_list.ai_hub_support); jso_add_int(hub_scan_info, "current_bound", scan_list.current_bound); jso_add_int(hub_scan_info, "max_bound", scan_list.max_bound); } } /* 读取搜索状态并添加至响应对象 */ if (0 == ds_read(TDPC_SRCH_STATUS_PATH, &srch_sta, sizeof(TDPC_SRCH_STATUS))) { HUB_MANAGE_ERROR("read srch_sta fail."); ret = ERROR; } else { jso_add_string(context->res_obj, "scan_status", srch_sta.scan_status?"scanning":"idle"); } out: return ret; } /***************************************************************************** * 函数名称 : set_hub_config_handle * 功能描述 : 处理设置Hub配置的请求 * 输入参数 : * context - DS_HANDLE_CONTEXT类型的指针,用于传递执行上下文信息 * params - JSON_OBJPTR类型的指针,指向包含配置参数的JSON对象 * 输出参数 : 无 * 返回值 : OK表示处理成功,ERROR表示处理失败 ****************************************************************************/ LOCAL S32 set_hub_config_handle(DS_HANDLE_CONTEXT *context, JSON_OBJPTR params) { S32 ret = ERROR; JSON_OBJPTR wifi_backup_obj = NULL; /* 用于存储Wi-Fi备份信息的JSON对象指针 */ JSON_OBJPTR hub_storage_obj = NULL; /* 用于存储Hub存储配置的JSON对象指针 */ /* 检查输入参数是否有效 */ if (NULL == context || NULL == params) { HUB_MANAGE_ERROR("No params in request."); ret = ERROR; goto ERR; /* 参数无效跳过解析 */ } /* 解析Wi-Fi备份信息 */ wifi_backup_obj = jso_obj_get(params, "wifi_backup"); if (NULL != wifi_backup_obj) { ret = wifi_backup_info_parse(wifi_backup_obj); if (OK != ret) { HUB_MANAGE_ERROR("wrong params in wifi_backup request."); } } /* 解析Hub存储配置 */ hub_storage_obj = jso_obj_get(params, "hub_storage"); if (NULL != hub_storage_obj) { ret = hub_storage_info_parse(hub_storage_obj); if (OK != ret) { HUB_MANAGE_ERROR("wrong params in hub_storage request."); } } ERR: return ret; } LOCAL S32 hub_reset_sync_handle(DS_HANDLE_CONTEXT *context, JSON_OBJPTR params) { S32 ret = 0; const char *hub_mac = NULL; HUB_MANAGE_WIFI_BACKUP wifi_info = {0}; /* 检查输入参数是否有效 */ if (NULL == context || NULL == params) { HUB_MANAGE_ERROR("No params in request."); ret = ERROR; goto END; /* 遇到错误时直接返回 */ } HUB_MANAGE_INFO(" recv hub reset sync msg."); hub_mac = jso_obj_get_string_origin(params, "hub_mac"); if (!hub_mac) { HUB_MANAGE_ERROR("The parameter [hub_mac] error"); ret = ERROR; goto END; } hub_client_stop(); clear_hub_storage_info(); if (0 == ds_read(HUB_MANAGE_WIFI_BACKUP_PATH, &wifi_info, sizeof(HUB_MANAGE_WIFI_BACKUP))) { HUB_MANAGE_ERROR("read wifi info error."); return ERROR; } if (0 == strcmp(wifi_info.hubMac, hub_mac)) { memset(&wifi_info, 0, sizeof(HUB_MANAGE_WIFI_BACKUP)); ds_advanced_write(HUB_MANAGE_WIFI_BACKUP_PATH, &wifi_info, sizeof(HUB_MANAGE_WIFI_BACKUP), DS_FLAG_SAVE_FLASH | DS_FLAG_NOTIFY); } END: return ret; } /*------------------------------------------------wifi_backup---------------------------------------------------*/ LOCAL S32 get_wifi_backup_info(DS_HANDLE_CONTEXT *context, JSON_OBJPTR section_obj) { HUB_MANAGE_WIFI_BACKUP wifi_info = {0}; HUB_MANAGE_STORAGE_INFO hub_storage_info = {0}; STORAGE_TMP_INFO storage_tmp = {0}; if (0 == ds_read(HUB_MANAGE_WIFI_BACKUP_PATH, &wifi_info, sizeof(HUB_MANAGE_WIFI_BACKUP))) { HUB_MANAGE_ERROR("hub_info Parameter could not be NULL."); return ERROR; } if (0 == ds_read(HUB_MANAGE_STORAGE_INFO_PATH, &hub_storage_info, sizeof(HUB_MANAGE_STORAGE_INFO))) { HUB_MANAGE_ERROR("hub_storage Parameter could not be NULL."); return ERROR; } if (0 == ds_read(HUB_MANAGE_STORAGE_TMP_PATH, &storage_tmp, sizeof(STORAGE_TMP_INFO))) { HUB_MANAGE_ERROR("storage_tmp Parameter could not be NULL."); return ERROR; } jso_add_string(section_obj, "enabled", wifi_info.enabled?"on":"off"); jso_add_string(section_obj, "backup", wifi_info.backup); if (0 < strlen(wifi_info.hubMac) && wifi_info.enabled) { jso_add_string(section_obj, "wifi_mac", wifi_info.hubMac); if (!strcmp(wifi_info.hubMac, hub_storage_info.hub_mac)) { jso_add_string(section_obj, "status", (storage_tmp.offline >= TURN_OFFLINE_BOUND_TIMES)?"offline":"online"); } else { jso_add_string(section_obj, "status", "online"); } } HUB_MANAGE_DEBUG("\n" "**************************************************\n" "backup wifi info:\n" "ipaddr:%s\n" "ssid:%s\n" "bssid:%s\n" "asyncIp:%s\n" "asyncMac:%s\n" "**************************************************\n", wifi_info.ipaddr, wifi_info.ssid, wifi_info.bssid, wifi_info.asyncIp, wifi_info.asyncMac); return SLP_ENONE; } /*----------------------------------------------hub_storage--------------------------------------------------*/ LOCAL S32 get_storage_info(DS_HANDLE_CONTEXT *context, JSON_OBJPTR section_obj) { HUB_MANAGE_STORAGE_INFO hub_storage_info = {0}; STORAGE_TMP_INFO storage_tmp = {0}; int offline = 0; if (0 == ds_read(HUB_MANAGE_STORAGE_TMP_PATH, &storage_tmp, sizeof(STORAGE_TMP_INFO))) { HUB_MANAGE_ERROR("read storage tmp info fail."); return ERROR; } if (0 == ds_read(HUB_MANAGE_STORAGE_INFO_PATH, &hub_storage_info, sizeof(HUB_MANAGE_STORAGE_INFO))) { HUB_MANAGE_ERROR("hub_storage Parameter could not be NULL."); return ERROR; } jso_add_string(section_obj, "enabled", hub_storage_info.enabled?"on":"off"); jso_add_int(section_obj, "storage_media_status", hub_storage_info.storage_media_status); jso_add_string(section_obj, "last_stored_mac", storage_tmp.last_stored_mac); if (TURN_OFFLINE_BOUND_TIMES <= storage_tmp.offline) { offline = 1; } if (0 < strlen(hub_storage_info.ipaddr) && hub_storage_info.enabled) { jso_add_string(section_obj, "storage_mac", hub_storage_info.hub_mac); jso_add_string(section_obj, "status", offline?"offline":"online"); } HUB_MANAGE_DEBUG("\n" "**************************************************\n" "storage info:\n" "dev_id:%s\n" "ipaddr:%s\n" "model:%s\n" "type:%s\n" "auth_type:%s\n" "asyncIp:%s\n" "asyncMac:%s\n" "max_bound:%d\n" "**************************************************\n", hub_storage_info.dev_id, hub_storage_info.ipaddr, hub_storage_info.model, hub_storage_info.type, hub_storage_info.auth_type, hub_storage_info.asyncIp, hub_storage_info.asyncMac, hub_storage_info.max_bound); return SLP_ENONE; } LOCAL S32 sync_hub_state_handle(DS_HANDLE_CONTEXT *context, JSON_OBJPTR params) { STORAGE_TMP_INFO storage_tmp = {0}; /* 检查输入参数是否有效 */ if (NULL == context || NULL == context->res_obj) { HUB_MANAGE_ERROR("context is null"); return ERROR; } if (0 == ds_read(HUB_MANAGE_STORAGE_TMP_PATH, &storage_tmp, sizeof(STORAGE_TMP_INFO))) { HUB_MANAGE_ERROR("storage tmp could not be NULL."); return ERROR; } switch (storage_tmp.sync_hub_state) { case SYNC_HUB_IDLE: jso_add_string(context->res_obj, "sync_hub_state", "idle"); break; case SYNC_HUB_SYNCING: jso_add_string(context->res_obj, "sync_hub_state", "syncing"); break; case SYNC_HUB_UNLOCAL: jso_add_string(context->res_obj, "sync_hub_state", "unlocalErr"); break; case SYNC_HUB_OTHER_ERR: jso_add_string(context->res_obj, "sync_hub_state", "otherErr"); break; case SYNC_HUB_SUCCESS: jso_add_string(context->res_obj, "sync_hub_state", "success"); break; default: /* 对未知类型的消息不进行处理 */ HUB_MANAGE_ERROR("unknown state:%d.",storage_tmp.sync_hub_state); return SLP_ESYSTEM; } HUB_MANAGE_DEBUG("sync_hub_state:%d.",storage_tmp.sync_hub_state); return SLP_ENONE; } /*------------------------------------------------------------------------------------------------*/ /* ubus回调函数 */ /*------------------------------------------------------------------------------------------------*/ /***************************************************************************** * 函数名称:hub_manage_reset_msg_handle * 功能描述:处理与HUB管理相关的重置消息,reset时需要发送HTTP请求通知hub * 输入参数: * handler - dms_handler_t类型的指针(未在示例中使用,推测为句柄) * mbuf - 消息缓冲区指针 * mlen - 消息长度 * sender_dms_id - 发送者DMS ID * 输出参数:无 * 返回值:OK表示成功,ERROR表示失败 *****************************************************************************/ LOCAL S32 hub_manage_reset_msg_handle(dms_handler_t *handler, U8 *mbuf, U32 mlen, U32 sender_dms_id) { S32 ret = OK; HUB_MANAGE_STORAGE_INFO hub_storage = {0}; HUB_MANAGE_WIFI_BACKUP wifi_backup = {0}; STORAGE_TMP_INFO storage_tmp = {0}; BACKUP_TMP_INFO wifi_backup_tmp = {0}; /* 从指定路径读取wifi_backup信息,若读取失败则输出错误信息并返回错误码 */ if (0 == ds_read(HUB_MANAGE_WIFI_BACKUP_PATH, &wifi_backup, sizeof(HUB_MANAGE_WIFI_BACKUP))) { HUB_MANAGE_ERROR("hub_info Parameter could not be NULL."); return SLP_ESYSTEM; } /* 若wifi_backup已启用且IP地址非空,则禁用wifi_backup功能 */ if (TRUE == wifi_backup.enabled && '\0' != wifi_backup.ipaddr[0]) { wifi_backup.enabled = FALSE; wifi_backup_tmp.backup_tmp_enabled = FALSE; } /* 从指定路径读取hub_storage,若读取失败则报错 */ if (ds_read(HUB_MANAGE_STORAGE_INFO_PATH, (U8 *)&hub_storage, sizeof(HUB_MANAGE_STORAGE_INFO)) == 0) { HUB_MANAGE_ERROR("read hub_info fail."); ret = ERROR; goto END; } /* 若存储功能已启用且IP地址非空,则禁用存储功能 */ if (TRUE == hub_storage.enabled && '\0' != hub_storage.ipaddr[0]) { hub_storage.enabled = FALSE; storage_tmp.storage_tmp_enabled = FALSE; } /* 将更新后的hub_storage写入指定路径,若写入失败则输出错误信息并将ret设为错误 */ if (ds_write(HUB_MANAGE_STORAGE_TMP_PATH, &storage_tmp, sizeof(STORAGE_TMP_INFO)) == 0) { HUB_MANAGE_ERROR("The parameter [hub_storage] error"); ret = ERROR; goto END; } if (ds_write(HUB_MANAGE_STORAGE_INFO_PATH, &hub_storage, sizeof(HUB_MANAGE_STORAGE_INFO)) == 0) { HUB_MANAGE_ERROR("ds_write hub_storage error."); ret = ERROR; goto END; } /* 将更新后的wifi_backup信息写入指定路径,若写入失败则输出错误信息并将ret设为错误 */ if (ds_write(HUB_MANAGE_BACKUP_TMP_PATH, &wifi_backup_tmp, sizeof(BACKUP_TMP_INFO)) == 0) { HUB_MANAGE_ERROR("The parameter [wifi_backup] error"); ret = ERROR; goto END; } if (0 == ds_write(HUB_MANAGE_WIFI_BACKUP_PATH, &wifi_backup, sizeof(HUB_MANAGE_WIFI_BACKUP))) { HUB_MANAGE_ERROR("ds_write wifi_backup error."); goto END; } /* 使用新的hub_storage发起HTTP请求到Hub设备 */ if (!hub_client.http_ctx) { http_client_request_hub(0, CONN_NOT_KEEPALIVE, STATUS_LOGIN_FINISH, NULL, TRUE, hub_storage.ipaddr, HUB_POST_PORT, HUB_MAN_REQ_TYPE_SYNC_CONFIG, hub_http_message_handler); } else { hub_client_msg_send(hub_client.http_ctx, HUB_MAN_REQ_TYPE_SYNC_CONFIG); } END: /* 返回执行结果状态 */ return ret; } /**************************************************************************** * Function : hub_storage_reset_cb * Description: 当需要重置Hubhub_storage时调用的回调函数。 * Input : *handler - 指向dms_handler_t结构体的指针,用于处理存储管理相关的操作。 * *mbuf - 指向包含消息体的缓冲区的指针。 * mlen - 消息体长度。 * sender_dms_id - 发送请求的DMS的ID。 * Output : N/A * Return : OK/ERROR - 函数执行成功返回SLP_ENONE(通常表示无错误)。 ****************************************************************************/ LOCAL S32 hub_storage_reset_cb(dms_handler_t *handler, U8 *mbuf, U32 mlen, U32 sender_dms_id) { HUB_MANAGE_STORAGE_INFO hub_storage_info = {0}; HUB_MANAGE_WIFI_BACKUP wifi_info = {0}; ds_read(HUB_MANAGE_STORAGE_INFO_PATH, &hub_storage_info, sizeof(HUB_MANAGE_STORAGE_INFO)); clear_hub_storage_info(); HUB_MANAGE_ERROR("hub storage reset success "); if (0 == strcmp(wifi_info.hubMac, hub_storage_info.hub_mac)) { memset(&wifi_info, 0, sizeof(HUB_MANAGE_WIFI_BACKUP)); ds_advanced_write(HUB_MANAGE_WIFI_BACKUP_PATH, &wifi_info, sizeof(HUB_MANAGE_WIFI_BACKUP), DS_FLAG_SAVE_FLASH | DS_FLAG_NOTIFY); } return SLP_ENONE; } /**************************************************************************** * 函数名称 : tdp_client_out_msg_handle * 功能描述 : 处理TDP客户端发出的消息 * 输入参数 : * handler - 处理器句柄,用于标识消息处理的上下文 * mbuf - 指向消息缓冲区的指针 * mlen - 消息缓冲区的长度 * sender_dms_id - 发送消息的DMS ID * 输出参数 : 无 * 返回值 : OK - 消息处理成功,ERROR - 消息处理失败 ****************************************************************************/ LOCAL S32 tdp_client_out_msg_handle(dms_handler_t *handler, U8 *mbuf, U32 mlen, U32 sender_dms_id) { TDP_CLIENT_OUT_MSG *msg = (TDP_CLIENT_OUT_MSG *)mbuf; if ((NULL == mbuf) || (mlen != sizeof(TDP_CLIENT_OUT_MSG))) { return ERROR; } /* 根据消息类型处理消息 */ switch (msg->type) { case TC_TYPE_OUT_RESYNC_CONFIG: /* 处理重同步配置消息 */ http_client_resync_hub_handle(); break; default: /* 对未知类型的消息不进行处理 */ break; } return OK; } LOCAL S32 hub_info_update_cb(dms_handler_t *handler, U8 *mbuf, U32 mlen, U32 sender_dms_id) { HUB_INFO_UPDATE_MSG *msg = (HUB_INFO_UPDATE_MSG *)mbuf; if ((NULL == mbuf) || (mlen != sizeof(HUB_INFO_UPDATE_MSG))) { return ERROR; } /* 根据消息类型处理消息 */ HUB_MANAGE_STORAGE_INFO hub_storage_info = {0}; if (0 == ds_read(HUB_MANAGE_STORAGE_INFO_PATH, &hub_storage_info, sizeof(HUB_MANAGE_STORAGE_INFO))) { HUB_MANAGE_ERROR("hub_storage Parameter could not be NULL."); return ERROR; } if (hub_storage_info.storage_media_status != msg->media_sta) { hub_storage_info.storage_media_status = msg->media_sta; ds_advanced_write(HUB_MANAGE_STORAGE_INFO_PATH, &hub_storage_info, sizeof(HUB_MANAGE_STORAGE_INFO), DS_FLAG_NOTIFY | DS_FLAG_SAVE_FLASH); } return OK; } /**************************************************************************** * Function : hub_client_timer_handler * Description: * Input : N/A * Output : N/A * Return : 0(OK)/-1(ERROR) ****************************************************************************/ void hub_client_timer_handler() { HUB_MANAGE_STORAGE_INFO hub_storage_info = {0}; HUB_AUTH_USER_MANAGEMENT hub_auth_mgt = {{0}}; HUB_PWD_UNIT hub_passwd_list[HUB_PASSWD_LIST_NUM] = {{0}}; if (hub_client.resync_timer != ERROR) { inet_del_timer(hub_client.resync_timer); hub_client.resync_timer = ERROR; } if (hub_client.http_ctx) { HUB_MANAGE_INFO("hub client already connect"); return; } if (0 == ds_read(HUB_MANAGE_STORAGE_INFO_PATH, &hub_storage_info, sizeof(HUB_MANAGE_STORAGE_INFO))) { HUB_MANAGE_ERROR("hub_storage Parameter could not be NULL."); return; } if (0 == ds_read(HUB_AUTH_PATH, &hub_auth_mgt, sizeof(HUB_AUTH_USER_MANAGEMENT))) { HUB_MANAGE_ERROR("read hub_auth info error"); return; } if(hub_auth_mgt.passwd[0] != '\0') { strncpy(hub_passwd_list[0].passwd, hub_auth_mgt.passwd, SHA256_BLOCK_SIZE); } if(camera_force_hub_configuration_synchronization_flag != 0) { HUB_MANAGE_ERROR("camera_force_hub_configuration_synchronization"); hub_client.http_ctx = http_client_request_hub(FALSE, CONN_WANT_KEEPALIVE, STATUS_NOT_LOGIN, hub_passwd_list, FALSE, g_hub_force_ip, g_hub_force_port, HUB_MAN_REQ_TYPE_SYNC_CONFIG, hub_http_message_handler); }else { hub_client.http_ctx = http_client_request_hub(FALSE, CONN_WANT_KEEPALIVE, STATUS_NOT_LOGIN, hub_passwd_list, TRUE, hub_storage_info.ipaddr, HUB_POST_PORT, HUB_MAN_REQ_TYPE_SYNC_CONFIG, hub_http_message_handler); } // hub_client.http_ctx = http_client_request_hub(FALSE, CONN_WANT_KEEPALIVE, STATUS_NOT_LOGIN, hub_passwd_list, TRUE, // hub_storage_info.ipaddr, HUB_POST_PORT, HUB_MAN_REQ_TYPE_SYNC_CONFIG, hub_http_message_handler); if (!hub_client.http_ctx) { HUB_MANAGE_ERROR("hub client creat failed."); hub_client.recon_delay = hub_manage_sync_retry(hub_client.recon_delay); hub_keepalive_client_start(hub_client.recon_delay); return; } return; } /**************************************************************************** * Function : hub_keepalive_client_start * Description: * Input : delay_ms * Output : N/A * Return : 0(OK)/-1(ERROR) ****************************************************************************/ void hub_keepalive_client_start(int delay_sec) { HUB_MANAGE_STORAGE_INFO hub_storage = {0}; if (hub_client.resync_timer != ERROR) { inet_del_timer(hub_client.resync_timer); hub_client.resync_timer = ERROR; } if (ds_read(HUB_MANAGE_STORAGE_INFO_PATH, (U8 *)&hub_storage, sizeof(HUB_MANAGE_STORAGE_INFO)) == 0) { HUB_MANAGE_ERROR("read hub_info fail."); return; } if (!hub_storage.enabled) { HUB_MANAGE_INFO("hub_storage off,no need to link"); return; } if (delay_sec == 0) { hub_client_timer_handler(); return; } HUB_MANAGE_INFO("hub_client delay_sec %d.", delay_sec); hub_client.resync_timer = inet_add_timer(hub_client_timer_handler, 0, delay_sec, EXECUTE_SINGLE); return; } /**************************************************************************** * Function : hub_client_stop * Description: * Input : N/A * Output : N/A * Return : 0(OK)/-1(ERROR) ****************************************************************************/ void hub_client_stop() { if (!hub_client.http_ctx) { return; } hub_client.recon_delay = 0; if (ERROR != hub_client.resync_timer) { inet_del_timer(hub_client.resync_timer); hub_client.resync_timer = ERROR; } if (hub_client.http_ctx) { hub_client.http_ctx = NULL; hub_client_session_free(hub_client.http_ctx); } return; } /**************************************************************************** * Function : hub_client_restart * Description: * Input : N/A * Output : N/A * Return : 0(OK)/-1(ERROR) ****************************************************************************/ void hub_client_restart() { hub_client.recon_delay = hub_manage_sync_retry(hub_client.recon_delay); hub_keepalive_client_start(hub_client.recon_delay); return; } /*------------------------------------------------------------------------------------------------*/ /* 模块初始化注册 */ /*------------------------------------------------------------------------------------------------*/ LOCAL S32 hub_manage_deinit() { msg_detach_handler(SYSTEM_RESET_MSG_ID, hub_manage_reset_msg_handle); msg_detach_handler(HUB_STORAGE_RESET_MSG_ID, hub_storage_reset_cb); msg_detach_handler(TDP_CLIENT_OUT_MSG_ID, tdp_client_out_msg_handle); msg_attach_handler(HUB_INFO_UPDATE_MSG_ID, hub_info_update_cb); return OK; } LOCAL S32 hub_manage_init() { ds_register_action("hub_manage", "get_scan_hub_list", hub_list_handle);/* app获取当前缓存的扫描结果 */ ds_register_action("hub_manage", "hub_config_set", set_hub_config_handle);/* onboarding后配置(app调用) */ ds_register_action("hub_manage", "ai_enhance_info", get_ai_enhance_handle);/* app获取AI增強配置接口 */ ds_register_action("hub_manage", "sync_ai_enhance", sync_ai_enhance_handle);/* hub设置AI增強接口 */ ds_register_action("hub_manage", "hub_reset_sync", hub_reset_sync_handle);/* hub reset事件通知 */ ds_register_action("hub_manage", "sync_hub_state", sync_hub_state_handle);/* 获取配置开关的同步状态 */ /* 注册获取设备配置信息的 action */ ds_register_get_json("hub_manage", "wifi_backup", "wifi_backup", get_wifi_backup_info); ds_register_get_json("hub_manage", "hub_storage_info", "hub_storage_info", get_storage_info); msg_attach_handler(SYSTEM_RESET_MSG_ID, hub_manage_reset_msg_handle); msg_attach_handler(HUB_STORAGE_RESET_MSG_ID, hub_storage_reset_cb); msg_attach_handler(TDP_CLIENT_OUT_MSG_ID, tdp_client_out_msg_handle); msg_attach_handler(HUB_INFO_UPDATE_MSG_ID, hub_info_update_cb); ai_enhance_obj_init(); HUB_MANAGE_DEBUG("hub_manage init over."); return OK; } LOCAL S32 hub_manage_start() { hub_config_check(); dev_dyn_info_init(); hub_man_debug_start(); detect_support_load(); HUB_MANAGE_INFO("hub_manage start over."); return OK; } LOCAL S32 hub_manage_reload(DS_MSG *msg) { if (ds_path_id_exist(msg->id, msg->num, SYSTEM_SYS_PATH)) { SYSTEM_SYS sysInfo = {{0}}; HUB_MANAGE_STORAGE_INFO hub_info = {0}; if (ds_read(HUB_MANAGE_STORAGE_INFO_PATH, (U8 *)&hub_info, sizeof(HUB_MANAGE_STORAGE_INFO)) == 0) { HUB_MANAGE_ERROR("read hub_info fail."); return ERROR; } if (ds_read(SYSTEM_SYS_PATH, &sysInfo, sizeof(SYSTEM_SYS)) == 0) { HUB_MANAGE_ERROR("read hub_info fail."); return ERROR; } if (hub_info.ipaddr[0] == '\0') { return OK; } if (hub_client.http_ctx && (strcmp(sysInfo.avatar, g_sys_info.avatar) || strcmp(sysInfo.dev_alias, g_sys_info.dev_alias))) { hub_client_msg_send(hub_client.http_ctx, HUB_MAN_REQ_TYPE_SYNC_CONFIG); } } /* 网络连接状态发生变化 */ if (ds_path_id_exist(msg->id, msg->num, LINK_STATUS_PATH)) { LINK_STATUS link_status = {0}; ds_read(LINK_STATUS_PATH, &link_status, sizeof(LINK_STATUS)); if (LINK_UP == link_status.link_status) { HUB_MANAGE_ERROR("link status change,reload connect"); hub_keepalive_client_start(0); } } /* 图像翻转 */ if (ds_path_id_exist(msg->id, msg->num, IMAGE_SWITCH_PATH)) { FLIP_TYPE flip_type = FLIP_OFF; IMAGE_SWITCH image_switch = {0}; ds_read(IMAGE_SWITCH_PATH, &image_switch, sizeof(IMAGE_SWITCH)); flip_type = image_switch.flip_type; if (flip_type != g_last_flip_type) { g_last_flip_type = flip_type; if (hub_client.http_ctx) { hub_client_msg_send(hub_client.http_ctx, HUB_MAN_REQ_TYPE_SYNC_CONFIG); } } } return OK; } LOCAL S32 hub_manage_stop() { hub_manage_deinit(); ai_enhance_obj_deinit(); hub_man_debug_stop(); return OK; } LOCAL void hub_manage_main() { DS_DAT_MON_DESC hub_manage_data_monitor[] = { DS_DAT_MON(SYSTEM_SYS_PATH, DATA_ATTRI_NOTIFY), DS_DAT_MON(LINK_STATUS_PATH, DATA_ATTRI_NOTIFY), DS_DAT_MON(REC_PLAN_ENABLE_PATH, DATA_ATTRI_NOTIFY), DS_DAT_MON(HUB_MANAGE_STORAGE_INFO_PATH, DATA_ATTRI_NOTIFY), DS_DAT_MON(HUB_MANAGE_AI_ENHANCE_DYN_PATH, DATA_ATTRI_NOTIFY), DS_DAT_MON(IMAGE_SWITCH_PATH, DATA_ATTRI_NOTIFY), }; DS_MOD_DESC hub_manage_module = DS_STRUCT_MOD("hub_manage", hub_manage_init, NULL, hub_manage_reload, hub_manage_start, hub_manage_stop, NULL, hub_manage_data_monitor); MODULE *module_node = ds_register_module("hub_manage", &hub_manage_module); SDM_ASSERT(NULL != module_node); } NSD_INIT(hub_manage_main);
最新发布
10-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值