diff --git a/hgdriver/hgdev/hg_scanner.cpp b/hgdriver/hgdev/hg_scanner.cpp index 4b407ef..0fc1a7f 100644 --- a/hgdriver/hgdev/hg_scanner.cpp +++ b/hgdriver/hgdev/hg_scanner.cpp @@ -17,7 +17,6 @@ - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // @@ -91,7 +90,7 @@ hg_scanner::hg_scanner(ONLNSCANNER* dev, imgproc_mgr* imgproc, hguser* user, std { thread_image_processor(); }; - imgpr_thread_.start(tf, "hg_scanner::thread_image_processor", NULL); + imgpr_thread_.start(tf, 0, "hg_scanner::thread_image_processor"); #else imgpr_thread_.reset(new std::thread(&hg_scanner::thread_image_processor, this)); #endif @@ -258,10 +257,9 @@ void hg_scanner::thread_image_processor(void) } void hg_scanner::process_image(image_holder_ptr img) { - PACKIMAGE h; + bool addref = true; - h.prc_stage = -1; - if (!dump_path_.empty() && img->get_info()->prc_stage != h.prc_stage) + if (!dump_path_.empty()) { int stage = img->get_info()->prc_stage; char alg[128] = { 0 }; @@ -272,11 +270,34 @@ void hg_scanner::process_image(image_holder_ptr img) sprintf(alg, "%04X_Unk", stage); 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) { - img->add_ref(); - final_imgs_.save(img, true); + // decode ... +#ifdef TEST_HGSCANNER +#else + cv::ImreadModes mode = img->get_info()->channels == 1 ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR; + std::vector 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(); + final_imgs_.save(img, true); } image_holder_ptr hg_scanner::wait_image(void) { @@ -488,7 +509,12 @@ 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->depth = ptr->get_info()->bpp; // 此处指每一个颜色分量的位深,我们的扫描仪固定为“8” pii->last_frame = SANE_TRUE; // 一幅图片如果各个分量相互分离,则最后一个分量的时候设置为true。彩色图像RGB时也只有一“帧”,所以也为true - pii->format = ptr->get_info()->channels == 3 ? SANE_FRAME_RGB : SANE_FRAME_GRAY; + 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->lines = ptr->get_info()->height; 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); } + diff --git a/hgdriver/hgdev/scanner/async_usb_host.cpp b/hgdriver/hgdev/scanner/async_usb_host.cpp index 61f5b08..d9fcb0f 100644 --- a/hgdriver/hgdev/scanner/async_usb_host.cpp +++ b/hgdriver/hgdev/scanner/async_usb_host.cpp @@ -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:: * r)(void) = &async_usb_host::thread_read_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_w, "async_usb_host::thread_write_bulk", *(void**)&w); - worker_.start(thread_r, "async_usb_host::thread_read_bulk", *(void**)&r); + worker_.start(thread_p, 0, "async_usb_host::thread_pump_task", *(void**)&p); + worker_.start(thread_w, 0, "async_usb_host::thread_write_bulk", *(void**)&w); + worker_.start(thread_r, 0, "async_usb_host::thread_read_bulk", *(void**)&r); #else 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)); diff --git a/hgdriver/hgdev/usb_manager.cpp b/hgdriver/hgdev/usb_manager.cpp index 7665ec0..ec9e6fe 100644 --- a/hgdriver/hgdev/usb_manager.cpp +++ b/hgdriver/hgdev/usb_manager.cpp @@ -183,7 +183,7 @@ usb_manager::usb_manager() : run_(true) 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 if (!usb_notify_thread_.get()) { @@ -281,7 +281,7 @@ void usb_manager::init_notify_thread() 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 if(!usb_monitor_thread_.get()) { diff --git a/sdk/base/data.cpp b/sdk/base/data.cpp index 9c8b048..cc7395e 100644 --- a/sdk/base/data.cpp +++ b/sdk/base/data.cpp @@ -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(buf, size), destroy_(destroy), param_(param) -{} +dyn_mem_shared::dyn_mem_shared(void* buf, size_t size, BEFORE_DESTROY_FUNC destroy) + : dyn_mem(buf, size), destroy_(destroy) +{ + memset(param_, 0, sizeof(param_)); +} dyn_mem_shared::~dyn_mem_shared() { 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(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid +image_packet::image_packet(LPPACKIMAGE head, std::shared_ptr> img + , uint32_t scanid , const void* info, size_t info_size) : 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; paper_ind_ = head->pos.paper_ind; - img->add_ref(); if(info && info_size) info_ = std::string((const char*)info, info_size); else @@ -926,7 +949,7 @@ image_packet::image_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid pack->payload_len = sizeof(PACKIMAGE); memcpy(pimg, head, sizeof(*pimg)); - pimg->data_size = img->get_rest(); + pimg->data_size = img->size(); pimg->info_size = info_size; 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() { head_->release(); - img_->release(); } 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) { - 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 @@ -1000,15 +1022,15 @@ int image_packet::fetch_data(void* buf, uint32_t* size) } else { - if(*size + offset_ >= img_->get_rest()) + if(*size + offset_ >= img_->size()) { - memcpy(buf, img_->ptr() + offset_, img_->get_rest() - offset_); - *size = img_->get_rest() - offset_; - offset_ = img_->get_rest(); + memcpy(buf, img_->data() + offset_, img_->size() - offset_); + *size = img_->size() - offset_; + offset_ = img_->size(); } else { - memcpy(buf, img_->ptr() + offset_, *size); + memcpy(buf, img_->data() + offset_, *size); offset_ += *size; } } diff --git a/sdk/base/data.h b/sdk/base/data.h index 6373660..f880a5b 100644 --- a/sdk/base/data.h +++ b/sdk/base/data.h @@ -11,6 +11,9 @@ #include #define CLS_PTR(cls) typedef cls* cls##_ptr; +#ifndef uchar +typedef unsigned char uchar; +#endif //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -213,7 +216,7 @@ public: // #define STAT_MEM #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 class dyn_mem : public data_source @@ -263,13 +266,17 @@ public: class dyn_mem_shared : public dyn_mem { BEFORE_DESTROY_FUNC destroy_ = BEFORE_DESTROY_FUNC(); - void* param_ = nullptr; + void* param_[4]; 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: ~dyn_mem_shared(); + +public: + bool set_param(void* param, int index = 0); + void* get_param(int index = 0); }; class file_reader : public data_source @@ -305,7 +312,8 @@ public: class image_packet : public data_source { - dyn_mem* img_; + // dyn_mem* img_; + std::shared_ptr> img_; dyn_mem* head_; uint32_t offset_; uint32_t paper_ind_ = 0; @@ -314,7 +322,7 @@ class image_packet : public data_source std::string pos_str_; 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> img, uint32_t scanid, const void* info = nullptr, size_t info_size = 0); protected: virtual ~image_packet(); diff --git a/sdk/base/packet.h b/sdk/base/packet.h index cc501de..a39ce0a 100644 --- a/sdk/base/packet.h +++ b/sdk/base/packet.h @@ -40,6 +40,12 @@ // protocol version, The first thing to do after connecting is to check whether the field is compatible !!! #define PROTOCOL_VER MAKE_WORD(0, 1) +// resource manager callback +#define CHK_RES_FUNC std::function +#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 !!! enum cancel_io @@ -53,7 +59,7 @@ enum ep0_req USB_REQ_EP0_GET_STATUS, // 鑾峰彇鍚勫伐浣滅嚎绋嬬姸鎬, return EP0REPLYSTATUS. req = me, ind = 0, val = bool: whether write log, len = sizeof(EP0REPLYSTATUS) USB_REQ_EP0_CANCEL_IO, // 璁剧疆褰撳墠IO鏁版嵁鐨勬湁鏁堟. req = me, ind = 0, val = 0, len = sizeof(uint32_t), discard IO data when data is CANCEL_IO_CANCEL // work-flow: write control with 'CANCEL_IO_CANCEL', write bulk with 1 byte, write control with not 'CANCEL_IO_CANCEL' to restore - USB_REQ_EP0_SET_ENCRYPT, // 璁剧疆鍔犲瘑鏂瑰紡锛 req = me, ind = 0, val = 0, len = sizeof(PACK_BASE) + USB_REQ_EP0_SET_ENCRYPT, // 璁剧疆鍔犲瘑鏂瑰紡锛 req = me, ind = 0, val = 0, len = sizeof(PACK_BASE) }; enum woker_status { @@ -64,6 +70,15 @@ enum woker_status WORKER_STATUS_RESET, // in reset(close and reopen) process 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 { @@ -123,9 +138,9 @@ enum packet_cmd enum img_cb_type { - IMG_CB_IMAGE = 0, - IMG_CB_STATUS, - IMG_CB_STOPPED, + IMG_CB_IMAGE = 0, + IMG_CB_STATUS, + IMG_CB_STOPPED, }; // option affection if value changed, see SANE_INFO_xxx @@ -160,13 +175,13 @@ enum img_compression enum img_status { IMG_STATUS_OK = 0, // normal - IMG_STATUS_DOUBLE = 1 << 0, // double-feeded paper - IMG_STATUS_JAM = 1 << 1, // jammed paper - IMG_STATUS_STAPLE = 1 << 2, // staples on the paper + IMG_STATUS_DOUBLE = 1 << 0, // double-feeded paper + IMG_STATUS_JAM = 1 << 1, // jammed paper + IMG_STATUS_STAPLE = 1 << 2, // staples on the paper IMG_STATUS_SIZE_ERR = 1 << 3, // size check failed - IMG_STATUS_DOGEAR = 1 << 4, // paper has dogear - common + IMG_STATUS_DOGEAR = 1 << 4, // paper has dogear - common IMG_STATUS_DOGEAR_PARTIAL = 1 << 5, // dogear - scanned partial - IMG_STATUS_BLANK = 1 << 6, // blank image + IMG_STATUS_BLANK = 1 << 6, // blank image }; enum data_type { @@ -230,14 +245,14 @@ typedef struct _ep0_reply uint32_t task_required_bytes; // required byte of this packet 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 -}EP0REPLYSTATUS, * LPEP0REPLYSTATUS; +}EP0REPLYSTATUS, *LPEP0REPLYSTATUS; typedef struct _peer_config { uint64_t pid; // [in] - host pc process id; [out] - usb service process id uint32_t io_size; // IO buffer size uint16_t ver; // protocol version -}PEERCFG, * LPPEERCFG; +}PEERCFG, *LPPEERCFG; 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 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. -}CFGVAL, * LPCFGVAL; +}CFGVAL, *LPCFGVAL; typedef struct _img_pos { @@ -324,7 +339,7 @@ typedef struct _tx_file uint64_t size; // total size uint64_t offset; // offset in the file char path[2]; // file full path-name -}TXFILE, * LPTXFILE; +}TXFILE, *LPTXFILE; typedef struct _file_info { OPERTOKEN token; // operation token, returned by command PACK_CMD_TOKEN_GET diff --git a/sdk/base/plat_types.h b/sdk/base/plat_types.h index 89d38d0..dde7936 100644 --- a/sdk/base/plat_types.h +++ b/sdk/base/plat_types.h @@ -12,9 +12,12 @@ #define SIZE_MB(n) SIZE_KB((n) * 1024) #define SIZE_GB(n) SIZE_MB((n) * 1024) -#define SEC_2_MS(s) ((s) * 1000) -#define MSEC_2_US(ms) ((ms) * 1000) +#define USEC_2_NS(us) ((long)(us) * 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_NS(s) USEC_2_NS(SEC_2_US(s)) #define MM_PER_INCH 25.4f #define IS_DOUBLE_EQUAL(a, b) fabs((a) - (b)) < .000001 @@ -104,6 +107,11 @@ typedef struct _size u_int32_t cx; u_int32_t cy; }SIZE, *LPSIZE; +typedef struct _point +{ + u_int32_t x; + u_int32_t y; +}POINT, *LPPOINT; #pragma pack(pop) @@ -175,6 +183,10 @@ extern uint64_t GetCurrentThreadId(void); #define FSEEK _fseeki64 #define FTELL _ftelli64 #define pid_t int +#define pthread_t HANDLE + +#define _GLIBCXX_TXN_SAFE_DYN +#define _GLIBCXX_USE_NOEXCEPT #endif diff --git a/sdk/base/ui.cpp b/sdk/base/ui.cpp new file mode 100644 index 0000000..7ebd4b0 --- /dev/null +++ b/sdk/base/ui.cpp @@ -0,0 +1,410 @@ +#include "ui.h" + +#include "utils.h" +#include +#include +#include +#include + +#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 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 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 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 cb_; + safe_fifo 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 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 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)); + } +}; diff --git a/sdk/base/ui.h b/sdk/base/ui.h new file mode 100644 index 0000000..9ed3b5a --- /dev/null +++ b/sdk/base/ui.h @@ -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 +#include + +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 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); +}; diff --git a/sdk/base/utils.cpp b/sdk/base/utils.cpp index a3a62ba..700f817 100644 --- a/sdk/base/utils.cpp +++ b/sdk/base/utils.cpp @@ -1,12 +1,12 @@ 锘#include "utils.h" #include "ini_file.h" -#include #include #include #if OS_WIN +#include #include #include #include @@ -218,6 +218,7 @@ class log_cls FILE* file_; int level_; int type_; + int max_file_size_ = MAX_LOG_FILE_SIZE; std::mutex lock_; static log_cls* inst_; @@ -256,15 +257,16 @@ class log_cls static void log_file(const char* info, void* param, void* param2) { FILE** file = (FILE**)param; + log_cls *cls = (log_cls*)param2; 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) { fwrite(info, 1, strlen(info), *file); fflush(*file); - if (ftell(*file) >= MAX_LOG_FILE_SIZE) + if (ftell(*file) >= cls->max_file_size_) { fclose(*file); remove(((std::string*)param2)->c_str()); @@ -344,6 +346,10 @@ public: { level_ = level; } + void set_max_file_size(int size) + { + max_file_size_ = size; + } int level(void) { return level_; @@ -357,7 +363,7 @@ public: { std::lock_guard lock(lock_); - log_(info, &file_, &path_file_); + log_(info, &file_, this); } 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); } + + 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 // 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") @@ -549,6 +573,169 @@ namespace utils } #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 result(""); @@ -788,8 +975,22 @@ namespace utils FILE* dst = fopen(file, append ? "a+b" : "wb"); 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; + } if(append && max_size != -1 && ftell(dst) >= max_size) fseek(dst, 0, SEEK_SET); @@ -896,6 +1097,26 @@ namespace utils 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) { *v = 0; @@ -1127,6 +1348,58 @@ namespace utils 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) { @@ -1283,6 +1556,10 @@ namespace utils return std::move(file); } + void set_log_file_max_size(int size) + { + log_cls::instance()->set_max_file_size(size); + } void uninit(void) { 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))); } + 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 bool run_get_message(HWND hwnd, UINT filter_min, UINT filter_max, std::function msghandler) @@ -1770,6 +2067,7 @@ void chronograph::reset() uint32_t global_info::page_size = 0; uint32_t global_info::page_map_size = 0; uint32_t global_info::cluster_size = 0; +uint32_t global_info::stack_size = 0; uint32_t global_info::gray_pallete[] = {0}; global_info::global_info() @@ -1784,7 +2082,9 @@ global_info::global_info() for(int i = 0; i < _countof(global_info::gray_pallete); ++i) 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() {} @@ -1895,9 +2195,20 @@ bool platform_event::wait(unsigned timeout) utils::to_log(LOG_LEVEL_DEBUG, "clock_gettime failed: %d - %s\n", errno, strerror(errno)); 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_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; } if (log_) @@ -2186,6 +2497,7 @@ safe_thread::~safe_thread() void safe_thread::thread_worker(std::function func, std::string name, void* addr) { + printf("stack size of thread '%s': %u\n", name.c_str(), utils::get_stack_size()); try { 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 func, std::string name utils::to_log(LOG_LEVEL_DEBUG, "--- safe_thread of '%s - %p' exited.\n", name.c_str(), GetCurrentThreadId()); 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) { 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 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 on_exception) { excep_handler_ = on_exception; } -int safe_thread::start(std::function f, const char* thread_name, void* addr) +int safe_thread::start(std::function f, std::size_t stack, const char* thread_name, void* addr) { SAFETHRD st; st.name = thread_name ? thread_name : ""; - st.thread.reset(new std::thread(&safe_thread::thread_worker, this, f, thread_name, addr)); - + if(stack == 0) + { + st.raw = false; + 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_); threads_.push_back(st); @@ -2243,8 +2613,20 @@ int safe_thread::stop(const char* thread_name) { if(!thread_name || threads_[i].name == thread_name) { - if(threads_[i].thread.get() && threads_[i].thread->joinable()) - threads_[i].thread->join(); + 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()) + threads_[i].thread->join(); + } threads_.erase(threads_.begin() + i); ret = 0; if(thread_name) @@ -2255,4 +2637,147 @@ int safe_thread::stop(const char* thread_name) } return ret; -} \ No newline at end of file +} + + +//////////////////////////////////////////////////////////////////////////////////////////////// +// 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 : ""; +} diff --git a/sdk/base/utils.h b/sdk/base/utils.h index 6353505..0565f5e 100644 --- a/sdk/base/utils.h +++ b/sdk/base/utils.h @@ -37,6 +37,43 @@ namespace utils std::string utf82ansi(const char* utf8); 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_local_data_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* 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, uint16_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 move_file(const char* from, const char* to); int make_file_size(const char* file, uint64_t size); // truncate or extend file size to 'size', create if not exist + int get_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); 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 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 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 ... @@ -88,6 +129,7 @@ namespace utils // 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_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 // Function: pump message recycle (GetMessageW) @@ -256,6 +298,10 @@ public: { return obj_; } + T* get(void) + { + return obj_; + } }; // time utility @@ -289,6 +335,7 @@ public: static uint32_t page_size; static uint32_t page_map_size; static uint32_t cluster_size; + static uint32_t stack_size; static uint32_t gray_pallete[256]; }; @@ -435,8 +482,10 @@ class safe_thread { typedef struct _safe_thrd { + bool raw; std::string name; - std::shared_ptr thread; + std::shared_ptr thread; // valid when !raw + pthread_t thread_raw; // valid when raw }SAFETHRD; volatile bool run_ = true; MUTEX lock_; @@ -448,12 +497,77 @@ class safe_thread void thread_worker(std::function func, std::string name, void* addr); void thread_notify_exception(void); + typedef struct _cr_raw_thread + { + safe_thread* obj; + std::function func; + std::string name; + void* addr; + }CRAWTHRD, *LPCRAWTHRD; + static +#if OS_WIN + DWORD WINAPI +#else + void* +#endif + raw_thread(void* lp); + public: safe_thread(void); ~safe_thread(); public: void set_exception_handler(std::function on_exception = std::function()); - int start(std::function f, const char* thread_name, void* addr = nullptr); + int start(std::function f, std::size_t stack = 0, const char* thread_name = nullptr, void* addr = nullptr); 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 +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); +}; diff --git a/sdk/base/words.cpp b/sdk/base/words.cpp new file mode 100644 index 0000000..59496c8 --- /dev/null +++ b/sdk/base/words.cpp @@ -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 ""; +} diff --git a/sdk/base/words.h b/sdk/base/words.h index 5184458..2f6a48e 100644 --- a/sdk/base/words.h +++ b/sdk/base/words.h @@ -3,14 +3,92 @@ // Date: 2024-01-24 #pragma once -#define WORDS_COLOR_COLOR "\345\275\251\350\211\262" -#define WORDS_COLOR_GRAY "\347\201\260\345\272\246" +#define WORDS_AND_ID_DECL(def) \ + 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); \ No newline at end of file diff --git a/sdk/sane_opt_json/device_opt.cpp b/sdk/sane_opt_json/device_opt.cpp index dc59f78..02180d2 100644 --- a/sdk/sane_opt_json/device_opt.cpp +++ b/sdk/sane_opt_json/device_opt.cpp @@ -794,6 +794,7 @@ bool device_option::parse_simple_logic_expression(gb_json* root, const char* exp { v = std::string(next, tag - next); calc.val2 = device_option::from_text_value(n.c_str(), v.c_str()); + ret = device_option::get_between(n.c_str(), &calc.compare); } } }