From f9aea5269434d3abddebcca4b28c520ace02453d Mon Sep 17 00:00:00 2001 From: gb <741021719@qq.com> Date: Fri, 24 Feb 2023 17:24:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=8E=E9=AB=98=E5=9B=BD=E4=BA=A7=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E5=B0=8F=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BlockingQueue.h | 133 ++++ CMakeLists.txt | 27 + base.cpp | 943 ++++++++++++++++++++++++ base.h | 164 +++++ cmd.cpp | 308 ++++++++ cmd.h | 148 ++++ hg_ipc.cpp | 886 +++++++++++++++++++++++ hg_ipc.h | 244 +++++++ hgscanner_error.h | 348 +++++++++ main.cpp | 1765 +++++++++++++++++++++++++++++++++++++++++++++ usb_manager.cpp | 1162 +++++++++++++++++++++++++++++ usb_manager.h | 206 ++++++ 12 files changed, 6334 insertions(+) create mode 100644 BlockingQueue.h create mode 100644 CMakeLists.txt create mode 100644 base.cpp create mode 100644 base.h create mode 100644 cmd.cpp create mode 100644 cmd.h create mode 100644 hg_ipc.cpp create mode 100644 hg_ipc.h create mode 100644 hgscanner_error.h create mode 100644 main.cpp create mode 100644 usb_manager.cpp create mode 100644 usb_manager.h diff --git a/BlockingQueue.h b/BlockingQueue.h new file mode 100644 index 0000000..b877bb0 --- /dev/null +++ b/BlockingQueue.h @@ -0,0 +1,133 @@ +#ifndef BLOCKING_QUEUE_H +#define BLOCKING_QUEUE_H + +//#include +//#include +#if defined(WIN32) || defined(_WIN64) +#include +#endif +#include +#include +#include +#include +#include +using namespace std; + +template +class BlockingQueue +{ +private: + BlockingQueue(const BlockingQueue& rhs); + BlockingQueue& operator =(const BlockingQueue& rhs); + mutable std::mutex _mutex; + std::condition_variable _condvar; + typedef struct _dq + { + size_t bytes; + uint32_t id; + T t; + }DQ; + deque _queue; + size_t bytes_; + bool isShutDown; + T tRet; + +public: + BlockingQueue() + : _mutex() + , _condvar() + , _queue() + , isShutDown(false), bytes_(0) + { + } + + ~BlockingQueue() + { + ShutDown(); + std::cout << "blocking queue release" << std::endl; + } + + void Clear() + { + lock_guard lock(_mutex); + _condvar.notify_all(); + _queue.clear(); + bytes_ = 0; + } + + void ShutDown() + { + isShutDown = true; + _condvar.notify_all(); + _queue.clear(); + bytes_ = 0; + } + + bool IsShutDown() + { + return isShutDown; + } + + void Put(const T task, size_t bytes, uint32_t id = -1) + { + lock_guard lock(_mutex); + if (!isShutDown) + { + { + DQ dq = { bytes, id, task }; + _queue.push_back(dq); + bytes_ += bytes; + } + _condvar.notify_all(); + } + + } + + T Take(uint32_t* id = nullptr) + { + unique_lock lock(_mutex); + if (_queue.size() <= 0) + _condvar.wait(lock); + + if (isShutDown || _queue.empty()) + { + return tRet; + } + + DQ front(_queue.front()); + _queue.pop_front(); + bytes_ -= front.bytes; + if (id) + *id = front.id; + + return front.t; + } + + T Front(uint32_t* id = nullptr) + { + unique_lock lock(_mutex); + if (_queue.size() <= 0) + _condvar.wait(lock); + + if (isShutDown || _queue.empty()) + { + return tRet; + } + + DQ front(_queue.front()); + + return front.t; + } + + size_t Size(size_t* bytes = nullptr) const + { + lock_guard lock(_mutex); + + if (bytes) + *bytes = bytes_; + + return _queue.size(); + } +}; + +#endif diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c2f6636 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,27 @@ +project(hgutil) +add_definitions(-DBACKEND_NAME=hgsane) +#add_compile_options(-std=c++11) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") +aux_source_directory(${PROJECT_SOURCE_DIR} DIR_SRCS) +file(GLOB DIR_HEADS "${PROJECT_SOURCE_DIR}/*.h" "${PROJECT_SOURCE_DIR}/*.hpp") +set(DIR_SRCS ${DIR_SRCS} ${DIR_HEADS}) +add_executable(hgutil main.cpp usb_manager.cpp hg_ipc.cpp cmd.cpp base.cpp) +link_libraries(dl) +#add_executable(libhgsane.so IMPORTED) + +#link_directories(${PROJECT_NAME} PRIVATE +# ${PROJECT_SOURCE_DIR}/../../sdk/lib +# ) + +#target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR} +# ${PROJECT_SOURCE_DIR}/../../sdk/sane +# ${PROJECT_SOURCE_DIR}/../../sdk +# ) + +target_link_libraries(${PROJECT_NAME} PRIVATE + pthread + usb-1.0 + ) + +set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/out) diff --git a/base.cpp b/base.cpp new file mode 100644 index 0000000..013c3e6 --- /dev/null +++ b/base.cpp @@ -0,0 +1,943 @@ +#include "base.h" + +#include + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// refer +refer::refer() : ref_(1) +{ + on_born(); +} +refer::~refer() +{ + on_dead(); +} + +void refer::on_born(void) +{} +void refer::on_dead(void) +{} + +int32_t refer::add_ref(void) +{ + LOCKER lock(mutex_); + + return ++ref_; +} +int32_t refer::release(void) +{ + int32_t ref = 0; + + { + LOCKER lock(mutex_); + ref = --ref_; + } + + if (ref == 0) + delete this; + + return ref; +} + + + + + + + + + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// chronograph +#include + + +chronograph::chronograph() +{ + reset(); +} +chronograph::~chronograph() +{} + +bool chronograph::now(struct timeval* tv) +{ + struct timezone tz = { 0 }; + + return gettimeofday(tv, &tz) == 0; +} +bool chronograph::now(uint64_t* seconds, uint64_t* u_seconds) +{ + struct timeval tv = { 0 }; + struct timezone tz = { 0 }; + + if (gettimeofday(&tv, &tz) == 0) + { + if (seconds) + *seconds = tv.tv_sec; + if (u_seconds) + *u_seconds = tv.tv_usec; + + return true; + } + else + { + return false; + } +} +std::string chronograph::now(bool with_ms/*whether with milliseconds*/) // return '2022-11-30 10:38:42.123', no '.123' if with_ms was false +{ + struct timeval tv = { 0 }; + + if (!chronograph::now(&tv)) + return ""; + + char buf[40] = { 0 }; + time_t t = tv.tv_sec; + struct tm* l = localtime(&t); + + if (with_ms) + sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d.%06d", l->tm_year + 1900, l->tm_mon + 1, l->tm_mday + , l->tm_hour, l->tm_min, l->tm_sec, tv.tv_usec); + else + sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", l->tm_year + 1900, l->tm_mon + 1, l->tm_mday + , l->tm_hour, l->tm_min, l->tm_sec); + + return buf; +} + +uint64_t chronograph::elapse_s(void) +{ + struct timeval tv = { 0 }; + + chronograph::now(&tv); + + return tv.tv_sec - bgn_.tv_sec; +} +uint64_t chronograph::elapse_ms(void) +{ + struct timeval tv = { 0 }; + uint64_t dif = 0; + + chronograph::now(&tv); + dif = SEC_2_MS(tv.tv_sec - bgn_.tv_sec); + dif += tv.tv_usec / MSEC_2_US(1); + dif -= bgn_.tv_usec / MSEC_2_US(1); + + return dif; +} +uint64_t chronograph::elapse_us(void) +{ + struct timeval tv = { 0 }; + uint64_t dif = 0; + + chronograph::now(&tv); + dif = SEC_2_US(tv.tv_sec - bgn_.tv_sec); + dif += tv.tv_usec; + dif -= bgn_.tv_usec; + + return dif; +} +void chronograph::reset() +{ + chronograph::now(&bgn_); +} + + + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// sys utility +#include +#include +#include +#include + +namespace sys_util +{ + static bool find_module(const char* path, bool is_dir, void* param) + { + std::string* para = (std::string*)param; + + if (para[0].empty()) + { + const char* now = getenv("PWD"); + bool found = strstr(path, now) == path; + + if(found) + { + found = path[strlen(now)] == '/' && strstr(path + strlen(now) + 1, "/") == nullptr; + } + if(found || para[1].empty()) + para[1] = path; + + return !found; + } + else + { + const char* name = strrchr(path, '/'); + if (name++ == nullptr) + name = path; + if (strstr(name, para[0].c_str())) + { + para[1] = path; + + return false; + } + + return true; + } + } + typedef struct _enum_proc_cb + { + bool process; + bool(*on_found)(uint64_t pid, const char* path_name, void* param); + void* param; + }ENPROCCB, * LPENPROCCB; + static bool found_process(const char* path, bool is_dir, void* param) + { + LPENPROCCB cb = (LPENPROCCB)param; + const char* id = strrchr(path, '/'); + uint64_t pid = 0; + std::string path_name(""); + + if (id++ == nullptr) + { + id = path; + } + while (*id) + { + if (*id < '0' || *id > '9') + break; + + pid *= 10; + pid += *id - '0'; + id++; + } + if (*id) + return true; + + if (cb->process) + { + path_name = get_module_path(nullptr, pid); + id = path_name.c_str(); + } + else + { + // get start address of pid to path_name + id = 0; + } + + return cb->on_found(pid, id, cb->param); + } + static bool on_stack_line_read(char* line, void* param) + { + LPENPROCCB cb = (LPENPROCCB)param; + std::string m(line); + uint64_t off = 0; + size_t pos = m.find("]"); + + if (pos++ != std::string::npos) + m.erase(0, pos); + trim_left(m); + pos = m.find("+0x"); + if (pos != std::string::npos) + { + off = from_hex_str(m.c_str() + pos + 3); + m.erase(pos); + } + + return cb->on_found(off, m.c_str(), cb->param); + } + + int32_t enum_modules(bool(*on_found)(const char* path_module_name, bool is_dir, void* param),// return false to stop enumeratin + void* param, // user defined data, passed into callback on_found + unsigned pid // process id, -1 is self + ) // return errno + { + char path[128] = { 0 }; + + if (pid == -1) + pid = getpid(); + sprintf(path, "/proc/%u/map_files/", pid); + + return enum_files(path, on_found, param, false); + } + + int32_t enum_files(const char* dir, // dir path + bool(*on_found)(const char* path_name, bool is_dir, void* param), // return false to stop enumeratin + void* param // user defined data, passed into callback on_found + , bool recursive + ) // return errno + { + int32_t ret = 0; + DIR* pdir = nullptr; + struct dirent* ent = nullptr; + + pdir = opendir(dir); + if (!pdir) + return errno; + + while ((ent = readdir(pdir))) + { + if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) + continue; + + std::string file(dir); + + file += "/"; + file += ent->d_name; + if ((ent->d_type & DT_DIR) == 0) + { + file = read_link(file.c_str()); + if(file.empty()) + file = std::string(dir) + "/" + ent->d_name; + } + if (!on_found(file.c_str(), ent->d_type & DT_DIR, param)) + { + ret = 0x5e17; + break; + } + + if ((ent->d_type & DT_DIR) && recursive) + { + std::string sub(dir); + sub += "/"; + sub += ent->d_name; + ret = enum_files(sub.c_str(), on_found, param, recursive); + if (ret == 0x5e17) + break; + } + } + closedir(pdir); + + return ret == 0x5e17 ? 0 : ret; + } + + int32_t enum_processes(bool(*on_found)(uint64_t pid, const char* path_name, void* param), void* param) + { + ENPROCCB cb; + + cb.on_found = on_found; + cb.param = param; + cb.process = true; + + return enum_files("/proc", found_process, &cb, false); + } + uint32_t enum_threads(uint64_t pid, bool(*on_found)(uint64_t tid, void* start_addr, void* param), void* param) + { + ENPROCCB cb; + + cb.process = false; + cb.param = param; + *(void**)&cb.on_found = *(void**)&on_found; + + return enum_files(("/proc/" + std::to_string(pid) + "/task").c_str(), found_process, &cb, false); + } + uint32_t get_thread_callstack(uint64_t pid, uint64_t tid, bool(*on_found)(uint64_t off, const char* module, void* param), void* param) + { + ENPROCCB cb; + + cb.process = false; + cb.param = param; + *(void**)&cb.on_found = *(void**)&on_found; + + return read_line(("/proc/" + std::to_string(pid) + "/task/" + std::to_string(tid) + "/stack").c_str(), on_stack_line_read, &cb); + } + uint32_t read_line(const char* file, bool(*on_line)(char* line, void* param), void* param) + { + FILE* src = fopen(file, "rb"); + int err = 0; + + if (!src) + return errno; + + size_t ll = 1024; + char* line = new char[ll]; + while (fgets(line, ll - 1, src)) + { + if (!on_line(line, param)) + break; + + memset(line, 0, ll); + } + err = errno; + delete[] line; + fclose(src); + + return err; + } + + std::string get_module_path(const char* module_name, unsigned pid) // get module full path, nullptr is for main-exe + { + std::string param[] = { module_name ? module_name : "", "" }; + + enum_modules(find_module, param, pid); + + return param[1]; + } + std::string read_link(const char* lnk) + { + char path[512] = { 0 }; + + readlink(lnk, path, sizeof(path) - 1); + + return path; + } + size_t get_page_size(void) + { + size_t size = sysconf(_SC_PAGESIZE); + + if (size < 1024 || (size & 0x0fe0000ff)) // nKB && < 16MB + size = getpagesize(); + + return size; + } + bool create_folder(const char* dir) + { + bool ret = mkdir(dir, S_IREAD | S_IWRITE | S_IEXEC) == 0 || errno == EEXIST; + + if(errno == ENOENT) + { + std::string path(dir), cur(""); + size_t pos = path.find("/", 1); + + while(pos != std::string::npos) + { + ret = mkdir(path.substr(0, pos).c_str(), S_IREAD | S_IWRITE | S_IEXEC) == 0 || errno == EEXIST; + if(!ret) + { + printf("mkdir(%s) = %d(%s)\n", path.substr(0, pos).c_str(), errno, strerror(errno)); + break; + } + pos = path.find("/", pos + 1); + } + if(ret) + ret = mkdir(path.c_str(), S_IREAD | S_IWRITE | S_IEXEC) == 0; + } + + return ret; + } + + int32_t get_memory_info(uint64_t* total, uint64_t* available) + { + if (!total && !available) + return 0; + + char line[128] = { 0 }; + FILE* src = fopen("/proc/meminfo", "rb"); + int32_t count = total && available ? 2 : 1; + unsigned long val = 0; + + if (!src) + return errno; + + while (fgets(line, sizeof(line) - 1, src)) + { + if (sscanf(line, "MemTotal: %ld", &val)) + { + if (total) + { + *total = val * 1024; + if (--count == 0) + break; + } + } + else if (sscanf(line, "MemFree: %ld", &val)) + { + if (available) + { + *available = val * 1024; + if (--count == 0) + break; + } + } + } + + fclose(src); + + return 0; + } + std::string format_readable_bytes(uint64_t bytes) + { + std::string str("\0", 80); + + if (bytes >= SIZE_GB(1)) + { + double v = bytes * 1.0f / (SIZE_GB(1)); + size_t pos = 0; + + sprintf(&str[0], "%.2fGB", v); + pos = str.find("."); + while (pos > 3) + { + pos -= 3; + str.insert(pos, ","); + } + } + else if (bytes >= SIZE_MB(1)) + { + double v = bytes * 1.0f / (SIZE_MB(1)); + sprintf(&str[0], "%.2fMB", v); + } + else if (bytes >= SIZE_KB(1)) + { + double v = bytes * 1.0f / (SIZE_KB(1)); + sprintf(&str[0], "%.2fKB", v); + } + else + { + sprintf(&str[0], "%uB", (unsigned)bytes); + } + + return str; + } + std::string get_command_output(const char* cmd, uint16_t max_line_len, bool one_line) + { + FILE* src = popen(cmd, "r"); + std::string ret(""); + + if (src) + { + char* buf = new char[max_line_len + 4]; + if (buf) + { + memset(buf, 0, max_line_len + 4); + fgets(buf, max_line_len, src); + ret = buf; + while (!one_line && fgets(buf, max_line_len, src)) + ret += "\n" + std::string(buf); + + delete[] buf; + } + + pclose(src); + } + + return ret; + } + + static bool is_char_in(const char* str, char ch) + { + if (ch == 0) + return false; + + while (*str) + { + if (*str++ == ch) + return true; + } + + return false; + } + bool trim_left(std::string& str, const char* space) + { + int off = 0; + + for (; off < str.length(); ++off) + { + if (!is_char_in(space, str[off])) + break; + } + if (off) + str.erase(0, off); + + return off > 0; + } + bool trim_right(std::string& str, const char* space) + { + int off = str.length() - 1; + + for (; off >= 0; --off) + { + if (!is_char_in(space, str[off])) + break; + } + if (off < str.length() - 1) + { + str.erase(off + 1); + return true; + } + + return false; + } + uint64_t from_hex_str(const char* hex, const char** end) + { + uint64_t val = 0; + + for (int i = 0; i < 16; ++i) + { + if (*hex >= '0' && *hex <= '9') + { + val <<= 4; + val += *hex - '0'; + } + else if (*hex >= 'a' && *hex <= 'f') + { + val <<= 4; + val += *hex - 'a' + 10; + } + else if (*hex >= 'A' && *hex <= 'F') + { + val <<= 4; + val += *hex - 'A' + 10; + } + else + { + break; + } + hex++; + } + + if (end) + *end = hex; + + return val; + } + + static uint64_t from_dec_str(const char* str, const char** end) + { + uint64_t val = 0; + + for(int i = 0; *str && i < 19; ++i, ++str) + { + if(*str >= '0' && *str <= '9') + { + val *= 10; + val += *str - '0'; + } + else + break; + } + if(end) + *end = str; + + return val; + } + static uint64_t from_oct_str(const char* str, const char** end) + { + uint64_t val = 0; + + for(int i = 0; *str && i < 21; ++i, ++str) + { + if(*str >= '0' && *str <= '7') + { + val *= 8; + val += *str - '0'; + } + else + break; + } + if(end) + *end = str; + + return val; + } + static uint64_t from_bin_str(const char* str, const char** end) + { + uint64_t val = 0; + + for(int i = 0; *str && i < 64; ++i, ++str) + { + if(*str >= '0' && *str <= '1') + { + val *= 2; + val += *str - '0'; + } + else + break; + } + if(end) + *end = str; + + return val; + } + uint64_t to_int(const char* str, const char** end) + { + if(!str || *str == 0) + { + if(end) + *end = str; + + return 0; + } + + if(strstr(str, "0x") == str) + return from_hex_str(str + 2, end); + + if(str[strlen(str) - 1] == 'h' || str[strlen(str) - 1] == 'H') + return from_hex_str(str, end); + if(str[strlen(str) - 1] == 'o' || str[strlen(str) - 1] == 'O') + return from_oct_str(str, end); + if(str[strlen(str) - 1] == 'b' || str[strlen(str) - 1] == 'B') + return from_bin_str(str, end); + + bool hex = false; + for(int i = 0; str[i]; ++i) + { + if(str[i] < '0') + break; + if(str[i] > '9') + { + if((str[i] >= 'a' && str[i] <= 'f') || + (str[i] >= 'A' && str[i] <= 'F')) + hex = true; + break; + } + } + + return hex ? from_hex_str(str, end) : from_dec_str(str, end); + } + + /* iconv_open language options: + + Europe: + ASCII, ISO-8859-{1,2,3,4,5,7,9,10,13,14,15,16}, KOI8-R, KOI8-U, KOI8-RU, + CP{1250,1251,1252,1253,1254,1257}, CP{850,866}, + Mac{Roman,CentralEurope,Iceland,Croatian,Romania}, + Mac{Cyrillic,Ukraine,Greek,Turkish}, Macintosh + + Semitic: + ISO-8859-{6,8}, CP{1255,1256}, CP862, Mac{Hebrew,Arabic} + + Janpanese: + EUC-JP, SHIFT-JIS, CP932, ISO-2022-JP, ISO-2022-JP-2, ISO-2022-JP-1 + + Chinese: + EUC-CN, HZ, GBK, GB18030, EUC-TW, BIG5, CP950, BIG5-HKSCS, ISO-2022-CN, ISO-2022-CN-EXT + + Korean: + EUC-KR, CP949, ISO-2022-KR, JOHAB + + Armenian: + ARMSCII-8 + + Georgian: + Georgian-Academy, Georgian-PS + + Thai: + TIS-620, CP874, MacThai + + Laos: + MuleLao-1, CP1133 + + Vietnam: + VISCII, TCVN, CP1258 + + Special: + HP-ROMAN8, NEXTSTEP + + Full Unicode: + UTF-8 + UCS-2, UCS-2BE, UCS-2LE + UCS-4, UCS-4BE, UCS-4LE + UTF-16, UTF-16BE, UTF-16LE + UTF-32, UTF-32BE, UTF-32LE + UTF-7 + JAVA + */ + std::string transform_between_gbk_and_utf8(const char* in, bool to_utf8, int *err) + { + size_t len = strlen(in) + 8, ol = len * 2; + char *buf = (char*)malloc(len), *oper = buf, *out = nullptr, *oper1 = nullptr; + iconv_t conv; + + memset(buf, 0, len); + strcpy(buf, in); + if(to_utf8) + conv = iconv_open("UTF-8", "GBK"); + else + conv = iconv_open("GBK", "UTF-8"); + if(conv == (iconv_t)-1) + { + if(err) + *err = errno; + + free(buf); + + return ""; + } + + oper1 = out = (char*)malloc(ol); + memset(out, 0, ol); + len -= 8; + if(iconv(conv, &oper, &len, &oper1, &ol)) + { + if(err) + *err = errno; + } + else if(err) + *err = 0; + + std::string ret(out); + + free(buf); + free(out); + iconv_close(conv); + + return std::move(ret); + } + std::string transform_between_utf16_and_utf8(const char* in, size_t bytes, bool to_utf8) + { + static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + std::string ret(""); + + if(to_utf8) + { + unsigned short *uc = *(unsigned short**)&in, val = 0; + for(size_t i = 0; i < bytes / 2; ++i, ++uc) + { + val = *uc; + if ((*uc>=0xDC00 && *uc<=0xDFFF) || *uc==0) break; /* check for invalid. */ + + if (*uc>=0xD800 && *uc<=0xDBFF) /* UTF16 surrogate pairs. */ + { + unsigned short uc2 = uc[1]; + if (uc2 < 0xDC00 || uc2 > 0xDFFF) break; /* invalid second-half of surrogate. */ + val = 0x10000 + (((*uc & 0x3FF) << 10) | (uc2 & 0x3FF)); + } + + int len = 4; + char buf[4] = {0}, *ptr2 = buf; + if (val<0x80) len=1;else if (val<0x800) len=2;else if (val<0x10000) len=3; ptr2+=len; + + switch (len) { + case 4: *--ptr2 =((val | 0x80) & 0xBF); val >>= 6; + case 3: *--ptr2 =((val | 0x80) & 0xBF); val >>= 6; + case 2: *--ptr2 =((val | 0x80) & 0xBF); val >>= 6; + case 1: *--ptr2 =(val | firstByteMark[len]); + } + ret += std::string(buf, len); + } + } + else + { + char* unic = (char*)malloc(strlen(in) * 3 + 8); + unsigned char * cur = (unsigned char*)unic; + + while (*cur = *in++) + { + if ((*cur & 0x0f0) == 0x0e0) + { + if (((unsigned char)in[0] & 0x0c0) == 0x80 && + ((unsigned char)in[1] & 0x0c0) == 0x80) + { + char* hex = "0123456789ABCDEF"; + unsigned short us = *cur & 0x0f; + us <<= 6; + us += in[0] & 0x3f; + us <<= 6; + us += in[1] & 0x3f; + + *cur++ = '\\'; + *cur++ = 'u'; + cur[3] = hex[us & 0x0f]; + us >>= 4; + cur[2] = hex[us & 0x0f]; + us >>= 4; + cur[1] = hex[us & 0x0f]; + us >>= 4; + cur[0] = hex[us & 0x0f]; + cur += 3; + in += 2; + } + } + cur++; + } + *cur++ = 0; + ret = std::string(unic, (char*)cur - unic); + free(unic); + } + + return std::move(ret); + } + + std::string to_abs_path(const char* base, const char* rel_path) + { + if(*rel_path == '/') + return rel_path; + + std::string b(base), r(rel_path); + size_t pos = 0; + + while(b.length() && b[b.length() - 1] == '/') + b.erase(b.length() - 1); + + while(r[0] == '.') + { + if(r[1] == '/') + r.erase(0, 2); + else if(r[1] == '.' && r[2] == '/') + { + pos = b.rfind('/'); + if(pos == std::string::npos) + break; + b.erase(pos); + r.erase(0, 3); + } + else + break; + } + + b += "/" + r; + + return std::move(b); + } + std::string to_rel_path(const char* base, const char* abs_path) + { + if(*abs_path != '/') + return abs_path; + + std::string rel(""), b(base), a(abs_path); + size_t pos = 0; + + while(b.length() && b[b.length() - 1] == '/') + b.erase(b.length() - 1); + + while(a.find(b) == std::string::npos) + { + rel += "../"; + pos = b.rfind('/'); + if(pos == 0) + break; + b.erase(pos - 1); + } + if(rel.empty()) + rel = "./"; + + return std::move(rel + a); + } + + const char* pick_simple_block(const char* head, char end) + { + const char* tail = head + 1; + int cnt = 1; + + while(*tail) + { + if(*tail == end) + { + cnt--; + if(cnt == 0) + break; + } + else if(*tail == *head) + { + cnt++; + } + else if(*tail == '\\') + { + tail++; + if(*tail == 0) + break; + } + tail++; + } + + return cnt == 0 ? tail : nullptr; + } +} + diff --git a/base.h b/base.h new file mode 100644 index 0000000..9fae726 --- /dev/null +++ b/base.h @@ -0,0 +1,164 @@ +#pragma once + +// Objects life management +// +// created on 2022-11-29 +// + +#include +#include + +#define ALIGN_INT(val, n) ((((val) + (n) - 1) / (n)) * (n)) + +#define SIZE_KB(n) ((n) * 1024) +#define SIZE_MB(n) SIZE_KB((n) * 1024) +#define SIZE_GB(n) SIZE_MB((n) * 1024) + +#define WAIT_INFINITE 0 + +#define SEC_2_MS(s) ((s) * 1000) +#define MSEC_2_US(ms) ((ms) * 1000) +#define USEC_2_NS(us) ((us) * 1000) +#define SEC_2_US(s) MSEC_2_US(SEC_2_MS(s)) +#define SEC_2_NS(s) USEC_2_NS(MSEC_2_US(SEC_2_MS(s))) +#define MSEC_2_NS(ms) USEC_2_NS(MSEC_2_US(ms)) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef std::mutex MUTEX; +typedef std::lock_guard LOCKER; + +// object life referer +// +// derived from 'refer' if your class used in multi-threads +// +class refer +{ + volatile int32_t ref_; + MUTEX mutex_; + +protected: + refer(); + virtual ~refer(); + + virtual void on_born(void); + virtual void on_dead(void); + +public: + virtual int32_t add_ref(void); + virtual int32_t release(void); +}; + +#include +class chronograph +{ + struct timeval bgn_; + +public: + chronograph(); + ~chronograph(); + + static bool now(struct timeval* tv); + static bool now(uint64_t* seconds, uint64_t* u_seconds); + static std::string now(bool with_ms = true/*whether with milliseconds*/); // return '2022-11-30 10:38:42.123', no '.123' if with_ms was false + +public: + uint64_t elapse_s(void); + uint64_t elapse_ms(void); + uint64_t elapse_us(void); + void reset(void); +}; + +#include +namespace sys_util +{ + int32_t enum_modules(bool(*on_found)(const char* path_module_name, bool is_dir, void* param),// return false to stop enumeratin + void* param, // user defined data, passed into callback on_found + unsigned pid = -1 // process id, -1 is self + ); // return errno + + int32_t enum_files(const char* dir // dir path + , bool(*on_found)(const char* path_name, bool is_dir, void* param)// return false to stop enumeratin + , void* param // user defined data, passed into callback on_found + , bool recursive = true // walk recursive + ); // return errno + int32_t enum_processes(bool(*on_found)(uint64_t pid, const char* path_name, void* param), void* param); + uint32_t enum_threads(uint64_t pid, bool(*on_found)(uint64_t tid, void* start_addr, void* param), void* param); + uint32_t get_thread_callstack(uint64_t pid, uint64_t tid, bool(*on_found)(uint64_t off, const char* module, void* param), void* param); + uint32_t read_line(const char* file, bool(*on_line)(char* line, void* param), void* param); + + std::string get_module_path(const char* module_name = nullptr + , unsigned pid = -1); // get module full path, nullptr is for main-exe + std::string read_link(const char* lnk); + size_t get_page_size(void); + bool create_folder(const char* dir); + + // Function: pick single-line info file data, return count of set-value variable + // + // Parameters: file - full path of local file + // + // line_max - max bytes of a line in file 'file' + // + // fmt - line fromat string, e.g. "model name : %60[\x20-\x7e]", "MemoryTotal: %ld", "address sizes : %d bits physical, %d bits virtual", ... + // + // args - variable list + // + // Return: count of the variable which got the value + template + int32_t get_inf_file_data(const char* file, size_t line_max, const char* fmt, Args ... args) + { + std::string buf("\0", line_max + 8); + FILE* src = fopen(file, "rb"); + int32_t count = 0; + + if (!src) + return 0; + + while (fgets(&buf[0], line_max, src)) + { + count = sscanf(&buf[0], fmt, args ...); + if (count > 0) + break; + } + fclose(src); + + return count; + } + + int32_t get_memory_info(uint64_t* total, uint64_t* available); + std::string format_readable_bytes(uint64_t bytes); // convert to readable text: 512B, 1.21KB, 1.10MB, 3.45GB, 1,234.56GB ... + std::string get_command_output(const char* cmd, uint16_t max_line_len = 256, bool one_line = true); + + // trim string, return whether space trimmed + bool trim_left(std::string& str, const char* space = " \t"); + bool trim_right(std::string& str, const char* space = " \t"); + uint64_t from_hex_str(const char* hex, const char** end = nullptr); // convert 0x100 to 256. parameter 'end' to receive the stopped position + + // Function: convert number string to integer, support hex, dec, oct and bin + // + // Parameter: str - number string. + // 0x.../...h: as hexadecimal + // ...o: as octonary + // ...b: as binary + // ...: as decimal, or as hexadecimal if has hex letter + // + // end - to receive the ending point when covert over + // + // Return: integer, default is ZERO, you should check the ending point when this value returned + uint64_t to_int(const char* str, const char** end = nullptr); + + std::string transform_between_gbk_and_utf8(const char* in, bool to_utf8, int* err = nullptr); + std::string transform_between_utf16_and_utf8(const char* in, size_t bytes, bool to_utf8); + + std::string to_abs_path(const char* base, const char* rel_path); + std::string to_rel_path(const char* base, const char* abs_path); + + // Function: pick simple block in pair chars + // + // Parameter: head - beginning of the string, and the first character is the beginning char + // + // end - ending character of the block + // + // Return: the last positoin of the block (*ret = end), or nullptr if not matched + const char* pick_simple_block(const char* head, char end); +} diff --git a/cmd.cpp b/cmd.cpp new file mode 100644 index 0000000..fc2b9dd --- /dev/null +++ b/cmd.cpp @@ -0,0 +1,308 @@ +#include "cmd.h" + + + + +namespace parser +{ + static void command_line_to_arguments(const char* cmdl, std::vector& args) + { + while(*cmdl) + { + const char* h = cmdl; + while(*h == ' ' || *h == '\t') + h++; + if(*h == 0) + break; + + cmdl = h; + if(*h == '\"') + { + cmdl++; + h++; + while(*h) + { + if(*h == '\"') + break; + if(*h == '\\') + h++; + h++; + } + } + else + { + while(*h) + { + if(*h == ' ' || *h == '\t') + break; + h++; + } + } + if(h > cmdl) + args.push_back(std::string(cmdl, h - cmdl)); + else if(*h == '\"') + args.push_back(""); + + if(*h == 0) + break; + + cmdl = h + 1; + } + } +} + + + + + + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// +cmd_line::cmd_line() +{} +cmd_line::~cmd_line() +{} + +cmd_line* cmd_line::from_console(const char* tips) +{ + std::string in(""); + char ch = 0; + + if(!tips || *tips == 0) + tips = "input"; + + printf("%s%s>%s", CONSOLE_COLOR_FRONT_PURPLE, tips, CONSOLE_COLOR_NONE); + while((ch = getchar()) != '\n') + in.append(1, ch); + + return cmd_line::from_command_line(in.c_str()); +} +cmd_line* cmd_line::from_command_line(const char* cmdl) +{ + cmd_line* cmd = new cmd_line(); + + cmd->cmd_line_ = cmdl; + parser::command_line_to_arguments(cmdl, cmd->arguments_); + + return cmd; +} + +size_t cmd_line::count(void) +{ + return arguments_.size(); +} +const char* cmd_line::parameter(int ind) +{ + if(ind >= 0 && ind < arguments_.size()) + return arguments_[ind].c_str(); + else + return nullptr; +} +const char* cmd_line::parameter(const char* key) +{ + for(int i = 0; i < (int)arguments_.size() - 1; ++i) + { + if(arguments_[i] == key) + return arguments_[i + 1].c_str(); + } + + return nullptr; +} +void cmd_line::remove(int ind) +{ + if(ind >= 0 && ind < arguments_.size()) + arguments_.erase(arguments_.begin() + ind); +} +void cmd_line::remove(const char* key) +{ + for(int i = 0; i < (int)arguments_.size() - 1; ++i) + { + if(arguments_[i] == key) + { + arguments_.erase(arguments_.begin() + i); + arguments_.erase(arguments_.begin() + i); + break; + } + } +} +std::string cmd_line::to_command_line(void) +{ + std::string cmdl(""); + + for(auto& v: arguments_) + { + if(v.find(" ") != std::string::npos || + v.find("\t") != std::string::npos) + { + cmdl += "\"" + v + "\""; + } + else + cmdl += v; + cmdl += " "; + } + + return std::move(cmdl); +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// +std::vector console_dispatcher::super_cmd_routine_; +static std::string format_64_addr(uint64_t addr) +{ + char buf[40] = {0}; + uint32_t *ptr = (uint32_t*)&addr; + + sprintf(buf, "%08X%08X", ptr[1], ptr[0]); + + return buf; +} + +console_dispatcher::console_dispatcher() : un_handle_(&console_dispatcher::unhandled), un_handle_param_(nullptr) +{} +console_dispatcher::~console_dispatcher() +{} + + quit_cmd console_dispatcher::unhandled(cmd_line* cmd, void* param) + { + return QUIT_CMD_NONE; + } +void console_dispatcher::add_command(std::vector& routine, const char* cmd, quit_cmd(*handle)(cmd_line*, void*), void* param) +{ + std::vector::iterator it = std::find(routine.begin(), routine.end(), cmd); + if(it == routine.end()) + { + console_dispatcher::CMDROUT cr; + cr.cmd = cmd; + cr.param = param; + cr.routine = handle; + + routine.push_back(std::move(cr)); + } + else + { + it->param = param; + it->routine = handle; + } +} + +quit_cmd console_dispatcher::dispatch_command(cmd_line* cmd) +{ + if(*cmd->parameter(0) == 0) + return QUIT_CMD_NONE; + + std::vector::iterator it = std::find(console_dispatcher::super_cmd_routine_.begin(), + console_dispatcher::super_cmd_routine_.end(), + cmd->parameter(0)); + if(console_dispatcher::super_cmd_routine_.end() == it) + it = std::find(cmd_routine_.begin(), cmd_routine_.end(), cmd->parameter(0)); + + if(it == cmd_routine_.end()) + return un_handle_(cmd, un_handle_param_); + + cmd->remove(0); + + return it->routine(cmd, it->param); +} + +void console_dispatcher::add_supper_command_routine(const char* cmd, quit_cmd(*handle)(cmd_line*, void*), void* param) +{ + console_dispatcher::add_command(console_dispatcher::super_cmd_routine_, cmd, handle, param); +} +void console_dispatcher::print_sector(uint8_t* data, size_t bytes, uint64_t addr) +{ + std::string space(""); + + if(addr & 0x0f) + { + int l = addr & 0x0f; + + space.append((16 - l) * 3, ' '); + if(l >= 8) + space.append(1, ' '); + addr >>= 4; + addr <<= 4; + printf("0x%s %s", format_64_addr(addr).c_str(), space.c_str()); + space = ""; + for(int i = 0; i < 16 - l && i < bytes; ++i) + { + printf("%02X ", *data); + if(*data >= ' ' && *data < 0x7f) + space.append(1, *data); + else + space += "."; + data++; + } + printf(" %s\n", space.c_str()); + + if(bytes <= 16 - l) + return; + bytes -= 16 - l; + addr += 0x10; + } + + for(size_t i = 0; i < bytes; ++i) + { + if((i % 16) == 0) + { + if(space.length()) + printf(" %s\n", space.c_str()); + space = ""; + printf("0x%s", format_64_addr(addr + i).c_str()); + } + if((i % 8) == 0) + printf(" "); + + printf("%02X ", *data); + if(*data >= ' ' && *data < 0x7f) + space.append(1, *data); + else + space += "."; + data++; + } + + if(space.length()) + { + if(space.length() < 16) + { + std::string fill(""); + + fill.append((16 - space.length()) * 3, ' '); + if(space.length() < 8) + fill.append(1, ' '); + printf("%s", fill.c_str()); + } + printf("%s\n", space.c_str()); + } +} + +void console_dispatcher::add_command_routine(const char* cmd, quit_cmd(*handle)(cmd_line*, void*), void* param) +{ + console_dispatcher::add_command(cmd_routine_, cmd, handle, param); +} +void console_dispatcher::set_unhandled_routine(quit_cmd(*handle)(cmd_line*, void*), void* param) +{ + un_handle_ = handle ? handle : &console_dispatcher::unhandled; + un_handle_param_ = param; +} +quit_cmd console_dispatcher::run(const char* tips, const char* cmdl) +{ + cmd_line* cmd = nullptr; + quit_cmd quit = QUIT_CMD_NONE; + + if(cmdl && *cmdl) + { + cmd = cmd_line::from_command_line(cmdl); + quit = dispatch_command(cmd); + cmd->release(); + } + while(quit == QUIT_CMD_NONE && (cmd = cmd_line::from_console(tips))) + { + if(cmd->count()) + quit = dispatch_command(cmd); + cmd->release(); + } + + return quit; +} + diff --git a/cmd.h b/cmd.h new file mode 100644 index 0000000..e084110 --- /dev/null +++ b/cmd.h @@ -0,0 +1,148 @@ +#pragma once + +// command line utility +// +// created on 2023-02-10 +// + +#include "base.h" +#include +#include +#include + +#define CONSOLE_COLOR_NONE "\033[0m" +#define CONSOLE_COLOR_FRONT_BLACK "\033[0;30m" +#define CONSOLE_COLOR_FRONT_DARK_GRAY "\033[1;30m" +#define CONSOLE_COLOR_FRONT_RED "\033[0;31m" +#define CONSOLE_COLOR_FRONT_LIGHT_RED "\033[1;31m" +#define CONSOLE_COLOR_FRONT_GREEN "\033[0;32m" +#define CONSOLE_COLOR_FRONT_LIGHT_GREEN "\033[1;32m" +#define CONSOLE_COLOR_FRONT_BROWN "\033[0;33m" +#define CONSOLE_COLOR_FRONT_YELLOW "\033[1;33m" +#define CONSOLE_COLOR_FRONT_BLUE "\033[0;34m" +#define CONSOLE_COLOR_FRONT_LIGHT_BLUE "\033[1;34m" +#define CONSOLE_COLOR_FRONT_PURPLE "\033[0;35m" +#define CONSOLE_COLOR_FRONT_LIGHT_PURPLE "\033[1;35m" +#define CONSOLE_COLOR_FRONT_CYAN "\033[0;36m" +#define CONSOLE_COLOR_FRONT_LIGHT_CYAN "\033[1;36m" +#define CONSOLE_COLOR_FRONT_LIGHT_GRAY "\033[0;37m" +#define CONSOLE_COLOR_FRONT_WHITE "\033[1;37m" + +#define CONSOLE_COLOR_BACK_BLACK "\033[0;40m" +#define CONSOLE_COLOR_BACK_DARK_GRAY "\033[1;40m" +#define CONSOLE_COLOR_BACK_RED "\033[0;41m" +#define CONSOLE_COLOR_BACK_LIGHT_RED "\033[1;41m" +#define CONSOLE_COLOR_BACK_GREEN "\033[0;42m" +#define CONSOLE_COLOR_BACK_LIGHT_GREEN "\033[1;42m" +#define CONSOLE_COLOR_BACK_BROWN "\033[0;43m" +#define CONSOLE_COLOR_BACK_YELLOW "\033[1;43m" +#define CONSOLE_COLOR_BACK_BLUE "\033[0;44m" +#define CONSOLE_COLOR_BACK_LIGHT_BLUE "\033[1;44m" +#define CONSOLE_COLOR_BACK_PURPLE "\033[0;45m" +#define CONSOLE_COLOR_BACK_LIGHT_PURPLE "\033[1;45m" +#define CONSOLE_COLOR_BACK_CYAN "\033[0;46m" +#define CONSOLE_COLOR_BACK_LIGHT_CYAN "\033[1;46m" +#define CONSOLE_COLOR_BACK_LIGHT_GRAY "\033[0;47m" +#define CONSOLE_COLOR_BACK_WHITE "\033[1;47m" + + +namespace console +{ + // special effects: + // \033[0m close all attributes + // \033[1m set high-light + // \033[4m underline + // \033[5m blink + // \033[7m reverse(反显) + // \033[8m blanking(消隐) + // \033[30m -- \033[37m set foreground color + // \033[40m -- \033[47m set background color + // + // cursor position: + // \033[nA move up n lines + // \033[nB move down n lines + // \033[nC move right n cols + // \033[nD move left n cols + // \033[y;xH set cursor position + // \033[2J clear screen + // \033[K clear the line after cursor position + // \033[s save cursor position + // \033[u restore cursor position + // \033[?25l hide cursor + // \033[?25h show cursor +}; + +class cmd_line : public refer +{ + std::string cmd_line_; + std::vector arguments_; + +protected: + cmd_line(); + ~cmd_line(); + +public: + static cmd_line* from_console(const char* tips); + static cmd_line* from_command_line(const char* cmdl); + +public: + size_t count(void); + const char* parameter(int ind); + const char* parameter(const char* key); + void remove(int ind); // remove parameter at ind + void remove(const char* key); // remove parameters named 'key' and the next + std::string to_command_line(void); +}; + + +#define PASTE(a, b) a##b +#define CONSOLE_ROUTINE(func) \ + quit_cmd func(cmd_line* cmd, void* param) + +enum quit_cmd +{ + QUIT_CMD_NONE = 0, + QUIT_CMD_QUIT_ME, + QUIT_CMD_QUIT_ALL, +}; +class console_dispatcher : public refer +{ + typedef struct _cmd_routine + { + std::string cmd; + void* param; + quit_cmd(*routine)(cmd_line* cmd, void* param); + + bool operator==(const char* command) + { + return cmd == command; + } + bool operator<(const _cmd_routine& r) + { + return cmd.compare(r.cmd) < 0; + } + }CMDROUT; + std::vector cmd_routine_; + quit_cmd(*un_handle_)(cmd_line*, void*); + void* un_handle_param_; + + static std::vector super_cmd_routine_; + + static void add_command(std::vector& routine, const char* cmd, quit_cmd(*handle)(cmd_line*, void*), void* param); + static quit_cmd unhandled(cmd_line* cmd, void* param); + + quit_cmd dispatch_command(cmd_line* cmd); // return whether continue + +public: + console_dispatcher(); + ~console_dispatcher(); + +public: + static void add_supper_command_routine(const char* cmd, quit_cmd(*handle)(cmd_line*, void*), void* param = nullptr); + static void print_sector(uint8_t* data, size_t bytes, uint64_t addr = 0); + + void add_command_routine(const char* cmd, quit_cmd(*handle)(cmd_line*, void*), void* param = nullptr); + void set_unhandled_routine(quit_cmd(*handle)(cmd_line*, void*), void* param = nullptr); + quit_cmd run(const char* tips, const char* cmdl = nullptr); +}; + diff --git a/hg_ipc.cpp b/hg_ipc.cpp new file mode 100644 index 0000000..a22f6fe --- /dev/null +++ b/hg_ipc.cpp @@ -0,0 +1,886 @@ +#include "hg_ipc.h" +#include "hgscanner_error.h" + +#if defined(WIN32) || defined(_WIN64) +//#include "scanner_manager.h" +#else +#include +#include +#include +#include +#include +#endif + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// memory management ... +void* allocate_memory(size_t bytes, const char* log_msg) +{ + bytes += 7; + bytes /= 8; + bytes *= 8; + + return new char[bytes]; +} +void free_memory(void* ptr) +{ + if (ptr) + delete[] ptr; +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// windows event ... +#if defined(WIN32) || defined(_WIN64) +int __stdcall sem_init(sem_t* handle, int, int) +{ + if (!handle) + { + errno = EINVAL; + return -1; + } + + *handle = CreateEvent(NULL, TRUE, FALSE, NULL); + if (*handle) + return 0; + else + { + errno = GetLastError(); + + return -1; + } +} +void __stdcall sem_destroy(sem_t* handle) +{ + if (*handle) + { + CloseHandle(*handle); + *handle = NULL; + } +} +int __stdcall sem_trywait(sem_t* handle) +{ + return WaitForSingleObject(*handle, 1) == WAIT_TIMEOUT ? -1 : 0; +} +void __stdcall sem_wait(sem_t* handle) +{ + if(WaitForSingleObject(*handle, INFINITE) == WAIT_OBJECT_0) + ResetEvent(*handle); +} +int __stdcall sem_timedwait(sem_t* handle, struct timespec* to) +{ + DWORD elapse = to->tv_sec * 1000; + elapse += to->tv_nsec / (1000 * 1000); + + int ret = WaitForSingleObject(*handle, elapse) == WAIT_TIMEOUT ? -1 : 0; + + if(ret == 0) + ResetEvent(*handle); + + return ret; +} +void __stdcall sem_post(sem_t* handle) +{ + SetEvent(*handle); +} + +#define pid_t int + +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// platform_event (base on semaphore) +platform_event::platform_event() : waiting_(false), dbg_info_("") +{ + int err = sem_init(&sem_, 0, 0); + + if (err == -1) + { + err = errno; + // VLOG_MINI_2(LOG_LEVEL_FATAL, "(%s)sem_init failed: %d\n", hg_log::format_ptr(this).c_str(), err); + } +} +platform_event::~platform_event() +{ + sem_destroy(&sem_); +} + +bool platform_event::try_wait(void) +{ + return sem_trywait(&sem_) == 0; +} +bool platform_event::wait(unsigned timeout) +{ + bool waited = true; + + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "platform_event(%s - %s) --> waiting...\n", hg_log::format_ptr(this).c_str(), dbg_info_.c_str()); + waiting_ = true; + if (timeout == USB_TIMEOUT_INFINITE) + sem_wait(&sem_); + else + { + struct timespec to; + to.tv_sec = timeout / 1000; + to.tv_nsec = (long)((timeout % 1000) * 1000 * 1000); + waited = sem_timedwait(&sem_, &to) == 0; + } + // VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "platform_event(%s - %s) --> %s.\n", hg_log::format_ptr(this).c_str(), dbg_info_.c_str(), waited ? "waited" : "wait timeout"); + waiting_ = false; + + return waited; +} +void platform_event::notify(void) +{ + sem_post(&sem_); +} +bool platform_event::is_waiting(void) +{ + return waiting_; +} +void platform_event::set_debug_info(const char* info) +{ + dbg_info_ = info ? info : ""; +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// shared_memory +shared_memory::shared_memory(unsigned long long key, size_t size) : key_(key), obj_((void*)-1), first_(true), bytes_(size), len_(0) +{ + unsigned int* ptr = (unsigned int*)&key_; + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "shared memory key = 0x%x%08x\n", ptr[1], ptr[0]); + + init(); +} +shared_memory::~shared_memory() +{ + clear(); +} + +void shared_memory::init(void) +{ +#if defined(WIN32) || defined(_WIN64) + char name[40] = { 0 }; + DWORD* key = (DWORD*)&key_; + HANDLE h = NULL; + + sprintf(name, "scanner_0x%08x-%08x", key[1], key[0]); + h = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, bytes_, name); + if (h == NULL) + return; + + first_ = !(GetLastError() == ERROR_ALREADY_EXISTS); + obj_ = (void*)h; +#else + int obj = shmget(key_, bytes_, IPC_EXCL | IPC_CREAT | 0600); + if (obj < 0) + { + unsigned int* v = (unsigned int*)&key_; + if (errno == EEXIST) + { + first_ = false; + obj = shmget(key_, bytes_, 0600); + if(obj == -1) + obj = shmget(key_, bytes_, 0); + // VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "open existing: shmget(0x%x%08x) = %d\n", v[1], v[0], obj); + obj_ = (void*)obj; + + std::string prev(read()), proc(""); + // VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "shared memory content: %s\n", prev.c_str()); + if(prev.length()) + { + proc = prev; + size_t pos = proc.find("pid: "); + if (pos != std::string::npos) + proc.erase(0, pos + 5); + pos = proc.find(")"); + if (pos != std::string::npos) + proc.erase(pos); + proc = shared_memory::get_proc_name_by_pid(atoi(proc.c_str())); + if (proc.length()) + { + pos = prev.find("("); + if (pos == std::string::npos) + pos = prev.length(); + if (strcasecmp(proc.c_str(), prev.substr(0, pos).c_str())) + proc = ""; + } + } + if (proc.empty()) + { + first_ = true; + clear(); + obj = shmget(key_, bytes_, IPC_EXCL | IPC_CREAT | 0600); + // VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "%s is not existing and reopen it\n", prev.c_str()); + } + } + else + { + // VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "shmget(0x%x%08x) = %d\n", v[1], v[0], errno); + return; + } + } + obj_ = (void*)obj; + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "shared memory id = %d[%s], \n", obj, first_ ? "created" : "opened"); +#endif + + if(first_) + { + pid_t pid = getpid(); + std::string me(""); + char buf[40] = { 0 }; + unsigned int* pn = (unsigned int*)&pid; + + if (sizeof(pid) > 4 && pn[1]) + sprintf(buf, "(pid: 0x%x%08x)", pn[1], pn[0]); + else + sprintf(buf, "(pid: %u)", pn[0]); + // hg_log::pe_path(&me); + me += buf; + write(me.c_str(), me.length()); + } +} +void shared_memory::clear(void) +{ + if (obj_ != (void*)-1) +#if defined(WIN32) || defined(_WIN64) + CloseHandle((HANDLE)obj_); +#else + { + if (first_) + { + struct shmid_ds ds = { 0 }; + int* h = (int*)&obj_; + shmctl(*h, IPC_RMID, &ds); + } + } +#endif + + obj_ = (void*)-1; +} +char* shared_memory::get_buf(void) +{ +#if defined(WIN32) || defined(_WIN64) + char* buf = (char*)MapViewOfFile((HANDLE)obj_, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); + if (!buf) + buf = (char*)-1; +#else + int* h = (int*)&obj_; + char* buf = (char*)shmat(*h, 0, 0); + // VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "shared memory %d buffer = %s, error = %d\n", *h, hg_log::format_ptr(buf).c_str(), errno); +#endif + + return buf; +} +void shared_memory::release_buf(void* buf) +{ +#if defined(WIN32) || defined(_WIN64) + UnmapViewOfFile(buf); +#else + shmdt(buf); +#endif +} + +#if !defined(WIN32) && !defined(_WIN64) +std::string shared_memory::get_proc_name_by_pid(pid_t pid) +{ + char path[512] = { 0 }; + unsigned int* v = (unsigned int*)&pid; + std::string ret(""); + + if (sizeof(pid) > 4 && v[1]) + sprintf(path, "/proc/%lld/status", pid); + else + sprintf(path, "/proc/%u/status", pid); + + FILE* src = fopen(path, "rb"); + if (src) + { + char val[512] = { 0 }; + + memset(path, 0, sizeof(path)); + fgets(path, sizeof(path) - 1, src); + fclose(src); + sscanf(path, "%*s %s", val); + ret = val; + } + if (sizeof(pid) > 4 && v[1]) + { + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "PID(%lld) name is: %s\n", pid, ret.c_str()); + } + else + { + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "PID(%u) name is: %s\n", pid, ret.c_str()); + } + + return ret; +} +#endif + +bool shared_memory::is_ok(void) +{ + return obj_ != (void*)-1; +} +bool shared_memory::is_first(void) +{ + return is_ok() && first_; +} +std::string shared_memory::read(void) +{ + if (obj_ == (void*)-1) + return ""; + + char* buf = get_buf(); + if (buf == (char*)-1) + return ""; + + std::string ret(""); + size_t len = 0; + int off = 4; // sizeof(size_t); + + memcpy(&len, buf, off); + ret = std::string(buf + off, len); + release_buf(buf); + + return ret; +} +int shared_memory::write(const char* data, size_t len) +{ + if (len > bytes_) + return SCANNER_ERR_INSUFFICIENT_MEMORY; + + char* buf = get_buf(); + int off = 4; // sizeof(len); + if (buf == (char*)-1) + return errno; + + memcpy(buf, &len, off); + memcpy(buf + off, data, len); + len_ = len; + release_buf(buf); + + return 0; +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// tiny_file_map ... +tiny_file_map::tiny_file_map() : size_(0), map_(INVALID_HANDLE_NAME), buf_(nullptr), file_(""), keep_f_(false) + , map_off_(0), map_bytes_(0), page_size_(4096) +{ + // hg_log::get_page_size(&page_size_); +} +tiny_file_map::~tiny_file_map() +{ + close(); +} + +HANDLE_NAME tiny_file_map::open_file_for_mapping(const char* file, unsigned* bytes, bool create) +{ + HANDLE_NAME ret = INVALID_HANDLE_NAME; + +#if defined(WIN32) || defined(_WIN64) + HANDLE f = INVALID_HANDLE_VALUE; + if (create) + { + f = CreateFileA(file, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (f != INVALID_HANDLE_VALUE) + { + DWORD wrote = SetFilePointer(f, *bytes - 1, NULL, FILE_BEGIN); + if (wrote != *bytes - 1 || !WriteFile(f, "\0", 1, &wrote, NULL)) + { + CloseHandle(f); + f = INVALID_HANDLE_VALUE; + } + } + } + else + { + f = CreateFileA(file, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (f != INVALID_HANDLE_VALUE) + *bytes = GetFileSize(f, NULL); + } + if (f != INVALID_HANDLE_VALUE) + { + ret = CreateFileMapping(f, NULL, PAGE_READWRITE, 0, *bytes, NULL); + CloseHandle(f); + } +#else + if (create) + { + ret = ::open(file, O_CREAT | O_RDWR,0777); + if (ret != INVALID_HANDLE_NAME) + { + if (lseek(ret, *bytes - 1, SEEK_SET) < 0) + { + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "set file size to %u - 1 bytes failed: %d\n", *bytes, errno); + ::close(ret); + remove(file); + ret = INVALID_HANDLE_NAME; + } + if (write(ret, "0", 1) < 0) + { + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "set file size to %u bytes failed: %d\n", *bytes, errno); + ::close(ret); + remove(file); + ret = INVALID_HANDLE_NAME; + } + } + } + else + { + ret = ::open(file, O_RDWR); + if (ret != INVALID_HANDLE_NAME) + { + struct stat fsize; + if (fstat(ret, &fsize) >= 0) + *bytes = fsize.st_size; + } + } +#endif + + return ret; +} +void tiny_file_map::close_handle_name(HANDLE_NAME h) +{ +#if defined(WIN32) || defined(_WIN64) + CloseHandle(h); +#else + ::close(h); +#endif +} +void* tiny_file_map::sys_map_api(HANDLE_NAME h, int access, unsigned int off, unsigned size, int* err) +{ + void* mem = nullptr; + +#if defined(WIN32) || defined(_WIN64) + mem = MapViewOfFile(h, access, 0, off, size); + if (err) + { + if (mem) + *err = SCANNER_ERR_OK; + else + { + if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) + *err = SCANNER_ERR_INSUFFICIENT_MEMORY; + else + *err = SCANNER_ERR_OUT_OF_RANGE; + } + } +#else + mem = mmap(nullptr, size, access, MAP_SHARED, h, off); + if (mem == MAP_FAILED) + { + mem = nullptr; + if (errno == ENOMEM) + *err = SCANNER_ERR_INSUFFICIENT_MEMORY; + else + *err = SCANNER_ERR_OUT_OF_RANGE; + } + else if(err) + *err = SCANNER_ERR_OK; +#endif + + return mem; +} +void tiny_file_map::sys_unmap_api(void* buf, size_t size) +{ +#if defined(WIN32) || defined(_WIN64) + UnmapViewOfFile(buf); +#else + munmap(buf, size); +#endif +} + +int tiny_file_map::map_to_mem(unsigned int off) +{ + int err = SCANNER_ERR_OUT_OF_RANGE; + +#if defined(WIN32) || defined(_WIN64) + int acc = FILE_MAP_READ | FILE_MAP_WRITE; +#else + int acc = PROT_READ | PROT_WRITE; +#endif + if (off < size_) + { + unsigned int bytes = size_ - off; + if (off >= map_off_ && off + bytes <= map_off_ + map_bytes_) + err = SCANNER_ERR_OK; + else + { + if (buf_) + tiny_file_map::sys_unmap_api(buf_, map_bytes_); + off /= page_size_; + off *= page_size_; + map_bytes_ = bytes; + map_off_ = off; + buf_ = (unsigned char*)tiny_file_map::sys_map_api(map_, acc, map_off_, map_bytes_, &err); // MapViewOfFile(map_, FILE_MAP_READ | FILE_MAP_WRITE, 0, off, map_bytes_); + if (err != SCANNER_ERR_OK) + { + map_bytes_ /= page_size_; + map_bytes_ *= page_size_; + while (map_bytes_ >= page_size_ + && !(buf_ = (unsigned char*)tiny_file_map::sys_map_api(map_, acc, map_off_, map_bytes_, &err)) + && err == SCANNER_ERR_INSUFFICIENT_MEMORY) + map_bytes_ -= page_size_; + } + } + } + + return err; +} + +int tiny_file_map::open(const char* file, bool existing, unsigned int size) +{ + int ret = SCANNER_ERR_INSUFFICIENT_MEMORY; + + close(); + map_ = tiny_file_map::open_file_for_mapping(file, &size, !existing); + if (map_ != INVALID_HANDLE_NAME) + { + ret = SCANNER_ERR_OK; + size_ = size; + } + + // VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "map([%s]%s) = %d\n", existing ? "existing" : "new", file, ret); + if (ret == SCANNER_ERR_OK) + file_ = file; + + return ret; +} +void tiny_file_map::close(void) +{ + if (buf_) + { + tiny_file_map::sys_unmap_api(buf_, size_); + buf_ = nullptr; + } + if (map_ != INVALID_HANDLE_NAME) + { + close_handle_name(map_); + map_ = INVALID_HANDLE_NAME; + } + if (!keep_f_ && !file_.empty()) + remove(file_.c_str()); + + size_ = 0; + file_ = ""; + keep_f_ = false; + map_off_ = map_bytes_ = 0; +} +void tiny_file_map::keep_file(bool keep) +{ + keep_f_ = keep; +} +unsigned char* tiny_file_map::mapping_buffer(unsigned int off, unsigned int* bytes) +{ + unsigned int len = bytes ? *bytes : size_; + unsigned char* buf = nullptr; + + if (off >= size_) + { + return buf; + } + if (!buf_ && map_to_mem(off) != SCANNER_ERR_OK) + { + return buf; + } + + if (off >= map_off_ && off + len <= map_off_ + map_bytes_) + { + buf = buf_ + off - map_off_; + + return buf; + } + + if (off < map_off_ || off >= map_off_ + map_bytes_) + { + if (map_to_mem(off) == SCANNER_ERR_OK) + { + buf = buf_ + off - map_off_; + if (bytes) + *bytes = map_bytes_ - (off - map_off_); + } + + return buf; + } + + // + buf = buf_ + off - map_off_; + if (bytes) + *bytes = map_bytes_ - (off - map_off_); + + return buf; +} +std::string tiny_file_map::file(void) +{ + return file_; +} +unsigned int tiny_file_map::size(void) +{ + return size_; +} + +bool tiny_file_map::swap(void) +{ + bool ret = true; + + tiny_file_map::sys_unmap_api(buf_, size_); + buf_ = nullptr; + + return ret; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// memory or file mapping ... +tiny_buffer::tiny_buffer(unsigned int size + , const char* tmp_path + , const char* name_leading + , const char* ext + , unsigned int uniq_id) + : size_(size), buf_(nullptr), img_statu_(0) +{ + init(tmp_path, name_leading, ext, uniq_id); +} +tiny_buffer::tiny_buffer(const char* src_file) : size_(0), buf_(nullptr) +{ + fmap_.open(src_file); + size_ = fmap_.size(); + + unsigned int len = size_; + buf_ = fmap_.mapping_buffer(0, &len); +} +tiny_buffer::~tiny_buffer() +{ + if (buf_) + { + if (fmap_.file().empty()) + delete[] buf_; + else + fmap_.close(); + } +} + +void tiny_buffer::init(const char* tmp_path, const char* name_leading, const char* ext, unsigned int uniq_id) +{ + try + { + buf_ = new unsigned char[size_]; + memset(buf_, 0, size_); + } + catch (...) + { + if (tmp_path && *tmp_path) + { + std::string f(tmp_path); + char buf[128] = { 0 }; + + f += "/"; + f += name_leading ? name_leading : "mapf"; + sprintf(buf, "_%05u.%s", uniq_id, ext ? ext : "tmp"); + f += buf; + + unsigned int bytes = size_; + fmap_.open(f.c_str(), false, size_); + buf_ = fmap_.mapping_buffer(0, &bytes); + } + } +} + +unsigned int tiny_buffer::size(void) +{ + return size_; +} +unsigned char* tiny_buffer::data(unsigned int off, unsigned int* bytes) +{ + if (off >= size_) + return nullptr; + + if (fmap_.file().empty()) + { + if (size_ - off < *bytes) + *bytes = size_ - off; + + return buf_ + off; + } + + return fmap_.mapping_buffer(off, bytes); +} +void tiny_buffer::keep_file(bool keep) +{ + fmap_.keep_file(keep); +} +std::string tiny_buffer::file(void) +{ + return fmap_.file(); +} + +bool tiny_buffer::swap(void) +{ + if (fmap_.file().empty()) + return true; + + bool ret = fmap_.swap(); + unsigned int bytes = size_; + + buf_ = fmap_.mapping_buffer(0, &bytes); + + return ret; +} +int tiny_buffer::to_file(const char* file) +{ + FILE* dst = fopen(file, "wb"); + + if (!dst) + return errno; + + unsigned int off = 0, len = size_; + unsigned char* buf = data(off, &len); + while (buf) + { + fwrite(buf, 1, len, dst); + off += len; + if (off >= size_) + break; + len = size_ - off; + buf = data(off, &len); + } + fclose(dst); + + return 0; +} + +void tiny_buffer::set_image_statu(int statu) +{ + img_statu_ = statu; +} +int tiny_buffer::get_image_statu(void) +{ + return img_statu_; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// final_img_queue + +final_img_queue::final_img_queue() : mem_usage_(0) +{} +final_img_queue::~final_img_queue() +{} + +unsigned long long final_img_queue::mem_usage(void) +{ + return mem_usage_; +} +size_t final_img_queue::size(void) +{ + std::lock_guard lck(lock_); + + return queue_.size(); +} +void final_img_queue::clear(void) +{ + std::lock_guard lck(lock_); + + mem_usage_ = 0; + queue_.clear(); +} +bool final_img_queue::put(int w, int h, int bpp, int channels, int line_bytes, void* data, unsigned bytes + , const char* tmp_path, const char* name_leading, const char* ext, int ind, uint32_t id) +{ + IMGDT imgd; + bool ret = false; + unsigned int l = bytes, off = 0; + + imgd.header.bits = bpp; + imgd.header.bytes = bytes; + imgd.header.channels = channels; + imgd.header.height = h; + imgd.header.line_bytes = line_bytes; + imgd.header.width = w; + imgd.header.src_id = id; + imgd.offset = 0; + imgd.data.reset(new tiny_buffer(bytes, tmp_path, name_leading, ext, ind)); + + unsigned char* buf = imgd.data->data(off, &l), + * src = (unsigned char*)data; + while(buf) + { + memcpy(buf, src, l); + off += l; + if (off >= bytes) + break; + + src += l; + l = bytes - off; + buf = imgd.data->data(off, &l); + } + if (off >= bytes && imgd.data->swap()) + { + std::lock_guard lck(lock_); + queue_.push_back(imgd); + mem_usage_ += bytes; + ret = true; + } + else + imgd.data.reset(); + + return ret; +} +bool final_img_queue::front(IMH* header) +{ + std::lock_guard lck(lock_); + if (queue_.size() == 0) + return false; + + memcpy(header, &queue_[0].header, sizeof(*header)); + + return true; +} +void final_img_queue::fetch_front(void* buf, int* len, bool* over) +{ + std::lock_guard lck(lock_); + + if (queue_.size() == 0) + { + if(len) + *len = 0; + if(over) + *over = true; + } + else + { + // for third-apps, we make fake data upto len when re-map file failed here + IMGDT& imgd = queue_[0]; + + if (imgd.offset == 0) + { + if (!imgd.data->swap()) + { + // VLOG_MINI_1(LOG_LEVEL_FATAL, "Reload final image '%s' failed!\n", imgd.data->file().c_str()); + } + } + + if (imgd.offset + *len >= imgd.header.bytes) + *len = imgd.header.bytes - imgd.offset; + + unsigned char* src = imgd.data->data(imgd.offset, (unsigned int*)len); + if (src) + { + memcpy(buf, src, *len); + } + else + { + // VLOG_MINI_2(LOG_LEVEL_FATAL, "Remap final image '%s + 0x%08x' failed!\n", imgd.data->file().c_str(), imgd.offset); + } + imgd.offset += *len; + if (imgd.offset >= imgd.header.bytes) + { + mem_usage_ -= imgd.header.bytes; + if (mem_usage_ < 0) + mem_usage_ = 0; + if (over) + *over = true; + queue_.erase(queue_.begin()); + } + } +} diff --git a/hg_ipc.h b/hg_ipc.h new file mode 100644 index 0000000..58ddccc --- /dev/null +++ b/hg_ipc.h @@ -0,0 +1,244 @@ +#pragma once + +// Objects for Inter-Process-Communication +// +// created on 2022-03-01 +// + +#if defined(WIN32) || defined(_WIN64) +#include + +#define sem_t HANDLE +#define USB_TIMEOUT_INFINITE -1 +#else +#include +#include +#include +#include +#define USB_TIMEOUT_INFINITE 0 +#endif + +#include +#include +#include +#include + +#include "base.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// memory management ... +void* allocate_memory(size_t bytes, const char* log_msg = ""); +void free_memory(void* ptr); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class platform_event +{ + sem_t sem_; + volatile bool waiting_; + std::string dbg_info_; + +public: + platform_event(); + ~platform_event(); + +public: + bool try_wait(void); + bool wait(unsigned timeout = USB_TIMEOUT_INFINITE/*ms*/); // USB_TIMEOUT_INFINITE is waiting unfinite, true when watied and false for wait timeout + void notify(void); + bool is_waiting(void); + + void set_debug_info(const char* info); +}; + +// class refer +// { +// volatile int ref_; +// std::mutex mutex_; + +// protected: +// refer() : ref_(1) +// {} +// virtual ~refer() +// {} + +// public: +// int add_ref(void) +// { +// std::lock_guard lock(mutex_); + +// return ++ref_; +// } +// int release(void) +// { +// int ref = 0; + +// { +// std::lock_guard lock(mutex_); +// ref = --ref_; +// } + +// if (ref == 0) +// delete this; + +// return ref; +// } +// }; + +template +class do_when_born_and_dead : public refer +{ + T* obj_; + void(T::* dead_)(void*); + void* param_; + +public: + do_when_born_and_dead(T* obj, void(T::* born)(void*), void(T::* dead)(void*), void* param) + : obj_(obj), dead_(dead), param_(param) + { + if(born) + (obj_->*born)(param_); + } + +protected: + ~do_when_born_and_dead() + { + (obj_->*dead_)(param_); + } +}; + +// mutex object +class shared_memory : public refer +{ + unsigned long long key_; + void* obj_; + bool first_; + size_t bytes_; + size_t len_; + + void init(void); + void clear(void); + char* get_buf(void); + void release_buf(void* buf); + +#if !defined(WIN32) && !defined(_WIN64) + static std::string get_proc_name_by_pid(pid_t pid); +#endif + +public: + shared_memory(unsigned long long key, size_t size = 1024); + +protected: + ~shared_memory(); + +public: + bool is_ok(void); + bool is_first(void); + std::string read(void); + int write(const char* data, size_t len); +}; + +// buffer +#if defined(WIN32) || defined(_WIN64) +#define HANDLE_NAME HANDLE +#define INVALID_HANDLE_NAME NULL +#else +#define HANDLE_NAME int +#define INVALID_HANDLE_NAME -1 +#endif +class tiny_file_map +{ + unsigned int size_; + unsigned int page_size_; + HANDLE_NAME map_; + unsigned char *buf_; + std::string file_; + bool keep_f_; + unsigned int map_off_; + unsigned int map_bytes_; + + int map_to_mem(unsigned int off = 0); + +public: + tiny_file_map(); + ~tiny_file_map(); + + static HANDLE_NAME open_file_for_mapping(const char* file, unsigned* bytes, bool create); + static void close_handle_name(HANDLE_NAME h); + static void* sys_map_api(HANDLE_NAME h, int access, unsigned int off, unsigned size, int* err); + static void sys_unmap_api(void* buf, size_t size = 0); + +public: + int open(const char* file, bool existing = true, unsigned int size = 0); + void close(void); + void keep_file(bool keep); + unsigned char* mapping_buffer(unsigned int off, unsigned int* bytes); + std::string file(void); + unsigned int size(void); + + // mapping if unmapped; or unmapping if mapped + bool swap(void); +}; +class tiny_buffer +{ + unsigned int size_; + unsigned char *buf_; + tiny_file_map fmap_; + int img_statu_; + + void init(const char* tmp_path, const char* name_leading, const char* ext, unsigned int uniq_id); + +public: + tiny_buffer(unsigned int size, const char* tmp_path, const char* name_leading, const char* ext, unsigned int uniq_id); + tiny_buffer(const char* src_file); + ~tiny_buffer(); + +public: + unsigned int size(void); + unsigned char* data(unsigned int off, unsigned int* bytes/*[in] - need bytes, [out] - real bytes*/); + void keep_file(bool keep); + std::string file(void); + + // mapping if unmapped; or unmapping if mapped + bool swap(void); + int to_file(const char* file); + + void set_image_statu(int statu); + int get_image_statu(void); +}; + +typedef struct _img_header +{ + int width; + int height; + int bits; + int channels; + int line_bytes; + unsigned bytes; + uint32_t src_id; +}IMH; +typedef struct _img +{ + IMH header; + unsigned offset; + std::shared_ptr data; +}IMGDT; +class final_img_queue +{ + mutable std::mutex lock_; + std::vector queue_; + long long mem_usage_; + +public: + final_img_queue(); + ~final_img_queue(); + +public: + unsigned long long mem_usage(void); + size_t size(void); + void clear(void); + bool put(int w, int h, int bpp, int channels, int line_bytes, void* data, unsigned bytes + , const char* tmp_path, const char* name_leading, const char* ext, int ind, uint32_t id); + bool front(IMH* header); + void fetch_front(void* buf, int* len, bool* over); +}; \ No newline at end of file diff --git a/hgscanner_error.h b/hgscanner_error.h new file mode 100644 index 0000000..1d86c1b --- /dev/null +++ b/hgscanner_error.h @@ -0,0 +1,348 @@ +// this file is include huagao scanner error definitions +// +// created: 2022-02-07 +// + +#pragma once + +#define RETURN_IF(var, enum_val) \ + if(var == enum_val) \ + return #enum_val; + +#define RETURN_DESC_IF(var, hgerr) \ + if(var == hgerr) \ + return hg_log::lang_load(ID_##STATU_DESC_##hgerr); + +enum scanner_err +{ + SCANNER_ERR_OK = 0, // 成功,正常状态 + + // 1:软件逻辑错误 + SCANNER_ERR_INVALID_PARAMETER = 0x100, // 非法的参数调用 + SCANNER_ERR_USER_CANCELED, // 用户取消了操作 + SCANNER_ERR_INSUFFICIENT_MEMORY, // 分配的内存不足 + SCANNER_ERR_ACCESS_DENIED, // 访问被拒绝 + SCANNER_ERR_IO_PENDING, // 异步访问,数据稍后返回 + SCANNER_ERR_NOT_EXACT, // 数据不精确,精确的数据已经在同一缓存中返回 + SCANNER_ERR_CONFIGURATION_CHANGED, // 设备的配置项发生改变,需要重新加载显示 + SCANNER_ERR_NOT_OPEN, // 设备未打开 + SCANNER_ERR_NOT_START, // 设备没有启动 + SCANNER_ERR_NOT_ANY_MORE, // 用于回调返回,在本次扫描中,对相同操作不再回调 + SCANNER_ERR_NO_DATA, // 没有数据 + SCANNER_ERR_HAS_DATA_YET, // 有数据未被读取(异步操作中) + SCANNER_ERR_OUT_OF_RANGE, // 相关操作超出范围 + SCANNER_ERR_IO, // IO错误 + SCANNER_ERR_TIMEOUT, // 超时错误 + SCANNER_ERR_OPEN_FILE_FAILED, // 打开本地文件失败 + SCANNER_ERR_CREATE_FILE_FAILED, // 创建本地文件失败 + SCANNER_ERR_WRITE_FILE_FAILED, // 写本地文件失败 + SCANNER_ERR_DATA_DAMAGED, // 数据损坏(内置资源数据损坏) + SCANNER_ERR_OPENED_BY_OTHER_PROCESS, // 设备已经被其它进程打开占用 + SCANNER_ERR_LANG_PAK_LOST, // 语言包丢失 + SCANNER_ERR_RELOAD_IMAGE_PARAM, // 配置成功,会影响图像参数,应用需要重新加载图像参数 - added on 2023-02-18 for XSANE修改影响图像参数的属性后扫描崩溃的问题 + SCANNER_ERR_RELOAD_OPT_PARAM, // SCANNER_ERR_CONFIGURATION_CHANGED + SCANNER_ERR_RELOAD_IMAGE_PARAM - added on 2023-02-18 for XSANE修改影响图像参数的属性后扫描崩溃的问题 + + // 2:USB错误 + SCANNER_ERR_USB_INIT_FAILED = 0x5b00, // libusb_init 失败 + SCANNER_ERR_USB_REGISTER_PNP_FAILED, // 注册USB监听事件失败 + SCANNER_ERR_USB_CLAIM_INTERFACE_FAILED, // failed in calling libusb_claim_interface + + // 3:硬件错误 + SCANNER_ERR_DEVICE_NOT_FOUND = 0x0de00, // 设备未找到 + SCANNER_ERR_DEVICE_NOT_SUPPORT, // 设备不支持该操作 + SCANNER_ERR_DEVICE_BUSY, // 设备正忙,不能响应该操作 + SCANNER_ERR_DEVICE_SLEEPING, // 设备处于睡眠状态 + SCANNER_ERR_DEVICE_COUNT_MODE, // 设备处于计数扫描状态? + SCANNER_ERR_DEVICE_STOPPED, // 扫描停止 + SCANNER_ERR_DEVICE_COVER_OPENNED, // 扫描仪盖板呈打开状态 + SCANNER_ERR_DEVICE_NO_PAPER, // 没有纸张输入 + SCANNER_ERR_DEVICE_FEEDING_PAPER, // 搓纸失败 + SCANNER_ERR_DEVICE_DOUBLE_FEEDING, // 双张检测 + SCANNER_ERR_DEVICE_PAPER_JAMMED, // 卡纸 + SCANNER_ERR_DEVICE_STAPLE_ON, // 有钉书钉 + SCANNER_ERR_DEVICE_PAPER_SKEW, // 纸张倾斜 + SCANNER_ERR_DEVICE_SIZE_CHECK, // 尺寸检测错误 + SCANNER_ERR_DEVICE_DOGEAR, // 纸张有折角 + SCANNER_ERR_DEVICE_NO_IMAGE, // 设备没取到图 + SCANNER_ERR_DEVICE_SCANN_ERROR, // 设备扫图失败 + SCANNER_ERR_DEVICE_PC_BUSY, // PC繁忙或出错 + SCANNER_ERR_DEVICE_ISLOCK, // 设备被锁定 + SCANNER_ERR_DEVICE_UPGRADE_SUCCESSFUL, // 固件升级成功 + SCANNER_ERR_DEVICE_UPGRADE_FAIL, // 固件升级失败+ + SCANNER_ERR_DEVICE_AUTO_FAIL_OVER, // 设备平场自动校正结束 + SCANNER_ERR_DEVICE_AUTO_FAIL_INFO, // 设备平场自动校正信息传输 + SCANNER_ERR_DEVICE_DISTORTION, // 畸变修正失败 +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 状态信息描述符 +// +// #define STATU_DESC_PREPARE_START "准备启动……" +#define STATU_DESC_PREPARE_START "\345\207\206\345\244\207\345\220\257\345\212\250\342\200\246\342\200\246" +#define ID_STATU_DESC_PREPARE_START 62135 + +// #define STATU_DESC_REWRITE_CONFIGURATION "写入配置……" +#define STATU_DESC_REWRITE_CONFIGURATION "\345\206\231\345\205\245\351\205\215\347\275\256\342\200\246\342\200\246" +#define ID_STATU_DESC_REWRITE_CONFIGURATION 16489 + +// #define STATU_DESC_CLEAR_CACHE "清理缓存……" +#define STATU_DESC_CLEAR_CACHE "\346\270\205\347\220\206\347\274\223\345\255\230\342\200\246\342\200\246" +#define ID_STATU_DESC_CLEAR_CACHE 6523 + +// #define STATU_DESC_START_SUCCESS "启动成功" +#define STATU_DESC_START_SUCCESS "\345\220\257\345\212\250\346\210\220\345\212\237" +#define ID_STATU_DESC_START_SUCCESS 33731 + +// #define STATU_DESC_START_FAIL "启动失败" +#define STATU_DESC_START_FAIL "\345\220\257\345\212\250\345\244\261\350\264\245" +#define ID_STATU_DESC_START_FAIL 51358 + +// #define STATU_DESC_SCAN_WORKING "正在扫描……" +#define STATU_DESC_SCAN_WORKING "\346\255\243\345\234\250\346\211\253\346\217\217\342\200\246\342\200\246" +#define ID_STATU_DESC_SCAN_WORKING 21315 + +// #define STATU_DESC_SCAN_STOPPED "扫描完成" +#define STATU_DESC_SCAN_STOPPED "\346\211\253\346\217\217\345\256\214\346\210\220" +#define ID_STATU_DESC_SCAN_STOPPED 17731 + +// #define STATU_DESC_SCAN_CANCELED "扫描已取消" +#define STATU_DESC_SCAN_CANCELED "\346\211\253\346\217\217\345\267\262\345\217\226\346\266\210" +#define ID_STATU_DESC_SCAN_CANCELED 63314 + +// #define STATU_DESC_WAIT_FOR_MEM "内存不足,等待内存释放……" +#define STATU_DESC_WAIT_FOR_MEM "\345\206\205\345\255\230\344\270\215\350\266\263\357\274\214\347\255\211\345\276\205\345\206\205\345\255\230\351\207\212\346\224\276\342\200\246\342\200\246" +#define ID_STATU_DESC_WAIT_FOR_MEM 7697 + +// #define STATU_DESC_DEVICE_RESET "正在重置,如果设备迟迟没有动作,请重新扫描……" +#define STATU_DESC_DEVICE_RESET "\346\255\243\345\234\250\351\207\215\347\275\256\357\274\214\345\246\202\346\236\234\350\256\276\345\244\207\350\277\237\350\277\237\346\262\241\346\234\211\345\212\250\344\275\234\357\274\214\350\257\267\351\207\215\346\226\260\346\211\253\346\217\217\342\200\246\342\200\246" +#define ID_STATU_DESC_DEVICE_RESET 47482 + +// #define STATU_DESC_SCANNER_ERR_OK "操作成功" +#define STATU_DESC_SCANNER_ERR_OK "\346\223\215\344\275\234\346\210\220\345\212\237" +#define ID_STATU_DESC_SCANNER_ERR_OK 3249 + +// #define STATU_DESC_SCANNER_ERR_USER_CANCELED "操作被取消" +#define STATU_DESC_SCANNER_ERR_USER_CANCELED "\346\223\215\344\275\234\350\242\253\345\217\226\346\266\210" +#define ID_STATU_DESC_SCANNER_ERR_USER_CANCELED 48546 + +// #define STATU_DESC_SCANNER_ERR_DATA_DAMAGED "数据损坏" +#define STATU_DESC_SCANNER_ERR_DATA_DAMAGED "\346\225\260\346\215\256\346\215\237\345\235\217" +#define ID_STATU_DESC_SCANNER_ERR_DATA_DAMAGED 45852 + +// #define STATU_DESC_SCANNER_ERR_INVALID_PARAMETER "非法的参数调用" +#define STATU_DESC_SCANNER_ERR_INVALID_PARAMETER "\351\235\236\346\263\225\347\232\204\345\217\202\346\225\260\350\260\203\347\224\250" +#define ID_STATU_DESC_SCANNER_ERR_INVALID_PARAMETER 6119 + +// #define STATU_DESC_SCANNER_ERR_INSUFFICIENT_MEMORY "内存不足或内存分配失败" +#define STATU_DESC_SCANNER_ERR_INSUFFICIENT_MEMORY "\345\206\205\345\255\230\344\270\215\350\266\263\346\210\226\345\206\205\345\255\230\345\210\206\351\205\215\345\244\261\350\264\245" +#define ID_STATU_DESC_SCANNER_ERR_INSUFFICIENT_MEMORY 56958 + +// #define STATU_DESC_SCANNER_ERR_ACCESS_DENIED "访问被拒绝" +#define STATU_DESC_SCANNER_ERR_ACCESS_DENIED "\350\256\277\351\227\256\350\242\253\346\213\222\347\273\235" +#define ID_STATU_DESC_SCANNER_ERR_ACCESS_DENIED 56275 + +// #define STATU_DESC_SCANNER_ERR_IO_PENDING "异步访问,数据稍后返回" +#define STATU_DESC_SCANNER_ERR_IO_PENDING "\345\274\202\346\255\245\350\256\277\351\227\256\357\274\214\346\225\260\346\215\256\347\250\215\345\220\216\350\277\224\345\233\236" +#define ID_STATU_DESC_SCANNER_ERR_IO_PENDING 25758 + +// #define STATU_DESC_SCANNER_ERR_NOT_EXACT "数据不精确,精确的数据已经在同一缓存中返回" +#define STATU_DESC_SCANNER_ERR_NOT_EXACT "\346\225\260\346\215\256\344\270\215\347\262\276\347\241\256\357\274\214\347\262\276\347\241\256\347\232\204\346\225\260\346\215\256\345\267\262\347\273\217\345\234\250\345\220\214\344\270\200\347\274\223\345\255\230\344\270\255\350\277\224\345\233\236" +#define ID_STATU_DESC_SCANNER_ERR_NOT_EXACT 64193 + +// #define STATU_DESC_SCANNER_ERR_CONFIGURATION_CHANGED "设备的配置项发生改变,需要重新加载显示" +#define STATU_DESC_SCANNER_ERR_CONFIGURATION_CHANGED "\350\256\276\345\244\207\347\232\204\351\205\215\347\275\256\351\241\271\345\217\221\347\224\237\346\224\271\345\217\230\357\274\214\351\234\200\350\246\201\351\207\215\346\226\260\345\212\240\350\275\275\346\230\276\347\244\272" +#define ID_STATU_DESC_SCANNER_ERR_CONFIGURATION_CHANGED 26730 + +// #define STATU_DESC_SCANNER_ERR_RELOAD_IMAGE_PARAM "图像参数已经改变,请重新加载" +#define STATU_DESC_SCANNER_ERR_RELOAD_IMAGE_PARAM "\345\233\276\345\203\217\345\217\202\346\225\260\345\267\262\347\273\217\346\224\271\345\217\230\357\274\214\350\257\267\351\207\215\346\226\260\345\212\240\350\275\275" +#define ID_STATU_DESC_SCANNER_ERR_RELOAD_IMAGE_PARAM 54637 + +// #define STATU_DESC_SCANNER_ERR_RELOAD_OPT_PARAM "关联属性状态及图像参数已经改变,请重新加载" +#define STATU_DESC_SCANNER_ERR_RELOAD_OPT_PARAM "\345\205\263\350\201\224\345\261\236\346\200\247\347\212\266\346\200\201\345\217\212\345\233\276\345\203\217\345\217\202\346\225\260\345\267\262\347\273\217\346\224\271\345\217\230\357\274\214\350\257\267\351\207\215\346\226\260\345\212\240\350\275\275" +#define ID_STATU_DESC_SCANNER_ERR_RELOAD_OPT_PARAM 4762 + +// #define STATU_DESC_SCANNER_ERR_NOT_OPEN "设备未打开" +#define STATU_DESC_SCANNER_ERR_NOT_OPEN "\350\256\276\345\244\207\346\234\252\346\211\223\345\274\200" +#define ID_STATU_DESC_SCANNER_ERR_NOT_OPEN 38521 + +// #define STATU_DESC_SCANNER_ERR_NOT_START "设备没有启动" +#define STATU_DESC_SCANNER_ERR_NOT_START "\350\256\276\345\244\207\346\262\241\346\234\211\345\220\257\345\212\250" +#define ID_STATU_DESC_SCANNER_ERR_NOT_START 5681 + +// #define STATU_DESC_SCANNER_ERR_NOT_ANY_MORE "在本次扫描中,对相同操作不再询问" +#define STATU_DESC_SCANNER_ERR_NOT_ANY_MORE "\345\234\250\346\234\254\346\254\241\346\211\253\346\217\217\344\270\255\357\274\214\345\257\271\347\233\270\345\220\214\346\223\215\344\275\234\344\270\215\345\206\215\350\257\242\351\227\256" +#define ID_STATU_DESC_SCANNER_ERR_NOT_ANY_MORE 16267 + +// #define STATU_DESC_SCANNER_ERR_NO_DATA "没有数据" +#define STATU_DESC_SCANNER_ERR_NO_DATA "\346\262\241\346\234\211\346\225\260\346\215\256" +#define ID_STATU_DESC_SCANNER_ERR_NO_DATA 15331 + +// #define STATU_DESC_SCANNER_ERR_HAS_DATA_YET "有数据未被读取" +#define STATU_DESC_SCANNER_ERR_HAS_DATA_YET "\346\234\211\346\225\260\346\215\256\346\234\252\350\242\253\350\257\273\345\217\226" +#define ID_STATU_DESC_SCANNER_ERR_HAS_DATA_YET 31030 + +// #define STATU_DESC_SCANNER_ERR_OUT_OF_RANGE "操作超出范围" +#define STATU_DESC_SCANNER_ERR_OUT_OF_RANGE "\346\223\215\344\275\234\350\266\205\345\207\272\350\214\203\345\233\264" +#define ID_STATU_DESC_SCANNER_ERR_OUT_OF_RANGE 22268 + +// #define STATU_DESC_SCANNER_ERR_IO "IO错误,请重启设备或拔插USB" +#define STATU_DESC_SCANNER_ERR_IO "IO\351\224\231\350\257\257\357\274\214\350\257\267\351\207\215\345\220\257\350\256\276\345\244\207\346\210\226\346\213\224\346\217\222USB" +#define ID_STATU_DESC_SCANNER_ERR_IO 27027 + +// #define STATU_DESC_SCANNER_ERR_TIMEOUT "操作超时" +#define STATU_DESC_SCANNER_ERR_TIMEOUT "\346\223\215\344\275\234\350\266\205\346\227\266" +#define ID_STATU_DESC_SCANNER_ERR_TIMEOUT 65371 + +// #define STATU_DESC_SCANNER_ERR_OPEN_FILE_FAILED "打开本地文件失败" +#define STATU_DESC_SCANNER_ERR_OPEN_FILE_FAILED "\346\211\223\345\274\200\346\234\254\345\234\260\346\226\207\344\273\266\345\244\261\350\264\245" +#define ID_STATU_DESC_SCANNER_ERR_OPEN_FILE_FAILED 52380 + +// #define STATU_DESC_SCANNER_ERR_CREATE_FILE_FAILED "创建本地文件失败" +#define STATU_DESC_SCANNER_ERR_CREATE_FILE_FAILED "\345\210\233\345\273\272\346\234\254\345\234\260\346\226\207\344\273\266\345\244\261\350\264\245" +#define ID_STATU_DESC_SCANNER_ERR_CREATE_FILE_FAILED 23361 + +// #define STATU_DESC_SCANNER_ERR_WRITE_FILE_FAILED "写本地文件失败" +#define STATU_DESC_SCANNER_ERR_WRITE_FILE_FAILED "\345\206\231\346\234\254\345\234\260\346\226\207\344\273\266\345\244\261\350\264\245" +#define ID_STATU_DESC_SCANNER_ERR_WRITE_FILE_FAILED 22164 + +// #define STATU_DESC_SCANNER_ERR_OPENED_BY_OTHER_PROCESS "设备已经被其它进程占用" +#define STATU_DESC_SCANNER_ERR_OPENED_BY_OTHER_PROCESS "\350\256\276\345\244\207\345\267\262\347\273\217\350\242\253\345\205\266\345\256\203\350\277\233\347\250\213\345\215\240\347\224\250" +#define ID_STATU_DESC_SCANNER_ERR_OPENED_BY_OTHER_PROCESS 62384 + +// #define STATU_DESC_SCANNER_ERR_USB_INIT_FAILED "USB通信初始化失败" +#define STATU_DESC_SCANNER_ERR_USB_INIT_FAILED "USB\351\200\232\344\277\241\345\210\235\345\247\213\345\214\226\345\244\261\350\264\245" +#define ID_STATU_DESC_SCANNER_ERR_USB_INIT_FAILED 49159 + +// #define STATU_DESC_SCANNER_ERR_USB_REGISTER_PNP_FAILED "注册USB监听事件失败" +#define STATU_DESC_SCANNER_ERR_USB_REGISTER_PNP_FAILED "\346\263\250\345\206\214USB\347\233\221\345\220\254\344\272\213\344\273\266\345\244\261\350\264\245" +#define ID_STATU_DESC_SCANNER_ERR_USB_REGISTER_PNP_FAILED 5685 + +// #define STATU_DESC_SCANNER_ERR_USB_CLAIM_INTERFACE_FAILED "声明USB接口失败" +#define STATU_DESC_SCANNER_ERR_USB_CLAIM_INTERFACE_FAILED "\345\243\260\346\230\216USB\346\216\245\345\217\243\345\244\261\350\264\245" +#define ID_STATU_DESC_SCANNER_ERR_USB_CLAIM_INTERFACE_FAILED 21918 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_NOT_FOUND "设备未找到" +#define STATU_DESC_SCANNER_ERR_DEVICE_NOT_FOUND "\350\256\276\345\244\207\346\234\252\346\211\276\345\210\260" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_NOT_FOUND 43988 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_NOT_SUPPORT "设备不支持该操作" +#define STATU_DESC_SCANNER_ERR_DEVICE_NOT_SUPPORT "\350\256\276\345\244\207\344\270\215\346\224\257\346\214\201\350\257\245\346\223\215\344\275\234" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_NOT_SUPPORT 15726 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_BUSY "设备正忙,不能响应该操作" +#define STATU_DESC_SCANNER_ERR_DEVICE_BUSY "\350\256\276\345\244\207\346\255\243\345\277\231\357\274\214\344\270\215\350\203\275\345\223\215\345\272\224\350\257\245\346\223\215\344\275\234" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_BUSY 29315 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_SLEEPING "设备处于睡眠状态" +#define STATU_DESC_SCANNER_ERR_DEVICE_SLEEPING "\350\256\276\345\244\207\345\244\204\344\272\216\347\235\241\347\234\240\347\212\266\346\200\201" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_SLEEPING 26372 + +//#define STATU_DESC_SCANNER_ERR_DEVICE_NOTIFY_SLEEP 正在唤醒...请等待十秒再次扫描 +#define STATU_DESC_SCANNER_ERR_DEVICE_NOTIFY_SLEEP "\346\255\243\345\234\250\345\224\244\351\206\222...\350\257\267\347\255\211\345\276\205\345\215\201\347\247\222\345\206\215\346\254\241\346\211\253\346\217\217" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_NOTIFY_SLEEP 64756 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_COUNT_MODE "设备处于计数模式扫描状态" +#define STATU_DESC_SCANNER_ERR_DEVICE_COUNT_MODE "\350\256\276\345\244\207\345\244\204\344\272\216\350\256\241\346\225\260\346\250\241\345\274\217\346\211\253\346\217\217\347\212\266\346\200\201" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_COUNT_MODE 602 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_STOPPED "扫描停止" +#define STATU_DESC_SCANNER_ERR_DEVICE_STOPPED "\346\211\253\346\217\217\345\201\234\346\255\242" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_STOPPED 45291 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_COVER_OPENNED "请关闭扫描仪盖板" +#define STATU_DESC_SCANNER_ERR_DEVICE_COVER_OPENNED "\350\257\267\345\205\263\351\227\255\346\211\253\346\217\217\344\273\252\347\233\226\346\235\277" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_COVER_OPENNED 29725 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_NO_PAPER "无纸" +#define STATU_DESC_SCANNER_ERR_DEVICE_NO_PAPER "\346\227\240\347\272\270" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_NO_PAPER 61284 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_FEEDING_PAPER "搓纸失败" +#define STATU_DESC_SCANNER_ERR_DEVICE_FEEDING_PAPER "\346\220\223\347\272\270\345\244\261\350\264\245" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_FEEDING_PAPER 60256 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_DOUBLE_FEEDING "有多张纸被同时搓进扫描仪" +#define STATU_DESC_SCANNER_ERR_DEVICE_DOUBLE_FEEDING "\346\234\211\345\244\232\345\274\240\347\272\270\350\242\253\345\220\214\346\227\266\346\220\223\350\277\233\346\211\253\346\217\217\344\273\252" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_DOUBLE_FEEDING 58398 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_PAPER_JAMMED "扫描仪卡纸" +#define STATU_DESC_SCANNER_ERR_DEVICE_PAPER_JAMMED "\346\211\253\346\217\217\344\273\252\345\215\241\347\272\270" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_PAPER_JAMMED 39928 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_STAPLE_ON "纸张上检测到有钉书钉" +#define STATU_DESC_SCANNER_ERR_DEVICE_STAPLE_ON "\347\272\270\345\274\240\344\270\212\346\243\200\346\265\213\345\210\260\346\234\211\351\222\211\344\271\246\351\222\211" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_STAPLE_ON 3126 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_PAPER_SKEW "纸张倾斜" +#define STATU_DESC_SCANNER_ERR_DEVICE_PAPER_SKEW "\347\272\270\345\274\240\345\200\276\346\226\234" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_PAPER_SKEW 5570 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_SIZE_CHECK "纸张尺寸检测错误" +#define STATU_DESC_SCANNER_ERR_DEVICE_SIZE_CHECK "\347\272\270\345\274\240\345\260\272\345\257\270\346\243\200\346\265\213\351\224\231\350\257\257" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_SIZE_CHECK 32107 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_DOGEAR "纸张有折角" +#define STATU_DESC_SCANNER_ERR_DEVICE_DOGEAR "\347\272\270\345\274\240\346\234\211\346\212\230\350\247\222" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_DOGEAR 61565 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_NO_IMAGE "设备没取到图" +#define STATU_DESC_SCANNER_ERR_DEVICE_NO_IMAGE "\350\256\276\345\244\207\346\262\241\345\217\226\345\210\260\345\233\276" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_NO_IMAGE 41789 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_SCANN_ERROR "扫描失败" +#define STATU_DESC_SCANNER_ERR_DEVICE_SCANN_ERROR "\346\211\253\346\217\217\345\244\261\350\264\245" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_SCANN_ERROR 14901 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_PC_BUSY "PC繁忙或出错" +#define STATU_DESC_SCANNER_ERR_DEVICE_PC_BUSY "PC\347\271\201\345\277\231\346\210\226\345\207\272\351\224\231" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_PC_BUSY 61142 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_ISLOCK "设备被锁定" +#define STATU_DESC_SCANNER_ERR_DEVICE_ISLOCK "\350\256\276\345\244\207\350\242\253\351\224\201\345\256\232" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_ISLOCK 1535 + +// #define STATU_DESC_SCANNER_ERR_DEVICE_ISLOCK "此固件不支持待纸扫描" +#define STATU_DESC_SCANNER_ERR_DEVICE_NOT_SUPPORTED "\346\255\244\345\233\272\344\273\266\344\270\215\346\224\257\346\214\201\345\276\205\347\272\270\346\211\253\346\217\217" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_NOT_SUPPORTED 9610 + +//#define STATU_DESC_SCANNER_ERR_DEVICE_AUTO_FAIL_OVER "自动平场校正结束" +#define STATU_DESC_SCANNER_ERR_DEVICE_AUTO_FAIL_OVER "\350\207\252\345\212\250\345\271\263\345\234\272\346\240\241\346\255\243\347\273\223\346\235\237" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_AUTO_FAIL_OVER 38824 + +//#define STATU_DESC_SCANNER_ERR_DEVICE_DISTORTION "疑是非专用畸变修正纸" +#define STATU_DESC_SCANNER_ERR_DEVICE_DISTORTION "\347\226\221\346\230\257\351\235\236\344\270\223\347\224\250\347\225\270\345\217\230\344\277\256\346\255\243\347\272\270" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_DISTORTION 32402 + +//#define STATU_DESC_SCANNER_ERR_DEVICE_GET_IMAGE_OUTTIME "取图通信超时" +#define STATU_DESC_SCANNER_ERR_DEVICE_GET_IMAGE_OUTTIME "\345\217\226\345\233\276\351\200\232\344\277\241\350\266\205\346\227\266" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_GET_IMAGE_OUTTIME 10438 + +//#define STATU_DESC_SCANNER_ERR_DEVICE_GET_USER_CANCEL_SCAN "用户取消扫描" +#define STATU_DESC_SCANNER_ERR_DEVICE_GET_USER_CANCEL_SCAN "\347\224\250\346\210\267\345\217\226\346\266\210\346\211\253\346\217\217" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_GET_USER_CANCEL_SCAN 39020 + +//#define STATU_DESC_SCANNER_ERR_DEVICE_FAIL_OUTTIME "设备校正超时" +#define STATU_DESC_SCANNER_ERR_DEVICE_FAIL_OUTTIME "\350\256\276\345\244\207\346\240\241\346\255\243\350\266\205\346\227\266" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_FAIL_OUTTIME 21710 + +//#define STATU_DESC_SCANNER_ERR_DEVICE_ROUND_SACN_OVER "此轮扫描完成" +#define STATU_DESC_SCANNER_ERR_DEVICE_ROUND_SACN_OVER "\346\255\244\350\275\256\346\211\253\346\217\217\345\256\214\346\210\220" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_ROUND_SACN_OVER 57619 + +//#define STATU_DESC_SCANNER_ERR_DEVICE_DEVS "设备" +#define STATU_DESC_SCANNER_ERR_DEVICE_DEVS "\350\256\276\345\244\207\342\200\234" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_DEVS 603 + +//#define STATU_DESC_SCANNER_ERR_DEVICE_IS_CLOSE "已经关闭" +#define STATU_DESC_SCANNER_ERR_DEVICE_IS_CLOSE "\342\200\235\345\267\262\347\273\217\345\205\263\351\227\255\343\200\202" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_IS_CLOSE 35078 + +//#define STATU_DESC_SCANNER_ERR_DEVICE_UNKNOWN_ERROR "未知错误,请重启设备,等待设备复位成功在启动软件。" +#define STATU_DESC_SCANNER_ERR_DEVICE_UNKNOWN_ERROR "\346\234\252\347\237\245\351\224\231\350\257\257\357\274\214\350\257\267\351\207\215\345\220\257\350\256\276\345\244\207\357\274\214\347\255\211\345\276\205\350\256\276\345\244\207\345\244\215\344\275\215\346\210\220\345\212\237\345\234\250\345\220\257\345\212\250\350\275\257\344\273\266" +#define ID_STATU_DESC_SCANNER_ERR_DEVICE_UNKNOWN_ERROR 22744 + +// 状态信息描述符 - OVER + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..92be902 --- /dev/null +++ b/main.cpp @@ -0,0 +1,1765 @@ +// scanner.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 +// + +#include +#include +#include +#include +#include +#include +#include + +#include "cmd.h" +#include "usb_manager.h" + +#define CONST_E 2.7182818284590452353602874713527f +#define CONST_PI 3.1415926535897932384626433832795f +#define MM_PER_INCH 25.4f +#define IS_EQUAL(v, t) ((v - t) >= -.00001f && (v - t) <= .00001f) + +namespace proc_util +{ + static bool is_match(const char* str, const char* pattern) + { + std::vector parts; + std::string all(pattern); + size_t pos = all.find("*"); + + while(pos != std::string::npos) + { + if(pos) + parts.push_back(all.substr(0, pos)); + all.erase(0, pos + 1); + pos = all.find("*"); + } + if(!all.empty()) + parts.push_back(all); + + for(pos = 0; pos < parts.size(); ++pos) + { + str = strstr(str, parts[pos].c_str()); + if(!str) + break; + str += parts[pos].length(); + } + + return pos == parts.size(); + } + static bool found_proc(uint64_t pid, const char* path, void* param) + { + struct + { + uint32_t cnt = 0; + std::string filter = ""; + }*ptr; + *((void**)&ptr) = param; + + if(ptr->filter.empty() || is_match(path, ptr->filter.c_str())) + printf("%d - %ld: %s\n", ++ptr->cnt, pid, path); + + return true; + } + static bool found_modules(const char* path, bool is_dir, void* param) + { + uint32_t* cnt = (uint32_t*)param; + + printf("%d - %s\n", ++cnt[0], path); + + return true; + } + static bool found_modules_norepeat(const char* path, bool is_dir, void* param) + { + struct + { + uint32_t cnt; + std::vector modules; + }*data = nullptr; + + *(void**)&data = param; + + if (std::find(data->modules.begin(), data->modules.end(), path) == data->modules.end()) + { + printf("%d - %s\n", ++data->cnt, path); + data->modules.push_back(path); + } + + return true; + } + static bool on_found_thread(uint64_t tid, void* start_addr, void* param) + { + uint32_t* cnt = (uint32_t*)param; + + printf("%d - %p(%u): starting at %p\n", ++cnt[0], tid, tid, start_addr); + + return true; + } + static bool on_stack(uint64_t off, const char* module, void* param) + { + uint32_t* cnt = (uint32_t*)param; + + printf("%d - %s + %p\n", ++cnt[0], module, off); + + return true; + } + + // -proc + static CONSOLE_ROUTINE(print_help) + { + printf("\ +usage: enmo [-nrp]: to enumerate modules of process pid. -nrp is no repeating\n\ + enpr [-filter *.so]: to enum all processes\n\ + enth : to enumerate threads of process pid\n\ + exit: to exit this APP\n\ + q: quit process utility\n\ + stck : to get thread(tid) calling stack of process pid\n\n\ +"); + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(enum_module) + { + if(cmd->count()) + { + uint64_t pid = sys_util::to_int(cmd->parameter(0)); + bool nrp = cmd->count() >= 2 && strcmp(cmd->parameter(1), "-nrp") == 0; + + if(nrp) + { + struct + { + uint32_t cnt = 0; + std::vector modules; + }data; + + sys_util::enum_modules(found_modules_norepeat, &data, pid); + } + else + { + uint32_t cnt = 0; + sys_util::enum_modules(found_modules, &cnt, pid); + } + } + else + printf(" enmo [-nrp]\n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(enum_process) + { + struct + { + uint32_t cnt = 0; + std::string filter = ""; + }para; + + if(cmd->parameter("-filter")) + { + para.filter = cmd->parameter("-filter"); + } + + sys_util::enum_processes(found_proc, ¶); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(enum_thread) + { + if(cmd->count()) + { + uint32_t cnt = 0; + + sys_util::enum_threads(sys_util::to_int(cmd->parameter(0)), on_found_thread, &cnt); + } + else + printf(" enth \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(get_stack) + { + if(cmd->count() >= 2) + { + uint32_t cnt = 0; + + sys_util::get_thread_callstack(sys_util::to_int(cmd->parameter(0)), sys_util::to_int(cmd->parameter(1)), on_stack, &cnt); + } + else + printf(" stck \n"); + + return QUIT_CMD_NONE; + } + + static CONSOLE_ROUTINE(run_console) + { + quit_cmd quit = QUIT_CMD_NONE; + std::string pre_cmd = cmd->to_command_line(); + console_dispatcher me; + + me.add_command_routine("enmo", enum_module); + me.add_command_routine("enpr", enum_process); + me.add_command_routine("enth", enum_thread); + me.add_command_routine("stck", get_stack); + me.set_unhandled_routine(print_help); + quit = me.run("hgutil-proc", pre_cmd.c_str()); + + return quit == QUIT_CMD_QUIT_ALL ? quit : QUIT_CMD_NONE; + } +} +namespace kernel_obj +{ + // -kobj + static quit_cmd print_help(cmd_line* cmd, void* param) + { + printf("\ +usage: enmsg: enumerate all shared memories\n\ + ensem: enumerate all semaphores\n\ + enshm: enumerate all shared memories\n\ + rdshm [-size] [-f save-local-file]: read shared memory\n\ + rmshm : remove shared-memory which defined by 'shm-key'\n\ + exit: to exit this APP\n\ + q: quit process utility\n\ +\n\ +"); + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(read_shm) + { + if(cmd->count()) + { + key_t k = (key_t)sys_util::to_int(cmd->parameter(0)); + int shm = shmget(k, 0, 0600); + if(shm == -1) + { + printf(" Failed: shmget(%p, 0, 0600) = %d(%s)\n", k, errno, strerror(errno)); + } + else + { + size_t size = sys_util::get_page_size(); + FILE *dst = nullptr; + char *buf = nullptr; + std::string file(""); + + if(cmd->parameter("-size")) + size = sys_util::to_int(cmd->parameter("-size")); + if(cmd->parameter("-f")) + { + file = sys_util::to_abs_path(getenv("PWD"), cmd->parameter("-f")); + dst = fopen(file.c_str(), "wb"); + if(!dst) + printf(" Failed to create target file(%s) = %d(%s)\n", file.c_str(), errno, strerror(errno)); + else + printf(" Write down to file '%s'\n", file.c_str()); + } + + buf = (char*)shmat(shm, 0, 0); + if(buf == (char*)-1) + { + printf(" Failed to map shared memory(%p) = %d(%s)\n", k, errno, strerror(errno)); + if(dst) + { + fclose(dst); + remove(file.c_str()); + } + } + else + { + if(dst) + { + size = fwrite(buf, 1, size, dst); + fclose(dst); + printf(" %u bytes saved into file '%s'\n", size, file.c_str()); + } + else + console_dispatcher::print_sector((uint8_t*)buf, size); + shmdt(buf); + } + } + } + else + printf(" rmshm \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(remove_shm) + { + if(cmd->count()) + { + key_t k = (key_t)sys_util::to_int(cmd->parameter(0)); + int shm = shmget(k, 0, 0600); + if(shm == -1) + { + printf("Failed: shmget(%p, 0, 0600) = %d(%s), try system command 'ipcs -M %s'\n", k, errno, strerror(errno), cmd->parameter(0)); + } + else + { + struct shmid_ds ds = {0}; + if(shmctl(shm, IPC_RMID, &ds)) + { + printf("Failed: shmctl(%d, IPC_RMID, (shmid_ds*)%p) = %d(%s)\n", shm, &ds, k, errno, strerror(errno)); + } + else + printf("Remove shared-memory(%p) success.\n", k); + } + } + else + printf(" rmshm \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(enum_shm) + { + system("ipcs -m"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(enum_sem) + { + system("ipcs -s"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(enum_msg) + { + system("ipcs -q"); + + return QUIT_CMD_NONE; + } + + static CONSOLE_ROUTINE(run_console) + { + quit_cmd quit = QUIT_CMD_NONE; + std::string pre_cmd = cmd->to_command_line(); + console_dispatcher me; + + me.add_command_routine("rmshm", remove_shm); + me.add_command_routine("rdshm", read_shm); + me.add_command_routine("enshm", enum_shm); + me.add_command_routine("enmsg", enum_msg); + me.add_command_routine("ensem", enum_sem); + me.set_unhandled_routine(print_help); + quit = me.run("hgutil-kobj", pre_cmd.c_str()); + + return quit == QUIT_CMD_QUIT_ALL ? quit : QUIT_CMD_NONE; + } +} +namespace mem_util +{ + // -mem + static uint32_t handle(int32_t argc, char** argv) + { + uint64_t total = 0, avail = 0; + uint32_t page = sys_util::get_page_size(), + err = sys_util::get_memory_info(&total, &avail); + char cpu[256] = {0}; + + sys_util::get_inf_file_data("/proc/cpuinfo", sizeof(cpu) - 1, "model name\t:%s %s %s %s @ %s", cpu, cpu + 50, cpu + 100, cpu + 150, cpu + 200); + printf("CPU model: %s %s %s %s @ %s\n", cpu, cpu + 50, cpu + 100, cpu + 150, cpu + 200); + if(err) + printf("get memory info failed: %d(%s)\n", err, strerror(err)); + else + { + printf("Memory total: %s\n", sys_util::format_readable_bytes(total).c_str()); + printf("Memory avail: %s\n", sys_util::format_readable_bytes(avail).c_str()); + } + printf("Page size: %d\n", page); + + return err; + } + + static quit_cmd run_console(cmd_line* cmd, void* param) + { + quit_cmd quit = QUIT_CMD_NONE; + + handle(0, nullptr); + + return quit; + } +} +namespace parse_util +{ + // we assume the console locale is in UTF-8 here ... + static CONSOLE_ROUTINE(print_help) + { + printf("\ +usage: dbl : parse hex-string as double\n\ + fdbl : convert a decimal to inn-code double. command: fdbl -123.456\n\ + fflt : convert a decimal to inn-code float. command: fflt -123.456\n\ + flt : parse hex-string as float\n\ + fstr : convert ansi-string to inn-code\n\ + fuf8 : convert utf8-string to inn-code\n\ + funi : convert unic-string to inn-code\n\ + int : parse hex-string as integer\n\ + str : parse hex-string as ansi-string\n\ + unic : parse hex-string as unicode-16-string\n\ + utf8 : parse hex-string as utf8-string\n\ + exit: to exit this APP\n\ + q: quit process utility\n\ +"); + return QUIT_CMD_NONE; + } + static std::string from_hex_str(const char* hex) + { + const char* h = hex, *t = nullptr; + uint64_t v = sys_util::from_hex_str(h, &t); + char buf[80] = {0}; + int off = 0; + std::string in(""); + + while(t > h) + { + if((t - h) % 2) + v <<= 4; + off = 8; + for(int i = 0; i < (t - h + 1) / 2; ++i, v >>= 8) + buf[--off] = v & 0xff; + in += std::string(buf + off, 8 - off); + h = t; + v = sys_util::from_hex_str(h, &t); + } + in.append(8, '\0'); + + return std::move(in); + } + + static CONSOLE_ROUTINE(as_double) + { + if(cmd->count()) + { + std::string val(from_hex_str(cmd->parameter(0))); + + printf("Result: %f\n", *(double*)&val[0]); + } + else + printf(" dbl \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(from_double) + { + if(cmd->count()) + { + double val = atof(cmd->parameter(0)); + + printf("Result: "); + for(int i = 0; i < sizeof(val); ++i) + printf("%02X", ((uint8_t*)&val)[i]); + printf("\n"); + } + else + printf(" fdbl \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(from_float) + { + if(cmd->count()) + { + float val = atof(cmd->parameter(0)); + + printf("Result: "); + for(int i = 0; i < sizeof(val); ++i) + printf("%02X", ((uint8_t*)&val)[i]); + printf("\n"); + } + else + printf(" fflt \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(as_float) + { + if(cmd->count()) + { + std::string val(from_hex_str(cmd->parameter(0))); + + printf("Result: %f\n", *(float*)&val[0]); + } + else + printf(" flt \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(as_integer) + { + if(cmd->count()) + { + std::string val(from_hex_str(cmd->parameter(0))); + + if(val.length() - 8 <= 4) + { + int n = 0; + if(val.length() - 8 == 1) + n = (char)val[0]; + else if(val.length() - 8 == 2) + n = *(short*)&val[0]; + else + n = *(int*)&val[0]; + printf("Result: %d(%u)\n", n, n); + } + else + printf("Result: %ld\n", *(uint64_t*)&val[0]); + } + else + printf(" int \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(as_ansi_str) + { + if(cmd->count()) + { + std::string val(from_hex_str(cmd->parameter(0))); + + printf("Result: '%s'\n", sys_util::transform_between_gbk_and_utf8(val.c_str(), true).c_str()); + } + else + printf(" str \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(as_unicode) + { + if(cmd->count()) + { + std::string val(from_hex_str(cmd->parameter(0))); + + printf("Result: '%s'\n", sys_util::transform_between_utf16_and_utf8(val.c_str(), val.length(), true).c_str()); + } + else + printf(" unic \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(as_utf8) + { + if(cmd->count()) + { + std::string val(from_hex_str(cmd->parameter(0))); + + printf("Result: '%s'\n", val.c_str()); + } + else + printf(" utf8 \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(from_ansi) + { + if(cmd->count()) + { + std::string val(from_hex_str(cmd->parameter(0))); + + val = sys_util::transform_between_gbk_and_utf8(val.c_str(), false); + printf("Result: "); + for(int i = 0; i < val.length(); ++i) + printf("%02X", (uint8_t)val[i]); + printf("\n"); + } + else + printf(" fstr \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(from_utf8) + { + if(cmd->count()) + { + std::string val(from_hex_str(cmd->parameter(0))); + + printf("Result: "); + for(int i = 0; i < val.length(); ++i) + printf("%02X", (uint8_t)val[i]); + printf("\n"); + } + else + printf(" fuf8 \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(from_unicode) + { + if(cmd->count()) + { + std::string val(from_hex_str(cmd->parameter(0))); + + val = sys_util::transform_between_utf16_and_utf8(val.c_str(), val.length(), false); + printf("Result: "); + for(int i = 0; i < val.length(); ++i) + printf("%02X", (uint8_t)val[i]); + printf("\n"); + } + else + printf(" funi \n"); + + return QUIT_CMD_NONE; + } + + static CONSOLE_ROUTINE(run_console) + { + quit_cmd quit = QUIT_CMD_NONE; + std::string pre_cmd = cmd->to_command_line(); + console_dispatcher me; + + me.add_command_routine("dbl", as_double); + me.add_command_routine("fdbl", from_double); + me.add_command_routine("fflt", from_float); + me.add_command_routine("flt", as_float); + me.add_command_routine("int", as_integer); + me.add_command_routine("str", as_ansi_str); + me.add_command_routine("unic", as_unicode); + me.add_command_routine("utf8", as_utf8); + me.add_command_routine("fstr", from_ansi); + me.add_command_routine("fuf8", from_utf8); + me.add_command_routine("funi", from_unicode); + me.set_unhandled_routine(print_help); + quit = me.run("hgutil-parse", pre_cmd.c_str()); + + return quit == QUIT_CMD_QUIT_ALL ? quit : QUIT_CMD_NONE; + } +} +namespace calculator +{ + static std::string format_readable_integer(uint64_t v, const char* fmt, int align = 4, const char* sep = " ", bool patch = true) + { + char buf[80] = {0}; + std::string ret(""); + + if(strcmp(fmt, "%lb") == 0) + { + while(v) + { + ret.insert(0, v & 1 ? "1" : "0"); + v >>= 1; + } + if(ret.empty()) + ret = "0"; + } + else + { + sprintf(buf, fmt, v); + ret = buf; + } + if(patch && (ret.length() % align)) + { + std::string fill(""); + + fill.append(align, '0'); + ret.insert(0, fill); + ret.erase(0, ret.length() % align); + } + for(int i = ret.length() - align; i > 0; i -= align) + ret.insert(i, sep); + + return std::move(ret); + } + static bool is_valid_double(double v) + { + return isnan(v) == 0; + } + static double pick_decimal(const char*& dec, bool* ok) + { + double sign = 1.0f, radix = 1.0f, val = .0f, coef = 10.0f; + + if(ok) + *ok = true; + if(*dec == '-') + { + sign = -1.0f; + dec++; + } + while(*dec) + { + if(*dec == '.') + { + if(radix < 1.0f) + { + if(ok) + *ok = false; + break; + } + radix = .1f; + coef = 1.0f; + } + else if(*dec == '-') + break; + else if(*dec >= '0' && *dec <= '9') + { + val *= coef; + val += (*dec - '0') * radix; + if(radix < 1.0f) + radix *= .1f; + } + else + break; + dec++; + } + + if(!is_valid_double(val) && ok) + *ok = false; + + return val * sign; + } + static double calc_exp(const char* exp, bool *ok = nullptr) + { + bool good = true; + double val = .0f, sign = 1.0f; + std::string sop(""); + + if(!ok) + ok = &good; + + while(*exp) + { + double hi = .0f; + bool calc = false; + if(*exp == '(') + { + const char* end = sys_util::pick_simple_block(exp, ')'); + if(!end) + { + *ok = false; + printf("Invalid expression: '%s'\n", exp); + break; + } + + std::string sub(exp + 1, end - exp - 1); + + sys_util::trim_left(sub); + sys_util::trim_right(sub); + hi = calc_exp(sub.c_str(), ok); + if(!ok[0]) + break; + + exp = end + 1; + calc = true; + } + else if(*exp == '-') + { + sign = -1.0f; + exp++; + } + else if(*exp == '.' || (*exp >= '0' && *exp <= '9')) + { + // number ... + hi = pick_decimal(exp, ok); + calc = true; + } + + if(!ok[0]) + { + printf("Invalid expression.\n"); + break; + } + if(calc) + { + hi *= sign; + sign = 1.0f; + } + } + + return val; + } + + static CONSOLE_ROUTINE(print_help) + { + printf("\ +usage: acos : perform arccos(num)\n\ + add [... num_n]: perform num1 + num2 + ... + num_n\n\ + asin : perform arcsin(num)\n\ + atan : perform atan(num)\n\ + cos : perform cos(num)\n\ + deg : transform between degree and radian\n\ + div [... num_n]: perform num1 / num2 / ... / num_n\n\ + iam : transfrom between millimeters and inches\n\ + ln : e ^ result = num\n\ + log [base = 10]: base ^ result = num\n\ + mul [... num_n]: perform num1 * num2 * ... * num_n\n\ + paper [paper-type ]: list all paper type, or calculate image size in with given paper and dpi\n\ + pow : calculate base^exp\n\ + radix : print a interger into hex, decimal, oct and binary\n\ + sin : perform sin(num)\n\ + sqrt [exp]: perform base^(1/2), or base^(1/exp)\n\ + sub [... num_n]: perform num1 - num2 - ... - num_n\n\ + tan : perform tan(num)\n\ + exit: to exit this APP\n\ + q: quit process utility\n\ +"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(radix) + { + if(cmd->count()) + { + const char* end = nullptr; + uint64_t v(sys_util::to_int(cmd->parameter(0), &end)); + + if(end == cmd->parameter(0)) + printf("Invalid interger: %s\n", cmd->parameter(0)); + else + { + std::string bin(format_readable_integer(v, "%lX")); + + printf("Hex: %s\n", bin.c_str()); + + bin = format_readable_integer(v, "%ld", 3, ",", false); + printf("Dec: %s\n", bin.c_str()); + + bin = format_readable_integer(v, "%lo", 3); + printf("Oct: %s\n", bin.c_str()); + + bin = format_readable_integer(v, "%lb"); + printf("Bin: %s\n", bin.c_str()); + } + } + else + printf(" radix \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(calculate) + { + std::string exp(cmd->to_command_line()); + double val = .0f; + bool ok = true; + + sys_util::trim_left(exp); + sys_util::trim_right(exp); + val = calc_exp(exp.c_str(), &ok); + if(ok) + printf("Result: %f\n", val); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(add) + { + if(cmd->count() >= 2) + { + const char* para = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(para, &ok), sum = .0f; + int ind = 0; + + while(ok && *para == 0) + { + sum += v; + if(!is_valid_double(sum)) + { + printf("Invalid result when calculate %d data: %s\n", ind + 1, cmd->parameter(ind)); + + return QUIT_CMD_NONE; + } + if(ind + 1 >= cmd->count()) + break; + para = cmd->parameter(++ind); + v = pick_decimal(para, &ok); + } + if(ok && *para == 0) + printf("Result: %f\n", sum); + else + printf("Invalid number: %s\n", cmd->parameter(ind)); + } + else + printf(" add [...num_n]\n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(sub) + { + if(cmd->count() >= 2) + { + const char* para = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(para, &ok), sum = .0f; + int ind = 0; + + while(ok && *para == 0) + { + if(ind == 0) + sum = v; + else + sum -= v; + if(!is_valid_double(sum)) + { + printf("Invalid result when calculate %d data: %s\n", ind + 1, cmd->parameter(ind)); + + return QUIT_CMD_NONE; + } + if(ind + 1 >= cmd->count()) + break; + para = cmd->parameter(++ind); + v = pick_decimal(para, &ok); + } + if(ok && *para == 0) + printf("Result: %f\n", sum); + else + printf("Invalid number: %s\n", cmd->parameter(ind)); + } + else + printf(" sub [...num_n]\n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(mul) + { + if(cmd->count() >= 2) + { + const char* para = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(para, &ok), sum = 1.0f; + int ind = 0; + + while(ok && *para == 0) + { + sum *= v; + if(!is_valid_double(sum)) + { + printf("Invalid result when calculate %d data: %s\n", ind + 1, cmd->parameter(ind)); + + return QUIT_CMD_NONE; + } + if(ind + 1 >= cmd->count()) + break; + para = cmd->parameter(++ind); + v = pick_decimal(para, &ok); + } + if(ok && *para == 0) + printf("Result: %f\n", sum); + else + printf("Invalid number: %s\n", cmd->parameter(ind)); + } + else + printf(" add [...num_n]\n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(div) + { + if(cmd->count() >= 2) + { + const char* para = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(para, &ok), sum = .0f; + int ind = 0; + + while(ok && *para == 0) + { + if(ind == 0) + sum = v; + else + sum /= v; + if(!is_valid_double(sum)) + { + printf("Invalid result when calculate %d data: %s\n", ind + 1, cmd->parameter(ind)); + + return QUIT_CMD_NONE; + } + if(ind + 1 >= cmd->count()) + break; + para = cmd->parameter(++ind); + v = pick_decimal(para, &ok); + } + if(ok && *para == 0) + printf("Result: %f\n", sum); + else + printf("Invalid number: %s\n", cmd->parameter(ind)); + } + else + printf(" sub [...num_n]\n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(inch_and_mm) + { + if(cmd->count()) + { + const char* oper = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(oper, &ok); + + if(*oper == 0 && ok) + { + printf("%fmm = %finch\n", v, v / MM_PER_INCH); + printf("%finch = %fmm\n", v, v * MM_PER_INCH); + } + else + printf("Invalid number: %s\n", cmd->parameter(0)); + } + else + printf(" iam \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(func_log) + { + if(cmd->count()) + { + const char* oper = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(oper, &ok), vb = 10.0f; + + if(*oper == 0 && ok && v > .0f) + { + if(cmd->count() >= 2) + { + oper = cmd->parameter(1); + vb = pick_decimal(oper, &ok); + if(*oper || !ok || vb <= .0f) + { + printf("Invalid number: %s\n", cmd->parameter(1)); + return QUIT_CMD_NONE; + } + } + printf("Result: %f\n", log(v) / log(vb)); + } + else + printf("Invalid number: %s\n", cmd->parameter(0)); + } + else + printf(" log \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(func_ln) + { + if(cmd->count()) + { + const char* oper = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(oper, &ok); + + if(*oper == 0 && ok && v > .0f) + { + printf("Result: %f\n", log(v) / log(CONST_E)); + } + else + printf("Invalid number: %s\n", cmd->parameter(0)); + } + else + printf(" log \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(func_degree) + { + if(cmd->count()) + { + const char* oper = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(oper, &ok); + + if(*oper == 0 && ok) + { + printf("%f degree = %f radian\n", v, v / 180.0f * CONST_PI); + printf("%f radian = %f degree\n", v, v / CONST_PI * 180.0f); + } + else + printf("Invalid number: %s\n", cmd->parameter(0)); + } + else + printf(" deg \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(func_sin) + { + if(cmd->count()) + { + const char* oper = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(oper, &ok); + + if(*oper == 0 && ok) + { + printf("Result in degree: %f\n", sin(v / 180.0f * CONST_PI)); + printf("Result in radian: %f\n", sin(v)); + } + else + printf("Invalid number: %s\n", cmd->parameter(0)); + } + else + printf(" sin \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(func_cos) + { + if(cmd->count()) + { + const char* oper = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(oper, &ok); + + if(*oper == 0 && ok) + { + printf("Result in degree: %f\n", cos(v / 180.0f * CONST_PI)); + printf("Result in radian: %f\n", cos(v)); + } + else + printf("Invalid number: %s\n", cmd->parameter(0)); + } + else + printf(" cos \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(func_tan) + { + if(cmd->count()) + { + const char* oper = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(oper, &ok); + + if(*oper == 0 && ok) + { + printf("Result in degree: %f\n", tan(v / 180.0f * CONST_PI)); + printf("Result in radian: %f\n", tan(v)); + } + else + printf("Invalid number: %s\n", cmd->parameter(0)); + } + else + printf(" tan \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(func_asin) + { + if(cmd->count()) + { + const char* oper = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(oper, &ok); + + if(*oper == 0 && ok && v >= -1.0f && v <= 1.0f) + { + printf("Result in degree: %f\n", asin(v) / CONST_PI * 180.0f); + printf("Result in radian: %f\n", asin(v)); + } + else + printf("Invalid number: %s\n", cmd->parameter(0)); + } + else + printf(" asin \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(func_acos) + { + if(cmd->count()) + { + const char* oper = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(oper, &ok); + + if(*oper == 0 && ok && v >= -1.0f && v <= 1.0f) + { + printf("Result in degree: %f\n", acos(v) / CONST_PI * 180.0f); + printf("Result in radian: %f\n", acos(v)); + } + else + printf("Invalid number: %s\n", cmd->parameter(0)); + } + else + printf(" acos \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(func_atan) + { + if(cmd->count()) + { + const char* oper = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(oper, &ok); + + if(*oper == 0 && ok && v >= -1.0f && v <= 1.0f) + { + printf("Result in degree: %f\n", atan(v) / CONST_PI * 180.0f); + printf("Result in radian: %f\n", atan(v)); + } + else + printf("Invalid number: %s\n", cmd->parameter(0)); + } + else + printf(" atan \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(paper) + { + struct + { + std::string type; + float w; + float h; + }papers[] = { + {"A3", 297.0, 420.0}, + {"A4", 210.0, 297.0}, + {"A5", 148.0, 210.0}, + {"A6", 105.0, 148.0}, + {"B4", 257.0, 364.0}, + {"B5", 182.0, 257.0}, + {"JIS-B5", 176.0, 250.0}, + {"B6", 125.0, 176.0} + }; + if(cmd->count() == 0) + { + printf("Paper-type\tSize (mm)\n"); + for(auto& v: papers) + printf(" %s %f * %f\n", v.type.c_str(), v.w, v.h); + } + else + { + bool help = true; + if(cmd->count() >= 2) + { + const char* str = cmd->parameter(1); + bool ok = true; + double dpi = pick_decimal(str, &ok); + + if(ok && *str == 0 && dpi > .0f) + { + for(auto& v: papers) + { + if(v.type == cmd->parameter(0)) + { + double w = v.w / MM_PER_INCH * dpi + .999f, + h = v.h / MM_PER_INCH * dpi + .999f; + printf("Paper '%s' in DPI(%f) image size(pixel): %d * %d\n", v.type.c_str(), dpi, (int)w, (int)h); + help = false; + break; + } + } + } + else + { + printf("Invalid DPI: %s\n", cmd->parameter(1)); + help = false; + } + } + if(help) + { + printf(" paper [paper-type ]. paper type now support following:\n "); + for(auto& v: papers) + printf("%s ", v.type.c_str()); + printf("\n"); + } + } + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(func_pow) + { + if(cmd->count() >= 2) + { + const char* oper = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(oper, &ok), e = .0f; + + if(*oper == 0 && ok) + { + oper = cmd->parameter(1); + e = pick_decimal(oper, &ok); + if(*oper == 0 && ok) + { + printf("Result: %f\n", pow(v, e)); + } + else + printf("Invalid number: %s\n", cmd->parameter(1)); + } + else + printf("Invalid number: %s\n", cmd->parameter(0)); + } + else + printf(" pow \n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(func_sqrt) + { + if(cmd->count()) + { + const char* oper = cmd->parameter(0); + bool ok = true; + double v = pick_decimal(oper, &ok), e = .5f; + + if(*oper == 0 && ok) + { + if(cmd->count() >= 2) + { + oper = cmd->parameter(1); + e = pick_decimal(oper, &ok); + if(*oper == 0 && ok && !IS_EQUAL(e, .0f)) + { + e = 1.0f / e; + } + else + { + ok = false; + printf("Invalid number: %s\n", cmd->parameter(1)); + } + } + if(ok) + printf("Result: %f\n", pow(v, e)); + } + else + printf("Invalid number: %s\n", cmd->parameter(0)); + } + else + printf(" sqrt [exp]\n"); + + return QUIT_CMD_NONE; + } + + static CONSOLE_ROUTINE(run_console) + { + quit_cmd quit = QUIT_CMD_NONE; + std::string pre_cmd = cmd->to_command_line(); + console_dispatcher me; + + me.add_command_routine("add", add); + me.add_command_routine("sub", sub); + me.add_command_routine("mul", mul); + me.add_command_routine("div", div); + me.add_command_routine("iam", inch_and_mm); + me.add_command_routine("ln", func_ln); + me.add_command_routine("log", func_log); + me.add_command_routine("deg", func_degree); + me.add_command_routine("cos", func_cos); + me.add_command_routine("sin", func_sin); + me.add_command_routine("tan", func_tan); + me.add_command_routine("acos", func_acos); + me.add_command_routine("asin", func_asin); + me.add_command_routine("atan", func_atan); + me.add_command_routine("paper", paper); + me.add_command_routine("radix", radix); + me.add_command_routine("pow", func_pow); + me.add_command_routine("sqrt", func_sqrt); + me.set_unhandled_routine(print_help); + quit = me.run("hgutil-calc", pre_cmd.c_str()); + + return quit == QUIT_CMD_QUIT_ALL ? quit : QUIT_CMD_NONE; + } + +} + +namespace top +{ + static CONSOLE_ROUTINE(print_help); + static CONSOLE_ROUTINE(clear_screen); + static CONSOLE_ROUTINE(quit_me); + static CONSOLE_ROUTINE(quit_all); + static CONSOLE_ROUTINE(system_call); + static CONSOLE_ROUTINE(recursive_file_oper); + static CONSOLE_ROUTINE(error_message); +}; + +namespace usb +{ + struct { + int vid; + int pid; +}g_scanner[] = { + {0x31c9, 0x8200}, + {0x31c9, 0x8420}, + {0x31c9, 0x8429}, + {0x31c9, 0x8520}, + {0x31c9, 0x8529}, + {0x31c9, 0x8620}, + {0x31c9, 0x8629}, + {0x31c9, 0x8730}, + {0x31c9, 0x8739}, + {0x2903, 0x1000}, + {0x2903, 0x1002}, + {0x2903, 0x7000}, + {0x2903, 0x7002}, + {0x2903, 0x7039}, + {0x2903, 0x8000}, + {0x2903, 0x9000}, + {0x3308, 0x6006}, + {0x3308, 0x6005}, + {0x3308, 0x0238}, + {0x3308, 0x0138}, + {0X05DA, 0x9220}, + {0x3072, 0x100}, + {0x3072, 0x139}, + {0x3072, 0x200}, + {0x3072, 0x239}, + {0x3072, 0x300}, + {0x3072, 0x302}, + {0x3072, 0x339}, + {0x3072, 0x400}, + {0x3072, 0x402}, + {0x3072, 0x439}, + {0x064B, 0x7823} +}; + typedef struct _usb_device_que + { + int vid = 0; + int pid = 0; + libusb_device* device = nullptr; + usb_io* io = nullptr; + + bool operator==(const libusb_device* dev) + { + return dev == device; + } + }USBDEVQ, *LPUSBDEVQ; + std::vector devs_; + std::mutex dev_lock_; + + void usb_event_function(usb_event ev, libusb_device* device, int vid, int pid, int usb_ver_h, int usb_ver_l, bool* retry, void* user) // usb_ver_h.usb_ver_l + { + std::lock_guard lock(dev_lock_); + std::vector::iterator it = std::find(devs_.begin(), devs_.end(), device); + + if (USB_EVENT_DEVICE_ARRIVED == ev) + { + if(it == devs_.end()) + { + USBDEVQ dev; + dev.vid = vid; + dev.pid = pid; + dev.device = device; + devs_.push_back(dev); + } + else + { + it->vid = vid; + it->pid = pid; + } + } + else if (USB_EVENT_DEVICE_LEFT == ev) + { + if(it != devs_.end()) + { + if(it->io) + it->io->release(); + devs_.erase(it); + } + } + } + static bool is_scanner(int vid, int pid) + { + for(auto& v: g_scanner) + { + if(v.vid == vid && v.pid == pid) + return true; + } + + return false; + } + static void resolve(USBDEVQ& dev) + { + std::string msg(""); + usb_io* io = nullptr; + int err = usb_manager::instance()->open(dev.device, &io, &msg); + + if(err) + { + printf(" Open failed: %d - %s\n", dev.vid, dev.pid, err, msg.c_str()); + printf(" To resolve this device, try RESTART it!\n\n"); + if(io) + io->release(); + + return; + } + + int size = 1024 * 1024, + len = size, + total = 0; + char *buf = new char[size]; + + io->set_timeout(100); + printf(" First: Clear bulk end-point ..."); + while((err = io->read_bulk(buf, &len)) == 0) + { + total += len; + len = size; + } + printf(" %d byte(s) cleared with last error(%d).\n", total, err); + + printf(" Second: Clear interrupt end-point ..."); + total = 0; + len = size; + io->set_timeout(100); + while((err = io->read_interrupt(buf, &len)) == 0) + { + total += len; + len = size; + } + printf(" %d byte(s) cleared with last error(%d).\n", total, err == SCANNER_ERR_TIMEOUT ? 0 : err); + + // try get SN: + printf(" Last: try get serial number ... "); + total = sizeof(len); + len = 0; + err = io->control_io(0x40, 0x64, 18, 0, &len, &total); + if(err == SCANNER_ERR_TIMEOUT) + { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + err = io->control_io(0x40, 0x64, 18, 0, &len, &total); + } + if(err) + printf("write command failed: %d\n", err); + else + { + len = size; + err = io->read_bulk(buf, &len); + buf[len] = 0; + printf("%s (%d)\n", buf, err == SCANNER_ERR_TIMEOUT ? 0 : err); + } + delete[] buf; + printf("\n"); + + io->release(); + } + + static CONSOLE_ROUTINE(print_help) + { + printf("\ +usage: trouble: to resolve problem with HGs scanner\n\ + lsusb: to print all USB devices\n\ + exit: to exit this APP\n\ + q: quit process utility\n\ +"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(trouble) + { + std::lock_guard lock(dev_lock_); + int cnt = 0; + for(auto& v : devs_) + { + if(!is_scanner(v.vid, v.pid)) + continue; + + printf(" %d: Resolve %04X:%04X ...\n", ++cnt, v.vid, v.pid); + resolve(v); + } + if(cnt == 0) + printf(" No scanner found!\n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(list_usb) + { + std::lock_guard lock(dev_lock_); + int cnt = 0; + + for(auto& v : devs_) + printf(" %d: %04X:%04X\n", ++cnt, v.vid, v.pid); + if(cnt == 0) + printf(" No USB device found!\n"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(usb_tool) + { + usb_manager::instance()->register_hotplug(&usb_event_function, nullptr); + + console_dispatcher me; + + me.add_command_routine("trouble", &trouble); + me.add_command_routine("lsusb", &list_usb); + me.set_unhandled_routine(print_help); + + quit_cmd ret = me.run("hgutil-usb"); + + return ret == QUIT_CMD_QUIT_ALL ? ret : QUIT_CMD_NONE; + } +} + +int32_t main(int32_t argc, char *argv[]) +{ + // hgutil -proc + int err = 0; + + console_dispatcher::add_supper_command_routine("clear", &top::clear_screen); + console_dispatcher::add_supper_command_routine("exit", &top::quit_all); + console_dispatcher::add_supper_command_routine("q", &top::quit_me); + console_dispatcher::add_supper_command_routine("sys", &top::system_call); + console_dispatcher::add_supper_command_routine("errm", &top::error_message); + + console_dispatcher top; + + top.add_command_routine("proc", proc_util::run_console); + top.add_command_routine("kobj", kernel_obj::run_console); + top.add_command_routine("mem", mem_util::run_console); + top.add_command_routine("parse", parse_util::run_console); + top.add_command_routine("calc", calculator::run_console); + top.add_command_routine("recf", top::recursive_file_oper); + top.add_command_routine("usb", usb::usb_tool); + top.set_unhandled_routine(top::print_help); + top.run("hgutil"); + + return 0; +} + +namespace top +{ + static CONSOLE_ROUTINE(print_help) + { + printf("\ +usage: calc: calculator utility\n\ + clear: clear screen\n\ + errm: print error message of 'err-no'\n\ + kobj: named kernel objects(shared memory, event...) utility\n\ + mem: memory utility\n\ + parse: parse inner-code as readable target\n\ + proc: process utilities\n\ + recf: recursive execute system command on files\n\ + usb : usb utilities\n\ + q: exit\n\ + sys: invoke system command\n\n\ +"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(clear_screen) + { + system("clear"); + + return QUIT_CMD_NONE; + } + static CONSOLE_ROUTINE(quit_me) + { + return QUIT_CMD_QUIT_ME; + } + static CONSOLE_ROUTINE(quit_all) + { + return QUIT_CMD_QUIT_ALL; + } + static CONSOLE_ROUTINE(system_call) + { + std::string cmdl(cmd->to_command_line()); + + system(cmdl.c_str()); + + return QUIT_CMD_NONE; + } + + bool is_wildcard_match(const char* str, const char* pattern, int str_len, int patt_len) + { + int str_ind = 0, pattern_ind = 0, star = -1, m = 0; + + if (str_len == -1) + str_len = strlen(str); + if (patt_len == -1) + patt_len = strlen(pattern); + while (str_ind < str_len) + { + if (pattern_ind < patt_len && (str[str_ind] == pattern[pattern_ind] || pattern[pattern_ind] == '?')) + { + str_ind++; + pattern_ind++; + } + else if (pattern_ind < patt_len && pattern[pattern_ind] == '*') + { + star = pattern_ind++; + m = str_ind; + } + else if (star != -1) + { + pattern_ind = star + 1; + str_ind = ++m; + } + else + return false; + } + while (pattern_ind < patt_len && pattern[pattern_ind] == '*') + pattern_ind++; + + return pattern_ind == patt_len; + } + static bool is_match(const char* val, const char* pattern) + { + if(strstr(pattern, "*")) + { + return is_wildcard_match(val, pattern, strlen(val), strlen(pattern)); + } + else + { + return strcmp(val, pattern) == 0; + } + } + static bool on_file_found(const char* path, bool is_dir, void* param) + { + if(is_dir) + return true; + struct + { + std::string pattern; + std::string syscmd; + }*para = nullptr; + const char* name = strrchr(path, '/'); + + if(name++ == nullptr) + name = path; + *((void**)¶) = param; + if(is_match(name, para->pattern.c_str())) + { + std::string cmd(para->syscmd), file(path); + size_t pos = cmd.find("%s"); + + if(file.find(" ") != std::string::npos) + { + file += "\""; + file.insert(0, "\""); + } + cmd.replace(pos, 2, file); + printf(" %s = %d\n", cmd.c_str(), system(cmd.c_str())); + } + + return true; + } + static CONSOLE_ROUTINE(recursive_file_oper) + { + // recf + bool help = true; + + if(cmd->count() > 3) + { + std::string path(cmd->parameter(0)), + file(cmd->parameter(1)), + syscmd(""); + struct + { + std::string pattern; + std::string syscmd; + }para; + + + cmd->remove(0); + cmd->remove(0); + para.syscmd = cmd->to_command_line(); + para.pattern = std::move(file); + help = para.syscmd.find("%s") == std::string::npos; + + if(!help) + sys_util::enum_files(path.c_str(), on_file_found, ¶); + } + if(help) + { + printf(" recf \n"); + } + + return QUIT_CMD_NONE; + } + + static CONSOLE_ROUTINE(error_message) + { + if(cmd->count()) + { + printf(" error %d: %s\n", atoi(cmd->parameter(0)), strerror(atoi(cmd->parameter(0)))); + } + else + { + printf(" errm \n"); + } + + return QUIT_CMD_NONE; + } +}; + diff --git a/usb_manager.cpp b/usb_manager.cpp new file mode 100644 index 0000000..8273c62 --- /dev/null +++ b/usb_manager.cpp @@ -0,0 +1,1162 @@ +#include "usb_manager.h" +#include + +#define IF_CLASS(code, cls) \ + if(code == cls) \ + return #cls; + +#if defined(WIN32) || defined(_WIN64) +#include "scanner_manager.h" +#else +void memset(void* buf, unsigned char fill, int len) +{ + unsigned char* data = (unsigned char*)buf; + while (len-- > 0) + *data++ = fill; +} +#endif + +usb_manager* usb_manager::inst_ = NULL; +uint8_t usb_manager::uninit_uint8 = 0x0ff; + +usb_manager::usb_manager() : run_(true) + , usb_cb_handle_(NULL) + , usb_cb_(&usb_manager::usb_event_handle), usb_cb_param_(NULL) + , context_(NULL), status_(SCANNER_ERR_OK) + , born_(std::chrono::system_clock::now()) +{ + int ret = libusb_init(&context_); + + // libusb_set_log_cb(context_, &usb_manager::usb_log_callback, LIBUSB_LOG_CB_CONTEXT); // LIBUSB_API_VERSION >= 0x01000107 + // VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "usb_manager(%s) libusb_init(%s) = %s, context = %s\n", hg_log::format_ptr(this).c_str(), hg_log::format_ptr(&context_).c_str(), libusb_error_name(ret), hg_log::format_ptr(context_).c_str()); + if (ret) + status_ = SCANNER_ERR_USB_INIT_FAILED; + + wait_pnp_.set_debug_info("Waiting PNP"); + if (!usb_notify_thread_.get()) + { + run_ = true; + usb_notify_thread_.reset(new std::thread(&usb_manager::thread_notify_usb_event, this)); + } +} +usb_manager::~usb_manager() +{ + run_ = false; + wait_pnp_.notify(); + libusb_context* ctx = nullptr; +#if defined(WIN32) || defined(_WIN64) + ctx = context_; + libusb_quit(ctx); +#endif + if(usb_cb_handle_) + libusb_hotplug_deregister_callback(ctx, usb_cb_handle_); + if (usb_monitor_thread_.get() && usb_monitor_thread_->joinable()) + { + usb_monitor_thread_->join(); + usb_monitor_thread_.reset(); + } + if (usb_notify_thread_.get() && usb_notify_thread_->joinable()) + { + usb_notify_thread_->join(); + usb_notify_thread_.reset(); + } + libusb_exit(context_); + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "usb_manager(%s) destroying and free context(%s)\n", hg_log::format_ptr(this).c_str(), hg_log::format_ptr(context_).c_str()); +} + +int LIBUSB_CALL usb_manager::usb_pnp_callback(libusb_context* ctx, libusb_device* device, libusb_hotplug_event event, void* monitor) +{ + usb_manager* obj = (usb_manager*)monitor; + +// if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) + libusb_ref_device(device); // keep the object until handle it + //else if(event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) + // libusb_unref_device(device); + + return obj->on_usb_pnp_event(ctx, device, event); +} +void usb_manager::usb_event_handle(usb_event ev, libusb_device* device, int vid, int pid, int usb_ver_h, int usb_ver_l, bool* retry, void* user) // usb_ver_h.usb_ver_l +{ + +} +void usb_manager::usb_log_callback(libusb_context* ctx, libusb_log_level level, const char* str) +{ + // used when LIBUSB_API_VERSION >= 0x01000107 + // if (level == LIBUSB_LOG_LEVEL_NONE || LIBUSB_LOG_LEVEL_INFO || LIBUSB_LOG_LEVEL_DEBUG) + // { + // LOG_INFO(LOG_LEVEL_DEBUG_INFO, str); + // } + // else + // { + // LOG_INFO(LOG_LEVEL_FATAL, str); + // } +} + +int usb_manager::register_usb_pnp(void) +{ + libusb_context* ctx = nullptr; +#if defined(WIN32) || defined(_WIN64) + ctx = context_; +#endif + int ret = libusb_hotplug_register_callback(ctx, (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), + (libusb_hotplug_flag)LIBUSB_HOTPLUG_ENUMERATE, + LIBUSB_HOTPLUG_MATCH_ANY,//LIBUSB_HOTPLUG_MATCH_ANY + LIBUSB_HOTPLUG_MATCH_ANY,//LIBUSB_HOTPLUG_MATCH_ANY, + LIBUSB_HOTPLUG_MATCH_ANY, + &usb_manager::usb_pnp_callback, + this, + &usb_cb_handle_); + + if (ret != LIBUSB_SUCCESS) + { + //LOG_INFO(LOG_LEVEL_FATAL, (std::string("regist usbhotplug callback error msg: ") + libusb_error_name(ret) + "\n").c_str()); + usb_cb_handle_ = NULL; + status_ = SCANNER_ERR_USB_REGISTER_PNP_FAILED; + } + else + status_ = SCANNER_ERR_OK; + + return ret; +} +void usb_manager::init_notify_thread() +{ + if(!usb_monitor_thread_.get()) + { + usb_monitor_thread_.reset(new std::thread(&usb_manager::thread_trigger_usb_event, this)); + } + +} +void usb_manager::fake_usb_pnp(std::vector& devices) +{ + libusb_device** devs = NULL; + libusb_get_device_list(context_, &devs); + if (devs) + { + std::vector current; + + // handle arrived ... + for (int ind = 0; devs[ind]; ++ind) + { + std::vector::iterator it + = std::find(devices.begin(), devices.end(), devs[ind]); + if (it == devices.end()) + { + current.push_back(devs[ind]); + on_usb_pnp_event(context_, devs[ind], LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED); + } + } + + // handle left ... + for (int ind = 0; ind < devices.size(); ++ind) + { + std::vector::iterator it + = std::find(current.begin(), current.end(), devices[ind]); + if (it == current.end()) + { + on_usb_pnp_event(context_, devices[ind], LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT); + } + } + devices = current; + libusb_free_device_list(devs, 0); + } +} +void usb_manager::thread_notify_usb_event() +{ + while (run_) + { + if (!wait_pnp_.wait()) + continue; + + if (!run_) + break; + + + int delay = 50; // milliseconds ... + while (pnp_events_.Size() && run_) + { + PNPDEV pd = pnp_events_.Take(); + bool retry = false; + + if (pd.event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) + { + unsigned ms = std::chrono::duration_cast(std::chrono::system_clock::now() - pd.happen_time).count(); + if (ms < delay) + { + this_thread::sleep_for(chrono::milliseconds(delay)); + } + } + + notify_usb_event(pd, &retry); + if (retry) + { + if(std::chrono::duration_cast(std::chrono::system_clock::now() - pd.happen_time).count() + <= 5000) + pnp_events_.Put(pd, sizeof(pd)); + if(pnp_events_.Size() == 1) + this_thread::sleep_for(chrono::milliseconds(1000)); + else + this_thread::sleep_for(chrono::milliseconds(delay)); + } + } + } +} +void usb_manager::notify_usb_event(PNPDEV& pd, bool* retry) +{ + usb_event ev = USB_EVENT_NULL; + usb_dev ud; + bool re_try = false; + + std::string evstr(""); + usb_manager::get_device_info(pd.dev, &ud); + ud.contex = pd.ctx; + if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == pd.event) + { + ev = USB_EVENT_DEVICE_ARRIVED; + evstr = "USB_EVENT_DEVICE_ARRIVED"; + } + else if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == pd.event) + { + ev = USB_EVENT_DEVICE_LEFT; + evstr = "USB_EVENT_DEVICE_LEFT"; + } + else + { + char buf[20]; + sprintf(buf, "0x%x", pd.event); + evstr = buf; + } + // VLOG_MINI_5(LOG_LEVEL_DEBUG_INFO, "USB%u.%x of pid:vid(%x:%x) event(%s) received.\n" + // , HIBYTE(ud.ver), LOBYTE(ud.ver) / 0x10, ud.pid, ud.vid, evstr.c_str()); + if (ev != USB_EVENT_NULL) + { + if (!retry) + retry = &re_try; + usb_cb_(ev, pd.dev, ud.vid, ud.pid, HIBYTE(ud.ver), LOBYTE(ud.ver) / 0x10, retry, usb_cb_param_); + } + libusb_unref_device(pd.dev); // response for libusb_ref_device in usb_manager::usb_pnp_callback +} +void usb_manager::thread_trigger_usb_event() +{ + if (!usb_cb_handle_) + { + // we try manually find device here + int times = 10, elapse_max = 60 * 2, elapse = elapse_max; + std::vector devices; + + while (run_) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + + // simulate PNP events ... + fake_usb_pnp(devices); + + // retry register pnp ... + if (--elapse == 0 && --times > 0) + { + elapse_max *= 2; + elapse = elapse_max; + if (register_usb_pnp() == LIBUSB_SUCCESS) + { + // ^_^ + devices.clear(); + // LOG_INFO(LOG_LEVEL_DEBUG_INFO, "register_usb_pnp success ^_^\n"); + break; + } + } + } + } + + while(run_) + { + timeval tm={1,0}; + int ret=libusb_handle_events_timeout(context_, &tm); + // if(ret < 0) + // LOG_INFO(LOG_LEVEL_FATAL, (std::string("libusb_handle_events_timeout error ") + libusb_error_name(ret) + "\n").c_str()); + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } +} +int usb_manager::on_usb_pnp_event(libusb_context *ctx, libusb_device *device, libusb_hotplug_event event) +{ + PNPDEV pd; + unsigned ms = std::chrono::duration_cast(std::chrono::system_clock::now() - born_).count(); + + pd.ctx = ctx; + pd.dev = device; + pd.event = event; + pd.happen_time = std::chrono::system_clock::now(); + if (ms > 1000) + { + pnp_events_.Put(pd, sizeof(pd)); + wait_pnp_.notify(); + } + else + { + bool retry = false; + notify_usb_event(pd, &retry); + if(retry) + pnp_events_.Put(pd, sizeof(pd)); + } + + return 0; +} + +usb_manager* usb_manager::instance(void) +{ + if (usb_manager::inst_ == NULL) + usb_manager::inst_ = new usb_manager(); + + return usb_manager::inst_; +} +void usb_manager::clear(void) +{ + if (usb_manager::inst_) + { + delete usb_manager::inst_; + usb_manager::inst_ = NULL; + } +} +int usb_manager::usb_error_2_hg_err(int usb_err) +{ + if (usb_err == LIBUSB_ERROR_TIMEOUT) + return SCANNER_ERR_TIMEOUT; + else if (usb_err == LIBUSB_ERROR_PIPE) + return SCANNER_ERR_IO; + else if (usb_err == LIBUSB_ERROR_NO_DEVICE) + return SCANNER_ERR_DEVICE_NOT_FOUND; + else if (usb_err == LIBUSB_ERROR_BUSY) + return SCANNER_ERR_DEVICE_BUSY; + else if (usb_err == LIBUSB_ERROR_INVALID_PARAM) + return SCANNER_ERR_INVALID_PARAMETER; + else if (usb_err == LIBUSB_ERROR_OVERFLOW) + return SCANNER_ERR_OUT_OF_RANGE; + else if (usb_err == LIBUSB_ERROR_NO_MEM) + return SCANNER_ERR_INSUFFICIENT_MEMORY; + else if (usb_err == LIBUSB_ERROR_ACCESS) + return SCANNER_ERR_ACCESS_DENIED; + else if (usb_err < 0) + return (scanner_err)usb_err; + else + return SCANNER_ERR_OK; + +} +void usb_manager::init_endpoint(USBENDP* uep) +{ + uep->in.port = uep->out.port = usb_manager::uninit_uint8; + uep->in.iface = uep->out.iface = usb_manager::uninit_uint8; + uep->in.iconf = uep->out.iconf = usb_manager::uninit_uint8; + uep->in.claimed = uep->out.claimed = 0; + uep->in.max_packet = uep->out.max_packet = 0; +} +std::string usb_manager::device_class(libusb_class_code code) +{ + IF_CLASS(code, LIBUSB_CLASS_PER_INTERFACE); + IF_CLASS(code, LIBUSB_CLASS_AUDIO); + IF_CLASS(code, LIBUSB_CLASS_COMM); + IF_CLASS(code, LIBUSB_CLASS_HID); + IF_CLASS(code, LIBUSB_CLASS_PHYSICAL); + IF_CLASS(code, LIBUSB_CLASS_IMAGE); + IF_CLASS(code, LIBUSB_CLASS_PRINTER); + IF_CLASS(code, LIBUSB_CLASS_MASS_STORAGE); + IF_CLASS(code, LIBUSB_CLASS_HUB); + IF_CLASS(code, LIBUSB_CLASS_DATA); + IF_CLASS(code, LIBUSB_CLASS_SMART_CARD); + IF_CLASS(code, LIBUSB_CLASS_CONTENT_SECURITY); + IF_CLASS(code, LIBUSB_CLASS_VIDEO); + IF_CLASS(code, LIBUSB_CLASS_PERSONAL_HEALTHCARE); + IF_CLASS(code, LIBUSB_CLASS_DIAGNOSTIC_DEVICE); + IF_CLASS(code, LIBUSB_CLASS_WIRELESS); + //IF_CLASS(code, LIBUSB_CLASS_MISCELLANEOUS); + IF_CLASS(code, LIBUSB_CLASS_APPLICATION); + IF_CLASS(code, LIBUSB_CLASS_VENDOR_SPEC); + + char buf[40]; + + sprintf(buf, "unknown class: %d", code); + + return buf; +} +std::string usb_manager::endpoint_type(libusb_transfer_type type) +{ + IF_CLASS(type, LIBUSB_TRANSFER_TYPE_CONTROL); + IF_CLASS(type, LIBUSB_TRANSFER_TYPE_ISOCHRONOUS); + IF_CLASS(type, LIBUSB_TRANSFER_TYPE_BULK); + IF_CLASS(type, LIBUSB_TRANSFER_TYPE_INTERRUPT); + IF_CLASS(type, LIBUSB_TRANSFER_TYPE_BULK_STREAM); + + char buf[40]; + + sprintf(buf, "unknown type: %d", type); + + return buf; +} +bool usb_manager::get_device_info(libusb_device* device, usb_dev* devinfo) +{ + libusb_device_descriptor descriptor; + int ret = libusb_get_device_descriptor(device, &descriptor); + + if (ret != LIBUSB_SUCCESS) + return false; + + devinfo->device = device; + devinfo->ver = descriptor.bcdUSB; + devinfo->vid = descriptor.idVendor; + devinfo->pid = descriptor.idProduct; + devinfo->addr = 0; // libusb_get_device_address(device); - initialize at open + + return true; +} +int usb_manager::enum_endpoints(libusb_device* device, USBTRANSENDP* endp) +{ + libusb_device_descriptor desc; + libusb_config_descriptor *conf = NULL; + // std::string dev(hg_log::format_ptr(device)); + int ret = libusb_get_device_descriptor(device, &desc), eps = 0; + bool found_ep = false; + + if (ret != 0) + { + //LOG_INFO(LOG_LEVEL_WARNING, (std::string("Get device descriptor of device(") + dev + ") failed.\n").c_str()); + + return eps; + } + + if (endp) + { + usb_manager::init_endpoint(&endp->bulk); + usb_manager::init_endpoint(&endp->bulk_stream); + usb_manager::init_endpoint(&endp->control); + usb_manager::init_endpoint(&endp->interrupt); + usb_manager::init_endpoint(&endp->isochronous); + } + //else + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " +Device(%s) has %u configurations ...\n", dev.c_str(), desc.bNumConfigurations); + for (int i = 0; i < (int)desc.bNumConfigurations; ++i) + { + ret = libusb_get_config_descriptor(device, i, &conf); + if (ret != 0) + { + //if (!endp) + // VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, " Get %d configuration failed.\n", i + 1); + continue; + } + //if (!endp) + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " Configuration %d has %d interfaces\n", i + 1, conf->bNumInterfaces); + for (int j = 0; j < conf->bNumInterfaces; ++j) + { + // if (!endp) + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " Interface %d has %d alt-settings\n", j + 1, conf->interface[j].num_altsetting); + for (int k = 0; k < conf->interface[j].num_altsetting; ++k) + { + // if (!endp) + // VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, " Setting %d: %d - %s has %d endpoints\n", k + 1, conf->interface[j].altsetting[k].bInterfaceNumber + // , usb_manager::device_class((libusb_class_code)conf->interface[j].altsetting[k].bInterfaceClass).c_str() + // , conf->interface[j].altsetting[k].bNumEndpoints); + for (int l = 0; l < conf->interface[j].altsetting[k].bNumEndpoints; ++l) + { + eps++; + if (endp) + { + USBENDP* ep = NULL; + + if (conf->interface[j].altsetting[k].endpoint[l].bmAttributes == LIBUSB_TRANSFER_TYPE_CONTROL) + { + // VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Found endpoint(%x) for device(VID: %x, PID: %x) of control\n", conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress, desc.idVendor, desc.idProduct); + ep = &endp->control; + } + else if (conf->interface[j].altsetting[k].endpoint[l].bmAttributes == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) + { + // VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Found endpoint(%x) for device(VID: %x, PID: %x) of isochronous\n", conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress, desc.idVendor, desc.idProduct); + ep = &endp->isochronous; + } + if (conf->interface[j].altsetting[k].endpoint[l].bmAttributes == LIBUSB_TRANSFER_TYPE_BULK) + { + // VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Found endpoint(%x) for device(VID: %x, PID: %x) of bulk\n", conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress, desc.idVendor, desc.idProduct); + ep = &endp->bulk; + } + if (conf->interface[j].altsetting[k].endpoint[l].bmAttributes == LIBUSB_TRANSFER_TYPE_INTERRUPT) + { + // VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Found endpoint(%x) for device(VID: %x, PID: %x) of interrupt\n", conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress, desc.idVendor, desc.idProduct); + ep = &endp->interrupt; + } + if (conf->interface[j].altsetting[k].endpoint[l].bmAttributes == LIBUSB_TRANSFER_TYPE_BULK_STREAM) + { + // VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Found endpoint(%x) for device(VID: %x, PID: %x) of bulk-stream\n", conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress, desc.idVendor, desc.idProduct); + ep = &endp->bulk_stream; + } + if (ep) + { + USBSIMPLEX* s = NULL; + if (conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress & LIBUSB_ENDPOINT_IN) + s = &ep->in;// = (conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress & 3) | LIBUSB_ENDPOINT_IN; + else + s = &ep->out; // = (conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress & 3) | LIBUSB_ENDPOINT_OUT; + + // NOTE: 这里应该尽量将输入输出端口统一到同一个接口上来,目前未做,只取第一�? + if (s->port == usb_manager::uninit_uint8) + { + s->port = conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress & (LIBUSB_ENDPOINT_IN | LIBUSB_ENDPOINT_OUT | 3); + s->iconf = conf->bConfigurationValue; + s->iface = j; + s->claimed = 0; + s->max_packet = conf->interface[j].altsetting[k].endpoint[l].wMaxPacketSize; + // VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, " Endpoint address = 0x%02x, origin = 0x%02x, max packet: 0x%x\n", s->port, conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress + // , s->max_packet); + } + found_ep = true; + } + } + //else + // VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, " Endpoint %d(%s) address: %x, Max packet: 0x%x bytes\n", l + 1 + // , usb_manager::endpoint_type((libusb_transfer_type)conf->interface[j].altsetting[k].endpoint[l].bmAttributes).c_str() + // , conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress + // , conf->interface[j].altsetting[k].endpoint[l].wMaxPacketSize); + } + } + } + libusb_free_config_descriptor(conf); + } + + //if (endp && !found_ep) + // VLOG_MINI_2(LOG_LEVEL_FATAL, "No endpoint has been found on device (VID: %x, PID: %x)\n", desc.idVendor, desc.idProduct); + + return eps; +} + +int usb_manager::register_hotplug(usb_event_handler cb, void* user) +{ + if (cb) + usb_cb_ = cb; + else + usb_cb_ = &usb_manager::usb_event_handle; + usb_cb_param_ = user; + + int ret = register_usb_pnp(); + if (ret != LIBUSB_SUCCESS) + { + // then we find devices manually, and need not return failure here + } + init_notify_thread(); + + return SCANNER_ERR_OK; +} +int usb_manager::open(libusb_device* device, usb_io** usbio, std::string* msg) +{ + if (!usbio) + return SCANNER_ERR_INVALID_PARAMETER; + + usb_dev dev; + usb_io* usb = NULL; + if (!get_device_info(device, &dev)) + return SCANNER_ERR_DEVICE_NOT_FOUND; + + dev.contex = context_; + usb = new usb_io(dev); + if (!usb->is_ready()) + { + int err = usb->last_error(); + + if (msg) + *msg = usb->init_error_msg(); + usb->release(); + // VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Open %04x:%04x failed: %s\n", dev.vid, dev.pid, hg_scanner_err_name(err)); + + return err; + } + + *usbio = dynamic_cast(usb); + + return SCANNER_ERR_OK; +} +int usb_manager::last_status(void) +{ + return status_; +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// usb_io +//#define USE_OLD_USB + +#ifdef USE_OLD_USB +#include "libusbex.h" +std::shared_ptr usb_; +#endif + +usb_io::usb_io(const usb_dev& dev) : ref_(1), handle_(NULL), dev_info_(dev), to_(1000), last_err_(SCANNER_ERR_NOT_START), ref_device_(nullptr) + , singleton_(nullptr) +{ +#ifdef USE_OLD_USB + std::list> all = Libusb_List::find_vid_pid(0x3072, 0x239); + if (all.size()) + { + usb_ = *all.begin(); + usb_->open(); + handle_ = (libusb_device_handle*)1; + } +#else + + clear_endpoints(); + open(); +#endif +} +usb_io::~usb_io() +{ + close(); +} + +bool usb_io::make_singleton(void) +{ + unsigned long long key = dev_info_.vid; + key <<= 16; + key |= dev_info_.pid; + key <<= 16; + if (dev_info_.addr == 0) + dev_info_.addr = libusb_get_device_address(dev_info_.device); + key |= dev_info_.addr; + if (singleton_) + singleton_->release(); + + singleton_ = new shared_memory(key); + if (singleton_->is_first()) + { + return true; + } + + std::string str(singleton_->read()); + + singleton_->release(); + singleton_ = nullptr; + last_err_ = SCANNER_ERR_OPENED_BY_OTHER_PROCESS; + str.insert(0, "\350\256\276\345\244\207\345\267\262\347\273\217\350\242\253\350\277\233\347\250\213 '"); + str += "' \345\215\240\347\224\250"; + init_err_msg_ = str; + // VLOG_MINI_1(LOG_LEVEL_FATAL, "Open failed: %s\n", str.c_str()); + + return false; +} +void usb_io::clear_endpoints(void) +{ + usb_manager::init_endpoint(&endpoints_.bulk); + usb_manager::init_endpoint(&endpoints_.bulk_stream); + usb_manager::init_endpoint(&endpoints_.control); + usb_manager::init_endpoint(&endpoints_.interrupt); + usb_manager::init_endpoint(&endpoints_.isochronous); +} +bool usb_io::claim_interterface(usb_manager::USBSIMPLEX* spl) +{ + int ret = libusb_claim_interface(handle_, spl->iface); + if (ret == LIBUSB_SUCCESS) + { + spl->claimed = true; + return true; + } + + // VLOG_MINI_2(LOG_LEVEL_FATAL, "libusb_claim_interface(%d) = %s, now try some actions ...\n", spl->iface, libusb_error_name(ret)); + + ret = libusb_kernel_driver_active(handle_, spl->iface); + if (ret == 1) + { + ret = libusb_detach_kernel_driver(handle_, spl->iface); + + // VLOG_MINI_2(LOG_LEVEL_FATAL, " libusb_detach_kernel_driver(%d) = %s\n", spl->iface, libusb_error_name(ret)); + } + else if (ret == LIBUSB_ERROR_NO_DEVICE) + { + last_err_ = SCANNER_ERR_DEVICE_NOT_FOUND; + // VLOG_MINI_1(LOG_LEVEL_FATAL, " device(%s) maybe left when libusb_kernel_driver_active.\n", hg_log::format_ptr(dev_info_.device).c_str()); + + return false; + } + else + { + // VLOG_MINI_2(LOG_LEVEL_FATAL, " libusb_kernel_driver_active(%d) = %d\n", spl->iface, ret); + } + ret = libusb_clear_halt(handle_, spl->port); + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " libusb_clear_halt(%x) = %s\n", spl->port, libusb_error_name(ret)); + ret = libusb_release_interface(handle_, spl->iface); + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " libusb_release_interface(%u) = %s\n", spl->iface, libusb_error_name(ret)); + ret = libusb_set_configuration(handle_, spl->iconf); + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " libusb_set_configuration(%u) = %s\n", spl->iconf, libusb_error_name(ret)); + //ret = libusb_reset_device(handle_); + //// VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, " libusb_reset_device = %s\n", libusb_error_name(ret)); + //if (ret == LIBUSB_ERROR_NOT_FOUND) + //{ + // last_err_ = usb_manager::usb_error_2_hg_err(ret); + // // VLOG_MINI_1(LOG_LEVEL_FATAL, "device(%s) maybe left when libusb_reset_device.\n", hg_log::format_ptr(dev_info_.device).c_str()); + // + // return false; + //} + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + ret = libusb_claim_interface(handle_, spl->iface); + if (ret == LIBUSB_SUCCESS) + { + spl->claimed = true; + // VLOG_MINI_2(LOG_LEVEL_FATAL, "second libusb_claim_interface(%d) = %s\n", spl->iface, libusb_error_name(ret)); + return true; + } + + // VLOG_MINI_2(LOG_LEVEL_FATAL, "second try libusb_claim_interface(%d) = %s\n", spl->iface, libusb_error_name(ret)); + last_err_ = SCANNER_ERR_USB_CLAIM_INTERFACE_FAILED; + + return false; +} +int usb_io::claim_interfaces(bool claim) +{ + usb_manager::USBENDP* eps[] = { &endpoints_.control, &endpoints_.isochronous, &endpoints_.bulk, &endpoints_.interrupt, &endpoints_.bulk_stream }; + std::vector claimed; + + if (claim) + { + for (size_t i = 0; i < _countof(eps); ++i) + { + if (eps[i]->in.port != usb_manager::uninit_uint8 + && std::find(claimed.begin(), claimed.end(), eps[i]->in.iface) == claimed.end()) + { + if (!claim_interterface(&eps[i]->in)) + break; + + claimed.push_back(eps[i]->in.iface); + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "claimed %s interface %d\n", usb_manager::endpoint_type((libusb_transfer_type)i).c_str(), eps[i]->in.iface); + } + if (eps[i]->out.port != usb_manager::uninit_uint8 && eps[i]->out.iface != eps[i]->in.iface + && std::find(claimed.begin(), claimed.end(), eps[i]->out.iface) == claimed.end()) + { + if (!claim_interterface(&eps[i]->out)) + break; + claimed.push_back(eps[i]->out.iface); + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "claimed %s interface %d\n", usb_manager::endpoint_type((libusb_transfer_type)i).c_str(), eps[i]->out.iface); + } + } + } + else + { + for (size_t i = 0; i < _countof(eps); ++i) + { + if (eps[i]->in.claimed) + libusb_release_interface(handle_, eps[i]->in.iface); + if (eps[i]->out.claimed) + libusb_release_interface(handle_, eps[i]->out.iface); + } + last_err_ = SCANNER_ERR_OK; + } + + return last_err_; +} +void usb_io::init_after_open(void) +{ + last_err_ = SCANNER_ERR_OK; + libusb_set_auto_detach_kernel_driver(handle_, 1); + if(usb_manager::enum_endpoints(dev_info_.device, &endpoints_) == 0) + { + close(); + last_err_ = LIBUSB_ERROR_PIPE; + } + else if (claim_interfaces(true) != SCANNER_ERR_OK) + { + int err = last_err_; + + close(); + last_err_ = err; + } +} +void usb_io::open(void) +{ + if (!make_singleton()) + return; + + if (ref_device_) + libusb_unref_device(ref_device_); + ref_device_ = libusb_ref_device(dev_info_.device); + + int ret = libusb_open(dev_info_.device, &handle_); + // VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "call libusb_open(%s, %s) = %s\n", hg_log::format_ptr(dev_info_.device).c_str() + // , hg_log::format_ptr(handle_).c_str(), libusb_error_name(ret)); + if (ret == LIBUSB_SUCCESS) + { + init_after_open(); + } + else + { + handle_ = libusb_open_device_with_vid_pid(dev_info_.contex, dev_info_.vid, dev_info_.pid); + if (handle_) + { + init_after_open(); + + return; + } + last_err_ = usb_manager::usb_error_2_hg_err(ret); + // VLOG_MINI_4(LOG_LEVEL_FATAL, "Open USB%u.%u-%s failed: %s\n", HIBYTE(dev_info_.ver), LOBYTE(dev_info_.ver) / 0x10, hg_log::format_ptr(dev_info_.device).c_str(), libusb_error_name(ret)); + init_err_msg_ = std::to_string(last_err_); + handle_ = NULL; + } +} +bool usb_io::on_io_error(scanner_err err, usb_manager::USBSIMPLEX* endp) +{ + if (err == SCANNER_ERR_OK) + return true; + + if (err == SCANNER_ERR_TIMEOUT) + { + //因为在发送img参数出现timeout,暂时禁�? + // //LOG_INFO(LOG_LEVEL_DEBUG_INFO, "Operation timeout\n"); + // libusb_clear_halt(handle_, endp->port); + + // return libusb_reset_device(handle_) == LIBUSB_SUCCESS; + + return true; + } + + return true; +} + +int usb_io::add_ref(void) +{ + return ++ref_; // InterlockedIncreament in linux ? +} +int usb_io::release(void) +{ + int ref = --ref_; // InterlockedDecreament in linux ? + + if (ref == 0) + delete this; + + return ref; +} + +int usb_io::control_io(uint8_t type, uint8_t req, uint16_t val, uint16_t ind, void* buf, int* len) +{ +#ifdef USE_OLD_USB + return usb_->control_msg(type, req, val, ind, *len, buf); +#endif + + if (!handle_) + return last_err_; + + //if (endpoints_.control.in == usb_manager::uninit_uint8) + // return SCANNER_ERR_DEVICE_NOT_SUPPORT; + + if (!len) + return SCANNER_ERR_INVALID_PARAMETER; + + int ret = libusb_control_transfer(handle_, type, req, val, ind, (unsigned char*)buf, *len, to_); + + if (ret > 0) + { + *len = ret; + + last_err_ = SCANNER_ERR_OK; + } + else + { + //if (on_io_error((scanner_err)usb_manager::usb_error_2_hg_err(ret), &endpoints_.control.in)) + //{ + // ret = libusb_control_transfer(handle_, type, req, val, ind, (unsigned char*)buf, *len, to_); + // if (ret > 0) + // { + // *len = ret; + + // last_err_ = SCANNER_ERR_OK; + + // return last_err_; + // } + // else + // *len = 0; + //} + //else + *len = 0; + // VLOG_MINI_5(LOG_LEVEL_DEBUG_INFO, "libusb_control_transfer(%x, %x, %d, %d) = %s\n", type, req, val, ind, libusb_error_name(ret)); + last_err_ = usb_manager::usb_error_2_hg_err(ret); + } + + return last_err_; +} +int usb_io::read_bulk(void* buf, int* len) +{ +#ifdef USE_OLD_USB + *len = usb_->read_bulk(buf, *len); + return SCANNER_ERR_OK; +#endif + if (!handle_) + return last_err_; + + if(endpoints_.bulk.in.port == usb_manager::uninit_uint8) + return SCANNER_ERR_DEVICE_NOT_SUPPORT; + + if (!len) + return SCANNER_ERR_INVALID_PARAMETER; + + //if (*len < endpoints_.bulk.in.max_packet) // avoid transferring overflows ... + //{ + // *len = endpoints_.bulk.in.max_packet; + // + // return SCANNER_ERR_INSUFFICIENT_MEMORY; + //} + // libusb_clear_halt(handle_,endpoints_.bulk.in.port); + int total = 0, + err = libusb_bulk_transfer(handle_, endpoints_.bulk.in.port, (unsigned char*)buf, *len, &total, to_); + + if (err) + { + // VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "read_bulk(%x, %d/%d) = %s\n", endpoints_.bulk.in.port, total, *len, libusb_error_name(err)); + if (err == LIBUSB_ERROR_TIMEOUT && *len == total) + { + int old = to_; + if(to_ < 10 * 1000) + to_ *= 1.5f; + //err = LIBUSB_SUCCESS; + // VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " Read full length, we consider it as success, and increament timeout from %d to %d\n", old, to_); + } + } + *len = total; + last_err_ = usb_manager::usb_error_2_hg_err(err); + + return last_err_; +} +int usb_io::write_bulk(void* buf, int* len) +{ +#ifdef USE_OLD_USB + * len = usb_->write_bulk(buf, *len); + return SCANNER_ERR_OK; +#endif + if (!handle_) + return last_err_; + + if (endpoints_.bulk.out.port == usb_manager::uninit_uint8) + return SCANNER_ERR_DEVICE_NOT_SUPPORT; + + if (!len) + return SCANNER_ERR_INVALID_PARAMETER; + + unsigned char* data = (unsigned char*)buf; + int total = 0, t = 0, + + + err = usb_manager::usb_error_2_hg_err(libusb_bulk_transfer(handle_, endpoints_.bulk.out.port, data, *len, &t, to_)); + + //// VLOG_MINI_6(LOG_LEVEL_DEBUG_INFO, "First write port %x bulk %d/%d = %s(timeout = %d, packet size = %x)\n", endpoints_.bulk.out.port, t, *len, hg_scanner_err_name((scanner_err)err).c_str(), to_, endpoints_.bulk.out.max_packet); + // printf("First write port %x bulk %d/%d = %s(timeout = %d, packet size = %x)\n", endpoints_.bulk.out.port, t, *len, hg_scanner_err_name((scanner_err)err).c_str(), to_, endpoints_.bulk.out.max_packet); + if (!on_io_error((scanner_err)err, &endpoints_.bulk.out)) + { + *len = t; + + return err; + } + + total += t; + while (total < *len && (err == SCANNER_ERR_TIMEOUT || err == SCANNER_ERR_DEVICE_BUSY)) + { + if (!t) + break; + data += t; + t = 0; + err = usb_manager::usb_error_2_hg_err(libusb_bulk_transfer(handle_, endpoints_.bulk.out.port, data, *len - total, &t, to_)); + total += t; + } + //// VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Last write bulk %d/%d = %s\n", total, *len, hg_scanner_err_name((scanner_err)err).c_str()); + *len = total; + last_err_ = err; + + return last_err_; +} +int usb_io::read_interrupt(void* buf, int* len) +{ +#ifdef USE_OLD_USB + * len = usb_->read_int(buf, *len); + return SCANNER_ERR_OK; +#endif + if (!handle_) + return last_err_; + + if (endpoints_.interrupt.in.port == usb_manager::uninit_uint8) + return SCANNER_ERR_DEVICE_NOT_SUPPORT; + + if (!len) + return SCANNER_ERR_INVALID_PARAMETER; + + if (*len < endpoints_.interrupt.in.max_packet) // avoid transferring overflows ... + { + *len = endpoints_.interrupt.in.max_packet; + + return SCANNER_ERR_INSUFFICIENT_MEMORY; + } + + int io = 0; + + last_err_ = usb_manager::usb_error_2_hg_err(libusb_interrupt_transfer(handle_, endpoints_.interrupt.in.port, (unsigned char*)buf, *len, &io, to_)); + *len = io; + + return last_err_; +} +int usb_io::write_interrupt(void* buf, int* len) +{ + if (!handle_) + return last_err_; + + if (endpoints_.interrupt.out.port == usb_manager::uninit_uint8) + return SCANNER_ERR_DEVICE_NOT_SUPPORT; + + if (!len) + return SCANNER_ERR_INVALID_PARAMETER; + + unsigned char* data = (unsigned char*)buf; + int total = 0, t = 0, + err = usb_manager::usb_error_2_hg_err(libusb_bulk_transfer(handle_, endpoints_.interrupt.out.port, data, *len, &t, to_)); + + total += t; + while (total < *len && (err == SCANNER_ERR_TIMEOUT || err == SCANNER_ERR_DEVICE_BUSY)) + { + data += t; + t = 0; + err = usb_manager::usb_error_2_hg_err(libusb_interrupt_transfer(handle_, endpoints_.interrupt.out.port, data, *len - total, &t, to_)); + total += t; + } + *len = total; + last_err_ = err; + + return last_err_; +} +int usb_io::read_isochronous(void* buf, int* len) +{ + if (!handle_) + return last_err_; + + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int usb_io::write_isochronous(void* buf, int* len) +{ + if (!handle_) + return last_err_; + + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int usb_io::read_bulk_stream(void* buf, int* len) +{ + if (!handle_) + return last_err_; + + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int usb_io::write_bulk_stream(void* buf, int* len) +{ + if (!handle_) + return last_err_; + + return SCANNER_ERR_DEVICE_NOT_SUPPORT; +} +int usb_io::reset(void) +{ + if (!handle_) + return SCANNER_ERR_NOT_OPEN; + + return usb_manager::usb_error_2_hg_err(libusb_reset_device(handle_)); +} +int usb_io::reopen(void) +{ + close(); + open(); + + return last_err_; +} +int usb_io::close(void) +{ +#ifdef USE_OLD_USB + usb_.reset(); + return SCANNER_ERR_OK; +#endif + if (singleton_) + singleton_->release(); + singleton_ = nullptr; + + if (handle_) + { + claim_interfaces(false); + + libusb_close(handle_); + handle_ = nullptr; + } + clear_endpoints(); + if (ref_device_) + { + libusb_unref_device(ref_device_); + ref_device_ = nullptr; + } + + return SCANNER_ERR_OK; +} + +libusb_device* usb_io::get_usb_device(void) +{ + return dev_info_.device; +} +int usb_io::get_vid(void) +{ + return dev_info_.vid; +} +int usb_io::get_pid(void) +{ + return dev_info_.pid; +} + +void usb_io::on_disconnected(void) +{ + close(); + last_err_ = SCANNER_ERR_DEVICE_NOT_FOUND; +} +std::string usb_io::init_error_msg(void) +{ + return init_err_msg_; +} + +bool usb_io::is_ready(void) +{ + return handle_ != NULL; +} +int usb_io::last_error(void) +{ + return last_err_; +} +int usb_io::get_bulk_packet_size(int* bytes) +{ + if (!bytes) + return SCANNER_ERR_INVALID_PARAMETER; + + if (endpoints_.bulk.in.port == usb_manager::uninit_uint8 && endpoints_.bulk.out.port == usb_manager::uninit_uint8) + return SCANNER_ERR_DEVICE_NOT_SUPPORT; + + *bytes = endpoints_.bulk.in.max_packet; + + return SCANNER_ERR_OK; +} +int usb_io::get_interrupt_packet_size(int* bytes) +{ + if (!bytes) + return SCANNER_ERR_INVALID_PARAMETER; + + if (endpoints_.interrupt.in.port == usb_manager::uninit_uint8 && endpoints_.interrupt.out.port == usb_manager::uninit_uint8) + return SCANNER_ERR_DEVICE_NOT_SUPPORT; + + *bytes = endpoints_.interrupt.in.max_packet; + + return SCANNER_ERR_OK; +} +unsigned int usb_io::set_timeout(unsigned int to) +{ + unsigned int old = to_; + + to_ = to; + +#if defined(WIN32) || defined(_WIN64) + if (handle_) + { + libusb_set_timeout(handle_, to_); + } +#endif + + return old; +} +unsigned int usb_io::get_timeout(void) +{ + return to_; +} diff --git a/usb_manager.h b/usb_manager.h new file mode 100644 index 0000000..29d04fb --- /dev/null +++ b/usb_manager.h @@ -0,0 +1,206 @@ +#pragma once + +#if defined(WIN32) || defined(_WIN64) +#include "win_usb/win_usb.h" +#else +#include + +#define HIBYTE(w) (((w) >> 8) & 0x0ff) +#define LOBYTE(w) ((w) & 0x0ff) +#define _countof(a) (sizeof(a) / sizeof((a)[0])) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "hgscanner_error.h" +#include "BlockingQueue.h" +#include "hg_ipc.h" + + +struct usb_dev +{ + libusb_context* contex; + libusb_device* device; // unique device object + uint16_t ver; // 0x200, 0x101, ... + uint16_t vid; // vendor ID + uint16_t pid; // product ID + uint8_t addr; // usb port ? + + bool operator==(const libusb_device* dev) + { + return dev == device; + } +}; +typedef struct _dev_sn +{ + std::string serial; + bool operator==(const struct _dev_sn& other) + { + return serial == other.serial; + } +}DEVSN; + + +enum usb_event +{ + USB_EVENT_NULL = 0, + USB_EVENT_DEVICE_ARRIVED, + USB_EVENT_DEVICE_LEFT, + USB_EVENT_DATA_ARRIVED, + USB_EVENT_ERROR, +}; + +typedef void(*usb_event_handler)(usb_event ev, libusb_device* device, int vid, int pid, int usb_ver_h, int usb_ver_l, bool* retry/*whether */, void* user); // usb_ver_h.usb_ver_l +class usb_io; +class usb_manager +{ + volatile bool run_; + usb_event_handler usb_cb_; + libusb_context* context_; // declare my own context, avoid sharing the default context with other processes + int status_; + void* usb_cb_param_; + std::shared_ptr usb_notify_thread_; + std::shared_ptr usb_monitor_thread_; // some unknown reason, operation is accessible after certain delay + libusb_hotplug_callback_handle usb_cb_handle_; + std::chrono::system_clock::time_point born_; + + typedef struct _pnp_dev + { + libusb_context* ctx; + libusb_device* dev; + libusb_hotplug_event event; + std::chrono::system_clock::time_point happen_time; // millisecond + }PNPDEV; + BlockingQueue pnp_events_; + platform_event wait_pnp_; + + static int LIBUSB_CALL usb_pnp_callback(libusb_context* ctx, + libusb_device* device, + libusb_hotplug_event event, + void* monitor); + static void usb_event_handle(usb_event ev, libusb_device* device, int vid, int pid, int usb_ver_h, int usb_ver_l, bool* retry, void* user); // usb_ver_h.usb_ver_l + static void usb_log_callback(libusb_context* ctx, libusb_log_level level, const char* str); + + int register_usb_pnp(void); + void init_notify_thread(); + void fake_usb_pnp(std::vector& devices); + void thread_notify_usb_event(); + void notify_usb_event(PNPDEV& pd, bool* retry); + void thread_trigger_usb_event(); + int on_usb_pnp_event(struct libusb_context* ctx, + struct libusb_device* device, + libusb_hotplug_event event); + + static usb_manager* inst_; + +protected: + usb_manager(); + ~usb_manager(); + +public: + typedef struct _usb_simplex + { + uint8_t port; + uint8_t iconf; + uint8_t iface; + uint8_t claimed; + uint16_t max_packet; + }USBSIMPLEX; + typedef struct _usb_endpoints + { + USBSIMPLEX in; + USBSIMPLEX out; + }USBENDP; + typedef struct _usb_transfer_endpoints + { + USBENDP control; + USBENDP isochronous; + USBENDP bulk; + USBENDP interrupt; + USBENDP bulk_stream; + }USBTRANSENDP; + static uint8_t uninit_uint8; + + static usb_manager* instance(void); + static void clear(void); + static int usb_error_2_hg_err(int usb_err); + static void init_endpoint(USBENDP* uep); + static std::string device_class(libusb_class_code code); + static std::string endpoint_type(libusb_transfer_type type); + static bool get_device_info(libusb_device* device, usb_dev* devinfo); + static int enum_endpoints(libusb_device* device, USBTRANSENDP* endp = nullptr); + +public: + int register_hotplug(usb_event_handler cb, void* user); + int open(libusb_device* device, usb_io** usbio, std::string* msg = nullptr); + int last_status(void); +}; + +class usb_io +{ + volatile int ref_; + shared_memory *singleton_; + libusb_device_handle *handle_; + usb_dev dev_info_; + unsigned int to_; // NOTE: For an unlimited timeout, use value 0. + int last_err_; + std::string init_err_msg_; + libusb_device *ref_device_; + + // endpoint ports + usb_manager::USBTRANSENDP endpoints_; + + bool make_singleton(void); + void clear_endpoints(void); + bool claim_interterface(usb_manager::USBSIMPLEX* spl); + int claim_interfaces(bool claim); + void init_after_open(void); + void open(void); + + bool on_io_error(scanner_err err, usb_manager::USBSIMPLEX* endp); + +protected: + virtual ~usb_io(); + +public: + usb_io(const usb_dev& dev); + + int add_ref(void); // 拥有者在第一次获取时调用一次 + int release(void); // 拥有者不再使用时调用 + + // IO操作返回值全部为错误代码 (scanner_err) + int control_io(uint8_t type, uint8_t req, uint16_t val, uint16_t ind, void* buf, int* len); // 读取数据, len: [in] - buf size, [out] - real read bytes in buf + int read_bulk(void* buf, int* len); // 读取数据, len: [in] - buf size, [out] - real read bytes in buf. 如果缓冲区太小,则返回SCANNER_ERR_INSUFFICIENT_MEMORY的错误,并在该值中保存建议的最小缓冲区大小 + int write_bulk(void* buf, int* len); // 写入数据, len : [in] - content bytes in buf, [out] - real wrote bytes + int read_interrupt(void* buf, int* len); // 读取数据, len: [in] - buf size, [out] - real read bytes in buf + int write_interrupt(void* buf, int* len); // 写入数据, len : [in] - content bytes in buf, [out] - real wrote bytes + int read_isochronous(void* buf, int* len); // 读取数据, len: [in] - buf size, [out] - real read bytes in buf + int write_isochronous(void* buf, int* len); // 写入数据, len : [in] - content bytes in buf, [out] - real wrote bytes + int read_bulk_stream(void* buf, int* len); // 读取数据, len: [in] - buf size, [out] - real read bytes in buf + int write_bulk_stream(void* buf, int* len); // 写入数据, len : [in] - content bytes in buf, [out] - real wrote bytes + int reset(void); + int reopen(void); + int close(void); // 关闭该对象 + + libusb_device* get_usb_device(void); // 获取该USB对象 + int get_vid(void); // 获取连接到该USB端口上的设备VID + int get_pid(void); // 获取连接到该USB端口上的设备PID + + void on_disconnected(void); + std::string init_error_msg(void); + +public: + bool is_ready(void); + int last_error(void); + int get_bulk_packet_size(int* bytes); // 获取bulk方式的数据包大小,返回错误代码 + int get_interrupt_packet_size(int* bytes); + unsigned int set_timeout(unsigned int to = USB_TIMEOUT_INFINITE); + unsigned int get_timeout(void); +}; +