code_device/hgdriver/hgdev/usb_manager.h

207 lines
7.3 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.

#pragma once
#ifdef WIN32
#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_;
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);
};