g1g2hardwarechecker/USB/usb_manager.cpp

1176 lines
38 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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_;
}