#pragma once #if defined(WIN32) || defined(_WIN64) #include "win_usb/win_usb.h" #else #include #define HIBYTE(w) (((w) >> 8) & 0x0ff) #define LOBYTE(w) ((w) & 0x0ff) #define _countof(a) (sizeof(a) / sizeof((a)[0])) #endif #include #include #include #include #include #include #include #include "huagao/hgscanner_error.h" #include "BlockingQueue.h" #include "hg_ipc.h" struct usb_dev { libusb_context* contex; libusb_device* device; // unique device object uint16_t ver; // 0x200, 0x101, ... uint16_t vid; // vendor ID uint16_t pid; // product ID uint8_t addr; // usb port ? bool operator==(const libusb_device* dev) { return dev == device; } }; typedef struct _dev_sn { std::string serial; bool operator==(const struct _dev_sn& other) { return serial == other.serial; } }DEVSN; enum usb_event { USB_EVENT_NULL = 0, USB_EVENT_DEVICE_ARRIVED, USB_EVENT_DEVICE_LEFT, USB_EVENT_DATA_ARRIVED, USB_EVENT_ERROR, }; typedef void(*usb_event_handler)(usb_event ev, libusb_device* device, int vid, int pid, int usb_ver_h, int usb_ver_l, bool* retry/*whether */, void* user); // usb_ver_h.usb_ver_l class usb_io; class usb_manager { volatile bool run_; usb_event_handler usb_cb_; libusb_context* context_; // declare my own context, avoid sharing the default context with other processes int status_; void* usb_cb_param_; std::shared_ptr usb_notify_thread_; std::shared_ptr usb_monitor_thread_; // some unknown reason, operation is accessible after certain delay libusb_hotplug_callback_handle usb_cb_handle_; std::chrono::system_clock::time_point born_; typedef struct _pnp_dev { libusb_context* ctx; libusb_device* dev; libusb_hotplug_event event; std::chrono::system_clock::time_point happen_time; // millisecond }PNPDEV; BlockingQueue pnp_events_; platform_event wait_pnp_; static int LIBUSB_CALL usb_pnp_callback(libusb_context* ctx, libusb_device* device, libusb_hotplug_event event, void* monitor); static void 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 static void usb_log_callback(libusb_context* ctx, libusb_log_level level, const char* str); int register_usb_pnp(void); void init_notify_thread(); void fake_usb_pnp(std::vector& devices); void thread_notify_usb_event(); void notify_usb_event(PNPDEV& pd, bool* retry); void thread_trigger_usb_event(); int on_usb_pnp_event(struct libusb_context* ctx, struct libusb_device* device, libusb_hotplug_event event); static usb_manager* inst_; protected: usb_manager(); ~usb_manager(); public: typedef struct _usb_simplex { uint8_t port; uint8_t iconf; uint8_t iface; uint8_t claimed; uint16_t max_packet; }USBSIMPLEX; typedef struct _usb_endpoints { USBSIMPLEX in; USBSIMPLEX out; }USBENDP; typedef struct _usb_transfer_endpoints { USBENDP control; USBENDP isochronous; USBENDP bulk; USBENDP interrupt; USBENDP bulk_stream; }USBTRANSENDP; static uint8_t uninit_uint8; static usb_manager* instance(void); static void clear(void); static int usb_error_2_hg_err(int usb_err); static void init_endpoint(USBENDP* uep); static std::string device_class(libusb_class_code code); static std::string endpoint_type(libusb_transfer_type type); static bool get_device_info(libusb_device* device, usb_dev* devinfo); static void enum_endpoints(libusb_device* device, USBTRANSENDP* endp = nullptr); public: int register_hotplug(usb_event_handler cb, void* user); int open(libusb_device* device, usb_io** usbio, std::string* msg = nullptr); int last_status(void); }; class usb_io { volatile int ref_; shared_memory *singleton_; libusb_device_handle *handle_; usb_dev dev_info_; unsigned int to_; // NOTE: For an unlimited timeout, use value 0. int last_err_; std::string init_err_msg_; libusb_device *ref_device_; // endpoint ports usb_manager::USBTRANSENDP endpoints_; bool make_singleton(void); void clear_endpoints(void); bool claim_interterface(usb_manager::USBSIMPLEX* spl); int claim_interfaces(bool claim); void init_after_open(void); void open(void); bool on_io_error(scanner_err err, usb_manager::USBSIMPLEX* endp); protected: virtual ~usb_io(); public: usb_io(const usb_dev& dev); int add_ref(void); // 拥有者在第一次获取时调用一次 int release(void); // 拥有者不再使用时调用 // IO操作返回值全部为错误代码 (scanner_err) int control_io(uint8_t type, uint8_t req, uint16_t val, uint16_t ind, void* buf, int* len); // 读取数据, len: [in] - buf size, [out] - real read bytes in buf int read_bulk(void* buf, int* len); // 读取数据, len: [in] - buf size, [out] - real read bytes in buf. 如果缓冲区太小,则返回SCANNER_ERR_INSUFFICIENT_MEMORY的错误,并在该值中保存建议的最小缓冲区大小 int write_bulk(void* buf, int* len); // 写入数据, len : [in] - content bytes in buf, [out] - real wrote bytes int read_interrupt(void* buf, int* len); // 读取数据, len: [in] - buf size, [out] - real read bytes in buf int write_interrupt(void* buf, int* len); // 写入数据, len : [in] - content bytes in buf, [out] - real wrote bytes int read_isochronous(void* buf, int* len); // 读取数据, len: [in] - buf size, [out] - real read bytes in buf int write_isochronous(void* buf, int* len); // 写入数据, len : [in] - content bytes in buf, [out] - real wrote bytes int read_bulk_stream(void* buf, int* len); // 读取数据, len: [in] - buf size, [out] - real read bytes in buf int write_bulk_stream(void* buf, int* len); // 写入数据, len : [in] - content bytes in buf, [out] - real wrote bytes int reset(void); int reopen(void); int close(void); // 关闭该对象 libusb_device* get_usb_device(void); // 获取该USB对象 int get_vid(void); // 获取连接到该USB端口上的设备VID int get_pid(void); // 获取连接到该USB端口上的设备PID void on_disconnected(void); std::string init_error_msg(void); public: bool is_ready(void); int last_error(void); int get_bulk_packet_size(int* bytes); // 获取bulk方式的数据包大小,返回错误代码 int get_interrupt_packet_size(int* bytes); unsigned int set_timeout(unsigned int to = USB_TIMEOUT_INFINITE); unsigned int get_timeout(void); };