code_device/hgdriver/hgdev/scanner_manager.cpp

781 lines
24 KiB
C++

#include "scanner_manager.h"
#include <base/utils.h>
#include <lang/app_language.h>
#include <iostream>
#include <fstream>
#include <string.h>
#include <huagao/brand.h>
#include "hg_scanner.h"
#include "user-opt/user.h"
#include "user-opt/offline_opt.h"
#include <sane_opt_json/device_opt.h>
#include <imgprc/imgprc_mgr.h>
// kinds of scanners ...
#define SCAN_PTR(ptr) ((hg_scanner*)ptr)
static struct _scanner_device
{
int vid;
int pid;
std::string family;
std::string name;
} g_supporting_devices[] = { ALL_FAMILIES };
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// language option ...
class lang_opt : public sane_opt_provider
{
public:
lang_opt()
{
set_where("language-option");
const char* lang = language_option_descriptor();
if (lang && *lang)
{
std::string t(lang);
set_opt_json_text(&t[0]);
}
}
protected:
virtual ~lang_opt()
{}
public:
virtual int set_value(const char* name, void* val) override
{
if (strcmp(name, "language"))
return SCANNER_ERR_NO_DATA;
LANATTR** pla = lang_get_supported_languages();
int err = SCANNER_ERR_OK;
if (!pla)
err = SCANNER_ERR_DEVICE_NOT_SUPPORT;
else
{
std::string n(to_default_language((char*)val, nullptr)), now("");
int id = -1, cur = lang_get_cur_code_page();
for (int i = 0; pla[i]; ++i)
{
if (pla[i]->cp == cur)
now = pla[i]->name;
if (n == pla[i]->name)
{
id = pla[i]->cp;
break;
}
}
if (id == -1)
{
err = SCANNER_ERR_NOT_EXACT;
::strcpy((char*)val, now.c_str());
}
else if (cur != id)
{
err = SCANNER_ERR_CONFIGURATION_CHANGED;
lang_set_code_page(id);
}
}
return err;
}
};
static lang_opt* g_language = nullptr;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
hg_scanner_mgr* hg_scanner_mgr::inst_ = NULL;
sane_callback hg_scanner_mgr::event_callback_ = NULL;
bool hg_scanner_mgr::async_io_enabled_ = false;
int hg_scanner_mgr::ver_major_ = 1;
int hg_scanner_mgr::ver_minor_ = 0;
int hg_scanner_mgr::ver_build_ = 0;
int hg_scanner_mgr::ver_patch_ = 1;
std::string hg_scanner_mgr::pe_path_("");
std::string hg_scanner_mgr::pe_name_("");
std::string hg_scanner_mgr::last_open_msg_("");
bool hg_scanner_mgr::read_over_with_eof_ = true;
uint32_t hg_scanner_mgr::unique_img_id_ = 0;;
std::mutex hg_scanner_mgr::mutex_img_id;
hg_scanner_mgr::hg_scanner_mgr() : same_ind_(1), cf_name("")
{
std::string cfgf(utils::get_local_data_path() + PATH_SEPARATOR + "config" + PATH_SEPARATOR + "debug.cfg");
char buf[260] = {0};
int l = GetPrivateProfileStringA("devs_name", "name", "", buf, _countof(buf) - 1, cfgf.c_str());
init_debug_config(cfgf.c_str());
buf[l] = 0;
cf_name = buf;
usb_manager::instance()->register_hotplug(&hg_scanner_mgr::usb_event_handle, this);
int code_page = lang_get_cur_code_page();
url_en = BRAND_COMPANY_URL;
url_link_en = BRAND_URL_COMPANY_URL;
if (code_page == 20127)
{
url_en = BRAND_COMPANY_URL_EN;
url_link_en = BRAND_URL_COMPANY_URL_EN;
}
user_ = new hguser();
offline_ = new offline_opts(user_);
g_language = new lang_opt();
}
hg_scanner_mgr::~hg_scanner_mgr()
{
usb_manager::instance()->register_hotplug(nullptr, nullptr);
{
std::lock_guard<std::mutex> lock(mutex_dev_);
for (auto& v : online_devices_)
{
if (v.scanner)
{
v.scanner->close();
v.scanner->release();
v.scanner = nullptr;
}
libusb_unref_device(v.dev);
}
online_devices_.clear();
}
usb_manager::clear();
offline_->release();
delete user_;
g_language->release();
}
int hg_scanner_mgr::ui_default_callback(scanner_handle h, int ev, void* data, unsigned int* len, void* param)
{
// if (!hg_scanner_mgr::async_io_enabled_ &&
// ev == SANE_EVENT_IS_MEMORY_ENOUGH)
// {
// struct sysinfo si;
// if(sysinfo(&si) == 0)
// return si.freeram * si.mem_unit > *len + 200 * 1024 * 1024 ? SCANNER_ERR_OK : SCANNER_ERR_INSUFFICIENT_MEMORY;
// return SCANNER_ERR_OK;
// }
if (hg_scanner_mgr::event_callback_)
return hg_scanner_mgr::event_callback_(h, ev, data, len, param);
return SCANNER_ERR_OK;
}
hg_scanner_mgr* hg_scanner_mgr::instance(sane_callback cb)
{
if (!hg_scanner_mgr::inst_)
{
hg_scanner_mgr::event_callback_ = cb;
if (cb)
hg_scanner_mgr::async_io_enabled_ = cb(NULL, SANE_EVENT_SUPPORT_ASYNC_IO, NULL, NULL, NULL) == 0;
hg_scanner_mgr::unique_img_id_ = (uint32_t)INT_MAX + 1;
hg_scanner_mgr::inst_ = new hg_scanner_mgr();
utils::to_log(LOG_LEVEL_DEBUG, "async image transferring is %s\n", hg_scanner_mgr::async_io_enabled_ ? "enabled" : "disabled");
}
return hg_scanner_mgr::inst_;
}
void hg_scanner_mgr::clear(void)
{
if (hg_scanner_mgr::inst_)
{
{
std::lock_guard<std::mutex> lock(hg_scanner_mgr::inst_->mutex_dev_);
hg_scanner_mgr::event_callback_ = nullptr;
}
delete hg_scanner_mgr::inst_;
hg_scanner_mgr::inst_ = NULL;
}
}
void hg_scanner_mgr::set_version(int hh, int hl, int lh, int ll)
{
hg_scanner_mgr::ver_major_ = hh;
hg_scanner_mgr::ver_minor_ = hl;
hg_scanner_mgr::ver_build_ = lh;
hg_scanner_mgr::ver_patch_ = ll;
}
void hg_scanner_mgr::get_version(int* hh, int* hl, int* lh, int* ll)
{
if(hh)
*hh = hg_scanner_mgr::ver_major_;
if(hl)
*hl = hg_scanner_mgr::ver_minor_;
if(lh)
*lh = hg_scanner_mgr::ver_build_;
if(ll)
*ll = hg_scanner_mgr::ver_patch_;
}
void hg_scanner_mgr::set_exe_name(const char* path, const char* name)
{
std::string cfgf(utils::get_local_data_path() + PATH_SEPARATOR + "config" + PATH_SEPARATOR + "debug.cfg");
char buf[260] = {0};
int l = 0;
hg_scanner_mgr::pe_path_ = path ? path : "";
hg_scanner_mgr::pe_name_ = name ? name : "";
std::string str(utils::get_command_result("scanimage -V"));
bool is_scanimg =false;
is_scanimg = str >= "1.0.29" ? true : false;
utils::to_log(LOG_LEVEL_ALL, "imgascan ver is: %s is_scanimg is:%d\n", str.c_str(),is_scanimg);
if (name && *name)
{
// int ret = system("scanimage -V");
l = GetPrivateProfileStringA("read_eof", name, "", buf, _countof(buf) - 1, cfgf.c_str());
if (l == 0)
{
if(is_scanimg)
hg_scanner_mgr::read_over_with_eof_ = STRICMP(name, "simple-scan") != 0;
else
hg_scanner_mgr::read_over_with_eof_ = STRICMP(name, "simple-scan") != 0 && (!is_scanimg? (STRICMP(name, "scanimage") != 0) : 1);
}
else
hg_scanner_mgr::read_over_with_eof_ = strcmp(buf, "0") != 0;
}
else
{
l = GetPrivateProfileStringA("read_eof", "first", "", buf, _countof(buf) - 1, cfgf.c_str());
if (l == 0)
hg_scanner_mgr::read_over_with_eof_ = true;
else
hg_scanner_mgr::read_over_with_eof_ = strcmp(buf, "0") != 0;
}
utils::to_log(LOG_LEVEL_ALL, "read image data end with EOF: %s\n", hg_scanner_mgr::read_over_with_eof_ ? "true" : "false");
}
std::string hg_scanner_mgr::get_pe_name(std::string* path)
{
if (path)
*path = hg_scanner_mgr::pe_path_;
return hg_scanner_mgr::pe_name_;
}
uint32_t hg_scanner_mgr::unique_id(int type)
{
if (type == UNIQUE_ID_IMG)
{
std::lock_guard<std::mutex> lock(hg_scanner_mgr::mutex_img_id);
return hg_scanner_mgr::unique_img_id_++;
}
return -1;
}
void hg_scanner_mgr::usb_event_handle(usb_event ev, libusb_device* device, int vid, int pid, int usb_ver_h, int usb_ver_l, bool* retry, void* user) // usb_ver_h.usb_ver_l
{
hg_scanner_mgr* obj = (hg_scanner_mgr*)user;
obj->on_hgscanner_pnp(ev, device, vid, pid, usb_ver_h, usb_ver_l, retry);
}
void hg_scanner_mgr::on_hgscanner_pnp(usb_event ev, libusb_device* device, int vid, int pid, int usb_ver_h, int usb_ver_l, bool* retry)
{
char model[40],
vendor[40];
SANE_Device_Ex de;
int ev_ui = 0, addr = 0;
scanner_handle h = NULL;
unsigned int len = sizeof(de);
std::string name(""), type("");
std::lock_guard<std::mutex> lock(mutex_dev_);
sprintf(model, "%x", pid);
sprintf(vendor, "%x", vid);
de.model = model;
de.name = NULL;
de.family = NULL;
de.vendor = vendor;
de.openned = SANE_FALSE;
addr = libusb_get_device_address(device);
if (ev == USB_EVENT_DEVICE_ARRIVED)
{
int index = -1;
for (int i = 0; i < _countof(g_supporting_devices); ++i)
{
if (g_supporting_devices[i].vid == vid && g_supporting_devices[i].pid == pid)
{
index = i;
ev_ui = SANE_EVENT_DEVICE_ARRIVED;
name = g_supporting_devices[i].name.c_str();
type = g_supporting_devices[i].family.c_str();
if (vid == 0x064B && !cf_name.empty())
{
if (cf_name == g_supporting_devices[i].family)
{
name = g_supporting_devices[i].name.c_str();
type = g_supporting_devices[i].family.c_str();
break;
}
}
else
break;
}
}
if (index != -1)
{
bool add = true;
size_t i = 0;
for (; i < online_devices_.size(); ++i)
{
if (online_devices_[i].dev == device)
{
add = false;
break;
}
}
if (add)
{
i = 0;
for (auto& v : online_devices_)
{
if (v.scanner && !v.scanner->is_online())
{
add = false;
break;
}
i++;
}
}
if (add)
{
ONLNSCANNER ols;
ols.vid = vid;
ols.pid = pid;
ols.addr = addr;
ols.dev = device;
ols.scanner = nullptr;
ols.family = g_supporting_devices[index].family;
ols.display_name = g_supporting_devices[index].name;
if (std::find(online_devices_.begin(), online_devices_.end(), ols.display_name.c_str()) != online_devices_.end())
{
int sn = 0;
while (std::find(online_devices_.begin(), online_devices_.end(), (ols.display_name + " - " + std::to_string(++sn)).c_str()) != online_devices_.end());
ols.display_name += " - " + std::to_string(sn);
}
libusb_ref_device(ols.dev); // ref to the device of queue online_devices_
online_devices_.push_back(ols);
name = ols.display_name;
utils::to_log(LOG_LEVEL_DEBUG, "%s connected.\n", name.c_str());
type = g_supporting_devices[index].family;
}
else if (i < online_devices_.size() && online_devices_[i].scanner && !online_devices_[i].scanner->is_online())
{
name = online_devices_[i].display_name;
type = g_supporting_devices[index].family;
if (online_devices_[i].dev)
libusb_unref_device(online_devices_[i].dev);
online_devices_[i].dev = device;
libusb_ref_device(online_devices_[i].dev);
h = online_devices_[i].scanner;
if (pid == 0x300 || pid == 0x400)
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
//len = usb_manager::instance()->open(device, &io);
utils::to_log(LOG_LEVEL_WARNING, "[%04x:%04x]%s re-connected.\n", vid, pid, online_devices_[i].display_name.c_str());
len = online_devices_[i].scanner->re_connect();
if (len == SCANNER_ERR_OK)
{
//online_devices_[i].scanner->reset_io(io);
de.openned = SANE_TRUE;
}
add = false;
}
}
}
else if (ev == USB_EVENT_DEVICE_LEFT)
{
std::vector<ONLNSCANNER>::iterator it = std::find(online_devices_.begin(), online_devices_.end(), device);
if (it != online_devices_.end())
{
ev_ui = SANE_EVENT_DEVICE_LEFT;
name = it->display_name;
type = it->family;
h = it->scanner;
utils::to_log(LOG_LEVEL_DEBUG, "%s Dis-connected.\n", name.c_str());
if (!it->scanner)
{
libusb_unref_device(it->dev); // unref the device of queue online_devices_
online_devices_.erase(it);
}
}
}
if (ev_ui)
{
de.name = name.c_str();
de.family = type.c_str();
hg_scanner_mgr::ui_default_callback(h, ev_ui, &de, &len, NULL);
}
}
void hg_scanner_mgr::get_online_devices(std::vector<ONLNSCANNER>& devs)
{
std::lock_guard<std::mutex> lock(mutex_dev_);
devs = online_devices_;
}
void hg_scanner_mgr::init_debug_config(const char* cfg_file)
{
// dumping images ...
dump_img_path_ = utils::get_local_data_path() + PATH_SEPARATOR + "imgs";
if (GetPrivateProfileIntA("dump", "dumpusb", 0, cfg_file) == 1)
{
char strbuf[260] = { 0 };
int getl = 0;
dump_img_ = true;
getl = GetPrivateProfileStringA("dump", "usb_path", "", strbuf, _countof(strbuf) - 1, cfg_file);
if (getl)
dump_img_path_ = strbuf;
}
}
imgproc_mgr* hg_scanner_mgr::create_image_processor(device_option* devopts)
{
imgproc_mgr* proc = new imgproc_mgr(devopts, dump_img_, dump_img_path_.c_str());
std::string path(utils::get_module_full_path(MODULE_NAME_SCANNER));
size_t pos = path.rfind(PATH_SEPARATOR[0]);
if (pos++ == std::string::npos)
pos = 0;
path.erase(pos);
path += std::string("imgproc") + PATH_SEPARATOR;
// load image-processors ...
proc->load_processor(path.c_str());
return proc;
}
scanner_err hg_scanner_mgr::hg_scanner_enum(ScannerInfo* scanner_list, long* count, bool local_only)
{
std::vector<ONLNSCANNER> devusbuf;
long size = *count;
scanner_err ret = SCANNER_ERR_OK;
std::string g_vendor(from_default_language(COMPANY_NAME, nullptr));
get_online_devices(devusbuf);
*count = devusbuf.size();
if (*count > size)
{
ret = SCANNER_ERR_INSUFFICIENT_MEMORY;
}
else
{
for (size_t i = 0; i < devusbuf.size(); i++)
{
scanner_list->vid = devusbuf[i].vid;
scanner_list->pid = devusbuf[i].pid;
strcpy(scanner_list->name, devusbuf[i].display_name.c_str());
strcpy(scanner_list->model, devusbuf[i].family.c_str());
strcpy(scanner_list->vendor, g_vendor.c_str());
scanner_list++;
}
}
return ret;
}
scanner_err hg_scanner_mgr::hg_scanner_open(scanner_handle* h, const char* name, bool shared, const char* user, const char* pwd, const char* check, char* rsc)
{
std::vector<ONLNSCANNER>::iterator it;
scanner_err ret = SCANNER_ERR_DEVICE_NOT_FOUND;
SIMPLE_LOCK(mutex_dev_);
*h = NULL;
it = std::find(online_devices_.begin(), online_devices_.end(), name);
if (it != online_devices_.end())
{
std::vector<sane_opt_provider*> cnst;
cnst.push_back(offline_);
cnst.push_back(g_language);
it->scanner = new hg_scanner(&(*it), nullptr, user_, &cnst);
if (it->scanner->status() == SCANNER_ERR_OK)
{
*h = it->scanner;
}
else
{
ret = (scanner_err)it->scanner->status();
hg_scanner_mgr::last_open_msg_ = it->scanner->status_message();
it->scanner->close();
it->scanner->release();
it->scanner = nullptr;
}
}
return *h ? SCANNER_ERR_OK : ret;
}
scanner_err hg_scanner_mgr::hg_scanner_close(scanner_handle h, bool force)
{
{
std::lock_guard<std::mutex> lock(mutex_dev_);
for (auto& v : online_devices_)
{
if (v.scanner == h)
{
v.scanner->close(/*force*/);
v.scanner->release();
v.scanner = nullptr;
break;
}
}
}
return SCANNER_ERR_OK;
}
scanner_err hg_scanner_mgr::hg_scanner_get_parameter(scanner_handle h, const char* name, char* data, long* len, int type)
{
scanner_err err = SCANNER_ERR_INVALID_PARAMETER;
if (len)
{
device_option* tmp = nullptr;
if (!h)
{
tmp = new device_option();
tmp->add(offline_);
tmp->add(g_language);
}
else
{
err = SCANNER_ERR_DEVICE_NOT_FOUND;
std::lock_guard<std::mutex> lock(mutex_dev_);
for (auto& v : online_devices_)
{
if (v.scanner == h)
{
tmp = v.scanner->get_device_opt();
break;
}
}
}
if (tmp)
{
std::string raw(tmp->get_option_value(name == PARAM_ALL ? nullptr : name, type, nullptr, data));
if (*len < raw.length())
{
*len = raw.length();
err = SCANNER_ERR_INSUFFICIENT_MEMORY;
}
else
{
memcpy(data, raw.c_str(), raw.length());
if (*len > raw.length())
data[raw.length()] = 0;
*len = raw.length();
err = SCANNER_ERR_OK;
#if defined(_WIN32) && defined(_DEBUG)
if (name == PARAM_ALL)
{
std::string file(utils::get_local_data_path() + PATH_SEPARATOR + "Log" + PATH_SEPARATOR + "allopt.txt");
FILE* dst = fopen(file.c_str(), "wb");
if (dst)
{
fwrite(raw.c_str(), 1, raw.length(), dst);
fclose(dst);
}
}
#endif
}
tmp->release();
}
}
return err;
}
scanner_err hg_scanner_mgr::hg_scanner_set_parameter(scanner_handle h, const char* name, void* data, bool to_default)
{
scanner_err err = SCANNER_ERR_OK, se = SCANNER_ERR_OK;
std::string init("");
device_option* tmp = nullptr;
if (!h)
{
tmp = new device_option();
tmp->add(offline_);
tmp->add(g_language);
}
else
{
for (auto& v : online_devices_)
{
if (v.scanner == h)
{
tmp = v.scanner->get_device_opt();
break;
}
}
}
if (tmp)
{
// do restore here ?
if (name && strcmp(name, SANE_STD_OPT_NAME_RESTORE) == 0)
{
sane_opt_provider* sop = dynamic_cast<sane_opt_provider*>(SCAN_PTR(h));
err = (scanner_err)tmp->restore(sop);
utils::to_log(LOG_LEVEL_DEBUG, "Restore all options ...\n");
}
else
{
// 1 - paper option removes 'lateral' choices and add new option with name 'lateral'
// 2 - page option replaces 'single side' with 'front side' and 'back side'
//
// here to transfer them ...
std::string prev("");
bool lateral = false, restore_data = false;
if (to_default)
{
int size = 0;
init = tmp->get_option_value(name, SANE_ACTION_GET_DEFAULT_VALUE, &size);
if (size > init.length())
{
std::string t(std::move(init));
init.reserve(size);
memset(&init[0], 0, size);
memcpy(&init[0], &t[0], t.length());
}
data = &init[0];
}
else
{
if (strcmp(name, SANE_STD_OPT_NAME_PAPER) == 0)
{
std::string hx(from_default_language("\346\250\252\345\220\221"));
char* lat = strstr((char*)data, hx.c_str());
if (lat)
{
prev = (char*)data;
lateral = true;
restore_data = true;
*lat = 0;
}
}
else if (strcmp(name, SANE_STD_OPT_NAME_PAGE) == 0)
{
if (strcmp((char*)data, from_default_language("\345\215\225\351\235\242")) == 0) // single side
{
prev = (char*)data;
restore_data = true;
strcpy((char*)data, from_default_language("\346\255\243\351\235\242")); // front side
utils::to_log(LOG_LEVEL_DEBUG, "compatible for old page option '%s' to '%s'.\n", prev.c_str(), (char*)data);
}
}
err = tmp->refine_data(name, data) ? SCANNER_ERR_NOT_EXACT : SCANNER_ERR_OK;
}
se = (scanner_err)tmp->update_data(name, data);
if (se != SCANNER_ERR_OK)
err = se;
else if (restore_data)
{
// here handle options paper and page are both string ...
strcpy((char*)data, prev.c_str());
if (lateral)
{
utils::to_log(LOG_LEVEL_DEBUG, "compatible for old paper option '%s', set lateral to '%s' additional.\n", prev.c_str(), lateral ? "true" : "false");
tmp->refine_data(SANE_STD_OPT_NAME_LATERAL, &lateral);
tmp->update_data(SANE_STD_OPT_NAME_LATERAL, &lateral);
}
}
}
tmp->release();
}
return err;
}
scanner_err hg_scanner_mgr::hg_scanner_start(scanner_handle h, void* async_event, int num)
{
return (scanner_err)SCAN_PTR(h)->start();
}
scanner_err hg_scanner_mgr::hg_scanner_stop(scanner_handle h)
{
scanner_err err = (scanner_err)SCAN_PTR(h)->stop();
// call from APP, block when all working-threads stopped - added on 2023-10-18 when handled double-feeding in SANE
//while (SCAN_PTR(h)->is_running() != hg_scanner::THREAD_RUNNING_IDLE)
// std::this_thread::sleep_for(std::chrono::milliseconds(3));
return err;
}
scanner_err hg_scanner_mgr::hg_scanner_get_img_info(scanner_handle h, SANE_Parameters* bmi, long len)
{
return (scanner_err)SCAN_PTR(h)->get_image_info(bmi);
}
scanner_err hg_scanner_mgr::hg_scanner_read_img_data(scanner_handle h, unsigned char* data, long* len)
{
if (!len)
return SCANNER_ERR_INVALID_PARAMETER;
size_t l = *len,
err = SCAN_PTR(h)->read_image_data(data, &l);
*len = l;
return (scanner_err)err;
}
scanner_err hg_scanner_mgr::hg_scanner_get_status(scanner_handle h, int setstutas)
{
return (scanner_err)SCAN_PTR(h)->status();
}
scanner_err hg_scanner_mgr::hg_scanner_reset(scanner_handle h)
{
return SCANNER_ERR_OK; // (scanner_err)SCAN_PTR(h)->reset();
}
scanner_err hg_scanner_mgr::hg_scanner_control(scanner_handle h, unsigned long code, void* data, unsigned* len)
{
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
}
void hg_scanner_mgr::on_language_changed(void)
{
std::lock_guard<std::mutex> lock(mutex_dev_);
for (auto& v: online_devices_)
{
if (v.scanner)
{
device_option* opt = v.scanner->get_device_opt();
opt->update_data(nullptr, nullptr, false);
opt->release();
}
}
}
const char* hg_scanner_mgr::last_open_message(void)
{
return hg_scanner_mgr::last_open_msg_.c_str();
}