蓝牙键鼠 HID Reports

USB与BT HID reports描述符实践与抓包分析 文章内容提示 这篇文章主要说明如何获取与查看USB和BLE HoGP HID设备报告描述符,如何根据获取的描述符读懂report。然后说明了可以使用hidrd-convert工具,来如何根据hex报告描述符转化得到C语言格式的描述符,这对于我们编码是有意义的。 其中,还截取了USB 逻辑分析仪,Wireshark等工具来查看input report。 如何看懂HID report de 阅读详情
AI摘要

本文深入探讨了蓝牙HID设备的工作原理,详细介绍了其配置文件(Profile)框架、HID报文描述符结构以及报告(Report)的种类。此外,还讲解了蓝牙设备间的数据交换流程,特别关注了GAP、GATT等核心组件。

一. 引言

 蓝牙是一种短距的无线通讯技术,可实现固定设备、移动设备之间的数据交换。一般将蓝牙3.0之前的BR/EDR蓝牙称为传统蓝牙,而将蓝牙4.0规范下的蓝牙BLE(BluetoohLow Energy)称为低功耗蓝牙。 (BLE)连接都是建立在 GATT (Generic Attribute Profile) 协议之上。GATT 是一个在蓝牙连接之上的发送和接收很短的数据段的通用规范,这些很短的数据段被称为属性(Attribute)。  3.0 &4.0 4.0&5.0区别  
 

Bluetooth的一个很重要特性,就是所有的Bluetooth产品都无须实现全部的Bluetooth规范。为了更容易的保持Bluetooth设备之间的兼容,Bluetooth规范中定义了Profile。Profile定义了设备如何实现一种连接或者应用,你可以把Profile理解为连接层或者应用层协议。

(从 Android 3.0 开始,Bluetooth API 便支持使用蓝牙配置文件) 

一、Profile

1.1 常用的profile介绍

请参考“蓝牙Profile的概念和常见种类”,几种种最基本的配置文件为:常见种类 在android源码中的体现  

 

1.通用访问配置文件(Generic Access Profile, GAP)   GAP&&GATT https://www.cnblogs.com/yongdaimi/p/11507397.html GAP&&GATT 

GAP是所有其他配置文件的https://www.cnblogs.com/yongdaimi/p/11507397.html基础,它定义了在蓝牙设备间建立基带链路的通用方法.除此之外,GAP还定义了下列内容:

   ① 必须在所有蓝牙设备中实施的功能
   ② 发现和链接设备的通用步骤
   ③ 基本用户界面术语.

它在用来控制设备连接和广播。GAP 使你的设备被其他设备可见,并决定了你的设备是否可以或者怎样与合同设备进行交互。例如 Beacon 设备就只是向外广播,不支持连接,小米手环就等设备就可以与中心设备连接。

2.服务发现应用配置文件(Service Discovery Application Profile, SDAP)
  

SDAP描述了应用程序如何使用SDP发现远程设备上的服务.由于GAP的要求,任何蓝牙设备都应能够连接至其他蓝牙设备.基于此,SDAP要求任何应用程序都应当能够发现它要连接的其他蓝牙设备上的可用服务.此配置文件可承担搜索已知和特定服务及一般的任务.SDAP涉及了称为“服务发现用户应用程序”的一个应用程序,这是蓝牙设备查找服务所必需的.此应用程序可与向/从其他蓝牙设备发送/接收服务查询的SDP相接.SDAP依赖于GAP,并可以重新使用部分GAP.

BluetoothHidDevice框架在应用注册期间添加了SDP记录,这样Android设备可以被发现为蓝牙HID设备。  (BluetoothHidDeviceAppSdpSettings)

3.串行端口配置文件(Serial Port Profile, SPP)
  

SPP定义了如何设置虚拟串行端口及如何连接两个蓝牙设备.SPP基于ETSI TS 07.10规格,使用RFCOMM协议提供串行商品仿真.SPP提供了以无线方式替代现有的RS-232串行通信应用程序和控制信号的方法.SPP为DUN,FAX,HSP和LAN配置文件提供了基础.此配置文件可以支持最高128kb/s的数据率.SPP依赖于GAP.

4.通用对象交换配置文件(Generic Object Exchange Profile, GOEP)
 

GOEP可用于将对象从一个设备传输到另一个设备.对象可以是任意的.如:图片,文档,名片等.此配置文件定义了两个角色:提供拉提或推送对象位置的服务器及启动操作的客户端.使用GOEP的应用程序假定链路和信道已按GAP的定义建立.GOEP依赖于串行端口配置文件.
GOEP为使用OBEX协议的其他配置文件提供了通用蓝图,并为设备定义了客户端和服务器角色.对于所有的OBEX事务.GOEP规定应由客户端启动所有事务.但是此配置文件并没有描述应用程序就如何定义要交换的对象或如何实施交换.这些细节留给属于GOEP的配置文件.即OPP,FTP和SYNC去完成.通常使用此配置文件的蓝牙设备为笔记本电脑,PDA,手机及智能电话.

注意:蓝牙1.1版本规范所有蓝牙设备的最小实现必须支持通用访问配置文件,服务发现应用配置文件和串行端口配置文件.

在两台电脑或者Labtop之间就可以建立这种连接,如下图所示: 

    SPP是基于RFCOMM的,spp 协议处于rfcomm的上层,spp的应用需走rfcomm层。如果你使用RFCOMM能够实现,那么也就不需要使用SPP,而却速度还会比SPP来做快,因为省略了采用profile的一些数据包头等。不过,还是推荐采用SPP来做,兼容性有保证,这也是为什么蓝牙本质上数据和语音的传送却出现HFP,HSP,SPP,OPP等诸多具体应用profile的原因。

1.2蓝牙profile框架

每个attribute属性被UUID(通用唯一标识符)唯一标识 ,UUID是标准128-bit格式的ID用来唯一标识信息。attributes 被 ATT 格式化characteristics和services形式进行传送。

特征(Characteristics)— 一个characteristics包含一个单独的value值和0 –n个用来描述characteristic 值(value)的descriptors。一个characteristics可以被认为是一种类型的,类似于一个类。

描述符(descriptor)—descriptor是被定义的attributes,用来描述一个characteristic的值。例如,一个descriptor可以指定一个人类可读的描述中,在可接受的范围里characteristic值,或者是测量单位,用来明确characteristic的值。

服务(service)—service是characteristic的集合。例如,你可以有一个所谓的“Heart RateMonitor”service,其中包括characteristic,如“heart rate measurement ”。你可以在 bluetooth.org 找到关于一系列基于GATT的profile和service。

如上图所示:蓝牙设备可以包括多个Profile,一个Profile中有多个Service,一个Service中有多个Characteristic,一个Characteristic中包括一个value和多个Descriptor ()。

描述符 HID_v1.1.1.pdf    from  bluetooth.org   描述HID_USB 

BLE HID规范是以USB HID规范为基础的,HID设备,即人机交互设备,常见的有鼠标,键盘,游戏手柄,等等。

二、HID Reports

Bluetooth HID devices 支持三种Report:Input, Output, Feature。


Input Reports,输入报告
Ble 中,表示 Bluetooth HID device 发送数据给 Bluetooth HID Host.
USB 中输入报告通常通过 中断输入端点来传输。当然也可以通过 控制端点由 HOST 使用 GET REPORT 控制传输请求来获取数据,即host 先发送 get report 命令,device 随后回复 input report,之后 host 会回复一个状态(0 字节数据表示成功)。
Output Reports,输出报告
Ble 中表示 Bluetooth HID Host.发送数据给 Bluetooth HID device.
USB 中输出报告通常通过 中断输出端点来传输。当然也可以通过 控制端点由 HOST 使用 SET REPORT 控制传输请求来发出数据,即HOST 先发送 set report 命令,随后 HOST 发送待发送的数据,最后 DEVICE 回复一个状态(0 字节表示成功)。
Feature Reports,特征报告
Ble 中双向数据通道
USB 中只能通过控制端点来传输双向数据, HOST 使用 GET REPORT 来从 DEVICE 获取数据,或者 HOST 使用 SET REPORT 发送数据给 DEVICE。

 HID报文描述符的结构

下图引用开源项目中的 蓝牙键鼠 输入报告描述    (结合 HID_v1.1.1.pdf  &描述HID_USB  & HID Usage表 查看) HID描述符 由各种  描述符宏  表述 

BluetoothHidDevice.SUBCLASS1_COMBO  
BluetoothHidDeviceAppSdpSettings(
            "Pixel HID1",
            "Mobile BController",
            "bla",
            BluetoothHidDevice.SUBCLASS1_COMBO,
            DescriptorCollection.MOUSE_KEYBOARD_COMBO
        )
val MOUSE_KEYBOARD_COMBO = byteArrayOf(
        //MOUSE TLC
        0x05.toByte(), 0x01.toByte(),                         // USAGE_PAGE (Generic Desktop) 
        0x09.toByte(), 0x02.toByte(),                         // USAGE (Mouse)

        0xa1.toByte(), 0x01.toByte(),                         // COLLECTION (Application)
        0x05.toByte(), 0x01.toByte(),                         // USAGE_PAGE (Generic Desktop)
        0x09.toByte(), 0x02.toByte(),                         // USAGE (Mouse)
        0xa1.toByte(), 0x02.toByte(),        //       COLLECTION (Logical) 集合开始

        0x85.toByte(), 0x04.toByte(),               //   REPORT_ID (Mouse)
        0x09.toByte(), 0x01.toByte(),                         //   USAGE (Pointer)
        0xa1.toByte(), 0x00.toByte(),                         //   COLLECTION (Physical)
        0x05.toByte(), 0x09.toByte(),                         //     USAGE_PAGE (Button)   //左键右键定义
        0x19.toByte(), 0x01.toByte(),                         //     USAGE_MINIMUM (Button 1)
        0x29.toByte(), 0x02.toByte(),                         //     USAGE_MAXIMUM (Button 2)
        0x15.toByte(), 0x00.toByte(),                         //     LOGICAL_MINIMUM (0)
        0x25.toByte(), 0x01.toByte(),                         //     LOGICAL_MAXIMUM (1)
        0x75.toByte(), 0x01.toByte(),                         //     REPORT_SIZE (1)
        0x95.toByte(), 0x02.toByte(),                         //     REPORT_COUNT (2)  //2 bit
        0x81.toByte(), 0x02.toByte(),                         //     INPUT (Data,Var,Abs)报文的类型,
        0x95.toByte(), 0x01.toByte(),                         //     REPORT_COUNT (1) 数据个数 
        0x75.toByte(), 0x06.toByte(),                         //     REPORT_SIZE (6)  数据大小
        0x81.toByte(), 0x03.toByte(),                         //     INPUT (Cnst,Var,Abs) ;Add field to the input report
        0x05.toByte(), 0x01.toByte(),                         //     USAGE_PAGE (Generic Desktop)
        0x09.toByte(), 0x30.toByte(),                         //     USAGE (X) 
        0x09.toByte(), 0x31.toByte(),                         //     USAGE (Y)
        0x16.toByte(), 0x01.toByte(),0xf8.toByte(),                         //     LOGICAL_MINIMUM (-2047)
        0x26.toByte(), 0xff.toByte(),0x07.toByte(),                         //     LOGICAL_MAXIMUM (2047)
        0x75.toByte(), 0x10.toByte(),                         //     REPORT_SIZE (16)
        0x95.toByte(), 0x02.toByte(),                         //     REPORT_COUNT (2)  //2x2 四个字节
        0x81.toByte(), 0x06.toByte(),                         //     INPUT (Data,Var,Rel) //相对位置

        0xa1.toByte(), 0x02.toByte(),        //       COLLECTION (Logical)
        0x85.toByte(), 0x06.toByte(),               //   REPORT_ID (Feature)
        0x09.toByte(), 0x48.toByte(),        //         USAGE (Resolution Multiplier)

        0x15.toByte(), 0x00.toByte(),        //         LOGICAL_MINIMUM (0)
        0x25.toByte(), 0x01.toByte(),        //         LOGICAL_MAXIMUM (1)
        0x35.toByte(), 0x01.toByte(),        //         PHYSICAL_MINIMUM (1)
        0x45.toByte(), 0x04.toByte(),        //         PHYSICAL_MAXIMUM (4)
        0x75.toByte(), 0x02.toByte(),        //         REPORT_SIZE (2)
        0x95.toByte(), 0x01.toByte(),        //         REPORT_COUNT (1)

        0xb1.toByte(), 0x02.toByte(),        //         FEATURE (Data,Var,Abs)


        0x85.toByte(), 0x04.toByte(),               //   REPORT_ID (Mouse)
        //0x05.toByte(), 0x01.toByte(),                         //     USAGE_PAGE (Generic Desktop)
        0x09.toByte(), 0x38.toByte(),        //         USAGE (Wheel)

        0x15.toByte(), 0x81.toByte(),        //         LOGICAL_MINIMUM (-127)
        0x25.toByte(), 0x7f.toByte(),        //         LOGICAL_MAXIMUM (127)
        0x35.toByte(), 0x00.toByte(),        //         PHYSICAL_MINIMUM (0)        - reset physical
        0x45.toByte(), 0x00.toByte(),        //         PHYSICAL_MAXIMUM (0)
        0x75.toByte(), 0x08.toByte(),        //         REPORT_SIZE (8)                 //1字节 6个了 滚轮scroll 有符号数
        0x95.toByte(), 0x01.toByte(),                         //     REPORT_COUNT (1)
        0x81.toByte(), 0x06.toByte(),                         //     INPUT (Data,Var,Rel)
        0xc0.toByte(),              //       END_COLLECTION

        0xa1.toByte(), 0x02.toByte(),        //       COLLECTION (Logical)
        0x85.toByte(), 0x06.toByte(),               //   REPORT_ID (Feature)
        0x09.toByte(), 0x48.toByte(),        //         USAGE (Resolution Multiplier)

        0x15.toByte(), 0x00.toByte(),        //         LOGICAL_MINIMUM (0)
        0x25.toByte(), 0x01.toByte(),        //         LOGICAL_MAXIMUM (1)
        0x35.toByte(), 0x01.toByte(),        //         PHYSICAL_MINIMUM (1)
        0x45.toByte(), 0x04.toByte(),        //         PHYSICAL_MAXIMUM (4)
        0x75.toByte(), 0x02.toByte(),        //         REPORT_SIZE (2)
        0x95.toByte(), 0x01.toByte(),        //         REPORT_COUNT (1)

        0xb1.toByte(), 0x02.toByte(),        //         FEATURE (Data,Var,Abs)

        0x35.toByte(), 0x00.toByte(),        //         PHYSICAL_MINIMUM (0)        - reset physical
        0x45.toByte(), 0x00.toByte(),        //         PHYSICAL_MAXIMUM (0)
        0x75.toByte(), 0x04.toByte(),        //         REPORT_SIZE (4)
        0xb1.toByte(), 0x03.toByte(),        //         FEATURE (Cnst,Var,Abs)



        0x85.toByte(), 0x04.toByte(),               //   REPORT_ID (Mouse)         //显示鼠标 图标位图 bitmap
        0x05.toByte(), 0x0c.toByte(),        //         USAGE_PAGE (Consumer Devices)
        0x0a.toByte(), 0x38.toByte(), 0x02.toByte(),  //         USAGE (AC Pan)

        0x15.toByte(), 0x81.toByte(),        //         LOGICAL_MINIMUM (-127)
        0x25.toByte(), 0x7f.toByte(),        //         LOGICAL_MAXIMUM (127)
        0x75.toByte(), 0x08.toByte(),        //         REPORT_SIZE (8)
        0x95.toByte(), 0x01.toByte(),        //         REPORT_COUNT (1)  //7个字节
        0x81.toByte(), 0x06.toByte(),        //         INPUT (Data,Var,Rel)
        0xc0.toByte(),              //       END_COLLECTION
        0xc0.toByte(),              //       END_COLLECTION

        0xc0.toByte(),                               //   END_COLLECTION
        0xc0.toByte(),                                //END_COLLECTION

        0x05.toByte(), 0x01.toByte(),                         // USAGE_PAGE (Generic Desktop)

        0x09.toByte(), 0x06.toByte(),                         // Usage (Keyboard)
        0xA1.toByte(), 0x01.toByte(),                         // Collection (Application)
        0x85.toByte(), 0x08.toByte(),                           //   REPORT_ID (Keyboard)
        0x05.toByte(), 0x07.toByte(),                         //     Usage Page (Key Codes)
        0x19.toByte(), 0xe0.toByte(),                         //     Usage Minimum (224)
        0x29.toByte(), 0xe7.toByte(),                         //     Usage Maximum (231)
        0x15.toByte(), 0x00.toByte(),                         //     Logical Minimum (0)
        0x25.toByte(), 0x01.toByte(),                         //     Logical Maximum (1)
        0x75.toByte(), 0x01.toByte(),                         //     Report Size (1)
        0x95.toByte(), 0x08.toByte(),                         //     Report Count (8)
        0x81.toByte(), 0x02.toByte(),                         //     Input (Data, Variable, Absolute)

        0x95.toByte(), 0x01.toByte(),                         //     Report Count (1)
        0x75.toByte(), 0x08.toByte(),                         //     Report Size (8)
        0x81.toByte(), 0x01.toByte(),                         //     Input (Constant) reserved byte(1)



        0x95.toByte(), 0x01.toByte(),                         //     Report Count (1)
        0x75.toByte(), 0x08.toByte(),                         //     Report Size (8)
        0x15.toByte(), 0x00.toByte(),                         //     Logical Minimum (0)
        0x25.toByte(), 0x65.toByte(),                         //     Logical Maximum (101)
        0x05.toByte(), 0x07.toByte(),                         //     Usage Page (Key codes)
        0x19.toByte(), 0x00.toByte(),                         //     Usage Minimum (0)
        0x29.toByte(), 0x65.toByte(),                         //     Usage Maximum (101)
        0x81.toByte(), 0x00.toByte(),                         //     Input (Data, Array) Key array(6 bytes)
        0xc0.toByte()                               // End Collection (Application)

    )
键鼠设备向主机发送数据调用api  
hidDevice.sendReport(this.host, 4, mouseReport.bytes)

mouseReport.bytes 按照上图发送给主机的报告 构建  7个字节 

inline class ScrollableTrackpadMouseReport (
    val bytes: ByteArray = ByteArray(7) {0}
    ) {


        var leftButton: Boolean
        get() = bytes[0] and 0b1 != 0.toByte()
        set(value) {
            bytes[0] = if (value)
                bytes[0] or 0b1
            else
                bytes[0] and 0b110
        }

        var rightButton: Boolean
        get() = bytes[0] and 0b10 != 0.toByte()
        set(value) {
            bytes[0] = if (value)
                bytes[0] or 0b10
            else
                bytes[0] and 0b101
        }

  //X坐标变化量,,负数表示向左移,正数表右移。
        var dxLsb: Byte
        get() = bytes[1]
        set(value) { bytes[1] = value }

     
        var dxMsb: Byte
        get() = bytes[2]
        set(value) { bytes[2] = value }

    //Y坐标变化,负数表示向下移,正数表上移   
        var dyLsb: Byte
        get() = bytes[3]
        set(value) { bytes[3] = value }

    //y
        var dyMsb: Byte
        get() = bytes[4]
        set(value) { bytes[4] = value }

    // wheel

    var vScroll : Byte
        get() = bytes[5]
        set(value) {
            bytes[5]=value
        }

        var hScroll : Byte
        get() = bytes[6]
        set(value) {
            bytes[6]=value
        }



        fun reset() = bytes.fill(0)

        companion object {
            const val ID = 4
        }
}

HID TLC 描述

第1、2、3行组成一个TLC(Top Level Collection), 这个TLC是用来让主机加载相应的驱动的。也就是说主机收到前3行的数据后,它会在设备管理器里生成一个设备结点,并把蓝牙键盘鼠标的驱动挂到这个结点上。

HID Report Id

在报文描述符的第7 行有一个report id, 这个report id就代表这一组的报文。 上面的报文report id为1, 主机如果收到report id是 4 的话,它就知道它收到的报文是一个蓝牙键鼠的report. 总之一句话,report id跟这个TLC(或是说这个报文)是绑定在一起的。

比较重要的描述符  hid1_11.pdf (HID_USB )

 INPUT (Data,Var,Rel)   

Bit0位 =1 固定值 0  变化值  bit2 0 绝对值 在示例中 此致为 1表示 x y是相对值   0 则为鼠标绝对位置 

 Usages (HID Usage表)

参考

HID_USB

描述符 HID_v1.1.1.pdf

蓝牙BLE: GATT Profile 简介(GATT 与 GAP) - 夜行过客 - 博客园

https://usb.org/sites/default/files/hut1_22.pdf

蓝牙核心技术了解(蓝牙协议、架构、硬件和软件笔记) - 焦少 - 博客园

蓝牙概览  |  Android 开发者  |  Android Developers

HID报表描述符(目前最全的解析,也是USB最复杂的描述符) 报表描述符定义了执行设备功能的数据格式和使用方法。 报表描述符和 USB 的其他描述符是不一样的,它不是一个简单的表格,报表描述符是 USB 所有描述符中最复杂的。报表描述符非常复杂而有弹性,因为它需要处理各种用途的设备报表的数据必须以简洁的格式来储存,这样才不会浪费设备内的储存空间以及数据传输时的总线时间。实际上可以这样理解,报表内容的简洁,是通过报表描述符全面的、复杂的数据描述实现的。 报表描述符必须先描述数据的大小与内容。报表描述符的内容与大小因设备的不同而不同,在进行报表传输之前,主机必须先请求 阅读详情

相关推荐

蓝牙鼠标HID设备连接流程

蓝牙连接流程

好记性不如烂笔头 3252

HID协议详解 - Report Descriptor报告描述符构建与解析

本文共12000字,提供详细理解HID Report Descriptor的机会。 HID Report Descriptor报告描述符就是描述连接建立之后设备端发送给主机端的数据,每一字节(bytes)每一位(bits)所代表的意义。

雨落子衿的博客 1万+

Windows Touchpad 报告描述符实例

Windows USB Touchpad 报告描述符实例说明

qq_35733019的博客 2149

HID 报告描述

HID 报告描述 1 报告描述简介  Report Description,即上报事件的描述,描述所支持事件的格式及取值意义,比如鼠标按键上报格式、左键右键中间键分别对应的值等;报告描述跟JSON有些类似,都是结构数据,格式类似{usage:1, {id:0,usage:1.1,size:1,count:1,min:0,max:5,format:xx}} 2 描述符结构 几个主要的名词

sK.坤 1万+

HID报告类型详解:输入输出特征入门

深入讲解HID报告的三种类型——输入、输出与特征报告,帮助理解设备与主机间的数据交互机制,掌握hid在实际应用中的核心作用。

weixin_33506815的博客 1030

HID报文讲解

HID报文讲解 1 什么是HID? HID全称Human Interface Device,人机接口设备,具体指键盘鼠标,蓝牙和USB都采用相同的报文协议,https://www.usb.org/sites/default/files/documents/hid1_11.pdf 协议里有详细描述。 2 什么是HID报文? HID报文全称为HID Report Description,是一段用指令和数值来描述通信数据结构的数据组,定义了由设备发给PC或手机的数据包里的数据所表示的意思,比如哪个数据

sK.坤 5153

Android设备通过蓝牙HID技术模拟鼠标技术实现

日常生活中,各种物理遥控器和鼠标等设备,需要摆放和携带,便捷性有待考验。根据蓝牙HID特性,可以用蓝牙协议模仿鼠标事件,来实现空中鼠标等功能。

allen_xu_2012_new的博客 3920

DIY蓝牙键盘(2) - 理解HID报文描述符

1. 前情回顾 上篇主要讲了键盘报文的分类与格式,并留下了一个问题:那主机为什么知道我这些报文的格式?那肯定是主机要提前知道我们发的报文的格式,那么问题就变成了:在发送报文前我们要怎么通知主机,让它知道我们报文的格式。 这篇将回答这个问题,主机如何知道键盘报文的格式。答案就是键盘将发送HID report descriptor(HID报文描述符)给主机,主机根据HID描述符就知道键盘的报文格式。 2. HID 报文描述符简介 我们先理解一下逻辑: (1) 键盘通过发送报文描述符给主机,告诉主机它后面发出来的

easybook_zhu的博客 5965

蓝牙HID——将android设备变成蓝牙键盘(BluetoothHidDevice)

前段时间发现自己的老笔记本键盘失灵了,又没有多的键盘,于是苦恼了好久。于是萌生了自己做一个键盘的想法。这段时间一直在研究蓝牙HID,通过蓝牙HID将android手机变成一个蓝牙键盘,这样就不用担心无键盘的问题了。通过研究发现android9.0之后开放了等HID相关的API,从此入手开始HID开发。(一定要看到最后!) 首先通过获取HID设备代理得到: 需要开启设备发现: 这样才能被主机端发现并进行配对,上面的方式会弹框手动点击允许才可以启动设备发现。当然也可以通过反射调用隐藏的接口开启设备发现,这样就没

分享技术与经验的博客 2万+

【HOGP】规范精讲[6]: HID ISO Service服务定义与GATT落地解析

做过BLE电竞外设、VR交互控制器、高精度工业手柄的开发者都有过这样的经历:明明把HID ISO的传输机制、时序参数、CIS通道配置都调通了,却还是遇到主机不认设备的低延迟能力、模式切换频繁失败、写操作一直返回未知错误、ISO通道建立后数据完全无法解析的问题。排查到最后会发现,90%的坑,都出在HID ISO Service的GATT实现不符合规范上。

byte轻骑兵的技术小窝 7620

USB HID Report详解 以及游戏手柄HID报告描述符分析.pdf

详细的分析了游戏手柄的HID报告描述符

BLE HID简介

HID

幕色夜行 3万+

Verilog基本代码结构及常用语句always、begin...end解读

Verilog基本代码结构及常用语句always、begin...end解读 线性反馈以为寄存器(LFSR)

weixin_62380586的博客 1万+

Android Bluetooth HID Device模拟蓝牙键盘鼠标

Android Bluetooth HID Device模拟蓝牙键盘鼠标

lgdlchshg的专栏 4350

基于 OptiSystem 的掺铒光纤放大器(EDFA)分析

通过构建 EDFA 仿真模型,系统分析了铒离子掺杂半径、离子浓度、光纤长度及泵浦功率等关键参数对放大器增益和噪声特性的影响规律,为 EDFA 的优化设计提供了理论依据与仿真支撑。继续增大至 9μm,增益趋于稳定(约 19dB)。继续增加至 200mW,增益仅增加 2dB,表明泵浦功率存在阈值效应(约 100mW),超过后增益饱和明显。:作为增益介质,主要参数包括光纤长度(5~50m)、铒离子掺杂半径(1~10μm)、离子浓度(1×10²⁵~5×10²⁵m⁻³)、纤芯半径 2.2μm、数值孔径 0.24。

2501_91855190的博客 2677

用FPGA在HDMI上显示自定义字符:从COE文件到OSD叠加的保姆级教程

本文详细介绍了如何在FPGA上实现HDMI视频流的OSD字符叠加技术,从COE文件生成到动态区域控制的完整流程。通过Verilog代码示例和实战技巧,帮助开发者掌握字符ROM设计、像素坐标追踪和动态混合等核心技术,适用于视频监控、系统状态显示等应用场景。

weixin_28720767的博客 231

usb hid report descriptor

usb 设备固件中通常会烧写一些描述信息。 根据usb设计规范, 通常描述符信息包含以下几类: 设备描述符 |-- 配置描述符 |-- 接口描述符 |--端点描述符 | -- 字符串描述符 分别描述该usb设备的厂商, 类别, ID, 配置, 接口, 端点等等。 对于usb hid设备来说, 比较特殊的是其...

River的专栏 2767

Hcaptcha验证码破解深度解析:从环境检测到n值算法的攻防实战

本文深入解析Hcaptcha验证码的攻防技术,从环境检测到n值算法的全面突破策略。详细介绍了浏览器指纹模拟、图像识别工程化解决方案及协议层逆向分析,为安全研究人员提供高效破解Hcaptcha的实战指南。

weixin_42563415的博客 375

Hid Report Descriptor

  在USB中,USB HOST是通过各种描述符来识别设备的,有设备描述符,配置描述符,接口描述符,端点描述符,字符串描述符,报告描述符等等。USB报告描述符(Report Descriptor)是HID设备中的一个描述符,它是比较复杂的一个描述符。     USB HID设备是通过报告来给传送数据的,报告有输入报告和输出报告。输入报告是USB设备发送给主机的,例如USB鼠标将...

weixin_30267691的博客 724

【Win10/11】Windows电脑WiFi显示小地球/断网的解决方法 Windows WiFi小地球、网络连接中断、网络重置、无线网卡驱动、Win10/Win11网络修复

最近经常有粉丝留言问我,Windows 电脑突然连不上 WiFi,右下角网络图标显示成了“小地球 🌐”,或者干脆提示“未连接 - 没有可用的连接”。明明其他设备网络都正常,唯独自己的电脑断了。作为在互联网大厂混迹多年的前端程序员,我自己也碰到过这个问题。总结几种比较常见、亲测有效的解决方法,写出来供大家参考,希望能帮你快速恢复上网!问题原因推荐解决方法系统设置错乱使用网络重置功能驱动异常或冲突卸载后重启自动安装驱动驱动版本过旧手动更新网卡驱动实在不行考虑使用系统还原点或重装系统这几个方法中,

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 3850

LVGL 磁罗盘效果

环境:LVGL 9.x + SDL2,窗口 1280×800。界面文案用英文(默认 Montserrat,无 CJK)。本文按实现顺序讲:先建立两个耦合转动体,再把磁倾角误差从卡面倾斜里推出来,最后用同一套投影把刻度、数字和目标画到卡上。画面上的迟滞、涡流、摆动和读数偏差都来自方程,没有补间动画。

摸鱼专家 88

android usb hid键盘键值,avr模拟电脑USBHID键盘,键值对应关系问题,和ASCII表对应符不符?请教!...

原帖:http://www.ourdev.cn/bbs/bbs_content_all.jsp?bbs_sn=3253865上面是用attiny45模拟usb键盘,定时发送CapsLocker(大写锁定按键)本人疑惑代码:reportBuffer[0]=0; //特殊功能键reportBuffer[1]=0x39;//键值usbSetInterrupt(reportBuffer, sizeof...

weixin_34966742的博客 726

QGC4.0.11界面修改

QGC4.0.11。

超维空间科技的博客 2467

USB HID报告及报告描述符简介

在USB中,USB HOST是通过各种描述符来识别设备的,有设备描述符, 配置描述符,接口描述符,端点描述符,字符串描述符,报告描述符等等。 USB报告描述符(Report Descriptor)是HID设备中的一个描述符,它是比较 复杂的一个描述符。         USB HID设备是通过报告来给传送数据的,报告有输入报告和输出报告。 输入报告是USB设备发送给主机的,例如USB鼠标

wu55uw的专栏 1611

华为OD面试八股真题 - 操作系统相关 - 2

华为OD技术面,操作系统相关八股真题提供详细解答,这篇博客主要涉及于进程和线程相关知识点

qq_45776114的博客 968

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

USB/HID设备报告描述符详解(zhuan)

概述: 报告在这里意思是数据传输(data transfer),而报告描述符是对这些传输的数据作用途(usage)上的说明。 USB通讯协议的规范是以1ms产生一个USB帧(frame),USB设备可以每一个帧中发送和接收一...

cuj2489的博客 5208

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

上一篇: Webrtc添加滤镜
下一篇: Translation Lookaside Buffer (TLB)
江太翁
博客等级 码龄15年 271粉丝 141原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值