From 1ca053bea6457784eb02739f94a5e462c2a05b0b Mon Sep 17 00:00:00 2001 From: gb <741021719@qq.com> Date: Sat, 9 Dec 2023 18:21:05 +0800 Subject: [PATCH] add file_map --- scanner/async_scanner.cpp | 51 ++++- scanner/async_scanner.h | 4 + sdk/base/data.cpp | 335 +++++++++++++++++++++++++++++-- sdk/base/data.h | 45 ++++- sdk/base/packet.h | 12 +- sdk/base/plat_types.h | 6 +- sdk/base/utils.cpp | 66 ++++-- sdk/base/utils.h | 8 +- sdk/sane_opt_json/device_opt.cpp | 52 ++++- usb/usb_dev.cpp | 19 ++ usb/usb_io.cpp | 119 ++++++----- usb/usb_io.h | 11 +- 12 files changed, 625 insertions(+), 103 deletions(-) diff --git a/scanner/async_scanner.cpp b/scanner/async_scanner.cpp index a58cad1..515ce69 100644 --- a/scanner/async_scanner.cpp +++ b/scanner/async_scanner.cpp @@ -71,6 +71,10 @@ async_scanner::~async_scanner() cfg_mgr_->clear(); delete cfg_mgr_; } + for(auto& v: send_files_) + v->release(); + send_files_.clear(); + utils::uninit(); } @@ -114,6 +118,9 @@ dyn_mem_ptr async_scanner::handle_bulk_cmd(LPPACK_BASE pack, uint32_t* used, pac case PACK_CMD_FILE_READ_REQ: reply = handle_file_send(pack, used, required); break; + case PACK_CMD_FILE_READ_REQ_ROGER: + reply = handle_file_send_roger(pack, used, required); + break; case PACK_CMD_SCAN_START: reply = handle_scan_start(pack, used, required); break; @@ -256,7 +263,7 @@ dyn_mem_ptr async_scanner::handle_file_receive(LPPACK_BASE pack, uint32_t* used, int err = 0; file_saver *saver = new file_saver(); - err = saver->open(path.c_str(), pfi->size); + err = saver->open(path.c_str(), pfi->size, true, pfi->offset); reply = dyn_mem::memory(base_head_size); reply->set_len(base_head_size); BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err); @@ -293,7 +300,7 @@ dyn_mem_ptr async_scanner::handle_file_send(LPPACK_BASE pack, uint32_t* used, pa int err = 0; file_reader *reader = new file_reader(); - err = reader->open(path.c_str()); + err = reader->open(path.c_str(), true, pfi->offset); reply = dyn_mem::memory(base_head_size + sizeof(TXFILE)); reply->set_len(base_head_size + sizeof(TXFILE)); BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err); @@ -309,12 +316,52 @@ dyn_mem_ptr async_scanner::handle_file_send(LPPACK_BASE pack, uint32_t* used, pa ((LPPACK_BASE)reply->ptr())->payload_len = sizeof(TXFILE); ((LPTXFILE)((LPPACK_BASE)reply->ptr())->payload)->size = reader->get_rest(); reader->set_packet_param(pack->cmd, pack->pack_id); + { + // move to PACK_CMD_FILE_READ_REQ_ROGER + SIMPLE_LOCK(fsender_); + send_files_.push_back(reader); + reader = nullptr; + } } *required = dynamic_cast(reader); } return reply; } +dyn_mem_ptr async_scanner::handle_file_send_roger(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required) +{ + uint32_t base_head_size = sizeof(PACK_BASE); + dyn_mem_ptr reply = nullptr; + + if(*used < base_head_size) + { + *used = 0; + } + else + { + file_reader* reader = nullptr; + + { + SIMPLE_LOCK(fsender_); + for(size_t i = 0; i < send_files_.size(); ++i) + { + if(send_files_[i]->get_packet_id() == pack->pack_id) + { + reader = send_files_[i]; + send_files_.erase(send_files_.begin() + i); + break; + } + } + } + *used = base_head_size; + *required = dynamic_cast(reader); + + // if reader was nullptr, notify failed by INT or control ? + utils::to_log(LOG_LEVEL_DEBUG, "File Send beginning (%p) ...\n", reader); + } + + return reply; +} dyn_mem_ptr async_scanner::handle_scan_start(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required) { if(!used) diff --git a/scanner/async_scanner.h b/scanner/async_scanner.h index b434093..3be36a2 100644 --- a/scanner/async_scanner.h +++ b/scanner/async_scanner.h @@ -28,6 +28,9 @@ class async_scanner : public refer volatile bool reply_start_; int last_err_ = 0; + MUTEX fsender_; + std::vector send_files_; + dyn_mem_ptr handle_bulk_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); void init(void); @@ -37,6 +40,7 @@ class async_scanner : public refer dyn_mem_ptr handle_set_opt(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); dyn_mem_ptr handle_file_receive(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); dyn_mem_ptr handle_file_send(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); + dyn_mem_ptr handle_file_send_roger(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); dyn_mem_ptr handle_scan_start(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); dyn_mem_ptr handle_scan_stop(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); dyn_mem_ptr handle_process_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required); diff --git a/sdk/base/data.cpp b/sdk/base/data.cpp index 8c6c9dd..7c2a13c 100644 --- a/sdk/base/data.cpp +++ b/sdk/base/data.cpp @@ -3,10 +3,11 @@ #include -#if defined(WIN32) || defined(_WIN64) +#if OS_WIN #else #include #include +#include #endif //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -20,7 +21,7 @@ packet_data_base::~packet_data_base() int packet_data_base::notify_progress(uint64_t total, uint64_t cur_size, uint32_t err) { if (progress_notify_) - progress_notify_(total, cur_size, err, user_data_); + return progress_notify_(total, cur_size, err, user_data_); else return ENOENT; } @@ -148,11 +149,16 @@ file_saver::file_saver(void) : size_(0), wrote_(0), path_(""), check_(""), dst_( {} file_saver::~file_saver() { + utils::to_log(LOG_LEVEL_DEBUG, "Write file(%s) over(%ld/%ld).\n", path_.c_str(), wrote_, size_); close(); } void file_saver::close(void) { + if (map_) + map_->release(); + map_ = nullptr; + if(dst_) fclose(dst_); dst_ = nullptr; @@ -161,17 +167,48 @@ void file_saver::close(void) path_ = check_ = ""; } -int file_saver::open(const char* path, uint64_t size, const char* check) +int file_saver::set_verify_data(const char* data, size_t len) +{ + if (data) + check_ = std::string(data, len); + else + check_ = ""; + + return 0; +} +int file_saver::open(const char* path, uint64_t size, bool in_mem, size_t off) { int err = 0; close(); - dst_ = fopen(path, "wb"); - if(dst_) + wrote_ = off; + path_ = path; + size_ = size; + + if (in_mem) + { + map_ = new file_map(); + err = map_->open(path, size, false); + if (err || !map_->map()) + { + map_->release(); + map_ = nullptr; + } + else + return err; + } + + err = utils::make_file_size(path, wrote_); + dst_ = fopen(path, "ab+"); + if (dst_) { unsigned long long space = 0; + std::string dir(path); + size_t pos = dir.rfind(PATH_SEPARATOR[0]); - err = utils::get_disk_space(path, nullptr, &space, nullptr); + if (pos != std::string::npos) + dir.erase(pos); + err = utils::get_disk_space(dir.c_str(), nullptr, &space, nullptr); if (err || space < size * 1.5) { fclose(dst_); @@ -180,12 +217,6 @@ int file_saver::open(const char* path, uint64_t size, const char* check) if (err == 0) err = ENOSPC; } - else - { - path_ = path; - size_ = size; - check_ = check ? check : ""; - } } else { @@ -197,8 +228,22 @@ int file_saver::open(const char* path, uint64_t size, const char* check) int file_saver::put_data(const void* data, uint32_t* size/*[in] - total bytes of data; [out] - used bytes*/) { - if(!dst_) + if (!dst_) + { + if (map_) + { + // fix me: we consider whole file is all mapped in memory + int w = *size > size_ - wrote_ ? size_ - wrote_ : *size; + memcpy(map_->buffer() + wrote_, data, w); + *size = w; + wrote_ += w; + notify_progress(size_, wrote_, 0); + + return 0; + } + return ENOENT; + } int w = *size > size_ - wrote_ ? size_ - wrote_ : *size, real_w = fwrite(data, 1, w, dst_), // should handle error here ! @@ -229,9 +274,11 @@ uint32_t file_saver::get_required(void) } void file_saver::cancel(void) { + std::string discard(path_); + utils::to_log(LOG_LEVEL_DEBUG, "Discard receiving file (%u/%u): '%s'.\n", wrote_, size_, path_.c_str()); close(); - remove(path_.c_str()); + remove(discard.c_str()); } @@ -401,12 +448,41 @@ file_reader::~file_reader() { if(src_) fclose(src_); + if (map_) + map_->release(); + utils::to_log(LOG_LEVEL_DEBUG, "Read file(%s) over(%ld/%ld).\n", path_.c_str(), consume_, len_); } -int file_reader::open(const char* file) +int file_reader::open(const char* file, bool in_mem, size_t off) { if(src_) fclose(src_); + src_ = nullptr; + consume_ = off; + + if (in_mem) + { + map_ = new file_map(); + if (map_->open(file, 0, true) || !map_->map()) + { + map_->release(); + map_ = nullptr; + } + else + { + if (map_->total_size() <= off) + { + map_->release(); + map_ = nullptr; + + return EOVERFLOW; + } + path_ = file; + len_ = map_->total_size(); + + return 0; + } + } src_ = fopen(file, "rb"); if(!src_) @@ -414,9 +490,15 @@ int file_reader::open(const char* file) FSEEK(src_, 0, SEEK_END); len_ = FTELL(src_); - FSEEK(src_, 0, SEEK_SET); + FSEEK(src_, consume_, SEEK_SET); path_ = file; - consume_ = 0; + if (len_ <= consume_) + { + fclose(src_); + src_ = nullptr; + + return EOVERFLOW; + } return 0; } @@ -427,6 +509,11 @@ int file_reader::attach(FILE* f) fclose(src_); src_ = nullptr; } + if (map_) + { + map_->release(); + map_ = nullptr; + } uint64_t cur = FTELL(f); @@ -455,7 +542,7 @@ FILE* file_reader::detach(void) bool file_reader::is_memory_block(void) { - return false; + return map_ != nullptr; } uint32_t file_reader::get_rest(void) { @@ -465,14 +552,27 @@ uint32_t file_reader::get_rest(void) // following API valid when is_memory_block() return true uint8_t* file_reader::ptr(void) { - return nullptr; + return map_ ? map_->buffer() : nullptr; } // following API valid when is_memory_block() return false int file_reader::fetch_data(void* buf, uint32_t* size) { if (!src_) + { + if (map_) + { + if (*size + consume_ >= len_) + *size = len_ - consume_; + memcpy(buf, map_->buffer() + consume_, *size); + consume_ += *size; + notify_progress(len_, consume_, 0); + + return 0; + } + return ENODATA; + } size_t r = fread(buf, 1, *size, src_); // fix me if ERROR occurs !!! @@ -487,3 +587,200 @@ int file_reader::fetch_data(void* buf, uint32_t* size) return 0; } + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +file_map::file_map() +{ + utils::get_page_size(&os_map_size_); +} +file_map::~file_map() +{ + close(); +} + +void file_map::unmap(void) +{ + if (buf_) +#if OS_WIN + UnmapViewOfFile(buf_); +#else + munmap(buf_, map_size_); +#endif + + buf_ = nullptr; + map_off_ = map_size_ = off_ = 0; +} + +int file_map::open(const char* file, uint64_t size, bool readonly) +{ + close(); + + std::string oper(readonly ? "open" : "create"); + +#if OS_WIN + HANDLE h = INVALID_HANDLE_VALUE; + DWORD access = PAGE_READONLY; + if (readonly) + { + h = CreateFileA(file, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } + else + { + access = PAGE_READWRITE; + h = CreateFileA(file, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + } + if (h == INVALID_HANDLE_VALUE) + { + utils::to_log(LOG_LEVEL_WARNING, "FileMapping: %s '%s' failed: %d\n", oper.c_str(), file, GetLastError()); + return EFAULT; + } + + if (readonly) + { + DWORD* hi = (DWORD*)&size + 1, + * lo = (DWORD*)&size; + *lo = GetFileSize(h, hi); + } + else + { + LONG lo = size & 0x0ffffffff, + hi = size >> 32; + DWORD ret = SetFilePointer(h, lo, &hi, FILE_BEGIN); + if (ret == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) + { + CloseHandle(h); + remove(file); + utils::to_log(LOG_LEVEL_WARNING, "FileMapping: no space(%ld) for '%s'.\n", size, file); + + return ENOSPC; + } + else + { + // write a byte to ensure map success + SetFilePointer(h, -1, NULL, FILE_CURRENT); + lo = 0; + WriteFile(h, &lo, 1, &ret, NULL); + } + } + map_ = CreateFileMappingA(h, NULL, access, 0, 0, NULL); + access = GetLastError(); + CloseHandle(h); + if (!map_) + { + remove(file); + map_ = INVALID_HANDLE_VALUE; + utils::to_log(LOG_LEVEL_WARNING, "FileMapping: create mapping object for '%s' failed: %d.\n", file, access); + + return EFAULT; + } +#else + if (readonly) + map_ = (HANDLE)::open(file, O_RDONLY, 0644); + else + { + int err = utils::make_file_size(file, size); + if(err) + { + utils::to_log(LOG_LEVEL_FATAL, "FileMapping: make file(%s) size(%ld) = %d\n", file, size, err); + return err; + } + map_ = (HANDLE)::open(file, O_RDWR, 0666); + utils::to_log(LOG_LEVEL_DEBUG, "FileMapping: open('%s', O_APPEND, 0666) = %p\n", file, map_); + } + if (map_ == INVALID_HANDLE_VALUE) + { + int err = errno; + + if(!readonly) + remove(file); + utils::to_log(LOG_LEVEL_WARNING, "FileMapping: create mapping object for '%s' failed: %d.\n", file, err); + + return err; + } +#endif + + path_file_ = file; + total_ = size; + read_only_ = readonly; + + return 0; +} +int file_map::close(void) +{ + unmap(); + + if (map_ != INVALID_HANDLE_VALUE) +#if OS_WIN + CloseHandle(map_); +#else + ::close((int)(long)map_); +#endif + + map_ = INVALID_HANDLE_VALUE; + total_ = 0; + + return 0; +} +uint64_t file_map::total_size(void) +{ + return total_; +} +uint8_t* file_map::map(uint64_t off, uint32_t* size) +{ + uint32_t len = 0; + + unmap(); + + if (!size) + size = &len; + + if (off < total_) + { + DWORD hi = 0, + lo = 0, + cnt = 0; + + map_off_ = off / os_map_size_ * os_map_size_; + off_ = off - map_off_; + hi = map_off_ >> 32; + lo = map_off_; + cnt = total_ - map_off_; + if (cnt - off > *size && *size) + { + cnt = ALIGN_TO(*size + off, os_map_size_); + if(cnt > total_ - map_off_) + cnt = total_ - map_off_; + } + map_size_ = cnt; +#if OS_WIN + buf_ = (uint8_t*)MapViewOfFile(map_, read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE, hi, lo, map_size_); +#else + int priv = PROT_READ, prot = MAP_PRIVATE; + if (!read_only_) + { + priv |= PROT_WRITE; + prot = MAP_SHARED; + } + buf_ = (uint8_t*)mmap(nullptr, map_size_, priv, prot, (int)(long)map_, map_off_); + if(buf_ == INVALID_HANDLE_VALUE) + buf_ = nullptr; +#endif + if (!buf_) + { + utils::to_log(LOG_LEVEL_WARNING, "FileMapping: request map(%p + %u), real map(%p + %u) failed: %d\n" + , off, *size, map_off_, map_size_, GetLastError()); + *size = 0; + } + else + *size = cnt - off; + } + + return buf_ ? buf_ + off_ : nullptr; +} +uint8_t* file_map::buffer(void) +{ + return buf_ ? buf_ + off_ : nullptr; +} diff --git a/sdk/base/data.h b/sdk/base/data.h index 6a22515..e5a30d5 100644 --- a/sdk/base/data.h +++ b/sdk/base/data.h @@ -47,6 +47,35 @@ public: void set_progress_notify(PROGRESS_NOTIFYER notify = PROGRESS_NOTIFYER(), void* param = nullptr); }; +class file_map : public refer +{ + bool read_only_ = false; // + uint32_t os_map_size_ = 0; // desired mapping size of OS + uint64_t total_ = 0; // total size of the whole file + HANDLE map_ = INVALID_HANDLE_VALUE; // handle of the map-object + std::string path_file_; // local file + + uint64_t map_off_ = 0; // offset in the file of current mapping buffer + uint32_t map_size_ = 0; // size of current mapping buffer + uint32_t off_ = 0; // offset to align to os_map_size_ + uint8_t* buf_ = nullptr; // current mapping buffer + + void unmap(void); + +public: + file_map(); + +protected: + ~file_map(); + +public: + int open(const char* file, uint64_t size, bool readonly); + int close(void); + uint64_t total_size(void); + uint8_t* map(uint64_t off = 0, uint32_t* size = 0); // size - in: desired size, 0 is from off to end; out: real size + uint8_t* buffer(void); +}; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // /* data_holder, used when data is also required for a certain packet @@ -112,6 +141,7 @@ class file_saver : public data_holder std::string path_; std::string check_; FILE *dst_; + file_map *map_ = nullptr; uint32_t pack_cmd_; uint32_t pack_id_; @@ -123,7 +153,8 @@ protected: ~file_saver(); public: - int open(const char* path, uint64_t size, const char* check = nullptr); + int set_verify_data(const char* data, size_t len); + int open(const char* path, uint64_t size, bool in_mem = false, size_t off = 0); public: virtual int put_data(const void* data, uint32_t* size/*[in] - total bytes of data; [out] - used bytes*/) override; @@ -204,9 +235,10 @@ public: class file_reader : public data_source { - size_t len_; - size_t consume_; - FILE *src_; + size_t len_; + size_t consume_; + FILE *src_ = nullptr; + file_map *map_ = nullptr; std::string path_; public: @@ -216,7 +248,7 @@ protected: ~file_reader(); public: - int open(const char* file); + int open(const char* file, bool in_mem, size_t off = 0); int attach(FILE* f); FILE* detach(void); @@ -231,6 +263,7 @@ public: virtual int fetch_data(void* buf, uint32_t* size) override; }; + CLS_PTR(packet_data_base); CLS_PTR(data_holder); CLS_PTR(mem_holder); @@ -251,7 +284,7 @@ CLS_PTR(file_reader); // // when invalid packet, suggest use the entire data // -// packet_data_base_ptr* - return data_holder or data_source or nullptr ��The number of bytes required for this packet, 0 is over for this packet�� +// packet_data_base_ptr* - return data_holder or data_source or nullptr The number of bytes required for this packet, 0 is over for this packet // // data_holder: the packet/command need more data than dyn_mem_ptr provides to complete the business. such as 'write a large file' // diff --git a/sdk/base/packet.h b/sdk/base/packet.h index e40ae4c..dfc51e2 100644 --- a/sdk/base/packet.h +++ b/sdk/base/packet.h @@ -50,13 +50,13 @@ enum ep0_req USB_REQ_EP0_SET_ENCRYPT, // 设置加密方式, req = me, ind = 0, val = 0, len = sizeof(PACK_BASE) USB_REQ_EP0_SET_BULK_BUFFER, // 设置bulk缓冲区大小系数, req = me, ind = coef, val = 0, len = 0 }; -enum bulk_status +enum woker_status { - BULK_STATUS_NOT_START = 0, // has not initialized - BULK_STATUS_IDLE, // wait IO - BULK_STATUS_IO, // in reading or writing - BULK_STATUS_ERROR, // error occurs - BULK_STATUS_RESET, // in reset(close and reopen) process + WORKER_STATUS_NOT_START = 0, // has not start + WORKER_STATUS_IDLE, // idle + WORKER_STATUS_BUSY, // in working + WORKER_STATUS_ERROR, // error occurs + WORKER_STATUS_RESET, // in reset(close and reopen) process }; enum packet_cmd diff --git a/sdk/base/plat_types.h b/sdk/base/plat_types.h index bc54e17..17f31ce 100644 --- a/sdk/base/plat_types.h +++ b/sdk/base/plat_types.h @@ -24,6 +24,7 @@ #if !OS_WIN // migrate codes from windows to linux ... #include +#include #include #include #include @@ -97,6 +98,7 @@ typedef int BOOL; #define USB_TIMEOUT_INFINITE 0 #define FSEEK fseek #define FTELL ftell +#define INVALID_HANDLE_VALUE ((HANDLE)(-1)) extern DWORD GetLastError(void); @@ -104,8 +106,8 @@ extern DWORD GetPrivateProfileIntA(const char* app, const char* key, DWORD def, extern DWORD GetPrivateProfileStringA(const char* app, const char* key, const char* init, char* buf, size_t len, const char* file); extern void Sleep(DWORD milliseconds); extern int GetModuleFileNameA(HMODULE module, char* buf, size_t len); // NOTE: parameter 'module' is consinder as a part of the module file name -extern int GetCurrentProcessId(void); -extern int GetCurrentThreadId(void); +extern uint64_t GetCurrentProcessId(void); +extern uint64_t GetCurrentThreadId(void); #else #include diff --git a/sdk/base/utils.cpp b/sdk/base/utils.cpp index 1d0d03a..574c626 100644 --- a/sdk/base/utils.cpp +++ b/sdk/base/utils.cpp @@ -196,13 +196,13 @@ int GetModuleFileNameA(HMODULE module, char* buf, size_t len) return len; } -int GetCurrentThreadId(void) +uint64_t GetCurrentThreadId(void) { - return pthread_self(); + return (uint64_t)pthread_self(); } -int GetCurrentProcessId(void) +uint64_t GetCurrentProcessId(void) { - return getpid(); + return (uint64_t)getpid(); } #endif @@ -236,7 +236,7 @@ class log_cls } else { - std::string sep("\n\n===================================================================================================================\n"); + std::string sep("\n\n========================================================================================================================\n"); fwrite(sep.c_str(), sizeof(sep[0]), sep.length(), file_); } @@ -575,10 +575,18 @@ namespace utils } rv = fread(buf, 1, sizeof(buf) - 1, src); } + if(rv == -1 && err) + { + *err = errno; + utils::to_log(LOG_LEVEL_DEBUG, "Failed to excute shell command '%s' in read pipe: %d - %s\n", cmd, errno, strerror(errno)); + } pclose(src); } else if(err) + { *err = errno; + utils::to_log(LOG_LEVEL_DEBUG, "Failed to excute shell command '%s' in open pipe: %d - %s\n", cmd, errno, strerror(errno)); + } #endif return std::move(result); @@ -978,6 +986,36 @@ namespace utils { return rename(from, to); } + int make_file_size(const char* file, uint64_t size) + { + int err = 0; + + get_command_result(("fallocate -l " + std::to_string(size) + " " + file).c_str(), -1, &err); + if(err == 0) + { + get_command_result(("truncate -s " + std::to_string(size) + " " + file).c_str(), -1, &err); + if(err == 0) + { + FILE* dst = fopen(file, "rb"); + if(dst) + { + uint64_t rs = 0; + + FSEEK(dst, 0, SEEK_END); + rs = FTELL(dst); + fclose(dst); + if(rs != size) + err = ENOSPC; + } + else + err = errno; + } + } + if(err) + remove(file); + + return err; + } int get_disk_space(const char* path, unsigned long long* total, unsigned long long* avail, unsigned long long* block) { @@ -1049,7 +1087,7 @@ namespace utils return ps; } - void init_log(log_type type, log_level level, const char* fn_appendix) + std::string init_log(log_type type, log_level level, const char* fn_appendix) { std::string file(""); @@ -1072,6 +1110,8 @@ namespace utils log_cls::instance()->set_log_type(type, &file[0]); log_cls::instance()->set_log_level(level); + + return std::move(file); } void uninit(void) { @@ -1872,22 +1912,22 @@ safe_thread::~safe_thread() threads_.clear(); } -void safe_thread::thread_worker(std::function func, std::string name) +void safe_thread::thread_worker(std::function func, std::string name, void* addr) { try { - utils::to_log(LOG_LEVEL_DEBUG, "+++ safe_thread of '%s' is running ...\n", name.c_str()); + utils::to_log(LOG_LEVEL_DEBUG, "+++ safe_thread of '%s(%p) - %p' is running ...\n", name.c_str(), addr, GetCurrentThreadId()); func(); - utils::to_log(LOG_LEVEL_DEBUG, "--- safe_thread of '%s' exited.\n", name.c_str()); + utils::to_log(LOG_LEVEL_DEBUG, "--- safe_thread of '%s - %p' exited.\n", name.c_str(), GetCurrentThreadId()); return; } catch (std::exception e) { - utils::to_log(LOG_LEVEL_FATAL, "Exception in thread '%s': %s\n", name.c_str(), e.what()); + utils::to_log(LOG_LEVEL_FATAL, "Exception in thread '%p - %s': %s\n", GetCurrentThreadId(), name.c_str(), e.what()); } catch (...) { - utils::to_log(LOG_LEVEL_FATAL, "Unknown exception in thread '%s'!\n", name.c_str()); + utils::to_log(LOG_LEVEL_FATAL, "Unknown exception in thread '%p - %s'!\n", GetCurrentThreadId(), name.c_str()); } excep_que_.save(name, true); } @@ -1908,12 +1948,12 @@ void safe_thread::set_exception_handler(std::function on_exce { excep_handler_ = on_exception; } -int safe_thread::start(std::function f, const char* thread_name) +int safe_thread::start(std::function f, const char* thread_name, void* addr) { SAFETHRD st; st.name = thread_name ? thread_name : ""; - st.thread.reset(new std::thread(&safe_thread::thread_worker, this, f, thread_name)); + st.thread.reset(new std::thread(&safe_thread::thread_worker, this, f, thread_name, addr)); { SIMPLE_LOCK(lock_); diff --git a/sdk/base/utils.h b/sdk/base/utils.h index 1805f35..811c833 100644 --- a/sdk/base/utils.h +++ b/sdk/base/utils.h @@ -57,11 +57,13 @@ namespace utils void set_ini_value(const char* seg, const char* key, const char* val, const char* cfg_file); int enum_file(const char* folder, bool recursive, bool/*return false to stop enumeration*/(STDCALL* found)(const char* path_name, bool dir, void* param), void* param); int move_file(const char* from, const char* to); + int make_file_size(const char* file, uint64_t size); // truncate or extend file size to 'size', create if not exist int get_disk_space(const char* path, unsigned long long* total, unsigned long long* avail, unsigned long long* block); unsigned int get_page_size(unsigned int* map_unit = nullptr); - void init_log(log_type type, log_level level = LOG_LEVEL_ALL, const char* fn_appendix = nullptr/*appendix to default log-file-name*/); + // return logging file path if 'type' was LOG_TYPE_FILE + std::string init_log(log_type type, log_level level = LOG_LEVEL_ALL, const char* fn_appendix = nullptr/*appendix to default log-file-name*/); void uninit(void); void log_info(const char* info, int level = LOG_LEVEL_ALL); void log_mem_info(const char* desc, const void* data, size_t bytes, int level = LOG_LEVEL_ALL); // log as 0x12345678 00 01 02 ... @@ -354,7 +356,7 @@ class safe_thread safe_fifo excep_que_; std::function excep_handler_ = std::function(); - void thread_worker(std::function func, std::string name); + void thread_worker(std::function func, std::string name, void* addr); void thread_notify_exception(void); public: @@ -363,6 +365,6 @@ public: public: void set_exception_handler(std::function on_exception = std::function()); - int start(std::function f, const char* thread_name); + int start(std::function f, const char* thread_name, void* addr = nullptr); int stop(const char* thread_name); }; diff --git a/sdk/sane_opt_json/device_opt.cpp b/sdk/sane_opt_json/device_opt.cpp index fd82cab..59aa556 100644 --- a/sdk/sane_opt_json/device_opt.cpp +++ b/sdk/sane_opt_json/device_opt.cpp @@ -1158,13 +1158,42 @@ void device_option::insert_option(gb_json* opt, sane_opt_provider* from, const c } else { - int index = -1; + int index = -1, pos = -1; if (group) index = insert_group(group, group); - index = next_group(index + 1); + // insert poisition according to 'ui-pos' + if (!opt->get_value("ui-pos", pos) || pos == -1) + { + index = next_group(index + 1); + } + else + { + for (index++; index < origin_->children(); ++index) + { + gb_json* sib = origin_->child(index); + std::string t(""); + int sit = -1; + + if (!sib->get_value("type", t) || t == JSON_SANE_TYPE_GROUP) + { + sib->release(); + break; + } + if (!sib->get_value("ui-pos", sit) || sit == -1) + { + sib->release(); + break; + } + sib->release(); + + if (pos < sit) + break; + } + } origin_->insert(index, opt->key().c_str(), opt); + src_[opt->key()] = from; from->add_ref(); } @@ -1310,7 +1339,24 @@ gb_json* device_option::copy_opt(gb_json* from) // 2: enabled ... if (slaver_.count(to->key())) - to->set_value("enabled", slaver_[to->key()]->value(&device_option::calc_simple_logic_expression, this)); + { + bool enable = slaver_[to->key()]->value(&device_option::calc_simple_logic_expression, this); + to->set_value("enabled", enable); + if (src_.count(to->key())) + { + src_[to->key()]->enable(to->key().c_str(), enable); + + sane_opt_provider* next = src_[to->key()]->get_following(to->key().c_str()); + while (next) + { + next->enable(to->key().c_str(), enable); + + sane_opt_provider* next1 = next->get_following(to->key().c_str()); + next->release(); + next = next1; + } + } + } // 3: default value ... if (init_value_.count(to->key())) diff --git a/usb/usb_dev.cpp b/usb/usb_dev.cpp index 76fc1af..8bcf264 100644 --- a/usb/usb_dev.cpp +++ b/usb/usb_dev.cpp @@ -688,6 +688,25 @@ int usb_device::close_device(void) } int usb_device::pull_up(std::string* msg) { + { + int dst = open(udc_.c_str(), O_RDWR); + if(dst == -1) + utils::to_log(LOG_LEVEL_DEBUG, "Try write '%s' to '%s' failed(open): %s\n", dwc3_.c_str(), udc_.c_str(), strerror(errno)); + else + { + int l = write(dst, dwc3_.c_str(), dwc3_.length()), + err = errno; + close(dst); + if(l == dwc3_.length()) + { + utils::to_log(LOG_LEVEL_DEBUG, "pull up device by write '%s' to '%s' directly success.\n", dwc3_.c_str(), udc_.c_str()); + return 0; + } + else + utils::to_log(LOG_LEVEL_DEBUG, "Try write '%s' to '%s' failed(write): %s\n", dwc3_.c_str(), udc_.c_str(), strerror(errno)); + } + } + std::string cmd("echo " + pwd_ + " | sudo -S sh -c \"echo " + dwc3_ + " > " + udc_ + "\""); int err = 0; std::string info(utils::get_command_result(cmd.c_str(), -1, &err)); diff --git a/usb/usb_io.cpp b/usb/usb_io.cpp index cbe599c..046abc9 100644 --- a/usb/usb_io.cpp +++ b/usb/usb_io.cpp @@ -21,7 +21,8 @@ async_usb_gadget::async_usb_gadget(std::function , cmd_que_("in-queue"), sent_que_("out-queue") , wait_in_("wait_usb_enable_in"), wait_out_("wait_usb_enable_out") { - memset((void*)&status_, 0, sizeof(status_)); + cmd_que_.enable_wait_log(false); + sent_que_.enable_wait_log(false); dev_ = new usb_device("fe900000.dwc3", "/opt/cfg/usb_gadget/g1/UDC", "linaro"); dev_->add_endpoint(USB_EP_BULK_IN, true, true); @@ -87,10 +88,10 @@ async_usb_gadget::async_usb_gadget(std::function threads_.set_exception_handler(excep); unit_in_ = unit_out_ = dev_->get_max_packet(); - threads_.start(task, "thread_pump_task"); - threads_.start(bulkw, "thread_read_bulk"); - threads_.start(bulkr, "thread_write_bulk"); - threads_.start(ep0, "thread_read_ep0"); + threads_.start(task, "thread_pump_task", (void*)&async_usb_gadget::thread_pump_task); + threads_.start(bulkw, "thread_write_bulk", (void*)&async_usb_gadget::thread_write_bulk); + threads_.start(bulkr, "thread_read_bulk", (void*)&async_usb_gadget::thread_read_bulk); + threads_.start(ep0, "thread_read_ep0", (void*)&async_usb_gadget::thread_read_ep0); } async_usb_gadget::~async_usb_gadget() @@ -149,19 +150,19 @@ dyn_mem_ptr async_usb_gadget::handle_ctrl_message(dyn_mem_ptr data) switch (pev->type) { case FUNCTIONFS_ENABLE: - utils::to_log(LOG_LEVEL_ALL, "EP0 FFS ENABLE\n"); - online_ = true; session_id_++; + utils::to_log(LOG_LEVEL_DEBUG, "////////////// EP0 FFS ENABLE, start session %u ...\n", session_id_); + online_ = true; wait_in_.trigger(); wait_out_.trigger(); if(dev_connect_) - dev_connect_(true); + dev_connect_(online_); break; case FUNCTIONFS_DISABLE: - utils::to_log(LOG_LEVEL_ALL, "EP0 FFS DISABLE\n"); online_ = false; if(dev_connect_) - dev_connect_(false); + dev_connect_(online_); + utils::to_log(LOG_LEVEL_DEBUG, "////////////// EP0 FFS DISABLE, end session %u ...\n\n", session_id_); break; case FUNCTIONFS_SETUP: reply = handle_ctrl_setup(data); @@ -219,8 +220,17 @@ dyn_mem_ptr async_usb_gadget::handle_ctrl_setup(dyn_mem_ptr data) break; case USB_REQ_EP0_GET_STATUS: reply = dyn_mem::memory(sizeof(struct _ep0_reply)); + reply->set_len(sizeof(struct _ep0_reply)); { - reply->put((void*)&status_, sizeof(status_)); + LPEP0REPLYSTATUS lps = (LPEP0REPLYSTATUS)reply->ptr(); + lps->in_status = statu_in_; + lps->out_status = statu_out_; + lps->task_cmd = task_cmd_; + lps->task_pack_id = task_packet_id_; + lps->task_required_bytes = want_bytes_task_; + lps->packets_to_sent = sent_que_.size(); + lps->bytes_to_sent = want_bytes_in_; + utils::log_mem_info("threads status:", lps, sizeof(*lps), LOG_LEVEL_DEBUG); } break; case USB_REQ_EP0_RESET_BULK: @@ -255,6 +265,8 @@ dyn_mem_ptr async_usb_gadget::handle_ctrl_setup(dyn_mem_ptr data) utils::to_log(LOG_LEVEL_ALL, "EP0 event(0x%x, 0x%x, 0x%x, 0x%x, 0x%x) has not handled by user business.\n" , pev->u.setup.bRequestType, pev->u.setup.bRequest, pev->u.setup.wValue, pev->u.setup.wIndex, pev->u.setup.wLength); } + if(reply) + reply->set_session_id(data->get_session_id()); return reply; } @@ -264,13 +276,16 @@ int async_usb_gadget::inner_write_bulk(int fd, data_source_ptr data, int* err) size_t bulk_size = unit_in_ * get_buf_coefficient(), total = data->get_rest(), off = 0, size = total > bulk_size ? bulk_size : total; int w = 0; + bool fail = false; + statu_in_ = WORKER_STATUS_BUSY; + want_bytes_in_ = total; if(data->is_memory_block()) { while((w = write(fd, ptr + off, size)) > 0) { off += w; - status_.bytes_to_sent -= w; + want_bytes_in_ -= w; if(off >= total) break; if(off + bulk_size < total) @@ -279,7 +294,10 @@ int async_usb_gadget::inner_write_bulk(int fd, data_source_ptr data, int* err) size = total - off; } if(w <= 0 && err) + { *err = errno; + } + fail = w <= 0; } else { @@ -296,7 +314,7 @@ int async_usb_gadget::inner_write_bulk(int fd, data_source_ptr data, int* err) w = write(fd, ptr + off, len); while(w > 0 && w + off < len) { - status_.bytes_to_sent -= w; + want_bytes_in_ -= w; total += w; off += w; w = write(fd, ptr + off, len - off); @@ -304,14 +322,14 @@ int async_usb_gadget::inner_write_bulk(int fd, data_source_ptr data, int* err) if(w <= 0) { + fail = true; if(err) *err = errno; - utils::to_log(LOG_LEVEL_ALL, "inner_write_bulk error(%d/%d): %d (%s)\n", off, len, errno, strerror(errno)); break; } else { - status_.bytes_to_sent -= w; + want_bytes_in_ -= w; total += w; } @@ -322,6 +340,8 @@ int async_usb_gadget::inner_write_bulk(int fd, data_source_ptr data, int* err) buf->release(); off = total; } + statu_in_ = fail ? WORKER_STATUS_ERROR : WORKER_STATUS_IDLE; + want_bytes_in_ = 0; return off; } @@ -358,7 +378,6 @@ void async_usb_gadget::thread_read_ep0(void) std::string msg(""); struct usb_functionfs_event* pe = (struct usb_functionfs_event*)ptr; - utils::to_log(LOG_LEVEL_ALL, "EP0 monitoring thread(%p of id %lx) started ...\n", &async_usb_gadget::thread_read_ep0, getpid()); ret = dev_->pull_up(&msg); while(run_) { @@ -424,17 +443,17 @@ void async_usb_gadget::thread_read_bulk(int fd) dyn_mem_ptr buf(dyn_mem::memory(bulk_size)); int l = 0; - status_.out_status = BULK_STATUS_IO; + statu_out_ = WORKER_STATUS_BUSY; buf->set_session_id(session_id_); l = read(fd, buf->ptr(), bulk_size); + statu_out_ = WORKER_STATUS_IDLE; if(l <= 0) { buf->release(); if(errno) { utils::to_log(LOG_LEVEL_ALL, "read bulk(%d) failed: %d(%s)\n", l, errno, strerror(errno)); - status_.out_status = BULK_STATUS_ERROR; - status_.out_err = errno; + statu_out_ = WORKER_STATUS_ERROR; break; } else @@ -446,22 +465,19 @@ void async_usb_gadget::thread_read_bulk(int fd) { utils::to_log(LOG_LEVEL_ALL, "thread_read_bulk do reset-bulk ...\n"); buf->release(); - if(!run_) - break; + break; } else { - status_.out_status = BULK_STATUS_IDLE; buf->set_len(l); cmd_que_.save(buf, true); } } - if(status_.out_status == BULK_STATUS_IDLE) - status_.out_status = BULK_STATUS_NOT_START; + statu_out_ = WORKER_STATUS_NOT_START; } void async_usb_gadget::thread_write_bulk(int fd) { - status_.in_status = BULK_STATUS_IDLE; + statu_in_ = WORKER_STATUS_IDLE; while(run_) { data_source_ptr data; @@ -469,24 +485,17 @@ void async_usb_gadget::thread_write_bulk(int fd) if(sent_que_.take(data, true)) { - status_.packets_to_sent = sent_que_.size(); - status_.bytes_to_sent = data->get_rest(); - status_.in_status = BULK_STATUS_IO; + want_bytes_in_ = data->get_rest(); inner_write_bulk(fd, data, &err); - status_.in_status = BULK_STATUS_IDLE; - status_.bytes_to_sent = 0; data->release(); if(err) { utils::to_log(LOG_LEVEL_ALL, "write bulk failed: %d(%s)\n", errno, strerror(errno)); - status_.in_status = BULK_STATUS_ERROR; - status_.in_err = err; break; } } } - if(status_.in_status == BULK_STATUS_IDLE) - status_.in_status = BULK_STATUS_NOT_START; + statu_in_ = WORKER_STATUS_NOT_START; } void async_usb_gadget::thread_pump_task(void) { @@ -500,11 +509,12 @@ void async_usb_gadget::thread_pump_task(void) while(run_) { data = nullptr; + statu_task_ = WORKER_STATUS_IDLE; if(cmd_que_.take(data, true) && data) { - status_.task_cnt = cmd_que_.size(); - if(max_que < status_.task_cnt) - max_que = status_.task_cnt; + statu_task_ = WORKER_STATUS_BUSY; + if(max_que < cmd_que_.size()) + max_que = cmd_que_.size(); if(prev) { @@ -549,8 +559,9 @@ void async_usb_gadget::thread_pump_task(void) else { pack = (LPPACK_BASE)data->ptr(); - status_.task_cmd = pack->cmd; - status_.task_pack_id = pack->pack_id; + task_cmd_ = pack->cmd; + task_packet_id_ = pack->pack_id; + want_bytes_task_ = 0; used = data->get_rest(); reply = handle_bulk_command(data, &used, &pack_data); notify_reply_ok = used & (INT32_MAX + 1); @@ -564,9 +575,14 @@ void async_usb_gadget::thread_pump_task(void) ds = dynamic_cast(pack_data); if(!ds) pack_data->release(); + else + want_bytes_task_ = ds->get_rest(); } else + { total_size = 0; + want_bytes_task_ = dh->get_required(); + } } } } @@ -588,10 +604,15 @@ void async_usb_gadget::thread_pump_task(void) BASE_PACKET_REPLY(*pack, dh->get_packet_command() + 1, dh->get_packet_id(), err); reply->set_len(sizeof(PACK_BASE)); - utils::to_log(LOG_LEVEL_ALL, "Finished receiving file with error(Max queue size is %u): %d, total size = 0x%x\n", max_que, err, total_size); + utils::to_log(LOG_LEVEL_ALL, "Finished receiving large data with error(Max queue size is %u): %d, total size = 0x%x\n", max_que, err, total_size); dh->release(); dh = nullptr; + want_bytes_task_ = 0; + } + else + { + want_bytes_task_ = dh->get_required(); } used = len; @@ -612,7 +633,7 @@ void async_usb_gadget::thread_pump_task(void) reply->release(); reply = enc; } - + reply->set_session_id(data->get_session_id()); write_bulk(dynamic_cast(reply)); if(notify_reply_ok) handle_bulk_command(data, nullptr, nullptr); @@ -628,17 +649,19 @@ void async_usb_gadget::thread_pump_task(void) ds = nullptr; } - status_.task_required_bytes = dh ? dh->get_required() : 0; - if(status_.task_required_bytes == 0) - status_.task_cmd = status_.task_pack_id = 0; - data->used(used); }while(used && data->get_rest()); - + if(data->get_rest()) prev = data; else + { + if(!dh) + { + task_cmd_ = task_packet_id_ = want_bytes_task_ = 0; + } data->release(); + } } } if(prev) @@ -674,7 +697,7 @@ int async_usb_gadget::write_bulk(data_source_ptr data) { if(data->get_session_id() != session_id_ || !online_) { - utils::to_log(LOG_LEVEL_DEBUG, "Discard packet for the session ID(%u) is not equal current session(%u) or is offline.\n", data->get_session_id(), session_id_); + utils::to_log(LOG_LEVEL_DEBUG, "Discard reply packet for the session ID(%u) is not equal current session(%u) or is offline.\n", data->get_session_id(), session_id_); data->release(); return sent_que_.size(); @@ -692,4 +715,4 @@ int async_usb_gadget::write_bulk(data_source_ptr data) int async_usb_gadget::last_error(void) { return last_err_; -} \ No newline at end of file +} diff --git a/usb/usb_io.h b/usb/usb_io.h index a7b5ae2..4828d8d 100644 --- a/usb/usb_io.h +++ b/usb/usb_io.h @@ -59,7 +59,16 @@ class async_usb_gadget : public refer uint8_t enc_data_; int last_err_ = 0; - volatile EP0REPLYSTATUS status_; + uint8_t statu_in_ = WORKER_STATUS_NOT_START; + uint32_t want_bytes_in_ = 0; + + uint8_t statu_out_ = WORKER_STATUS_NOT_START; + + uint8_t statu_task_ = WORKER_STATUS_NOT_START; + uint32_t want_bytes_task_ = 0; + uint32_t task_cmd_ = 0; + uint32_t task_packet_id_ = 0; + safe_fifo cmd_que_; safe_fifo sent_que_;