其他分享
首页 > 其他分享> > USB报告描述符热身-后续会详解

USB报告描述符热身-后续会详解

作者:互联网

在USB中,USB HOST是通过各种描述符来识别设备的,有设备描述符,配置描述符,接口描述符,端点描述符,字符串描述符,报告描述符等等。USB报告描述符(Report Descriptor)是HID设备中的一个描述符,它是比较复杂的一个描述符。


USB HID设备是通过报告来给传送数据的,报告有输入报告和输出报告。输入报告是USB设备发送给主机的,例如USB鼠标将鼠标移动和鼠标点击等信息返回给电脑,键盘将按键数据数据返回给电脑等;输出报告是主机发送给USB设备的,例如键盘上的数字键盘锁定灯和大写字母锁定灯等。报告其实就是一个数据包,只是换了一种说法,就是设备要把自己的状态报告给主机的意思,里面包含的是所要传送的数据。输入报告是通过中断输入端点输入的,而输出报告有点区别,当没有中断输出端点时,可以通过控制输出端点0发送,当有中断输出端点时,通过中断输出端点发出。


报告描述符,就是描述一个报告(数据包)以及报告里面的数据(数据包里面的数据)是用来干什么用的。通过它,USB HOST可以分析出报告里面的数据所表示的意思,也就是设备传过来的这些字节是什么意思(下面代码会讲解)。报告描述符(也就是下面的数据结构)通过控制输入端点0返回(大家都知道描述符都是通过控制端点0返回给主机的,报告描述符也是描述符),主机使用获取报告描述符命令来获取报告描述符。一个报告描述符可以描述多个报告(数据包),不同的报告通过报告ID来识别,报告ID在报告最前面,即第一个字节。当报告描述符中没有规定报告ID时,报告中就没有ID字段,开始就是数据。更详细的说明请参看USB HID协议,该协议可从Http://www.usb.org下载。

 

下图报告描述符:

const unsigned char ReportDesc[0x2b] =   // Report descriptor
	{
	0x05,0x01,		/* Usage Page (generic desktop) */
	0x09,0x06,		/* Usage (keyboard) */
	0xA1,0x01,		/* Collection */
	0x05,0x07,		/*   Usage Page 7 (keyboard/keypad) */
	0x19,0xE0,		/*   Usage Minimum = 224 */
	0x29,0xE7,		/*   Usage Maximum = 231 */
	0x15,0x00,		/*   Logical Minimum = 0 */
	0x25,0x01,		/*   Logical Maximum = 1 */
	0x75,0x01,		/*   Report Size = 1 */
	0x95,0x08,		/*   Report Count = 8 */
	0x81,0x02,		/*  Input(Data,Variable,Absolute) */
	0x95,0x01,		/*   Report Count = 1 */
	0x75,0x08,		/*   Report Size = 8 */
	0x81,0x01,		/*  Input(Constant) */
	0x19,0x00,		/*   Usage Minimum = 0 */
	0x29,0x65,		/*   Usage Maximum = 101 */
	0x15,0x00,		/*   Logical Minimum = 0 */
	0x25,0x65,		/*   Logical Maximum = 101 */
	0x75,0x08,		/*   Report Size = 8 */
	0x95,0x01,		/*   Report Count = 1 */
	0x81,0x00,		/*  Input(Data,Variable,Array) */
	0xC0};			/* End Collection */

下图报告(数据包):

unsigned char Message[] = {
	0x00,0x00,0x28,0x00};

XUsb_EpDataSend(&UsbInstance, 1,
			(unsigned char *)&Message[Index], 3);

核心的核心:其实上面的报告描述符就是描述下面报告具体的含义,也就是描述Message里面的每一个字节的每一位都代表什么意思。

 

下面看报告描述符的构成:

code char KeyBoardReportDescriptor[63] = {
//表示用途页为通用桌面设备
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
//表示用途为键盘
0x09, 0x06, // USAGE (Keyboard)

//表示应用集合,必须要以END_COLLECTION来结束它,见最后的END_COLLECTION
0xa1, 0x01, // COLLECTION (Application)

 
// 第1个字节(input):8个按键 

	//表示用途页为按键
	0x05, 0x07, // USAGE_PAGE (Keyboard)
	//用途最小值,这里为左ctrl键
	0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
	//用途最大值,这里为右GUI键,即window键
	0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
	//逻辑最小值为0
	0x15, 0x00, // LOGICAL_MINIMUM (0)
	//逻辑最大值为1
	0x25, 0x01, // LOGICAL_MAXIMUM (1)
	//报告大小(即这个字段的宽度)为1bit,所以前面的逻辑最小值为0,逻辑最大值为1
	0x75, 0x01, // REPORT_SIZE (1)
	//报告的个数为8,即总共有8个bits
	0x95, 0x08, // REPORT_COUNT (8)
	//输入用,变量,值,绝对值。像键盘这类一般报告绝对值,
	//而鼠标移动这样的则报告相对值,表示鼠标移动多少
	0x81, 0x02, // INPUT (Data,Var,Abs)
	//上面这这几项描述了一个输入用的字段,总共为8个bits,每个bit表示一个按键
	//分别从左ctrl键到右GUI键。这8个bits刚好构成一个字节,它位于报告的第一个字节。
	//它的最低位,即bit-0对应着左ctrl键,如果返回的数据该位为1,则表示左ctrl键被按下,
	//否则,左ctrl键没有按下。最高位,即bit-7表示右GUI键的按下情况。中间的几个位,
	//需要根据HID协议中规定的用途页表(HID Usage Tables)来确定。这里通常用来表示
	//特殊键,例如ctrl,shift,del键等

 
// 第2个字节(input):常量,必须返回0 

	//这样的数据段个数为1
	0x95, 0x01, // REPORT_COUNT (1)
	//每个段长度为8bits
	0x75, 0x08, // REPORT_SIZE (8)
	//输入用,常量,值,绝对值
	0x81, 0x03, // INPUT (Cnst,Var,Abs)
	//上面这8个bit是常量,设备必须返回0

 
// 第1个字节(output):控制键盘LED

	//这样的数据段个数为5
	0x95, 0x05, // REPORT_COUNT (5)
	//每个段大小为1bit
	0x75, 0x01, // REPORT_SIZE (1)
	//用途是LED,即用来控制键盘上的LED用的,因此下面会说明它是输出用
	0x05, 0x08, // USAGE_PAGE (LEDs)
	//用途最小值是Num Lock,即数字键锁定灯
	0x19, 0x01, // USAGE_MINIMUM (Num Lock)
	//用途最大值是Kana,这个是什么灯我也不清楚^_^
	0x29, 0x05, // USAGE_MAXIMUM (Kana)
	//如前面所说,这个字段是输出用的,用来控制LED。变量,值,绝对值。
	//1表示灯亮,0表示灯灭
	0x91, 0x02, // OUTPUT (Data,Var,Abs)
	//这样的数据段个数为1
	0x95, 0x01, // REPORT_COUNT (1)
	//每个段大小为3bits
	0x75, 0x03, // REPORT_SIZE (3)
	//输出用,常量,值,绝对
	0x91, 0x03, // OUTPUT (Cnst,Var,Abs) 
	//由于要按字节对齐,而前面控制LED的只用了5个bit,
	//所以后面需要附加3个不用bit,设置为常量。

 
// 第3-8个字节(input):其他按键

	//报告个数为6
	0x95, 0x06, // REPORT_COUNT (6)
	//每个段大小为8bits
	0x75, 0x08, // REPORT_SIZE (8)
	//逻辑最小值0
	0x15, 0x00, // LOGICAL_MINIMUM (0)
	//逻辑最大值255
	0x25, 0xFF, // LOGICAL_MAXIMUM (255)
	//用途页为按键
	0x05, 0x07, // USAGE_PAGE (Keyboard)
	//使用最小值为0
	0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
	//使用最大值为0x65
	0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
	//输入用,变量,数组,绝对值
	0x81, 0x00, // INPUT (Data,Ary,Abs)
	//以上定义了6个8bit宽的数组,每个8bit(即一个字节)用来表示一个按键,所以可以同时
	//有6个按键按下。没有按键按下时,全部返回0。如果按下的键太多,导致键盘扫描系统
	//无法区分按键时,则全部返回0x01,即6个0x01。如果有一个键按下,则这6个字节中的第一
	//个字节为相应的键值(具体的值参看HID Usage Tables),如果两个键按下,则第1、2两个
	//字节分别为相应的键值,以次类推。

//关集合,跟上面的对应
0xc0 // END_COLLECTION
};

code char MouseReportDescriptor[52] = {
//通用桌面设备
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
//鼠标
0x09, 0x02, // USAGE (Mouse)
//集合
0xa1, 0x01, // COLLECTION (Application)


	//指针设备
	0x09, 0x01, // USAGE (Pointer)
	//集合
	0xa1, 0x00, // COLLECTION (Physical)
 
// 第1个字节(input):3个按键 
	
		//按键
		0x05, 0x09, // USAGE_PAGE (Button)
		//使用最小值1
		0x19, 0x01, // USAGE_MINIMUM (Button 1)
		//使用最大值3。1表示左键,2表示右键,3表示中键
		0x29, 0x03, // USAGE_MAXIMUM (Button 3)
		//逻辑最小值0
		0x15, 0x00, // LOGICAL_MINIMUM (0)
		//逻辑最大值1
		0x25, 0x01, // LOGICAL_MAXIMUM (1)
		//数量为3
		0x95, 0x03, // REPORT_COUNT (3)
		//大小为1bit
		0x75, 0x01, // REPORT_SIZE (1)
		//输入,变量,数值,绝对值
		//以上3个bit分别表示鼠标的三个按键情况,最低位(bit-0)为左键
		//bit-1为右键,bit-2为中键,按下时对应的位值为1,释放时对应的值为0
		0x81, 0x02, // INPUT (Data,Var,Abs)
		//填充5个bit,补足一个字节
		0x95, 0x01, // REPORT_COUNT (1)
		0x75, 0x05, // REPORT_SIZE (5)
		0x81, 0x03, // INPUT (Cnst,Var,Abs)
		
 
// 第3个字节(input):鼠标左右移动、上下移动、滚轮上下移动 
		
		//用途页为通用桌面
		0x05, 0x01, // USAGE_PAGE (Generic Desktop)
		//用途为X
		0x09, 0x30, // USAGE (X)
		//用途为Y
		0x09, 0x31, // USAGE (Y)
		//用途为滚轮
		0x09, 0x38, // USAGE (Wheel)
		//逻辑最小值为-127
		0x15, 0x81, // LOGICAL_MINIMUM (-127)
		//逻辑最大值为+127
		0x25, 0x7f, // LOGICAL_MAXIMUM (127)
		//大小为8个bits
		0x75, 0x08, // REPORT_SIZE (8)
		//数量为3个,即分别代表x,y,滚轮
		0x95, 0x03, // REPORT_COUNT (3)
		//输入,变量,值,相对值
		0x81, 0x06, // INPUT (Data,Var,Rel)
	//关集合
	0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};

标签:USB,报告,0x01,热身,REPORT,描述符,USAGE,字节
来源: https://blog.csdn.net/weiaipan1314/article/details/112314726