增加匹配压缩图像接收的功能

This commit is contained in:
gb 2024-02-27 12:05:25 +08:00
parent 3ce1d9a368
commit b1af6d0d4d
14 changed files with 1526 additions and 71 deletions

View File

@ -17,7 +17,6 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //
@ -91,7 +90,7 @@ hg_scanner::hg_scanner(ONLNSCANNER* dev, imgproc_mgr* imgproc, hguser* user, std
{ {
thread_image_processor(); thread_image_processor();
}; };
imgpr_thread_.start(tf, "hg_scanner::thread_image_processor", NULL); imgpr_thread_.start(tf, 0, "hg_scanner::thread_image_processor");
#else #else
imgpr_thread_.reset(new std::thread(&hg_scanner::thread_image_processor, this)); imgpr_thread_.reset(new std::thread(&hg_scanner::thread_image_processor, this));
#endif #endif
@ -258,10 +257,9 @@ void hg_scanner::thread_image_processor(void)
} }
void hg_scanner::process_image(image_holder_ptr img) void hg_scanner::process_image(image_holder_ptr img)
{ {
PACKIMAGE h; bool addref = true;
h.prc_stage = -1; if (!dump_path_.empty())
if (!dump_path_.empty() && img->get_info()->prc_stage != h.prc_stage)
{ {
int stage = img->get_info()->prc_stage; int stage = img->get_info()->prc_stage;
char alg[128] = { 0 }; char alg[128] = { 0 };
@ -272,11 +270,34 @@ void hg_scanner::process_image(image_holder_ptr img)
sprintf(alg, "%04X_Unk", stage); sprintf(alg, "%04X_Unk", stage);
img->save_2_file(dump_path_.c_str(), alg); img->save_2_file(dump_path_.c_str(), alg);
} }
if (img->get_info()->prc_stage == h.prc_stage)
if (img->get_info()->format != IMG_FMT_BMP)
{ {
// decode ...
#ifdef TEST_HGSCANNER
#else
cv::ImreadModes mode = img->get_info()->channels == 1 ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR;
std::vector<uchar> buf(img->data_length());
memcpy(buf.data(), img->data(), img->data_length());
cv::Mat mat(cv::imdecode(buf, mode));
PACKIMAGE head(*img->get_info());
image_holder *ptr = nullptr;
uint32_t size = mat.total() * mat.channels();
head.data_size = size;
head.format = IMG_FMT_BMP;
ptr = new image_holder(&head);
ptr->put_data(mat.ptr(), &size);
img = ptr;
addref = false;
#endif
}
if(addref)
img->add_ref(); img->add_ref();
final_imgs_.save(img, true); final_imgs_.save(img, true);
}
} }
image_holder_ptr hg_scanner::wait_image(void) image_holder_ptr hg_scanner::wait_image(void)
{ {
@ -488,6 +509,11 @@ int hg_scanner::get_image_info(SANE_Parameters* pii)
pii->bytes_per_line = (ptr->get_info()->bpp * ptr->get_info()->width * ptr->get_info()->channels + 7) / 8; // no 4-bytes align pii->bytes_per_line = (ptr->get_info()->bpp * ptr->get_info()->width * ptr->get_info()->channels + 7) / 8; // no 4-bytes align
pii->depth = ptr->get_info()->bpp; // 此处指每一个颜色分量的位深我们的扫描仪固定为“8” pii->depth = ptr->get_info()->bpp; // 此处指每一个颜色分量的位深我们的扫描仪固定为“8”
pii->last_frame = SANE_TRUE; // 一幅图片如果各个分量相互分离则最后一个分量的时候设置为true。彩色图像RGB时也只有一“帧”所以也为true pii->last_frame = SANE_TRUE; // 一幅图片如果各个分量相互分离则最后一个分量的时候设置为true。彩色图像RGB时也只有一“帧”所以也为true
if (ptr->get_info()->format == IMG_FMT_JPEG)
pii->format = (SANE_Frame)SANE_FRAME_JPEG;
else if (ptr->get_info()->format == IMG_FMT_PNG)
pii->format = (SANE_Frame)SANE_FRAME_PNG;
else
pii->format = ptr->get_info()->channels == 3 ? SANE_FRAME_RGB : SANE_FRAME_GRAY; pii->format = ptr->get_info()->channels == 3 ? SANE_FRAME_RGB : SANE_FRAME_GRAY;
pii->lines = ptr->get_info()->height; pii->lines = ptr->get_info()->height;
pii->pixels_per_line = ptr->get_info()->width; pii->pixels_per_line = ptr->get_info()->width;
@ -647,3 +673,4 @@ int hg_scanner::file_transfer(const char* local, const char* remote, bool to_rem
return scanner_->file_transfer(local, remote, to_remote, prog); return scanner_->file_transfer(local, remote, to_remote, prog);
} }

View File

@ -451,9 +451,9 @@ void async_usb_host::create_worker_threads(void)
void(async_usb_host:: * p)(void) = &async_usb_host::thread_pump_task; void(async_usb_host:: * p)(void) = &async_usb_host::thread_pump_task;
void(async_usb_host:: * r)(void) = &async_usb_host::thread_read_bulk; void(async_usb_host:: * r)(void) = &async_usb_host::thread_read_bulk;
void(async_usb_host:: * w)(void) = &async_usb_host::thread_write_bulk; void(async_usb_host:: * w)(void) = &async_usb_host::thread_write_bulk;
worker_.start(thread_p, "async_usb_host::thread_pump_task", *(void**)&p); worker_.start(thread_p, 0, "async_usb_host::thread_pump_task", *(void**)&p);
worker_.start(thread_w, "async_usb_host::thread_write_bulk", *(void**)&w); worker_.start(thread_w, 0, "async_usb_host::thread_write_bulk", *(void**)&w);
worker_.start(thread_r, "async_usb_host::thread_read_bulk", *(void**)&r); worker_.start(thread_r, 0, "async_usb_host::thread_read_bulk", *(void**)&r);
#else #else
thread_w_.reset(new std::thread(&async_usb_host::thread_write_bulk, this)); thread_w_.reset(new std::thread(&async_usb_host::thread_write_bulk, this));
thread_r_.reset(new std::thread(&async_usb_host::thread_read_bulk, this)); thread_r_.reset(new std::thread(&async_usb_host::thread_read_bulk, this));

View File

@ -183,7 +183,7 @@ usb_manager::usb_manager() : run_(true)
thread_notify_usb_event(); thread_notify_usb_event();
}; };
void(usb_manager:: * pnp)(void) = &usb_manager::thread_notify_usb_event; void(usb_manager:: * pnp)(void) = &usb_manager::thread_notify_usb_event;
usb_notify_thread_.start(tf, "usb_manager::thread_notify_usb_event", *(void**)&pnp); usb_notify_thread_.start(tf, 0, "usb_manager::thread_notify_usb_event", *(void**)&pnp);
#else #else
if (!usb_notify_thread_.get()) if (!usb_notify_thread_.get())
{ {
@ -281,7 +281,7 @@ void usb_manager::init_notify_thread()
thread_trigger_usb_event(); thread_trigger_usb_event();
}; };
void(usb_manager:: * t)(void) = &usb_manager::thread_trigger_usb_event; void(usb_manager:: * t)(void) = &usb_manager::thread_trigger_usb_event;
usb_monitor_thread_.start(tf, "usb_manager::thread_trigger_usb_event", *(void**)&t); usb_monitor_thread_.start(tf, 0, "usb_manager::thread_trigger_usb_event", *(void**)&t);
#else #else
if(!usb_monitor_thread_.get()) if(!usb_monitor_thread_.get())
{ {

View File

@ -543,13 +543,36 @@ int dyn_mem::fetch_data(void* buf, uint32_t* size)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //
dyn_mem_shared::dyn_mem_shared(void* buf, size_t size, BEFORE_DESTROY_FUNC destroy, void* param) dyn_mem_shared::dyn_mem_shared(void* buf, size_t size, BEFORE_DESTROY_FUNC destroy)
: dyn_mem(buf, size), destroy_(destroy), param_(param) : dyn_mem(buf, size), destroy_(destroy)
{} {
memset(param_, 0, sizeof(param_));
}
dyn_mem_shared::~dyn_mem_shared() dyn_mem_shared::~dyn_mem_shared()
{ {
if(destroy_) if(destroy_)
destroy_(this, param_); destroy_(this);
}
bool dyn_mem_shared::set_param(void* param, int index)
{
if(index >= 0 && index < _countof(param_))
{
param_[index] = param;
return true;
}
else
{
return false;
}
}
void* dyn_mem_shared::get_param(int index)
{
if(index >= 0 && index < _countof(param_))
return param_[index];
else
return nullptr;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -905,7 +928,8 @@ uint8_t* file_map::buffer(void)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// image_packet // image_packet
image_packet::image_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid image_packet::image_packet(LPPACKIMAGE head, std::shared_ptr<std::vector<uchar>> img
, uint32_t scanid
, const void* info, size_t info_size) , const void* info, size_t info_size)
: img_(img), offset_(0), info_over_(false) : img_(img), offset_(0), info_over_(false)
{ {
@ -913,7 +937,6 @@ image_packet::image_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid
LPPACKIMAGE pimg = nullptr; LPPACKIMAGE pimg = nullptr;
paper_ind_ = head->pos.paper_ind; paper_ind_ = head->pos.paper_ind;
img->add_ref();
if(info && info_size) if(info && info_size)
info_ = std::string((const char*)info, info_size); info_ = std::string((const char*)info, info_size);
else else
@ -926,7 +949,7 @@ image_packet::image_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid
pack->payload_len = sizeof(PACKIMAGE); pack->payload_len = sizeof(PACKIMAGE);
memcpy(pimg, head, sizeof(*pimg)); memcpy(pimg, head, sizeof(*pimg));
pimg->data_size = img->get_rest(); pimg->data_size = img->size();
pimg->info_size = info_size; pimg->info_size = info_size;
head_->set_len(sizeof(PACK_BASE) + sizeof(PACKIMAGE)); head_->set_len(sizeof(PACK_BASE) + sizeof(PACKIMAGE));
@ -947,7 +970,6 @@ image_packet::image_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid
image_packet::~image_packet() image_packet::~image_packet()
{ {
head_->release(); head_->release();
img_->release();
} }
bool image_packet::is_memory_block(void) bool image_packet::is_memory_block(void)
@ -956,7 +978,7 @@ bool image_packet::is_memory_block(void)
} }
uint32_t image_packet::get_rest(void) uint32_t image_packet::get_rest(void)
{ {
return head_->get_rest() + info_.length() + img_->get_rest() - offset_; return head_->get_rest() + info_.length() + img_->size() - offset_;
} }
// following API valid when is_memory_block() return true // following API valid when is_memory_block() return true
@ -1000,15 +1022,15 @@ int image_packet::fetch_data(void* buf, uint32_t* size)
} }
else else
{ {
if(*size + offset_ >= img_->get_rest()) if(*size + offset_ >= img_->size())
{ {
memcpy(buf, img_->ptr() + offset_, img_->get_rest() - offset_); memcpy(buf, img_->data() + offset_, img_->size() - offset_);
*size = img_->get_rest() - offset_; *size = img_->size() - offset_;
offset_ = img_->get_rest(); offset_ = img_->size();
} }
else else
{ {
memcpy(buf, img_->ptr() + offset_, *size); memcpy(buf, img_->data() + offset_, *size);
offset_ += *size; offset_ += *size;
} }
} }

View File

@ -11,6 +11,9 @@
#include <functional> #include <functional>
#define CLS_PTR(cls) typedef cls* cls##_ptr; #define CLS_PTR(cls) typedef cls* cls##_ptr;
#ifndef uchar
typedef unsigned char uchar;
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -213,7 +216,7 @@ public:
// #define STAT_MEM // #define STAT_MEM
#define BEFORE_DESTROY_RET void #define BEFORE_DESTROY_RET void
#define BEFORE_DESTROY_PARAM dyn_mem* mem, void* param #define BEFORE_DESTROY_PARAM dyn_mem_shared* mem
#define BEFORE_DESTROY_FUNC std::function<BEFORE_DESTROY_RET(BEFORE_DESTROY_PARAM)> #define BEFORE_DESTROY_FUNC std::function<BEFORE_DESTROY_RET(BEFORE_DESTROY_PARAM)>
class dyn_mem : public data_source class dyn_mem : public data_source
@ -263,13 +266,17 @@ public:
class dyn_mem_shared : public dyn_mem class dyn_mem_shared : public dyn_mem
{ {
BEFORE_DESTROY_FUNC destroy_ = BEFORE_DESTROY_FUNC(); BEFORE_DESTROY_FUNC destroy_ = BEFORE_DESTROY_FUNC();
void* param_ = nullptr; void* param_[4];
public: public:
dyn_mem_shared(void* buf, size_t size, BEFORE_DESTROY_FUNC destroy = BEFORE_DESTROY_FUNC(), void* param = nullptr); dyn_mem_shared(void* buf, size_t size, BEFORE_DESTROY_FUNC destroy = BEFORE_DESTROY_FUNC());
protected: protected:
~dyn_mem_shared(); ~dyn_mem_shared();
public:
bool set_param(void* param, int index = 0);
void* get_param(int index = 0);
}; };
class file_reader : public data_source class file_reader : public data_source
@ -305,7 +312,8 @@ public:
class image_packet : public data_source class image_packet : public data_source
{ {
dyn_mem* img_; // dyn_mem* img_;
std::shared_ptr<std::vector<uchar>> img_;
dyn_mem* head_; dyn_mem* head_;
uint32_t offset_; uint32_t offset_;
uint32_t paper_ind_ = 0; uint32_t paper_ind_ = 0;
@ -314,7 +322,7 @@ class image_packet : public data_source
std::string pos_str_; std::string pos_str_;
public: public:
image_packet(LPPACKIMAGE head, dyn_mem* img, uint32_t scanid, const void* info = nullptr, size_t info_size = 0); image_packet(LPPACKIMAGE head, std::shared_ptr<std::vector<uchar>> img, uint32_t scanid, const void* info = nullptr, size_t info_size = 0);
protected: protected:
virtual ~image_packet(); virtual ~image_packet();

View File

@ -40,6 +40,12 @@
// protocol version, The first thing to do after connecting is to check whether the field is compatible !!! // protocol version, The first thing to do after connecting is to check whether the field is compatible !!!
#define PROTOCOL_VER MAKE_WORD(0, 1) #define PROTOCOL_VER MAKE_WORD(0, 1)
// resource manager callback
#define CHK_RES_FUNC std::function<bool(int, bool, int)>
#define DECL_CHK_RES_FUNC(where, n) \
auto n = [where](int task, bool wait, int to_ms) -> bool
// NOTE: All text transmitted by pack cmd is in UTF-8 format !!! // NOTE: All text transmitted by pack cmd is in UTF-8 format !!!
enum cancel_io enum cancel_io
@ -64,6 +70,15 @@ enum woker_status
WORKER_STATUS_RESET, // in reset(close and reopen) process WORKER_STATUS_RESET, // in reset(close and reopen) process
WORKER_STATUS_WAIT_RESOURCE, // wait resource WORKER_STATUS_WAIT_RESOURCE, // wait resource
}; };
enum _task
{
TASK_NONE = 0,
TASK_EP0,
TASK_BULK_IN,
TASK_BULK_OUT,
TASK_CAPTURER,
TASK_IMG_PROCESSOR,
};
enum packet_cmd enum packet_cmd
{ {
@ -230,14 +245,14 @@ typedef struct _ep0_reply
uint32_t task_required_bytes; // required byte of this packet uint32_t task_required_bytes; // required byte of this packet
uint32_t packets_to_sent; // how many packets in sent queue uint32_t packets_to_sent; // how many packets in sent queue
uint32_t bytes_to_sent; // how many bytes data is waiting for be sent in one replying packet uint32_t bytes_to_sent; // how many bytes data is waiting for be sent in one replying packet
}EP0REPLYSTATUS, * LPEP0REPLYSTATUS; }EP0REPLYSTATUS, *LPEP0REPLYSTATUS;
typedef struct _peer_config typedef struct _peer_config
{ {
uint64_t pid; // [in] - host pc process id; [out] - usb service process id uint64_t pid; // [in] - host pc process id; [out] - usb service process id
uint32_t io_size; // IO buffer size uint32_t io_size; // IO buffer size
uint16_t ver; // protocol version uint16_t ver; // protocol version
}PEERCFG, * LPPEERCFG; }PEERCFG, *LPPEERCFG;
typedef struct _pack_base // A piece of data has only one header typedef struct _pack_base // A piece of data has only one header
{ {
@ -274,7 +289,7 @@ typedef struct _config_val
uint16_t val_size; // real size of value uint16_t val_size; // real size of value
uint16_t max_size; // max size of this option, this value has given in gb_json::size uint16_t max_size; // max size of this option, this value has given in gb_json::size
char data[0]; // contains value and name. fetch them according name_off and val_off members. char data[0]; // contains value and name. fetch them according name_off and val_off members.
}CFGVAL, * LPCFGVAL; }CFGVAL, *LPCFGVAL;
typedef struct _img_pos typedef struct _img_pos
{ {
@ -324,7 +339,7 @@ typedef struct _tx_file
uint64_t size; // total size uint64_t size; // total size
uint64_t offset; // offset in the file uint64_t offset; // offset in the file
char path[2]; // file full path-name char path[2]; // file full path-name
}TXFILE, * LPTXFILE; }TXFILE, *LPTXFILE;
typedef struct _file_info typedef struct _file_info
{ {
OPERTOKEN token; // operation token, returned by command PACK_CMD_TOKEN_GET OPERTOKEN token; // operation token, returned by command PACK_CMD_TOKEN_GET

View File

@ -12,9 +12,12 @@
#define SIZE_MB(n) SIZE_KB((n) * 1024) #define SIZE_MB(n) SIZE_KB((n) * 1024)
#define SIZE_GB(n) SIZE_MB((n) * 1024) #define SIZE_GB(n) SIZE_MB((n) * 1024)
#define SEC_2_MS(s) ((s) * 1000) #define USEC_2_NS(us) ((long)(us) * 1000)
#define MSEC_2_US(ms) ((ms) * 1000) #define MSEC_2_US(ms) ((long)(ms) * 1000)
#define SEC_2_MS(s) ((long)(s) * 1000)
#define MSEC_2_NS(ms) USEC_2_NS(MSEC_2_US(ms))
#define SEC_2_US(s) MSEC_2_US(SEC_2_MS(s)) #define SEC_2_US(s) MSEC_2_US(SEC_2_MS(s))
#define SEC_2_NS(s) USEC_2_NS(SEC_2_US(s))
#define MM_PER_INCH 25.4f #define MM_PER_INCH 25.4f
#define IS_DOUBLE_EQUAL(a, b) fabs((a) - (b)) < .000001 #define IS_DOUBLE_EQUAL(a, b) fabs((a) - (b)) < .000001
@ -104,6 +107,11 @@ typedef struct _size
u_int32_t cx; u_int32_t cx;
u_int32_t cy; u_int32_t cy;
}SIZE, *LPSIZE; }SIZE, *LPSIZE;
typedef struct _point
{
u_int32_t x;
u_int32_t y;
}POINT, *LPPOINT;
#pragma pack(pop) #pragma pack(pop)
@ -175,6 +183,10 @@ extern uint64_t GetCurrentThreadId(void);
#define FSEEK _fseeki64 #define FSEEK _fseeki64
#define FTELL _ftelli64 #define FTELL _ftelli64
#define pid_t int #define pid_t int
#define pthread_t HANDLE
#define _GLIBCXX_TXN_SAFE_DYN
#define _GLIBCXX_USE_NOEXCEPT
#endif #endif

410
sdk/base/ui.cpp Normal file
View File

@ -0,0 +1,410 @@
#include "ui.h"
#include "utils.h"
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define PIPE_PROTO_VER MAKEWORD(0, 1)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ipc class
namespace devui
{
class pipe_reader : public refer
{
std::string pipe_path_;
int fd_ = -1;
safe_thread worker_;
volatile bool run_ = true;
std::function<void(uint8_t*, size_t)> handler_;
void worker(void)
{
uint8_t buf[512] = {0};
while(run_)
{
int len = read(fd_, buf, sizeof(buf));
if(len == -1)
break;
handler_(buf, len);
}
}
public:
pipe_reader(const char* fifo, std::function<void(uint8_t*, size_t)> h) : pipe_path_(fifo), handler_(h)
{
auto r = [this](void) -> void
{
int cycle = 0;
while(run_)
{
fd_ = ::open(pipe_path_.c_str(), O_RDONLY);
utils::to_log(LOG_LEVEL_ALL, "open pipe_reader(%s) %d times = %d\n", ++cycle, fd_);
if(fd_ != -1)
{
worker();
if(fd_ != -1)
{
::close(fd_);
fd_ = -1;
}
}
}
};
worker_.start(r, SIZE_MB(1), "worker", (void*)&pipe_reader::worker);
}
protected:
virtual ~pipe_reader()
{
stop();
}
public:
bool is_ready(void)
{
return fd_ != -1;
}
void stop(void)
{
run_ = false;
if(fd_ != -1)
{
int fd = fd_;
fd_ = -1;
::close(fd);
}
}
};
class pipe_sender : public refer
{
std::string pipe_path_;
int fd_ = -1;
safe_thread worker_;
volatile bool run_ = true;
safe_fifo<std::string> sent_que_;
void worker(void)
{
while(run_)
{
std::string cont("");
if(sent_que_.take(cont, true))
{
int s = 0, off = 0;
do
{
s = write(fd_, cont.c_str() + off, cont.length() - off);
if(s == -1)
{
utils::to_log(LOG_LEVEL_FATAL, "Send UI message failed: %d(%s)\n", errno, strerror(errno));
break;
}
off += s;
}while(off < cont.length());
if(s == -1)
break;
}
}
}
public:
pipe_sender(const char* fifo) : pipe_path_(fifo), sent_que_("sent-que")
{
sent_que_.enable_wait_log(false);
auto r = [this](void) -> void
{
int cycle = 0;
while(run_)
{
fd_ = ::open(pipe_path_.c_str(), O_WRONLY);
utils::to_log(LOG_LEVEL_ALL, "open pipe_sender(%s) %d times = %d\n", ++cycle, fd_);
if(fd_ != -1)
{
worker();
if(fd_ != -1)
{
::close(fd_);
fd_ = -1;
}
}
}
};
worker_.start(r, SIZE_MB(1), "worker", (void*)&pipe_sender::worker);
}
protected:
virtual ~pipe_sender()
{
stop();
}
public:
bool is_ready(void)
{
return fd_ != -1;
}
void stop(void)
{
run_ = false;
if(fd_ != -1)
{
int fd = fd_;
fd_ = -1;
::close(fd);
}
}
void send(std::string& msg)
{
sent_que_.save(msg, true);
}
};
class ui_messenger
{
std::function<void(LPMSGSTREAM)> cb_;
safe_fifo<std::string> sent_que_;
volatile bool run_ = true;
bool ui_;
bool ready_ = true;
safe_thread workers_;
int fdo_ = -1;
int fdi_ = -1;
std::string fmode(int m)
{
if(m == O_RDONLY)
return "O_RDONLY";
if(m == O_WRONLY)
return "O_WRONLY";
return "Unk";
}
void init(void)
{
const char* fifo[] = {"/tmp/worker", "/tmp/ui"};
int mode[] = {O_RDONLY, O_WRONLY};
int *fd[] = {&fdi_, &fdo_};
mkfifo(fifo[!ui_], 0777);
mkfifo(fifo[ui_], 0777);
*fd[ui_] = open(fifo[1], mode[ui_]);
utils::to_log(LOG_LEVEL_ALL, "open pipe(%s) = %d\n", fifo[1], *fd[ui_]);
*fd[!ui_] = open(fifo[0], mode[!ui_]);
utils::to_log(LOG_LEVEL_ALL, "open pipe(%s) = %d\n", fifo[0], *fd[!ui_]);
if(fdo_ == -1 || fdi_ == -1)
{
printf("Out fd = %d, In fd = %d\n", fdo_, fdi_);
this->close();
}
else
{
auto r = [this](void) -> void
{
receiver();
};
auto s = [this](void) -> void
{
sender();
};
workers_.start(r, SIZE_MB(1), "receiver");
workers_.start(s, SIZE_MB(1), "sender");
}
}
void close(void)
{
ready_ = false;
if(fdo_ != -1)
::close(fdo_);
if(fdi_ != -1)
::close(fdi_);
fdi_ = fdo_ = -1;
}
void receiver(void)
{
std::string rcv("");
char buf[300] = {0};
LPMSGSTREAM pack = nullptr;
chronograph watch;
printf("ui-receiver running ...\n");
while(run_)
{
watch.reset();
int r = read(fdi_, buf, _countof(buf));
if(r == -1)
{
printf("Read UI message failed: %d(%s)\n", errno, strerror(errno));
utils::to_log(LOG_LEVEL_FATAL, "Read UI message failed: %d(%s)\n", errno, strerror(errno));
this->close();
break;
}
else if(r == 0 /*&& errno == ENOENT*/) // errno maybe ZERO, here ommit the error code
{
// peer closed, wait 10ms ...
if(watch.elapse_ms() > 10)
{
MSGSTREAM ms;
memset(&ms, 0, sizeof(ms));
ms.ver = PIPE_PROTO_VER;
ms.msg = UI_STATUS_PEER_CLOSED;
cb_(&ms);
printf("PIPE: peer closed(read ZERO byte and error = %d).\n", errno);
utils::to_log(LOG_LEVEL_DEBUG, "PIPE: peer closed(read ZERO byte and error = %d).\n", errno);
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
continue;
}
rcv += std::string(buf, r);
if(rcv.length())
{
int off = 0;
pack = (LPMSGSTREAM)&rcv[off];
while(pack->whole_size() <= rcv.length() - off)
{
cb_(pack);
off += pack->whole_size();
pack = (LPMSGSTREAM)&rcv[off];
}
if(off)
rcv.erase(0, off);
}
}
printf("ui-receiver exited.\n");
}
void sender(void)
{
printf("ui-sender running ...\n");
while(run_)
{
std::string cont("");
if(sent_que_.take(cont, true))
{
int s = 0, off = 0;
do
{
s = write(fdo_, cont.c_str() + off, cont.length() - off);
if(s == -1)
{
printf("Send UI message failed: %d(%s)\n", errno, strerror(errno));
utils::to_log(LOG_LEVEL_FATAL, "Send UI message failed: %d(%s)\n", errno, strerror(errno));
this->close();
break;
}
off += s;
}while(off < cont.length());
if(s == -1)
break;
}
}
printf("ui-sender exited.\n");
}
public:
ui_messenger(std::function<void(LPMSGSTREAM)> uicb
, bool ui) : sent_que_("ui-sent-que")
, cb_(uicb), ui_(ui)
{
sent_que_.enable_wait_log(false);
init();
}
~ui_messenger()
{
close();
}
public:
bool send(std::string& msg)
{
if(ready_)
sent_que_.save(msg, true);
return ready_;
}
void stop(void)
{
sent_que_.trigger();
run_ = false;
this->close();
}
};
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// interface
static MUTEX msg_lk_;
static devui::ui_messenger *msgr = nullptr;
namespace devui
{
void init_ui(std::function<void(LPMSGSTREAM)> uicb, bool ui)
{
SIMPLE_LOCK(msg_lk_);
if(!msgr)
msgr = new ui_messenger(uicb, ui);
}
void uninit_ui(void)
{
SIMPLE_LOCK(msg_lk_);
if(msgr)
{
msgr->stop();
delete msgr;
}
msgr = nullptr;
}
bool send_message(uint32_t msgid, uint8_t* data, uint8_t size)
{
std::string stream("");
MSGSTREAM pack;
bool ret = false;
size_t fix = sizeof(pack.data);
memset(&pack, 0, sizeof(pack));
pack.ver = PIPE_PROTO_VER;
pack.msg = msgid;
pack.size = size;
if(size > fix)
{
memcpy(pack.data, data, fix);
stream = std::string((char*)&pack, sizeof(pack));
stream += std::string((char*)data + fix, size - fix);
}
else
{
memcpy(pack.data, data, size);
stream = std::string((char*)&pack, sizeof(pack));
}
{
SIMPLE_LOCK(msg_lk_);
if(msgr)
ret = msgr->send(stream);
}
return ret;
}
bool send_status_message(uint32_t msgid, int align_h, int align_v, int font, int clears)
{
devui::STATMSG msg;
msg.msg_words_id = msgid;
msg.align_h = align_h;
msg.align_v = align_v;
msg.clear = clears;
msg.font = font;
msg.reserved = 0;
return send_message(devui::UI_STATUS_MESSAGE, (uint8_t*)&msg, sizeof(msg));
}
};

86
sdk/base/ui.h Normal file
View File

@ -0,0 +1,86 @@
// Purpose: IPC methods between scanner and user-interface (keyboard, monitor, power, ...)
//
// Date: 2024-01-09
//
// Thinking: This module can provide services independently of the scanner-service program
//
#pragma once
#include <functional>
#include <string>
namespace devui
{
enum scan
{
SCAN_STOPPED = 0, // scanning work is stopped
SCAN_PAUSED, // finished ONE turn scanning in auto-scan
SCAN_NORMAL,
SCAN_COUNT_MODE,
};
enum uicmd
{
UI_CMD_COUNT_PAPER = 0x10,
UI_CMD_STOP_SCAN,
UI_CMD_CLEAN_PASSWAY = 0x30,
UI_STATUS_SCANNING = 0x1000, // begin scanning. data: (LPSCANSTREAM)
UI_STATUS_PAPER_CNT, // ONE paper has pass through. data: (uint32_t*)milliseconds for paper pass through
UI_STATUS_MESSAGE, // status message, hold screen. data: LPSTATMSG
UI_STATUS_PEER_CLOSED = 0x8000, // peer closed.
};
enum align_component
{
ALIGN_COMPONENT_HEAD = 0,
ALIGN_COMPONENT_MID,
ALIGN_COMPONENT_TAIL,
};
enum clear_method
{
CLEAR_NONE = 0, // no clear
CLEAR_ALL, // clear all screen
CLEAR_LINE, // clear the lines which the content will output
};
#pragma pack(push)
#pragma pack(1)
typedef struct _msg_stream
{
uint16_t ver;
uint16_t size; // bytes of data
uint32_t msg; // uicmd
uint8_t data[4];
uint32_t whole_size(void)
{
if(size > sizeof(data))
return sizeof(*this) + size - sizeof(data);
else
return sizeof(*this);
}
}MSGSTREAM, *LPMSGSTREAM;
typedef struct _scan_stream
{
uint32_t mode : 5; // see enum scan
uint32_t speed : 27;
uint32_t err; // err message word ID, 0 is normal
}SCANSTREAM, *LPSCANSTREAM;
typedef struct _status_msg
{
uint32_t msg_words_id; // words.h
uint32_t align_h : 3; // align_component
uint32_t align_v : 3; // align_component
uint32_t clear : 4; // clear screen method
uint32_t font : 8; // font size
uint32_t reserved : 14;
}STATMSG, *LPSTATMSG;
#pragma pack(pop)
void init_ui(std::function<void(LPMSGSTREAM)> uicb, bool ui);
void uninit_ui(void);
bool send_message(uint32_t msgid, uint8_t* data = nullptr, uint8_t size = 0); // re-init if return false
bool send_status_message(uint32_t msgid, int align_h = ALIGN_COMPONENT_MID, int align_v = ALIGN_COMPONENT_MID, int font = 16, int clears = CLEAR_ALL);
};

View File

@ -1,12 +1,12 @@
#include "utils.h" #include "utils.h"
#include "ini_file.h" #include "ini_file.h"
#include <huagao/brand.h>
#include <mutex> #include <mutex>
#include <algorithm> #include <algorithm>
#if OS_WIN #if OS_WIN
#include <huagao/brand.h>
#include <direct.h> #include <direct.h>
#include <Windows.h> #include <Windows.h>
#include <time.h> #include <time.h>
@ -218,6 +218,7 @@ class log_cls
FILE* file_; FILE* file_;
int level_; int level_;
int type_; int type_;
int max_file_size_ = MAX_LOG_FILE_SIZE;
std::mutex lock_; std::mutex lock_;
static log_cls* inst_; static log_cls* inst_;
@ -256,15 +257,16 @@ class log_cls
static void log_file(const char* info, void* param, void* param2) static void log_file(const char* info, void* param, void* param2)
{ {
FILE** file = (FILE**)param; FILE** file = (FILE**)param;
log_cls *cls = (log_cls*)param2;
if (*file == nullptr) if (*file == nullptr)
*file = create_log_file(((std::string*)param2)->c_str(), false); *file = create_log_file(cls->path_file_.c_str(), false);
if (*file) if (*file)
{ {
fwrite(info, 1, strlen(info), *file); fwrite(info, 1, strlen(info), *file);
fflush(*file); fflush(*file);
if (ftell(*file) >= MAX_LOG_FILE_SIZE) if (ftell(*file) >= cls->max_file_size_)
{ {
fclose(*file); fclose(*file);
remove(((std::string*)param2)->c_str()); remove(((std::string*)param2)->c_str());
@ -344,6 +346,10 @@ public:
{ {
level_ = level; level_ = level;
} }
void set_max_file_size(int size)
{
max_file_size_ = size;
}
int level(void) int level(void)
{ {
return level_; return level_;
@ -357,7 +363,7 @@ public:
{ {
std::lock_guard<std::mutex> lock(lock_); std::lock_guard<std::mutex> lock(lock_);
log_(info, &file_, &path_file_); log_(info, &file_, this);
} }
std::string get_log_file_path(const char* dst = nullptr) std::string get_log_file_path(const char* dst = nullptr)
{ {
@ -493,6 +499,24 @@ namespace utils
{ {
return u2m(m2u(ansi, CP_ACP).c_str(), CP_UTF8); return u2m(m2u(ansi, CP_ACP).c_str(), CP_UTF8);
} }
static time_t file_time_2_utc(FILETIME ft)
{
SYSTEMTIME sys = { 0 };
struct tm t = { 0 };
if (FileTimeToSystemTime(&ft, &sys))
{
t.tm_year = sys.wYear - 1900;
t.tm_mon = sys.wMonth - 1;
t.tm_mday = sys.wDay;
t.tm_hour = sys.wHour;
t.tm_min = sys.wMinute;
t.tm_sec = sys.wSecond;
}
return mktime(&t);
}
#else #else
// This function will return 'in' string if failed ! // This function will return 'in' string if failed !
static std::string transform_between_gbk_and_utf8(const char* in, bool to_utf8, int *err, const char* ansi = "GBK") static std::string transform_between_gbk_and_utf8(const char* in, bool to_utf8, int *err, const char* ansi = "GBK")
@ -549,6 +573,169 @@ namespace utils
} }
#endif #endif
int parse_utf8_char(const char*& str, char ch[])
{
uint8_t first = *str, ind = 0;
int ret = EINVAL;
if(first < 0x80)
{
ret = 0;
ch[ind++] = *str++;
}
else if(first >= 0x0c00)
{
ret = 0;
first &= 0x0fc;
while(first & 0x80)
{
ch[ind] = str[ind];
if(ch[ind] == 0)
{
ret = ENODATA;
break;
}
ind++;
first <<= 1;
}
if(ret == 0)
str += ind;
}
ch[ind++] = 0;
return ret;
}
int utf16_2_8(unsigned short* &in, char ch[])
{
int len = 0;
int ret = 0, used = 0;
if(in[0] >= 0 && in[0] <= 0x7f)
{
ch[len++] = *in++;
}
else if(in[0] >= 0x0dc00 && in[0] <= 0x0dfff)
{
ret = EINVAL;
}
else
{
unsigned int val = in[0];
if(in[0] >= 0x0d800 && in[0] <= 0x0dbff)
{
if(in[1] < 0x0dc00 || in[1] > 0x0dfff)
ret = EINVAL;
else
{
used = 1;
val = 0x10000 + (((val & 0x3ff) << 10) | (in[1] & 0x3ff));
}
}
if(ret == 0)
{
static unsigned char lead[] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
char *ptr = ch;
used++;
len = 4;
if(val < 0x80)
len = 1;
else if(val < 0x800)
len = 2;
else if(val < 0x10000)
len = 3;
ptr += len;
switch(len)
{
case 4:
*--ptr = (val | 0x80) & 0x0bf;
val >>= 6;
case 3:
*--ptr = (val | 0x80) & 0x0bf;
val >>= 6;
case 2:
*--ptr = (val | 0x80) & 0x0bf;
val >>= 6;
case 1:
*--ptr = val | lead[len];
}
}
}
ch[len++] = 0;
in += used;
return ret;
}
int utf8_2_16(uint8_t* &in, uint16_t& ch)
{
static uint8_t lead[] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
int ret = 0;
if(*in < 0x80)
{
ch = *in++;
}
else if(*in < 0x0E0)
{
ch = *in++;
ch &= ~0x0C0;
if(*in < 0x80)
ret = EINVAL;
else
{
ch <<= 6;
ch |= *in++ & 0x3f;
}
}
else if(*in < 0x0F0)
{
ch = *in++;
ch &= ~0x0E0;
if(*in < 0x80)
ret = EINVAL;
else
{
ch <<= 6;
ch |= *in++ & 0x3f;
if(*in < 0x80)
ret = EINVAL;
else
{
ch <<= 6;
ch |= *in++ & 0x3f;
}
}
}
else
{
ret = EINVAL;
}
return ret;
}
int utf8_2_web(uint8_t* &in, std::string& web)
{
int ret = 0;
while(*in)
{
uint16_t v = 0;
char buf[40] = {0};
ret = utf8_2_16(in, v);
if(ret)
break;
if(v < 0x80)
buf[0] = v;
else
sprintf(buf, "\\u%04X", v);
web += buf;
}
return ret;
}
std::string get_command_result(const char* cmd, int len, int *err) std::string get_command_result(const char* cmd, int len, int *err)
{ {
std::string result(""); std::string result("");
@ -788,8 +975,22 @@ namespace utils
FILE* dst = fopen(file, append ? "a+b" : "wb"); FILE* dst = fopen(file, append ? "a+b" : "wb");
int err = 0; int err = 0;
if (!dst) while (!dst)
{
std::string dir(file);
size_t pos = dir.rfind(PATH_SEPARATOR[0]);
if(pos != std::string::npos)
{
dir.erase(pos);
create_folder(dir.c_str());
dst = fopen(file, append ? "a+b" : "wb");
if(dst)
break;
}
return errno; return errno;
}
if(append && max_size != -1 && ftell(dst) >= max_size) if(append && max_size != -1 && ftell(dst) >= max_size)
fseek(dst, 0, SEEK_SET); fseek(dst, 0, SEEK_SET);
@ -896,6 +1097,26 @@ namespace utils
return str.c_str(); return str.c_str();
} }
int get_stack_size(void)
{
int size = 0;
#if OS_WIN
ULONG_PTR low = 0, up = 0;
GetCurrentThreadStackLimits(&low, &up);
size = up - low;
#else
pthread_attr_t attr;
pthread_getattr_np(pthread_self(), &attr);
// pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, (size_t*)&size);
pthread_attr_destroy(&attr);
#endif
return size;
}
static bool hex_str_2_num(char hex, uint8_t* v) static bool hex_str_2_num(char hex, uint8_t* v)
{ {
*v = 0; *v = 0;
@ -1127,6 +1348,58 @@ namespace utils
return err; return err;
} }
int get_file_time(const char* file, uint64_t* born, uint64_t* modify, uint64_t* last_access)
{
int err = 0;
#if OS_WIN
if (born)
{
WIN32_FILE_ATTRIBUTE_DATA wfd = { 0 };
if (GetFileAttributesExA(file, GetFileExInfoStandard, &wfd))
{
if (born)
*born = file_time_2_utc(wfd.ftCreationTime);
if (modify)
*modify = file_time_2_utc(wfd.ftLastWriteTime);
if (last_access)
*last_access = file_time_2_utc(wfd.ftLastAccessTime);
}
else
{
err = GetLastError();
}
}
#else
if(born)
{
std::string str(get_command_result((std::string("stat -c %W ") + file).c_str()));
if(str.empty())
err = ENOENT;
else
*born = atoi(str.c_str());
}
if(modify && err == 0)
{
std::string str(get_command_result((std::string("stat -c %Y ") + file).c_str()));
if(str.empty())
err = ENOENT;
else
*modify = atoi(str.c_str());
}
if(last_access && err == 0)
{
std::string str(get_command_result((std::string("stat -c %X ") + file).c_str()));
if(str.empty())
err = ENOENT;
else
*last_access = atoi(str.c_str());
}
#endif
return err;
}
int get_memory_usage(uint64_t* peak, uint64_t* now, uint64_t* phymem, uint32_t pid) int get_memory_usage(uint64_t* peak, uint64_t* now, uint64_t* phymem, uint32_t pid)
{ {
@ -1283,6 +1556,10 @@ namespace utils
return std::move(file); return std::move(file);
} }
void set_log_file_max_size(int size)
{
log_cls::instance()->set_max_file_size(size);
}
void uninit(void) void uninit(void)
{ {
log_info(("=====================================--Exited--" + std::to_string(GetCurrentProcessId()) + "=====================================\n\n\n\n").c_str(), LOG_LEVEL_FATAL); log_info(("=====================================--Exited--" + std::to_string(GetCurrentProcessId()) + "=====================================\n\n\n\n").c_str(), LOG_LEVEL_FATAL);
@ -1405,6 +1682,26 @@ namespace utils
return std::move(std::string((char*)&bfh, sizeof(bfh))); return std::move(std::string((char*)&bfh, sizeof(bfh)));
} }
int save_bitmap(const char* file, int w, int h, int bpp, int dpix, int dpiy, void* bits)
{
int err = 0;
FILE* dst = fopen(file, "wb");
if(dst)
{
std::string bih(bitmap_info_header(w, h, bpp, dpix, dpiy)),
bfh(bitmap_file_header((BITMAPINFOHEADER*)&bih[0]));
fwrite(bfh.c_str(), 1, bfh.length(), dst);
fwrite(bih.c_str(), 1, bih.length(), dst);
fwrite(bits, 1, ((BITMAPINFOHEADER*)&bih[0])->biSizeImage, dst);
fclose(dst);
}
else
err = errno;
return err;
}
#if OS_WIN #if OS_WIN
bool run_get_message(HWND hwnd, UINT filter_min, UINT filter_max, std::function<bool(MSG*, bool*)> msghandler) bool run_get_message(HWND hwnd, UINT filter_min, UINT filter_max, std::function<bool(MSG*, bool*)> msghandler)
@ -1770,6 +2067,7 @@ void chronograph::reset()
uint32_t global_info::page_size = 0; uint32_t global_info::page_size = 0;
uint32_t global_info::page_map_size = 0; uint32_t global_info::page_map_size = 0;
uint32_t global_info::cluster_size = 0; uint32_t global_info::cluster_size = 0;
uint32_t global_info::stack_size = 0;
uint32_t global_info::gray_pallete[] = {0}; uint32_t global_info::gray_pallete[] = {0};
global_info::global_info() global_info::global_info()
@ -1784,7 +2082,9 @@ global_info::global_info()
for(int i = 0; i < _countof(global_info::gray_pallete); ++i) for(int i = 0; i < _countof(global_info::gray_pallete); ++i)
global_info::gray_pallete[i] = MAKELONG(MAKEWORD(i, i), MAKEWORD(i, 0)); global_info::gray_pallete[i] = MAKELONG(MAKEWORD(i, i), MAKEWORD(i, 0));
printf("Page size: %u\nMap size: %u\nCluster : %u\n", global_info::page_size, global_info::page_map_size, global_info::cluster_size); path = utils::get_command_result("ulimit -s");
global_info::stack_size = SIZE_KB(atoi(path.c_str()));
printf("Page size: %u\nMap size: %u\nCluster : %u\nStck size: %u\n", global_info::page_size, global_info::page_map_size, global_info::cluster_size, global_info::stack_size);
} }
global_info::~global_info() global_info::~global_info()
{} {}
@ -1896,8 +2196,19 @@ bool platform_event::wait(unsigned timeout)
to.tv_sec = time(nullptr); to.tv_sec = time(nullptr);
} }
#endif #endif
//*/
to.tv_nsec += MSEC_2_NS(timeout);
to.tv_sec += to.tv_nsec / SEC_2_NS(1);
to.tv_nsec %= SEC_2_NS(1);
/*/
to.tv_sec += timeout / 1000; to.tv_sec += timeout / 1000;
to.tv_nsec += (long)((timeout % 1000) * 1000 * 1000); to.tv_nsec += MSEC_2_NS(timeout % 1000);
if(to.tv_nsec >= SEC_2_NS(1))
{
to.tv_sec++;
to.tv_nsec -= SEC_2_NS(1);
}
////////*//////////////////
waited = sem_timedwait(&sem_, &to) == 0; waited = sem_timedwait(&sem_, &to) == 0;
} }
if (log_) if (log_)
@ -2186,6 +2497,7 @@ safe_thread::~safe_thread()
void safe_thread::thread_worker(std::function<void(void)> func, std::string name, void* addr) void safe_thread::thread_worker(std::function<void(void)> func, std::string name, void* addr)
{ {
printf("stack size of thread '%s': %u\n", name.c_str(), utils::get_stack_size());
try try
{ {
utils::to_log(LOG_LEVEL_DEBUG, "+++ safe_thread of '%s(addr: %p) - id: %p' is running ...\n", name.c_str(), addr, GetCurrentThreadId()); utils::to_log(LOG_LEVEL_DEBUG, "+++ safe_thread of '%s(addr: %p) - id: %p' is running ...\n", name.c_str(), addr, GetCurrentThreadId());
@ -2193,6 +2505,10 @@ void safe_thread::thread_worker(std::function<void(void)> func, std::string name
utils::to_log(LOG_LEVEL_DEBUG, "--- safe_thread of '%s - %p' exited.\n", name.c_str(), GetCurrentThreadId()); utils::to_log(LOG_LEVEL_DEBUG, "--- safe_thread of '%s - %p' exited.\n", name.c_str(), GetCurrentThreadId());
return; return;
} }
catch (exception_ex e)
{
utils::to_log(LOG_LEVEL_FATAL, "Exception in thread '%p - %s': %s\n", GetCurrentThreadId(), name.c_str(), e.what());
}
catch (std::exception e) catch (std::exception e)
{ {
utils::to_log(LOG_LEVEL_FATAL, "Exception in thread '%p - %s': %s\n", GetCurrentThreadId(), name.c_str(), e.what()); utils::to_log(LOG_LEVEL_FATAL, "Exception in thread '%p - %s': %s\n", GetCurrentThreadId(), name.c_str(), e.what());
@ -2215,18 +2531,72 @@ void safe_thread::thread_notify_exception(void)
} }
} }
} }
#if OS_WIN
DWORD WINAPI
#else
void*
#endif
safe_thread::raw_thread(void* lp)
{
safe_thread *obj = ((LPCRAWTHRD)lp)->obj;
std::function<void(void)> func = ((LPCRAWTHRD)lp)->func;
std::string name(((LPCRAWTHRD)lp)->name);
void* addr = ((LPCRAWTHRD)lp)->addr;
delete lp;
obj->thread_worker(func, name, addr);
return 0;
}
void safe_thread::set_exception_handler(std::function<void(const char*)> on_exception) void safe_thread::set_exception_handler(std::function<void(const char*)> on_exception)
{ {
excep_handler_ = on_exception; excep_handler_ = on_exception;
} }
int safe_thread::start(std::function<void(void)> f, const char* thread_name, void* addr) int safe_thread::start(std::function<void(void)> f, std::size_t stack, const char* thread_name, void* addr)
{ {
SAFETHRD st; SAFETHRD st;
st.name = thread_name ? thread_name : ""; st.name = thread_name ? thread_name : "";
if(stack == 0)
{
st.raw = false;
st.thread.reset(new std::thread(&safe_thread::thread_worker, this, f, thread_name, addr)); st.thread.reset(new std::thread(&safe_thread::thread_worker, this, f, thread_name, addr));
}
else
{
// st.thread.reset(new std::thread(std::thread(&safe_thread::thread_worker, this, f, thread_name, addr), std::move(stack)));
LPCRAWTHRD param = new CRAWTHRD;
int err = 0;
param->obj = this;
param->func = f;
param->name = thread_name;
param->addr = addr;
#if OS_WIN
st.thread_raw = CreateThread(NULL, stack, &safe_thread::raw_thread, param, 0, nullptr);
if(!st.thread_raw)
err = GetLastError();
#else
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, stack);
st.raw = true;
err = pthread_create(&st.thread_raw, &attr, &safe_thread::raw_thread, param);
if(err)
err = errno;
pthread_attr_destroy(&attr);
#endif
if(err)
{
delete param;
return err;
}
}
{ {
SIMPLE_LOCK(lock_); SIMPLE_LOCK(lock_);
threads_.push_back(st); threads_.push_back(st);
@ -2242,9 +2612,21 @@ int safe_thread::stop(const char* thread_name)
for(int i = 0; i < threads_.size(); ++i) for(int i = 0; i < threads_.size(); ++i)
{ {
if(!thread_name || threads_[i].name == thread_name) if(!thread_name || threads_[i].name == thread_name)
{
if(threads_[i].raw)
{
#if OS_WIN
WaitForSingleObject(threads_[i].thread_raw, INFINITE);
CloseHandle(threads_[i].thread_raw);
#else
pthread_join(threads_[i].thread_raw, nullptr);
#endif
}
else
{ {
if(threads_[i].thread.get() && threads_[i].thread->joinable()) if(threads_[i].thread.get() && threads_[i].thread->joinable())
threads_[i].thread->join(); threads_[i].thread->join();
}
threads_.erase(threads_.begin() + i); threads_.erase(threads_.begin() + i);
ret = 0; ret = 0;
if(thread_name) if(thread_name)
@ -2256,3 +2638,146 @@ int safe_thread::stop(const char* thread_name)
return ret; return ret;
} }
////////////////////////////////////////////////////////////////////////////////////////////////
// safe_file
safe_file::safe_file(const char* path)
{
set_file_path(path);
}
safe_file::~safe_file()
{}
uint32_t safe_file::checksum(const void* data, size_t bytes, uint32_t prev)
{
uint32_t chk = prev, mask[] = {0, 0x0ff, 0x0ffff, 0x0ffffff};
const uint32_t *d = (const uint32_t*)data;
for(int i = 0; i < bytes / 4; ++i)
chk ^= *d++;
chk ^= *d & mask[bytes % 4];
return chk;
}
std::string safe_file::load_with_check(const char* file, bool ignore_lost)
{
FILE* src = fopen(file, "rb");
std::string cont("");
if(src)
{
long l = 0;
fseek(src, 0, SEEK_END);
l = ftell(src);
fseek(src, 0, SEEK_SET);
if(l > sizeof(SFHEAD))
{
SFHEAD head;
fread(&head, 1, sizeof(head), src);
if(head.len == l - sizeof(head))
{
char buf[256] = {0};
int r = fread(buf, 1, sizeof(buf), src);
while(r > 0)
{
cont += std::string(buf, r);
r = fread(buf, 1, sizeof(buf), src);
}
uint32_t chk = checksum(&head, sizeof(head));
chk = checksum(cont.c_str(), cont.length(), chk);
if(chk)
{
utils::to_log(LOG_LEVEL_FATAL, "Checksum(%08x) of safe_file(%s) failed!\n", chk, file);
cont = "";
}
else
{
iotimes_ = head.iotimes;
}
}
else
{
utils::to_log(LOG_LEVEL_FATAL, "safe_file(%s) length(%d) is mismatched(%d)!\n", file, (int)l, head.len);
}
}
else
{
utils::to_log(LOG_LEVEL_FATAL, "safe_file(%s) length(%d) is too small!\n", file, (int)l);
}
fclose(src);
}
else if(!ignore_lost)
{
utils::to_log(LOG_LEVEL_FATAL, "open safe_file(%s) failed: %d(%s).\n", file, errno, strerror(errno));
}
return std::move(cont);
}
void safe_file::set_file_path(const char* path)
{
path_ = path ? path : "";
iotimes_ = 0;
}
std::string safe_file::load(void)
{
std::string cont(load_with_check((path_ + tmp_appendix_).c_str(), true));
if(cont.empty())
cont = load_with_check(path_.c_str(), false);
return std::move(cont);
}
int safe_file::save(const void* data, uint16_t bytes)
{
// io time ...
if(iotimes_ == 0)
{
load();
}
SFHEAD head;
FILE *dst = nullptr;
head.chksum = 0;
head.iotimes = ++iotimes_;
head.len = bytes;
head.time = time(nullptr);
head.chksum = checksum(&head, sizeof(head));
head.chksum = checksum(data, bytes, head.chksum);
dst = fopen((path_ + tmp_appendix_).c_str(), "wb");
if(!dst)
return errno;
fwrite(&head, 1, sizeof(head), dst);
fwrite(data, 1, bytes, dst);
fclose(dst);
return rename((path_ + tmp_appendix_).c_str(), path_.c_str());
}
////////////////////////////////////////////////////////////////////////////////////////////////
// exception_ex
exception_ex::exception_ex() : what_("exception_ex")
{}
exception_ex::exception_ex(const char* msg) : what_(msg ? msg : "")
{}
exception_ex::exception_ex(const exception_ex& r) : what_(r.what_)
{}
exception_ex::~exception_ex()
{}
const char* exception_ex::what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT
{
return what_.c_str();
}
void exception_ex::set_info(const char* info)
{
what_ = info ? info : "";
}

View File

@ -37,6 +37,43 @@ namespace utils
std::string utf82ansi(const char* utf8); std::string utf82ansi(const char* utf8);
std::string ansi2utf8(const char* ansi); std::string ansi2utf8(const char* ansi);
// Function: parse ONE character from a utf8 string
//
// Parameters: str - [in]: head of utf8 string
//
// [out]: beginning of the next character if success or no changes on failure
//
// ch - to receive the character, at least 8 bytes
//
// Return: 0 - success
// EINVAL - invalid utf8 string
// ENODATA - need more data
int parse_utf8_char(const char*& str, char ch[8]);
// Function: transfere from utf16 to utf8
//
// Parameters: in - [in]: head of utf16 beginning
//
// [out]: beginning of the next character if success or no changes on failure
// ch - to receive the character, at least 8 bytes
//
// Return: 0 - success
// EINVAL - invalid utf8 string
// ENODATA - need more data
int utf16_2_8(unsigned short* &in, char ch[8]);
// Function: transfere from utf8 to utf16
//
// Parameters: in - [in]: head of utf8 beginning
//
// [out]: beginning of the next character if success or no changes on failure
// ch - to receive the character
//
// Return: 0 - success
// EINVAL - invalid utf8 string
int utf8_2_16(uint8_t* &in, uint16_t& ch);
int utf8_2_web(uint8_t* &in, std::string& web); // convert 'E5 A5 BD' to '\u597D'
std::string get_command_result(const char* cmd, int len = -1, int *err = nullptr); std::string get_command_result(const char* cmd, int len = -1, int *err = nullptr);
std::string get_local_data_path(void); std::string get_local_data_path(void);
std::string temporary_path(void); std::string temporary_path(void);
@ -54,6 +91,8 @@ namespace utils
const char* to_lower(std::string& str); // return str.c_str() const char* to_lower(std::string& str); // return str.c_str()
const char* trim(std::string& str, const char* sp = "\r\n\t "); // return str.c_str() const char* trim(std::string& str, const char* sp = "\r\n\t "); // return str.c_str()
int get_stack_size(void);
bool from_hex_string(const char* hex, uint8_t* val); bool from_hex_string(const char* hex, uint8_t* val);
bool from_hex_string(const char* hex, uint16_t* val); bool from_hex_string(const char* hex, uint16_t* val);
bool from_hex_string(const char* hex, uint32_t* val); bool from_hex_string(const char* hex, uint32_t* val);
@ -65,6 +104,7 @@ namespace utils
int enum_file(const char* folder, bool recursive, bool/*return false to stop enumeration*/(STDCALL* found)(const char* path_name, bool dir, void* param), void* param); int enum_file(const char* folder, bool recursive, bool/*return false to stop enumeration*/(STDCALL* found)(const char* path_name, bool dir, void* param), void* param);
int move_file(const char* from, const char* to); int move_file(const char* from, const char* to);
int make_file_size(const char* file, uint64_t size); // truncate or extend file size to 'size', create if not exist int make_file_size(const char* file, uint64_t size); // truncate or extend file size to 'size', create if not exist
int get_file_time(const char* file, uint64_t* born, uint64_t* modify, uint64_t* last_access); // all time are both in seconds from 1970-01-01 00:00:00
int get_memory_usage(uint64_t* peak, uint64_t* now, uint64_t* phymem, uint32_t pid = -1); int get_memory_usage(uint64_t* peak, uint64_t* now, uint64_t* phymem, uint32_t pid = -1);
void print_memory_usage(const char* tips, bool to_log_file); void print_memory_usage(const char* tips, bool to_log_file);
@ -73,6 +113,7 @@ namespace utils
// return logging file path if 'type' was LOG_TYPE_FILE // return logging file path if 'type' was LOG_TYPE_FILE
std::string init_log(log_type type, log_level level = LOG_LEVEL_ALL, const char* fn_appendix = nullptr/*appendix to default log-file-name*/); std::string init_log(log_type type, log_level level = LOG_LEVEL_ALL, const char* fn_appendix = nullptr/*appendix to default log-file-name*/);
void set_log_file_max_size(int size = SIZE_MB(10));
void uninit(void); void uninit(void);
void log_info(const char* info, int level = LOG_LEVEL_ALL); void log_info(const char* info, int level = LOG_LEVEL_ALL);
void log_mem_info(const char* desc, const void* data, size_t bytes, int level = LOG_LEVEL_ALL); // log as 0x12345678 00 01 02 ... void log_mem_info(const char* desc, const void* data, size_t bytes, int level = LOG_LEVEL_ALL); // log as 0x12345678 00 01 02 ...
@ -88,6 +129,7 @@ namespace utils
// bitmap header ... // bitmap header ...
std::string bitmap_info_header(int pixel_w, int pixel_h, int bpp, int dpix, int dpiy = 0); // return BITMPINFOHEADER + pallete if need. dpiy same as dpix if was ZERO std::string bitmap_info_header(int pixel_w, int pixel_h, int bpp, int dpix, int dpiy = 0); // return BITMPINFOHEADER + pallete if need. dpiy same as dpix if was ZERO
std::string bitmap_file_header(BITMAPINFOHEADER *lpbi); // return BITMAPFILEHEADER std::string bitmap_file_header(BITMAPINFOHEADER *lpbi); // return BITMAPFILEHEADER
int save_bitmap(const char* file, int w, int h, int bpp, int dpix, int dpiy, void* bits);
#if OS_WIN #if OS_WIN
// Function: pump message recycle (GetMessageW) // Function: pump message recycle (GetMessageW)
@ -256,6 +298,10 @@ public:
{ {
return obj_; return obj_;
} }
T* get(void)
{
return obj_;
}
}; };
// time utility // time utility
@ -289,6 +335,7 @@ public:
static uint32_t page_size; static uint32_t page_size;
static uint32_t page_map_size; static uint32_t page_map_size;
static uint32_t cluster_size; static uint32_t cluster_size;
static uint32_t stack_size;
static uint32_t gray_pallete[256]; static uint32_t gray_pallete[256];
}; };
@ -435,8 +482,10 @@ class safe_thread
{ {
typedef struct _safe_thrd typedef struct _safe_thrd
{ {
bool raw;
std::string name; std::string name;
std::shared_ptr<std::thread> thread; std::shared_ptr<std::thread> thread; // valid when !raw
pthread_t thread_raw; // valid when raw
}SAFETHRD; }SAFETHRD;
volatile bool run_ = true; volatile bool run_ = true;
MUTEX lock_; MUTEX lock_;
@ -448,12 +497,77 @@ class safe_thread
void thread_worker(std::function<void(void)> func, std::string name, void* addr); void thread_worker(std::function<void(void)> func, std::string name, void* addr);
void thread_notify_exception(void); void thread_notify_exception(void);
typedef struct _cr_raw_thread
{
safe_thread* obj;
std::function<void(void)> func;
std::string name;
void* addr;
}CRAWTHRD, *LPCRAWTHRD;
static
#if OS_WIN
DWORD WINAPI
#else
void*
#endif
raw_thread(void* lp);
public: public:
safe_thread(void); safe_thread(void);
~safe_thread(); ~safe_thread();
public: public:
void set_exception_handler(std::function<void(const char*)> on_exception = std::function<void(const char*)>()); void set_exception_handler(std::function<void(const char*)> on_exception = std::function<void(const char*)>());
int start(std::function<void(void)> f, const char* thread_name, void* addr = nullptr); int start(std::function<void(void)> f, std::size_t stack = 0, const char* thread_name = nullptr, void* addr = nullptr);
int stop(const char* thread_name); int stop(const char* thread_name);
}; };
// Purpose: safe file ensure the integrity of small data files
//
// Format: (uint16_t)raw data len + (uint32_t)checksum + raw data
//
// Flow: when save, write into file 'name.new' first, and rename to 'name' at last
// when read, check 'name.new' first, and open name if '.new' not exists
class safe_file
{
typedef struct _sf_head // ensure this struct size be multiple of size uint32_t
{
uint32_t chksum;
uint32_t time;
uint64_t len : 16;
uint64_t iotimes : 48;
}SFHEAD, *LPSFHEAD;
const std::string tmp_appendix_ = ".new";
std::string path_;
uint64_t iotimes_ = 0;
uint32_t checksum(const void* data, size_t bytes, uint32_t prev = 0);
std::string load_with_check(const char* file, bool ignore_lost);
public:
safe_file(const char* path);
~safe_file();
public:
void set_file_path(const char* path);
std::string load(void);
int save(const void* data, uint16_t bytes);
};
#include <exception>
class exception_ex : public std::exception
{
std::string what_;
public:
exception_ex();
exception_ex(const char* msg);
exception_ex(const exception_ex& r);
~exception_ex();
public:
virtual const char*
what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT override;
void set_info(const char* info);
};

157
sdk/base/words.cpp Normal file
View File

@ -0,0 +1,157 @@
#include "words.h"
#define WORDS_AND_ID_IMPL(def, str) \
const char* def = str; \
const int ID_##def = __LINE__;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
WORDS_AND_ID_IMPL(WORDS_COLOR_COLOR, "\345\275\251\350\211\262");
WORDS_AND_ID_IMPL(WORDS_COLOR_GRAY, "\347\201\260\345\272\246");
WORDS_AND_ID_IMPL(WORDS_PAPER_ORIGIN_SIZE, "\345\214\271\351\205\215\345\216\237\345\247\213\345\260\272\345\257\270");
WORDS_AND_ID_IMPL(WORDS_PAPER_MAX_SIZE_CROP, "\346\234\200\345\244\247\346\211\253\346\217\217\345\260\272\345\257\270\350\207\252\345\212\250\350\243\201\345\210\207");
WORDS_AND_ID_IMPL(WORDS_FORBIDDEN, "\347\246\201\347\224\250");
WORDS_AND_ID_IMPL(WORDS_SCAN_CONTINUOUS, "\350\277\236\347\273\255\346\211\253\346\217\217");
WORDS_AND_ID_IMPL(WORDS_FILLBG_CONVEX, "\345\207\270\345\244\232\350\276\271\345\275\242");
WORDS_AND_ID_IMPL(WORDS_MENU_WELCOME, "\346\254\242\350\277\216");
WORDS_AND_ID_IMPL(WORDS_MENU_SELECTED, "\342\210\232");
WORDS_AND_ID_IMPL(WORDS_MENU_RETURN, "\350\277\224\345\233\236\344\270\212\347\272\247\350\217\234\345\215\225");
WORDS_AND_ID_IMPL(WORDS_MENU_SEPARATE_STRENGTH, "\345\210\206\347\272\270\345\274\272\345\272\246");
WORDS_AND_ID_IMPL(WORDS_MENU_LOW, "\344\275\216");
WORDS_AND_ID_IMPL(WORDS_MENU_MID, "\344\270\255");
WORDS_AND_ID_IMPL(WORDS_MENU_HIGH, "\351\253\230");
WORDS_AND_ID_IMPL(WORDS_MENU_POWER, "\344\274\221\347\234\240\346\227\266\351\227\264");
WORDS_AND_ID_IMPL(WORDS_MENU_SLEEP_NONE, "\344\270\215\344\274\221\347\234\240");
WORDS_AND_ID_IMPL(WORDS_MENU_SLEEP_NOW, "\347\253\213\345\215\263\344\274\221\347\234\240");
WORDS_AND_ID_IMPL(WORDS_MENU_SLEEP_5_MIN, "5min");
WORDS_AND_ID_IMPL(WORDS_MENU_SLEEP_10_MIN, "10min");
WORDS_AND_ID_IMPL(WORDS_MENU_SLEEP_20_MIN, "20min");
WORDS_AND_ID_IMPL(WORDS_MENU_SLEEP_30_MIN, "30min");
WORDS_AND_ID_IMPL(WORDS_MENU_SLEEP_1_HOUR, "1h");
WORDS_AND_ID_IMPL(WORDS_MENU_SLEEP_2_HOUR, "2h");
WORDS_AND_ID_IMPL(WORDS_MENU_SLEEP_4_HOUR, "4h");
WORDS_AND_ID_IMPL(WORDS_MENU_LIFTER_POS, "\345\215\207\351\231\215\345\217\260\344\275\215\347\275\256");
WORDS_AND_ID_IMPL(WORDS_MENU_COUNT_MODE, "\350\256\241\346\225\260\346\250\241\345\274\217");
WORDS_AND_ID_IMPL(WORDS_MENU_MANUAL_MODE, "\346\211\213\345\212\250\346\250\241\345\274\217");
WORDS_AND_ID_IMPL(WORDS_MENU_CLEAR_PASSWAY, "\346\270\205\347\220\206\347\272\270\351\201\223");
WORDS_AND_ID_IMPL(WORDS_MENU_HISTORY_COUNT, "\345\216\206\345\217\262\345\274\240\346\225\260");
WORDS_AND_ID_IMPL(WORDS_MENU_ROLLER_COUNT, "\346\273\232\350\275\264\345\274\240\346\225\260");
WORDS_AND_ID_IMPL(WORDS_MENU_RESET_ROLLOER_CNT, "\346\270\205\351\231\244\346\273\232\350\275\264\345\274\240\346\225\260");
WORDS_AND_ID_IMPL(WORDS_MENU_ADJUST_TIME, "\350\260\203\346\225\264\347\263\273\347\273\237\346\227\266\351\227\264");
WORDS_AND_ID_IMPL(WORDS_MENU_ADJUST_HOUR, "\346\227\266\351\222\237");
WORDS_AND_ID_IMPL(WORDS_MENU_ADJUST_MINUTE, "\345\210\206\351\222\237");
WORDS_AND_ID_IMPL(WORDS_MENU_SHUTDOWN, "\345\205\263\346\234\272");
WORDS_AND_ID_IMPL(WORDS_MENU_YES, "\347\241\256\345\256\232");
WORDS_AND_ID_IMPL(WORDS_MENU_NO, "\345\217\226\346\266\210");
WORDS_AND_ID_IMPL(WORDS_FUNCTION_COUNT, "\345\274\240\346\225\260\357\274\232");
WORDS_AND_ID_IMPL(WORDS_STATUS_READY, "\345\260\261\347\273\252");
WORDS_AND_ID_IMPL(WORDS_STATUS_SCANNING_NORMAL, "\346\255\243\345\234\250\346\211\253\346\217\217\342\200\246");
WORDS_AND_ID_IMPL(WORDS_STATUS_SCANNING_COUNT, "\346\255\243\345\234\250\350\256\241\346\225\260\346\211\253\346\217\217\342\200\246");
WORDS_AND_ID_IMPL(WORDS_STATUS_TOTAL, "\346\200\273\357\274\232");
WORDS_AND_ID_IMPL(WORDS_STATUS_NO_PAPER, "\346\227\240\347\272\270");
WORDS_AND_ID_IMPL(WORDS_STATUS_COVER_OPEN, "\347\233\226\346\235\277\346\211\223\345\274\200");
WORDS_AND_ID_IMPL(WORDS_STATUS_FEED_ERR, "\346\220\223\347\272\270\345\244\261\350\264\245");
WORDS_AND_ID_IMPL(WORDS_STATUS_DOUBLE_FEED, "\346\243\200\346\265\213\345\210\260\345\217\214\345\274\240");
WORDS_AND_ID_IMPL(WORDS_STATUS_STAPLE, "\346\243\200\346\265\213\345\210\260\351\222\211\344\271\246\351\222\211");
WORDS_AND_ID_IMPL(WORDS_STATUS_ASKEW, "\347\272\270\345\274\240\346\255\252\346\226\234");
WORDS_AND_ID_IMPL(WORDS_STATUS_CIS_TIMEOUT, "\345\217\226\345\233\276\350\266\205\346\227\266");
WORDS_AND_ID_IMPL(WORDS_STATUS_JAMMED, "\345\215\241\347\272\270");
WORDS_AND_ID_IMPL(WORDS_STATUS_CAPTURE_FAILED, "\351\207\207\345\233\276\345\244\261\350\264\245");
WORDS_AND_ID_IMPL(WORDS_STATUS_CIS_OUT_OF_MEM, "\347\274\223\345\206\262\345\214\272\350\200\227\345\260\275");
WORDS_AND_ID_IMPL(WORDS_STATUS_DEVICE_HD_001, "\347\241\254\344\273\266\351\224\231\350\257\257001");
WORDS_AND_ID_IMPL(WORDS_STATUS_DEVICE_HD_002, "\347\241\254\344\273\266\351\224\231\350\257\257002");
WORDS_AND_ID_IMPL(WORDS_STATUS_DEVICE_HD_003, "\347\241\254\344\273\266\351\224\231\350\257\257003");
WORDS_AND_ID_IMPL(WORDS_STATUS_SCANNER_CONN, "\346\211\253\346\217\217\347\250\213\345\272\217\345\267\262\351\200\200\345\207\272");
WORDS_AND_ID_IMPL(WORDS_STATUS_SCANNER_CONN_1, "\346\211\253\346\217\217\347\250\213\345\272\217\345\267\262\350\277\220\350\241\214");
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
#define RETURN_ID_STR(val, def) \
if(val == ID_##def) \
return def;
const char* words_from_id(int id)
{
RETURN_ID_STR(id, WORDS_COLOR_COLOR);
RETURN_ID_STR(id, WORDS_COLOR_GRAY);
RETURN_ID_STR(id, WORDS_PAPER_ORIGIN_SIZE);
RETURN_ID_STR(id, WORDS_PAPER_MAX_SIZE_CROP);
RETURN_ID_STR(id, WORDS_FORBIDDEN);
RETURN_ID_STR(id, WORDS_SCAN_CONTINUOUS);
RETURN_ID_STR(id, WORDS_FILLBG_CONVEX);
RETURN_ID_STR(id, WORDS_MENU_WELCOME);
RETURN_ID_STR(id, WORDS_MENU_SELECTED);
RETURN_ID_STR(id, WORDS_MENU_RETURN);
RETURN_ID_STR(id, WORDS_MENU_SEPARATE_STRENGTH);
RETURN_ID_STR(id, WORDS_MENU_LOW);
RETURN_ID_STR(id, WORDS_MENU_MID);
RETURN_ID_STR(id, WORDS_MENU_HIGH);
RETURN_ID_STR(id, WORDS_MENU_POWER);
RETURN_ID_STR(id, WORDS_MENU_SLEEP_NONE);
RETURN_ID_STR(id, WORDS_MENU_SLEEP_NOW);
RETURN_ID_STR(id, WORDS_MENU_SLEEP_5_MIN);
RETURN_ID_STR(id, WORDS_MENU_SLEEP_10_MIN);
RETURN_ID_STR(id, WORDS_MENU_SLEEP_20_MIN);
RETURN_ID_STR(id, WORDS_MENU_SLEEP_30_MIN);
RETURN_ID_STR(id, WORDS_MENU_SLEEP_1_HOUR);
RETURN_ID_STR(id, WORDS_MENU_SLEEP_2_HOUR);
RETURN_ID_STR(id, WORDS_MENU_SLEEP_4_HOUR);
RETURN_ID_STR(id, WORDS_MENU_LIFTER_POS);
RETURN_ID_STR(id, WORDS_MENU_COUNT_MODE);
RETURN_ID_STR(id, WORDS_MENU_MANUAL_MODE);
RETURN_ID_STR(id, WORDS_MENU_CLEAR_PASSWAY);
RETURN_ID_STR(id, WORDS_MENU_HISTORY_COUNT);
RETURN_ID_STR(id, WORDS_MENU_ROLLER_COUNT);
RETURN_ID_STR(id, WORDS_MENU_RESET_ROLLOER_CNT);
RETURN_ID_STR(id, WORDS_MENU_SHUTDOWN);
RETURN_ID_STR(id, WORDS_MENU_YES);
RETURN_ID_STR(id, WORDS_MENU_NO);
RETURN_ID_STR(id, WORDS_FUNCTION_COUNT);
RETURN_ID_STR(id, WORDS_STATUS_READY);
RETURN_ID_STR(id, WORDS_STATUS_SCANNING_NORMAL);
RETURN_ID_STR(id, WORDS_STATUS_SCANNING_COUNT);
RETURN_ID_STR(id, WORDS_STATUS_TOTAL);
RETURN_ID_STR(id, WORDS_STATUS_NO_PAPER);
RETURN_ID_STR(id, WORDS_STATUS_COVER_OPEN);
RETURN_ID_STR(id, WORDS_STATUS_FEED_ERR);
RETURN_ID_STR(id, WORDS_STATUS_DOUBLE_FEED);
RETURN_ID_STR(id, WORDS_STATUS_STAPLE);
RETURN_ID_STR(id, WORDS_STATUS_ASKEW);
RETURN_ID_STR(id, WORDS_STATUS_CIS_TIMEOUT);
RETURN_ID_STR(id, WORDS_STATUS_JAMMED);
RETURN_ID_STR(id, WORDS_STATUS_CAPTURE_FAILED);
RETURN_ID_STR(id, WORDS_STATUS_CIS_OUT_OF_MEM);
RETURN_ID_STR(id, WORDS_STATUS_DEVICE_HD_001);
RETURN_ID_STR(id, WORDS_STATUS_DEVICE_HD_002);
RETURN_ID_STR(id, WORDS_STATUS_DEVICE_HD_003);
RETURN_ID_STR(id, WORDS_STATUS_SCANNER_CONN);
return "";
}

View File

@ -3,14 +3,92 @@
// Date: 2024-01-24 // Date: 2024-01-24
#pragma once #pragma once
#define WORDS_COLOR_COLOR "\345\275\251\350\211\262" #define WORDS_AND_ID_DECL(def) \
#define WORDS_COLOR_GRAY "\347\201\260\345\272\246" extern const char* def; \
extern const int ID_##def;
#define WORDS_PAPER_ORIGIN_SIZE "\345\214\271\351\205\215\345\216\237\345\247\213\345\260\272\345\257\270"
#define WORDS_PAPER_MAX_SIZE_CROP "\346\234\200\345\244\247\346\211\253\346\217\217\345\260\272\345\257\270\350\207\252\345\212\250\350\243\201\345\210\207"
#define WORDS_FORBIDDEN "\347\246\201\347\224\250" #define WORDS_STR(tail) WORDS_##tail
#define WORDS_ID(tail) ID_WORDS_##tail
#define MENU_WORDS_STR(tail) WORDS_MENU_##tail
#define MENU_WORDS_ID(tail) ID_WORDS_MENU_##tail
#define STATUS_WORDS_STR(tail) WORDS_STATUS_##tail
#define STATUS_WORDS_ID(tail) ID_WORDS_STATUS_##tail
#define WORDS_SCAN_CONTINUOUS "\350\277\236\347\273\255\346\211\253\346\217\217"
#define WORDS_FILLBG_CONVEX "\345\207\270\345\244\232\350\276\271\345\275\242"
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
const char* words_from_id(int id);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
WORDS_AND_ID_DECL(WORDS_COLOR_COLOR);
WORDS_AND_ID_DECL(WORDS_COLOR_GRAY);
WORDS_AND_ID_DECL(WORDS_PAPER_ORIGIN_SIZE);
WORDS_AND_ID_DECL(WORDS_PAPER_MAX_SIZE_CROP);
WORDS_AND_ID_DECL(WORDS_FORBIDDEN);
WORDS_AND_ID_DECL(WORDS_SCAN_CONTINUOUS);
WORDS_AND_ID_DECL(WORDS_FILLBG_CONVEX);
WORDS_AND_ID_DECL(WORDS_MENU_WELCOME);
WORDS_AND_ID_DECL(WORDS_MENU_SELECTED);
WORDS_AND_ID_DECL(WORDS_MENU_RETURN);
WORDS_AND_ID_DECL(WORDS_MENU_SEPARATE_STRENGTH);
WORDS_AND_ID_DECL(WORDS_MENU_LOW);
WORDS_AND_ID_DECL(WORDS_MENU_MID);
WORDS_AND_ID_DECL(WORDS_MENU_HIGH);
WORDS_AND_ID_DECL(WORDS_MENU_POWER);
WORDS_AND_ID_DECL(WORDS_MENU_SLEEP_NONE);
WORDS_AND_ID_DECL(WORDS_MENU_SLEEP_NOW);
WORDS_AND_ID_DECL(WORDS_MENU_SLEEP_5_MIN);
WORDS_AND_ID_DECL(WORDS_MENU_SLEEP_10_MIN);
WORDS_AND_ID_DECL(WORDS_MENU_SLEEP_20_MIN);
WORDS_AND_ID_DECL(WORDS_MENU_SLEEP_30_MIN);
WORDS_AND_ID_DECL(WORDS_MENU_SLEEP_1_HOUR);
WORDS_AND_ID_DECL(WORDS_MENU_SLEEP_2_HOUR);
WORDS_AND_ID_DECL(WORDS_MENU_SLEEP_4_HOUR);
WORDS_AND_ID_DECL(WORDS_MENU_LIFTER_POS);
WORDS_AND_ID_DECL(WORDS_MENU_COUNT_MODE);
WORDS_AND_ID_DECL(WORDS_MENU_MANUAL_MODE);
WORDS_AND_ID_DECL(WORDS_MENU_CLEAR_PASSWAY);
WORDS_AND_ID_DECL(WORDS_MENU_HISTORY_COUNT);
WORDS_AND_ID_DECL(WORDS_MENU_ROLLER_COUNT);
WORDS_AND_ID_DECL(WORDS_MENU_RESET_ROLLOER_CNT);
WORDS_AND_ID_DECL(WORDS_MENU_ADJUST_TIME);
WORDS_AND_ID_DECL(WORDS_MENU_ADJUST_HOUR);
WORDS_AND_ID_DECL(WORDS_MENU_ADJUST_MINUTE);
WORDS_AND_ID_DECL(WORDS_MENU_SHUTDOWN);
WORDS_AND_ID_DECL(WORDS_MENU_YES);
WORDS_AND_ID_DECL(WORDS_MENU_NO);
WORDS_AND_ID_DECL(WORDS_FUNCTION_COUNT);
WORDS_AND_ID_DECL(WORDS_STATUS_READY);
WORDS_AND_ID_DECL(WORDS_STATUS_SCANNING_NORMAL);
WORDS_AND_ID_DECL(WORDS_STATUS_SCANNING_COUNT);
WORDS_AND_ID_DECL(WORDS_STATUS_TOTAL);
WORDS_AND_ID_DECL(WORDS_STATUS_NO_PAPER);
WORDS_AND_ID_DECL(WORDS_STATUS_COVER_OPEN);
WORDS_AND_ID_DECL(WORDS_STATUS_FEED_ERR);
WORDS_AND_ID_DECL(WORDS_STATUS_DOUBLE_FEED);
WORDS_AND_ID_DECL(WORDS_STATUS_STAPLE);
WORDS_AND_ID_DECL(WORDS_STATUS_ASKEW);
WORDS_AND_ID_DECL(WORDS_STATUS_CIS_TIMEOUT);
WORDS_AND_ID_DECL(WORDS_STATUS_JAMMED);
WORDS_AND_ID_DECL(WORDS_STATUS_CAPTURE_FAILED);
WORDS_AND_ID_DECL(WORDS_STATUS_CIS_OUT_OF_MEM);
WORDS_AND_ID_DECL(WORDS_STATUS_DEVICE_HD_001);
WORDS_AND_ID_DECL(WORDS_STATUS_DEVICE_HD_002);
WORDS_AND_ID_DECL(WORDS_STATUS_DEVICE_HD_003);
WORDS_AND_ID_DECL(WORDS_STATUS_SCANNER_CONN);

View File

@ -794,6 +794,7 @@ bool device_option::parse_simple_logic_expression(gb_json* root, const char* exp
{ {
v = std::string(next, tag - next); v = std::string(next, tag - next);
calc.val2 = device_option::from_text_value(n.c_str(), v.c_str()); calc.val2 = device_option::from_text_value(n.c_str(), v.c_str());
ret = device_option::get_between(n.c_str(), &calc.compare);
} }
} }
} }