usb协议
-
设备中的endpoint端点 通信使用pipe管道
-
主机到从机out 反之in
-
pipe数据通信方式主要是message stream
-
端点有四种类型 控制 中断 批量 等时 常用控制传输
-
逻辑设备 多端点设备 一个设备也可能有多个接口
-
USB架构中, hub负责检测设备的连接和断开,利用其中断IN端点(Interrupt IN Endpoint)来向主机(Host)报告。在系统启动时,主机轮询它的根hub(Root Hub)的状态看是否有设备(包括子hub和子hub上的设备)连接。
-
描述符 区分从设备 设备描述符>配置描述符>接口描述符>端点描述符
-
设备描述符 :一个设备一个,设备类型、设备遵循的协议、厂商ID、产品id、序列号
:::
DEVICE DESCRIPTOR
bLength: 18
bDescriptorType: 0x01 (DEVICE)
bcdUSB: 0x0200
bDeviceClass: Vendor Specific (0xff)
bDeviceSubClass: 255
bDeviceProtocol: 255
bMaxPacketSize0: 64
idVendor: Marvell Semiconductor, Inc. (0x1286)
idProduct: Unknown (0x812a)
bcdDevice: 0x0000
iManufacturer: 3
iProduct: 2
iSerialNumber: 0
bNumConfigurations: 1
:::
- 配置描述符:一个设备同一时刻只能有一种配置生效
:::
CONFIGURATION DESCRIPTOR
bLength: 9
bDescriptorType: 0x02 (CONFIGURATION)
wTotalLength: 121
bNumInterfaces: 4
bConfigurationValue: 1
iConfiguration: 0
Configuration bmAttributes: 0xc0 SELF-POWERED NO REMOTE-WAKEUP
1... .... = Must be 1: Must be 1 for USB 1.1 and higher
.1.. .... = Self-Powered: This device is SELF-POWERED
..0. .... = Remote Wakeup: This device does NOT support remote wakeup
bMaxPower: 250 (500mA)
:::
- **接口描述符:**复合设备多个接口
:::
INTERFACE DESCRIPTOR (2.0): class Vendor Specific
bLength: 9
bDescriptorType: 0x04 (INTERFACE)
bInterfaceNumber: 2
bAlternateSetting: 0
bNumEndpoints: 2
bInterfaceClass: Vendor Specific (0xff)
bInterfaceSubClass: 0x00
bInterfaceProtocol: 0x00
iInterface: 8
:::
- 端点描述符:USB通信的基本物理单位,一个endpiont只能承载一个方向的数据,control interrupt bulk iso
12.class 描述设备是哪种设备,class分为class subclass protol 用于系统加载对应的驱动文件
枚举
13.传输->事务->包
14.上电,检测速度,主机发请求获取包的最大长度,主机给设备分配地址,主机获取设备配置
传输过程
帧格式:传输信息,数据,设备应答
主机读取设备描述符代码:
joystick hid
oystick HID(Human Interface Device)是指使用 USB HID 协议通信的游戏手柄或者操纵杆设备。
- 报告描述器
定义了设备支持的各种报告类型和格式, 报告描述器通常以二进制格式表示,描述了设备的物理按钮、摇杆、轴等控件。
2.报告协议
Joystick HID 设备通常使用中断传输报告
Joystick HID 设备通常包含多个按钮、摇杆、方向键等控件,用于用户输入。这些控件的状态(按下或释放、摇动的方向和幅度等)会被编码为报告数据,并通过 USB HID 协议传输到计算机上。
custom hid
Custom HID(Custom Human Interface Device)是指自定义的 USB HID 设备,它们不属于标准的键盘、鼠标、游戏手柄等常见类型,而是根据特定的需求和应用场景而设计的设备。
t113固件烧写
纸飞机if 0 1 一个是主机发送,设备传回 一个是设备持续发送数据。使用的就是usb协议
qt动态链接hidapi库,可以使用定义好的api来读信息
win32:LIBS += -L$$_PRO_FILE_PWD_\
-lhidapi
常用api
-
**hid_init()**
:初始化**hidapi**
库,用于在程序开始时调用。 -
**hid_exit()**
:关闭**hidapi**
库,用于在程序结束时调用。 -
**hid_open()**
:打开指定路径的 HID 设备。 -
**hid_open_path()**
:通过设备路径打开 HID 设备。 -
**hid_close()**
:关闭已打开的 HID 设备。 -
**hid_read()**
:从 HID 设备中读取数据。 -
**hid_write()**
:向 HID 设备中写入数据。 -
**hid_send_feature_report()**
:发送 Feature 报告到 HID 设备。 -
**hid_get_feature_report()**
:从 HID 设备中获取 Feature 报告。 -
**hid_get_manufacturer_string()**
:获取设备的制造商字符串。 -
**hid_get_product_string()**
:获取设备的产品字符串。 -
**hid_get_serial_number_string()**
:获取设备的序列号字符串。 -
**hid_error()**
:获取最近一次发生的错误信息。
可以读取到固件连续发出的信息,24个字节
除去vid pid 接口数,interface number 有0 和1
hiddevinfo信息
:::
**vendor_id**
:设备的制造商 ID。
**product_id**
:设备的产品 ID。
**path**
:设备的路径(在某些操作系统中,可以用来打开设备)。
**serial_number**
:设备的序列号。
**release_number**
:设备的发布版本号。
**manufacturer_string**
:设备制造商的字符串描述。
**product_string**
:设备产品的字符串描述。
**usage_page**
:设备的使用页面(Usage Page)。
**usage**
:设备的使用(Usage)。
**interface_number**
:设备接口的编号。
:::
设备、接口信息
0接口
\?\HID#VID_2A62&PID_0088&MI_01#7&6bb4252&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
1接口
\?\HID#VID_2A62&PID_0088&MI_00#7&7899f96&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
**QByteArray**
是用于存储二进制数据的类,通常用于处理字节流数据
可以使用 **QIODevice**
子类(例如 **QTcpSocket**
、**QUdpSocket**
等)的 **write**
和 **read**
方法来发送和接收数据。
HIDDEVICE
枚举参数
:::
enum
{
REPORT\_ID\_JOY = 1,
REPORT\_ID\_PARAM,//参数请求报告
REPORT\_ID\_CONFIG\_IN,//读取配置模式
REPORT\_ID\_CONFIG\_OUT,//应该是写入配置模式
REPORT\_ID\_FIRMWARE,
};
:::
方向:修改和32不同的字符名称、端口数量
线程安全:在多线程环境中,如果多个线程同时尝试修改共享的数据结构,比如清空列表 **m_hidDevicesList**
,就可能导致竞态条件(Race Condition)的发生,进而造成不确定的行为,甚至是程序崩溃。这里是因为修改公共数据,所以两个线程进行数据处理时候加了锁。
:::
**processData()**
函数中的 **th**
线程和主线程都会访问和修改 **m_hidDevicesList**
列表。
#include
// 声明互斥锁
std::mutex m_mutex;
void someFunction() {
// 创建 lock\_guard 对象并传入互斥锁
std::lock\_guard<std::mutex> lock(m\_mutex);
// 在这个作用域中,m\_mutex 已经被锁定,可以安全地访问共享资源
// ...
// 在作用域结束时,lock\_guard 的析构函数会自动释放互斥锁
}
:::
同一个函数内如果存在两个进程,也属于不同的作用域,锁定义为成员变量,可以理解为两个作用域调用了同一个锁对象。
handle processdata function entry,create thread using movetothread()
:::
m_hidDeviceWorker->moveToThread(m_thread);
connect(m\_thread,&QThread::started,m\_hidDeviceWorker,&HidDevice::processData);
:::
**QString::fromWCharArray**
是 Qt 中用于将宽字符数组转换为 QString 对象的函数。它的作用是将以 null 结尾的宽字符数组(wchar_t[])转换为 QString 对象。
:::
QString QString::fromWCharArray(const wchar_t *unicode, int size = -1)
:::
代码分析,可以根据执行流程来进行 qDebug()<<“执行到这里”;
if (m_selectedDevice != oldSelectedDevice || (deviceCountChanged && m_selectedDevice >= 0))
这个是作者设置的判断条件,没有注释功能,之后再看,已进入了这个判断。
usb_hid设备收发
读配置
hid_write(m_paramsRead, config_request_buffer, 2);
res=hid_read_timeout(m_paramsRead, buffer, BUFFERSIZE,100);//返回数据的字节数
hid_set_nonblocking(handle,0)==0) 句柄 要打开的interface number 成功返回0,失败 -1
interface_num=0,设备并没有向外发数据,而是一个发啥读啥的过程。
设备会发送数据给主机,需要设置一个接收数据的循环。通过库函数从设备读取数据,并_根据报告描述符解析数据_
extern GlobalEnvironment gEnv;
这行代码,在当前文件中引用该变量,以便在当前文件中使用它而不需要重新定义。其他文件中已经定义了此结构体
NXP公司74HC165 移位寄存器 并行输入串行输出
pl
全局变量 extern 作用范围群全部程序
// 在头文件中定义全局变量
extern int global_var;
// 在源文件中定义全局变量
int global_var = 0;
当主机操作系统检测到新连接的USB设备时,会通过控制传输向USB设备发送请求获取设备描述符。USB设备在收到请求后,会将相应的设备描述符数据通过控制传输发送给主机操作系统。主机操作系统接收到设备描述符数据后,会解析数据并根据其中的信息来配置和识别USB设备。这部分在识别到设备之前就已经完成了。
// 将字符串转换为字节数组
QByteArray byteArray = str.toUtf8(); // 或者使用 toLatin1() 或 toLocal8Bit()
// 将字节数组转换为十六进制表示
QByteArray hexArray = byteArray.toHex();
// 输出十六进制表示
qDebug() << hexArray;
在写入数据时,应该构造一个比实际数据长1个字节的数组。然后将这个数组的第一个字节赋值为0,接着调用该函数,差一点就会出错乱码。
usb线接入电脑端口不同,也会导致读取到interface_number不同