diff --git a/components/DBoT/Kconfig b/components/DBoT/Kconfig index 04819f51a80ac36a28da20da4a001bb1fbeae4c0..5fd865600a993074b3311c8d1a6fa2cdccc6e60f 100644 --- a/components/DBoT/Kconfig +++ b/components/DBoT/Kconfig @@ -99,7 +99,7 @@ config OS_USING_DBOT if RECORDER_EXAMPLE config RECORDER_DEV_NAME string "Recorder device name" - default "audio1" + default "audio1" endif config SPEAKER_EXAMPLE @@ -122,6 +122,10 @@ config OS_USING_DBOT config FILESYSTEM_USING_WRITE_FILE bool "Filesystem using write file" default n + + config FILESYSTEM_USING_READ_FILE + bool "Filesystem using read file" + default n endif endif diff --git a/components/DBoT/example/example_cmd.c b/components/DBoT/example/example_cmd.c index 5eb73f3d19e640927607f99e41cad2708e4e7633..4f1d71484ae0bd31809184c46fae6a043d69f6a5 100644 --- a/components/DBoT/example/example_cmd.c +++ b/components/DBoT/example/example_cmd.c @@ -134,16 +134,16 @@ int dbot_remove_session(int argc, char **argv) } /************************************显示目录***************************************************/ -static DTP_SERVICE_CONTEXT_S *s_show_directory_ctx = NULL; -static pthread_t s_show_directory_pid = 0; -static char s_show_directory_path[128] = {0}; +static DTP_SERVICE_CONTEXT_S *gs_show_directory_ctx = NULL; +static pthread_t gs_show_directory_pid = 0; +static char gs_show_directory_path[128] = {0}; void free_show_directory_resource(void) { - if (NULL != s_show_directory_ctx) + if (NULL != gs_show_directory_ctx) { - dbot_service_destory_dtp(s_show_directory_ctx); - s_show_directory_ctx = NULL; + dbot_service_destory_dtp(gs_show_directory_ctx); + gs_show_directory_ctx = NULL; } } @@ -182,23 +182,23 @@ static void *show_directory_thread_func(void *param) ListFilesRequest list_files_request = {0}; /* If path not given, the server will list the root directory */ - if (strlen(s_show_directory_path) == 0) + if (strlen(gs_show_directory_path) == 0) { list_files_request.has_path = false; } else { list_files_request.has_path = true; - if (strlen(s_show_directory_path) + 1 > sizeof(list_files_request.path)) + if (strlen(gs_show_directory_path) + 1 > sizeof(list_files_request.path)) { DBOT_LOG_E("Too long path \r\n"); goto __err; } - strcpy(list_files_request.path, s_show_directory_path); + strcpy(list_files_request.path, gs_show_directory_path); } - result = dbot_nanopb_msg_output((void *)s_show_directory_ctx, ListFilesRequest_fields, &list_files_request); + result = dbot_nanopb_msg_output((void *)gs_show_directory_ctx, ListFilesRequest_fields, &list_files_request); if (result != DBOT_OK) { DBOT_LOG_E("dbot nanopb msg output failed\r\n"); @@ -210,7 +210,7 @@ static void *show_directory_thread_func(void *param) { ListFilesResponse list_files_response = {0}; - result = dbot_nanopb_msg_input((void *)s_show_directory_ctx, ListFilesResponse_fields, &list_files_response); + result = dbot_nanopb_msg_input((void *)gs_show_directory_ctx, ListFilesResponse_fields, &list_files_response); if (result != DBOT_OK) { DBOT_LOG_E("dbot nanopb msg input failed\r\n"); @@ -227,7 +227,7 @@ static void *show_directory_thread_func(void *param) __err: free_show_directory_resource(); - s_show_directory_pid = 0; + gs_show_directory_pid = 0; DBOT_LOG_D("show_directory task quit\r\n"); return NULL; @@ -247,7 +247,7 @@ static int show_directory_resp_func(char *resp, int resp_len) DBOT_LOG_D("recv resp %s\r\n", resp); - if (NULL != s_show_directory_ctx) + if (NULL != gs_show_directory_ctx) { DBOT_LOG_D("show directory task already exists\r\n"); return -1; @@ -261,14 +261,14 @@ static int show_directory_resp_func(char *resp, int resp_len) port = cJSON_GetObjectItem(root, "port"); BREAK_IF(NULL == ip || NULL == port); - s_show_directory_ctx = dbot_service_init_dtp(DTP_SERVICE_TCP_CLIENT, ip->valuestring, port->valueint); - BREAK_IF(NULL == s_show_directory_ctx); + gs_show_directory_ctx = dbot_service_init_dtp(DTP_SERVICE_TCP_CLIENT, ip->valuestring, port->valueint); + BREAK_IF(NULL == gs_show_directory_ctx); pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_attr_setstacksize(&attr, 4096); - BREAK_IF(0 != pthread_create(&s_show_directory_pid, &attr, show_directory_thread_func, NULL)); + BREAK_IF(0 != pthread_create(&gs_show_directory_pid, &attr, show_directory_thread_func, NULL)); ret = DBOT_OK; DBOT_LOG_E("show directory task started\r\n"); @@ -297,9 +297,9 @@ int dbot_show_directory(int argc, char **argv) } char param[138] = {0}; - memset(s_show_directory_path, 0, sizeof(s_show_directory_path)); - strncpy(s_show_directory_path, argv[2], sizeof(s_show_directory_path)); - snprintf(param, sizeof(param), "{\"path\":\"%s\"}", s_show_directory_path); + memset(gs_show_directory_path, 0, sizeof(gs_show_directory_path)); + strncpy(gs_show_directory_path, argv[2], sizeof(gs_show_directory_path)); + snprintf(param, sizeof(param), "{\"path\":\"%s\"}", gs_show_directory_path); return dbot_service_call_service(atoi(argv[1]), CAPABILITY_TYPE_FILESYSTEM, @@ -309,7 +309,7 @@ int dbot_show_directory(int argc, char **argv) } /************************************显示目录***************************************************/ -/************************************传输文件***************************************************/ +/************************************写文件***************************************************/ // 传输文件应用,调用对端的文件系统能力 static DTP_SERVICE_CONTEXT_S *gs_write_file_ctx = NULL; static pthread_t gs_write_file_pid = 0; @@ -529,7 +529,341 @@ int dbot_write_file(int argc, char **argv) write_file_resp_func); } -/************************************传输文件**************************************************/ +/************************************写文件**************************************************/ + + + + + + + + +/************************************读文件***************************************************/ + +#define FILESYSTEM_THREAD_STACK_SIZE 5120 +#define FILE_NAME_MAX_LEN 128 +#define FILE_FLOW_PACKAGE_FIX_SIZE 1460 +static char gs_read_file_name[FILE_NAME_MAX_LEN] = {0}; + +typedef struct file_package_read_node +{ + os_list_node_t node; + uint8_t *ptr; + uint32_t size; + uint32_t offset; + uint32_t seq; +}file_package_read_node_t; + +typedef struct file_flow_read_cache +{ + uint8_t file_name[FILE_NAME_MAX_LEN]; + uint8_t file_type; + uint32_t file_expect_size; + uint32_t file_actual_size; + uint8_t sha1[20]; + os_list_node_t file_package_list; +}file_flow_read_cache_t; + +static pthread_t gs_read_file_pid = 0; +static DTP_SERVICE_CONTEXT_S *gs_read_file_dtp_ctx = NULL; +static FILE *gs_read_file_fp = NULL; +static uint32_t gs_recv_file_size = 0; +static uint32_t gs_sequence = 0; +static file_flow_read_cache_t gs_file_flow_read_cache = {0}; +static pthread_mutex_t file_flow_cache_list_lock; +static pthread_t gs_read_file_flow_cache_pid = 0; + +static void file_flow_cache_lock(void) +{ + pthread_mutex_lock(&file_flow_cache_list_lock); +} + +static inline void file_flow_cache_unlock(void) +{ + pthread_mutex_unlock(&file_flow_cache_list_lock); +} + +void free_read_file_task_resource(void) +{ + if (NULL != gs_read_file_dtp_ctx) + { + dbot_service_destory_dtp(gs_read_file_dtp_ctx); + gs_read_file_dtp_ctx = NULL; + } +} + +static bool file_flow_decode_repeated_payload_callback(pb_istream_t *istream, const pb_field_t *field, void **arg) +{ + + file_package_read_node_t *file_cache_pkg_node = NULL; + uint8_t *payload = NULL; + size_t len = istream->bytes_left; + + + payload = calloc(1, FILE_FLOW_PACKAGE_FIX_SIZE); + if (NULL == payload) + { + DBOT_LOG_E("file flow package payload calloc failed\r\n"); + return false; + } + + if (len > FILE_FLOW_PACKAGE_FIX_SIZE) + { + free(payload); + DBOT_LOG_E("recv file flow package too large\r\n"); + return false; + } + + if(!pb_read(istream, payload, len)) + { + free(payload); + DBOT_LOG_E("read istream payload failed\r\n"); + return false; + } + + file_cache_pkg_node = calloc(1, sizeof(file_package_read_node_t)); + if (NULL == file_cache_pkg_node) + { + free(payload); + DBOT_LOG_E("file flow cache node calloc failed\r\n"); + return false; + } + + file_cache_pkg_node->ptr = payload; + file_cache_pkg_node->size = len; + file_cache_pkg_node->offset = gs_recv_file_size; + file_cache_pkg_node->seq = gs_sequence++; + + os_list_init(&file_cache_pkg_node->node); + file_flow_cache_lock(); + os_list_add_tail(&gs_file_flow_read_cache.file_package_list, &file_cache_pkg_node->node); + file_flow_cache_unlock(); + + gs_recv_file_size += len; + + return true; +} + +static void *read_file_flow_cache_thread_func(void *param) +{ + file_package_read_node_t *file_cache_pkg_node_tmp = NULL; + uint32_t total_read_len = (uint32_t)-1; + uint32_t read_len = 0; + + pthread_mutex_init(&file_flow_cache_list_lock, NULL); + memset(&gs_file_flow_read_cache, 0, sizeof(file_flow_read_cache_t)); + os_list_init(&gs_file_flow_read_cache.file_package_list); + + while(total_read_len != gs_file_flow_read_cache.file_actual_size) + { + if (!os_list_empty(&gs_file_flow_read_cache.file_package_list)) + { + file_flow_cache_lock(); + file_cache_pkg_node_tmp = os_list_first_entry_or_null(&gs_file_flow_read_cache.file_package_list, file_package_read_node_t, node); + os_list_del(&file_cache_pkg_node_tmp->node); + file_flow_cache_unlock(); + if (file_cache_pkg_node_tmp != NULL) + { + if (file_cache_pkg_node_tmp->ptr != NULL) + { + read_len = fwrite(file_cache_pkg_node_tmp->ptr, 1, file_cache_pkg_node_tmp->size, gs_read_file_fp); + if (total_read_len == (uint32_t)-1) + { + total_read_len = 0; + } + + total_read_len += read_len; + free(file_cache_pkg_node_tmp->ptr); + } + free(file_cache_pkg_node_tmp); + } + } + else + { + dbot_msleep(10); + } + } + + pthread_mutex_destroy(&file_flow_cache_list_lock); + if (NULL != gs_read_file_fp) + { + fclose(gs_read_file_fp); + gs_read_file_fp = NULL; + } + DBOT_LOG_I("file flow cache task read file %d bytes\r\n", total_read_len); + + return NULL; +} + +static void *read_file_thread(void *param) +{ + FileFlow file_flow = {0}; + int32_t result = 0; + + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setstacksize(&attr, 2048); + if(0 != pthread_create(&gs_read_file_flow_cache_pid, &attr, read_file_flow_cache_thread_func, NULL)) + { + DBOT_LOG_E("dbot creat file flow cache thread failed\r\n"); + goto __err; + } + + file_flow.payload.funcs.decode = &file_flow_decode_repeated_payload_callback; + file_flow.payload.arg = gs_read_file_fp; + result = dbot_nanopb_msg_input((void *)gs_read_file_dtp_ctx, FileFlow_fields, &file_flow); + if (result != DBOT_OK) + { + DBOT_LOG_E("dbot nanopb msg input failed\r\n"); + } + + if (file_flow.has_header == true) + { + strncpy((char *)gs_file_flow_read_cache.file_name, file_flow.header.name, sizeof(gs_file_flow_read_cache.file_name)); + gs_file_flow_read_cache.file_type = file_flow.header.type; + gs_file_flow_read_cache.file_expect_size = file_flow.header.size; + if (gs_recv_file_size != 0) + { + gs_file_flow_read_cache.file_actual_size = gs_recv_file_size; + } + else + { + gs_file_flow_read_cache.file_actual_size = (uint32_t)-1; + } + if (file_flow.header.has_sha1 == true) + { + /* user can read file from filesystem and check sha1 */ + memcpy(gs_file_flow_read_cache.sha1, file_flow.header.sha1.bytes, file_flow.header.sha1.size); + } + DBOT_LOG_D("file_flow has head: file_name:%s, file_type:%d, file_expect_size:%d, file_actual_size:%d\r\n", gs_file_flow_read_cache.file_name, gs_file_flow_read_cache.file_type, gs_file_flow_read_cache.file_expect_size, gs_file_flow_read_cache.file_actual_size); + } + else + { + /* without head, error accur very early, read_file_flow_cache_thread also need return */ + gs_file_flow_read_cache.file_actual_size = (uint32_t)-1; + } + +__err: + free_read_file_task_resource(); + gs_read_file_pid = 0; + DBOT_LOG_D("recv file task quit, total received payload %d bytes\r\n", gs_recv_file_size); + return NULL; +} + +static int read_file_resp_func(char *resp, int resp_len) +{ + int ret = DBOT_ERROR; + cJSON *root = NULL; + cJSON *ip = NULL; + cJSON *port = NULL; + + + if (NULL == resp) + { + return -1; + } + + DBOT_LOG_D("recv resp %s\r\n", resp); + + if (NULL != gs_read_file_dtp_ctx) + { + DBOT_LOG_D("tranport file task already exists\r\n"); + return -1; + } + + do + { + root = cJSON_Parse(resp); + BREAK_IF(NULL == root); + ip = cJSON_GetObjectItem(root, "ip"); + port = cJSON_GetObjectItem(root, "port"); + BREAK_IF(NULL == ip || NULL == port); + + gs_read_file_fp = fopen(gs_read_file_name, "wb+"); + BREAK_IF(NULL == gs_read_file_fp); + + gs_read_file_dtp_ctx = dbot_service_init_dtp(DTP_SERVICE_TCP_CLIENT, ip->valuestring, port->valueint); + BREAK_IF(NULL == gs_read_file_dtp_ctx); + + pthread_attr_t attr; + pthread_attr_init(&attr); + struct sched_param param; + param.sched_priority = 20; + pthread_attr_setschedpolicy(&attr, SCHED_FIFO); + pthread_attr_setschedparam(&attr, ¶m); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setstacksize(&attr, 5120); + BREAK_IF(0 != pthread_create(&gs_read_file_pid, &attr, read_file_thread, NULL)); + + + ret = DBOT_OK; + gs_recv_file_size = 0; + gs_sequence = 0; + DBOT_LOG_E("read file task started\r\n"); + } while (0); + + DELETE_CJSON(root); + if (DBOT_OK != ret) + { + free_read_file_task_resource(); + } + return ret; +} + + + + +int dbot_read_file(int argc, char **argv) +{ + if (3 > argc) + { + DBOT_LOG_D("usage:dbot_read_file [device id] [file name]\r\n"); + return -1; + } + + if(!dbot_service_started()) + { + DBOT_LOG_D("dbot not started\r\n"); + return -1; + } + + char param[100] = {0}; + memset(gs_read_file_name, 0, sizeof(gs_read_file_name)); + strncpy(gs_read_file_name, argv[2], sizeof(gs_read_file_name)); + + char *p = gs_read_file_name; + char *pos = NULL; + while(1) + { + p = strstr(p, "/"); + if(NULL != p) + { + p += 1; + pos = p; + } + else + { + break; + } + } + snprintf(param, sizeof(param), "{\"file_name\":\"%s\"}", pos); + + return dbot_service_call_service(atoi(argv[1]), + CAPABILITY_TYPE_FILESYSTEM, + "read_file", + param, + read_file_resp_func); +} + + +/************************************读文件***************************************************/ + + + + + + /************************************音频流转**************************************************/ // 在节点A调用B的麦克风能力录音并在C节点播放,即A告知C调用B的麦克风能力 @@ -942,6 +1276,7 @@ SH_CMD_EXPORT(dbot_remove_session, dbot_remove_session, "dbot_remove_session"); SH_CMD_EXPORT(dbot_discovery_service, dbot_service_discovery_service, "dbot_discovery_service"); SH_CMD_EXPORT(dbot_show_directory, dbot_show_directory, "dbot_show_directory"); SH_CMD_EXPORT(dbot_write_file, dbot_write_file, "dbot_write_file"); +SH_CMD_EXPORT(dbot_read_file, dbot_read_file, "dbot_read_file"); SH_CMD_EXPORT(dbot_audio_dataflow, dbot_audio_dataflow, "dbot_audio_dataflow"); SH_CMD_EXPORT(dbot_audio_dataflow_stop, dbot_audio_dataflow_stop, "dbot_audio_dataflow_stop"); SH_CMD_EXPORT(dbot_video_dataflow, dbot_video_dataflow, "dbot_video_dataflow"); diff --git a/components/DBoT/example/filesystem_example.c b/components/DBoT/example/filesystem_example.c index a243e2d4dd9c3ee569f1880e6cab5548e3df508b..6d0c8ffdaca57112169c3412de196d2c1c4cddd4 100644 --- a/components/DBoT/example/filesystem_example.c +++ b/components/DBoT/example/filesystem_example.c @@ -22,19 +22,19 @@ #define SHOW_DIRECTORY_THREAD_STACK_SIZE 4096 #define SHOW_DIRECTORY_PATH_LEN_MAX 128 static char show_directory_path[SHOW_DIRECTORY_PATH_LEN_MAX] = {0}; -static pthread_t s_show_directory_pid = 0; -static DTP_SERVICE_CONTEXT_S *s_show_directory_dtp_ctx = NULL; +static pthread_t gs_show_directory_pid = 0; +static DTP_SERVICE_CONTEXT_S *gs_show_directory_dtp_ctx = NULL; void free_show_directory_task_resource(void) { - if (NULL != s_show_directory_dtp_ctx) + if (NULL != gs_show_directory_dtp_ctx) { - dbot_service_destory_dtp(s_show_directory_dtp_ctx); - s_show_directory_dtp_ctx = NULL; + dbot_service_destory_dtp(gs_show_directory_dtp_ctx); + gs_show_directory_dtp_ctx = NULL; } } -bool server_list_files_response_callback(pb_ostream_t *ostream, const pb_field_iter_t *field) +bool server_list_files_response_callback(pb_ostream_t *ostream, const pb_field_iter_t *field) { DIR *dir = *(DIR **)field->pData; struct dirent *file; @@ -91,7 +91,7 @@ static void *show_directory_thread(void *param) { ListFilesRequest list_files_request = {0}; - result = dbot_nanopb_msg_input((void *)s_show_directory_dtp_ctx, ListFilesRequest_fields, &list_files_request); + result = dbot_nanopb_msg_input((void *)gs_show_directory_dtp_ctx, ListFilesRequest_fields, &list_files_request); if (result == DBOT_ERROR) { DBOT_LOG_E("dbot nanopb msg input failed\r\n"); @@ -118,7 +118,7 @@ static void *show_directory_thread(void *param) list_files_response.file = directory; } - result = dbot_nanopb_msg_output((void *)s_show_directory_dtp_ctx, ListFilesResponse_fields, &list_files_response); + result = dbot_nanopb_msg_output((void *)gs_show_directory_dtp_ctx, ListFilesResponse_fields, &list_files_response); if (result != DBOT_OK) { DBOT_LOG_E("dbot nanopb msg output failed\r\n"); @@ -133,7 +133,7 @@ __err: } free_show_directory_task_resource(); - s_show_directory_pid = 0; + gs_show_directory_pid = 0; DBOT_LOG_D("show directory info task quit\r\n"); return NULL; @@ -148,7 +148,7 @@ int show_directory(int len, char *req, char **resp) RETURN_IF_NULL(req, DBOT_INVALID_PARAM); - if (0 != s_show_directory_pid) + if (0 != gs_show_directory_pid) { DBOT_LOG_E("show directory task already exists\r\n"); return DBOT_ERROR; @@ -163,20 +163,20 @@ int show_directory(int len, char *req, char **resp) memset(show_directory_path, 0, SHOW_DIRECTORY_PATH_LEN_MAX); strncpy(show_directory_path, path->valuestring, SHOW_DIRECTORY_PATH_LEN_MAX); - s_show_directory_dtp_ctx = dbot_service_init_dtp(DTP_SERVICE_TCP_SERVER, NULL, 0); - BREAK_IF(NULL == s_show_directory_dtp_ctx); + gs_show_directory_dtp_ctx = dbot_service_init_dtp(DTP_SERVICE_TCP_SERVER, NULL, 0); + BREAK_IF(NULL == gs_show_directory_dtp_ctx); pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_attr_setstacksize(&attr, SHOW_DIRECTORY_THREAD_STACK_SIZE); - BREAK_IF(0 != pthread_create(&s_show_directory_pid, &attr, show_directory_thread, NULL)) + BREAK_IF(0 != pthread_create(&gs_show_directory_pid, &attr, show_directory_thread, NULL)) res_root = cJSON_CreateObject(); if (NULL != res_root) { cJSON_AddStringToObject(res_root, "ip", dbot_service_get_ctx()->profile->device_ip); - cJSON_AddNumberToObject(res_root, "port", s_show_directory_dtp_ctx->port); + cJSON_AddNumberToObject(res_root, "port", gs_show_directory_dtp_ctx->port); cJSON_AddNumberToObject(res_root, "protocol", 1); *resp = cJSON_PrintUnformatted(res_root); cJSON_Delete(res_root); @@ -222,14 +222,14 @@ typedef struct file_flow_cache os_list_node_t file_package_list; }file_flow_cache_t; -static pthread_t s_write_file_pid = 0; -static DTP_SERVICE_CONTEXT_S *s_write_file_dtp_ctx = NULL; -static FILE *s_write_file_fp = NULL; -static uint32_t s_recv_file_size = 0; -static uint32_t s_sequence = 0; +static pthread_t gs_write_file_pid = 0; +static DTP_SERVICE_CONTEXT_S *gs_write_file_dtp_ctx = NULL; +static FILE *gs_write_file_fp = NULL; +static uint32_t gs_recv_file_size = 0; +static uint32_t gs_sequence = 0; static file_flow_cache_t gs_file_flow_cache = {0}; static pthread_mutex_t file_flow_cache_list_lock; -static pthread_t s_read_file_flow_cache_pid = 0; +static pthread_t gs_read_file_flow_cache_pid = 0; static void file_flow_cache_lock(void) { @@ -243,10 +243,10 @@ static inline void file_flow_cache_unlock(void) void free_write_file_task_resource(void) { - if (NULL != s_write_file_dtp_ctx) + if (NULL != gs_write_file_dtp_ctx) { - dbot_service_destory_dtp(s_write_file_dtp_ctx); - s_write_file_dtp_ctx = NULL; + dbot_service_destory_dtp(gs_write_file_dtp_ctx); + gs_write_file_dtp_ctx = NULL; } } @@ -289,15 +289,15 @@ static bool file_flow_decode_repeated_payload_callback(pb_istream_t *istream, co file_cache_pkg_node->ptr = payload; file_cache_pkg_node->size = len; - file_cache_pkg_node->offset = s_recv_file_size; - file_cache_pkg_node->seq = s_sequence++; + file_cache_pkg_node->offset = gs_recv_file_size; + file_cache_pkg_node->seq = gs_sequence++; os_list_init(&file_cache_pkg_node->node); file_flow_cache_lock(); os_list_add_tail(&gs_file_flow_cache.file_package_list, &file_cache_pkg_node->node); file_flow_cache_unlock(); - s_recv_file_size += len; + gs_recv_file_size += len; return true; } @@ -324,7 +324,7 @@ static void *read_file_flow_cache_thread_func(void *param) { if (file_cache_pkg_node_tmp->ptr != NULL) { - write_len = fwrite(file_cache_pkg_node_tmp->ptr, 1, file_cache_pkg_node_tmp->size, s_write_file_fp); + write_len = fwrite(file_cache_pkg_node_tmp->ptr, 1, file_cache_pkg_node_tmp->size, gs_write_file_fp); if (total_write_len == (uint32_t)-1) { total_write_len = 0; @@ -342,10 +342,10 @@ static void *read_file_flow_cache_thread_func(void *param) } pthread_mutex_destroy(&file_flow_cache_list_lock); - if (NULL != s_write_file_fp) + if (NULL != gs_write_file_fp) { - fclose(s_write_file_fp); - s_write_file_fp = NULL; + fclose(gs_write_file_fp); + gs_write_file_fp = NULL; } DBOT_LOG_I("file flow cache task write file %d bytes\r\n", total_write_len); @@ -361,15 +361,15 @@ static void *write_file_thread(void *param) pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_attr_setstacksize(&attr, 2048); - if(0 != pthread_create(&s_read_file_flow_cache_pid, &attr, read_file_flow_cache_thread_func, NULL)) + if(0 != pthread_create(&gs_read_file_flow_cache_pid, &attr, read_file_flow_cache_thread_func, NULL)) { DBOT_LOG_E("dbot creat file flow cache thread failed\r\n"); goto __err; } file_flow.payload.funcs.decode = &file_flow_decode_repeated_payload_callback; - file_flow.payload.arg = s_write_file_fp; - result = dbot_nanopb_msg_input((void *)s_write_file_dtp_ctx, FileFlow_fields, &file_flow); + file_flow.payload.arg = gs_write_file_fp; + result = dbot_nanopb_msg_input((void *)gs_write_file_dtp_ctx, FileFlow_fields, &file_flow); if (result != DBOT_OK) { DBOT_LOG_E("dbot nanopb msg input failed\r\n"); @@ -380,9 +380,9 @@ static void *write_file_thread(void *param) strncpy((char *)gs_file_flow_cache.file_name, file_flow.header.name, sizeof(gs_file_flow_cache.file_name)); gs_file_flow_cache.file_type = file_flow.header.type; gs_file_flow_cache.file_expect_size = file_flow.header.size; - if (s_recv_file_size != 0) + if (gs_recv_file_size != 0) { - gs_file_flow_cache.file_actual_size = s_recv_file_size; + gs_file_flow_cache.file_actual_size = gs_recv_file_size; } else { @@ -403,8 +403,8 @@ static void *write_file_thread(void *param) __err: free_write_file_task_resource(); - s_write_file_pid = 0; - DBOT_LOG_D("recv file task quit, total received payload %d bytes\r\n", s_recv_file_size); + gs_write_file_pid = 0; + DBOT_LOG_D("recv file task quit, total received payload %d bytes\r\n", gs_recv_file_size); return NULL; } @@ -418,7 +418,7 @@ int write_file(int len, char *req, char **resp) RETURN_IF_NULL(req, DBOT_INVALID_PARAM); - if (0 != s_write_file_pid) + if (0 != gs_write_file_pid) { DBOT_LOG_E("write file task already exists\r\n"); return DBOT_ERROR; @@ -436,11 +436,11 @@ int write_file(int len, char *req, char **resp) DBOT_LOG_E("file %s already exists\r\n", file_name->valuestring); break; } - s_write_file_fp = fopen(file_name->valuestring, "wb+"); - BREAK_IF(NULL == s_write_file_fp); + gs_write_file_fp = fopen(file_name->valuestring, "wb+"); + BREAK_IF(NULL == gs_write_file_fp); - s_write_file_dtp_ctx = dbot_service_init_dtp(DTP_SERVICE_TCP_SERVER, NULL, 0); - BREAK_IF(NULL == s_write_file_dtp_ctx); + gs_write_file_dtp_ctx = dbot_service_init_dtp(DTP_SERVICE_TCP_SERVER, NULL, 0); + BREAK_IF(NULL == gs_write_file_dtp_ctx); pthread_attr_t attr; pthread_attr_init(&attr); @@ -450,20 +450,20 @@ int write_file(int len, char *req, char **resp) pthread_attr_setschedparam(&attr, ¶m); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_attr_setstacksize(&attr, FILESYSTEM_THREAD_STACK_SIZE); - BREAK_IF(0 != pthread_create(&s_write_file_pid, &attr, write_file_thread, NULL)) + BREAK_IF(0 != pthread_create(&gs_write_file_pid, &attr, write_file_thread, NULL)) res_root = cJSON_CreateObject(); if (NULL != res_root) { cJSON_AddStringToObject(res_root, "ip", dbot_service_get_ctx()->profile->device_ip); - cJSON_AddNumberToObject(res_root, "port", s_write_file_dtp_ctx->port); + cJSON_AddNumberToObject(res_root, "port", gs_write_file_dtp_ctx->port); cJSON_AddNumberToObject(res_root, "protocol", 1); *resp = cJSON_PrintUnformatted(res_root); cJSON_Delete(res_root); } ret = DBOT_OK; - s_recv_file_size = 0; - s_sequence = 0; + gs_recv_file_size = 0; + gs_sequence = 0; DBOT_LOG_E("write file task started\r\n"); } while (0); @@ -478,6 +478,196 @@ int write_file(int len, char *req, char **resp) #endif /* FILESYSTEM_USING_WRITE_FILE */ + + + + + + + + + + +#ifdef FILESYSTEM_USING_READ_FILE +static DTP_SERVICE_CONTEXT_S *gs_read_file_ctx = NULL; +static pthread_t gs_read_file_pid = 0; +static FILE *gs_read_file_fp = NULL; +static char gs_read_file_name[100] = {0}; + + +void free_read_file_resource(void) +{ + if (NULL != gs_read_file_ctx) + { + dbot_service_destory_dtp(gs_read_file_ctx); + gs_read_file_ctx = NULL; + } + if (NULL != gs_read_file_fp) + { + fclose(gs_read_file_fp); + gs_read_file_fp = NULL; + } +} + +static bool file_flow_encode_repeated_payload_callback(pb_ostream_t *ostream, const pb_field_t *field, void * const *arg) +{ + pb_byte_t payload[1460] = {0}; + uint32_t read_len = 0; + FILE *file_fp = (FILE *)(*arg); + + if (ostream->callback != NULL) + { + dbot_msleep(3000); + } + + while ((read_len = fread(payload, 1, sizeof(payload), file_fp)) > 0) + { + if (!pb_encode_tag_for_field(ostream, field)) + return false; + + if (!pb_encode_string(ostream, payload, read_len)) + return false; + + if (ostream->callback == NULL) /* callback NULL is for sizing */ + { + continue; + } + dbot_msleep(40); /* waiting for opposite write in flash */ + } + rewind(file_fp); /* this callback will come in twice, so need rewind */ + + return true; +} + +static void *read_file_thread_func(void *param) +{ + FileFlow file_flow = {0}; + struct stat stat_buf = {0}; + int32_t result = 0; + + file_flow.has_header = true; + if (file_flow.has_header == true) + { + strncpy(file_flow.header.name, gs_read_file_name, sizeof(file_flow.header.name)); + stat(gs_read_file_name, &stat_buf); +#ifdef _WIN32 + file_flow.header.type = 0; +#else + if (S_ISREG(stat_buf.st_mode)) + file_flow.header.type = DT_REG; + else if (S_ISDIR(stat_buf.st_mode)) + file_flow.header.type = DT_DIR; + else if (S_ISCHR(stat_buf.st_mode)) + file_flow.header.type = DT_CHR; + else if (S_ISBLK(stat_buf.st_mode)) + file_flow.header.type = DT_BLK; + else if (S_ISFIFO(stat_buf.st_mode)) + file_flow.header.type = DT_FIFO; + else if (S_ISLNK(stat_buf.st_mode)) + file_flow.header.type = DT_LNK; + else if (S_ISSOCK(stat_buf.st_mode)) + file_flow.header.type = DT_SOCK; + else + file_flow.header.type = DT_UNKNOWN; +#endif + file_flow.header.size = stat_buf.st_size; + file_flow.header.has_sha1 = false; + } + else + { + /* if file_flow.has_header is false, file_flow.header will be ignore */ + } + file_flow.payload.funcs.encode = &file_flow_encode_repeated_payload_callback; + file_flow.payload.arg = gs_read_file_fp; + + result = dbot_nanopb_msg_output((void *)gs_read_file_ctx, FileFlow_fields, &file_flow); + if (result != DBOT_OK) + { + DBOT_LOG_E("dbot nanopb msg output failed\r\n"); + } + + free_read_file_resource(); + gs_read_file_pid = 0; + DBOT_LOG_D("read file task quit\r\n"); + + return NULL; +} + +static int read_file(int len, char *req, char **resp) +{ + int ret = DBOT_ERROR; + cJSON *root = NULL; + cJSON *res_root = NULL; + cJSON *file_name = NULL; + + if (0 != gs_read_file_pid) + { + DBOT_LOG_E("read file task already exists\r\n"); + return DBOT_ERROR; + } + + do + { + + root = cJSON_Parse(req); + BREAK_IF(NULL == root); + file_name = cJSON_GetObjectItem(root, "file_name"); + BREAK_IF(NULL == file_name); + if (access(file_name->valuestring, 0) != 0) + { + DBOT_LOG_E("file %s not exists\r\n", file_name->valuestring); + break; + } + + + strncpy(gs_read_file_name,file_name->valuestring, sizeof(gs_read_file_name)); + gs_read_file_fp = fopen(gs_read_file_name, "rb"); + BREAK_IF(NULL == gs_read_file_fp); + + gs_read_file_ctx = dbot_service_init_dtp(DTP_SERVICE_TCP_SERVER, NULL, 0); + BREAK_IF(NULL == gs_read_file_ctx); + + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setstacksize(&attr, FILESYSTEM_THREAD_STACK_SIZE); + BREAK_IF(0 != pthread_create(&gs_read_file_pid, &attr, read_file_thread_func, NULL)) + + res_root = cJSON_CreateObject(); + if (NULL != res_root) + { + cJSON_AddStringToObject(res_root, "ip", dbot_service_get_ctx()->profile->device_ip); + cJSON_AddNumberToObject(res_root, "port", gs_read_file_ctx->port); + cJSON_AddNumberToObject(res_root, "protocol", 1); + *resp = cJSON_PrintUnformatted(res_root); + cJSON_Delete(res_root); + } + ret = DBOT_OK; + DBOT_LOG_E("read file task started\r\n"); + } while (0); + + DELETE_CJSON(root); + if (DBOT_OK != ret) + { + free_read_file_resource(); + } + + return ret; +} + +#endif /* FILESYSTEM_USING_READ_FILE */ + + + + + + + + + + + + static ATTR_INFO_S filesystem_attrs[] = { #ifdef FILESYSTEM_USING_SHOW_DIRECTORY {"show_directory", "{\"path\":\"/\"}", show_directory}, @@ -485,6 +675,9 @@ static ATTR_INFO_S filesystem_attrs[] = { #ifdef FILESYSTEM_USING_WRITE_FILE {"write_file", "{\"file_name\":\"music.pcm\"}", write_file}, #endif +#ifdef FILESYSTEM_USING_READ_FILE + {"read_file", "{\"file_name\":\"music.pcm\"}", read_file}, +#endif }; #if !defined __linux__ && !defined _WIN32