优化UI与服务程序通信;属性菜单由服务程序动态添加

This commit is contained in:
gb 2024-03-21 15:16:39 +08:00
parent bf151014ea
commit 1443eb9445
22 changed files with 883 additions and 352 deletions

View File

@ -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",

View File

@ -543,13 +543,18 @@ int scanner_hw::scan_one_turn(LPPACKIMAGE img, safe_fifo<int>* 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);
}
#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<int>* 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;

View File

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

View File

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

View File

@ -4,7 +4,7 @@
#include <sane/sane_ex.h>
#include <string.h>
#include <base/ui.h>
#include <huagao/hgscanner_error.h>
@ -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;
}

View File

@ -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;
};

View File

@ -5,6 +5,7 @@
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#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<void(LPMSGSTREAM)> cb_;
safe_fifo<std::string> 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();
}
};

View File

@ -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<void(LPMSGSTREAM)> uicb, bool ui);

View File

@ -1101,6 +1101,46 @@ namespace utils
return str.c_str();
}
std::string string_array(const std::vector<std::string>& 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;

View File

@ -95,6 +95,12 @@ 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()
// string array
std::string string_array(const std::vector<std::string>& 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);
bool from_hex_string(const char* hex, uint8_t* val);

View File

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

View File

@ -139,6 +139,7 @@ extern "C" {
SANE_ACTION_GET_DEFAULT_VALUE = 100, // 获取设置项默认值参数同SANE_ACTION_GET_VALUE
SANE_ACTION_GET_FIX_ID, // 获取属性的固定IDvoid* = 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

View File

@ -5,7 +5,45 @@
#include <sane/sane_ex.h>
#include <string.h>
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
template<class T>
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<bool>(value, range, &isrng);
}
else if(*type == SANE_TYPE_INT)
{
get_range_values<int>(value, range, &isrng);
}
else if(*type == SANE_TYPE_FIXED)
{
get_range_values<double>(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)
{

View File

@ -8,6 +8,7 @@
#include <string>
#include <map>
#include <base/utils.h> // for refer
#include <sane/sane_ex.h>
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();

View File

@ -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<bool>(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("");

View File

@ -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<class T>
@ -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
};

View File

@ -3,6 +3,7 @@
#include <string.h>
// #include "Displaydef.h"
#include <base/words.h>
#include <sane/sane_name.h>
#include <base/ui.h>
#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<void(dev_menu*)> f)
{
reset_pos_ = f;
}
void dev_menu::clear(std::function<void(const char*)> 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)

View File

@ -23,14 +23,16 @@
#include <string.h>
#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<MENU_CMD_HANDLER_RET(MEMNU_CMD_HANDLER_PARAM)>
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<void(dev_menu*)> f);
void clear(std::function<void(const char*)> erase_func = std::function<void(const char*)>());
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<int, MENU_CMD_CALLBACK> handler_;
std::map<std::string, MENU_CMD_CALLBACK> handler_s_;
std::unique_ptr<Lcd> lcd_;
std::unique_ptr<KeyMonitor> keyboard_;
@ -285,7 +295,10 @@ class ui_mgr : public refer
};
refer_guard<permanent_data> 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);

View File

@ -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;
}

View File

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

View File

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

View File

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