mirror of http://192.168.1.51:8099/gb/code_util
华高国产系统小工具
This commit is contained in:
commit
f9aea52694
|
@ -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
|
|
@ -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)
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
};
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
};
|
|
@ -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
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue