code_util/usb_manager.h

207 lines
7.3 KiB
C
Raw Permalink Normal View History

2023-02-24 09:24:48 +00:00
#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 "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 int 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);
};