华高国产系统小工具

This commit is contained in:
gb 2023-02-24 17:24:48 +08:00
commit f9aea52694
12 changed files with 6334 additions and 0 deletions

133
BlockingQueue.h Normal file
View File

@ -0,0 +1,133 @@
#ifndef BLOCKING_QUEUE_H
#define BLOCKING_QUEUE_H
//#include <boost/thread/mutex.hpp>
//#include <boost/thread/condition_variable.hpp>
#if defined(WIN32) || defined(_WIN64)
#include <Windows.h>
#endif
#include <mutex>
#include <condition_variable>
#include <deque>
#include <iostream>
#include <exception>
using namespace std;
template <typename T>
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<DQ> _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<mutex> 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<mutex> 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<mutex> 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<mutex> 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<mutex> lock(_mutex);
if (bytes)
*bytes = bytes_;
return _queue.size();
}
};
#endif

27
CMakeLists.txt Normal file
View File

@ -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)

943
base.cpp Normal file
View File

@ -0,0 +1,943 @@
#include "base.h"
#include <iconv.h>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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 <sys/time.h>
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 <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
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;
}
}

164
base.h Normal file
View File

@ -0,0 +1,164 @@
#pragma once
// Objects life management
//
// created on 2022-11-29
//
#include <semaphore.h>
#include <mutex>
#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<MUTEX> 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 <sys/time.h>
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 <string>
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<typename ... Args>
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);
}

308
cmd.cpp Normal file
View File

@ -0,0 +1,308 @@
#include "cmd.h"
namespace parser
{
static void command_line_to_arguments(const char* cmdl, std::vector<std::string>& 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::CMDROUT> 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<CMDROUT>& routine, const char* cmd, quit_cmd(*handle)(cmd_line*, void*), void* param)
{
std::vector<console_dispatcher::CMDROUT>::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<console_dispatcher::CMDROUT>::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;
}

148
cmd.h Normal file
View File

@ -0,0 +1,148 @@
#pragma once
// command line utility
//
// created on 2023-02-10
//
#include "base.h"
#include <string>
#include <vector>
#include <algorithm>
#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<std::string> 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<CMDROUT> cmd_routine_;
quit_cmd(*un_handle_)(cmd_line*, void*);
void* un_handle_param_;
static std::vector<CMDROUT> super_cmd_routine_;
static void add_command(std::vector<CMDROUT>& 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);
};

886
hg_ipc.cpp Normal file
View File

@ -0,0 +1,886 @@
#include "hg_ipc.h"
#include "hgscanner_error.h"
#if defined(WIN32) || defined(_WIN64)
//#include "scanner_manager.h"
#else
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#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<std::mutex> lck(lock_);
return queue_.size();
}
void final_img_queue::clear(void)
{
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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());
}
}
}

244
hg_ipc.h Normal file
View File

@ -0,0 +1,244 @@
#pragma once
// Objects for Inter-Process-Communication
//
// created on 2022-03-01
//
#if defined(WIN32) || defined(_WIN64)
#include <Windows.h>
#define sem_t HANDLE
#define USB_TIMEOUT_INFINITE -1
#else
#include <semaphore.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#define USB_TIMEOUT_INFINITE 0
#endif
#include <string>
#include <vector>
#include <mutex>
#include <memory>
#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<std::mutex> lock(mutex_);
// return ++ref_;
// }
// int release(void)
// {
// int ref = 0;
// {
// std::lock_guard<std::mutex> lock(mutex_);
// ref = --ref_;
// }
// if (ref == 0)
// delete this;
// return ref;
// }
// };
template<class T>
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<tiny_buffer> data;
}IMGDT;
class final_img_queue
{
mutable std::mutex lock_;
std::vector<IMGDT> 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);
};

348
hgscanner_error.h Normal file
View File

@ -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修改影响图像参数的属性后扫描崩溃的问题
// 2USB错误
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
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

1765
main.cpp Normal file

File diff suppressed because it is too large Load Diff

1162
usb_manager.cpp Normal file

File diff suppressed because it is too large Load Diff

206
usb_manager.h Normal file
View File

@ -0,0 +1,206 @@
#pragma once
#if defined(WIN32) || defined(_WIN64)
#include "win_usb/win_usb.h"
#else
#include <libusb-1.0/libusb.h>
#define HIBYTE(w) (((w) >> 8) & 0x0ff)
#define LOBYTE(w) ((w) & 0x0ff)
#define _countof(a) (sizeof(a) / sizeof((a)[0]))
#endif
#include <thread>
#include <memory>
#include <algorithm>
#include <string>
#include <mutex>
#include <vector>
#include <chrono>
#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<std::thread> usb_notify_thread_;
std::shared_ptr<std::thread> 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<PNPDEV> 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<libusb_device*>& 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);
};