1176 lines
38 KiB
C++
1176 lines
38 KiB
C++
|
#include "usb_manager.h"
|
|||
|
#include "hg_log.h"
|
|||
|
#include <iostream>
|
|||
|
#include <thread>
|
|||
|
#include "hgscanner_error.h"
|
|||
|
|
|||
|
using namespace std;
|
|||
|
#define IF_CLASS(code, cls) \
|
|||
|
if(code == cls) \
|
|||
|
return #cls;
|
|||
|
|
|||
|
#if defined(WIN32) || defined(_WIN64)
|
|||
|
|
|||
|
|
|||
|
#else
|
|||
|
void memset(void* buf, unsigned char fill, int len)
|
|||
|
{
|
|||
|
unsigned char* data = (unsigned char*)buf;
|
|||
|
while (len-- > 0)
|
|||
|
*data++ = fill;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
usb_manager* usb_manager::inst_ = NULL;
|
|||
|
uint8_t usb_manager::uninit_uint8 = 0x0ff;
|
|||
|
|
|||
|
usb_manager::usb_manager() : run_(true)
|
|||
|
, usb_cb_handle_(NULL)
|
|||
|
, usb_cb_(&usb_manager::usb_event_handle), usb_cb_param_(NULL)
|
|||
|
, context_(NULL), status_(0)
|
|||
|
, born_(std::chrono::system_clock::now())
|
|||
|
{
|
|||
|
int ret = libusb_init(&context_);
|
|||
|
|
|||
|
// libusb_set_log_cb(context_, &usb_manager::usb_log_callback, LIBUSB_LOG_CB_CONTEXT); // LIBUSB_API_VERSION >= 0x01000107
|
|||
|
//VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "usb_manager(%s) libusb_init(%s) = %s, context = %s\n", hg_log::format_ptr(this).c_str(), hg_log::format_ptr(&context_).c_str(), libusb_error_name(ret), hg_log::format_ptr(context_).c_str());
|
|||
|
if (ret)
|
|||
|
status_ = SCANNER_ERR_USB_INIT_FAILED;
|
|||
|
|
|||
|
wait_pnp_.set_debug_info("Waiting PNP");
|
|||
|
if (!usb_notify_thread_.get())
|
|||
|
{
|
|||
|
run_ = true;
|
|||
|
usb_notify_thread_.reset(new std::thread(&usb_manager::thread_notify_usb_event, this));
|
|||
|
}
|
|||
|
}
|
|||
|
usb_manager::~usb_manager()
|
|||
|
{
|
|||
|
run_ = false;
|
|||
|
wait_pnp_.notify();
|
|||
|
libusb_context* ctx = nullptr;
|
|||
|
#if defined(WIN32) || defined(_WIN64)
|
|||
|
ctx = context_;
|
|||
|
libusb_quit(ctx);
|
|||
|
#endif
|
|||
|
if(usb_cb_handle_)
|
|||
|
libusb_hotplug_deregister_callback(ctx, usb_cb_handle_);
|
|||
|
if (usb_monitor_thread_.get() && usb_monitor_thread_->joinable())
|
|||
|
{
|
|||
|
usb_monitor_thread_->join();
|
|||
|
usb_monitor_thread_.reset();
|
|||
|
}
|
|||
|
if (usb_notify_thread_.get() && usb_notify_thread_->joinable())
|
|||
|
{
|
|||
|
usb_notify_thread_->join();
|
|||
|
usb_notify_thread_.reset();
|
|||
|
}
|
|||
|
libusb_exit(context_);
|
|||
|
//VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "usb_manager(%s) destroying and free context(%s)\n", hg_log::format_ptr(this).c_str(), hg_log::format_ptr(context_).c_str());
|
|||
|
}
|
|||
|
|
|||
|
int LIBUSB_CALL usb_manager::usb_pnp_callback(libusb_context* ctx, libusb_device* device, libusb_hotplug_event event, void* monitor)
|
|||
|
{
|
|||
|
usb_manager* obj = (usb_manager*)monitor;
|
|||
|
|
|||
|
//if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)
|
|||
|
//libusb_ref_device(device); // keep the object until handle it
|
|||
|
//else if(event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
|
|||
|
// libusb_unref_device(device);
|
|||
|
|
|||
|
return obj->on_usb_pnp_event(ctx, device, event);
|
|||
|
}
|
|||
|
void usb_manager::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
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
void usb_manager::usb_log_callback(libusb_context* ctx, libusb_log_level level, const char* str)
|
|||
|
{
|
|||
|
// used when LIBUSB_API_VERSION >= 0x01000107
|
|||
|
//if (level == LIBUSB_LOG_LEVEL_NONE || LIBUSB_LOG_LEVEL_INFO || LIBUSB_LOG_LEVEL_DEBUG)
|
|||
|
//{
|
|||
|
// //LOG_INFO(LOG_LEVEL_DEBUG_INFO, str);
|
|||
|
//}
|
|||
|
//else
|
|||
|
//{
|
|||
|
// //LOG_INFO(LOG_LEVEL_FATAL, str);
|
|||
|
//}
|
|||
|
}
|
|||
|
|
|||
|
int usb_manager::register_usb_pnp(void)
|
|||
|
{
|
|||
|
libusb_context* ctx = nullptr;
|
|||
|
#if defined(WIN32) || defined(_WIN64)
|
|||
|
ctx = context_;
|
|||
|
#endif
|
|||
|
int ret = libusb_hotplug_register_callback(ctx, (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
|
|||
|
(libusb_hotplug_flag)LIBUSB_HOTPLUG_ENUMERATE,
|
|||
|
LIBUSB_HOTPLUG_MATCH_ANY,//LIBUSB_HOTPLUG_MATCH_ANY
|
|||
|
LIBUSB_HOTPLUG_MATCH_ANY,//LIBUSB_HOTPLUG_MATCH_ANY,
|
|||
|
LIBUSB_HOTPLUG_MATCH_ANY,
|
|||
|
&usb_manager::usb_pnp_callback,
|
|||
|
this,
|
|||
|
&usb_cb_handle_);
|
|||
|
|
|||
|
if (ret != LIBUSB_SUCCESS)
|
|||
|
{
|
|||
|
//LOG_INFO(LOG_LEVEL_FATAL, (std::string("regist usbhotplug callback error msg: ") + libusb_error_name(ret) + "\n").c_str());
|
|||
|
usb_cb_handle_ = NULL;
|
|||
|
status_ = SCANNER_ERR_USB_REGISTER_PNP_FAILED;
|
|||
|
}
|
|||
|
else
|
|||
|
status_ = SCANNER_ERR_OK;
|
|||
|
|
|||
|
return ret;
|
|||
|
}
|
|||
|
void usb_manager::init_notify_thread()
|
|||
|
{
|
|||
|
if(!usb_monitor_thread_.get())
|
|||
|
{
|
|||
|
usb_monitor_thread_.reset(new std::thread(&usb_manager::thread_trigger_usb_event, this));
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
void usb_manager::fake_usb_pnp(std::vector<libusb_device*>& devices)
|
|||
|
{
|
|||
|
libusb_device** devs = NULL;
|
|||
|
libusb_get_device_list(context_, &devs);
|
|||
|
if (devs)
|
|||
|
{
|
|||
|
std::vector<libusb_device*> current;
|
|||
|
|
|||
|
// handle arrived ...
|
|||
|
for (int ind = 0; devs[ind]; ++ind)
|
|||
|
{
|
|||
|
std::vector<libusb_device*>::iterator it
|
|||
|
= std::find(devices.begin(), devices.end(), devs[ind]);
|
|||
|
if (it == devices.end())
|
|||
|
{
|
|||
|
current.push_back(devs[ind]);
|
|||
|
on_usb_pnp_event(context_, devs[ind], LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// handle left ...
|
|||
|
for (int ind = 0; ind < devices.size(); ++ind)
|
|||
|
{
|
|||
|
std::vector<libusb_device*>::iterator it
|
|||
|
= std::find(current.begin(), current.end(), devices[ind]);
|
|||
|
if (it == current.end())
|
|||
|
{
|
|||
|
on_usb_pnp_event(context_, devices[ind], LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT);
|
|||
|
}
|
|||
|
}
|
|||
|
devices = current;
|
|||
|
libusb_free_device_list(devs, 0);
|
|||
|
}
|
|||
|
}
|
|||
|
void usb_manager::thread_notify_usb_event()
|
|||
|
{
|
|||
|
while (run_)
|
|||
|
{
|
|||
|
if (!wait_pnp_.wait())
|
|||
|
continue;
|
|||
|
|
|||
|
if (!run_)
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
int delay = 50; // milliseconds ...
|
|||
|
while (pnp_events_.Size() && run_)
|
|||
|
{
|
|||
|
PNPDEV pd = pnp_events_.Take();
|
|||
|
bool retry = false;
|
|||
|
|
|||
|
if (pd.event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)
|
|||
|
{
|
|||
|
unsigned ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - pd.happen_time).count();
|
|||
|
if (ms < delay)
|
|||
|
{
|
|||
|
this_thread::sleep_for(chrono::milliseconds(delay));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
libusb_ref_device(pd.dev);
|
|||
|
notify_usb_event(pd, &retry);
|
|||
|
if (retry)
|
|||
|
{
|
|||
|
if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - pd.happen_time).count()
|
|||
|
<= 5000)
|
|||
|
pnp_events_.Put(pd, sizeof(pd));
|
|||
|
else
|
|||
|
retry = false;
|
|||
|
if(pnp_events_.Size() == 1)
|
|||
|
this_thread::sleep_for(chrono::milliseconds(1000));
|
|||
|
else
|
|||
|
this_thread::sleep_for(chrono::milliseconds(delay));
|
|||
|
}
|
|||
|
if (!retry)
|
|||
|
libusb_unref_device(pd.dev);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
void usb_manager::notify_usb_event(PNPDEV& pd, bool* retry)
|
|||
|
{
|
|||
|
usb_event ev = USB_EVENT_NULL;
|
|||
|
usb_dev ud;
|
|||
|
bool re_try = false;
|
|||
|
|
|||
|
std::string evstr("");
|
|||
|
usb_manager::get_device_info(pd.dev, &ud);
|
|||
|
ud.contex = pd.ctx;
|
|||
|
if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == pd.event)
|
|||
|
{
|
|||
|
ev = USB_EVENT_DEVICE_ARRIVED;
|
|||
|
evstr = "USB_EVENT_DEVICE_ARRIVED";
|
|||
|
|
|||
|
}
|
|||
|
else if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == pd.event)
|
|||
|
{
|
|||
|
ev = USB_EVENT_DEVICE_LEFT;
|
|||
|
evstr = "USB_EVENT_DEVICE_LEFT";
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
char buf[20];
|
|||
|
sprintf(buf, "0x%x", pd.event);
|
|||
|
evstr = buf;
|
|||
|
}
|
|||
|
//VLOG_MINI_5(LOG_LEVEL_DEBUG_INFO, "USB%u.%x of pid:vid(%x:%x) event(%s) received.\n"
|
|||
|
// , HIBYTE(ud.ver), LOBYTE(ud.ver) / 0x10, ud.pid, ud.vid, evstr.c_str());
|
|||
|
if (ev != USB_EVENT_NULL)
|
|||
|
{
|
|||
|
if (!retry)
|
|||
|
retry = &re_try;
|
|||
|
usb_cb_(ev, pd.dev, ud.vid, ud.pid, HIBYTE(ud.ver), LOBYTE(ud.ver) / 0x10, retry, usb_cb_param_);
|
|||
|
}
|
|||
|
libusb_unref_device(pd.dev); // response for libusb_ref_device in usb_manager::usb_pnp_callback
|
|||
|
}
|
|||
|
void usb_manager::thread_trigger_usb_event()
|
|||
|
{
|
|||
|
if (!usb_cb_handle_)
|
|||
|
{
|
|||
|
// we try manually find device here
|
|||
|
int times = 10, elapse_max = 60 * 2, elapse = elapse_max;
|
|||
|
std::vector<libusb_device*> devices;
|
|||
|
|
|||
|
while (run_)
|
|||
|
{
|
|||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
|||
|
|
|||
|
// simulate PNP events ...
|
|||
|
fake_usb_pnp(devices);
|
|||
|
|
|||
|
// retry register pnp ...
|
|||
|
if (--elapse == 0 && --times > 0)
|
|||
|
{
|
|||
|
elapse_max *= 2;
|
|||
|
elapse = elapse_max;
|
|||
|
if (register_usb_pnp() == LIBUSB_SUCCESS)
|
|||
|
{
|
|||
|
// ^_^
|
|||
|
devices.clear();
|
|||
|
//LOG_INFO(LOG_LEVEL_DEBUG_INFO, "register_usb_pnp success ^_^\n");
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
while(run_)
|
|||
|
{
|
|||
|
timeval tm={1,0};
|
|||
|
int ret=libusb_handle_events_timeout(context_, &tm);
|
|||
|
//if(ret < 0)
|
|||
|
// LOG_INFO(LOG_LEVEL_FATAL, (std::string("libusb_handle_events_timeout error ") + libusb_error_name(ret) + "\n").c_str());
|
|||
|
|
|||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|||
|
}
|
|||
|
}
|
|||
|
int usb_manager::on_usb_pnp_event(libusb_context *ctx, libusb_device *device, libusb_hotplug_event event)
|
|||
|
{
|
|||
|
PNPDEV pd;
|
|||
|
unsigned ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - born_).count();
|
|||
|
|
|||
|
libusb_ref_device(device);
|
|||
|
pd.ctx = ctx;
|
|||
|
pd.dev = device;
|
|||
|
pd.event = event;
|
|||
|
pd.happen_time = std::chrono::system_clock::now();
|
|||
|
if (ms > 1000)
|
|||
|
{
|
|||
|
pnp_events_.Put(pd, sizeof(pd));
|
|||
|
wait_pnp_.notify();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
bool retry = false;
|
|||
|
libusb_ref_device(device);
|
|||
|
notify_usb_event(pd, &retry);
|
|||
|
if(retry)
|
|||
|
pnp_events_.Put(pd, sizeof(pd));
|
|||
|
else
|
|||
|
libusb_unref_device(device);
|
|||
|
}
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
usb_manager* usb_manager::instance(void)
|
|||
|
{
|
|||
|
if (usb_manager::inst_ == NULL)
|
|||
|
usb_manager::inst_ = new usb_manager();
|
|||
|
|
|||
|
return usb_manager::inst_;
|
|||
|
}
|
|||
|
void usb_manager::clear(void)
|
|||
|
{
|
|||
|
if (usb_manager::inst_)
|
|||
|
{
|
|||
|
delete usb_manager::inst_;
|
|||
|
usb_manager::inst_ = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
int usb_manager::usb_error_2_hg_err(int usb_err)
|
|||
|
{
|
|||
|
if (usb_err == LIBUSB_ERROR_TIMEOUT)
|
|||
|
return SCANNER_ERR_TIMEOUT;
|
|||
|
else if (usb_err == LIBUSB_ERROR_PIPE)
|
|||
|
return SCANNER_ERR_IO;
|
|||
|
else if (usb_err == LIBUSB_ERROR_NO_DEVICE)
|
|||
|
return SCANNER_ERR_DEVICE_NOT_FOUND;
|
|||
|
else if (usb_err == LIBUSB_ERROR_BUSY)
|
|||
|
return SCANNER_ERR_DEVICE_BUSY;
|
|||
|
else if (usb_err == LIBUSB_ERROR_INVALID_PARAM)
|
|||
|
return SCANNER_ERR_INVALID_PARAMETER;
|
|||
|
else if (usb_err == LIBUSB_ERROR_OVERFLOW)
|
|||
|
return SCANNER_ERR_OUT_OF_RANGE;
|
|||
|
else if (usb_err == LIBUSB_ERROR_NO_MEM)
|
|||
|
return SCANNER_ERR_INSUFFICIENT_MEMORY;
|
|||
|
else if (usb_err == LIBUSB_ERROR_ACCESS)
|
|||
|
return SCANNER_ERR_ACCESS_DENIED;
|
|||
|
else if (usb_err < 0)
|
|||
|
return (scanner_err)usb_err;
|
|||
|
else
|
|||
|
return SCANNER_ERR_OK;
|
|||
|
|
|||
|
}
|
|||
|
void usb_manager::init_endpoint(USBENDP* uep)
|
|||
|
{
|
|||
|
uep->in.port = uep->out.port = usb_manager::uninit_uint8;
|
|||
|
uep->in.iface = uep->out.iface = usb_manager::uninit_uint8;
|
|||
|
uep->in.iconf = uep->out.iconf = usb_manager::uninit_uint8;
|
|||
|
uep->in.claimed = uep->out.claimed = 0;
|
|||
|
uep->in.max_packet = uep->out.max_packet = 0;
|
|||
|
}
|
|||
|
std::string usb_manager::device_class(libusb_class_code code)
|
|||
|
{
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_PER_INTERFACE);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_AUDIO);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_COMM);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_HID);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_PHYSICAL);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_IMAGE);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_PRINTER);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_MASS_STORAGE);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_HUB);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_DATA);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_SMART_CARD);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_CONTENT_SECURITY);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_VIDEO);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_PERSONAL_HEALTHCARE);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_DIAGNOSTIC_DEVICE);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_WIRELESS);
|
|||
|
//IF_CLASS(code, LIBUSB_CLASS_MISCELLANEOUS);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_APPLICATION);
|
|||
|
IF_CLASS(code, LIBUSB_CLASS_VENDOR_SPEC);
|
|||
|
|
|||
|
char buf[40];
|
|||
|
|
|||
|
sprintf(buf, "unknown class: %d", code);
|
|||
|
|
|||
|
return buf;
|
|||
|
}
|
|||
|
std::string usb_manager::endpoint_type(libusb_transfer_type type)
|
|||
|
{
|
|||
|
IF_CLASS(type, LIBUSB_TRANSFER_TYPE_CONTROL);
|
|||
|
IF_CLASS(type, LIBUSB_TRANSFER_TYPE_ISOCHRONOUS);
|
|||
|
IF_CLASS(type, LIBUSB_TRANSFER_TYPE_BULK);
|
|||
|
IF_CLASS(type, LIBUSB_TRANSFER_TYPE_INTERRUPT);
|
|||
|
IF_CLASS(type, LIBUSB_TRANSFER_TYPE_BULK_STREAM);
|
|||
|
|
|||
|
char buf[40];
|
|||
|
|
|||
|
sprintf(buf, "unknown type: %d", type);
|
|||
|
|
|||
|
return buf;
|
|||
|
}
|
|||
|
bool usb_manager::get_device_info(libusb_device* device, usb_dev* devinfo)
|
|||
|
{
|
|||
|
libusb_device_descriptor descriptor;
|
|||
|
int ret = libusb_get_device_descriptor(device, &descriptor);
|
|||
|
|
|||
|
if (ret != LIBUSB_SUCCESS)
|
|||
|
return false;
|
|||
|
|
|||
|
devinfo->device = device;
|
|||
|
devinfo->ver = descriptor.bcdUSB;
|
|||
|
devinfo->vid = descriptor.idVendor;
|
|||
|
devinfo->pid = descriptor.idProduct;
|
|||
|
devinfo->addr = 0; // libusb_get_device_address(device); - initialize at open
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
void usb_manager::enum_endpoints(libusb_device* device, USBTRANSENDP* endp)
|
|||
|
{
|
|||
|
libusb_device_descriptor desc;
|
|||
|
libusb_config_descriptor *conf = NULL;
|
|||
|
std::string dev(hg_log::format_ptr(device));
|
|||
|
int ret = libusb_get_device_descriptor(device, &desc);
|
|||
|
bool found_ep = false;
|
|||
|
|
|||
|
if (ret != 0)
|
|||
|
{
|
|||
|
//LOG_INFO(LOG_LEVEL_WARNING, (std::string("Get device descriptor of device(") + dev + ") failed.\n").c_str());
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (endp)
|
|||
|
{
|
|||
|
usb_manager::init_endpoint(&endp->bulk);
|
|||
|
usb_manager::init_endpoint(&endp->bulk_stream);
|
|||
|
usb_manager::init_endpoint(&endp->control);
|
|||
|
usb_manager::init_endpoint(&endp->interrupt);
|
|||
|
usb_manager::init_endpoint(&endp->isochronous);
|
|||
|
}
|
|||
|
//else
|
|||
|
//VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " +Device(%s) has %u configurations ...\n", dev.c_str(), desc.bNumConfigurations);
|
|||
|
for (int i = 0; i < (int)desc.bNumConfigurations; ++i)
|
|||
|
{
|
|||
|
ret = libusb_get_config_descriptor(device, i, &conf);
|
|||
|
if (ret != 0)
|
|||
|
{
|
|||
|
//if (!endp)
|
|||
|
// VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, " Get %d configuration failed.\n", i + 1);
|
|||
|
continue;
|
|||
|
}
|
|||
|
//if (!endp)
|
|||
|
//VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " Configuration %d has %d interfaces\n", i + 1, conf->bNumInterfaces);
|
|||
|
for (int j = 0; j < conf->bNumInterfaces; ++j)
|
|||
|
{
|
|||
|
//if (!endp)
|
|||
|
//VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " Interface %d has %d alt-settings\n", j + 1, conf->interface[j].num_altsetting);
|
|||
|
for (int k = 0; k < conf->interface[j].num_altsetting; ++k)
|
|||
|
{
|
|||
|
//if (!endp)
|
|||
|
// VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, " Setting %d: %d - %s has %d endpoints\n", k + 1, conf->interface[j].altsetting[k].bInterfaceNumber
|
|||
|
// , usb_manager::device_class((libusb_class_code)conf->interface[j].altsetting[k].bInterfaceClass).c_str()
|
|||
|
// , conf->interface[j].altsetting[k].bNumEndpoints);
|
|||
|
for (int l = 0; l < conf->interface[j].altsetting[k].bNumEndpoints; ++l)
|
|||
|
{
|
|||
|
if (endp)
|
|||
|
{
|
|||
|
USBENDP* ep = NULL;
|
|||
|
|
|||
|
if (conf->interface[j].altsetting[k].endpoint[l].bmAttributes == LIBUSB_TRANSFER_TYPE_CONTROL)
|
|||
|
{
|
|||
|
//VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Found endpoint(%x) for device(VID: %x, PID: %x) of control\n", conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress, desc.idVendor, desc.idProduct);
|
|||
|
ep = &endp->control;
|
|||
|
}
|
|||
|
else if (conf->interface[j].altsetting[k].endpoint[l].bmAttributes == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS)
|
|||
|
{
|
|||
|
//VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Found endpoint(%x) for device(VID: %x, PID: %x) of isochronous\n", conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress, desc.idVendor, desc.idProduct);
|
|||
|
ep = &endp->isochronous;
|
|||
|
}
|
|||
|
if (conf->interface[j].altsetting[k].endpoint[l].bmAttributes == LIBUSB_TRANSFER_TYPE_BULK)
|
|||
|
{
|
|||
|
//VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Found endpoint(%x) for device(VID: %x, PID: %x) of bulk\n", conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress, desc.idVendor, desc.idProduct);
|
|||
|
ep = &endp->bulk;
|
|||
|
}
|
|||
|
if (conf->interface[j].altsetting[k].endpoint[l].bmAttributes == LIBUSB_TRANSFER_TYPE_INTERRUPT)
|
|||
|
{
|
|||
|
//VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Found endpoint(%x) for device(VID: %x, PID: %x) of interrupt\n", conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress, desc.idVendor, desc.idProduct);
|
|||
|
ep = &endp->interrupt;
|
|||
|
}
|
|||
|
if (conf->interface[j].altsetting[k].endpoint[l].bmAttributes == LIBUSB_TRANSFER_TYPE_BULK_STREAM)
|
|||
|
{
|
|||
|
//VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Found endpoint(%x) for device(VID: %x, PID: %x) of bulk-stream\n", conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress, desc.idVendor, desc.idProduct);
|
|||
|
ep = &endp->bulk_stream;
|
|||
|
}
|
|||
|
if (ep)
|
|||
|
{
|
|||
|
USBSIMPLEX* s = NULL;
|
|||
|
if (conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress & LIBUSB_ENDPOINT_IN)
|
|||
|
s = &ep->in;// = (conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress & 3) | LIBUSB_ENDPOINT_IN;
|
|||
|
else
|
|||
|
s = &ep->out; // = (conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress & 3) | LIBUSB_ENDPOINT_OUT;
|
|||
|
|
|||
|
// NOTE: 这里应该尽量将输入输出端口统一到同一个接口上来,目前未做,只取第一<E7ACAC>?
|
|||
|
if (s->port == usb_manager::uninit_uint8)
|
|||
|
{
|
|||
|
s->port = conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress & (LIBUSB_ENDPOINT_IN | LIBUSB_ENDPOINT_OUT | 3);
|
|||
|
s->iconf = conf->bConfigurationValue;
|
|||
|
s->iface = j;
|
|||
|
s->claimed = 0;
|
|||
|
s->max_packet = conf->interface[j].altsetting[k].endpoint[l].wMaxPacketSize;
|
|||
|
//VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, " Endpoint address = 0x%02x, origin = 0x%02x, max packet: 0x%x\n", s->port, conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress
|
|||
|
// , s->max_packet);
|
|||
|
}
|
|||
|
found_ep = true;
|
|||
|
}
|
|||
|
}
|
|||
|
//else
|
|||
|
//VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, " Endpoint %d(%s) address: %x, Max packet: 0x%x bytes\n", l + 1
|
|||
|
// , usb_manager::endpoint_type((libusb_transfer_type)conf->interface[j].altsetting[k].endpoint[l].bmAttributes).c_str()
|
|||
|
// , conf->interface[j].altsetting[k].endpoint[l].bEndpointAddress
|
|||
|
// , conf->interface[j].altsetting[k].endpoint[l].wMaxPacketSize);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
libusb_free_config_descriptor(conf);
|
|||
|
}
|
|||
|
|
|||
|
//if (endp && !found_ep)
|
|||
|
//VLOG_MINI_2(LOG_LEVEL_FATAL, "No endpoint has been found on device (VID: %x, PID: %x)\n", desc.idVendor, desc.idProduct);
|
|||
|
}
|
|||
|
|
|||
|
int usb_manager::register_hotplug(usb_event_handler cb, void* user)
|
|||
|
{
|
|||
|
if (cb)
|
|||
|
usb_cb_ = cb;
|
|||
|
else
|
|||
|
usb_cb_ = &usb_manager::usb_event_handle;
|
|||
|
usb_cb_param_ = user;
|
|||
|
|
|||
|
int ret = register_usb_pnp();
|
|||
|
if (ret != LIBUSB_SUCCESS)
|
|||
|
{
|
|||
|
// then we find devices manually, and need not return failure here
|
|||
|
}
|
|||
|
init_notify_thread();
|
|||
|
|
|||
|
return SCANNER_ERR_OK;
|
|||
|
}
|
|||
|
int usb_manager::open(libusb_device* device, usb_io** usbio, std::string* msg)
|
|||
|
{
|
|||
|
if (!usbio)
|
|||
|
return SCANNER_ERR_INVALID_PARAMETER;
|
|||
|
|
|||
|
usb_dev dev;
|
|||
|
usb_io* usb = NULL;
|
|||
|
if (!get_device_info(device, &dev))
|
|||
|
return SCANNER_ERR_DEVICE_NOT_FOUND;
|
|||
|
|
|||
|
dev.contex = context_;
|
|||
|
usb = new usb_io(dev);
|
|||
|
if (!usb->is_ready())
|
|||
|
{
|
|||
|
int err = usb->last_error();
|
|||
|
|
|||
|
if (msg)
|
|||
|
*msg = usb->init_error_msg();
|
|||
|
usb->release();
|
|||
|
//VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Open %04x:%04x failed: %s\n", dev.vid, dev.pid, hg_scanner_err_name(err));
|
|||
|
|
|||
|
return err;
|
|||
|
}
|
|||
|
|
|||
|
*usbio = dynamic_cast<usb_io*>(usb);
|
|||
|
|
|||
|
return SCANNER_ERR_OK;
|
|||
|
}
|
|||
|
int usb_manager::last_status(void)
|
|||
|
{
|
|||
|
return status_;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|||
|
// usb_io
|
|||
|
//#define USE_OLD_USB
|
|||
|
|
|||
|
#ifdef USE_OLD_USB
|
|||
|
#include "libusbex.h"
|
|||
|
std::shared_ptr<IUsb> usb_;
|
|||
|
#endif
|
|||
|
|
|||
|
usb_io::usb_io(const usb_dev& dev) : ref_(1), handle_(NULL), dev_info_(dev), to_(1000), last_err_(SCANNER_ERR_NOT_START), ref_device_(nullptr)
|
|||
|
, singleton_(nullptr)
|
|||
|
{
|
|||
|
#ifdef USE_OLD_USB
|
|||
|
std::list<std::shared_ptr<IUsb>> all = Libusb_List::find_vid_pid(0x3072, 0x239);
|
|||
|
if (all.size())
|
|||
|
{
|
|||
|
usb_ = *all.begin();
|
|||
|
usb_->open();
|
|||
|
handle_ = (libusb_device_handle*)1;
|
|||
|
}
|
|||
|
#else
|
|||
|
|
|||
|
clear_endpoints();
|
|||
|
open();
|
|||
|
#endif
|
|||
|
}
|
|||
|
usb_io::~usb_io()
|
|||
|
{
|
|||
|
close();
|
|||
|
}
|
|||
|
|
|||
|
bool usb_io::make_singleton(void)
|
|||
|
{
|
|||
|
unsigned long long key = dev_info_.vid;
|
|||
|
key <<= 16;
|
|||
|
key |= dev_info_.pid;
|
|||
|
key <<= 16;
|
|||
|
if (dev_info_.addr == 0)
|
|||
|
dev_info_.addr = libusb_get_device_address(dev_info_.device);
|
|||
|
key |= dev_info_.addr;
|
|||
|
if (singleton_)
|
|||
|
singleton_->release();
|
|||
|
|
|||
|
singleton_ = new shared_memory(key);
|
|||
|
if (singleton_->is_first())
|
|||
|
{
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
std::string str(singleton_->read());
|
|||
|
|
|||
|
singleton_->release();
|
|||
|
singleton_ = nullptr;
|
|||
|
last_err_ = SCANNER_ERR_OPENED_BY_OTHER_PROCESS;
|
|||
|
|
|||
|
//std::string tips(from_default_language("\350\256\276\345\244\207\345\267\262\347\273\217\350\242\253\350\277\233\347\250\213 '%s' \345\215\240\347\224\250"));
|
|||
|
//size_t pos = tips.find("%s");
|
|||
|
|
|||
|
// if (pos != std::string::npos)
|
|||
|
// tips.replace(pos, 2, str);
|
|||
|
//str = std::move(tips);
|
|||
|
//init_err_msg_ = str;
|
|||
|
//VLOG_MINI_1(LOG_LEVEL_FATAL, "Open failed: %s\n", str.c_str());
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
void usb_io::clear_endpoints(void)
|
|||
|
{
|
|||
|
usb_manager::init_endpoint(&endpoints_.bulk);
|
|||
|
usb_manager::init_endpoint(&endpoints_.bulk_stream);
|
|||
|
usb_manager::init_endpoint(&endpoints_.control);
|
|||
|
usb_manager::init_endpoint(&endpoints_.interrupt);
|
|||
|
usb_manager::init_endpoint(&endpoints_.isochronous);
|
|||
|
}
|
|||
|
bool usb_io::claim_interterface(usb_manager::USBSIMPLEX* spl)
|
|||
|
{
|
|||
|
int ret = libusb_claim_interface(handle_, spl->iface);
|
|||
|
if (ret == LIBUSB_SUCCESS)
|
|||
|
{
|
|||
|
spl->claimed = true;
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
//VLOG_MINI_2(LOG_LEVEL_FATAL, "libusb_claim_interface(%d) = %s, now try some actions ...\n", spl->iface, libusb_error_name(ret));
|
|||
|
|
|||
|
ret = libusb_kernel_driver_active(handle_, spl->iface);
|
|||
|
if (ret == 1)
|
|||
|
{
|
|||
|
ret = libusb_detach_kernel_driver(handle_, spl->iface);
|
|||
|
|
|||
|
//VLOG_MINI_2(LOG_LEVEL_FATAL, " libusb_detach_kernel_driver(%d) = %s\n", spl->iface, libusb_error_name(ret));
|
|||
|
}
|
|||
|
else if (ret == LIBUSB_ERROR_NO_DEVICE)
|
|||
|
{
|
|||
|
//last_err_ = SCANNER_ERR_DEVICE_NOT_FOUND;
|
|||
|
//VLOG_MINI_1(LOG_LEVEL_FATAL, " device(%s) maybe left when libusb_kernel_driver_active.\n", hg_log::format_ptr(dev_info_.device).c_str());
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
//else
|
|||
|
//{
|
|||
|
// VLOG_MINI_2(LOG_LEVEL_FATAL, " libusb_kernel_driver_active(%d) = %d\n", spl->iface, ret);
|
|||
|
// }
|
|||
|
ret = libusb_clear_halt(handle_, spl->port);
|
|||
|
//VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " libusb_clear_halt(%x) = %s\n", spl->port, libusb_error_name(ret));
|
|||
|
ret = libusb_release_interface(handle_, spl->iface);
|
|||
|
//VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " libusb_release_interface(%u) = %s\n", spl->iface, libusb_error_name(ret));
|
|||
|
ret = libusb_set_configuration(handle_, spl->iconf);
|
|||
|
//VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " libusb_set_configuration(%u) = %s\n", spl->iconf, libusb_error_name(ret));
|
|||
|
//ret = libusb_reset_device(handle_);
|
|||
|
//VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, " libusb_reset_device = %s\n", libusb_error_name(ret));
|
|||
|
//if (ret == LIBUSB_ERROR_NOT_FOUND)
|
|||
|
//{
|
|||
|
// last_err_ = usb_manager::usb_error_2_hg_err(ret);
|
|||
|
// VLOG_MINI_1(LOG_LEVEL_FATAL, "device(%s) maybe left when libusb_reset_device.\n", hg_log::format_ptr(dev_info_.device).c_str());
|
|||
|
//
|
|||
|
// return false;
|
|||
|
//}
|
|||
|
|
|||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|||
|
ret = libusb_claim_interface(handle_, spl->iface);
|
|||
|
if (ret == LIBUSB_SUCCESS)
|
|||
|
{
|
|||
|
spl->claimed = true;
|
|||
|
//VLOG_MINI_2(LOG_LEVEL_FATAL, "second libusb_claim_interface(%d) = %s\n", spl->iface, libusb_error_name(ret));
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
//VLOG_MINI_2(LOG_LEVEL_FATAL, "second try libusb_claim_interface(%d) = %s\n", spl->iface, libusb_error_name(ret));
|
|||
|
// last_err_ = SCANNER_ERR_USB_CLAIM_INTERFACE_FAILED;
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
int usb_io::claim_interfaces(bool claim)
|
|||
|
{
|
|||
|
usb_manager::USBENDP* eps[] = { &endpoints_.control, &endpoints_.isochronous, &endpoints_.bulk, &endpoints_.interrupt, &endpoints_.bulk_stream };
|
|||
|
std::vector<uint8_t> claimed;
|
|||
|
|
|||
|
if (claim)
|
|||
|
{
|
|||
|
for (size_t i = 0; i < _countof(eps); ++i)
|
|||
|
{
|
|||
|
if (eps[i]->in.port != usb_manager::uninit_uint8
|
|||
|
&& std::find(claimed.begin(), claimed.end(), eps[i]->in.iface) == claimed.end())
|
|||
|
{
|
|||
|
if (!claim_interterface(&eps[i]->in))
|
|||
|
break;
|
|||
|
|
|||
|
claimed.push_back(eps[i]->in.iface);
|
|||
|
//VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "claimed %s interface %d\n", usb_manager::endpoint_type((libusb_transfer_type)i).c_str(), eps[i]->in.iface);
|
|||
|
}
|
|||
|
if (eps[i]->out.port != usb_manager::uninit_uint8 && eps[i]->out.iface != eps[i]->in.iface
|
|||
|
&& std::find(claimed.begin(), claimed.end(), eps[i]->out.iface) == claimed.end())
|
|||
|
{
|
|||
|
if (!claim_interterface(&eps[i]->out))
|
|||
|
break;
|
|||
|
claimed.push_back(eps[i]->out.iface);
|
|||
|
//VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "claimed %s interface %d\n", usb_manager::endpoint_type((libusb_transfer_type)i).c_str(), eps[i]->out.iface);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
for (size_t i = 0; i < _countof(eps); ++i)
|
|||
|
{
|
|||
|
if (eps[i]->in.claimed)
|
|||
|
libusb_release_interface(handle_, eps[i]->in.iface);
|
|||
|
if (eps[i]->out.claimed)
|
|||
|
libusb_release_interface(handle_, eps[i]->out.iface);
|
|||
|
}
|
|||
|
last_err_ = 0;
|
|||
|
}
|
|||
|
|
|||
|
return last_err_;
|
|||
|
}
|
|||
|
void usb_io::init_after_open(void)
|
|||
|
{
|
|||
|
last_err_ = 0;
|
|||
|
libusb_set_auto_detach_kernel_driver(handle_, 1);
|
|||
|
usb_manager::enum_endpoints(dev_info_.device, &endpoints_);
|
|||
|
if (claim_interfaces(true) != 0)
|
|||
|
{
|
|||
|
int err = last_err_;
|
|||
|
|
|||
|
close();
|
|||
|
last_err_ = err;
|
|||
|
}
|
|||
|
}
|
|||
|
void usb_io::open(void)
|
|||
|
{
|
|||
|
if (!make_singleton())
|
|||
|
return;
|
|||
|
|
|||
|
if (ref_device_)
|
|||
|
libusb_unref_device(ref_device_);
|
|||
|
ref_device_ = libusb_ref_device(dev_info_.device);
|
|||
|
|
|||
|
int ret = libusb_open(dev_info_.device, &handle_);
|
|||
|
//VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "call libusb_open(%s, %s) = %s\n", hg_log::format_ptr(dev_info_.device).c_str()
|
|||
|
// , hg_log::format_ptr(handle_).c_str(), libusb_error_name(ret));
|
|||
|
if (ret == LIBUSB_SUCCESS)
|
|||
|
{
|
|||
|
init_after_open();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
handle_ = libusb_open_device_with_vid_pid(dev_info_.contex, dev_info_.vid, dev_info_.pid);
|
|||
|
if (handle_)
|
|||
|
{
|
|||
|
init_after_open();
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
last_err_ = usb_manager::usb_error_2_hg_err(ret);
|
|||
|
//VLOG_MINI_4(LOG_LEVEL_FATAL, "Open USB%u.%u-%s failed: %s\n", HIBYTE(dev_info_.ver), LOBYTE(dev_info_.ver) / 0x10, hg_log::format_ptr(dev_info_.device).c_str(), libusb_error_name(ret));
|
|||
|
//init_err_msg_ = hg_scanner_err_description(last_err_);
|
|||
|
handle_ = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
//bool usb_io::on_io_error(scanner_err err, usb_manager::USBSIMPLEX* endp)
|
|||
|
//{
|
|||
|
// //if (err == SCANNER_ERR_OK)
|
|||
|
// return true;
|
|||
|
//
|
|||
|
// //if (err == SCANNER_ERR_TIMEOUT)
|
|||
|
// //{
|
|||
|
// //因为在发送img参数出现timeout,暂时禁<E697B6>?
|
|||
|
// // //LOG_INFO(LOG_LEVEL_DEBUG_INFO, "Operation timeout\n");
|
|||
|
// // libusb_clear_halt(handle_, endp->port);
|
|||
|
//
|
|||
|
// // return libusb_reset_device(handle_) == LIBUSB_SUCCESS;
|
|||
|
//
|
|||
|
// //return true;
|
|||
|
// //}
|
|||
|
//
|
|||
|
// return true;
|
|||
|
//}
|
|||
|
|
|||
|
int usb_io::add_ref(void)
|
|||
|
{
|
|||
|
return ++ref_; // InterlockedIncreament in linux ?
|
|||
|
}
|
|||
|
int usb_io::release(void)
|
|||
|
{
|
|||
|
int ref = --ref_; // InterlockedDecreament in linux ?
|
|||
|
|
|||
|
if (ref == 0)
|
|||
|
delete this;
|
|||
|
|
|||
|
return ref;
|
|||
|
}
|
|||
|
|
|||
|
int usb_io::control_io(uint8_t type, uint8_t req, uint16_t val, uint16_t ind, void* buf, int* len)
|
|||
|
{
|
|||
|
#ifdef USE_OLD_USB
|
|||
|
return usb_->control_msg(type, req, val, ind, *len, buf);
|
|||
|
#endif
|
|||
|
|
|||
|
if (!handle_)
|
|||
|
return last_err_;
|
|||
|
|
|||
|
//if (endpoints_.control.in == usb_manager::uninit_uint8)
|
|||
|
// return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|||
|
|
|||
|
if (!len)
|
|||
|
return SCANNER_ERR_INVALID_PARAMETER;
|
|||
|
|
|||
|
int ret = libusb_control_transfer(handle_, type, req, val, ind, (unsigned char*)buf, *len, to_);
|
|||
|
|
|||
|
if (ret > 0)
|
|||
|
{
|
|||
|
*len = ret;
|
|||
|
|
|||
|
last_err_ = SCANNER_ERR_OK;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//if (on_io_error((scanner_err)usb_manager::usb_error_2_hg_err(ret), &endpoints_.control.in))
|
|||
|
//{
|
|||
|
// ret = libusb_control_transfer(handle_, type, req, val, ind, (unsigned char*)buf, *len, to_);
|
|||
|
// if (ret > 0)
|
|||
|
// {
|
|||
|
// *len = ret;
|
|||
|
|
|||
|
// last_err_ = SCANNER_ERR_OK;
|
|||
|
|
|||
|
// return last_err_;
|
|||
|
// }
|
|||
|
// else
|
|||
|
// *len = 0;
|
|||
|
//}
|
|||
|
//else
|
|||
|
*len = 0;
|
|||
|
//VLOG_MINI_5(LOG_LEVEL_DEBUG_INFO, "libusb_control_transfer(%x, %x, %d, %d) = %s\n", type, req, val, ind, libusb_error_name(ret));
|
|||
|
last_err_ = usb_manager::usb_error_2_hg_err(ret);
|
|||
|
}
|
|||
|
|
|||
|
return last_err_;
|
|||
|
}
|
|||
|
int usb_io::read_bulk(void* buf, int* len)
|
|||
|
{
|
|||
|
#ifdef USE_OLD_USB
|
|||
|
*len = usb_->read_bulk(buf, *len);
|
|||
|
return SCANNER_ERR_OK;
|
|||
|
#endif
|
|||
|
if (!handle_)
|
|||
|
return last_err_;
|
|||
|
|
|||
|
if(endpoints_.bulk.in.port == usb_manager::uninit_uint8)
|
|||
|
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|||
|
|
|||
|
if (!len)
|
|||
|
return SCANNER_ERR_INVALID_PARAMETER;
|
|||
|
|
|||
|
//if (*len < endpoints_.bulk.in.max_packet) // avoid transferring overflows ...
|
|||
|
//{
|
|||
|
// *len = endpoints_.bulk.in.max_packet;
|
|||
|
//
|
|||
|
// return SCANNER_ERR_INSUFFICIENT_MEMORY;
|
|||
|
//}
|
|||
|
// libusb_clear_halt(handle_,endpoints_.bulk.in.port);
|
|||
|
int total = 0,
|
|||
|
err = libusb_bulk_transfer(handle_, endpoints_.bulk.in.port, (unsigned char*)buf, *len, &total, to_);
|
|||
|
|
|||
|
if (err)
|
|||
|
{
|
|||
|
//VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "read_bulk(%x, %d/%d) = %s\n", endpoints_.bulk.in.port, total, *len, libusb_error_name(err));
|
|||
|
if (err == LIBUSB_ERROR_TIMEOUT && *len == total)
|
|||
|
{
|
|||
|
int old = to_;
|
|||
|
if(to_ < 10 * 1000)
|
|||
|
to_ *= 1.5f;
|
|||
|
//err = LIBUSB_SUCCESS;
|
|||
|
// VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, " Read full length, we consider it as success, and increament timeout from %d to %d\n", old, to_);
|
|||
|
}
|
|||
|
}
|
|||
|
*len = total;
|
|||
|
last_err_ = usb_manager::usb_error_2_hg_err(err);
|
|||
|
|
|||
|
return last_err_;
|
|||
|
}
|
|||
|
int usb_io::write_bulk(void* buf, int* len)
|
|||
|
{
|
|||
|
#ifdef USE_OLD_USB
|
|||
|
* len = usb_->write_bulk(buf, *len);
|
|||
|
return SCANNER_ERR_OK;
|
|||
|
#endif
|
|||
|
if (!handle_)
|
|||
|
return last_err_;
|
|||
|
|
|||
|
if (endpoints_.bulk.out.port == usb_manager::uninit_uint8)
|
|||
|
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|||
|
|
|||
|
if (!len)
|
|||
|
return SCANNER_ERR_INVALID_PARAMETER;
|
|||
|
|
|||
|
unsigned char* data = (unsigned char*)buf;
|
|||
|
int total = 0, t = 0,
|
|||
|
|
|||
|
|
|||
|
err = usb_manager::usb_error_2_hg_err(libusb_bulk_transfer(handle_, endpoints_.bulk.out.port, data, *len, &t, to_));
|
|||
|
|
|||
|
//VLOG_MINI_6(LOG_LEVEL_DEBUG_INFO, "First write port %x bulk %d/%d = %s(timeout = %d, packet size = %x)\n", endpoints_.bulk.out.port, t, *len, hg_scanner_err_name((scanner_err)err).c_str(), to_, endpoints_.bulk.out.max_packet);
|
|||
|
// printf("First write port %x bulk %d/%d = %s(timeout = %d, packet size = %x)\n", endpoints_.bulk.out.port, t, *len, hg_scanner_err_name((scanner_err)err).c_str(), to_, endpoints_.bulk.out.max_packet);
|
|||
|
//if (!on_io_error((scanner_err)err, &endpoints_.bulk.out))
|
|||
|
//{
|
|||
|
// *len = t;
|
|||
|
|
|||
|
// return err;
|
|||
|
//}
|
|||
|
|
|||
|
total += t;
|
|||
|
while (total < *len && (err == SCANNER_ERR_TIMEOUT || err == SCANNER_ERR_DEVICE_BUSY))
|
|||
|
{
|
|||
|
if (!t)
|
|||
|
break;
|
|||
|
data += t;
|
|||
|
t = 0;
|
|||
|
err = usb_manager::usb_error_2_hg_err(libusb_bulk_transfer(handle_, endpoints_.bulk.out.port, data, *len - total, &t, to_));
|
|||
|
total += t;
|
|||
|
}
|
|||
|
//VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Last write bulk %d/%d = %s\n", total, *len, hg_scanner_err_name((scanner_err)err).c_str());
|
|||
|
*len = total;
|
|||
|
last_err_ = err;
|
|||
|
|
|||
|
return last_err_;
|
|||
|
}
|
|||
|
int usb_io::read_interrupt(void* buf, int* len)
|
|||
|
{
|
|||
|
#ifdef USE_OLD_USB
|
|||
|
* len = usb_->read_int(buf, *len);
|
|||
|
return SCANNER_ERR_OK;
|
|||
|
#endif
|
|||
|
if (!handle_)
|
|||
|
return last_err_;
|
|||
|
|
|||
|
if (endpoints_.interrupt.in.port == usb_manager::uninit_uint8)
|
|||
|
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|||
|
|
|||
|
if (!len)
|
|||
|
return SCANNER_ERR_INVALID_PARAMETER;
|
|||
|
|
|||
|
if (*len < endpoints_.interrupt.in.max_packet) // avoid transferring overflows ...
|
|||
|
{
|
|||
|
*len = endpoints_.interrupt.in.max_packet;
|
|||
|
|
|||
|
return SCANNER_ERR_INSUFFICIENT_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
int io = 0;
|
|||
|
|
|||
|
last_err_ = usb_manager::usb_error_2_hg_err(libusb_interrupt_transfer(handle_, endpoints_.interrupt.in.port, (unsigned char*)buf, *len, &io, to_));
|
|||
|
*len = io;
|
|||
|
|
|||
|
return last_err_;
|
|||
|
}
|
|||
|
int usb_io::write_interrupt(void* buf, int* len)
|
|||
|
{
|
|||
|
if (!handle_)
|
|||
|
return last_err_;
|
|||
|
|
|||
|
if (endpoints_.interrupt.out.port == usb_manager::uninit_uint8)
|
|||
|
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|||
|
|
|||
|
if (!len)
|
|||
|
return SCANNER_ERR_INVALID_PARAMETER;
|
|||
|
|
|||
|
unsigned char* data = (unsigned char*)buf;
|
|||
|
int total = 0, t = 0,
|
|||
|
err = usb_manager::usb_error_2_hg_err(libusb_bulk_transfer(handle_, endpoints_.interrupt.out.port, data, *len, &t, to_));
|
|||
|
|
|||
|
total += t;
|
|||
|
while (total < *len && (err == SCANNER_ERR_TIMEOUT || err == SCANNER_ERR_DEVICE_BUSY))
|
|||
|
{
|
|||
|
data += t;
|
|||
|
t = 0;
|
|||
|
err = usb_manager::usb_error_2_hg_err(libusb_interrupt_transfer(handle_, endpoints_.interrupt.out.port, data, *len - total, &t, to_));
|
|||
|
total += t;
|
|||
|
}
|
|||
|
*len = total;
|
|||
|
last_err_ = err;
|
|||
|
|
|||
|
return last_err_;
|
|||
|
}
|
|||
|
int usb_io::read_isochronous(void* buf, int* len)
|
|||
|
{
|
|||
|
if (!handle_)
|
|||
|
return last_err_;
|
|||
|
|
|||
|
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|||
|
}
|
|||
|
int usb_io::write_isochronous(void* buf, int* len)
|
|||
|
{
|
|||
|
if (!handle_)
|
|||
|
return last_err_;
|
|||
|
|
|||
|
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|||
|
}
|
|||
|
int usb_io::read_bulk_stream(void* buf, int* len)
|
|||
|
{
|
|||
|
if (!handle_)
|
|||
|
return last_err_;
|
|||
|
|
|||
|
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|||
|
}
|
|||
|
int usb_io::write_bulk_stream(void* buf, int* len)
|
|||
|
{
|
|||
|
if (!handle_)
|
|||
|
return last_err_;
|
|||
|
|
|||
|
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|||
|
}
|
|||
|
int usb_io::reset(void)
|
|||
|
{
|
|||
|
if (!handle_)
|
|||
|
return SCANNER_ERR_NOT_OPEN;
|
|||
|
|
|||
|
return usb_manager::usb_error_2_hg_err(libusb_reset_device(handle_));
|
|||
|
}
|
|||
|
int usb_io::reopen(void)
|
|||
|
{
|
|||
|
close();
|
|||
|
open();
|
|||
|
|
|||
|
return last_err_;
|
|||
|
}
|
|||
|
int usb_io::close(void)
|
|||
|
{
|
|||
|
#ifdef USE_OLD_USB
|
|||
|
usb_.reset();
|
|||
|
return SCANNER_ERR_OK;
|
|||
|
#endif
|
|||
|
if (singleton_)
|
|||
|
singleton_->release();
|
|||
|
singleton_ = nullptr;
|
|||
|
|
|||
|
if (handle_)
|
|||
|
{
|
|||
|
claim_interfaces(false);
|
|||
|
|
|||
|
libusb_close(handle_);
|
|||
|
handle_ = nullptr;
|
|||
|
}
|
|||
|
clear_endpoints();
|
|||
|
if (ref_device_)
|
|||
|
{
|
|||
|
libusb_unref_device(ref_device_);
|
|||
|
ref_device_ = nullptr;
|
|||
|
}
|
|||
|
|
|||
|
return SCANNER_ERR_OK;
|
|||
|
}
|
|||
|
|
|||
|
libusb_device* usb_io::get_usb_device(void)
|
|||
|
{
|
|||
|
return dev_info_.device;
|
|||
|
}
|
|||
|
int usb_io::get_vid(void)
|
|||
|
{
|
|||
|
return dev_info_.vid;
|
|||
|
}
|
|||
|
int usb_io::get_pid(void)
|
|||
|
{
|
|||
|
return dev_info_.pid;
|
|||
|
}
|
|||
|
|
|||
|
void usb_io::on_disconnected(void)
|
|||
|
{
|
|||
|
close();
|
|||
|
last_err_ = SCANNER_ERR_DEVICE_NOT_FOUND;
|
|||
|
}
|
|||
|
std::string usb_io::init_error_msg(void)
|
|||
|
{
|
|||
|
return init_err_msg_;
|
|||
|
}
|
|||
|
|
|||
|
bool usb_io::is_ready(void)
|
|||
|
{
|
|||
|
return handle_ != NULL;
|
|||
|
}
|
|||
|
int usb_io::last_error(void)
|
|||
|
{
|
|||
|
return last_err_;
|
|||
|
}
|
|||
|
int usb_io::get_bulk_packet_size(int* bytes)
|
|||
|
{
|
|||
|
if (!bytes)
|
|||
|
return SCANNER_ERR_INVALID_PARAMETER;
|
|||
|
|
|||
|
if (endpoints_.bulk.in.port == usb_manager::uninit_uint8 && endpoints_.bulk.out.port == usb_manager::uninit_uint8)
|
|||
|
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|||
|
|
|||
|
*bytes = endpoints_.bulk.in.max_packet;
|
|||
|
|
|||
|
return SCANNER_ERR_OK;
|
|||
|
}
|
|||
|
int usb_io::get_interrupt_packet_size(int* bytes)
|
|||
|
{
|
|||
|
if (!bytes)
|
|||
|
return SCANNER_ERR_INVALID_PARAMETER;
|
|||
|
|
|||
|
if (endpoints_.interrupt.in.port == usb_manager::uninit_uint8 && endpoints_.interrupt.out.port == usb_manager::uninit_uint8)
|
|||
|
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|||
|
|
|||
|
*bytes = endpoints_.interrupt.in.max_packet;
|
|||
|
|
|||
|
return SCANNER_ERR_OK;
|
|||
|
}
|
|||
|
unsigned int usb_io::set_timeout(unsigned int to)
|
|||
|
{
|
|||
|
unsigned int old = to_;
|
|||
|
|
|||
|
to_ = to;
|
|||
|
|
|||
|
#if defined(WIN32) || defined(_WIN64)
|
|||
|
if (handle_)
|
|||
|
{
|
|||
|
libusb_set_timeout(handle_, to_);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
return old;
|
|||
|
}
|
|||
|
unsigned int usb_io::get_timeout(void)
|
|||
|
{
|
|||
|
return to_;
|
|||
|
}
|