From 1443eb94457809d9ca0d305b22b897ef596f1022 Mon Sep 17 00:00:00 2001 From: gb <741021719@qq.com> Date: Thu, 21 Mar 2024 15:16:39 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96UI=E4=B8=8E=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E9=80=9A=E4=BF=A1=EF=BC=9B=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E7=94=B1=E6=9C=8D=E5=8A=A1=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=E5=8A=A8=E6=80=81=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/sane-opts/scanner_const_opts.txt | 26 +- hardware/hardware.cpp | 12 +- scanner/async_scanner.cpp | 188 ++++++++++---- scanner/async_scanner.h | 10 + scanner/scanner_const_opts.cpp | 34 ++- scanner/scanner_const_opts.h | 5 +- sdk/base/ui.cpp | 118 +++++---- sdk/base/ui.h | 28 +- sdk/base/utils.cpp | 40 +++ sdk/base/utils.h | 6 + sdk/base/words.cpp | 2 +- sdk/sane/sane_ex.h | 13 +- sdk/sane_opt_json/base_opt.cpp | 204 ++++++++++++++- sdk/sane_opt_json/base_opt.h | 8 +- sdk/sane_opt_json/device_opt.cpp | 87 +++---- sdk/sane_opt_json/device_opt.h | 8 +- ui/dev_menu.cpp | 359 +++++++++++++++----------- ui/dev_menu.h | 25 +- ui/font.cpp | 53 +++- usb/usb_io.cpp | 4 + usb/usb_io.h | 1 + xmake.lua | 4 +- 22 files changed, 883 insertions(+), 352 deletions(-) diff --git a/docs/sane-opts/scanner_const_opts.txt b/docs/sane-opts/scanner_const_opts.txt index 28cdb12..252be82 100644 --- a/docs/sane-opts/scanner_const_opts.txt +++ b/docs/sane-opts/scanner_const_opts.txt @@ -90,20 +90,21 @@ "cur": "G2393B0500", "default": "G2393B0500" }, - "roller-life": { + "total-cnt": { "cat": "base", "group": "about", - "title": "滚轴寿命", - "desc": "该设备滚轴过纸的最大张数", + "title": "历史张数", + "desc": "该设备历史总计扫描张数", "type": "int", - "fix-id": 34907, + "fix-id": 34889, "ui-pos": 20, "auth": 0, "readonly": true, "size": 4, "auto": false, - "cur": 450000, - "default": 450000 + "ownread": true, + "cur": 0, + "default": 0 }, "roll-cnt": { "cat": "base", @@ -121,21 +122,20 @@ "cur": 0, "default": 0 }, - "total-cnt": { + "roller-life": { "cat": "base", "group": "about", - "title": "历史张数", - "desc": "该设备历史总计扫描张数", + "title": "滚轴寿命", + "desc": "该设备滚轴过纸的最大张数", "type": "int", - "fix-id": 34889, + "fix-id": 34907, "ui-pos": 22, "auth": 0, "readonly": true, "size": 4, "auto": false, - "ownread": true, - "cur": 0, - "default": 0 + "cur": 450000, + "default": 450000 }, "ip-addr": { "cat": "base", diff --git a/hardware/hardware.cpp b/hardware/hardware.cpp index 7346910..4448fd4 100644 --- a/hardware/hardware.cpp +++ b/hardware/hardware.cpp @@ -543,13 +543,18 @@ int scanner_hw::scan_one_turn(LPPACKIMAGE img, safe_fifo* cism, int* cism_c mem->release(); mem = nullptr; retrieve_v4l2_mem(cism, cism_cnt); + + resok = res_(TASK_CAPTURER, false, 0); + dbg_print_("\t%d: to check resource spend %ums.\n", ++oper_index, chronograph::from_process_born() - bgn); } -#endif +#else + resok = res_(TASK_CAPTURER, false, 0); + dbg_print_("\t%d: to check resource spend %ums.\n", ++oper_index, chronograph::from_process_born() - bgn); +#endif + int fatal = 0; ret = SCANNER_ERR_DEVICE_HD_002; words = ID_WORDS_STATUS_DEVICE_HD_002; - resok = res_(TASK_CAPTURER, false, 0); - dbg_print_("\t%d: to check resource spend %ums.\n", ++oper_index, chronograph::from_process_born() - bgn); if(!motor_->wait_event(MOTOR_BORD_EVENT_PAPER_PASSING, &ret, to_paper_out_, &fatal, &words)) { @@ -561,6 +566,7 @@ int scanner_hw::scan_one_turn(LPPACKIMAGE img, safe_fifo* cism, int* cism_c if(mbstopped) *mbstopped = true; printf("-->scan done event received from motorboard.\n"); + utils::to_log(LOG_LEVEL_ALL, "scan done from motorboard.\n"); } // else break; diff --git a/scanner/async_scanner.cpp b/scanner/async_scanner.cpp index 270729d..23f5b83 100644 --- a/scanner/async_scanner.cpp +++ b/scanner/async_scanner.cpp @@ -125,49 +125,6 @@ async_scanner::async_scanner() : usb_(nullptr), cfg_mgr_(nullptr), scan_id_(0) , global_info::page_size, global_info::page_map_size, global_info::cluster_size, global_info::stack_size); res_mgr_.reset(new resource_mgr()); init(); - - auto bulk_handle = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* required) -> dyn_mem_ptr - { - LPPACK_BASE pack = (LPPACK_BASE)data->ptr(); - - if(used) - *used = data->get_rest(); - - return handle_bulk_cmd(pack, used, required, data->get_session_id()); - }; - auto on_connect = [this](bool connected) -> void - { - utils::to_log(LOG_LEVEL_ALL, "USB %s\n", connected ? "connected" : "dis-connected"); - connected_ = connected; - if(!connected) - cis_->stop_scan(); - }; - - auto user = [&](int priv) -> bool - { - return user_->has_privilege(priv); - }; - auto on_log = [&](const char* msg) -> void - { - utils::log_info(msg, LOG_LEVEL_DEBUG); - }; - - cfg_mgr_ = new device_option(true, user, on_log); - utils::to_log(LOG_LEVEL_DEBUG, "OPT - initializing ...\n"); - user_ = new user_priv(); - - cfg_mgr_->add(const_opts_); - cis_->set_value(SANE_OPT_NAME(DEVICE_MODEL), &cfg_mgr_->get_option_value(SANE_OPT_NAME(DEVICE_MODEL), SANE_ACTION_GET_VALUE)[0]); - cfg_mgr_->add(cis_); - cfg_mgr_->add(user_); - img_prcr_ = new imgproc_mgr(cfg_mgr_, &async_scanner::image_sender, (void*)this, &async_scanner::resource_check, (void*)res_mgr_.get()); - cfg_mgr_->add(img_prcr_); - utils::to_log(LOG_LEVEL_DEBUG, "OPT - initialized %u options.\n", cfg_mgr_->count()); - - usb_ = new async_usb_gadget(bulk_handle, on_connect); - last_err_ = usb_->last_error(); - - devui::send_status_message(ID_WORDS_STATUS_SCANNER_CONN + 1); } async_scanner::~async_scanner() @@ -226,6 +183,26 @@ void async_scanner::image_sender(SENDER_PROTO) obj->usb_->write_bulk(ptr); } +dyn_mem_ptr async_scanner::option_changed_packet(const char* name, void* val, size_t val_len, int pkid, int err) +{ + size_t name_len = strlen(name) + 1, + size = sizeof(PACK_BASE) + sizeof(CFGVAL) + name_len + val_len + 1; + dyn_mem_ptr ptr = dyn_mem::memory(size); + LPPACK_BASE pck = (LPPACK_BASE)ptr->ptr(); + LPCFGVAL cfg = (LPCFGVAL)pck->payload; + + BASE_PACKET_REPLY(*pck, PACK_CMD_SETTING_SET, pkid, err); + pck->payload_len = sizeof(CFGVAL) + name_len + val_len + 1; + cfg->after_do = 0; + cfg->name_off = 0; + cfg->val_size = val_len; + strcpy(cfg->data, name); + cfg->val_off = name_len; + memcpy(cfg->data + cfg->val_off, val, val_len); + ptr->set_len(size); + + return ptr; +} dyn_mem_ptr async_scanner::handle_bulk_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required, uint32_t session) { @@ -297,7 +274,13 @@ void async_scanner::init(void) auto uicb = [this](devui::LPMSGSTREAM pack) -> void { - if(devui::UI_CMD_COUNT_PAPER == pack->msg) + if(devui::UI_STATUS_PEER_CONNECTED == pack->msg) + { + // add feed-strength && time-to-sleep menu ... + add_option_to_ui_menu(SANE_OPT_NAME(FEED_STRENGTH), 0); + add_option_to_ui_menu(SANE_OPT_NAME(TIME_TO_SLEEP), 1); + } + else if(devui::UI_CMD_COUNT_PAPER == pack->msg) { auto receiver = [this](dyn_mem_ptr data, bool img, LPPACKIMAGE lpinfo) -> void { @@ -320,19 +303,120 @@ void async_scanner::init(void) { cis_->clean_paper_passway(); } - else if(devui::UI_CMD_GET_HISTORY_COUNT == pack->msg) + else if(devui::UI_CMD_SET_OPTION_VALUE == pack->msg) { - const_opts_->set_history_count(*(uint32_t*)pack->data); - } - else if(devui::UI_CMD_GET_ROLLER_COUNT == pack->msg) - { - const_opts_->set_roller_count(*(uint32_t*)pack->data); + char *name = (char*)pack->data, + *val = utils::next_string(name); + std::string type(cfg_mgr_->get_option_value_type(name)), + rv(sane_opt_provider::sane_value_from_readable_text(type.c_str(), val)); + dyn_mem_ptr ptr = async_scanner::option_changed_packet(name, &rv[0], rv.length()); + + utils::to_log(LOG_LEVEL_DEBUG, "From UI set '%s' to '%s'.\n", name, val); + + cfg_mgr_->update_data(name, &rv[0], true, false); + + if(!usb_) + { + int cond = MUST_COND_ROLLER_CNT | MUST_COND_HISTORY_CNT; + + if(strcmp(name, SANE_OPT_NAME(ROLLER_COUNT)) == 0) + must_ready_ |= MUST_COND_ROLLER_CNT; + else if(strcmp(name, SANE_OPT_NAME(HISTORY_COUNT)) == 0) + must_ready_ |= MUST_COND_HISTORY_CNT; + if((must_ready_ & cond) == cond) + init_usb(); + } + if(usb_) + { + ptr->set_session_id(usb_->current_session()); + usb_->write_bulk(ptr); + } + ptr->release(); } }; + auto user = [this](int priv) -> bool + { + return user_->has_privilege(priv); + }; + auto on_log = [&](const char* msg) -> void + { + utils::log_info(msg, LOG_LEVEL_DEBUG); + }; + + cfg_mgr_ = new device_option(true, user, on_log); + utils::to_log(LOG_LEVEL_DEBUG, "OPT - initializing ...\n"); + user_ = new user_priv(); + + cfg_mgr_->add(const_opts_); + cis_->set_value(SANE_OPT_NAME(DEVICE_MODEL), &cfg_mgr_->get_option_value(SANE_OPT_NAME(DEVICE_MODEL), SANE_ACTION_GET_VALUE)[0]); + cfg_mgr_->add(cis_); + cfg_mgr_->add(user_); + img_prcr_ = new imgproc_mgr(cfg_mgr_, &async_scanner::image_sender, (void*)this, &async_scanner::resource_check, (void*)res_mgr_.get()); + cfg_mgr_->add(img_prcr_); + utils::to_log(LOG_LEVEL_DEBUG, "OPT - initialized %u options.\n", cfg_mgr_->count()); + + // init_usb(); + devui::init_ui(uicb, false); - devui::send_message(devui::UI_CMD_GET_HISTORY_COUNT); - devui::send_message(devui::UI_CMD_GET_ROLLER_COUNT); + devui::send_message(devui::UI_STATUS_READY, nullptr, 0); +} +void async_scanner::init_usb(void) +{ + auto bulk_handle = [this](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* required) -> dyn_mem_ptr + { + LPPACK_BASE pack = (LPPACK_BASE)data->ptr(); + + if(used) + *used = data->get_rest(); + + return handle_bulk_cmd(pack, used, required, data->get_session_id()); + }; + auto on_connect = [this](bool connected) -> void + { + utils::to_log(LOG_LEVEL_ALL, "USB %s\n", connected ? "connected" : "dis-connected"); + connected_ = connected; + if(!connected) + cis_->stop_scan(); + }; + + usb_ = new async_usb_gadget(bulk_handle, on_connect); + last_err_ = usb_->last_error(); +} +void async_scanner::add_option_to_ui_menu(const char* name, int pos) +{ + SANE_Constraint_Type constraint = SANE_CONSTRAINT_NONE; + std::string vals(cfg_mgr_->get_option_value(name, SANE_ACTION_GET_ALL_VALUES, nullptr, nullptr, &constraint)), + cur(vals.c_str()), + title(cfg_mgr_->get_option_field_string(name, "title")); + const char *val = utils::next_string(vals.c_str()); + devui::LPOPTMENU opl = nullptr; + size_t len = sizeof(devui::OPTMENU) + strlen(name) + 1 + title.length() + 1; + + val = utils::next_string(val); + if(val) + vals.erase(0, val - vals.c_str()); + else + vals = std::string("\0\0\0\0", 4); + len += vals.length(); + opl = (devui::LPOPTMENU)malloc(len); + memset(opl, 0, len); + opl->title_off = strlen(name) + 1; + strcpy(opl->name, name); + strcpy(opl->name + opl->title_off, title.c_str()); + opl->value_off = opl->title_off + title.length() + 1; + memcpy(opl->name + opl->value_off, vals.c_str(), vals.length()); + opl->pos = pos; + val = vals.c_str(); + while(val) + { + if(cur == val) + break; + val = utils::next_string(val); + opl->cur_sel++; + } + devui::send_message(devui::UI_CMD_ADD_MENU, (uint8_t*)opl, len); + free(opl); } bool async_scanner::on_energy_conservation(bool normal) { diff --git a/scanner/async_scanner.h b/scanner/async_scanner.h index a39de18..a212a35 100644 --- a/scanner/async_scanner.h +++ b/scanner/async_scanner.h @@ -21,6 +21,12 @@ class user_priv; class imgproc_mgr; class resource_mgr; +enum must_cond +{ + MUST_COND_ROLLER_CNT = 1 << 0, + MUST_COND_HISTORY_CNT = 1 << 1, +}; + class async_scanner : public refer { async_usb_gadget *usb_ = nullptr; @@ -29,6 +35,7 @@ class async_scanner : public refer scanner_hw *cis_ = nullptr; user_priv *user_ = nullptr; imgproc_mgr *img_prcr_ = nullptr; + uint32_t must_ready_ = 0; MUTEX locker_; volatile bool connected_ = false; @@ -45,9 +52,12 @@ class async_scanner : public refer static bool resource_check(RES_CHK_PROTO); static void image_sender(SENDER_PROTO); + static dyn_mem_ptr option_changed_packet(const char* name, void* val, size_t val_len, int pkid = 0, int err = 0); dyn_mem_ptr handle_bulk_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required, uint32_t session); void init(void); + void init_usb(void); + void add_option_to_ui_menu(const char* name, int pos = -1); bool on_energy_conservation(bool normal/*true - working status; false - go to sleep*/); // return true to enable get into 'normal' status dyn_mem_ptr handle_simple_roger(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required, uint32_t session); diff --git a/scanner/scanner_const_opts.cpp b/scanner/scanner_const_opts.cpp index f6c73ea..d38c4de 100644 --- a/scanner/scanner_const_opts.cpp +++ b/scanner/scanner_const_opts.cpp @@ -4,7 +4,7 @@ #include #include #include - +#include @@ -21,7 +21,7 @@ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // option json: static std::string device_opt_json[] = { - "{\"dev-vid\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"USB-VID\",\"desc\":\"\\u8bbe\\u5907\\u5236\\u9020\\u5546\\u5728USB\\u7ec4\\u7ec7\\u7684ID\",\"type\":\"string\",\"fix-id\":34898,\"ui-pos\":10,\"auth\":0,\"readonly\":true,\"size\":16,\"auto\":false,\"cur\":\"3072\",\"default\":\"3072\"},\"dev-pid\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"USB-PID\",\"desc\":\"\\u8bbe\\u5907\\u5728USB\\u7ec4\\u7ec7\\u4e2d\\u7684\\u4ea7\\u54c1ID\",\"type\":\"string\",\"fix-id\":34899,\"ui-pos\":11,\"auth\":0,\"readonly\":true,\"size\":16,\"auto\":false,\"cur\":\"0306\",\"default\":\"0306\"},\"dev-name\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"\\u8bbe\\u5907\\u540d\\u79f0\",\"desc\":\"\\u8bbe\\u5907\\u540d\\u79f0\",\"type\":\"string\",\"fix-id\":34900,\"ui-pos\":12,\"auth\":0,\"readonly\":true,\"size\":96,\"auto\":false,\"cur\":\"HUAGOSCAN G200\",\"default\":\"HUAGOSCAN G200\"},\"dev-model\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"\\u4ea7\\u54c1\\u7cfb\\u5217\",\"desc\":\"\\u8bbe\\u5907\\u6240\\u5c5e\\u4ea7\\u54c1\\u7cfb\\u5217\\u540d\\u79f0\",\"type\":\"string\",\"fix-id\":34901,\"ui-pos\":13,\"auth\":0,\"readonly\":true,\"size\":96,\"auto\":false,\"cur\":\"G200\",\"default\":\"G200\"},\"dev-sn\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"\\u5e8f\\u5217\\u53f7\",\"desc\":\"\\u8bbe\\u5907\\u5e8f\\u5217\\u53f7\",\"type\":\"string\",\"fix-id\":34902,\"ui-pos\":14,\"auth\":0,\"readonly\":true,\"size\":32,\"auto\":false,\"ownread\":true,\"cur\":\"GB20231201\",\"default\":\"GB20231201\"},\"fmw-ver\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"\\u56fa\\u4ef6\\u7248\\u672c\",\"desc\":\"\\u8bbe\\u5907\\u56fa\\u4ef6\\u7248\\u672c\\u53f7\",\"type\":\"string\",\"fix-id\":34903,\"ui-pos\":15,\"auth\":0,\"readonly\":true,\"size\":32,\"auto\":false,\"cur\":\"G2393B0500\",\"default\":\"G2393B0500\"},\"roller-life\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"\\u6eda\\u8f74\\u5bff\\u547d\",\"desc\":\"\\u8be5\\u8bbe\\u5907\\u6eda\\u8f74\\u8fc7\\u7eb8\\u7684\\u6700\\u5927\\u5f20\\u6570\",\"type\":\"int\",\"fix-id\":34907,\"ui-pos\":20,\"auth\":0,\"readonly\":true,\"size\":4,\"auto\":false,\"cur\":450000,\"default\":450000},\"roll-cnt\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"\\u6eda\\u8f74\\u5f20\\u6570\",\"desc\":\"\\u5f53\\u524d\\u6eda\\u8f74\\u626b\\u63cf\\u5f20\\u6570\",\"type\":\"int\",\"fix-id\":39170,\"ui-pos\":21,\"auth\":0,\"readonly\":true,\"size\":4,\"auto\":false,\"ownread\":true,\"cur\":0,\"default\":0},\"total-cnt\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"\\u5386\\u53f2\\u5f20\\u6570\",\"desc\":\"\\u8be5\\u8bbe\\u5907\\u5386\\u53f2\\u603b\\u8ba1\\u626b\\u63cf\\u5f20\\u6570\",\"type\":\"int\",\"fix-id\":34889,\"ui-pos\":22,\"auth\":0,\"readonly\":true,\"size\":4,\"auto\":false,\"ownread\":true,\"cur\":0,\"default\":0},\"ip-addr\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"IP\",\"desc\":\"\\u8bbe\\u5907\\u8054\\u7f51\\u65f6\\u6240\\u5206\\u914d\\u7684IP\\u5730\\u5740\",\"type\":\"string\",\"fix-id\":34904,\"ui-pos\":30,\"auth\":0,\"readonly\":true,\"size\":96,\"auto\":false,\"ownread\":true,\"cur\":\"0\",\"default\":\"0\"},\"mac-addr\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"MAC\",\"desc\":\"\\u8bbe\\u5907\\u7f51\\u5361\\u5730\\u5740\",\"type\":\"string\",\"fix-id\":34905,\"ui-pos\":31,\"auth\":0,\"readonly\":true,\"size\":96,\"auto\":false,\"ownread\":true,\"cur\":\"0\",\"default\":\"0\"}}" + "{\"dev-vid\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"USB-VID\",\"desc\":\"\\u8bbe\\u5907\\u5236\\u9020\\u5546\\u5728USB\\u7ec4\\u7ec7\\u7684ID\",\"type\":\"string\",\"fix-id\":34898,\"ui-pos\":10,\"auth\":0,\"readonly\":true,\"size\":16,\"auto\":false,\"cur\":\"3072\",\"default\":\"3072\"},\"dev-pid\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"USB-PID\",\"desc\":\"\\u8bbe\\u5907\\u5728USB\\u7ec4\\u7ec7\\u4e2d\\u7684\\u4ea7\\u54c1ID\",\"type\":\"string\",\"fix-id\":34899,\"ui-pos\":11,\"auth\":0,\"readonly\":true,\"size\":16,\"auto\":false,\"cur\":\"0306\",\"default\":\"0306\"},\"dev-name\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"\\u8bbe\\u5907\\u540d\\u79f0\",\"desc\":\"\\u8bbe\\u5907\\u540d\\u79f0\",\"type\":\"string\",\"fix-id\":34900,\"ui-pos\":12,\"auth\":0,\"readonly\":true,\"size\":96,\"auto\":false,\"cur\":\"HUAGOSCAN G200\",\"default\":\"HUAGOSCAN G200\"},\"dev-model\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"\\u4ea7\\u54c1\\u7cfb\\u5217\",\"desc\":\"\\u8bbe\\u5907\\u6240\\u5c5e\\u4ea7\\u54c1\\u7cfb\\u5217\\u540d\\u79f0\",\"type\":\"string\",\"fix-id\":34901,\"ui-pos\":13,\"auth\":0,\"readonly\":true,\"size\":96,\"auto\":false,\"cur\":\"G200\",\"default\":\"G200\"},\"dev-sn\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"\\u5e8f\\u5217\\u53f7\",\"desc\":\"\\u8bbe\\u5907\\u5e8f\\u5217\\u53f7\",\"type\":\"string\",\"fix-id\":34902,\"ui-pos\":14,\"auth\":0,\"readonly\":true,\"size\":32,\"auto\":false,\"ownread\":true,\"cur\":\"GB20231201\",\"default\":\"GB20231201\"},\"fmw-ver\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"\\u56fa\\u4ef6\\u7248\\u672c\",\"desc\":\"\\u8bbe\\u5907\\u56fa\\u4ef6\\u7248\\u672c\\u53f7\",\"type\":\"string\",\"fix-id\":34903,\"ui-pos\":15,\"auth\":0,\"readonly\":true,\"size\":32,\"auto\":false,\"cur\":\"G2393B0500\",\"default\":\"G2393B0500\"},\"total-cnt\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"\\u5386\\u53f2\\u5f20\\u6570\",\"desc\":\"\\u8be5\\u8bbe\\u5907\\u5386\\u53f2\\u603b\\u8ba1\\u626b\\u63cf\\u5f20\\u6570\",\"type\":\"int\",\"fix-id\":34889,\"ui-pos\":20,\"auth\":0,\"readonly\":true,\"size\":4,\"auto\":false,\"ownread\":true,\"cur\":0,\"default\":0},\"roll-cnt\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"\\u6eda\\u8f74\\u5f20\\u6570\",\"desc\":\"\\u5f53\\u524d\\u6eda\\u8f74\\u626b\\u63cf\\u5f20\\u6570\",\"type\":\"int\",\"fix-id\":39170,\"ui-pos\":21,\"auth\":0,\"readonly\":true,\"size\":4,\"auto\":false,\"ownread\":true,\"cur\":0,\"default\":0},\"roller-life\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"\\u6eda\\u8f74\\u5bff\\u547d\",\"desc\":\"\\u8be5\\u8bbe\\u5907\\u6eda\\u8f74\\u8fc7\\u7eb8\\u7684\\u6700\\u5927\\u5f20\\u6570\",\"type\":\"int\",\"fix-id\":34907,\"ui-pos\":22,\"auth\":0,\"readonly\":true,\"size\":4,\"auto\":false,\"cur\":450000,\"default\":450000},\"ip-addr\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"IP\",\"desc\":\"\\u8bbe\\u5907\\u8054\\u7f51\\u65f6\\u6240\\u5206\\u914d\\u7684IP\\u5730\\u5740\",\"type\":\"string\",\"fix-id\":34904,\"ui-pos\":30,\"auth\":0,\"readonly\":true,\"size\":96,\"auto\":false,\"ownread\":true,\"cur\":\"0\",\"default\":\"0\"},\"mac-addr\":{\"cat\":\"base\",\"group\":\"about\",\"title\":\"MAC\",\"desc\":\"\\u8bbe\\u5907\\u7f51\\u5361\\u5730\\u5740\",\"type\":\"string\",\"fix-id\":34905,\"ui-pos\":31,\"auth\":0,\"readonly\":true,\"size\":96,\"auto\":false,\"ownread\":true,\"cur\":\"0\",\"default\":\"0\"}}" }; @@ -227,14 +227,10 @@ char* scanner_const_opts::get_value(const char* name, void* value, size_t* size, } else if(strcmp(SANE_OPT_NAME(ROLLER_COUNT), name) == 0) { - devui::send_message(devui::UI_CMD_GET_ROLLER_COUNT); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); val = std::string((char*)&roller_cnt_, sizeof(roller_cnt_)); } else if(strcmp(SANE_OPT_NAME(HISTORY_COUNT), name) == 0) { - devui::send_message(devui::UI_CMD_GET_HISTORY_COUNT); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); val = std::string((char*)&hist_cnt_, sizeof(hist_cnt_)); } else if(err) @@ -244,19 +240,29 @@ char* scanner_const_opts::get_value(const char* name, void* value, size_t* size, { ret = (char*)malloc(val.length() + 1); memset(ret, 0, val.length() + 1); - strcpy(ret, val.c_str()); + memcpy(ret, val.c_str(), val.length()); if(size) *size = val.length(); } return ret; } +int scanner_const_opts::set_value(const char* name, void* val) +{ + int ret = SCANNER_ERR_OK; -void scanner_const_opts::set_roller_count(uint32_t cnt) -{ - roller_cnt_ = cnt; -} -void scanner_const_opts::set_history_count(uint32_t cnt) -{ - hist_cnt_ = cnt; + if(strcmp(SANE_OPT_NAME(ROLLER_COUNT), name) == 0) + { + roller_cnt_ = *(int*)val; + } + else if(strcmp(SANE_OPT_NAME(HISTORY_COUNT), name) == 0) + { + hist_cnt_ = *(int*)val; + } + else + { + ret = SCANNER_ERR_ACCESS_DENIED; + } + + return ret; } diff --git a/scanner/scanner_const_opts.h b/scanner/scanner_const_opts.h index e14f87e..9bb51d2 100644 --- a/scanner/scanner_const_opts.h +++ b/scanner/scanner_const_opts.h @@ -26,10 +26,7 @@ protected: public: // return malloc(), real data size stored in parameter 'size'. invoker should free() the returned value virtual char* get_value(const char* name, void* value, size_t* size, int* err = nullptr) override; - -public: - void set_roller_count(uint32_t cnt); - void set_history_count(uint32_t cnt); + virtual int set_value(const char* name, void* val) override; }; diff --git a/sdk/base/ui.cpp b/sdk/base/ui.cpp index 8d076a7..948b7a2 100644 --- a/sdk/base/ui.cpp +++ b/sdk/base/ui.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #define PIPE_PROTO_VER MAKEWORD(0, 1) @@ -12,6 +13,7 @@ // ipc class namespace devui { + // open reader will be blocked until the sender openned !!! class pipe_reader : public refer { std::string pipe_path_; @@ -170,8 +172,8 @@ namespace devui std::function cb_; safe_fifo sent_que_; volatile bool run_ = true; + volatile bool ready_ = false; bool ui_; - bool ready_ = true; safe_thread workers_; int fdo_ = -1; int fdi_ = -1; @@ -205,16 +207,12 @@ namespace devui } else { - auto r = [this](void*) -> void - { - receiver(); - }; auto s = [this](void*) -> void { sender(); }; - workers_.start(r, nullptr, SIZE_MB(1), "receiver"); - workers_.start(s, nullptr, SIZE_MB(1), "sender"); + ready_ = true; + workers_.start(s, nullptr, SIZE_MB(1), "sender", (void*)&ui_messenger::sender); } } void close(void) @@ -234,48 +232,66 @@ namespace devui chronograph watch; printf("ui-receiver running ...\n"); - while(run_) + init(); + if(ready_) { - watch.reset(); - int r = read(fdi_, buf, _countof(buf)); - if(r == -1) + MSGSTREAM ms; + memset(&ms, 0, sizeof(ms)); + ms.ver = PIPE_PROTO_VER; + ms.msg = UI_STATUS_PEER_CONNECTED; + cb_(&ms); + + while(run_) { - 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) + watch.reset(); + int r = read(fdi_, buf, _countof(buf)); + if(r == -1) { - MSGSTREAM ms; - memset(&ms, 0, sizeof(ms)); - ms.ver = PIPE_PROTO_VER; - ms.msg = UI_STATUS_PEER_CLOSED; + 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) + if(ready_) + { + ready_ = false; + + MSGSTREAM ms; + memset(&ms, 0, sizeof(ms)); + ms.ver = PIPE_PROTO_VER; + ms.msg = UI_STATUS_PEER_CLOSED; + cb_(&ms); + + printf("[%s] PIPE: peer closed(read ZERO byte and error = %d).\n", utils::format_current_time().c_str(), 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; + } + + if(!ready_) + { + ready_ = true; cb_(&ms); - - printf("[%s] PIPE: peer closed(read ZERO byte and error = %d).\n", utils::format_current_time().c_str(), 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) + rcv += std::string(buf, r); + if(rcv.length()) { - cb_(pack); - off += pack->whole_size(); + 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); } - if(off) - rcv.erase(0, off); } } printf("ui-receiver exited.\n"); @@ -296,11 +312,14 @@ namespace devui { 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(); + if(ready_) + this->close(); + else + s = 0; break; } off += s; - }while(off < cont.length()); + }while(ready_ && off < cont.length()); if(s == -1) break; } @@ -313,12 +332,19 @@ namespace devui , bool ui) : sent_que_("ui-sent-que") , cb_(uicb), ui_(ui) { + // to avoid crash when write a closed pipe + signal(SIGPIPE, SIG_IGN); sent_que_.enable_wait_log(false); - init(); + + auto r = [this](void*) -> void + { + receiver(); + }; + workers_.start(r, nullptr, SIZE_MB(1), "receiver", (void*)&ui_messenger::receiver); } ~ui_messenger() { - close(); + stop(); } public: @@ -331,8 +357,8 @@ namespace devui } void stop(void) { - sent_que_.trigger(); run_ = false; + sent_que_.trigger(); this->close(); } }; diff --git a/sdk/base/ui.h b/sdk/base/ui.h index a37efc3..89c8056 100644 --- a/sdk/base/ui.h +++ b/sdk/base/ui.h @@ -18,6 +18,12 @@ namespace devui SCAN_NORMAL, SCAN_COUNT_MODE, }; + enum strength + { + STRENGTH_LOW = 1, + STRENGTH_MID, + STRENGTH_HIGH, + }; enum uicmd { UI_CMD_COUNT_PAPER = 0x10, @@ -25,14 +31,16 @@ namespace devui UI_CMD_CLEAN_PASSWAY = 0x30, - UI_CMD_GET_HISTORY_COUNT = 0x50, - UI_CMD_GET_ROLLER_COUNT, + UI_CMD_ADD_MENU = 0x100, // data: LPADDMENU + UI_CMD_SET_OPTION_VALUE, // data: string array - name + value - 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_READY = 0x1000, + UI_STATUS_SCANNING, // 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. + UI_STATUS_PEER_CONNECTED = 0x8000, // peer connected. + UI_STATUS_PEER_CLOSED, }; enum align_component { @@ -79,6 +87,14 @@ namespace devui uint32_t font : 8; // font size uint32_t reserved : 14; }STATMSG, *LPSTATMSG; + typedef struct _opt_menu + { + uint32_t pos; // -1 is not care + uint8_t cur_sel; + uint8_t title_off; // -1 is no title + uint16_t value_off; + char name[4]; + }OPTMENU, *LPOPTMENU; #pragma pack(pop) void init_ui(std::function uicb, bool ui); diff --git a/sdk/base/utils.cpp b/sdk/base/utils.cpp index ec8766a..9573a00 100644 --- a/sdk/base/utils.cpp +++ b/sdk/base/utils.cpp @@ -1101,6 +1101,46 @@ namespace utils return str.c_str(); } + std::string string_array(const std::vector& strs) + { + std::string stra(""); + + for(const auto& v: strs) + { + stra += v; + stra.append(1, '\0'); + } + stra.append(2, '\0'); + + return std::move(stra); + } + void add_2_string_array(std::string& stra, const char* str) + { + if(stra.length() >= 2) + stra.erase(stra.length() - 2); + + stra += std::string(str, strlen(str) + 1); + stra.append(2, '\0'); + } + const char* next_string(const char* stra) + { + if(*stra) + stra += strlen(stra) + 1; + if(*stra == 0) + stra = nullptr; + + return stra; + } + char* next_string(char* stra) + { + if(*stra) + stra += strlen(stra) + 1; + if(*stra == 0) + stra = nullptr; + + return stra; + } + int get_stack_size(void) { int size = 0; diff --git a/sdk/base/utils.h b/sdk/base/utils.h index 2c85ff9..e8528ab 100644 --- a/sdk/base/utils.h +++ b/sdk/base/utils.h @@ -94,6 +94,12 @@ namespace utils bool is_match_pattern(const char* text, const char* pattern); 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() + + // string array + std::string string_array(const std::vector& strs); + void add_2_string_array(std::string& stra, const char* str); + const char* next_string(const char* stra); + char* next_string(char* stra); int get_stack_size(void); diff --git a/sdk/base/words.cpp b/sdk/base/words.cpp index 6e45cec..86da02f 100644 --- a/sdk/base/words.cpp +++ b/sdk/base/words.cpp @@ -36,7 +36,7 @@ WORDS_AND_ID_IMPL(WORDS_FILLBG_CONVEX, "\345\207\270\345\244\232\350 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_RETURN, "\350\277\224\345\233\236"); 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"); diff --git a/sdk/sane/sane_ex.h b/sdk/sane/sane_ex.h index 7bdcb16..9ad96f3 100644 --- a/sdk/sane/sane_ex.h +++ b/sdk/sane/sane_ex.h @@ -139,6 +139,7 @@ extern "C" { SANE_ACTION_GET_DEFAULT_VALUE = 100, // 获取设置项默认值,参数同SANE_ACTION_GET_VALUE SANE_ACTION_GET_FIX_ID, // 获取属性的固定ID,void* = SANE_Int* SANE_ACTION_GET_ENTIRE_JSON, // 获取该属性JSON文本 + SANE_ACTION_GET_ALL_VALUES, // 获取该属性所有值,see SANE_Value_Index. // Function: 枚举对SANE协议不可见的固定ID属性(以使TWAIN可访问) // @@ -146,7 +147,17 @@ extern "C" { SANE_ACTION_ENUM_INVISIBLE_FIX_ID = 0x0FEC7, }; - enum SANE_Frame_Ex // after SANE_Frame + enum SANE_Value_Index // when get constrainted value list, the index of special value. DO NOT change their sequence !!! + { + SANE_VAL_IND_CURRENT = 0, // current value + SANE_VAL_IND_DEFAULT, + SANE_VAL_IND_LIST_0, // the first value of list + SANE_VAL_IND_RANGE_LOWER = SANE_VAL_IND_LIST_0, // lower value of range + SANE_VAL_IND_RANGE_UPPER, + SANE_VAL_IND_RANGE_STEP, + }; + + enum SANE_Frame_Ex // after SANE_Frame { SANE_FRAME_RAW = 100, SANE_FRAME_MIME, // MIME descriptor diff --git a/sdk/sane_opt_json/base_opt.cpp b/sdk/sane_opt_json/base_opt.cpp index c840773..3603748 100644 --- a/sdk/sane_opt_json/base_opt.cpp +++ b/sdk/sane_opt_json/base_opt.cpp @@ -5,7 +5,45 @@ #include #include +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +template +static void get_range_values(std::string& ret, gb_json* range, bool* isrange) +{ + std::string values(""); + T v; + if(range->get_value("min", v)) + { + if(isrange) + *isrange = true; + ret += std::string((char*)&v, sizeof(v)); + + range->get_value("max", v); + ret += std::string((char*)&v, sizeof(v)); + + range->get_value("step", v); + ret += std::string((char*)&v, sizeof(v)); + } + else + { + if(isrange) + *isrange = false; + + gb_json* val = range->first_child(); + while(val) + { + val->value(v); + ret += std::string((char*)&v, sizeof(v)); + + val->release(); + val = range->next_child(); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// sane_opt_provider::sane_opt_provider() { set_where(nullptr); @@ -18,7 +56,20 @@ sane_opt_provider::~sane_opt_provider() following_.clear(); } -std::string sane_opt_provider::sane_value_2_text(const char* type, void* value) +std::string sane_opt_provider::sane_value_2_readable_text(SANE_Value_Type type, void* value) +{ + if(type == SANE_TYPE_BOOL) + return *(bool*)value ? "true" : "false"; + else if(type == SANE_TYPE_INT) + return std::to_string(*(int*)value); + else if(type == SANE_TYPE_FIXED) + return std::to_string(*(double*)value); + else if(type == SANE_TYPE_STRING) + return (char*)value; + else + return ""; +} +std::string sane_opt_provider::sane_value_2_readable_text(const char* type, void* value) { if(strcmp(type, JSON_SANE_TYPE_BOOL) == 0) return *(bool*)value ? "true" : "false"; @@ -31,6 +82,58 @@ std::string sane_opt_provider::sane_value_2_text(const char* type, void* value) else return ""; } +std::string sane_opt_provider::sane_value_from_readable_text(SANE_Value_Type type, const char* text) +{ + std::string val(""); + + if(type == SANE_TYPE_BOOL) + { + bool v = strcmp(text, "true") == 0; + val = std::string((char*)&v, sizeof(v)); + } + else if(type == SANE_TYPE_INT) + { + int v = atoi(text); + val = std::string((char*)&v, sizeof(v)); + } + else if(type == SANE_TYPE_FIXED) + { + double v = atof(text); + val = std::string((char*)&v, sizeof(v)); + } + else if(type == SANE_TYPE_STRING) + { + val = text; + } + + return std::move(val); +} +std::string sane_opt_provider::sane_value_from_readable_text(const char* type, const char* text) +{ + std::string val(""); + + if(strcmp(type, JSON_SANE_TYPE_BOOL) == 0) + { + bool v = strcmp(text, "true") == 0; + val = std::string((char*)&v, sizeof(v)); + } + else if(strcmp(type, JSON_SANE_TYPE_INT) == 0) + { + int v = atoi(text); + val = std::string((char*)&v, sizeof(v)); + } + else if(strcmp(type, JSON_SANE_TYPE_FIXED) == 0) + { + double v = atof(text); + val = std::string((char*)&v, sizeof(v)); + } + else if(strcmp(type, JSON_SANE_TYPE_STRING) == 0) + { + val = text; + } + + return std::move(val); +} bool sane_opt_provider::set_opt_value(gb_json* opt, void* value, const char* key) { std::string type(""); @@ -89,6 +192,105 @@ bool sane_opt_provider::is_opt_value_equal(gb_json* opt, void* v1, void* v2) return ret; } +std::string sane_opt_provider::option_value(gb_json* jsn, bool def_val, SANE_Value_Type* type) +{ + std::string vt(""), key(def_val ? "default" : "cur"); + + jsn->get_value("type", vt); + if (vt == "bool") + { + bool v = false; + jsn->get_value(key.c_str(), v); + vt = std::string((char*)&v, sizeof(v)); + if(type) + *type = SANE_TYPE_BOOL; + } + else if (vt == "int") + { + int v = 0; + jsn->get_value(key.c_str(), v); + vt = std::string((char*)&v, sizeof(v)); + if(type) + *type = SANE_TYPE_INT; + } + else if (vt == "float") + { + double v = .0f; + jsn->get_value(key.c_str(), v); + vt = std::string((char*)&v, sizeof(v)); + if(type) + *type = SANE_TYPE_FIXED; + } + else if (vt == "string") + { + if (!jsn->get_value(key.c_str(), vt)) + vt = ""; + if(type) + *type = SANE_TYPE_STRING; + } + else + { + vt = ""; + } + + return std::move(vt); +} +std::string sane_opt_provider::get_all_values(gb_json* opt, SANE_Constraint_Type* constraint, SANE_Value_Type* type) +{ + std::string vt(""), value(""); + SANE_Value_Type t = SANE_TYPE_BOOL; + gb_json *range = nullptr, *child = nullptr; + + if(!type) + type = &t; + value = sane_opt_provider::option_value(opt, false, type); + opt->get_value("range", range); + if(*type == SANE_TYPE_STRING) + { + value.append(3, '\0'); + utils::add_2_string_array(value, sane_opt_provider::option_value(opt, true).c_str()); + if(range) + { + if(constraint) + *constraint = SANE_CONSTRAINT_STRING_LIST; + + child = range->first_child(); + while(child) + { + child->value(vt); + utils::add_2_string_array(value, vt.c_str()); + child->release(); + child = range->next_child(); + } + range->release(); + } + } + else + { + value += sane_opt_provider::option_value(opt, true); + if(range) + { + bool isrng = false; + if(*type == SANE_TYPE_BOOL) + { + get_range_values(value, range, &isrng); + } + else if(*type == SANE_TYPE_INT) + { + get_range_values(value, range, &isrng); + } + else if(*type == SANE_TYPE_FIXED) + { + get_range_values(value, range, &isrng); + } + range->release(); + if(constraint) + *constraint = isrng ? SANE_CONSTRAINT_RANGE : SANE_CONSTRAINT_WORD_LIST; + } + } + + return std::move(value); +} bool sane_opt_provider::set_opt_json_text(char* txt) { diff --git a/sdk/sane_opt_json/base_opt.h b/sdk/sane_opt_json/base_opt.h index 869d1cb..eed7e27 100644 --- a/sdk/sane_opt_json/base_opt.h +++ b/sdk/sane_opt_json/base_opt.h @@ -8,6 +8,7 @@ #include #include #include // for refer +#include class gb_json; @@ -24,9 +25,14 @@ protected: public: sane_opt_provider(); - static std::string sane_value_2_text(const char* type, void* value); // convert to readable text. e.g. bool to "true" or "false", ... + static std::string sane_value_2_readable_text(SANE_Value_Type type, void* value); // convert to readable text. e.g. bool to "true" or "false", ... + static std::string sane_value_2_readable_text(const char* type, void* value); // convert to readable text. e.g. bool to "true" or "false", ... + static std::string sane_value_from_readable_text(SANE_Value_Type type, const char* text); // convert from readable text. e.g. bool to "true" or "false", ... + static std::string sane_value_from_readable_text(const char* type, const char* text); // convert from readable text. e.g. bool to "true" or "false", ... static bool set_opt_value(gb_json* opt, void* value, const char* key = "cur"); static bool is_opt_value_equal(gb_json* opt, void* v1, void* v2); + static std::string option_value(gb_json* jsn, bool def_val, SANE_Value_Type* type = nullptr); + static std::string get_all_values(gb_json* opt, SANE_Constraint_Type* constraint, SANE_Value_Type* type); protected: virtual ~sane_opt_provider(); diff --git a/sdk/sane_opt_json/device_opt.cpp b/sdk/sane_opt_json/device_opt.cpp index b8c6ae6..eb131cf 100644 --- a/sdk/sane_opt_json/device_opt.cpp +++ b/sdk/sane_opt_json/device_opt.cpp @@ -1251,7 +1251,7 @@ void device_option::insert_option(gb_json* opt, sane_opt_provider* from, const c // std::string type(""); // opt->get_value("type", type); // val.resize(size); - // type = sane_opt_provider::sane_value_2_text(type.c_str(), &val[0]); + // type = sane_opt_provider::sane_value_2_readable_text(type.c_str(), &val[0]); // write_log("Set option '%s' to default value: '%s'\n", opt->key().c_str(), type.c_str()); // from->set_value(opt->key().c_str(), &val[0]); // sane_opt_provider::set_opt_value(opt, &val[0]); @@ -1823,41 +1823,6 @@ bool device_option::is_hidden_option(gb_json* opt) return hidden; } -std::string device_option::option_value(gb_json* jsn, bool def_val) -{ - std::string type(""), key(def_val ? "default" : "cur"); - - jsn->get_value("type", type); - if (type == "bool") - { - bool v = false; - jsn->get_value(key.c_str(), v); - type = std::string((char*)&v, sizeof(v)); - } - else if (type == "int") - { - int v = 0; - jsn->get_value(key.c_str(), v); - type = std::string((char*)&v, sizeof(v)); - } - else if (type == "float") - { - double v = .0f; - jsn->get_value(key.c_str(), v); - type = std::string((char*)&v, sizeof(v)); - } - else if (type == "string") - { - if (!jsn->get_value(key.c_str(), type)) - type = ""; - } - else - { - type = ""; - } - - return std::move(type); -} void device_option::revise_number_type(gb_json* opt, bool to_double) { gb_json* child = nullptr; @@ -1993,7 +1958,7 @@ bool device_option::refine_data(const char* name, void* value) { std::string type(""), org(""), result(""); child->get_value("type", type); - org = sane_opt_provider::sane_value_2_text(type.c_str(), value); + org = sane_opt_provider::sane_value_2_readable_text(type.c_str(), value); if (type == JSON_SANE_TYPE_BOOL) { refined = refine_data_to_range(child, value); @@ -2012,7 +1977,7 @@ bool device_option::refine_data(const char* name, void* value) } if(refined) { - result = sane_opt_provider::sane_value_2_text(type.c_str(), value); + result = sane_opt_provider::sane_value_2_readable_text(type.c_str(), value); write_log("Refine value of '%s' from '%s' to '%s'.\n", name, org.c_str(), result.c_str()); } @@ -2021,7 +1986,7 @@ bool device_option::refine_data(const char* name, void* value) return refined; } -int device_option::update_data(const char* name, void* value, bool reorder_if_need) +int device_option::update_data(const char* name, void* value, bool reorder_if_need, bool from_user) { int err = SCANNER_ERR_NO_DATA; @@ -2040,8 +2005,8 @@ int device_option::update_data(const char* name, void* value, bool reorder_if_ne if (child) { bool ro = false; - if ((child->get_value("readonly", ro) && ro) - || (child->get_value("auth", err) && user_ && !user_(err))) + if (from_user && ((child->get_value("readonly", ro) && ro) + || (child->get_value("auth", err) && user_ && !user_(err)))) { err = SCANNER_ERR_ACCESS_DENIED; @@ -2050,14 +2015,14 @@ int device_option::update_data(const char* name, void* value, bool reorder_if_ne } else { - std::string pre(device_option::option_value(child, false)); + std::string pre(sane_opt_provider::option_value(child, false)); bool changed = false; // pass to sane_opt_provider ... err = update_provider_value(name, value); child->get_value("type", type); - write_log("set option '%s' value to '%s' = %d.\n", name, sane_opt_provider::sane_value_2_text(type.c_str(), value).c_str(), err); + write_log("set option '%s' value to '%s' = %d.\n", name, sane_opt_provider::sane_value_2_readable_text(type.c_str(), value).c_str(), err); if (err == SCANNER_ERR_OK || err == SCANNER_ERR_NOT_EXACT || err == SCANNER_ERR_RELOAD_IMAGE_PARAM || err == SCANNER_ERR_RELOAD_OPT_PARAM @@ -2165,7 +2130,7 @@ int device_option::restore(sane_opt_provider* holder) // && is_auto_restore_default(child) ) { - std::string val(device_option::option_value(child, true)); + std::string val(sane_opt_provider::option_value(child, true)); update_data(child->key().c_str(), &val[0], false); } child->release(); @@ -2207,6 +2172,25 @@ bool device_option::is_auto_restore_default(gb_json* jsn) return support; } +int device_option::sane_id_from_name(const char* name) +{ + gb_json* jsn = now_ ? now_ : origin_; + int sn = -1; + + if(jsn) + { + gb_json* child = nullptr; + + jsn->get_value(name, child); + if(child) + { + sn = jsn->index(child) + 1; + child->release(); + } + } + + return sn; +} std::string device_option::get_name_by_sane_id(int sane_ind) { std::string value(""); @@ -2247,7 +2231,7 @@ std::string device_option::get_option_value_type(const char* name, size_t* size) return std::move(value); } -std::string device_option::get_option_value(const char* name, int type, int* size, void* in_data) +std::string device_option::get_option_value(const char* name, int type, int* size, void* in_data, SANE_Constraint_Type *constraint) { std::string value(""); gb_json* jsn = now_ ? now_ : origin_; @@ -2264,10 +2248,13 @@ std::string device_option::get_option_value(const char* name, int type, int* siz { if (is_hidden_option(child)) // The option count must stay the same in SANE protocol, replace hidden option with meaninless option here { + char key[40] = { 0 }; + child->get_value("group", value); child->release(); child = device_option::meaningless_option(value.c_str()); - child->key() = "hidden-" + std::to_string(++hidden); + sprintf(key, "%p-%d", this, ++hidden); + child->key() = key; // "hidden-" + std::to_string(++hidden); // the same hidden id ... } filter->set_value(child->key().c_str(), child); child->release(); @@ -2293,6 +2280,10 @@ std::string device_option::get_option_value(const char* name, int type, int* siz { if (type == SANE_ACTION_GET_ENTIRE_JSON) value = child->to_string(); + else if(type == SANE_ACTION_GET_ALL_VALUES) + { + value = sane_opt_provider::get_all_values(child, constraint, nullptr); + } else if (child->get_value("ownread", own_read) && own_read) { if (src_.count(name)) @@ -2307,7 +2298,7 @@ std::string device_option::get_option_value(const char* name, int type, int* siz } } else - value = device_option::option_value(child, type == SANE_ACTION_GET_DEFAULT_VALUE); + value = sane_opt_provider::option_value(child, type == SANE_ACTION_GET_DEFAULT_VALUE); if (size) { @@ -2362,7 +2353,7 @@ std::string device_option::get_option_value_type(int sane_ind, size_t* size) return std::move(value); } -std::string device_option::get_option_value(int sane_ind, int type, int* size, void* in_data) +std::string device_option::get_option_value_by_id(int sane_ind, int type, int* size, void* in_data) { std::string value(""); diff --git a/sdk/sane_opt_json/device_opt.h b/sdk/sane_opt_json/device_opt.h index 0e4d7bf..677590b 100644 --- a/sdk/sane_opt_json/device_opt.h +++ b/sdk/sane_opt_json/device_opt.h @@ -202,7 +202,6 @@ class device_option : public refer bool is_hidden_option(gb_json* opt); protected: - static std::string option_value(gb_json* jsn, bool def_val); static void revise_number_type(gb_json* opt, bool to_double); template @@ -376,16 +375,17 @@ public: bool add(sane_opt_provider* sop, bool apply_default_val = true); bool remove(sane_opt_provider* sop); bool refine_data(const char* name, void* value); // return true if the 'value' is out of range and refined it in the range - int update_data(const char* name, void* value, bool reorder_if_need = true); // return scanner_err. name and value would be null if invoked for language changed + int update_data(const char* name, void* value, bool reorder_if_need = true, bool from_user = true); // return scanner_err. name and value would be null if invoked for language changed int restore(sane_opt_provider* holder); // int count(void); // return option count bool is_auto_restore_default(gb_json* jsn); + int sane_id_from_name(const char* name); std::string get_name_by_sane_id(int sane_ind); std::string get_option_value_type(const char* name, size_t* size = nullptr); std::string get_option_value_type(int sane_ind, size_t* size = nullptr); std::string get_option_field_string(const char* name, const char* key); - std::string get_option_value(const char* name, int type/*OPT_VAL_xxx*/, int* size = nullptr, void* in_data = nullptr); // return whole json-text if name was null - std::string get_option_value(int sane_ind, int type/*OPT_VAL_xxx*/, int* size = nullptr, void* in_data = nullptr); // return whole json-text if name was null + std::string get_option_value(const char* name, int type/*SANE_ACTION_GET_xxx*/, int* size = nullptr, void* in_data = nullptr, SANE_Constraint_Type *constraint = nullptr/*used in SANE_ACTION_GET_ALL_VALUES*/); // return whole json-text if name was null + std::string get_option_value_by_id(int sane_ind, int type/*SANE_ACTION_GET_xxx*/, int* size = nullptr, void* in_data = nullptr); // return whole json-text if name was null }; diff --git a/ui/dev_menu.cpp b/ui/dev_menu.cpp index 184a036..281c001 100644 --- a/ui/dev_menu.cpp +++ b/ui/dev_menu.cpp @@ -3,6 +3,7 @@ #include // #include "Displaydef.h" #include +#include #include #include "keymonitor.h" #include "Lcd.h" @@ -73,7 +74,7 @@ void dev_menu::set_parent(dev_menu* parent) } } -bool dev_menu::add_menu(const char* text, int id) +bool dev_menu::add_menu(const char* text, int id, int pos) { int ind = find_item(text); @@ -85,11 +86,14 @@ bool dev_menu::add_menu(const char* text, int id) mi.id = id; mi.leaf = true; mi.text = text; - items_.push_back(mi); + if(pos < 0 || pos >= items_.size()) + items_.push_back(mi); + else + items_.insert(items_.begin() + pos, mi); return true; } -bool dev_menu::add_menu(const char* text, dev_menu* submenu) +bool dev_menu::add_menu(const char* text, dev_menu* submenu, int pos) { int ind = find_item(text); @@ -101,7 +105,10 @@ bool dev_menu::add_menu(const char* text, dev_menu* submenu) mi.child = submenu; mi.leaf = false; mi.text = text; - items_.push_back(mi); + if(pos < 0 || pos >= items_.size()) + items_.push_back(mi); + else + items_.insert(items_.begin() + pos, mi); submenu->add_ref(); submenu->set_parent(this); @@ -173,13 +180,79 @@ void dev_menu::set_default_pos(std::function f) { reset_pos_ = f; } +void dev_menu::clear(std::function erase_func) +{ + for(auto& v: items_) + { + if(v.leaf) + { + if(erase_func) + erase_func(v.text.c_str()); + } + else + { + v.child->clear(erase_func); + v.child->release(); + } + } + items_.clear(); +} +int dev_menu::count(void) +{ + return items_.size(); +} +std::string& dev_menu::name(void) +{ + return name_; +} +dev_menu* dev_menu::get_sub_menu(const char* text) +{ + dev_menu* sub = nullptr; -dev_menu* dev_menu::enter(int* id) + for(auto& v: items_) + { + if(v.text == text) + { + if(!v.leaf) + { + sub = v.child; + sub->add_ref(); + } + break; + } + } + + return sub; +} +dev_menu* dev_menu::get_sub_menu(int index, std::string* title) +{ + dev_menu* sub = nullptr; + + if(title) + *title = ""; + + if(index >= 0 && index < items_.size()) + { + if(!items_[index].leaf) + { + sub = items_[index].child; + sub->add_ref(); + } + if(title) + *title = items_[index].text; + } + + return sub; +} + +dev_menu* dev_menu::enter(int* id, std::string* text) { dev_menu *menu = this; if(id) *id = -1; + if(text) + *text = ""; if(cur_ >= 0 && cur_ < items_.size()) { if(items_[cur_].leaf) @@ -189,9 +262,12 @@ dev_menu* dev_menu::enter(int* id) if(parent_) menu = parent_; } - else if(id) + else { - *id = items_[cur_].id; + if(id) + *id = items_[cur_].id; + if(text) + *text = items_[cur_].text; if(check_item_) sel_ = cur_; } @@ -486,7 +562,11 @@ ui_mgr::ui_mgr() : disp_data_("lcd-msg") { utils::log_mem_info("status message", pack, pack->whole_size()); - if(pack->msg == devui::UI_STATUS_SCANNING) + if(pack->msg == devui::UI_STATUS_PEER_CONNECTED) + { + send_paper_count(); + } + else if(pack->msg == devui::UI_STATUS_SCANNING) { devui::LPSCANSTREAM scan = (devui::LPSCANSTREAM)pack->data; scanning_ = scan->mode != devui::SCAN_STOPPED; @@ -514,11 +594,13 @@ ui_mgr::ui_mgr() : disp_data_("lcd-msg") display_scan_title(); perm_data_->set_speed(scan->speed); paper_total_ = 0; + send_paper_count(); } } else { perm_data_->save(); + send_paper_count(); if(scan->err) { devui::STATMSG msg; @@ -568,6 +650,37 @@ ui_mgr::ui_mgr() : disp_data_("lcd-msg") if(((devui::LPSTATMSG)pack->data)->msg_words_id == ID_WORDS_STATUS_SCANNER_CONN + 1) set_ready_status_enabled(true); } + else if(pack->msg == devui::UI_STATUS_READY) + { + set_ready_status_enabled(true); + } + else if(pack->msg == devui::UI_CMD_ADD_MENU) + { + add_menu((devui::LPOPTMENU)pack->data); + } + else if(pack->msg == devui::UI_CMD_SET_OPTION_VALUE) + { + char *name = (char*)pack->data; + + for(int i = 0; i < root_->count(); ++i) + { + dev_menu* m = root_->get_sub_menu(i); + if(m) + { + bool over = false; + if(m->name() == name) + { + char* val = utils::next_string(name); + over = true; + m->select(val, true); + utils::to_log(LOG_LEVEL_DEBUG, "select menu '%s' to '%s'\n", name, val); + } + m->release(); + if(over) + break; + } + } + } else if(pack->msg == devui::UI_STATUS_PEER_CLOSED) { peer_connected_ = *(bool*)pack->data; @@ -582,16 +695,6 @@ ui_mgr::ui_mgr() : disp_data_("lcd-msg") if(!display_status(&msg)) set_ready_status_enabled(true); } - else if(pack->msg == devui::UI_CMD_GET_HISTORY_COUNT) - { - uint32_t cnt = (uint32_t)perm_data_->history_count(); - devui::send_message(pack->msg, (uint8_t*)&cnt, sizeof(cnt)); - } - else if(pack->msg == devui::UI_CMD_GET_ROLLER_COUNT) - { - uint32_t cnt = (uint32_t)perm_data_->roller_count(); - devui::send_message(pack->msg, (uint8_t*)&cnt, sizeof(cnt)); - } }; devui::init_ui(statu, true); } @@ -608,19 +711,65 @@ ui_mgr::~ui_mgr() utils::uninit(); } -bool ui_mgr::do_menu_command(int cmd) +void ui_mgr::add_menu(void* data) +{ + devui::LPOPTMENU opt = (devui::LPOPTMENU)data; + char *title = opt->name + opt->title_off, + *val = utils::next_string(title); + dev_menu *menu = root_->get_sub_menu(title); + std::string cur(""); + auto f = [this](MEMNU_CMD_HANDLER_PARAM) -> MENU_CMD_HANDLER_RET + { + set_option_value(menu->name().c_str(), text, strlen(text)); + + return false; + }; + + root_->remove_menu(title); + if(menu) + { + auto ef = [this](const char* text) -> void + { + handler_s_.erase(text); + }; + menu->clear(ef); + menu->release(); + menu = nullptr; + } + else + { + handler_s_.erase(title); + } + + menu = new dev_menu(true); + menu->name() = opt->name; + while(val) + { + if(opt->cur_sel-- == 0) + cur = val; + handler_s_[val] = f; + menu->add_menu(val, MENU_ID_BY_TEXT); + val = utils::next_string(val); + } + menu->select(cur.c_str(), true); + root_->add_menu(title, menu, opt->pos); + menu->release(); +} +bool ui_mgr::do_menu_command(int cmd, const char* text) { bool holdui = false; - utils::to_log(LOG_LEVEL_DEBUG, "Do menu command: %s\n", menu_command::command_string(cmd).c_str()); + utils::to_log(LOG_LEVEL_DEBUG, "Do menu command: %s(%s - %s)\n", menu_command::command_string(cmd).c_str(), cur_->name().c_str(), text); if(cmd >= menu_command::MENU_CMD_ID_SEQ_0 && cmd <= menu_command::MENU_CMD_ID_SEQ_LAST) { if(handler_.count(menu_command::MENU_CMD_ID_SEQ_0)) - holdui = handler_[menu_command::MENU_CMD_ID_SEQ_0](cur_, cmd - menu_command::MENU_CMD_ID_SEQ_0); + holdui = handler_[menu_command::MENU_CMD_ID_SEQ_0](cur_, cmd - menu_command::MENU_CMD_ID_SEQ_0, text); } else if(handler_.count(cmd)) - holdui = handler_[cmd](cur_, cmd); + holdui = handler_[cmd](cur_, cmd, text); + else if(text && *text && handler_s_.count(text)) + holdui = handler_s_[text](cur_, cmd, text); // at last, we return to main menu OR parent ? if(holdui) @@ -634,127 +783,35 @@ bool ui_mgr::do_menu_command(int cmd) return holdui; } +bool ui_mgr::set_option_value(const char* name, const char* val, size_t size) +{ + std::string str(name); + + str.append(1, '\0'); + str += std::string(val, size); + str.append(2, '\0'); + + return devui::send_message(devui::UI_CMD_SET_OPTION_VALUE, (uint8_t*)&str[0], str.length()); +} +bool ui_mgr::send_paper_count(void) +{ + std::string val(std::to_string(perm_data_->roller_count())); + + set_option_value(SANE_OPT_NAME(ROLLER_COUNT), val.c_str(), val.length()); + val = std::to_string(perm_data_->history_count()); + + return set_option_value(SANE_OPT_NAME(HISTORY_COUNT), val.c_str(), val.length()); +} void ui_mgr::init(void) { dev_menu *child = nullptr; root_ = new dev_menu(); - // 分纸强度(低中高) - { - child = new dev_menu(true); - child->add_menu(WORDS_MENU_LOW, menu_command::MENU_CMD_ID_SEPARATE_LOW); - { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET - { - return false; - }; - handler_[menu_command::MENU_CMD_ID_SEPARATE_LOW] = f; - } - child->add_menu(WORDS_MENU_MID, menu_command::MENU_CMD_ID_SEPARATE_MID); - { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET - { - return false; - }; - handler_[menu_command::MENU_CMD_ID_SEPARATE_MID] = f; - } - child->add_menu(WORDS_MENU_HIGH, menu_command::MENU_CMD_ID_SEPARATE_HIGH); - { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET - { - return false; - }; - handler_[menu_command::MENU_CMD_ID_SEPARATE_HIGH] = f; - } - child->select(WORDS_MENU_MID); - root_->add_menu(WORDS_MENU_SEPARATE_STRENGTH, child); - child->release(); - } - // 休眠时间(不休眠,5min, 10min, 20min, 30min, 1h, 2h, 4h) - { - child = new dev_menu(true); - child->add_menu(WORDS_MENU_SLEEP_NONE, menu_command::MENU_CMD_ID_SLEEP_NEVER); - { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET - { - return false; - }; - handler_[menu_command::MENU_CMD_ID_SLEEP_NEVER] = f; - } - child->add_menu(WORDS_MENU_SLEEP_NOW, menu_command::MENU_CMD_ID_SLEEP_IMMEDIATELY); - { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET - { - return false; - }; - handler_[menu_command::MENU_CMD_ID_SLEEP_IMMEDIATELY] = f; - } - child->add_menu(WORDS_MENU_SLEEP_5_MIN, menu_command::MENU_CMD_ID_SLEEP_5MIN); - { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET - { - return false; - }; - handler_[menu_command::MENU_CMD_ID_SLEEP_5MIN] = f; - } - child->add_menu(WORDS_MENU_SLEEP_10_MIN, menu_command::MENU_CMD_ID_SLEEP_10MIN); - { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET - { - return false; - }; - handler_[menu_command::MENU_CMD_ID_SLEEP_10MIN] = f; - } - child->add_menu(WORDS_MENU_SLEEP_20_MIN, menu_command::MENU_CMD_ID_SLEEP_20MIN); - { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET - { - return false; - }; - handler_[menu_command::MENU_CMD_ID_SLEEP_20MIN] = f; - } - child->add_menu(WORDS_MENU_SLEEP_30_MIN, menu_command::MENU_CMD_ID_SLEEP_30MIN); - { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET - { - return false; - }; - handler_[menu_command::MENU_CMD_ID_SLEEP_30MIN] = f; - } - child->add_menu(WORDS_MENU_SLEEP_1_HOUR, menu_command::MENU_CMD_ID_SLEEP_1H); - { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET - { - return false; - }; - handler_[menu_command::MENU_CMD_ID_SLEEP_1H] = f; - } - child->add_menu(WORDS_MENU_SLEEP_2_HOUR, menu_command::MENU_CMD_ID_SLEEP_2H); - { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET - { - return false; - }; - handler_[menu_command::MENU_CMD_ID_SLEEP_2H] = f; - } - child->add_menu(WORDS_MENU_SLEEP_4_HOUR, menu_command::MENU_CMD_ID_SLEEP_4H); - { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET - { - return false; - }; - handler_[menu_command::MENU_CMD_ID_SLEEP_4H] = f; - } - child->select(WORDS_MENU_SLEEP_NONE); - root_->add_menu(WORDS_MENU_POWER, child); - child->release(); - } - // 计数模式、手动模式、清理纸道、历史张数、滚轴张数、清除滚轴张数(确定,取消)、进入休眠、关机 root_->add_menu(WORDS_MENU_COUNT_MODE, menu_command::MENU_CMD_ID_COUNT_MODE); { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET + auto f = [this](MEMNU_CMD_HANDLER_PARAM) -> MENU_CMD_HANDLER_RET { // 保持界面:第一行显示当前保持的功能 // 第二行显示当前功能的信息,过程中只更新该行 @@ -791,7 +848,7 @@ void ui_mgr::init(void) } root_->add_menu(WORDS_MENU_MANUAL_MODE, menu_command::MENU_CMD_ID_HANDLE_MODE); { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET + auto f = [this](MEMNU_CMD_HANDLER_PARAM) -> MENU_CMD_HANDLER_RET { return true; }; @@ -799,7 +856,7 @@ void ui_mgr::init(void) } root_->add_menu(WORDS_MENU_CLEAR_PASSWAY, menu_command::MENU_CMD_ID_CLEAR_PASSWAY); { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET + auto f = [this](MEMNU_CMD_HANDLER_PARAM) -> MENU_CMD_HANDLER_RET { devui::send_message(devui::UI_CMD_CLEAN_PASSWAY); @@ -809,7 +866,7 @@ void ui_mgr::init(void) } root_->add_menu(WORDS_MENU_HISTORY_COUNT, menu_command::MENU_CMD_ID_GET_HISTORY_COUNT); { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET + auto f = [this](MEMNU_CMD_HANDLER_PARAM) -> MENU_CMD_HANDLER_RET { DISPDATA dd; @@ -833,7 +890,7 @@ void ui_mgr::init(void) } root_->add_menu(WORDS_MENU_ROLLER_COUNT, menu_command::MENU_CMD_ID_GET_ROLLER_COUNT); { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET + auto f = [this](MEMNU_CMD_HANDLER_PARAM) -> MENU_CMD_HANDLER_RET { DISPDATA dd; char cnt[40] = {0}; @@ -861,9 +918,14 @@ void ui_mgr::init(void) child = new dev_menu(false, false); child->add_menu(WORDS_MENU_YES, menu_command::MENU_CMD_ID_CLEAR_ROLLER_CNT); { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET + auto f = [this](MEMNU_CMD_HANDLER_PARAM) -> MENU_CMD_HANDLER_RET { + std::string str(""); + perm_data_->clear_roller_count(); + utils::add_2_string_array(str, SANE_OPT_NAME(ROLLER_COUNT)); + utils::add_2_string_array(str, "0"); + devui::send_message(devui::UI_CMD_SET_OPTION_VALUE, (uint8_t*)&str[0], str.length()); return false; }; @@ -879,7 +941,7 @@ void ui_mgr::init(void) child = new dev_menu(true); child->add_menu(WORDS_MENU_LOW, menu_command::MENU_CMD_ID_LIFTER_LOW); { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET + auto f = [this](MEMNU_CMD_HANDLER_PARAM) -> MENU_CMD_HANDLER_RET { return false; }; @@ -887,7 +949,7 @@ void ui_mgr::init(void) } child->add_menu(WORDS_MENU_MID, menu_command::MENU_CMD_ID_LIFTER_MID); { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET + auto f = [this](MEMNU_CMD_HANDLER_PARAM) -> MENU_CMD_HANDLER_RET { return false; }; @@ -895,7 +957,7 @@ void ui_mgr::init(void) } child->add_menu(WORDS_MENU_HIGH, menu_command::MENU_CMD_ID_LIFTER_HIGH); { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET + auto f = [this](MEMNU_CMD_HANDLER_PARAM) -> MENU_CMD_HANDLER_RET { return false; }; @@ -907,7 +969,7 @@ void ui_mgr::init(void) } // 调整系统时间 { - auto adjtm = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET + auto adjtm = [this](MEMNU_CMD_HANDLER_PARAM) -> MENU_CMD_HANDLER_RET { int hour = -1, min = -1; @@ -995,7 +1057,7 @@ void ui_mgr::init(void) child = new dev_menu(false, false); child->add_menu(WORDS_MENU_YES, menu_command::MENU_CMD_ID_SHUTDOWN); { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET + auto f = [this](MEMNU_CMD_HANDLER_PARAM) -> MENU_CMD_HANDLER_RET { system("poweroff"); @@ -1011,7 +1073,7 @@ void ui_mgr::init(void) root_->add_menu(WORDS_MENU_WELCOME, menu_command::MENU_CMD_ID_WELCOME); { - auto f = [this](dev_menu* m, int id) -> MENU_CMD_HANDLER_RET + auto f = [this](MEMNU_CMD_HANDLER_PARAM) -> MENU_CMD_HANDLER_RET { DISPDATA dd; dd.mask = 0; @@ -1097,12 +1159,13 @@ void ui_mgr::enter(void) { int id = -1; dev_menu* bef = cur_; + std::string text(""); - cur_ = cur_->enter(&id); + cur_ = cur_->enter(&id, &text); bef->release(); - if(id != -1) + if(id != -1 || !text.empty()) { - bool holdui = do_menu_command(id); + bool holdui = do_menu_command(id, text.c_str()); set_ready_status_enabled(!holdui); } if(cur_ != bef) diff --git a/ui/dev_menu.h b/ui/dev_menu.h index bff22de..985bf67 100644 --- a/ui/dev_menu.h +++ b/ui/dev_menu.h @@ -23,14 +23,16 @@ #include #define MENU_ID_RETURN -1 // ID of menu item that return to parent +#define MENU_ID_BY_TEXT -2 #define LINK_DEFINE(x, y) x##y -#define MEMNU_CMD_HANDLER_PARAM dev_menu* menu, int id -#define MENU_CMD_HANDLER_RET bool +#define MEMNU_CMD_HANDLER_PARAM dev_menu* menu, int id, const char* text +#define MENU_CMD_HANDLER_RET bool // whether hold ui #define MENU_CMD_CALLBACK std::function class dev_menu : public refer { dev_menu* parent_ = nullptr; + std::string name_ = ""; typedef struct _menu_item { @@ -61,8 +63,8 @@ protected: void set_parent(dev_menu* parent); public: - bool add_menu(const char* text, int id); - bool add_menu(const char* text, dev_menu* submenu); + bool add_menu(const char* text, int id, int pos = -1); + bool add_menu(const char* text, dev_menu* submenu, int pos = -1); bool remove_menu(const char* text); void set_need_return_parent(bool need); bool move_to(bool next); // true - move to next, false - move to previous. if at end position of move direction, return false @@ -70,13 +72,20 @@ public: void reset_pos(void); void set_default_pos(int pos = 0); void set_default_pos(std::function f); + void clear(std::function erase_func = std::function()); + int count(void); + std::string& name(void); + dev_menu* get_sub_menu(const char* text); + dev_menu* get_sub_menu(int index, std::string* title = nullptr); // Function: access current menu // // Parameter: id - to receive ID of current menu item if leaf, fill '-1' if a submenu // + // text - to receive text of current menu if leaf, empty if submenu + // // Return: current menu, user should call 'release' after use - dev_menu* enter(int* id); + dev_menu* enter(int* id, std::string* text); // Function: get all menus text // @@ -111,6 +120,7 @@ class ui_mgr : public refer POINT hold_pos_ = {0, 0}; std::map handler_; + std::map handler_s_; std::unique_ptr lcd_; std::unique_ptr keyboard_; @@ -285,7 +295,10 @@ class ui_mgr : public refer }; refer_guard perm_data_; - bool do_menu_command(int cmd); // return whether should hold UI ? + void add_menu(void* data); + bool do_menu_command(int cmd, const char* text); // return whether should hold UI ? + bool set_option_value(const char* name, const char* val, size_t size); + bool send_paper_count(void); void init(void); void clear(void); void refresh_lcd(bool cur_at_top); diff --git a/ui/font.cpp b/ui/font.cpp index 306e16f..4fd66d3 100644 --- a/ui/font.cpp +++ b/ui/font.cpp @@ -806,6 +806,54 @@ namespace custom_font }; font_map_["\345\274\200"] = kai; + static uint8_t ban1[] = {16, 16 + , 0x80, 0x80, 0xFC, 0x96, 0xE5, 0x84, 0xFC, 0x00, 0xA0, 0x9E, 0x82, 0x82, 0x9E, 0xA0, 0x20, 0x00 + , 0x80, 0x60, 0x1F, 0x02, 0x4C, 0x80, 0x7F, 0x80, 0x80, 0x43, 0x2C, 0x10, 0x2C, 0x43, 0x80, 0x00 + }; + font_map_["\350\210\254"] = ban1; + + static uint8_t ruo[] = {16, 16 + , 0x00, 0xF2, 0x92, 0x92, 0x92, 0x92, 0x9E, 0x00, 0xF2, 0x92, 0x92, 0x92, 0x92, 0x9E, 0x00, 0x00 + , 0x00, 0x10, 0x11, 0x4A, 0x88, 0x44, 0x3F, 0x00, 0x10, 0x11, 0x4A, 0x88, 0x44, 0x3F, 0x00, 0x00 + }; + font_map_["\345\274\261"] = ruo; + + static uint8_t wu3[] = {16, 16 + , 0x00, 0x02, 0x42, 0x42, 0x42, 0xC2, 0x7E, 0x42, 0x42, 0x42, 0x42, 0xC2, 0x02, 0x02, 0x00, 0x00 + , 0x40, 0x40, 0x40, 0x40, 0x78, 0x47, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7F, 0x40, 0x40, 0x40, 0x00 + }; + font_map_["\344\272\224"] = wu3; + + static uint8_t shi2[] = {16, 16 + , 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xFF, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + font_map_["\345\215\201"] = shi2; + + static uint8_t ban4[] = {16, 16 + , 0x00, 0x00, 0x42, 0x44, 0x58, 0x40, 0x40, 0xFF, 0x40, 0x40, 0x50, 0x48, 0x46, 0x00, 0x00, 0x00 + , 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0xFF, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00 + }; + font_map_["\345\215\212"] = ban4; + + static uint8_t liang[] = {16, 16 + , 0x02, 0xE2, 0x22, 0x22, 0x22, 0xFE, 0x22, 0x22, 0x22, 0xFE, 0x22, 0x22, 0x22, 0xE2, 0x02, 0x00 + , 0x00, 0xFF, 0x00, 0x08, 0x06, 0x01, 0x16, 0x08, 0x06, 0x01, 0x02, 0x4C, 0x80, 0x7F, 0x00, 0x00 + }; + font_map_["\344\270\244"] = liang; + + static uint8_t si[] = {16, 16 + , 0x00, 0xFC, 0x04, 0x04, 0x04, 0xFC, 0x04, 0x04, 0x04, 0xFC, 0x04, 0x04, 0x04, 0xFC, 0x00, 0x00 + , 0x00, 0x7F, 0x28, 0x24, 0x23, 0x20, 0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x22, 0x7F, 0x00, 0x00 + }; + font_map_["\345\233\233"] = si; + + static uint8_t xiao3[] = {16, 16 + , 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x20, 0x40, 0x80, 0x00, 0x00 + , 0x08, 0x04, 0x03, 0x00, 0x00, 0x40, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00 + }; + font_map_["\345\260\217"] = xiao3; + } ~font_init() {} @@ -819,6 +867,7 @@ namespace custom_font return font_map8x8_[str]; } + printf("%s(8) not found\n", str); return custom_font::question8x8; } else if(fs == FONT_SIZE_16) @@ -827,7 +876,7 @@ namespace custom_font { return font_map_[str]; } - + printf("%s(16) not found\n", str); return custom_font::question; } else if(fs == FONT_SIZE_32) @@ -836,7 +885,7 @@ namespace custom_font { return font_map32x32_[str]; } - + printf("%s(32) not found\n", str); return custom_font::question32x32; } diff --git a/usb/usb_io.cpp b/usb/usb_io.cpp index 17d672d..ab8fa2e 100644 --- a/usb/usb_io.cpp +++ b/usb/usb_io.cpp @@ -897,6 +897,10 @@ int async_usb_gadget::last_error(void) { return last_err_; } +uint32_t async_usb_gadget::current_session(void) +{ + return session_id_; +} void async_usb_gadget::get_ep_status(LPEP0REPLYSTATUS status) { diff --git a/usb/usb_io.h b/usb/usb_io.h index 5eeb3c6..48b82d7 100644 --- a/usb/usb_io.h +++ b/usb/usb_io.h @@ -122,6 +122,7 @@ public: int stop(void); int write_bulk(data_source_ptr data); // return sent-que length int last_error(void); + uint32_t current_session(void); void get_ep_status(LPEP0REPLYSTATUS status); }; diff --git a/xmake.lua b/xmake.lua index 5b2a860..34c7b33 100644 --- a/xmake.lua +++ b/xmake.lua @@ -60,8 +60,8 @@ add_packagedirs("sdk") add_defines("BUILD_AS_DEVICE") add_defines("VER_MAIN=2") add_defines("VER_FAMILY=200") -add_defines("VER_DATE=20240318") -add_defines("VER_BUILD=15") +add_defines("VER_DATE=20240321") +add_defines("VER_BUILD=21") target("conf") set_kind("phony")