208 lines
7.4 KiB
C++
208 lines
7.4 KiB
C++
#pragma once
|
||
|
||
#if defined(WIN32) || defined(_WIN64)
|
||
#include "win_usb/win_usb.h"
|
||
#else
|
||
#include <libusb-1.0/libusb.h>
|
||
|
||
#define HIBYTE(w) (((w) >> 8) & 0x0ff)
|
||
#define LOBYTE(w) ((w) & 0x0ff)
|
||
#define _countof(a) (sizeof(a) / sizeof((a)[0]))
|
||
#endif
|
||
|
||
#include <thread>
|
||
#include <memory>
|
||
#include <algorithm>
|
||
#include <string>
|
||
#include <mutex>
|
||
#include <vector>
|
||
#include <chrono>
|
||
|
||
#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_;
|
||
std::mutex usb_cb_locker_;
|
||
libusb_context* context_; // declare my own context, avoid sharing the default context with other processes
|
||
int status_;
|
||
void* usb_cb_param_;
|
||
std::shared_ptr<std::thread> usb_notify_thread_;
|
||
std::shared_ptr<std::thread> 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<PNPDEV> 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<libusb_device*>& 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);
|
||
};
|
||
|